Author: Brian Kearns <bdkea...@gmail.com> Branch: py3k Changeset: r62245:17454c649f51 Date: 2013-03-08 14:56 -0500 http://bitbucket.org/pypy/pypy/changeset/17454c649f51/
Log: merge default 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 @@ -92,15 +92,20 @@ cdata1 = self._cdata other = space.interpclass_w(w_other) if isinstance(other, W_CData): + if requires_ordering: + if (isinstance(self.ctype, W_CTypePrimitive) or + isinstance(other.ctype, W_CTypePrimitive)): + raise OperationError(space.w_TypeError, + space.wrap("cannot do comparison on a " + "primitive cdata")) cdata2 = other._cdata + elif (misc.is_zero(space, w_other) and + not isinstance(self.ctype, W_CTypePrimitive)): + cdata2 = lltype.nullptr(rffi.CCHARP.TO) else: return space.w_NotImplemented if requires_ordering: - if (isinstance(self.ctype, W_CTypePrimitive) or - isinstance(other.ctype, W_CTypePrimitive)): - raise OperationError(space.w_TypeError, - space.wrap("cannot do comparison on a primitive cdata")) cdata1 = rffi.cast(lltype.Unsigned, cdata1) cdata2 = rffi.cast(lltype.Unsigned, cdata2) return space.newbool(op(cdata1, cdata2)) 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 @@ -156,6 +156,10 @@ space = self.space ob = space.interpclass_w(w_ob) if not isinstance(ob, cdataobj.W_CData): + if misc.is_zero(space, w_ob): + NULL = lltype.nullptr(rffi.CCHARP.TO) + rffi.cast(rffi.CCHARPP, cdata)[0] = NULL + return raise self._convert_error("cdata pointer", w_ob) other = ob.ctype if not isinstance(other, W_CTypePtrBase): @@ -176,8 +180,8 @@ class W_CTypePointer(W_CTypePtrBase): - _attrs_ = ['cache_array_type'] - _immutable_fields_ = ['cache_array_type?'] + _attrs_ = ['is_file', 'cache_array_type'] + _immutable_fields_ = ['is_file', 'cache_array_type?'] kind = "pointer" cache_array_type = None @@ -188,6 +192,8 @@ extra = "(*)" # obscure case: see test_array_add else: extra = " *" + self.is_file = (ctitem.name == "struct _IO_FILE" or + ctitem.name == "struct $FILE") W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem) def newp(self, w_init): @@ -239,23 +245,53 @@ p = rffi.ptradd(cdata, i * self.ctitem.size) return cdataobj.W_CData(space, p, self) + def cast(self, w_ob): + if self.is_file: + value = self.prepare_file(w_ob) + if value: + return cdataobj.W_CData(self.space, value, self) + return W_CTypePtrBase.cast(self, w_ob) + + def prepare_file(self, w_ob): + from pypy.module._file.interp_file import W_File + from pypy.module._cffi_backend import ctypefunc + ob = self.space.interpclass_w(w_ob) + if isinstance(ob, W_File): + return prepare_file_argument(self.space, ob) + else: + return lltype.nullptr(rffi.CCHARP.TO) + def _prepare_pointer_call_argument(self, w_init, cdata): space = self.space - if (space.isinstance_w(w_init, space.w_list) or + if misc.is_zero(space, w_init): + # Convert 0 to NULL. Note that passing 0 is not ambigous, + # despite the potential confusion: as a 'T*' argument, 0 means + # NULL, but as a 'T[]' argument it would mean "array of size 0" + # --- except that we specifically refuse to interpret numbers + # as the array size when passing arguments. + rffi.cast(rffi.CCHARPP, cdata)[0] = lltype.nullptr(rffi.CCHARP.TO) + return 3 + elif (space.isinstance_w(w_init, space.w_list) or space.isinstance_w(w_init, space.w_tuple)): length = space.int_w(space.len(w_init)) elif (space.isinstance_w(w_init, space.w_unicode) or space.isinstance_w(w_init, space.w_bytes)): # from a string, we add the null terminator length = space.int_w(space.len(w_init)) + 1 + elif self.is_file: + result = self.prepare_file(w_init) + if result: + rffi.cast(rffi.CCHARPP, cdata)[0] = result + return 2 + return 0 else: - return False + return 0 itemsize = self.ctitem.size if itemsize <= 0: if isinstance(self.ctitem, ctypevoid.W_CTypeVoid): itemsize = 1 else: - return False + return 0 try: datasize = ovfcheck(length * itemsize) except OverflowError: @@ -269,7 +305,7 @@ lltype.free(result, flavor='raw') raise rffi.cast(rffi.CCHARPP, cdata)[0] = result - return True + return 1 def convert_argument_from_object(self, cdata, w_ob): from pypy.module._cffi_backend.ctypefunc import set_mustfree_flag @@ -277,7 +313,7 @@ ob = space.interpclass_w(w_ob) result = (not isinstance(ob, cdataobj.W_CData) and self._prepare_pointer_call_argument(w_ob, cdata)) - if not result: + if result == 0: self.convert_from_object(cdata, w_ob) set_mustfree_flag(cdata, result) return result @@ -307,3 +343,36 @@ if attrchar == 'i': # item return self.space.wrap(self.ctitem) return W_CTypePtrBase._fget(self, attrchar) + +# ____________________________________________________________ + + +rffi_fdopen = rffi.llexternal("fdopen", [rffi.INT, rffi.CCHARP], rffi.CCHARP) +rffi_setbuf = rffi.llexternal("setbuf", [rffi.CCHARP, rffi.CCHARP], lltype.Void) +rffi_fclose = rffi.llexternal("fclose", [rffi.CCHARP], rffi.INT) + +class CffiFileObj(object): + _immutable_ = True + + def __init__(self, fd, mode): + self.llf = rffi_fdopen(fd, mode) + if not self.llf: + raise OSError(rposix.get_errno(), "fdopen failed") + rffi_setbuf(self.llf, lltype.nullptr(rffi.CCHARP.TO)) + + def close(self): + rffi_fclose(self.llf) + + +def prepare_file_argument(space, fileobj): + fileobj.direct_flush() + if fileobj.cffi_fileobj is None: + fd = fileobj.direct_fileno() + if fd < 0: + raise OperationError(space.w_ValueError, + space.wrap("file has no OS file descriptor")) + try: + fileobj.cffi_fileobj = CffiFileObj(fd, fileobj.mode) + except OSError, e: + raise wrap_oserror(space, e) + return fileobj.cffi_fileobj.llf diff --git a/pypy/module/_cffi_backend/misc.py b/pypy/module/_cffi_backend/misc.py --- a/pypy/module/_cffi_backend/misc.py +++ b/pypy/module/_cffi_backend/misc.py @@ -209,6 +209,11 @@ neg_msg = "can't convert negative number to unsigned" ovf_msg = "long too big to convert" +def is_zero(space, w_ob): + return ((space.isinstance_w(w_ob, space.w_int) or + space.isinstance_w(w_ob, space.w_long)) + and not space.is_true(w_ob)) + # ____________________________________________________________ class _NotStandardObject(Exception): 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 @@ -387,8 +387,19 @@ assert (x != None) is True assert (x == ["hello"]) is False assert (x != ["hello"]) is True - y = cast(p, 0) - assert (y == None) is False + +def test_cmp_pointer_with_0(): + p = new_pointer_type(new_primitive_type("int")) + x = cast(p, 0) + assert (x == 0) is True + assert (x != 0) is False + assert (0 == x) is True + assert (0 != x) is False + y = cast(p, 42) + assert (y == 0) is False + assert (y != 0) is True + assert (0 == y) is False + assert (0 != y) is True def test_invalid_indexing(): p = new_primitive_type("int") @@ -768,7 +779,7 @@ assert s.a2 == 456 assert s.a3 == 0 assert s.p4 == cast(BVoidP, 0) - assert s.p4 != 0 + assert s.p4 == 0 # s = newp(BStructPtr, {'a2': 41122, 'a3': -123}) assert s.a1 == 0 @@ -781,11 +792,14 @@ p = newp(BIntPtr, 14141) s = newp(BStructPtr, [12, 34, 56, p]) assert s.p4 == p - assert s.p4 + s.p4 = 0 + assert s.p4 == 0 # s = newp(BStructPtr, [12, 34, 56, cast(BVoidP, 0)]) + assert s.p4 == 0 + # + s = newp(BStructPtr, [12, 34, 56, 0]) assert s.p4 == cast(BVoidP, 0) - assert not s.p4 # py.test.raises(TypeError, newp, BStructPtr, [12, 34, 56, None]) @@ -1003,10 +1017,11 @@ f = cast(BFunc23, _testfunc(23)) res = f(b"foo") assert res == 1000 * ord(b'f') - res = f(cast(BVoidP, 0)) # NULL + res = f(0) # NULL + assert res == -42 + res = f(long(0)) # NULL assert res == -42 py.test.raises(TypeError, f, None) - py.test.raises(TypeError, f, 0) py.test.raises(TypeError, f, 0.0) def test_call_function_23_bis(): @@ -2497,7 +2512,6 @@ pass # win32 def test_FILE(): - """FILE is not supported natively any more.""" if sys.platform == "win32": py.test.skip("testing FILE not implemented") # @@ -2507,16 +2521,82 @@ BCharP = new_pointer_type(BChar) BInt = new_primitive_type("int") BFunc = new_function_type((BCharP, BFILEP), BInt, False) + BFunc2 = new_function_type((BFILEP, BCharP), BInt, True) + ll = find_and_load_library('c') + fputs = ll.load_function(BFunc, "fputs") + fscanf = ll.load_function(BFunc2, "fscanf") + # + import posix + fdr, fdw = posix.pipe() + fr1 = posix.fdopen(fdr, 'rb', 256) + fw1 = posix.fdopen(fdw, 'wb', 256) + # + fw1.write(b"X") + res = fputs(b"hello world\n", fw1) + assert res >= 0 + fw1.flush() # should not be needed + # + p = newp(new_array_type(BCharP, 100), None) + res = fscanf(fr1, b"%s\n", p) + assert res == 1 + assert string(p) == b"Xhello" + fr1.close() + fw1.close() + +def test_FILE_only_for_FILE_arg(): + if sys.platform == "win32": + py.test.skip("testing FILE not implemented") + # + B_NOT_FILE = new_struct_type("NOT_FILE") + B_NOT_FILEP = new_pointer_type(B_NOT_FILE) + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BInt = new_primitive_type("int") + BFunc = new_function_type((BCharP, B_NOT_FILEP), BInt, False) ll = find_and_load_library('c') fputs = ll.load_function(BFunc, "fputs") # import posix fdr, fdw = posix.pipe() - fr1 = posix.fdopen(fdr, 'rb', 256) + fr1 = posix.fdopen(fdr, 'r') + fw1 = posix.fdopen(fdw, 'w') + # + e = py.test.raises(TypeError, fputs, b"hello world\n", fw1) + assert str(e.value).startswith( + "initializer for ctype 'struct NOT_FILE *' must " + "be a cdata pointer, not ") + +def test_FILE_object(): + if sys.platform == "win32": + py.test.skip("testing FILE not implemented") + # + BFILE = new_struct_type("$FILE") + BFILEP = new_pointer_type(BFILE) + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BInt = new_primitive_type("int") + BFunc = new_function_type((BCharP, BFILEP), BInt, False) + BFunc2 = new_function_type((BFILEP,), BInt, False) + ll = find_and_load_library('c') + fputs = ll.load_function(BFunc, "fputs") + fileno = ll.load_function(BFunc2, "fileno") + # + import posix + fdr, fdw = posix.pipe() fw1 = posix.fdopen(fdw, 'wb', 256) - py.test.raises(TypeError, fputs, b"hello world\n", fw1) - fr1.close() + # + fw1p = cast(BFILEP, fw1) + fw1.write(b"X") + fw1.flush() + res = fputs(b"hello\n", fw1p) + assert res >= 0 + res = fileno(fw1p) + assert (res == fdw) == (sys.version_info < (3,)) fw1.close() + # + data = posix.read(fdr, 256) + assert data == b"Xhello\n" + posix.close(fdr) def test_GetLastError(): if sys.platform != "win32": @@ -2644,17 +2724,6 @@ c[1:3] = d assert list(c) == [0, 40, 50, 30, 0] -def test_FILE_forbidden(): - BFILE = new_struct_type("_IO_FILE") - BFILEP = new_pointer_type(BFILE) - BFunc = new_function_type((BFILEP,), BFILEP, False) - func = cast(BFunc, 0) - with open(__file__, "rb") as f: - e = py.test.raises(TypeError, func, f) - if '__pypy__' not in sys.builtin_module_names: - assert ('note that you cannot pass Python files directly ' - 'any more since CFFI 0.6') in str(e.value) - def test_version(): # this test is here mostly for PyPy assert __version__ == "0.6" diff --git a/pypy/module/_cffi_backend/test/test_ztranslation.py b/pypy/module/_cffi_backend/test/test_ztranslation.py --- a/pypy/module/_cffi_backend/test/test_ztranslation.py +++ b/pypy/module/_cffi_backend/test/test_ztranslation.py @@ -1,7 +1,20 @@ from pypy.objspace.fake.checkmodule import checkmodule +from pypy.module._cffi_backend import ctypeptr +from rpython.rtyper.lltypesystem import lltype, rffi # side-effect: FORMAT_LONGDOUBLE must be built before test_checkmodule() from pypy.module._cffi_backend import misc def test_checkmodule(): - checkmodule('_cffi_backend') + # prepare_file_argument() is not working without translating the _file + # module too + def dummy_prepare_file_argument(space, fileobj): + return lltype.nullptr(rffi.CCHARP.TO) + old = ctypeptr.prepare_file_argument + try: + ctypeptr.prepare_file_argument = dummy_prepare_file_argument + # + checkmodule('_cffi_backend') + # + finally: + ctypeptr.prepare_file_argument = old diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -4281,6 +4281,35 @@ """ self.optimize_loop(ops, expected) + def test_add_sub_ovf_second_operation_regular(self): + py.test.skip("Smalltalk would like this to pass") + # This situation occurs in Smalltalk because it uses 1-based indexing. + # The below code is equivalent to a loop over an array. + ops = """ + [i1] + i2 = int_sub(i1, 1) + escape(i2) + i3 = int_add_ovf(i1, 1) + guard_no_overflow() [] + jump(i3) + """ + preamble = """ + [i1] + i2 = int_sub(i1, 1) + escape(i2) + i3 = int_add_ovf(i1, 1) + guard_no_overflow() [] + jump(i3, i1) + """ + expected = """ + [i1, i2] + escape(i2) + i3 = int_add_ovf(i1, 1) + guard_no_overflow() [] + jump(i3, i1) + """ + self.optimize_loop(ops, expected, preamble) + def test_add_sub_ovf_virtual_unroll(self): ops = """ [p15] _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit