Author: David Schneider <david.schnei...@picle.org> Branch: Changeset: r64957:162603593f00 Date: 2013-06-23 04:24 -0500 http://bitbucket.org/pypy/pypy/changeset/162603593f00/
Log: ctypes/_rawffi can generate unaligned access to floating point fields in structures. Directly reading unaligned floats from memory is not supported on ARM. This change adds a wrapper around the reads and writes that checks the pointer alignment and uses memcpy in case of unaligned access on ARM. diff --git a/pypy/module/_rawffi/array.py b/pypy/module/_rawffi/array.py --- a/pypy/module/_rawffi/array.py +++ b/pypy/module/_rawffi/array.py @@ -13,19 +13,9 @@ from pypy.module._rawffi.interp_rawffi import TYPEMAP from pypy.module._rawffi.interp_rawffi import size_alignment from pypy.module._rawffi.interp_rawffi import unpack_shape_with_length +from pypy.module._rawffi.interp_rawffi import read_ptr, write_ptr from rpython.rlib.rarithmetic import r_uint -def push_elem(ll_array, pos, value): - TP = lltype.typeOf(value) - ll_array = rffi.cast(rffi.CArrayPtr(TP), ll_array) - ll_array[pos] = value -push_elem._annspecialcase_ = 'specialize:argtype(2)' - -def get_elem(ll_array, pos, ll_t): - ll_array = rffi.cast(rffi.CArrayPtr(ll_t), ll_array) - return ll_array[pos] -get_elem._annspecialcase_ = 'specialize:arg(2)' - class W_Array(W_DataShape): def __init__(self, basicffitype, size): @@ -57,7 +47,7 @@ " array length")) for num in range(iterlength): w_item = items_w[num] - unwrap_value(space, push_elem, result.ll_buffer, num, + unwrap_value(space, write_ptr, result.ll_buffer, num, self.itemcode, w_item) return space.wrap(result) @@ -118,7 +108,7 @@ raise segfault_exception(space, "setting element of freed array") if num >= self.length or num < 0: raise OperationError(space.w_IndexError, space.w_None) - unwrap_value(space, push_elem, self.ll_buffer, num, + unwrap_value(space, write_ptr, self.ll_buffer, num, self.shape.itemcode, w_value) def descr_setitem(self, space, w_index, w_value): @@ -136,7 +126,7 @@ raise segfault_exception(space, "accessing elements of freed array") if num >= self.length or num < 0: raise OperationError(space.w_IndexError, space.w_None) - return wrap_value(space, get_elem, self.ll_buffer, num, + return wrap_value(space, read_ptr, self.ll_buffer, num, self.shape.itemcode) def descr_getitem(self, space, w_index): diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py --- a/pypy/module/_rawffi/callback.py +++ b/pypy/module/_rawffi/callback.py @@ -2,7 +2,7 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty from rpython.rtyper.lltypesystem import lltype, rffi -from pypy.module._rawffi.array import push_elem +from pypy.module._rawffi.interp_rawffi import read_ptr, write_ptr from pypy.module._rawffi.structure import W_Structure from pypy.module._rawffi.interp_rawffi import (W_DataInstance, letter2tp, unwrap_value, unpack_argshapes, got_libffi_error) @@ -40,7 +40,7 @@ args_w[i] = space.wrap(rffi.cast(rffi.ULONG, ll_args[i])) w_res = space.call(w_callable, space.newtuple(args_w)) if callback_ptr.result is not None: # don't return void - unwrap_value(space, push_elem, ll_res, 0, + unwrap_value(space, write_ptr, ll_res, 0, callback_ptr.result, w_res) except OperationError, e: tbprint(space, space.wrap(e.get_traceback()), diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -5,6 +5,7 @@ from rpython.rlib.clibffi import * from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper.tool import rffi_platform from rpython.rlib.unroll import unrolling_iterable import rpython.rlib.rposix as rposix @@ -43,6 +44,8 @@ } TYPEMAP_PTR_LETTERS = "POszZ" TYPEMAP_NUMBER_LETTERS = "bBhHiIlLqQ?" +TYPEMAP_FLOAT_LETTERS = "fd" # XXX long doubles are not propperly supported in + # rpython, so we ignore then here if _MS_WINDOWS: TYPEMAP['X'] = ffi_type_pointer @@ -239,6 +242,52 @@ ) unroll_letters_for_numbers = unrolling_iterable(TYPEMAP_NUMBER_LETTERS) +unroll_letters_for_floats = unrolling_iterable(TYPEMAP_FLOAT_LETTERS) + +_ARM = rffi_platform.getdefined('__arm__', '') + +def read_ptr(ptr, ofs, TP): + T = lltype.Ptr(rffi.CArray(TP)) + for c in unroll_letters_for_floats: + # Note: if we are on ARM and have a float-ish value that is not word + # aligned accessing it directly causes a SIGBUS. Instead we use memcpy + # to avoid the problem + if (_ARM and LL_TYPEMAP[c] is TP + and rffi.cast(lltype.Signed, ptr) & 3 != 0): + if ofs != 0: + ptr = rffi.ptradd(ptr, ofs*rffi.sizeof(TP)) + with lltype.scoped_alloc(T.TO, 1) as t_array: + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, t_array), + rffi.cast(rffi.VOIDP, ptr), + rffi.sizeof(TP)) + ptr_val = t_array[0] + return ptr_val + else: + return rffi.cast(T, ptr)[ofs] +read_ptr._annspecialcase_ = 'specialize:arg(2)' + +def write_ptr(ptr, ofs, value): + TP = lltype.typeOf(value) + T = lltype.Ptr(rffi.CArray(TP)) + for c in unroll_letters_for_floats: + # Note: if we are on ARM and have a float-ish value that is not word + # aligned accessing it directly causes a SIGBUS. Instead we use memcpy + # to avoid the problem + if (_ARM and LL_TYPEMAP[c] is TP + and rffi.cast(lltype.Signed, ptr) & 3 != 0): + if ofs != 0: + ptr = rffi.ptradd(ptr, ofs*rffi.sizeof(TP)) + with lltype.scoped_alloc(T.TO, 1) as s_array: + s_array[0] = value + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, ptr), + rffi.cast(rffi.VOIDP, s_array), + rffi.sizeof(TP)) + return + else: + rffi.cast(T, ptr)[ofs] = value +write_ptr._annspecialcase_ = 'specialize:argtype(2)' def segfault_exception(space, reason): w_mod = space.getbuiltinmodule("_rawffi") diff --git a/pypy/module/_rawffi/structure.py b/pypy/module/_rawffi/structure.py --- a/pypy/module/_rawffi/structure.py +++ b/pypy/module/_rawffi/structure.py @@ -12,8 +12,10 @@ from pypy.module._rawffi.interp_rawffi import W_DataShape, W_DataInstance from pypy.module._rawffi.interp_rawffi import wrap_value, unwrap_value from pypy.module._rawffi.interp_rawffi import unpack_shape_with_length -from pypy.module._rawffi.interp_rawffi import size_alignment, LL_TYPEMAP +from pypy.module._rawffi.interp_rawffi import LL_TYPEMAP from pypy.module._rawffi.interp_rawffi import unroll_letters_for_numbers +from pypy.module._rawffi.interp_rawffi import size_alignment +from pypy.module._rawffi.interp_rawffi import read_ptr, write_ptr from rpython.rlib import clibffi from rpython.rlib.rarithmetic import intmask, signedtype, widen from rpython.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong @@ -289,19 +291,18 @@ value = widen(value) bitmask = BIT_MASK(numbits, TP) # - current = widen(rffi.cast(T, ptr)[0]) + current = widen(read_ptr(ptr, 0, TP)) current &= ~ (bitmask << lowbit) current |= (value & bitmask) << lowbit value = rffi.cast(TP, current) break - - rffi.cast(T, ptr)[0] = value + write_ptr(ptr, 0, value) push_field._annspecialcase_ = 'specialize:argtype(2)' def cast_pos(self, i, ll_t): pos = rffi.ptradd(self.ll_buffer, self.shape.ll_positions[i]) TP = lltype.Ptr(rffi.CArray(ll_t)) - value = rffi.cast(TP, pos)[0] + value = read_ptr(pos, 0, ll_t) # Handle bitfields for c in unroll_letters_for_numbers: diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py --- a/pypy/module/_rawffi/test/test__rawffi.py +++ b/pypy/module/_rawffi/test/test__rawffi.py @@ -211,6 +211,7 @@ cls.w_platform = space.wrap(platform.name) cls.w_sizes_and_alignments = space.wrap(dict( [(k, (v.c_size, v.c_alignment)) for k,v in TYPEMAP.iteritems()])) + cls.w_typemap = space.wrap(TYPEMAP.keys()) def test_libload(self): import _rawffi @@ -751,6 +752,18 @@ assert _rawffi.sizeof(k) == s assert _rawffi.alignment(k) == a + def test_unaligned(self): + import _rawffi + for k in self.typemap: + if k not in 'fdg': + continue + S = _rawffi.Structure([('pad', 'c'), ('value', k)], pack=1) + s = S() + s.value = 4 + assert s.value == 4 + s.free() + + def test_array_addressof(self): import _rawffi lib = _rawffi.CDLL(self.lib_name) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit