[pypy-svn] r77828 - in pypy/trunk/pypy: config doc/config interpreter module/__builtin__ module/__builtin__/test module/_weakref module/cpyext module/pypyjit/test objspace/std objspace/std/test rlib rlib/test

arigo at codespeak.net arigo at codespeak.net
Tue Oct 12 14:38:12 CEST 2010


Author: arigo
Date: Tue Oct 12 14:38:09 2010
New Revision: 77828

Added:
   pypy/trunk/pypy/doc/config/objspace.std.withmapdict.txt
      - copied unchanged from r77827, pypy/branch/better-map-instances/pypy/doc/config/objspace.std.withmapdict.txt
   pypy/trunk/pypy/objspace/std/mapdict.py
      - copied unchanged from r77827, pypy/branch/better-map-instances/pypy/objspace/std/mapdict.py
   pypy/trunk/pypy/objspace/std/test/test_mapdict.py
      - copied unchanged from r77827, pypy/branch/better-map-instances/pypy/objspace/std/test/test_mapdict.py
   pypy/trunk/pypy/rlib/rerased.py
      - copied unchanged from r77827, pypy/branch/better-map-instances/pypy/rlib/rerased.py
   pypy/trunk/pypy/rlib/test/test_rerased.py
      - copied unchanged from r77827, pypy/branch/better-map-instances/pypy/rlib/test/test_rerased.py
Modified:
   pypy/trunk/pypy/config/pypyoption.py
   pypy/trunk/pypy/interpreter/baseobjspace.py
   pypy/trunk/pypy/interpreter/pycode.py
   pypy/trunk/pypy/interpreter/pyopcode.py
   pypy/trunk/pypy/interpreter/typedef.py
   pypy/trunk/pypy/module/__builtin__/interp_classobj.py
   pypy/trunk/pypy/module/__builtin__/test/test_classobj.py
   pypy/trunk/pypy/module/_weakref/interp__weakref.py
   pypy/trunk/pypy/module/cpyext/classobject.py
   pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py
   pypy/trunk/pypy/objspace/std/celldict.py
   pypy/trunk/pypy/objspace/std/dictmultiobject.py
   pypy/trunk/pypy/objspace/std/objspace.py
   pypy/trunk/pypy/objspace/std/sharingdict.py
   pypy/trunk/pypy/objspace/std/test/test_dictmultiobject.py
   pypy/trunk/pypy/objspace/std/test/test_shadowtracking.py
   pypy/trunk/pypy/objspace/std/typeobject.py
Log:
Merge branch/better-map-instances.  Not enabled by default for the JIT
yet; more clean-ups needed first.  But it is enabled by default for
-Omem translations, experimentally.


Modified: pypy/trunk/pypy/config/pypyoption.py
==============================================================================
--- pypy/trunk/pypy/config/pypyoption.py	(original)
+++ pypy/trunk/pypy/config/pypyoption.py	Tue Oct 12 14:38:09 2010
@@ -242,6 +242,16 @@
                    default=False,
                    requires=[("objspace.std.withshadowtracking", False)]),
 
