Author: Armin Rigo <ar...@tunes.org> Branch: cpyext-gc-support-2 Changeset: r82398:e4cdc09604fe Date: 2016-02-22 17:20 +0100 http://bitbucket.org/pypy/pypy/changeset/e4cdc09604fe/
Log: (ronan, arigo) refactor and made more explicit the "layout" of W_TypeObjects, to be used by cpyext diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -262,7 +262,7 @@ def user_setup(self, space, w_subtype): self.space = space self.w__class__ = w_subtype - self.user_setup_slots(w_subtype.nslots) + self.user_setup_slots(w_subtype.layout.nslots) def user_setup_slots(self, nslots): assert nslots == 0 diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -523,7 +523,7 @@ def best_base(space, bases_w): if not bases_w: return None - return find_best_base(space, bases_w) + return find_best_base(bases_w) def inherit_slots(space, pto, w_base): # XXX missing: nearly everything diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -359,7 +359,8 @@ subcls = get_subclass_of_correct_size(self, cls, w_subtype) else: subcls = get_unique_interplevel_subclass( - self.config, cls, w_subtype.hasdict, w_subtype.nslots != 0, + self.config, cls, w_subtype.hasdict, + w_subtype.layout.nslots != 0, w_subtype.needsdel, w_subtype.weakrefable) instance = instantiate(subcls) assert isinstance(instance, cls) diff --git a/pypy/objspace/std/transparent.py b/pypy/objspace/std/transparent.py --- a/pypy/objspace/std/transparent.py +++ b/pypy/objspace/std/transparent.py @@ -62,7 +62,7 @@ return W_TransparentGenerator(space, w_type, w_controller) if space.is_true(space.issubtype(w_type, space.gettypeobject(PyCode.typedef))): return W_TransparentCode(space, w_type, w_controller) - if w_type.instancetypedef is space.w_object.instancetypedef: + if w_type.layout.typedef is space.w_object.layout.typedef: return W_Transparent(space, w_type, w_controller) else: raise OperationError(space.w_TypeError, space.wrap("type expected as first argument")) diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -87,6 +87,29 @@ for i in range(len(self.lookup_where)): self.lookup_where[i] = None_None + +class Layout(object): + """A Layout is attached to every W_TypeObject to represent the + layout of instances. Some W_TypeObjects share the same layout. + If a W_TypeObject is a base of another, then the layout of + the first is either the same or a parent layout of the second. + The Layouts have single inheritance, unlike W_TypeObjects. + """ + _immutable_ = True + + def __init__(self, typedef, nslots, base_layout=None): + self.typedef = typedef + self.nslots = nslots + self.base_layout = base_layout + + def issublayout(self, parent): + while self is not parent: + self = self.base_layout + if self is None: + return False + return True + + # possible values of compares_by_identity_status UNKNOWN = 0 COMPARES_BY_IDENTITY = 1 @@ -106,8 +129,7 @@ 'needsdel', 'weakrefable', 'hasdict', - 'nslots', - 'instancetypedef', + 'layout', 'terminator', '_version_tag?', 'name?', @@ -131,7 +153,6 @@ w_self.name = name w_self.bases_w = bases_w w_self.dict_w = dict_w - w_self.nslots = 0 w_self.hasdict = False w_self.needsdel = False w_self.weakrefable = False @@ -141,13 +162,12 @@ w_self.flag_cpytype = False w_self.flag_abstract = False w_self.flag_sequence_bug_compat = False - w_self.instancetypedef = overridetypedef if overridetypedef is not None: - setup_builtin_type(w_self) + layout = setup_builtin_type(w_self, overridetypedef) else: - setup_user_defined_type(w_self) - w_self.w_same_layout_as = get_parent_layout(w_self) + layout = setup_user_defined_type(w_self) + w_self.layout = layout if space.config.objspace.std.withtypeversion: if not is_mro_purely_of_types(w_self.mro_w): @@ -268,8 +288,8 @@ # compute a tuple that fully describes the instance layout def get_full_instance_layout(w_self): - w_layout = w_self.w_same_layout_as or w_self - return (w_layout, w_self.hasdict, w_self.needsdel, w_self.weakrefable) + layout = w_self.layout + return (layout, w_self.hasdict, w_self.needsdel, w_self.weakrefable) def compute_default_mro(w_self): return compute_C3_mro(w_self.space, w_self) @@ -467,7 +487,7 @@ raise oefmt(space.w_TypeError, "%N.__new__(%N): %N is not a subtype of %N", w_self, w_subtype, w_subtype, w_self) - if w_self.instancetypedef is not w_subtype.instancetypedef: + if w_self.layout.typedef is not w_subtype.layout.typedef: raise oefmt(space.w_TypeError, "%N.__new__(%N) is not safe, use %N.__new__()", w_self, w_subtype, w_subtype) @@ -821,11 +841,10 @@ for w_subclass in w_type.get_subclasses(): if isinstance(w_subclass, W_TypeObject): w_subclass._version_tag = None - assert w_type.w_same_layout_as is get_parent_layout(w_type) # invariant def descr__base(space, w_type): w_type = _check(space, w_type) - return find_best_base(space, w_type.bases_w) + return find_best_base(w_type.bases_w) def descr__doc(space, w_type): if space.is_w(w_type, space.w_type): @@ -928,48 +947,7 @@ # ____________________________________________________________ # Initialization of type objects -def get_parent_layout(w_type): - """Compute the most parent class of 'w_type' whose layout - is the same as 'w_type', or None if all parents of 'w_type' - have a different layout than 'w_type'. - """ - w_starttype = w_type - while len(w_type.bases_w) > 0: - w_bestbase = find_best_base(w_type.space, w_type.bases_w) - if w_type.instancetypedef is not w_bestbase.instancetypedef: - break - if w_type.nslots != w_bestbase.nslots: - break - w_type = w_bestbase - if w_type is not w_starttype: - return w_type - else: - return None - -def issublayout(w_layout1, w_layout2): - space = w_layout2.space - while w_layout1 is not w_layout2: - w_layout1 = find_best_base(space, w_layout1.bases_w) - if w_layout1 is None: - return False - w_layout1 = w_layout1.w_same_layout_as or w_layout1 - return True - -@unroll_safe -def issubtypedef(a, b): - from pypy.objspace.std.objectobject import W_ObjectObject - if b is W_ObjectObject.typedef: - return True - if a is None: - return False - if a is b: - return True - for a1 in a.bases: - if issubtypedef(a1, b): - return True - return False - -def find_best_base(space, bases_w): +def find_best_base(bases_w): """The best base is one of the bases in the given list: the one whose layout a new type should use as a starting point. """ @@ -980,14 +958,10 @@ if w_bestbase is None: w_bestbase = w_candidate # for now continue - candtypedef = w_candidate.instancetypedef - besttypedef = w_bestbase.instancetypedef - if candtypedef is besttypedef: - # two candidates with the same typedef are equivalent unless - # one has extra slots over the other - if w_candidate.nslots > w_bestbase.nslots: - w_bestbase = w_candidate - elif issubtypedef(candtypedef, besttypedef): + cand_layout = w_candidate.layout + best_layout = w_bestbase.layout + if (cand_layout is not best_layout and + cand_layout.issublayout(best_layout)): w_bestbase = w_candidate return w_bestbase @@ -996,20 +970,21 @@ whose layout a new type should use as a starting point. This version checks that bases_w is an acceptable tuple of bases. """ - w_bestbase = find_best_base(space, bases_w) + w_bestbase = find_best_base(bases_w) if w_bestbase is None: raise oefmt(space.w_TypeError, "a new-style class can't have only classic bases") - if not w_bestbase.instancetypedef.acceptable_as_base_class: + if not w_bestbase.layout.typedef.acceptable_as_base_class: raise oefmt(space.w_TypeError, "type '%N' is not an acceptable base class", w_bestbase) - # check that all other bases' layouts are superclasses of the bestbase - w_bestlayout = w_bestbase.w_same_layout_as or w_bestbase + # check that all other bases' layouts are "super-layouts" of the + # bestbase's layout + best_layout = w_bestbase.layout for w_base in bases_w: if isinstance(w_base, W_TypeObject): - w_layout = w_base.w_same_layout_as or w_base - if not issublayout(w_bestlayout, w_layout): + layout = w_base.layout + if not best_layout.issublayout(layout): raise oefmt(space.w_TypeError, "instance layout conflicts in multiple inheritance") return w_bestbase @@ -1023,10 +998,11 @@ w_self.hasdict = w_self.hasdict or w_base.hasdict w_self.needsdel = w_self.needsdel or w_base.needsdel w_self.weakrefable = w_self.weakrefable or w_base.weakrefable - w_self.nslots = w_bestbase.nslots return hasoldstylebase def create_all_slots(w_self, hasoldstylebase, w_bestbase): + base_layout = w_bestbase.layout + index_next_extra_slot = base_layout.nslots space = w_self.space dict_w = w_self.dict_w if '__slots__' not in dict_w: @@ -1054,7 +1030,8 @@ "__weakref__ slot disallowed: we already got one") wantweakref = True else: - create_slot(w_self, slot_name) + index_next_extra_slot = create_slot(w_self, slot_name, + index_next_extra_slot) wantdict = wantdict or hasoldstylebase if wantdict: create_dict_slot(w_self) @@ -1062,8 +1039,14 @@ create_weakref_slot(w_self) if '__del__' in dict_w: w_self.needsdel = True + # + if index_next_extra_slot == base_layout.nslots: + return base_layout + else: + return Layout(base_layout.typedef, index_next_extra_slot, + base_layout=base_layout) -def create_slot(w_self, slot_name): +def create_slot(w_self, slot_name, index_next_extra_slot): space = w_self.space if not valid_slot_name(slot_name): raise oefmt(space.w_TypeError, "__slots__ must be identifiers") @@ -1073,9 +1056,10 @@ # Force interning of slot names. slot_name = space.str_w(space.new_interned_str(slot_name)) # in cpython it is ignored less, but we probably don't care - member = Member(w_self.nslots, slot_name, w_self) + member = Member(index_next_extra_slot, slot_name, w_self) + index_next_extra_slot += 1 w_self.dict_w[slot_name] = space.wrap(member) - w_self.nslots += 1 + return index_next_extra_slot def create_dict_slot(w_self): if not w_self.hasdict: @@ -1101,7 +1085,6 @@ if len(w_self.bases_w) == 0: w_self.bases_w = [w_self.space.w_object] w_bestbase = check_and_find_best_base(w_self.space, w_self.bases_w) - w_self.instancetypedef = w_bestbase.instancetypedef w_self.flag_heaptype = True for w_base in w_self.bases_w: if not isinstance(w_base, W_TypeObject): @@ -1110,16 +1093,28 @@ w_self.flag_abstract |= w_base.flag_abstract hasoldstylebase = copy_flags_from_bases(w_self, w_bestbase) - create_all_slots(w_self, hasoldstylebase, w_bestbase) + layout = create_all_slots(w_self, hasoldstylebase, w_bestbase) ensure_common_attributes(w_self) + return layout -def setup_builtin_type(w_self): - w_self.hasdict = w_self.instancetypedef.hasdict - w_self.weakrefable = w_self.instancetypedef.weakrefable - w_self.w_doc = w_self.space.wrap(w_self.instancetypedef.doc) +def setup_builtin_type(w_self, instancetypedef): + w_self.hasdict = instancetypedef.hasdict + w_self.weakrefable = instancetypedef.weakrefable + w_self.w_doc = w_self.space.wrap(instancetypedef.doc) ensure_common_attributes(w_self) - w_self.flag_heaptype = w_self.instancetypedef.heaptype + w_self.flag_heaptype = instancetypedef.heaptype + # + # usually 'instancetypedef' is new, i.e. not seen in any base, + # but not always (see Exception class) + w_bestbase = find_best_base(w_self.bases_w) + if w_bestbase is None: + parent_layout = None + else: + parent_layout = w_bestbase.layout + if parent_layout.typedef is instancetypedef: + return parent_layout + return Layout(instancetypedef, 0, base_layout=parent_layout) def ensure_common_attributes(w_self): ensure_static_new(w_self) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit