[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