[pypy-commit] pypy py3k: hg merge default.
amauryfa
noreply at buildbot.pypy.org
Wed May 30 23:11:12 CEST 2012
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3k
Changeset: r55210:66685752ce86
Date: 2012-05-30 22:32 +0200
http://bitbucket.org/pypy/pypy/changeset/66685752ce86/
Log: hg merge default. Note: the step-one-xrange optimization was not
ported.
diff --git a/lib-python/2.7/test/test_fileio.py b/lib-python/2.7/test/test_fileio.py
--- a/lib-python/2.7/test/test_fileio.py
+++ b/lib-python/2.7/test/test_fileio.py
@@ -318,6 +318,7 @@
self.assertRaises(ValueError, _FileIO, -10)
self.assertRaises(OSError, _FileIO, make_bad_fd())
if sys.platform == 'win32':
+ raise unittest.SkipTest('Set _invalid_parameter_handler for low level io')
import msvcrt
self.assertRaises(IOError, msvcrt.get_osfhandle, make_bad_fd())
diff --git a/lib-python/2.7/test/test_os.py b/lib-python/2.7/test/test_os.py
--- a/lib-python/2.7/test/test_os.py
+++ b/lib-python/2.7/test/test_os.py
@@ -690,7 +690,8 @@
class PosixUidGidTests(unittest.TestCase):
pass
- at unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
+ at unittest.skipUnless(sys.platform == "win32" and hasattr(os,'kill'),
+ "Win32 specific tests")
class Win32KillTests(unittest.TestCase):
def _kill(self, sig):
# Start sys.executable as a subprocess and communicate from the
diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py
--- a/pypy/annotation/bookkeeper.py
+++ b/pypy/annotation/bookkeeper.py
@@ -531,8 +531,11 @@
try:
assert pyobj._freeze_()
except AttributeError:
- raise Exception("unexpected prebuilt constant: %r" % (
- pyobj,))
+ if hasattr(pyobj, '__call__'):
+ msg = "object with a __call__ is not RPython"
+ else:
+ msg = "unexpected prebuilt constant"
+ raise Exception("%s: %r" % (msg, pyobj))
result = self.getfrozen(pyobj)
self.descs[pyobj] = result
return result
diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py
--- a/pypy/annotation/builtin.py
+++ b/pypy/annotation/builtin.py
@@ -298,6 +298,9 @@
def rarith_intmask(s_obj):
return SomeInteger()
+def rarith_longlongmask(s_obj):
+ return SomeInteger(knowntype=pypy.rlib.rarithmetic.r_longlong)
+
def robjmodel_instantiate(s_clspbc):
assert isinstance(s_clspbc, SomePBC)
clsdef = None
@@ -376,6 +379,7 @@
BUILTIN_ANALYZERS[original] = value
BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.intmask] = rarith_intmask
+BUILTIN_ANALYZERS[pypy.rlib.rarithmetic.longlongmask] = rarith_longlongmask
BUILTIN_ANALYZERS[pypy.rlib.objectmodel.instantiate] = robjmodel_instantiate
BUILTIN_ANALYZERS[pypy.rlib.objectmodel.r_dict] = robjmodel_r_dict
BUILTIN_ANALYZERS[pypy.rlib.objectmodel.hlinvoke] = robjmodel_hlinvoke
diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py
--- a/pypy/annotation/test/test_annrpython.py
+++ b/pypy/annotation/test/test_annrpython.py
@@ -3756,6 +3756,29 @@
s = a.build_types(main, [int])
assert isinstance(s, annmodel.SomeInteger)
+ def test_join_none_and_nonnull(self):
+ from pypy.rlib.rstring import assert_str0
+
+ def f(i):
+ a = str(i)
+ a = assert_str0(a)
+ return a.join([None])
+
+ a = self.RPythonAnnotator()
+ s = a.build_types(f, [int])
+ assert isinstance(s, annmodel.SomeString)
+ assert not s.can_be_None
+
+ def test_no___call__(self):
+ class X(object):
+ def __call__(self):
+ xxx
+ x = X()
+ def f():
+ return x
+ a = self.RPythonAnnotator()
+ e = py.test.raises(Exception, a.build_types, f, [])
+ assert 'object with a __call__ is not RPython' in str(e.value)
def g(n):
return [0,1,2,n]
diff --git a/pypy/annotation/unaryop.py b/pypy/annotation/unaryop.py
--- a/pypy/annotation/unaryop.py
+++ b/pypy/annotation/unaryop.py
@@ -494,7 +494,7 @@
return SomeImpossibleValue()
getbookkeeper().count("str_join", str)
s_item = s_list.listdef.read_item()
- if isinstance(s_item, SomeImpossibleValue):
+ if s_None.contains(s_item):
if isinstance(str, SomeUnicodeString):
return immutablevalue(u"")
return immutablevalue("")
diff --git a/pypy/doc/_ref.txt b/pypy/doc/_ref.txt
--- a/pypy/doc/_ref.txt
+++ b/pypy/doc/_ref.txt
@@ -84,7 +84,6 @@
.. _`pypy/rlib/rbigint.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/rlib/rbigint.py
.. _`pypy/rlib/rrandom.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/rlib/rrandom.py
.. _`pypy/rlib/rsocket.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/rlib/rsocket.py
-.. _`pypy/rlib/rstack.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/rlib/rstack.py
.. _`pypy/rlib/streamio.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/rlib/streamio.py
.. _`pypy/rlib/test`: https://bitbucket.org/pypy/pypy/src/default/pypy/rlib/test/
.. _`pypy/rlib/unroll.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/rlib/unroll.py
@@ -97,7 +96,6 @@
.. _`pypy/rpython/memory/gc/hybrid.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/rpython/memory/gc/hybrid.py
.. _`pypy/rpython/memory/gc/markcompact.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/rpython/memory/gc/markcompact.py
.. _`pypy/rpython/memory/gc/marksweep.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/rpython/memory/gc/marksweep.py
-.. _`pypy/rpython/memory/gc/minimark.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/rpython/memory/gc/minimark.py
.. _`pypy/rpython/memory/gc/minimarkpage.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/rpython/memory/gc/minimarkpage.py
.. _`pypy/rpython/memory/gc/semispace.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/rpython/memory/gc/semispace.py
.. _`pypy/rpython/ootypesystem/`: https://bitbucket.org/pypy/pypy/src/default/pypy/rpython/ootypesystem/
@@ -116,8 +114,8 @@
.. _`pypy/translator/backendopt/`: https://bitbucket.org/pypy/pypy/src/default/pypy/translator/backendopt/
.. _`pypy/translator/c/`: https://bitbucket.org/pypy/pypy/src/default/pypy/translator/c/
.. _`pypy/translator/c/src/stacklet/`: https://bitbucket.org/pypy/pypy/src/default/pypy/translator/c/src/stacklet/
+.. _`pypy/translator/c/src/stacklet/stacklet.h`: https://bitbucket.org/pypy/pypy/src/default/pypy/translator/c/src/stacklet/stacklet.h
.. _`pypy/translator/cli/`: https://bitbucket.org/pypy/pypy/src/default/pypy/translator/cli/
.. _`pypy/translator/goal/`: https://bitbucket.org/pypy/pypy/src/default/pypy/translator/goal/
.. _`pypy/translator/jvm/`: https://bitbucket.org/pypy/pypy/src/default/pypy/translator/jvm/
-.. _`pypy/translator/stackless/`: https://bitbucket.org/pypy/pypy/src/default/pypy/translator/stackless/
.. _`pypy/translator/tool/`: https://bitbucket.org/pypy/pypy/src/default/pypy/translator/tool/
diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst
--- a/pypy/doc/getting-started-python.rst
+++ b/pypy/doc/getting-started-python.rst
@@ -50,10 +50,10 @@
libz-dev libbz2-dev libncurses-dev libexpat1-dev \
libssl-dev libgc-dev python-sphinx python-greenlet
- On a Fedora box these are::
+ On a Fedora-16 box these are::
[user at fedora-or-rh-box ~]$ sudo yum install \
- gcc make python-devel libffi-devel pkg-config \
+ gcc make python-devel libffi-devel pkgconfig \
zlib-devel bzip2-devel ncurses-devel expat-devel \
openssl-devel gc-devel python-sphinx python-greenlet
diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py
new file mode 100644
--- /dev/null
+++ b/pypy/doc/test/test_whatsnew.py
@@ -0,0 +1,80 @@
+import py
+import pypy
+from commands import getoutput
+ROOT = py.path.local(pypy.__file__).dirpath().dirpath()
+
+
+def parse_doc(s):
+ startrev = None
+ branches = set()
+ def parseline(line):
+ _, value = line.split(':', 1)
+ return value.strip()
+ #
+ for line in s.splitlines():
+ if line.startswith('.. startrev:'):
+ startrev = parseline(line)
+ elif line.startswith('.. branch:'):
+ branches.add(parseline(line))
+ return startrev, branches
+
+def get_merged_branches(path, startrev, endrev):
+ # X = take all the merges which are descendants of startrev and are on default
+ # revset = all the parents of X which are not on default
+ # ===>
+ # revset contains all the branches which have been merged to default since
+ # startrev
+ revset = 'parents(%s::%s and \
+ merge() and \
+ branch(default)) and \
+ not branch(default)' % (startrev, endrev)
+ cmd = r"hg log -R '%s' -r '%s' --template '{branches}\n'" % (path, revset)
+ out = getoutput(cmd)
+ branches = set(map(str.strip, out.splitlines()))
+ return branches
+
+
+def test_parse_doc():
+ s = """
+=====
+Title
+=====
+
+.. startrev: 12345
+
+bla bla bla bla
+
+.. branch: foobar
+
+xxx yyy zzz
+
+.. branch: hello
+
+qqq www ttt
+"""
+ startrev, branches = parse_doc(s)
+ assert startrev == '12345'
+ assert branches == set(['foobar', 'hello'])
+
+def test_get_merged_branches():
+ branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93')
+ assert branches == set(['numpy-indexing-by-arrays-bool',
+ 'better-jit-hooks-2',
+ 'numpypy-ufuncs'])
+
+def test_whatsnew():
+ doc = ROOT.join('pypy', 'doc')
+ whatsnew_list = doc.listdir('whatsnew-*.rst')
+ whatsnew_list.sort()
+ last_whatsnew = whatsnew_list[-1].read()
+ startrev, documented = parse_doc(last_whatsnew)
+ merged = get_merged_branches(ROOT, startrev, '')
+ not_documented = merged.difference(documented)
+ not_merged = documented.difference(merged)
+ print 'Branches merged but not documented:'
+ print '\n'.join(not_documented)
+ print
+ print 'Branches documented but not merged:'
+ print '\n'.join(not_merged)
+ print
+ assert not not_documented and not not_merged
diff --git a/pypy/doc/whatsnew-1.9.rst b/pypy/doc/whatsnew-1.9.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/whatsnew-1.9.rst
@@ -0,0 +1,80 @@
+======================
+What's new in PyPy 1.9
+======================
+
+.. this is the revision just after the creation of the release-1.8.x branch
+.. startrev: a4261375b359
+
+.. branch: array_equal
+.. branch: better-jit-hooks-2
+.. branch: faster-heapcache
+.. branch: faster-str-decode-escape
+.. branch: float-bytes
+Added some primitives for dealing with floats as raw bytes.
+.. branch: float-bytes-2
+Added more float byte primitives.
+.. branch: jit-frame-counter
+Put more debug info into resops.
+.. branch: kill-geninterp
+.. branch: kqueue
+Finished select.kqueue.
+.. branch: kwargsdict-strategy
+.. branch: matrixmath-dot
+numpypy can now handle matrix multiplication.
+.. branch: merge-2.7.2
+The stdlib was updated to version 2.7.2
+.. branch: ndmin
+.. branch: newindex
+.. branch: non-null-threadstate
+cpyext: Better support for PyEval_SaveThread and other PyTreadState_*
+functions.
+.. branch: numppy-flatitter
+.. branch: numpy-back-to-applevel
+.. branch: numpy-concatenate
+.. branch: numpy-indexing-by-arrays-bool
+.. branch: numpy-record-dtypes
+.. branch: numpy-single-jitdriver
+.. branch: numpy-ufuncs2
+.. branch: numpy-ufuncs3
+.. branch: numpypy-issue1137
+.. branch: numpypy-out
+The "out" argument was added to most of the numypypy functions.
+.. branch: numpypy-shape-bug
+.. branch: numpypy-ufuncs
+.. branch: pytest
+.. branch: safe-getargs-freelist
+.. branch: set-strategies
+.. branch: speedup-list-comprehension
+.. branch: stdlib-unification
+The directory "lib-python/modified-2.7" has been removed, and its
+content merged into "lib-python/2.7".
+.. branch: step-one-xrange
+The common case of a xrange iterator with no step argument specifed
+was somewhat optimized. The tightest loop involving it,
+sum(xrange(n)), is now 18% faster on average.
+.. branch: string-NUL
+PyPy refuses filenames with chr(0) characters. This is implemented in
+RPython which can enforce no-NUL correctness and propagation, similar
+to const-correctness in C++.
+.. branch: win32-cleanup
+.. branch: win32-cleanup2
+.. branch: win32-cleanup_2
+Many bugs were corrected for windows 32 bit. New functionality was added to
+test validity of file descriptors, leading to the removal of the global
+_invalid_parameter_handler
+.. branch: win32-kill
+Add os.kill to windows even if translating python does not have os.kill
+.. branch: win64-stage1
+.. branch: zlib-mem-pressure
+
+.. branch: ffistruct
+The ``ffistruct`` branch adds a very low level way to express C structures
+with _ffi in a very JIT-friendly way
+
+
+
+.. "uninteresting" branches that we should just ignore for the whatsnew:
+.. branch: exception-cannot-occur
+.. branch: sanitize-finally-stack
+.. branch: revive-dlltool
+ (preliminary work for sepcomp)
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1440,7 +1440,7 @@
self.wrap("expected a 32-bit integer"))
return value
- def truncatedint(self, w_obj):
+ def truncatedint_w(self, w_obj):
# Like space.gateway_int_w(), but return the integer truncated
# instead of raising OverflowError. For obscure cases only.
try:
@@ -1451,6 +1451,17 @@
from pypy.rlib.rarithmetic import intmask
return intmask(self.bigint_w(w_obj).uintmask())
+ def truncatedlonglong_w(self, w_obj):
+ # Like space.gateway_r_longlong_w(), but return the integer truncated
+ # instead of raising OverflowError.
+ try:
+ return self.r_longlong_w(w_obj)
+ except OperationError, e:
+ if not e.match(self, self.w_OverflowError):
+ raise
+ from pypy.rlib.rarithmetic import longlongmask
+ return longlongmask(self.bigint_w(w_obj).ulonglongmask())
+
def c_filedescriptor_w(self, w_fd):
# This is only used sometimes in CPython, e.g. for os.fsync() but
# not os.close(). It's likely designed for 'select'. It's irregular
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -145,7 +145,7 @@
def visit_c_nonnegint(self, el, app_sig):
self.checked_space_method(el, app_sig)
- def visit_truncatedint(self, el, app_sig):
+ def visit_truncatedint_w(self, el, app_sig):
self.checked_space_method(el, app_sig)
def visit__Wrappable(self, el, app_sig):
@@ -268,8 +268,8 @@
def visit_c_nonnegint(self, typ):
self.run_args.append("space.c_nonnegint_w(%s)" % (self.scopenext(),))
- def visit_truncatedint(self, typ):
- self.run_args.append("space.truncatedint(%s)" % (self.scopenext(),))
+ def visit_truncatedint_w(self, typ):
+ self.run_args.append("space.truncatedint_w(%s)" % (self.scopenext(),))
def _make_unwrap_activation_class(self, unwrap_spec, cache={}):
try:
@@ -404,8 +404,8 @@
def visit_c_nonnegint(self, typ):
self.unwrap.append("space.c_nonnegint_w(%s)" % (self.nextarg(),))
- def visit_truncatedint(self, typ):
- self.unwrap.append("space.truncatedint(%s)" % (self.nextarg(),))
+ def visit_truncatedint_w(self, typ):
+ self.unwrap.append("space.truncatedint_w(%s)" % (self.nextarg(),))
def make_fastfunc(unwrap_spec, func):
unwrap_info = UnwrapSpec_FastFunc_Unwrap()
diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py
--- a/pypy/interpreter/test/test_objspace.py
+++ b/pypy/interpreter/test/test_objspace.py
@@ -234,6 +234,37 @@
w_obj = space.wrap(-12)
space.raises_w(space.w_ValueError, space.r_ulonglong_w, w_obj)
+ def test_truncatedint_w(self):
+ space = self.space
+ assert space.truncatedint_w(space.wrap(42)) == 42
+ assert space.truncatedint_w(space.wrap(sys.maxint)) == sys.maxint
+ assert space.truncatedint_w(space.wrap(sys.maxint+1)) == -sys.maxint-1
+ assert space.truncatedint_w(space.wrap(-1)) == -1
+ assert space.truncatedint_w(space.wrap(-sys.maxint-2)) == sys.maxint
+
+ def test_truncatedlonglong_w(self):
+ space = self.space
+ w_value = space.wrap(12)
+ res = space.truncatedlonglong_w(w_value)
+ assert res == 12
+ assert type(res) is r_longlong
+ #
+ w_value = space.wrap(r_ulonglong(9223372036854775808))
+ res = space.truncatedlonglong_w(w_value)
+ assert res == -9223372036854775808
+ assert type(res) is r_longlong
+ #
+ w_value = space.wrap(r_ulonglong(18446744073709551615))
+ res = space.truncatedlonglong_w(w_value)
+ assert res == -1
+ assert type(res) is r_longlong
+ #
+ w_value = space.wrap(r_ulonglong(18446744073709551616))
+ res = space.truncatedlonglong_w(w_value)
+ assert res == 0
+ assert type(res) is r_longlong
+
+
def test_call_obj_args(self):
from pypy.interpreter.argument import Arguments
diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -823,7 +823,9 @@
op_getfield_gc_pure = op_getfield_gc
def op_getfield_raw(self, fielddescr, struct):
- if fielddescr.typeinfo == REF:
+ if fielddescr.arg_types == 'dynamic': # abuse of .arg_types
+ return do_getfield_raw_dynamic(struct, fielddescr)
+ elif fielddescr.typeinfo == REF:
return do_getfield_raw_ptr(struct, fielddescr.ofs)
elif fielddescr.typeinfo == INT:
return do_getfield_raw_int(struct, fielddescr.ofs)
@@ -919,7 +921,9 @@
raise NotImplementedError
def op_setfield_raw(self, fielddescr, struct, newvalue):
- if fielddescr.typeinfo == REF:
+ if fielddescr.arg_types == 'dynamic': # abuse of .arg_types
+ do_setfield_raw_dynamic(struct, fielddescr, newvalue)
+ elif fielddescr.typeinfo == REF:
do_setfield_raw_ptr(struct, fielddescr.ofs, newvalue)
elif fielddescr.typeinfo == INT:
do_setfield_raw_int(struct, fielddescr.ofs, newvalue)
@@ -1500,6 +1504,17 @@
def do_getfield_raw_ptr(struct, fieldnum):
return cast_to_ptr(_getfield_raw(struct, fieldnum))
+def do_getfield_raw_dynamic(struct, fielddescr):
+ from pypy.rlib import libffi
+ addr = cast_from_int(rffi.VOIDP, struct)
+ ofs = fielddescr.ofs
+ if fielddescr.is_pointer_field():
+ assert False, 'fixme'
+ elif fielddescr.is_float_field():
+ assert False, 'fixme'
+ else:
+ return libffi._struct_getfield(lltype.Signed, addr, ofs)
+
def do_new(size):
TYPE = symbolic.Size2Type[size]
x = lltype.malloc(TYPE, zero=True)
@@ -1597,6 +1612,17 @@
newvalue = cast_from_ptr(FIELDTYPE, newvalue)
setattr(ptr, fieldname, newvalue)
+def do_setfield_raw_dynamic(struct, fielddescr, newvalue):
+ from pypy.rlib import libffi
+ addr = cast_from_int(rffi.VOIDP, struct)
+ ofs = fielddescr.ofs
+ if fielddescr.is_pointer_field():
+ assert False, 'fixme'
+ elif fielddescr.is_float_field():
+ assert False, 'fixme'
+ else:
+ libffi._struct_setfield(lltype.Signed, addr, ofs, newvalue)
+
def do_newstr(length):
x = rstr.mallocstr(length)
return cast_to_ptr(x)
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -334,6 +334,16 @@
token = history.getkind(getattr(S, fieldname))
return self.getdescr(ofs, token[0], name=fieldname)
+ def fielddescrof_dynamic(self, offset, fieldsize, is_pointer, is_float, is_signed):
+ if is_pointer:
+ typeinfo = REF
+ elif is_float:
+ typeinfo = FLOAT
+ else:
+ typeinfo = INT
+ # we abuse the arg_types field to distinguish dynamic and static descrs
+ return self.getdescr(offset, typeinfo, arg_types='dynamic', name='<dynamic field>')
+
def interiorfielddescrof(self, A, fieldname):
S = A.OF
width = symbolic.get_size(A)
diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py
--- a/pypy/jit/backend/llsupport/descr.py
+++ b/pypy/jit/backend/llsupport/descr.py
@@ -237,18 +237,25 @@
cache[(ARRAY, name)] = descr
return descr
+def compute_flag(is_pointer, is_float, is_signed):
+ if is_pointer:
+ assert not is_float
+ return FLAG_POINTER
+ elif is_float:
+ return FLAG_FLOAT
+ elif is_signed:
+ return FLAG_SIGNED
+ else:
+ return FLAG_UNSIGNED
+
+def get_dynamic_field_descr(offset, fieldsize, is_pointer, is_float, is_signed):
+ flag = compute_flag(is_pointer, is_float, is_signed)
+ return FieldDescr('dynamic', offset, fieldsize, flag)
+
def get_dynamic_interiorfield_descr(gc_ll_descr, offset, width, fieldsize,
is_pointer, is_float, is_signed):
arraydescr = ArrayDescr(0, width, None, FLAG_STRUCT)
- if is_pointer:
- assert not is_float
- flag = FLAG_POINTER
- elif is_float:
- flag = FLAG_FLOAT
- elif is_signed:
- flag = FLAG_SIGNED
- else:
- flag = FLAG_UNSIGNED
+ flag = compute_flag(is_pointer, is_float, is_signed)
fielddescr = FieldDescr('dynamic', offset, fieldsize, flag)
return InteriorFieldDescr(arraydescr, fielddescr)
diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py
--- a/pypy/jit/backend/llsupport/llmodel.py
+++ b/pypy/jit/backend/llsupport/llmodel.py
@@ -11,7 +11,7 @@
from pypy.jit.backend.llsupport.descr import (
get_size_descr, get_field_descr, get_array_descr,
get_call_descr, get_interiorfield_descr, get_dynamic_interiorfield_descr,
- FieldDescr, ArrayDescr, CallDescr, InteriorFieldDescr)
+ FieldDescr, ArrayDescr, CallDescr, InteriorFieldDescr, get_dynamic_field_descr)
from pypy.jit.backend.llsupport.asmmemmgr import AsmMemoryManager
@@ -245,6 +245,9 @@
def fielddescrof(self, STRUCT, fieldname):
return get_field_descr(self.gc_ll_descr, STRUCT, fieldname)
+ def fielddescrof_dynamic(self, offset, fieldsize, is_pointer, is_float, is_signed):
+ return get_dynamic_field_descr(offset, fieldsize, is_pointer, is_float, is_signed)
+
def unpack_fielddescr(self, fielddescr):
assert isinstance(fielddescr, FieldDescr)
return fielddescr.offset
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -1660,20 +1660,37 @@
assert s.x == chr(190)
assert s.y == chr(150)
- def test_field_raw_pure(self):
- # This is really testing the same thing as test_field_basic but can't
- # hurt...
- S = lltype.Struct('S', ('x', lltype.Signed))
+ def test_fielddescrof_dynamic(self):
+ S = lltype.Struct('S',
+ ('x', lltype.Signed),
+ ('y', lltype.Signed),
+ )
+ longsize = rffi.sizeof(lltype.Signed)
+ y_ofs = longsize
s = lltype.malloc(S, flavor='raw')
sa = llmemory.cast_ptr_to_adr(s)
s_box = BoxInt(heaptracker.adr2int(sa))
+ #
+ field = self.cpu.fielddescrof(S, 'y')
+ field_dyn = self.cpu.fielddescrof_dynamic(offset=y_ofs,
+ fieldsize=longsize,
+ is_pointer=False,
+ is_float=False,
+ is_signed=True)
+ assert field.is_pointer_field() == field_dyn.is_pointer_field()
+ assert field.is_float_field() == field_dyn.is_float_field()
+ if 'llgraph' not in str(self.cpu):
+ assert field.is_field_signed() == field_dyn.is_field_signed()
+
+ #
for get_op, set_op in ((rop.GETFIELD_RAW, rop.SETFIELD_RAW),
(rop.GETFIELD_RAW_PURE, rop.SETFIELD_RAW)):
- fd = self.cpu.fielddescrof(S, 'x')
- self.execute_operation(set_op, [s_box, BoxInt(32)], 'void',
- descr=fd)
- res = self.execute_operation(get_op, [s_box], 'int', descr=fd)
- assert res.getint() == 32
+ for descr in (field, field_dyn):
+ self.execute_operation(set_op, [s_box, BoxInt(32)], 'void',
+ descr=descr)
+ res = self.execute_operation(get_op, [s_box], 'int', descr=descr)
+ assert res.getint() == 32
+
lltype.free(s, flavor='raw')
def test_new_with_vtable(self):
diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py
--- a/pypy/jit/codewriter/effectinfo.py
+++ b/pypy/jit/codewriter/effectinfo.py
@@ -48,8 +48,10 @@
OS_LIBFFI_PREPARE = 60
OS_LIBFFI_PUSH_ARG = 61
OS_LIBFFI_CALL = 62
- OS_LIBFFI_GETARRAYITEM = 63
- OS_LIBFFI_SETARRAYITEM = 64
+ OS_LIBFFI_STRUCT_GETFIELD = 63
+ OS_LIBFFI_STRUCT_SETFIELD = 64
+ OS_LIBFFI_GETARRAYITEM = 65
+ OS_LIBFFI_SETARRAYITEM = 66
#
OS_LLONG_INVERT = 69
OS_LLONG_ADD = 70
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -1675,6 +1675,12 @@
elif oopspec_name.startswith('libffi_call_'):
oopspecindex = EffectInfo.OS_LIBFFI_CALL
extraeffect = EffectInfo.EF_RANDOM_EFFECTS
+ elif oopspec_name == 'libffi_struct_getfield':
+ oopspecindex = EffectInfo.OS_LIBFFI_STRUCT_GETFIELD
+ extraeffect = EffectInfo.EF_CANNOT_RAISE
+ elif oopspec_name == 'libffi_struct_setfield':
+ oopspecindex = EffectInfo.OS_LIBFFI_STRUCT_SETFIELD
+ extraeffect = EffectInfo.EF_CANNOT_RAISE
elif oopspec_name == 'libffi_array_getitem':
oopspecindex = EffectInfo.OS_LIBFFI_GETARRAYITEM
extraeffect = EffectInfo.EF_CANNOT_RAISE
diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -456,7 +456,6 @@
def _ll_3_libffi_call_void(llfunc, funcsym, ll_args):
return func(llfunc)._do_call(funcsym, ll_args, lltype.Void)
-
# in the following calls to builtins, the JIT is allowed to look inside:
inline_calls_to = [
('int_floordiv_ovf_zer', [lltype.Signed, lltype.Signed], lltype.Signed),
diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py
--- a/pypy/jit/metainterp/optimizeopt/fficall.py
+++ b/pypy/jit/metainterp/optimizeopt/fficall.py
@@ -7,7 +7,9 @@
from pypy.rlib.libffi import Func
from pypy.rlib.objectmodel import we_are_translated
from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
-from pypy.rpython.lltypesystem import llmemory, rffi
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.rarithmetic import intmask
class FuncInfo(object):
@@ -118,6 +120,9 @@
ops = self.do_push_arg(op)
elif oopspec == EffectInfo.OS_LIBFFI_CALL:
ops = self.do_call(op)
+ elif (oopspec == EffectInfo.OS_LIBFFI_STRUCT_GETFIELD or
+ oopspec == EffectInfo.OS_LIBFFI_STRUCT_SETFIELD):
+ ops = self.do_struct_getsetfield(op, oopspec)
elif (oopspec == EffectInfo.OS_LIBFFI_GETARRAYITEM or
oopspec == EffectInfo.OS_LIBFFI_SETARRAYITEM):
ops = self.do_getsetarrayitem(op, oopspec)
@@ -195,6 +200,46 @@
ops.append(newop)
return ops
+ def do_struct_getsetfield(self, op, oopspec):
+ ffitypeval = self.getvalue(op.getarg(1))
+ addrval = self.getvalue(op.getarg(2))
+ offsetval = self.getvalue(op.getarg(3))
+ if not ffitypeval.is_constant() or not offsetval.is_constant():
+ return [op]
+ #
+ ffitypeaddr = ffitypeval.box.getaddr()
+ ffitype = llmemory.cast_adr_to_ptr(ffitypeaddr, clibffi.FFI_TYPE_P)
+ offset = offsetval.box.getint()
+ descr = self._get_field_descr(ffitype, offset)
+ #
+ arglist = [addrval.force_box(self.optimizer)]
+ if oopspec == EffectInfo.OS_LIBFFI_STRUCT_GETFIELD:
+ opnum = rop.GETFIELD_RAW
+ else:
+ opnum = rop.SETFIELD_RAW
+ newval = self.getvalue(op.getarg(4))
+ arglist.append(newval.force_box(self.optimizer))
+ #
+ newop = ResOperation(opnum, arglist, op.result, descr=descr)
+ return [newop]
+
+ def _get_field_descr(self, ffitype, offset):
+ kind = libffi.types.getkind(ffitype)
+ is_pointer = is_float = is_signed = False
+ if ffitype is libffi.types.pointer:
+ is_pointer = True
+ elif kind == 'i':
+ is_signed = True
+ elif kind == 'f' or kind == 'I' or kind == 'U':
+ # longlongs are treated as floats, see e.g. llsupport/descr.py:getDescrClass
+ is_float = True
+ else:
+ assert False, "unsupported ffitype or kind"
+ #
+ fieldsize = intmask(ffitype.c_size)
+ return self.optimizer.cpu.fielddescrof_dynamic(offset, fieldsize,
+ is_pointer, is_float, is_signed)
+
def do_getsetarrayitem(self, op, oopspec):
ffitypeval = self.getvalue(op.getarg(1))
widthval = self.getvalue(op.getarg(2))
@@ -245,6 +290,7 @@
offset, width, fieldsize, is_pointer, is_float, is_signed
)
+
def propagate_forward(self, op):
if self.logops is not None:
debug_print(self.logops.repr_of_resop(op))
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -5068,6 +5068,7 @@
self.optimize_strunicode_loop(ops, expected)
def test_call_pure_vstring_const(self):
+ py.test.skip("implement me")
ops = """
[]
p0 = newstr(3)
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py
@@ -56,6 +56,13 @@
restype=types.sint,
flags=43)
#
+ ffi_slong = types.slong
+ dyn_123_field = cpu.fielddescrof_dynamic(offset=123,
+ fieldsize=types.slong.c_size,
+ is_pointer=False,
+ is_float=False,
+ is_signed=True)
+ #
def calldescr(cpu, FUNC, oopspecindex, extraeffect=None):
if extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
f = None # means "can force all" really
@@ -69,6 +76,8 @@
libffi_push_arg = calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_PUSH_ARG)
libffi_call = calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_CALL,
EffectInfo.EF_RANDOM_EFFECTS)
+ libffi_struct_getfield = calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_STRUCT_GETFIELD)
+ libffi_struct_setfield = calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_STRUCT_SETFIELD)
namespace = namespace.__dict__
@@ -277,3 +286,30 @@
jump(i3, f1, p2)
"""
loop = self.optimize_loop(ops, expected)
+
+ def test_ffi_struct_fields(self):
+ ops = """
+ [i0]
+ i1 = call(0, ConstClass(ffi_slong), i0, 123, descr=libffi_struct_getfield)
+ i2 = int_add(i1, 1)
+ call(0, ConstClass(ffi_slong), i0, 123, i2, descr=libffi_struct_setfield)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ i1 = getfield_raw(i0, descr=dyn_123_field)
+ i2 = int_add(i1, 1)
+ setfield_raw(i0, i2, descr=dyn_123_field)
+ jump(i1)
+ """
+ loop = self.optimize_loop(ops, expected)
+
+ def test_ffi_struct_fields_nonconst(self):
+ ops = """
+ [i0, i1]
+ i2 = call(0, ConstClass(ffi_slong), i0, i1, descr=libffi_struct_getfield)
+ i3 = call(0, i1 , i0, 123, descr=libffi_struct_getfield)
+ jump(i1)
+ """
+ expected = ops
+ loop = self.optimize_loop(ops, expected)
diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py
--- a/pypy/jit/metainterp/test/test_fficall.py
+++ b/pypy/jit/metainterp/test/test_fficall.py
@@ -4,7 +4,7 @@
from pypy.jit.metainterp.test.support import LLJitMixin
from pypy.rlib.jit import JitDriver, promote, dont_look_inside
from pypy.rlib.libffi import (ArgChain, IS_32_BIT, array_getitem, array_setitem,
- types)
+ types, struct_setfield_int, struct_getfield_int)
from pypy.rlib.objectmodel import specialize
from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong
from pypy.rlib.test.test_libffi import TestLibffiCall as _TestLibffiCall
@@ -187,5 +187,24 @@
class TestFfiCallSupportAll(FfiCallTests, LLJitMixin):
supports_all = True # supports_{floats,longlong,singlefloats}
+ def test_struct_getfield(self):
+ myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'addr'])
+
+ def f(n):
+ i = 0
+ addr = lltype.malloc(rffi.VOIDP.TO, 10, flavor='raw')
+ while i < n:
+ myjitdriver.jit_merge_point(n=n, i=i, addr=addr)
+ struct_setfield_int(types.slong, addr, 0, 1)
+ i += struct_getfield_int(types.slong, addr, 0)
+ lltype.free(addr, flavor='raw')
+ return i
+ assert self.meta_interp(f, [20]) == f(20)
+ self.check_resops(
+ setfield_raw=2,
+ getfield_raw=2,
+ call=0)
+
+
class TestFfiLookup(FfiLookupTests, LLJitMixin):
pass
diff --git a/pypy/module/__builtin__/test/test_functional.py b/pypy/module/__builtin__/test/test_functional.py
--- a/pypy/module/__builtin__/test/test_functional.py
+++ b/pypy/module/__builtin__/test/test_functional.py
@@ -146,6 +146,25 @@
y = callable(*args)
assert list(y) == list(x)
+ def test_xrange_iter_reduce(self):
+ x = iter(xrange(2, 9, 3))
+ x.next()
+ callable, args = x.__reduce__()
+ y = callable(*args)
+ assert list(y) == list(x)
+
+ def test_xrange_iter_reduce_one(self):
+ x = iter(xrange(2, 9))
+ x.next()
+ callable, args = x.__reduce__()
+ y = callable(*args)
+ assert list(y) == list(x)
+
+ def test_lib_python_xrange_optimization(self):
+ x = xrange(1)
+ assert type(reversed(x)) == type(iter(x))
+
+
class AppTestReversed:
def test_reversed(self):
r = reversed("hello")
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -3,7 +3,6 @@
from pypy.interpreter.mixedmodule import MixedModule
from pypy.module.imp.importing import get_pyc_magic
-
class BuildersModule(MixedModule):
appleveldefs = {}
@@ -43,6 +42,7 @@
'lookup_special' : 'interp_magic.lookup_special',
'do_what_I_mean' : 'interp_magic.do_what_I_mean',
'list_strategy' : 'interp_magic.list_strategy',
+ 'validate_fd' : 'interp_magic.validate_fd',
}
submodules = {
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -1,9 +1,10 @@
from pypy.interpreter.baseobjspace import ObjSpace, W_Root
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import OperationError, wrap_oserror
from pypy.interpreter.gateway import unwrap_spec
from pypy.rlib.objectmodel import we_are_translated
from pypy.objspace.std.typeobject import MethodCache
from pypy.objspace.std.mapdict import IndexCache
+from pypy.rlib import rposix
def internal_repr(space, w_object):
return space.wrap('%r' % (w_object,))
@@ -77,3 +78,10 @@
else:
w_msg = space.wrap("Can only get the list strategy of a list")
raise OperationError(space.w_TypeError, w_msg)
+
+ at unwrap_spec(fd='c_int')
+def validate_fd(space, fd):
+ try:
+ rposix.validate_fd(fd)
+ except OSError, e:
+ raise wrap_oserror(space, e)
diff --git a/pypy/module/_ffi/__init__.py b/pypy/module/_ffi/__init__.py
--- a/pypy/module/_ffi/__init__.py
+++ b/pypy/module/_ffi/__init__.py
@@ -1,13 +1,16 @@
from pypy.interpreter.mixedmodule import MixedModule
-from pypy.module._ffi import interp_ffi
class Module(MixedModule):
interpleveldefs = {
- 'CDLL': 'interp_ffi.W_CDLL',
- 'types': 'interp_ffi.W_types',
- 'FuncPtr': 'interp_ffi.W_FuncPtr',
- 'get_libc':'interp_ffi.get_libc',
+ 'types': 'interp_ffitype.W_types',
+ 'CDLL': 'interp_funcptr.W_CDLL',
+ 'FuncPtr': 'interp_funcptr.W_FuncPtr',
+ 'get_libc':'interp_funcptr.get_libc',
+ '_StructDescr': 'interp_struct.W__StructDescr',
+ 'Field': 'interp_struct.W_Field',
}
- appleveldefs = {}
+ appleveldefs = {
+ 'Structure': 'app_struct.Structure',
+ }
diff --git a/pypy/module/_ffi/app_struct.py b/pypy/module/_ffi/app_struct.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/app_struct.py
@@ -0,0 +1,21 @@
+import _ffi
+
+class MetaStructure(type):
+
+ def __new__(cls, name, bases, dic):
+ cls._compute_shape(name, dic)
+ return type.__new__(cls, name, bases, dic)
+
+ @classmethod
+ def _compute_shape(cls, name, dic):
+ fields = dic.get('_fields_')
+ if fields is None:
+ return
+ struct_descr = _ffi._StructDescr(name, fields)
+ for field in fields:
+ dic[field.name] = field
+ dic['_struct_'] = struct_descr
+
+
+class Structure(object):
+ __metaclass__ = MetaStructure
diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py
deleted file mode 100644
--- a/pypy/module/_ffi/interp_ffi.py
+++ /dev/null
@@ -1,514 +0,0 @@
-from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.error import OperationError, wrap_oserror, \
- operationerrfmt
-from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.typedef import TypeDef
-from pypy.module._rawffi.structure import W_StructureInstance, W_Structure
-#
-from pypy.rpython.lltypesystem import lltype, rffi
-#
-from pypy.rlib import jit
-from pypy.rlib import libffi
-from pypy.rlib.rdynload import DLOpenError
-from pypy.rlib.rarithmetic import intmask, r_uint
-from pypy.rlib.objectmodel import we_are_translated
-
-class W_FFIType(Wrappable):
-
- _immutable_fields_ = ['name', 'ffitype', 'w_datashape', 'w_pointer_to']
-
- def __init__(self, name, ffitype, w_datashape=None, w_pointer_to=None):
- self.name = name
- self.ffitype = ffitype
- self.w_datashape = w_datashape
- self.w_pointer_to = w_pointer_to
- if self.is_struct():
- assert w_datashape is not None
-
- def descr_deref_pointer(self, space):
- if self.w_pointer_to is None:
- return space.w_None
- return self.w_pointer_to
-
- def repr(self, space):
- return space.wrap(self.__repr__())
-
- def __repr__(self):
- return "<ffi type %s>" % self.name
-
- def is_signed(self):
- return (self is app_types.slong or
- self is app_types.sint or
- self is app_types.sshort or
- self is app_types.sbyte or
- self is app_types.slonglong)
-
- def is_unsigned(self):
- return (self is app_types.ulong or
- self is app_types.uint or
- self is app_types.ushort or
- self is app_types.ubyte or
- self is app_types.ulonglong)
-
- def is_pointer(self):
- return self.ffitype is libffi.types.pointer
-
- def is_char(self):
- return self is app_types.char
-
- def is_unichar(self):
- return self is app_types.unichar
-
- def is_longlong(self):
- return libffi.IS_32_BIT and (self is app_types.slonglong or
- self is app_types.ulonglong)
-
- def is_double(self):
- return self is app_types.double
-
- def is_singlefloat(self):
- return self is app_types.float
-
- def is_void(self):
- return self is app_types.void
-
- def is_struct(self):
- return libffi.types.is_struct(self.ffitype)
-
- def is_char_p(self):
- return self is app_types.char_p
-
- def is_unichar_p(self):
- return self is app_types.unichar_p
-
-
-W_FFIType.typedef = TypeDef(
- 'FFIType',
- __repr__ = interp2app(W_FFIType.repr),
- deref_pointer = interp2app(W_FFIType.descr_deref_pointer),
- )
-
-
-def build_ffi_types():
- types = [
- # note: most of the type name directly come from the C equivalent,
- # with the exception of bytes: in C, ubyte and char are equivalent,
- # but for _ffi the first expects a number while the second a 1-length
- # string
- W_FFIType('slong', libffi.types.slong),
- W_FFIType('sint', libffi.types.sint),
- W_FFIType('sshort', libffi.types.sshort),
- W_FFIType('sbyte', libffi.types.schar),
- W_FFIType('slonglong', libffi.types.slonglong),
- #
- W_FFIType('ulong', libffi.types.ulong),
- W_FFIType('uint', libffi.types.uint),
- W_FFIType('ushort', libffi.types.ushort),
- W_FFIType('ubyte', libffi.types.uchar),
- W_FFIType('ulonglong', libffi.types.ulonglong),
- #
- W_FFIType('char', libffi.types.uchar),
- W_FFIType('unichar', libffi.types.wchar_t),
- #
- W_FFIType('double', libffi.types.double),
- W_FFIType('float', libffi.types.float),
- W_FFIType('void', libffi.types.void),
- W_FFIType('void_p', libffi.types.pointer),
- #
- # missing types:
-
- ## 's' : ffi_type_pointer,
- ## 'z' : ffi_type_pointer,
- ## 'O' : ffi_type_pointer,
- ## 'Z' : ffi_type_pointer,
-
- ]
- d = dict([(t.name, t) for t in types])
- w_char = d['char']
- w_unichar = d['unichar']
- d['char_p'] = W_FFIType('char_p', libffi.types.pointer, w_pointer_to = w_char)
- d['unichar_p'] = W_FFIType('unichar_p', libffi.types.pointer, w_pointer_to = w_unichar)
- return d
-
-class app_types:
- pass
-app_types.__dict__ = build_ffi_types()
-
-def descr_new_pointer(space, w_cls, w_pointer_to):
- try:
- return descr_new_pointer.cache[w_pointer_to]
- except KeyError:
- if w_pointer_to is app_types.char:
- w_result = app_types.char_p
- elif w_pointer_to is app_types.unichar:
- w_result = app_types.unichar_p
- else:
- w_pointer_to = space.interp_w(W_FFIType, w_pointer_to)
- name = '(pointer to %s)' % w_pointer_to.name
- w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to)
- descr_new_pointer.cache[w_pointer_to] = w_result
- return w_result
-descr_new_pointer.cache = {}
-
-class W_types(Wrappable):
- pass
-W_types.typedef = TypeDef(
- 'types',
- Pointer = interp2app(descr_new_pointer, as_classmethod=True),
- **app_types.__dict__)
-
-
-def unwrap_ffitype(space, w_argtype, allow_void=False):
- res = w_argtype.ffitype
- if res is libffi.types.void and not allow_void:
- msg = 'void is not a valid argument type'
- raise OperationError(space.w_TypeError, space.wrap(msg))
- return res
-
-def unwrap_truncate_int(TP, space, w_arg):
- if space.is_true(space.isinstance(w_arg, space.w_int)):
- return rffi.cast(TP, space.int_w(w_arg))
- else:
- return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask())
-unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)'
-
-# ========================================================================
-
-class W_FuncPtr(Wrappable):
-
- _immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype']
-
- def __init__(self, func, argtypes_w, w_restype):
- self.func = func
- self.argtypes_w = argtypes_w
- self.w_restype = w_restype
- self.to_free = []
-
- @jit.unroll_safe
- def build_argchain(self, space, args_w):
- expected = len(self.argtypes_w)
- given = len(args_w)
- if given != expected:
- arg = 'arguments'
- if len(self.argtypes_w) == 1:
- arg = 'argument'
- raise operationerrfmt(space.w_TypeError,
- '%s() takes exactly %d %s (%d given)',
- self.func.name, expected, arg, given)
- #
- argchain = libffi.ArgChain()
- for i in range(expected):
- w_argtype = self.argtypes_w[i]
- w_arg = args_w[i]
- if w_argtype.is_longlong():
- # note that we must check for longlong first, because either
- # is_signed or is_unsigned returns true anyway
- assert libffi.IS_32_BIT
- self.arg_longlong(space, argchain, w_arg)
- elif w_argtype.is_signed():
- argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg))
- elif self.add_char_p_maybe(space, argchain, w_arg, w_argtype):
- # the argument is added to the argchain direcly by the method above
- pass
- elif w_argtype.is_pointer():
- w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype)
- argchain.arg(intmask(space.uint_w(w_arg)))
- elif w_argtype.is_unsigned():
- argchain.arg(unwrap_truncate_int(rffi.ULONG, space, w_arg))
- elif w_argtype.is_char():
- w_arg = space.ord(w_arg)
- argchain.arg(space.int_w(w_arg))
- elif w_argtype.is_unichar():
- w_arg = space.ord(w_arg)
- argchain.arg(space.int_w(w_arg))
- elif w_argtype.is_double():
- self.arg_float(space, argchain, w_arg)
- elif w_argtype.is_singlefloat():
- self.arg_singlefloat(space, argchain, w_arg)
- elif w_argtype.is_struct():
- # arg_raw directly takes value to put inside ll_args
- w_arg = space.interp_w(W_StructureInstance, w_arg)
- ptrval = w_arg.ll_buffer
- argchain.arg_raw(ptrval)
- else:
- assert False, "Argument shape '%s' not supported" % w_argtype
- return argchain
-
- def add_char_p_maybe(self, space, argchain, w_arg, w_argtype):
- """
- Automatic conversion from string to char_p. The allocated buffer will
- be automatically freed after the call.
- """
- w_type = jit.promote(space.type(w_arg))
- if w_argtype.is_char_p() and w_type is space.w_str:
- strval = space.str_w(w_arg)
- buf = rffi.str2charp(strval)
- self.to_free.append(rffi.cast(rffi.VOIDP, buf))
- addr = rffi.cast(rffi.ULONG, buf)
- argchain.arg(addr)
- return True
- elif w_argtype.is_unichar_p() and (w_type is space.w_str or
- w_type is space.w_unicode):
- unicodeval = space.unicode_w(w_arg)
- buf = rffi.unicode2wcharp(unicodeval)
- self.to_free.append(rffi.cast(rffi.VOIDP, buf))
- addr = rffi.cast(rffi.ULONG, buf)
- argchain.arg(addr)
- return True
- return False
-
- def convert_pointer_arg_maybe(self, space, w_arg, w_argtype):
- """
- Try to convert the argument by calling _as_ffi_pointer_()
- """
- meth = space.lookup(w_arg, '_as_ffi_pointer_') # this also promotes the type
- if meth:
- return space.call_function(meth, w_arg, w_argtype)
- else:
- return w_arg
-
- def arg_float(self, space, argchain, w_arg):
- # a separate function, which can be seen by the jit or not,
- # depending on whether floats are supported
- argchain.arg(space.float_w(w_arg))
-
- def arg_longlong(self, space, argchain, w_arg):
- # a separate function, which can be seen by the jit or not,
- # depending on whether longlongs are supported
- bigarg = space.bigint_w(w_arg)
- ullval = bigarg.ulonglongmask()
- llval = rffi.cast(rffi.LONGLONG, ullval)
- argchain.arg(llval)
-
- def arg_singlefloat(self, space, argchain, w_arg):
- # a separate function, which can be seen by the jit or not,
- # depending on whether singlefloats are supported
- from pypy.rlib.rarithmetic import r_singlefloat
- fval = space.float_w(w_arg)
- sfval = r_singlefloat(fval)
- argchain.arg(sfval)
-
- def call(self, space, args_w):
- self = jit.promote(self)
- argchain = self.build_argchain(space, args_w)
- return self._do_call(space, argchain)
-
- def free_temp_buffers(self, space):
- for buf in self.to_free:
- if not we_are_translated():
- buf[0] = '\00' # invalidate the buffer, so that
- # test_keepalive_temp_buffer can fail
- lltype.free(buf, flavor='raw')
- self.to_free = []
-
- def _do_call(self, space, argchain):
- w_restype = self.w_restype
- if w_restype.is_longlong():
- # note that we must check for longlong first, because either
- # is_signed or is_unsigned returns true anyway
- assert libffi.IS_32_BIT
- return self._call_longlong(space, argchain)
- elif w_restype.is_signed():
- return self._call_int(space, argchain)
- elif w_restype.is_unsigned() or w_restype.is_pointer():
- return self._call_uint(space, argchain)
- elif w_restype.is_char():
- intres = self.func.call(argchain, rffi.UCHAR)
- return space.wrap(chr(intres))
- elif w_restype.is_unichar():
- intres = self.func.call(argchain, rffi.WCHAR_T)
- return space.wrap(unichr(intres))
- elif w_restype.is_double():
- return self._call_float(space, argchain)
- elif w_restype.is_singlefloat():
- return self._call_singlefloat(space, argchain)
- elif w_restype.is_struct():
- w_datashape = w_restype.w_datashape
- assert isinstance(w_datashape, W_Structure)
- ptrval = self.func.call(argchain, rffi.ULONG, is_struct=True)
- return w_datashape.fromaddress(space, ptrval)
- elif w_restype.is_void():
- voidres = self.func.call(argchain, lltype.Void)
- assert voidres is None
- return space.w_None
- else:
- assert False, "Return value shape '%s' not supported" % w_restype
-
- def _call_int(self, space, argchain):
- # if the declared return type of the function is smaller than LONG,
- # the result buffer may contains garbage in its higher bits. To get
- # the correct value, and to be sure to handle the signed/unsigned case
- # correctly, we need to cast the result to the correct type. After
- # that, we cast it back to LONG, because this is what we want to pass
- # to space.wrap in order to get a nice applevel <int>.
- #
- restype = self.func.restype
- call = self.func.call
- if restype is libffi.types.slong:
- intres = call(argchain, rffi.LONG)
- elif restype is libffi.types.sint:
- intres = rffi.cast(rffi.LONG, call(argchain, rffi.INT))
- elif restype is libffi.types.sshort:
- intres = rffi.cast(rffi.LONG, call(argchain, rffi.SHORT))
- elif restype is libffi.types.schar:
- intres = rffi.cast(rffi.LONG, call(argchain, rffi.SIGNEDCHAR))
- else:
- raise OperationError(space.w_ValueError,
- space.wrap('Unsupported restype'))
- return space.wrap(intres)
-
- def _call_uint(self, space, argchain):
- # the same comment as above apply. Moreover, we need to be careful
- # when the return type is ULONG, because the value might not fit into
- # a signed LONG: this is the only case in which we cast the result to
- # something different than LONG; as a result, the applevel value will
- # be a <long>.
- #
- # Note that we check for ULONG before UINT: this is needed on 32bit
- # machines, where they are they same: if we checked for UINT before
- # ULONG, we would cast to the wrong type. Note that this also means
- # that on 32bit the UINT case will never be entered (because it is
- # handled by the ULONG case).
- restype = self.func.restype
- call = self.func.call
- if restype is libffi.types.ulong:
- # special case
- uintres = call(argchain, rffi.ULONG)
- return space.wrap(uintres)
- elif restype is libffi.types.pointer:
- ptrres = call(argchain, rffi.VOIDP)
- uintres = rffi.cast(rffi.ULONG, ptrres)
- return space.wrap(uintres)
- elif restype is libffi.types.uint:
- intres = rffi.cast(rffi.LONG, call(argchain, rffi.UINT))
- elif restype is libffi.types.ushort:
- intres = rffi.cast(rffi.LONG, call(argchain, rffi.USHORT))
- elif restype is libffi.types.uchar:
- intres = rffi.cast(rffi.LONG, call(argchain, rffi.UCHAR))
- else:
- raise OperationError(space.w_ValueError,
- space.wrap('Unsupported restype'))
- return space.wrap(intres)
-
- def _call_float(self, space, argchain):
- # a separate function, which can be seen by the jit or not,
- # depending on whether floats are supported
- floatres = self.func.call(argchain, rffi.DOUBLE)
- return space.wrap(floatres)
-
- def _call_longlong(self, space, argchain):
- # a separate function, which can be seen by the jit or not,
- # depending on whether longlongs are supported
- restype = self.func.restype
- call = self.func.call
- if restype is libffi.types.slonglong:
- llres = call(argchain, rffi.LONGLONG)
- return space.wrap(llres)
- elif restype is libffi.types.ulonglong:
- ullres = call(argchain, rffi.ULONGLONG)
- return space.wrap(ullres)
- else:
- raise OperationError(space.w_ValueError,
- space.wrap('Unsupported longlong restype'))
-
- def _call_singlefloat(self, space, argchain):
- # a separate function, which can be seen by the jit or not,
- # depending on whether singlefloats are supported
- sfres = self.func.call(argchain, rffi.FLOAT)
- return space.wrap(float(sfres))
-
- def getaddr(self, space):
- """
- Return the physical address in memory of the function
- """
- return space.wrap(rffi.cast(rffi.LONG, self.func.funcsym))
-
-
-
-def unpack_argtypes(space, w_argtypes, w_restype):
- argtypes_w = [space.interp_w(W_FFIType, w_argtype)
- for w_argtype in space.listview(w_argtypes)]
- argtypes = [unwrap_ffitype(space, w_argtype) for w_argtype in
- argtypes_w]
- w_restype = space.interp_w(W_FFIType, w_restype)
- restype = unwrap_ffitype(space, w_restype, allow_void=True)
- return argtypes_w, argtypes, w_restype, restype
-
- at unwrap_spec(addr=r_uint, name=str)
-def descr_fromaddr(space, w_cls, addr, name, w_argtypes, w_restype):
- argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space,
- w_argtypes,
- w_restype)
- addr = rffi.cast(rffi.VOIDP, addr)
- func = libffi.Func(name, argtypes, restype, addr)
- return W_FuncPtr(func, argtypes_w, w_restype)
-
-
-W_FuncPtr.typedef = TypeDef(
- '_ffi.FuncPtr',
- __call__ = interp2app(W_FuncPtr.call),
- getaddr = interp2app(W_FuncPtr.getaddr),
- free_temp_buffers = interp2app(W_FuncPtr.free_temp_buffers),
- fromaddr = interp2app(descr_fromaddr, as_classmethod=True)
- )
-
-
-
-# ========================================================================
-
-class W_CDLL(Wrappable):
- def __init__(self, space, name, mode):
- self.space = space
- if name is None:
- self.name = "<None>"
- else:
- self.name = name
- try:
- self.cdll = libffi.CDLL(name, mode)
- except DLOpenError, e:
- raise operationerrfmt(space.w_OSError, '%s: %s', self.name,
- e.msg or 'unspecified error')
-
- @unwrap_spec(name=str)
- def getfunc(self, space, name, w_argtypes, w_restype):
- argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space,
- w_argtypes,
- w_restype)
- try:
- func = self.cdll.getpointer(name, argtypes, restype)
- except KeyError:
- raise operationerrfmt(space.w_AttributeError,
- "No symbol %s found in library %s", name, self.name)
-
- return W_FuncPtr(func, argtypes_w, w_restype)
-
- @unwrap_spec(name=str)
- def getaddressindll(self, space, name):
- try:
- address_as_uint = rffi.cast(lltype.Unsigned,
- self.cdll.getaddressindll(name))
- except KeyError:
- raise operationerrfmt(space.w_ValueError,
- "No symbol %s found in library %s", name, self.name)
- return space.wrap(address_as_uint)
-
- at unwrap_spec(name='str_or_None', mode=int)
-def descr_new_cdll(space, w_type, name, mode=-1):
- return space.wrap(W_CDLL(space, name, mode))
-
-
-W_CDLL.typedef = TypeDef(
- '_ffi.CDLL',
- __new__ = interp2app(descr_new_cdll),
- getfunc = interp2app(W_CDLL.getfunc),
- getaddressindll = interp2app(W_CDLL.getaddressindll),
- )
-
-# ========================================================================
-
-def get_libc(space):
- from pypy.rlib.clibffi import get_libc_name
- try:
- return space.wrap(W_CDLL(space, get_libc_name(), -1))
- except OSError, e:
- raise wrap_oserror(space, e)
diff --git a/pypy/module/_ffi/interp_ffitype.py b/pypy/module/_ffi/interp_ffitype.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/interp_ffitype.py
@@ -0,0 +1,181 @@
+from pypy.rlib import libffi, clibffi
+from pypy.rlib.rarithmetic import intmask
+from pypy.rlib import jit
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.typedef import TypeDef, interp_attrproperty
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.error import OperationError
+
+class W_FFIType(Wrappable):
+
+ _immutable_fields_ = ['name', 'w_structdescr', 'w_pointer_to']
+
+ def __init__(self, name, ffitype, w_structdescr=None, w_pointer_to=None):
+ self.name = name
+ self._ffitype = clibffi.FFI_TYPE_NULL
+ self.w_structdescr = w_structdescr
+ self.w_pointer_to = w_pointer_to
+ self.set_ffitype(ffitype)
+
+ @jit.elidable
+ def get_ffitype(self):
+ if not self._ffitype:
+ raise ValueError("Operation not permitted on an incomplete type")
+ return self._ffitype
+
+ def set_ffitype(self, ffitype):
+ if self._ffitype:
+ raise ValueError("The _ffitype is already set")
+ self._ffitype = ffitype
+ if ffitype and self.is_struct():
+ assert self.w_structdescr is not None
+
+ def descr_deref_pointer(self, space):
+ if self.w_pointer_to is None:
+ return space.w_None
+ return self.w_pointer_to
+
+ def descr_sizeof(self, space):
+ try:
+ return space.wrap(self.sizeof())
+ except ValueError:
+ msg = "Operation not permitted on an incomplete type"
+ raise OperationError(space.w_ValueError, space.wrap(msg))
+
+ def sizeof(self):
+ return intmask(self.get_ffitype().c_size)
+
+ def get_alignment(self):
+ return intmask(self.get_ffitype().c_alignment)
+
+ def repr(self, space):
+ return space.wrap(self.__repr__())
+
+ def __repr__(self):
+ name = self.name
+ if not self._ffitype:
+ name += ' (incomplete)'
+ return "<ffi type %s>" % name
+
+ def is_signed(self):
+ return (self is app_types.slong or
+ self is app_types.sint or
+ self is app_types.sshort or
+ self is app_types.sbyte or
+ self is app_types.slonglong)
+
+ def is_unsigned(self):
+ return (self is app_types.ulong or
+ self is app_types.uint or
+ self is app_types.ushort or
+ self is app_types.ubyte or
+ self is app_types.ulonglong)
+
+ def is_pointer(self):
+ return self.get_ffitype() is libffi.types.pointer
+
+ def is_char(self):
+ return self is app_types.char
+
+ def is_unichar(self):
+ return self is app_types.unichar
+
+ def is_longlong(self):
+ return libffi.IS_32_BIT and (self is app_types.slonglong or
+ self is app_types.ulonglong)
+
+ def is_double(self):
+ return self is app_types.double
+
+ def is_singlefloat(self):
+ return self is app_types.float
+
+ def is_void(self):
+ return self is app_types.void
+
+ def is_struct(self):
+ return libffi.types.is_struct(self.get_ffitype())
+
+ def is_char_p(self):
+ return self is app_types.char_p
+
+ def is_unichar_p(self):
+ return self is app_types.unichar_p
+
+
+W_FFIType.typedef = TypeDef(
+ 'FFIType',
+ name = interp_attrproperty('name', W_FFIType),
+ __repr__ = interp2app(W_FFIType.repr),
+ deref_pointer = interp2app(W_FFIType.descr_deref_pointer),
+ sizeof = interp2app(W_FFIType.descr_sizeof),
+ )
+
+
+def build_ffi_types():
+ types = [
+ # note: most of the type name directly come from the C equivalent,
+ # with the exception of bytes: in C, ubyte and char are equivalent,
+ # but for _ffi the first expects a number while the second a 1-length
+ # string
+ W_FFIType('slong', libffi.types.slong),
+ W_FFIType('sint', libffi.types.sint),
+ W_FFIType('sshort', libffi.types.sshort),
+ W_FFIType('sbyte', libffi.types.schar),
+ W_FFIType('slonglong', libffi.types.slonglong),
+ #
+ W_FFIType('ulong', libffi.types.ulong),
+ W_FFIType('uint', libffi.types.uint),
+ W_FFIType('ushort', libffi.types.ushort),
+ W_FFIType('ubyte', libffi.types.uchar),
+ W_FFIType('ulonglong', libffi.types.ulonglong),
+ #
+ W_FFIType('char', libffi.types.uchar),
+ W_FFIType('unichar', libffi.types.wchar_t),
+ #
+ W_FFIType('double', libffi.types.double),
+ W_FFIType('float', libffi.types.float),
+ W_FFIType('void', libffi.types.void),
+ W_FFIType('void_p', libffi.types.pointer),
+ #
+ # missing types:
+
+ ## 's' : ffi_type_pointer,
+ ## 'z' : ffi_type_pointer,
+ ## 'O' : ffi_type_pointer,
+ ## 'Z' : ffi_type_pointer,
+
+ ]
+ d = dict([(t.name, t) for t in types])
+ w_char = d['char']
+ w_unichar = d['unichar']
+ d['char_p'] = W_FFIType('char_p', libffi.types.pointer, w_pointer_to = w_char)
+ d['unichar_p'] = W_FFIType('unichar_p', libffi.types.pointer, w_pointer_to = w_unichar)
+ return d
+
+class app_types:
+ pass
+app_types.__dict__ = build_ffi_types()
+
+def descr_new_pointer(space, w_cls, w_pointer_to):
+ try:
+ return descr_new_pointer.cache[w_pointer_to]
+ except KeyError:
+ if w_pointer_to is app_types.char:
+ w_result = app_types.char_p
+ elif w_pointer_to is app_types.unichar:
+ w_result = app_types.unichar_p
+ else:
+ w_pointer_to = space.interp_w(W_FFIType, w_pointer_to)
+ name = '(pointer to %s)' % w_pointer_to.name
+ w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to)
+ descr_new_pointer.cache[w_pointer_to] = w_result
+ return w_result
+descr_new_pointer.cache = {}
+
+class W_types(Wrappable):
+ pass
+W_types.typedef = TypeDef(
+ 'types',
+ Pointer = interp2app(descr_new_pointer, as_classmethod=True),
+ **app_types.__dict__)
diff --git a/pypy/module/_ffi/interp_funcptr.py b/pypy/module/_ffi/interp_funcptr.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/interp_funcptr.py
@@ -0,0 +1,311 @@
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.error import OperationError, wrap_oserror, \
+ operationerrfmt
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef
+from pypy.module._ffi.interp_ffitype import W_FFIType
+#
+from pypy.rpython.lltypesystem import lltype, rffi
+#
+from pypy.rlib import jit
+from pypy.rlib import libffi
+from pypy.rlib.rdynload import DLOpenError
+from pypy.rlib.rarithmetic import intmask, r_uint
+from pypy.rlib.objectmodel import we_are_translated
+from pypy.module._ffi.type_converter import FromAppLevelConverter, ToAppLevelConverter
+
+
+def unwrap_ffitype(space, w_argtype, allow_void=False):
+ res = w_argtype.get_ffitype()
+ if res is libffi.types.void and not allow_void:
+ msg = 'void is not a valid argument type'
+ raise OperationError(space.w_TypeError, space.wrap(msg))
+ return res
+
+
+# ========================================================================
+
+class W_FuncPtr(Wrappable):
+
+ _immutable_fields_ = ['func', 'argtypes_w[*]', 'w_restype']
+
+ def __init__(self, func, argtypes_w, w_restype):
+ self.func = func
+ self.argtypes_w = argtypes_w
+ self.w_restype = w_restype
+ self.to_free = []
+
+ @jit.unroll_safe
+ def build_argchain(self, space, args_w):
+ expected = len(self.argtypes_w)
+ given = len(args_w)
+ if given != expected:
+ arg = 'arguments'
+ if len(self.argtypes_w) == 1:
+ arg = 'argument'
+ raise operationerrfmt(space.w_TypeError,
+ '%s() takes exactly %d %s (%d given)',
+ self.func.name, expected, arg, given)
+ #
+ argchain = libffi.ArgChain()
+ argpusher = PushArgumentConverter(space, argchain, self)
+ for i in range(expected):
+ w_argtype = self.argtypes_w[i]
+ w_arg = args_w[i]
+ argpusher.unwrap_and_do(w_argtype, w_arg)
+ return argchain
+
+ def call(self, space, args_w):
+ self = jit.promote(self)
+ argchain = self.build_argchain(space, args_w)
+ func_caller = CallFunctionConverter(space, self.func, argchain)
+ return func_caller.do_and_wrap(self.w_restype)
+ #return self._do_call(space, argchain)
+
+ def free_temp_buffers(self, space):
+ for buf in self.to_free:
+ if not we_are_translated():
+ buf[0] = '\00' # invalidate the buffer, so that
+ # test_keepalive_temp_buffer can fail
+ lltype.free(buf, flavor='raw')
+ self.to_free = []
+
+ def getaddr(self, space):
+ """
+ Return the physical address in memory of the function
+ """
+ return space.wrap(rffi.cast(rffi.LONG, self.func.funcsym))
+
+
+class PushArgumentConverter(FromAppLevelConverter):
+ """
+ A converter used by W_FuncPtr to unwrap the app-level objects into
+ low-level types and push them to the argchain.
+ """
+
+ def __init__(self, space, argchain, w_func):
+ FromAppLevelConverter.__init__(self, space)
+ self.argchain = argchain
+ self.w_func = w_func
+
+ def handle_signed(self, w_ffitype, w_obj, intval):
+ self.argchain.arg(intval)
+
+ def handle_unsigned(self, w_ffitype, w_obj, uintval):
+ self.argchain.arg(uintval)
+
+ def handle_pointer(self, w_ffitype, w_obj, intval):
+ self.argchain.arg(intval)
+
+ def handle_char(self, w_ffitype, w_obj, intval):
+ self.argchain.arg(intval)
+
+ def handle_unichar(self, w_ffitype, w_obj, intval):
+ self.argchain.arg(intval)
+
+ def handle_longlong(self, w_ffitype, w_obj, longlongval):
+ self.argchain.arg(longlongval)
+
+ def handle_char_p(self, w_ffitype, w_obj, strval):
+ buf = rffi.str2charp(strval)
+ self.w_func.to_free.append(rffi.cast(rffi.VOIDP, buf))
+ addr = rffi.cast(rffi.ULONG, buf)
+ self.argchain.arg(addr)
+
+ def handle_unichar_p(self, w_ffitype, w_obj, unicodeval):
+ buf = rffi.unicode2wcharp(unicodeval)
+ self.w_func.to_free.append(rffi.cast(rffi.VOIDP, buf))
+ addr = rffi.cast(rffi.ULONG, buf)
+ self.argchain.arg(addr)
+
+ def handle_float(self, w_ffitype, w_obj, floatval):
+ self.argchain.arg(floatval)
+
+ def handle_singlefloat(self, w_ffitype, w_obj, singlefloatval):
+ self.argchain.arg(singlefloatval)
+
+ def handle_struct(self, w_ffitype, w_structinstance):
+ # arg_raw directly takes value to put inside ll_args
+ ptrval = w_structinstance.rawmem
+ self.argchain.arg_raw(ptrval)
+
+ def handle_struct_rawffi(self, w_ffitype, w_structinstance):
+ # arg_raw directly takes value to put inside ll_args
+ ptrval = w_structinstance.ll_buffer
+ self.argchain.arg_raw(ptrval)
+
+
+class CallFunctionConverter(ToAppLevelConverter):
+ """
+ A converter used by W_FuncPtr to call the function, expect the result of
+ a correct low-level type and wrap it to the corresponding app-level type
+ """
+
+ def __init__(self, space, func, argchain):
+ ToAppLevelConverter.__init__(self, space)
+ self.func = func
+ self.argchain = argchain
+
+ def get_longlong(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.LONGLONG)
+
+ def get_ulonglong(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.ULONGLONG)
+
+ def get_signed(self, w_ffitype):
+ # if the declared return type of the function is smaller than LONG,
+ # the result buffer may contains garbage in its higher bits. To get
+ # the correct value, and to be sure to handle the signed/unsigned case
+ # correctly, we need to cast the result to the correct type. After
+ # that, we cast it back to LONG, because this is what we want to pass
+ # to space.wrap in order to get a nice applevel <int>.
+ #
+ restype = w_ffitype.get_ffitype()
+ call = self.func.call
+ if restype is libffi.types.slong:
+ return call(self.argchain, rffi.LONG)
+ elif restype is libffi.types.sint:
+ return rffi.cast(rffi.LONG, call(self.argchain, rffi.INT))
+ elif restype is libffi.types.sshort:
+ return rffi.cast(rffi.LONG, call(self.argchain, rffi.SHORT))
+ elif restype is libffi.types.schar:
+ return rffi.cast(rffi.LONG, call(self.argchain, rffi.SIGNEDCHAR))
+ else:
+ self.error(w_ffitype)
+
+ def get_unsigned(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.ULONG)
+
+ def get_unsigned_which_fits_into_a_signed(self, w_ffitype):
+ # the same comment as get_signed apply
+ restype = w_ffitype.get_ffitype()
+ call = self.func.call
+ if restype is libffi.types.uint:
+ assert not libffi.IS_32_BIT
+ # on 32bit machines, we should never get here, because it's a case
+ # which has already been handled by get_unsigned above.
+ return rffi.cast(rffi.LONG, call(self.argchain, rffi.UINT))
+ elif restype is libffi.types.ushort:
+ return rffi.cast(rffi.LONG, call(self.argchain, rffi.USHORT))
+ elif restype is libffi.types.uchar:
+ return rffi.cast(rffi.LONG, call(self.argchain, rffi.UCHAR))
+ else:
+ self.error(w_ffitype)
+
+
+ def get_pointer(self, w_ffitype):
+ ptrres = self.func.call(self.argchain, rffi.VOIDP)
+ return rffi.cast(rffi.ULONG, ptrres)
+
+ def get_char(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.UCHAR)
+
+ def get_unichar(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.WCHAR_T)
+
+ def get_float(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.DOUBLE)
+
+ def get_singlefloat(self, w_ffitype):
+ return self.func.call(self.argchain, rffi.FLOAT)
+
+ def get_struct(self, w_ffitype, w_structdescr):
+ addr = self.func.call(self.argchain, rffi.LONG, is_struct=True)
+ return w_structdescr.fromaddress(self.space, addr)
+
+ def get_struct_rawffi(self, w_ffitype, w_structdescr):
+ uintval = self.func.call(self.argchain, rffi.ULONG, is_struct=True)
+ return w_structdescr.fromaddress(self.space, uintval)
+
+ def get_void(self, w_ffitype):
+ return self.func.call(self.argchain, lltype.Void)
+
+
+def unpack_argtypes(space, w_argtypes, w_restype):
+ argtypes_w = [space.interp_w(W_FFIType, w_argtype)
+ for w_argtype in space.listview(w_argtypes)]
+ argtypes = [unwrap_ffitype(space, w_argtype) for w_argtype in
+ argtypes_w]
+ w_restype = space.interp_w(W_FFIType, w_restype)
+ restype = unwrap_ffitype(space, w_restype, allow_void=True)
+ return argtypes_w, argtypes, w_restype, restype
+
+ at unwrap_spec(addr=r_uint, name=str)
+def descr_fromaddr(space, w_cls, addr, name, w_argtypes, w_restype):
+ argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space,
+ w_argtypes,
+ w_restype)
+ addr = rffi.cast(rffi.VOIDP, addr)
+ func = libffi.Func(name, argtypes, restype, addr)
+ return W_FuncPtr(func, argtypes_w, w_restype)
+
+
+W_FuncPtr.typedef = TypeDef(
+ '_ffi.FuncPtr',
+ __call__ = interp2app(W_FuncPtr.call),
+ getaddr = interp2app(W_FuncPtr.getaddr),
+ free_temp_buffers = interp2app(W_FuncPtr.free_temp_buffers),
+ fromaddr = interp2app(descr_fromaddr, as_classmethod=True)
+ )
+
+
+
+# ========================================================================
+
+class W_CDLL(Wrappable):
+ def __init__(self, space, name, mode):
+ self.space = space
+ if name is None:
+ self.name = "<None>"
+ else:
+ self.name = name
+ try:
+ self.cdll = libffi.CDLL(name, mode)
+ except DLOpenError, e:
+ raise operationerrfmt(space.w_OSError, '%s: %s', self.name,
+ e.msg or 'unspecified error')
+
+ @unwrap_spec(name=str)
+ def getfunc(self, space, name, w_argtypes, w_restype):
+ argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space,
+ w_argtypes,
+ w_restype)
+ try:
+ func = self.cdll.getpointer(name, argtypes, restype)
+ except KeyError:
+ raise operationerrfmt(space.w_AttributeError,
+ "No symbol %s found in library %s", name, self.name)
+
+ return W_FuncPtr(func, argtypes_w, w_restype)
+
+ @unwrap_spec(name=str)
+ def getaddressindll(self, space, name):
+ try:
+ address_as_uint = rffi.cast(lltype.Unsigned,
+ self.cdll.getaddressindll(name))
+ except KeyError:
+ raise operationerrfmt(space.w_ValueError,
+ "No symbol %s found in library %s", name, self.name)
+ return space.wrap(address_as_uint)
+
+ at unwrap_spec(name='str_or_None', mode=int)
+def descr_new_cdll(space, w_type, name, mode=-1):
+ return space.wrap(W_CDLL(space, name, mode))
+
+
+W_CDLL.typedef = TypeDef(
+ '_ffi.CDLL',
+ __new__ = interp2app(descr_new_cdll),
+ getfunc = interp2app(W_CDLL.getfunc),
+ getaddressindll = interp2app(W_CDLL.getaddressindll),
+ )
+
+# ========================================================================
+
+def get_libc(space):
+ from pypy.rlib.clibffi import get_libc_name
+ try:
+ return space.wrap(W_CDLL(space, get_libc_name(), -1))
+ except OSError, e:
+ raise wrap_oserror(space, e)
+
diff --git a/pypy/module/_ffi/interp_struct.py b/pypy/module/_ffi/interp_struct.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/interp_struct.py
@@ -0,0 +1,319 @@
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib import clibffi
+from pypy.rlib import libffi
+from pypy.rlib import jit
+from pypy.rlib.rgc import must_be_light_finalizer
+from pypy.rlib.rarithmetic import r_uint, r_ulonglong, r_singlefloat, intmask
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.typedef import TypeDef, interp_attrproperty
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.error import operationerrfmt
+from pypy.objspace.std.typetype import type_typedef
+from pypy.module._ffi.interp_ffitype import W_FFIType, app_types
+from pypy.module._ffi.type_converter import FromAppLevelConverter, ToAppLevelConverter
+
+
+class W_Field(Wrappable):
+
+ def __init__(self, name, w_ffitype):
+ self.name = name
+ self.w_ffitype = w_ffitype
+ self.offset = -1
+
+ def __repr__(self):
+ return '<Field %s %s>' % (self.name, self.w_ffitype.name)
+
+ at unwrap_spec(name=str)
+def descr_new_field(space, w_type, name, w_ffitype):
+ w_ffitype = space.interp_w(W_FFIType, w_ffitype)
+ return W_Field(name, w_ffitype)
+
+W_Field.typedef = TypeDef(
+ 'Field',
+ __new__ = interp2app(descr_new_field),
+ name = interp_attrproperty('name', W_Field),
+ ffitype = interp_attrproperty('w_ffitype', W_Field),
+ offset = interp_attrproperty('offset', W_Field),
+ )
+
+
+# ==============================================================================
+
+class FFIStructOwner(object):
+ """
+ The only job of this class is to stay outside of the reference cycle
+ W__StructDescr -> W_FFIType -> W__StructDescr and free the ffistruct
+ """
+
+ def __init__(self, ffistruct):
+ self.ffistruct = ffistruct
+
+ @must_be_light_finalizer
+ def __del__(self):
+ if self.ffistruct:
+ lltype.free(self.ffistruct, flavor='raw', track_allocation=True)
+
+
+class W__StructDescr(Wrappable):
+
+ def __init__(self, space, name):
+ self.space = space
+ self.w_ffitype = W_FFIType('struct %s' % name, clibffi.FFI_TYPE_NULL,
+ w_structdescr=self)
+ self.fields_w = None
+ self.name2w_field = {}
+ self._ffistruct_owner = None
+
+ def define_fields(self, space, w_fields):
+ if self.fields_w is not None:
+ raise operationerrfmt(space.w_ValueError,
+ "%s's fields has already been defined",
+ self.w_ffitype.name)
+ space = self.space
+ fields_w = space.fixedview(w_fields)
+ # note that the fields_w returned by compute_size_and_alignement has a
+ # different annotation than the original: list(W_Root) vs list(W_Field)
+ size, alignment, fields_w = compute_size_and_alignement(space, fields_w)
+ self.fields_w = fields_w
+ field_types = [] # clibffi's types
+ for w_field in fields_w:
+ field_types.append(w_field.w_ffitype.get_ffitype())
+ self.name2w_field[w_field.name] = w_field
+ #
+ # on CPython, the FFIStructOwner might go into gc.garbage and thus the
+ # __del__ never be called. Thus, we don't track the allocation of the
+ # malloc done inside this function, else the leakfinder might complain
+ ffistruct = clibffi.make_struct_ffitype_e(size, alignment, field_types,
+ track_allocation=False)
+ self.w_ffitype.set_ffitype(ffistruct.ffistruct)
+ self._ffistruct_owner = FFIStructOwner(ffistruct)
+
+ def check_complete(self, space):
+ if self.fields_w is None:
+ raise operationerrfmt(space.w_ValueError, "%s has an incomplete type",
+ self.w_ffitype.name)
+
+ def allocate(self, space):
+ self.check_complete(space)
+ return W__StructInstance(self)
+
+ @unwrap_spec(addr=int)
+ def fromaddress(self, space, addr):
+ self.check_complete(space)
+ rawmem = rffi.cast(rffi.VOIDP, addr)
+ return W__StructInstance(self, allocate=False, autofree=True, rawmem=rawmem)
+
+ @jit.elidable_promote('0')
+ def get_type_and_offset_for_field(self, name):
+ try:
+ w_field = self.name2w_field[name]
+ except KeyError:
+ raise operationerrfmt(self.space.w_AttributeError, '%s', name)
+
+ return w_field.w_ffitype, w_field.offset
+
+
+
+ at unwrap_spec(name=str)
+def descr_new_structdescr(space, w_type, name, w_fields=None):
+ descr = W__StructDescr(space, name)
+ if w_fields is not space.w_None:
+ descr.define_fields(space, w_fields)
+ return descr
+
+def round_up(size, alignment):
+ return (size + alignment - 1) & -alignment
+
+def compute_size_and_alignement(space, fields_w):
+ size = 0
+ alignment = 1
+ fields_w2 = []
+ for w_field in fields_w:
+ w_field = space.interp_w(W_Field, w_field)
+ fieldsize = w_field.w_ffitype.sizeof()
+ fieldalignment = w_field.w_ffitype.get_alignment()
+ alignment = max(alignment, fieldalignment)
+ size = round_up(size, fieldalignment)
+ w_field.offset = size
+ size += fieldsize
+ fields_w2.append(w_field)
+ #
+ size = round_up(size, alignment)
+ return size, alignment, fields_w2
+
+
+
+W__StructDescr.typedef = TypeDef(
+ '_StructDescr',
+ __new__ = interp2app(descr_new_structdescr),
+ ffitype = interp_attrproperty('w_ffitype', W__StructDescr),
+ define_fields = interp2app(W__StructDescr.define_fields),
+ allocate = interp2app(W__StructDescr.allocate),
+ fromaddress = interp2app(W__StructDescr.fromaddress),
+ )
+
+
+# ==============================================================================
+
+NULL = lltype.nullptr(rffi.VOIDP.TO)
+
+class W__StructInstance(Wrappable):
+
+ _immutable_fields_ = ['structdescr', 'rawmem']
+
+ def __init__(self, structdescr, allocate=True, autofree=True, rawmem=NULL):
+ self.structdescr = structdescr
+ self.autofree = autofree
+ if allocate:
+ assert not rawmem
+ assert autofree
+ size = structdescr.w_ffitype.sizeof()
+ self.rawmem = lltype.malloc(rffi.VOIDP.TO, size, flavor='raw',
+ zero=True, add_memory_pressure=True)
+ else:
+ self.rawmem = rawmem
+
+ @must_be_light_finalizer
+ def __del__(self):
+ if self.autofree and self.rawmem:
+ lltype.free(self.rawmem, flavor='raw')
+ self.rawmem = lltype.nullptr(rffi.VOIDP.TO)
+
+ def getaddr(self, space):
+ addr = rffi.cast(rffi.ULONG, self.rawmem)
+ return space.wrap(addr)
+
+ @unwrap_spec(name=str)
+ def getfield(self, space, name):
+ w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(name)
+ field_getter = GetFieldConverter(space, self.rawmem, offset)
+ return field_getter.do_and_wrap(w_ffitype)
+
+ @unwrap_spec(name=str)
+ def setfield(self, space, name, w_value):
+ w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(name)
+ field_setter = SetFieldConverter(space, self.rawmem, offset)
+ field_setter.unwrap_and_do(w_ffitype, w_value)
+
+
+class GetFieldConverter(ToAppLevelConverter):
+ """
+ A converter used by W__StructInstance to get a field from the struct and
+ wrap it to the correct app-level type.
+ """
+
+ def __init__(self, space, rawmem, offset):
+ self.space = space
+ self.rawmem = rawmem
+ self.offset = offset
+
+ def get_longlong(self, w_ffitype):
+ return libffi.struct_getfield_longlong(libffi.types.slonglong,
+ self.rawmem, self.offset)
+
+ def get_ulonglong(self, w_ffitype):
+ longlongval = libffi.struct_getfield_longlong(libffi.types.ulonglong,
+ self.rawmem, self.offset)
+ return r_ulonglong(longlongval)
+
+
+ def get_signed(self, w_ffitype):
+ return libffi.struct_getfield_int(w_ffitype.get_ffitype(),
+ self.rawmem, self.offset)
+
+ def get_unsigned(self, w_ffitype):
+ value = libffi.struct_getfield_int(w_ffitype.get_ffitype(),
+ self.rawmem, self.offset)
+ return r_uint(value)
+
+ get_unsigned_which_fits_into_a_signed = get_signed
+ get_pointer = get_unsigned
+
+ def get_char(self, w_ffitype):
+ intval = libffi.struct_getfield_int(w_ffitype.get_ffitype(),
+ self.rawmem, self.offset)
+ return rffi.cast(rffi.UCHAR, intval)
+
+ def get_unichar(self, w_ffitype):
+ intval = libffi.struct_getfield_int(w_ffitype.get_ffitype(),
+ self.rawmem, self.offset)
+ return rffi.cast(rffi.WCHAR_T, intval)
+
+ def get_float(self, w_ffitype):
+ return libffi.struct_getfield_float(w_ffitype.get_ffitype(),
+ self.rawmem, self.offset)
+
+ def get_singlefloat(self, w_ffitype):
+ return libffi.struct_getfield_singlefloat(w_ffitype.get_ffitype(),
+ self.rawmem, self.offset)
+
+ def get_struct(self, w_ffitype, w_structdescr):
+ assert isinstance(w_structdescr, W__StructDescr)
+ rawmem = rffi.cast(rffi.CCHARP, self.rawmem)
+ innermem = rffi.cast(rffi.VOIDP, rffi.ptradd(rawmem, self.offset))
+ # we return a reference to the inner struct, not a copy
+ # autofree=False because it's still owned by the parent struct
+ return W__StructInstance(w_structdescr, allocate=False, autofree=False,
+ rawmem=innermem)
+
+ ## def get_void(self, w_ffitype):
+ ## ...
+
+
+class SetFieldConverter(FromAppLevelConverter):
+ """
+ A converter used by W__StructInstance to convert an app-level object to
+ the corresponding low-level value and set the field of a structure.
+ """
+
+ def __init__(self, space, rawmem, offset):
+ self.space = space
+ self.rawmem = rawmem
+ self.offset = offset
+
+ def handle_signed(self, w_ffitype, w_obj, intval):
+ libffi.struct_setfield_int(w_ffitype.get_ffitype(), self.rawmem, self.offset,
+ intval)
+
+ def handle_unsigned(self, w_ffitype, w_obj, uintval):
+ libffi.struct_setfield_int(w_ffitype.get_ffitype(), self.rawmem, self.offset,
+ intmask(uintval))
+
+ handle_pointer = handle_signed
+ handle_char = handle_signed
+ handle_unichar = handle_signed
+
+ def handle_longlong(self, w_ffitype, w_obj, longlongval):
+ libffi.struct_setfield_longlong(w_ffitype.get_ffitype(),
+ self.rawmem, self.offset, longlongval)
+
+ def handle_float(self, w_ffitype, w_obj, floatval):
+ libffi.struct_setfield_float(w_ffitype.get_ffitype(),
+ self.rawmem, self.offset, floatval)
+
+ def handle_singlefloat(self, w_ffitype, w_obj, singlefloatval):
+ libffi.struct_setfield_singlefloat(w_ffitype.get_ffitype(),
+ self.rawmem, self.offset, singlefloatval)
+
+ def handle_struct(self, w_ffitype, w_structinstance):
+ rawmem = rffi.cast(rffi.CCHARP, self.rawmem)
+ dst = rffi.cast(rffi.VOIDP, rffi.ptradd(rawmem, self.offset))
+ src = w_structinstance.rawmem
+ length = w_ffitype.sizeof()
+ rffi.c_memcpy(dst, src, length)
+
+ ## def handle_char_p(self, w_ffitype, w_obj, strval):
+ ## ...
+
+ ## def handle_unichar_p(self, w_ffitype, w_obj, unicodeval):
+ ## ...
+
+
+
+
+W__StructInstance.typedef = TypeDef(
+ '_StructInstance',
+ getaddr = interp2app(W__StructInstance.getaddr),
+ getfield = interp2app(W__StructInstance.getfield),
+ setfield = interp2app(W__StructInstance.setfield),
+ )
diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py
deleted file mode 100644
--- a/pypy/module/_ffi/test/test__ffi.py
+++ /dev/null
@@ -1,542 +0,0 @@
-from pypy.conftest import gettestobjspace
-from pypy.translator.platform import platform
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.module._rawffi.interp_rawffi import TYPEMAP
-from pypy.module._rawffi.tracker import Tracker
-from pypy.translator.platform import platform
-
-import os, sys, py
-
-class AppTestFfi:
-
- @classmethod
- def prepare_c_example(cls):
- from pypy.tool.udir import udir
- from pypy.translator.tool.cbuild import ExternalCompilationInfo
- from pypy.translator.platform import platform
-
- c_file = udir.ensure("test__ffi", dir=1).join("foolib.c")
- # automatically collect the C source from the docstrings of the tests
- snippets = ["""
- #ifdef _WIN32
- #define DLLEXPORT __declspec(dllexport)
- #else
- #define DLLEXPORT
- #endif
- """]
- for name in dir(cls):
- if name.startswith('test_'):
- meth = getattr(cls, name)
- # the heuristic to determine it it's really C code could be
- # improved: so far we just check that there is a '{' :-)
- if meth.__doc__ is not None and '{' in meth.__doc__:
- snippets.append(meth.__doc__)
- #
- c_file.write(py.code.Source('\n'.join(snippets)))
- eci = ExternalCompilationInfo(export_symbols=[])
- return str(platform.compile([c_file], eci, 'x', standalone=False))
-
-
- def setup_class(cls):
- from pypy.rpython.lltypesystem import rffi
- from pypy.rlib.libffi import get_libc_name, CDLL, types
- from pypy.rlib.test.test_libffi import get_libm_name
- space = gettestobjspace(usemodules=('_ffi', '_rawffi'))
- cls.space = space
- cls.w_iswin32 = space.wrap(sys.platform == 'win32')
- cls.w_libfoo_name = space.wrap(cls.prepare_c_example())
- cls.w_libc_name = space.wrap(get_libc_name())
- libm_name = get_libm_name(sys.platform)
- cls.w_libm_name = space.wrap(libm_name)
- libm = CDLL(libm_name)
- pow = libm.getpointer('pow', [], types.void)
- pow_addr = rffi.cast(rffi.LONG, pow.funcsym)
- cls.w_pow_addr = space.wrap(pow_addr)
- #
- # these are needed for test_single_float_args
- from ctypes import c_float
- f_12_34 = c_float(12.34).value
- f_56_78 = c_float(56.78).value
- f_result = c_float(f_12_34 + f_56_78).value
- cls.w_f_12_34_plus_56_78 = space.wrap(f_result)
-
- def test_libload(self):
- import _ffi
- _ffi.CDLL(self.libc_name)
-
- def test_libload_fail(self):
- import _ffi
- raises(OSError, _ffi.CDLL, "xxxxx_this_name_does_not_exist_xxxxx")
-
- def test_libload_None(self):
- if self.iswin32:
- skip("unix specific")
- from _ffi import CDLL, types
- # this should return *all* loaded libs, dlopen(NULL)
- dll = CDLL(None)
- # Assume CPython, or PyPy compiled with cpyext
- res = dll.getfunc('Py_IsInitialized', [], types.slong)()
- assert res == 1
-
- def test_simple_types(self):
- from _ffi import types
- assert str(types.sint) == "<ffi type sint>"
- assert str(types.uint) == "<ffi type uint>"
-
- def test_callfunc(self):
- from _ffi import CDLL, types
- libm = CDLL(self.libm_name)
- pow = libm.getfunc('pow', [types.double, types.double], types.double)
- assert pow(2, 3) == 8
-
- def test_getaddr(self):
- from _ffi import CDLL, types
- libm = CDLL(self.libm_name)
- pow = libm.getfunc('pow', [types.double, types.double], types.double)
- assert pow.getaddr() == self.pow_addr
-
- def test_getaddressindll(self):
- import sys
- from _ffi import CDLL, types
- libm = CDLL(self.libm_name)
- pow_addr = libm.getaddressindll('pow')
- fff = sys.maxint*2-1
- if sys.platform == 'win32':
- fff = sys.maxint*2+1
- assert pow_addr == self.pow_addr & fff
-
- def test_func_fromaddr(self):
- import sys
- from _ffi import CDLL, types, FuncPtr
- libm = CDLL(self.libm_name)
- pow_addr = libm.getaddressindll('pow')
- pow = FuncPtr.fromaddr(pow_addr, 'pow', [types.double, types.double],
- types.double)
- assert pow(2, 3) == 8
-
- def test_int_args(self):
- """
- DLLEXPORT int sum_xy(int x, int y)
- {
- return x+y;
- }
- """
- py3k_skip('missing support for longs')
- import sys
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint)
- assert sum_xy(30, 12) == 42
- assert sum_xy(sys.maxint*2, 0) == -2
-
- def test_void_result(self):
- """
- int dummy = 0;
- DLLEXPORT void set_dummy(int val) { dummy = val; }
- DLLEXPORT int get_dummy() { return dummy; }
- """
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- set_dummy = libfoo.getfunc('set_dummy', [types.sint], types.void)
- get_dummy = libfoo.getfunc('get_dummy', [], types.sint)
- assert get_dummy() == 0
- assert set_dummy(42) is None
- assert get_dummy() == 42
- set_dummy(0)
-
- def test_pointer_args(self):
- """
- extern int dummy; // defined in test_void_result
- DLLEXPORT int* get_dummy_ptr() { return &dummy; }
- DLLEXPORT void set_val_to_ptr(int* ptr, int val) { *ptr = val; }
- """
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- get_dummy = libfoo.getfunc('get_dummy', [], types.sint)
- get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p)
- set_val_to_ptr = libfoo.getfunc('set_val_to_ptr',
- [types.void_p, types.sint],
- types.void)
- assert get_dummy() == 0
- ptr = get_dummy_ptr()
- set_val_to_ptr(ptr, 123)
- assert get_dummy() == 123
- set_val_to_ptr(ptr, 0)
-
- def test_convert_pointer_args(self):
- """
- extern int dummy; // defined in test_void_result
- DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args
- DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto
- """
- from _ffi import CDLL, types
-
- class MyPointerWrapper(object):
- def __init__(self, value):
- self.value = value
- def _as_ffi_pointer_(self, ffitype):
- assert ffitype is types.void_p
- return self.value
-
- libfoo = CDLL(self.libfoo_name)
- get_dummy = libfoo.getfunc('get_dummy', [], types.sint)
- get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p)
- set_val_to_ptr = libfoo.getfunc('set_val_to_ptr',
- [types.void_p, types.sint],
- types.void)
- assert get_dummy() == 0
- ptr = get_dummy_ptr()
- assert type(ptr) is int
- ptr2 = MyPointerWrapper(ptr)
- set_val_to_ptr(ptr2, 123)
- assert get_dummy() == 123
- set_val_to_ptr(ptr2, 0)
-
- def test_convert_strings_to_char_p(self):
- """
- DLLEXPORT
- long mystrlen(char* s)
- {
- long len = 0;
- while(*s++)
- len++;
- return len;
- }
- """
- py3k_skip('missing support for unicode')
- from _ffi import CDLL, types
- import _rawffi
- libfoo = CDLL(self.libfoo_name)
- mystrlen = libfoo.getfunc('mystrlen', [types.char_p], types.slong)
- #
- # first, try automatic conversion from a string
- assert mystrlen('foobar') == 6
- # then, try to pass an explicit pointer
- CharArray = _rawffi.Array('c')
- mystr = CharArray(7, 'foobar')
- assert mystrlen(mystr.buffer) == 6
- mystr.free()
- mystrlen.free_temp_buffers()
-
- def test_convert_unicode_to_unichar_p(self):
- """
- #include <wchar.h>
- DLLEXPORT
- long mystrlen_u(wchar_t* s)
- {
- long len = 0;
- while(*s++)
- len++;
- return len;
- }
- """
- from _ffi import CDLL, types
- import _rawffi
- libfoo = CDLL(self.libfoo_name)
- mystrlen = libfoo.getfunc('mystrlen_u', [types.unichar_p], types.slong)
- #
- # first, try automatic conversion from strings and unicode
- assert mystrlen('foobar') == 6
- assert mystrlen('foobar') == 6
- assert mystrlen('ab\u2070') == 3
- # then, try to pass an explicit pointer
- UniCharArray = _rawffi.Array('u')
- mystr = UniCharArray(7, 'foobar')
- assert mystrlen(mystr.buffer) == 6
- mystr.free()
- mystrlen.free_temp_buffers()
-
- def test_keepalive_temp_buffer(self):
- """
- DLLEXPORT
- char* do_nothing(char* s)
- {
- return s;
- }
- """
- py3k_skip('missing support for unicode')
- from _ffi import CDLL, types
- import _rawffi
- libfoo = CDLL(self.libfoo_name)
- do_nothing = libfoo.getfunc('do_nothing', [types.char_p], types.char_p)
- CharArray = _rawffi.Array('c')
- #
- ptr = do_nothing('foobar')
- array = CharArray.fromaddress(ptr, 7)
- assert list(array) == list('foobar\00')
- do_nothing.free_temp_buffers()
-
- def test_typed_pointer(self):
- from _ffi import types
- intptr = types.Pointer(types.sint) # create a typed pointer to sint
- assert intptr.deref_pointer() is types.sint
- assert str(intptr) == '<ffi type (pointer to sint)>'
- assert types.sint.deref_pointer() is None
- raises(TypeError, "types.Pointer(42)")
-
- def test_pointer_identity(self):
- from _ffi import types
- x = types.Pointer(types.slong)
- y = types.Pointer(types.slong)
- z = types.Pointer(types.char)
- assert x is y
- assert x is not z
-
- def test_char_p_cached(self):
- from _ffi import types
- x = types.Pointer(types.char)
- assert x is types.char_p
- x = types.Pointer(types.unichar)
- assert x is types.unichar_p
-
- def test_typed_pointer_args(self):
- """
- extern int dummy; // defined in test_void_result
- DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args
- DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto
- """
- from _ffi import CDLL, types
-
- libfoo = CDLL(self.libfoo_name)
- intptr = types.Pointer(types.sint)
- get_dummy = libfoo.getfunc('get_dummy', [], types.sint)
- get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], intptr)
- set_val_to_ptr = libfoo.getfunc('set_val_to_ptr', [intptr, types.sint], types.void)
- assert get_dummy() == 0
- ptr = get_dummy_ptr()
- set_val_to_ptr(ptr, 123)
- assert get_dummy() == 123
- set_val_to_ptr(ptr, 0)
-
- def test_huge_pointer_args(self):
- """
- #include <stdlib.h>
- DLLEXPORT long is_null_ptr(void* ptr) { return ptr == NULL; }
- """
- import sys
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- is_null_ptr = libfoo.getfunc('is_null_ptr', [types.void_p], types.ulong)
- assert not is_null_ptr(sys.maxint+1)
-
- def test_unsigned_long_args(self):
- """
- DLLEXPORT unsigned long sum_xy_ul(unsigned long x, unsigned long y)
- {
- return x+y;
- }
- """
- py3k_skip('missing support for longs')
- import sys
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- sum_xy = libfoo.getfunc('sum_xy_ul', [types.ulong, types.ulong],
- types.ulong)
- assert sum_xy(sys.maxint, 12) == sys.maxint+12
- assert sum_xy(sys.maxint+1, 12) == sys.maxint+13
- #
- res = sum_xy(sys.maxint*2+3, 0)
- assert res == 1
-
- def test_unsigned_short_args(self):
- """
- DLLEXPORT unsigned short sum_xy_us(unsigned short x, unsigned short y)
- {
- return x+y;
- }
- """
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- sum_xy = libfoo.getfunc('sum_xy_us', [types.ushort, types.ushort],
- types.ushort)
- assert sum_xy(32000, 8000) == 40000
- assert sum_xy(60000, 30000) == 90000 % 65536
-
- def test_unsigned_byte_args(self):
- """
- DLLEXPORT unsigned char sum_xy_ub(unsigned char x, unsigned char y)
- {
- return x+y;
- }
- """
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- sum_xy = libfoo.getfunc('sum_xy_us', [types.ubyte, types.ubyte],
- types.ubyte)
- assert sum_xy(100, 40) == 140
- assert sum_xy(200, 60) == 260 % 256
-
- def test_signed_byte_args(self):
- """
- DLLEXPORT signed char sum_xy_sb(signed char x, signed char y)
- {
- return x+y;
- }
- """
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- sum_xy = libfoo.getfunc('sum_xy_sb', [types.sbyte, types.sbyte],
- types.sbyte)
- assert sum_xy(10, 20) == 30
- assert sum_xy(100, 28) == -128
-
- def test_char_args(self):
- """
- DLLEXPORT char my_toupper(char x)
- {
- return x - ('a'-'A');
- }
- """
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- my_toupper = libfoo.getfunc('my_toupper', [types.char],
- types.char)
- assert my_toupper('c') == 'C'
-
- def test_unichar_args(self):
- """
- #include <stddef.h>
- DLLEXPORT wchar_t sum_xy_wc(wchar_t x, wchar_t y)
- {
- return x + y;
- }
- """
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- sum_xy = libfoo.getfunc('sum_xy_wc', [types.unichar, types.unichar],
- types.unichar)
- res = sum_xy(chr(1000), chr(2000))
- assert type(res) is str
- assert ord(res) == 3000
-
- def test_single_float_args(self):
- """
- DLLEXPORT float sum_xy_float(float x, float y)
- {
- return x+y;
- }
- """
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- sum_xy = libfoo.getfunc('sum_xy_float', [types.float, types.float],
- types.float)
- res = sum_xy(12.34, 56.78)
- assert res == self.f_12_34_plus_56_78
-
-
- def test_slonglong_args(self):
- """
- DLLEXPORT long long sum_xy_longlong(long long x, long long y)
- {
- return x+y;
- }
- """
- from _ffi import CDLL, types
- maxint32 = 2147483647 # we cannot really go above maxint on 64 bits
- # (and we would not test anything, as there long
- # is the same as long long)
-
- libfoo = CDLL(self.libfoo_name)
- sum_xy = libfoo.getfunc('sum_xy_longlong', [types.slonglong, types.slonglong],
- types.slonglong)
- x = maxint32+1
- y = maxint32+2
- res = sum_xy(x, y)
- expected = maxint32*2 + 3
- assert res == expected
-
- def test_ulonglong_args(self):
- """
- DLLEXPORT unsigned long long sum_xy_ulonglong(unsigned long long x,
- unsigned long long y)
- {
- return x+y;
- }
- """
- py3k_skip('missing support for ulonglong')
- from _ffi import CDLL, types
- maxint64 = 9223372036854775807 # maxint64+1 does not fit into a
- # longlong, but it does into a
- # ulonglong
- libfoo = CDLL(self.libfoo_name)
- sum_xy = libfoo.getfunc('sum_xy_ulonglong', [types.ulonglong, types.ulonglong],
- types.ulonglong)
- x = maxint64+1
- y = 2
- res = sum_xy(x, y)
- expected = maxint64 + 3
- assert res == expected
- #
- res = sum_xy(maxint64*2+3, 0)
- assert res == 1
-
- def test_byval_argument(self):
- """
- struct Point {
- long x;
- long y;
- };
-
- DLLEXPORT long sum_point(struct Point p) {
- return p.x + p.y;
- }
- """
- import _rawffi
- from _ffi import CDLL, types
- POINT = _rawffi.Structure([('x', 'l'), ('y', 'l')])
- ffi_point = POINT.get_ffi_type()
- libfoo = CDLL(self.libfoo_name)
- sum_point = libfoo.getfunc('sum_point', [ffi_point], types.slong)
- #
- p = POINT()
- p.x = 30
- p.y = 12
- res = sum_point(p)
- assert res == 42
- p.free()
-
- def test_byval_result(self):
- """
- DLLEXPORT struct Point make_point(long x, long y) {
- struct Point p;
- p.x = x;
- p.y = y;
- return p;
- }
- """
- import _rawffi
- from _ffi import CDLL, types
- POINT = _rawffi.Structure([('x', 'l'), ('y', 'l')])
- ffi_point = POINT.get_ffi_type()
- libfoo = CDLL(self.libfoo_name)
- make_point = libfoo.getfunc('make_point', [types.slong, types.slong], ffi_point)
- #
- p = make_point(12, 34)
- assert p.x == 12
- assert p.y == 34
- p.free()
-
- def test_TypeError_numargs(self):
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint)
- raises(TypeError, "sum_xy(1, 2, 3)")
- raises(TypeError, "sum_xy(1)")
-
- def test_TypeError_voidarg(self):
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- raises(TypeError, "libfoo.getfunc('sum_xy', [types.void], types.sint)")
-
- def test_OSError_loading(self):
- from _ffi import CDLL, types
- raises(OSError, "CDLL('I do not exist')")
-
- def test_AttributeError_missing_function(self):
- from _ffi import CDLL, types
- libfoo = CDLL(self.libfoo_name)
- raises(AttributeError, "libfoo.getfunc('I_do_not_exist', [], types.void)")
- if self.iswin32:
- skip("unix specific")
- libnone = CDLL(None)
- raises(AttributeError, "libnone.getfunc('I_do_not_exist', [], types.void)")
diff --git a/pypy/module/_ffi/test/test_ffitype.py b/pypy/module/_ffi/test/test_ffitype.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/test/test_ffitype.py
@@ -0,0 +1,39 @@
+from pypy.module._ffi.test.test_funcptr import BaseAppTestFFI
+
+class AppTestFFIType(BaseAppTestFFI):
+
+ def test_simple_types(self):
+ from _ffi import types
+ assert str(types.sint) == "<ffi type sint>"
+ assert str(types.uint) == "<ffi type uint>"
+ assert types.sint.name == 'sint'
+ assert types.uint.name == 'uint'
+
+ def test_sizeof(self):
+ from _ffi import types
+ assert types.sbyte.sizeof() == 1
+ assert types.sint.sizeof() == 4
+
+ def test_typed_pointer(self):
+ from _ffi import types
+ intptr = types.Pointer(types.sint) # create a typed pointer to sint
+ assert intptr.deref_pointer() is types.sint
+ assert str(intptr) == '<ffi type (pointer to sint)>'
+ assert types.sint.deref_pointer() is None
+ raises(TypeError, "types.Pointer(42)")
+
+ def test_pointer_identity(self):
+ from _ffi import types
+ x = types.Pointer(types.slong)
+ y = types.Pointer(types.slong)
+ z = types.Pointer(types.char)
+ assert x is y
+ assert x is not z
+
+ def test_char_p_cached(self):
+ from _ffi import types
+ x = types.Pointer(types.char)
+ assert x is types.char_p
+ x = types.Pointer(types.unichar)
+ assert x is types.unichar_p
+
diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/test/test_funcptr.py
@@ -0,0 +1,576 @@
+from pypy.conftest import gettestobjspace
+from pypy.translator.platform import platform
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+from pypy.module._rawffi.interp_rawffi import TYPEMAP
+from pypy.module._rawffi.tracker import Tracker
+from pypy.translator.platform import platform
+
+import os, sys, py
+
+class BaseAppTestFFI(object):
+
+ @classmethod
+ def prepare_c_example(cls):
+ from pypy.tool.udir import udir
+ from pypy.translator.tool.cbuild import ExternalCompilationInfo
+ from pypy.translator.platform import platform
+
+ c_file = udir.ensure("test__ffi", dir=1).join("foolib.c")
+ # automatically collect the C source from the docstrings of the tests
+ snippets = ["""
+ #ifdef _WIN32
+ #define DLLEXPORT __declspec(dllexport)
+ #else
+ #define DLLEXPORT
+ #endif
+ """]
+ for name in dir(cls):
+ if name.startswith('test_'):
+ meth = getattr(cls, name)
+ # the heuristic to determine it it's really C code could be
+ # improved: so far we just check that there is a '{' :-)
+ if meth.__doc__ is not None and '{' in meth.__doc__:
+ snippets.append(meth.__doc__)
+ #
+ c_file.write(py.code.Source('\n'.join(snippets)))
+ eci = ExternalCompilationInfo(export_symbols=[])
+ return str(platform.compile([c_file], eci, 'x', standalone=False))
+
+ def setup_class(cls):
+ from pypy.rpython.lltypesystem import rffi
+ from pypy.rlib.libffi import get_libc_name, CDLL, types
+ from pypy.rlib.test.test_libffi import get_libm_name
+ space = gettestobjspace(usemodules=('_ffi', '_rawffi'))
+ cls.space = space
+ cls.w_iswin32 = space.wrap(sys.platform == 'win32')
+ cls.w_libfoo_name = space.wrap(cls.prepare_c_example())
+ cls.w_libc_name = space.wrap(get_libc_name())
+ libm_name = get_libm_name(sys.platform)
+ cls.w_libm_name = space.wrap(libm_name)
+ libm = CDLL(libm_name)
+ pow = libm.getpointer('pow', [], types.void)
+ pow_addr = rffi.cast(rffi.LONG, pow.funcsym)
+ cls.w_pow_addr = space.wrap(pow_addr)
+
+class AppTestFFI(BaseAppTestFFI):
+
+ def setup_class(cls):
+ BaseAppTestFFI.setup_class.im_func(cls)
+ space = cls.space
+ # these are needed for test_single_float_args
+ from ctypes import c_float
+ f_12_34 = c_float(12.34).value
+ f_56_78 = c_float(56.78).value
+ f_result = c_float(f_12_34 + f_56_78).value
+ cls.w_f_12_34_plus_56_78 = space.wrap(f_result)
+
+ def test_libload(self):
+ import _ffi
+ _ffi.CDLL(self.libc_name)
+
+ def test_libload_fail(self):
+ import _ffi
+ raises(OSError, _ffi.CDLL, "xxxxx_this_name_does_not_exist_xxxxx")
+
+ def test_libload_None(self):
+ if self.iswin32:
+ skip("unix specific")
+ from _ffi import CDLL, types
+ # this should return *all* loaded libs, dlopen(NULL)
+ dll = CDLL(None)
+ # Assume CPython, or PyPy compiled with cpyext
+ res = dll.getfunc('Py_IsInitialized', [], types.slong)()
+ assert res == 1
+
+ def test_callfunc(self):
+ from _ffi import CDLL, types
+ libm = CDLL(self.libm_name)
+ pow = libm.getfunc('pow', [types.double, types.double], types.double)
+ assert pow(2, 3) == 8
+
+ def test_getaddr(self):
+ from _ffi import CDLL, types
+ libm = CDLL(self.libm_name)
+ pow = libm.getfunc('pow', [types.double, types.double], types.double)
+ assert pow.getaddr() == self.pow_addr
+
+ def test_getaddressindll(self):
+ import sys
+ from _ffi import CDLL, types
+ libm = CDLL(self.libm_name)
+ pow_addr = libm.getaddressindll('pow')
+ fff = sys.maxint*2-1
+ if sys.platform == 'win32':
+ fff = sys.maxint*2+1
+ assert pow_addr == self.pow_addr & fff
+
+ def test_func_fromaddr(self):
+ import sys
+ from _ffi import CDLL, types, FuncPtr
+ libm = CDLL(self.libm_name)
+ pow_addr = libm.getaddressindll('pow')
+ pow = FuncPtr.fromaddr(pow_addr, 'pow', [types.double, types.double],
+ types.double)
+ assert pow(2, 3) == 8
+
+ def test_int_args(self):
+ """
+ DLLEXPORT int sum_xy(int x, int y)
+ {
+ return x+y;
+ }
+ """
+ py3k_skip('missing support for longs')
+ import sys
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint)
+ assert sum_xy(30, 12) == 42
+ assert sum_xy(sys.maxint*2, 0) == -2
+
+ def test_void_result(self):
+ """
+ int dummy = 0;
+ DLLEXPORT void set_dummy(int val) { dummy = val; }
+ DLLEXPORT int get_dummy() { return dummy; }
+ """
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ set_dummy = libfoo.getfunc('set_dummy', [types.sint], types.void)
+ get_dummy = libfoo.getfunc('get_dummy', [], types.sint)
+ assert get_dummy() == 0
+ assert set_dummy(42) is None
+ assert get_dummy() == 42
+ set_dummy(0)
+
+ def test_pointer_args(self):
+ """
+ extern int dummy; // defined in test_void_result
+ DLLEXPORT int* get_dummy_ptr() { return &dummy; }
+ DLLEXPORT void set_val_to_ptr(int* ptr, int val) { *ptr = val; }
+ """
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ get_dummy = libfoo.getfunc('get_dummy', [], types.sint)
+ get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p)
+ set_val_to_ptr = libfoo.getfunc('set_val_to_ptr',
+ [types.void_p, types.sint],
+ types.void)
+ assert get_dummy() == 0
+ ptr = get_dummy_ptr()
+ set_val_to_ptr(ptr, 123)
+ assert get_dummy() == 123
+ set_val_to_ptr(ptr, 0)
+
+ def test_convert_pointer_args(self):
+ """
+ extern int dummy; // defined in test_void_result
+ DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args
+ DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto
+ """
+ from _ffi import CDLL, types
+
+ class MyPointerWrapper(object):
+ def __init__(self, value):
+ self.value = value
+ def _as_ffi_pointer_(self, ffitype):
+ assert ffitype is types.void_p
+ return self.value
+
+ libfoo = CDLL(self.libfoo_name)
+ get_dummy = libfoo.getfunc('get_dummy', [], types.sint)
+ get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p)
+ set_val_to_ptr = libfoo.getfunc('set_val_to_ptr',
+ [types.void_p, types.sint],
+ types.void)
+ assert get_dummy() == 0
+ ptr = get_dummy_ptr()
+ assert type(ptr) is int
+ ptr2 = MyPointerWrapper(ptr)
+ set_val_to_ptr(ptr2, 123)
+ assert get_dummy() == 123
+ set_val_to_ptr(ptr2, 0)
+
+ def test_convert_strings_to_char_p(self):
+ """
+ DLLEXPORT
+ long mystrlen(char* s)
+ {
+ long len = 0;
+ while(*s++)
+ len++;
+ return len;
+ }
+ """
+ py3k_skip('missing support for unicode')
+ from _ffi import CDLL, types
+ import _rawffi
+ libfoo = CDLL(self.libfoo_name)
+ mystrlen = libfoo.getfunc('mystrlen', [types.char_p], types.slong)
+ #
+ # first, try automatic conversion from a string
+ assert mystrlen('foobar') == 6
+ # then, try to pass an explicit pointer
+ CharArray = _rawffi.Array('c')
+ mystr = CharArray(7, 'foobar')
+ assert mystrlen(mystr.buffer) == 6
+ mystr.free()
+ mystrlen.free_temp_buffers()
+
+ def test_convert_unicode_to_unichar_p(self):
+ """
+ #include <wchar.h>
+ DLLEXPORT
+ long mystrlen_u(wchar_t* s)
+ {
+ long len = 0;
+ while(*s++)
+ len++;
+ return len;
+ }
+ """
+ from _ffi import CDLL, types
+ import _rawffi
+ libfoo = CDLL(self.libfoo_name)
+ mystrlen = libfoo.getfunc('mystrlen_u', [types.unichar_p], types.slong)
+ #
+ # first, try automatic conversion from strings and unicode
+ assert mystrlen('foobar') == 6
+ assert mystrlen('foobar') == 6
+ assert mystrlen('ab\u2070') == 3
+ # then, try to pass an explicit pointer
+ UniCharArray = _rawffi.Array('u')
+ mystr = UniCharArray(7, 'foobar')
+ assert mystrlen(mystr.buffer) == 6
+ mystr.free()
+ mystrlen.free_temp_buffers()
+
+ def test_keepalive_temp_buffer(self):
+ """
+ DLLEXPORT
+ char* do_nothing(char* s)
+ {
+ return s;
+ }
+ """
+ py3k_skip('missing support for unicode')
+ from _ffi import CDLL, types
+ import _rawffi
+ libfoo = CDLL(self.libfoo_name)
+ do_nothing = libfoo.getfunc('do_nothing', [types.char_p], types.char_p)
+ CharArray = _rawffi.Array('c')
+ #
+ ptr = do_nothing('foobar')
+ array = CharArray.fromaddress(ptr, 7)
+ assert list(array) == list('foobar\00')
+ do_nothing.free_temp_buffers()
+
+ def test_typed_pointer_args(self):
+ """
+ extern int dummy; // defined in test_void_result
+ DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args
+ DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto
+ """
+ from _ffi import CDLL, types
+
+ libfoo = CDLL(self.libfoo_name)
+ intptr = types.Pointer(types.sint)
+ get_dummy = libfoo.getfunc('get_dummy', [], types.sint)
+ get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], intptr)
+ set_val_to_ptr = libfoo.getfunc('set_val_to_ptr', [intptr, types.sint], types.void)
+ assert get_dummy() == 0
+ ptr = get_dummy_ptr()
+ set_val_to_ptr(ptr, 123)
+ assert get_dummy() == 123
+ set_val_to_ptr(ptr, 0)
+
+ def test_huge_pointer_args(self):
+ """
+ #include <stdlib.h>
+ DLLEXPORT long is_null_ptr(void* ptr) { return ptr == NULL; }
+ """
+ import sys
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ is_null_ptr = libfoo.getfunc('is_null_ptr', [types.void_p], types.ulong)
+ assert not is_null_ptr(sys.maxint+1)
+
+ def test_unsigned_long_args(self):
+ """
+ DLLEXPORT unsigned long sum_xy_ul(unsigned long x, unsigned long y)
+ {
+ return x+y;
+ }
+ """
+ py3k_skip('missing support for longs')
+ import sys
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ sum_xy = libfoo.getfunc('sum_xy_ul', [types.ulong, types.ulong],
+ types.ulong)
+ assert sum_xy(sys.maxint, 12) == sys.maxint+12
+ assert sum_xy(sys.maxint+1, 12) == sys.maxint+13
+ #
+ res = sum_xy(sys.maxint*2+3, 0)
+ assert res == 1
+
+ def test_unsigned_short_args(self):
+ """
+ DLLEXPORT unsigned short sum_xy_us(unsigned short x, unsigned short y)
+ {
+ return x+y;
+ }
+ """
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ sum_xy = libfoo.getfunc('sum_xy_us', [types.ushort, types.ushort],
+ types.ushort)
+ assert sum_xy(32000, 8000) == 40000
+ assert sum_xy(60000, 30000) == 90000 % 65536
+
+ def test_unsigned_byte_args(self):
+ """
+ DLLEXPORT unsigned char sum_xy_ub(unsigned char x, unsigned char y)
+ {
+ return x+y;
+ }
+ """
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ sum_xy = libfoo.getfunc('sum_xy_us', [types.ubyte, types.ubyte],
+ types.ubyte)
+ assert sum_xy(100, 40) == 140
+ assert sum_xy(200, 60) == 260 % 256
+
+ def test_unsigned_int_args(self):
+ r"""
+ DLLEXPORT unsigned int sum_xy_ui(unsigned int x, unsigned int y)
+ {
+ return x+y;
+ }
+ """
+ import sys
+ from _ffi import CDLL, types
+ maxint32 = 2147483647
+ libfoo = CDLL(self.libfoo_name)
+ sum_xy = libfoo.getfunc('sum_xy_ui', [types.uint, types.uint],
+ types.uint)
+ assert sum_xy(maxint32, 1) == maxint32+1
+ assert sum_xy(maxint32, maxint32+2) == 0
+
+ def test_signed_byte_args(self):
+ """
+ DLLEXPORT signed char sum_xy_sb(signed char x, signed char y)
+ {
+ return x+y;
+ }
+ """
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ sum_xy = libfoo.getfunc('sum_xy_sb', [types.sbyte, types.sbyte],
+ types.sbyte)
+ assert sum_xy(10, 20) == 30
+ assert sum_xy(100, 28) == -128
+
+ def test_char_args(self):
+ """
+ DLLEXPORT char my_toupper(char x)
+ {
+ return x - ('a'-'A');
+ }
+ """
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ my_toupper = libfoo.getfunc('my_toupper', [types.char],
+ types.char)
+ assert my_toupper('c') == 'C'
+
+ def test_unichar_args(self):
+ """
+ #include <stddef.h>
+ DLLEXPORT wchar_t sum_xy_wc(wchar_t x, wchar_t y)
+ {
+ return x + y;
+ }
+ """
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ sum_xy = libfoo.getfunc('sum_xy_wc', [types.unichar, types.unichar],
+ types.unichar)
+ res = sum_xy(chr(1000), chr(2000))
+ assert type(res) is str
+ assert ord(res) == 3000
+
+ def test_single_float_args(self):
+ """
+ DLLEXPORT float sum_xy_float(float x, float y)
+ {
+ return x+y;
+ }
+ """
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ sum_xy = libfoo.getfunc('sum_xy_float', [types.float, types.float],
+ types.float)
+ res = sum_xy(12.34, 56.78)
+ assert res == self.f_12_34_plus_56_78
+
+
+ def test_slonglong_args(self):
+ """
+ DLLEXPORT long long sum_xy_longlong(long long x, long long y)
+ {
+ return x+y;
+ }
+ """
+ from _ffi import CDLL, types
+ maxint32 = 2147483647 # we cannot really go above maxint on 64 bits
+ # (and we would not test anything, as there long
+ # is the same as long long)
+
+ libfoo = CDLL(self.libfoo_name)
+ sum_xy = libfoo.getfunc('sum_xy_longlong', [types.slonglong, types.slonglong],
+ types.slonglong)
+ x = maxint32+1
+ y = maxint32+2
+ res = sum_xy(x, y)
+ expected = maxint32*2 + 3
+ assert res == expected
+
+ def test_ulonglong_args(self):
+ """
+ DLLEXPORT unsigned long long sum_xy_ulonglong(unsigned long long x,
+ unsigned long long y)
+ {
+ return x+y;
+ }
+ """
+ py3k_skip('missing support for ulonglong')
+ from _ffi import CDLL, types
+ maxint64 = 9223372036854775807 # maxint64+1 does not fit into a
+ # longlong, but it does into a
+ # ulonglong
+ libfoo = CDLL(self.libfoo_name)
+ sum_xy = libfoo.getfunc('sum_xy_ulonglong', [types.ulonglong, types.ulonglong],
+ types.ulonglong)
+ x = maxint64+1
+ y = 2
+ res = sum_xy(x, y)
+ expected = maxint64 + 3
+ assert res == expected
+ #
+ res = sum_xy(maxint64*2+3, 0)
+ assert res == 1
+
+ def test_byval_argument(self):
+ """
+ struct Point {
+ long x;
+ long y;
+ };
+
+ DLLEXPORT long sum_point(struct Point p) {
+ return p.x + p.y;
+ }
+ """
+ from _ffi import CDLL, types, _StructDescr, Field
+ Point = _StructDescr('Point', [
+ Field('x', types.slong),
+ Field('y', types.slong),
+ ])
+ libfoo = CDLL(self.libfoo_name)
+ sum_point = libfoo.getfunc('sum_point', [Point.ffitype], types.slong)
+ #
+ p = Point.allocate()
+ p.setfield('x', 30)
+ p.setfield('y', 12)
+ res = sum_point(p)
+ assert res == 42
+
+ def test_byval_result(self):
+ """
+ DLLEXPORT struct Point make_point(long x, long y) {
+ struct Point p;
+ p.x = x;
+ p.y = y;
+ return p;
+ }
+ """
+ from _ffi import CDLL, types, _StructDescr, Field
+ Point = _StructDescr('Point', [
+ Field('x', types.slong),
+ Field('y', types.slong),
+ ])
+ libfoo = CDLL(self.libfoo_name)
+ make_point = libfoo.getfunc('make_point', [types.slong, types.slong],
+ Point.ffitype)
+ #
+ p = make_point(12, 34)
+ assert p.getfield('x') == 12
+ assert p.getfield('y') == 34
+
+ # XXX: support for _rawffi structures should be killed as soon as we
+ # implement ctypes.Structure on top of _ffi. In the meantime, we support
+ # both
+ def test_byval_argument__rawffi(self):
+ """
+ // defined above
+ struct Point;
+ DLLEXPORT long sum_point(struct Point p);
+ """
+ import _rawffi
+ from _ffi import CDLL, types
+ POINT = _rawffi.Structure([('x', 'l'), ('y', 'l')])
+ ffi_point = POINT.get_ffi_type()
+ libfoo = CDLL(self.libfoo_name)
+ sum_point = libfoo.getfunc('sum_point', [ffi_point], types.slong)
+ #
+ p = POINT()
+ p.x = 30
+ p.y = 12
+ res = sum_point(p)
+ assert res == 42
+ p.free()
+
+ def test_byval_result__rawffi(self):
+ """
+ // defined above
+ DLLEXPORT struct Point make_point(long x, long y);
+ """
+ import _rawffi
+ from _ffi import CDLL, types
+ POINT = _rawffi.Structure([('x', 'l'), ('y', 'l')])
+ ffi_point = POINT.get_ffi_type()
+ libfoo = CDLL(self.libfoo_name)
+ make_point = libfoo.getfunc('make_point', [types.slong, types.slong], ffi_point)
+ #
+ p = make_point(12, 34)
+ assert p.x == 12
+ assert p.y == 34
+ p.free()
+
+
+ def test_TypeError_numargs(self):
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ sum_xy = libfoo.getfunc('sum_xy', [types.sint, types.sint], types.sint)
+ raises(TypeError, "sum_xy(1, 2, 3)")
+ raises(TypeError, "sum_xy(1)")
+
+ def test_TypeError_voidarg(self):
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ raises(TypeError, "libfoo.getfunc('sum_xy', [types.void], types.sint)")
+
+ def test_OSError_loading(self):
+ from _ffi import CDLL, types
+ raises(OSError, "CDLL('I do not exist')")
+
+ def test_AttributeError_missing_function(self):
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ raises(AttributeError, "libfoo.getfunc('I_do_not_exist', [], types.void)")
+ if self.iswin32:
+ skip("unix specific")
+ libnone = CDLL(None)
+ raises(AttributeError, "libnone.getfunc('I_do_not_exist', [], types.void)")
diff --git a/pypy/module/_ffi/test/test_struct.py b/pypy/module/_ffi/test/test_struct.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/test/test_struct.py
@@ -0,0 +1,323 @@
+import sys
+from pypy.conftest import gettestobjspace, option
+from pypy.module._ffi.test.test_funcptr import BaseAppTestFFI
+from pypy.module._ffi.interp_struct import compute_size_and_alignement, W_Field
+from pypy.module._ffi.interp_ffitype import app_types, W_FFIType
+
+
+class TestStruct(object):
+
+ class FakeSpace(object):
+ def interp_w(self, cls, obj):
+ return obj
+
+ def compute(self, ffitypes_w):
+ fields_w = [W_Field('<dummy>', w_ffitype) for
+ w_ffitype in ffitypes_w]
+ return compute_size_and_alignement(self.FakeSpace(), fields_w)
+
+ def sizeof(self, ffitypes_w):
+ size, aligned, fields_w = self.compute(ffitypes_w)
+ return size
+
+ def test_compute_size(self):
+ T = app_types
+ byte_size = app_types.sbyte.sizeof()
+ long_size = app_types.slong.sizeof()
+ llong_size = app_types.slonglong.sizeof()
+ llong_align = app_types.slonglong.get_alignment()
+ #
+ assert llong_align >= 4
+ assert self.sizeof([T.sbyte, T.slong]) == 2*long_size
+ assert self.sizeof([T.sbyte, T.slonglong]) == llong_align + llong_size
+ assert self.sizeof([T.sbyte, T.sbyte, T.slonglong]) == llong_align + llong_size
+ assert self.sizeof([T.sbyte, T.sbyte, T.sbyte, T.slonglong]) == llong_align + llong_size
+ assert self.sizeof([T.sbyte, T.sbyte, T.sbyte, T.sbyte, T.slonglong]) == llong_align + llong_size
+ assert self.sizeof([T.slonglong, T.sbyte]) == llong_size + llong_align
+ assert self.sizeof([T.slonglong, T.sbyte, T.sbyte]) == llong_size + llong_align
+ assert self.sizeof([T.slonglong, T.sbyte, T.sbyte, T.sbyte]) == llong_size + llong_align
+ assert self.sizeof([T.slonglong, T.sbyte, T.sbyte, T.sbyte, T.sbyte]) == llong_size + llong_align
+
+class AppTestStruct(BaseAppTestFFI):
+
+ def setup_class(cls):
+ BaseAppTestFFI.setup_class.im_func(cls)
+ #
+ def read_raw_mem(self, addr, typename, length):
+ import ctypes
+ addr = ctypes.cast(addr, ctypes.c_void_p)
+ c_type = getattr(ctypes, typename)
+ array_type = ctypes.POINTER(c_type * length)
+ ptr_array = ctypes.cast(addr, array_type)
+ array = ptr_array[0]
+ lst = [array[i] for i in range(length)]
+ return lst
+ cls.w_read_raw_mem = cls.space.wrap(read_raw_mem)
+ #
+ from pypy.rlib import clibffi
+ from pypy.rlib.rarithmetic import r_uint
+ from pypy.rpython.lltypesystem import lltype, rffi
+ dummy_type = lltype.malloc(clibffi.FFI_TYPE_P.TO, flavor='raw')
+ dummy_type.c_size = r_uint(123)
+ dummy_type.c_alignment = rffi.cast(rffi.USHORT, 0)
+ dummy_type.c_type = rffi.cast(rffi.USHORT, 0)
+ cls.w_dummy_type = W_FFIType('dummy', dummy_type)
+ cls.w_runappdirect = cls.space.wrap(option.runappdirect)
+
+ def test__StructDescr(self):
+ from _ffi import _StructDescr, Field, types
+ longsize = types.slong.sizeof()
+ fields = [
+ Field('x', types.slong),
+ Field('y', types.slong),
+ ]
+ descr = _StructDescr('foo', fields)
+ assert descr.ffitype.sizeof() == longsize*2
+ assert descr.ffitype.name == 'struct foo'
+
+ def test_alignment(self):
+ from _ffi import _StructDescr, Field, types
+ longsize = types.slong.sizeof()
+ fields = [
+ Field('x', types.sbyte),
+ Field('y', types.slong),
+ ]
+ descr = _StructDescr('foo', fields)
+ assert descr.ffitype.sizeof() == longsize*2
+ assert fields[0].offset == 0
+ assert fields[1].offset == longsize # aligned to WORD
+
+ def test_missing_field(self):
+ from _ffi import _StructDescr, Field, types
+ longsize = types.slong.sizeof()
+ fields = [
+ Field('x', types.slong),
+ Field('y', types.slong),
+ ]
+ descr = _StructDescr('foo', fields)
+ struct = descr.allocate()
+ raises(AttributeError, "struct.getfield('missing')")
+ raises(AttributeError, "struct.setfield('missing', 42)")
+
+ def test_unknown_type(self):
+ if self.runappdirect:
+ skip('cannot use self.dummy_type with -A')
+ from _ffi import _StructDescr, Field
+ fields = [
+ Field('x', self.dummy_type),
+ ]
+ descr = _StructDescr('foo', fields)
+ struct = descr.allocate()
+ raises(TypeError, "struct.getfield('x')")
+ raises(TypeError, "struct.setfield('x', 42)")
+
+ def test_getfield_setfield(self):
+ from _ffi import _StructDescr, Field, types
+ longsize = types.slong.sizeof()
+ fields = [
+ Field('x', types.slong),
+ Field('y', types.slong),
+ ]
+ descr = _StructDescr('foo', fields)
+ struct = descr.allocate()
+ struct.setfield('x', 42)
+ struct.setfield('y', 43)
+ assert struct.getfield('x') == 42
+ assert struct.getfield('y') == 43
+ mem = self.read_raw_mem(struct.getaddr(), 'c_long', 2)
+ assert mem == [42, 43]
+
+ def test_getfield_setfield_signed_types(self):
+ import sys
+ from _ffi import _StructDescr, Field, types
+ longsize = types.slong.sizeof()
+ fields = [
+ Field('sbyte', types.sbyte),
+ Field('sshort', types.sshort),
+ Field('sint', types.sint),
+ Field('slong', types.slong),
+ ]
+ descr = _StructDescr('foo', fields)
+ struct = descr.allocate()
+ struct.setfield('sbyte', 128)
+ assert struct.getfield('sbyte') == -128
+ struct.setfield('sshort', 32768)
+ assert struct.getfield('sshort') == -32768
+ struct.setfield('sint', 43)
+ assert struct.getfield('sint') == 43
+ struct.setfield('slong', sys.maxint+1)
+ assert struct.getfield('slong') == -sys.maxint-1
+ struct.setfield('slong', sys.maxint*3)
+ assert struct.getfield('slong') == sys.maxint-2
+
+ def test_getfield_setfield_unsigned_types(self):
+ import sys
+ from _ffi import _StructDescr, Field, types
+ longsize = types.slong.sizeof()
+ fields = [
+ Field('ubyte', types.ubyte),
+ Field('ushort', types.ushort),
+ Field('uint', types.uint),
+ Field('ulong', types.ulong),
+ Field('char', types.char),
+ Field('unichar', types.unichar),
+ Field('ptr', types.void_p),
+ ]
+ descr = _StructDescr('foo', fields)
+ struct = descr.allocate()
+ struct.setfield('ubyte', -1)
+ assert struct.getfield('ubyte') == 255
+ struct.setfield('ushort', -1)
+ assert struct.getfield('ushort') == 65535
+ struct.setfield('uint', 43)
+ assert struct.getfield('uint') == 43
+ struct.setfield('ulong', -1)
+ assert struct.getfield('ulong') == sys.maxint*2 + 1
+ struct.setfield('ulong', sys.maxint*2 + 2)
+ assert struct.getfield('ulong') == 0
+ struct.setfield('char', 'a')
+ assert struct.getfield('char') == 'a'
+ struct.setfield('unichar', u'\u1234')
+ assert struct.getfield('unichar') == u'\u1234'
+ struct.setfield('ptr', -1)
+ assert struct.getfield('ptr') == sys.maxint*2 + 1
+
+ def test_getfield_setfield_longlong(self):
+ import sys
+ from _ffi import _StructDescr, Field, types
+ longsize = types.slong.sizeof()
+ fields = [
+ Field('slonglong', types.slonglong),
+ Field('ulonglong', types.ulonglong),
+ ]
+ descr = _StructDescr('foo', fields)
+ struct = descr.allocate()
+ struct.setfield('slonglong', 9223372036854775808)
+ assert struct.getfield('slonglong') == -9223372036854775808
+ struct.setfield('ulonglong', -1)
+ assert struct.getfield('ulonglong') == 18446744073709551615
+ mem = self.read_raw_mem(struct.getaddr(), 'c_longlong', 2)
+ assert mem == [-9223372036854775808, -1]
+
+ def test_getfield_setfield_float(self):
+ import sys
+ from _ffi import _StructDescr, Field, types
+ longsize = types.slong.sizeof()
+ fields = [
+ Field('x', types.double),
+ ]
+ descr = _StructDescr('foo', fields)
+ struct = descr.allocate()
+ struct.setfield('x', 123.4)
+ assert struct.getfield('x') == 123.4
+ mem = self.read_raw_mem(struct.getaddr(), 'c_double', 1)
+ assert mem == [123.4]
+
+ def test_getfield_setfield_singlefloat(self):
+ import sys
+ from _ffi import _StructDescr, Field, types
+ longsize = types.slong.sizeof()
+ fields = [
+ Field('x', types.float),
+ ]
+ descr = _StructDescr('foo', fields)
+ struct = descr.allocate()
+ struct.setfield('x', 123.4) # this is a value which DOES loose
+ # precision in a single float
+ assert 0 < abs(struct.getfield('x') - 123.4) < 0.0001
+ #
+ struct.setfield('x', 123.5) # this is a value which does not loose
+ # precision in a single float
+ assert struct.getfield('x') == 123.5
+ mem = self.read_raw_mem(struct.getaddr(), 'c_float', 1)
+ assert mem == [123.5]
+
+ def test_define_fields(self):
+ from _ffi import _StructDescr, Field, types
+ longsize = types.slong.sizeof()
+ fields = [
+ Field('x', types.slong),
+ Field('y', types.slong),
+ ]
+ descr = _StructDescr('foo')
+ assert descr.ffitype.name == 'struct foo'
+ assert repr(descr.ffitype) == '<ffi type struct foo (incomplete)>'
+ raises(ValueError, "descr.ffitype.sizeof()")
+ raises(ValueError, "descr.allocate()")
+ #
+ descr.define_fields(fields)
+ assert repr(descr.ffitype) == '<ffi type struct foo>'
+ assert descr.ffitype.sizeof() == longsize*2
+ raises(ValueError, "descr.define_fields(fields)")
+
+ def test_pointer_to_incomplete_struct(self):
+ from _ffi import _StructDescr, Field, types
+ longsize = types.slong.sizeof()
+ fields = [
+ Field('x', types.slong),
+ Field('y', types.slong),
+ ]
+ descr = _StructDescr('foo')
+ foo_ffitype = descr.ffitype
+ foo_p = types.Pointer(descr.ffitype)
+ assert foo_p.deref_pointer() is foo_ffitype
+ descr.define_fields(fields)
+ assert descr.ffitype is foo_ffitype
+ assert foo_p.deref_pointer() is foo_ffitype
+ assert types.Pointer(descr.ffitype) is foo_p
+
+ def test_nested_structure(self):
+ from _ffi import _StructDescr, Field, types
+ longsize = types.slong.sizeof()
+ foo_fields = [
+ Field('x', types.slong),
+ Field('y', types.slong),
+ ]
+ foo_descr = _StructDescr('foo', foo_fields)
+ #
+ bar_fields = [
+ Field('x', types.slong),
+ Field('foo', foo_descr.ffitype),
+ ]
+ bar_descr = _StructDescr('bar', bar_fields)
+ assert bar_descr.ffitype.sizeof() == longsize*3
+ #
+ struct = bar_descr.allocate()
+ struct.setfield('x', 40)
+ # reading a nested structure yields a reference to it
+ struct_foo = struct.getfield('foo')
+ struct_foo.setfield('x', 41)
+ struct_foo.setfield('y', 42)
+ mem = self.read_raw_mem(struct.getaddr(), 'c_long', 3)
+ assert mem == [40, 41, 42]
+ #
+ struct_foo2 = foo_descr.allocate()
+ struct_foo2.setfield('x', 141)
+ struct_foo2.setfield('y', 142)
+ # writing a nested structure copies its memory into the target
+ struct.setfield('foo', struct_foo2)
+ struct_foo2.setfield('x', 241)
+ struct_foo2.setfield('y', 242)
+ mem = self.read_raw_mem(struct.getaddr(), 'c_long', 3)
+ assert mem == [40, 141, 142]
+ mem = self.read_raw_mem(struct_foo2.getaddr(), 'c_long', 2)
+ assert mem == [241, 242]
+
+
+
+ def test_compute_shape(self):
+ from _ffi import Structure, Field, types
+ class Point(Structure):
+ _fields_ = [
+ Field('x', types.slong),
+ Field('y', types.slong),
+ ]
+
+ longsize = types.slong.sizeof()
+ assert isinstance(Point.x, Field)
+ assert isinstance(Point.y, Field)
+ assert Point.x.offset == 0
+ assert Point.y.offset == longsize
+ assert Point._struct_.ffitype.sizeof() == longsize*2
+ assert Point._struct_.ffitype.name == 'struct Point'
+
diff --git a/pypy/module/_ffi/test/test_type_converter.py b/pypy/module/_ffi/test/test_type_converter.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/test/test_type_converter.py
@@ -0,0 +1,170 @@
+import sys
+from pypy.conftest import gettestobjspace
+from pypy.rlib.rarithmetic import r_uint, r_singlefloat, r_longlong, r_ulonglong
+from pypy.rlib.libffi import IS_32_BIT
+from pypy.module._ffi.interp_ffitype import app_types, descr_new_pointer
+from pypy.module._ffi.type_converter import FromAppLevelConverter, ToAppLevelConverter
+
+class DummyFromAppLevelConverter(FromAppLevelConverter):
+
+ def handle_all(self, w_ffitype, w_obj, val):
+ self.lastval = val
+
+ handle_signed = handle_all
+ handle_unsigned = handle_all
+ handle_pointer = handle_all
+ handle_char = handle_all
+ handle_unichar = handle_all
+ handle_longlong = handle_all
+ handle_char_p = handle_all
+ handle_unichar_p = handle_all
+ handle_float = handle_all
+ handle_singlefloat = handle_all
+
+ def handle_struct(self, w_ffitype, w_structinstance):
+ self.lastval = w_structinstance
+
+ def convert(self, w_ffitype, w_obj):
+ self.unwrap_and_do(w_ffitype, w_obj)
+ return self.lastval
+
+
+class TestFromAppLevel(object):
+
+ def setup_class(cls):
+ cls.space = gettestobjspace(usemodules=('_ffi',))
+ converter = DummyFromAppLevelConverter(cls.space)
+ cls.from_app_level = staticmethod(converter.convert)
+
+ def check(self, w_ffitype, w_obj, expected):
+ v = self.from_app_level(w_ffitype, w_obj)
+ assert v == expected
+ assert type(v) is type(expected)
+
+ def test_int(self):
+ self.check(app_types.sint, self.space.wrap(42), 42)
+ self.check(app_types.sint, self.space.wrap(sys.maxint+1), -sys.maxint-1)
+ self.check(app_types.sint, self.space.wrap(sys.maxint*2), -2)
+
+ def test_unsigned(self):
+ space = self.space
+ self.check(app_types.uint, space.wrap(42), r_uint(42))
+ self.check(app_types.uint, space.wrap(-1), r_uint(sys.maxint*2 +1))
+ self.check(app_types.uint, space.wrap(sys.maxint*3),
+ r_uint(sys.maxint - 2))
+ self.check(app_types.ulong, space.wrap(sys.maxint+12),
+ r_uint(sys.maxint+12))
+ self.check(app_types.ulong, space.wrap(sys.maxint*2+3), r_uint(1))
+
+ def test_char(self):
+ space = self.space
+ self.check(app_types.char, space.wrap('a'), ord('a'))
+ self.check(app_types.unichar, space.wrap(u'\u1234'), 0x1234)
+
+ def test_signed_longlong(self):
+ space = self.space
+ maxint32 = 2147483647 # we cannot really go above maxint on 64 bits
+ # (and we would not test anything, as there long
+ # is the same as long long)
+ expected = maxint32+1
+ if IS_32_BIT:
+ expected = r_longlong(expected)
+ self.check(app_types.slonglong, space.wrap(maxint32+1), expected)
+
+ def test_unsigned_longlong(self):
+ space = self.space
+ maxint64 = 9223372036854775807 # maxint64+1 does not fit into a
+ # longlong, but it does into a
+ # ulonglong
+ if IS_32_BIT:
+ # internally, the type converter always casts to signed longlongs
+ expected = r_longlong(-maxint64-1)
+ else:
+ # on 64 bit, ulonglong == uint (i.e., unsigned long in C terms)
+ expected = r_uint(maxint64+1)
+ self.check(app_types.ulonglong, space.wrap(maxint64+1), expected)
+
+ def test_float_and_double(self):
+ space = self.space
+ self.check(app_types.float, space.wrap(12.34), r_singlefloat(12.34))
+ self.check(app_types.double, space.wrap(12.34), 12.34)
+
+ def test_pointer(self):
+ # pointers are "unsigned" at applevel, but signed at interp-level (for
+ # no good reason, at interp-level Signed or Unsigned makes no
+ # difference for passing bits around)
+ space = self.space
+ self.check(app_types.void_p, space.wrap(42), 42)
+ self.check(app_types.void_p, space.wrap(sys.maxint+1), -sys.maxint-1)
+ #
+ # typed pointers
+ w_ptr_sint = descr_new_pointer(space, None, app_types.sint)
+ self.check(w_ptr_sint, space.wrap(sys.maxint+1), -sys.maxint-1)
+
+
+ def test__as_ffi_pointer_(self):
+ space = self.space
+ w_MyPointerWrapper = space.appexec([], """():
+ import _ffi
+ class MyPointerWrapper(object):
+ def __init__(self, value):
+ self.value = value
+ def _as_ffi_pointer_(self, ffitype):
+ assert ffitype is _ffi.types.void_p
+ return self.value
+
+ return MyPointerWrapper
+ """)
+ w_obj = space.call_function(w_MyPointerWrapper, space.wrap(42))
+ self.check(app_types.void_p, w_obj, 42)
+
+ def test_strings(self):
+ # first, try automatic conversion from applevel
+ self.check(app_types.char_p, self.space.wrap('foo'), 'foo')
+ self.check(app_types.unichar_p, self.space.wrap(u'foo\u1234'), u'foo\u1234')
+ self.check(app_types.unichar_p, self.space.wrap('foo'), u'foo')
+ # then, try to pass explicit pointers
+ self.check(app_types.char_p, self.space.wrap(42), 42)
+ self.check(app_types.unichar_p, self.space.wrap(42), 42)
+
+
+
+class DummyToAppLevelConverter(ToAppLevelConverter):
+
+ def get_all(self, w_ffitype):
+ return self.val
+
+ get_signed = get_all
+ get_unsigned = get_all
+ get_pointer = get_all
+ get_char = get_all
+ get_unichar = get_all
+ get_longlong = get_all
+ get_char_p = get_all
+ get_unichar_p = get_all
+ get_float = get_all
+ get_singlefloat = get_all
+
+ def convert(self, w_ffitype, val):
+ self.val = val
+ return self.do_and_wrap(w_ffitype)
+
+
+class TestFromAppLevel(object):
+
+ def setup_class(cls):
+ cls.space = gettestobjspace(usemodules=('_ffi',))
+ converter = DummyToAppLevelConverter(cls.space)
+ cls.from_app_level = staticmethod(converter.convert)
+
+ def check(self, w_ffitype, val, w_expected):
+ w_v = self.from_app_level(w_ffitype, val)
+ assert self.space.eq_w(w_v, w_expected)
+
+ def test_int(self):
+ self.check(app_types.sint, 42, self.space.wrap(42))
+ self.check(app_types.sint, -sys.maxint-1, self.space.wrap(-sys.maxint-1))
+
+ def test_uint(self):
+ self.check(app_types.uint, 42, self.space.wrap(42))
+ self.check(app_types.uint, r_uint(sys.maxint+1), self.space.wrap(sys.maxint+1))
diff --git a/pypy/module/_ffi/type_converter.py b/pypy/module/_ffi/type_converter.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/type_converter.py
@@ -0,0 +1,366 @@
+from pypy.rlib import libffi
+from pypy.rlib import jit
+from pypy.rlib.rarithmetic import intmask, r_uint
+from pypy.rpython.lltypesystem import rffi
+from pypy.interpreter.error import operationerrfmt, OperationError
+from pypy.module._rawffi.structure import W_StructureInstance, W_Structure
+from pypy.module._ffi.interp_ffitype import app_types
+
+class FromAppLevelConverter(object):
+ """
+ Unwrap an app-level object to the corresponding low-level type, following
+ the conversion rules which apply to the specified w_ffitype. Once
+ unwrapped, the value is passed to the corresponding handle_* method.
+ Subclasses should override the desired ones.
+ """
+
+ def __init__(self, space):
+ self.space = space
+
+ def unwrap_and_do(self, w_ffitype, w_obj):
+ from pypy.module._ffi.interp_struct import W__StructInstance
+ space = self.space
+ if w_ffitype.is_longlong():
+ # note that we must check for longlong first, because either
+ # is_signed or is_unsigned returns true anyway
+ assert libffi.IS_32_BIT
+ self._longlong(w_ffitype, w_obj)
+ elif w_ffitype.is_signed():
+ intval = space.truncatedint_w(w_obj)
+ self.handle_signed(w_ffitype, w_obj, intval)
+ elif self.maybe_handle_char_or_unichar_p(w_ffitype, w_obj):
+ # the object was already handled from within
+ # maybe_handle_char_or_unichar_p
+ pass
+ elif w_ffitype.is_pointer():
+ w_obj = self.convert_pointer_arg_maybe(w_obj, w_ffitype)
+ intval = space.truncatedint_w(w_obj)
+ self.handle_pointer(w_ffitype, w_obj, intval)
+ elif w_ffitype.is_unsigned():
+ uintval = r_uint(space.truncatedint_w(w_obj))
+ self.handle_unsigned(w_ffitype, w_obj, uintval)
+ elif w_ffitype.is_char():
+ intval = space.int_w(space.ord(w_obj))
+ self.handle_char(w_ffitype, w_obj, intval)
+ elif w_ffitype.is_unichar():
+ intval = space.int_w(space.ord(w_obj))
+ self.handle_unichar(w_ffitype, w_obj, intval)
+ elif w_ffitype.is_double():
+ self._float(w_ffitype, w_obj)
+ elif w_ffitype.is_singlefloat():
+ self._singlefloat(w_ffitype, w_obj)
+ elif w_ffitype.is_struct():
+ if isinstance(w_obj, W_StructureInstance):
+ self.handle_struct_rawffi(w_ffitype, w_obj)
+ else:
+ w_obj = space.interp_w(W__StructInstance, w_obj)
+ self.handle_struct(w_ffitype, w_obj)
+ else:
+ self.error(w_ffitype, w_obj)
+
+ def _longlong(self, w_ffitype, w_obj):
+ # a separate function, which can be seen by the jit or not,
+ # depending on whether longlongs are supported
+ longlongval = self.space.truncatedlonglong_w(w_obj)
+ self.handle_longlong(w_ffitype, w_obj, longlongval)
+
+ def _float(self, w_ffitype, w_obj):
+ # a separate function, which can be seen by the jit or not,
+ # depending on whether floats are supported
+ floatval = self.space.float_w(w_obj)
+ self.handle_float(w_ffitype, w_obj, floatval)
+
+ def _singlefloat(self, w_ffitype, w_obj):
+ # a separate function, which can be seen by the jit or not,
+ # depending on whether singlefloats are supported
+ from pypy.rlib.rarithmetic import r_singlefloat
+ floatval = self.space.float_w(w_obj)
+ singlefloatval = r_singlefloat(floatval)
+ self.handle_singlefloat(w_ffitype, w_obj, singlefloatval)
+
+ def maybe_handle_char_or_unichar_p(self, w_ffitype, w_obj):
+ w_type = jit.promote(self.space.type(w_obj))
+ if w_ffitype.is_char_p() and w_type is self.space.w_str:
+ strval = self.space.str_w(w_obj)
+ self.handle_char_p(w_ffitype, w_obj, strval)
+ return True
+ elif w_ffitype.is_unichar_p() and (w_type is self.space.w_str or
+ w_type is self.space.w_unicode):
+ unicodeval = self.space.unicode_w(w_obj)
+ self.handle_unichar_p(w_ffitype, w_obj, unicodeval)
+ return True
+ return False
+
+ def convert_pointer_arg_maybe(self, w_arg, w_argtype):
+ """
+ Try to convert the argument by calling _as_ffi_pointer_()
+ """
+ space = self.space
+ meth = space.lookup(w_arg, '_as_ffi_pointer_') # this also promotes the type
+ if meth:
+ return space.call_function(meth, w_arg, w_argtype)
+ else:
+ return w_arg
+
+ def error(self, w_ffitype, w_obj):
+ raise operationerrfmt(self.space.w_TypeError,
+ 'Unsupported ffi type to convert: %s',
+ w_ffitype.name)
+
+ def handle_signed(self, w_ffitype, w_obj, intval):
+ """
+ intval: lltype.Signed
+ """
+ self.error(w_ffitype, w_obj)
+
+ def handle_unsigned(self, w_ffitype, w_obj, uintval):
+ """
+ uintval: lltype.Unsigned
+ """
+ self.error(w_ffitype, w_obj)
+
+ def handle_pointer(self, w_ffitype, w_obj, intval):
+ """
+ intval: lltype.Signed
+ """
+ self.error(w_ffitype, w_obj)
+
+ def handle_char(self, w_ffitype, w_obj, intval):
+ """
+ intval: lltype.Signed
+ """
+ self.error(w_ffitype, w_obj)
+
+ def handle_unichar(self, w_ffitype, w_obj, intval):
+ """
+ intval: lltype.Signed
+ """
+ self.error(w_ffitype, w_obj)
+
+ def handle_longlong(self, w_ffitype, w_obj, longlongval):
+ """
+ longlongval: lltype.SignedLongLong
+ """
+ self.error(w_ffitype, w_obj)
+
+ def handle_char_p(self, w_ffitype, w_obj, strval):
+ """
+ strval: interp-level str
+ """
+ self.error(w_ffitype, w_obj)
+
+ def handle_unichar_p(self, w_ffitype, w_obj, unicodeval):
+ """
+ unicodeval: interp-level unicode
+ """
+ self.error(w_ffitype, w_obj)
+
+ def handle_float(self, w_ffitype, w_obj, floatval):
+ """
+ floatval: lltype.Float
+ """
+ self.error(w_ffitype, w_obj)
+
+ def handle_singlefloat(self, w_ffitype, w_obj, singlefloatval):
+ """
+ singlefloatval: lltype.SingleFloat
+ """
+ self.error(w_ffitype, w_obj)
+
+ def handle_struct(self, w_ffitype, w_structinstance):
+ """
+ w_structinstance: W_StructureInstance
+ """
+ self.error(w_ffitype, w_structinstance)
+
+ def handle_struct_rawffi(self, w_ffitype, w_structinstance):
+ """
+ This method should be killed as soon as we remove support for _rawffi structures
+
+ w_structinstance: W_StructureInstance
+ """
+ self.error(w_ffitype, w_structinstance)
+
+
+
+class ToAppLevelConverter(object):
+ """
+ Wrap a low-level value to an app-level object, following the conversion
+ rules which apply to the specified w_ffitype. The value is got by calling
+ the get_* method corresponding to the w_ffitype. Subclasses should
+ override the desired ones.
+ """
+
+ def __init__(self, space):
+ self.space = space
+
+ def do_and_wrap(self, w_ffitype):
+ from pypy.module._ffi.interp_struct import W__StructDescr
+ space = self.space
+ if w_ffitype.is_longlong():
+ # note that we must check for longlong first, because either
+ # is_signed or is_unsigned returns true anyway
+ assert libffi.IS_32_BIT
+ return self._longlong(w_ffitype)
+ elif w_ffitype.is_signed():
+ intval = self.get_signed(w_ffitype)
+ return space.wrap(intval)
+ elif (w_ffitype is app_types.ulonglong or
+ w_ffitype is app_types.ulong or (libffi.IS_32_BIT and
+ w_ffitype is app_types.uint)):
+ # Note that we the second check (for ulonglong) is meaningful only
+ # on 64 bit, because on 32 bit the ulonglong case would have been
+ # handled by the is_longlong() branch above. On 64 bit, ulonglong
+ # is essentially the same as ulong.
+ #
+ # We need to be careful when the return type is ULONG, because the
+ # value might not fit into a signed LONG, and thus might require
+ # and app-evel <long>. This is why we need to treat it separately
+ # than the other unsigned types.
+ uintval = self.get_unsigned(w_ffitype)
+ return space.wrap(uintval)
+ elif w_ffitype.is_unsigned(): # note that ulong is handled just before
+ intval = self.get_unsigned_which_fits_into_a_signed(w_ffitype)
+ return space.wrap(intval)
+ elif w_ffitype.is_pointer():
+ uintval = self.get_pointer(w_ffitype)
+ return space.wrap(uintval)
+ elif w_ffitype.is_char():
+ ucharval = self.get_char(w_ffitype)
+ return space.wrap(chr(ucharval))
+ elif w_ffitype.is_unichar():
+ wcharval = self.get_unichar(w_ffitype)
+ return space.wrap(unichr(wcharval))
+ elif w_ffitype.is_double():
+ return self._float(w_ffitype)
+ elif w_ffitype.is_singlefloat():
+ return self._singlefloat(w_ffitype)
+ elif w_ffitype.is_struct():
+ w_structdescr = w_ffitype.w_structdescr
+ if isinstance(w_structdescr, W__StructDescr):
+ return self.get_struct(w_ffitype, w_structdescr)
+ elif isinstance(w_structdescr, W_Structure):
+ return self.get_struct_rawffi(w_ffitype, w_structdescr)
+ else:
+ raise OperationError(self.space.w_TypeError,
+ self.space.wrap("Unsupported struct shape"))
+ elif w_ffitype.is_void():
+ voidval = self.get_void(w_ffitype)
+ assert voidval is None
+ return space.w_None
+ else:
+ self.error(w_ffitype)
+
+ def _longlong(self, w_ffitype):
+ # a separate function, which can be seen by the jit or not,
+ # depending on whether longlongs are supported
+ if w_ffitype is app_types.slonglong:
+ longlongval = self.get_longlong(w_ffitype)
+ return self.space.wrap(longlongval)
+ elif w_ffitype is app_types.ulonglong:
+ ulonglongval = self.get_ulonglong(w_ffitype)
+ return self.space.wrap(ulonglongval)
+ else:
+ self.error(w_ffitype)
+
+ def _float(self, w_ffitype):
+ # a separate function, which can be seen by the jit or not,
+ # depending on whether floats are supported
+ floatval = self.get_float(w_ffitype)
+ return self.space.wrap(floatval)
+
+ def _singlefloat(self, w_ffitype):
+ # a separate function, which can be seen by the jit or not,
+ # depending on whether singlefloats are supported
+ singlefloatval = self.get_singlefloat(w_ffitype)
+ return self.space.wrap(float(singlefloatval))
+
+ def error(self, w_ffitype):
+ raise operationerrfmt(self.space.w_TypeError,
+ 'Unsupported ffi type to convert: %s',
+ w_ffitype.name)
+
+ def get_longlong(self, w_ffitype):
+ """
+ Return type: lltype.SignedLongLong
+ """
+ self.error(w_ffitype)
+
+ def get_ulonglong(self, w_ffitype):
+ """
+ Return type: lltype.UnsignedLongLong
+ """
+ self.error(w_ffitype)
+
+ def get_signed(self, w_ffitype):
+ """
+ Return type: lltype.Signed
+ """
+ self.error(w_ffitype)
+
+ def get_unsigned(self, w_ffitype):
+ """
+ Return type: lltype.Unsigned
+ """
+ self.error(w_ffitype)
+
+ def get_unsigned_which_fits_into_a_signed(self, w_ffitype):
+ """
+ Return type: lltype.Signed.
+
+ We return Signed even if the input type is unsigned, because this way
+ we get an app-level <int> instead of a <long>.
+ """
+ self.error(w_ffitype)
+
+ def get_pointer(self, w_ffitype):
+ """
+ Return type: lltype.Unsigned
+ """
+ self.error(w_ffitype)
+
+ def get_char(self, w_ffitype):
+ """
+ Return type: rffi.UCHAR
+ """
+ self.error(w_ffitype)
+
+ def get_unichar(self, w_ffitype):
+ """
+ Return type: rffi.WCHAR_T
+ """
+ self.error(w_ffitype)
+
+ def get_float(self, w_ffitype):
+ """
+ Return type: lltype.Float
+ """
+ self.error(w_ffitype)
+
+ def get_singlefloat(self, w_ffitype):
+ """
+ Return type: lltype.SingleFloat
+ """
+ self.error(w_ffitype)
+
+ def get_struct(self, w_ffitype, w_structdescr):
+ """
+ Return type: lltype.Signed
+ (the address of the structure)
+ """
+ self.error(w_ffitype)
+
+ def get_struct_rawffi(self, w_ffitype, w_structdescr):
+ """
+ This should be killed as soon as we kill support for _rawffi structures
+
+ Return type: lltype.Unsigned
+ (the address of the structure)
+ """
+ self.error(w_ffitype)
+
+ def get_void(self, w_ffitype):
+ """
+ Return type: None
+ """
+ self.error(w_ffitype)
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
@@ -253,7 +253,7 @@
# XXX: this assumes that you have the _ffi module enabled. In the long
# term, probably we will move the code for build structures and arrays
# from _rawffi to _ffi
- from pypy.module._ffi.interp_ffi import W_FFIType
+ from pypy.module._ffi.interp_ffitype import W_FFIType
return W_FFIType('<unknown>', self.get_basic_ffi_type(), self)
@unwrap_spec(n=int)
diff --git a/pypy/module/binascii/interp_crc32.py b/pypy/module/binascii/interp_crc32.py
--- a/pypy/module/binascii/interp_crc32.py
+++ b/pypy/module/binascii/interp_crc32.py
@@ -61,7 +61,7 @@
crc_32_tab = map(r_uint, crc_32_tab)
- at unwrap_spec(data='bufferstr', oldcrc='truncatedint')
+ at unwrap_spec(data='bufferstr', oldcrc='truncatedint_w')
def crc32(space, data, oldcrc=0):
"Compute the CRC-32 incrementally."
diff --git a/pypy/module/micronumpy/signature.py b/pypy/module/micronumpy/signature.py
--- a/pypy/module/micronumpy/signature.py
+++ b/pypy/module/micronumpy/signature.py
@@ -441,7 +441,11 @@
ofs = frame.iterators[0].offset
arr.left.setitem(ofs, self.right.eval(frame, arr.right).convert_to(
self.calc_dtype))
-
+
+ def _invent_numbering(self, cache, allnumbers):
+ self.left._invent_numbering(new_cache(), allnumbers)
+ self.right._invent_numbering(cache, allnumbers)
+
def debug_repr(self):
return 'SliceLoop(%s, %s, %s)' % (self.name, self.left.debug_repr(),
self.right.debug_repr())
diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py
--- a/pypy/module/micronumpy/test/test_dtypes.py
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -212,6 +212,30 @@
b = array([0] * 10, dtype=int64)
for idx in b: a[idx] += 1
+ def test_hash_int8(self):
+ from _numpypy import int8
+
+ hash(int8(0))
+ d = {int8(5):99}
+
+ def test_hash_int16(self):
+ from _numpypy import int16
+
+ hash(int16(0))
+ d = {int16(99):42}
+
+ def test_hash_int32(self):
+ from _numpypy import int32
+
+ hash(int32(0))
+ d = {int32(5):99}
+
+ def test_hash_int64(self):
+ from _numpypy import int64
+
+ hash(int64(0))
+ d = {int64(99):42}
+
class AppTestTypes(BaseNumpyAppTest):
def test_abstract_types(self):
import _numpypy as numpy
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -1530,6 +1530,12 @@
# test virtual
assert ((x + x).swapaxes(0,1) == array([[[ 2, 4, 6], [14, 16, 18]],
[[ 8, 10, 12], [20, 22, 24]]])).all()
+
+ def test_filter_bug(self):
+ from numpypy import array
+ a = array([1.0,-1.0])
+ a[a<0] = -a[a<0]
+ assert (a == [1, 1]).all()
class AppTestMultiDim(BaseNumpyAppTest):
def test_init(self):
diff --git a/pypy/module/posix/__init__.py b/pypy/module/posix/__init__.py
--- a/pypy/module/posix/__init__.py
+++ b/pypy/module/posix/__init__.py
@@ -86,6 +86,8 @@
'_exit' : 'interp_posix._exit',
'utime' : 'interp_posix.utime',
'_statfields': 'interp_posix.getstatfields(space)',
+ 'kill' : 'interp_posix.kill',
+ 'abort' : 'interp_posix.abort',
}
if os.name == 'nt':
@@ -107,9 +109,6 @@
interpleveldefs['putenv'] = 'interp_posix.putenv'
if hasattr(posix, 'unsetenv'): # note: emulated in os
interpleveldefs['unsetenv'] = 'interp_posix.unsetenv'
- if hasattr(os, 'kill') and sys.platform != 'win32':
- interpleveldefs['kill'] = 'interp_posix.kill'
- interpleveldefs['abort'] = 'interp_posix.abort'
if hasattr(os, 'killpg'):
interpleveldefs['killpg'] = 'interp_posix.killpg'
if hasattr(os, 'getpid'):
diff --git a/pypy/module/posix/app_posix.py b/pypy/module/posix/app_posix.py
--- a/pypy/module/posix/app_posix.py
+++ b/pypy/module/posix/app_posix.py
@@ -1,5 +1,6 @@
# NOT_RPYTHON
from _structseq import structseqtype, structseqfield
+from __pypy__ import validate_fd
# XXX we need a way to access the current module's globals more directly...
import sys
@@ -73,9 +74,7 @@
except IOError as e:
raise OSError(e.errno, e.strerror, e.filename)
else:
- def _validate_fd(fd):
- # XXX for the moment
- return
+ _validate_fd = validate_fd
if osname == 'posix':
def wait():
diff --git a/pypy/module/posix/interp_posix.py b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -621,7 +621,7 @@
def kill(space, pid, sig):
"Kill a process with a signal."
try:
- os.kill(pid, sig)
+ rposix.os_kill(pid, sig)
except OSError, e:
raise wrap_oserror(space, e)
@@ -637,7 +637,7 @@
"""Abort the interpreter immediately. This 'dumps core' or otherwise fails
in the hardest way possible on the hosting operating system."""
import signal
- os.kill(os.getpid(), signal.SIGABRT)
+ rposix.os_kill(os.getpid(), signal.SIGABRT)
@unwrap_spec(src='str0', dst='str0')
def link(space, src, dst):
@@ -747,22 +747,7 @@
path: path of executable file
args: iterable of strings
"""
- command = fsencode_w(space, w_command)
- try:
- args_w = space.unpackiterable(w_args)
- if len(args_w) < 1:
- w_msg = space.wrap("execv() must have at least one argument")
- raise OperationError(space.w_ValueError, w_msg)
- args = [fsencode_w(space, w_arg) for w_arg in args_w]
- except OperationError, e:
- if not e.match(space, space.w_TypeError):
- raise
- msg = "execv() arg 2 must be an iterable of strings"
- raise OperationError(space.w_TypeError, space.wrap(str(msg)))
- try:
- os.execv(command, args)
- except OSError, e:
- raise wrap_oserror(space, e)
+ execve(space, w_command, w_args, None)
def _env2interp(space, w_env):
env = {}
@@ -782,12 +767,29 @@
env: dictionary of strings mapping to strings
"""
command = fsencode_w(space, w_command)
- args = [fsencode_w(space, w_arg) for w_arg in space.unpackiterable(w_args)]
- env = _env2interp(space, w_env)
try:
- os.execve(command, args, env)
- except OSError, e:
- raise wrap_oserror(space, e)
+ args_w = space.unpackiterable(w_args)
+ if len(args_w) < 1:
+ w_msg = space.wrap("execv() must have at least one argument")
+ raise OperationError(space.w_ValueError, w_msg)
+ args = [fsencode_w(space, w_arg) for w_arg in args_w]
+ except OperationError, e:
+ if not e.match(space, space.w_TypeError):
+ raise
+ msg = "execv() arg 2 must be an iterable of strings"
+ raise OperationError(space.w_TypeError, space.wrap(str(msg)))
+ #
+ if w_env is None: # when called via execv() above
+ try:
+ os.execv(command, args)
+ except OSError, e:
+ raise wrap_oserror(space, e)
+ else:
+ env = _env2interp(space, w_env)
+ try:
+ os.execve(command, args, env)
+ except OSError, e:
+ raise wrap_oserror(space, e)
@unwrap_spec(mode=int, path='str0')
def spawnv(space, mode, path, w_args):
diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -384,6 +384,7 @@
def test_execv_no_args(self):
os = self.posix
raises(ValueError, os.execv, "notepad", [])
+ raises(ValueError, os.execve, "notepad", [], {})
def test_execv_raising2(self):
os = self.posix
@@ -454,12 +455,11 @@
if hasattr(__import__(os.name), "spawnve"):
def test_spawnve(self):
os = self.posix
- import sys
- print(self.python)
+ env = {'PATH':os.environ['PATH'], 'FOOBAR': '42'}
ret = os.spawnve(os.P_WAIT, self.python,
['python', '-c',
"raise(SystemExit(int(__import__('os').environ['FOOBAR'])))"],
- {'FOOBAR': '42'})
+ env)
assert ret == 42
if hasattr(__import__(os.name), '_getfullpathname'):
@@ -839,6 +839,71 @@
# How else could we test that getlogin is properly
# working?
+ def test_tmpfile(self):
+ os = self.posix
+ f = os.tmpfile()
+ f.write("xxx")
+ f.flush()
+ f.seek(0, 0)
+ assert isinstance(f, file)
+ assert f.read() == 'xxx'
+
+ def test_tmpnam(self):
+ import stat, os
+ s1 = os.tmpnam()
+ s2 = os.tmpnam()
+ assert s1 != s2
+ def isdir(s):
+ try:
+ return stat.S_ISDIR(os.stat(s).st_mode)
+ except OSError:
+ return -1
+ assert isdir(s1) == -1
+ assert isdir(s2) == -1
+ assert isdir(os.path.dirname(s1)) == 1
+ assert isdir(os.path.dirname(s2)) == 1
+
+ def test_tempnam(self):
+ import stat, os
+ for dir in [None, self.udir]:
+ for prefix in [None, 'foobar']:
+ s1 = os.tempnam(dir, prefix)
+ s2 = os.tempnam(dir, prefix)
+ assert s1 != s2
+ def isdir(s):
+ try:
+ return stat.S_ISDIR(os.stat(s).st_mode)
+ except OSError:
+ return -1
+ assert isdir(s1) == -1
+ assert isdir(s2) == -1
+ assert isdir(os.path.dirname(s1)) == 1
+ assert isdir(os.path.dirname(s2)) == 1
+ if dir:
+ assert os.path.dirname(s1) == dir
+ assert os.path.dirname(s2) == dir
+ assert os.path.basename(s1).startswith(prefix or 'tmp')
+ assert os.path.basename(s2).startswith(prefix or 'tmp')
+
+ def test_tmpnam_warning(self):
+ import warnings, os
+ #
+ def f_tmpnam_warning(): os.tmpnam() # a single line
+ #
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter("always")
+ f_tmpnam_warning()
+ assert len(w) == 1
+ assert issubclass(w[-1].category, RuntimeWarning)
+ assert "potential security risk" in str(w[-1].message)
+ # check that the warning points to the call to os.tmpnam(),
+ # not to some code inside app_posix.py
+ assert w[-1].lineno == f_tmpnam_warning.func_code.co_firstlineno
+
+ def test_has_kill(self):
+ import os
+ assert hasattr(os, 'kill')
+
class AppTestEnvironment(object):
def setup_class(cls):
cls.space = space
diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
@@ -134,3 +134,31 @@
call = ops[idx]
assert (call.args[0] == 'ConstClass(fabs)' or # e.g. OS/X
int(call.args[0]) == fabs_addr)
+
+
+ def test__ffi_struct(self):
+ def main():
+ from _ffi import _StructDescr, Field, types
+ fields = [
+ Field('x', types.slong),
+ ]
+ descr = _StructDescr('foo', fields)
+ struct = descr.allocate()
+ i = 0
+ while i < 300:
+ x = struct.getfield('x') # ID: getfield
+ x = x+1
+ struct.setfield('x', x) # ID: setfield
+ i += 1
+ return struct.getfield('x')
+ #
+ log = self.run(main, [])
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match_by_id('getfield', """
+ guard_not_invalidated(descr=...)
+ i57 = getfield_raw(i46, descr=<FieldS dynamic 0>)
+ """)
+ assert loop.match_by_id('setfield', """
+ setfield_raw(i44, i57, descr=<FieldS dynamic 0>)
+ """)
+
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -131,6 +131,36 @@
jump(..., descr=...)
""")
+ def test_xrange_iter(self):
+ def main(n):
+ def g(n):
+ return xrange(n)
+ s = 0
+ for i in xrange(n): # ID: for
+ tmp = g(n)
+ s += tmp[i] # ID: getitem
+ a = 0
+ return s
+ #
+ log = self.run(main, [1000])
+ assert log.result == 1000 * 999 / 2
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i15 = int_lt(i10, i11)
+ guard_true(i15, descr=...)
+ i17 = int_add(i10, 1)
+ i18 = force_token()
+ setfield_gc(p9, i17, descr=<.* .*W_XRangeIterator.inst_current .*>)
+ guard_not_invalidated(descr=...)
+ i21 = int_lt(i10, 0)
+ guard_false(i21, descr=...)
+ i22 = int_lt(i10, i14)
+ guard_true(i22, descr=...)
+ i23 = int_add_ovf(i6, i10)
+ guard_no_overflow(descr=...)
+ --TICK--
+ jump(..., descr=...)
+ """)
def test_range_iter(self):
def main(n):
diff --git a/pypy/module/select/interp_kqueue.py b/pypy/module/select/interp_kqueue.py
--- a/pypy/module/select/interp_kqueue.py
+++ b/pypy/module/select/interp_kqueue.py
@@ -3,6 +3,7 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef, generic_new_descr, GetSetProperty
from pypy.rlib._rsocket_rffi import socketclose
+from pypy.rlib.rarithmetic import r_uint
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.rpython.tool import rffi_platform
from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -226,9 +227,12 @@
if self.event:
lltype.free(self.event, flavor="raw")
- @unwrap_spec(filter=int, flags='c_uint', fflags='c_uint', data=int, udata='c_uint')
- def descr__init__(self, space, w_ident, filter=KQ_FILTER_READ, flags=KQ_EV_ADD, fflags=0, data=0, udata=0):
- ident = space.c_filedescriptor_w(w_ident)
+ @unwrap_spec(filter=int, flags='c_uint', fflags='c_uint', data=int, udata=r_uint)
+ def descr__init__(self, space, w_ident, filter=KQ_FILTER_READ, flags=KQ_EV_ADD, fflags=0, data=0, udata=r_uint(0)):
+ if space.isinstance_w(w_ident, space.w_long):
+ ident = space.uint_w(w_ident)
+ else:
+ ident = r_uint(space.c_filedescriptor_w(w_ident))
self.event = lltype.malloc(kevent, flavor="raw")
rffi.setintfield(self.event, "c_ident", ident)
@@ -320,7 +324,7 @@
return space.wrap(self.event.c_data)
def descr_get_udata(self, space):
- return space.wrap(rffi.cast(rffi.SIZE_T, self.event.c_udata))
+ return space.wrap(rffi.cast(rffi.UINTPTR_T, self.event.c_udata))
W_Kevent.typedef = TypeDef("select.kevent",
diff --git a/pypy/module/select/interp_select.py b/pypy/module/select/interp_select.py
--- a/pypy/module/select/interp_select.py
+++ b/pypy/module/select/interp_select.py
@@ -74,6 +74,32 @@
pollmethods[methodname] = interp2app(getattr(Poll, methodname))
Poll.typedef = TypeDef('select.poll', **pollmethods)
+# ____________________________________________________________
+
+
+from pypy.rlib import _rsocket_rffi as _c
+from pypy.rpython.lltypesystem import lltype, rffi
+
+
+def _build_fd_set(space, list_w, ll_list, nfds):
+ _c.FD_ZERO(ll_list)
+ fdlist = []
+ for w_f in list_w:
+ fd = space.c_filedescriptor_w(w_f)
+ if fd > nfds:
+ nfds = fd
+ _c.FD_SET(fd, ll_list)
+ fdlist.append(fd)
+ return fdlist, nfds
+_build_fd_set._always_inline_ = True # get rid of the tuple result
+
+def _unbuild_fd_set(space, list_w, fdlist, ll_list, reslist_w):
+ for i in range(len(fdlist)):
+ fd = fdlist[i]
+ if _c.FD_ISSET(fd, ll_list):
+ reslist_w.append(list_w[i])
+
+
def select(space, w_iwtd, w_owtd, w_ewtd, w_timeout=None):
"""Wait until one or more file descriptors are ready for some kind of I/O.
The first three arguments are sequences of file descriptors to be waited for:
@@ -99,29 +125,62 @@
iwtd_w = space.listview(w_iwtd)
owtd_w = space.listview(w_owtd)
ewtd_w = space.listview(w_ewtd)
- iwtd = [space.c_filedescriptor_w(w_f) for w_f in iwtd_w]
- owtd = [space.c_filedescriptor_w(w_f) for w_f in owtd_w]
- ewtd = [space.c_filedescriptor_w(w_f) for w_f in ewtd_w]
- iwtd_d = {}
- owtd_d = {}
- ewtd_d = {}
- for i in range(len(iwtd)):
- iwtd_d[iwtd[i]] = iwtd_w[i]
- for i in range(len(owtd)):
- owtd_d[owtd[i]] = owtd_w[i]
- for i in range(len(ewtd)):
- ewtd_d[ewtd[i]] = ewtd_w[i]
+
+ ll_inl = lltype.nullptr(_c.fd_set.TO)
+ ll_outl = lltype.nullptr(_c.fd_set.TO)
+ ll_errl = lltype.nullptr(_c.fd_set.TO)
+ ll_timeval = lltype.nullptr(_c.timeval)
+
try:
+ fdlistin = None
+ fdlistout = None
+ fdlisterr = None
+ nfds = -1
+ if len(iwtd_w) > 0:
+ ll_inl = lltype.malloc(_c.fd_set.TO, flavor='raw')
+ fdlistin, nfds = _build_fd_set(space, iwtd_w, ll_inl, nfds)
+ if len(owtd_w) > 0:
+ ll_outl = lltype.malloc(_c.fd_set.TO, flavor='raw')
+ fdlistout, nfds = _build_fd_set(space, owtd_w, ll_outl, nfds)
+ if len(ewtd_w) > 0:
+ ll_errl = lltype.malloc(_c.fd_set.TO, flavor='raw')
+ fdlisterr, nfds = _build_fd_set(space, ewtd_w, ll_errl, nfds)
+
if space.is_w(w_timeout, space.w_None):
- iwtd, owtd, ewtd = rpoll.select(iwtd, owtd, ewtd)
+ timeout = -1.0
else:
- iwtd, owtd, ewtd = rpoll.select(iwtd, owtd, ewtd, space.float_w(w_timeout))
- except rpoll.SelectError, s:
- w_errortype = space.fromcache(Cache).w_error
- raise OperationError(w_errortype, space.newtuple([
- space.wrap(s.errno), space.wrap(s.get_msg())]))
+ timeout = space.float_w(w_timeout)
+ if timeout >= 0.0:
+ ll_timeval = rffi.make(_c.timeval)
+ i = int(timeout)
+ rffi.setintfield(ll_timeval, 'c_tv_sec', i)
+ rffi.setintfield(ll_timeval, 'c_tv_usec', int((timeout-i)*1000000))
- return space.newtuple([
- space.newlist([iwtd_d[i] for i in iwtd]),
- space.newlist([owtd_d[i] for i in owtd]),
- space.newlist([ewtd_d[i] for i in ewtd])])
+ res = _c.select(nfds + 1, ll_inl, ll_outl, ll_errl, ll_timeval)
+
+ if res < 0:
+ errno = _c.geterrno()
+ msg = _c.socket_strerror_str(errno)
+ w_errortype = space.fromcache(Cache).w_error
+ raise OperationError(w_errortype, space.newtuple([
+ space.wrap(errno), space.wrap(msg)]))
+
+ resin_w = []
+ resout_w = []
+ reserr_w = []
+ if res > 0:
+ if fdlistin is not None:
+ _unbuild_fd_set(space, iwtd_w, fdlistin, ll_inl, resin_w)
+ if fdlistout is not None:
+ _unbuild_fd_set(space, owtd_w, fdlistout, ll_outl, resout_w)
+ if fdlisterr is not None:
+ _unbuild_fd_set(space, ewtd_w, fdlisterr, ll_errl, reserr_w)
+ finally:
+ if ll_timeval: lltype.free(ll_timeval, flavor='raw')
+ if ll_errl: lltype.free(ll_errl, flavor='raw')
+ if ll_outl: lltype.free(ll_outl, flavor='raw')
+ if ll_inl: lltype.free(ll_inl, flavor='raw')
+
+ return space.newtuple([space.newlist(resin_w),
+ space.newlist(resout_w),
+ space.newlist(reserr_w)])
diff --git a/pypy/module/select/test/test_kqueue.py b/pypy/module/select/test/test_kqueue.py
--- a/pypy/module/select/test/test_kqueue.py
+++ b/pypy/module/select/test/test_kqueue.py
@@ -100,7 +100,7 @@
client.setblocking(False)
try:
client.connect(("127.0.0.1", server_socket.getsockname()[1]))
- except socket.error as e:
+ except socket.error, e:
if 'bsd' in sys.platform:
assert e.args[0] == errno.ENOENT
else:
diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -16,7 +16,8 @@
def setup():
for key, value in cpy_signal.__dict__.items():
if (key.startswith('SIG') or key.startswith('CTRL_')) and \
- is_valid_int(value):
+ is_valid_int(value) and \
+ key != 'SIG_DFL' and key != 'SIG_IGN':
globals()[key] = value
yield key
@@ -24,11 +25,18 @@
SIG_DFL = cpy_signal.SIG_DFL
SIG_IGN = cpy_signal.SIG_IGN
signal_names = list(setup())
-signal_values = [globals()[key] for key in signal_names]
signal_values = {}
for key in signal_names:
signal_values[globals()[key]] = None
-
+if sys.platform == 'win32' and not hasattr(cpy_signal,'CTRL_C_EVENT'):
+ # XXX Hack to revive values that went missing,
+ # Remove this once we are sure the host cpy module has them.
+ signal_values[0] = None
+ signal_values[1] = None
+ signal_names.append('CTRL_C_EVENT')
+ signal_names.append('CTRL_BREAK_EVENT')
+ CTRL_C_EVENT = 0
+ CTRL_BREAK_EVENT = 1
includes = ['stdlib.h', 'src/signals.h']
if sys.platform != 'win32':
includes.append('sys/time.h')
diff --git a/pypy/module/signal/test/test_signal.py b/pypy/module/signal/test/test_signal.py
--- a/pypy/module/signal/test/test_signal.py
+++ b/pypy/module/signal/test/test_signal.py
@@ -43,7 +43,11 @@
cls.w_signal = space.appexec([], "(): import signal; return signal")
def test_exported_names(self):
+ import os
self.signal.__dict__ # crashes if the interpleveldefs are invalid
+ if os.name == 'nt':
+ assert self.signal.CTRL_BREAK_EVENT == 1
+ assert self.signal.CTRL_C_EVENT == 0
def test_basics(self):
import types, os
@@ -61,8 +65,6 @@
received.append(signum)
signal.signal(signum, myhandler)
- print dir(os)
-
os.kill(os.getpid(), signum)
# the signal should be delivered to the handler immediately
assert received == [signum]
diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py
--- a/pypy/module/sys/version.py
+++ b/pypy/module/sys/version.py
@@ -7,7 +7,8 @@
from pypy.interpreter import gateway
#XXX # the release serial 42 is not in range(16)
-CPYTHON_VERSION = (3, 2, 2, "final", 0) #XXX # sync patchlevel.h
+CPYTHON_VERSION = (3, 2, 2, "final", 0)
+#XXX # sync CPYTHON_VERSION with patchlevel.h, package.py
CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h
PYPY_VERSION = (1, 9, 1, "dev", 0) #XXX # sync patchlevel.h
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c b/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c
--- a/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c
+++ b/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c
@@ -14,6 +14,7 @@
#include <string.h>
#include <wchar.h>
#include <stdio.h>
+#include <errno.h>
#define HAVE_LONG_LONG
#define LONG_LONG long long
@@ -559,3 +560,10 @@
{
return 42;
}
+
+EXPORT(int) test_errno(void)
+{
+ int result = errno;
+ errno = result + 1;
+ return result;
+}
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_errno.py b/pypy/module/test_lib_pypy/ctypes_tests/test_errno.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_errno.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_errno.py
@@ -19,3 +19,5 @@
f._call_funcptr(check)
assert _rawffi.get_errno() == old
ctypes.set_errno(0)
+
+ # see also test_functions.test_errno
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
@@ -5,6 +5,7 @@
Later...
"""
+from __future__ import with_statement
from ctypes import *
import sys
import py
@@ -20,7 +21,7 @@
def setup_module(mod):
import conftest
_ctypes_test = str(conftest.sofile)
- mod.dll = CDLL(_ctypes_test)
+ mod.dll = CDLL(_ctypes_test, use_errno=True)
if sys.platform == "win32":
mod.windll = WinDLL(_ctypes_test)
@@ -521,3 +522,12 @@
assert len(w) == 0
warnings.resetwarnings()
+
+
+ def test_errno(self):
+ test_errno = dll.test_errno
+ test_errno.restype = c_int
+ set_errno(42)
+ res = test_errno()
+ n = get_errno()
+ assert (res, n) == (42, 43)
diff --git a/pypy/module/unicodedata/generate_unicodedb.py b/pypy/module/unicodedata/generate_unicodedb.py
--- a/pypy/module/unicodedata/generate_unicodedb.py
+++ b/pypy/module/unicodedata/generate_unicodedb.py
@@ -430,9 +430,19 @@
print >> outfile, 'version = %r' % version
print >> outfile
- cjk_end = 0x9FA5
- if version >= "4.1":
- cjk_end = 0x9FBB
+ if version < "4.1":
+ cjk_interval = ("(0x3400 <= code <= 0x4DB5 or"
+ " 0x4E00 <= code <= 0x9FA5 or"
+ " 0x20000 <= code <= 0x2A6D6)")
+ elif version < "5": # don't know the exact limit
+ cjk_interval = ("(0x3400 <= code <= 0x4DB5 or"
+ " 0x4E00 <= code <= 0x9FBB or"
+ " 0x20000 <= code <= 0x2A6D6)")
+ else:
+ cjk_interval = ("(0x3400 <= code <= 0x4DB5 or"
+ " 0x4E00 <= code <= 0x9FCB or"
+ " 0x20000 <= code <= 0x2A6D6 or"
+ " 0x2A700 <= code <= 0x2B734)")
write_character_names(outfile, table, base_mod)
@@ -488,9 +498,7 @@
if not ('0' <= c <= '9' or 'A' <= c <= 'F'):
raise KeyError
code = int(cjk_code, 16)
- if (0x3400 <= code <= 0x4DB5 or
- 0x4E00 <= code <= 0x%X or
- 0x20000 <= code <= 0x2A6D6):
+ if %s:
return code
raise KeyError
@@ -512,9 +520,7 @@
raise
def name(code):
- if (0x3400 <= code <= 0x4DB5 or
- 0x4E00 <= code <= 0x%X or
- 0x20000 <= code <= 0x2A6D6):
+ if %s:
return "CJK UNIFIED IDEOGRAPH-" + hex(code)[2:].upper()
if 0xAC00 <= code <= 0xD7A3:
# vl_code, t_code = divmod(code - 0xAC00, len(_hangul_T))
@@ -536,7 +542,7 @@
return base_mod.lookup_charcode(code)
else:
raise
-''' % (cjk_end, cjk_end)
+''' % (cjk_interval, cjk_interval)
# Categories
writeDbRecord(outfile, table)
diff --git a/pypy/module/unicodedata/test/test_unicodedata.py b/pypy/module/unicodedata/test/test_unicodedata.py
--- a/pypy/module/unicodedata/test/test_unicodedata.py
+++ b/pypy/module/unicodedata/test/test_unicodedata.py
@@ -53,7 +53,12 @@
import unicodedata
cases = ((0x3400, 0x4DB5),
(0x4E00, 0x9FA5))
- if unicodedata.unidata_version >= "4.1":
+ if unicodedata.unidata_version >= "5": # don't know the exact limit
+ cases = ((0x3400, 0x4DB5),
+ (0x4E00, 0x9FCB),
+ (0x20000, 0x2A6D6),
+ (0x2A700, 0x2B734))
+ elif unicodedata.unidata_version >= "4.1":
cases = ((0x3400, 0x4DB5),
(0x4E00, 0x9FBB),
(0x20000, 0x2A6D6))
diff --git a/pypy/module/unicodedata/unicodedb_5_2_0.py b/pypy/module/unicodedata/unicodedb_5_2_0.py
--- a/pypy/module/unicodedata/unicodedb_5_2_0.py
+++ b/pypy/module/unicodedata/unicodedb_5_2_0.py
@@ -134464,9 +134464,7 @@
if not ('0' <= c <= '9' or 'A' <= c <= 'F'):
raise KeyError
code = int(cjk_code, 16)
- if (0x3400 <= code <= 0x4DB5 or
- 0x4E00 <= code <= 0x9FBB or
- 0x20000 <= code <= 0x2A6D6):
+ if (0x3400 <= code <= 0x4DB5 or 0x4E00 <= code <= 0x9FCB or 0x20000 <= code <= 0x2A6D6 or 0x2A700 <= code <= 0x2B734):
return code
raise KeyError
@@ -134488,9 +134486,7 @@
raise
def name(code):
- if (0x3400 <= code <= 0x4DB5 or
- 0x4E00 <= code <= 0x9FBB or
- 0x20000 <= code <= 0x2A6D6):
+ if (0x3400 <= code <= 0x4DB5 or 0x4E00 <= code <= 0x9FCB or 0x20000 <= code <= 0x2A6D6 or 0x2A700 <= code <= 0x2B734):
return "CJK UNIFIED IDEOGRAPH-" + hex(code)[2:].upper()
if 0xAC00 <= code <= 0xD7A3:
# vl_code, t_code = divmod(code - 0xAC00, len(_hangul_T))
diff --git a/pypy/module/zlib/interp_zlib.py b/pypy/module/zlib/interp_zlib.py
--- a/pypy/module/zlib/interp_zlib.py
+++ b/pypy/module/zlib/interp_zlib.py
@@ -20,7 +20,7 @@
return intmask((x ^ SIGN_EXTEND2) - SIGN_EXTEND2)
- at unwrap_spec(string='bufferstr', start='truncatedint')
+ at unwrap_spec(string='bufferstr', start='truncatedint_w')
def crc32(space, string, start = rzlib.CRC32_DEFAULT_START):
"""
crc32(string[, start]) -- Compute a CRC-32 checksum of string.
@@ -41,7 +41,7 @@
return space.wrap(checksum)
- at unwrap_spec(string='bufferstr', start='truncatedint')
+ at unwrap_spec(string='bufferstr', start='truncatedint_w')
def adler32(space, string, start=rzlib.ADLER32_DEFAULT_START):
"""
adler32(string[, start]) -- Compute an Adler-32 checksum of string.
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -55,6 +55,9 @@
from pypy.rlib.rbigint import rbigint
return rbigint.fromint(NonConstant(42))
+class W_MyType(W_MyObject):
+ def __init__(self):
+ self.mro_w = [w_some_obj(), w_some_obj()]
def w_some_obj():
if NonConstant(False):
@@ -66,6 +69,9 @@
return None
return w_some_obj()
+def w_some_type():
+ return W_MyType()
+
def is_root(w_obj):
assert isinstance(w_obj, W_Root)
is_root.expecting = W_Root
@@ -224,6 +230,9 @@
assert typedef is not None
return self.fromcache(TypeCache).getorbuild(typedef)
+ def type(self, w_obj):
+ return w_some_type()
+
def unpackiterable(self, w_iterable, expected_length=-1):
is_root(w_iterable)
if expected_length < 0:
@@ -291,10 +300,13 @@
ObjSpace.ExceptionTable +
['int', 'str', 'float', 'long', 'tuple', 'list',
'dict', 'bytes', 'complex', 'slice', 'bool',
- 'type', 'text', 'object', 'unicode']):
+ 'text', 'object', 'unicode']):
setattr(FakeObjSpace, 'w_' + name, w_some_obj())
+ FakeObjSpace.w_type = w_some_type()
#
for (name, _, arity, _) in ObjSpace.MethodTable:
+ if name == 'type':
+ continue
args = ['w_%d' % i for i in range(arity)]
params = args[:]
d = {'is_root': is_root,
diff --git a/pypy/objspace/fake/test/test_checkmodule.py b/pypy/objspace/fake/test/test_checkmodule.py
--- a/pypy/objspace/fake/test/test_checkmodule.py
+++ b/pypy/objspace/fake/test/test_checkmodule.py
@@ -1,9 +1,9 @@
-import py
+
from pypy.objspace.fake.objspace import FakeObjSpace, is_root
from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.interpreter.gateway import interp2app, W_Root, ObjSpace
-
+from pypy.rpython.test.test_llinterp import interpret
def make_checker():
check = []
@@ -61,3 +61,18 @@
assert not check
space.translates()
assert check
+
+def test_gettype_mro_untranslated():
+ space = FakeObjSpace()
+ w_type = space.type(space.wrap(1))
+ assert len(w_type.mro_w) == 2
+
+def test_gettype_mro():
+ space = FakeObjSpace()
+
+ def f(i):
+ w_x = space.wrap(i)
+ w_type = space.type(w_x)
+ return len(w_type.mro_w)
+
+ assert interpret(f, [1]) == 2
diff --git a/pypy/objspace/std/test/test_stdobjspace.py b/pypy/objspace/std/test/test_stdobjspace.py
--- a/pypy/objspace/std/test/test_stdobjspace.py
+++ b/pypy/objspace/std/test/test_stdobjspace.py
@@ -74,3 +74,20 @@
space = gettestobjspace(withstrbuf=True)
cls = space._get_interplevel_cls(space.w_str)
assert cls is W_AbstractStringObject
+
+ def test_wrap_various_unsigned_types(self):
+ import sys
+ from pypy.rpython.lltypesystem import lltype, rffi
+ space = self.space
+ value = sys.maxint * 2
+ x = rffi.cast(lltype.Unsigned, value)
+ assert space.eq_w(space.wrap(value), space.wrap(x))
+ x = rffi.cast(rffi.UINTPTR_T, value)
+ assert x > 0
+ assert space.eq_w(space.wrap(value), space.wrap(x))
+ value = 60000
+ x = rffi.cast(rffi.USHORT, value)
+ assert space.eq_w(space.wrap(value), space.wrap(x))
+ value = 200
+ x = rffi.cast(rffi.UCHAR, value)
+ assert space.eq_w(space.wrap(value), space.wrap(x))
diff --git a/pypy/rlib/_rsocket_rffi.py b/pypy/rlib/_rsocket_rffi.py
--- a/pypy/rlib/_rsocket_rffi.py
+++ b/pypy/rlib/_rsocket_rffi.py
@@ -58,12 +58,12 @@
header_lines = [
'#include <WinSock2.h>',
'#include <WS2tcpip.h>',
- '#include <Mstcpip.h>',
# winsock2 defines AF_UNIX, but not sockaddr_un
'#undef AF_UNIX',
]
if _MSVC:
header_lines.extend([
+ '#include <Mstcpip.h>',
# these types do not exist on microsoft compilers
'typedef int ssize_t;',
'typedef unsigned __int16 uint16_t;',
@@ -71,7 +71,6 @@
])
else: # MINGW
includes = ('stdint.h',)
- """
header_lines.extend([
'''\
#ifndef _WIN32_WINNT
@@ -89,7 +88,6 @@
u_long keepaliveinterval;
};'''
])
- """
HEADER = '\n'.join(header_lines)
COND_HEADER = ''
constants = {}
diff --git a/pypy/rlib/clibffi.py b/pypy/rlib/clibffi.py
--- a/pypy/rlib/clibffi.py
+++ b/pypy/rlib/clibffi.py
@@ -11,6 +11,7 @@
from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal
from pypy.rlib.rdynload import DLOpenError, DLLHANDLE
from pypy.rlib import jit
+from pypy.rlib.objectmodel import specialize
from pypy.tool.autopath import pypydir
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.translator.platform import platform
@@ -141,6 +142,7 @@
FFI_TYPE_P = lltype.Ptr(lltype.ForwardReference())
FFI_TYPE_PP = rffi.CArrayPtr(FFI_TYPE_P)
+FFI_TYPE_NULL = lltype.nullptr(FFI_TYPE_P.TO)
class CConfig:
_compilation_info_ = eci
@@ -346,11 +348,13 @@
('ffistruct', FFI_TYPE_P.TO),
('members', lltype.Array(FFI_TYPE_P))))
-def make_struct_ffitype_e(size, aligment, field_types):
+ at specialize.arg(3)
+def make_struct_ffitype_e(size, aligment, field_types, track_allocation=True):
"""Compute the type of a structure. Returns a FFI_STRUCT_P out of
which the 'ffistruct' member is a regular FFI_TYPE.
"""
- tpe = lltype.malloc(FFI_STRUCT_P.TO, len(field_types)+1, flavor='raw')
+ tpe = lltype.malloc(FFI_STRUCT_P.TO, len(field_types)+1, flavor='raw',
+ track_allocation=track_allocation)
tpe.ffistruct.c_type = rffi.cast(rffi.USHORT, FFI_TYPE_STRUCT)
tpe.ffistruct.c_size = rffi.cast(rffi.SIZE_T, size)
tpe.ffistruct.c_alignment = rffi.cast(rffi.USHORT, aligment)
diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py
--- a/pypy/rlib/libffi.py
+++ b/pypy/rlib/libffi.py
@@ -210,7 +210,7 @@
_immutable_fields_ = ['funcsym']
argtypes = []
- restype = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+ restype = clibffi.FFI_TYPE_NULL
flags = 0
funcsym = lltype.nullptr(rffi.VOIDP.TO)
@@ -416,6 +416,96 @@
def getaddressindll(self, name):
return dlsym(self.lib, name)
+# ======================================================================
+
+ at jit.oopspec('libffi_struct_getfield(ffitype, addr, offset)')
+def struct_getfield_int(ffitype, addr, offset):
+ """
+ Return the field of type ``ffitype`` at ``addr+offset``, widened to
+ lltype.Signed.
+ """
+ for TYPE, ffitype2 in clibffi.ffitype_map_int_or_ptr:
+ if ffitype is ffitype2:
+ value = _struct_getfield(TYPE, addr, offset)
+ return rffi.cast(lltype.Signed, value)
+ assert False, "cannot find the given ffitype"
+
+
+ at jit.oopspec('libffi_struct_setfield(ffitype, addr, offset, value)')
+def struct_setfield_int(ffitype, addr, offset, value):
+ """
+ Set the field of type ``ffitype`` at ``addr+offset``. ``value`` is of
+ type lltype.Signed, and it's automatically converted to the right type.
+ """
+ for TYPE, ffitype2 in clibffi.ffitype_map_int_or_ptr:
+ if ffitype is ffitype2:
+ value = rffi.cast(TYPE, value)
+ _struct_setfield(TYPE, addr, offset, value)
+ return
+ assert False, "cannot find the given ffitype"
+
+
+ at jit.oopspec('libffi_struct_getfield(ffitype, addr, offset)')
+def struct_getfield_longlong(ffitype, addr, offset):
+ """
+ Return the field of type ``ffitype`` at ``addr+offset``, casted to
+ lltype.LongLong.
+ """
+ value = _struct_getfield(lltype.SignedLongLong, addr, offset)
+ return value
+
+ at jit.oopspec('libffi_struct_setfield(ffitype, addr, offset, value)')
+def struct_setfield_longlong(ffitype, addr, offset, value):
+ """
+ Set the field of type ``ffitype`` at ``addr+offset``. ``value`` is of
+ type lltype.LongLong
+ """
+ _struct_setfield(lltype.SignedLongLong, addr, offset, value)
+
+
+ at jit.oopspec('libffi_struct_getfield(ffitype, addr, offset)')
+def struct_getfield_float(ffitype, addr, offset):
+ value = _struct_getfield(lltype.Float, addr, offset)
+ return value
+
+ at jit.oopspec('libffi_struct_setfield(ffitype, addr, offset, value)')
+def struct_setfield_float(ffitype, addr, offset, value):
+ _struct_setfield(lltype.Float, addr, offset, value)
+
+
+ at jit.oopspec('libffi_struct_getfield(ffitype, addr, offset)')
+def struct_getfield_singlefloat(ffitype, addr, offset):
+ value = _struct_getfield(lltype.SingleFloat, addr, offset)
+ return value
+
+ at jit.oopspec('libffi_struct_setfield(ffitype, addr, offset, value)')
+def struct_setfield_singlefloat(ffitype, addr, offset, value):
+ _struct_setfield(lltype.SingleFloat, addr, offset, value)
+
+
+ at specialize.arg(0)
+def _struct_getfield(TYPE, addr, offset):
+ """
+ Read the field of type TYPE at addr+offset.
+ addr is of type rffi.VOIDP, offset is an int.
+ """
+ addr = rffi.ptradd(addr, offset)
+ PTR_FIELD = lltype.Ptr(rffi.CArray(TYPE))
+ return rffi.cast(PTR_FIELD, addr)[0]
+
+
+ at specialize.arg(0)
+def _struct_setfield(TYPE, addr, offset, value):
+ """
+ Write the field of type TYPE at addr+offset.
+ addr is of type rffi.VOIDP, offset is an int.
+ """
+ addr = rffi.ptradd(addr, offset)
+ PTR_FIELD = lltype.Ptr(rffi.CArray(TYPE))
+ rffi.cast(PTR_FIELD, addr)[0] = value
+
+# ======================================================================
+
# These specialize.call_location's should really be specialize.arg(0), however
# you can't hash a pointer obj, which the specialize machinery wants to do.
# Given the present usage of these functions, it's good enough.
diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py
--- a/pypy/rlib/rarithmetic.py
+++ b/pypy/rlib/rarithmetic.py
@@ -97,6 +97,9 @@
# XXX TODO: replace all int(n) by long(n) and fix everything that breaks.
# XXX Then relax it and replace int(n) by n.
def intmask(n):
+ """
+ NOT_RPYTHON
+ """
if isinstance(n, objectmodel.Symbolic):
return n # assume Symbolics don't overflow
assert not isinstance(n, float)
@@ -109,6 +112,9 @@
return int(n)
def longlongmask(n):
+ """
+ NOT_RPYTHON
+ """
assert isinstance(n, (int, long))
n = long(n)
n &= LONGLONG_MASK
diff --git a/pypy/rlib/rposix.py b/pypy/rlib/rposix.py
--- a/pypy/rlib/rposix.py
+++ b/pypy/rlib/rposix.py
@@ -1,11 +1,11 @@
import os
-from pypy.rpython.lltypesystem.rffi import (CConstant, CExternVariable,
- INT, CCHARPP)
-from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi
+from pypy.rpython.lltypesystem.rffi import CConstant, CExternVariable, INT
+from pypy.rpython.lltypesystem import ll2ctypes, rffi
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.rlib.rarithmetic import intmask
from pypy.rlib.objectmodel import specialize
from pypy.rlib import jit
+from pypy.translator.platform import platform
class CConstantErrno(CConstant):
# these accessors are used when calling get_errno() or set_errno()
@@ -21,6 +21,10 @@
assert index == 0
ll2ctypes.TLS.errno = value
if os.name == 'nt':
+ if platform.name == 'msvc':
+ includes=['errno.h','stdio.h']
+ else:
+ includes=['errno.h','stdio.h', 'stdint.h']
separate_module_sources =['''
/* Lifted completely from CPython 3.3 Modules/posix_module.c */
#include <malloc.h> /* for _msize */
@@ -79,10 +83,11 @@
else:
separate_module_sources = []
export_symbols = []
+ includes=['errno.h','stdio.h']
errno_eci = ExternalCompilationInfo(
- includes=['errno.h','stdio.h'],
- separate_module_sources = separate_module_sources,
- export_symbols = export_symbols,
+ includes=includes,
+ separate_module_sources=separate_module_sources,
+ export_symbols=export_symbols,
)
_get_errno, _set_errno = CExternVariable(INT, 'errno', errno_eci,
@@ -242,6 +247,7 @@
else:
return nt._getfullpathname(path.as_bytes())
+<<<<<<< local
@specialize.argtype(0, 1)
def putenv(name, value):
if isinstance(name, str):
@@ -256,3 +262,11 @@
else:
del os.environ[name.as_bytes()]
+=======
+if os.name == 'nt':
+ from pypy.rlib import rwin32
+ os_kill = rwin32.os_kill
+else:
+ os_kill = os.kill
+
+>>>>>>> other
diff --git a/pypy/rlib/rwin32.py b/pypy/rlib/rwin32.py
--- a/pypy/rlib/rwin32.py
+++ b/pypy/rlib/rwin32.py
@@ -8,7 +8,6 @@
from pypy.translator.platform import CompilationError
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rlib.rarithmetic import intmask
-from pypy.rlib.rposix import validate_fd
from pypy.rlib import jit
import os, sys, errno
@@ -76,11 +75,25 @@
DEFAULT_LANGUAGE = rffi_platform.ConstantInteger(
"MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)")
- for name in """FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_FROM_SYSTEM
+ defines = """FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_FROM_SYSTEM
MAX_PATH
WAIT_OBJECT_0 WAIT_TIMEOUT INFINITE
ERROR_INVALID_HANDLE
- """.split():
+ DELETE READ_CONTROL SYNCHRONIZE WRITE_DAC
+ WRITE_OWNER PROCESS_ALL_ACCESS
+ PROCESS_CREATE_PROCESS PROCESS_CREATE_THREAD
+ PROCESS_DUP_HANDLE PROCESS_QUERY_INFORMATION
+ PROCESS_SET_QUOTA
+ PROCESS_SUSPEND_RESUME PROCESS_TERMINATE
+ PROCESS_VM_OPERATION PROCESS_VM_READ
+ PROCESS_VM_WRITE
+ CTRL_C_EVENT CTRL_BREAK_EVENT
+ """
+ from pypy.translator.platform import host_factory
+ static_platform = host_factory()
+ if static_platform.name == 'msvc':
+ defines += ' PROCESS_QUERY_LIMITED_INFORMATION'
+ for name in defines.split():
locals()[name] = rffi_platform.ConstantInteger(name)
for k, v in rffi_platform.configure(CConfig).items():
@@ -129,6 +142,7 @@
_get_osfhandle = rffi.llexternal('_get_osfhandle', [rffi.INT], HANDLE)
def get_osfhandle(fd):
+ from pypy.rlib.rposix import validate_fd
validate_fd(fd)
handle = _get_osfhandle(fd)
if handle == INVALID_HANDLE_VALUE:
@@ -316,4 +330,53 @@
'SetEvent', [HANDLE], BOOL)
ResetEvent = winexternal(
'ResetEvent', [HANDLE], BOOL)
+ _OpenProcess = winexternal(
+ 'OpenProcess', [DWORD, BOOL, DWORD], HANDLE)
+ def OpenProcess(*args):
+ ''' OpenProcess( dwDesiredAccess, bInheritHandle, dwProcessId)
+ where dwDesiredAccess is a combination of the flags:
+ DELETE (0x00010000L)
+ READ_CONTROL (0x00020000L)
+ SYNCHRONIZE (0x00100000L)
+ WRITE_DAC (0x00040000L)
+ WRITE_OWNER (0x00080000L)
+ PROCESS_ALL_ACCESS
+ PROCESS_CREATE_PROCESS (0x0080)
+ PROCESS_CREATE_THREAD (0x0002)
+ PROCESS_DUP_HANDLE (0x0040)
+ PROCESS_QUERY_INFORMATION (0x0400)
+ PROCESS_QUERY_LIMITED_INFORMATION (0x1000)
+ PROCESS_SET_QUOTA (0x0100)
+ PROCESS_SUSPEND_RESUME (0x0800)
+ PROCESS_TERMINATE (0x0001)
+ PROCESS_VM_OPERATION (0x0008)
+ PROCESS_VM_READ (0x0010)
+ PROCESS_VM_WRITE (0x0020)
+ SYNCHRONIZE (0x00100000L)
+ '''
+ handle = _OpenProcess(*args)
+ if handle == NULL_HANDLE:
+ raise lastWindowsError("OpenProcess")
+ return handle
+ TerminateProcess = winexternal(
+ 'TerminateProcess', [HANDLE, rffi.UINT], BOOL)
+ GenerateConsoleCtrlEvent = winexternal(
+ 'GenerateConsoleCtrlEvent', [DWORD, DWORD], BOOL)
+ _GetCurrentProcessId = winexternal(
+ 'GetCurrentProcessId', [], DWORD)
+ def GetCurrentProcessId():
+ return rffi.cast(lltype.Signed, _GetCurrentProcessId())
+ def os_kill(pid, sig):
+ if sig == CTRL_C_EVENT or sig == CTRL_BREAK_EVENT:
+ if GenerateConsoleCtrlEvent(sig, pid) == 0:
+ raise lastWindowsError('os_kill failed generating event')
+ return
+ handle = OpenProcess(PROCESS_ALL_ACCESS, False, pid)
+ if handle == NULL_HANDLE:
+ raise lastWindowsError('os_kill failed opening process')
+ try:
+ if TerminateProcess(handle, sig) == 0:
+ raise lastWindowsError('os_kill failed to terminate process')
+ finally:
+ CloseHandle(handle)
diff --git a/pypy/rlib/test/test_libffi.py b/pypy/rlib/test/test_libffi.py
--- a/pypy/rlib/test/test_libffi.py
+++ b/pypy/rlib/test/test_libffi.py
@@ -2,12 +2,16 @@
import py
-from pypy.rlib.libffi import (CDLL, Func, get_libc_name, ArgChain, types,
- IS_32_BIT, array_getitem, array_setitem)
from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong
from pypy.rlib.test.test_clibffi import BaseFfiTest, get_libm_name, make_struct_ffitype_e
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED
+from pypy.rlib.libffi import (CDLL, Func, get_libc_name, ArgChain, types,
+ IS_32_BIT, array_getitem, array_setitem)
+from pypy.rlib.libffi import (struct_getfield_int, struct_setfield_int,
+ struct_getfield_longlong, struct_setfield_longlong,
+ struct_getfield_float, struct_setfield_float,
+ struct_getfield_singlefloat, struct_setfield_singlefloat)
class TestLibffiMisc(BaseFfiTest):
@@ -54,6 +58,33 @@
del lib
assert not ALLOCATED
+ def test_struct_fields(self):
+ longsize = 4 if IS_32_BIT else 8
+ POINT = lltype.Struct('POINT',
+ ('x', rffi.LONG),
+ ('y', rffi.SHORT),
+ ('z', rffi.VOIDP),
+ )
+ y_ofs = longsize
+ z_ofs = longsize*2
+ p = lltype.malloc(POINT, flavor='raw')
+ p.x = 42
+ p.y = rffi.cast(rffi.SHORT, -1)
+ p.z = rffi.cast(rffi.VOIDP, 0x1234)
+ addr = rffi.cast(rffi.VOIDP, p)
+ assert struct_getfield_int(types.slong, addr, 0) == 42
+ assert struct_getfield_int(types.sshort, addr, y_ofs) == -1
+ assert struct_getfield_int(types.pointer, addr, z_ofs) == 0x1234
+ #
+ struct_setfield_int(types.slong, addr, 0, 43)
+ struct_setfield_int(types.sshort, addr, y_ofs, 0x1234FFFE) # 0x1234 is masked out
+ struct_setfield_int(types.pointer, addr, z_ofs, 0x4321)
+ assert p.x == 43
+ assert p.y == -2
+ assert rffi.cast(rffi.LONG, p.z) == 0x4321
+ #
+ lltype.free(p, flavor='raw')
+
def test_array_fields(self):
POINT = lltype.Struct("POINT",
("x", lltype.Float),
@@ -69,18 +100,81 @@
assert array_getitem(types.double, 16, points, 0, 8) == 2.0
assert array_getitem(types.double, 16, points, 1, 0) == 3.0
assert array_getitem(types.double, 16, points, 1, 8) == 4.0
-
+ #
array_setitem(types.double, 16, points, 0, 0, 10.0)
array_setitem(types.double, 16, points, 0, 8, 20.0)
array_setitem(types.double, 16, points, 1, 0, 30.0)
array_setitem(types.double, 16, points, 1, 8, 40.0)
-
+ #
assert array_getitem(types.double, 16, points, 0, 0) == 10.0
assert array_getitem(types.double, 16, points, 0, 8) == 20.0
assert array_getitem(types.double, 16, points, 1, 0) == 30.0
assert array_getitem(types.double, 16, points, 1, 8) == 40.0
+ #
+ lltype.free(points, flavor="raw")
- lltype.free(points, flavor="raw")
+
+ def test_struct_fields_longlong(self):
+ POINT = lltype.Struct('POINT',
+ ('x', rffi.LONGLONG),
+ ('y', rffi.ULONGLONG)
+ )
+ y_ofs = 8
+ p = lltype.malloc(POINT, flavor='raw')
+ p.x = r_longlong(123)
+ p.y = r_ulonglong(456)
+ addr = rffi.cast(rffi.VOIDP, p)
+ assert struct_getfield_longlong(types.slonglong, addr, 0) == 123
+ assert struct_getfield_longlong(types.ulonglong, addr, y_ofs) == 456
+ #
+ v = rffi.cast(lltype.SignedLongLong, r_ulonglong(9223372036854775808))
+ struct_setfield_longlong(types.slonglong, addr, 0, v)
+ struct_setfield_longlong(types.ulonglong, addr, y_ofs, r_longlong(-1))
+ assert p.x == -9223372036854775808
+ assert rffi.cast(lltype.UnsignedLongLong, p.y) == 18446744073709551615
+ #
+ lltype.free(p, flavor='raw')
+
+ def test_struct_fields_float(self):
+ POINT = lltype.Struct('POINT',
+ ('x', rffi.DOUBLE),
+ ('y', rffi.DOUBLE)
+ )
+ y_ofs = 8
+ p = lltype.malloc(POINT, flavor='raw')
+ p.x = 123.4
+ p.y = 567.8
+ addr = rffi.cast(rffi.VOIDP, p)
+ assert struct_getfield_float(types.double, addr, 0) == 123.4
+ assert struct_getfield_float(types.double, addr, y_ofs) == 567.8
+ #
+ struct_setfield_float(types.double, addr, 0, 321.0)
+ struct_setfield_float(types.double, addr, y_ofs, 876.5)
+ assert p.x == 321.0
+ assert p.y == 876.5
+ #
+ lltype.free(p, flavor='raw')
+
+ def test_struct_fields_singlefloat(self):
+ POINT = lltype.Struct('POINT',
+ ('x', rffi.FLOAT),
+ ('y', rffi.FLOAT)
+ )
+ y_ofs = 4
+ p = lltype.malloc(POINT, flavor='raw')
+ p.x = r_singlefloat(123.4)
+ p.y = r_singlefloat(567.8)
+ addr = rffi.cast(rffi.VOIDP, p)
+ assert struct_getfield_singlefloat(types.double, addr, 0) == r_singlefloat(123.4)
+ assert struct_getfield_singlefloat(types.double, addr, y_ofs) == r_singlefloat(567.8)
+ #
+ struct_setfield_singlefloat(types.double, addr, 0, r_singlefloat(321.0))
+ struct_setfield_singlefloat(types.double, addr, y_ofs, r_singlefloat(876.5))
+ assert p.x == r_singlefloat(321.0)
+ assert p.y == r_singlefloat(876.5)
+ #
+ lltype.free(p, flavor='raw')
+
class TestLibffiCall(BaseFfiTest):
"""
diff --git a/pypy/rlib/test/test_rwin32.py b/pypy/rlib/test/test_rwin32.py
--- a/pypy/rlib/test/test_rwin32.py
+++ b/pypy/rlib/test/test_rwin32.py
@@ -26,3 +26,24 @@
rwin32.validate_fd = validate_fd
raises(WindowsError, rwin32.get_osfhandle, fd)
rwin32.validate_fd = _validate_fd
+
+def test_open_process():
+ pid = rwin32.GetCurrentProcessId()
+ assert pid != 0
+ handle = rwin32.OpenProcess(rwin32.PROCESS_QUERY_INFORMATION, False, pid)
+ rwin32.CloseHandle(handle)
+ raises(WindowsError, rwin32.OpenProcess, rwin32.PROCESS_TERMINATE, False, 0)
+
+def test_terminate_process():
+ import subprocess, signal, sys
+ proc = subprocess.Popen([sys.executable, "-c",
+ "import time;"
+ "time.sleep(10)",
+ ],
+ )
+ print proc.pid
+ handle = rwin32.OpenProcess(rwin32.PROCESS_ALL_ACCESS, False, proc.pid)
+ assert rwin32.TerminateProcess(handle, signal.SIGTERM) == 0
+ rwin32.CloseHandle(handle)
+ assert proc.wait() == signal.SIGTERM
+
diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py
--- a/pypy/rpython/lltypesystem/rdict.py
+++ b/pypy/rpython/lltypesystem/rdict.py
@@ -518,8 +518,6 @@
else:
return default
-# XXX: Move the size checking and resize into a single call which is opauqe to
-# the JIT when the dict isn't virtual, to avoid extra branches.
@jit.look_inside_iff(lambda d, i: jit.isvirtual(d) and jit.isconstant(i))
def _ll_dict_del(d, i):
d.entries.mark_deleted(i)
@@ -532,18 +530,32 @@
entry.key = lltype.nullptr(ENTRY.key.TO)
if ENTRIES.must_clear_value:
entry.value = lltype.nullptr(ENTRY.value.TO)
- num_entries = len(d.entries)
- if num_entries > DICT_INITSIZE and d.num_items < num_entries / 4:
- ll_dict_resize(d)
+ #
+ # The rest is commented out: like CPython we no longer shrink the
+ # dictionary here. It may shrink later if we try to append a number
+ # of new items to it. Unsure if this behavior was designed in
+ # CPython or is accidental. A design reason would be that if you
+ # delete all items in a dictionary (e.g. with a series of
+ # popitem()), then CPython avoids shrinking the table several times.
+ #num_entries = len(d.entries)
+ #if num_entries > DICT_INITSIZE and d.num_items <= num_entries / 4:
+ # ll_dict_resize(d)
+ # A previous xxx: move the size checking and resize into a single
+ # call which is opaque to the JIT when the dict isn't virtual, to
+ # avoid extra branches.
def ll_dict_resize(d):
old_entries = d.entries
old_size = len(old_entries)
# make a 'new_size' estimate and shrink it if there are many
- # deleted entry markers
- new_size = old_size * 2
- while new_size > DICT_INITSIZE and d.num_items < new_size / 4:
- new_size /= 2
+ # deleted entry markers. See CPython for why it is a good idea to
+ # quadruple the dictionary size as long as it's not too big.
+ if d.num_items > 50000: new_estimate = d.num_items * 2
+ else: new_estimate = d.num_items * 4
+ new_size = DICT_INITSIZE
+ while new_size <= new_estimate:
+ new_size *= 2
+ #
d.entries = lltype.typeOf(old_entries).TO.allocate(new_size)
d.num_items = 0
d.resize_counter = new_size * 2
diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py
--- a/pypy/rpython/lltypesystem/rffi.py
+++ b/pypy/rpython/lltypesystem/rffi.py
@@ -436,6 +436,7 @@
'long long', 'unsigned long long',
'size_t', 'time_t', 'wchar_t',
'uintptr_t', 'intptr_t']
+_TYPES_ARE_UNSIGNED = set(['size_t', 'uintptr_t']) # plus "unsigned *"
if os.name != 'nt':
TYPES.append('mode_t')
TYPES.append('pid_t')
@@ -454,7 +455,7 @@
name = 'u' + name[9:]
signed = False
else:
- signed = (name != 'size_t')
+ signed = (name not in _TYPES_ARE_UNSIGNED)
name = name.replace(' ', '')
names.append(name)
populatelist.append((name.upper(), c_name, signed))
diff --git a/pypy/rpython/module/ll_os.py b/pypy/rpython/module/ll_os.py
--- a/pypy/rpython/module/ll_os.py
+++ b/pypy/rpython/module/ll_os.py
@@ -7,11 +7,11 @@
import os, sys, errno
import py
-from pypy.rpython.module.support import ll_strcpy, OOSupport
-from pypy.tool.sourcetools import func_with_new_name, func_renamer
+from pypy.rpython.module.support import OOSupport
+from pypy.tool.sourcetools import func_renamer
from pypy.rlib.rarithmetic import r_longlong
from pypy.rpython.extfunc import (
- BaseLazyRegistering, lazy_register, register_external)
+ BaseLazyRegistering, register_external)
from pypy.rpython.extfunc import registering, registering_if, extdef
from pypy.annotation.model import (
SomeInteger, SomeString, SomeTuple, SomeFloat, SomeUnicodeString)
@@ -20,21 +20,14 @@
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.tool import rffi_platform as platform
from pypy.rlib import rposix
-from pypy.tool.udir import udir
from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.rpython.lltypesystem.rstr import mallocstr
-from pypy.rpython.annlowlevel import llstr
-from pypy.rpython.lltypesystem.llmemory import sizeof,\
- itemoffsetof, cast_ptr_to_adr, cast_adr_to_ptr, offsetof
+from pypy.rpython.lltypesystem.llmemory import itemoffsetof, offsetof
from pypy.rpython.lltypesystem.rstr import STR
-from pypy.rpython.annlowlevel import llstr
-from pypy.rlib import rgc
from pypy.rlib.objectmodel import specialize
str0 = SomeString(no_nul=True)
unicode0 = SomeUnicodeString(no_nul=True)
-
def monkeypatch_rposix(posixfunc, unicodefunc, signature):
func_name = posixfunc.__name__
@@ -514,27 +507,23 @@
from pypy.rpython.module.ll_win32file import make_utime_impl
os_utime_llimpl = make_utime_impl(traits)
- if traits.str is str:
- s_string = SomeString()
- else:
- s_string = SomeUnicodeString()
s_tuple_of_2_floats = SomeTuple([SomeFloat(), SomeFloat()])
def os_utime_normalize_args(s_path, s_times):
# special handling of the arguments: they can be either
# [str, (float, float)] or [str, s_None], and get normalized
# to exactly one of these two.
- if not s_string.contains(s_path):
+ if not traits.str0.contains(s_path):
raise Exception("os.utime() arg 1 must be a string, got %s" % (
s_path,))
case1 = s_None.contains(s_times)
case2 = s_tuple_of_2_floats.contains(s_times)
if case1 and case2:
- return [s_string, s_ImpossibleValue] #don't know which case yet
+ return [traits.str0, s_ImpossibleValue] #don't know which case yet
elif case1:
- return [s_string, s_None]
+ return [traits.str0, s_None]
elif case2:
- return [s_string, s_tuple_of_2_floats]
+ return [traits.str0, s_tuple_of_2_floats]
else:
raise Exception("os.utime() arg 2 must be None or a tuple of "
"2 floats, got %s" % (s_times,))
@@ -977,7 +966,7 @@
os_lseek = self.llexternal(funcname,
[rffi.INT, rffi.LONGLONG, rffi.INT],
- rffi.LONGLONG)
+ rffi.LONGLONG, macro=True)
def lseek_llimpl(fd, pos, how):
rposix.validate_fd(fd)
@@ -1544,9 +1533,8 @@
def register_os_umask(self):
os_umask = self.llexternal(underscore_on_windows+'umask', [rffi.MODE_T], rffi.MODE_T)
- def umask_llimpl(fd):
- rposix.validate_fd(fd)
- res = os_umask(rffi.cast(rffi.MODE_T, fd))
+ def umask_llimpl(newmask):
+ res = os_umask(rffi.cast(rffi.MODE_T, newmask))
return rffi.cast(lltype.Signed, res)
return extdef([int], int, llimpl=umask_llimpl,
@@ -1556,13 +1544,11 @@
def register_os_kill(self):
os_kill = self.llexternal('kill', [rffi.PID_T, rffi.INT],
rffi.INT)
-
def kill_llimpl(pid, sig):
res = rffi.cast(lltype.Signed, os_kill(rffi.cast(rffi.PID_T, pid),
rffi.cast(rffi.INT, sig)))
if res < 0:
raise OSError(rposix.get_errno(), "os_kill failed")
-
return extdef([int, int], s_None, llimpl=kill_llimpl,
export_name="ll_os.ll_os_kill")
diff --git a/pypy/rpython/module/test/test_ll_os.py b/pypy/rpython/module/test/test_ll_os.py
--- a/pypy/rpython/module/test/test_ll_os.py
+++ b/pypy/rpython/module/test/test_ll_os.py
@@ -252,6 +252,22 @@
os.close(fd)
raises(OSError, f, fd)
+
+def test_os_kill():
+ if not hasattr(os,'kill') or sys.platform == 'win32':
+ skip('No kill in os')
+ f = getllimpl(os.kill)
+ import subprocess
+ import signal
+ proc = subprocess.Popen([sys.executable, "-c",
+ "import time;"
+ "time.sleep(10)",
+ ],
+ )
+ f(proc.pid, signal.SIGTERM)
+ expected = -signal.SIGTERM
+ assert proc.wait() == expected
+
class ExpectTestOs:
def setup_class(cls):
if not hasattr(os, 'ttyname'):
@@ -273,3 +289,4 @@
assert ll_to_string(interpret(f, [0])) == f(0)
assert ll_to_string(interpret(f, [338])) == ''
+
diff --git a/pypy/rpython/rbuiltin.py b/pypy/rpython/rbuiltin.py
--- a/pypy/rpython/rbuiltin.py
+++ b/pypy/rpython/rbuiltin.py
@@ -247,6 +247,11 @@
vlist = hop.inputargs(lltype.Signed)
return vlist[0]
+def rtype_longlongmask(hop):
+ hop.exception_cannot_occur()
+ vlist = hop.inputargs(lltype.SignedLongLong)
+ return vlist[0]
+
def rtype_builtin_min(hop):
v1, v2 = hop.inputargs(hop.r_result, hop.r_result)
hop.exception_cannot_occur()
@@ -564,6 +569,7 @@
BUILTIN_TYPER[lltype.Ptr] = rtype_const_result
BUILTIN_TYPER[lltype.runtime_type_info] = rtype_runtime_type_info
BUILTIN_TYPER[rarithmetic.intmask] = rtype_intmask
+BUILTIN_TYPER[rarithmetic.longlongmask] = rtype_longlongmask
BUILTIN_TYPER[objectmodel.hlinvoke] = rtype_hlinvoke
diff --git a/pypy/rpython/test/test_llinterp.py b/pypy/rpython/test/test_llinterp.py
--- a/pypy/rpython/test/test_llinterp.py
+++ b/pypy/rpython/test/test_llinterp.py
@@ -137,7 +137,7 @@
info = py.test.raises(LLException, "interp.eval_graph(graph, values)")
try:
got = interp.find_exception(info.value)
- except ValueError as message:
+ except ValueError, message:
got = 'None %r' % message
assert got is exc, "wrong exception type, expected %r got %r" % (exc, got)
diff --git a/pypy/rpython/test/test_rbuiltin.py b/pypy/rpython/test/test_rbuiltin.py
--- a/pypy/rpython/test/test_rbuiltin.py
+++ b/pypy/rpython/test/test_rbuiltin.py
@@ -5,7 +5,7 @@
from pypy.rlib.debug import llinterpcall
from pypy.rpython.lltypesystem import lltype
from pypy.tool import udir
-from pypy.rlib.rarithmetic import intmask, is_valid_int
+from pypy.rlib.rarithmetic import intmask, longlongmask, r_int64, is_valid_int
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
@@ -79,6 +79,16 @@
res = self.interpret(f, [r_uint(5)])
assert type(res) is int and res == 5
+ def test_longlongmask(self):
+ def f(x=r_ulonglong):
+ try:
+ return longlongmask(x)
+ except ValueError:
+ return 0
+
+ res = self.interpret(f, [r_ulonglong(5)])
+ assert type(res) is r_int64 and res == 5
+
def test_rbuiltin_list(self):
def f():
l=list((1,2,3))
diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py
--- a/pypy/rpython/test/test_rdict.py
+++ b/pypy/rpython/test/test_rdict.py
@@ -759,13 +759,20 @@
assert count_frees >= 3
def test_dict_resize(self):
+ # XXX we no longer automatically resize on 'del'. We need to
+ # hack a bit in this test to trigger a resize by continuing to
+ # fill the dict's table while keeping the actual size very low
+ # in order to force a resize to shrink the table back
def func(want_empty):
d = {}
- for i in range(rdict.DICT_INITSIZE):
+ for i in range(rdict.DICT_INITSIZE << 1):
d[chr(ord('a') + i)] = i
if want_empty:
- for i in range(rdict.DICT_INITSIZE):
+ for i in range(rdict.DICT_INITSIZE << 1):
del d[chr(ord('a') + i)]
+ for i in range(rdict.DICT_INITSIZE << 3):
+ d[chr(ord('A') - i)] = i
+ del d[chr(ord('A') - i)]
return d
res = self.interpret(func, [0])
assert len(res.entries) > rdict.DICT_INITSIZE
diff --git a/pypy/rpython/tool/rfficache.py b/pypy/rpython/tool/rfficache.py
--- a/pypy/rpython/tool/rfficache.py
+++ b/pypy/rpython/tool/rfficache.py
@@ -4,17 +4,16 @@
import py
import os
-import distutils
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.tool.udir import udir
-from pypy.tool.autopath import pypydir
from pypy.rlib import rarithmetic
from pypy.rpython.lltypesystem import lltype
from pypy.tool.gcc_cache import build_executable_cache
def ask_gcc(question, add_source=""):
+ from pypy.translator.platform import platform
includes = ['stdlib.h', 'stdio.h', 'sys/types.h']
- if os.name != 'nt':
+ if platform.name != 'msvc':
includes += ['inttypes.h']
include_string = "\n".join(["#include <%s>" % i for i in includes])
c_source = py.code.Source('''
diff --git a/pypy/testrunner_cfg.py b/pypy/testrunner_cfg.py
--- a/pypy/testrunner_cfg.py
+++ b/pypy/testrunner_cfg.py
@@ -1,15 +1,16 @@
# nightly test configuration for the paraller runner
import os
+DIRS_SPLIT = [
+ 'translator/c', 'translator/jvm', 'rlib', 'rpython/memory',
+ 'jit/backend/x86', 'jit/metainterp', 'rpython/test',
+]
+
def collect_one_testdir(testdirs, reldir, tests):
- if (reldir.startswith('translator/c/') or
- reldir.startswith('translator/jvm/') or
- reldir.startswith('rlib/test') or
- reldir.startswith('rpython/memory/') or
- reldir.startswith('jit/backend/x86/') or
- #reldir.startswith('jit/backend/cli') or
- 0):
- testdirs.extend(tests)
+ for dir in DIRS_SPLIT:
+ if reldir.startswith(dir):
+ testdirs.extend(tests)
+ break
else:
testdirs.append(reldir)
diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -21,6 +21,8 @@
USE_ZIPFILE_MODULE = sys.platform == 'win32'
+STDLIB_VER = "2.7"
+
def ignore_patterns(*patterns):
"""Function that can be used as copytree() ignore parameter.
@@ -52,7 +54,15 @@
pypy_c = py.path.local(override_pypy_c)
if not pypy_c.check():
print pypy_c
- raise PyPyCNotFound('Please compile pypy first, using translate.py')
+ if os.path.isdir(os.path.dirname(str(pypy_c))):
+ raise PyPyCNotFound(
+ 'Please compile pypy first, using translate.py,'
+ ' or check that you gave the correct path'
+ ' (see docstring for more info)')
+ else:
+ raise PyPyCNotFound(
+ 'Bogus path: %r does not exist (see docstring for more info)'
+ % (os.path.dirname(str(pypy_c)),))
if sys.platform == 'win32' and not rename_pypy_c.lower().endswith('.exe'):
rename_pypy_c += '.exe'
binaries = [(pypy_c, rename_pypy_c)]
@@ -77,8 +87,8 @@
pypydir = builddir.ensure(name, dir=True)
# Careful: to copy lib_pypy, copying just the svn-tracked files
# would not be enough: there are also ctypes_config_cache/_*_cache.py.
- shutil.copytree(str(basedir.join('lib-python')),
- str(pypydir.join('lib-python')),
+ shutil.copytree(str(basedir.join('lib-python').join(STDLIB_VER)),
+ str(pypydir.join('lib-python').join(STDLIB_VER)),
ignore=ignore_patterns('.svn', 'py', '*.pyc', '*~'))
shutil.copytree(str(basedir.join('lib_pypy')),
str(pypydir.join('lib_pypy')),
diff --git a/pypy/tool/release/win32build.py b/pypy/tool/release/win32build.py
deleted file mode 100644
--- a/pypy/tool/release/win32build.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import autopath
-import package
-import subprocess
-import py, sys
-import shutil
-
-pypydir = py.path.local(autopath.pypydir)
-builddir = pypydir.join('translator', 'goal')
-
-VERSION = "1.5.0a0"
-
-def make_pypy(tag, options):
- pypy = 'pypy%s' % (tag,)
- args = [sys.executable,
- str(builddir.join('translate.py')),
- '--output=' + pypy,
- ] + options
- print "Execute", args
- p = subprocess.Popen(args, cwd=str(builddir))
- p.wait()
- zipfile = 'pypy-%s-win32%s' % (VERSION, tag)
- package.package(pypydir.dirpath(), zipfile, pypy, pypydir)
-
-shutil.copy(str(pypydir.join('..', '..', 'expat-2.0.1', 'win32', 'bin', 'release', 'libexpat.dll')), str(builddir))
-
-make_pypy('', ['-Ojit'])
-make_pypy('-nojit', ['-O2'])
-#make_pypy('-stackless', [--stackless])
-#make_pypy('-sandbox', [--sandbox])
diff --git a/pypy/tool/test/test_package.py b/pypy/tool/test/test_package.py
new file mode 100644
--- /dev/null
+++ b/pypy/tool/test/test_package.py
@@ -0,0 +1,6 @@
+from pypy.tool.release import package
+from pypy.module.sys import version
+
+def test_version():
+ assert package.STDLIB_VER == '%d.%d' % (version.CPYTHON_VERSION[0],
+ version.CPYTHON_VERSION[1])
diff --git a/pypy/translator/backendopt/test/test_finalizer.py b/pypy/translator/backendopt/test/test_finalizer.py
--- a/pypy/translator/backendopt/test/test_finalizer.py
+++ b/pypy/translator/backendopt/test/test_finalizer.py
@@ -84,8 +84,8 @@
def __del__(self):
if self.x:
+ lltype.free(self.x, flavor='raw')
self.x = lltype.nullptr(S)
- lltype.free(self.x, flavor='raw')
def f():
return A()
diff --git a/pypy/translator/c/database.py b/pypy/translator/c/database.py
--- a/pypy/translator/c/database.py
+++ b/pypy/translator/c/database.py
@@ -62,7 +62,7 @@
else:
self.exctransformer = translator.getexceptiontransformer()
if translator is not None:
- self.gctransformer = self.gcpolicy.transformerclass(translator)
+ self.gctransformer = self.gcpolicy.gettransformer()
self.completed = False
self.instrument_ncounter = 0
diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py
--- a/pypy/translator/c/gc.py
+++ b/pypy/translator/c/gc.py
@@ -5,8 +5,6 @@
from pypy.rpython.lltypesystem.lltype import \
typeOf, Ptr, ContainerType, RttiStruct, \
RuntimeTypeInfo, getRuntimeTypeInfo, top_container
-from pypy.rpython.memory.gctransform import \
- refcounting, boehm, framework, asmgcroot
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -111,7 +109,10 @@
from pypy.rlib.objectmodel import CDefinedIntSymbolic
class RefcountingGcPolicy(BasicGcPolicy):
- transformerclass = refcounting.RefcountingGCTransformer
+
+ def gettransformer(self):
+ from pypy.rpython.memory.gctransform import refcounting
+ return refcounting.RefcountingGCTransformer(self.db.translator)
def common_gcheader_initdata(self, defnode):
if defnode.db.gctransformer is not None:
@@ -196,7 +197,10 @@
class BoehmGcPolicy(BasicGcPolicy):
- transformerclass = boehm.BoehmGCTransformer
+
+ def gettransformer(self):
+ from pypy.rpython.memory.gctransform import boehm
+ return boehm.BoehmGCTransformer(self.db.translator)
def common_gcheader_initdata(self, defnode):
if defnode.db.gctransformer is not None:
@@ -246,9 +250,11 @@
yield 'boehm_gc_startup_code();'
def get_real_weakref_type(self):
+ from pypy.rpython.memory.gctransform import boehm
return boehm.WEAKLINK
def convert_weakref_to(self, ptarget):
+ from pypy.rpython.memory.gctransform import boehm
return boehm.convert_weakref_to(ptarget)
def OP_GC__COLLECT(self, funcgen, op):
@@ -305,7 +311,12 @@
class FrameworkGcPolicy(BasicGcPolicy):
- transformerclass = framework.FrameworkGCTransformer
+
+ def gettransformer(self):
+ if hasattr(self, 'transformerclass'): # for rpython/memory tests
+ return self.transformerclass(self.db.translator)
+ from pypy.rpython.memory.gctransform import framework
+ return framework.FrameworkGCTransformer(self.db.translator)
def struct_setup(self, structdefnode, rtti):
if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'):
@@ -337,9 +348,11 @@
yield '%s();' % (self.db.get(fnptr),)
def get_real_weakref_type(self):
+ from pypy.rpython.memory.gctransform import framework
return framework.WEAKREF
def convert_weakref_to(self, ptarget):
+ from pypy.rpython.memory.gctransform import framework
return framework.convert_weakref_to(ptarget)
def OP_GC_RELOAD_POSSIBLY_MOVED(self, funcgen, op):
@@ -395,7 +408,10 @@
raise Exception("the FramewokGCTransformer should handle this")
class AsmGcRootFrameworkGcPolicy(FrameworkGcPolicy):
- transformerclass = asmgcroot.AsmGcRootFrameworkGCTransformer
+
+ def gettransformer(self):
+ from pypy.rpython.memory.gctransform import asmgcroot
+ return asmgcroot.AsmGcRootFrameworkGCTransformer(self.db.translator)
def GC_KEEPALIVE(self, funcgen, v):
return 'pypy_asm_keepalive(%s);' % funcgen.expr(v)
diff --git a/pypy/translator/c/test/test_extfunc.py b/pypy/translator/c/test/test_extfunc.py
--- a/pypy/translator/c/test/test_extfunc.py
+++ b/pypy/translator/c/test/test_extfunc.py
@@ -134,6 +134,13 @@
res = os.lseek(fd, -r5200000000, 2)
assert res == r4800000000
os.close(fd)
+ try:
+ os.lseek(fd, 0, 0)
+ except OSError:
+ pass
+ else:
+ print "DID NOT RAISE"
+ raise AssertionError
st = os.stat(filename)
assert st.st_size == r10000000000
does_stuff()
diff --git a/pypy/translator/c/test/test_typed.py b/pypy/translator/c/test/test_typed.py
--- a/pypy/translator/c/test/test_typed.py
+++ b/pypy/translator/c/test/test_typed.py
@@ -885,3 +885,13 @@
assert res == 'acquire, hello, raised, release'
res = f(2)
assert res == 'acquire, hello, raised, release'
+
+ def test_longlongmask(self):
+ from pypy.rlib.rarithmetic import longlongmask, r_ulonglong
+ def func(n):
+ m = r_ulonglong(n)
+ m *= 100000
+ return longlongmask(m)
+ f = self.getcompiled(func, [int])
+ res = f(-2000000000)
+ assert res == -200000000000000
diff --git a/pypy/translator/cli/test/test_builtin.py b/pypy/translator/cli/test/test_builtin.py
--- a/pypy/translator/cli/test/test_builtin.py
+++ b/pypy/translator/cli/test/test_builtin.py
@@ -16,7 +16,10 @@
test_os_isdir = skip_os
test_os_dup_oo = skip_os
test_os_access = skip_os
-
+
+ def test_longlongmask(self):
+ py.test.skip("fix me")
+
def test_builtin_math_frexp(self):
self._skip_powerpc("Mono math floating point problem")
BaseTestBuiltin.test_builtin_math_frexp(self)
diff --git a/pypy/translator/goal/win32/gc_patch_windows.py b/pypy/translator/goal/win32/gc_patch_windows.py
deleted file mode 100644
--- a/pypy/translator/goal/win32/gc_patch_windows.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# patches for the Boehm GC for PyPy under Windows
-
-"""
-This file is obsolete now since gc-7.0 / gc-7.1 .
-Please use the instructions in pypy\doc\windows.rst .
-
-How to build a pypy compatible version of the Boehm collector
-for Windows and Visual Studio .net 2003.
-
-First of all, download the official Boehm collector suite
-from http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/gc.tar.gz
-At the time of writing (2005-10-06) this contains version gc6.5 .
-
-Unpack this folder somewhere, for instance to "d:\tmp".
-Change to this folder using
-
-d:
-cd \tmp\gc6.5
-
-Then copy the file NT_THREADS_MAKEFILE to Makefile:
-
-copy NT_THREADS_MAKEFILE Makefile
-
-This file is the general-purpose gc dll makefile. For some internal
-reasons, this file's defaults are bad for PyPy. The early initialisation
-in DllMain() inhibits the changes necessary for PyPy. Use this script to
-do a patch: (assuming that you have d:\pypy\dist\pypy\translator\goal)
-
-python d:\pypy\dist\pypy\translator\goal\win32\gc_patch_windows.py
-
-Now, your makefile is patched a little bit. In particular,
-
-ALL_INTERIOR_POINTERS is now undefined, which PyPy wants to have
-NO_GETENV is specified, since we don't want dependencies
-
-and the name of the .lib and .dll files is changed to gc_pypy.???
-
-Now you need to build your gc, either as a debug or as a release
-build. First of all, make sure that you have your environment prepared.
-Please note that you will need to use Microsoft's cmd, as cygwin bash
-doesn't correctly handle the batch file in the next step.
-
-With my setup, I have to do
-
-"e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\bin\vcvars32.bat"
-
-After that, you can either build a release or a debug gc.
-
-After a successful build, you need to enable gc_pypy.dll for your compiler.
-There are many ways to install this. The following recommendation just
-works without changing your environment variables. I think this is the
-easiest way possible, but this is a matter of taste. What I did is:
-
-nmake CFG="gc - Win32 Release"
-
-After the build, you will find a gc_pypy.dll file in the Release folder.
-Copy this file to c:\windows\system32 or any other folder that is always
-in your PATH variable.
-
-Also, copy Release\gc_pypy.lib to (in my case)
-"e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\lib";
-
-finally, copy d:\tmp\gc6.5\include to
-"e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\include"
-and rename this folder to "gc", so that "gc/gc.h" is valid.
-
-That's all, folks!
-
-In case of a debug build, replace "Release" by "Debug", and also copy
-gc_pypy.pdb to your lib folder. This allows you to use source-level
-debugging. Please note: If you want to both build the default gc.dll
-and gc_pypy.dll, please delete the Debug resp. Release folders in
-between. The generated .sbr files are in the way.
-
-Please use the above recipe and report any bugs to me.
-In case of trouble, I also can provide you with pre-built dlls.
-Note: We also could have solved this by including the gc source
-into the PyPy build. This may or may not become necessary if something
-changes dramatically, again. As long as this is not needed, I prefer
-this simple solution.
-
-Summary transcript of the steps involved: (please adjust paths)
-
-d:
-cd \tmp\gc6.5
-copy NT_THREADS_MAKEFILE Makefile
-python d:\pypy\dist\pypy\translator\goal\win32\gc_patch_windows.py
-"e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\bin\vcvars32.bat"
-nmake CFG="gc - Win32 Release"
-copy Release\gc_pypy.dll c:\windows\system32
-copy Release\gc_pypy.lib "e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\lib"
-mkdir "e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\include\gc"
-copy include "e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\include\gc"
-
-cheers - chris
-"""
-
-REPLACE = {
- '"ALL_INTERIOR_POINTERS"': '"NO_GETENV"',
- }
-
-for ending in "lib exp map pdb bsc dll pch".split():
- REPLACE["gc.%s" % ending] = "gc_pypy.%s" % ending
-
-def change_settings(src):
- for old, new in REPLACE.items():
- newsrc = src.replace(old, new)
- if newsrc == src:
- raise ValueError, "this makefile does not contain %s" % old
- src = newsrc
- return src
-
-def find_file():
- import os
- for name in os.listdir("."):
- if name.lower() == 'makefile':
- return name
- else:
- raise ValueError, 'Makefile not found'
-
-try:
- name = find_file()
- source = change_settings(file(name).read())
- file(name, "w").write(source)
- print "Updated your Makefile to fit PyPy's needs. Your lib will be named gc_pypy.dll"
- print "and gc_pypy.lib. Please put them into appropriate places, see __doc__."
-except:
- print __doc__
- raise
diff --git a/pypy/translator/jvm/test/test_builtin.py b/pypy/translator/jvm/test/test_builtin.py
--- a/pypy/translator/jvm/test/test_builtin.py
+++ b/pypy/translator/jvm/test/test_builtin.py
@@ -47,6 +47,9 @@
res = self.interpret(fn, [])
assert stat.S_ISREG(res)
+ def test_longlongmask(self):
+ py.test.skip("fix me")
+
class TestJvmTime(JvmTest, BaseTestTime):
pass
diff --git a/pypy/translator/platform/posix.py b/pypy/translator/platform/posix.py
--- a/pypy/translator/platform/posix.py
+++ b/pypy/translator/platform/posix.py
@@ -55,6 +55,9 @@
if relto:
response_file = relto.bestrelpath(response_file)
+ if self.cc == 'mingw32' or (self.cc== 'gcc' and os.name=='nt'):
+ return ["-Wl,--export-all-symbols,--version-script=%s" % \
+ (response_file,)]
return ["-Wl,--export-dynamic,--version-script=%s" % (response_file,)]
def _link(self, cc, ofiles, link_args, standalone, exe_name):
diff --git a/pypy/translator/platform/windows.py b/pypy/translator/platform/windows.py
--- a/pypy/translator/platform/windows.py
+++ b/pypy/translator/platform/windows.py
@@ -13,7 +13,7 @@
cc = os.environ.get('CC','')
if not cc:
return MsvcPlatform(cc=cc, x64=x64_flag)
- elif cc.startswith('mingw'):
+ elif cc.startswith('mingw') or cc == 'gcc':
return MingwPlatform(cc)
try:
subprocess.check_output([cc, '--version'])
diff --git a/testrunner/filetimes.py b/testrunner/filetimes.py
new file mode 100644
--- /dev/null
+++ b/testrunner/filetimes.py
@@ -0,0 +1,59 @@
+from lxml.etree import parse
+from collections import defaultdict
+from os.path import join, exists
+import argparse
+parser = argparse.ArgumentParser()
+parser.add_argument('junitxml')
+parser.add_argument('fileroot')
+
+opts = parser.parse_args()
+
+xml = parse(opts.junitxml)
+root = xml.getroot()
+
+
+bugstarts = 'interpreter', 'tool', 'module'
+def findfile(root, classname):
+ if not classname:
+ return
+ parts = classname.split('.')
+
+ #pytest bug workaround
+ first = parts[0]
+ for start in bugstarts:
+ if first.startswith(start) and \
+ first != start and \
+ first[len(start)] != '.':
+ parts[0] = start
+ parts.insert(1, 'py'+first[len(start):])
+
+ while parts:
+ path = join(root, *parts) + '.py'
+ if exists(path):
+ return join(*parts) + '.py'
+ parts.pop()
+
+accum = defaultdict(list)
+garbageitems = []
+
+for item in root:
+ filename = findfile(opts.fileroot, item.attrib['classname'])
+ accum[filename].append(float(item.attrib['time']))
+ if filename is None:
+ garbageitems.append(item)
+
+
+
+
+garbage = accum.pop(None, [])
+if garbage:
+ print 'garbage', sum(garbage), len(garbage)
+
+for key in sorted(accum):
+ value = accum[key]
+ print key, sum(value), len(value)
+
+print '-'*30
+
+for item in garbageitems:
+ print item.attrib
diff --git a/testrunner/junitmerge.py b/testrunner/junitmerge.py
new file mode 100644
--- /dev/null
+++ b/testrunner/junitmerge.py
@@ -0,0 +1,49 @@
+"""
+simple scrpt for junitxml file merging
+"""
+
+from lxml.etree import parse, Element, tostring
+from collections import defaultdict
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--out')
+parser.add_argument('path', nargs='...')
+
+opts = parser.parse_args()
+
+files = []
+
+for path in opts.path:
+ files.append(parse(path))
+
+
+accum = defaultdict(int)
+children = []
+
+for item in files:
+ root = item.getroot()
+ for key, value in root.attrib.items():
+ if not value:
+ continue
+ value = float(value) if '.' in value else int(value)
+ accum[key] += value
+ children.extend(root)
+
+
+
+
+assert len(children) == sum(accum[x] for x in 'tests errors skips'.split())
+
+children.sort(key=lambda x:(x.attrib['classname'], x.attrib['name']))
+
+
+
+new = Element('testsuite', dict((k, str(v)) for k, v in accum.items()))
+new.extend(children)
+
+data = tostring(new)
+
+with open(opts.out, 'w') as fp:
+ fp.write(data)
+
More information about the pypy-commit
mailing list