[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