+        BoolOption("withmapdict",
+                   "make instances really small but slow without the JIT",
+                   default=False,
+                   requires=[("objspace.std.withshadowtracking", False),
+                             ("objspace.std.withinlineddict", False),
+                             ("objspace.std.withsharingdict", False),
+                             ("objspace.std.getattributeshortcut", True),
+                             ("objspace.std.withtypeversion", True),
+                       ]),
+
         BoolOption("withrangelist",
                    "enable special range list implementation that does not "
                    "actually create the full list until the resulting "
@@ -347,7 +357,7 @@
         config.objspace.std.suggest(withprebuiltint=True)
         config.objspace.std.suggest(withrangelist=True)
         config.objspace.std.suggest(withprebuiltchar=True)
-        config.objspace.std.suggest(withinlineddict=True)
+        config.objspace.std.suggest(withmapdict=True)
         config.objspace.std.suggest(withstrslice=True)
         config.objspace.std.suggest(withstrjoin=True)
         # xxx other options? ropes maybe?
@@ -363,6 +373,7 @@
     # extra optimizations with the JIT
     if level == 'jit':
         config.objspace.std.suggest(withcelldict=True)
+        #config.objspace.std.suggest(withmapdict=True)
 
 
 def enable_allworkingmodules(config):

Modified: pypy/trunk/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/trunk/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/trunk/pypy/interpreter/baseobjspace.py	Tue Oct 12 14:38:09 2010
@@ -168,6 +168,20 @@
     def _call_builtin_destructor(self):
         pass     # method overridden in typedef.py
 
+    # hooks that the mapdict implementations needs:
+    def _get_mapdict_map(self):
+        return None
+    def _set_mapdict_map(self, map):
+        raise NotImplementedError
+    def _mapdict_read_storage(self, index):
+        raise NotImplementedError
+    def _mapdict_write_storage(self, index, value):
+        raise NotImplementedError
+    def _mapdict_storage_length(self):
+        raise NotImplementedError
+    def _set_mapdict_storage_and_map(self, storage, map):
+        raise NotImplementedError
+
 
 class Wrappable(W_Root):
     """A subclass of Wrappable is an internal, interpreter-level class

Modified: pypy/trunk/pypy/interpreter/pycode.py
==============================================================================
--- pypy/trunk/pypy/interpreter/pycode.py	(original)
+++ pypy/trunk/pypy/interpreter/pycode.py	Tue Oct 12 14:38:09 2010
@@ -117,6 +117,10 @@
 
         self._compute_flatcall()
 
+        if self.space.config.objspace.std.withmapdict:
+            from pypy.objspace.std.mapdict import init_mapdict_cache
+            init_mapdict_cache(self)
+
     def _freeze_(self):
         if (self.magic == cpython_magic and
             '__pypy__' not in sys.builtin_module_names):

Modified: pypy/trunk/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/trunk/pypy/interpreter/pyopcode.py	(original)
+++ pypy/trunk/pypy/interpreter/pyopcode.py	Tue Oct 12 14:38:09 2010
@@ -710,9 +710,14 @@
 
     def LOAD_ATTR(self, nameindex, next_instr):
         "obj.attributename"
-        w_attributename = self.getname_w(nameindex)
         w_obj = self.popvalue()
-        w_value = self.space.getattr(w_obj, w_attributename)
+        if (self.space.config.objspace.std.withmapdict
+            and not jit.we_are_jitted()):
+            from pypy.objspace.std.mapdict import LOAD_ATTR_caching
+            w_value = LOAD_ATTR_caching(self.getcode(), w_obj, nameindex)
+        else:
+            w_attributename = self.getname_w(nameindex)
+            w_value = self.space.getattr(w_obj, w_attributename)
         self.pushvalue(w_value)
     LOAD_ATTR._always_inline_ = True
 

Modified: pypy/trunk/pypy/interpreter/typedef.py
==============================================================================
--- pypy/trunk/pypy/interpreter/typedef.py	(original)
+++ pypy/trunk/pypy/interpreter/typedef.py	Tue Oct 12 14:38:09 2010
@@ -133,6 +133,13 @@
     typedef = cls.typedef
     if wants_dict and typedef.hasdict:
         wants_dict = False
+    if config.objspace.std.withmapdict and not typedef.hasdict:
+        # mapdict only works if the type does not already have a dict
+        if wants_del:
+            parentcls = get_unique_interplevel_subclass(config, cls, True, True,
+                                                        False, True)
+            return _usersubclswithfeature(config, parentcls, "del")
+        return _usersubclswithfeature(config, cls, "user", "dict", "weakref", "slots")
     # Forest of if's - see the comment above.
     if wants_del:
         if wants_dict:
@@ -186,10 +193,20 @@
 
     def add(Proto):
         for key, value in Proto.__dict__.items():
-            if not key.startswith('__') or key == '__del__':
+            if (not key.startswith('__') and not key.startswith('_mixin_') 
+                    or key == '__del__'):
+                if hasattr(value, "func_name"):
+                    value = func_with_new_name(value, value.func_name)
                 body[key] = value
 
+    if (config.objspace.std.withmapdict and "dict" in features):
+        from pypy.objspace.std.mapdict import BaseMapdictObject, ObjectMixin
+        add(BaseMapdictObject)
+        add(ObjectMixin)
+        features = ()
+
     if "user" in features:     # generic feature needed by all subcls
+
         class Proto(object):
             user_overridden_class = True
 
@@ -255,6 +272,9 @@
             wantdict = False
 
     if wantdict:
+        base_user_setup = supercls.user_setup.im_func
+        if "user_setup" in body:
+            base_user_setup = body["user_setup"]
         class Proto(object):
             def getdict(self):
                 return self.w__dict__
@@ -263,11 +283,9 @@
                 self.w__dict__ = check_new_dictionary(space, w_dict)
             
             def user_setup(self, space, w_subtype):
-                self.space = space
-                self.w__class__ = w_subtype
                 self.w__dict__ = space.newdict(
                     instance=True, classofinstance=w_subtype)
-                self.user_setup_slots(w_subtype.nslots)
+                base_user_setup(self, space, w_subtype)
 
             def setclass(self, space, w_subtype):
                 # only used by descr_set___class__

Modified: pypy/trunk/pypy/module/__builtin__/interp_classobj.py
==============================================================================
--- pypy/trunk/pypy/module/__builtin__/interp_classobj.py	(original)
+++ pypy/trunk/pypy/module/__builtin__/interp_classobj.py	Tue Oct 12 14:38:09 2010
@@ -2,9 +2,11 @@
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.gateway import ObjSpace, W_Root, NoneNotWrapped, applevel
 from pypy.interpreter.gateway import interp2app, ObjSpace
-from pypy.interpreter.typedef import TypeDef, make_weakref_descr
+from pypy.interpreter.typedef import TypeDef
 from pypy.interpreter.argument import Arguments
 from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.typedef import GetSetProperty, descr_get_dict
+from pypy.interpreter.typedef import descr_set_dict
 from pypy.rlib.rarithmetic import r_uint, intmask
 from pypy.rlib.objectmodel import compute_identity_hash
 from pypy.rlib.debug import make_sure_not_resized
@@ -57,6 +59,14 @@
         self.bases_w = bases
         self.w_dict = w_dict
  
+    def instantiate(self, space):
+        cache = space.fromcache(Cache)
+        if self.lookup(space, '__del__') is not None:
+            w_inst = cache.cls_with_del(space, self)
+        else:
+            w_inst = cache.cls_without_del(space, self)
+        return w_inst
+
     def getdict(self):
         return self.w_dict
 
@@ -100,15 +110,15 @@
         return False
 
     @jit.unroll_safe
-    def lookup(self, space, w_attr):
+    def lookup(self, space, attr):
         # returns w_value or interplevel None
-        w_result = space.finditem(self.w_dict, w_attr)
+        w_result = space.finditem_str(self.w_dict, attr)
         if w_result is not None:
             return w_result
         for base in self.bases_w:
             # XXX fix annotation of bases_w to be a list of W_ClassObjects
             assert isinstance(base, W_ClassObject)
-            w_result = base.lookup(space, w_attr)
+            w_result = base.lookup(space, attr)
             if w_result is not None:
                 return w_result
         return None
@@ -122,7 +132,7 @@
                 return space.wrap(self.name)
             elif name == "__bases__":
                 return space.newtuple(self.bases_w)
-        w_value = self.lookup(space, w_attr)
+        w_value = self.lookup(space, name)
         if w_value is None:
             raise operationerrfmt(
                 space.w_AttributeError,
@@ -147,7 +157,7 @@
                 self.setbases(space, w_value)
                 return
             elif name == "__del__":
-                if self.lookup(space, w_attr) is None:
+                if self.lookup(space, name) is None:
                     msg = ("a __del__ method added to an existing class "
                            "will not be called")
                     space.warn(msg, space.w_RuntimeWarning)
@@ -195,13 +205,20 @@
         # NOT_RPYTHON
         return '<W_ClassObject(%s)>' % self.name
 
+class Cache:
+    def __init__(self, space):
+        from pypy.interpreter.typedef import _usersubclswithfeature
+        # evil
+        self.cls_without_del = _usersubclswithfeature(
+                space.config, W_InstanceObject, "dict", "weakref")
+        self.cls_with_del = _usersubclswithfeature(
+                space.config, self.cls_without_del, "del")
+
+
 def class_descr_call(space, w_self, __args__):
     self = space.interp_w(W_ClassObject, w_self)
-    if self.lookup(space, space.wrap('__del__')) is not None:
-        w_inst = W_InstanceObjectWithDel(space, self)
-    else:
-        w_inst = W_InstanceObject(space, self)
-    w_init = w_inst.getattr_from_class(space, space.wrap('__init__'))
+    w_inst = self.instantiate(space)
+    w_init = w_inst.getattr_from_class(space, '__init__')
     if w_init is not None:
         w_result = space.call_args(w_init, __args__)
         if not space.is_w(w_result, space.w_None):
@@ -234,7 +251,7 @@
 
 def make_unary_instance_method(name):
     def unaryop(self, space):
-        w_meth = self.getattr(space, space.wrap(name), True)
+        w_meth = self.getattr(space, name, True)
         return space.call_function(w_meth)
     unaryop.func_name = name
     return unaryop
@@ -242,7 +259,7 @@
 def make_binary_returning_notimplemented_instance_method(name):
     def binaryop(self, space, w_other):
         try:
-            w_meth = self.getattr(space, space.wrap(name), False)
+            w_meth = self.getattr(space, name, False)
         except OperationError, e:
             if e.match(space, space.w_AttributeError):
                 return space.w_NotImplemented
@@ -267,7 +284,7 @@
             w_a = self
             w_b = w_other
         if w_a is self:
-            w_meth = self.getattr(space, space.wrap(specialname), False)
+            w_meth = self.getattr(space, specialname, False)
             if w_meth is None:
                 return space.w_NotImplemented
             return space.call_function(w_meth, w_b)
@@ -278,7 +295,7 @@
     def rbinaryop(self, space, w_other):
         w_a, w_b = _coerce_helper(space, self, w_other)
         if w_a is None or w_a is self:
-            w_meth = self.getattr(space, space.wrap(rspecialname), False)
+            w_meth = self.getattr(space, rspecialname, False)
             if w_meth is None:
                 return space.w_NotImplemented
             return space.call_function(w_meth, w_other)
@@ -302,46 +319,34 @@
         raise OperationError(
             space.w_TypeError,
             space.wrap("instance() first arg must be class"))
-    if space.is_w(w_dict, space.w_None):
-        w_dict = None
-    elif not space.is_true(space.isinstance(w_dict, space.w_dict)):
-        raise OperationError(
-            space.w_TypeError,
-            space.wrap("instance() second arg must be dictionary or None"))
-    return W_InstanceObject(space, w_class, w_dict)
+    w_result = w_class.instantiate(space)
+    if not space.is_w(w_dict, space.w_None):
+        w_result.setdict(space, w_dict)
+    return w_result
 
 class W_InstanceObject(Wrappable):
-    def __init__(self, space, w_class, w_dict=None):
-        if w_dict is None:
-            w_dict = space.newdict(instance=True)
+    def __init__(self, space, w_class):
+        # note that user_setup is overridden by the typedef.py machinery
+        self.user_setup(space, space.gettypeobject(self.typedef))
         assert isinstance(w_class, W_ClassObject)
         self.w_class = w_class
-        self.w_dict = w_dict
-        self.space = space
-
-    def getdict(self):
-        return self.w_dict
 
-    def setdict(self, space, w_dict):
-        if (w_dict is None or
-            not space.is_true(space.isinstance(w_dict, space.w_dict))):
-            raise OperationError(
-                space.w_TypeError,
-                space.wrap("__dict__ must be a dictionary object"))
-        self.w_dict = w_dict
+    def user_setup(self, space, w_subtype):
+        self.space = space
 
-    def setclass(self, space, w_class):
+    def set_oldstyle_class(self, space, w_class):
         if w_class is None or not isinstance(w_class, W_ClassObject):
             raise OperationError(
                 space.w_TypeError,
                 space.wrap("__class__ must be set to a class"))
         self.w_class = w_class
 
-    def getattr_from_class(self, space, w_name):
+    def getattr_from_class(self, space, name):
         # Look up w_name in the class dict, and call its __get__.
         # This method ignores the instance dict and the __getattr__.
         # Returns None if not found.
-        w_value = self.w_class.lookup(space, w_name)
+        assert isinstance(name, str)
+        w_value = self.w_class.lookup(space, name)
         if w_value is None:
             return None
         w_descr_get = space.lookup(w_value, '__get__')
@@ -349,19 +354,20 @@
             return w_value
         return space.call_function(w_descr_get, w_value, self, self.w_class)
 
-    def getattr(self, space, w_name, exc=True):
+    def getattr(self, space, name, exc=True):
         # Normal getattr rules: look up w_name in the instance dict,
         # in the class dict, and then via a call to __getatttr__.
-        w_result = space.finditem(self.w_dict, w_name)
+        assert isinstance(name, str)
+        w_result = self.getdictvalue(space, name)
         if w_result is not None:
             return w_result
-        w_result = self.getattr_from_class(space, w_name)
+        w_result = self.getattr_from_class(space, name)
         if w_result is not None:
             return w_result
-        w_meth = self.getattr_from_class(space, space.wrap('__getattr__'))
+        w_meth = self.getattr_from_class(space, '__getattr__')
         if w_meth is not None:
             try:
-                return space.call_function(w_meth, w_name)
+                return space.call_function(w_meth, space.wrap(name))
             except OperationError, e:
                 if not exc and e.match(space, space.w_AttributeError):
                     return None     # eat the AttributeError
@@ -371,7 +377,7 @@
             raise operationerrfmt(
                 space.w_AttributeError,
                 "%s instance has no attribute '%s'",
-                self.w_class.name, space.str_w(w_name))
+                self.w_class.name, name)
         else:
             return None
 
@@ -379,44 +385,46 @@
         name = space.str_w(w_attr)
         if len(name) >= 8 and name[0] == '_':
             if name == "__dict__":
-                return self.w_dict
+                return self.getdict()
             elif name == "__class__":
                 return self.w_class
-        return self.getattr(space, w_attr)
+        return self.getattr(space, name)
 
     def descr_setattr(self, space, w_name, w_value):
         name = unwrap_attr(space, w_name)
-        w_meth = self.getattr_from_class(space, space.wrap('__setattr__'))
+        w_meth = self.getattr_from_class(space, '__setattr__')
         if name and name[0] == "_":
             if name == '__dict__':
                 self.setdict(space, w_value)
                 return
             if name == '__class__':
-                self.setclass(space, w_value)
+                self.set_oldstyle_class(space, w_value)
                 return
             if name == '__del__' and w_meth is None:
-                if (not isinstance(self, W_InstanceObjectWithDel)
-                    and space.finditem(self.w_dict, w_name) is None):
+                cache = space.fromcache(Cache)
+                if (not isinstance(self, cache.cls_with_del)
+                    and self.getdictvalue(space, '__del__') is None):
                     msg = ("a __del__ method added to an instance "
                            "with no __del__ in the class will not be called")
                     space.warn(msg, space.w_RuntimeWarning)
         if w_meth is not None:
             space.call_function(w_meth, w_name, w_value)
         else:
-            self.setdictvalue(space, name, w_value)
+            # bit obscure: appease normalization
+            self.setdictvalue(space, name, w_value, True)
 
     def descr_delattr(self, space, w_name):
         name = unwrap_attr(space, w_name)
         if name and name[0] == "_":
             if name == '__dict__':
                 # use setdict to raise the error
-                self.setdict(space, None)
+                self.setdict(space, space.w_None)
                 return
             elif name == '__class__':
-                # use setclass to raise the error
-                self.setclass(space, None)
+                # use set_oldstyle_class to raise the error
+                self.set_oldstyle_class(space, None)
                 return
-        w_meth = self.getattr_from_class(space, space.wrap('__delattr__'))
+        w_meth = self.getattr_from_class(space, '__delattr__')
         if w_meth is not None:
             space.call_function(w_meth, w_name)
         else:
@@ -427,7 +435,7 @@
                     self.w_class.name, name)
 
     def descr_repr(self, space):
-        w_meth = self.getattr(space, space.wrap('__repr__'), False)
+        w_meth = self.getattr(space, '__repr__', False)
         if w_meth is None:
             w_class = self.w_class
             mod = w_class.get_module_string(space)
@@ -435,19 +443,19 @@
         return space.call_function(w_meth)
 
     def descr_str(self, space):
-        w_meth = self.getattr(space, space.wrap('__str__'), False)
+        w_meth = self.getattr(space, '__str__', False)
         if w_meth is None:
             return self.descr_repr(space)
         return space.call_function(w_meth)
 
     def descr_unicode(self, space):
-        w_meth = self.getattr(space, space.wrap('__unicode__'), False)
+        w_meth = self.getattr(space, '__unicode__', False)
         if w_meth is None:
             return self.descr_str(space)
         return space.call_function(w_meth)
 
     def descr_len(self, space):
-        w_meth = self.getattr(space, space.wrap('__len__'))
+        w_meth = self.getattr(space, '__len__')
         w_result = space.call_function(w_meth)
         if space.is_true(space.isinstance(w_result, space.w_int)):
             if space.is_true(space.lt(w_result, space.wrap(0))):
@@ -460,22 +468,22 @@
             space.wrap("__len__() should return an int"))
 
     def descr_getitem(self, space, w_key):
-        w_meth = self.getattr(space, space.wrap('__getitem__'))
+        w_meth = self.getattr(space, '__getitem__')
         return space.call_function(w_meth, w_key)
 
     def descr_setitem(self, space, w_key, w_value):
-        w_meth = self.getattr(space, space.wrap('__setitem__'))
+        w_meth = self.getattr(space, '__setitem__')
         space.call_function(w_meth, w_key, w_value)
 
     def descr_delitem(self, space, w_key):
-        w_meth = self.getattr(space, space.wrap('__delitem__'))
+        w_meth = self.getattr(space, '__delitem__')
         space.call_function(w_meth, w_key)
 
     def descr_iter(self, space):
-        w_meth = self.getattr(space, space.wrap('__iter__'), False)
+        w_meth = self.getattr(space, '__iter__', False)
         if w_meth is not None:
             return space.call_function(w_meth)
-        w_meth = self.getattr(space, space.wrap('__getitem__'), False)
+        w_meth = self.getattr(space, '__getitem__', False)
         if w_meth is None:
             raise OperationError(
                 space.w_TypeError,
@@ -485,14 +493,14 @@
     # don't see the point
 
     def descr_getslice(self, space, w_i, w_j):
-        w_meth = self.getattr(space, space.wrap('__getslice__'), False)
+        w_meth = self.getattr(space, '__getslice__', False)
         if w_meth is not None:
             return space.call_function(w_meth, w_i, w_j)
         else:
             return space.getitem(self, space.newslice(w_i, w_j, space.w_None))
 
     def descr_setslice(self, space, w_i, w_j, w_sequence):
-        w_meth = self.getattr(space, space.wrap('__setslice__'), False)
+        w_meth = self.getattr(space, '__setslice__', False)
         if w_meth is not None:
             space.call_function(w_meth, w_i, w_j, w_sequence)
         else:
@@ -500,20 +508,20 @@
                           w_sequence)
 
     def descr_delslice(self, space, w_i, w_j):
-        w_meth = self.getattr(space, space.wrap('__delslice__'), False)
+        w_meth = self.getattr(space, '__delslice__', False)
         if w_meth is not None:
             space.call_function(w_meth, w_i, w_j)
         else:
             return space.delitem(self, space.newslice(w_i, w_j, space.w_None))
 
     def descr_call(self, space, __args__):
-        w_meth = self.getattr(space, space.wrap('__call__'))
+        w_meth = self.getattr(space, '__call__')
         return space.call_args(w_meth, __args__)
 
     def descr_nonzero(self, space):
-        w_func = self.getattr(space, space.wrap('__nonzero__'), False)
+        w_func = self.getattr(space, '__nonzero__', False)
         if w_func is None:
-            w_func = self.getattr(space, space.wrap('__len__'), False)
+            w_func = self.getattr(space, '__len__', False)
             if w_func is None:
                 return space.w_True
         w_result = space.call_function(w_func)
@@ -537,7 +545,7 @@
                 not isinstance(w_b, W_InstanceObject)):
                 return space.cmp(w_a, w_b)
         if isinstance(w_a, W_InstanceObject):
-            w_func = w_a.getattr(space, space.wrap('__cmp__'), False)
+            w_func = w_a.getattr(space, '__cmp__', False)
             if w_func is not None:
                 w_res = space.call_function(w_func, w_b)
                 if space.is_w(w_res, space.w_NotImplemented):
@@ -556,7 +564,7 @@
                     return space.wrap(-1)
                 return space.wrap(0)
         if isinstance(w_b, W_InstanceObject):
-            w_func = w_b.getattr(space, space.wrap('__cmp__'), False)
+            w_func = w_b.getattr(space, '__cmp__', False)
             if w_func is not None:
                 w_res = space.call_function(w_func, w_a)
                 if space.is_w(w_res, space.w_NotImplemented):
@@ -577,10 +585,10 @@
         return space.w_NotImplemented
 
     def descr_hash(self, space):
-        w_func = self.getattr(space, space.wrap('__hash__'), False)
+        w_func = self.getattr(space, '__hash__', False)
         if w_func is None:
-            w_eq =  self.getattr(space, space.wrap('__eq__'), False)
-            w_cmp =  self.getattr(space, space.wrap('__cmp__'), False)
+            w_eq =  self.getattr(space, '__eq__', False)
+            w_cmp =  self.getattr(space, '__cmp__', False)
             if w_eq is not None or w_cmp is not None:
                 raise OperationError(space.w_TypeError,
                                      space.wrap("unhashable instance"))
@@ -595,7 +603,7 @@
         return w_ret
 
     def descr_index(self, space):
-        w_func = self.getattr(space, space.wrap('__index__'), False)
+        w_func = self.getattr(space, '__index__', False)
         if w_func is not None:
             return space.call_function(w_func)
         raise OperationError(
@@ -603,7 +611,7 @@
             space.wrap("object cannot be interpreted as an index"))
 
     def descr_contains(self, space, w_obj):
-        w_func = self.getattr(space, space.wrap('__contains__'), False)
+        w_func = self.getattr(space, '__contains__', False)
         if w_func is not None:
             return space.wrap(space.is_true(space.call_function(w_func, w_obj)))
         # now do it ourselves
@@ -626,7 +634,7 @@
                 w_a = self
                 w_b = w_other
             if w_a is self:
-                w_func = self.getattr(space, space.wrap('__pow__'), False)
+                w_func = self.getattr(space, '__pow__', False)
                 if w_func is not None:
                     return space.call_function(w_func, w_other)
                 return space.w_NotImplemented
@@ -634,7 +642,7 @@
                 return space.pow(w_a, w_b, space.w_None)
         else:
             # CPython also doesn't try coercion in this case
-            w_func = self.getattr(space, space.wrap('__pow__'), False)
+            w_func = self.getattr(space, '__pow__', False)
             if w_func is not None:
                 return space.call_function(w_func, w_other, w_modulo)
             return space.w_NotImplemented
@@ -646,7 +654,7 @@
                 w_a = self
                 w_b = w_other
             if w_a is self:
-                w_func = self.getattr(space, space.wrap('__rpow__'), False)
+                w_func = self.getattr(space, '__rpow__', False)
                 if w_func is not None:
                     return space.call_function(w_func, w_other)
                 return space.w_NotImplemented
@@ -654,13 +662,13 @@
                 return space.pow(w_b, w_a, space.w_None)
         else:
             # CPython also doesn't try coercion in this case
-            w_func = self.getattr(space, space.wrap('__rpow__'), False)
+            w_func = self.getattr(space, '__rpow__', False)
             if w_func is not None:
                 return space.call_function(w_func, w_other, w_modulo)
             return space.w_NotImplemented
 
     def descr_next(self, space):
-        w_func = self.getattr(space, space.wrap('next'), False)
+        w_func = self.getattr(space, 'next', False)
         if w_func is None:
             raise OperationError(space.w_TypeError,
                                  space.wrap("instance has no next() method"))
@@ -669,10 +677,9 @@
     def descr_del(self, space):
         # Note that this is called from executioncontext.UserDelAction
         # via the space.userdel() method.
-        w_name = space.wrap('__del__')
-        w_func = space.finditem(self.w_dict, w_name)
+        w_func = self.getdictvalue(space, '__del__')
         if w_func is None:
-            w_func = self.getattr_from_class(space, w_name)
+            w_func = self.getattr_from_class(space, '__del__')
         if w_func is not None:
             space.call_function(w_func)
 
@@ -717,6 +724,14 @@
         rmeth,
         unwrap_spec=["self", ObjSpace, W_Root])
 
+
+def descr_del_dict(space, w_inst):
+    # use setdict to raise the error
+    w_inst.setdict(space, space.w_None)
+
+dict_descr = GetSetProperty(descr_get_dict, descr_set_dict, descr_del_dict)
+dict_descr.name = '__dict__'
+
 W_InstanceObject.typedef = TypeDef("instance",
     __new__ = interp2app(descr_instance_new),
     __getattribute__ = interp2app(W_InstanceObject.descr_getattribute,
@@ -766,12 +781,9 @@
                          unwrap_spec=['self', ObjSpace, W_Root, W_Root]),
     next = interp2app(W_InstanceObject.descr_next,
                       unwrap_spec=['self', ObjSpace]),
-    __weakref__ = make_weakref_descr(W_InstanceObject),
     __del__ = interp2app(W_InstanceObject.descr_del,
                          unwrap_spec=['self', ObjSpace]),
+    __dict__ = dict_descr,
     **rawdict
 )
-
-class W_InstanceObjectWithDel(W_InstanceObject):
-    def __del__(self):
-        self._enqueue_for_destruction(self.space)
+W_InstanceObject.typedef.acceptable_as_base_class = False

Modified: pypy/trunk/pypy/module/__builtin__/test/test_classobj.py
==============================================================================
--- pypy/trunk/pypy/module/__builtin__/test/test_classobj.py	(original)
+++ pypy/trunk/pypy/module/__builtin__/test/test_classobj.py	Tue Oct 12 14:38:09 2010
@@ -928,6 +928,31 @@
         assert x is b
         assert y == 5
 
+    def test_cant_subclass_instance(self):
+        class A:
+            pass
+        try:
+            class B(type(A())):
+                pass
+        except TypeError:
+            pass
+        else:
+            assert 0, "should have raised"
+
+    def test_dict_descriptor(self):
+        import sys
+        if not hasattr(sys, 'pypy_objspaceclass'):
+            skip("on CPython old-style instances don't have a __dict__ descriptor")
+        class A:
+            pass
+        a = A()
+        a.x = 1
+        descr = type(a).__dict__['__dict__']
+        assert descr.__get__(a) == {'x': 1}
+        descr.__set__(a, {'x': 2})
+        assert a.x == 2
+        raises(TypeError, descr.__delete__, a)
+
 
 class AppTestOldStyleSharing(AppTestOldstyle):
     def setup_class(cls):
@@ -966,3 +991,22 @@
             a = 1
             b = 2
         assert self.is_strdict(A)
+
+class AppTestOldStyleMapDict(AppTestOldstyle):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withmapdict": True})
+        if option.runappdirect:
+            py.test.skip("can only be run on py.py")
+        def has_mapdict(space, w_inst):
+            return space.wrap(w_inst._get_mapdict_map() is not None)
+        cls.w_has_mapdict = cls.space.wrap(gateway.interp2app(has_mapdict))
+
+
+    def test_has_mapdict(self):
+        class A:
+            def __init__(self):
+                self.x = 42
+        a = A()
+        assert a.x == 42
+        assert self.has_mapdict(a)
+

Modified: pypy/trunk/pypy/module/_weakref/interp__weakref.py
==============================================================================
--- pypy/trunk/pypy/module/_weakref/interp__weakref.py	(original)
+++ pypy/trunk/pypy/module/_weakref/interp__weakref.py	Tue Oct 12 14:38:09 2010
@@ -7,7 +7,7 @@
 import weakref
 
 
-class WeakrefLifeline(object):
+class WeakrefLifeline(W_Root):
     def __init__(self, space):
         self.space = space       # this is here for W_Root.clear_all_weakrefs()
         self.refs_weak = []

Modified: pypy/trunk/pypy/module/cpyext/classobject.py
==============================================================================
--- pypy/trunk/pypy/module/cpyext/classobject.py	(original)
+++ pypy/trunk/pypy/module/cpyext/classobject.py	Tue Oct 12 14:38:09 2010
@@ -15,16 +15,20 @@
     class is the class of new object.  The dict parameter will be used as the
     object's __dict__; if NULL, a new dictionary will be created for the
     instance."""
-    if not PyClass_Check(space, w_class):
+    if not isinstance(w_class, W_ClassObject):
         return PyErr_BadInternalCall(space)
-    return W_InstanceObject(space, w_class, w_dict)
+    w_result = w_class.instantiate(space)
+    if w_dict is not None:
+        w_result.setdict(space, w_dict)
+    return w_result
 
 @cpython_api([PyObject, PyObject], PyObject, error=CANNOT_FAIL)
 def _PyInstance_Lookup(space, w_instance, w_name):
+    name = space.str_w(w_name)
     assert isinstance(w_instance, W_InstanceObject)
-    w_result = space.finditem(w_instance.w_dict, w_name)
+    w_result = w_instance.getdictvalue(space, name)
     if w_result is not None:
         return w_result
-    return w_instance.w_class.lookup(space, w_name)
+    return w_instance.w_class.lookup(space, name)
 
 

Modified: pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py
==============================================================================
--- pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py	(original)
+++ pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py	Tue Oct 12 14:38:09 2010
@@ -272,7 +272,7 @@
         assert len(ops) == 2
         assert not ops[0].get_opnames("call")
         assert not ops[0].get_opnames("new")
-        assert len(ops[0].get_opnames("guard")) <= 7
+        assert len(ops[0].get_opnames("guard")) <= 2
         assert not ops[1] # second LOOKUP_METHOD folded away
 
         ops = self.get_by_bytecode("CALL_METHOD")
@@ -283,7 +283,7 @@
             else:
                 assert not bytecode.get_opnames("call")
             assert not bytecode.get_opnames("new")
-            assert len(bytecode.get_opnames("guard")) <= 9
+            assert len(bytecode.get_opnames("guard")) <= 6
         assert len(ops[1]) < len(ops[0])
 
         ops = self.get_by_bytecode("LOAD_ATTR")
@@ -317,8 +317,8 @@
         assert len(ops) == 2
         assert not ops[0].get_opnames("call")
         assert not ops[0].get_opnames("new")
-        assert len(ops[0].get_opnames("guard")) <= 7
-        assert len(ops[0].get_opnames("getfield")) < 6
+        assert len(ops[0].get_opnames("guard")) <= 2
+        assert len(ops[0].get_opnames("getfield")) < 5
         assert not ops[1] # second LOOKUP_METHOD folded away
 
     def test_default_and_kw(self):
@@ -382,7 +382,7 @@
                     a.x = 2
                     i = i + a.x
                 return i
-        ''', 67,
+        ''', 69,
                    ([20], 20),
                    ([31], 32))
 
@@ -390,7 +390,7 @@
                 self.get_by_bytecode("CALL_FUNCTION"))
         assert not callA.get_opnames("call")
         assert not callA.get_opnames("new")
-        assert len(callA.get_opnames("guard")) <= 8
+        assert len(callA.get_opnames("guard")) <= 2
         assert not callisinstance1.get_opnames("call")
         assert not callisinstance1.get_opnames("new")
         assert len(callisinstance1.get_opnames("guard")) <= 2
@@ -742,6 +742,8 @@
                     '''%(op1, float(a)/4.0, float(b)/4.0, op2), 109, ([], res))
 
     def test_boolrewrite_ptr(self):
+        # XXX this test is way too imprecise in what it is actually testing
+        # it should count the number of guards instead
         compares = ('a == b', 'b == a', 'a != b', 'b != a', 'a == c', 'c != b')
         for e1 in compares:
             for e2 in compares:
@@ -765,7 +767,7 @@
                 print
                 print 'Test:', e1, e2, n, res
                 self.run_source('''
-                class tst:
+                class tst(object):
                     pass
                 def main():
                     a = tst()
@@ -847,6 +849,8 @@
             ''', 65, ([], 122880))
 
     def test_array_intimg(self):
+        # XXX this test is way too imprecise in what it is actually testing
+        # it should count the number of guards instead
         for tc, maxops in zip('ilILd', (67, 67, 69, 69, 61)):
             res = 73574560
             if tc in 'IL':

Modified: pypy/trunk/pypy/objspace/std/celldict.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/celldict.py	(original)
+++ pypy/trunk/pypy/objspace/std/celldict.py	Tue Oct 12 14:38:09 2010
@@ -45,7 +45,7 @@
         if space.is_w(space.type(w_key), space.w_str):
             self.impl_setitem_str(self.space.str_w(w_key), w_value)
         else:
-            self._as_rdict().setitem(w_key, w_value)
+            self._as_rdict().impl_fallback_setitem(w_key, w_value)
 
     def impl_setitem_str(self, name, w_value, shadows_type=True):
         self.getcell(name, True).w_value = w_value
@@ -66,7 +66,7 @@
         elif _is_sane_hash(space, w_key_type):
             raise KeyError
         else:
-            self._as_rdict().delitem(w_key)
+            self._as_rdict().impl_fallback_delitem(w_key)
         
     def impl_length(self):
         # inefficient, but do we care?
@@ -85,7 +85,7 @@
         elif _is_sane_hash(space, w_lookup_type):
             return None
         else:
-            return self._as_rdict().getitem(w_lookup)
+            return self._as_rdict().impl_fallback_getitem(w_lookup)
 
     def impl_getitem_str(self, lookup):
         res = self.getcell(lookup, False)

Modified: pypy/trunk/pypy/objspace/std/dictmultiobject.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/dictmultiobject.py	(original)
+++ pypy/trunk/pypy/objspace/std/dictmultiobject.py	Tue Oct 12 14:38:09 2010
@@ -102,17 +102,17 @@
         else:
             return None
 
-    # _________________________________________________________________ 
+    # _________________________________________________________________
     # implementation methods
     def impl_getitem(self, w_key):
         #return w_value or None
         raise NotImplementedError("abstract base class")
 
-    def impl_getitem_str(self, w_key):
+    def impl_getitem_str(self, key):
         #return w_value or None
         raise NotImplementedError("abstract base class")
 
-    def impl_setitem_str(self,  key, w_value, shadows_type=True):
+    def impl_setitem_str(self, key, w_value, shadows_type=True):
         raise NotImplementedError("abstract base class")
 
     def impl_setitem(self,  w_key, w_value):
@@ -120,7 +120,7 @@
 
     def impl_delitem(self, w_key):
         raise NotImplementedError("abstract base class")
- 
+
     def impl_length(self):
         raise NotImplementedError("abstract base class")
 
@@ -310,7 +310,7 @@
         if space.is_w(space.type(w_key), space.w_str):
             self.impl_setitem_str(self.space.str_w(w_key), w_value)
         else:
-            self._as_rdict().setitem(w_key, w_value)
+            self._as_rdict().impl_fallback_setitem(w_key, w_value)
 
     def impl_setitem_str(self, key, w_value, shadows_type=True):
         self.content[key] = w_value
@@ -324,7 +324,7 @@
         elif _is_sane_hash(space, w_key_type):
             raise KeyError
         else:
-            self._as_rdict().delitem(w_key)
+            self._as_rdict().impl_fallback_delitem(w_key)
         
     def impl_length(self):
         return len(self.content)
@@ -344,7 +344,7 @@
         elif _is_sane_hash(space, w_lookup_type):
             return None
         else:
-            return self._as_rdict().getitem(w_key)
+            return self._as_rdict().impl_fallback_getitem(w_key)
 
     def impl_iter(self):
         return StrIteratorImplementation(self.space, self)
@@ -414,7 +414,7 @@
             StrDictImplementation.impl_setitem_str(
                 self, self.space.str_w(w_key), w_value, False)
         else:
-            self._as_rdict().setitem(w_key, w_value)
+            self._as_rdict().impl_fallback_setitem(w_key, w_value)
 
     def impl_shadows_anything(self):
         return (self._shadows_anything or 
@@ -446,7 +446,7 @@
         elif _is_sane_hash(space, w_key_type):
             raise KeyError
         else:
-            self._as_rdict().delitem(w_key)
+            self._as_rdict().impl_fallback_delitem(w_key)
 
     def impl_get_builtin_indexed(self, i):
         return self.shadowed[i]

Modified: pypy/trunk/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/objspace.py	(original)
+++ pypy/trunk/pypy/objspace/std/objspace.py	Tue Oct 12 14:38:09 2010
@@ -23,6 +23,7 @@
 from pypy.objspace.std.listobject import W_ListObject
 from pypy.objspace.std.longobject import W_LongObject
 from pypy.objspace.std.noneobject import W_NoneObject
+from pypy.objspace.std.objectobject import W_ObjectObject
 from pypy.objspace.std.ropeobject import W_RopeObject
 from pypy.objspace.std.iterobject import W_SeqIterObject
 from pypy.objspace.std.setobject import W_SetObject, W_FrozensetObject
@@ -317,9 +318,14 @@
             w_subtype = w_type.check_user_subclass(w_subtype)
             if cls.typedef.applevel_subclasses_base is not None:
                 cls = cls.typedef.applevel_subclasses_base
-            subcls = get_unique_interplevel_subclass(
-                    self.config, cls, w_subtype.hasdict, w_subtype.nslots != 0,
-                    w_subtype.needsdel, w_subtype.weakrefable)
+            if (self.config.objspace.std.withmapdict and cls is W_ObjectObject
+                    and not w_subtype.needsdel):
+                from pypy.objspace.std.mapdict import get_subclass_of_correct_size
+                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,
+                        w_subtype.needsdel, w_subtype.weakrefable)
             instance = instantiate(subcls)
             assert isinstance(instance, cls)
             instance.user_setup(self, w_subtype)

Modified: pypy/trunk/pypy/objspace/std/sharingdict.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/sharingdict.py	(original)
+++ pypy/trunk/pypy/objspace/std/sharingdict.py	Tue Oct 12 14:38:09 2010
@@ -71,7 +71,7 @@
         elif _is_sane_hash(space, w_lookup_type):
             return None
         else:
-            return self._as_rdict().getitem(w_lookup)
+            return self._as_rdict().impl_fallback_getitem(w_lookup)
 
     def impl_getitem_str(self, lookup):
         i = self.structure.lookup_position(lookup)
@@ -84,7 +84,7 @@
         if space.is_w(space.type(w_key), space.w_str):
             self.impl_setitem_str(self.space.str_w(w_key), w_value)
         else:
-            self._as_rdict().setitem(w_key, w_value)
+            self._as_rdict().impl_fallback_setitem(w_key, w_value)
 
     @unroll_safe
     def impl_setitem_str(self, key, w_value, shadows_type=True):
@@ -132,7 +132,7 @@
         elif _is_sane_hash(space, w_key_type):
             raise KeyError
         else:
-            self._as_rdict().delitem(w_key)
+            self._as_rdict().impl_fallback_delitem(w_key)
         
     def impl_length(self):
         return self.structure.length

Modified: pypy/trunk/pypy/objspace/std/test/test_dictmultiobject.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/test/test_dictmultiobject.py	(original)
+++ pypy/trunk/pypy/objspace/std/test/test_dictmultiobject.py	Tue Oct 12 14:38:09 2010
@@ -602,6 +602,15 @@
                 classofinstance=classofinstance,
                 from_strdict_shared=from_strdict_shared)
 
+    def finditem_str(self, w_dict, s):
+        return w_dict.getitem_str(s) # assume it's a multidict
+
+    def setitem_str(self, w_dict, s, w_value):
+        return w_dict.setitem_str(s, w_value) # assume it's a multidict
+
+    def delitem(self, w_dict, w_s):
+        return w_dict.delitem(w_s) # assume it's a multidict
+
     def allocate_instance(self, cls, type):
         return object.__new__(cls)
 
@@ -611,7 +620,7 @@
     w_StopIteration = StopIteration
     w_None = None
     StringObjectCls = FakeString
-    w_dict = None
+    w_dict = W_DictMultiObject
     iter = iter
     fixedview = list
     listview  = list
@@ -687,6 +696,14 @@
         assert self.impl.length() == 0
         self.check_not_devolved()
 
+    def test_clear(self):
+        self.fill_impl()
+        assert self.impl.length() == 2
+        self.impl.clear()
+        assert self.impl.length() == 0
+        self.check_not_devolved()
+
+
     def test_keys(self):
         self.fill_impl()
         keys = self.impl.keys()

Modified: pypy/trunk/pypy/objspace/std/test/test_shadowtracking.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/test/test_shadowtracking.py	(original)
+++ pypy/trunk/pypy/objspace/std/test/test_shadowtracking.py	Tue Oct 12 14:38:09 2010
@@ -3,7 +3,8 @@
 
 class TestShadowTracking(object):
     def setup_class(cls):
-        cls.space = gettestobjspace(**{"objspace.std.withshadowtracking": True})
+        cls.space = gettestobjspace(**{"objspace.std.withshadowtracking": True,
+                                       "objspace.std.withmapdict": False})
 
     def test_simple_shadowing(self):
         space = self.space

Modified: pypy/trunk/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/typeobject.py	(original)
+++ pypy/trunk/pypy/objspace/std/typeobject.py	Tue Oct 12 14:38:09 2010
@@ -75,7 +75,9 @@
                           'weakrefable',
                           'hasdict',
                           'nslots',
-                          'instancetypedef']
+                          'instancetypedef',
+                          'terminator',
+                          ]
 
     # for config.objspace.std.getattributeshortcut
     # (False is a conservative default, fixed during real usage)
@@ -116,6 +118,12 @@
                 # dict_w of any of the types in the mro changes, or if the mro
                 # itself changes
                 w_self._version_tag = VersionTag()
+        if space.config.objspace.std.withmapdict:
+            from pypy.objspace.std.mapdict import DictTerminator, NoDictTerminator
+            if w_self.hasdict:
+                w_self.terminator = DictTerminator(space, w_self)
+            else:
+                w_self.terminator = NoDictTerminator(space, w_self)
 
     def mutated(w_self):
         space = w_self.space



More information about the Pypy-commit mailing list