mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-22 21:32:31 +00:00
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:
parent
6f658f058b
commit
7fe9e70117
71 changed files with 4154 additions and 2450 deletions
99
third_party/python/Objects/dictobject.c
vendored
99
third_party/python/Objects/dictobject.c
vendored
|
@ -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__},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue