diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index 754eb88a85c33c..754e47a978517e 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -44,6 +44,8 @@ extern int _PyDict_Next( extern int _PyDict_HasOnlyStringKeys(PyObject *mp); +extern PyObject *_PyDict_Subscript(PyObject *self, PyObject *key); + // Export for '_ctypes' shared extension PyAPI_FUNC(Py_ssize_t) _PyDict_SizeOf(PyDictObject *); diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 521f7a92cf08c4..4097eafbd89f7a 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1069,7 +1069,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [BINARY_OP_SUBSCR_DICT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [BINARY_OP_SUBSCR_DICT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BINARY_OP_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG }, [BINARY_OP_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [BINARY_OP_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, @@ -1316,7 +1316,7 @@ _PyOpcode_macro_expansion[256] = { [BINARY_OP_INPLACE_ADD_UNICODE] = { .nuops = 3, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_INPLACE_ADD_UNICODE, OPARG_SIMPLE, 5 } } }, [BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 3, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_MULTIPLY_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_INT, OPARG_SIMPLE, 5 } } }, - [BINARY_OP_SUBSCR_DICT] = { .nuops = 2, .uops = { { _GUARD_NOS_DICT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_DICT, OPARG_SIMPLE, 5 } } }, + [BINARY_OP_SUBSCR_DICT] = { .nuops = 2, .uops = { { _GUARD_NOS_DICT_NOT_EXACT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_DICT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_GETITEM] = { .nuops = 4, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_CHECK_FUNC, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_INIT_CALL, OPARG_SIMPLE, 5 }, { _PUSH_FRAME, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_LIST_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_INT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_STR_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_STR_INT, OPARG_SIMPLE, 5 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index e9a536919da598..3c58b478d9c90b 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -125,32 +125,33 @@ extern "C" { #define _GUARD_IS_TRUE_POP 377 #define _GUARD_KEYS_VERSION 378 #define _GUARD_NOS_DICT 379 -#define _GUARD_NOS_FLOAT 380 -#define _GUARD_NOS_INT 381 -#define _GUARD_NOS_LIST 382 -#define _GUARD_NOS_TUPLE 383 -#define _GUARD_NOS_UNICODE 384 -#define _GUARD_NOT_EXHAUSTED_LIST 385 -#define _GUARD_NOT_EXHAUSTED_RANGE 386 -#define _GUARD_NOT_EXHAUSTED_TUPLE 387 -#define _GUARD_TOS_ANY_SET 388 -#define _GUARD_TOS_DICT 389 -#define _GUARD_TOS_FLOAT 390 -#define _GUARD_TOS_INT 391 -#define _GUARD_TOS_LIST 392 -#define _GUARD_TOS_TUPLE 393 -#define _GUARD_TOS_UNICODE 394 -#define _GUARD_TYPE_VERSION 395 -#define _GUARD_TYPE_VERSION_AND_LOCK 396 +#define _GUARD_NOS_DICT_NOT_EXACT 380 +#define _GUARD_NOS_FLOAT 381 +#define _GUARD_NOS_INT 382 +#define _GUARD_NOS_LIST 383 +#define _GUARD_NOS_TUPLE 384 +#define _GUARD_NOS_UNICODE 385 +#define _GUARD_NOT_EXHAUSTED_LIST 386 +#define _GUARD_NOT_EXHAUSTED_RANGE 387 +#define _GUARD_NOT_EXHAUSTED_TUPLE 388 +#define _GUARD_TOS_ANY_SET 389 +#define _GUARD_TOS_DICT 390 +#define _GUARD_TOS_FLOAT 391 +#define _GUARD_TOS_INT 392 +#define _GUARD_TOS_LIST 393 +#define _GUARD_TOS_TUPLE 394 +#define _GUARD_TOS_UNICODE 395 +#define _GUARD_TYPE_VERSION 396 +#define _GUARD_TYPE_VERSION_AND_LOCK 397 #define _IMPORT_FROM IMPORT_FROM #define _IMPORT_NAME IMPORT_NAME -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 397 -#define _INIT_CALL_PY_EXACT_ARGS 398 -#define _INIT_CALL_PY_EXACT_ARGS_0 399 -#define _INIT_CALL_PY_EXACT_ARGS_1 400 -#define _INIT_CALL_PY_EXACT_ARGS_2 401 -#define _INIT_CALL_PY_EXACT_ARGS_3 402 -#define _INIT_CALL_PY_EXACT_ARGS_4 403 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 398 +#define _INIT_CALL_PY_EXACT_ARGS 399 +#define _INIT_CALL_PY_EXACT_ARGS_0 400 +#define _INIT_CALL_PY_EXACT_ARGS_1 401 +#define _INIT_CALL_PY_EXACT_ARGS_2 402 +#define _INIT_CALL_PY_EXACT_ARGS_3 403 +#define _INIT_CALL_PY_EXACT_ARGS_4 404 #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD @@ -160,163 +161,163 @@ extern "C" { #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE #define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE -#define _IS_NONE 404 +#define _IS_NONE 405 #define _IS_OP IS_OP -#define _ITER_CHECK_LIST 405 -#define _ITER_CHECK_RANGE 406 -#define _ITER_CHECK_TUPLE 407 -#define _ITER_JUMP_LIST 408 -#define _ITER_JUMP_RANGE 409 -#define _ITER_JUMP_TUPLE 410 -#define _ITER_NEXT_LIST 411 -#define _ITER_NEXT_LIST_TIER_TWO 412 -#define _ITER_NEXT_RANGE 413 -#define _ITER_NEXT_TUPLE 414 -#define _JUMP_TO_TOP 415 +#define _ITER_CHECK_LIST 406 +#define _ITER_CHECK_RANGE 407 +#define _ITER_CHECK_TUPLE 408 +#define _ITER_JUMP_LIST 409 +#define _ITER_JUMP_RANGE 410 +#define _ITER_JUMP_TUPLE 411 +#define _ITER_NEXT_LIST 412 +#define _ITER_NEXT_LIST_TIER_TWO 413 +#define _ITER_NEXT_RANGE 414 +#define _ITER_NEXT_TUPLE 415 +#define _JUMP_TO_TOP 416 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND -#define _LOAD_ATTR 416 -#define _LOAD_ATTR_CLASS 417 +#define _LOAD_ATTR 417 +#define _LOAD_ATTR_CLASS 418 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 418 -#define _LOAD_ATTR_METHOD_LAZY_DICT 419 -#define _LOAD_ATTR_METHOD_NO_DICT 420 -#define _LOAD_ATTR_METHOD_WITH_VALUES 421 -#define _LOAD_ATTR_MODULE 422 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 423 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 424 -#define _LOAD_ATTR_PROPERTY_FRAME 425 -#define _LOAD_ATTR_SLOT 426 -#define _LOAD_ATTR_WITH_HINT 427 +#define _LOAD_ATTR_INSTANCE_VALUE 419 +#define _LOAD_ATTR_METHOD_LAZY_DICT 420 +#define _LOAD_ATTR_METHOD_NO_DICT 421 +#define _LOAD_ATTR_METHOD_WITH_VALUES 422 +#define _LOAD_ATTR_MODULE 423 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 424 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 425 +#define _LOAD_ATTR_PROPERTY_FRAME 426 +#define _LOAD_ATTR_SLOT 427 +#define _LOAD_ATTR_WITH_HINT 428 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS -#define _LOAD_BYTECODE 428 +#define _LOAD_BYTECODE 429 #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST #define _LOAD_CONST_IMMORTAL LOAD_CONST_IMMORTAL -#define _LOAD_CONST_INLINE 429 -#define _LOAD_CONST_INLINE_BORROW 430 +#define _LOAD_CONST_INLINE 430 +#define _LOAD_CONST_INLINE_BORROW 431 #define _LOAD_CONST_MORTAL LOAD_CONST_MORTAL #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 431 -#define _LOAD_FAST_0 432 -#define _LOAD_FAST_1 433 -#define _LOAD_FAST_2 434 -#define _LOAD_FAST_3 435 -#define _LOAD_FAST_4 436 -#define _LOAD_FAST_5 437 -#define _LOAD_FAST_6 438 -#define _LOAD_FAST_7 439 +#define _LOAD_FAST 432 +#define _LOAD_FAST_0 433 +#define _LOAD_FAST_1 434 +#define _LOAD_FAST_2 435 +#define _LOAD_FAST_3 436 +#define _LOAD_FAST_4 437 +#define _LOAD_FAST_5 438 +#define _LOAD_FAST_6 439 +#define _LOAD_FAST_7 440 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR -#define _LOAD_FAST_BORROW 440 -#define _LOAD_FAST_BORROW_0 441 -#define _LOAD_FAST_BORROW_1 442 -#define _LOAD_FAST_BORROW_2 443 -#define _LOAD_FAST_BORROW_3 444 -#define _LOAD_FAST_BORROW_4 445 -#define _LOAD_FAST_BORROW_5 446 -#define _LOAD_FAST_BORROW_6 447 -#define _LOAD_FAST_BORROW_7 448 +#define _LOAD_FAST_BORROW 441 +#define _LOAD_FAST_BORROW_0 442 +#define _LOAD_FAST_BORROW_1 443 +#define _LOAD_FAST_BORROW_2 444 +#define _LOAD_FAST_BORROW_3 445 +#define _LOAD_FAST_BORROW_4 446 +#define _LOAD_FAST_BORROW_5 447 +#define _LOAD_FAST_BORROW_6 448 +#define _LOAD_FAST_BORROW_7 449 #define _LOAD_FAST_BORROW_LOAD_FAST_BORROW LOAD_FAST_BORROW_LOAD_FAST_BORROW #define _LOAD_FAST_CHECK LOAD_FAST_CHECK #define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS -#define _LOAD_GLOBAL 449 -#define _LOAD_GLOBAL_BUILTINS 450 -#define _LOAD_GLOBAL_MODULE 451 +#define _LOAD_GLOBAL 450 +#define _LOAD_GLOBAL_BUILTINS 451 +#define _LOAD_GLOBAL_MODULE 452 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME -#define _LOAD_SMALL_INT 452 -#define _LOAD_SMALL_INT_0 453 -#define _LOAD_SMALL_INT_1 454 -#define _LOAD_SMALL_INT_2 455 -#define _LOAD_SMALL_INT_3 456 +#define _LOAD_SMALL_INT 453 +#define _LOAD_SMALL_INT_0 454 +#define _LOAD_SMALL_INT_1 455 +#define _LOAD_SMALL_INT_2 456 +#define _LOAD_SMALL_INT_3 457 #define _LOAD_SPECIAL LOAD_SPECIAL #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD -#define _MAKE_CALLARGS_A_TUPLE 457 +#define _MAKE_CALLARGS_A_TUPLE 458 #define _MAKE_CELL MAKE_CELL #define _MAKE_FUNCTION MAKE_FUNCTION -#define _MAKE_WARM 458 +#define _MAKE_WARM 459 #define _MAP_ADD MAP_ADD #define _MATCH_CLASS MATCH_CLASS #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MAYBE_EXPAND_METHOD 459 -#define _MAYBE_EXPAND_METHOD_KW 460 -#define _MONITOR_CALL 461 -#define _MONITOR_CALL_KW 462 -#define _MONITOR_JUMP_BACKWARD 463 -#define _MONITOR_RESUME 464 +#define _MAYBE_EXPAND_METHOD 460 +#define _MAYBE_EXPAND_METHOD_KW 461 +#define _MONITOR_CALL 462 +#define _MONITOR_CALL_KW 463 +#define _MONITOR_JUMP_BACKWARD 464 +#define _MONITOR_RESUME 465 #define _NOP NOP #define _POP_EXCEPT POP_EXCEPT -#define _POP_JUMP_IF_FALSE 465 -#define _POP_JUMP_IF_TRUE 466 +#define _POP_JUMP_IF_FALSE 466 +#define _POP_JUMP_IF_TRUE 467 #define _POP_TOP POP_TOP -#define _POP_TOP_LOAD_CONST_INLINE 467 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 468 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW 469 +#define _POP_TOP_LOAD_CONST_INLINE 468 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 469 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW 470 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 470 +#define _PUSH_FRAME 471 #define _PUSH_NULL PUSH_NULL -#define _PUSH_NULL_CONDITIONAL 471 -#define _PY_FRAME_GENERAL 472 -#define _PY_FRAME_KW 473 -#define _QUICKEN_RESUME 474 -#define _REPLACE_WITH_TRUE 475 +#define _PUSH_NULL_CONDITIONAL 472 +#define _PY_FRAME_GENERAL 473 +#define _PY_FRAME_KW 474 +#define _QUICKEN_RESUME 475 +#define _REPLACE_WITH_TRUE 476 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR #define _RETURN_VALUE RETURN_VALUE -#define _SAVE_RETURN_OFFSET 476 -#define _SEND 477 -#define _SEND_GEN_FRAME 478 +#define _SAVE_RETURN_OFFSET 477 +#define _SEND 478 +#define _SEND_GEN_FRAME 479 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _START_EXECUTOR 479 -#define _STORE_ATTR 480 -#define _STORE_ATTR_INSTANCE_VALUE 481 -#define _STORE_ATTR_SLOT 482 -#define _STORE_ATTR_WITH_HINT 483 +#define _START_EXECUTOR 480 +#define _STORE_ATTR 481 +#define _STORE_ATTR_INSTANCE_VALUE 482 +#define _STORE_ATTR_SLOT 483 +#define _STORE_ATTR_WITH_HINT 484 #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST 484 -#define _STORE_FAST_0 485 -#define _STORE_FAST_1 486 -#define _STORE_FAST_2 487 -#define _STORE_FAST_3 488 -#define _STORE_FAST_4 489 -#define _STORE_FAST_5 490 -#define _STORE_FAST_6 491 -#define _STORE_FAST_7 492 +#define _STORE_FAST 485 +#define _STORE_FAST_0 486 +#define _STORE_FAST_1 487 +#define _STORE_FAST_2 488 +#define _STORE_FAST_3 489 +#define _STORE_FAST_4 490 +#define _STORE_FAST_5 491 +#define _STORE_FAST_6 492 +#define _STORE_FAST_7 493 #define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST #define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 493 -#define _STORE_SUBSCR 494 -#define _STORE_SUBSCR_DICT 495 -#define _STORE_SUBSCR_LIST_INT 496 +#define _STORE_SLICE 494 +#define _STORE_SUBSCR 495 +#define _STORE_SUBSCR_DICT 496 +#define _STORE_SUBSCR_LIST_INT 497 #define _SWAP SWAP -#define _TIER2_RESUME_CHECK 497 -#define _TO_BOOL 498 +#define _TIER2_RESUME_CHECK 498 +#define _TO_BOOL 499 #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT -#define _TO_BOOL_LIST 499 +#define _TO_BOOL_LIST 500 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 500 +#define _TO_BOOL_STR 501 #define _UNARY_INVERT UNARY_INVERT #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 501 -#define _UNPACK_SEQUENCE_LIST 502 -#define _UNPACK_SEQUENCE_TUPLE 503 -#define _UNPACK_SEQUENCE_TWO_TUPLE 504 +#define _UNPACK_SEQUENCE 502 +#define _UNPACK_SEQUENCE_LIST 503 +#define _UNPACK_SEQUENCE_TUPLE 504 +#define _UNPACK_SEQUENCE_TWO_TUPLE 505 #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 504 +#define MAX_UOP_ID 505 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 8fa50ff2c291c4..5b235887ef4f1a 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -103,6 +103,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_GUARD_TOS_TUPLE] = HAS_EXIT_FLAG, [_BINARY_OP_SUBSCR_TUPLE_INT] = HAS_DEOPT_FLAG, [_GUARD_NOS_DICT] = HAS_EXIT_FLAG, + [_GUARD_NOS_DICT_NOT_EXACT] = HAS_DEOPT_FLAG, [_GUARD_TOS_DICT] = HAS_EXIT_FLAG, [_BINARY_OP_SUBSCR_DICT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_BINARY_OP_SUBSCR_CHECK_FUNC] = HAS_DEOPT_FLAG, @@ -419,6 +420,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_GUARD_IS_TRUE_POP] = "_GUARD_IS_TRUE_POP", [_GUARD_KEYS_VERSION] = "_GUARD_KEYS_VERSION", [_GUARD_NOS_DICT] = "_GUARD_NOS_DICT", + [_GUARD_NOS_DICT_NOT_EXACT] = "_GUARD_NOS_DICT_NOT_EXACT", [_GUARD_NOS_FLOAT] = "_GUARD_NOS_FLOAT", [_GUARD_NOS_INT] = "_GUARD_NOS_INT", [_GUARD_NOS_LIST] = "_GUARD_NOS_LIST", @@ -758,6 +760,8 @@ int _PyUop_num_popped(int opcode, int oparg) return 2; case _GUARD_NOS_DICT: return 0; + case _GUARD_NOS_DICT_NOT_EXACT: + return 0; case _GUARD_TOS_DICT: return 0; case _BINARY_OP_SUBSCR_DICT: diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index ac132465b227ad..add17ce1505d4f 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -1,3 +1,4 @@ +import collections import copy import pickle import dis @@ -1729,9 +1730,43 @@ def binary_subscr_dict(): self.assertEqual(a[1], 2) self.assertEqual(a[2], 3) - binary_subscr_dict() - self.assert_specialized(binary_subscr_dict, "BINARY_OP_SUBSCR_DICT") - self.assert_no_opcode(binary_subscr_dict, "BINARY_OP") + def binary_subscr_dict_subclass_defaultdict(): + for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a = collections.defaultdict(lambda : 42, {1: 2, 2: 3}) + self.assertEqual(a[1], 2) + self.assertEqual(a[2], 3) + self.assertEqual(a[7], 42) + + def binary_subscr_dict_subclass_Counter(): + for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a = collections.Counter('abcdeabcdabcaba') + self.assertEqual(a['a'], 5) + self.assertEqual(a['b'], 4) + self.assertEqual(a['m'], 0) + + for f in [binary_subscr_dict, + binary_subscr_dict_subclass_defaultdict, + binary_subscr_dict_subclass_Counter]: + + with self.subTest(f=f): + f() + self.assert_specialized(f, "BINARY_OP_SUBSCR_DICT") + self.assert_no_opcode(f, "BINARY_OP") + + def binary_subscr_dict_subclass_with_subscript_override(): + class MyDict(dict): + def __getitem__(self, key): + return 42 + + for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a = MyDict() + self.assertEqual(a['a'], 42) + self.assertEqual(a['b'], 42) + + binary_subscr_dict_subclass_with_subscript_override() + self.assert_no_opcode( + binary_subscr_dict_subclass_with_subscript_override, + "BINARY_OP_SUBSCR_DICT") def binary_subscr_str_int(): for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 792a34cc569fe8..e8b060046dbce4 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -3388,8 +3388,8 @@ dict_length(PyObject *self) return FT_ATOMIC_LOAD_SSIZE_RELAXED(((PyDictObject *)self)->ma_used); } -static PyObject * -dict_subscript(PyObject *self, PyObject *key) +PyObject * +_PyDict_Subscript(PyObject *self, PyObject *key) { PyDictObject *mp = (PyDictObject *)self; Py_ssize_t ix; @@ -3434,7 +3434,7 @@ dict_ass_sub(PyObject *mp, PyObject *v, PyObject *w) static PyMappingMethods dict_as_mapping = { dict_length, /*mp_length*/ - dict_subscript, /*mp_subscript*/ + _PyDict_Subscript, /*mp_subscript*/ dict_ass_sub, /*mp_ass_subscript*/ }; @@ -4712,7 +4712,7 @@ In either case, this is followed by: for k in F: D[k] = F[k]"); static PyMethodDef mapp_methods[] = { DICT___CONTAINS___METHODDEF - {"__getitem__", dict_subscript, METH_O | METH_COEXIST, + {"__getitem__", _PyDict_Subscript, METH_O | METH_COEXIST, getitem__doc__}, DICT___SIZEOF___METHODDEF DICT_GET_METHODDEF diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e9dced654d1492..f43c4d29b33954 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -959,27 +959,28 @@ dummy_func( EXIT_IF(!PyDict_CheckExact(o)); } + op(_GUARD_NOS_DICT_NOT_EXACT, (nos, unused -- nos, unused)) { + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + DEOPT_IF(!Py_TYPE(o)->tp_as_mapping); + DEOPT_IF(Py_TYPE(o)->tp_as_mapping->mp_subscript != _PyDict_Subscript); + } + op(_GUARD_TOS_DICT, (tos -- tos)) { PyObject *o = PyStackRef_AsPyObjectBorrow(tos); EXIT_IF(!PyDict_CheckExact(o)); } macro(BINARY_OP_SUBSCR_DICT) = - _GUARD_NOS_DICT + unused/5 + _BINARY_OP_SUBSCR_DICT; + _GUARD_NOS_DICT_NOT_EXACT + unused/5 + _BINARY_OP_SUBSCR_DICT; op(_BINARY_OP_SUBSCR_DICT, (dict_st, sub_st -- res)) { PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); - assert(PyDict_CheckExact(dict)); STAT_INC(BINARY_OP, hit); - PyObject *res_o; - int rc = PyDict_GetItemRef(dict, sub, &res_o); - if (rc == 0) { - _PyErr_SetKeyError(sub); - } + PyObject *res_o = _PyDict_Subscript(dict, sub); DECREF_INPUTS(); - ERROR_IF(rc <= 0, error); // not found or error + ERROR_IF(res_o == NULL, error); // not found or error res = PyStackRef_FromPyObjectSteal(res_o); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 938a80fe665c0b..885496ed12925f 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1432,6 +1432,21 @@ break; } + case _GUARD_NOS_DICT_NOT_EXACT: { + _PyStackRef nos; + nos = stack_pointer[-2]; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!Py_TYPE(o)->tp_as_mapping) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + if (Py_TYPE(o)->tp_as_mapping->mp_subscript != _PyDict_Subscript) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + break; + } + case _GUARD_TOS_DICT: { _PyStackRef tos; tos = stack_pointer[-1]; @@ -1451,18 +1466,9 @@ dict_st = stack_pointer[-2]; PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); - assert(PyDict_CheckExact(dict)); STAT_INC(BINARY_OP, hit); - PyObject *res_o; - _PyFrame_SetStackPointer(frame, stack_pointer); - int rc = PyDict_GetItemRef(dict, sub, &res_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (rc == 0) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyErr_SetKeyError(sub); - stack_pointer = _PyFrame_GetStackPointer(frame); - } _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = _PyDict_Subscript(dict, sub); _PyStackRef tmp = sub_st; sub_st = PyStackRef_NULL; stack_pointer[-1] = sub_st; @@ -1474,7 +1480,7 @@ stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; assert(WITHIN_STACK_BOUNDS()); - if (rc <= 0) { + if (res_o == NULL) { JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 97bffce8d82767..73223d3f627a5c 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -539,11 +539,16 @@ _PyStackRef dict_st; _PyStackRef sub_st; _PyStackRef res; - // _GUARD_NOS_DICT + // _GUARD_NOS_DICT_NOT_EXACT { nos = stack_pointer[-2]; PyObject *o = PyStackRef_AsPyObjectBorrow(nos); - if (!PyDict_CheckExact(o)) { + if (!Py_TYPE(o)->tp_as_mapping) { + UPDATE_MISS_STATS(BINARY_OP); + assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); + JUMP_TO_PREDICTED(BINARY_OP); + } + if (Py_TYPE(o)->tp_as_mapping->mp_subscript != _PyDict_Subscript) { UPDATE_MISS_STATS(BINARY_OP); assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); JUMP_TO_PREDICTED(BINARY_OP); @@ -556,18 +561,9 @@ dict_st = nos; PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); - assert(PyDict_CheckExact(dict)); STAT_INC(BINARY_OP, hit); - PyObject *res_o; - _PyFrame_SetStackPointer(frame, stack_pointer); - int rc = PyDict_GetItemRef(dict, sub, &res_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (rc == 0) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyErr_SetKeyError(sub); - stack_pointer = _PyFrame_GetStackPointer(frame); - } _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = _PyDict_Subscript(dict, sub); _PyStackRef tmp = sub_st; sub_st = PyStackRef_NULL; stack_pointer[-1] = sub_st; @@ -579,7 +575,7 @@ stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; assert(WITHIN_STACK_BOUNDS()); - if (rc <= 0) { + if (res_o == NULL) { JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 0c617137a8893d..69d722d3227a2e 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -634,6 +634,10 @@ break; } + case _GUARD_NOS_DICT_NOT_EXACT: { + break; + } + case _GUARD_TOS_DICT: { JitOptSymbol *tos; tos = stack_pointer[-1]; diff --git a/Python/specialize.c b/Python/specialize.c index ceb396c5b54815..01e593acbdaf9d 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2648,9 +2648,13 @@ _Py_Specialize_BinaryOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *in return; } } - if (PyDict_CheckExact(lhs)) { - specialize(instr, BINARY_OP_SUBSCR_DICT); - return; + if (PyDict_Check(lhs)) { + if ((Py_TYPE(lhs)->tp_as_mapping != NULL) && + (Py_TYPE(lhs)->tp_as_mapping->mp_subscript == _PyDict_Subscript)) + { + specialize(instr, BINARY_OP_SUBSCR_DICT); + return; + } } unsigned int tp_version; PyTypeObject *container_type = Py_TYPE(lhs);