[pypy-commit] pypy cpyext-gc-support-2: (ronan, arigo)

arigo pypy.commits at gmail.com
Mon Feb 22 11:24:07 EST 2016


Author: Armin Rigo <arigo at 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
-
- at 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)


More information about the pypy-commit mailing list