[pypy-commit] pypy default: Add translation option --hash=siphash24

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89776:ccc88590dc02
Date: 2017-01-26 09:30 +0100
http://bitbucket.org/pypy/pypy/changeset/ccc88590dc02/

Log:Add translation option --hash=siphash24

diff --git a/rpython/config/translationoption.py 
b/rpython/config/translationoption.py
--- a/rpython/config/translationoption.py
+++ b/rpython/config/translationoption.py
@@ -201,6 +201,10 @@
 StrOption("icon", "Path to the (Windows) icon to use for the executable"),
 StrOption("libname",
   "Windows: name and possibly location of the lib file to create"),
+ChoiceOption("hash",
+ "The hash to use for strings",
+ ["rpython", "siphash24"],
+ default="rpython", cmdline="--hash"),
 
 OptionDescription("backendopt", "Backend Optimization Options", [
 # control inlining
@@ -390,6 +394,12 @@
 if sys.platform == "darwin" or sys.platform =="win32":
 raise ConfigError("'asmgcc' not supported on this platform")
 
+def apply_extra_settings(config):
+# make the setting of config.hash definitive
+from rpython.rlib.objectmodel import set_hash_algorithm
+config.translation.hash = config.translation.hash
+set_hash_algorithm(config.translation.hash)
+
 # 
 
 def set_platform(config):
diff --git a/rpython/translator/goal/translate.py 
b/rpython/translator/goal/translate.py
--- a/rpython/translator/goal/translate.py
+++ b/rpython/translator/goal/translate.py
@@ -11,7 +11,8 @@
 from rpython.config.config import (to_optparse, OptionDescription, BoolOption,
 ArbitraryOption, StrOption, IntOption, Config, ChoiceOption, 
OptHelpFormatter)
 from rpython.config.translationoption import (get_combined_translation_config,
-set_opt_level, OPT_LEVELS, DEFAULT_OPT_LEVEL, set_platform, CACHE_DIR)
+set_opt_level, OPT_LEVELS, DEFAULT_OPT_LEVEL, set_platform, CACHE_DIR,
+apply_extra_settings)
 
 # clean up early rpython/_cache
 try:
@@ -177,6 +178,9 @@
 if 'handle_config' in targetspec_dic:
 targetspec_dic['handle_config'](config, translateconfig)
 
+# apply extra settings
+apply_extra_settings(config)
+
 return targetspec_dic, translateconfig, config, args
 
 def show_help(translateconfig, opt_parser, targetspec_dic, config):
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: hg merge default

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89777:ad1beddd3f43
Date: 2017-01-26 09:34 +0100
http://bitbucket.org/pypy/pypy/changeset/ad1beddd3f43/

Log:hg merge default

diff --git a/pypy/goal/targetpypystandalone.py 
b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -311,8 +311,8 @@
 if config.objspace.usemodules.cpyext:
 if config.translation.gc not in ('incminimark', 'boehm'):
 raise Exception("The 'cpyext' module requires the 
'incminimark'"
-" 'boehm' GC.  You need either 
'targetpypystandalone.py"
-" --withoutmod-cpyext' or '--gc=incminimark'")
+" or 'boehm' GC.  You need either 'targetpypystandalone.py"
+" --withoutmod-cpyext', or use one of these two GCs.")
 
 config.translating = True
 
diff --git a/pypy/module/_cffi_backend/cdataobj.py 
b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -323,17 +323,28 @@
 #
 return self._add_or_sub(w_other, -1)
 
-def getcfield(self, w_attr):
-return self.ctype.getcfield(self.space.str_w(w_attr))
+def getcfield(self, w_attr, mode):
+space = self.space
+attr = space.str_w(w_attr)
+try:
+cfield = self.ctype.getcfield(attr)
+except KeyError:
+raise oefmt(space.w_AttributeError, "cdata '%s' has no field '%s'",
+self.ctype.name, attr)
+if cfield is None:
+raise oefmt(space.w_AttributeError,
+"cdata '%s' points to an opaque type: cannot %s 
fields",
+self.ctype.name, mode)
+return cfield
 
 def getattr(self, w_attr):
-cfield = self.getcfield(w_attr)
+cfield = self.getcfield(w_attr, mode="read")
 with self as ptr:
 w_res = cfield.read(ptr, self)
 return w_res
 
 def setattr(self, w_attr, w_value):
-cfield = self.getcfield(w_attr)
+cfield = self.getcfield(w_attr, mode="write")
 with self as ptr:
 cfield.write(ptr, w_value)
 
diff --git a/pypy/module/_cffi_backend/ctypeptr.py 
b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -348,7 +348,10 @@
 return result
 
 def getcfield(self, attr):
-return self.ctitem.getcfield(attr)
+from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
+if isinstance(self.ctitem, W_CTypeStructOrUnion):
+return self.ctitem.getcfield(attr)
+return W_CType.getcfield(self, attr)
 
 def typeoffsetof_field(self, fieldname, following):
 if following == 0:
diff --git a/pypy/module/_cffi_backend/ctypestruct.py 
b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -161,18 +161,18 @@
 return self._fields_dict[attr]
 
 def getcfield(self, attr):
-ready = self._fields_dict is not None
-if not ready and self.size >= 0:
+# Returns a W_CField.  Error cases: returns None if we are an
+# opaque struct; or raises KeyError if the particular field
+# 'attr' does not exist.  The point of not directly building the
+# error here is to get the exact ctype in the error message: it
+# might be of the kind 'struct foo' or 'struct foo *'.
+if self._fields_dict is None:
+if self.size < 0:
+return None
 self.force_lazy_struct()
-ready = True
-if ready:
-self = jit.promote(self)
-attr = jit.promote_string(attr)
-try:
-return self._getcfield_const(attr)
-except KeyError:
-pass
-return W_CType.getcfield(self, attr)
+self = jit.promote(self)
+attr = jit.promote_string(attr)
+return self._getcfield_const(attr)# <= KeyError here
 
 def cdata_dir(self):
 if self.size < 0:
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py 
b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -737,8 +737,14 @@
 BInt = new_primitive_type("int")
 BStruct = new_struct_type("struct foo")
 BStructPtr = new_pointer_type(BStruct)
-p = cast(BStructPtr, 0)
-py.test.raises(AttributeError, "p.a1")# opaque
+p = cast(BStructPtr, 42)
+e = py.test.raises(AttributeError, "p.a1")# opaque
+assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
+"cannot read fields")
+e = py.test.raises(AttributeError, "p.a1 = 10")# opaque
+

[pypy-commit] pypy py3.5: change the default for the --hash option in py3.5

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89778:45239e9d6953
Date: 2017-01-26 09:42 +0100
http://bitbucket.org/pypy/pypy/changeset/45239e9d6953/

Log:change the default for the --hash option in py3.5

diff --git a/pypy/goal/targetpypystandalone.py 
b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -229,6 +229,10 @@
 raise Exception("You have to specify the --opt level.\n"
 "Try --opt=2 or --opt=jit, or equivalently -O2 or -Ojit .")
 self.translateconfig = translateconfig
+
+# change the default for this option
+config.translation.suggest(hash="siphash24")
+
 # set up the objspace optimizations based on the --opt argument
 from pypy.config.pypyoption import set_pypy_opt_level
 set_pypy_opt_level(config, translateconfig.opt)
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: revert to the default of --hash=rpython

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89780:1921e9b65a21
Date: 2017-01-26 09:52 +0100
http://bitbucket.org/pypy/pypy/changeset/1921e9b65a21/

Log:revert to the default of --hash=rpython

diff --git a/pypy/goal/targetpypystandalone.py 
b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -231,7 +231,9 @@
 self.translateconfig = translateconfig
 
 # change the default for this option
-config.translation.suggest(hash="siphash24")
+# XXX disabled until we fix the real problem: a per-translation
+# seed for siphash is bad
+#config.translation.suggest(hash="siphash24")
 
 # set up the objspace optimizations based on the --opt argument
 from pypy.config.pypyoption import set_pypy_opt_level
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy default: Document the problem (thanks njs)

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89779:1042ceb32763
Date: 2017-01-26 09:51 +0100
http://bitbucket.org/pypy/pypy/changeset/1042ceb32763/

Log:Document the problem (thanks njs)

diff --git a/rpython/rlib/rsiphash.py b/rpython/rlib/rsiphash.py
--- a/rpython/rlib/rsiphash.py
+++ b/rpython/rlib/rsiphash.py
@@ -21,6 +21,9 @@
 # that as easily because many details may rely on getting the same hash
 # value before and after translation.  We can, however, pick a random
 # seed once per translation, which should already be quite good.
+#
+# XXX no, it is not: e.g. all Ubuntu installations of the same Ubuntu
+# would get the same seed.  That's not good enough.
 
 @not_rpython
 def select_random_seed():
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy default: fix test

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89781:8ecc4591e7ec
Date: 2017-01-26 10:02 +0100
http://bitbucket.org/pypy/pypy/changeset/8ecc4591e7ec/

Log:fix test

diff --git a/pypy/interpreter/test/test_appinterp.py 
b/pypy/interpreter/test/test_appinterp.py
--- a/pypy/interpreter/test/test_appinterp.py
+++ b/pypy/interpreter/test/test_appinterp.py
@@ -23,7 +23,9 @@
 (): 
 y y 
 """)
-assert str(excinfo.value.errorstr(space)).find('y y') != -1 
+# NOTE: the following test only works because excinfo.value is not
+# normalized so far
+assert str(excinfo.value.get_w_value(space)).find('y y') != -1 
 
 def test_simple_applevel(space):
 app = appdef("""app(x,y): 
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy default: Fix

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89782:9eb7c2912413
Date: 2017-01-26 10:13 +0100
http://bitbucket.org/pypy/pypy/changeset/9eb7c2912413/

Log:Fix

diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -71,7 +71,8 @@
 
 def errorstr(self, space, use_repr=False):
 "The exception class and value, as a string."
-self.normalize_exception(space)
+if not use_repr:# see write_unraisable()
+self.normalize_exception(space)
 w_value = self.get_w_value(space)
 if space is None:
 # this part NOT_RPYTHON
@@ -262,6 +263,11 @@
 traceback.print_exception(t, v, tb)
 """)
 else:
+# Note that like CPython, we don't normalize the
+# exception here.  So from `'foo'.index('bar')` you get
+# "Exception ValueError: 'substring not found' in x ignored"
+# but from `raise ValueError('foo')` you get
+# "Exception ValueError: ValueError('foo',) in x ignored"
 msg = 'Exception %s in %s%s ignored\n' % (
 self.errorstr(space, use_repr=True), where, objrepr)
 space.call_method(space.sys.get('stderr'), 'write',
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] cffi default: complain clearly if set_source() is given a /-separated name

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r2875:510280ce4cc4
Date: 2017-01-26 11:14 +0100
http://bitbucket.org/cffi/cffi/changeset/510280ce4cc4/

Log:complain clearly if set_source() is given a /-separated name

diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -593,11 +593,15 @@
 ensure('extra_link_args', '/MANIFEST')
 
 def set_source(self, module_name, source, source_extension='.c', **kwds):
+import os
 if hasattr(self, '_assigned_source'):
 raise ValueError("set_source() cannot be called several times "
  "per ffi object")
 if not isinstance(module_name, basestring):
 raise TypeError("'module_name' must be a string")
+if os.sep in module_name or (os.altsep and os.altsep in module_name):
+raise ValueError("'module_name' must not contain '/': use a dotted 
"
+ "name to make a 'package.module' location")
 self._assigned_source = (str(module_name), source,
  source_extension, kwds)
 
diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -36,6 +36,11 @@
   ['-Werror'])
 return recompiler._verify(ffi, module_name, source, *args, **kwds)
 
+def test_set_source_no_slashes():
+ffi = FFI()
+py.test.raises(ValueError, ffi.set_source, "abc/def", None)
+py.test.raises(ValueError, ffi.set_source, "abc/def", "C code")
+
 
 def test_type_table_func():
 check_type_table("double sin(double);",
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy rpython-hash: A quick disable of the hash-preservation logic, fix a few tests

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: rpython-hash
Changeset: r89784:11355355dff6
Date: 2017-01-26 12:26 +0100
http://bitbucket.org/pypy/pypy/changeset/11355355dff6/

Log:A quick disable of the hash-preservation logic, fix a few tests

diff --git a/rpython/memory/gctransform/boehm.py 
b/rpython/memory/gctransform/boehm.py
--- a/rpython/memory/gctransform/boehm.py
+++ b/rpython/memory/gctransform/boehm.py
@@ -11,7 +11,7 @@
 class BoehmGCTransformer(GCTransformer):
 malloc_zero_filled = True
 FINALIZER_PTR = lltype.Ptr(lltype.FuncType([llmemory.Address], 
lltype.Void))
-HDR = lltype.Struct("header", ("hash", lltype.Signed))
+HDR = lltype.Struct("header")
 
 def __init__(self, translator, inline=False):
 super(BoehmGCTransformer, self).__init__(translator, inline=inline)
@@ -33,9 +33,7 @@
 
 def ll_identityhash(addr):
 obj = llmemory.cast_adr_to_ptr(addr, HDRPTR)
-h = obj.hash
-if h == 0:
-obj.hash = h = ~llmemory.cast_adr_to_int(addr)
+h = ~llmemory.cast_adr_to_int(addr)
 return h
 
 if self.translator:
@@ -196,7 +194,7 @@
 
 def gcheader_initdata(self, obj):
 hdr = lltype.malloc(self.HDR, immortal=True)
-hdr.hash = lltype.identityhash_nocache(obj._as_ptr())
+#hdr.hash = lltype.identityhash_nocache(obj._as_ptr())
 return hdr._obj
 
 
diff --git a/rpython/memory/gctransform/framework.py 
b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -1518,7 +1518,7 @@
 hdr = self.gc_header_for(o, needs_hash)
 return hdr._obj
 
-def get_prebuilt_hash(self, obj):
+def DISABLED_get_prebuilt_hash(self, obj):
 # for prebuilt objects that need to have their hash stored and
 # restored.  Note that only structures that are StructNodes all
 # the way have their hash stored (and not e.g. structs with var-
diff --git a/rpython/translator/c/node.py b/rpython/translator/c/node.py
--- a/rpython/translator/c/node.py
+++ b/rpython/translator/c/node.py
@@ -663,6 +663,7 @@
 def gcstructnode_factory(db, T, obj):
 if (db.gctransformer and
 db.gctransformer.get_prebuilt_hash(obj) is not None):
+DISABLED
 cls = GcStructNodeWithHash
 else:
 cls = StructNode
diff --git a/rpython/translator/c/test/test_boehm.py 
b/rpython/translator/c/test/test_boehm.py
--- a/rpython/translator/c/test/test_boehm.py
+++ b/rpython/translator/c/test/test_boehm.py
@@ -381,7 +381,7 @@
 current_object_addr_as_int(d2),
 compute_hash(c),
 compute_hash(d),
-compute_hash(("Hi", None, (7.5, 2, d)
+compute_hash(("Hi", None, (7.5, 2)
 
 f = self.getcompiled(fn)
 res = f()
@@ -390,8 +390,10 @@
 # xxx the next line is too precise, checking the exact implementation
 assert res[0] == ~res[1]
 assert res[2] != compute_hash(c) # likely
-assert res[3] == compute_hash(d)
-assert res[4] == compute_hash(("Hi", None, (7.5, 2, d)))
+assert res[3] != compute_hash(d) # likely *not* preserved
+assert res[4] == compute_hash(("Hi", None, (7.5, 2)))
+# ^^ true as long as we're using the 'rpython' hash for strings
+#and not e.g. siphash24
 
 def test_finalizer_queue(self):
 class A(object):
diff --git a/rpython/translator/c/test/test_newgc.py 
b/rpython/translator/c/test/test_newgc.py
--- a/rpython/translator/c/test/test_newgc.py
+++ b/rpython/translator/c/test/test_newgc.py
@@ -780,7 +780,7 @@
 c = C()
 d = D()
 h_d = compute_hash(d) # force to be cached on 'd', but not on 'c'
-h_t = compute_hash(("Hi", None, (7.5, 2, d)))
+h_t = compute_hash(("Hi", None, (7.5, 2)))
 S = lltype.GcStruct('S', ('x', lltype.Signed),
  ('a', lltype.Array(lltype.Signed)))
 s = lltype.malloc(S, 15, zero=True)
@@ -789,10 +789,10 @@
 def f():
 if compute_hash(c) != compute_identity_hash(c):
 return 12
-if compute_hash(d) != h_d:
+if compute_hash(d) == h_d: # likely *not* preserved
 return 13
-if compute_hash(("Hi", None, (7.5, 2, d))) != h_t:
-return 14
+if compute_hash(("Hi", None, (7.5, 2))) != h_t:
+return 14   # ^^ true as long as we're not using e.g. siphash24
 c2 = C()
 h_c2 = compute_hash(c2)
 if compute_hash(c2) != h_c2:
diff --git a/rpython/translator/c/test/test_typed.py 
b/rpython/translator/c/test/test_typed.py
--- a/rpython/translator/c/test/test_typed.py
+++ b/rpython/translator/c/test/test_typed.py
@@ -588,7 +588,7 @@
 current_object_addr_as_int(d2),

[pypy-commit] pypy rpython-hash: A branch to try and remove the guarantee: "the rpython hash of any object doesn't change before and after translation"

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: rpython-hash
Changeset: r89783:533fd2120ac6
Date: 2017-01-26 12:12 +0100
http://bitbucket.org/pypy/pypy/changeset/533fd2120ac6/

Log:A branch to try and remove the guarantee: "the rpython hash of any
object doesn't change before and after translation"

___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy rpython-hash: Disable support for explicitly non-ordered, non-empty prebuilt dicts

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: rpython-hash
Changeset: r89785:ab8402f0c677
Date: 2017-01-26 12:35 +0100
http://bitbucket.org/pypy/pypy/changeset/ab8402f0c677/

Log:Disable support for explicitly non-ordered, non-empty prebuilt dicts

diff --git a/rpython/rtyper/lltypesystem/rdict.py 
b/rpython/rtyper/lltypesystem/rdict.py
--- a/rpython/rtyper/lltypesystem/rdict.py
+++ b/rpython/rtyper/lltypesystem/rdict.py
@@ -236,21 +236,14 @@
 if self.r_rdict_hashfn.lowleveltype != lltype.Void:
 l_fn = self.r_rdict_hashfn.convert_const(dictobj.key_hash)
 l_dict.fnkeyhash = l_fn
-
-for dictkeycontainer, dictvalue in dictobj._dict.items():
-llkey = r_key.convert_const(dictkeycontainer.key)
-llvalue = r_value.convert_const(dictvalue)
-ll_dict_insertclean(l_dict, llkey, llvalue,
-dictkeycontainer.hash)
-return l_dict
-
+any_items = dictobj._dict.items()
 else:
-for dictkey, dictvalue in dictobj.items():
-llkey = r_key.convert_const(dictkey)
-llvalue = r_value.convert_const(dictvalue)
-ll_dict_insertclean(l_dict, llkey, llvalue,
-l_dict.keyhash(llkey))
-return l_dict
+any_items = dictobj.items()
+if any_items:
+raise TyperError("found a prebuilt, explicitly non-ordered, "
+ "non-empty dict.  it would require additional"
+ " support to rehash it at program start-up")
+return l_dict
 
 def rtype_len(self, hop):
 v_dict, = hop.inputargs(self)
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy rpython-hash: in-progress: support dicts with no indexes

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: rpython-hash
Changeset: r89786:73f39f5b582e
Date: 2017-01-26 14:19 +0100
http://bitbucket.org/pypy/pypy/changeset/73f39f5b582e/

Log:in-progress: support dicts with no indexes

diff --git a/rpython/rtyper/lltypesystem/rordereddict.py 
b/rpython/rtyper/lltypesystem/rordereddict.py
--- a/rpython/rtyper/lltypesystem/rordereddict.py
+++ b/rpython/rtyper/lltypesystem/rordereddict.py
@@ -46,20 +46,25 @@
 @jit.look_inside_iff(lambda d, key, hash, flag: jit.isvirtual(d))
 @jit.oopspec('ordereddict.lookup(d, key, hash, flag)')
 def ll_call_lookup_function(d, key, hash, flag):
-fun = d.lookup_function_no & FUNC_MASK
-# This likely() here forces gcc to compile the check for fun == FUNC_BYTE
-# first.  Otherwise, this is a regular switch and gcc (at least 4.7)
-# compiles this as a series of checks, with the FUNC_BYTE case last.
-# It sounds minor, but it is worth 6-7% on a PyPy microbenchmark.
-if likely(fun == FUNC_BYTE):
-return ll_dict_lookup(d, key, hash, flag, TYPE_BYTE)
-elif fun == FUNC_SHORT:
-return ll_dict_lookup(d, key, hash, flag, TYPE_SHORT)
-elif IS_64BIT and fun == FUNC_INT:
-return ll_dict_lookup(d, key, hash, flag, TYPE_INT)
-elif fun == FUNC_LONG:
-return ll_dict_lookup(d, key, hash, flag, TYPE_LONG)
-assert False
+while True:
+fun = d.lookup_function_no & FUNC_MASK
+# This likely() here forces gcc to compile the check for fun==FUNC_BYTE
+# first.  Otherwise, this is a regular switch and gcc (at least 4.7)
+# compiles this as a series of checks, with the FUNC_BYTE case last.
+# It sounds minor, but it is worth 6-7% on a PyPy microbenchmark.
+if likely(fun == FUNC_BYTE):
+return ll_dict_lookup(d, key, hash, flag, TYPE_BYTE)
+elif fun == FUNC_SHORT:
+return ll_dict_lookup(d, key, hash, flag, TYPE_SHORT)
+elif IS_64BIT and fun == FUNC_INT:
+return ll_dict_lookup(d, key, hash, flag, TYPE_INT)
+elif fun == FUNC_LONG:
+return ll_dict_lookup(d, key, hash, flag, TYPE_LONG)
+elif fun == FUNC_NO_INDEX:
+ll_dict_create_index(d)
+# then, retry
+else:
+assert False
 
 def get_ll_dict(DICTKEY, DICTVALUE, get_custom_eq_hash=None, DICT=None,
 ll_fasthash_function=None, ll_hash_function=None,
@@ -254,7 +259,6 @@
 llvalue = r_value.convert_const(dictvalue)
 _ll_dict_insertclean(l_dict, llkey, llvalue,
  dictkeycontainer.hash)
-return l_dict
 
 else:
 for dictkey, dictvalue in dictobj.items():
@@ -262,7 +266,9 @@
 llvalue = r_value.convert_const(dictvalue)
 _ll_dict_insertclean(l_dict, llkey, llvalue,
  l_dict.keyhash(llkey))
-return l_dict
+
+ll_remove_index(l_dict)
+return l_dict
 
 def rtype_len(self, hop):
 v_dict, = hop.inputargs(self)
@@ -458,17 +464,27 @@
 
 IS_64BIT = sys.maxint != 2 ** 31 - 1
 
-FUNC_SHIFT = 2
-FUNC_MASK  = 0x03  # two bits
 if IS_64BIT:
-FUNC_BYTE, FUNC_SHORT, FUNC_INT, FUNC_LONG = range(4)
+FUNC_SHIFT = 3
+FUNC_MASK  = 0x07  # three bits
+FUNC_NO_INDEX, FUNC_BYTE, FUNC_SHORT, FUNC_INT, FUNC_LONG = range(5)
 else:
-FUNC_BYTE, FUNC_SHORT, FUNC_LONG = range(3)
+FUNC_SHIFT = 2
+FUNC_MASK  = 0x03  # two bits
+FUNC_NO_INDEX, FUNC_BYTE, FUNC_SHORT, FUNC_LONG = range(4)
 TYPE_BYTE  = rffi.UCHAR
 TYPE_SHORT = rffi.USHORT
 TYPE_INT   = rffi.UINT
 TYPE_LONG  = lltype.Unsigned
 
+NULL = lltype.nullptr(llmemory.GCREF.TO)
+
+def ll_remove_index(d):
+# Used in MemoryError situation, or when translating prebuilt dicts.
+# Remove the index completely.
+d.indexes = NULL
+d.lookup_function_no = FUNC_NO_INDEX
+
 def ll_malloc_indexes_and_choose_lookup(d, n):
 # keep in sync with ll_clear_indexes() below
 if n <= 256:
@@ -503,22 +519,30 @@
 rgc.ll_arrayclear(lltype.cast_opaque_ptr(DICTINDEX_INT, d.indexes))
 elif fun == FUNC_LONG:
 rgc.ll_arrayclear(lltype.cast_opaque_ptr(DICTINDEX_LONG, d.indexes))
+elif fun == FUNC_NO_INDEX:
+# nothing to clear in this case
+ll_assert(not d.indexes,
+  "ll_clear_indexes: FUNC_NO_INDEX but d.indexes != NULL")
 else:
 assert False
 
 @jit.dont_look_inside
 def ll_call_insert_clean_function(d, hash, i):
-fun = d.lookup_function_no & FUNC_MASK
-if fun == FUNC_BYTE:
-ll_dict_store_clean(d, hash, i, TYPE_BYTE)
-elif fun == FUNC_SHORT:
-ll_dict_store_clean(d, hash, i, TYPE_SHORT)
-elif IS_64BIT and fun == FUNC_INT:
-ll_dict_store_clean(d, hash, i, TYPE_INT)
-elif fun == FUNC_LONG:
-ll_dict_store_clean(d, hash, i, TYPE_LONG)
-else:
-assert False
+while T

[pypy-commit] pypy rpython-hash: Fix test_memoryerror by using the most tight estimate in

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: rpython-hash
Changeset: r89787:9a1928019d6b
Date: 2017-01-26 14:54 +0100
http://bitbucket.org/pypy/pypy/changeset/9a1928019d6b/

Log:Fix test_memoryerror by using the most tight estimate in
ll_dict_create_index. This value should have the same guarantee in
real program: if we get out of memory inserting a new item, then the
recreated index is still of the smaller size instead of being bigger
(and then likely not fitting in memory either)

diff --git a/rpython/rtyper/lltypesystem/rordereddict.py 
b/rpython/rtyper/lltypesystem/rordereddict.py
--- a/rpython/rtyper/lltypesystem/rordereddict.py
+++ b/rpython/rtyper/lltypesystem/rordereddict.py
@@ -879,9 +879,15 @@
 if d.num_live_items == 0:
 new_size = DICT_INITSIZE # fast path
 else:
-new_estimate = d.num_live_items  * 2
+# Use a more conservative estimate than _ll_dict_resize_to() here.
+# This function is called when initially creating the index (so,
+# for prebuilt dicts, the chance is that it will never grow);
+# after we got a MemoryError; and when throwing the index away
+# because of heavy shrinking of the dict.  The minimum value
+# here is such that 'new_estimate * 2 - num_live_items * 3 > 0'.
+new_estimate = (d.num_live_items * 3) // 2 + 1
 new_size = DICT_INITSIZE
-while new_size <= new_estimate:
+while new_size < new_estimate:
 new_size *= 2
 ll_dict_reindex(d, new_size)
 
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy rpython-hash: better fast path

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: rpython-hash
Changeset: r89788:b24fe8a08009
Date: 2017-01-26 15:00 +0100
http://bitbucket.org/pypy/pypy/changeset/b24fe8a08009/

Log:better fast path

diff --git a/rpython/rtyper/lltypesystem/rordereddict.py 
b/rpython/rtyper/lltypesystem/rordereddict.py
--- a/rpython/rtyper/lltypesystem/rordereddict.py
+++ b/rpython/rtyper/lltypesystem/rordereddict.py
@@ -876,7 +876,7 @@
 ll_dict_reindex(d, new_size)
 
 def ll_dict_create_index(d):
-if d.num_live_items == 0:
+if d.num_live_items < DICT_INITSIZE * 2 // 3:
 new_size = DICT_INITSIZE # fast path
 else:
 # Use a more conservative estimate than _ll_dict_resize_to() here.
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy rpython-hash: Check popitem() in the hypothesis test

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: rpython-hash
Changeset: r89789:90dc3abfc8f2
Date: 2017-01-26 16:55 +0100
http://bitbucket.org/pypy/pypy/changeset/90dc3abfc8f2/

Log:Check popitem() in the hypothesis test

diff --git a/rpython/rtyper/test/test_rdict.py 
b/rpython/rtyper/test/test_rdict.py
--- a/rpython/rtyper/test/test_rdict.py
+++ b/rpython/rtyper/test/test_rdict.py
@@ -1155,6 +1155,8 @@
 
 class MappingSpace(object):
 def __init__(self, s_key, s_value):
+from rpython.rtyper.rtuple import TupleRepr
+
 self.s_key = s_key
 self.s_value = s_value
 rtyper = PseudoRTyper()
@@ -1168,6 +1170,8 @@
 self.reference = self.new_reference()
 self.ll_key = r_key.convert_const
 self.ll_value = r_value.convert_const
+r_tuple = TupleRepr(rtyper, [r_key, r_value])
+self.TUPLE = r_tuple.lowleveltype
 
 def setitem(self, key, value):
 ll_key = self.ll_key(key)
@@ -1191,6 +1195,22 @@
 self.reference.clear()
 assert self.ll_len(self.l_dict) == 0
 
+def popitem(self):
+try:
+ll_tuple = self.ll_popitem(self.TUPLE, self.l_dict)
+except KeyError:
+assert len(self.reference) == 0
+else:
+ll_key = ll_tuple.item0
+ll_value = ll_tuple.item1
+for key, value in self.reference.iteritems():
+if self.ll_key(key) == ll_key:
+assert self.ll_value(value) == ll_value
+del self.reference[key]
+break
+else:
+raise AssertionError("popitem() returned unexpected key")
+
 def fullcheck(self):
 assert self.ll_len(self.l_dict) == len(self.reference)
 for key, value in self.reference.iteritems():
@@ -1217,7 +1237,8 @@
 def steps(self):
 if not self.space:
 return builds(Action, just('setup'), tuples(st_keys, st_values))
-global_actions = [Action('copydict', ()), Action('cleardict', ())]
+global_actions = [Action('copydict', ()), Action('cleardict', ()),
+  Action('popitem', ())]
 if self.space.reference:
 return (
 self.st_setitem() | sampled_from(global_actions) |
@@ -1249,6 +1270,7 @@
 ll_contains = staticmethod(rdict.ll_contains)
 ll_copy = staticmethod(rdict.ll_copy)
 ll_clear = staticmethod(rdict.ll_clear)
+ll_popitem = staticmethod(rdict.ll_popitem)
 
 def newdict(self, repr):
 return rdict.ll_newdict(repr.DICT)
diff --git a/rpython/rtyper/test/test_rordereddict.py 
b/rpython/rtyper/test/test_rordereddict.py
--- a/rpython/rtyper/test/test_rordereddict.py
+++ b/rpython/rtyper/test/test_rordereddict.py
@@ -345,6 +345,7 @@
 ll_contains = staticmethod(rodct.ll_dict_contains)
 ll_copy = staticmethod(rodct.ll_dict_copy)
 ll_clear = staticmethod(rodct.ll_dict_clear)
+ll_popitem = staticmethod(rodct.ll_dict_popitem)
 
 def newdict(self, repr):
 return rodct.ll_newdict(repr.DICT)
@@ -363,6 +364,20 @@
 break
 return keys_ll
 
+def popitem(self):
+# overridden to check that we're getting the most recent key,
+# not a random one
+try:
+ll_tuple = self.ll_popitem(self.TUPLE, self.l_dict)
+except KeyError:
+assert len(self.reference) == 0
+else:
+ll_key = ll_tuple.item0
+ll_value = ll_tuple.item1
+key, value = self.reference.popitem()
+assert self.ll_key(key) == ll_key
+assert self.ll_value(value) == ll_value
+
 def fullcheck(self):
 # overridden to also check key order
 assert self.ll_len(self.l_dict) == len(self.reference)
@@ -379,4 +394,4 @@
 
 def test_hypothesis():
 run_state_machine_as_test(
-ODictSM, settings(max_examples=500, stateful_step_count=100))
+ODictSM, settings(max_examples=5, stateful_step_count=100))
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy default: Cleanup: don't pass the whole CConfig to places that only need an ECI

2017-01-26 Thread rlamy
Author: Ronan Lamy 
Branch: 
Changeset: r89790:ae071d58c03a
Date: 2017-01-26 17:01 +
http://bitbucket.org/pypy/pypy/changeset/ae071d58c03a/

Log:Cleanup: don't pass the whole CConfig to places that only need an
ECI

diff --git a/rpython/rtyper/tool/rffi_platform.py 
b/rpython/rtyper/tool/rffi_platform.py
--- a/rpython/rtyper/tool/rffi_platform.py
+++ b/rpython/rtyper/tool/rffi_platform.py
@@ -131,8 +131,8 @@
 # General interface
 
 class ConfigResult:
-def __init__(self, CConfig, info, entries):
-self.CConfig = CConfig
+def __init__(self, eci, info, entries):
+self.eci = eci
 self.result = {}
 self.info = info
 self.entries = entries
@@ -154,15 +154,14 @@
 class _CWriter(object):
 """ A simple class which aggregates config parts
 """
-def __init__(self, CConfig):
+def __init__(self, eci):
 self.path = uniquefilepath()
 self.f = self.path.open("w")
-self.config = CConfig
+self.eci = eci
 
 def write_header(self):
 f = self.f
-CConfig = self.config
-CConfig._compilation_info_.write_c_header(f)
+self.eci.write_c_header(f)
 print >> f, C_HEADER
 print >> f
 
@@ -194,8 +193,7 @@
 self.start_main()
 self.f.write(question + "\n")
 self.close()
-eci = self.config._compilation_info_
-try_compile_cache([self.path], eci)
+try_compile_cache([self.path], self.eci)
 
 def configure(CConfig, ignore_errors=False):
 """Examine the local system by running the C compiler.
@@ -208,6 +206,7 @@
 assert not hasattr(CConfig, attr), \
 "Found legacy attribute %s on CConfig" % attr
 
+eci = CConfig._compilation_info_
 entries = []
 for key in dir(CConfig):
 value = getattr(CConfig, key)
@@ -215,7 +214,7 @@
 entries.append((key, value))
 
 if entries:   # can be empty if there are only CConfigSingleEntries
-writer = _CWriter(CConfig)
+writer = _CWriter(eci)
 writer.write_header()
 for key, entry in entries:
 writer.write_entry(key, entry)
@@ -225,7 +224,6 @@
 writer.write_entry_main(key)
 writer.close()
 
-eci = CConfig._compilation_info_
 infolist = list(run_example_code(writer.path, eci,
  ignore_errors=ignore_errors))
 assert len(infolist) == len(entries)
@@ -236,7 +234,7 @@
 resultinfo[key] = info
 resultentries[entry] = key
 
-result = ConfigResult(CConfig, resultinfo, resultentries)
+result = ConfigResult(eci, resultinfo, resultentries)
 for name, entry in entries:
 result.get_entry_result(entry)
 res = result.get_result()
@@ -246,7 +244,7 @@
 for key in dir(CConfig):
 value = getattr(CConfig, key)
 if isinstance(value, CConfigSingleEntry):
-writer = _CWriter(CConfig)
+writer = _CWriter(eci)
 writer.write_header()
 res[key] = value.question(writer.ask_gcc)
 
@@ -344,7 +342,7 @@
 allfields = tuple(['c_' + name for name, _ in fields])
 padfields = tuple(padfields)
 name = self.name
-eci = config_result.CConfig._compilation_info_
+eci = config_result.eci
 padding_drop = PaddingDrop(name, allfields, padfields, eci)
 hints = {'align': info['align'],
  'size': info['size'],
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy default: Extract configure_entries() from configure()

2017-01-26 Thread rlamy
Author: Ronan Lamy 
Branch: 
Changeset: r89791:5cf849b8cd32
Date: 2017-01-26 17:29 +
http://bitbucket.org/pypy/pypy/changeset/5cf849b8cd32/

Log:Extract configure_entries() from configure()

diff --git a/rpython/rtyper/tool/rffi_platform.py 
b/rpython/rtyper/tool/rffi_platform.py
--- a/rpython/rtyper/tool/rffi_platform.py
+++ b/rpython/rtyper/tool/rffi_platform.py
@@ -214,30 +214,7 @@
 entries.append((key, value))
 
 if entries:   # can be empty if there are only CConfigSingleEntries
-writer = _CWriter(eci)
-writer.write_header()
-for key, entry in entries:
-writer.write_entry(key, entry)
-
-writer.start_main()
-for key, entry in entries:
-writer.write_entry_main(key)
-writer.close()
-
-infolist = list(run_example_code(writer.path, eci,
- ignore_errors=ignore_errors))
-assert len(infolist) == len(entries)
-
-resultinfo = {}
-resultentries = {}
-for info, (key, entry) in zip(infolist, entries):
-resultinfo[key] = info
-resultentries[entry] = key
-
-result = ConfigResult(eci, resultinfo, resultentries)
-for name, entry in entries:
-result.get_entry_result(entry)
-res = result.get_result()
+res = configure_entries(entries, eci, ignore_errors=ignore_errors)
 else:
 res = {}
 
@@ -250,6 +227,33 @@
 
 return res
 
+
+def configure_entries(entries, eci, ignore_errors=False):
+writer = _CWriter(eci)
+writer.write_header()
+for key, entry in entries:
+writer.write_entry(key, entry)
+
+writer.start_main()
+for key, entry in entries:
+writer.write_entry_main(key)
+writer.close()
+
+infolist = list(run_example_code(
+writer.path, eci, ignore_errors=ignore_errors))
+assert len(infolist) == len(entries)
+
+resultinfo = {}
+resultentries = {}
+for info, (key, entry) in zip(infolist, entries):
+resultinfo[key] = info
+resultentries[entry] = key
+
+result = ConfigResult(eci, resultinfo, resultentries)
+for name, entry in entries:
+result.get_entry_result(entry)
+return result.get_result()
+
 # 
 
 
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy default: Use rffi_platform.configure_entries() in cparser

2017-01-26 Thread rlamy
Author: Ronan Lamy 
Branch: 
Changeset: r89792:75fb54ed4989
Date: 2017-01-26 17:46 +
http://bitbucket.org/pypy/pypy/changeset/75fb54ed4989/

Log:Use rffi_platform.configure_entries() in cparser

diff --git a/pypy/module/cpyext/cparser.py b/pypy/module/cpyext/cparser.py
--- a/pypy/module/cpyext/cparser.py
+++ b/pypy/module/cpyext/cparser.py
@@ -699,7 +699,7 @@
 self.headers = headers if headers is not None else ['sys/types.h']
 self.parsed_headers = []
 self.sources = []
-self._Config = type('Config', (object,), {})
+self._config_entries = []
 self._TYPES = {}
 self.includes = []
 self.struct_typedefs = {}
@@ -759,8 +759,9 @@
 def realize_struct(self, struct):
 type_name = struct.get_type_name()
 configname = type_name.replace(' ', '__')
-setattr(self._Config, configname,
-rffi_platform.Struct(type_name, struct.fields))
+assert not any(x[0] == configname for x in self._config_entries)
+self._config_entries.append(
+(configname, rffi_platform.Struct(type_name, struct.fields)))
 self._TYPES[configname] = struct.TYPE
 return struct.TYPE
 
@@ -795,13 +796,17 @@
 elif name.startswith('macro '):
 name = name[6:]
 self.add_macro(name, obj)
-self._Config._compilation_info_ = self.build_eci()
-for name, TYPE in rffi_platform.configure(self._Config).iteritems():
+if not self._config_entries:
+return
+eci = self.build_eci()
+result = rffi_platform.configure_entries(self._config_entries, eci)
+for name, TYPE in result.iteritems():
 # hack: prevent the source from being pasted into common_header.h
 del TYPE._hints['eci']
 if name in self._TYPES:
 self._TYPES[name].become(TYPE)
 del self._TYPES[name]
+self._config_entries[:] = []
 
 def convert_type(self, obj, quals=0):
 if isinstance(obj, model.DefinedType):
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy default: Preserve the order of entries in configure_entries() which now takes a list instead of a dict

2017-01-26 Thread rlamy
Author: Ronan Lamy 
Branch: 
Changeset: r89793:e484cf6b06b6
Date: 2017-01-26 19:54 +
http://bitbucket.org/pypy/pypy/changeset/e484cf6b06b6/

Log:Preserve the order of entries in configure_entries() which now takes
a list instead of a dict

diff --git a/pypy/module/cpyext/cparser.py b/pypy/module/cpyext/cparser.py
--- a/pypy/module/cpyext/cparser.py
+++ b/pypy/module/cpyext/cparser.py
@@ -699,8 +699,7 @@
 self.headers = headers if headers is not None else ['sys/types.h']
 self.parsed_headers = []
 self.sources = []
-self._config_entries = []
-self._TYPES = {}
+self._config_entries = OrderedDict()
 self.includes = []
 self.struct_typedefs = {}
 self._handled = set()
@@ -758,11 +757,8 @@
 
 def realize_struct(self, struct):
 type_name = struct.get_type_name()
-configname = type_name.replace(' ', '__')
-assert not any(x[0] == configname for x in self._config_entries)
-self._config_entries.append(
-(configname, rffi_platform.Struct(type_name, struct.fields)))
-self._TYPES[configname] = struct.TYPE
+entry = rffi_platform.Struct(type_name, struct.fields)
+self._config_entries[entry] = struct.TYPE
 return struct.TYPE
 
 def build_eci(self):
@@ -799,14 +795,12 @@
 if not self._config_entries:
 return
 eci = self.build_eci()
-result = rffi_platform.configure_entries(self._config_entries, eci)
-for name, TYPE in result.iteritems():
+result = rffi_platform.configure_entries(list(self._config_entries), 
eci)
+for entry, TYPE in zip(self._config_entries, result):
 # hack: prevent the source from being pasted into common_header.h
 del TYPE._hints['eci']
-if name in self._TYPES:
-self._TYPES[name].become(TYPE)
-del self._TYPES[name]
-self._config_entries[:] = []
+self._config_entries[entry].become(TYPE)
+self._config_entries.clear()
 
 def convert_type(self, obj, quals=0):
 if isinstance(obj, model.DefinedType):
diff --git a/rpython/rtyper/tool/rffi_platform.py 
b/rpython/rtyper/tool/rffi_platform.py
--- a/rpython/rtyper/tool/rffi_platform.py
+++ b/rpython/rtyper/tool/rffi_platform.py
@@ -131,25 +131,20 @@
 # General interface
 
 class ConfigResult:
-def __init__(self, eci, info, entries):
+def __init__(self, eci, info):
 self.eci = eci
+self.info = info
 self.result = {}
-self.info = info
-self.entries = entries
 
 def get_entry_result(self, entry):
 try:
 return self.result[entry]
 except KeyError:
 pass
-name = self.entries[entry]
-info = self.info[name]
+info = self.info[entry]
 self.result[entry] = entry.build_result(info, self)
 return self.result[entry]
 
-def get_result(self):
-return dict([(name, self.result[entry])
- for entry, name in self.entries.iteritems()])
 
 class _CWriter(object):
 """ A simple class which aggregates config parts
@@ -207,16 +202,18 @@
 "Found legacy attribute %s on CConfig" % attr
 
 eci = CConfig._compilation_info_
-entries = []
+entries = {}
 for key in dir(CConfig):
 value = getattr(CConfig, key)
 if isinstance(value, CConfigEntry):
-entries.append((key, value))
+entries[key] = value
 
+res = {}
 if entries:   # can be empty if there are only CConfigSingleEntries
-res = configure_entries(entries, eci, ignore_errors=ignore_errors)
-else:
-res = {}
+results = configure_entries(
+entries.values(), eci, ignore_errors=ignore_errors)
+for name, result in zip(entries, results):
+res[name] = result
 
 for key in dir(CConfig):
 value = getattr(CConfig, key)
@@ -231,12 +228,12 @@
 def configure_entries(entries, eci, ignore_errors=False):
 writer = _CWriter(eci)
 writer.write_header()
-for key, entry in entries:
-writer.write_entry(key, entry)
+for i, entry in enumerate(entries):
+writer.write_entry(str(i), entry)
 
 writer.start_main()
-for key, entry in entries:
-writer.write_entry_main(key)
+for i, entry in enumerate(entries):
+writer.write_entry_main(str(i))
 writer.close()
 
 infolist = list(run_example_code(
@@ -244,15 +241,11 @@
 assert len(infolist) == len(entries)
 
 resultinfo = {}
-resultentries = {}
-for info, (key, entry) in zip(infolist, entries):
-resultinfo[key] = info
-resultentries[entry] = key
+for info, entry in zip(infolist, entries):
+resultinfo[entry] = info
 
-result = ConfigResult(eci, resultinfo, resultentries)
-for name, entry in entries:
-result.get_entry_result(entry)
-return result.get_result(

[pypy-commit] pypy rpython-hash: Tweaks, possibly fix a bug

2017-01-26 Thread arigo
Author: Armin Rigo 
Branch: rpython-hash
Changeset: r89794:eaa33d328249
Date: 2017-01-26 22:05 +0100
http://bitbucket.org/pypy/pypy/changeset/eaa33d328249/

Log:Tweaks, possibly fix a bug

diff --git a/rpython/rtyper/lltypesystem/rordereddict.py 
b/rpython/rtyper/lltypesystem/rordereddict.py
--- a/rpython/rtyper/lltypesystem/rordereddict.py
+++ b/rpython/rtyper/lltypesystem/rordereddict.py
@@ -642,19 +642,17 @@
 except:
 ll_remove_index(d)
 raise
-rc = d.resize_counter - 3
-if rc <= 0:
+if d.resize_counter <= 3:
 try:
 ll_dict_resize(d)
 reindexed = True
 except:
 ll_remove_index(d)
 raise
-rc = d.resize_counter - 3
-ll_assert(rc > 0, "ll_dict_resize failed?")
 if reindexed:
 ll_call_insert_clean_function(d, hash, d.num_ever_used_items)
-#
+rc = d.resize_counter - 3
+ll_assert(rc > 0, "ll_dict_resize failed?")
 d.resize_counter = rc
 entry = d.entries[d.num_ever_used_items]
 entry.key = key
@@ -799,7 +797,7 @@
 # then maybe it is a better idea to keep it instead of reallocating
 # an identical index very soon.  In this case we update the index now.
 if bool(d.indexes):
-new_estimate = d.num_live_items  * 2
+new_estimate = d.num_live_items * 2
 new_size = DICT_INITSIZE
 while new_size <= new_estimate:
 new_size *= 2
@@ -842,12 +840,13 @@
 # also possible that there are more dead items immediately behind the
 # last one, we reclaim all the dead items at the end of the ordereditem
 # at the same point.
-i = d.num_ever_used_items - 2
-while i >= 0 and not d.entries.valid(i):
+i = index
+while True:
 i -= 1
-j = i + 1
-assert j >= 0
-d.num_ever_used_items = j
+assert i >= 0
+if d.entries.valid(i):# must be at least one
+break
+d.num_ever_used_items = i + 1
 
 # If the dictionary is more than 75% dead items, then clean up the
 # deleted items and remove the index.
@@ -1065,7 +1064,6 @@
 ll_remove_index(d)
 d.num_live_items = 0
 d.num_ever_used_items = 0
-d.resize_counter = DICT_INITSIZE * 2
 return d
 OrderedDictRepr.ll_newdict = staticmethod(ll_newdict)
 
@@ -1232,7 +1230,6 @@
 ll_remove_index(d)
 d.num_live_items = 0
 d.num_ever_used_items = 0
-d.resize_counter = DICT_INITSIZE * 2
 # old_entries.delete() XXX
 ll_dict_clear.oopspec = 'odict.clear(d)'
 
diff --git a/rpython/rtyper/test/test_rdict.py 
b/rpython/rtyper/test/test_rdict.py
--- a/rpython/rtyper/test/test_rdict.py
+++ b/rpython/rtyper/test/test_rdict.py
@@ -1170,6 +1170,7 @@
 self.reference = self.new_reference()
 self.ll_key = r_key.convert_const
 self.ll_value = r_value.convert_const
+self.removed_keys = []
 r_tuple = TupleRepr(rtyper, [r_key, r_value])
 self.TUPLE = r_tuple.lowleveltype
 
@@ -1185,6 +1186,7 @@
 self.ll_delitem(self.l_dict, ll_key)
 del self.reference[key]
 assert not self.ll_contains(self.l_dict, ll_key)
+self.removed_keys.append(key)
 
 def copydict(self):
 self.l_dict = self.ll_copy(self.l_dict)
@@ -1192,6 +1194,8 @@
 
 def cleardict(self):
 self.ll_clear(self.l_dict)
+for key in self.reference:
+self.removed_keys.append(key)
 self.reference.clear()
 assert self.ll_len(self.l_dict) == 0
 
@@ -1207,15 +1211,27 @@
 if self.ll_key(key) == ll_key:
 assert self.ll_value(value) == ll_value
 del self.reference[key]
+self.removed_keys.append(key)
 break
 else:
 raise AssertionError("popitem() returned unexpected key")
 
+def removeindex(self):
+pass # overridden in test_rordereddict
+
 def fullcheck(self):
 assert self.ll_len(self.l_dict) == len(self.reference)
 for key, value in self.reference.iteritems():
 assert (self.ll_getitem(self.l_dict, self.ll_key(key)) ==
 self.ll_value(value))
+for key in self.removed_keys:
+if key not in self.reference:
+try:
+self.ll_getitem(self.l_dict, self.ll_key(key))
+except KeyError:
+pass
+else:
+raise AssertionError("removed key still shows up")
 
 class MappingSM(GenericStateMachine):
 def __init__(self):
@@ -1238,7 +1254,7 @@
 if not self.space:
 return builds(Action, just('setup'), tuples(st_keys, st_values))
 global_actions = [Action('copydict', ()), Action('cleardict', ()),
-  Action('popitem', ())]
+