def convert_bitfield_from_object(self, cdata, w_ob): ctype = self.ctype space = ctype.space # value = misc.as_long_long(space, w_ob) if isinstance(ctype, ctypeprim.W_CTypePrimitiveSigned): is_signed = True fmin = -(r_longlong(1) << (self.bitsize - 1)) fmax = (r_longlong(1) << (self.bitsize - 1)) - 1 if fmax == 0: fmax = 1 # special case to let "int x:1" receive "1" else: is_signed = False fmin = r_longlong(0) fmax = r_longlong((r_ulonglong(1) << self.bitsize) - 1) if value < fmin or value > fmax: raise oefmt(space.w_OverflowError, "value %d outside the range allowed by the bit field " "width: %d <= x <= %d", value, fmin, fmax) rawmask = ((r_ulonglong(1) << self.bitsize) - 1) << self.bitshift rawvalue = r_ulonglong(value) << self.bitshift rawfielddata = misc.read_raw_unsigned_data(cdata, ctype.size) rawfielddata = (rawfielddata & ~rawmask) | (rawvalue & rawmask) if is_signed: misc.write_raw_signed_data(cdata, rawfielddata, ctype.size) else: misc.write_raw_unsigned_data(cdata, rawfielddata, ctype.size)
def convert_bitfield_from_object(self, cdata, w_ob): ctype = self.ctype space = ctype.space # value = misc.as_long_long(space, w_ob) if isinstance(ctype, ctypeprim.W_CTypePrimitiveSigned): is_signed = True fmin = -(r_longlong(1) << (self.bitsize - 1)) fmax = (r_longlong(1) << (self.bitsize - 1)) - 1 if fmax == 0: fmax = 1 # special case to let "int x:1" receive "1" else: is_signed = False fmin = r_longlong(0) fmax = r_longlong((r_ulonglong(1) << self.bitsize) - 1) if value < fmin or value > fmax: raise oefmt( space.w_OverflowError, "value %d outside the range allowed by the bit field " "width: %d <= x <= %d", value, fmin, fmax) rawmask = ((r_ulonglong(1) << self.bitsize) - 1) << self.bitshift rawvalue = r_ulonglong(value) << self.bitshift rawfielddata = misc.read_raw_unsigned_data(cdata, ctype.size) rawfielddata = (rawfielddata & ~rawmask) | (rawvalue & rawmask) if is_signed: misc.write_raw_signed_data(cdata, rawfielddata, ctype.size) else: misc.write_raw_unsigned_data(cdata, rawfielddata, ctype.size)
def test_it_writes_nothing_and_returns_None(self, space): data = lltype.malloc(rffi.CCHARP.TO, 1, flavor='raw') misc.write_raw_signed_data(data, 11, 1) w_void_type = ffitype.VoidRWStrategy() res = w_void_type.write(space, data, 0) assert misc.read_raw_signed_data(data, 1) == 11 assert res is None lltype.free(data, flavor='raw')
def convert_from_object(self, cdata, w_ob): if self.value_fits_long: value = misc.as_long(self.space, w_ob) if self.value_smaller_than_long: if value != misc.signext(value, self.size): self._overflow(w_ob) misc.write_raw_signed_data(cdata, value, self.size) else: self._convert_from_object_longlong(cdata, w_ob)
def rcall(self, funcaddr, args): assert self.cif_descr self = jit.promote(self) # no checking of len(args) needed, as calls in this context are not dynamic # The following code is functionally similar to W_CTypeFunc._call, but its # implementation is tailored to the restricted use (include memory handling) # of the CAPI calls. space = self.space cif_descr = self.cif_descr size = cif_descr.exchange_size raw_string = rffi.cast(rffi.CCHARP, 0) # only ever have one in the CAPI buffer = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw') try: for i in range(len(args)): data = rffi.ptradd(buffer, cif_descr.exchange_args[i]) obj = args[i] argtype = self.fargs[i] # the following is clumsy, but the data types used as arguments are # very limited, so it'll do for now if obj.tc == 'l': assert isinstance(argtype, ctypeprim.W_CTypePrimitiveSigned) misc.write_raw_signed_data(data, rffi.cast(rffi.LONG, obj._long), argtype.size) elif obj.tc == 'h': assert isinstance(argtype, ctypeprim.W_CTypePrimitiveUnsigned) misc.write_raw_unsigned_data( data, rffi.cast(rffi.ULONG, obj._handle), argtype.size) elif obj.tc == 'p': assert obj._voidp != rffi.cast(rffi.VOIDP, 0) data = rffi.cast(rffi.VOIDPP, data) data[0] = obj._voidp else: # only other use is sring assert obj.tc == 's' n = len(obj._string) assert raw_string == rffi.cast(rffi.CCHARP, 0) # XXX could use rffi.get_nonmovingbuffer_final_null() raw_string = rffi.str2charp(obj._string) data = rffi.cast(rffi.CCHARPP, data) data[0] = raw_string jit_libffi.jit_ffi_call(cif_descr, rffi.cast(rffi.VOIDP, funcaddr), buffer) resultdata = rffi.ptradd(buffer, cif_descr.exchange_result) # this wrapping is unnecessary, but the assumption is that given the # immediate unwrapping, the round-trip is removed w_res = self.ctitem.copy_and_convert_to_object(resultdata) finally: if raw_string != rffi.cast(rffi.CCHARP, 0): rffi.free_charp(raw_string) lltype.free(buffer, flavor='raw') return w_res
def convert_from_object(self, cdata, w_ob): if self.value_fits_long: value = misc.as_long(self.space, w_ob) if self.size < rffi.sizeof(lltype.Signed): if r_uint(value) - self.vmin > self.vrangemax: self._overflow(w_ob) misc.write_raw_signed_data(cdata, value, self.size) else: value = misc.as_long_long(self.space, w_ob) misc.write_raw_signed_data(cdata, value, self.size)
def rcall(self, funcaddr, args): assert self.cif_descr self = jit.promote(self) # no checking of len(args) needed, as calls in this context are not dynamic # The following code is functionally similar to W_CTypeFunc._call, but its # implementation is tailored to the restricted use (include memory handling) # of the CAPI calls. space = self.space cif_descr = self.cif_descr size = cif_descr.exchange_size raw_string = rffi.cast(rffi.CCHARP, 0) # only ever have one in the CAPI buffer = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw') try: for i in range(len(args)): data = rffi.ptradd(buffer, cif_descr.exchange_args[i]) obj = args[i] argtype = self.fargs[i] # the following is clumsy, but the data types used as arguments are # very limited, so it'll do for now if obj.tc == 'l': assert isinstance(argtype, ctypeprim.W_CTypePrimitiveSigned) misc.write_raw_signed_data(data, rffi.cast(rffi.LONG, obj._long), argtype.size) elif obj.tc == 'h': assert isinstance(argtype, ctypeprim.W_CTypePrimitiveUnsigned) misc.write_raw_unsigned_data(data, rffi.cast(rffi.ULONG, obj._handle), argtype.size) elif obj.tc == 'p': assert obj._voidp != rffi.cast(rffi.VOIDP, 0) data = rffi.cast(rffi.VOIDPP, data) data[0] = obj._voidp else: # only other use is sring assert obj.tc == 's' n = len(obj._string) assert raw_string == rffi.cast(rffi.CCHARP, 0) # XXX could use rffi.get_nonmovingbuffer_final_null() raw_string = rffi.str2charp(obj._string) data = rffi.cast(rffi.CCHARPP, data) data[0] = raw_string jit_libffi.jit_ffi_call(cif_descr, rffi.cast(rffi.VOIDP, funcaddr), buffer) resultdata = rffi.ptradd(buffer, cif_descr.exchange_result) # this wrapping is unnecessary, but the assumption is that given the # immediate unwrapping, the round-trip is removed w_res = self.ctitem.copy_and_convert_to_object(resultdata) finally: if raw_string != rffi.cast(rffi.CCHARP, 0): rffi.free_charp(raw_string) lltype.free(buffer, flavor='raw') return w_res
def test_it_reads_signed_types_to_buffer(self, space): for t in [ ffitype.INT8, ffitype.INT16, ffitype.INT32, ffitype.INT64, ffitype.LONG ]: w_signed_type = ffitype.SignedRWStrategy(t) size = w_signed_type.typesize # make new buffer for every t data = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw') misc.write_raw_signed_data(data, -88, size) w_res = w_signed_type.read(space, data) assert self.unwrap(space, w_res) == -88 lltype.free(data, flavor='raw')
def test_it_reads_signed_types_to_buffer(self, space): for t in [ffitype.INT8, ffitype.INT16, ffitype.INT32, ffitype.INT64, ffitype.LONG]: w_signed_type = ffitype.SignedRWStrategy(t) size = w_signed_type.typesize # make new buffer for every t data = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw') misc.write_raw_signed_data(data, -88, size) w_res = w_signed_type.read(space, data) assert self.unwrap(space, w_res) == -88 lltype.free(data, flavor='raw')
def convert_from_object(self, cdata, w_ob): if self.value_fits_long: value = misc.as_long(self.space, w_ob) if self.value_smaller_than_long: size = self.size if size == 1: signextended = misc.signext(value, 1) elif size == 2: signextended = misc.signext(value, 2) elif size == 4: signextended = misc.signext(value, 4) else: raise AssertionError("unsupported size") if value != signextended: self._overflow(w_ob) misc.write_raw_signed_data(cdata, value, self.size) else: self._convert_from_object_longlong(cdata, w_ob)
def convert_from_object_fficallback(fresult, ll_res, w_res, encode_result_for_libffi): space = fresult.space if isinstance(fresult, W_CTypeVoid): if not space.is_w(w_res, space.w_None): raise oefmt( space.w_TypeError, "callback with the return type 'void' must return " "None") return # small_result = encode_result_for_libffi and fresult.size < SIZE_OF_FFI_ARG if small_result and fresult.is_primitive_integer: # work work work around a libffi irregularity: for integer return # types we have to fill at least a complete 'ffi_arg'-sized result # buffer. if type(fresult) is W_CTypePrimitiveSigned: # It's probably fine to always zero-extend, but you never # know: maybe some code somewhere expects a negative # 'short' result to be returned into EAX as a 32-bit # negative number. Better safe than sorry. This code # is about that case. Let's ignore this for enums. # # do a first conversion only to detect overflows. This # conversion produces stuff that is otherwise ignored. fresult.convert_from_object(ll_res, w_res) # # manual inlining and tweaking of # W_CTypePrimitiveSigned.convert_from_object() in order # to write a whole 'ffi_arg'. value = misc.as_long(space, w_res) misc.write_raw_signed_data(ll_res, value, SIZE_OF_FFI_ARG) return else: # zero extension: fill the '*result' with zeros, and (on big- # endian machines) correct the 'result' pointer to write to misc._raw_memclear(ll_res, SIZE_OF_FFI_ARG) if BIG_ENDIAN: diff = SIZE_OF_FFI_ARG - fresult.size ll_res = rffi.ptradd(ll_res, diff) # fresult.convert_from_object(ll_res, w_res)
def convert_from_object_fficallback(fresult, ll_res, w_res, encode_result_for_libffi): space = fresult.space if isinstance(fresult, W_CTypeVoid): if not space.is_w(w_res, space.w_None): raise oefmt(space.w_TypeError, "callback with the return type 'void' must return " "None") return # small_result = encode_result_for_libffi and fresult.size < SIZE_OF_FFI_ARG if small_result and fresult.is_primitive_integer: # work work work around a libffi irregularity: for integer return # types we have to fill at least a complete 'ffi_arg'-sized result # buffer. if type(fresult) is W_CTypePrimitiveSigned: # It's probably fine to always zero-extend, but you never # know: maybe some code somewhere expects a negative # 'short' result to be returned into EAX as a 32-bit # negative number. Better safe than sorry. This code # is about that case. Let's ignore this for enums. # # do a first conversion only to detect overflows. This # conversion produces stuff that is otherwise ignored. fresult.convert_from_object(ll_res, w_res) # # manual inlining and tweaking of # W_CTypePrimitiveSigned.convert_from_object() in order # to write a whole 'ffi_arg'. value = misc.as_long(space, w_res) misc.write_raw_signed_data(ll_res, value, SIZE_OF_FFI_ARG) return else: # zero extension: fill the '*result' with zeros, and (on big- # endian machines) correct the 'result' pointer to write to misc._raw_memclear(ll_res, SIZE_OF_FFI_ARG) if BIG_ENDIAN: diff = SIZE_OF_FFI_ARG - fresult.size ll_res = rffi.ptradd(ll_res, diff) # fresult.convert_from_object(ll_res, w_res)
def _convert_from_object_longlong(self, cdata, w_ob): # in its own function: LONGLONG may make the whole function jit-opaque value = misc.as_long_long(self.space, w_ob) misc.write_raw_signed_data(cdata, value, self.size)
def rcall(self, funcaddr, args): assert self.cif_descr self = jit.promote(self) # no checking of len(args) needed, as calls in this context are not dynamic # The following code is functionally similar to W_CTypeFunc._call, but its # implementation is tailored to the restricted use (include memory handling) # of the CAPI calls. space = self.space cif_descr = self.cif_descr size = cif_descr.exchange_size raw_string1 = rffi.cast(rffi.CCHARP, 0) raw_string2 = rffi.cast(rffi.CCHARP, 0) # have max two in any CAPI buffer = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw') try: for i in range(len(args)): data = rffi.ptradd(buffer, cif_descr.exchange_args[i]) obj = args[i] argtype = self.fargs[i] # the following is clumsy, but the data types used as arguments are # very limited, so it'll do for now if obj.tc == 'h': misc.write_raw_unsigned_data( data, rffi.cast(rffi.SIZE_T, obj._scope), argtype.size) elif obj.tc == 'm': misc.write_raw_signed_data( data, rffi.cast(rffi.INTPTR_T, obj._method), argtype.size) elif obj.tc == 'o': # additional cast of void* to intptr_t required for 32b (or intmask fails) misc.write_raw_signed_data( data, rffi.cast(rffi.INTPTR_T, rffi.cast(rffi.VOIDP, obj._object)), argtype.size) elif obj.tc == 'u': misc.write_raw_unsigned_data( data, rffi.cast(rffi.SIZE_T, obj._index), argtype.size) elif obj.tc == 'i': misc.write_raw_signed_data(data, rffi.cast(rffi.INT, obj._int), argtype.size) elif obj.tc == 'd': misc.write_raw_float_data( data, rffi.cast(rffi.DOUBLE, obj._double), argtype.size) elif obj.tc == 'p': assert obj._voidp != rffi.cast(rffi.VOIDP, 0) data = rffi.cast(rffi.VOIDPP, data) data[0] = obj._voidp elif obj.tc == 's': n = len(obj._string) data = rffi.cast(rffi.CCHARPP, data) if raw_string1 == rffi.cast(rffi.CCHARP, 0): # XXX could use rffi.get_nonmovingbuffer_final_null() raw_string1 = rffi.str2charp(obj._string) data[0] = raw_string1 else: assert raw_string2 == rffi.cast(rffi.CCHARP, 0) raw_string2 = rffi.str2charp(obj._string) data[0] = raw_string2 else: # only other use is voidp assert obj.tc == 'p' assert obj._voidp != rffi.cast(rffi.VOIDP, 0) data = rffi.cast(rffi.VOIDPP, data) data[0] = obj._voidp jit_libffi.jit_ffi_call(cif_descr, rffi.cast(rffi.VOIDP, funcaddr), buffer) resultdata = rffi.ptradd(buffer, cif_descr.exchange_result) # this wrapping is unnecessary, but the assumption is that given the # immediate unwrapping, the round-trip is removed w_res = self.ctitem.copy_and_convert_to_object(resultdata) finally: if raw_string1 != rffi.cast(rffi.CCHARP, 0): rffi.free_charp(raw_string1) if raw_string2 != rffi.cast(rffi.CCHARP, 0): rffi.free_charp(raw_string2) lltype.free(buffer, flavor='raw') return w_res
def write_raw_signed_data(self, source): with self as ptr: misc.write_raw_signed_data(ptr, source, self.ctype.size)
def write(self, space, data, w_arg): arg = space.int_w(w_arg) misc.write_raw_signed_data(data, arg, self.typesize)
def write_raw_signed_data(self, source): misc.write_raw_signed_data(self._cdata, source, self.ctype.size) keepalive_until_here(self)