[pypy-commit] pypy py3.5-siphash24: hg merge rpython-hash

arigo pypy.commits at gmail.com
Tue Jan 31 07:00:18 EST 2017


Author: Armin Rigo <arigo at tunes.org>
Branch: py3.5-siphash24
Changeset: r89850:ecfcf2c386eb
Date: 2017-01-31 11:03 +0100
http://bitbucket.org/pypy/pypy/changeset/ecfcf2c386eb/

Log:	hg merge rpython-hash

diff --git a/rpython/rlib/rsiphash.py b/rpython/rlib/rsiphash.py
--- a/rpython/rlib/rsiphash.py
+++ b/rpython/rlib/rsiphash.py
@@ -59,8 +59,8 @@
     # This uses the same algorithms as CPython 3.5.  The environment
     # variable we read also defaults to "PYTHONHASHSEED".  If needed,
     # a different RPython interpreter can patch the value of the
-    # global variable 'env_var_name', or just pass a different init
-    # function to enable_siphash24().
+    # global variable 'env_var_name', or just patch the whole
+    # initialize_from_env() function.
     value = os.environ.get(env_var_name)
     if value and value != "random":
         with rffi.scoped_view_charp(value) as ptr:
@@ -74,8 +74,8 @@
             seed == lltype.cast_primitive(lltype.Unsigned,
                                           rffi.cast(rffi.ULONG, -1))):
             os.write(2,
-                "PYTHONHASHSEED must be \"random\" or an integer "
-                "in range [0; 4294967295]\n")
+                "%s must be \"random\" or an integer "
+                "in range [0; 4294967295]\n" % (env_var_name,))
             os._exit(1)
         if not seed:
             # disable the randomized hash
@@ -104,28 +104,16 @@
 
 _FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void))
 
-def enable_siphash24(*init):
+def enable_siphash24():
     """
     Enable the use of siphash-2-4 for all RPython strings and unicodes
     in the translated program.  You must call this function anywhere
-    from your interpreter (from a place that is annotated).  Optionally,
-    you can pass a function to call to initialize the state; the default
-    is 'initialize_from_env' above.  Don't call this more than once.
+    from your interpreter (from a place that is annotated).  Don't call
+    more than once.
     """
-    _internal_enable_siphash24()
-    if init:
-        (init_func,) = init
-    else:
-        init_func = initialize_from_env
-    if NonConstant(0):
-        init_func()   # pre-annotate it
-    llop.call_at_startup(lltype.Void, llhelper(_FUNC, init_func))
-
-def _internal_enable_siphash24():
-    pass
 
 class Entry(ExtRegistryEntry):
-    _about_ = _internal_enable_siphash24
+    _about_ = enable_siphash24
 
     def compute_result_annotation(self):
         translator = self.bookkeeper.annotator.translator
@@ -133,9 +121,19 @@
             assert translator.ll_hash_string == ll_hash_string_siphash24
         else:
             translator.ll_hash_string = ll_hash_string_siphash24
+        bk = self.bookkeeper
+        s_callable = bk.immutablevalue(initialize_from_env)
+        key = (enable_siphash24,)
+        bk.emulate_pbc_call(key, s_callable, [])
 
     def specialize_call(self, hop):
         hop.exception_cannot_occur()
+        bk = hop.rtyper.annotator.bookkeeper
+        s_callable = bk.immutablevalue(initialize_from_env)
+        r_callable = hop.rtyper.getrepr(s_callable)
+        ll_init = r_callable.get_unique_llfn().value
+        bk.annotator.translator._call_at_startup.append(ll_init)
+
 
 @rgc.no_collect
 def ll_hash_string_siphash24(ll_s):
diff --git a/rpython/rlib/test/test_rweakvaldict.py b/rpython/rlib/test/test_rweakvaldict.py
--- a/rpython/rlib/test/test_rweakvaldict.py
+++ b/rpython/rlib/test/test_rweakvaldict.py
@@ -1,10 +1,3 @@
-import sys, os
-
-if __name__ == '__main__':
-    # hack for test_translation_prebuilt_2()
-    sys.path.insert(0, os.path.join(os.path.dirname(__file__),
-                                    '..', '..', '..'))
-
 import py
 from rpython.annotator.model import UnionError
 from rpython.rlib import rgc, nonconst
@@ -238,23 +231,16 @@
     fc()
 
 def _test_translation_prebuilt_2():
-    from rpython.rlib import objectmodel
-    objectmodel.set_hash_algorithm("siphash24")
+    from rpython.rlib import rsiphash
     d = RWeakValueDictionary(str, X)
     k1 = "key1"; k2 = "key2"
     x1 = X(); x2 = X()
     d.set(k1, x1)
     d.set(k2, x2)
     def f():
+        rsiphash.enable_siphash24()
         i = nonconst.NonConstant(1)
         assert d.get("key%d" % (i,)) is x1
         assert d.get("key%d" % (i+1,)) is x2
     fc = compile(f, [], gcpolicy="boehm", rweakref=True)
     fc()
-
-def test_translation_prebuilt_2():
-    import subprocess
-    subprocess.check_call([sys.executable, __file__])
-
-if __name__ == "__main__":
-    _test_translation_prebuilt_2()
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -513,9 +513,6 @@
     # __________________________________________________________
     # misc LL operation implementations
 
-    def op_call_at_startup(self, *args):
-        pass
-
     def op_debug_view(self, *ll_objects):
         from rpython.translator.tool.lltracker import track
         track(*ll_objects)
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -539,7 +539,7 @@
     'decode_arg_def':       LLOp(canraise=(Exception,)),
     'getslice':             LLOp(canraise=(Exception,)),
     'check_and_clear_exc':  LLOp(),
-    'call_at_startup':      LLOp(),
+    'call_at_startup':      LLOp(canrun=True),
 
     'threadlocalref_addr':  LLOp(),                   # get (or make) addr of tl
     'threadlocalref_get':   LLOp(sideeffects=False),  # read field (no check)
diff --git a/rpython/rtyper/lltypesystem/opimpl.py b/rpython/rtyper/lltypesystem/opimpl.py
--- a/rpython/rtyper/lltypesystem/opimpl.py
+++ b/rpython/rtyper/lltypesystem/opimpl.py
@@ -742,6 +742,9 @@
 def op_gc_move_out_of_nursery(obj):
     return obj
 
+def op_call_at_startup(init_func):
+    pass    # do nothing
+
 # ____________________________________________________________
 
 def get_op_impl(opname):
diff --git a/rpython/rtyper/lltypesystem/rstr.py b/rpython/rtyper/lltypesystem/rstr.py
--- a/rpython/rtyper/lltypesystem/rstr.py
+++ b/rpython/rtyper/lltypesystem/rstr.py
@@ -384,6 +384,7 @@
 
     @staticmethod
     @dont_inline
+    @jit.dont_look_inside
     def _ll_strhash(s):
         # unlike CPython, there is no reason to avoid to return -1
         # but our malloc initializes the memory to zero, so we use zero as the
diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py
--- a/rpython/translator/c/funcgen.py
+++ b/rpython/translator/c/funcgen.py
@@ -193,6 +193,7 @@
 
     def gen_block(self, block):
         if 1:      # (preserve indentation)
+            self._current_block = block
             myblocknum = self.blocknum[block]
             if block in self.inlinable_blocks:
                 # debug comment
@@ -942,7 +943,16 @@
                 self.expr(op.result))
 
     def OP_CALL_AT_STARTUP(self, op):
-        assert isinstance(op.args[0], Constant)
-        func = self.expr(op.args[0])
+        c = op.args[0]
+        if not isinstance(c, Constant):
+            # Bah, maybe it comes from a same_as(const) just before...
+            # Can occur if running without backendopts
+            for op1 in self._current_block.operations:
+                if op1.result is op.args[0]:
+                    assert op1.opname == "same_as"
+                    c = op1.args[0]
+                    break
+            assert isinstance(c, Constant)
+        func = self.expr(c)
         self.db.call_at_startup.add(func)
         return '/* call_at_startup %s */' % (func,)
diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py
--- a/rpython/translator/c/genc.py
+++ b/rpython/translator/c/genc.py
@@ -156,6 +156,10 @@
         for obj in exports.EXPORTS_obj2name.keys():
             db.getcontainernode(obj)
         exports.clear()
+
+        for ll_func in db.translator._call_at_startup:
+            db.get(ll_func)
+
         db.complete()
 
         self.collect_compilation_info(db)
@@ -822,8 +826,8 @@
             for line in lines:
                 print >> f, '\t'+line
 
-    for extra in database.call_at_startup:
-        print >> f, '\t%s();\t/* call_at_startup */' % (extra,)
+    for ll_init in database.translator._call_at_startup:
+        print >> f, '\t%s();\t/* call_at_startup */' % (database.get(ll_init),)
 
     print >> f, '}'
 
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
@@ -2,11 +2,6 @@
 
 import math
 import sys, os
-
-if __name__ == '__main__':
-    # hack for test_hash_string_siphash24()
-    sys.path.insert(0, os.path.join(os.path.dirname(__file__),
-                                    '..', '..', '..', '..'))
 import py
 
 from rpython.rlib.rstackovf import StackOverflow
@@ -604,8 +599,6 @@
         #    and not e.g. siphash24
 
     def _test_hash_string(self, algo):
-        from rpython.rlib import objectmodel
-        objectmodel.set_hash_algorithm(algo)
         s = "hello"
         u = u"world"
         v = u"\u1234\u2318+\u2bcd\u2102"
@@ -616,6 +609,9 @@
         assert hash_u == compute_hash("world")    #    a latin-1 unicode
         #
         def fn(length):
+            if algo == "siphash24":
+                from rpython.rlib import rsiphash
+                rsiphash.enable_siphash24()
             assert length >= 1
             return str((compute_hash(s),
                         compute_hash(u),
@@ -630,21 +626,23 @@
         f = self.getcompiled(fn, [int])
         res = f(5)
         res = [int(a) for a in res[1:-1].split(",")]
-        assert res[0] == hash_s
-        assert res[1] == hash_u
-        assert res[2] == hash_v
-        assert res[3] == hash_s
-        assert res[4] == hash_u
-        assert res[5] == hash_v
+        if algo == "fnv":
+            assert res[0] == hash_s
+            assert res[1] == hash_u
+            assert res[2] == hash_v
+        else:
+            assert res[0] != hash_s
+            assert res[1] != hash_u
+            assert res[2] != hash_v
+        assert res[3] == res[0]
+        assert res[4] == res[1]
+        assert res[5] == res[2]
 
-    def test_hash_string_rpython(self):
-        self._test_hash_string("rpython")
+    def test_hash_string_fnv(self):
+        self._test_hash_string("fnv")
 
     def test_hash_string_siphash24(self):
-        import subprocess
-        subprocess.check_call([sys.executable, __file__, "siphash24",
-                               self.__class__.__module__,
-                               self.__class__.__name__])
+        self._test_hash_string("siphash24")
 
     def test_list_basic_ops(self):
         def list_basic_ops(i, j):
@@ -945,11 +943,3 @@
         f = self.getcompiled(func, [int])
         res = f(2)
         assert res == 1     # and not 2
-
-
-if __name__ == '__main__':
-    # for test_hash_string_siphash24()
-    algo, clsmodule, clsname = sys.argv[1:]
-    mod = __import__(clsmodule, None, None, [clsname])
-    cls = getattr(mod, clsname)
-    cls()._test_hash_string(algo)
diff --git a/rpython/translator/translator.py b/rpython/translator/translator.py
--- a/rpython/translator/translator.py
+++ b/rpython/translator/translator.py
@@ -38,6 +38,7 @@
         self.graphs = []      # [graph]
         self.callgraph = {}   # {opaque_tag: (caller-graph, callee-graph)}
         self._prebuilt_graphs = {}   # only used by the pygame viewer
+        self._call_at_startup = []
 
     def buildflowgraph(self, func, mute_dot=False):
         """Get the flow graph for a function."""


More information about the pypy-commit mailing list