[pypy-commit] pypy py3.5: hg merge default
arigo
pypy.commits at gmail.com
Thu Jan 26 03:35:43 EST 2017
Author: Armin Rigo <arigo at tunes.org>
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
+ assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
+ "cannot write fields")
+
complete_struct_or_union(BStruct, [('a1', BInt, -1),
('a2', BInt, -1)])
p = newp(BStructPtr, None)
@@ -749,8 +755,29 @@
assert s.a2 == 123
py.test.raises(OverflowError, "s.a1 = sys.maxsize+1")
assert s.a1 == 0
- py.test.raises(AttributeError, "p.foobar")
- py.test.raises(AttributeError, "s.foobar")
+ e = py.test.raises(AttributeError, "p.foobar")
+ assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
+ e = py.test.raises(AttributeError, "p.foobar = 42")
+ assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
+ e = py.test.raises(AttributeError, "s.foobar")
+ assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
+ e = py.test.raises(AttributeError, "s.foobar = 42")
+ assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
+ j = cast(BInt, 42)
+ e = py.test.raises(AttributeError, "j.foobar")
+ assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
+ e = py.test.raises(AttributeError, "j.foobar = 42")
+ assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
+ j = cast(new_pointer_type(BInt), 42)
+ e = py.test.raises(AttributeError, "j.foobar")
+ assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
+ e = py.test.raises(AttributeError, "j.foobar = 42")
+ assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
+ pp = newp(new_pointer_type(BStructPtr), p)
+ e = py.test.raises(AttributeError, "pp.a1")
+ assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'"
+ e = py.test.raises(AttributeError, "pp.a1 = 42")
+ assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'"
def test_union_instance():
BInt = new_primitive_type("int")
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -437,6 +437,9 @@
for i in range(len(self.cached_attrs)):
self.cached_attrs[i] = None
+ def _cleanup_(self):
+ self.clear()
+
# ____________________________________________________________
# object implementation
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -72,6 +72,10 @@
class MethodCache(object):
def __init__(self, space):
+ # Note: these attributes never change which object they contain,
+ # so reading 'cache.versions' for example is constant-folded.
+ # The actual list in 'cache.versions' is not a constant, of
+ # course.
SIZE = 1 << space.config.objspace.std.methodcachesizeexp
self.versions = [None] * SIZE
self.names = [None] * SIZE
@@ -89,6 +93,9 @@
for i in range(len(self.lookup_where)):
self.lookup_where[i] = None_None
+ def _cleanup_(self):
+ self.clear()
+
class _Global(object):
weakref_warning_printed = False
_global = _Global()
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/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -520,10 +520,22 @@
# ----------
HASH_ALGORITHM = "rpython" # XXX Is there a better name?
+HASH_ALGORITHM_FIXED = False
-def _hash_string(s):
- """The algorithm behind compute_hash() for a string or a unicode."""
+ at not_rpython
+def set_hash_algorithm(algo):
+ """Must be called very early, before any string is hashed with
+ compute_hash()!"""
+ global HASH_ALGORITHM
+ if HASH_ALGORITHM != algo:
+ assert not HASH_ALGORITHM_FIXED, "compute_hash() already called!"
+ assert algo in ("rpython", "siphash24")
+ HASH_ALGORITHM = algo
+
+
+def _hash_string_rpython(s):
from rpython.rlib.rarithmetic import intmask
+
length = len(s)
if length == 0:
return -1
@@ -535,6 +547,101 @@
x ^= length
return intmask(x)
+
+ at not_rpython
+def _hash_string_siphash24(s):
+ """This version is called when untranslated only."""
+ import array
+ from rpython.rlib.rsiphash import siphash24
+ from rpython.rtyper.lltypesystem import lltype, rffi
+ from rpython.rlib.rarithmetic import intmask
+
+ if not isinstance(s, str):
+ if isinstance(s, unicode):
+ lst = map(ord, s)
+ else:
+ lst = map(ord, s.chars) # for rstr.STR or UNICODE
+ # NOTE: a latin-1 unicode string must have the same hash as the
+ # corresponding byte string.
+ if all(n <= 0xFF for n in lst):
+ kind = "B"
+ elif rffi.sizeof(lltype.UniChar) == 4:
+ kind = "I"
+ else:
+ kind = "H"
+ s = array.array(kind, lst).tostring()
+ ptr = rffi.str2charp(s)
+ x = siphash24(ptr, len(s))
+ rffi.free_charp(ptr)
+ return intmask(x)
+
+def ll_hash_string_siphash24(ll_s):
+ """Called from lltypesystem/rstr.py. 'll_s' is a rstr.STR or UNICODE."""
+ from rpython.rlib.rsiphash import siphash24
+ from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr
+ from rpython.rlib.rarithmetic import intmask
+
+ length = len(ll_s.chars)
+ if lltype.typeOf(ll_s).TO.chars.OF == lltype.Char:
+ # no GC operation from here!
+ addr = rstr._get_raw_buf_string(rstr.STR, ll_s, 0)
+ else:
+ # NOTE: a latin-1 unicode string must have the same hash as the
+ # corresponding byte string. If the unicode is all within
+ # 0-255, then we need to allocate a byte buffer and copy the
+ # latin-1 encoding in it manually.
+ for i in range(length):
+ if ord(ll_s.chars[i]) > 0xFF:
+ # no GC operation from here!
+ addr = rstr._get_raw_buf_unicode(rstr.UNICODE, ll_s, 0)
+ length *= rffi.sizeof(rstr.UNICODE.chars.OF)
+ break
+ else:
+ p = lltype.malloc(rffi.CCHARP.TO, length, flavor='raw')
+ i = 0
+ while i < length:
+ p[i] = chr(ord(ll_s.chars[i]))
+ i += 1
+ x = siphash24(llmemory.cast_ptr_to_adr(p), length)
+ lltype.free(p, flavor='raw')
+ return intmask(x)
+ x = siphash24(addr, length)
+ keepalive_until_here(ll_s)
+ return intmask(x)
+ll_hash_string_siphash24._jit_look_inside_ = False
+
+
+ at not_rpython
+def _hash_string(s):
+ """The algorithm behind compute_hash() for a string or a unicode.
+ This version is only for untranslated usage, and 's' is a str or unicode.
+ """
+ global HASH_ALGORITHM_FIXED
+ HASH_ALGORITHM_FIXED = True
+ if HASH_ALGORITHM == "rpython":
+ return _hash_string_rpython(s)
+ if HASH_ALGORITHM == "siphash24":
+ return _hash_string_siphash24(s)
+ raise NotImplementedError
+
+def ll_hash_string(ll_s):
+ """The algorithm behind compute_hash() for a string or a unicode.
+ This version is called from lltypesystem/rstr.py, and 'll_s' is a
+ rstr.STR or rstr.UNICODE.
+ """
+ if not we_are_translated():
+ global HASH_ALGORITHM_FIXED
+ HASH_ALGORITHM_FIXED = True
+ if HASH_ALGORITHM == "rpython":
+ return _hash_string_rpython(ll_s.chars)
+ if HASH_ALGORITHM == "siphash24":
+ if we_are_translated():
+ return ll_hash_string_siphash24(ll_s)
+ else:
+ return _hash_string_siphash24(ll_s)
+ raise NotImplementedError
+
+
def _hash_float(f):
"""The algorithm behind compute_hash() for a float.
This implementation is identical to the CPython implementation,
diff --git a/rpython/rlib/rsiphash.py b/rpython/rlib/rsiphash.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rsiphash.py
@@ -0,0 +1,157 @@
+import sys, os, struct
+from contextlib import contextmanager
+from rpython.rlib import rarithmetic
+from rpython.rlib.objectmodel import not_rpython, always_inline
+from rpython.rlib.rgc import no_collect
+from rpython.rlib.rarithmetic import r_uint64
+from rpython.rlib.rawstorage import misaligned_is_fine
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
+from rpython.rtyper.lltypesystem.lloperation import llop
+
+
+if sys.byteorder == 'little':
+ def _le64toh(x):
+ return x
+else:
+ _le64toh = rarithmetic.byteswap
+
+
+# Initialize the values of the secret seed: two 64-bit constants.
+# CPython picks a new seed every time 'python' starts. PyPy cannot do
+# 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.
+
+ at not_rpython
+def select_random_seed():
+ global k0, k1 # note: the globals k0, k1 are already byte-swapped
+ v0, v1 = struct.unpack("QQ", os.urandom(16))
+ k0 = r_uint64(v0)
+ k1 = r_uint64(v1)
+
+select_random_seed()
+
+ at contextmanager
+def choosen_seed(new_k0, new_k1, test_misaligned_path=False):
+ global k0, k1, misaligned_is_fine
+ old = k0, k1, misaligned_is_fine
+ k0 = _le64toh(r_uint64(new_k0))
+ k1 = _le64toh(r_uint64(new_k1))
+ if test_misaligned_path:
+ misaligned_is_fine = False
+ yield
+ k0, k1, misaligned_is_fine = old
+
+def get_current_seed():
+ return _le64toh(k0), _le64toh(k1)
+
+
+magic0 = r_uint64(0x736f6d6570736575)
+magic1 = r_uint64(0x646f72616e646f6d)
+magic2 = r_uint64(0x6c7967656e657261)
+magic3 = r_uint64(0x7465646279746573)
+
+
+ at always_inline
+def _rotate(x, b):
+ return (x << b) | (x >> (64 - b))
+
+ at always_inline
+def _half_round(a, b, c, d, s, t):
+ a += b
+ c += d
+ b = _rotate(b, s) ^ a
+ d = _rotate(d, t) ^ c
+ a = _rotate(a, 32)
+ return a, b, c, d
+
+ at always_inline
+def _double_round(v0, v1, v2, v3):
+ v0,v1,v2,v3 = _half_round(v0,v1,v2,v3,13,16)
+ v2,v1,v0,v3 = _half_round(v2,v1,v0,v3,17,21)
+ v0,v1,v2,v3 = _half_round(v0,v1,v2,v3,13,16)
+ v2,v1,v0,v3 = _half_round(v2,v1,v0,v3,17,21)
+ return v0, v1, v2, v3
+
+
+ at no_collect
+def siphash24(addr_in, size):
+ """Takes an address pointer and a size. Returns the hash as a r_uint64,
+ which can then be casted to the expected type."""
+
+ direct = (misaligned_is_fine or
+ (rffi.cast(lltype.Signed, addr_in) & 7) == 0)
+
+ b = r_uint64(size) << 56
+ v0 = k0 ^ magic0
+ v1 = k1 ^ magic1
+ v2 = k0 ^ magic2
+ v3 = k1 ^ magic3
+
+ index = 0
+ if direct:
+ while size >= 8:
+ mi = llop.raw_load(rffi.ULONGLONG, addr_in, index)
+ mi = _le64toh(mi)
+ size -= 8
+ index += 8
+ v3 ^= mi
+ v0, v1, v2, v3 = _double_round(v0, v1, v2, v3)
+ v0 ^= mi
+ else:
+ while size >= 8:
+ mi = (
+ r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index)) |
+ r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 1)) << 8 |
+ r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 2)) << 16 |
+ r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 3)) << 24 |
+ r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 4)) << 32 |
+ r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 5)) << 40 |
+ r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 6)) << 48 |
+ r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 7)) << 56
+ )
+ mi = _le64toh(mi)
+ size -= 8
+ index += 8
+ v3 ^= mi
+ v0, v1, v2, v3 = _double_round(v0, v1, v2, v3)
+ v0 ^= mi
+
+ t = r_uint64(0)
+ if size == 7:
+ t = r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 6)) << 48
+ size = 6
+ if size == 6:
+ t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 5)) << 40
+ size = 5
+ if size == 5:
+ t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 4)) << 32
+ size = 4
+ if size == 4:
+ if direct:
+ t |= r_uint64(llop.raw_load(rffi.UINT, addr_in, index))
+ size = 0
+ else:
+ t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 3)) << 24
+ size = 3
+ if size == 3:
+ t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 2)) << 16
+ size = 2
+ if size == 2:
+ t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 1)) << 8
+ size = 1
+ if size == 1:
+ t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index))
+ size = 0
+ assert size == 0
+
+ b |= _le64toh(t)
+
+ v3 ^= b
+ v0, v1, v2, v3 = _double_round(v0, v1, v2, v3)
+ v0 ^= b
+ v2 ^= 0xff
+ v0, v1, v2, v3 = _double_round(v0, v1, v2, v3)
+ v0, v1, v2, v3 = _double_round(v0, v1, v2, v3)
+
+ return (v0 ^ v1) ^ (v2 ^ v3)
diff --git a/rpython/rlib/test/test_rsiphash.py b/rpython/rlib/test/test_rsiphash.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/test/test_rsiphash.py
@@ -0,0 +1,44 @@
+from rpython.rlib.rsiphash import siphash24, choosen_seed
+from rpython.rtyper.lltypesystem import llmemory, rffi
+
+
+CASES = [
+ (2323638336262702335 , ""),
+ (5150479602681463644 , "h"),
+ (1013213613370725794 , "he"),
+ (7028032310911240238 , "hel"),
+ (9535960132410784494 , "hell"),
+ (3256502711089771242 , "hello"),
+ (2389188832234450176 , "hello "),
+ (13253855839845990393, "hello w"),
+ (7850036019043917323 , "hello wo"),
+ (14283308628425005953, "hello wor"),
+ (9605549962279590084 , "hello worl"),
+ (16371281469632894235, "hello world"),
+ (7298637955795769949 , "hello world\x9a"),
+ (13530878135053370821, "hello world\xf3\x80"),
+ (1643533543579802994 , "\xffhel\x82lo world\xbc"),
+ (14632093238728197380, "hexlylxox rewqw"),
+ (3434253029196696424 , "hexlylxox rewqws"),
+ (9855754545877066788 , "hexlylxox rewqwsv"),
+ (5233065012564472454 , "hexlylxox rewqwkashdw89"),
+ (16768585622569081808, "hexlylxox rewqwkeashdw89"),
+ (17430482483431293463, "HEEExlylxox rewqwkashdw89"),
+ (695783005783737705 , "hello woadwealidewd 3829ez 32ig dxwaebderld"),
+]
+
+def check(s):
+ p = rffi.str2charp(s)
+ q = rffi.str2charp('?' + s)
+ with choosen_seed(0x8a9f065a358479f4, 0x11cb1e9ee7f40e1f,
+ test_misaligned_path=True):
+ x = siphash24(llmemory.cast_ptr_to_adr(p), len(s))
+ y = siphash24(llmemory.cast_ptr_to_adr(rffi.ptradd(q, 1)), len(s))
+ rffi.free_charp(p)
+ rffi.free_charp(q)
+ assert x == y
+ return x
+
+def test_siphash24():
+ for expected, string in CASES:
+ assert check(string) == expected
diff --git a/rpython/rtyper/lltypesystem/rbytearray.py b/rpython/rtyper/lltypesystem/rbytearray.py
--- a/rpython/rtyper/lltypesystem/rbytearray.py
+++ b/rpython/rtyper/lltypesystem/rbytearray.py
@@ -8,10 +8,10 @@
def mallocbytearray(size):
return lltype.malloc(BYTEARRAY, size)
-_, _, copy_bytearray_contents = rstr._new_copy_contents_fun(BYTEARRAY, BYTEARRAY,
+_, _, copy_bytearray_contents, _ = rstr._new_copy_contents_fun(BYTEARRAY, BYTEARRAY,
lltype.Char,
'bytearray')
-_, _, copy_bytearray_contents_from_str = rstr._new_copy_contents_fun(rstr.STR,
+_, _, copy_bytearray_contents_from_str, _ = rstr._new_copy_contents_fun(rstr.STR,
BYTEARRAY,
lltype.Char,
'bytearray_from_str')
diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -1073,8 +1073,9 @@
if size is None:
size = llmemory.sizeof(tp) # a symbolic result in this case
return size
- if isinstance(tp, lltype.Ptr) or tp is llmemory.Address:
- return globals()['r_void*'].BITS/8
+ if (tp is lltype.Signed or isinstance(tp, lltype.Ptr)
+ or tp is llmemory.Address):
+ return LONG_BIT/8
if tp is lltype.Char or tp is lltype.Bool:
return 1
if tp is lltype.UniChar:
@@ -1087,8 +1088,6 @@
# :-/
return sizeof_c_type("long double")
assert isinstance(tp, lltype.Number)
- if tp is lltype.Signed:
- return LONG_BIT/8
return tp._type.BITS/8
sizeof._annspecialcase_ = 'specialize:memo'
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
@@ -3,7 +3,7 @@
from rpython.annotator import model as annmodel
from rpython.rlib import jit, types
from rpython.rlib.objectmodel import (malloc_zero_filled, we_are_translated,
- _hash_string, keepalive_until_here, specialize, enforceargs)
+ ll_hash_string, keepalive_until_here, specialize, enforceargs)
from rpython.rlib.signature import signature
from rpython.rlib.rarithmetic import ovfcheck
from rpython.rtyper.error import TyperError
@@ -44,11 +44,13 @@
mallocstr = new_malloc(STR, 'mallocstr')
mallocunicode = new_malloc(UNICODE, 'mallocunicode')
+ at specialize.memo()
def emptystrfun():
- return emptystr
+ return string_repr.convert_const("")
+ at specialize.memo()
def emptyunicodefun():
- return emptyunicode
+ return unicode_repr.convert_const(u'')
def _new_copy_contents_fun(SRC_TP, DST_TP, CHAR_TP, name):
@specialize.arg(0)
@@ -136,15 +138,19 @@
copy_raw_to_string = func_with_new_name(copy_raw_to_string,
'copy_raw_to_%s' % name)
- return copy_string_to_raw, copy_raw_to_string, copy_string_contents
+ return (copy_string_to_raw, copy_raw_to_string, copy_string_contents,
+ _get_raw_buf)
(copy_string_to_raw,
copy_raw_to_string,
- copy_string_contents) = _new_copy_contents_fun(STR, STR, Char, 'string')
+ copy_string_contents,
+ _get_raw_buf_string) = _new_copy_contents_fun(STR, STR, Char, 'string')
(copy_unicode_to_raw,
copy_raw_to_unicode,
- copy_unicode_contents) = _new_copy_contents_fun(UNICODE, UNICODE, UniChar, 'unicode')
+ copy_unicode_contents,
+ _get_raw_buf_unicode) = _new_copy_contents_fun(UNICODE, UNICODE, UniChar,
+ 'unicode')
CONST_STR_CACHE = WeakValueDictionary()
CONST_UNICODE_CACHE = WeakValueDictionary()
@@ -382,7 +388,7 @@
# but our malloc initializes the memory to zero, so we use zero as the
# special non-computed-yet value. Also, jit.conditional_call_elidable
# always checks for zero, for now.
- x = _hash_string(s.chars)
+ x = ll_hash_string(s)
if x == 0:
x = 29872897
s.hash = x
@@ -1276,8 +1282,6 @@
char_repr.ll = LLHelpers
unichar_repr.ll = LLHelpers
unicode_repr = UnicodeRepr()
-emptystr = string_repr.convert_const("")
-emptyunicode = unicode_repr.convert_const(u'')
StringRepr.repr = string_repr
UnicodeRepr.repr = unicode_repr
@@ -1336,14 +1340,6 @@
string_repr.iterator_repr = StringIteratorRepr()
unicode_repr.iterator_repr = UnicodeIteratorRepr()
-# these should be in rclass, but circular imports prevent (also it's
-# not that insane that a string constant is built in this file).
-
-instance_str_prefix = string_repr.convert_const("<")
-instance_str_infix = string_repr.convert_const(" object at 0x")
-instance_str_suffix = string_repr.convert_const(">")
-
-null_str = string_repr.convert_const("NULL")
-
-unboxed_instance_str_prefix = string_repr.convert_const("<unboxed ")
-unboxed_instance_str_suffix = string_repr.convert_const(">")
+ at specialize.memo()
+def conststr(s):
+ return string_repr.convert_const(s)
diff --git a/rpython/rtyper/lltypesystem/rtagged.py b/rpython/rtyper/lltypesystem/rtagged.py
--- a/rpython/rtyper/lltypesystem/rtagged.py
+++ b/rpython/rtyper/lltypesystem/rtagged.py
@@ -117,9 +117,9 @@
from rpython.rtyper.lltypesystem import rstr
from rpython.rtyper.rint import signed_repr
llstr1 = signed_repr.ll_str(ll_unboxed_to_int(i))
- return rstr.ll_strconcat(rstr.unboxed_instance_str_prefix,
+ return rstr.ll_strconcat(rstr.conststr("<unboxed "),
rstr.ll_strconcat(llstr1,
- rstr.unboxed_instance_str_suffix))
+ rstr.conststr(">")))
else:
return InstanceRepr.ll_str(self, i)
diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py
--- a/rpython/rtyper/rclass.py
+++ b/rpython/rtyper/rclass.py
@@ -840,18 +840,18 @@
from rpython.rtyper.lltypesystem.ll_str import ll_int2hex
from rpython.rlib.rarithmetic import r_uint
if not i:
- return rstr.null_str
+ return rstr.conststr("NULL")
instance = cast_pointer(OBJECTPTR, i)
# Two choices: the first gives a fast answer but it can change
# (typically only once) during the life of the object.
#uid = r_uint(cast_ptr_to_int(i))
uid = r_uint(llop.gc_id(lltype.Signed, i))
#
- res = rstr.instance_str_prefix
+ res = rstr.conststr("<")
res = rstr.ll_strconcat(res, instance.typeptr.name)
- res = rstr.ll_strconcat(res, rstr.instance_str_infix)
+ res = rstr.ll_strconcat(res, rstr.conststr(" object at 0x"))
res = rstr.ll_strconcat(res, ll_int2hex(uid, False))
- res = rstr.ll_strconcat(res, rstr.instance_str_suffix)
+ res = rstr.ll_strconcat(res, rstr.conststr(">"))
return res
def get_ll_eq_function(self):
@@ -1092,7 +1092,6 @@
except StandardError:
return None
-
# ____________________________________________________________
#
# Low-level implementation of operations on classes and instances
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
@@ -1,8 +1,12 @@
from __future__ import with_statement
import math
-import sys
+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
@@ -597,6 +601,49 @@
assert res[3] == compute_hash(d)
assert res[4] == compute_hash(("Hi", None, (7.5, 2, d)))
+ 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"
+ hash_s = compute_hash(s)
+ hash_u = compute_hash(u)
+ hash_v = compute_hash(v)
+ assert hash_s == compute_hash(u"hello") # same hash because it's
+ assert hash_u == compute_hash("world") # a latin-1 unicode
+ #
+ def fn(length):
+ assert length >= 1
+ return str((compute_hash(s),
+ compute_hash(u),
+ compute_hash(v),
+ compute_hash(s[0] + s[1:length]),
+ compute_hash(u[0] + u[1:length]),
+ compute_hash(v[0] + v[1:length]),
+ ))
+
+ assert fn(5) == str((hash_s, hash_u, hash_v, hash_s, hash_u, hash_v))
+
+ 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
+
+ def test_hash_string_rpython(self):
+ self._test_hash_string("rpython")
+
+ def test_hash_string_siphash24(self):
+ import subprocess
+ subprocess.check_call([sys.executable, __file__, "siphash24",
+ self.__class__.__module__,
+ self.__class__.__name__])
+
def test_list_basic_ops(self):
def list_basic_ops(i, j):
l = [1, 2, 3]
@@ -896,3 +943,11 @@
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/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):
More information about the pypy-commit
mailing list