def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, can_invalidate=False, call_release_gil_target= EffectInfo._NO_CALL_RELEASE_GIL_TARGET, extradescr=None): from rpython.translator.backendopt.writeanalyze import top_set if effects is top_set or extraeffect == EffectInfo.EF_RANDOM_EFFECTS: readonly_descrs_fields = None readonly_descrs_arrays = None readonly_descrs_interiorfields = None write_descrs_fields = None write_descrs_arrays = None write_descrs_interiorfields = None extraeffect = EffectInfo.EF_RANDOM_EFFECTS else: readonly_descrs_fields = [] readonly_descrs_arrays = [] readonly_descrs_interiorfields = [] write_descrs_fields = [] write_descrs_arrays = [] write_descrs_interiorfields = [] def add_struct(descrs_fields, (_, T, fieldname)): T = deref(T) if consider_struct(T, fieldname): descr = cpu.fielddescrof(T, fieldname) descrs_fields.append(descr) def add_array(descrs_arrays, (_, T)): ARRAY = deref(T) if consider_array(ARRAY): descr = cpu.arraydescrof(ARRAY) descrs_arrays.append(descr)
def builtin_func_for_spec(rtyper, oopspec_name, ll_args, ll_res, extra=None, extrakey=None): assert (extra is None) == (extrakey is None) key = (oopspec_name, tuple(ll_args), ll_res, extrakey) try: return rtyper._builtin_func_for_spec_cache[key] except (KeyError, AttributeError): pass args_s = [lltype_to_annotation(v) for v in ll_args] if '.' not in oopspec_name: # 'newxxx' operations LIST_OR_DICT = ll_res else: LIST_OR_DICT = ll_args[0] s_result = lltype_to_annotation(ll_res) impl = setup_extra_builtin(rtyper, oopspec_name, len(args_s), extra) if getattr(impl, 'need_result_type', False): bk = rtyper.annotator.bookkeeper args_s.insert(0, annmodel.SomePBC([bk.getdesc(deref(ll_res))])) # if hasattr(rtyper, 'annotator'): # regular case mixlevelann = MixLevelHelperAnnotator(rtyper) c_func = mixlevelann.constfunc(impl, args_s, s_result) mixlevelann.finish() else: # for testing only c_func = Constant(oopspec_name, lltype.Ptr(lltype.FuncType(ll_args, ll_res))) # if not hasattr(rtyper, '_builtin_func_for_spec_cache'): rtyper._builtin_func_for_spec_cache = {} rtyper._builtin_func_for_spec_cache[key] = (c_func, LIST_OR_DICT) # return c_func, LIST_OR_DICT
def test_immutable_fields_subclass_2(self): from rpython.jit.metainterp.typesystem import deref class A(object): _immutable_fields_ = ["x"] def __init__(self, x): self.x = x class B(A): _immutable_fields_ = ["y"] def __init__(self, x, y): A.__init__(self, x) self.y = y def f(): return B(3, 5) t, typer, graph = self.gengraph(f, []) B_TYPE = deref(graph.getreturnvar().concretetype) accessor = B_TYPE._hints["immutable_fields"] assert accessor.fields == { "inst_x": IR_IMMUTABLE, "inst_y": IR_IMMUTABLE }
def test_quasi_immutable(self): from rpython.jit.metainterp.typesystem import deref class A(object): _immutable_fields_ = ['x', 'y', 'a?', 'b?'] class B(A): pass def f(): a = A() a.x = 42 a.a = 142 b = B() b.x = 43 b.y = 41 b.a = 44 b.b = 45 return B() t, typer, graph = self.gengraph(f, []) B_TYPE = deref(graph.getreturnvar().concretetype) accessor = B_TYPE._hints["immutable_fields"] assert accessor.fields == { "inst_y": IR_IMMUTABLE, "inst_b": IR_QUASIIMMUTABLE } found = [] for op in graph.startblock.operations: if op.opname == 'jit_force_quasi_immutable': found.append(op.args[1].value) assert found == ['mutate_a', 'mutate_a', 'mutate_b']
def test_quasi_immutable(self): from rpython.jit.metainterp.typesystem import deref class A(object): _immutable_fields_ = ['x', 'y', 'a?', 'b?'] class B(A): pass def f(): a = A() a.x = 42 a.a = 142 b = B() b.x = 43 b.y = 41 b.a = 44 b.b = 45 return B() t, typer, graph = self.gengraph(f, []) B_TYPE = deref(graph.getreturnvar().concretetype) accessor = B_TYPE._hints["immutable_fields"] assert accessor.fields == {"inst_y": IR_IMMUTABLE, "inst_b": IR_QUASIIMMUTABLE} found = [] for op in graph.startblock.operations: if op.opname == 'jit_force_quasi_immutable': found.append(op.args[1].value) assert found == ['mutate_a', 'mutate_a', 'mutate_b']
def test_immutable_subclass_2(self): from rpython.jit.metainterp.typesystem import deref class A(object): pass class B(A): _immutable_ = True def f(): A() B().v = 123 return B() t, typer, graph = self.gengraph(f, []) B_TYPE = deref(graph.getreturnvar().concretetype) assert B_TYPE._hints["immutable"]
def effectinfo_from_writeanalyze( effects, cpu, extraeffect=EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_NONE, can_invalidate=False, call_release_gil_target=EffectInfo._NO_CALL_RELEASE_GIL_TARGET, extradescr=None, can_collect=True): from rpython.translator.backendopt.writeanalyze import top_set if effects is top_set or extraeffect == EffectInfo.EF_RANDOM_EFFECTS: readonly_descrs_fields = None readonly_descrs_arrays = None readonly_descrs_interiorfields = None write_descrs_fields = None write_descrs_arrays = None write_descrs_interiorfields = None extraeffect = EffectInfo.EF_RANDOM_EFFECTS else: readonly_descrs_fields = [] readonly_descrs_arrays = [] readonly_descrs_interiorfields = [] write_descrs_fields = [] write_descrs_arrays = [] write_descrs_interiorfields = [] def add_struct(descrs_fields, (_, T, fieldname)): T = deref(T) if consider_struct(T, fieldname): descr = cpu.fielddescrof(T, fieldname) descrs_fields.append(descr) def add_array(descrs_arrays, (_, T)): ARRAY = deref(T) if consider_array(ARRAY): descr = cpu.arraydescrof(ARRAY) descrs_arrays.append(descr)
def builtin_func_for_spec(rtyper, oopspec_name, ll_args, ll_res, extra=None, extrakey=None): assert (extra is None) == (extrakey is None) key = (oopspec_name, tuple(ll_args), ll_res, extrakey) try: return rtyper._builtin_func_for_spec_cache[key] except (KeyError, AttributeError): pass args_s = [lltype_to_annotation(v) for v in ll_args] if '.' not in oopspec_name: # 'newxxx' operations LIST_OR_DICT = ll_res else: LIST_OR_DICT = ll_args[0] s_result = lltype_to_annotation(ll_res) impl = setup_extra_builtin(rtyper, oopspec_name, len(args_s), extra) if getattr(impl, 'need_result_type', False): if hasattr(rtyper, 'annotator'): bk = rtyper.annotator.bookkeeper ll_restype = ll_res if impl.need_result_type != 'exact': ll_restype = deref(ll_restype) desc = bk.getdesc(ll_restype) else: class TestingDesc(object): knowntype = int pyobj = None desc = TestingDesc() args_s.insert(0, annmodel.SomePBC([desc])) # if hasattr(rtyper, 'annotator'): # regular case mixlevelann = MixLevelHelperAnnotator(rtyper) c_func = mixlevelann.constfunc(impl, args_s, s_result) mixlevelann.finish() else: # for testing only c_func = Constant(oopspec_name, lltype.Ptr(lltype.FuncType(ll_args, ll_res))) # if not hasattr(rtyper, '_builtin_func_for_spec_cache'): rtyper._builtin_func_for_spec_cache = {} rtyper._builtin_func_for_spec_cache[key] = (c_func, LIST_OR_DICT) # return c_func, LIST_OR_DICT
def test_immutable_subclass_void(self): from rpython.jit.metainterp.typesystem import deref class A(object): pass class B(A): _immutable_ = True def myfunc(): pass def f(): A().f = myfunc # it's ok to add Void attributes to A B().v = 123 # even though only B is declared _immutable_ return B() t, typer, graph = self.gengraph(f, []) B_TYPE = deref(graph.getreturnvar().concretetype) assert B_TYPE._hints["immutable"]
def test_immutable_fields(self): from rpython.jit.metainterp.typesystem import deref class A(object): _immutable_fields_ = ["x", "y[*]"] def __init__(self, x, y): self.x = x self.y = y def f(): return A(3, []) t, typer, graph = self.gengraph(f, []) A_TYPE = deref(graph.getreturnvar().concretetype) accessor = A_TYPE._hints["immutable_fields"] assert accessor.fields == {"inst_x": IR_IMMUTABLE, "inst_y": IR_IMMUTABLE_ARRAY}
def test_immutable_ok_inheritance_2(self): from rpython.jit.metainterp.typesystem import deref class A(object): _immutable_fields_ = ['v'] class B(A): _immutable_ = True def f(): A().v = 123 B().w = 456 return B() t, typer, graph = self.gengraph(f, []) B_TYPE = deref(graph.getreturnvar().concretetype) assert B_TYPE._hints["immutable"] A_TYPE = B_TYPE.super accessor = A_TYPE._hints["immutable_fields"] assert accessor.fields == {"inst_v": IR_IMMUTABLE}
def test_immutable_fields_only_in_subclass(self): from rpython.jit.metainterp.typesystem import deref class A(object): def __init__(self, x): self.x = x class B(A): _immutable_fields_ = ["y"] def __init__(self, x, y): A.__init__(self, x) self.y = y def f(): return B(3, 5) t, typer, graph = self.gengraph(f, []) B_TYPE = deref(graph.getreturnvar().concretetype) accessor = B_TYPE._hints["immutable_fields"] assert accessor.fields == {"inst_y": IR_IMMUTABLE}
def test_quasi_immutable_array(self): from rpython.jit.metainterp.typesystem import deref class A(object): _immutable_fields_ = ['c?[*]'] class B(A): pass def f(): a = A() a.c = [3, 4, 5] return A() t, typer, graph = self.gengraph(f, []) A_TYPE = deref(graph.getreturnvar().concretetype) accessor = A_TYPE._hints["immutable_fields"] assert accessor.fields == {"inst_c": IR_QUASIIMMUTABLE_ARRAY} found = [] for op in graph.startblock.operations: if op.opname == 'jit_force_quasi_immutable': found.append(op.args[1].value) assert found == ['mutate_c']
def test_immutable_fields(self): from rpython.jit.metainterp.typesystem import deref class A(object): _immutable_fields_ = ["x", "y[*]"] def __init__(self, x, y): self.x = x self.y = y def f(): return A(3, []) t, typer, graph = self.gengraph(f, []) A_TYPE = deref(graph.getreturnvar().concretetype) accessor = A_TYPE._hints["immutable_fields"] assert accessor.fields == { "inst_x": IR_IMMUTABLE, "inst_y": IR_IMMUTABLE_ARRAY }
def __init__(self, warmrunnerdesc, VTYPEPTR): self.warmrunnerdesc = warmrunnerdesc cpu = warmrunnerdesc.cpu self.cpu = cpu # VTYPEPTR1 = VTYPEPTR while 'virtualizable_accessor' not in deref(VTYPEPTR)._hints: VTYPEPTR = cpu.ts.get_superclass(VTYPEPTR) assert VTYPEPTR is not None, ( "%r is listed in the jit driver's 'virtualizables', " "but that class doesn't have a '_virtualizable_' attribute " "(if it has _virtualizable2_, rename it to _virtualizable_)" % (VTYPEPTR1, )) self.VTYPEPTR = VTYPEPTR self.VTYPE = VTYPE = deref(VTYPEPTR) self.vable_token_descr = cpu.fielddescrof(VTYPE, 'vable_token') # accessor = VTYPE._hints['virtualizable_accessor'] all_fields = accessor.fields static_fields = [] array_fields = [] for name, tp in all_fields.iteritems(): if tp == IR_IMMUTABLE_ARRAY: array_fields.append(name) elif tp == IR_IMMUTABLE: static_fields.append(name) else: raise Exception("unknown type: %s" % tp) 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) if not isinstance(ARRAY, lltype.GcArray): raise Exception( "The virtualizable field '%s' is not an array (found %r)." " It usually means that you must try harder to ensure that" " the list is not resized at run-time. You can do that by" " using rpython.rlib.debug.make_sure_not_resized()." % (name, 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 ] for descr in self.static_field_descrs: descr.vinfo = self for descr in self.array_field_descrs: descr.vinfo = self self.static_field_by_descrs = dict([ (descr, i) for (i, descr) in enumerate(self.static_field_descrs) ]) self.array_field_by_descrs = dict([ (descr, i) for (i, descr) in enumerate(self.array_field_descrs) ]) # getlength = cpu.ts.getlength getarrayitem = cpu.ts.getarrayitem setarrayitem = cpu.ts.setarrayitem def read_boxes(cpu, virtualizable): assert lltype.typeOf(virtualizable) == llmemory.GCREF virtualizable = cast_gcref_to_vtype(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): virtualizable = cast_gcref_to_vtype(virtualizable) 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 get_total_size(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) size = 0 for _, fieldname in unroll_array_fields: lst = getattr(virtualizable, fieldname) size += getlength(lst) for _, fieldname in unroll_static_fields: size += 1 return size def write_from_resume_data_partial(virtualizable, reader): virtualizable = cast_gcref_to_vtype(virtualizable) # Load values from the reader (see resume.py) described by # the list of numbers 'nums', and write them in their proper # place in the 'virtualizable'. for FIELDTYPE, fieldname in unroll_static_fields: x = reader.load_next_value_of_type(FIELDTYPE) setattr(virtualizable, fieldname, x) for ARRAYITEMTYPE, fieldname in unroll_array_fields: lst = getattr(virtualizable, fieldname) for j in range(getlength(lst)): x = reader.load_next_value_of_type(ARRAYITEMTYPE) setarrayitem(lst, j, x) def load_list_of_boxes(virtualizable, reader, vable_box): virtualizable = cast_gcref_to_vtype(virtualizable) # Uses 'virtualizable' only to know the length of the arrays; # does not write anything into it. The returned list is in # the format expected of virtualizable_boxes, so it ends in # the virtualizable itself. boxes = [] for FIELDTYPE, fieldname in unroll_static_fields: box = reader.next_box_of_type(FIELDTYPE) boxes.append(box) for ARRAYITEMTYPE, fieldname in unroll_array_fields: lst = getattr(virtualizable, fieldname) for j in range(getlength(lst)): box = reader.next_box_of_type(ARRAYITEMTYPE) boxes.append(box) boxes.append(vable_box) return boxes def check_boxes(virtualizable, boxes): virtualizable = cast_gcref_to_vtype(virtualizable) # 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): virtualizable = cast_gcref_to_vtype(virtualizable) 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): virtualizable = cast_gcref_to_vtype(virtualizable) j = 0 for _, fieldname in unroll_array_fields: if arrayindex == j: lst = getattr(virtualizable, fieldname) return getlength(lst) j += 1 assert False, "invalid arrayindex" unroll_static_fields = unrolling_iterable( zip(FIELDTYPES, static_fields)) unroll_array_fields = unrolling_iterable( zip(ARRAYITEMTYPES, array_fields)) unroll_static_fields_rev = unrolling_iterable( reversed(list(unroll_static_fields))) unroll_array_fields_rev = unrolling_iterable( reversed(list(unroll_array_fields))) self.read_boxes = read_boxes self.write_boxes = write_boxes self.write_from_resume_data_partial = write_from_resume_data_partial self.load_list_of_boxes = load_list_of_boxes self.check_boxes = check_boxes self.get_index_in_array = get_index_in_array self.get_array_length = get_array_length self.get_total_size = get_total_size def cast_to_vtype(virtualizable): return self.cpu.ts.cast_to_instance_maybe(VTYPEPTR, virtualizable) self.cast_to_vtype = cast_to_vtype def cast_gcref_to_vtype(virtualizable): assert lltype.typeOf(virtualizable) == llmemory.GCREF return lltype.cast_opaque_ptr(VTYPEPTR, virtualizable) self.cast_gcref_to_vtype = cast_gcref_to_vtype def clear_vable_token(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) if virtualizable.vable_token: force_now(virtualizable) assert not virtualizable.vable_token self.clear_vable_token = clear_vable_token def tracing_before_residual_call(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) assert not virtualizable.vable_token virtualizable.vable_token = TOKEN_TRACING_RESCALL self.tracing_before_residual_call = tracing_before_residual_call def tracing_after_residual_call(virtualizable): """ Returns whether or not the virtualizable was forced during a CALL_MAY_FORCE. """ virtualizable = cast_gcref_to_vtype(virtualizable) if virtualizable.vable_token: # not modified by the residual call; assert that it is still # set to TOKEN_TRACING_RESCALL and clear it. assert virtualizable.vable_token == TOKEN_TRACING_RESCALL virtualizable.vable_token = TOKEN_NONE return False else: # marker "modified during residual call" set. return True self.tracing_after_residual_call = tracing_after_residual_call def force_now(virtualizable): token = virtualizable.vable_token if token == TOKEN_TRACING_RESCALL: # The values in the virtualizable are always correct during # tracing. We only need to reset vable_token to TOKEN_NONE # as a marker for the tracing, to tell it that this # virtualizable escapes. virtualizable.vable_token = TOKEN_NONE else: from rpython.jit.metainterp.compile import ResumeGuardForcedDescr ResumeGuardForcedDescr.force_now(cpu, token) assert virtualizable.vable_token == TOKEN_NONE force_now._dont_inline_ = True self.force_now = force_now def is_token_nonnull_gcref(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) return bool(virtualizable.vable_token) self.is_token_nonnull_gcref = is_token_nonnull_gcref def reset_token_gcref(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) virtualizable.vable_token = TOKEN_NONE self.reset_token_gcref = reset_token_gcref def reset_vable_token(virtualizable): virtualizable.vable_token = TOKEN_NONE self.reset_vable_token = reset_vable_token
write_descrs_interiorfields = [] def add_struct(descrs_fields, (_, T, fieldname)): T = deref(T) if consider_struct(T, fieldname): descr = cpu.fielddescrof(T, fieldname) descrs_fields.append(descr) def add_array(descrs_arrays, (_, T)): ARRAY = deref(T) if consider_array(ARRAY): descr = cpu.arraydescrof(ARRAY) descrs_arrays.append(descr) def add_interiorfield(descrs_interiorfields, (_, T, fieldname)): T = deref(T) if not isinstance(T, lltype.Array): return # let's not consider structs for now if not consider_array(T): return if getattr(T.OF, fieldname) is lltype.Void: return try: descr = cpu.interiorfielddescrof(T, fieldname) except UnsupportedFieldExc: return descrs_interiorfields.append(descr) # a read or a write to an interiorfield, inside an array of # structs, is additionally recorded as a read or write of # the array itself
write_descrs_interiorfields = [] def add_struct(descrs_fields, (_, T, fieldname)): T = deref(T) if consider_struct(T, fieldname): descr = cpu.fielddescrof(T, fieldname) descrs_fields.append(descr) def add_array(descrs_arrays, (_, T)): ARRAY = deref(T) if consider_array(ARRAY): descr = cpu.arraydescrof(ARRAY) descrs_arrays.append(descr) def add_interiorfield(descrs_interiorfields, (_, T, fieldname)): T = deref(T) if not isinstance(T, lltype.Array): return # let's not consider structs for now if not consider_array(T): return if getattr(T.OF, fieldname) is lltype.Void: return descr = cpu.interiorfielddescrof(T, fieldname) descrs_interiorfields.append(descr) # a read or a write to an interiorfield, inside an array of # structs, is additionally recorded as a read or write of # the array itself extraef = set() for tup in effects: if tup[0] == "interiorfield" or tup[0] == "readinteriorfield":
def __init__(self, warmrunnerdesc, VTYPEPTR): self.warmrunnerdesc = warmrunnerdesc cpu = warmrunnerdesc.cpu self.cpu = cpu self.BoxArray = cpu.ts.BoxRef # while 'virtualizable2_accessor' not in deref(VTYPEPTR)._hints: VTYPEPTR = cpu.ts.get_superclass(VTYPEPTR) self.VTYPEPTR = VTYPEPTR self.VTYPE = VTYPE = deref(VTYPEPTR) self.vable_token_descr = cpu.fielddescrof(VTYPE, 'vable_token') # accessor = VTYPE._hints['virtualizable2_accessor'] all_fields = accessor.fields static_fields = [] array_fields = [] for name, tp in all_fields.iteritems(): if tp == IR_IMMUTABLE_ARRAY: array_fields.append(name) elif tp == IR_IMMUTABLE: static_fields.append(name) else: raise Exception("unknown type: %s" % tp) 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) assert isinstance(ARRAY, lltype.GcArray) 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] self.static_field_by_descrs = dict( [(descr, i) for (i, descr) in enumerate(self.static_field_descrs)]) self.array_field_by_descrs = dict( [(descr, i) for (i, descr) in enumerate(self.array_field_descrs)]) # getlength = cpu.ts.getlength getarrayitem = cpu.ts.getarrayitem setarrayitem = cpu.ts.setarrayitem def read_boxes(cpu, virtualizable): assert lltype.typeOf(virtualizable) == llmemory.GCREF virtualizable = cast_gcref_to_vtype(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): virtualizable = cast_gcref_to_vtype(virtualizable) 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 write_from_resume_data_partial(virtualizable, reader, numb): virtualizable = cast_gcref_to_vtype(virtualizable) # Load values from the reader (see resume.py) described by # the list of numbers 'nums', and write them in their proper # place in the 'virtualizable'. This works from the end of # the list and returns the index in 'nums' of the start of # the virtualizable data found, allowing the caller to do # further processing with the start of the list. i = len(numb.nums) - 1 assert i >= 0 for ARRAYITEMTYPE, fieldname in unroll_array_fields_rev: lst = getattr(virtualizable, fieldname) for j in range(getlength(lst) - 1, -1, -1): i -= 1 assert i >= 0 x = reader.load_value_of_type(ARRAYITEMTYPE, numb.nums[i]) setarrayitem(lst, j, x) for FIELDTYPE, fieldname in unroll_static_fields_rev: i -= 1 assert i >= 0 x = reader.load_value_of_type(FIELDTYPE, numb.nums[i]) setattr(virtualizable, fieldname, x) return i def load_list_of_boxes(virtualizable, reader, numb): virtualizable = cast_gcref_to_vtype(virtualizable) # Uses 'virtualizable' only to know the length of the arrays; # does not write anything into it. The returned list is in # the format expected of virtualizable_boxes, so it ends in # the virtualizable itself. i = len(numb.nums) - 1 assert i >= 0 boxes = [reader.decode_box_of_type(self.VTYPEPTR, numb.nums[i])] for ARRAYITEMTYPE, fieldname in unroll_array_fields_rev: lst = getattr(virtualizable, fieldname) for j in range(getlength(lst) - 1, -1, -1): i -= 1 assert i >= 0 box = reader.decode_box_of_type(ARRAYITEMTYPE, numb.nums[i]) boxes.append(box) for FIELDTYPE, fieldname in unroll_static_fields_rev: i -= 1 assert i >= 0 box = reader.decode_box_of_type(FIELDTYPE, numb.nums[i]) boxes.append(box) boxes.reverse() return boxes def check_boxes(virtualizable, boxes): virtualizable = cast_gcref_to_vtype(virtualizable) # 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): virtualizable = cast_gcref_to_vtype(virtualizable) 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): virtualizable = cast_gcref_to_vtype(virtualizable) j = 0 for _, fieldname in unroll_array_fields: if arrayindex == j: lst = getattr(virtualizable, fieldname) return getlength(lst) j += 1 assert False, "invalid arrayindex" unroll_static_fields = unrolling_iterable(zip(FIELDTYPES, static_fields)) unroll_array_fields = unrolling_iterable(zip(ARRAYITEMTYPES, array_fields)) unroll_static_fields_rev = unrolling_iterable( reversed(list(unroll_static_fields))) unroll_array_fields_rev = unrolling_iterable( reversed(list(unroll_array_fields))) self.read_boxes = read_boxes self.write_boxes = write_boxes self.write_from_resume_data_partial = write_from_resume_data_partial self.load_list_of_boxes = load_list_of_boxes self.check_boxes = check_boxes self.get_index_in_array = get_index_in_array self.get_array_length = get_array_length def cast_to_vtype(virtualizable): return self.cpu.ts.cast_to_instance_maybe(VTYPEPTR, virtualizable) self.cast_to_vtype = cast_to_vtype def cast_gcref_to_vtype(virtualizable): assert lltype.typeOf(virtualizable) == llmemory.GCREF return lltype.cast_opaque_ptr(VTYPEPTR, virtualizable) self.cast_gcref_to_vtype = cast_gcref_to_vtype def reset_vable_token(virtualizable): virtualizable.vable_token = TOKEN_NONE self.reset_vable_token = reset_vable_token def clear_vable_token(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) if virtualizable.vable_token: force_now(virtualizable) assert not virtualizable.vable_token self.clear_vable_token = clear_vable_token def tracing_before_residual_call(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) assert not virtualizable.vable_token virtualizable.vable_token = TOKEN_TRACING_RESCALL self.tracing_before_residual_call = tracing_before_residual_call def tracing_after_residual_call(virtualizable): """ Returns whether or not the virtualizable was forced during a CALL_MAY_FORCE. """ virtualizable = cast_gcref_to_vtype(virtualizable) if virtualizable.vable_token: # not modified by the residual call; assert that it is still # set to TOKEN_TRACING_RESCALL and clear it. assert virtualizable.vable_token == TOKEN_TRACING_RESCALL virtualizable.vable_token = TOKEN_NONE return False else: # marker "modified during residual call" set. return True self.tracing_after_residual_call = tracing_after_residual_call def force_now(virtualizable): token = virtualizable.vable_token if token == TOKEN_TRACING_RESCALL: # The values in the virtualizable are always correct during # tracing. We only need to reset vable_token to TOKEN_NONE # as a marker for the tracing, to tell it that this # virtualizable escapes. virtualizable.vable_token = TOKEN_NONE else: from rpython.jit.metainterp.compile import ResumeGuardForcedDescr ResumeGuardForcedDescr.force_now(cpu, token) assert virtualizable.vable_token == TOKEN_NONE force_now._dont_inline_ = True self.force_now = force_now def is_token_nonnull_gcref(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) return bool(virtualizable.vable_token) self.is_token_nonnull_gcref = is_token_nonnull_gcref def reset_token_gcref(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) virtualizable.vable_token = TOKEN_NONE self.reset_token_gcref = reset_token_gcref