/rpython/jit/metainterp/pyjitpl.py
Python | 3361 lines | 3074 code | 141 blank | 146 comment | 143 complexity | 97877d59e379df1dde9641100abb1af8 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
Large files files are truncated, but you can click here to view the full file
- import sys
- import py
- from rpython.jit.codewriter import heaptracker, longlong
- from rpython.jit.codewriter.effectinfo import EffectInfo
- from rpython.jit.codewriter.jitcode import JitCode, SwitchDictDescr
- from rpython.jit.metainterp import history, compile, resume, executor, jitexc
- from rpython.jit.metainterp.heapcache import HeapCache
- from rpython.jit.metainterp.history import (Const, ConstInt, ConstPtr,
- ConstFloat, TargetToken, MissingValue, SwitchToBlackhole)
- from rpython.jit.metainterp.jitprof import EmptyProfiler
- from rpython.jit.metainterp.logger import Logger
- from rpython.jit.metainterp.optimizeopt.util import args_dict
- from rpython.jit.metainterp.resoperation import rop, OpHelpers, GuardResOp
- from rpython.rlib.rjitlog import rjitlog as jl
- from rpython.rlib import nonconst, rstack
- from rpython.rlib.debug import debug_start, debug_stop, debug_print
- from rpython.rlib.debug import have_debug_prints, make_sure_not_resized
- from rpython.rlib.jit import Counters
- from rpython.rlib.objectmodel import we_are_translated, specialize
- from rpython.rlib.unroll import unrolling_iterable
- from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
- from rpython.rtyper import rclass
- from rpython.rlib.objectmodel import compute_unique_id
- # ____________________________________________________________
- def arguments(*args):
- def decorate(func):
- func.argtypes = args
- return func
- return decorate
- # ____________________________________________________________
- FASTPATHS_SAME_BOXES = {
- "ne": "history.CONST_FALSE",
- "eq": "history.CONST_TRUE",
- "lt": "history.CONST_FALSE",
- "le": "history.CONST_TRUE",
- "gt": "history.CONST_FALSE",
- "ge": "history.CONST_TRUE",
- }
- class MIFrame(object):
- debug = False
- def __init__(self, metainterp):
- self.metainterp = metainterp
- self.registers_i = [None] * 256
- self.registers_r = [None] * 256
- self.registers_f = [None] * 256
- def setup(self, jitcode, greenkey=None):
- # if not translated, fill the registers with MissingValue()
- if not we_are_translated():
- self.registers_i = [MissingValue()] * 256
- self.registers_r = [MissingValue()] * 256
- self.registers_f = [MissingValue()] * 256
- assert isinstance(jitcode, JitCode)
- self.jitcode = jitcode
- self.bytecode = jitcode.code
- # this is not None for frames that are recursive portal calls
- self.greenkey = greenkey
- # copy the constants in place
- self.copy_constants(self.registers_i, jitcode.constants_i, ConstInt)
- self.copy_constants(self.registers_r, jitcode.constants_r, ConstPtr)
- self.copy_constants(self.registers_f, jitcode.constants_f, ConstFloat)
- self._result_argcode = 'v'
- # for resume.py operation
- self.parent_snapshot = None
- # counter for unrolling inlined loops
- self.unroll_iterations = 1
- @specialize.arg(3)
- def copy_constants(self, registers, constants, ConstClass):
- """Copy jitcode.constants[0] to registers[255],
- jitcode.constants[1] to registers[254],
- jitcode.constants[2] to registers[253], etc."""
- if nonconst.NonConstant(0): # force the right type
- constants[0] = ConstClass.value # (useful for small tests)
- i = len(constants) - 1
- while i >= 0:
- j = 255 - i
- assert j >= 0
- registers[j] = ConstClass(constants[i])
- i -= 1
- def cleanup_registers(self):
- # To avoid keeping references alive, this cleans up the registers_r.
- # It does not clear the references set by copy_constants(), but
- # these are all prebuilt constants anyway.
- for i in range(self.jitcode.num_regs_r()):
- self.registers_r[i] = None
- # ------------------------------
- # Decoding of the JitCode
- @specialize.arg(4)
- def prepare_list_of_boxes(self, outvalue, startindex, position, argcode):
- assert argcode in 'IRF'
- code = self.bytecode
- length = ord(code[position])
- position += 1
- for i in range(length):
- index = ord(code[position+i])
- if argcode == 'I': reg = self.registers_i[index]
- elif argcode == 'R': reg = self.registers_r[index]
- elif argcode == 'F': reg = self.registers_f[index]
- else: raise AssertionError(argcode)
- outvalue[startindex+i] = reg
- def _put_back_list_of_boxes(self, outvalue, startindex, position):
- code = self.bytecode
- length = ord(code[position])
- position += 1
- for i in range(length):
- index = ord(code[position+i])
- box = outvalue[startindex+i]
- if box.type == history.INT: self.registers_i[index] = box
- elif box.type == history.REF: self.registers_r[index] = box
- elif box.type == history.FLOAT: self.registers_f[index] = box
- else: raise AssertionError(box.type)
- def get_current_position_info(self):
- return self.jitcode.get_live_vars_info(self.pc)
- def get_list_of_active_boxes(self, in_a_call, new_array, encode):
- if in_a_call:
- # If we are not the topmost frame, self._result_argcode contains
- # the type of the result of the call instruction in the bytecode.
- # We use it to clear the box that will hold the result: this box
- # is not defined yet.
- argcode = self._result_argcode
- index = ord(self.bytecode[self.pc - 1])
- if argcode == 'i': self.registers_i[index] = history.CONST_FALSE
- elif argcode == 'r': self.registers_r[index] = history.CONST_NULL
- elif argcode == 'f': self.registers_f[index] = history.CONST_FZERO
- self._result_argcode = '?' # done
- #
- info = self.get_current_position_info()
- start_i = 0
- start_r = start_i + info.get_register_count_i()
- start_f = start_r + info.get_register_count_r()
- total = start_f + info.get_register_count_f()
- # allocate a list of the correct size
- env = new_array(total)
- make_sure_not_resized(env)
- # fill it now
- for i in range(info.get_register_count_i()):
- index = info.get_register_index_i(i)
- env[start_i + i] = encode(self.registers_i[index])
- for i in range(info.get_register_count_r()):
- index = info.get_register_index_r(i)
- env[start_r + i] = encode(self.registers_r[index])
- for i in range(info.get_register_count_f()):
- index = info.get_register_index_f(i)
- env[start_f + i] = encode(self.registers_f[index])
- return env
- def replace_active_box_in_frame(self, oldbox, newbox):
- if oldbox.type == 'i':
- count = self.jitcode.num_regs_i()
- registers = self.registers_i
- elif oldbox.type == 'r':
- count = self.jitcode.num_regs_r()
- registers = self.registers_r
- elif oldbox.type == 'f':
- count = self.jitcode.num_regs_f()
- registers = self.registers_f
- else:
- assert 0, oldbox
- for i in range(count):
- if registers[i] is oldbox:
- registers[i] = newbox
- if not we_are_translated():
- for b in registers[count:]:
- assert isinstance(b, (MissingValue, Const))
- def make_result_of_lastop(self, resultbox):
- got_type = resultbox.type
- if not we_are_translated():
- typeof = {'i': history.INT,
- 'r': history.REF,
- 'f': history.FLOAT}
- assert typeof[self.jitcode._resulttypes[self.pc]] == got_type
- target_index = ord(self.bytecode[self.pc-1])
- if got_type == history.INT:
- self.registers_i[target_index] = resultbox
- elif got_type == history.REF:
- #debug_print(' ->',
- # llmemory.cast_ptr_to_adr(resultbox.getref_base()))
- self.registers_r[target_index] = resultbox
- elif got_type == history.FLOAT:
- self.registers_f[target_index] = resultbox
- else:
- raise AssertionError("bad result box type")
- # ------------------------------
- for _opimpl in ['int_add', 'int_sub', 'int_mul',
- 'int_and', 'int_or', 'int_xor', 'int_signext',
- 'int_rshift', 'int_lshift', 'uint_rshift',
- 'uint_lt', 'uint_le', 'uint_gt', 'uint_ge',
- 'float_add', 'float_sub', 'float_mul', 'float_truediv',
- 'float_lt', 'float_le', 'float_eq',
- 'float_ne', 'float_gt', 'float_ge',
- ]:
- exec py.code.Source('''
- @arguments("box", "box")
- def opimpl_%s(self, b1, b2):
- return self.execute(rop.%s, b1, b2)
- ''' % (_opimpl, _opimpl.upper())).compile()
- for _opimpl in ['int_eq', 'int_ne', 'int_lt', 'int_le', 'int_gt', 'int_ge',
- 'ptr_eq', 'ptr_ne',
- 'instance_ptr_eq', 'instance_ptr_ne']:
- exec py.code.Source('''
- @arguments("box", "box")
- def opimpl_%s(self, b1, b2):
- if b1 is b2: # crude fast check
- return %s
- return self.execute(rop.%s, b1, b2)
- ''' % (_opimpl, FASTPATHS_SAME_BOXES[_opimpl.split("_")[-1]], _opimpl.upper())
- ).compile()
- for (_opimpl, resop) in [
- ('int_add_jump_if_ovf', 'INT_ADD_OVF'),
- ('int_sub_jump_if_ovf', 'INT_SUB_OVF'),
- ('int_mul_jump_if_ovf', 'INT_MUL_OVF')]:
- exec py.code.Source('''
- @arguments("label", "box", "box", "orgpc")
- def opimpl_%s(self, lbl, b1, b2, orgpc):
- self.metainterp.ovf_flag = False
- resbox = self.execute(rop.%s, b1, b2)
- if not isinstance(resbox, Const):
- return self.handle_possible_overflow_error(lbl, orgpc,
- resbox)
- elif self.metainterp.ovf_flag:
- self.pc = lbl
- return None # but don't emit GUARD_OVERFLOW
- return resbox
- ''' % (_opimpl, resop)).compile()
- for _opimpl in ['int_is_true', 'int_is_zero', 'int_neg', 'int_invert',
- 'cast_float_to_int', 'cast_int_to_float',
- 'cast_float_to_singlefloat', 'cast_singlefloat_to_float',
- 'float_neg', 'float_abs',
- 'cast_ptr_to_int', 'cast_int_to_ptr',
- 'convert_float_bytes_to_longlong',
- 'convert_longlong_bytes_to_float', 'int_force_ge_zero',
- ]:
- exec py.code.Source('''
- @arguments("box")
- def opimpl_%s(self, b):
- return self.execute(rop.%s, b)
- ''' % (_opimpl, _opimpl.upper())).compile()
- @arguments("box")
- def opimpl_int_same_as(self, box):
- # for tests only: emits a same_as, forcing the result to be in a Box
- resbox = self.metainterp._record_helper_nonpure_varargs(
- rop.SAME_AS_I, box.getint(), None, [box])
- return resbox
- @arguments("box")
- def opimpl_ptr_nonzero(self, box):
- return self.execute(rop.PTR_NE, box, history.CONST_NULL)
- @arguments("box")
- def opimpl_ptr_iszero(self, box):
- return self.execute(rop.PTR_EQ, box, history.CONST_NULL)
- @arguments("box", "box")
- def opimpl_record_exact_class(self, box, clsbox):
- from rpython.rtyper.lltypesystem import llmemory
- if self.metainterp.heapcache.is_class_known(box):
- return
- adr = clsbox.getaddr()
- self.execute(rop.RECORD_EXACT_CLASS, box, clsbox)
- self.metainterp.heapcache.class_now_known(box)
- @arguments("box")
- def _opimpl_any_return(self, box):
- self.metainterp.finishframe(box)
- opimpl_int_return = _opimpl_any_return
- opimpl_ref_return = _opimpl_any_return
- opimpl_float_return = _opimpl_any_return
- @arguments()
- def opimpl_void_return(self):
- self.metainterp.finishframe(None)
- @arguments("box")
- def _opimpl_any_copy(self, box):
- return box
- opimpl_int_copy = _opimpl_any_copy
- opimpl_ref_copy = _opimpl_any_copy
- opimpl_float_copy = _opimpl_any_copy
- @arguments("box")
- def _opimpl_any_push(self, box):
- self.pushed_box = box
- opimpl_int_push = _opimpl_any_push
- opimpl_ref_push = _opimpl_any_push
- opimpl_float_push = _opimpl_any_push
- @arguments()
- def _opimpl_any_pop(self):
- box = self.pushed_box
- self.pushed_box = None
- return box
- opimpl_int_pop = _opimpl_any_pop
- opimpl_ref_pop = _opimpl_any_pop
- opimpl_float_pop = _opimpl_any_pop
- @arguments("label")
- def opimpl_catch_exception(self, target):
- """This is a no-op when run normally. We can check that
- last_exc_value is a null ptr; it should have been set to None
- by the previous instruction. If the previous instruction
- raised instead, finishframe_exception() should have been
- called and we would not be there."""
- assert not self.metainterp.last_exc_value
- @arguments("label")
- def opimpl_goto(self, target):
- self.pc = target
- @arguments("box", "label", "orgpc")
- def opimpl_goto_if_not(self, box, target, orgpc):
- switchcase = box.getint()
- if switchcase:
- opnum = rop.GUARD_TRUE
- else:
- opnum = rop.GUARD_FALSE
- self.metainterp.generate_guard(opnum, box, resumepc=orgpc)
- if not switchcase:
- self.pc = target
- @arguments("box", "label", "orgpc")
- def opimpl_goto_if_not_int_is_true(self, box, target, orgpc):
- condbox = self.execute(rop.INT_IS_TRUE, box)
- self.opimpl_goto_if_not(condbox, target, orgpc)
- @arguments("box", "label", "orgpc")
- def opimpl_goto_if_not_int_is_zero(self, box, target, orgpc):
- condbox = self.execute(rop.INT_IS_ZERO, box)
- self.opimpl_goto_if_not(condbox, target, orgpc)
- for _opimpl in ['int_lt', 'int_le', 'int_eq', 'int_ne', 'int_gt', 'int_ge',
- 'ptr_eq', 'ptr_ne', 'float_lt', 'float_le', 'float_eq',
- 'float_ne', 'float_gt', 'float_ge']:
- exec py.code.Source('''
- @arguments("box", "box", "label", "orgpc")
- def opimpl_goto_if_not_%s(self, b1, b2, target, orgpc):
- if %s and b1 is b2:
- condbox = %s
- else:
- condbox = self.execute(rop.%s, b1, b2)
- self.opimpl_goto_if_not(condbox, target, orgpc)
- ''' % (_opimpl, not _opimpl.startswith('float_'),
- FASTPATHS_SAME_BOXES[_opimpl.split("_")[-1]], _opimpl.upper())
- ).compile()
- def _establish_nullity(self, box, orgpc):
- heapcache = self.metainterp.heapcache
- value = box.nonnull()
- if heapcache.is_nullity_known(box):
- return value
- if value:
- if not self.metainterp.heapcache.is_class_known(box):
- self.metainterp.generate_guard(rop.GUARD_NONNULL, box,
- resumepc=orgpc)
- else:
- if not isinstance(box, Const):
- self.metainterp.generate_guard(rop.GUARD_ISNULL, box,
- resumepc=orgpc)
- promoted_box = executor.constant_from_op(box)
- self.metainterp.replace_box(box, promoted_box)
- heapcache.nullity_now_known(box)
- return value
- @arguments("box", "label", "orgpc")
- def opimpl_goto_if_not_ptr_nonzero(self, box, target, orgpc):
- if not self._establish_nullity(box, orgpc):
- self.pc = target
- @arguments("box", "label", "orgpc")
- def opimpl_goto_if_not_ptr_iszero(self, box, target, orgpc):
- if self._establish_nullity(box, orgpc):
- self.pc = target
- @arguments("box", "box", "box")
- def opimpl_int_between(self, b1, b2, b3):
- b5 = self.execute(rop.INT_SUB, b3, b1)
- if isinstance(b5, ConstInt) and b5.getint() == 1:
- # the common case of int_between(a, b, a+1) turns into just INT_EQ
- return self.execute(rop.INT_EQ, b2, b1)
- else:
- b4 = self.execute(rop.INT_SUB, b2, b1)
- return self.execute(rop.UINT_LT, b4, b5)
- @arguments("box", "descr", "orgpc")
- def opimpl_switch(self, valuebox, switchdict, orgpc):
- search_value = valuebox.getint()
- assert isinstance(switchdict, SwitchDictDescr)
- try:
- target = switchdict.dict[search_value]
- except KeyError:
- # None of the cases match. Fall back to generating a chain
- # of 'int_eq'.
- # xxx as a minor optimization, if that's a bridge, then we would
- # not need the cases that we already tested (and failed) with
- # 'guard_value'. How to do it is not very clear though.
- for const1 in switchdict.const_keys_in_order:
- box = self.execute(rop.INT_EQ, valuebox, const1)
- assert box.getint() == 0
- target = switchdict.dict[const1.getint()]
- self.metainterp.generate_guard(rop.GUARD_FALSE, box,
- resumepc=orgpc)
- else:
- # found one of the cases
- self.implement_guard_value(valuebox, orgpc)
- self.pc = target
- @arguments()
- def opimpl_unreachable(self):
- raise AssertionError("unreachable")
- @arguments("descr")
- def opimpl_new(self, sizedescr):
- return self.metainterp.execute_new(sizedescr)
- @arguments("descr")
- def opimpl_new_with_vtable(self, sizedescr):
- return self.metainterp.execute_new_with_vtable(descr=sizedescr)
- @arguments("box", "descr")
- def opimpl_new_array(self, lengthbox, itemsizedescr):
- return self.metainterp.execute_new_array(itemsizedescr, lengthbox)
- @arguments("box", "descr")
- def opimpl_new_array_clear(self, lengthbox, itemsizedescr):
- return self.metainterp.execute_new_array_clear(itemsizedescr, lengthbox)
- @specialize.arg(1)
- def _do_getarrayitem_gc_any(self, op, arraybox, indexbox, arraydescr):
- tobox = self.metainterp.heapcache.getarrayitem(
- arraybox, indexbox, arraydescr)
- if tobox:
- # sanity check: see whether the current array value
- # corresponds to what the cache thinks the value is
- resvalue = executor.execute(self.metainterp.cpu, self.metainterp,
- op, arraydescr, arraybox, indexbox)
- if op == 'i':
- assert resvalue == tobox.getint()
- elif op == 'r':
- assert resvalue == tobox.getref_base()
- elif op == 'f':
- assert resvalue == tobox.getfloat()
- return tobox
- resop = self.execute_with_descr(op, arraydescr, arraybox, indexbox)
- self.metainterp.heapcache.getarrayitem_now_known(
- arraybox, indexbox, resop, arraydescr)
- return resop
- @arguments("box", "box", "descr")
- def opimpl_getarrayitem_gc_i(self, arraybox, indexbox, arraydescr):
- return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_I, arraybox,
- indexbox, arraydescr)
- @arguments("box", "box", "descr")
- def opimpl_getarrayitem_gc_r(self, arraybox, indexbox, arraydescr):
- return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_R, arraybox,
- indexbox, arraydescr)
- @arguments("box", "box", "descr")
- def opimpl_getarrayitem_gc_f(self, arraybox, indexbox, arraydescr):
- return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_F, arraybox,
- indexbox, arraydescr)
- @arguments("box", "box", "descr")
- def opimpl_getarrayitem_raw_i(self, arraybox, indexbox, arraydescr):
- return self.execute_with_descr(rop.GETARRAYITEM_RAW_I,
- arraydescr, arraybox, indexbox)
- @arguments("box", "box", "descr")
- def opimpl_getarrayitem_raw_f(self, arraybox, indexbox, arraydescr):
- return self.execute_with_descr(rop.GETARRAYITEM_RAW_F,
- arraydescr, arraybox, indexbox)
- @arguments("box", "box", "descr")
- def opimpl_getarrayitem_gc_i_pure(self, arraybox, indexbox, arraydescr):
- if isinstance(arraybox, ConstPtr) and isinstance(indexbox, ConstInt):
- # if the arguments are directly constants, bypass the heapcache
- # completely
- val = executor.execute(self.metainterp.cpu, self.metainterp,
- rop.GETARRAYITEM_GC_PURE_I, arraydescr,
- arraybox, indexbox)
- return executor.wrap_constant(val)
- return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_PURE_I,
- arraybox, indexbox, arraydescr)
- @arguments("box", "box", "descr")
- def opimpl_getarrayitem_gc_f_pure(self, arraybox, indexbox, arraydescr):
- if isinstance(arraybox, ConstPtr) and isinstance(indexbox, ConstInt):
- # if the arguments are directly constants, bypass the heapcache
- # completely
- resval = executor.execute(self.metainterp.cpu, self.metainterp,
- rop.GETARRAYITEM_GC_PURE_F, arraydescr,
- arraybox, indexbox)
- return executor.wrap_constant(resval)
- return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_PURE_F,
- arraybox, indexbox, arraydescr)
- @arguments("box", "box", "descr")
- def opimpl_getarrayitem_gc_r_pure(self, arraybox, indexbox, arraydescr):
- if isinstance(arraybox, ConstPtr) and isinstance(indexbox, ConstInt):
- # if the arguments are directly constants, bypass the heapcache
- # completely
- val = executor.execute(self.metainterp.cpu, self.metainterp,
- rop.GETARRAYITEM_GC_PURE_R, arraydescr,
- arraybox, indexbox)
- return executor.wrap_constant(val)
- return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_PURE_R,
- arraybox, indexbox, arraydescr)
- @arguments("box", "box", "box", "descr")
- def _opimpl_setarrayitem_gc_any(self, arraybox, indexbox, itembox,
- arraydescr):
- self.metainterp.execute_setarrayitem_gc(arraydescr, arraybox,
- indexbox, itembox)
- opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any
- opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any
- opimpl_setarrayitem_gc_f = _opimpl_setarrayitem_gc_any
- @arguments("box", "box", "box", "descr")
- def _opimpl_setarrayitem_raw_any(self, arraybox, indexbox, itembox,
- arraydescr):
- self.execute_with_descr(rop.SETARRAYITEM_RAW, arraydescr, arraybox,
- indexbox, itembox)
- opimpl_setarrayitem_raw_i = _opimpl_setarrayitem_raw_any
- opimpl_setarrayitem_raw_f = _opimpl_setarrayitem_raw_any
- @arguments("box", "descr")
- def opimpl_arraylen_gc(self, arraybox, arraydescr):
- lengthbox = self.metainterp.heapcache.arraylen(arraybox)
- if lengthbox is None:
- lengthbox = self.execute_with_descr(
- rop.ARRAYLEN_GC, arraydescr, arraybox)
- self.metainterp.heapcache.arraylen_now_known(arraybox, lengthbox)
- return lengthbox
- @arguments("box", "box", "descr", "orgpc")
- def opimpl_check_neg_index(self, arraybox, indexbox, arraydescr, orgpc):
- negbox = self.metainterp.execute_and_record(
- rop.INT_LT, None, indexbox, history.CONST_FALSE)
- negbox = self.implement_guard_value(negbox, orgpc)
- if negbox.getint():
- # the index is < 0; add the array length to it
- lengthbox = self.opimpl_arraylen_gc(arraybox, arraydescr)
- indexbox = self.metainterp.execute_and_record(
- rop.INT_ADD, None, indexbox, lengthbox)
- return indexbox
- @arguments("box", "descr", "descr", "descr", "descr")
- def opimpl_newlist(self, sizebox, structdescr, lengthdescr,
- itemsdescr, arraydescr):
- sbox = self.opimpl_new(structdescr)
- self._opimpl_setfield_gc_any(sbox, sizebox, lengthdescr)
- if (arraydescr.is_array_of_structs() or
- arraydescr.is_array_of_pointers()):
- abox = self.opimpl_new_array_clear(sizebox, arraydescr)
- else:
- abox = self.opimpl_new_array(sizebox, arraydescr)
- self._opimpl_setfield_gc_any(sbox, abox, itemsdescr)
- return sbox
- @arguments("box", "descr", "descr", "descr", "descr")
- def opimpl_newlist_clear(self, sizebox, structdescr, lengthdescr,
- itemsdescr, arraydescr):
- sbox = self.opimpl_new(structdescr)
- self._opimpl_setfield_gc_any(sbox, sizebox, lengthdescr)
- abox = self.opimpl_new_array_clear(sizebox, arraydescr)
- self._opimpl_setfield_gc_any(sbox, abox, itemsdescr)
- return sbox
- @arguments("box", "descr", "descr", "descr", "descr")
- def opimpl_newlist_hint(self, sizehintbox, structdescr, lengthdescr,
- itemsdescr, arraydescr):
- sbox = self.opimpl_new(structdescr)
- self._opimpl_setfield_gc_any(sbox, history.CONST_FALSE, lengthdescr)
- if (arraydescr.is_array_of_structs() or
- arraydescr.is_array_of_pointers()):
- abox = self.opimpl_new_array_clear(sizehintbox, arraydescr)
- else:
- abox = self.opimpl_new_array(sizehintbox, arraydescr)
- self._opimpl_setfield_gc_any(sbox, abox, itemsdescr)
- return sbox
- @arguments("box", "box", "descr", "descr")
- def opimpl_getlistitem_gc_i(self, listbox, indexbox,
- itemsdescr, arraydescr):
- arraybox = self.opimpl_getfield_gc_r(listbox, itemsdescr)
- return self.opimpl_getarrayitem_gc_i(arraybox, indexbox, arraydescr)
- @arguments("box", "box", "descr", "descr")
- def opimpl_getlistitem_gc_r(self, listbox, indexbox,
- itemsdescr, arraydescr):
- arraybox = self.opimpl_getfield_gc_r(listbox, itemsdescr)
- return self.opimpl_getarrayitem_gc_r(arraybox, indexbox, arraydescr)
- @arguments("box", "box", "descr", "descr")
- def opimpl_getlistitem_gc_f(self, listbox, indexbox,
- itemsdescr, arraydescr):
- arraybox = self.opimpl_getfield_gc_r(listbox, itemsdescr)
- return self.opimpl_getarrayitem_gc_f(arraybox, indexbox, arraydescr)
- @arguments("box", "box", "box", "descr", "descr")
- def _opimpl_setlistitem_gc_any(self, listbox, indexbox, valuebox,
- itemsdescr, arraydescr):
- arraybox = self.opimpl_getfield_gc_r(listbox, itemsdescr)
- self._opimpl_setarrayitem_gc_any(arraybox, indexbox, valuebox,
- arraydescr)
- opimpl_setlistitem_gc_i = _opimpl_setlistitem_gc_any
- opimpl_setlistitem_gc_r = _opimpl_setlistitem_gc_any
- opimpl_setlistitem_gc_f = _opimpl_setlistitem_gc_any
- @arguments("box", "box", "descr", "orgpc")
- def opimpl_check_resizable_neg_index(self, listbox, indexbox,
- lengthdescr, orgpc):
- negbox = self.metainterp.execute_and_record(
- rop.INT_LT, None, indexbox, history.CONST_FALSE)
- negbox = self.implement_guard_value(negbox, orgpc)
- if negbox.getint():
- # the index is < 0; add the array length to it
- lenbox = self.metainterp.execute_and_record(
- rop.GETFIELD_GC, lengthdescr, listbox)
- indexbox = self.metainterp.execute_and_record(
- rop.INT_ADD, None, indexbox, lenbox)
- return indexbox
- @arguments("box", "descr")
- def opimpl_getfield_gc_i(self, box, fielddescr):
- if fielddescr.is_always_pure() and isinstance(box, ConstPtr):
- # if 'box' is directly a ConstPtr, bypass the heapcache completely
- resbox = executor.execute(self.metainterp.cpu, self.metainterp,
- rop.GETFIELD_GC_I, fielddescr, box)
- return ConstInt(resbox)
- return self._opimpl_getfield_gc_any_pureornot(
- rop.GETFIELD_GC_I, box, fielddescr, 'i')
- @arguments("box", "descr")
- def opimpl_getfield_gc_f(self, box, fielddescr):
- if fielddescr.is_always_pure() and isinstance(box, ConstPtr):
- # if 'box' is directly a ConstPtr, bypass the heapcache completely
- resvalue = executor.execute(self.metainterp.cpu, self.metainterp,
- rop.GETFIELD_GC_F, fielddescr, box)
- return ConstFloat(resvalue)
- return self._opimpl_getfield_gc_any_pureornot(
- rop.GETFIELD_GC_F, box, fielddescr, 'f')
- @arguments("box", "descr")
- def opimpl_getfield_gc_r(self, box, fielddescr):
- if fielddescr.is_always_pure() and isinstance(box, ConstPtr):
- # if 'box' is directly a ConstPtr, bypass the heapcache completely
- val = executor.execute(self.metainterp.cpu, self.metainterp,
- rop.GETFIELD_GC_R, fielddescr, box)
- return ConstPtr(val)
- return self._opimpl_getfield_gc_any_pureornot(
- rop.GETFIELD_GC_R, box, fielddescr, 'r')
- opimpl_getfield_gc_i_pure = opimpl_getfield_gc_i
- opimpl_getfield_gc_r_pure = opimpl_getfield_gc_r
- opimpl_getfield_gc_f_pure = opimpl_getfield_gc_f
- @arguments("box", "box", "descr")
- def opimpl_getinteriorfield_gc_i(self, array, index, descr):
- return self.execute_with_descr(rop.GETINTERIORFIELD_GC_I, descr,
- array, index)
- @arguments("box", "box", "descr")
- def opimpl_getinteriorfield_gc_r(self, array, index, descr):
- return self.execute_with_descr(rop.GETINTERIORFIELD_GC_R, descr,
- array, index)
- @arguments("box", "box", "descr")
- def opimpl_getinteriorfield_gc_f(self, array, index, descr):
- return self.execute_with_descr(rop.GETINTERIORFIELD_GC_F, descr,
- array, index)
- @specialize.arg(1, 4)
- def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr, type):
- upd = self.metainterp.heapcache.get_field_updater(box, fielddescr)
- if upd.currfieldbox is not None:
- # sanity check: see whether the current struct value
- # corresponds to what the cache thinks the value is
- resvalue = executor.execute(self.metainterp.cpu, self.metainterp,
- opnum, fielddescr, box)
- if type == 'i':
- assert resvalue == upd.currfieldbox.getint()
- elif type == 'r':
- assert resvalue == upd.currfieldbox.getref_base()
- else:
- assert type == 'f'
- # make the comparison more robust again NaNs
- # see ConstFloat.same_constant
- assert ConstFloat(resvalue).same_constant(
- upd.currfieldbox.constbox())
- return upd.currfieldbox
- resbox = self.execute_with_descr(opnum, fielddescr, box)
- upd.getfield_now_known(resbox)
- return resbox
- @arguments("box", "descr", "orgpc")
- def _opimpl_getfield_gc_greenfield_any(self, box, fielddescr, pc):
- ginfo = self.metainterp.jitdriver_sd.greenfield_info
- opnum = OpHelpers.getfield_for_descr(fielddescr)
- if (ginfo is not None and fielddescr in ginfo.green_field_descrs
- and not self._nonstandard_virtualizable(pc, box, fielddescr)):
- # fetch the result, but consider it as a Const box and don't
- # record any operation
- return executor.execute_nonspec_const(self.metainterp.cpu,
- self.metainterp, opnum, [box], fielddescr)
- # fall-back
- if fielddescr.is_pointer_field():
- return self.execute_with_descr(rop.GETFIELD_GC_R, fielddescr, box)
- elif fielddescr.is_float_field():
- return self.execute_with_descr(rop.GETFIELD_GC_F, fielddescr, box)
- else:
- return self.execute_with_descr(rop.GETFIELD_GC_I, fielddescr, box)
- opimpl_getfield_gc_i_greenfield = _opimpl_getfield_gc_greenfield_any
- opimpl_getfield_gc_r_greenfield = _opimpl_getfield_gc_greenfield_any
- opimpl_getfield_gc_f_greenfield = _opimpl_getfield_gc_greenfield_any
- @arguments("box", "box", "descr")
- def _opimpl_setfield_gc_any(self, box, valuebox, fielddescr):
- upd = self.metainterp.heapcache.get_field_updater(box, fielddescr)
- if upd.currfieldbox is valuebox:
- return
- self.metainterp.execute_and_record(rop.SETFIELD_GC, fielddescr, box, valuebox)
- upd.setfield(valuebox)
- # The following logic is disabled because buggy. It is supposed
- # to be: not(we're writing null into a freshly allocated object)
- # but the bug is that is_unescaped() can be True even after the
- # field cache is cleared --- see test_ajit:test_unescaped_write_zero
- #
- # if tobox is not None or not self.metainterp.heapcache.is_unescaped(box) or not isinstance(valuebox, Const) or valuebox.nonnull():
- # self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox)
- # self.metainterp.heapcache.setfield(box, valuebox, fielddescr)
- opimpl_setfield_gc_i = _opimpl_setfield_gc_any
- opimpl_setfield_gc_r = _opimpl_setfield_gc_any
- opimpl_setfield_gc_f = _opimpl_setfield_gc_any
- @arguments("box", "box", "box", "descr")
- def _opimpl_setinteriorfield_gc_any(self, array, index, value, descr):
- self.metainterp.execute_setinteriorfield_gc(descr, array, index, value)
- opimpl_setinteriorfield_gc_i = _opimpl_setinteriorfield_gc_any
- opimpl_setinteriorfield_gc_f = _opimpl_setinteriorfield_gc_any
- opimpl_setinteriorfield_gc_r = _opimpl_setinteriorfield_gc_any
- @arguments("box", "descr")
- def opimpl_getfield_raw_i(self, box, fielddescr):
- return self.execute_with_descr(rop.GETFIELD_RAW_I, fielddescr, box)
- @arguments("box", "descr")
- def opimpl_getfield_raw_r(self, box, fielddescr): # for pure only
- return self.execute_with_descr(rop.GETFIELD_RAW_R, fielddescr, box)
- @arguments("box", "descr")
- def opimpl_getfield_raw_f(self, box, fielddescr):
- return self.execute_with_descr(rop.GETFIELD_RAW_F, fielddescr, box)
- @arguments("box", "box", "descr")
- def _opimpl_setfield_raw_any(self, box, valuebox, fielddescr):
- self.execute_with_descr(rop.SETFIELD_RAW, fielddescr, box, valuebox)
- opimpl_setfield_raw_i = _opimpl_setfield_raw_any
- opimpl_setfield_raw_f = _opimpl_setfield_raw_any
- @arguments("box", "box", "box", "descr")
- def _opimpl_raw_store(self, addrbox, offsetbox, valuebox, arraydescr):
- self.metainterp.execute_raw_store(arraydescr,
- addrbox, offsetbox, valuebox)
- opimpl_raw_store_i = _opimpl_raw_store
- opimpl_raw_store_f = _opimpl_raw_store
- @arguments("box", "box", "descr")
- def opimpl_raw_load_i(self, addrbox, offsetbox, arraydescr):
- return self.execute_with_descr(rop.RAW_LOAD_I, arraydescr,
- addrbox, offsetbox)
- @arguments("box", "box", "descr")
- def opimpl_raw_load_f(self, addrbox, offsetbox, arraydescr):
- return self.execute_with_descr(rop.RAW_LOAD_F, arraydescr,
- addrbox, offsetbox)
- def _remove_symbolics(self, c):
- if not we_are_translated():
- from rpython.rtyper.lltypesystem import ll2ctypes
- assert isinstance(c, ConstInt)
- c = ConstInt(ll2ctypes.lltype2ctypes(c.value))
- return c
- @arguments("box", "box", "box", "box", "box")
- def opimpl_gc_load_indexed_i(self, addrbox, indexbox,
- scalebox, baseofsbox, bytesbox):
- return self.execute(rop.GC_LOAD_INDEXED_I, addrbox, indexbox,
- self._remove_symbolics(scalebox),
- self._remove_symbolics(baseofsbox), bytesbox)
- @arguments("box", "box", "box", "box", "box")
- def opimpl_gc_load_indexed_f(self, addrbox, indexbox,
- scalebox, baseofsbox, bytesbox):
- return self.execute(rop.GC_LOAD_INDEXED_F, addrbox, indexbox,
- self._remove_symbolics(scalebox),
- self._remove_symbolics(baseofsbox), bytesbox)
- @arguments("box")
- def opimpl_hint_force_virtualizable(self, box):
- self.metainterp.gen_store_back_in_vable(box)
- @arguments("box", "descr", "descr", "orgpc")
- def opimpl_record_quasiimmut_field(self, box, fielddescr,
- mutatefielddescr, orgpc):
- from rpython.jit.metainterp.quasiimmut import QuasiImmutDescr
- cpu = self.metainterp.cpu
- if self.metainterp.heapcache.is_quasi_immut_known(fielddescr, box):
- return
- descr = QuasiImmutDescr(cpu, box.getref_base(), fielddescr,
- mutatefielddescr)
- self.metainterp.heapcache.quasi_immut_now_known(fielddescr, box)
- self.metainterp.history.record(rop.QUASIIMMUT_FIELD, [box],
- None, descr=descr)
- self.metainterp.generate_guard(rop.GUARD_NOT_INVALIDATED,
- resumepc=orgpc)
- @arguments("box", "descr", "orgpc")
- def opimpl_jit_force_quasi_immutable(self, box, mutatefielddescr, orgpc):
- # During tracing, a 'jit_force_quasi_immutable' usually turns into
- # the operations that check that the content of 'mutate_xxx' is null.
- # If it is actually not null already now, then we abort tracing.
- # The idea is that if we use 'jit_force_quasi_immutable' on a freshly
- # allocated object, then the GETFIELD_GC will know that the answer is
- # null, and the guard will be removed. So the fact that the field is
- # quasi-immutable will have no effect, and instead it will work as a
- # regular, probably virtual, structure.
- if mutatefielddescr.is_pointer_field():
- mutatebox = self.execute_with_descr(rop.GETFIELD_GC_R,
- mutatefielddescr, box)
- elif mutatefielddescr.is_float_field():
- mutatebox = self.execute_with_descr(rop.GETFIELD_GC_R,
- mutatefielddescr, box)
- else:
- mutatebox = self.execute_with_descr(rop.GETFIELD_GC_I,
- mutatefielddescr, box)
- if mutatebox.nonnull():
- from rpython.jit.metainterp.quasiimmut import do_force_quasi_immutable
- do_force_quasi_immutable(self.metainterp.cpu, box.getref_base(),
- mutatefielddescr)
- raise SwitchToBlackhole(Counters.ABORT_FORCE_QUASIIMMUT)
- self.metainterp.generate_guard(rop.GUARD_ISNULL, mutatebox,
- resumepc=orgpc)
- def _nonstandard_virtualizable(self, pc, box, fielddescr):
- # returns True if 'box' is actually not the "standard" virtualizable
- # that is stored in metainterp.virtualizable_boxes[-1]
- if self.metainterp.heapcache.is_nonstandard_virtualizable(box):
- return True
- if box is self.metainterp.forced_virtualizable:
- self.metainterp.forced_virtualizable = None
- if (self.metainterp.jitdriver_sd.virtualizable_info is not None or
- self.metainterp.jitdriver_sd.greenfield_info is not None):
- standard_box = self.metainterp.virtualizable_boxes[-1]
- if standard_box is box:
- return False
- vinfo = self.metainterp.jitdriver_sd.virtualizable_info
- if vinfo is fielddescr.get_vinfo():
- eqbox = self.metainterp.execute_and_record(rop.PTR_EQ, None,
- box, standard_box)
- eqbox = self.implement_guard_value(eqbox, pc)
- isstandard = eqbox.getint()
- if isstandard:
- if box.type == 'r':
- self.metainterp.replace_box(box, standard_box)
- return False
- if not self.metainterp.heapcache.is_unescaped(box):
- self.emit_force_virtualizable(fielddescr, box)
- self.metainterp.heapcache.nonstandard_virtualizables_now_known(box)
- return True
- def emit_force_virtualizable(self, fielddescr, box):
- vinfo = fielddescr.get_vinfo()
- assert vinfo is not None
- token_descr = vinfo.vable_token_descr
- mi = self.metainterp
- tokenbox = mi.execute_and_record(rop.GETFIELD_GC_R, token_descr, box)
- condbox = mi.execute_and_record(rop.PTR_NE, None, tokenbox,
- history.CONST_NULL)
- funcbox = ConstInt(rffi.cast(lltype.Signed, vinfo.clear_vable_ptr))
- calldescr = vinfo.clear_vable_descr
- self.execute_varargs(rop.COND_CALL, [condbox, funcbox, box],
- calldescr, False, False)
- def _get_virtualizable_field_index(self, fielddescr):
- # Get the index of a fielddescr. Must only be called for
- # the "standard" virtualizable.
- vinfo = self.metainterp.jitdriver_sd.virtualizable_info
- return vinfo.static_field_by_descrs[fielddescr]
- @arguments("box", "descr", "orgpc")
- def opimpl_getfield_vable_i(self, box, fielddescr, pc):
- if self._nonstandard_virtualizable(pc, box, fielddescr):
- return self.opimpl_getfield_gc_i(box, fielddescr)
- self.metainterp.check_synchronized_virtualizable()
- index = self._get_virtualizable_field_index(fielddescr)
- return self.metainterp.virtualizable_boxes[index]
- @arguments("box", "descr", "orgpc")
- def opimpl_getfield_vable_r(self, box, fielddescr, pc):
- if self._nonstandard_virtualizable(pc, box, fielddescr):
- return self.opimpl_getfield_gc_r(box, fielddescr)
- self.metainterp.check_synchronized_virtualizable()
- index = self._get_virtualizable_field_index(fielddescr)
- return self.metainterp.virtualizable_boxes[index]
- @arguments("box", "descr", "orgpc")
- def opimpl_getfield_vable_f(self, box, fielddescr, pc):
- if self._nonstandard_virtualizable(pc, box, fielddescr):
- return self.opimpl_getfield_gc_f(box, fielddescr)
- self.metainterp.check_synchronized_virtualizable()
- index = self._get_virtualizable_field_index(fielddescr)
- return self.metainterp.virtualizable_boxes[index]
- @arguments("box", "box", "descr", "orgpc")
- def _opimpl_setfield_vable(self, box, valuebox, fielddescr, pc):
- if self._nonstandard_virtualizable(pc, box, fielddescr):
- return self._opimpl_setfield_gc_any(box, valuebox, fielddescr)
- index = self._get_virtualizable_field_index(fielddescr)
- self.metainterp.virtualizable_boxes[index] = valuebox
- self.metainterp.synchronize_virtualizable()
- # XXX only the index'th field needs to be synchronized, really
- opimpl_setfield_vable_i = _opimpl_setfield_vable
- opimpl_setfield_vable_r = _opimpl_setfield_vable
- opimpl_setfield_vable_f = _opimpl_setfield_vable
- def _get_arrayitem_vable_index(self, pc, arrayfielddescr, indexbox):
- # Get the index of an array item: the index'th of the array
- # described by arrayfielddescr. Must only be called for
- # the "standard" virtualizable.
- indexbox = self.implement_guard_value(indexbox, pc)
- vinfo = self.metainterp.jitdriver_sd.virtualizable_info
- virtualizable_box = self.metainterp.virtualizable_boxes[-1]
- virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box)
- arrayindex = vinfo.array_field_by_descrs[arrayfielddescr]
- index = indexbox.getint()
- # Support for negative index: disabled
- # (see codewriter/jtransform.py, _check_no_vable_array).
- #if index < 0:
- # index += vinfo.get_array_length(virtualizable, arrayindex)
- assert 0 <= index < vinfo.get_array_length(virtualizable, arrayindex)
- return vinfo.get_index_in_array(virtualizable, arrayindex, index)
- @arguments("box", "box", "descr", "descr", "orgpc")
- def _opimpl_getarrayitem_vable(self, box, indexbox, fdescr, adescr, pc):
- if self._nonstandard_virtualizable(pc, box, fdescr):
- arraybox = self.opimpl_getfield_gc_r(box, fdescr)
- if adescr.is_array_of_pointers():
- return self.opimpl_getarrayitem_gc_r(arraybox, indexbox, adescr)
- elif adescr.is_array_of_floats():
- return self.opimpl_getarrayitem_gc_f(arraybox, indexbox, adescr)
- else:
- return self.opimpl_getarrayitem_gc_i(arraybox, indexbox, adescr)
- self.metainterp.check_synchronized_virtualizable()
- index = self._get_arrayitem_vable_index(pc, fdescr, indexbox)
- return self.metainterp.virtualizable_boxes[index]
- opimpl_getarrayitem_vable_i = _opimpl_getarrayitem_vable
- opimpl_getarrayitem_vable_r = _opimpl_getarrayitem_vable
- opimpl_getarrayitem_vable_f = _opimpl_getarrayitem_vable
- @arguments("box", "box", "box", "descr", "descr", "orgpc")
- def _opimpl_setarrayitem_vable(self, box, indexbox, valuebox,
- fdescr, adescr, pc):
- if self._nonstandard_virtualizable(pc, box, fdescr):
- arraybox = self.opimpl_getfield_gc_r(box, fdescr)
- self._opimpl_setarrayitem_gc_any(arraybox, indexbox, valuebox,
- adescr)
- return
- index = self._get_arrayitem_vable_index(pc, fdescr, indexbox)
- self.metainterp.virtualizable_boxes[index] = valuebox
- self.metainterp.synchronize_virtualizable()
- # XXX only the index'th field needs to be synchronized, really
- opimpl_setarrayitem_vable_i = _opimpl_setarrayitem_vable
- opimpl_setarrayitem_vable_r = _opimpl_setarrayitem_vable
- opimpl_setarrayitem_vable_f = _opimpl_setarrayitem_vable
- @arguments("box", "descr", "descr", "orgpc")
- def opimpl_arraylen_vable(self, box, fdescr, adescr, pc):
- if self._nonstandard_virtualizable(pc, box, fdescr):
- arraybox = self.opimpl_getfield_gc_r(box, fdescr)
- return self.opimpl_arraylen_gc(arraybox, adescr)
- vinfo = self.metainterp.jitdriver_sd.virtualizable_info
- virtualizable_box = self.metainterp.virtualizable_boxes[-1]
- virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box)
- arrayindex = vinfo.array_field_by_descrs[fdescr]
- result = vinfo.get_array_length(virtualizable, arrayindex)
- return ConstInt(result)
- @arguments("jitcode", "boxes")
- def _opimpl_inline_call1(self, jitcode, argboxes):
- return self.metainterp.perform_call(jitcode, argboxes)
- @arguments("jitcode", "boxes2")
- def _opimpl_inline_call2(self, jitcode, argboxes):
- return self.metainterp.perform_call(jitcode, argboxes)
- @arguments("jitcode", "boxes3")
- def _opimpl_inline_call3(self, jitcode, argboxes):
- return self.metainterp.perform_call(jitcode, argboxes)
- opimpl_inline_call_r_i = _opimpl_inline_call1
- opimpl_inline_call_r_r = _opimpl_inline_call1
- opimpl_inline_call_r_v = _opimpl_inline_call1
- opimpl_inline_call_ir_i = _opimpl_inline_call2
- opimpl_inline_call_ir_r = _opimpl_inline_call2
- opimpl_inline_call_ir_v = _opimpl_inline_call2
- opimpl_inline_call_irf_i = _opimpl_inline_call3
- opimpl_inline_call_irf_r = _opimpl_inline_call3
- opimpl_inline_call_irf_f = _opimpl_inline_call3
- opimpl_inline_call_irf_v = _opimpl_inline_call3
- @arguments("box", "boxes", "descr", "orgpc")
- def _opimpl_residual_call1(self, funcbox, argboxes, calldescr, pc):
- return self.do_residual_or_indirect_call(funcbox, argboxes, calldescr, pc)
- @arguments("box", "boxes2", "descr", "orgpc")
- def _opimpl_residual_call2(self, funcbox, argboxes, calldescr, pc):
- return self.do_residual_or_indirect_call(funcbox, argboxes, calldescr, pc)
- @arguments("box", "boxes3", "descr", "orgpc")
- def _opimpl_residual_call3(self, funcbox, argboxes, calldescr, pc):
- return self.do_residual_or_indirect_call(funcbox, argboxes, calldescr, pc)
- opimpl_residual_call_r_i = _opimpl_residual_call1
- opimpl_residual_call_r_r = _opimpl_residual_call1
- opimpl_residual_call_r_v = _opimpl_residual_call1
- opimpl_residual_call_ir_i = _opimpl_residual_call2
- opimpl_residual_call_ir_r = _opimpl_residual_call2
- opimpl_residual_call_ir_v = _opimpl_residual_call2
- opimpl_residual_call_irf_i = _opimpl_residual_call3
- opimpl_residual_call_irf_r = _opimpl_residual_call3
- opimpl_residual_call_irf_f = _opimpl_residual_call3
- opimpl_residual_call_irf_v = _opimpl_residual_call3
- @arguments("box", "box", "boxes", "descr", "orgpc")
- def opimpl_conditional_call_i_v(self, condbox, funcbox, argboxes, calldescr,
- …
Large files files are truncated, but you can click here to view the full file