Author: Carl Friedrich Bolz <[email protected]>
Branch:
Changeset: r84029:0b1c73820000
Date: 2016-04-29 16:52 +0300
http://bitbucket.org/pypy/pypy/changeset/0b1c73820000/
Log: merge share-mapdict-methods-2
reduce generated code for subclasses by using the same function
objects in all generated subclasses.
diff --git a/pypy/interpreter/test/test_typedef.py
b/pypy/interpreter/test/test_typedef.py
--- a/pypy/interpreter/test/test_typedef.py
+++ b/pypy/interpreter/test/test_typedef.py
@@ -362,6 +362,45 @@
""")
assert seen == [1]
+ def test_mapdict_number_of_slots(self):
+ space = self.space
+ a, b, c = space.unpackiterable(space.appexec([], """():
+ class A(object):
+ pass
+ a = A()
+ a.x = 1
+ class B:
+ pass
+ b = B()
+ b.x = 1
+ class C(int):
+ pass
+ c = C(1)
+ c.x = 1
+ return a, b, c
+ """), 3)
+ assert not hasattr(a, "storage")
+ assert not hasattr(b, "storage")
+ assert hasattr(c, "storage")
+
+ def test_del(self):
+ space = self.space
+ a, b, c, d = space.unpackiterable(space.appexec([], """():
+ class A(object):
+ pass
+ class B(object):
+ def __del__(self):
+ pass
+ class F(file):
+ pass
+ class G(file):
+ def __del__(self):
+ pass
+ return A(), B(), F("xyz", "w"), G("ghi", "w")
+ """))
+ assert type(b).__base__ is type(a)
+ assert hasattr(c, "__del__")
+ assert type(d) is type(c)
class AppTestTypeDef:
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -103,43 +103,61 @@
# we need two subclasses of the app-level type, one to add mapdict, and then
one
# to add del to not slow down the GC.
-def get_unique_interplevel_subclass(config, cls, needsdel=False):
+def get_unique_interplevel_subclass(space, cls, needsdel=False):
"NOT_RPYTHON: initialization-time only"
if hasattr(cls, '__del__') and getattr(cls, "handle_del_manually", False):
needsdel = False
assert cls.typedef.acceptable_as_base_class
- key = config, cls, needsdel
+ key = space, cls, needsdel
try:
return _subclass_cache[key]
except KeyError:
# XXX can save a class if cls already has a __del__
- if needsdel:
- cls = get_unique_interplevel_subclass(config, cls, False)
- subcls = _getusercls(config, cls, needsdel)
+ keys = [key]
+ base_has_del = hasattr(cls, '__del__')
+ if base_has_del:
+ # if the base has a __del__, we only need one class
+ keys = [(space, cls, True), (space, cls, False)]
+ needsdel = True
+ elif needsdel:
+ cls = get_unique_interplevel_subclass(space, cls, False)
+ subcls = _getusercls(space, cls, needsdel)
assert key not in _subclass_cache
- _subclass_cache[key] = subcls
+ for key in keys:
+ _subclass_cache[key] = subcls
return subcls
get_unique_interplevel_subclass._annspecialcase_ = "specialize:memo"
_subclass_cache = {}
-def _getusercls(config, cls, wants_del, reallywantdict=False):
+def _getusercls(space, cls, wants_del, reallywantdict=False):
from rpython.rlib import objectmodel
+ from pypy.objspace.std.objectobject import W_ObjectObject
+ from pypy.module.__builtin__.interp_classobj import W_InstanceObject
from pypy.objspace.std.mapdict import (BaseUserClassMapdict,
MapdictDictSupport, MapdictWeakrefSupport,
- _make_storage_mixin_size_n)
+ _make_storage_mixin_size_n, MapdictStorageMixin)
typedef = cls.typedef
name = cls.__name__ + "User"
- mixins_needed = [BaseUserClassMapdict, _make_storage_mixin_size_n()]
- if reallywantdict or not typedef.hasdict:
- # the type has no dict, mapdict to provide the dict
- mixins_needed.append(MapdictDictSupport)
- name += "Dict"
- if not typedef.weakrefable:
- # the type does not support weakrefs yet, mapdict to provide weakref
- # support
- mixins_needed.append(MapdictWeakrefSupport)
- name += "Weakrefable"
+ mixins_needed = []
+ copy_methods = []
+ mixins_needed = []
+ name = cls.__name__
+ if not cls.user_overridden_class:
+ if cls is W_ObjectObject or cls is W_InstanceObject:
+ mixins_needed.append(_make_storage_mixin_size_n())
+ else:
+ mixins_needed.append(MapdictStorageMixin)
+ copy_methods = [BaseUserClassMapdict]
+ if reallywantdict or not typedef.hasdict:
+ # the type has no dict, mapdict to provide the dict
+ copy_methods.append(MapdictDictSupport)
+ name += "Dict"
+ if not typedef.weakrefable:
+ # the type does not support weakrefs yet, mapdict to provide
weakref
+ # support
+ copy_methods.append(MapdictWeakrefSupport)
+ name += "Weakrefable"
if wants_del:
name += "Del"
parent_destructor = getattr(cls, '__del__', None)
@@ -148,14 +166,14 @@
parent_destructor(self)
def call_applevel_del(self):
assert isinstance(self, subcls)
- self.space.userdel(self)
+ space.userdel(self)
class Proto(object):
def __del__(self):
self.clear_all_weakrefs()
- self.enqueue_for_destruction(self.space, call_applevel_del,
+ self.enqueue_for_destruction(space, call_applevel_del,
'method __del__ of ')
if parent_destructor is not None:
- self.enqueue_for_destruction(self.space, call_parent_del,
+ self.enqueue_for_destruction(space, call_parent_del,
'internal destructor of ')
mixins_needed.append(Proto)
@@ -163,10 +181,17 @@
user_overridden_class = True
for base in mixins_needed:
objectmodel.import_from_mixin(base)
+ for copycls in copy_methods:
+ _copy_methods(copycls, subcls)
del subcls.base
subcls.__name__ = name
return subcls
+def _copy_methods(copycls, subcls):
+ for key, value in copycls.__dict__.items():
+ if (not key.startswith('__') or key == '__del__'):
+ setattr(subcls, key, value)
+
# ____________________________________________________________
diff --git a/pypy/module/__builtin__/interp_classobj.py
b/pypy/module/__builtin__/interp_classobj.py
--- a/pypy/module/__builtin__/interp_classobj.py
+++ b/pypy/module/__builtin__/interp_classobj.py
@@ -195,9 +195,9 @@
return
self.cls_without_del = _getusercls(
- space.config, W_InstanceObject, False, reallywantdict=True)
+ space, W_InstanceObject, False, reallywantdict=True)
self.cls_with_del = _getusercls(
- space.config, W_InstanceObject, True, reallywantdict=True)
+ space, W_InstanceObject, True, reallywantdict=True)
def class_descr_call(space, w_self, __args__):
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -452,19 +452,12 @@
# everything that's needed to use mapdict for a user subclass at all.
# This immediately makes slots possible.
- # assumes presence of _mapdict_init_empty, _mapdict_read_storage,
+ # assumes presence of _get_mapdict_map, _set_mapdict_map
+ # _mapdict_init_empty, _mapdict_read_storage,
# _mapdict_write_storage, _mapdict_storage_length,
# _set_mapdict_storage_and_map
# _____________________________________________
- # methods needed for mapdict
-
- def _get_mapdict_map(self):
- return jit.promote(self.map)
- def _set_mapdict_map(self, map):
- self.map = map
-
- # _____________________________________________
# objspace interface
# class access
@@ -478,7 +471,6 @@
def user_setup(self, space, w_subtype):
from pypy.module.__builtin__.interp_classobj import W_InstanceObject
- self.space = space
assert (not self.typedef.hasdict or
isinstance(w_subtype.terminator, NoDictTerminator) or
self.typedef is W_InstanceObject.typedef)
@@ -591,6 +583,11 @@
assert flag
class MapdictStorageMixin(object):
+ def _get_mapdict_map(self):
+ return jit.promote(self.map)
+ def _set_mapdict_map(self, map):
+ self.map = map
+
def _mapdict_init_empty(self, map):
from rpython.rlib.debug import make_sure_not_resized
self.map = map
@@ -605,6 +602,7 @@
def _mapdict_storage_length(self):
return len(self.storage)
+
def _set_mapdict_storage_and_map(self, storage, map):
self.storage = storage
self.map = map
@@ -635,6 +633,10 @@
rangenmin1 = unroll.unrolling_iterable(range(nmin1))
valnmin1 = "_value%s" % nmin1
class subcls(object):
+ def _get_mapdict_map(self):
+ return jit.promote(self.map)
+ def _set_mapdict_map(self, map):
+ self.map = map
def _mapdict_init_empty(self, map):
for i in rangenmin1:
setattr(self, "_value%s" % i, None)
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
@@ -358,7 +358,7 @@
cls = cls.typedef.applevel_subclasses_base
#
subcls = get_unique_interplevel_subclass(
- self.config, cls, w_subtype.needsdel)
+ self, cls, w_subtype.needsdel)
instance = instantiate(subcls)
assert isinstance(instance, cls)
instance.user_setup(self, w_subtype)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit