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
-
6
1
"""
7
2
Low-level version of `pycall!(ret, o, ...; kwargs...)`
8
3
Sets `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
21
16
friendly format but you don't have the python tuple to hold the arguments
22
17
(`pyargsptr`). Sets `ret.o` to the result of the call, and returns `ret::PyObject`.
23
18
"""
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)
35
22
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
37
29
return __pycall! (ret, pyargsptr, o, kw) # ::PyObject
38
30
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)
92
32
end
93
33
end
94
34
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
108
35
"""
109
36
Lowest level version of `pycall!(ret, o, ...)`, assumes `pyargsptr` and `kw`
110
37
have 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},
116
43
try
117
44
retptr = @pycheckn ccall ((@pysym :PyObject_Call ), PyPtr, (PyPtr,PyPtr,PyPtr), o,
118
45
pyargsptr, kw)
119
- pyincref_ (retptr)
120
- pydecref (ret)
121
- ret. o = retptr
46
+ pydecref_ (ret. o)
47
+ ret. o = pyincref_ (retptr)
122
48
finally
123
49
sigatomic_end ()
124
50
end
0 commit comments