1-
2- # pyarg_tuples[i] is a pointer to a python tuple of length i-1
3- # const pyarg_tuples = Vector{PyPtr}(32)
4- const pyarg_tuples = PyPtr[]
5-
61"""
72Low-level version of `pycall!(ret, o, ...; kwargs...)`
83Sets `ret.o` to the result of the call, and returns `ret::PyObject`
@@ -21,90 +16,22 @@ Low-level version of `pycall!(ret, o, ...)` for when `kw` is already in python
2116friendly format but you don't have the python tuple to hold the arguments
2217(`pyargsptr`). Sets `ret.o` to the result of the call, and returns `ret::PyObject`.
2318"""
24- function _pycall! (ret:: PyObject , o:: Union{PyObject,PyPtr} , args,
25- nargs:: Int = length (args), kw:: Union{Ptr{Cvoid}, PyObject} = C_NULL )
26- # pyarg_tuples[i] is a pointer to a python tuple of length i-1
27- for n in length (pyarg_tuples): nargs
28- push! (pyarg_tuples, @pycheckn ccall ((@pysym :PyTuple_New ), PyPtr, (Int,), n))
29- end
30- check_pyargsptr (nargs)
31- pyargsptr = pyarg_tuples[nargs+ 1 ]
32- # We temporarily set pyarg_tuples[nargs+1] to NULL to ensure that nested
33- # calls to pycall don't try to use the same tuple object (issue #533).
34- pyarg_tuples[nargs+ 1 ] = C_NULL
19+ function _pycall! (ret:: PyObject , o:: Union{PyObject,PyPtr} , args, nargs:: Int = length (args),
20+ kw:: Union{Ptr{Cvoid}, PyObject} = C_NULL )
21+ pyargsptr = @pycheckn ccall ((@pysym :PyTuple_New ), PyPtr, (Int,), nargs)
3522 try
36- pysetargs! (pyargsptr, args, nargs)
23+ for i = 1 : nargs
24+ pyarg = PyObject (args[i])
25+ pyincref (pyarg) # PyTuple_SetItem steals the reference
26+ @pycheckz ccall ((@pysym :PyTuple_SetItem ), Cint,
27+ (PyPtr,Int,PyPtr), pyargsptr, i- 1 , pyarg)
28+ end
3729 return __pycall! (ret, pyargsptr, o, kw) # ::PyObject
3830 finally
39- if nargs > 0 && unsafe_load (pyargsptr). ob_refcnt > 1
40- # we are no longer the only reference to the tuple,
41- # so PyTuple_SetItem will fail (see check_pyargsptr)
42- pydecref_ (pyargsptr)
43- else
44- pyunsetargs! (pyargsptr, nargs) # garbage-collect args
45- pydecref_ (pyarg_tuples[nargs+ 1 ]) # no-op if it's still NULL
46- pyarg_tuples[nargs+ 1 ] = pyargsptr # restore tuple cache
47- end
48- end
49- end
50-
51- """
52- Handle the situation where a callee had previously called incref on the
53- arguments tuple that was passed to it. We need to hold the only reference to the
54- arguments tuple, since setting a tuple item is only allowed when there is just
55- one reference to the tuple (tuples are supposed to be immutable in Python in all
56- other cases). Note that this actually happens when creating new builtin
57- exceptions, ref: https://github.com/python/cpython/blob/480ab05d5fee2b8fa161f799af33086a4e68c7dd/Objects/exceptions.c#L48
58- OTOH this py"def foo(*args): global z; z=args" doesn't trigger this.
59- Fortunately, this check for ob_refcnt is fast - only a few cpu clock cycles.
60- """
61- function check_pyargsptr (nargs:: Int )
62- if nargs > 0
63- p = pyarg_tuples[nargs+ 1 ]
64- if p == C_NULL || unsafe_load (p). ob_refcnt > 1
65- pydecref_ (p) # no-op for NULL p
66- pyarg_tuples[nargs+ 1 ] =
67- @pycheckn ccall ((@pysym :PyTuple_New ), PyPtr, (Int,), nargs)
68- end
69- end
70- end
71-
72- """
73- ```
74- pysetargs!(pyargsptr::PyPtr, args...)
75- ```
76- Convert `args` to `PyObject`s, and set them as the elements of the Python tuple
77- pointed to by `pyargsptr`
78- """
79- function pysetargs! (pyargsptr:: PyPtr , args, N:: Int )
80- for i = 1 : N
81- pysetarg! (pyargsptr, args[i], i)
82- end
83- end
84-
85- """
86- Decref the `N`` elements of the Python tuple `pyargsptr` by setting the
87- elements to NULL, to ensure that they are garbage-collected.
88- """
89- function pyunsetargs! (pyargsptr:: PyPtr , N:: Int )
90- for i = 1 : N
91- @pycheckz ccall ((@pysym :PyTuple_SetItem ), Cint, (PyPtr,Int,PyPtr), pyargsptr, i- 1 , C_NULL )
31+ pydecref_ (pyargsptr)
9232 end
9333end
9434
95- """
96- ```
97- pysetarg!(pyargsptr::PyPtr, arg, i::Integer=1)
98- ```
99- Convert `arg` to a `PyObject`, and set it as the `i-1`th element of the Python
100- tuple pointed to by `pyargsptr`
101- """
102- function pysetarg! (pyargsptr:: PyPtr , arg, i:: Integer = 1 )
103- pyarg = PyObject (arg)
104- pyincref (pyarg) # PyTuple_SetItem steals the reference
105- @pycheckz ccall ((@pysym :PyTuple_SetItem ), Cint,
106- (PyPtr,Int,PyPtr), pyargsptr, i- 1 , pyarg)
107- end
10835"""
10936Lowest level version of `pycall!(ret, o, ...)`, assumes `pyargsptr` and `kw`
11037have all their args set to Python values, so we can just call the function `o`.
@@ -116,9 +43,8 @@ function __pycall!(ret::PyObject, pyargsptr::PyPtr, o::Union{PyObject,PyPtr},
11643 try
11744 retptr = @pycheckn ccall ((@pysym :PyObject_Call ), PyPtr, (PyPtr,PyPtr,PyPtr), o,
11845 pyargsptr, kw)
119- pyincref_ (retptr)
120- pydecref (ret)
121- ret. o = retptr
46+ pydecref_ (ret. o)
47+ ret. o = pyincref_ (retptr)
12248 finally
12349 sigatomic_end ()
12450 end
0 commit comments