bpo-45609: Specialize STORE_SUBSCR (GH-29242)

* Specialize STORE_SUBSCR for list[int], and dict[object]

* Adds _PyDict_SetItem_Take2 which consumes references to the key and values.
This commit is contained in:
Dennis Sweeney 2021-11-19 05:30:37 -05:00 committed by GitHub
parent 4575c01b75
commit 036fead695
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 241 additions and 71 deletions

View File

@ -268,6 +268,7 @@ int _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *nam
int _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache); int _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache);
int _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache); int _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache);
int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache);
int _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr);
int _Py_Specialize_CallFunction(PyObject *callable, _Py_CODEUNIT *instr, int nargs, SpecializedCacheEntry *cache, PyObject *builtins); int _Py_Specialize_CallFunction(PyObject *callable, _Py_CODEUNIT *instr, int nargs, SpecializedCacheEntry *cache, PyObject *builtins);
void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
SpecializedCacheEntry *cache); SpecializedCacheEntry *cache);

View File

@ -22,6 +22,8 @@ typedef struct {
*/ */
Py_ssize_t _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr); Py_ssize_t _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr);
/* Consumes references to key and value */
int _PyDict_SetItem_Take2(PyDictObject *op, PyObject *key, PyObject *value);
#define DKIX_EMPTY (-1) #define DKIX_EMPTY (-1)
#define DKIX_DUMMY (-2) /* Used internally */ #define DKIX_DUMMY (-2) /* Used internally */

61
Include/opcode.h generated
View File

