Backporting METH_FASTCALL from Python 3.7 (#317)

* dict copy speedup

refer to bpo-31179 or python/cpython@boa7a037b8fde

* __build_class__() uses METH_FASTCALL

refer python/cpython@69de71b255
refer python/cpython@773dc6dd06

a single test related to __prepare__ fails.

* type_prepare uses METH_FASTCALL

refer python/cpython@d526cfe546
refer python/cpython@80ab22fa2c

the prepare-related test still fails.  It's just related to the error
message format though.

* separate into ParseStack and ParseStackAndKeywords

refer python/cpython@6518a93cb1
refer python/cpython@3e1fad6913
refer python/cpython@c0083fc47d

* Add _PyArg_NoStackKeywords

refer python/cpython@29d39cc8f5

* _PyStack_UnpackDict now returns int

refer python/cpython@998c20962c

* METH_FASTCALL changes to .inc files

done via python's Argument Clinic tool,
refer python/cpython@259f0e4437

* Added _PyArg_UnpackStack

refer python/cpython@fe54dda08

* Argument Clinic FASTCALL again

refer python/cpython@0c4a828ca

* Argument Clinic for ordered dictionary object

refer python/cpython@b05cbac052

* speed up getargs

refer python/cpython@1741441649

* FASTCALL for sorted, next, and getattr

refer python/cpython@5a60ecaa7a
refer python/cpython@fda6d0acf0
refer python/cpython@84b388bb80

* Optimize methoddescr_call

refer python/cpython@2a1b676d1f
refer python/cpython@c52572319c
refer python/cpython@35ecebe165
refer python/cpython@8128d5a491

* cleanup _PyMethodDef_RawFastCallDict

refer python/cpython@0a2e46835d
refer python/cpython@98ccba8344
refer python/cpython@c89ef828cf
refer python/cpython@250e4b0063

* print now uses METH_FASTCALL

refer python/cpython@c3858bd7c6
refer python/cpython@bd584f169f
refer python/cpython@06d34393c2

* _struct module now uses Argument Clinic

refer python/cpython@3f2d10132d

* make deque methods faster

refer python/cpython@dd407d5006

* recursive calls in PyObject_Call

refer python/cpython@7399a05965

only partially ported, because RawFastCallKeywords hasn't been ported

* add macros

refer python/cpython@68a001dd59

* all tests pass in MODE=dbg

* convert some internal functions to FASTCALL

__import__ might need to be changed later, if it is possible to backport
the METH_FASTCALL | METH_KEYWORDS flag distinction later.

* speed up unpickling

refer python/cpython@bee09aecc2

* added _PyMethodDef_RawFastCallKeywords

refer python/cpython@7399a05965

* PyCFunction_Call performance

refer python/cpython@12c5838dae

* avoid PyMethodObject in slots

main change in python/cpython@516b98161a
test_exceptions changed in python/cpython@331bbe6aaa
type_settattro changed in python/cpython@193f7e094f
_PyObject_CallFunctionVa changed in python/cpython@fe4ff83049

* fix refcount error found in MODE=dbg

all tests now pass in MODE=dbg
This commit is contained in:
Gautham 2021-11-13 04:56:57 +05:30 committed by GitHub
parent 6f658f058b
commit 7fe9e70117
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
71 changed files with 4154 additions and 2450 deletions

View file

@ -2255,27 +2255,38 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
PyObject *result;
/* PyObject_Call() must not be called with an exception set,
because it may clear it (directly or indirectly) and so the
because it can clear it (directly or indirectly) and so the
caller loses its exception */
assert(!PyErr_Occurred());
assert(PyTuple_Check(args));
assert(kwargs == NULL || PyDict_Check(kwargs));
call = callable->ob_type->tp_call;
if (call == NULL) {
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
callable->ob_type->tp_name);
return NULL;
if (PyFunction_Check(callable)) {
return _PyFunction_FastCallDict(callable,
&PyTuple_GET_ITEM(args, 0),
PyTuple_GET_SIZE(args),
kwargs);
}
else if (PyCFunction_Check(callable)) {
return PyCFunction_Call(callable, args, kwargs);
}
else {
call = callable->ob_type->tp_call;
if (call == NULL) {
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
callable->ob_type->tp_name);
return NULL;
}
if (Py_EnterRecursiveCall(" while calling a Python object"))
return NULL;
if (Py_EnterRecursiveCall(" while calling a Python object"))
return NULL;
result = (*call)(callable, args, kwargs);
result = (*call)(callable, args, kwargs);
Py_LeaveRecursiveCall();
Py_LeaveRecursiveCall();
return _Py_CheckFunctionResult(callable, result, NULL);
return _Py_CheckFunctionResult(callable, result, NULL);
}
}
/* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their
@ -2300,15 +2311,36 @@ _PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs)
return args;
}
PyObject*
_PyStack_AsTupleSlice(PyObject **stack, Py_ssize_t nargs,
Py_ssize_t start, Py_ssize_t end)
{
PyObject *args;
Py_ssize_t i;
assert(0 <= start);
assert(end <= nargs);
assert(start <= end);
args = PyTuple_New(end - start);
if (args == NULL) {
return NULL;
}
for (i=start; i < end; i++) {
PyObject *item = stack[i];
Py_INCREF(item);
PyTuple_SET_ITEM(args, i - start, item);
}
return args;
}
PyObject *
_PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs,
PyObject *kwargs)
{
ternaryfunc call;
PyObject *result = NULL;
/* _PyObject_FastCallDict() must not be called with an exception set,
because it may clear it (directly or indirectly) and so the
because it can clear it (directly or indirectly) and so the
caller loses its exception */
assert(!PyErr_Occurred());
@ -2317,51 +2349,84 @@ _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs,
assert(nargs == 0 || args != NULL);
assert(kwargs == NULL || PyDict_Check(kwargs));
if (Py_EnterRecursiveCall(" while calling a Python object")) {
return NULL;
}
if (PyFunction_Check(callable)) {
result = _PyFunction_FastCallDict(callable, args, nargs, kwargs);
return _PyFunction_FastCallDict(callable, args, nargs, kwargs);
}
else if (PyCFunction_Check(callable)) {
result = _PyCFunction_FastCallDict(callable, args, nargs, kwargs);
return _PyCFunction_FastCallDict(callable, args, nargs, kwargs);
}
else {
PyObject *tuple;
PyObject *argstuple, *result;
ternaryfunc call;
/* Slow-path: build a temporary tuple */
call = callable->ob_type->tp_call;
if (call == NULL) {
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
callable->ob_type->tp_name);
goto exit;
return NULL;
}
tuple = _PyStack_AsTuple(args, nargs);
if (tuple == NULL) {
goto exit;
argstuple = _PyStack_AsTuple(args, nargs);
if (argstuple == NULL) {
return NULL;
}
result = (*call)(callable, tuple, kwargs);
Py_DECREF(tuple);
if (Py_EnterRecursiveCall(" while calling a Python object")) {
return NULL;
}
result = (*call)(callable, argstuple, kwargs);
Py_LeaveRecursiveCall();
Py_DECREF(argstuple);
result = _Py_CheckFunctionResult(callable, result, NULL);
return result;
}
exit:
Py_LeaveRecursiveCall();
return result;
}
/* Positional arguments are obj followed by args:
call callable(obj, *args, **kwargs) */
PyObject *
_PyObject_FastCall_Prepend(PyObject *callable,
PyObject *obj, PyObject **args, Py_ssize_t nargs)
{
PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
PyObject **args2;
PyObject *result;
nargs++;
if (nargs <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
args2 = small_stack;
}
else {
args2 = PyMem_Malloc(nargs * sizeof(PyObject *));
if (args2 == NULL) {
PyErr_NoMemory();
return NULL;
}
}
/* use borrowed references */
args2[0] = obj;
memcpy(&args2[1],
args,
(nargs - 1)* sizeof(PyObject *));
result = _PyObject_FastCall(callable, args2, nargs);
if (args2 != small_stack) {
PyMem_Free(args2);
}
return result;
}
/* Call callable(obj, *args, **kwargs). */
PyObject *
_PyObject_Call_Prepend(PyObject *callable,
PyObject *obj, PyObject *args, PyObject *kwargs)
{
PyObject *small_stack[5];
PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
PyObject **stack;
Py_ssize_t argcount;
PyObject *result;
@ -2398,10 +2463,12 @@ _PyObject_Call_Prepend(PyObject *callable,
PyObject *
_PyStack_AsDict(PyObject **values, PyObject *kwnames)
{
Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames);
Py_ssize_t nkwargs;
PyObject *kwdict;
Py_ssize_t i;
assert(kwnames != NULL);
nkwargs = PyTuple_GET_SIZE(kwnames);
kwdict = _PyDict_NewPresized(nkwargs);
if (kwdict == NULL) {
return NULL;
@ -2410,8 +2477,6 @@ _PyStack_AsDict(PyObject **values, PyObject *kwnames)
for (i = 0; i < nkwargs; i++) {
PyObject *key = PyTuple_GET_ITEM(kwnames, i);
PyObject *value = *values++;
assert(PyUnicode_CheckExact(key));
assert(PyDict_GetItem(kwdict, key) == NULL);
if (PyDict_SetItem(kwdict, key, value)) {
Py_DECREF(kwdict);
return NULL;
@ -2420,9 +2485,9 @@ _PyStack_AsDict(PyObject **values, PyObject *kwnames)
return kwdict;
}
PyObject **
int
_PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs,
PyObject **p_kwnames, PyObject *func)
PyObject ***p_stack, PyObject **p_kwnames)
{
PyObject **stack, **kwstack;
Py_ssize_t nkwargs;
@ -2434,25 +2499,26 @@ _PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs,
assert(kwargs == NULL || PyDict_CheckExact(kwargs));
if (kwargs == NULL || (nkwargs = PyDict_GET_SIZE(kwargs)) == 0) {
*p_stack = args;
*p_kwnames = NULL;
return args;
return 0;
}
if ((size_t)nargs > PY_SSIZE_T_MAX / sizeof(stack[0]) - (size_t)nkwargs) {
PyErr_NoMemory();
return NULL;
return -1;
}
stack = PyMem_Malloc((nargs + nkwargs) * sizeof(stack[0]));
if (stack == NULL) {
PyErr_NoMemory();
return NULL;
return -1;
}
kwnames = PyTuple_New(nkwargs);
if (kwnames == NULL) {
PyMem_Free(stack);
return NULL;
return -1;
}
/* Copy position arguments (borrowed references) */
@ -2471,20 +2537,26 @@ _PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs,
i++;
}
*p_stack = stack;
*p_kwnames = kwnames;
return stack;
return 0;
}
PyObject *
_PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t nargs,
PyObject *kwnames)
{
/* _PyObject_FastCallKeywords() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the
caller loses its exception */
assert(!PyErr_Occurred());
assert(nargs >= 0);
assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
/* kwnames must only contains str strings, no subclass, and all keys must
be unique: these checks are implemented in Python/ceval.c and
_PyArg_ParseStack(). */
_PyArg_ParseStackAndKeywords(). */
if (PyFunction_Check(callable)) {
return _PyFunction_FastCallKeywords(callable, stack, nargs, kwnames);
@ -2497,47 +2569,48 @@ _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t narg
temporary dictionary for keyword arguments (if any) */
ternaryfunc call;
PyObject *argtuple;
PyObject *argstuple;
PyObject *kwdict, *result;
Py_ssize_t nkwargs;
result = NULL;
nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
if (Py_EnterRecursiveCall(" while calling a Python object")) {
return NULL;
}
call = callable->ob_type->tp_call;
if (call == NULL) {
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
callable->ob_type->tp_name);
goto exit;
return NULL;
}
argtuple = _PyStack_AsTuple(stack, nargs);
if (argtuple == NULL) {
goto exit;
argstuple = _PyStack_AsTuple(stack, nargs);
if (argstuple == NULL) {
return NULL;
}
if (nkwargs > 0) {
kwdict = _PyStack_AsDict(stack + nargs, kwnames);
if (kwdict == NULL) {
Py_DECREF(argtuple);
goto exit;
Py_DECREF(argstuple);
return NULL;
}
}
else {
kwdict = NULL;
}
result = (*call)(callable, argtuple, kwdict);
Py_DECREF(argtuple);
if (Py_EnterRecursiveCall(" while calling a Python object")) {
return NULL;
}
result = (*call)(callable, argstuple, kwdict);
Py_LeaveRecursiveCall();
Py_DECREF(argstuple);
Py_XDECREF(kwdict);
exit:
Py_LeaveRecursiveCall();
result = _Py_CheckFunctionResult(callable, result, NULL);
return result;
}
}
@ -2561,10 +2634,10 @@ _PyObject_CallFunctionVa(PyObject *callable, const char *format,
}
if (is_size_t) {
stack = _Py_VaBuildStack(small_stack, small_stack_len, format, va, &nargs);
stack = _Py_VaBuildStack_SizeT(small_stack, small_stack_len, format, va, &nargs);
}
else {
stack = _Py_VaBuildStack_SizeT(small_stack, small_stack_len, format, va, &nargs);
stack = _Py_VaBuildStack(small_stack, small_stack_len, format, va, &nargs);
}
if (stack == NULL) {
return NULL;

View file

@ -1,11 +1,4 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-
│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
Python 3
https://docs.python.org/3/license.html
╚─────────────────────────────────────────────────────────────────────────────*/
/* clang-format off */
/*[clinic input]
preserve
[clinic start generated code]*/
@ -74,7 +67,7 @@ bytearray_translate(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs,
PyObject *table;
PyObject *deletechars = NULL;
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&table, &deletechars)) {
goto exit;
}
@ -96,22 +89,26 @@ PyDoc_STRVAR(bytearray_maketrans__doc__,
"The bytes objects frm and to must be of the same length.");
#define BYTEARRAY_MAKETRANS_METHODDEF \
{"maketrans", (PyCFunction)bytearray_maketrans, METH_VARARGS|METH_STATIC, bytearray_maketrans__doc__},
{"maketrans", (PyCFunction)bytearray_maketrans, METH_FASTCALL|METH_STATIC, bytearray_maketrans__doc__},
static PyObject *
bytearray_maketrans_impl(Py_buffer *frm, Py_buffer *to);
static PyObject *
bytearray_maketrans(void *null, PyObject *args)
bytearray_maketrans(void *null, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
Py_buffer frm = {NULL, NULL};
Py_buffer to = {NULL, NULL};
if (!PyArg_ParseTuple(args, "y*y*:maketrans",
if (!_PyArg_ParseStack(args, nargs, "y*y*:maketrans",
&frm, &to)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("maketrans", kwnames)) {
goto exit;
}
return_value = bytearray_maketrans_impl(&frm, &to);
exit:
@ -141,24 +138,28 @@ PyDoc_STRVAR(bytearray_replace__doc__,
"replaced.");
#define BYTEARRAY_REPLACE_METHODDEF \
{"replace", (PyCFunction)bytearray_replace, METH_VARARGS, bytearray_replace__doc__},
{"replace", (PyCFunction)bytearray_replace, METH_FASTCALL, bytearray_replace__doc__},
static PyObject *
bytearray_replace_impl(PyByteArrayObject *self, Py_buffer *old,
Py_buffer *new, Py_ssize_t count);
static PyObject *
bytearray_replace(PyByteArrayObject *self, PyObject *args)
bytearray_replace(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
Py_buffer old = {NULL, NULL};
Py_buffer new = {NULL, NULL};
Py_ssize_t count = -1;
if (!PyArg_ParseTuple(args, "y*y*|n:replace",
if (!_PyArg_ParseStack(args, nargs, "y*y*|n:replace",
&old, &new, &count)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("replace", kwnames)) {
goto exit;
}
return_value = bytearray_replace_impl(self, &old, &new, count);
exit:
@ -204,7 +205,7 @@ bytearray_split(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyOb
PyObject *sep = Py_None;
Py_ssize_t maxsplit = -1;
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&sep, &maxsplit)) {
goto exit;
}
@ -279,7 +280,7 @@ bytearray_rsplit(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyO
PyObject *sep = Py_None;
Py_ssize_t maxsplit = -1;
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&sep, &maxsplit)) {
goto exit;
}
@ -319,22 +320,26 @@ PyDoc_STRVAR(bytearray_insert__doc__,
" The item to be inserted.");
#define BYTEARRAY_INSERT_METHODDEF \
{"insert", (PyCFunction)bytearray_insert, METH_VARARGS, bytearray_insert__doc__},
{"insert", (PyCFunction)bytearray_insert, METH_FASTCALL, bytearray_insert__doc__},
static PyObject *
bytearray_insert_impl(PyByteArrayObject *self, Py_ssize_t index, int item);
static PyObject *
bytearray_insert(PyByteArrayObject *self, PyObject *args)
bytearray_insert(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
Py_ssize_t index;
int item;
if (!PyArg_ParseTuple(args, "nO&:insert",
if (!_PyArg_ParseStack(args, nargs, "nO&:insert",
&index, _getbytevalue, &item)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("insert", kwnames)) {
goto exit;
}
return_value = bytearray_insert_impl(self, index, item);
exit:
@ -396,21 +401,25 @@ PyDoc_STRVAR(bytearray_pop__doc__,
"If no index argument is given, will pop the last item.");
#define BYTEARRAY_POP_METHODDEF \
{"pop", (PyCFunction)bytearray_pop, METH_VARARGS, bytearray_pop__doc__},
{"pop", (PyCFunction)bytearray_pop, METH_FASTCALL, bytearray_pop__doc__},
static PyObject *
bytearray_pop_impl(PyByteArrayObject *self, Py_ssize_t index);
static PyObject *
bytearray_pop(PyByteArrayObject *self, PyObject *args)
bytearray_pop(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
Py_ssize_t index = -1;
if (!PyArg_ParseTuple(args, "|n:pop",
if (!_PyArg_ParseStack(args, nargs, "|n:pop",
&index)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("pop", kwnames)) {
goto exit;
}
return_value = bytearray_pop_impl(self, index);
exit:
@ -456,22 +465,26 @@ PyDoc_STRVAR(bytearray_strip__doc__,
"If the argument is omitted or None, strip leading and trailing ASCII whitespace.");
#define BYTEARRAY_STRIP_METHODDEF \
{"strip", (PyCFunction)bytearray_strip, METH_VARARGS, bytearray_strip__doc__},
{"strip", (PyCFunction)bytearray_strip, METH_FASTCALL, bytearray_strip__doc__},
static PyObject *
bytearray_strip_impl(PyByteArrayObject *self, PyObject *bytes);
static PyObject *
bytearray_strip(PyByteArrayObject *self, PyObject *args)
bytearray_strip(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
PyObject *bytes = Py_None;
if (!PyArg_UnpackTuple(args, "strip",
if (!_PyArg_UnpackStack(args, nargs, "strip",
0, 1,
&bytes)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("strip", kwnames)) {
goto exit;
}
return_value = bytearray_strip_impl(self, bytes);
exit:
@ -487,22 +500,26 @@ PyDoc_STRVAR(bytearray_lstrip__doc__,
"If the argument is omitted or None, strip leading ASCII whitespace.");
#define BYTEARRAY_LSTRIP_METHODDEF \
{"lstrip", (PyCFunction)bytearray_lstrip, METH_VARARGS, bytearray_lstrip__doc__},
{"lstrip", (PyCFunction)bytearray_lstrip, METH_FASTCALL, bytearray_lstrip__doc__},
static PyObject *
bytearray_lstrip_impl(PyByteArrayObject *self, PyObject *bytes);
static PyObject *
bytearray_lstrip(PyByteArrayObject *self, PyObject *args)
bytearray_lstrip(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
PyObject *bytes = Py_None;
if (!PyArg_UnpackTuple(args, "lstrip",
if (!_PyArg_UnpackStack(args, nargs, "lstrip",
0, 1,
&bytes)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("lstrip", kwnames)) {
goto exit;
}
return_value = bytearray_lstrip_impl(self, bytes);
exit:
@ -518,22 +535,26 @@ PyDoc_STRVAR(bytearray_rstrip__doc__,
"If the argument is omitted or None, strip trailing ASCII whitespace.");
#define BYTEARRAY_RSTRIP_METHODDEF \
{"rstrip", (PyCFunction)bytearray_rstrip, METH_VARARGS, bytearray_rstrip__doc__},
{"rstrip", (PyCFunction)bytearray_rstrip, METH_FASTCALL, bytearray_rstrip__doc__},
static PyObject *
bytearray_rstrip_impl(PyByteArrayObject *self, PyObject *bytes);
static PyObject *
bytearray_rstrip(PyByteArrayObject *self, PyObject *args)
bytearray_rstrip(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
PyObject *bytes = Py_None;
if (!PyArg_UnpackTuple(args, "rstrip",
if (!_PyArg_UnpackStack(args, nargs, "rstrip",
0, 1,
&bytes)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("rstrip", kwnames)) {
goto exit;
}
return_value = bytearray_rstrip_impl(self, bytes);
exit:
@ -571,7 +592,7 @@ bytearray_decode(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyO
const char *encoding = NULL;
const char *errors = NULL;
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&encoding, &errors)) {
goto exit;
}
@ -617,7 +638,7 @@ bytearray_splitlines(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs,
static _PyArg_Parser _parser = {"|i:splitlines", _keywords, 0};
int keepends = 0;
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&keepends)) {
goto exit;
}
@ -682,21 +703,25 @@ PyDoc_STRVAR(bytearray_reduce_ex__doc__,
"Return state information for pickling.");
#define BYTEARRAY_REDUCE_EX_METHODDEF \
{"__reduce_ex__", (PyCFunction)bytearray_reduce_ex, METH_VARARGS, bytearray_reduce_ex__doc__},
{"__reduce_ex__", (PyCFunction)bytearray_reduce_ex, METH_FASTCALL, bytearray_reduce_ex__doc__},
static PyObject *
bytearray_reduce_ex_impl(PyByteArrayObject *self, int proto);
static PyObject *
bytearray_reduce_ex(PyByteArrayObject *self, PyObject *args)
bytearray_reduce_ex(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
int proto = 0;
if (!PyArg_ParseTuple(args, "|i:__reduce_ex__",
if (!_PyArg_ParseStack(args, nargs, "|i:__reduce_ex__",
&proto)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("__reduce_ex__", kwnames)) {
goto exit;
}
return_value = bytearray_reduce_ex_impl(self, proto);
exit:
@ -720,4 +745,4 @@ bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
{
return bytearray_sizeof_impl(self);
}
/*[clinic end generated code: output=8f022100f059226c input=a9049054013a1b77]*/
/*[clinic end generated code: output=c1b1b83b0e19df74 input=a9049054013a1b77]*/

View file

@ -1,11 +1,4 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-
│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
Python 3
https://docs.python.org/3/license.html
╚─────────────────────────────────────────────────────────────────────────────*/
/* clang-format off */
/*[clinic input]
preserve
[clinic start generated code]*/
@ -39,7 +32,7 @@ bytes_split(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kw
PyObject *sep = Py_None;
Py_ssize_t maxsplit = -1;
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&sep, &maxsplit)) {
goto exit;
}
@ -158,7 +151,7 @@ bytes_rsplit(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *k
PyObject *sep = Py_None;
Py_ssize_t maxsplit = -1;
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&sep, &maxsplit)) {
goto exit;
}
@ -192,22 +185,26 @@ PyDoc_STRVAR(bytes_strip__doc__,
"If the argument is omitted or None, strip leading and trailing ASCII whitespace.");
#define BYTES_STRIP_METHODDEF \
{"strip", (PyCFunction)bytes_strip, METH_VARARGS, bytes_strip__doc__},
{"strip", (PyCFunction)bytes_strip, METH_FASTCALL, bytes_strip__doc__},
static PyObject *
bytes_strip_impl(PyBytesObject *self, PyObject *bytes);
static PyObject *
bytes_strip(PyBytesObject *self, PyObject *args)
bytes_strip(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
PyObject *bytes = Py_None;
if (!PyArg_UnpackTuple(args, "strip",
if (!_PyArg_UnpackStack(args, nargs, "strip",
0, 1,
&bytes)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("strip", kwnames)) {
goto exit;
}
return_value = bytes_strip_impl(self, bytes);
exit:
@ -223,22 +220,26 @@ PyDoc_STRVAR(bytes_lstrip__doc__,
"If the argument is omitted or None, strip leading ASCII whitespace.");
#define BYTES_LSTRIP_METHODDEF \
{"lstrip", (PyCFunction)bytes_lstrip, METH_VARARGS, bytes_lstrip__doc__},
{"lstrip", (PyCFunction)bytes_lstrip, METH_FASTCALL, bytes_lstrip__doc__},
static PyObject *
bytes_lstrip_impl(PyBytesObject *self, PyObject *bytes);
static PyObject *
bytes_lstrip(PyBytesObject *self, PyObject *args)
bytes_lstrip(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
PyObject *bytes = Py_None;
if (!PyArg_UnpackTuple(args, "lstrip",
if (!_PyArg_UnpackStack(args, nargs, "lstrip",
0, 1,
&bytes)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("lstrip", kwnames)) {
goto exit;
}
return_value = bytes_lstrip_impl(self, bytes);
exit:
@ -254,22 +255,26 @@ PyDoc_STRVAR(bytes_rstrip__doc__,
"If the argument is omitted or None, strip trailing ASCII whitespace.");
#define BYTES_RSTRIP_METHODDEF \
{"rstrip", (PyCFunction)bytes_rstrip, METH_VARARGS, bytes_rstrip__doc__},
{"rstrip", (PyCFunction)bytes_rstrip, METH_FASTCALL, bytes_rstrip__doc__},
static PyObject *
bytes_rstrip_impl(PyBytesObject *self, PyObject *bytes);
static PyObject *
bytes_rstrip(PyBytesObject *self, PyObject *args)
bytes_rstrip(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
PyObject *bytes = Py_None;
if (!PyArg_UnpackTuple(args, "rstrip",
if (!_PyArg_UnpackStack(args, nargs, "rstrip",
0, 1,
&bytes)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("rstrip", kwnames)) {
goto exit;
}
return_value = bytes_rstrip_impl(self, bytes);
exit:
@ -304,7 +309,7 @@ bytes_translate(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject
PyObject *table;
PyObject *deletechars = NULL;
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&table, &deletechars)) {
goto exit;
}
@ -326,22 +331,26 @@ PyDoc_STRVAR(bytes_maketrans__doc__,
"The bytes objects frm and to must be of the same length.");
#define BYTES_MAKETRANS_METHODDEF \
{"maketrans", (PyCFunction)bytes_maketrans, METH_VARARGS|METH_STATIC, bytes_maketrans__doc__},
{"maketrans", (PyCFunction)bytes_maketrans, METH_FASTCALL|METH_STATIC, bytes_maketrans__doc__},
static PyObject *
bytes_maketrans_impl(Py_buffer *frm, Py_buffer *to);
static PyObject *
bytes_maketrans(void *null, PyObject *args)
bytes_maketrans(void *null, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
Py_buffer frm = {NULL, NULL};
Py_buffer to = {NULL, NULL};
if (!PyArg_ParseTuple(args, "y*y*:maketrans",
if (!_PyArg_ParseStack(args, nargs, "y*y*:maketrans",
&frm, &to)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("maketrans", kwnames)) {
goto exit;
}
return_value = bytes_maketrans_impl(&frm, &to);
exit:
@ -371,24 +380,28 @@ PyDoc_STRVAR(bytes_replace__doc__,
"replaced.");
#define BYTES_REPLACE_METHODDEF \
{"replace", (PyCFunction)bytes_replace, METH_VARARGS, bytes_replace__doc__},
{"replace", (PyCFunction)bytes_replace, METH_FASTCALL, bytes_replace__doc__},
static PyObject *
bytes_replace_impl(PyBytesObject *self, Py_buffer *old, Py_buffer *new,
Py_ssize_t count);
static PyObject *
bytes_replace(PyBytesObject *self, PyObject *args)
bytes_replace(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
Py_buffer old = {NULL, NULL};
Py_buffer new = {NULL, NULL};
Py_ssize_t count = -1;
if (!PyArg_ParseTuple(args, "y*y*|n:replace",
if (!_PyArg_ParseStack(args, nargs, "y*y*|n:replace",
&old, &new, &count)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("replace", kwnames)) {
goto exit;
}
return_value = bytes_replace_impl(self, &old, &new, count);
exit:
@ -435,7 +448,7 @@ bytes_decode(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *k
const char *encoding = NULL;
const char *errors = NULL;
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&encoding, &errors)) {
goto exit;
}
@ -468,7 +481,7 @@ bytes_splitlines(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObjec
static _PyArg_Parser _parser = {"|i:splitlines", _keywords, 0};
int keepends = 0;
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&keepends)) {
goto exit;
}
@ -507,4 +520,4 @@ bytes_fromhex(PyTypeObject *type, PyObject *arg)
exit:
return return_value;
}
/*[clinic end generated code: output=4ac7e35150d47467 input=a9049054013a1b77]*/
/*[clinic end generated code: output=debf785947e0eec2 input=a9049054013a1b77]*/

View file

@ -1,49 +1,48 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-
│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
Python 3
https://docs.python.org/3/license.html
╚─────────────────────────────────────────────────────────────────────────────*/
/* clang-format off */
/*[clinic input]
preserve
[clinic start generated code]*/
PyDoc_STRVAR(
dict_fromkeys__doc__,
"fromkeys($type, iterable, value=None, /)\n"
"--\n"
"\n"
"Returns a new dict with keys from iterable and values equal to value.");
PyDoc_STRVAR(dict_fromkeys__doc__,
"fromkeys($type, iterable, value=None, /)\n"
"--\n"
"\n"
"Returns a new dict with keys from iterable and values equal to value.");
#define DICT_FROMKEYS_METHODDEF \
{"fromkeys", (PyCFunction)dict_fromkeys, METH_VARARGS | METH_CLASS, \
dict_fromkeys__doc__},
#define DICT_FROMKEYS_METHODDEF \
{"fromkeys", (PyCFunction)dict_fromkeys, METH_FASTCALL|METH_CLASS, dict_fromkeys__doc__},
static PyObject *dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable,
PyObject *value);
static PyObject *
dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value);
static PyObject *dict_fromkeys(PyTypeObject *type, PyObject *args) {
PyObject *return_value = NULL;
PyObject *iterable;
PyObject *value = Py_None;
static PyObject *
dict_fromkeys(PyTypeObject *type, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
PyObject *iterable;
PyObject *value = Py_None;
if (!PyArg_UnpackTuple(args, "fromkeys", 1, 2, &iterable, &value)) {
goto exit;
}
return_value = dict_fromkeys_impl(type, iterable, value);
if (!_PyArg_UnpackStack(args, nargs, "fromkeys",
1, 2,
&iterable, &value)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("fromkeys", kwnames)) {
goto exit;
}
return_value = dict_fromkeys_impl(type, iterable, value);
exit:
return return_value;
return return_value;
}
PyDoc_STRVAR(dict___contains____doc__, "__contains__($self, key, /)\n"
"--\n"
"\n"
"True if D has a key k, else False.");
PyDoc_STRVAR(dict___contains____doc__,
"__contains__($self, key, /)\n"
"--\n"
"\n"
"True if D has a key k, else False.");
#define DICT___CONTAINS___METHODDEF \
{"__contains__", (PyCFunction)dict___contains__, METH_O | METH_COEXIST, \
dict___contains____doc__},
/*[clinic end generated code: output=926326109e3d9839 input=a9049054013a1b77]*/
#define DICT___CONTAINS___METHODDEF \
{"__contains__", (PyCFunction)dict___contains__, METH_O|METH_COEXIST, dict___contains____doc__},
/*[clinic end generated code: output=69f3d767ed44e8ec input=a9049054013a1b77]*/

View file

@ -0,0 +1,136 @@
/* clang-format off */
/*[clinic input]
preserve
[clinic start generated code]*/
PyDoc_STRVAR(OrderedDict_fromkeys__doc__,
"fromkeys($type, /, iterable, value=None)\n"
"--\n"
"\n"
"New ordered dictionary with keys from S.\n"
"\n"
"If not specified, the value defaults to None.");
#define ORDEREDDICT_FROMKEYS_METHODDEF \
{"fromkeys", (PyCFunction)OrderedDict_fromkeys, METH_FASTCALL|METH_CLASS, OrderedDict_fromkeys__doc__},
static PyObject *
OrderedDict_fromkeys_impl(PyTypeObject *type, PyObject *seq, PyObject *value);
static PyObject *
OrderedDict_fromkeys(PyTypeObject *type, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"iterable", "value", NULL};
static _PyArg_Parser _parser = {"O|O:fromkeys", _keywords, 0};
PyObject *seq;
PyObject *value = Py_None;
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&seq, &value)) {
goto exit;
}
return_value = OrderedDict_fromkeys_impl(type, seq, value);
exit:
return return_value;
}
PyDoc_STRVAR(OrderedDict_setdefault__doc__,
"setdefault($self, /, key, default=None)\n"
"--\n"
"\n"
"od.get(k,d), also set od[k]=d if k not in od.");
#define ORDEREDDICT_SETDEFAULT_METHODDEF \
{"setdefault", (PyCFunction)OrderedDict_setdefault, METH_FASTCALL, OrderedDict_setdefault__doc__},
static PyObject *
OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key,
PyObject *failobj);
static PyObject *
OrderedDict_setdefault(PyODictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"key", "default", NULL};
static _PyArg_Parser _parser = {"O|O:setdefault", _keywords, 0};
PyObject *key;
PyObject *failobj = Py_None;
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &failobj)) {
goto exit;
}
return_value = OrderedDict_setdefault_impl(self, key, failobj);
exit:
return return_value;
}
PyDoc_STRVAR(OrderedDict_popitem__doc__,
"popitem($self, /, last=True)\n"
"--\n"
"\n"
"Return (k, v) and remove a (key, value) pair.\n"
"\n"
"Pairs are returned in LIFO order if last is true or FIFO order if false.");
#define ORDEREDDICT_POPITEM_METHODDEF \
{"popitem", (PyCFunction)OrderedDict_popitem, METH_FASTCALL, OrderedDict_popitem__doc__},
static PyObject *
OrderedDict_popitem_impl(PyODictObject *self, int last);
static PyObject *
OrderedDict_popitem(PyODictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"last", NULL};
static _PyArg_Parser _parser = {"|p:popitem", _keywords, 0};
int last = 1;
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&last)) {
goto exit;
}
return_value = OrderedDict_popitem_impl(self, last);
exit:
return return_value;
}
PyDoc_STRVAR(OrderedDict_move_to_end__doc__,
"move_to_end($self, /, key, last=True)\n"
"--\n"
"\n"
"\"Move an existing element to the end (or beginning if last==False).\n"
"\n"
" Raises KeyError if the element does not exist.\n"
" When last=True, acts like a fast version of self[key]=self.pop(key).");
#define ORDEREDDICT_MOVE_TO_END_METHODDEF \
{"move_to_end", (PyCFunction)OrderedDict_move_to_end, METH_FASTCALL, OrderedDict_move_to_end__doc__},
static PyObject *
OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last);
static PyObject *
OrderedDict_move_to_end(PyODictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"key", "last", NULL};
static _PyArg_Parser _parser = {"O|p:move_to_end", _keywords, 0};
PyObject *key;
int last = 1;
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &last)) {
goto exit;
}
return_value = OrderedDict_move_to_end_impl(self, key, last);
exit:
return return_value;
}
/*[clinic end generated code: output=f2641e1277045b59 input=a9049054013a1b77]*/

View file

@ -1,11 +1,4 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-
│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
Python 3
https://docs.python.org/3/license.html
╚─────────────────────────────────────────────────────────────────────────────*/
/* clang-format off */
/*[clinic input]
preserve
[clinic start generated code]*/
@ -25,26 +18,30 @@ PyDoc_STRVAR(unicode_maketrans__doc__,
"must be a string, whose characters will be mapped to None in the result.");
#define UNICODE_MAKETRANS_METHODDEF \
{"maketrans", (PyCFunction)unicode_maketrans, METH_VARARGS|METH_STATIC, unicode_maketrans__doc__},
{"maketrans", (PyCFunction)unicode_maketrans, METH_FASTCALL|METH_STATIC, unicode_maketrans__doc__},
static PyObject *
unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z);
static PyObject *
unicode_maketrans(void *null, PyObject *args)
unicode_maketrans(void *null, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
PyObject *x;
PyObject *y = NULL;
PyObject *z = NULL;
if (!PyArg_ParseTuple(args, "O|UU:maketrans",
if (!_PyArg_ParseStack(args, nargs, "O|UU:maketrans",
&x, &y, &z)) {
goto exit;
}
if (!_PyArg_NoStackKeywords("maketrans", kwnames)) {
goto exit;
}
return_value = unicode_maketrans_impl(x, y, z);
exit:
return return_value;
}
/*[clinic end generated code: output=4a86dd108d92d104 input=a9049054013a1b77]*/
/*[clinic end generated code: output=af4804dbf21463b5 input=a9049054013a1b77]*/

View file

@ -228,15 +228,15 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
}
static PyObject *
methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
{
Py_ssize_t argc;
PyObject *self, *func, *result, **stack;
Py_ssize_t nargs;
PyObject *self, *result;
/* Make sure that the first argument is acceptable as 'self' */
assert(PyTuple_Check(args));
argc = PyTuple_GET_SIZE(args);
if (argc < 1) {
nargs = PyTuple_GET_SIZE(args);
if (nargs < 1) {
PyErr_Format(PyExc_TypeError,
"descriptor '%V' of '%.100s' "
"object needs an argument",
@ -257,12 +257,10 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
return NULL;
}
func = PyCFunction_NewEx(descr->d_method, self, NULL);
if (func == NULL)
return NULL;
stack = &PyTuple_GET_ITEM(args, 1);
result = _PyObject_FastCallDict(func, stack, argc - 1, kwds);
Py_DECREF(func);
result = _PyMethodDef_RawFastCallDict(descr->d_method, self,
&PyTuple_GET_ITEM(args, 1), nargs - 1,
kwargs);
result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
return result;
}

View file

@ -638,6 +638,51 @@ new_dict_with_shared_keys(PyDictKeysObject *keys)
return new_dict(keys, values);
}
static PyObject *
clone_combined_dict(PyDictObject *orig)
{
assert(PyDict_CheckExact(orig));
assert(orig->ma_values == NULL);
assert(orig->ma_keys->dk_refcnt == 1);
Py_ssize_t keys_size = _PyDict_KeysSize(orig->ma_keys);
PyDictKeysObject *keys = PyObject_Malloc(keys_size);
if (keys == NULL) {
PyErr_NoMemory();
return NULL;
}
memcpy(keys, orig->ma_keys, keys_size);
/* After copying key/value pairs, we need to incref all
keys and values and they are about to be co-owned by a
new dict object. */
PyDictKeyEntry *ep0 = DK_ENTRIES(keys);
Py_ssize_t n = keys->dk_nentries;
for (Py_ssize_t i = 0; i < n; i++) {
PyDictKeyEntry *entry = &ep0[i];
PyObject *value = entry->me_value;
if (value != NULL) {
Py_INCREF(value);
Py_INCREF(entry->me_key);
}
}
PyDictObject *new = (PyDictObject *)new_dict(keys, NULL);
if (new == NULL) {
/* In case of an error, `new_dict()` takes care of
cleaning up `keys`. */
return NULL;
}
new->ma_used = orig->ma_used;
assert(_PyDict_CheckConsistency(new));
if (_PyObject_GC_IS_TRACKED(orig)) {
/* Maintain tracking. */
_PyObject_GC_TRACK(new);
}
return (PyObject *)new;
}
PyObject *
PyDict_New(void)
{
@ -2656,6 +2701,12 @@ PyDict_Copy(PyObject *o)
return NULL;
}
mp = (PyDictObject *)o;
if (mp->ma_used == 0) {
/* The dict is empty; just return a new dict. */
return PyDict_New();
}
if (_PyDict_HasSplitTable(mp)) {
PyDictObject *split_copy;
Py_ssize_t size = USABLE_FRACTION(DK_SIZE(mp->ma_keys));
@ -2682,6 +2733,27 @@ PyDict_Copy(PyObject *o)
_PyObject_GC_TRACK(split_copy);
return (PyObject *)split_copy;
}
if (PyDict_CheckExact(mp) && mp->ma_values == NULL &&
(mp->ma_used >= (mp->ma_keys->dk_nentries * 2) / 3))
{
/* Use fast-copy if:
(1) 'mp' is an instance of a subclassed dict; and
(2) 'mp' is not a split-dict; and
(3) if 'mp' is non-compact ('del' operation does not resize dicts),
do fast-copy only if it has at most 1/3 non-used keys.
The last condition (3) is important to guard against a pathalogical
case when a large dict is almost emptied with multiple del/pop
operations and copied after that. In cases like this, we defer to
PyDict_Merge, which produces a compacted copy.
*/
return clone_combined_dict(mp);
}
copy = PyDict_New();
if (copy == NULL)
return NULL;
@ -2839,7 +2911,7 @@ dict___contains__(PyDictObject *self, PyObject *key)
}
static PyObject *
dict_get(PyDictObject *mp, PyObject *args)
dict_get(PyDictObject *mp, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key;
PyObject *failobj = Py_None;
@ -2848,7 +2920,10 @@ dict_get(PyDictObject *mp, PyObject *args)
Py_ssize_t ix;
PyObject **value_addr;
if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &failobj))
if (!_PyArg_UnpackStack(args, nargs, "get", 1, 2, &key, &failobj))
return NULL;
if (!_PyArg_NoStackKeywords("get", kwnames))
return NULL;
if (!PyUnicode_CheckExact(key) ||
@ -2957,14 +3032,17 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
}
static PyObject *
dict_setdefault(PyDictObject *mp, PyObject *args)
dict_setdefault(PyDictObject *mp, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key, *val;
PyObject *defaultobj = Py_None;
if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &key, &defaultobj))
if (!_PyArg_UnpackStack(args, nargs, "setdefault", 1, 2, &key, &defaultobj))
return NULL;
if(!_PyArg_NoStackKeywords("pop", kwnames))
return NULL;
val = PyDict_SetDefault((PyObject *)mp, key, defaultobj);
Py_XINCREF(val);
return val;
@ -2978,11 +3056,14 @@ dict_clear(PyDictObject *mp)
}
static PyObject *
dict_pop(PyDictObject *mp, PyObject *args)
dict_pop(PyDictObject *mp, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key, *deflt = NULL;
if(!PyArg_UnpackTuple(args, "pop", 1, 2, &key, &deflt))
if(!_PyArg_UnpackStack(args, nargs, "pop", 1, 2, &key, &deflt))
return NULL;
if(!_PyArg_NoStackKeywords("pop", kwnames))
return NULL;
return _PyDict_Pop((PyObject*)mp, key, deflt);
@ -3171,11 +3252,11 @@ static PyMethodDef mapp_methods[] = {
getitem__doc__},
{"__sizeof__", (PyCFunction)dict_sizeof, METH_NOARGS,
sizeof__doc__},
{"get", (PyCFunction)dict_get, METH_VARARGS,
{"get", (PyCFunction)dict_get, METH_FASTCALL,
get__doc__},
{"setdefault", (PyCFunction)dict_setdefault, METH_VARARGS,
{"setdefault", (PyCFunction)dict_setdefault, METH_FASTCALL,
setdefault_doc__},
{"pop", (PyCFunction)dict_pop, METH_VARARGS,
{"pop", (PyCFunction)dict_pop, METH_FASTCALL,
pop__doc__},
{"popitem", (PyCFunction)dict_popitem, METH_NOARGS,
popitem__doc__},

View file

@ -364,7 +364,7 @@ PyFile_NewStdPrinter(int fd)
}
static PyObject *
stdprinter_write(PyStdPrinter_Object *self, PyObject *args)
stdprinter_write(PyStdPrinter_Object *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *unicode;
PyObject *bytes = NULL;
@ -380,7 +380,10 @@ stdprinter_write(PyStdPrinter_Object *self, PyObject *args)
Py_RETURN_NONE;
}
if (!PyArg_ParseTuple(args, "U", &unicode))
if (!_PyArg_UnpackStack(args, nargs, "write", 1, 1, &unicode))
return NULL;
if(!_PyArg_NoStackKeywords("write", kwnames))
return NULL;
/* encode Unicode to UTF-8 */
@ -452,7 +455,7 @@ static PyMethodDef stdprinter_methods[] = {
{"flush", (PyCFunction)stdprinter_noop, METH_NOARGS, ""},
{"fileno", (PyCFunction)stdprinter_fileno, METH_NOARGS, ""},
{"isatty", (PyCFunction)stdprinter_isatty, METH_NOARGS, ""},
{"write", (PyCFunction)stdprinter_write, METH_VARARGS, ""},
{"write", (PyCFunction)stdprinter_write, METH_FASTCALL, ""},
{NULL, NULL} /*sentinel */
};

View file

@ -1038,15 +1038,19 @@ double_round(double x, int ndigits) {
/* round a Python float v to the closest multiple of 10**-ndigits */
static PyObject *
float_round(PyObject *v, PyObject *args)
float_round(PyObject *v, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
double x, rounded;
PyObject *o_ndigits = NULL;
Py_ssize_t ndigits;
x = PyFloat_AsDouble(v);
if (!PyArg_ParseTuple(args, "|O", &o_ndigits))
if (!_PyArg_UnpackStack(args, nargs, "__round__", 0, 1, &o_ndigits))
return NULL;
if(!_PyArg_NoStackKeywords("__round__", kwnames))
return NULL;
if (o_ndigits == NULL || o_ndigits == Py_None) {
/* single-argument round or with None ndigits:
* round to nearest integer */
@ -1762,13 +1766,16 @@ float_getzero(PyObject *v, void *closure)
}
static PyObject *
float__format__(PyObject *self, PyObject *args)
float__format__(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *format_spec;
_PyUnicodeWriter writer;
int ret;
if (!PyArg_ParseTuple(args, "U:__format__", &format_spec))
if (!_PyArg_ParseStack(args, nargs, "U:__format__", &format_spec))
return NULL;
if(!_PyArg_NoStackKeywords("__format__", kwnames))
return NULL;
_PyUnicodeWriter_Init(&writer);
@ -1794,7 +1801,7 @@ static PyMethodDef float_methods[] = {
"Return self, the complex conjugate of any float."},
{"__trunc__", (PyCFunction)float_trunc, METH_NOARGS,
"Return the Integral closest to x between 0 and x."},
{"__round__", (PyCFunction)float_round, METH_VARARGS,
{"__round__", (PyCFunction)float_round, METH_FASTCALL,
"Return the Integral closest to x, rounding half toward even.\n"
"When an argument is passed, work like built-in round(x, ndigits)."},
{"as_integer_ratio", (PyCFunction)float_as_integer_ratio, METH_NOARGS,
@ -1819,7 +1826,7 @@ static PyMethodDef float_methods[] = {
{"__setformat__", (PyCFunction)float_setformat,
METH_VARARGS|METH_CLASS, float_setformat_doc},
{"__format__", (PyCFunction)float__format__,
METH_VARARGS, float__format__doc},
METH_FASTCALL, float__format__doc},
{NULL, NULL} /* sentinel */
};

View file

@ -755,11 +755,12 @@ list_ass_item(PyListObject *a, Py_ssize_t i, PyObject *v)
}
static PyObject *
listinsert(PyListObject *self, PyObject *args)
listinsert(PyListObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
Py_ssize_t i;
PyObject *v;
if (!PyArg_ParseTuple(args, "nO:insert", &i, &v))
if (!_PyArg_ParseStack(args, nargs, "nO:insert", &i, &v)
|| !_PyArg_NoStackKeywords("insert", kwnames))
return NULL;
if (ins1(self, i, v) == 0)
Py_RETURN_NONE;
@ -920,13 +921,14 @@ list_inplace_concat(PyListObject *self, PyObject *other)
}
static PyObject *
listpop(PyListObject *self, PyObject *args)
listpop(PyListObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
Py_ssize_t i = -1;
PyObject *v;
int status;
if (!PyArg_ParseTuple(args, "|n:pop", &i))
if (!_PyArg_ParseStack(args, nargs, "|n:pop", &i)
|| !_PyArg_NoStackKeywords("pop", kwnames))
return NULL;
if (Py_SIZE(self) == 0) {
@ -2384,9 +2386,9 @@ static PyMethodDef list_methods[] = {
{"clear", (PyCFunction)listclear, METH_NOARGS, clear_doc},
{"copy", (PyCFunction)listcopy, METH_NOARGS, copy_doc},
{"append", (PyCFunction)listappend, METH_O, append_doc},
{"insert", (PyCFunction)listinsert, METH_VARARGS, insert_doc},
{"insert", (PyCFunction)listinsert, METH_FASTCALL, insert_doc},
{"extend", (PyCFunction)listextend, METH_O, extend_doc},
{"pop", (PyCFunction)listpop, METH_VARARGS, pop_doc},
{"pop", (PyCFunction)listpop, METH_FASTCALL, pop_doc},
{"remove", (PyCFunction)listremove, METH_O, remove_doc},
{"index", (PyCFunction)listindex, METH_VARARGS, index_doc},
{"count", (PyCFunction)listcount, METH_O, count_doc},

View file

@ -4907,13 +4907,13 @@ long_get1(PyLongObject *v, void *context) {
}
static PyObject *
long__format__(PyObject *self, PyObject *args)
long__format__(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *format_spec;
_PyUnicodeWriter writer;
int ret;
if (!PyArg_ParseTuple(args, "U:__format__", &format_spec))
if (!_PyArg_ParseStack(args, nargs, "U:__format__", &format_spec))
return NULL;
_PyUnicodeWriter_Init(&writer);
@ -5026,7 +5026,7 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b)
}
static PyObject *
long_round(PyObject *self, PyObject *args)
long_round(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *o_ndigits=NULL, *temp, *result, *ndigits;
@ -5044,7 +5044,7 @@ long_round(PyObject *self, PyObject *args)
*
* m - divmod_near(m, 10**n)[1].
*/
if (!PyArg_ParseTuple(args, "|O", &o_ndigits))
if (!_PyArg_ParseStack(args, nargs, "|O", &o_ndigits))
return NULL;
if (o_ndigits == NULL)
return long_long(self);
@ -5368,11 +5368,11 @@ static PyMethodDef long_methods[] = {
"Flooring an Integral returns itself."},
{"__ceil__", (PyCFunction)long_long, METH_NOARGS,
"Ceiling of an Integral returns itself."},
{"__round__", (PyCFunction)long_round, METH_VARARGS,
{"__round__", (PyCFunction)long_round, METH_FASTCALL,
"Rounding an Integral returns itself.\n"
"Rounding with an ndigits argument also returns an integer."},
{"__getnewargs__", (PyCFunction)long_getnewargs, METH_NOARGS},
{"__format__", (PyCFunction)long__format__, METH_VARARGS},
{"__format__", (PyCFunction)long__format__, METH_FASTCALL},
{"__sizeof__", (PyCFunction)long_sizeof, METH_NOARGS,
"Returns size in memory, in bytes"},
{NULL, NULL} /* sentinel */

View file

@ -90,117 +90,95 @@ PyCFunction_GetFlags(PyObject *op)
return PyCFunction_GET_FLAGS(op);
}
PyObject *
PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds)
static PyObject *
cfunction_call_varargs(PyObject *func, PyObject *args, PyObject *kwargs)
{
PyCFunctionObject* f = (PyCFunctionObject*)func;
assert(!PyErr_Occurred());
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
PyObject *self = PyCFunction_GET_SELF(func);
PyObject *arg, *res;
Py_ssize_t size;
int flags;
PyObject *result;
assert(kwds == NULL || PyDict_Check(kwds));
/* PyCFunction_Call() must not be called with an exception set,
if (PyCFunction_GET_FLAGS(func) & METH_KEYWORDS) {
if (Py_EnterRecursiveCall(" while calling a Python object")) {
return NULL;
}
result = (*(PyCFunctionWithKeywords)meth)(self, args, kwargs);
Py_LeaveRecursiveCall();
}
else {
if (kwargs != NULL && PyDict_Size(kwargs) != 0) {
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
((PyCFunctionObject*)func)->m_ml->ml_name);
return NULL;
}
if (Py_EnterRecursiveCall(" while calling a Python object")) {
return NULL;
}
result = (*meth)(self, args);
Py_LeaveRecursiveCall();
}
return _Py_CheckFunctionResult(func, result, NULL);
}
PyObject *
PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs)
{
/* first try METH_VARARGS to pass directly args tuple unchanged.
_PyMethodDef_RawFastCallDict() creates a new temporary tuple
for METH_VARARGS. */
if (PyCFunction_GET_FLAGS(func) & METH_VARARGS) {
return cfunction_call_varargs(func, args, kwargs);
}
else {
return _PyCFunction_FastCallDict(func,
&PyTuple_GET_ITEM(args, 0),
PyTuple_GET_SIZE(args),
kwargs);
}
}
PyObject *
_PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args,
Py_ssize_t nargs, PyObject *kwargs)
{
/* _PyMethodDef_RawFastCallDict() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the
caller loses its exception */
assert(!PyErr_Occurred());
flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
if (flags == (METH_VARARGS | METH_KEYWORDS)) {
res = (*(PyCFunctionWithKeywords)meth)(self, args, kwds);
}
else if (flags == METH_FASTCALL) {
PyObject **stack = &PyTuple_GET_ITEM(args, 0);
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
res = _PyCFunction_FastCallDict(func, stack, nargs, kwds);
}
else {
if (kwds != NULL && PyDict_GET_SIZE(kwds) != 0) {
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
f->m_ml->ml_name);
return NULL;
}
switch (flags) {
case METH_VARARGS:
res = (*meth)(self, args);
break;
case METH_NOARGS:
size = PyTuple_GET_SIZE(args);
if (size != 0) {
PyErr_Format(PyExc_TypeError,
"%.200s() takes no arguments (%zd given)",
f->m_ml->ml_name, size);
return NULL;
}
res = (*meth)(self, NULL);
break;
case METH_O:
size = PyTuple_GET_SIZE(args);
if (size != 1) {
PyErr_Format(PyExc_TypeError,
"%.200s() takes exactly one argument (%zd given)",
f->m_ml->ml_name, size);
return NULL;
}
arg = PyTuple_GET_ITEM(args, 0);
res = (*meth)(self, arg);
break;
default:
PyErr_SetString(PyExc_SystemError,
"Bad call flags in PyCFunction_Call. "
"METH_OLDARGS is no longer supported!");
return NULL;
}
}
return _Py_CheckFunctionResult(func, res, NULL);
}
PyObject *
_PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
PyObject *kwargs)
{
PyCFunctionObject *func;
PyCFunction meth;
PyObject *self;
PyObject *result;
int flags;
assert(func_obj != NULL);
assert(PyCFunction_Check(func_obj));
assert(method != NULL);
assert(nargs >= 0);
assert(nargs == 0 || args != NULL);
assert(kwargs == NULL || PyDict_Check(kwargs));
/* _PyCFunction_FastCallDict() must not be called with an exception set,
because it may clear it (directly or indirectly) and so the
caller loses its exception */
assert(!PyErr_Occurred());
PyCFunction meth = method->ml_meth;
int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
PyObject *result = NULL;
func = (PyCFunctionObject*)func_obj;
meth = PyCFunction_GET_FUNCTION(func);
self = PyCFunction_GET_SELF(func);
flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
if (Py_EnterRecursiveCall(" while calling a Python object")) {
return NULL;
}
switch (flags)
{
case METH_NOARGS:
if (nargs != 0) {
goto no_keyword_error;
PyErr_Format(PyExc_TypeError,
"%.200s() takes no arguments (%zd given)",
method->ml_name, nargs);
goto exit;
}
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
func->m_ml->ml_name);
return NULL;
goto no_keyword_error;
}
result = (*meth) (self, NULL);
@ -210,8 +188,8 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
if (nargs != 1) {
PyErr_Format(PyExc_TypeError,
"%.200s() takes exactly one argument (%zd given)",
func->m_ml->ml_name, nargs);
return NULL;
method->ml_name, nargs);
goto exit;
}
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
@ -222,28 +200,27 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
break;
case METH_VARARGS:
case METH_VARARGS | METH_KEYWORDS:
{
/* Slow-path: create a temporary tuple for positional arguments */
PyObject *tuple;
if (!(flags & METH_KEYWORDS)
&& kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
goto no_keyword_error;
}
/* fall through next case */
tuple = _PyStack_AsTuple(args, nargs);
if (tuple == NULL) {
return NULL;
case METH_VARARGS | METH_KEYWORDS:
{
/* Slow-path: create a temporary tuple for positional arguments */
PyObject *argstuple = _PyStack_AsTuple(args, nargs);
if (argstuple == NULL) {
goto exit;
}
if (flags & METH_KEYWORDS) {
result = (*(PyCFunctionWithKeywords)meth) (self, tuple, kwargs);
result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs);
}
else {
result = (*meth) (self, tuple);
result = (*meth) (self, argstuple);
}
Py_DECREF(tuple);
Py_DECREF(argstuple);
break;
}
@ -253,9 +230,8 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
PyObject *kwnames;
_PyCFunctionFast fastmeth = (_PyCFunctionFast)meth;
stack = _PyStack_UnpackDict(args, nargs, kwargs, &kwnames, func_obj);
if (stack == NULL) {
return NULL;
if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) {
goto exit;
}
result = (*fastmeth) (self, stack, nargs, kwnames);
@ -268,49 +244,62 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
default:
PyErr_SetString(PyExc_SystemError,
"Bad call flags in PyCFunction_Call. "
"Bad call flags in _PyMethodDef_RawFastCallDict. "
"METH_OLDARGS is no longer supported!");
return NULL;
goto exit;
}
result = _Py_CheckFunctionResult(func_obj, result, NULL);
return result;
goto exit;
no_keyword_error:
PyErr_Format(PyExc_TypeError,
"%.200s() takes no arguments (%zd given)",
func->m_ml->ml_name, nargs);
return NULL;
"%.200s() takes no keyword arguments",
method->ml_name, nargs);
exit:
Py_LeaveRecursiveCall();
return result;
}
PyObject *
_PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args,
Py_ssize_t nargs, PyObject *kwnames)
_PyCFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
PyObject *kwargs)
{
PyCFunctionObject *func;
PyCFunction meth;
PyObject *self, *result;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
int flags;
PyObject *result;
assert(func_obj != NULL);
assert(PyCFunction_Check(func_obj));
assert(func != NULL);
assert(PyCFunction_Check(func));
result = _PyMethodDef_RawFastCallDict(((PyCFunctionObject*)func)->m_ml,
PyCFunction_GET_SELF(func),
args, nargs, kwargs);
result = _Py_CheckFunctionResult(func, result, NULL);
return result;
}
PyObject *
_PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject **args,
Py_ssize_t nargs, PyObject *kwnames)
{
/* _PyMethodDef_RawFastCallKeywords() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the
caller loses its exception */
assert(!PyErr_Occurred());
assert(method != NULL);
assert(nargs >= 0);
assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
assert((nargs == 0 && nkwargs == 0) || args != NULL);
/* kwnames must only contains str strings, no subclass, and all keys must
be unique */
/* _PyCFunction_FastCallKeywords() must not be called with an exception
set, because it can clear it (directly or indirectly) and so the caller
loses its exception */
assert(!PyErr_Occurred());
PyCFunction meth = method->ml_meth;
int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_Size(kwnames);
PyObject *result = NULL;
func = (PyCFunctionObject*)func_obj;
meth = PyCFunction_GET_FUNCTION(func);
self = PyCFunction_GET_SELF(func);
flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
if (Py_EnterRecursiveCall(" while calling a Python object")) {
return NULL;
}
switch (flags)
{
@ -318,8 +307,8 @@ _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args,
if (nargs != 0) {
PyErr_Format(PyExc_TypeError,
"%.200s() takes no arguments (%zd given)",
func->m_ml->ml_name, nargs);
return NULL;
method->ml_name, nargs);
goto exit;
}
if (nkwargs) {
@ -333,8 +322,8 @@ _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args,
if (nargs != 1) {
PyErr_Format(PyExc_TypeError,
"%.200s() takes exactly one argument (%zd given)",
func->m_ml->ml_name, nargs);
return NULL;
method->ml_name, nargs);
goto exit;
}
if (nkwargs) {
@ -362,7 +351,7 @@ _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args,
argtuple = _PyStack_AsTuple(args, nargs);
if (argtuple == NULL) {
return NULL;
goto exit;
}
if (flags & METH_KEYWORDS) {
@ -372,7 +361,7 @@ _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args,
kwdict = _PyStack_AsDict(args + nargs, kwnames);
if (kwdict == NULL) {
Py_DECREF(argtuple);
return NULL;
goto exit;
}
}
else {
@ -393,19 +382,39 @@ _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args,
PyErr_SetString(PyExc_SystemError,
"Bad call flags in _PyCFunction_FastCallKeywords. "
"METH_OLDARGS is no longer supported!");
return NULL;
goto exit;
}
result = _Py_CheckFunctionResult(func_obj, result, NULL);
return result;
goto exit;
no_keyword_error:
PyErr_Format(PyExc_TypeError,
"%.200s() takes no keyword arguments",
func->m_ml->ml_name);
return NULL;
method->ml_name);
exit:
Py_LeaveRecursiveCall();
return result;
}
PyObject *
_PyCFunction_FastCallKeywords(PyObject *func, PyObject **args,
Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *result;
assert(func != NULL);
assert(PyCFunction_Check(func));
result = _PyMethodDef_RawFastCallKeywords(((PyCFunctionObject*)func)->m_ml,
PyCFunction_GET_SELF(func),
args, nargs, kwnames);
result = _Py_CheckFunctionResult(func, result, NULL);
return result;
}
/* Methods (the standard built-in methods, that is) */
static void

View file

@ -1255,6 +1255,7 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
return res;
}
int
PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
{

View file

@ -90,7 +90,7 @@ Linked-List API
As noted, the linked-list implemented here does not have all the bells and
whistles. However, we recognize that the implementation may need to
change to accommodate performance improvements or extra functionality. To
that end, we use a simple API to interact with the linked-list. Here's a
that end, We use a simple API to interact with the linked-list. Here's a
summary of the methods/macros:
Node info:
@ -124,6 +124,10 @@ Others:
* _odict_find_node(od, key)
* _odict_keys_equal(od1, od2)
Used, but specific to the linked-list implementation:
* _odict_free_fast_nodes(od)
And here's a look at how the linked-list relates to the OrderedDict API:
============ === === ==== ==== ==== === ==== ===== ==== ==== === ==== === ===
@ -397,6 +401,7 @@ tp_iter odict_iter
tp_dictoffset (offset)
tp_init odict_init
tp_alloc (repeated)
tp_new odict_new
================= ================
================= ================
@ -462,7 +467,7 @@ Potential Optimizations
- Set node->key to NULL to indicate the node is not-in-use.
- Add _odict_EXISTS()?
- How to maintain consistency across resizes? Existing node pointers
would be invalidated after a resize, which is particularly problematic
would be invalidate after a resize, which is particularly problematic
for the iterators.
* Use a more stream-lined implementation of update() and, likely indirectly,
__init__().
@ -487,6 +492,14 @@ later:
*/
#include "third_party/python/Objects/clinic/odictobject.inc"
/*[clinic input]
class OrderedDict "PyODictObject *" "&PyODict_Type"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ca0641cf6143d4af]*/
typedef struct _odictnode _ODictNode;
/* PyODictObject */
@ -534,15 +547,24 @@ struct _odictnode {
#define _odict_FOREACH(od, node) \
for (node = _odict_FIRST(od); node != NULL; node = _odictnode_NEXT(node))
#define _odict_FAST_SIZE(od) ((PyDictObject *)od)->ma_keys->dk_size
static void
_odict_free_fast_nodes(PyODictObject *od) {
if (od->od_fast_nodes) {
PyMem_FREE(od->od_fast_nodes);
}
}
/* Return the index into the hash table, regardless of a valid node. */
static Py_ssize_t
_odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
{
PyObject **value_addr = NULL;
PyObject **value = NULL;
PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys;
Py_ssize_t ix;
ix = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value_addr, NULL);
ix = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value, NULL);
if (ix == DKIX_EMPTY) {
return keys->dk_nentries; /* index of new entry */
}
@ -554,8 +576,7 @@ _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
/* Replace od->od_fast_nodes with a new table matching the size of dict's. */
static int
_odict_resize(PyODictObject *od)
{
_odict_resize(PyODictObject *od) {
Py_ssize_t size, i;
_ODictNode **fast_nodes, *node;
@ -581,7 +602,7 @@ _odict_resize(PyODictObject *od)
}
/* Replace the old fast nodes table. */
PyMem_FREE(od->od_fast_nodes);
_odict_free_fast_nodes(od);
od->od_fast_nodes = fast_nodes;
od->od_fast_nodes_size = size;
od->od_resize_sentinel = ((PyDictObject *)od)->ma_keys;
@ -619,7 +640,6 @@ _odict_find_node_hash(PyODictObject *od, PyObject *key, Py_hash_t hash)
index = _odict_get_index(od, key, hash);
if (index < 0)
return NULL;
assert(od->od_fast_nodes != NULL);
return od->od_fast_nodes[index];
}
@ -637,7 +657,6 @@ _odict_find_node(PyODictObject *od, PyObject *key)
index = _odict_get_index(od, key, hash);
if (index < 0)
return NULL;
assert(od->od_fast_nodes != NULL);
return od->od_fast_nodes[index];
}
@ -682,8 +701,7 @@ _odict_add_new_node(PyODictObject *od, PyObject *key, Py_hash_t hash)
Py_DECREF(key);
return -1;
}
assert(od->od_fast_nodes != NULL);
if (od->od_fast_nodes[i] != NULL) {
else if (od->od_fast_nodes[i] != NULL) {
/* We already have a node for the key so there's no need to add one. */
Py_DECREF(key);
return 0;
@ -762,7 +780,6 @@ _odict_clear_node(PyODictObject *od, _ODictNode *node, PyObject *key,
if (i < 0)
return PyErr_Occurred() ? -1 : 0;
assert(od->od_fast_nodes != NULL);
if (node == NULL)
node = od->od_fast_nodes[i];
assert(node == od->od_fast_nodes[i]);
@ -783,10 +800,8 @@ _odict_clear_nodes(PyODictObject *od)
{
_ODictNode *node, *next;
PyMem_FREE(od->od_fast_nodes);
_odict_free_fast_nodes(od);
od->od_fast_nodes = NULL;
od->od_fast_nodes_size = 0;
od->od_resize_sentinel = NULL;
node = _odict_FIRST(od);
_odict_FIRST(od) = NULL;
@ -885,7 +900,8 @@ odict_eq(PyObject *a, PyObject *b)
PyDoc_STRVAR(odict_init__doc__,
"Initialize an ordered dictionary. The signature is the same as\n\
regular dictionaries. Keyword argument order is preserved.\n\
regular dictionaries, but keyword arguments are not recommended because\n\
their insertion order is arbitrary.\n\
\n\
");
@ -921,25 +937,23 @@ PyDoc_STRVAR(odict_setitem__doc__, "od.__setitem__(i, y) <==> od[i]=y");
/* fromkeys() */
PyDoc_STRVAR(odict_fromkeys__doc__,
"OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.\n\
If not specified, the value defaults to None.\n\
\n\
");
/*[clinic input]
@classmethod
OrderedDict.fromkeys
iterable as seq: object
value: object = None
New ordered dictionary with keys from S.
If not specified, the value defaults to None.
[clinic start generated code]*/
static PyObject *
odict_fromkeys(PyObject *cls, PyObject *args, PyObject *kwargs)
OrderedDict_fromkeys_impl(PyTypeObject *type, PyObject *seq, PyObject *value)
/*[clinic end generated code: output=c10390d452d78d6d input=33eefc496d5eee7b]*/
{
static char *kwlist[] = {"iterable", "value", 0};
PyObject *seq;
PyObject *value = Py_None;
/* both borrowed */
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:fromkeys", kwlist,
&seq, &value)) {
return NULL;
}
return _PyDict_FromKeys(cls, seq, value);
return _PyDict_FromKeys((PyObject *)type, seq, value);
}
/* __sizeof__() */
@ -951,7 +965,7 @@ static PyObject *
odict_sizeof(PyODictObject *od)
{
Py_ssize_t res = _PyDict_SizeOf((PyDictObject *)od);
res += sizeof(_ODictNode *) * od->od_fast_nodes_size; /* od_fast_nodes */
res += sizeof(_ODictNode *) * _odict_FAST_SIZE(od); /* od_fast_nodes */
if (!_odict_EMPTY(od)) {
res += sizeof(_ODictNode) * PyODict_SIZE(od); /* linked-list */
}
@ -1009,32 +1023,32 @@ Done:
return result;
}
/* setdefault() */
/* setdefault(): Skips __missing__() calls. */
PyDoc_STRVAR(odict_setdefault__doc__,
"od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od");
/* Skips __missing__() calls. */
/*[clinic input]
OrderedDict.setdefault
key: object
default as failobj: object = None
od.get(k,d), also set od[k]=d if k not in od.
[clinic start generated code]*/
static PyObject *
odict_setdefault(register PyODictObject *od, PyObject *args, PyObject *kwargs)
OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key,
PyObject *failobj)
/*[clinic end generated code: output=605d0f6f61ccb0a6 input=4ee5006f32f5691b]*/
{
static char *kwlist[] = {"key", "default", 0};
PyObject *key, *result = NULL;
PyObject *failobj = Py_None;
PyObject *result = NULL;
/* both borrowed */
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:setdefault", kwlist,
&key, &failobj)) {
return NULL;
}
if (PyODict_CheckExact(od)) {
result = PyODict_GetItemWithError(od, key); /* borrowed */
if (PyODict_CheckExact(self)) {
result = PyODict_GetItemWithError(self, key); /* borrowed */
if (result == NULL) {
if (PyErr_Occurred())
return NULL;
assert(_odict_find_node(od, key) == NULL);
if (PyODict_SetItem((PyObject *)od, key, failobj) >= 0) {
assert(_odict_find_node(self, key) == NULL);
if (PyODict_SetItem((PyObject *)self, key, failobj) >= 0) {
result = failobj;
Py_INCREF(failobj);
}
@ -1044,14 +1058,14 @@ odict_setdefault(register PyODictObject *od, PyObject *args, PyObject *kwargs)
}
}
else {
int exists = PySequence_Contains((PyObject *)od, key);
int exists = PySequence_Contains((PyObject *)self, key);
if (exists < 0) {
return NULL;
}
else if (exists) {
result = PyObject_GetItem((PyObject *)od, key);
result = PyObject_GetItem((PyObject *)self, key);
}
else if (PyObject_SetItem((PyObject *)od, key, failobj) >= 0) {
else if (PyObject_SetItem((PyObject *)self, key, failobj) >= 0) {
result = failobj;
Py_INCREF(failobj);
}
@ -1161,41 +1175,37 @@ _odict_popkey(PyObject *od, PyObject *key, PyObject *failobj)
return _odict_popkey_hash(od, key, failobj, hash);
}
/* popitem() */
PyDoc_STRVAR(odict_popitem__doc__,
"popitem($self, /, last=True)\n"
"--\n"
"\n"
"Remove and return a (key, value) pair from the dictionary.\n"
"\n"
"Pairs are returned in LIFO order if last is true or FIFO order if false.");
/*[clinic input]
OrderedDict.popitem
last: bool = True
Return (k, v) and remove a (key, value) pair.
Pairs are returned in LIFO order if last is true or FIFO order if false.
[clinic start generated code]*/
static PyObject *
odict_popitem(PyObject *od, PyObject *args, PyObject *kwargs)
OrderedDict_popitem_impl(PyODictObject *self, int last)
/*[clinic end generated code: output=98e7d986690d49eb input=4937da2015939126]*/
{
static char *kwlist[] = {"last", 0};
PyObject *key, *value, *item = NULL;
_ODictNode *node;
int last = 1;
/* pull the item */
/* borrowed */
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|p:popitem", kwlist,
&last)) {
return NULL;
}
if (_odict_EMPTY(od)) {
if (_odict_EMPTY(self)) {
PyErr_SetString(PyExc_KeyError, "dictionary is empty");
return NULL;
}
node = last ? _odict_LAST(od) : _odict_FIRST(od);
node = last ? _odict_LAST(self) : _odict_FIRST(self);
key = _odictnode_KEY(node);
Py_INCREF(key);
value = _odict_popkey_hash(od, key, NULL, _odictnode_HASH(node));
value = _odict_popkey_hash((PyObject *)self, key, NULL, _odictnode_HASH(node));
if (value == NULL)
return NULL;
item = PyTuple_Pack(2, key, value);
@ -1241,10 +1251,12 @@ PyDoc_STRVAR(odict_clear__doc__,
"od.clear() -> None. Remove all items from od.");
static PyObject *
odict_clear(register PyODictObject *od, PyObject *Py_UNUSED(ignored))
odict_clear(register PyODictObject *od)
{
PyDict_Clear((PyObject *)od);
_odict_clear_nodes(od);
if (_odict_resize(od) < 0)
return NULL;
Py_RETURN_NONE;
}
@ -1265,7 +1277,7 @@ odict_copy(register PyODictObject *od)
if (PyODict_CheckExact(od))
od_copy = PyODict_New();
else
od_copy = PyObject_CallFunctionObjArgs((PyObject *)Py_TYPE(od), NULL);
od_copy = _PyObject_CallNoArg((PyObject *)Py_TYPE(od));
if (od_copy == NULL)
return NULL;
@ -1321,36 +1333,34 @@ odict_reversed(PyODictObject *od)
return odictiter_new(od, _odict_ITER_KEYS|_odict_ITER_REVERSED);
}
/* move_to_end() */
PyDoc_STRVAR(odict_move_to_end__doc__,
"Move an existing element to the end (or beginning if last==False).\n\
\n\
Raises KeyError if the element does not exist.\n\
When last=True, acts like a fast version of self[key]=self.pop(key).\n\
\n\
");
/*[clinic input]
OrderedDict.move_to_end
key: object
last: bool = True
"Move an existing element to the end (or beginning if last==False).
Raises KeyError if the element does not exist.
When last=True, acts like a fast version of self[key]=self.pop(key).
[clinic start generated code]*/
static PyObject *
odict_move_to_end(PyODictObject *od, PyObject *args, PyObject *kwargs)
OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last)
/*[clinic end generated code: output=fafa4c5cc9b92f20 input=3b8283f7d0e15e43]*/
{
static char *kwlist[] = {"key", "last", 0};
PyObject *key;
int last = 1;
_ODictNode *node;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|p:move_to_end", kwlist,
&key, &last)) {
return NULL;
}
if (_odict_EMPTY(od)) {
if (_odict_EMPTY(self)) {
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
}
node = last ? _odict_LAST(od) : _odict_FIRST(od);
node = last ? _odict_LAST(self) : _odict_FIRST(self);
if (key != _odictnode_KEY(node)) {
node = _odict_find_node(od, key);
node = _odict_find_node(self, key);
if (node == NULL) {
if (!PyErr_Occurred())
PyErr_SetObject(PyExc_KeyError, key);
@ -1358,16 +1368,16 @@ odict_move_to_end(PyODictObject *od, PyObject *args, PyObject *kwargs)
}
if (last) {
/* Only move if not already the last one. */
if (node != _odict_LAST(od)) {
_odict_remove_node(od, node);
_odict_add_tail(od, node);
if (node != _odict_LAST(self)) {
_odict_remove_node(self, node);
_odict_add_tail(self, node);
}
}
else {
/* Only move if not already the first one. */
if (node != _odict_FIRST(od)) {
_odict_remove_node(od, node);
_odict_add_head(od, node);
if (node != _odict_FIRST(self)) {
_odict_remove_node(self, node);
_odict_add_head(self, node);
}
}
}
@ -1395,20 +1405,17 @@ static PyMethodDef odict_methods[] = {
odict_repr__doc__},
{"__setitem__", (PyCFunction)odict_mp_ass_sub, METH_NOARGS,
odict_setitem__doc__},
{"fromkeys", (PyCFunction)odict_fromkeys,
METH_VARARGS | METH_KEYWORDS | METH_CLASS, odict_fromkeys__doc__},
ORDEREDDICT_FROMKEYS_METHODDEF
/* overridden dict methods */
{"__sizeof__", (PyCFunction)odict_sizeof, METH_NOARGS,
odict_sizeof__doc__},
{"__reduce__", (PyCFunction)odict_reduce, METH_NOARGS,
odict_reduce__doc__},
{"setdefault", (PyCFunction)odict_setdefault,
METH_VARARGS | METH_KEYWORDS, odict_setdefault__doc__},
ORDEREDDICT_SETDEFAULT_METHODDEF
{"pop", (PyCFunction)odict_pop,
METH_VARARGS | METH_KEYWORDS, odict_pop__doc__},
{"popitem", (PyCFunction)odict_popitem,
METH_VARARGS | METH_KEYWORDS, odict_popitem__doc__},
ORDEREDDICT_POPITEM_METHODDEF
{"keys", (PyCFunction)odictkeys_new, METH_NOARGS,
odict_keys__doc__},
{"values", (PyCFunction)odictvalues_new, METH_NOARGS,
@ -1425,8 +1432,7 @@ static PyMethodDef odict_methods[] = {
/* new methods */
{"__reversed__", (PyCFunction)odict_reversed, METH_NOARGS,
odict_reversed__doc__},
{"move_to_end", (PyCFunction)odict_move_to_end,
METH_VARARGS | METH_KEYWORDS, odict_move_to_end__doc__},
ORDEREDDICT_MOVE_TO_END_METHODDEF
{NULL, NULL} /* sentinel */
};
@ -1578,10 +1584,13 @@ odict_traverse(PyODictObject *od, visitproc visit, void *arg)
static int
odict_tp_clear(PyODictObject *od)
{
PyObject *res;
Py_CLEAR(od->od_inst_dict);
Py_CLEAR(od->od_weakreflist);
PyDict_Clear((PyObject *)od);
_odict_clear_nodes(od);
res = odict_clear(od);
if (res == NULL)
return -1;
Py_DECREF(res);
return 0;
}
@ -1656,6 +1665,27 @@ odict_init(PyObject *self, PyObject *args, PyObject *kwds)
}
}
/* tp_new */
static PyObject *
odict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyODictObject *od;
od = (PyODictObject *)PyDict_Type.tp_new(type, args, kwds);
if (od == NULL)
return NULL;
/* type constructor fills the memory with zeros (see
PyType_GenericAlloc()), there is no need to set them to zero again */
if (_odict_resize(od) < 0) {
Py_DECREF(od);
return NULL;
}
return (PyObject*)od;
}
/* PyODict_Type */
PyTypeObject PyODict_Type = {
@ -1696,7 +1726,7 @@ PyTypeObject PyODict_Type = {
offsetof(PyODictObject, od_inst_dict), /* tp_dictoffset */
(initproc)odict_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
0, /* tp_new */
(newfunc)odict_new, /* tp_new */
0, /* tp_free */
};
@ -1706,9 +1736,8 @@ PyTypeObject PyODict_Type = {
*/
PyObject *
PyODict_New(void)
{
return PyDict_Type.tp_new(&PyODict_Type, NULL, NULL);
PyODict_New(void) {
return odict_new(&PyODict_Type, NULL, NULL);
}
static int
@ -1906,21 +1935,40 @@ done:
PyDoc_STRVAR(reduce_doc, "Return state information for pickling");
static PyObject *
odictiter_reduce(odictiterobject *di, PyObject *Py_UNUSED(ignored))
odictiter_reduce(odictiterobject *di)
{
/* copy the iterator state */
odictiterobject tmp = *di;
Py_XINCREF(tmp.di_odict);
Py_XINCREF(tmp.di_current);
PyObject *list, *iter;
list = PyList_New(0);
if (!list)
return NULL;
/* iterate the temporary into a list */
PyObject *list = PySequence_List((PyObject*)&tmp);
Py_XDECREF(tmp.di_odict);
Py_XDECREF(tmp.di_current);
if (list == NULL) {
for(;;) {
PyObject *element = odictiter_iternext(di);
if (element) {
if (PyList_Append(list, element)) {
Py_DECREF(element);
Py_DECREF(list);
return NULL;
}
Py_DECREF(element);
}
else {
/* done iterating? */
break;
}
}
if (PyErr_Occurred()) {
Py_DECREF(list);
return NULL;
}
return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), list);
iter = _PyObject_GetBuiltin("iter");
if (iter == NULL) {
Py_DECREF(list);
return NULL;
}
return Py_BuildValue("N(N)", iter, list);
}
static PyMethodDef odictiter_methods[] = {
@ -2390,8 +2438,7 @@ mutablemapping_update(PyObject *self, PyObject *args, PyObject *kwargs)
/* now handle kwargs */
assert(kwargs == NULL || PyDict_Check(kwargs));
len = (kwargs != NULL) ? PyDict_Size(kwargs) : 0;
if (len > 0) {
if (kwargs != NULL && PyDict_GET_SIZE(kwargs)) {
PyObject *items = PyDict_Items(kwargs);
if (items == NULL)
return NULL;

File diff suppressed because it is too large Load diff