summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorInada Naoki <songofacandy@gmail.com>2022-03-01 23:09:28 (GMT)
committerGitHub <noreply@github.com>2022-03-01 23:09:28 (GMT)
commit9833bb91e4d5c2606421d9ec2085f5c2dfb6f72c (patch)
treecae368d226475abbeae93afd07081e78a7539cd9 /Python
parent21099fc064c61d59c936a2f6a0db3e07cd5c8de5 (diff)
downloadcpython-9833bb91e4d5c2606421d9ec2085f5c2dfb6f72c.zip
cpython-9833bb91e4d5c2606421d9ec2085f5c2dfb6f72c.tar.gz
cpython-9833bb91e4d5c2606421d9ec2085f5c2dfb6f72c.tar.bz2
bpo-46845: Reduce dict size when all keys are Unicode (GH-31564)
Diffstat (limited to 'Python')
-rw-r--r--Python/ceval.c93
1 files changed, 53 insertions, 40 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index b3673d7..e47e052 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1457,7 +1457,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
LOAD_##attr_or_method); \
assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); \
assert(cache0->index < dict->ma_keys->dk_nentries); \
- PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + cache0->index; \
+ PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + cache0->index; \
res = ep->me_value; \
DEOPT_IF(res == NULL, LOAD_##attr_or_method); \
STAT_INC(LOAD_##attr_or_method, hit); \
@@ -1595,6 +1595,19 @@ is_method(PyObject **stack_pointer, int args) {
return PEEK(args+2) != NULL;
}
+static PyObject*
+dictkeys_get_value_by_index(PyDictKeysObject *dk, int index)
+{
+ if (DK_IS_UNICODE(dk)) {
+ PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dk) + index;
+ return ep->me_value;
+ }
+ else {
+ PyDictKeyEntry *ep = DK_ENTRIES(dk) + index;
+ return ep->me_value;
+ }
+}
+
#define KWNAMES_LEN() \
(call_shape.kwnames == NULL ? 0 : ((int)PyTuple_GET_SIZE(call_shape.kwnames)))
@@ -3030,8 +3043,7 @@ handle_eval_breaker:
_PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
uint32_t version = read32(&cache->module_keys_version);
DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL);
- PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + cache->index;
- PyObject *res = ep->me_value;
+ PyObject *res = dictkeys_get_value_by_index(dict->ma_keys, cache->index);
DEOPT_IF(res == NULL, LOAD_GLOBAL);
JUMPBY(INLINE_CACHE_ENTRIES_LOAD_GLOBAL);
STAT_INC(LOAD_GLOBAL, hit);
@@ -3051,8 +3063,7 @@ handle_eval_breaker:
uint16_t bltn_version = cache->builtin_keys_version;
DEOPT_IF(mdict->ma_keys->dk_version != mod_version, LOAD_GLOBAL);
DEOPT_IF(bdict->ma_keys->dk_version != bltn_version, LOAD_GLOBAL);
- PyDictKeyEntry *ep = DK_ENTRIES(bdict->ma_keys) + cache->index;
- PyObject *res = ep->me_value;
+ PyObject *res = dictkeys_get_value_by_index(bdict->ma_keys, cache->index);
DEOPT_IF(res == NULL, LOAD_GLOBAL);
JUMPBY(INLINE_CACHE_ENTRIES_LOAD_GLOBAL);
STAT_INC(LOAD_GLOBAL, hit);
@@ -3272,20 +3283,12 @@ handle_eval_breaker:
}
TARGET(BUILD_MAP) {
- Py_ssize_t i;
- PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg);
+ PyObject *map = _PyDict_FromItems(
+ &PEEK(2*oparg), 2,
+ &PEEK(2*oparg - 1), 2,
+ oparg);
if (map == NULL)
goto error;
- for (i = oparg; i > 0; i--) {
- int err;
- PyObject *key = PEEK(2*i);
- PyObject *value = PEEK(2*i - 1);
- err = PyDict_SetItem(map, key, value);
- if (err != 0) {
- Py_DECREF(map);
- goto error;
- }
- }
while (oparg--) {
Py_DECREF(POP());
@@ -3351,7 +3354,6 @@ handle_eval_breaker:
}
TARGET(BUILD_CONST_KEY_MAP) {
- Py_ssize_t i;
PyObject *map;
PyObject *keys = TOP();
if (!PyTuple_CheckExact(keys) ||
@@ -3360,20 +3362,12 @@ handle_eval_breaker:
"bad BUILD_CONST_KEY_MAP keys argument");
goto error;
}
- map = _PyDict_NewPresized((Py_ssize_t)oparg);
+ map = _PyDict_FromItems(
+ &PyTuple_GET_ITEM(keys, 0), 1,
+ &PEEK(oparg + 1), 1, oparg);
if (map == NULL) {
goto error;
}
- for (i = oparg; i > 0; i--) {
- int err;
- PyObject *key = PyTuple_GET_ITEM(keys, oparg - i);
- PyObject *value = PEEK(i + 1);
- err = PyDict_SetItem(map, key, value);
- if (err != 0) {
- Py_DECREF(map);
- goto error;
- }
- }
Py_DECREF(POP());
while (oparg--) {
@@ -3538,9 +3532,16 @@ handle_eval_breaker:
PyObject *name = GETITEM(names, cache0->original_oparg);
uint16_t hint = cache0->index;
DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR);
- PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint;
- DEOPT_IF(ep->me_key != name, LOAD_ATTR);
- res = ep->me_value;
+ if (DK_IS_UNICODE(dict->ma_keys)) {
+ PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
+ DEOPT_IF(ep->me_key != name, LOAD_ATTR);
+ res = ep->me_value;
+ }
+ else {
+ PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint;
+ DEOPT_IF(ep->me_key != name, LOAD_ATTR);
+ res = ep->me_value;
+ }
DEOPT_IF(res == NULL, LOAD_ATTR);
STAT_INC(LOAD_ATTR, hit);
Py_INCREF(res);
@@ -3630,15 +3631,27 @@ handle_eval_breaker:
PyObject *name = GETITEM(names, cache0->original_oparg);
uint16_t hint = cache0->index;
DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR);
- PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint;
- DEOPT_IF(ep->me_key != name, STORE_ATTR);
- PyObject *old_value = ep->me_value;
- DEOPT_IF(old_value == NULL, STORE_ATTR);
- STAT_INC(STORE_ATTR, hit);
- STACK_SHRINK(1);
- PyObject *value = POP();
- ep->me_value = value;
+ PyObject *value, *old_value;
+ if (DK_IS_UNICODE(dict->ma_keys)) {
+ PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
+ DEOPT_IF(ep->me_key != name, STORE_ATTR);
+ old_value = ep->me_value;
+ DEOPT_IF(old_value == NULL, STORE_ATTR);
+ STACK_SHRINK(1);
+ value = POP();
+ ep->me_value = value;
+ }
+ else {
+ PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint;
+ DEOPT_IF(ep->me_key != name, STORE_ATTR);
+ old_value = ep->me_value;
+ DEOPT_IF(old_value == NULL, STORE_ATTR);
+ STACK_SHRINK(1);
+ value = POP();
+ ep->me_value = value;
+ }
Py_DECREF(old_value);
+ STAT_INC(STORE_ATTR, hit);
/* Ensure dict is GC tracked if it needs to be */
if (!_PyObject_GC_IS_TRACKED(dict) && _PyObject_GC_MAY_BE_TRACKED(value)) {
_PyObject_GC_TRACK(dict);