@ -125,35 +125,38 @@ extern "C" {
#define BINARY_SUBSCR_LIST_INT 23 #define BINARY_SUBSCR_LIST_INT 23
#define BINARY_SUBSCR_TUPLE_INT 24 #define BINARY_SUBSCR_TUPLE_INT 24
#define BINARY_SUBSCR_DICT 26 #define BINARY_SUBSCR_DICT 26
#define CALL_FUNCTION_ADAPTIVE 27 #define STORE_SUBSCR_ADAPTIVE 27
#define CALL_FUNCTION_BUILTIN_O 28 #define STORE_SUBSCR_LIST_INT 28
#define CALL_FUNCTION_BUILTIN_FAST 29 #define STORE_SUBSCR_DICT 29
#define CALL_FUNCTION_LEN 34 #define CALL_FUNCTION_ADAPTIVE 34
#define CALL_FUNCTION_ISINSTANCE 36 #define CALL_FUNCTION_BUILTIN_O 36
#define CALL_FUNCTION_PY_SIMPLE 38 #define CALL_FUNCTION_BUILTIN_FAST 38
#define JUMP_ABSOLUTE_QUICK 39 #define CALL_FUNCTION_LEN 39
#define LOAD_ATTR_ADAPTIVE 40 #define CALL_FUNCTION_ISINSTANCE 40
#define LOAD_ATTR_INSTANCE_VALUE 41 #define CALL_FUNCTION_PY_SIMPLE 41
#define LOAD_ATTR_WITH_HINT 42 #define JUMP_ABSOLUTE_QUICK 42
#define LOAD_ATTR_SLOT 43 #define LOAD_ATTR_ADAPTIVE 43
#define LOAD_ATTR_MODULE 44 #define LOAD_ATTR_INSTANCE_VALUE 44
#define LOAD_GLOBAL_ADAPTIVE 45 #define LOAD_ATTR_WITH_HINT 45
#define LOAD_GLOBAL_MODULE 46 #define LOAD_ATTR_SLOT 46
#define LOAD_GLOBAL_BUILTIN 47 #define LOAD_ATTR_MODULE 47
#define LOAD_METHOD_ADAPTIVE 48 #define LOAD_GLOBAL_ADAPTIVE 48
#define LOAD_METHOD_CACHED 55 #define LOAD_GLOBAL_MODULE 55
#define LOAD_METHOD_CLASS 56 #define LOAD_GLOBAL_BUILTIN 56
#define LOAD_METHOD_MODULE 57 #define LOAD_METHOD_ADAPTIVE 57
#define LOAD_METHOD_NO_DICT 58 #define LOAD_METHOD_CACHED 58
#define STORE_ATTR_ADAPTIVE 59 #define LOAD_METHOD_CLASS 59
#define STORE_ATTR_INSTANCE_VALUE 62 #define LOAD_METHOD_MODULE 62
#define STORE_ATTR_SLOT 63 #define LOAD_METHOD_NO_DICT 63
#define STORE_ATTR_WITH_HINT 64 #define STORE_ATTR_ADAPTIVE 64
#define LOAD_FAST__LOAD_FAST 65 #define STORE_ATTR_INSTANCE_VALUE 65
#define STORE_FAST__LOAD_FAST 66 #define STORE_ATTR_SLOT 66
#define LOAD_FAST__LOAD_CONST 67 #define STORE_ATTR_WITH_HINT 67
#define LOAD_CONST__LOAD_FAST 75 #define LOAD_FAST__LOAD_FAST 75
#define STORE_FAST__STORE_FAST 76 #define STORE_FAST__LOAD_FAST 76
#define LOAD_FAST__LOAD_CONST 77
#define LOAD_CONST__LOAD_FAST 78
#define STORE_FAST__STORE_FAST 79
#define DO_TRACING 255 #define DO_TRACING 255
#ifdef NEED_OPCODE_JUMP_TABLES #ifdef NEED_OPCODE_JUMP_TABLES
static uint32_t _PyOpcode_RelativeJump[8] = { static uint32_t _PyOpcode_RelativeJump[8] = {

View File

@ -238,6 +238,9 @@ _specialized_instructions = [
"BINARY_SUBSCR_LIST_INT", "BINARY_SUBSCR_LIST_INT",
"BINARY_SUBSCR_TUPLE_INT", "BINARY_SUBSCR_TUPLE_INT",
"BINARY_SUBSCR_DICT", "BINARY_SUBSCR_DICT",
"STORE_SUBSCR_ADAPTIVE",
"STORE_SUBSCR_LIST_INT",
"STORE_SUBSCR_DICT",
"CALL_FUNCTION_ADAPTIVE", "CALL_FUNCTION_ADAPTIVE",
"CALL_FUNCTION_BUILTIN_O", "CALL_FUNCTION_BUILTIN_O",
"CALL_FUNCTION_BUILTIN_FAST", "CALL_FUNCTION_BUILTIN_FAST",

View File

@ -892,6 +892,14 @@ class DictTest(unittest.TestCase):
gc.collect() gc.collect()
self.assertTrue(gc.is_tracked(t), t) self.assertTrue(gc.is_tracked(t), t)
def test_string_keys_can_track_values(self):
# Test that this doesn't leak.
for i in range(10):
d = {}
for j in range(10):
d[str(j)] = j
d["foo"] = d
@support.cpython_only @support.cpython_only
def test_track_literals(self): def test_track_literals(self):
# Test GC-optimization of dict literals # Test GC-optimization of dict literals

View File

@ -0,0 +1 @@
Specialized the ``STORE_SUBSCR`` opcode using the PEP 659 machinery.

View File

@ -1055,6 +1055,7 @@ insert_into_dictkeys(PyDictKeysObject *keys, PyObject *name)
Internal routine to insert a new item into the table. Internal routine to insert a new item into the table.
Used both by the internal resize routine and by the public insert routine. Used both by the internal resize routine and by the public insert routine.
Returns -1 if an error occurred, or 0 on success. Returns -1 if an error occurred, or 0 on success.
Consumes key and value references.
*/ */
static int static int
insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
@ -1062,8 +1063,6 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
PyObject *old_value; PyObject *old_value;
PyDictKeyEntry *ep; PyDictKeyEntry *ep;
Py_INCREF(key);
Py_INCREF(value);
if (mp->ma_values != NULL && !PyUnicode_CheckExact(key)) { if (mp->ma_values != NULL && !PyUnicode_CheckExact(key)) {
if (insertion_resize(mp) < 0) if (insertion_resize(mp) < 0)
goto Fail; goto Fail;
@ -1138,6 +1137,7 @@ Fail:
} }
// Same to insertdict but specialized for ma_keys = Py_EMPTY_KEYS. // Same to insertdict but specialized for ma_keys = Py_EMPTY_KEYS.
// Consumes key and value references.
static int static int
insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash, insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash,
PyObject *value) PyObject *value)
@ -1146,6 +1146,8 @@ insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash,
PyDictKeysObject *newkeys = new_keys_object(PyDict_LOG_MINSIZE); PyDictKeysObject *newkeys = new_keys_object(PyDict_LOG_MINSIZE);
if (newkeys == NULL) { if (newkeys == NULL) {
Py_DECREF(key);
Py_DECREF(value);
return -1; return -1;
} }
if (!PyUnicode_CheckExact(key)) { if (!PyUnicode_CheckExact(key)) {
@ -1155,8 +1157,6 @@ insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash,
mp->ma_keys = newkeys; mp->ma_keys = newkeys;
mp->ma_values = NULL; mp->ma_values = NULL;
Py_INCREF(key);
Py_INCREF(value);
MAINTAIN_TRACKING(mp, key, value); MAINTAIN_TRACKING(mp, key, value);
size_t hashpos = (size_t)hash & (PyDict_MINSIZE-1); size_t hashpos = (size_t)hash & (PyDict_MINSIZE-1);
@ -1529,6 +1529,31 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
return value; return value;
} }
/* Consumes references to key and value */
int
_PyDict_SetItem_Take2(PyDictObject *mp, PyObject *key, PyObject *value)
{
assert(key);
assert(value);
assert(PyDict_Check(mp));
Py_hash_t hash;
if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1)
{
hash = PyObject_Hash(key);
if (hash == -1) {
Py_DECREF(key);
Py_DECREF(value);
return -1;
}
}
if (mp->ma_keys == Py_EMPTY_KEYS) {
return insert_to_emptydict(mp, key, hash, value);
}
/* insertdict() handles any resizing that might be necessary */
return insertdict(mp, key, hash, value);
}
/* CAUTION: PyDict_SetItem() must guarantee that it won't resize the /* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
* dictionary if it's merely replacing the value for an existing key. * dictionary if it's merely replacing the value for an existing key.
* This means that it's safe to loop over a dictionary with PyDict_Next() * This means that it's safe to loop over a dictionary with PyDict_Next()
@ -1538,28 +1563,15 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
int int
PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value) PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value)
{ {
PyDictObject *mp;
Py_hash_t hash;
if (!PyDict_Check(op)) { if (!PyDict_Check(op)) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
return -1; return -1;
} }
assert(key); assert(key);
assert(value); assert(value);
mp = (PyDictObject *)op; Py_INCREF(key);
if (!PyUnicode_CheckExact(key) || Py_INCREF(value);
(hash = ((PyASCIIObject *) key)->hash) == -1) return _PyDict_SetItem_Take2((PyDictObject *)op, key, value);
{
hash = PyObject_Hash(key);
if (hash == -1)
return -1;
}
if (mp->ma_keys == Py_EMPTY_KEYS) {
return insert_to_emptydict(mp, key, hash, value);
}
/* insertdict() handles any resizing that might be necessary */
return insertdict(mp, key, hash, value);
} }
int int
@ -1577,6 +1589,8 @@ _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
assert(hash != -1); assert(hash != -1);
mp = (PyDictObject *)op; mp = (PyDictObject *)op;
Py_INCREF(key);
Py_INCREF(value);
if (mp->ma_keys == Py_EMPTY_KEYS) { if (mp->ma_keys == Py_EMPTY_KEYS) {
return insert_to_emptydict(mp, key, hash, value); return insert_to_emptydict(mp, key, hash, value);
} }
@ -1917,6 +1931,8 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
} }
while (_PyDict_Next(iterable, &pos, &key, &oldvalue, &hash)) { while (_PyDict_Next(iterable, &pos, &key, &oldvalue, &hash)) {
Py_INCREF(key);
Py_INCREF(value);
if (insertdict(mp, key, hash, value)) { if (insertdict(mp, key, hash, value)) {
Py_DECREF(d); Py_DECREF(d);
return NULL; return NULL;
@ -1936,6 +1952,8 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
} }
while (_PySet_NextEntry(iterable, &pos, &key, &hash)) { while (_PySet_NextEntry(iterable, &pos, &key, &hash)) {
Py_INCREF(key);
Py_INCREF(value);
if (insertdict(mp, key, hash, value)) { if (insertdict(mp, key, hash, value)) {
Py_DECREF(d); Py_DECREF(d);
return NULL; return NULL;
@ -2562,11 +2580,16 @@ dict_merge(PyObject *a, PyObject *b, int override)
int err = 0; int err = 0;
Py_INCREF(key); Py_INCREF(key);
Py_INCREF(value); Py_INCREF(value);
if (override == 1) if (override == 1) {
Py_INCREF(key);
Py_INCREF(value);
err = insertdict(mp, key, hash, value); err = insertdict(mp, key, hash, value);
}
else { else {
err = _PyDict_Contains_KnownHash(a, key, hash); err = _PyDict_Contains_KnownHash(a, key, hash);
if (err == 0) { if (err == 0) {
Py_INCREF(key);
Py_INCREF(value);
err = insertdict(mp, key, hash, value); err = insertdict(mp, key, hash, value);
} }
else if (err > 0) { else if (err > 0) {
@ -2967,7 +2990,10 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
if (hash == -1) if (hash == -1)
return NULL; return NULL;
} }
if (mp->ma_keys == Py_EMPTY_KEYS) { if (mp->ma_keys == Py_EMPTY_KEYS) {
Py_INCREF(key);
Py_INCREF(defaultobj);
if (insert_to_emptydict(mp, key, hash, defaultobj) < 0) { if (insert_to_emptydict(mp, key, hash, defaultobj) < 0) {
return NULL; return NULL;
} }

View File

@ -2279,6 +2279,8 @@ check_eval_breaker:
} }
TARGET(STORE_SUBSCR) { TARGET(STORE_SUBSCR) {
PREDICTED(STORE_SUBSCR);
STAT_INC(STORE_SUBSCR, unquickened);
PyObject *sub = TOP(); PyObject *sub = TOP();
PyObject *container = SECOND(); PyObject *container = SECOND();
PyObject *v = THIRD(); PyObject *v = THIRD();
@ -2294,6 +2296,64 @@ check_eval_breaker:
DISPATCH(); DISPATCH();
} }
TARGET(STORE_SUBSCR_ADAPTIVE) {
if (oparg == 0) {
PyObject *sub = TOP();
PyObject *container = SECOND();
next_instr--;
if (_Py_Specialize_StoreSubscr(container, sub, next_instr) < 0) {
goto error;
}
DISPATCH();
}
else {
STAT_INC(STORE_SUBSCR, deferred);
// oparg is the adaptive cache counter
UPDATE_PREV_INSTR_OPARG(next_instr, oparg - 1);
STAT_DEC(STORE_SUBSCR, unquickened);
JUMP_TO_INSTRUCTION(STORE_SUBSCR);
}
}
TARGET(STORE_SUBSCR_LIST_INT) {
PyObject *sub = TOP();
PyObject *list = SECOND();
PyObject *value = THIRD();
DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR);
DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR);
// Ensure nonnegative, zero-or-one-digit ints.
DEOPT_IF(((size_t)Py_SIZE(sub)) > 1, STORE_SUBSCR);
Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0];
// Ensure index < len(list)
DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR);
STAT_INC(STORE_SUBSCR, hit);
PyObject *old_value = PyList_GET_ITEM(list, index);
PyList_SET_ITEM(list, index, value);
STACK_SHRINK(3);
assert(old_value != NULL);
Py_DECREF(old_value);
Py_DECREF(sub);
Py_DECREF(list);
DISPATCH();
}
TARGET(STORE_SUBSCR_DICT) {
PyObject *sub = TOP();
PyObject *dict = SECOND();
PyObject *value = THIRD();
DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR);
STACK_SHRINK(3);
STAT_INC(STORE_SUBSCR, hit);
int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value);
Py_DECREF(dict);
if (err != 0) {
goto error;
}
DISPATCH();
}
TARGET(DELETE_SUBSCR) { TARGET(DELETE_SUBSCR) {
PyObject *sub = TOP(); PyObject *sub = TOP();
PyObject *container = SECOND(); PyObject *container = SECOND();
@ -3374,15 +3434,13 @@ check_eval_breaker:
PyObject *value = TOP(); PyObject *value = TOP();
PyObject *key = SECOND(); PyObject *key = SECOND();
PyObject *map; PyObject *map;
int err;
STACK_SHRINK(2); STACK_SHRINK(2);
map = PEEK(oparg); /* dict */ map = PEEK(oparg); /* dict */
assert(PyDict_CheckExact(map)); assert(PyDict_CheckExact(map));
err = PyDict_SetItem(map, key, value); /* map[key] = value */ /* map[key] = value */
Py_DECREF(value); if (_PyDict_SetItem_Take2((PyDictObject *)map, key, value) != 0) {
Py_DECREF(key);
if (err != 0)
goto error; goto error;
}
PREDICT(JUMP_ABSOLUTE); PREDICT(JUMP_ABSOLUTE);
DISPATCH(); DISPATCH();
} }
@ -4909,6 +4967,22 @@ opname ## _miss: \
JUMP_TO_INSTRUCTION(opname); \ JUMP_TO_INSTRUCTION(opname); \
} }
#define MISS_WITH_OPARG_COUNTER(opname) \
opname ## _miss: \
{ \
STAT_INC(opname, miss); \
uint8_t oparg = _Py_OPARG(next_instr[-1])-1; \
UPDATE_PREV_INSTR_OPARG(next_instr, oparg); \
assert(_Py_OPARG(next_instr[-1]) == oparg); \
if (oparg == 0) /* too many cache misses */ { \
oparg = ADAPTIVE_CACHE_BACKOFF; \
next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, oparg); \
STAT_INC(opname, deopt); \
} \
STAT_DEC(opname, unquickened); \
JUMP_TO_INSTRUCTION(opname); \
}
MISS_WITH_CACHE(LOAD_ATTR) MISS_WITH_CACHE(LOAD_ATTR)
MISS_WITH_CACHE(STORE_ATTR) MISS_WITH_CACHE(STORE_ATTR)
MISS_WITH_CACHE(LOAD_GLOBAL) MISS_WITH_CACHE(LOAD_GLOBAL)
@ -4916,6 +4990,7 @@ MISS_WITH_CACHE(LOAD_METHOD)
MISS_WITH_CACHE(CALL_FUNCTION) MISS_WITH_CACHE(CALL_FUNCTION)
MISS_WITH_CACHE(BINARY_OP) MISS_WITH_CACHE(BINARY_OP)
MISS_WITH_CACHE(BINARY_SUBSCR) MISS_WITH_CACHE(BINARY_SUBSCR)
MISS_WITH_OPARG_COUNTER(STORE_SUBSCR)
binary_subscr_dict_error: binary_subscr_dict_error:
{ {

View File

@ -26,17 +26,20 @@ static void *opcode_targets[256] = {
&&TARGET_BINARY_SUBSCR_TUPLE_INT, &&TARGET_BINARY_SUBSCR_TUPLE_INT,
&&TARGET_BINARY_SUBSCR, &&TARGET_BINARY_SUBSCR,
&&TARGET_BINARY_SUBSCR_DICT, &&TARGET_BINARY_SUBSCR_DICT,
&&TARGET_CALL_FUNCTION_ADAPTIVE, &&TARGET_STORE_SUBSCR_ADAPTIVE,
&&TARGET_CALL_FUNCTION_BUILTIN_O, &&TARGET_STORE_SUBSCR_LIST_INT,
&&TARGET_CALL_FUNCTION_BUILTIN_FAST, &&TARGET_STORE_SUBSCR_DICT,
&&TARGET_GET_LEN, &&TARGET_GET_LEN,
&&TARGET_MATCH_MAPPING, &&TARGET_MATCH_MAPPING,
&&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_SEQUENCE,
&&TARGET_MATCH_KEYS, &&TARGET_MATCH_KEYS,
&&TARGET_CALL_FUNCTION_LEN, &&TARGET_CALL_FUNCTION_ADAPTIVE,
&&TARGET_PUSH_EXC_INFO, &&TARGET_PUSH_EXC_INFO,
&&TARGET_CALL_FUNCTION_ISINSTANCE, &&TARGET_CALL_FUNCTION_BUILTIN_O,
&&TARGET_POP_EXCEPT_AND_RERAISE, &&TARGET_POP_EXCEPT_AND_RERAISE,
&&TARGET_CALL_FUNCTION_BUILTIN_FAST,
&&TARGET_CALL_FUNCTION_LEN,
&&TARGET_CALL_FUNCTION_ISINSTANCE,
&&TARGET_CALL_FUNCTION_PY_SIMPLE, &&TARGET_CALL_FUNCTION_PY_SIMPLE,
&&TARGET_JUMP_ABSOLUTE_QUICK, &&TARGET_JUMP_ABSOLUTE_QUICK,
&&TARGET_LOAD_ATTR_ADAPTIVE, &&TARGET_LOAD_ATTR_ADAPTIVE,
@ -45,28 +48,25 @@ static void *opcode_targets[256] = {
&&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_SLOT,
&&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_ATTR_MODULE,
&&TARGET_LOAD_GLOBAL_ADAPTIVE, &&TARGET_LOAD_GLOBAL_ADAPTIVE,
&&TARGET_LOAD_GLOBAL_MODULE,
&&TARGET_LOAD_GLOBAL_BUILTIN,
&&TARGET_LOAD_METHOD_ADAPTIVE,
&&TARGET_WITH_EXCEPT_START, &&TARGET_WITH_EXCEPT_START,
&&TARGET_GET_AITER, &&TARGET_GET_AITER,
&&TARGET_GET_ANEXT, &&TARGET_GET_ANEXT,
&&TARGET_BEFORE_ASYNC_WITH, &&TARGET_BEFORE_ASYNC_WITH,
&&TARGET_BEFORE_WITH, &&TARGET_BEFORE_WITH,
&&TARGET_END_ASYNC_FOR, &&TARGET_END_ASYNC_FOR,
&&TARGET_LOAD_GLOBAL_MODULE,
&&TARGET_LOAD_GLOBAL_BUILTIN,
&&TARGET_LOAD_METHOD_ADAPTIVE,
&&TARGET_LOAD_METHOD_CACHED, &&TARGET_LOAD_METHOD_CACHED,
&&TARGET_LOAD_METHOD_CLASS, &&TARGET_LOAD_METHOD_CLASS,
&&TARGET_STORE_SUBSCR,
&&TARGET_DELETE_SUBSCR,
&&TARGET_LOAD_METHOD_MODULE, &&TARGET_LOAD_METHOD_MODULE,
&&TARGET_LOAD_METHOD_NO_DICT, &&TARGET_LOAD_METHOD_NO_DICT,
&&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_STORE_ATTR_ADAPTIVE,
&&TARGET_STORE_SUBSCR,
&&TARGET_DELETE_SUBSCR,
&&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_INSTANCE_VALUE,
&&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_SLOT,
&&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_ATTR_WITH_HINT,
&&TARGET_LOAD_FAST__LOAD_FAST,
&&TARGET_STORE_FAST__LOAD_FAST,
&&TARGET_LOAD_FAST__LOAD_CONST,
&&TARGET_GET_ITER, &&TARGET_GET_ITER,
&&TARGET_GET_YIELD_FROM_ITER, &&TARGET_GET_YIELD_FROM_ITER,
&&TARGET_PRINT_EXPR, &&TARGET_PRINT_EXPR,
@ -74,13 +74,13 @@ static void *opcode_targets[256] = {
&&TARGET_YIELD_FROM, &&TARGET_YIELD_FROM,
&&TARGET_GET_AWAITABLE, &&TARGET_GET_AWAITABLE,
&&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_LOAD_ASSERTION_ERROR,
&&TARGET_LOAD_FAST__LOAD_FAST,
&&TARGET_STORE_FAST__LOAD_FAST,
&&TARGET_LOAD_FAST__LOAD_CONST,
&&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LOAD_CONST__LOAD_FAST,
&&TARGET_STORE_FAST__STORE_FAST, &&TARGET_STORE_FAST__STORE_FAST,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&TARGET_LIST_TO_TUPLE, &&TARGET_LIST_TO_TUPLE,
&&TARGET_RETURN_VALUE, &&TARGET_RETURN_VALUE,
&&TARGET_IMPORT_STAR, &&TARGET_IMPORT_STAR,

View File

@ -125,6 +125,7 @@ _Py_GetSpecializationStats(void) {
err += add_stat_dict(stats, LOAD_GLOBAL, "load_global"); err += add_stat_dict(stats, LOAD_GLOBAL, "load_global");
err += add_stat_dict(stats, LOAD_METHOD, "load_method"); err += add_stat_dict(stats, LOAD_METHOD, "load_method");
err += add_stat_dict(stats, BINARY_SUBSCR, "binary_subscr"); err += add_stat_dict(stats, BINARY_SUBSCR, "binary_subscr");
err += add_stat_dict(stats, STORE_SUBSCR, "store_subscr");
err += add_stat_dict(stats, STORE_ATTR, "store_attr"); err += add_stat_dict(stats, STORE_ATTR, "store_attr");
err += add_stat_dict(stats, CALL_FUNCTION, "call_function"); err += add_stat_dict(stats, CALL_FUNCTION, "call_function");
err += add_stat_dict(stats, BINARY_OP, "binary_op"); err += add_stat_dict(stats, BINARY_OP, "binary_op");
@ -182,6 +183,7 @@ _Py_PrintSpecializationStats(void)
print_stats(out, &_specialization_stats[LOAD_GLOBAL], "load_global"); print_stats(out, &_specialization_stats[LOAD_GLOBAL], "load_global");
print_stats(out, &_specialization_stats[LOAD_METHOD], "load_method"); print_stats(out, &_specialization_stats[LOAD_METHOD], "load_method");
print_stats(out, &_specialization_stats[BINARY_SUBSCR], "binary_subscr"); print_stats(out, &_specialization_stats[BINARY_SUBSCR], "binary_subscr");
print_stats(out, &_specialization_stats[STORE_SUBSCR], "store_subscr");
print_stats(out, &_specialization_stats[STORE_ATTR], "store_attr"); print_stats(out, &_specialization_stats[STORE_ATTR], "store_attr");
print_stats(out, &_specialization_stats[CALL_FUNCTION], "call_function"); print_stats(out, &_specialization_stats[CALL_FUNCTION], "call_function");
print_stats(out, &_specialization_stats[BINARY_OP], "binary_op"); print_stats(out, &_specialization_stats[BINARY_OP], "binary_op");
@ -233,6 +235,7 @@ static uint8_t adaptive_opcodes[256] = {
[LOAD_GLOBAL] = LOAD_GLOBAL_ADAPTIVE, [LOAD_GLOBAL] = LOAD_GLOBAL_ADAPTIVE,
[LOAD_METHOD] = LOAD_METHOD_ADAPTIVE, [LOAD_METHOD] = LOAD_METHOD_ADAPTIVE,
[BINARY_SUBSCR] = BINARY_SUBSCR_ADAPTIVE, [BINARY_SUBSCR] = BINARY_SUBSCR_ADAPTIVE,
[STORE_SUBSCR] = STORE_SUBSCR_ADAPTIVE,
[CALL_FUNCTION] = CALL_FUNCTION_ADAPTIVE, [CALL_FUNCTION] = CALL_FUNCTION_ADAPTIVE,
[STORE_ATTR] = STORE_ATTR_ADAPTIVE, [STORE_ATTR] = STORE_ATTR_ADAPTIVE,
[BINARY_OP] = BINARY_OP_ADAPTIVE, [BINARY_OP] = BINARY_OP_ADAPTIVE,
@ -244,6 +247,7 @@ static uint8_t cache_requirements[256] = {
[LOAD_GLOBAL] = 2, /* _PyAdaptiveEntry and _PyLoadGlobalCache */ [LOAD_GLOBAL] = 2, /* _PyAdaptiveEntry and _PyLoadGlobalCache */
[LOAD_METHOD] = 3, /* _PyAdaptiveEntry, _PyAttrCache and _PyObjectCache */ [LOAD_METHOD] = 3, /* _PyAdaptiveEntry, _PyAttrCache and _PyObjectCache */
[BINARY_SUBSCR] = 2, /* _PyAdaptiveEntry, _PyObjectCache */ [BINARY_SUBSCR] = 2, /* _PyAdaptiveEntry, _PyObjectCache */
[STORE_SUBSCR] = 0,
[CALL_FUNCTION] = 2, /* _PyAdaptiveEntry and _PyObjectCache/_PyCallCache */ [CALL_FUNCTION] = 2, /* _PyAdaptiveEntry and _PyObjectCache/_PyCallCache */
[STORE_ATTR] = 2, /* _PyAdaptiveEntry and _PyAttrCache */ [STORE_ATTR] = 2, /* _PyAdaptiveEntry and _PyAttrCache */
[BINARY_OP] = 1, // _PyAdaptiveEntry [BINARY_OP] = 1, // _PyAdaptiveEntry
@ -1228,6 +1232,53 @@ success:
return 0; return 0;
} }
int
_Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
{
PyTypeObject *container_type = Py_TYPE(container);
if (container_type == &PyList_Type) {
if (PyLong_CheckExact(sub)) {
if ((Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1)
&& ((PyLongObject *)sub)->ob_digit[0] < PyList_GET_SIZE(container))
{
*instr = _Py_MAKECODEUNIT(STORE_SUBSCR_LIST_INT,
initial_counter_value());
goto success;
}
else {
SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OUT_OF_RANGE);
goto fail;
}
}
else if (PySlice_Check(sub)) {
SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_LIST_SLICE);
goto fail;
}
else {
SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
goto fail;
}
}
else if (container_type == &PyDict_Type) {
*instr = _Py_MAKECODEUNIT(STORE_SUBSCR_DICT,
initial_counter_value());
goto success;
}
else {
SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
goto fail;
}
fail:
STAT_INC(STORE_SUBSCR, specialization_failure);
assert(!PyErr_Occurred());
*instr = _Py_MAKECODEUNIT(_Py_OPCODE(*instr), ADAPTIVE_CACHE_BACKOFF);
return 0;
success:
STAT_INC(STORE_SUBSCR, specialization_success);
assert(!PyErr_Occurred());
return 0;
}
static int static int
specialize_class_call( specialize_class_call(
PyObject *callable, _Py_CODEUNIT *instr, PyObject *callable, _Py_CODEUNIT *instr,