bpo-36974: implement PEP 590 (GH-13185) · python/cpython@aacc77f (original) (raw)

`@@ -47,7 +47,7 @@ PyAPI_FUNC(int) _PyStack_UnpackDict(

`

47

47

`/* Suggested size (number of positional arguments) for arrays of PyObject*

`

48

48

` allocated on a C stack to avoid allocating memory on the heap memory. Such

`

49

49

` array is used to pass positional arguments to call functions of the

`

50

``

`-

_PyObject_FastCall() family.

`

``

50

`+

_PyObject_Vectorcall() family.

`

51

51

``

52

52

` The size is chosen to not abuse the C stack and so limit the risk of stack

`

53

53

` overflow. The size is also chosen to allow using the small stack for most

`

`@@ -56,50 +56,103 @@ PyAPI_FUNC(int) _PyStack_UnpackDict(

`

56

56

`#define _PY_FASTCALL_SMALL_STACK 5

`

57

57

``

58

58

`/* Return 1 if callable supports FASTCALL calling convention for positional

`

59

``

`-

arguments: see _PyObject_FastCallDict() and _PyObject_FastCallKeywords() */

`

``

59

`+

arguments: see _PyObject_Vectorcall() and _PyObject_FastCallDict() */

`

60

60

`PyAPI_FUNC(int) _PyObject_HasFastCall(PyObject *callable);

`

61

61

``

62

``

`-

/* Call the callable object 'callable' with the "fast call" calling convention:

`

63

``

`-

args is a C array for positional arguments (nargs is the number of

`

64

``

`-

positional arguments), kwargs is a dictionary for keyword arguments.

`

``

62

`+

PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *callable,

`

``

63

`+

PyObject *result,

`

``

64

`+

const char *where);

`

65

65

``

66

``

`-

If nargs is equal to zero, args can be NULL. kwargs can be NULL.

`

67

``

`-

nargs must be greater or equal to zero.

`

``

66

`+

/* === Vectorcall protocol (PEP 590) ============================= */

`

68

67

``

69

``

`-

Return the result on success. Raise an exception and return NULL on

`

70

``

`-

error. */

`

71

``

`-

PyAPI_FUNC(PyObject *) _PyObject_FastCallDict(

`

``

68

`+

/* Call callable using tp_call. Arguments are like _PyObject_Vectorcall()

`

``

69

`+

or _PyObject_FastCallDict() (both forms are supported),

`

``

70

`+

except that nargs is plainly the number of arguments without flags. */

`

``

71

`+

PyAPI_FUNC(PyObject *) _PyObject_MakeTpCall(

`

72

72

`PyObject *callable,

`

73

``

`-

PyObject *const *args,

`

74

``

`-

Py_ssize_t nargs,

`

75

``

`-

PyObject *kwargs);

`

``

73

`+

PyObject *const *args, Py_ssize_t nargs,

`

``

74

`+

PyObject *keywords);

`

76

75

``

77

``

`-

/* Call the callable object 'callable' with the "fast call" calling convention:

`

78

``

`-

args is a C array for positional arguments followed by values of

`

79

``

`-

keyword arguments. Keys of keyword arguments are stored as a tuple

`

80

``

`-

of strings in kwnames. nargs is the number of positional parameters at

`

81

``

`-

the beginning of stack. The size of kwnames gives the number of keyword

`

82

``

`-

values in the stack after positional arguments.

`

``

76

`+

#define PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1))

`

83

77

``

84

``

`-

kwnames must only contains str strings, no subclass, and all keys must

`

85

``

`-

be unique.

`

``

78

`+

static inline Py_ssize_t

`

``

79

`+

PyVectorcall_NARGS(size_t n)

`

``

80

`+

{

`

``

81

`+

return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET;

`

``

82

`+

}

`

``

83

+

``

84

`+

static inline vectorcallfunc

`

``

85

`+

_PyVectorcall_Function(PyObject *callable)

`

``

86

`+

{

`

``

87

`+

PyTypeObject *tp = Py_TYPE(callable);

`

``

88

`+

if (!PyType_HasFeature(tp, _Py_TPFLAGS_HAVE_VECTORCALL)) {

`

``

89

`+

return NULL;

`

``

90

`+

}

`

``

91

`+

assert(PyCallable_Check(callable));

`

``

92

`+

Py_ssize_t offset = tp->tp_vectorcall_offset;

`

``

93

`+

assert(offset > 0);

`

``

94

`+

vectorcallfunc *ptr = (vectorcallfunc *)(((char *)callable) + offset);

`

``

95

`+

return *ptr;

`

``

96

`+

}

`

``

97

+

``

98

`+

/* Call the callable object 'callable' with the "vectorcall" calling

`

``

99

`+

convention.

`

``

100

+

``

101

`+

args is a C array for positional arguments.

`

``

102

+

``

103

`+

nargsf is the number of positional arguments plus optionally the flag

`

``

104

`+

PY_VECTORCALL_ARGUMENTS_OFFSET which means that the caller is allowed to

`

``

105

`+

modify args[-1].

`

86

106

``

87

``

`-

If nargs is equal to zero and there is no keyword argument (kwnames is

`

88

``

`-

NULL or its size is zero), args can be NULL.

`

``

107

`+

kwnames is a tuple of keyword names. The values of the keyword arguments

`

``

108

`+

are stored in "args" after the positional arguments (note that the number

`

``

109

`+

of keyword arguments does not change nargsf). kwnames can also be NULL if

`

``

110

`+

there are no keyword arguments.

`

``

111

+

``

112

`+

keywords must only contains str strings (no subclass), and all keys must

`

``

113

`+

be unique.

`

89

114

``

90

115

` Return the result on success. Raise an exception and return NULL on

`

91

116

` error. */

`

92

``

`-

PyAPI_FUNC(PyObject *) _PyObject_FastCallKeywords(

`

``

117

`+

static inline PyObject *

`

``

118

`+

_PyObject_Vectorcall(PyObject *callable, PyObject *const *args,

`

``

119

`+

size_t nargsf, PyObject *kwnames)

`

``

120

`+

{

`

``

121

`+

assert(kwnames == NULL || PyTuple_Check(kwnames));

`

``

122

`+

assert(args != NULL || PyVectorcall_NARGS(nargsf) == 0);

`

``

123

`+

vectorcallfunc func = _PyVectorcall_Function(callable);

`

``

124

`+

if (func == NULL) {

`

``

125

`+

Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);

`

``

126

`+

return _PyObject_MakeTpCall(callable, args, nargs, kwnames);

`

``

127

`+

}

`

``

128

`+

PyObject *res = func(callable, args, nargsf, kwnames);

`

``

129

`+

return _Py_CheckFunctionResult(callable, res, NULL);

`

``

130

`+

}

`

``

131

+

``

132

`+

/* Same as _PyObject_Vectorcall except that keyword arguments are passed as

`

``

133

`+

dict, which may be NULL if there are no keyword arguments. */

`

``

134

`+

PyAPI_FUNC(PyObject *) _PyObject_FastCallDict(

`

93

135

`PyObject *callable,

`

94

136

`PyObject *const *args,

`

95

``

`-

Py_ssize_t nargs,

`

96

``

`-

PyObject *kwnames);

`

``

137

`+

size_t nargsf,

`

``

138

`+

PyObject *kwargs);

`

97

139

``

98

``

`-

#define _PyObject_FastCall(func, args, nargs) \

`

99

``

`-

_PyObject_FastCallDict((func), (args), (nargs), NULL)

`

``

140

`+

/* Call "callable" (which must support vectorcall) with positional arguments

`

``

141

`+

"tuple" and keyword arguments "dict". "dict" may also be NULL */

`

``

142

`+

PyAPI_FUNC(PyObject *) PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict);

`

100

143

``

101

``

`-

#define _PyObject_CallNoArg(func) \

`

102

``

`-

_PyObject_FastCallDict((func), NULL, 0, NULL)

`

``

144

`+

/* Same as _PyObject_Vectorcall except without keyword arguments */

`

``

145

`+

static inline PyObject *

`

``

146

`+

_PyObject_FastCall(PyObject *func, PyObject *const *args, Py_ssize_t nargs)

`

``

147

`+

{

`

``

148

`+

return _PyObject_Vectorcall(func, args, (size_t)nargs, NULL);

`

``

149

`+

}

`

``

150

+

``

151

`+

/* Call a callable without any arguments */

`

``

152

`+

static inline PyObject *

`

``

153

`+

_PyObject_CallNoArg(PyObject *func) {

`

``

154

`+

return _PyObject_Vectorcall(func, NULL, 0, NULL);

`

``

155

`+

}

`

103

156

``

104

157

`PyAPI_FUNC(PyObject *) _PyObject_Call_Prepend(

`

105

158

`PyObject *callable,

`

`@@ -113,10 +166,6 @@ PyAPI_FUNC(PyObject *) _PyObject_FastCall_Prepend(

`

113

166

`PyObject *const *args,

`

114

167

`Py_ssize_t nargs);

`

115

168

``

116

``

`-

PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *callable,

`

117

``

`-

PyObject *result,

`

118

``

`-

const char *where);

`

119

``

-

120

169

`/* Like PyObject_CallMethod(), but expect a _Py_Identifier*

`

121

170

` as the method name. */

`

122

171

`PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *obj,

`