[pypy-svn] r72843 - in pypy/trunk/pypy: lib lib/app_test module/_socket/test module/readline/test objspace/std rpython/lltypesystem rpython/test rpython/tool rpython/tool/test translator/c translator/c/test
arigo at codespeak.net
arigo at codespeak.net
Thu Mar 25 19:29:55 CET 2010
Author: arigo
Date: Thu Mar 25 19:29:52 2010
New Revision: 72843
Modified:
pypy/trunk/pypy/lib/app_test/test_dbm_extra.py
pypy/trunk/pypy/lib/resource.py
pypy/trunk/pypy/module/_socket/test/test_sock_app.py
pypy/trunk/pypy/module/readline/test/test_c_readline.py
pypy/trunk/pypy/module/readline/test/test_with_pypy.py
pypy/trunk/pypy/objspace/std/typeobject.py
pypy/trunk/pypy/rpython/lltypesystem/lltype.py
pypy/trunk/pypy/rpython/lltypesystem/opimpl.py
pypy/trunk/pypy/rpython/test/test_rbuiltin.py
pypy/trunk/pypy/rpython/test/test_rdict.py
pypy/trunk/pypy/rpython/test/test_rint.py
pypy/trunk/pypy/rpython/tool/rffi_platform.py
pypy/trunk/pypy/rpython/tool/rfficache.py
pypy/trunk/pypy/rpython/tool/test/test_rffi_platform.py
pypy/trunk/pypy/translator/c/genc.py
pypy/trunk/pypy/translator/c/node.py
pypy/trunk/pypy/translator/c/test/test_lltyped.py
pypy/trunk/pypy/translator/c/test/test_newgc.py
pypy/trunk/pypy/translator/c/test/test_typed.py
Log:
Merge branch/fix-64.
Modified: pypy/trunk/pypy/lib/app_test/test_dbm_extra.py
==============================================================================
--- pypy/trunk/pypy/lib/app_test/test_dbm_extra.py (original)
+++ pypy/trunk/pypy/lib/app_test/test_dbm_extra.py Thu Mar 25 19:29:52 2010
@@ -1,6 +1,9 @@
import py
-from pypy.lib import dbm
from pypy.tool.udir import udir
+try:
+ from pypy.lib import dbm
+except ImportError, e:
+ py.test.skip(e)
def test_get():
path = str(udir.join('test_dbm_extra.test_get'))
Modified: pypy/trunk/pypy/lib/resource.py
==============================================================================
--- pypy/trunk/pypy/lib/resource.py (original)
+++ pypy/trunk/pypy/lib/resource.py Thu Mar 25 19:29:52 2010
@@ -28,8 +28,8 @@
class timeval(Structure):
_fields_ = (
- ("tv_sec", c_int),
- ("tv_usec", c_int),
+ ("tv_sec", c_long),
+ ("tv_usec", c_long),
)
def __str__(self):
return "(%s, %s)" % (self.tv_sec, self.tv_usec)
Modified: pypy/trunk/pypy/module/_socket/test/test_sock_app.py
==============================================================================
--- pypy/trunk/pypy/module/_socket/test/test_sock_app.py (original)
+++ pypy/trunk/pypy/module/_socket/test/test_sock_app.py Thu Mar 25 19:29:52 2010
@@ -32,13 +32,17 @@
def test_gethostbyaddr():
host = "localhost"
+ expected = socket.gethostbyaddr(host)
+ expecteds = (expected, expected[:2]+(['0.0.0.0'],))
ip = space.appexec([w_socket, space.wrap(host)],
"(_socket, host): return _socket.gethostbyaddr(host)")
- assert space.unwrap(ip) == socket.gethostbyaddr(host)
+ assert space.unwrap(ip) in expecteds
host = "127.0.0.1"
+ expected = socket.gethostbyaddr(host)
+ expecteds = (expected, expected[:2]+(['0.0.0.0'],))
ip = space.appexec([w_socket, space.wrap(host)],
"(_socket, host): return _socket.gethostbyaddr(host)")
- assert space.unwrap(ip) == socket.gethostbyaddr(host)
+ assert space.unwrap(ip) in expecteds
def test_getservbyname():
name = "smtp"
Modified: pypy/trunk/pypy/module/readline/test/test_c_readline.py
==============================================================================
--- pypy/trunk/pypy/module/readline/test/test_c_readline.py (original)
+++ pypy/trunk/pypy/module/readline/test/test_c_readline.py Thu Mar 25 19:29:52 2010
@@ -2,8 +2,14 @@
Directly test the basic ctypes wrappers.
"""
+import py
from pypy import conftest; conftest.translation_test_so_skip_if_appdirect()
-from pypy.module.readline import c_readline
+from pypy.rpython.tool import rffi_platform as platform
+
+try:
+ from pypy.module.readline import c_readline
+except platform.CompilationError, e:
+ py.test.skip(e)
def test_basic_import():
Modified: pypy/trunk/pypy/module/readline/test/test_with_pypy.py
==============================================================================
--- pypy/trunk/pypy/module/readline/test/test_with_pypy.py (original)
+++ pypy/trunk/pypy/module/readline/test/test_with_pypy.py Thu Mar 25 19:29:52 2010
@@ -3,7 +3,14 @@
in the PyPy interpreter, itself running on top of CPython
"""
+import py
from pypy.conftest import gettestobjspace
+from pypy.rpython.tool import rffi_platform as platform
+
+try:
+ from pypy.module.readline import c_readline
+except platform.CompilationError, e:
+ py.test.skip(e)
class AppTestReadline:
Modified: pypy/trunk/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/typeobject.py (original)
+++ pypy/trunk/pypy/objspace/std/typeobject.py Thu Mar 25 19:29:52 2010
@@ -264,7 +264,8 @@
@purefunction
def _pure_lookup_where_with_method_cache(w_self, name, version_tag):
space = w_self.space
- SHIFT = r_uint.BITS - space.config.objspace.std.methodcachesizeexp
+ SHIFT2 = r_uint.BITS - space.config.objspace.std.methodcachesizeexp
+ SHIFT1 = SHIFT2 - 5
version_tag_as_int = current_object_addr_as_int(version_tag)
# ^^^Note: if the version_tag object is moved by a moving GC, the
# existing method cache entries won't be found any more; new
@@ -273,7 +274,12 @@
# the time - so using the fast current_object_addr_as_int() instead
# of a slower solution like hash() is still a good trade-off.
hash_name = compute_hash(name)
- method_hash = r_uint(intmask(version_tag_as_int * hash_name)) >> SHIFT
+ product = intmask(version_tag_as_int * hash_name)
+ method_hash = (r_uint(product) ^ (r_uint(product) << SHIFT1)) >> SHIFT2
+ # ^^^Note2: we used to just take product>>SHIFT2, but on 64-bit
+ # platforms SHIFT2 is really large, and we loose too much information
+ # that way (as shown by failures of the tests that typically have
+ # method names like 'f' who hash to a number that has only ~33 bits).
cached_version_tag = space.method_cache_versions[method_hash]
if cached_version_tag is version_tag:
cached_name = space.method_cache_names[method_hash]
Modified: pypy/trunk/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/lltype.py (original)
+++ pypy/trunk/pypy/rpython/lltypesystem/lltype.py Thu Mar 25 19:29:52 2010
@@ -1494,8 +1494,13 @@
if n < 0:
raise ValueError, "negative array length"
_parentable.__init__(self, TYPE)
- self.items = [TYPE.OF._allocate(initialization=initialization, parent=self, parentindex=j)
- for j in range(n)]
+ try:
+ myrange = range(n)
+ except OverflowError:
+ raise MemoryError("definitely too many items")
+ self.items = [TYPE.OF._allocate(initialization=initialization,
+ parent=self, parentindex=j)
+ for j in myrange]
if parent is not None:
self._setparentstructure(parent, parentindex)
Modified: pypy/trunk/pypy/rpython/lltypesystem/opimpl.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/opimpl.py (original)
+++ pypy/trunk/pypy/rpython/lltypesystem/opimpl.py Thu Mar 25 19:29:52 2010
@@ -18,13 +18,20 @@
# global synonyms for some types
from pypy.rlib.rarithmetic import intmask
-from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
+from pypy.rlib.rarithmetic import r_int, r_uint, r_longlong, r_ulonglong
-type_by_name = {
+if r_longlong is r_int:
+ r_longlong_arg = (r_longlong, int)
+ r_longlong_result = int
+else:
+ r_longlong_arg = r_longlong
+ r_longlong_result = r_longlong
+
+argtype_by_name = {
'int': int,
'float': float,
'uint': r_uint,
- 'llong': r_longlong,
+ 'llong': r_longlong_arg,
'ullong': r_ulonglong,
}
@@ -56,9 +63,9 @@
adjust_result = intmask
else:
adjust_result = no_op
- assert typname in type_by_name, "%s: not a primitive op" % (
+ assert typname in argtype_by_name, "%s: not a primitive op" % (
fullopname,)
- argtype = type_by_name[typname]
+ argtype = argtype_by_name[typname]
if opname in ops_unary:
def op_function(x):
@@ -226,16 +233,16 @@
return r
def op_llong_floordiv(x, y):
- assert isinstance(x, r_longlong)
- assert isinstance(y, r_longlong)
+ assert isinstance(x, r_longlong_arg)
+ assert isinstance(y, r_longlong_arg)
r = x//y
if x^y < 0 and x%y != 0:
r += 1
return r
def op_llong_mod(x, y):
- assert isinstance(x, r_longlong)
- assert isinstance(y, r_longlong)
+ assert isinstance(x, r_longlong_arg)
+ assert isinstance(y, r_longlong_arg)
r = x%y
if x^y < 0 and x%y != 0:
r -= y
@@ -258,7 +265,7 @@
return float(u)
def op_cast_longlong_to_float(i):
- assert type(i) is r_longlong
+ assert isinstance(i, r_longlong_arg)
# take first 31 bits
li = float(int(i & r_longlong(0x7fffffff)))
ui = float(int(i >> 31)) * float(0x80000000)
@@ -290,7 +297,7 @@
small = f / r
high = int(small)
truncated = int((small - high) * r)
- return r_longlong(high) * 0x100000000 + truncated
+ return r_longlong_result(high) * 0x100000000 + truncated
def op_cast_char_to_int(b):
assert type(b) is str and len(b) == 1
@@ -314,10 +321,10 @@
def op_cast_int_to_longlong(b):
assert type(b) is int
- return r_longlong(b)
+ return r_longlong_result(b)
def op_truncate_longlong_to_int(b):
- assert type(b) is r_longlong
+ assert isinstance(b, r_longlong_arg)
return intmask(b)
def op_cast_pointer(RESTYPE, obj):
Modified: pypy/trunk/pypy/rpython/test/test_rbuiltin.py
==============================================================================
--- pypy/trunk/pypy/rpython/test/test_rbuiltin.py (original)
+++ pypy/trunk/pypy/rpython/test/test_rbuiltin.py Thu Mar 25 19:29:52 2010
@@ -5,7 +5,8 @@
from pypy.rlib.debug import llinterpcall
from pypy.rpython.lltypesystem import lltype
from pypy.tool import udir
-from pypy.rlib.rarithmetic import r_uint, intmask, r_longlong, r_ulonglong
+from pypy.rlib.rarithmetic import intmask
+from pypy.rlib.rarithmetic import r_int, r_uint, r_longlong, r_ulonglong
from pypy.annotation.builtin import *
from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
from pypy.rpython.lltypesystem import rffi
@@ -526,11 +527,21 @@
return rffi.cast(rffi.VOIDP, v)
res = self.interpret(llfn, [r_ulonglong(0)])
assert res == lltype.nullptr(rffi.VOIDP.TO)
+ #
def llfn(v):
return rffi.cast(rffi.LONGLONG, v)
res = self.interpret(llfn, [lltype.nullptr(rffi.VOIDP.TO)])
assert res == 0
- assert isinstance(res, r_longlong)
+ if r_longlong is not r_int:
+ assert isinstance(res, r_longlong)
+ else:
+ assert isinstance(res, int)
+ #
+ def llfn(v):
+ return rffi.cast(rffi.ULONGLONG, v)
+ res = self.interpret(llfn, [lltype.nullptr(rffi.VOIDP.TO)])
+ assert res == 0
+ assert isinstance(res, r_ulonglong)
class TestOOtype(BaseTestRbuiltin, OORtypeMixin):
Modified: pypy/trunk/pypy/rpython/test/test_rdict.py
==============================================================================
--- pypy/trunk/pypy/rpython/test/test_rdict.py (original)
+++ pypy/trunk/pypy/rpython/test/test_rdict.py Thu Mar 25 19:29:52 2010
@@ -4,7 +4,7 @@
from pypy.rpython.lltypesystem import rdict, rstr
from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
from pypy.rlib.objectmodel import r_dict
-from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
+from pypy.rlib.rarithmetic import r_int, r_uint, r_longlong, r_ulonglong
import py
py.log.setconsumer("rtyper", py.log.STDOUT)
@@ -567,6 +567,8 @@
def test_dict_of_r_uint(self):
for r_t in [r_uint, r_longlong, r_ulonglong]:
+ if r_t is r_int:
+ continue # for 64-bit platforms: skip r_longlong
d = {r_t(2): 3, r_t(4): 5}
def fn(x, y):
d[r_t(x)] = 123
Modified: pypy/trunk/pypy/rpython/test/test_rint.py
==============================================================================
--- pypy/trunk/pypy/rpython/test/test_rint.py (original)
+++ pypy/trunk/pypy/rpython/test/test_rint.py Thu Mar 25 19:29:52 2010
@@ -110,10 +110,10 @@
def f(i):
return str(i)
- res = self.interpret(f, [r_longlong(0)])
+ res = self.interpret(f, [int64(0)])
assert self.ll_to_string(res) == '0'
- res = self.interpret(f, [r_longlong(413974738222117)])
+ res = self.interpret(f, [int64(413974738222117)])
assert self.ll_to_string(res) == '413974738222117'
def test_unsigned(self):
@@ -135,7 +135,7 @@
f._annspecialcase_ = "specialize:argtype(0)"
def g(n):
if n > 0:
- return f(r_longlong(0))
+ return f(int64(0))
else:
return f(0)
res = self.interpret(g, [0])
@@ -147,7 +147,7 @@
def test_downcast_int(self):
def f(i):
return int(i)
- res = self.interpret(f, [r_longlong(0)])
+ res = self.interpret(f, [int64(0)])
assert res == 0
def test_isinstance_vs_int_types(self):
Modified: pypy/trunk/pypy/rpython/tool/rffi_platform.py
==============================================================================
--- pypy/trunk/pypy/rpython/tool/rffi_platform.py (original)
+++ pypy/trunk/pypy/rpython/tool/rffi_platform.py Thu Mar 25 19:29:52 2010
@@ -299,11 +299,16 @@
fieldoffsets.append(offset)
seen[cell] = True
+ allfields = tuple(['c_' + name for name, _ in fields])
+ padfields = tuple(padfields)
name = self.name
+ padding_drop = PaddingDrop(name, allfields, padfields,
+ config_result.CConfig._compilation_info_)
hints = {'align': info['align'],
'size': info['size'],
'fieldoffsets': tuple(fieldoffsets),
- 'padding': tuple(padfields)}
+ 'padding': padfields,
+ 'get_padding_drop': padding_drop}
if name.startswith('struct '):
name = name[7:]
else:
@@ -477,6 +482,89 @@
return info['size']
# ____________________________________________________________
+
+class PaddingDrop(object):
+ # Compute (lazily) the padding_drop for a structure.
+ # See test_generate_padding for more information.
+ cache = None
+
+ def __init__(self, name, allfields, padfields, eci):
+ self.name = name
+ self.allfields = allfields
+ self.padfields = padfields
+ self.eci = eci
+
+ def __call__(self, types):
+ if self.cache is None:
+ self.compute_now(types)
+ return self.cache
+
+ def compute_now(self, types):
+ # Some simplifying assumptions there. We assume that all fields
+ # are either integers or pointers, so can be written in C as '0'.
+ # We also assume that the C backend gives us in 'types' a dictionary
+ # mapping non-padding field names to their C type (without '@').
+ drops = []
+ staticfields = []
+ consecutive_pads = []
+ for fieldname in self.allfields:
+ if fieldname in self.padfields:
+ consecutive_pads.append(fieldname)
+ continue
+ staticfields.append(types[fieldname])
+ if consecutive_pads:
+ # In that case we have to ask: how many of these pads are
+ # really needed? The correct answer might be between none
+ # and all of the pads listed in 'consecutive_pads'.
+ for i in range(len(consecutive_pads)+1):
+ class CConfig:
+ _compilation_info_ = self.eci
+ FIELDLOOKUP = _PaddingDropFieldLookup(self.name,
+ staticfields,
+ fieldname)
+ try:
+ got = configure(CConfig)['FIELDLOOKUP']
+ if got == 1:
+ break # found
+ except CompilationError:
+ pass
+ staticfields.insert(-1, None)
+ else:
+ raise Exception("could not determine the detailed field"
+ " layout of %r" % (self.name,))
+ # succeeded with 'i' pads. Drop all pads beyond that.
+ drops += consecutive_pads[i:]
+ consecutive_pads = []
+ drops += consecutive_pads # drop the final pads too
+ self.cache = drops
+
+class _PaddingDropFieldLookup(CConfigEntry):
+ def __init__(self, name, staticfields, fieldname):
+ self.name = name
+ self.staticfields = staticfields
+ self.fieldname = fieldname
+
+ def prepare_code(self):
+ yield 'typedef %s platcheck_t;' % (self.name,)
+ yield 'static platcheck_t s = {'
+ for i, type in enumerate(self.staticfields):
+ if i == len(self.staticfields)-1:
+ value = -1
+ else:
+ value = 0
+ if type:
+ yield '\t(%s)%s,' % (type, value)
+ else:
+ yield '\t%s,' % (value,)
+ yield '};'
+ fieldname = self.fieldname
+ assert fieldname.startswith('c_')
+ yield 'dump("fieldlookup", s.%s != 0);' % (fieldname[2:],)
+
+ def build_result(self, info, config_result):
+ return info['fieldlookup']
+
+# ____________________________________________________________
#
# internal helpers
Modified: pypy/trunk/pypy/rpython/tool/rfficache.py
==============================================================================
--- pypy/trunk/pypy/rpython/tool/rfficache.py (original)
+++ pypy/trunk/pypy/rpython/tool/rfficache.py Thu Mar 25 19:29:52 2010
@@ -13,7 +13,7 @@
from pypy.tool.gcc_cache import build_executable_cache
def ask_gcc(question, add_source=""):
- includes = ['stdlib.h', 'sys/types.h']
+ includes = ['stdlib.h', 'stdio.h', 'sys/types.h']
include_string = "\n".join(["#include <%s>" % i for i in includes])
c_source = py.code.Source('''
// includes
@@ -34,8 +34,8 @@
return build_executable_cache([c_file], eci)
def sizeof_c_type(c_typename, **kwds):
- question = 'printf("sizeof %s=%%d", sizeof(%s));' % (c_typename,
- c_typename)
+ question = 'printf("sizeof %s=%%ld", (long)sizeof(%s));' % (c_typename,
+ c_typename)
answer = ask_gcc(question, **kwds).split('=')
assert answer[0] == "sizeof " + c_typename, "wrong program: " \
"sizeof %s expected, got %s" % (c_typename, answer[0])
Modified: pypy/trunk/pypy/rpython/tool/test/test_rffi_platform.py
==============================================================================
--- pypy/trunk/pypy/rpython/tool/test/test_rffi_platform.py (original)
+++ pypy/trunk/pypy/rpython/tool/test/test_rffi_platform.py Thu Mar 25 19:29:52 2010
@@ -256,3 +256,104 @@
library_dirs = [str(tmpdir)]
)
rffi_platform.verify_eci(eci)
+
+def test_generate_padding():
+ # 'padding_drop' is a bit strange, but is what we need to write C code
+ # that defines prebuilt structures of that type. Normally, the C
+ # backend would generate '0' entries for every field c__pad#. That's
+ # usually much more than the number of real fields in the real structure
+ # definition. So 'padding_drop' allows a quick fix: it lists fields
+ # that should be ignored by the C backend. It should only be used in
+ # that situation because it lists some of the c__pad# fields a bit
+ # randomly -- to the effect that writing '0' for the other fields gives
+ # the right amount of '0's.
+ S = rffi_platform.getstruct("foobar_t", """
+ typedef struct {
+ char c1; /* followed by one byte of padding */
+ short s1;
+ } foobar_t;
+ """, [("c1", lltype.Signed),
+ ("s1", lltype.Signed)])
+ assert S._hints['padding'] == ('c__pad0',)
+ d = {'c_c1': 'char', 'c_s1': 'short'}
+ assert S._hints['get_padding_drop'](d) == ['c__pad0']
+ #
+ S = rffi_platform.getstruct("foobar_t", """
+ typedef struct {
+ char c1;
+ char c2; /* _pad0 */
+ short s1;
+ } foobar_t;
+ """, [("c1", lltype.Signed),
+ ("s1", lltype.Signed)])
+ assert S._hints['padding'] == ('c__pad0',)
+ d = {'c_c1': 'char', 'c_s1': 'short'}
+ assert S._hints['get_padding_drop'](d) == []
+ #
+ S = rffi_platform.getstruct("foobar_t", """
+ typedef struct {
+ char c1;
+ char c2; /* _pad0 */
+ /* _pad1, _pad2 */
+ int i1;
+ } foobar_t;
+ """, [("c1", lltype.Signed),
+ ("i1", lltype.Signed)])
+ assert S._hints['padding'] == ('c__pad0', 'c__pad1', 'c__pad2')
+ d = {'c_c1': 'char', 'c_i1': 'int'}
+ assert S._hints['get_padding_drop'](d) == ['c__pad1', 'c__pad2']
+ #
+ S = rffi_platform.getstruct("foobar_t", """
+ typedef struct {
+ char c1;
+ char c2; /* _pad0 */
+ char c3; /* _pad1 */
+ /* _pad2 */
+ int i1;
+ } foobar_t;
+ """, [("c1", lltype.Signed),
+ ("i1", lltype.Signed)])
+ assert S._hints['padding'] == ('c__pad0', 'c__pad1', 'c__pad2')
+ d = {'c_c1': 'char', 'c_i1': 'int'}
+ assert S._hints['get_padding_drop'](d) == ['c__pad2']
+ #
+ S = rffi_platform.getstruct("foobar_t", """
+ typedef struct {
+ char c1;
+ /* _pad0 */
+ short s1; /* _pad1, _pad2 */
+ int i1;
+ } foobar_t;
+ """, [("c1", lltype.Signed),
+ ("i1", lltype.Signed)])
+ assert S._hints['padding'] == ('c__pad0', 'c__pad1', 'c__pad2')
+ d = {'c_c1': 'char', 'c_i1': 'int'}
+ assert S._hints['get_padding_drop'](d) == ['c__pad1', 'c__pad2']
+ #
+ S = rffi_platform.getstruct("foobar_t", """
+ typedef struct {
+ char c1;
+ char c2; /* _pad0 */
+ /* _pad1, _pad2 */
+ int i1;
+ char c3; /* _pad3 */
+ /* _pad4 */
+ short s1;
+ } foobar_t;
+ """, [("c1", lltype.Signed),
+ ("i1", lltype.Signed),
+ ("s1", lltype.Signed)])
+ assert S._hints['padding'] == ('c__pad0', 'c__pad1', 'c__pad2',
+ 'c__pad3', 'c__pad4')
+ d = {'c_c1': 'char', 'c_i1': 'int', 'c_s1': 'short'}
+ assert S._hints['get_padding_drop'](d) == ['c__pad1', 'c__pad2', 'c__pad4']
+ #
+ S = rffi_platform.getstruct("foobar_t", """
+ typedef struct {
+ char c1;
+ long l2; /* some number of _pads */
+ } foobar_t;
+ """, [("c1", lltype.Signed)])
+ padding = list(S._hints['padding'])
+ d = {'c_c1': 'char'}
+ assert S._hints['get_padding_drop'](d) == padding
Modified: pypy/trunk/pypy/translator/c/genc.py
==============================================================================
--- pypy/trunk/pypy/translator/c/genc.py (original)
+++ pypy/trunk/pypy/translator/c/genc.py Thu Mar 25 19:29:52 2010
@@ -167,16 +167,19 @@
have___thread = None
+ def merge_eci(self, *ecis):
+ self.eci = self.eci.merge(*ecis)
+
def collect_compilation_info(self, db):
# we need a concrete gcpolicy to do this
- self.eci = self.eci.merge(db.gcpolicy.compilation_info())
+ self.merge_eci(db.gcpolicy.compilation_info())
all = []
for node in self.db.globalcontainers():
eci = getattr(node, 'compilation_info', None)
if eci:
all.append(eci)
- self.eci = self.eci.merge(*all)
+ self.merge_eci(*all)
def get_gcpolicyclass(self):
if self.gcpolicy is None:
Modified: pypy/trunk/pypy/translator/c/node.py
==============================================================================
--- pypy/trunk/pypy/translator/c/node.py (original)
+++ pypy/trunk/pypy/translator/c/node.py Thu Mar 25 19:29:52 2010
@@ -37,6 +37,8 @@
class StructDefNode:
typetag = 'struct'
+ extra_union_for_varlength = True
+
def __init__(self, db, STRUCT, varlength=1):
self.db = db
self.STRUCT = STRUCT
@@ -82,7 +84,8 @@
self.fields = []
db = self.db
STRUCT = self.STRUCT
- varlength = self.varlength
+ if self.varlength != 1:
+ self.normalizedtypename = db.gettype(STRUCT, who_asks=self)
if needs_gcheader(self.STRUCT):
for fname, T in db.gcpolicy.struct_gcheader_definition(self):
self.fields.append((fname, db.gettype(T, who_asks=self)))
@@ -151,6 +154,12 @@
if is_empty:
yield '\t' + 'char _dummy; /* this struct is empty */'
yield '};'
+ if self.varlength != 1:
+ assert self.typetag == 'struct'
+ yield 'union %su {' % self.name
+ yield ' struct %s a;' % self.name
+ yield ' %s;' % cdecl(self.normalizedtypename, 'b')
+ yield '};'
def visitor_lines(self, prefix, on_field):
for name in self.fieldnames:
@@ -162,6 +171,7 @@
def debug_offsets(self):
# generate number exprs giving the offset of the elements in the struct
+ assert self.varlength == 1
for name in self.fieldnames:
FIELD_T = self.c_struct_field_type(name)
if FIELD_T is Void:
@@ -178,15 +188,15 @@
class ArrayDefNode:
typetag = 'struct'
+ extra_union_for_varlength = True
def __init__(self, db, ARRAY, varlength=1):
self.db = db
self.ARRAY = ARRAY
self.LLTYPE = ARRAY
- original_varlength = varlength
self.gcfields = []
self.varlength = varlength
- if original_varlength == 1:
+ if varlength == 1:
basename = 'array'
with_number = True
else:
@@ -204,6 +214,8 @@
db = self.db
ARRAY = self.ARRAY
self.gcinfo # force it to be computed
+ if self.varlength != 1:
+ self.normalizedtypename = db.gettype(ARRAY, who_asks=self)
if needs_gcheader(ARRAY):
for fname, T in db.gcpolicy.array_gcheader_definition(self):
self.gcfields.append((fname, db.gettype(T, who_asks=self)))
@@ -251,8 +263,14 @@
line = 'char _dummy; ' + line
yield '\t' + line
yield '};'
+ if self.varlength != 1:
+ yield 'union %su {' % self.name
+ yield ' struct %s a;' % self.name
+ yield ' %s;' % cdecl(self.normalizedtypename, 'b')
+ yield '};'
def visitor_lines(self, prefix, on_item):
+ assert self.varlength == 1
ARRAY = self.ARRAY
# we need a unique name for this C variable, or at least one that does
# not collide with the expression in 'prefix'
@@ -279,6 +297,7 @@
def debug_offsets(self):
# generate three offsets for debugging inspection
+ assert self.varlength == 1
if not self.ARRAY._hints.get('nolength', False):
yield 'offsetof(struct %s, length)' % (self.name,)
else:
@@ -299,6 +318,7 @@
gcinfo = None
name = None
forward_decl = None
+ extra_union_for_varlength = False
def __init__(self, db, ARRAY, varlength=1):
self.db = db
@@ -349,6 +369,7 @@
gcinfo = None
name = None
typetag = 'struct'
+ extra_union_for_varlength = False
def __init__(self, db, FIXEDARRAY):
self.db = db
@@ -461,28 +482,42 @@
parentnode = db.getcontainernode(parent)
defnode = db.gettypedefnode(parentnode.T)
self.name = defnode.access_expr(parentnode.name, parentindex)
- self.ptrname = '(&%s)' % self.name
if self.typename != self.implementationtypename:
- ptrtypename = db.gettype(Ptr(T))
- self.ptrname = '((%s)(void*)%s)' % (cdecl(ptrtypename, ''),
- self.ptrname)
+ if db.gettypedefnode(T).extra_union_for_varlength:
+ self.name += '.b'
+ self.ptrname = '(&%s)' % self.name
def is_thread_local(self):
return hasattr(self.T, "_hints") and self.T._hints.get('thread_local')
+ def get_declaration(self):
+ if self.name[-2:] == '.b':
+ # xxx fish fish
+ assert self.implementationtypename.startswith('struct ')
+ assert self.implementationtypename.endswith(' @')
+ uniontypename = 'union %su @' % self.implementationtypename[7:-2]
+ return uniontypename, self.name[:-2]
+ else:
+ return self.implementationtypename, self.name
+
def forward_declaration(self):
if llgroup.member_of_group(self.obj):
return
+ type, name = self.get_declaration()
yield '%s;' % (
- forward_cdecl(self.implementationtypename,
- self.name, self.db.standalone, self.is_thread_local()))
+ forward_cdecl(type, name, self.db.standalone,
+ self.is_thread_local()))
def implementation(self):
if llgroup.member_of_group(self.obj):
return []
lines = list(self.initializationexpr())
+ type, name = self.get_declaration()
+ if name != self.name:
+ lines[0] = '{ ' + lines[0] # extra braces around the 'a' part
+ lines[-1] += ' }' # of the union
lines[0] = '%s = %s' % (
- cdecl(self.implementationtypename, self.name, self.is_thread_local()),
+ cdecl(type, name, self.is_thread_local()),
lines[0])
lines[-1] += ';'
return lines
@@ -536,7 +571,19 @@
if hasattr(self.T, "_hints") and self.T._hints.get('union'):
data = data[0:1]
+ if 'get_padding_drop' in self.T._hints:
+ d = {}
+ for name, _ in data:
+ T = defnode.c_struct_field_type(name)
+ typename = self.db.gettype(T)
+ d[name] = cdecl(typename, '')
+ padding_drop = self.T._hints['get_padding_drop'](d)
+ else:
+ padding_drop = []
+
for name, value in data:
+ if name in padding_drop:
+ continue
c_expr = defnode.access_expr(self.name, name)
lines = generic_initializationexpr(self.db, value, c_expr,
decoration + name)
@@ -560,6 +607,7 @@
return 'struct _hashT_%s @' % self.name
def forward_declaration(self):
+ assert self.typename == self.implementationtypename # no array part
hash_typename = self.get_hash_typename()
hash_offset = self.db.gctransformer.get_hash_offset(self.T)
yield '%s {' % cdecl(hash_typename, '')
@@ -675,6 +723,7 @@
return 1 # not variable-sized!
def initializationexpr(self, decoration=''):
+ assert self.typename == self.implementationtypename # not var-sized
is_empty = True
yield '{'
# _names == ['item0', 'item1', ...]
Modified: pypy/trunk/pypy/translator/c/test/test_lltyped.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_lltyped.py (original)
+++ pypy/trunk/pypy/translator/c/test/test_lltyped.py Thu Mar 25 19:29:52 2010
@@ -782,3 +782,48 @@
fn = self.getcompiled(f, [])
res = fn()
assert res == 42
+
+ def test_padding_in_prebuilt_struct(self):
+ from pypy.rpython.lltypesystem import rffi
+ from pypy.rpython.tool import rffi_platform
+ eci = rffi_platform.eci_from_header("""
+ typedef struct {
+ char c1; /* followed by one byte of padding */
+ short s1;
+ char c2; /* followed by 3 bytes of padding */
+ int i2;
+ char c3; /* followed by 3 or 7 bytes of padding */
+ long l3;
+ char c4;
+ } foobar_t;
+ """)
+ class CConfig:
+ _compilation_info_ = eci
+ STRUCT = rffi_platform.Struct("foobar_t",
+ [("c1", Signed),
+ ("s1", Signed),
+ ("l3", Signed)])
+ S = rffi_platform.configure(CConfig)['STRUCT']
+ assert 'get_padding_drop' in S._hints
+ s1 = malloc(S, immortal=True)
+ s1.c_c1 = rffi.cast(S.c_c1, -12)
+ s1.c_s1 = rffi.cast(S.c_s1, -7843)
+ s1.c_l3 = -98765432
+ s2 = malloc(S, immortal=True)
+ s2.c_c1 = rffi.cast(S.c_c1, -123)
+ s2.c_s1 = rffi.cast(S.c_s1, -789)
+ s2.c_l3 = -9999999
+ #
+ def f(n):
+ if n > 5:
+ s = s1
+ else:
+ s = s2
+ return s.c_l3
+ #
+ self.include_also_eci = eci
+ fn = self.getcompiled(f, [int])
+ res = fn(10)
+ assert res == -98765432
+ res = fn(1)
+ assert res == -9999999
Modified: pypy/trunk/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_newgc.py (original)
+++ pypy/trunk/pypy/translator/c/test/test_newgc.py Thu Mar 25 19:29:52 2010
@@ -653,8 +653,8 @@
to_sort[2] = 1
to_sort[3] = 2
qsort.push_arg(rffi.cast(rffi.VOIDP, to_sort))
- qsort.push_arg(rffi.cast(rffi.SIZE_T, rffi.sizeof(rffi.LONG)))
qsort.push_arg(rffi.cast(rffi.SIZE_T, 4))
+ qsort.push_arg(rffi.cast(rffi.SIZE_T, rffi.sizeof(rffi.LONG)))
qsort.push_arg(rffi.cast(rffi.VOIDP, ptr.ll_closure))
qsort.call(lltype.Void)
result = [to_sort[i] for i in range(4)] == [1,2,3,4]
Modified: pypy/trunk/pypy/translator/c/test/test_typed.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_typed.py (original)
+++ pypy/trunk/pypy/translator/c/test/test_typed.py Thu Mar 25 19:29:52 2010
@@ -28,6 +28,8 @@
def compilefunc(self, t, func):
from pypy.translator.c import genc
self.builder = builder = genc.CExtModuleBuilder(t, func, config=t.config)
+ if hasattr(self, 'include_also_eci'):
+ builder.merge_eci(self.include_also_eci)
builder.generate_source()
builder.compile()
return builder.get_entry_point()
More information about the Pypy-commit
mailing list