[pypy-commit] pypy default: Add the requirement that W_XxxObject classes that are different
arigo
noreply at buildbot.pypy.org
Sat Nov 12 12:44:29 CET 2011
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r49355:b0c70fdea6b5
Date: 2011-11-12 12:44 +0100
http://bitbucket.org/pypy/pypy/changeset/b0c70fdea6b5/
Log: Add the requirement that W_XxxObject classes that are different
implementations of the same app-level type should inherit from a
common base class more precise than W_Object. This is actually
easy, just by adding some empty W_AbstractXxxObject classes here and
there.
This property allows us to build the _interplevel_classes for-speed-
only dictionary in a way that doesn't depend on dictionary order.
Previously it would randomly pick a class if there are several ones,
which might be (if you're unluckly) not the most commonly used one.
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -16,7 +16,10 @@
something CPython does not do anymore.
"""
-class W_IntObject(W_Object):
+class W_AbstractIntObject(W_Object):
+ pass
+
+class W_IntObject(W_AbstractIntObject):
__slots__ = 'intval'
_immutable_fields_ = ['intval']
diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py
--- a/pypy/objspace/std/iterobject.py
+++ b/pypy/objspace/std/iterobject.py
@@ -4,7 +4,10 @@
from pypy.objspace.std.register_all import register_all
-class W_AbstractSeqIterObject(W_Object):
+class W_AbstractIterObject(W_Object):
+ pass
+
+class W_AbstractSeqIterObject(W_AbstractIterObject):
from pypy.objspace.std.itertype import iter_typedef as typedef
def __init__(w_self, w_seq, index=0):
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -11,7 +11,10 @@
from pypy.rlib.listsort import make_timsort_class
from pypy.interpreter.argument import Signature
-class W_ListObject(W_Object):
+class W_AbstractListObject(W_Object):
+ pass
+
+class W_ListObject(W_AbstractListObject):
from pypy.objspace.std.listtype import list_typedef as typedef
def __init__(w_self, wrappeditems):
diff --git a/pypy/objspace/std/longobject.py b/pypy/objspace/std/longobject.py
--- a/pypy/objspace/std/longobject.py
+++ b/pypy/objspace/std/longobject.py
@@ -8,7 +8,10 @@
from pypy.objspace.std.noneobject import W_NoneObject
from pypy.rlib.rbigint import rbigint, SHIFT
-class W_LongObject(W_Object):
+class W_AbstractLongObject(W_Object):
+ pass
+
+class W_LongObject(W_AbstractLongObject):
"""This is a wrapper of rbigint."""
from pypy.objspace.std.longtype import long_typedef as typedef
_immutable_fields_ = ['num']
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
@@ -83,12 +83,7 @@
if self.config.objspace.std.withtproxy:
transparent.setup(self)
- interplevel_classes = {}
- for type, classes in self.model.typeorder.iteritems():
- if len(classes) >= 3: # XXX what does this 3 mean??!
- # W_Root, AnyXxx and actual object
- interplevel_classes[self.gettypefor(type)] = classes[0][0]
- self._interplevel_classes = interplevel_classes
+ self.setup_isinstance_cache()
def get_builtin_types(self):
return self.builtin_types
@@ -592,6 +587,63 @@
def isinstance_w(space, w_inst, w_type):
return space._type_isinstance(w_inst, w_type)
+ def setup_isinstance_cache(self):
+ # This assumes that all classes in the stdobjspace implementing a
+ # particular app-level type are distinguished by a common base class.
+ # Alternatively, you can turn off the cache on specific classes,
+ # like e.g. proxyobject. It is just a bit less performant but
+ # should not have any bad effect.
+ from pypy.objspace.std.model import W_Root, W_Object
+ #
+ # Build a dict {class: w_typeobject-or-None}. The value None is used
+ # on classes that are known to be abstract base classes.
+ class2type = {}
+ class2type[W_Root] = None
+ class2type[W_Object] = None
+ for cls in self.model.typeorder.keys():
+ if getattr(cls, 'typedef', None) is None:
+ continue
+ if getattr(cls, 'ignore_for_isinstance_cache', False):
+ continue
+ w_type = self.gettypefor(cls)
+ w_oldtype = class2type.setdefault(cls, w_type)
+ assert w_oldtype is w_type
+ #
+ # Build the real dict {w_typeobject: class-or-base-class}. For every
+ # w_typeobject we look for the most precise common base class of all
+ # the registered classes. If no such class is found, we will find
+ # W_Object or W_Root, and complain. Then you must either add an
+ # artificial common base class, or disable caching on one of the
+ # two classes with ignore_for_isinstance_cache.
+ def getmro(cls):
+ while True:
+ yield cls
+ if cls is W_Root:
+ break
+ cls = cls.__bases__[0]
+ self._interplevel_classes = {}
+ for cls, w_type in class2type.items():
+ if w_type is None:
+ continue
+ if w_type not in self._interplevel_classes:
+ self._interplevel_classes[w_type] = cls
+ else:
+ cls1 = self._interplevel_classes[w_type]
+ mro1 = list(getmro(cls1))
+ for base in getmro(cls):
+ if base in mro1:
+ break
+ if base in class2type and class2type[base] is not w_type:
+ if class2type.get(base) is None:
+ msg = ("cannot find a common interp-level base class"
+ " between %r and %r" % (cls1, cls))
+ else:
+ msg = ("%s is a base class of both %r and %r" % (
+ class2type[base], cls1, cls))
+ raise AssertionError("%r: %s" % (w_type, msg))
+ class2type[base] = w_type
+ self._interplevel_classes[w_type] = base
+
@specialize.memo()
def _get_interplevel_cls(self, w_type):
if not hasattr(self, "_interplevel_classes"):
diff --git a/pypy/objspace/std/proxyobject.py b/pypy/objspace/std/proxyobject.py
--- a/pypy/objspace/std/proxyobject.py
+++ b/pypy/objspace/std/proxyobject.py
@@ -16,6 +16,8 @@
def transparent_class(name, BaseCls):
class W_Transparent(BaseCls):
+ ignore_for_isinstance_cache = True
+
def __init__(self, space, w_type, w_controller):
self.w_type = w_type
self.w_controller = w_controller
diff --git a/pypy/objspace/std/rangeobject.py b/pypy/objspace/std/rangeobject.py
--- a/pypy/objspace/std/rangeobject.py
+++ b/pypy/objspace/std/rangeobject.py
@@ -5,7 +5,7 @@
from pypy.objspace.std.noneobject import W_NoneObject
from pypy.objspace.std.inttype import wrapint
from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
-from pypy.objspace.std.listobject import W_ListObject
+from pypy.objspace.std.listobject import W_AbstractListObject, W_ListObject
from pypy.objspace.std import listtype, iterobject, slicetype
from pypy.interpreter import gateway, baseobjspace
@@ -21,7 +21,7 @@
return (start - stop - step - 1)/-step
-class W_RangeListObject(W_Object):
+class W_RangeListObject(W_AbstractListObject):
typedef = listtype.list_typedef
def __init__(w_self, start, step, length):
diff --git a/pypy/objspace/std/ropeobject.py b/pypy/objspace/std/ropeobject.py
--- a/pypy/objspace/std/ropeobject.py
+++ b/pypy/objspace/std/ropeobject.py
@@ -6,7 +6,7 @@
from pypy.rlib.objectmodel import we_are_translated
from pypy.objspace.std.inttype import wrapint
from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
-from pypy.objspace.std import slicetype
+from pypy.objspace.std import stringobject, slicetype, iterobject
from pypy.objspace.std.listobject import W_ListObject
from pypy.objspace.std.noneobject import W_NoneObject
from pypy.objspace.std.tupleobject import W_TupleObject
@@ -19,7 +19,7 @@
str_format__String as str_format__Rope,
_upper, _lower, DEFAULT_NOOP_TABLE)
-class W_RopeObject(W_Object):
+class W_RopeObject(stringobject.W_AbstractStringObject):
from pypy.objspace.std.stringtype import str_typedef as typedef
_immutable_fields_ = ['_node']
@@ -59,7 +59,7 @@
registerimplementation(W_RopeObject)
-class W_RopeIterObject(W_Object):
+class W_RopeIterObject(iterobject.W_AbstractIterObject):
from pypy.objspace.std.itertype import iter_typedef as typedef
def __init__(w_self, w_rope, index=0):
diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py
--- a/pypy/objspace/std/ropeunicodeobject.py
+++ b/pypy/objspace/std/ropeunicodeobject.py
@@ -9,7 +9,7 @@
from pypy.objspace.std.noneobject import W_NoneObject
from pypy.rlib import rope
from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
-from pypy.objspace.std import slicetype
+from pypy.objspace.std import unicodeobject, slicetype, iterobject
from pypy.objspace.std.tupleobject import W_TupleObject
from pypy.rlib.rarithmetic import intmask, ovfcheck
from pypy.module.unicodedata import unicodedb
@@ -76,7 +76,7 @@
return encode_object(space, w_unistr, encoding, errors)
-class W_RopeUnicodeObject(W_Object):
+class W_RopeUnicodeObject(unicodeobject.W_AbstractUnicodeObject):
from pypy.objspace.std.unicodetype import unicode_typedef as typedef
_immutable_fields_ = ['_node']
@@ -117,7 +117,7 @@
return rope.LiteralUnicodeNode(space.unicode_w(w_str))
-class W_RopeUnicodeIterObject(W_Object):
+class W_RopeUnicodeIterObject(iterobject.W_AbstractIterObject):
from pypy.objspace.std.itertype import iter_typedef as typedef
def __init__(w_self, w_rope, index=0):
diff --git a/pypy/objspace/std/smallintobject.py b/pypy/objspace/std/smallintobject.py
--- a/pypy/objspace/std/smallintobject.py
+++ b/pypy/objspace/std/smallintobject.py
@@ -6,7 +6,7 @@
from pypy.objspace.std.model import registerimplementation, W_Object
from pypy.objspace.std.register_all import register_all
from pypy.objspace.std.noneobject import W_NoneObject
-from pypy.objspace.std.intobject import W_IntObject
+from pypy.objspace.std.intobject import W_AbstractIntObject, W_IntObject
from pypy.interpreter.error import OperationError
from pypy.rlib.objectmodel import UnboxedValue
from pypy.rlib.rbigint import rbigint
@@ -14,7 +14,7 @@
from pypy.tool.sourcetools import func_with_new_name
from pypy.objspace.std.inttype import wrapint
-class W_SmallIntObject(W_Object, UnboxedValue):
+class W_SmallIntObject(W_AbstractIntObject, UnboxedValue):
__slots__ = 'intval'
from pypy.objspace.std.inttype import int_typedef as typedef
diff --git a/pypy/objspace/std/smalllongobject.py b/pypy/objspace/std/smalllongobject.py
--- a/pypy/objspace/std/smalllongobject.py
+++ b/pypy/objspace/std/smalllongobject.py
@@ -9,7 +9,7 @@
from pypy.rlib.rarithmetic import r_longlong, r_int, r_uint
from pypy.rlib.rarithmetic import intmask, LONGLONG_BIT
from pypy.rlib.rbigint import rbigint
-from pypy.objspace.std.longobject import W_LongObject
+from pypy.objspace.std.longobject import W_AbstractLongObject, W_LongObject
from pypy.objspace.std.intobject import W_IntObject
from pypy.objspace.std.noneobject import W_NoneObject
from pypy.interpreter.error import OperationError
@@ -17,7 +17,7 @@
LONGLONG_MIN = r_longlong((-1) << (LONGLONG_BIT-1))
-class W_SmallLongObject(W_Object):
+class W_SmallLongObject(W_AbstractLongObject):
from pypy.objspace.std.longtype import long_typedef as typedef
_immutable_fields_ = ['longlong']
diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py
--- a/pypy/objspace/std/smalltupleobject.py
+++ b/pypy/objspace/std/smalltupleobject.py
@@ -9,9 +9,9 @@
from pypy.interpreter import gateway
from pypy.rlib.debug import make_sure_not_resized
from pypy.rlib.unroll import unrolling_iterable
-from pypy.objspace.std.tupleobject import W_TupleObject
+from pypy.objspace.std.tupleobject import W_AbstractTupleObject, W_TupleObject
-class W_SmallTupleObject(W_Object):
+class W_SmallTupleObject(W_AbstractTupleObject):
from pypy.objspace.std.tupletype import tuple_typedef as typedef
def tolist(self):
diff --git a/pypy/objspace/std/strbufobject.py b/pypy/objspace/std/strbufobject.py
--- a/pypy/objspace/std/strbufobject.py
+++ b/pypy/objspace/std/strbufobject.py
@@ -1,11 +1,12 @@
from pypy.objspace.std.model import registerimplementation, W_Object
from pypy.objspace.std.register_all import register_all
+from pypy.objspace.std.stringobject import W_AbstractStringObject
from pypy.objspace.std.stringobject import W_StringObject
from pypy.objspace.std.unicodeobject import delegate_String2Unicode
from pypy.rlib.rstring import StringBuilder
from pypy.interpreter.buffer import Buffer
-class W_StringBufferObject(W_Object):
+class W_StringBufferObject(W_AbstractStringObject):
from pypy.objspace.std.stringtype import str_typedef as typedef
w_str = None
diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -19,7 +19,10 @@
from pypy.objspace.std.formatting import mod_format
-class W_StringObject(W_Object):
+class W_AbstractStringObject(W_Object):
+ pass
+
+class W_StringObject(W_AbstractStringObject):
from pypy.objspace.std.stringtype import str_typedef as typedef
_immutable_fields_ = ['_value']
diff --git a/pypy/objspace/std/strjoinobject.py b/pypy/objspace/std/strjoinobject.py
--- a/pypy/objspace/std/strjoinobject.py
+++ b/pypy/objspace/std/strjoinobject.py
@@ -1,11 +1,12 @@
from pypy.objspace.std.model import registerimplementation, W_Object
from pypy.objspace.std.register_all import register_all
+from pypy.objspace.std.stringobject import W_AbstractStringObject
from pypy.objspace.std.stringobject import W_StringObject
from pypy.objspace.std.unicodeobject import delegate_String2Unicode
from pypy.objspace.std.stringtype import wrapstr
-class W_StringJoinObject(W_Object):
+class W_StringJoinObject(W_AbstractStringObject):
from pypy.objspace.std.stringtype import str_typedef as typedef
def __init__(w_self, joined_strs, until=-1):
diff --git a/pypy/objspace/std/strsliceobject.py b/pypy/objspace/std/strsliceobject.py
--- a/pypy/objspace/std/strsliceobject.py
+++ b/pypy/objspace/std/strsliceobject.py
@@ -1,6 +1,7 @@
from pypy.interpreter.error import OperationError
from pypy.objspace.std.model import registerimplementation, W_Object
from pypy.objspace.std.register_all import register_all
+from pypy.objspace.std.stringobject import W_AbstractStringObject
from pypy.objspace.std.stringobject import W_StringObject
from pypy.objspace.std.unicodeobject import delegate_String2Unicode
from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
@@ -12,7 +13,7 @@
stringendswith, stringstartswith
-class W_StringSliceObject(W_Object):
+class W_StringSliceObject(W_AbstractStringObject):
from pypy.objspace.std.stringtype import str_typedef as typedef
def __init__(w_self, str, start, stop):
diff --git a/pypy/objspace/std/test/test_stdobjspace.py b/pypy/objspace/std/test/test_stdobjspace.py
--- a/pypy/objspace/std/test/test_stdobjspace.py
+++ b/pypy/objspace/std/test/test_stdobjspace.py
@@ -50,6 +50,8 @@
def test_fastpath_isinstance(self):
from pypy.objspace.std.stringobject import W_StringObject
from pypy.objspace.std.intobject import W_IntObject
+ from pypy.objspace.std.iterobject import W_AbstractSeqIterObject
+ from pypy.objspace.std.iterobject import W_SeqIterObject
space = self.space
assert space._get_interplevel_cls(space.w_str) is W_StringObject
@@ -62,9 +64,13 @@
assert space.isinstance_w(X(), space.w_str)
+ w_sequenceiterator = space.gettypefor(W_SeqIterObject)
+ cls = space._get_interplevel_cls(w_sequenceiterator)
+ assert cls is W_AbstractSeqIterObject
+
def test_withstrbuf_fastpath_isinstance(self):
- from pypy.objspace.std.stringobject import W_StringObject
+ from pypy.objspace.std.stringobject import W_AbstractStringObject
- space = gettestobjspace(withstrbuf=True)
- assert space._get_interplevel_cls(space.w_str) is W_StringObject
-
+ space = gettestobjspace(withstrbuf=True)
+ cls = space._get_interplevel_cls(space.w_str)
+ assert cls is W_AbstractStringObject
diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py
--- a/pypy/objspace/std/tupleobject.py
+++ b/pypy/objspace/std/tupleobject.py
@@ -9,7 +9,10 @@
from pypy.interpreter import gateway
from pypy.rlib.debug import make_sure_not_resized
-class W_TupleObject(W_Object):
+class W_AbstractTupleObject(W_Object):
+ pass
+
+class W_TupleObject(W_AbstractTupleObject):
from pypy.objspace.std.tupletype import tuple_typedef as typedef
_immutable_fields_ = ['wrappeditems[*]']
diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py
--- a/pypy/objspace/std/unicodeobject.py
+++ b/pypy/objspace/std/unicodeobject.py
@@ -19,7 +19,10 @@
from pypy.objspace.std.formatting import mod_format
from pypy.objspace.std.stringtype import stringstartswith, stringendswith
-class W_UnicodeObject(W_Object):
+class W_AbstractUnicodeObject(W_Object):
+ pass
+
+class W_UnicodeObject(W_AbstractUnicodeObject):
from pypy.objspace.std.unicodetype import unicode_typedef as typedef
_immutable_fields_ = ['_value']
More information about the pypy-commit
mailing list