def indirect_residual_call_test(argtypes, restype, expectedkind): # an indirect call that is residual in all cases is very similar to # a residual direct call op = get_direct_call_op(argtypes, restype) op.opname = 'indirect_call' op.args[0] = varoftype(op.args[0].concretetype) op.args.append(Constant(['somegraph1', 'somegraph2'], lltype.Void)) tr = Transformer(FakeCPU(), FakeResidualIndirectCallControl()) tr.graph = 'someinitialgraph' oplist = tr.rewrite_operation(op) op0, op1 = oplist reskind = getkind(restype)[0] assert op0.opname == 'residual_call_%s_%s' % (expectedkind, reskind) assert op0.result == op.result assert op0.args[0] == op.args[0] assert op0.args[1] == 'calldescr' assert len(op0.args) == 2 + len(expectedkind) for sublist, kind1 in zip(op0.args[2:], expectedkind): assert sublist.kind.startswith(kind1) assert list(sublist) == [ v for v in op.args[1:] if getkind(v.concretetype) == sublist.kind ] for v in op.args[1:]: kind = getkind(v.concretetype) assert kind == 'void' or kind[0] in expectedkind assert op1.opname == '-live-' assert op1.args == []
def indirect_residual_call_test(argtypes, restype, expectedkind): # an indirect call that is residual in all cases is very similar to # a residual direct call op = get_direct_call_op(argtypes, restype) op.opname = 'indirect_call' op.args[0] = varoftype(op.args[0].concretetype) op.args.append(Constant(['somegraph1', 'somegraph2'], lltype.Void)) tr = Transformer(FakeCPU(), FakeResidualIndirectCallControl()) tr.graph = 'someinitialgraph' oplist = tr.rewrite_operation(op) op0, op1 = oplist reskind = getkind(restype)[0] assert op0.opname == 'residual_call_%s_%s' % (expectedkind, reskind) assert op0.result == op.result assert op0.args[0] == op.args[0] assert op0.args[1] == 'calldescr' assert len(op0.args) == 2 + len(expectedkind) for sublist, kind1 in zip(op0.args[2:], expectedkind): assert sublist.kind.startswith(kind1) assert list(sublist) == [v for v in op.args[1:] if getkind(v.concretetype)==sublist.kind] for v in op.args[1:]: kind = getkind(v.concretetype) assert kind == 'void' or kind[0] in expectedkind assert op1.opname == '-live-' assert op1.args == []
def calldescrof(self, FUNC, ARGS, RESULT, extrainfo): arg_types = [] for ARG in ARGS: token = history.getkind(ARG) if token != "void": if token == "float" and longlong.is_longlong(ARG): token = "L" arg_types.append(token[0]) token = history.getkind(RESULT) if token == "float" and longlong.is_longlong(RESULT): token = "L" return self.getdescr(0, token[0], extrainfo=extrainfo, arg_types="".join(arg_types))
def make_dependencies(self): dg = DependencyGraph() for block in self.graph.iterblocks(): # Compute die_at = {Variable: index_of_operation_with_last_usage} die_at = dict.fromkeys(block.inputargs, 0) for i, op in enumerate(block.operations): for v in op.args: if isinstance(v, Variable): die_at[v] = i elif isinstance(v, ListOfKind): for v1 in v: if isinstance(v1, Variable): die_at[v1] = i if op.result is not None: die_at[op.result] = i + 1 if isinstance(block.exitswitch, tuple): for x in block.exitswitch: die_at.pop(x, None) else: die_at.pop(block.exitswitch, None) for link in block.exits: for v in link.args: die_at.pop(v, None) die_at = [(value, key) for (key, value) in die_at.items()] die_at.sort() die_at.append((sys.maxint,)) # Done. XXX the code above this line runs 3 times # (for kind in KINDS) to produce the same result... livevars = [v for v in block.inputargs if getkind(v.concretetype) == self.kind] # Add the variables of this block to the dependency graph for i, v in enumerate(livevars): dg.add_node(v) for j in range(i): dg.add_edge(livevars[j], v) livevars = set(livevars) die_index = 0 for i, op in enumerate(block.operations): while die_at[die_index][0] == i: try: livevars.remove(die_at[die_index][1]) except KeyError: pass die_index += 1 if (op.result is not None and getkind(op.result.concretetype) == self.kind): dg.add_node(op.result) for v in livevars: if getkind(v.concretetype) == self.kind: dg.add_edge(v, op.result) livevars.add(op.result) self._depgraph = dg
def calldescrof(self, FUNC, ARGS, RESULT, extrainfo=None): arg_types = [] for ARG in ARGS: token = history.getkind(ARG) if token != 'void': if token == 'float' and longlong.is_longlong(ARG): token = 'L' arg_types.append(token[0]) token = history.getkind(RESULT) if token == 'float' and longlong.is_longlong(RESULT): token = 'L' return self.getdescr(0, token[0], extrainfo=extrainfo, arg_types=''.join(arg_types))
def calldescrof(self, FUNC, ARGS, RESULT, extrainfo): arg_types = [] for ARG in ARGS: token = history.getkind(ARG) if token != 'void': if token == 'float' and longlong.is_longlong(ARG): token = 'L' arg_types.append(token[0]) token = history.getkind(RESULT) if token == 'float' and longlong.is_longlong(RESULT): token = 'L' return self.getdescr(0, token[0], extrainfo=extrainfo, arg_types=''.join(arg_types))
def get_call_descr(gccache, ARGS, RESULT, extrainfo=None): arg_classes = [] for ARG in ARGS: kind = getkind(ARG) if kind == "int": if ARG is lltype.SingleFloat: arg_classes.append("S") else: arg_classes.append("i") elif kind == "ref": arg_classes.append("r") elif kind == "float": if is_longlong(ARG): arg_classes.append("L") else: arg_classes.append("f") else: raise NotImplementedError("ARG = %r" % (ARG,)) arg_classes = "".join(arg_classes) cls = getCallDescrClass(RESULT) key = (cls, arg_classes, extrainfo) cache = gccache._cache_call try: return cache[key] except KeyError: calldescr = cls(arg_classes, extrainfo) calldescr.create_call_stub(gccache.rtyper, RESULT) cache[key] = calldescr return calldescr
def make_args_specification(self, jd): graph, op = jd._jit_merge_point_pos greens_v, reds_v = support.decode_hp_hint_args(op) ALLARGS = [v.concretetype for v in (greens_v + reds_v)] jd._green_args_spec = [v.concretetype for v in greens_v] jd._red_args_types = [history.getkind(v.concretetype) for v in reds_v] jd.num_green_args = len(jd._green_args_spec) jd.num_red_args = len(jd._red_args_types) RESTYPE = graph.getreturnvar().concretetype (jd._JIT_ENTER_FUNCTYPE, jd._PTR_JIT_ENTER_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, lltype.Void) (jd._PORTAL_FUNCTYPE, jd._PTR_PORTAL_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, RESTYPE) # if jd.result_type == 'v': ASMRESTYPE = lltype.Void elif jd.result_type == history.INT: ASMRESTYPE = lltype.Signed elif jd.result_type == history.REF: ASMRESTYPE = llmemory.GCREF elif jd.result_type == history.FLOAT: ASMRESTYPE = lltype.Float else: assert False (_, jd._PTR_ASSEMBLER_HELPER_FUNCTYPE) = self.cpu.ts.get_FuncType( [lltype.Signed, llmemory.GCREF], ASMRESTYPE)
def split_graph_and_record_jitdriver(self, graph, block, pos): op = block.operations[pos] jd = JitDriverStaticData() jd._jit_merge_point_pos = (graph, op) args = op.args[2:] s_binding = self.translator.annotator.binding jd._portal_args_s = [s_binding(v) for v in args] graph = copygraph(graph) graph.startblock.isstartblock = False [jmpp] = find_jit_merge_points([graph]) graph.startblock = support.split_before_jit_merge_point(*jmpp) graph.startblock.isstartblock = True # a crash in the following checkgraph() means that you forgot # to list some variable in greens=[] or reds=[] in JitDriver. checkgraph(graph) for v in graph.getargs(): assert isinstance(v, Variable) assert len(dict.fromkeys(graph.getargs())) == len(graph.getargs()) self.translator.graphs.append(graph) jd.portal_graph = graph # it's a bit unbelievable to have a portal without func assert hasattr(graph, "func") graph.func._dont_inline_ = True graph.func._jit_unroll_safe_ = True jd.jitdriver = block.operations[pos].args[1].value jd.portal_runner_ptr = "<not set so far>" jd.result_type = history.getkind(jd.portal_graph.getreturnvar() .concretetype)[0] self.jitdrivers_sd.append(jd)
def make_args_specification(self, jd): graph = jd._jit_merge_point_in _, _, op = locate_jit_merge_point(graph) greens_v, reds_v = support.decode_hp_hint_args(op) ALLARGS = [v.concretetype for v in (greens_v + reds_v)] jd._green_args_spec = [v.concretetype for v in greens_v] jd.red_args_types = [history.getkind(v.concretetype) for v in reds_v] jd.num_green_args = len(jd._green_args_spec) jd.num_red_args = len(jd.red_args_types) RESTYPE = graph.getreturnvar().concretetype (jd._JIT_ENTER_FUNCTYPE, jd._PTR_JIT_ENTER_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, lltype.Void) (jd._PORTAL_FUNCTYPE, jd._PTR_PORTAL_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, RESTYPE) # if jd.result_type == 'v': ASMRESTYPE = lltype.Void elif jd.result_type == history.INT: ASMRESTYPE = lltype.Signed elif jd.result_type == history.REF: ASMRESTYPE = llmemory.GCREF elif jd.result_type == history.FLOAT: ASMRESTYPE = lltype.Float else: assert False (_, jd._PTR_ASSEMBLER_HELPER_FUNCTYPE) = self.cpu.ts.get_FuncType( [lltype.Signed, llmemory.GCREF], ASMRESTYPE)
def split_graph_and_record_jitdriver(self, graph, block, pos): op = block.operations[pos] jd = JitDriverStaticData() jd._jit_merge_point_in = graph args = op.args[2:] s_binding = self.translator.annotator.binding jd._portal_args_s = [s_binding(v) for v in args] graph = copygraph(graph) [jmpp] = find_jit_merge_points([graph]) graph.startblock = support.split_before_jit_merge_point(*jmpp) # a crash in the following checkgraph() means that you forgot # to list some variable in greens=[] or reds=[] in JitDriver, # or that a jit_merge_point() takes a constant as an argument. checkgraph(graph) for v in graph.getargs(): assert isinstance(v, Variable) assert len(dict.fromkeys(graph.getargs())) == len(graph.getargs()) self.translator.graphs.append(graph) jd.portal_graph = graph # it's a bit unbelievable to have a portal without func assert hasattr(graph, "func") graph.func._dont_inline_ = True graph.func._jit_unroll_safe_ = True jd.jitdriver = block.operations[pos].args[1].value jd.portal_runner_ptr = "<not set so far>" jd.result_type = history.getkind(jd.portal_graph.getreturnvar() .concretetype)[0] self.jitdrivers_sd.append(jd)
def decode_box_of_type(self, TYPE, tagged): kind = getkind(TYPE) if kind == 'int': kind = INT elif kind == 'ref': kind = REF elif kind == 'float': kind = FLOAT else: raise AssertionError(kind) return self.decode_box(tagged, kind)
def get_call_descr(gccache, ARGS, RESULT, extrainfo=None): arg_classes = [] for ARG in ARGS: kind = getkind(ARG) if kind == 'int': if ARG is lltype.SingleFloat: arg_classes.append('S') else: arg_classes.append('i') elif kind == 'ref': arg_classes.append('r') elif kind == 'float': if is_longlong(ARG): arg_classes.append('L') else: arg_classes.append('f') else: raise NotImplementedError('ARG = %r' % (ARG,)) arg_classes = ''.join(arg_classes) cls = getCallDescrClass(RESULT) key = (cls, arg_classes, extrainfo) cache = gccache._cache_call try: return cache[key] except KeyError: calldescr = cls(arg_classes, extrainfo) calldescr.create_call_stub(gccache.rtyper, RESULT) cache[key] = calldescr return calldescr
def serialize_op(self, op): args = self.flatten_list(op.args) if op.result is not None: kind = getkind(op.result.concretetype) if kind != 'void': args.append("->") args.append(self.getcolor(op.result)) self.emitline(op.opname, *args)
def __init__(self, TYPE, fieldname): self.TYPE = TYPE self.fieldname = fieldname _, T = TYPE._lookup_field(fieldname) def getfield(objbox): obj = objbox.getref(TYPE) value = getattr(obj, fieldname) return boxresult(T, value) def setfield(objbox, valuebox): obj = objbox.getref(TYPE) value = unwrap(T, valuebox) setattr(obj, fieldname, value) self.getfield = getfield self.setfield = setfield self._is_pointer_field = (history.getkind(T) == 'ref') self._is_float_field = (history.getkind(T) == 'float')
def arraydescrof(self, A): assert A.OF != lltype.Void size = symbolic.get_size(A) if isinstance(A.OF, lltype.Ptr) or isinstance(A.OF, lltype.Primitive): token = history.getkind(A.OF)[0] elif isinstance(A.OF, lltype.Struct): token = 's' else: token = '?' return self.getdescr(size, token)
def getcolor(self, v): if isinstance(v, Constant): return v kind = getkind(v.concretetype) col = self.regallocs[kind].getcolor(v) # if kind=='void', fix caller try: r = self.registers[kind, col] except KeyError: r = self.registers[kind, col] = Register(kind, col) return r
def residual_call_test(argtypes, restype, expectedkind): op = get_direct_call_op(argtypes, restype) tr = Transformer(FakeCPU(), FakeResidualCallControl()) oplist = tr.rewrite_operation(op) op0, op1 = oplist reskind = getkind(restype)[0] assert op0.opname == "residual_call_%s_%s" % (expectedkind, reskind) assert op0.result == op.result assert op0.args[0] == op.args[0] assert op0.args[1] == "calldescr" assert len(op0.args) == 2 + len(expectedkind) for sublist, kind1 in zip(op0.args[2:], expectedkind): assert sublist.kind.startswith(kind1) assert list(sublist) == [v for v in op.args[1:] if getkind(v.concretetype) == sublist.kind] for v in op.args[1:]: kind = getkind(v.concretetype) assert kind == "void" or kind[0] in expectedkind assert op1.opname == "-live-" assert op1.args == []
def _sort(args_v): from pypy.jit.metainterp.history import getkind lst = [v for v in args_v if v.concretetype is not lltype.Void] _kind2count = {'int': 1, 'ref': 2, 'float': 3} lst2 = sorted(lst, key=lambda v: _kind2count[getkind(v.concretetype)]) # a crash here means that you have to reorder the variable named in # the JitDriver. Indeed, greens and reds must both be sorted: first # all INTs, followed by all REFs, followed by all FLOATs. assert lst == lst2 return lst
def direct_call_test(argtypes, restype, expectedkind): op = get_direct_call_op(argtypes, restype) tr = Transformer(FakeCPU(), FakeRegularCallControl()) tr.graph = "someinitialgraph" oplist = tr.rewrite_operation(op) op0, op1 = oplist reskind = getkind(restype)[0] assert op0.opname == "inline_call_%s_%s" % (expectedkind, reskind) assert op0.result == op.result assert op0.args[0] == "somejitcode" assert len(op0.args) == 1 + len(expectedkind) for sublist, kind1 in zip(op0.args[1:], expectedkind): assert sublist.kind.startswith(kind1) assert list(sublist) == [v for v in op.args[1:] if getkind(v.concretetype) == sublist.kind] for v in op.args[1:]: kind = getkind(v.concretetype) assert kind == "void" or kind[0] in expectedkind assert op1.opname == "-live-" assert op1.args == []
def arraydescrof(self, A): assert A.OF != lltype.Void assert isinstance(A, lltype.GcArray) or A._hints.get('nolength', False) size = symbolic.get_size(A) if isinstance(A.OF, lltype.Ptr) or isinstance(A.OF, lltype.Primitive): token = history.getkind(A.OF)[0] elif isinstance(A.OF, lltype.Struct): token = 's' else: token = '?' return self.getdescr(size, token)
def load_value_of_type(self, TYPE, tagged): from pypy.jit.metainterp.warmstate import specialize_value kind = getkind(TYPE) if kind == 'int': x = self.decode_int(tagged) elif kind == 'ref': x = self.decode_ref(tagged) elif kind == 'float': x = self.decode_float(tagged) else: raise AssertionError(kind) return specialize_value(TYPE, x)
def map_type_to_argclass(ARG, accept_void=False): kind = getkind(ARG) if kind == 'int': if ARG is lltype.SingleFloat: return 'S' else: return 'i' elif kind == 'ref': return 'r' elif kind == 'float': if is_longlong(ARG): return 'L' else: return 'f' elif kind == 'void': if accept_void: return 'v' raise NotImplementedError('ARG = %r' % (ARG, ))
def residual_call_test(argtypes, restype, expectedkind): op = get_direct_call_op(argtypes, restype) tr = Transformer(FakeCPU(), FakeResidualCallControl()) oplist = tr.rewrite_operation(op) op0, op1 = oplist reskind = getkind(restype)[0] assert op0.opname == 'residual_call_%s_%s' % (expectedkind, reskind) assert op0.result == op.result assert op0.args[0] == op.args[0] assert op0.args[1] == 'calldescr' assert len(op0.args) == 2 + len(expectedkind) for sublist, kind1 in zip(op0.args[2:], expectedkind): assert sublist.kind.startswith(kind1) assert list(sublist) == [ v for v in op.args[1:] if getkind(v.concretetype) == sublist.kind ] for v in op.args[1:]: kind = getkind(v.concretetype) assert kind == 'void' or kind[0] in expectedkind assert op1.opname == '-live-' assert op1.args == []
def direct_call_test(argtypes, restype, expectedkind): op = get_direct_call_op(argtypes, restype) tr = Transformer(FakeCPU(), FakeRegularCallControl()) tr.graph = 'someinitialgraph' oplist = tr.rewrite_operation(op) op0, op1 = oplist reskind = getkind(restype)[0] assert op0.opname == 'inline_call_%s_%s' % (expectedkind, reskind) assert op0.result == op.result assert op0.args[0] == 'somejitcode' assert len(op0.args) == 1 + len(expectedkind) for sublist, kind1 in zip(op0.args[1:], expectedkind): assert sublist.kind.startswith(kind1) assert list(sublist) == [ v for v in op.args[1:] if getkind(v.concretetype) == sublist.kind ] for v in op.args[1:]: kind = getkind(v.concretetype) assert kind == 'void' or kind[0] in expectedkind assert op1.opname == '-live-' assert op1.args == []
def __init__(self, TYPE, fieldname): DescrWithKey.__init__(self, (TYPE, fieldname)) from pypy.jit.backend.llgraph.runner import boxresult from pypy.jit.metainterp.warmstate import unwrap _, T = TYPE._lookup_field(fieldname) def getfield(objbox): obj = objbox.getref(TYPE) value = getattr(obj, fieldname) return boxresult(T, value) def setfield(objbox, valuebox): obj = objbox.getref(TYPE) value = unwrap(T, valuebox) setattr(obj, fieldname, value) self.getfield = getfield self.setfield = setfield self.selfclass = ootype.runtimeClass(TYPE) self.fieldname = fieldname self.key = key_manager.getkey((TYPE, fieldname)) self._is_pointer_field = (history.getkind(T) == 'ref') self._is_float_field = (history.getkind(T) == 'float')
def map_type_to_argclass(ARG, accept_void=False): kind = getkind(ARG) if kind == 'int': if ARG is lltype.SingleFloat: return 'S' else: return 'i' elif kind == 'ref': return 'r' elif kind == 'float': if is_longlong(ARG): return 'L' else: return 'f' elif kind == 'void': if accept_void: return 'v' raise NotImplementedError('ARG = %r' % (ARG,))
def __init__(self, TYPE): DescrWithKey.__init__(self, TYPE) from pypy.jit.backend.llgraph.runner import boxresult from pypy.jit.metainterp.warmstate import unwrap ARRAY = ootype.Array(TYPE) def create(): if isinstance(TYPE, ootype.OOType): return boxresult(TYPE, ootype.new(TYPE)) return None def create_array(lengthbox): n = lengthbox.getint() return boxresult(ARRAY, ootype.oonewarray(ARRAY, n)) def getarrayitem(arraybox, ibox): array = arraybox.getref(ARRAY) i = ibox.getint() if TYPE is not ootype.Void: return boxresult(TYPE, array.ll_getitem_fast(i)) def setarrayitem(arraybox, ibox, valuebox): array = arraybox.getref(ARRAY) i = ibox.getint() value = unwrap(TYPE, valuebox) array.ll_setitem_fast(i, value) def getarraylength(arraybox): array = arraybox.getref(ARRAY) return boxresult(ootype.Signed, array.ll_length()) def instanceof(box): if isinstance(TYPE, ootype.Instance): obj = box.getref(ootype.ROOT) return BoxInt(ootype.instanceof(obj, TYPE)) return None self.create = create self.create_array = create_array self.getarrayitem = getarrayitem self.setarrayitem = setarrayitem self.getarraylength = getarraylength self.instanceof = instanceof self.ooclass = get_class_for_type(TYPE) self.typename = TYPE._short_name() self._is_array_of_pointers = (history.getkind(TYPE) == 'ref') self._is_array_of_floats = (history.getkind(TYPE) == 'float')
def indirect_regular_call_test(argtypes, restype, expectedkind): # a regular indirect call is preceded by a guard_value on the # function address, so that pyjitpl can know which jitcode to follow from pypy.jit.codewriter.flatten import IndirectCallTargets op = get_direct_call_op(argtypes, restype) op.opname = 'indirect_call' op.args[0] = varoftype(op.args[0].concretetype) op.args.append(Constant(['somegraph1', 'somegraph2'], lltype.Void)) tr = Transformer(FakeCPU(), FakeRegularIndirectCallControl()) tr.graph = 'someinitialgraph' oplist = tr.rewrite_operation(op) op0gv, op1gv, op0, op1 = oplist assert op0gv.opname == '-live-' assert op0gv.args == [] assert op1gv.opname == 'int_guard_value' assert op1gv.args == [op.args[0]] assert op1gv.result is None # reskind = getkind(restype)[0] assert op0.opname == 'residual_call_%s_%s' % (expectedkind, reskind) assert op0.result == op.result assert op0.args[0] == op.args[0] assert op0.args[1] == 'calldescr' assert isinstance(op0.args[2], IndirectCallTargets) assert op0.args[2].lst == ['somejitcode1', 'somejitcode2'] assert len(op0.args) == 3 + len(expectedkind) for sublist, kind1 in zip(op0.args[3:], expectedkind): assert sublist.kind.startswith(kind1) assert list(sublist) == [ v for v in op.args[1:] if getkind(v.concretetype) == sublist.kind ] for v in op.args[1:]: kind = getkind(v.concretetype) assert kind == 'void' or kind[0] in expectedkind # Note: we still expect a -live- here, even though canraise() returns # False, because this 'residual_call' will likely call further jitcodes # which can do e.g. guard_class or other stuff requiring anyway a -live-. assert op1.opname == '-live-' assert op1.args == []
def enforce_input_args(self): inputargs = self.graph.startblock.inputargs numkinds = {} for v in inputargs: kind = getkind(v.concretetype) if kind == 'void': continue curcol = self.regallocs[kind].getcolor(v) realcol = numkinds.get(kind, 0) numkinds[kind] = realcol + 1 if curcol != realcol: assert curcol > realcol self.regallocs[kind].swapcolors(realcol, curcol)
def _sort(args_v, is_green): from pypy.jit.metainterp.history import getkind lst = [v for v in args_v if v.concretetype is not lltype.Void] if is_green: assert len(lst) == len(args_v), ( "not supported so far: 'greens' variables contain Void") _kind2count = {'int': 1, 'ref': 2, 'float': 3} lst2 = sorted(lst, key=lambda v: _kind2count[getkind(v.concretetype)]) # a crash here means that you have to reorder the variable named in # the JitDriver. Indeed, greens and reds must both be sorted: first # all INTs, followed by all REFs, followed by all FLOATs. assert lst == lst2 return lst
def __init__(self, TYPE): self.TYPE = TYPE self.ARRAY = ARRAY = ootype.Array(TYPE) def create(): return boxresult(TYPE, ootype.new(TYPE)) def create_array(lengthbox): n = lengthbox.getint() return boxresult(ARRAY, ootype.oonewarray(ARRAY, n)) def getarrayitem(arraybox, ibox): array = arraybox.getref(ARRAY) i = ibox.getint() return boxresult(TYPE, array.ll_getitem_fast(i)) def setarrayitem(arraybox, ibox, valuebox): array = arraybox.getref(ARRAY) i = ibox.getint() value = unwrap(TYPE, valuebox) array.ll_setitem_fast(i, value) def getarraylength(arraybox): array = arraybox.getref(ARRAY) return boxresult(ootype.Signed, array.ll_length()) def instanceof(box): obj = box.getref(ootype.ROOT) return history.BoxInt(ootype.instanceof(obj, TYPE)) self.create = create self.create_array = create_array self.getarrayitem = getarrayitem self.setarrayitem = setarrayitem self.getarraylength = getarraylength self.instanceof = instanceof self._is_array_of_pointers = history.getkind(TYPE) == "ref" self._is_array_of_floats = history.getkind(TYPE) == "float"
def __init__(self, TYPE): self.TYPE = TYPE self.ARRAY = ARRAY = ootype.Array(TYPE) def create(): return boxresult(TYPE, ootype.new(TYPE)) def create_array(lengthbox): n = lengthbox.getint() return boxresult(ARRAY, ootype.oonewarray(ARRAY, n)) def getarrayitem(arraybox, ibox): array = arraybox.getref(ARRAY) i = ibox.getint() return boxresult(TYPE, array.ll_getitem_fast(i)) def setarrayitem(arraybox, ibox, valuebox): array = arraybox.getref(ARRAY) i = ibox.getint() value = unwrap(TYPE, valuebox) array.ll_setitem_fast(i, value) def getarraylength(arraybox): array = arraybox.getref(ARRAY) return boxresult(ootype.Signed, array.ll_length()) def instanceof(box): obj = box.getref(ootype.ROOT) return history.BoxInt(ootype.instanceof(obj, TYPE)) self.create = create self.create_array = create_array self.getarrayitem = getarrayitem self.setarrayitem = setarrayitem self.getarraylength = getarraylength self.instanceof = instanceof self._is_array_of_pointers = (history.getkind(TYPE) == 'ref') self._is_array_of_floats = (history.getkind(TYPE) == 'float')
def indirect_regular_call_test(argtypes, restype, expectedkind): # a regular indirect call is preceded by a guard_value on the # function address, so that pyjitpl can know which jitcode to follow from pypy.jit.codewriter.flatten import IndirectCallTargets op = get_direct_call_op(argtypes, restype) op.opname = 'indirect_call' op.args[0] = varoftype(op.args[0].concretetype) op.args.append(Constant(['somegraph1', 'somegraph2'], lltype.Void)) tr = Transformer(FakeCPU(), FakeRegularIndirectCallControl()) tr.graph = 'someinitialgraph' oplist = tr.rewrite_operation(op) op0gv, op1gv, op0, op1 = oplist assert op0gv.opname == '-live-' assert op0gv.args == [] assert op1gv.opname == 'int_guard_value' assert op1gv.args == [op.args[0]] assert op1gv.result is None # reskind = getkind(restype)[0] assert op0.opname == 'residual_call_%s_%s' % (expectedkind, reskind) assert op0.result == op.result assert op0.args[0] == op.args[0] assert op0.args[1] == 'calldescr' assert isinstance(op0.args[2], IndirectCallTargets) assert op0.args[2].lst == ['somejitcode1', 'somejitcode2'] assert len(op0.args) == 3 + len(expectedkind) for sublist, kind1 in zip(op0.args[3:], expectedkind): assert sublist.kind.startswith(kind1) assert list(sublist) == [v for v in op.args[1:] if getkind(v.concretetype)==sublist.kind] for v in op.args[1:]: kind = getkind(v.concretetype) assert kind == 'void' or kind[0] in expectedkind # Note: we still expect a -live- here, even though canraise() returns # False, because this 'residual_call' will likely call further jitcodes # which can do e.g. guard_class or other stuff requiring anyway a -live-. assert op1.opname == '-live-' assert op1.args == []
def _try_coalesce(self, v, w): if isinstance(v, Variable) and getkind(v.concretetype) == self.kind: dg = self._depgraph uf = self._unionfind v0 = uf.find_rep(v) w0 = uf.find_rep(w) if v0 is not w0 and v0 not in dg.neighbours[w0]: _, rep, _ = uf.union(v0, w0) assert uf.find_rep(v0) is uf.find_rep(w0) is rep if rep is v0: dg.coalesce(w0, v0) else: assert rep is w0 dg.coalesce(v0, w0)
def make_return(self, args): if len(args) == 1: # return from function [v] = args kind = getkind(v.concretetype) if kind == 'void': self.emitline("void_return") else: self.emitline("%s_return" % kind, self.getcolor(args[0])) elif len(args) == 2: # exception block, raising an exception from a function if isinstance(args[1], Variable): self.emitline("-live-") # xxx hack self.emitline("raise", self.getcolor(args[1])) else: raise Exception("?") self.emitline("---")
def map_type_to_argclass(ARG, accept_void=False): kind = getkind(ARG) if kind == "int": if ARG is lltype.SingleFloat: return "S" else: return "i" elif kind == "ref": return "r" elif kind == "float": if is_longlong(ARG): return "L" else: return "f" elif kind == "void": if accept_void: return "v" raise NotImplementedError("ARG = %r" % (ARG,))
def get_call_descr(gccache, ARGS, RESULT, extrainfo=None): arg_classes = [] for ARG in ARGS: kind = getkind(ARG) if kind == 'int': arg_classes.append('i') elif kind == 'ref': arg_classes.append('r') elif kind == 'float': arg_classes.append('f') else: raise NotImplementedError('ARG = %r' % (ARG, )) arg_classes = ''.join(arg_classes) cls = getCallDescrClass(RESULT) key = (cls, arg_classes, extrainfo) cache = gccache._cache_call try: return cache[key] except KeyError: calldescr = cls(arg_classes, extrainfo) cache[key] = calldescr return calldescr
def make_args_specification(self): graph, block, index = self.jit_merge_point_pos op = block.operations[index] args = op.args[2:] ALLARGS = [] self.green_args_spec = [] self.red_args_types = [] for i, v in enumerate(args): TYPE = v.concretetype ALLARGS.append(TYPE) if i < len(self.jitdriver.greens): self.green_args_spec.append(TYPE) else: self.red_args_types.append(history.getkind(TYPE)) self.num_green_args = len(self.green_args_spec) RESTYPE = graph.getreturnvar().concretetype (self.JIT_ENTER_FUNCTYPE, self.PTR_JIT_ENTER_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, lltype.Void) (self.PORTAL_FUNCTYPE, self.PTR_PORTAL_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, RESTYPE)
def get_call_descr(gccache, ARGS, RESULT): arg_classes = [] for ARG in ARGS: kind = getkind(ARG) if kind == "int": arg_classes.append("i") elif kind == "ref": arg_classes.append("r") elif kind == "float": arg_classes.append("f") else: raise NotImplementedError("ARG = %r" % (ARG,)) arg_classes = "".join(arg_classes) cls = getCallDescrClass(RESULT) key = (cls, arg_classes) cache = gccache._cache_call try: return cache[key] except KeyError: calldescr = cls(arg_classes) cache[key] = calldescr return calldescr
def make_args_specification(self): graph, block, index = self.jit_merge_point_pos op = block.operations[index] args = op.args[2:] ALLARGS = [] self.green_args_spec = [] self.red_args_types = [] for i, v in enumerate(args): TYPE = v.concretetype ALLARGS.append(TYPE) if i < len(self.jitdriver.greens): self.green_args_spec.append(TYPE) else: self.red_args_types.append(history.getkind(TYPE)) self.num_green_args = len(self.green_args_spec) RESTYPE = graph.getreturnvar().concretetype (self.JIT_ENTER_FUNCTYPE, self.PTR_JIT_ENTER_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, lltype.Void) (self.PORTAL_FUNCTYPE, self.PTR_PORTAL_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, RESTYPE) (_, self.PTR_ASSEMBLER_HELPER_FUNCTYPE) = self.cpu.ts.get_FuncType( [lltype.Signed, llmemory.GCREF], RESTYPE)
def _run_with_machine_code(testself, args): metainterp = testself.metainterp num_green_args = metainterp.jitdriver_sd.num_green_args loop_tokens = metainterp.get_compiled_merge_points(args[:num_green_args]) if len(loop_tokens) != 1: return NotImplemented # a loop was successfully created by _run_with_pyjitpl(); call it cpu = metainterp.cpu for i in range(len(args) - num_green_args): x = args[num_green_args + i] typecode = history.getkind(lltype.typeOf(x)) set_future_value(cpu, i, x, typecode) faildescr = cpu.execute_token(loop_tokens[0]) assert faildescr.__class__.__name__.startswith('DoneWithThisFrameDescr') if metainterp.jitdriver_sd.result_type == history.INT: return cpu.get_latest_value_int(0) elif metainterp.jitdriver_sd.result_type == history.REF: return cpu.get_latest_value_ref(0) elif metainterp.jitdriver_sd.result_type == history.FLOAT: return cpu.get_latest_value_float(0) else: return None
def arraydescrof(A): assert isinstance(A, lltype.GcArray) assert A.OF != lltype.Void size = symbolic.get_size(A) token = history.getkind(A.OF) return Descr(size, token[0])
def rewrite_jit_merge_point(self, policy): # # Mutate the original portal graph from this: # # def original_portal(..): # stuff # while 1: # jit_merge_point(*args) # more stuff # # to that: # # def original_portal(..): # stuff # return portal_runner(*args) # # def portal_runner(*args): # while 1: # try: # return portal(*args) # except ContinueRunningNormally, e: # *args = *e.new_args # except DoneWithThisFrame, e: # return e.return # except ExitFrameWithException, e: # raise Exception, e.value # # def portal(*args): # while 1: # more stuff # origportalgraph = self.jit_merge_point_pos[0] portalgraph = self.portal_graph PORTALFUNC = self.PORTAL_FUNCTYPE # ____________________________________________________________ # Prepare the portal_runner() helper # portal_ptr = self.cpu.ts.functionptr(PORTALFUNC, 'portal', graph=portalgraph) self.portal_ptr = portal_ptr portalfunc_ARGS = unrolling_iterable([ (i, 'arg%d' % i, ARG) for i, ARG in enumerate(PORTALFUNC.ARGS) ]) class DoneWithThisFrameVoid(JitException): def __str__(self): return 'DoneWithThisFrameVoid()' class DoneWithThisFrameInt(JitException): def __init__(self, result): assert lltype.typeOf(result) is lltype.Signed self.result = result def __str__(self): return 'DoneWithThisFrameInt(%s)' % (self.result, ) class DoneWithThisFrameRef(JitException): def __init__(self, cpu, result): assert lltype.typeOf(result) == cpu.ts.BASETYPE self.result = result def __str__(self): return 'DoneWithThisFrameRef(%s)' % (self.result, ) class DoneWithThisFrameFloat(JitException): def __init__(self, result): assert lltype.typeOf(result) is lltype.Float self.result = result def __str__(self): return 'DoneWithThisFrameFloat(%s)' % (self.result, ) class ExitFrameWithExceptionRef(JitException): def __init__(self, cpu, value): assert lltype.typeOf(value) == cpu.ts.BASETYPE self.value = value def __str__(self): return 'ExitFrameWithExceptionRef(%s)' % (self.value, ) class ContinueRunningNormally(ContinueRunningNormallyBase): def __init__(self, argboxes): # accepts boxes as argument, but unpacks them immediately # before we raise the exception -- the boxes' values will # be modified in a 'finally' by restore_patched_boxes(). from pypy.jit.metainterp.warmstate import unwrap for i, name, ARG in portalfunc_ARGS: v = unwrap(ARG, argboxes[i]) setattr(self, name, v) def __str__(self): return 'ContinueRunningNormally(%s)' % (', '.join( map(str, self.args)), ) self.DoneWithThisFrameVoid = DoneWithThisFrameVoid self.DoneWithThisFrameInt = DoneWithThisFrameInt self.DoneWithThisFrameRef = DoneWithThisFrameRef self.DoneWithThisFrameFloat = DoneWithThisFrameFloat self.ExitFrameWithExceptionRef = ExitFrameWithExceptionRef self.ContinueRunningNormally = ContinueRunningNormally self.metainterp_sd.DoneWithThisFrameVoid = DoneWithThisFrameVoid self.metainterp_sd.DoneWithThisFrameInt = DoneWithThisFrameInt self.metainterp_sd.DoneWithThisFrameRef = DoneWithThisFrameRef self.metainterp_sd.DoneWithThisFrameFloat = DoneWithThisFrameFloat self.metainterp_sd.ExitFrameWithExceptionRef = ExitFrameWithExceptionRef self.metainterp_sd.ContinueRunningNormally = ContinueRunningNormally rtyper = self.translator.rtyper RESULT = PORTALFUNC.RESULT result_kind = history.getkind(RESULT) ts = self.cpu.ts def ll_portal_runner(*args): while 1: try: return support.maybe_on_top_of_llinterp( rtyper, portal_ptr)(*args) except ContinueRunningNormally, e: args = () for _, name, _ in portalfunc_ARGS: v = getattr(e, name) args = args + (v, ) except DoneWithThisFrameVoid: assert result_kind == 'void' return except DoneWithThisFrameInt, e: assert result_kind == 'int' return lltype.cast_primitive(RESULT, e.result)
def fielddescrof(self, S, fieldname): ofs, size = symbolic.get_field_token(S, fieldname) token = history.getkind(getattr(S, fieldname)) return self.getdescr(ofs, token[0], name=fieldname)
def interiorfielddescrof(self, A, fieldname): S = A.OF width = symbolic.get_size(A) ofs, size = symbolic.get_field_token(S, fieldname) token = history.getkind(getattr(S, fieldname)) return self.getdescr(ofs, token[0], name=fieldname, width=width)
def _get_jitcodes(testself, CPUClass, func, values, type_system, supports_longlong=False, translationoptions={}, **kwds): from pypy.jit.codewriter import support class FakeJitCell(object): __product_token = None def get_procedure_token(self): return self.__product_token def set_procedure_token(self, token): self.__product_token = token class FakeWarmRunnerState(object): def attach_procedure_to_interp(self, greenkey, procedure_token): cell = self.jit_cell_at_key(greenkey) cell.set_procedure_token(procedure_token) def helper_func(self, FUNCPTR, func): from pypy.rpython.annlowlevel import llhelper return llhelper(FUNCPTR, func) def get_location_str(self, args): return 'location' def jit_cell_at_key(self, greenkey): assert greenkey == [] return self._cell _cell = FakeJitCell() trace_limit = sys.maxint enable_opts = ALL_OPTS_DICT func._jit_unroll_safe_ = True rtyper = support.annotate(func, values, type_system=type_system, translationoptions=translationoptions) graphs = rtyper.annotator.translator.graphs testself.all_graphs = graphs result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0] class FakeJitDriverSD: num_green_args = 0 portal_graph = graphs[0] virtualizable_info = None greenfield_info = None result_type = result_kind portal_runner_ptr = "???" stats = history.Stats() cpu = CPUClass(rtyper, stats, None, False) cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()]) cw.debug = True testself.cw = cw policy = JitPolicy() policy.set_supports_floats(True) policy.set_supports_longlong(supports_longlong) cw.find_all_graphs(policy) # testself.warmrunnerstate = FakeWarmRunnerState() testself.warmrunnerstate.cpu = cpu FakeJitDriverSD.warmstate = testself.warmrunnerstate if hasattr(testself, 'finish_setup_for_interp_operations'): testself.finish_setup_for_interp_operations() # cw.make_jitcodes(verbose=True)
def insert_exits(self, block): if len(block.exits) == 1: # A single link, fall-through link = block.exits[0] assert link.exitcase in (None, False, True) # the cases False or True should not really occur, but can show # up in the manually hacked graphs for generators... self.make_link(link) # elif block.exitswitch is c_last_exception: # An exception block. See test_exc_exitswitch in test_flatten.py # for an example of what kind of code this makes. index = -1 while True: lastopname = block.operations[index].opname if lastopname != '-live-': break index -= 1 assert block.exits[0].exitcase is None # is this always True? # if not self._include_all_exc_links: if index == -1: # cannot raise: the last instruction is not # actually a '-live-' self.make_link(block.exits[0]) return # self.emitline('catch_exception', TLabel(block.exits[0])) self.make_link(block.exits[0]) self.emitline(Label(block.exits[0])) for link in block.exits[1:]: if (link.exitcase is Exception or (link.exitcase is OverflowError and lastopname.startswith('int_') and lastopname.endswith('_ovf'))): # this link captures all exceptions self.make_exception_link(link) break self.emitline( 'goto_if_exception_mismatch', Constant(link.llexitcase, lltype.typeOf(link.llexitcase)), TLabel(link)) self.make_exception_link(link) self.emitline(Label(link)) else: # no link captures all exceptions, so we have to put a reraise # for the other exceptions self.emitline("reraise") self.emitline("---") # elif len(block.exits) == 2 and (isinstance(block.exitswitch, tuple) or block.exitswitch.concretetype == lltype.Bool): # Two exit links with a boolean condition linkfalse, linktrue = block.exits if linkfalse.llexitcase == True: linkfalse, linktrue = linktrue, linkfalse opname = 'goto_if_not' livebefore = False if isinstance(block.exitswitch, tuple): # special case produced by jtransform.optimize_goto_if_not() opname = 'goto_if_not_' + block.exitswitch[0] opargs = block.exitswitch[1:] if opargs[-1] == '-live-before': livebefore = True opargs = opargs[:-1] else: assert block.exitswitch.concretetype == lltype.Bool opargs = [block.exitswitch] # lst = self.flatten_list(opargs) + [TLabel(linkfalse)] if livebefore: self.emitline('-live-') self.emitline(opname, *lst) if not livebefore: self.emitline('-live-', TLabel(linkfalse)) # true path: self.make_link(linktrue) # false path: self.emitline(Label(linkfalse)) self.make_link(linkfalse) # else: # A switch. # def emitdefaultpath(): if block.exits[-1].exitcase == 'default': self.make_link(block.exits[-1]) else: self.emitline("unreachable") self.emitline("---") # self.emitline('-live-') switches = [ link for link in block.exits if link.exitcase != 'default' ] switches.sort(key=lambda link: link.llexitcase) kind = getkind(block.exitswitch.concretetype) if len(switches) >= 5 and kind == 'int': # A large switch on an integer, implementable efficiently # with the help of a SwitchDictDescr from pypy.jit.codewriter.jitcode import SwitchDictDescr switchdict = SwitchDictDescr() switchdict._labels = [] self.emitline('switch', self.getcolor(block.exitswitch), switchdict) emitdefaultpath() # for switch in switches: key = lltype.cast_primitive(lltype.Signed, switch.llexitcase) switchdict._labels.append((key, TLabel(switch))) # emit code for that path self.emitline(Label(switch)) self.make_link(switch) # else: # A switch with several possible answers, though not too # many of them -- a chain of int_eq comparisons is fine assert kind == 'int' # XXX color = self.getcolor(block.exitswitch) self.emitline('int_guard_value', color) for switch in switches: # make the case described by 'switch' self.emitline( 'goto_if_not_int_eq', color, Constant(switch.llexitcase, block.exitswitch.concretetype), TLabel(switch)) # emit code for the "taken" path self.make_link(switch) # finally, emit the label for the "non-taken" path self.emitline(Label(switch)) # emitdefaultpath()
def write_insn(self, insn): if insn[0] == '---': return if isinstance(insn[0], Label): self.label_positions[insn[0].name] = len(self.code) return if insn[0] == '-live-': key = len(self.code) live_i, live_r, live_f = self.liveness.get(key, ("", "", "")) live_i = self.get_liveness_info(live_i, insn[1:], 'int') live_r = self.get_liveness_info(live_r, insn[1:], 'ref') live_f = self.get_liveness_info(live_f, insn[1:], 'float') self.liveness[key] = live_i, live_r, live_f return startposition = len(self.code) self.code.append("temporary placeholder") # argcodes = [] allow_short = (insn[0] in USE_C_FORM) for x in insn[1:]: if isinstance(x, Register): self.emit_reg(x) argcodes.append(x.kind[0]) elif isinstance(x, Constant): kind = getkind(x.concretetype) is_short = self.emit_const(x, kind, allow_short=allow_short) if is_short: argcodes.append('c') else: argcodes.append(kind[0]) elif isinstance(x, TLabel): self.alllabels.add(len(self.code)) self.tlabel_positions.append((x.name, len(self.code))) self.code.append("temp 1") self.code.append("temp 2") argcodes.append('L') elif isinstance(x, ListOfKind): itemkind = x.kind lst = list(x) assert len(lst) <= 255, "list too long!" self.code.append(chr(len(lst))) for item in lst: if isinstance(item, Register): assert itemkind == item.kind self.emit_reg(item) elif isinstance(item, Constant): assert itemkind == getkind(item.concretetype) self.emit_const(item, itemkind) else: raise NotImplementedError("found in ListOfKind(): %r" % (item, )) argcodes.append(itemkind[0].upper()) elif isinstance(x, AbstractDescr): if x not in self._descr_dict: self._descr_dict[x] = len(self.descrs) self.descrs.append(x) if isinstance(x, SwitchDictDescr): self.switchdictdescrs.append(x) num = self._descr_dict[x] assert 0 <= num <= 0xFFFF, "too many AbstractDescrs!" self.code.append(chr(num & 0xFF)) self.code.append(chr(num >> 8)) argcodes.append('d') elif isinstance(x, IndirectCallTargets): self.indirectcalltargets.update(x.lst) elif x == '->': assert '>' not in argcodes argcodes.append('>') else: raise NotImplementedError(x) # opname = insn[0] if '>' in argcodes: assert argcodes.index('>') == len(argcodes) - 2 self.resulttypes[len(self.code)] = argcodes[-1] key = opname + '/' + ''.join(argcodes) num = self.insns.setdefault(key, len(self.insns)) self.code[startposition] = chr(num) self.startpoints.add(startposition)
def rewrite_jit_merge_point(self, policy): # # Mutate the original portal graph from this: # # def original_portal(..): # stuff # while 1: # jit_merge_point(*args) # more stuff # # to that: # # def original_portal(..): # stuff # return portal_runner(*args) # # def portal_runner(*args): # while 1: # try: # return portal(*args) # except ContinueRunningNormally, e: # *args = *e.new_args # except DoneWithThisFrame, e: # return e.return # except ExitFrameWithException, e: # raise Exception, e.value # # def portal(*args): # while 1: # more stuff # origportalgraph = self.jit_merge_point_pos[0] portalgraph = self.portal_graph PORTALFUNC = self.PORTAL_FUNCTYPE # ____________________________________________________________ # Prepare the portal_runner() helper # portal_ptr = self.cpu.ts.functionptr(PORTALFUNC, 'portal', graph = portalgraph) self.portal_ptr = portal_ptr portalfunc_ARGS = unrolling_iterable( [(i, 'arg%d' % i, ARG) for i, ARG in enumerate(PORTALFUNC.ARGS)]) rtyper = self.translator.rtyper RESULT = PORTALFUNC.RESULT result_kind = history.getkind(RESULT) ts = self.cpu.ts def ll_portal_runner(*args): while 1: try: self.maybe_enter_from_start_fn(*args) return support.maybe_on_top_of_llinterp(rtyper, portal_ptr)(*args) except self.ContinueRunningNormally, e: args = () for _, name, _ in portalfunc_ARGS: v = getattr(e, name) args = args + (v,) except self.DoneWithThisFrameVoid: assert result_kind == 'void' return except self.DoneWithThisFrameInt, e: assert result_kind == 'int' return lltype.cast_primitive(RESULT, e.result)
def perform_register_allocation(graph, kind): checkkind = lambda v: getkind(v.concretetype) == kind return regalloc.perform_register_allocation(graph, checkkind, ListOfKind)
def __init__(self, warmrunnerdesc): self.warmrunnerdesc = warmrunnerdesc jitdriver = warmrunnerdesc.jitdriver cpu = warmrunnerdesc.cpu self.cpu = cpu self.VABLERTI = cpu.ts.get_VABLERTI() self.null_vable_rti = cpu.ts.nullptr(deref(self.VABLERTI)) self.BoxArray = cpu.ts.BoxRef # assert len(jitdriver.virtualizables) == 1 # for now [vname] = jitdriver.virtualizables index = len(jitdriver.greens) + jitdriver.reds.index(vname) self.index_of_virtualizable = index VTYPEPTR = warmrunnerdesc.JIT_ENTER_FUNCTYPE.ARGS[index] while 'virtualizable2_accessor' not in deref(VTYPEPTR)._hints: VTYPEPTR = cpu.ts.get_superclass(VTYPEPTR) self.VTYPEPTR = VTYPEPTR self.VTYPE = VTYPE = deref(VTYPEPTR) self.null_vable = cpu.ts.nullptr(VTYPE) # accessor = VTYPE._hints['virtualizable2_accessor'] all_fields = accessor.fields static_fields = [] array_fields = [] for name, suffix in all_fields.iteritems(): if suffix == '[*]': array_fields.append(name) else: static_fields.append(name) self.static_fields = static_fields self.array_fields = array_fields # FIELDTYPES = [fieldType(VTYPE, name) for name in static_fields] ARRAYITEMTYPES = [] for name in array_fields: ARRAYPTR = fieldType(VTYPE, name) ARRAY = deref(ARRAYPTR) assert isinstance(ARRAYPTR, (lltype.Ptr, ootype.Array)) assert isinstance(ARRAY, (lltype.GcArray, ootype.Array)) ARRAYITEMTYPES.append(arrayItem(ARRAY)) self.array_descrs = [ cpu.arraydescrof(deref(fieldType(VTYPE, name))) for name in array_fields ] # self.num_static_extra_boxes = len(static_fields) self.num_arrays = len(array_fields) self.static_field_to_extra_box = dict([ (name, i) for (i, name) in enumerate(static_fields) ]) self.array_field_counter = dict([ (name, i) for (i, name) in enumerate(array_fields) ]) self.static_extra_types = [ history.getkind(TYPE) for TYPE in FIELDTYPES ] self.arrayitem_extra_types = [ history.getkind(ITEM) for ITEM in ARRAYITEMTYPES ] self.static_field_descrs = [ cpu.fielddescrof(VTYPE, name) for name in static_fields ] self.array_field_descrs = [ cpu.fielddescrof(VTYPE, name) for name in array_fields ] # getlength = cpu.ts.getlength getarrayitem = cpu.ts.getarrayitem setarrayitem = cpu.ts.setarrayitem # def read_boxes(cpu, virtualizable): boxes = [] for _, fieldname in unroll_static_fields: x = getattr(virtualizable, fieldname) boxes.append(wrap(cpu, x)) for _, fieldname in unroll_array_fields: lst = getattr(virtualizable, fieldname) for i in range(getlength(lst)): boxes.append(wrap(cpu, getarrayitem(lst, i))) return boxes # def write_boxes(virtualizable, boxes): i = 0 for FIELDTYPE, fieldname in unroll_static_fields: x = unwrap(FIELDTYPE, boxes[i]) setattr(virtualizable, fieldname, x) i = i + 1 for ARRAYITEMTYPE, fieldname in unroll_array_fields: lst = getattr(virtualizable, fieldname) for j in range(getlength(lst)): x = unwrap(ARRAYITEMTYPE, boxes[i]) setarrayitem(lst, j, x) i = i + 1 assert len(boxes) == i + 1 # def check_boxes(virtualizable, boxes): # for debugging i = 0 for FIELDTYPE, fieldname in unroll_static_fields: x = unwrap(FIELDTYPE, boxes[i]) assert getattr(virtualizable, fieldname) == x i = i + 1 for ARRAYITEMTYPE, fieldname in unroll_array_fields: lst = getattr(virtualizable, fieldname) for j in range(getlength(lst)): x = unwrap(ARRAYITEMTYPE, boxes[i]) assert getarrayitem(lst, j) == x i = i + 1 assert len(boxes) == i + 1 # def get_index_in_array(virtualizable, arrayindex, index): index += self.num_static_extra_boxes j = 0 for _, fieldname in unroll_array_fields: if arrayindex == j: return index lst = getattr(virtualizable, fieldname) index += getlength(lst) j = j + 1 assert False, "invalid arrayindex" # def get_array_length(virtualizable, arrayindex): j = 0 for _, fieldname in unroll_array_fields: if arrayindex == j: lst = getattr(virtualizable, fieldname) return getlength(lst) j = j + 1 assert False, "invalid arrayindex" # unroll_static_fields = unrolling_iterable( zip(FIELDTYPES, static_fields)) unroll_array_fields = unrolling_iterable( zip(ARRAYITEMTYPES, array_fields)) self.read_boxes = read_boxes self.write_boxes = write_boxes self.check_boxes = check_boxes self.get_index_in_array = get_index_in_array self.get_array_length = get_array_length