diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 1f7014e9cd426f..2ef1aa1d00ad29 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1752,6 +1752,25 @@ iterations of the loop. .. versionadded:: 3.13 +.. opcode:: MATCH_CLASS_ISINSTANCE + + Read match subject ``Stack[-2]`` and the type object ``Stack[-1]`` from stack. + Pop ``Stack[-1]`` and push ``True`` or ``False`` for the result of :func:`isinstance`. + + .. versionadded:: 3.15 + + +.. opcode:: MATCH_CLASS_GET_OPT_ATTR (namei) + + Replaces ``STACK[-1]`` with ``getattr(STACK[-1], co_names[namei])`` and get + optional attribute from match subject ``STACK[-2]``. + + Pop ``Stack[-1]``. If attribute is found, push it and ``True`` onto the stack. + Otherwise push ``None`` and ``False``. + + .. versionadded:: 3.15 + + .. opcode:: MATCH_CLASS (count) ``STACK[-1]`` is a tuple of keyword attribute names, ``STACK[-2]`` is the class diff --git a/Include/internal/pycore_magic_number.h b/Include/internal/pycore_magic_number.h index 9d36165c8a8ffb..531cbbf5a77138 100644 --- a/Include/internal/pycore_magic_number.h +++ b/Include/internal/pycore_magic_number.h @@ -294,6 +294,7 @@ Known values: Python 3.15a4 3661 (Lazy imports IMPORT_NAME opcode changes) Python 3.15a8 3662 (Add counter to RESUME) Python 3.15a8 3663 (Merge GET_ITER and GET_YIELD_FROM_ITER. Modify SEND to make it a bit more like FOR_ITER) + Python 3.15a7 3664 (Add MATCH_CLASS_ISINSTANCE & MATCH_CLASS_GET_OPT_ATTR) Python 3.16 will start with 3700 @@ -307,7 +308,7 @@ PC/launcher.c must also be updated. */ -#define PYC_MAGIC_NUMBER 3663 +#define PYC_MAGIC_NUMBER 3664 /* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes (little-endian) and then appending b'\r\n'. */ #define PYC_MAGIC_NUMBER_TOKEN \ diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 3260806f3222d6..4cf7245a912097 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -384,6 +384,10 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 3 + (oparg - 1); case MATCH_CLASS: return 3; + case MATCH_CLASS_GET_OPT_ATTR: + return 1; + case MATCH_CLASS_ISINSTANCE: + return 2; case MATCH_KEYS: return 2; case MATCH_MAPPING: @@ -875,6 +879,10 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 1 + (oparg - 1); case MATCH_CLASS: return 1; + case MATCH_CLASS_GET_OPT_ATTR: + return 3; + case MATCH_CLASS_ISINSTANCE: + return 2; case MATCH_KEYS: return 3; case MATCH_MAPPING: @@ -1260,6 +1268,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [MAKE_FUNCTION] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [MAP_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [MATCH_CLASS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [MATCH_CLASS_GET_OPT_ATTR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [MATCH_CLASS_ISINSTANCE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [MATCH_KEYS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [MATCH_MAPPING] = { true, INSTR_FMT_IX, 0 }, [MATCH_SEQUENCE] = { true, INSTR_FMT_IX, 0 }, @@ -1478,6 +1488,8 @@ _PyOpcode_macro_expansion[256] = { [MAKE_FUNCTION] = { .nuops = 1, .uops = { { _MAKE_FUNCTION, OPARG_SIMPLE, 0 } } }, [MAP_ADD] = { .nuops = 1, .uops = { { _MAP_ADD, OPARG_SIMPLE, 0 } } }, [MATCH_CLASS] = { .nuops = 4, .uops = { { _MATCH_CLASS, OPARG_SIMPLE, 0 }, { _POP_TOP, OPARG_SIMPLE, 0 }, { _POP_TOP, OPARG_SIMPLE, 0 }, { _POP_TOP, OPARG_SIMPLE, 0 } } }, + [MATCH_CLASS_GET_OPT_ATTR] = { .nuops = 1, .uops = { { _MATCH_CLASS_GET_OPT_ATTR, OPARG_SIMPLE, 0 } } }, + [MATCH_CLASS_ISINSTANCE] = { .nuops = 1, .uops = { { _MATCH_CLASS_ISINSTANCE, OPARG_SIMPLE, 0 } } }, [MATCH_KEYS] = { .nuops = 1, .uops = { { _MATCH_KEYS, OPARG_SIMPLE, 0 } } }, [MATCH_MAPPING] = { .nuops = 1, .uops = { { _MATCH_MAPPING, OPARG_SIMPLE, 0 } } }, [MATCH_SEQUENCE] = { .nuops = 1, .uops = { { _MATCH_SEQUENCE, OPARG_SIMPLE, 0 } } }, @@ -1712,6 +1724,8 @@ const char *_PyOpcode_OpName[267] = { [MAKE_FUNCTION] = "MAKE_FUNCTION", [MAP_ADD] = "MAP_ADD", [MATCH_CLASS] = "MATCH_CLASS", + [MATCH_CLASS_GET_OPT_ATTR] = "MATCH_CLASS_GET_OPT_ATTR", + [MATCH_CLASS_ISINSTANCE] = "MATCH_CLASS_ISINSTANCE", [MATCH_KEYS] = "MATCH_KEYS", [MATCH_MAPPING] = "MATCH_MAPPING", [MATCH_SEQUENCE] = "MATCH_SEQUENCE", @@ -1811,8 +1825,6 @@ const uint8_t _PyOpcode_Caches[256] = { PyAPI_DATA(const uint8_t) _PyOpcode_Deopt[256]; #ifdef NEED_OPCODE_METADATA const uint8_t _PyOpcode_Deopt[256] = { - [120] = 120, - [121] = 121, [122] = 122, [123] = 123, [124] = 124, @@ -2006,6 +2018,8 @@ const uint8_t _PyOpcode_Deopt[256] = { [MAKE_FUNCTION] = MAKE_FUNCTION, [MAP_ADD] = MAP_ADD, [MATCH_CLASS] = MATCH_CLASS, + [MATCH_CLASS_GET_OPT_ATTR] = MATCH_CLASS_GET_OPT_ATTR, + [MATCH_CLASS_ISINSTANCE] = MATCH_CLASS_ISINSTANCE, [MATCH_KEYS] = MATCH_KEYS, [MATCH_MAPPING] = MATCH_MAPPING, [MATCH_SEQUENCE] = MATCH_SEQUENCE, @@ -2072,8 +2086,6 @@ const uint8_t _PyOpcode_Deopt[256] = { #endif // NEED_OPCODE_METADATA #define EXTRA_CASES \ - case 120: \ - case 121: \ case 122: \ case 123: \ case 124: \ diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index f378c756654df7..faf53520b2e63a 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -296,6 +296,8 @@ extern "C" { #define _MAKE_WARM 524 #define _MAP_ADD MAP_ADD #define _MATCH_CLASS 525 +#define _MATCH_CLASS_GET_OPT_ATTR MATCH_CLASS_GET_OPT_ATTR +#define _MATCH_CLASS_ISINSTANCE MATCH_CLASS_ISINSTANCE #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE @@ -1089,222 +1091,224 @@ extern "C" { #define _MAKE_WARM_r33 1293 #define _MAP_ADD_r20 1294 #define _MATCH_CLASS_r33 1295 -#define _MATCH_KEYS_r23 1296 -#define _MATCH_MAPPING_r02 1297 -#define _MATCH_MAPPING_r12 1298 -#define _MATCH_MAPPING_r23 1299 -#define _MATCH_SEQUENCE_r02 1300 -#define _MATCH_SEQUENCE_r12 1301 -#define _MATCH_SEQUENCE_r23 1302 -#define _MAYBE_EXPAND_METHOD_r00 1303 -#define _MAYBE_EXPAND_METHOD_KW_r11 1304 -#define _MONITOR_CALL_r00 1305 -#define _MONITOR_CALL_KW_r11 1306 -#define _MONITOR_JUMP_BACKWARD_r00 1307 -#define _MONITOR_JUMP_BACKWARD_r11 1308 -#define _MONITOR_JUMP_BACKWARD_r22 1309 -#define _MONITOR_JUMP_BACKWARD_r33 1310 -#define _MONITOR_RESUME_r00 1311 -#define _NOP_r00 1312 -#define _NOP_r11 1313 -#define _NOP_r22 1314 -#define _NOP_r33 1315 -#define _POP_CALL_r20 1316 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1317 -#define _POP_CALL_ONE_r30 1318 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1319 -#define _POP_CALL_TWO_r30 1320 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1321 -#define _POP_EXCEPT_r10 1322 -#define _POP_ITER_r20 1323 -#define _POP_JUMP_IF_FALSE_r00 1324 -#define _POP_JUMP_IF_FALSE_r10 1325 -#define _POP_JUMP_IF_FALSE_r21 1326 -#define _POP_JUMP_IF_FALSE_r32 1327 -#define _POP_JUMP_IF_TRUE_r00 1328 -#define _POP_JUMP_IF_TRUE_r10 1329 -#define _POP_JUMP_IF_TRUE_r21 1330 -#define _POP_JUMP_IF_TRUE_r32 1331 -#define _POP_TOP_r10 1332 -#define _POP_TOP_FLOAT_r00 1333 -#define _POP_TOP_FLOAT_r10 1334 -#define _POP_TOP_FLOAT_r21 1335 -#define _POP_TOP_FLOAT_r32 1336 -#define _POP_TOP_INT_r00 1337 -#define _POP_TOP_INT_r10 1338 -#define _POP_TOP_INT_r21 1339 -#define _POP_TOP_INT_r32 1340 -#define _POP_TOP_LOAD_CONST_INLINE_r11 1341 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1342 -#define _POP_TOP_NOP_r00 1343 -#define _POP_TOP_NOP_r10 1344 -#define _POP_TOP_NOP_r21 1345 -#define _POP_TOP_NOP_r32 1346 -#define _POP_TOP_UNICODE_r00 1347 -#define _POP_TOP_UNICODE_r10 1348 -#define _POP_TOP_UNICODE_r21 1349 -#define _POP_TOP_UNICODE_r32 1350 -#define _POP_TWO_r20 1351 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1352 -#define _PUSH_EXC_INFO_r02 1353 -#define _PUSH_EXC_INFO_r12 1354 -#define _PUSH_EXC_INFO_r23 1355 -#define _PUSH_FRAME_r10 1356 -#define _PUSH_NULL_r01 1357 -#define _PUSH_NULL_r12 1358 -#define _PUSH_NULL_r23 1359 -#define _PUSH_NULL_CONDITIONAL_r00 1360 -#define _PY_FRAME_EX_r31 1361 -#define _PY_FRAME_GENERAL_r01 1362 -#define _PY_FRAME_KW_r11 1363 -#define _REPLACE_WITH_TRUE_r02 1364 -#define _REPLACE_WITH_TRUE_r12 1365 -#define _REPLACE_WITH_TRUE_r23 1366 -#define _RESUME_CHECK_r00 1367 -#define _RESUME_CHECK_r11 1368 -#define _RESUME_CHECK_r22 1369 -#define _RESUME_CHECK_r33 1370 -#define _RETURN_GENERATOR_r01 1371 -#define _RETURN_VALUE_r11 1372 -#define _SAVE_RETURN_OFFSET_r00 1373 -#define _SAVE_RETURN_OFFSET_r11 1374 -#define _SAVE_RETURN_OFFSET_r22 1375 -#define _SAVE_RETURN_OFFSET_r33 1376 -#define _SEND_r33 1377 -#define _SEND_GEN_FRAME_r33 1378 -#define _SETUP_ANNOTATIONS_r00 1379 -#define _SET_ADD_r10 1380 -#define _SET_FUNCTION_ATTRIBUTE_r01 1381 -#define _SET_FUNCTION_ATTRIBUTE_r11 1382 -#define _SET_FUNCTION_ATTRIBUTE_r21 1383 -#define _SET_FUNCTION_ATTRIBUTE_r32 1384 -#define _SET_IP_r00 1385 -#define _SET_IP_r11 1386 -#define _SET_IP_r22 1387 -#define _SET_IP_r33 1388 -#define _SET_UPDATE_r11 1389 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1390 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1391 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1392 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1393 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1394 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1395 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1396 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1397 -#define _SPILL_OR_RELOAD_r01 1398 -#define _SPILL_OR_RELOAD_r02 1399 -#define _SPILL_OR_RELOAD_r03 1400 -#define _SPILL_OR_RELOAD_r10 1401 -#define _SPILL_OR_RELOAD_r12 1402 -#define _SPILL_OR_RELOAD_r13 1403 -#define _SPILL_OR_RELOAD_r20 1404 -#define _SPILL_OR_RELOAD_r21 1405 -#define _SPILL_OR_RELOAD_r23 1406 -#define _SPILL_OR_RELOAD_r30 1407 -#define _SPILL_OR_RELOAD_r31 1408 -#define _SPILL_OR_RELOAD_r32 1409 -#define _START_EXECUTOR_r00 1410 -#define _STORE_ATTR_r20 1411 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1412 -#define _STORE_ATTR_SLOT_r21 1413 -#define _STORE_ATTR_WITH_HINT_r21 1414 -#define _STORE_DEREF_r10 1415 -#define _STORE_FAST_LOAD_FAST_r11 1416 -#define _STORE_FAST_STORE_FAST_r20 1417 -#define _STORE_GLOBAL_r10 1418 -#define _STORE_NAME_r10 1419 -#define _STORE_SLICE_r30 1420 -#define _STORE_SUBSCR_r30 1421 -#define _STORE_SUBSCR_DICT_r31 1422 -#define _STORE_SUBSCR_LIST_INT_r32 1423 -#define _SWAP_r11 1424 -#define _SWAP_2_r02 1425 -#define _SWAP_2_r12 1426 -#define _SWAP_2_r22 1427 -#define _SWAP_2_r33 1428 -#define _SWAP_3_r03 1429 -#define _SWAP_3_r13 1430 -#define _SWAP_3_r23 1431 -#define _SWAP_3_r33 1432 -#define _SWAP_FAST_r01 1433 -#define _SWAP_FAST_r11 1434 -#define _SWAP_FAST_r22 1435 -#define _SWAP_FAST_r33 1436 -#define _SWAP_FAST_0_r01 1437 -#define _SWAP_FAST_0_r11 1438 -#define _SWAP_FAST_0_r22 1439 -#define _SWAP_FAST_0_r33 1440 -#define _SWAP_FAST_1_r01 1441 -#define _SWAP_FAST_1_r11 1442 -#define _SWAP_FAST_1_r22 1443 -#define _SWAP_FAST_1_r33 1444 -#define _SWAP_FAST_2_r01 1445 -#define _SWAP_FAST_2_r11 1446 -#define _SWAP_FAST_2_r22 1447 -#define _SWAP_FAST_2_r33 1448 -#define _SWAP_FAST_3_r01 1449 -#define _SWAP_FAST_3_r11 1450 -#define _SWAP_FAST_3_r22 1451 -#define _SWAP_FAST_3_r33 1452 -#define _SWAP_FAST_4_r01 1453 -#define _SWAP_FAST_4_r11 1454 -#define _SWAP_FAST_4_r22 1455 -#define _SWAP_FAST_4_r33 1456 -#define _SWAP_FAST_5_r01 1457 -#define _SWAP_FAST_5_r11 1458 -#define _SWAP_FAST_5_r22 1459 -#define _SWAP_FAST_5_r33 1460 -#define _SWAP_FAST_6_r01 1461 -#define _SWAP_FAST_6_r11 1462 -#define _SWAP_FAST_6_r22 1463 -#define _SWAP_FAST_6_r33 1464 -#define _SWAP_FAST_7_r01 1465 -#define _SWAP_FAST_7_r11 1466 -#define _SWAP_FAST_7_r22 1467 -#define _SWAP_FAST_7_r33 1468 -#define _TIER2_RESUME_CHECK_r00 1469 -#define _TIER2_RESUME_CHECK_r11 1470 -#define _TIER2_RESUME_CHECK_r22 1471 -#define _TIER2_RESUME_CHECK_r33 1472 -#define _TO_BOOL_r11 1473 -#define _TO_BOOL_BOOL_r01 1474 -#define _TO_BOOL_BOOL_r11 1475 -#define _TO_BOOL_BOOL_r22 1476 -#define _TO_BOOL_BOOL_r33 1477 -#define _TO_BOOL_INT_r02 1478 -#define _TO_BOOL_INT_r12 1479 -#define _TO_BOOL_INT_r23 1480 -#define _TO_BOOL_LIST_r02 1481 -#define _TO_BOOL_LIST_r12 1482 -#define _TO_BOOL_LIST_r23 1483 -#define _TO_BOOL_NONE_r01 1484 -#define _TO_BOOL_NONE_r11 1485 -#define _TO_BOOL_NONE_r22 1486 -#define _TO_BOOL_NONE_r33 1487 -#define _TO_BOOL_STR_r02 1488 -#define _TO_BOOL_STR_r12 1489 -#define _TO_BOOL_STR_r23 1490 -#define _TRACE_RECORD_r00 1491 -#define _UNARY_INVERT_r12 1492 -#define _UNARY_NEGATIVE_r12 1493 -#define _UNARY_NOT_r01 1494 -#define _UNARY_NOT_r11 1495 -#define _UNARY_NOT_r22 1496 -#define _UNARY_NOT_r33 1497 -#define _UNPACK_EX_r10 1498 -#define _UNPACK_SEQUENCE_r10 1499 -#define _UNPACK_SEQUENCE_LIST_r10 1500 -#define _UNPACK_SEQUENCE_TUPLE_r10 1501 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1502 -#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r03 1503 -#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r13 1504 -#define _UNPACK_SEQUENCE_UNIQUE_TUPLE_r10 1505 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r02 1506 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r12 1507 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r23 1508 -#define _WITH_EXCEPT_START_r33 1509 -#define _YIELD_VALUE_r11 1510 -#define MAX_UOP_REGS_ID 1510 +#define _MATCH_CLASS_GET_OPT_ATTR_r13 1296 +#define _MATCH_CLASS_ISINSTANCE_r22 1297 +#define _MATCH_KEYS_r23 1298 +#define _MATCH_MAPPING_r02 1299 +#define _MATCH_MAPPING_r12 1300 +#define _MATCH_MAPPING_r23 1301 +#define _MATCH_SEQUENCE_r02 1302 +#define _MATCH_SEQUENCE_r12 1303 +#define _MATCH_SEQUENCE_r23 1304 +#define _MAYBE_EXPAND_METHOD_r00 1305 +#define _MAYBE_EXPAND_METHOD_KW_r11 1306 +#define _MONITOR_CALL_r00 1307 +#define _MONITOR_CALL_KW_r11 1308 +#define _MONITOR_JUMP_BACKWARD_r00 1309 +#define _MONITOR_JUMP_BACKWARD_r11 1310 +#define _MONITOR_JUMP_BACKWARD_r22 1311 +#define _MONITOR_JUMP_BACKWARD_r33 1312 +#define _MONITOR_RESUME_r00 1313 +#define _NOP_r00 1314 +#define _NOP_r11 1315 +#define _NOP_r22 1316 +#define _NOP_r33 1317 +#define _POP_CALL_r20 1318 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1319 +#define _POP_CALL_ONE_r30 1320 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1321 +#define _POP_CALL_TWO_r30 1322 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1323 +#define _POP_EXCEPT_r10 1324 +#define _POP_ITER_r20 1325 +#define _POP_JUMP_IF_FALSE_r00 1326 +#define _POP_JUMP_IF_FALSE_r10 1327 +#define _POP_JUMP_IF_FALSE_r21 1328 +#define _POP_JUMP_IF_FALSE_r32 1329 +#define _POP_JUMP_IF_TRUE_r00 1330 +#define _POP_JUMP_IF_TRUE_r10 1331 +#define _POP_JUMP_IF_TRUE_r21 1332 +#define _POP_JUMP_IF_TRUE_r32 1333 +#define _POP_TOP_r10 1334 +#define _POP_TOP_FLOAT_r00 1335 +#define _POP_TOP_FLOAT_r10 1336 +#define _POP_TOP_FLOAT_r21 1337 +#define _POP_TOP_FLOAT_r32 1338 +#define _POP_TOP_INT_r00 1339 +#define _POP_TOP_INT_r10 1340 +#define _POP_TOP_INT_r21 1341 +#define _POP_TOP_INT_r32 1342 +#define _POP_TOP_LOAD_CONST_INLINE_r11 1343 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1344 +#define _POP_TOP_NOP_r00 1345 +#define _POP_TOP_NOP_r10 1346 +#define _POP_TOP_NOP_r21 1347 +#define _POP_TOP_NOP_r32 1348 +#define _POP_TOP_UNICODE_r00 1349 +#define _POP_TOP_UNICODE_r10 1350 +#define _POP_TOP_UNICODE_r21 1351 +#define _POP_TOP_UNICODE_r32 1352 +#define _POP_TWO_r20 1353 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1354 +#define _PUSH_EXC_INFO_r02 1355 +#define _PUSH_EXC_INFO_r12 1356 +#define _PUSH_EXC_INFO_r23 1357 +#define _PUSH_FRAME_r10 1358 +#define _PUSH_NULL_r01 1359 +#define _PUSH_NULL_r12 1360 +#define _PUSH_NULL_r23 1361 +#define _PUSH_NULL_CONDITIONAL_r00 1362 +#define _PY_FRAME_EX_r31 1363 +#define _PY_FRAME_GENERAL_r01 1364 +#define _PY_FRAME_KW_r11 1365 +#define _REPLACE_WITH_TRUE_r02 1366 +#define _REPLACE_WITH_TRUE_r12 1367 +#define _REPLACE_WITH_TRUE_r23 1368 +#define _RESUME_CHECK_r00 1369 +#define _RESUME_CHECK_r11 1370 +#define _RESUME_CHECK_r22 1371 +#define _RESUME_CHECK_r33 1372 +#define _RETURN_GENERATOR_r01 1373 +#define _RETURN_VALUE_r11 1374 +#define _SAVE_RETURN_OFFSET_r00 1375 +#define _SAVE_RETURN_OFFSET_r11 1376 +#define _SAVE_RETURN_OFFSET_r22 1377 +#define _SAVE_RETURN_OFFSET_r33 1378 +#define _SEND_r33 1379 +#define _SEND_GEN_FRAME_r33 1380 +#define _SETUP_ANNOTATIONS_r00 1381 +#define _SET_ADD_r10 1382 +#define _SET_FUNCTION_ATTRIBUTE_r01 1383 +#define _SET_FUNCTION_ATTRIBUTE_r11 1384 +#define _SET_FUNCTION_ATTRIBUTE_r21 1385 +#define _SET_FUNCTION_ATTRIBUTE_r32 1386 +#define _SET_IP_r00 1387 +#define _SET_IP_r11 1388 +#define _SET_IP_r22 1389 +#define _SET_IP_r33 1390 +#define _SET_UPDATE_r11 1391 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1392 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1393 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1394 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1395 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1396 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1397 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1398 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1399 +#define _SPILL_OR_RELOAD_r01 1400 +#define _SPILL_OR_RELOAD_r02 1401 +#define _SPILL_OR_RELOAD_r03 1402 +#define _SPILL_OR_RELOAD_r10 1403 +#define _SPILL_OR_RELOAD_r12 1404 +#define _SPILL_OR_RELOAD_r13 1405 +#define _SPILL_OR_RELOAD_r20 1406 +#define _SPILL_OR_RELOAD_r21 1407 +#define _SPILL_OR_RELOAD_r23 1408 +#define _SPILL_OR_RELOAD_r30 1409 +#define _SPILL_OR_RELOAD_r31 1410 +#define _SPILL_OR_RELOAD_r32 1411 +#define _START_EXECUTOR_r00 1412 +#define _STORE_ATTR_r20 1413 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1414 +#define _STORE_ATTR_SLOT_r21 1415 +#define _STORE_ATTR_WITH_HINT_r21 1416 +#define _STORE_DEREF_r10 1417 +#define _STORE_FAST_LOAD_FAST_r11 1418 +#define _STORE_FAST_STORE_FAST_r20 1419 +#define _STORE_GLOBAL_r10 1420 +#define _STORE_NAME_r10 1421 +#define _STORE_SLICE_r30 1422 +#define _STORE_SUBSCR_r30 1423 +#define _STORE_SUBSCR_DICT_r31 1424 +#define _STORE_SUBSCR_LIST_INT_r32 1425 +#define _SWAP_r11 1426 +#define _SWAP_2_r02 1427 +#define _SWAP_2_r12 1428 +#define _SWAP_2_r22 1429 +#define _SWAP_2_r33 1430 +#define _SWAP_3_r03 1431 +#define _SWAP_3_r13 1432 +#define _SWAP_3_r23 1433 +#define _SWAP_3_r33 1434 +#define _SWAP_FAST_r01 1435 +#define _SWAP_FAST_r11 1436 +#define _SWAP_FAST_r22 1437 +#define _SWAP_FAST_r33 1438 +#define _SWAP_FAST_0_r01 1439 +#define _SWAP_FAST_0_r11 1440 +#define _SWAP_FAST_0_r22 1441 +#define _SWAP_FAST_0_r33 1442 +#define _SWAP_FAST_1_r01 1443 +#define _SWAP_FAST_1_r11 1444 +#define _SWAP_FAST_1_r22 1445 +#define _SWAP_FAST_1_r33 1446 +#define _SWAP_FAST_2_r01 1447 +#define _SWAP_FAST_2_r11 1448 +#define _SWAP_FAST_2_r22 1449 +#define _SWAP_FAST_2_r33 1450 +#define _SWAP_FAST_3_r01 1451 +#define _SWAP_FAST_3_r11 1452 +#define _SWAP_FAST_3_r22 1453 +#define _SWAP_FAST_3_r33 1454 +#define _SWAP_FAST_4_r01 1455 +#define _SWAP_FAST_4_r11 1456 +#define _SWAP_FAST_4_r22 1457 +#define _SWAP_FAST_4_r33 1458 +#define _SWAP_FAST_5_r01 1459 +#define _SWAP_FAST_5_r11 1460 +#define _SWAP_FAST_5_r22 1461 +#define _SWAP_FAST_5_r33 1462 +#define _SWAP_FAST_6_r01 1463 +#define _SWAP_FAST_6_r11 1464 +#define _SWAP_FAST_6_r22 1465 +#define _SWAP_FAST_6_r33 1466 +#define _SWAP_FAST_7_r01 1467 +#define _SWAP_FAST_7_r11 1468 +#define _SWAP_FAST_7_r22 1469 +#define _SWAP_FAST_7_r33 1470 +#define _TIER2_RESUME_CHECK_r00 1471 +#define _TIER2_RESUME_CHECK_r11 1472 +#define _TIER2_RESUME_CHECK_r22 1473 +#define _TIER2_RESUME_CHECK_r33 1474 +#define _TO_BOOL_r11 1475 +#define _TO_BOOL_BOOL_r01 1476 +#define _TO_BOOL_BOOL_r11 1477 +#define _TO_BOOL_BOOL_r22 1478 +#define _TO_BOOL_BOOL_r33 1479 +#define _TO_BOOL_INT_r02 1480 +#define _TO_BOOL_INT_r12 1481 +#define _TO_BOOL_INT_r23 1482 +#define _TO_BOOL_LIST_r02 1483 +#define _TO_BOOL_LIST_r12 1484 +#define _TO_BOOL_LIST_r23 1485 +#define _TO_BOOL_NONE_r01 1486 +#define _TO_BOOL_NONE_r11 1487 +#define _TO_BOOL_NONE_r22 1488 +#define _TO_BOOL_NONE_r33 1489 +#define _TO_BOOL_STR_r02 1490 +#define _TO_BOOL_STR_r12 1491 +#define _TO_BOOL_STR_r23 1492 +#define _TRACE_RECORD_r00 1493 +#define _UNARY_INVERT_r12 1494 +#define _UNARY_NEGATIVE_r12 1495 +#define _UNARY_NOT_r01 1496 +#define _UNARY_NOT_r11 1497 +#define _UNARY_NOT_r22 1498 +#define _UNARY_NOT_r33 1499 +#define _UNPACK_EX_r10 1500 +#define _UNPACK_SEQUENCE_r10 1501 +#define _UNPACK_SEQUENCE_LIST_r10 1502 +#define _UNPACK_SEQUENCE_TUPLE_r10 1503 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1504 +#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r03 1505 +#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r13 1506 +#define _UNPACK_SEQUENCE_UNIQUE_TUPLE_r10 1507 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r02 1508 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r12 1509 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r23 1510 +#define _WITH_EXCEPT_START_r33 1511 +#define _YIELD_VALUE_r11 1512 +#define MAX_UOP_REGS_ID 1512 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 46cdda273599c4..c7ece1cadb9a17 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -228,6 +228,8 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_IMPORT_FROM] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_IS_NONE] = HAS_ESCAPES_FLAG, [_GET_LEN] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_MATCH_CLASS_ISINSTANCE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_MATCH_CLASS_GET_OPT_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_MATCH_CLASS] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_MATCH_MAPPING] = 0, [_MATCH_SEQUENCE] = 0, @@ -2148,6 +2150,24 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { -1, -1, -1 }, }, }, + [_MATCH_CLASS_ISINSTANCE] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 2, 2, _MATCH_CLASS_ISINSTANCE_r22 }, + { -1, -1, -1 }, + }, + }, + [_MATCH_CLASS_GET_OPT_ATTR] = { + .best = { 1, 1, 1, 1 }, + .entries = { + { -1, -1, -1 }, + { 3, 1, _MATCH_CLASS_GET_OPT_ATTR_r13 }, + { -1, -1, -1 }, + { -1, -1, -1 }, + }, + }, [_MATCH_CLASS] = { .best = { 3, 3, 3, 3 }, .entries = { @@ -4012,6 +4032,8 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_IMPORT_FROM_r12] = _IMPORT_FROM, [_IS_NONE_r11] = _IS_NONE, [_GET_LEN_r12] = _GET_LEN, + [_MATCH_CLASS_ISINSTANCE_r22] = _MATCH_CLASS_ISINSTANCE, + [_MATCH_CLASS_GET_OPT_ATTR_r13] = _MATCH_CLASS_GET_OPT_ATTR, [_MATCH_CLASS_r33] = _MATCH_CLASS, [_MATCH_MAPPING_r02] = _MATCH_MAPPING, [_MATCH_MAPPING_r12] = _MATCH_MAPPING, @@ -5327,6 +5349,10 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_MAP_ADD_r20] = "_MAP_ADD_r20", [_MATCH_CLASS] = "_MATCH_CLASS", [_MATCH_CLASS_r33] = "_MATCH_CLASS_r33", + [_MATCH_CLASS_GET_OPT_ATTR] = "_MATCH_CLASS_GET_OPT_ATTR", + [_MATCH_CLASS_GET_OPT_ATTR_r13] = "_MATCH_CLASS_GET_OPT_ATTR_r13", + [_MATCH_CLASS_ISINSTANCE] = "_MATCH_CLASS_ISINSTANCE", + [_MATCH_CLASS_ISINSTANCE_r22] = "_MATCH_CLASS_ISINSTANCE_r22", [_MATCH_KEYS] = "_MATCH_KEYS", [_MATCH_KEYS_r23] = "_MATCH_KEYS_r23", [_MATCH_MAPPING] = "_MATCH_MAPPING", @@ -6010,6 +6036,10 @@ int _PyUop_num_popped(int opcode, int oparg) return 1; case _GET_LEN: return 0; + case _MATCH_CLASS_ISINSTANCE: + return 1; + case _MATCH_CLASS_GET_OPT_ATTR: + return 0; case _MATCH_CLASS: return 3; case _MATCH_MAPPING: diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h index ac6d4d964d3b5e..393daef9621138 100644 --- a/Include/opcode_ids.h +++ b/Include/opcode_ids.h @@ -32,104 +32,106 @@ extern "C" { #define LOAD_BUILD_CLASS 19 #define LOAD_LOCALS 20 #define MAKE_FUNCTION 21 -#define MATCH_KEYS 22 -#define MATCH_MAPPING 23 -#define MATCH_SEQUENCE 24 -#define NOP 25 -#define NOT_TAKEN 26 -#define POP_EXCEPT 27 -#define POP_ITER 28 -#define POP_TOP 29 -#define PUSH_EXC_INFO 30 -#define PUSH_NULL 31 -#define RETURN_GENERATOR 32 -#define RETURN_VALUE 33 -#define SETUP_ANNOTATIONS 34 -#define STORE_SLICE 35 -#define STORE_SUBSCR 36 -#define TO_BOOL 37 -#define UNARY_INVERT 38 -#define UNARY_NEGATIVE 39 -#define UNARY_NOT 40 -#define WITH_EXCEPT_START 41 -#define BINARY_OP 42 -#define BUILD_INTERPOLATION 43 -#define BUILD_LIST 44 -#define BUILD_MAP 45 -#define BUILD_SET 46 -#define BUILD_SLICE 47 -#define BUILD_STRING 48 -#define BUILD_TUPLE 49 -#define CALL 50 -#define CALL_INTRINSIC_1 51 -#define CALL_INTRINSIC_2 52 -#define CALL_KW 53 -#define COMPARE_OP 54 -#define CONTAINS_OP 55 -#define CONVERT_VALUE 56 -#define COPY 57 -#define COPY_FREE_VARS 58 -#define DELETE_ATTR 59 -#define DELETE_DEREF 60 -#define DELETE_FAST 61 -#define DELETE_GLOBAL 62 -#define DELETE_NAME 63 -#define DICT_MERGE 64 -#define DICT_UPDATE 65 -#define END_ASYNC_FOR 66 -#define EXTENDED_ARG 67 -#define FOR_ITER 68 -#define GET_AWAITABLE 69 -#define GET_ITER 70 -#define IMPORT_FROM 71 -#define IMPORT_NAME 72 -#define IS_OP 73 -#define JUMP_BACKWARD 74 -#define JUMP_BACKWARD_NO_INTERRUPT 75 -#define JUMP_FORWARD 76 -#define LIST_APPEND 77 -#define LIST_EXTEND 78 -#define LOAD_ATTR 79 -#define LOAD_COMMON_CONSTANT 80 -#define LOAD_CONST 81 -#define LOAD_DEREF 82 -#define LOAD_FAST 83 -#define LOAD_FAST_AND_CLEAR 84 -#define LOAD_FAST_BORROW 85 -#define LOAD_FAST_BORROW_LOAD_FAST_BORROW 86 -#define LOAD_FAST_CHECK 87 -#define LOAD_FAST_LOAD_FAST 88 -#define LOAD_FROM_DICT_OR_DEREF 89 -#define LOAD_FROM_DICT_OR_GLOBALS 90 -#define LOAD_GLOBAL 91 -#define LOAD_NAME 92 -#define LOAD_SMALL_INT 93 -#define LOAD_SPECIAL 94 -#define LOAD_SUPER_ATTR 95 -#define MAKE_CELL 96 -#define MAP_ADD 97 -#define MATCH_CLASS 98 -#define POP_JUMP_IF_FALSE 99 -#define POP_JUMP_IF_NONE 100 -#define POP_JUMP_IF_NOT_NONE 101 -#define POP_JUMP_IF_TRUE 102 -#define RAISE_VARARGS 103 -#define RERAISE 104 -#define SEND 105 -#define SET_ADD 106 -#define SET_FUNCTION_ATTRIBUTE 107 -#define SET_UPDATE 108 -#define STORE_ATTR 109 -#define STORE_DEREF 110 -#define STORE_FAST 111 -#define STORE_FAST_LOAD_FAST 112 -#define STORE_FAST_STORE_FAST 113 -#define STORE_GLOBAL 114 -#define STORE_NAME 115 -#define SWAP 116 -#define UNPACK_EX 117 -#define UNPACK_SEQUENCE 118 -#define YIELD_VALUE 119 +#define MATCH_CLASS_ISINSTANCE 22 +#define MATCH_KEYS 23 +#define MATCH_MAPPING 24 +#define MATCH_SEQUENCE 25 +#define NOP 26 +#define NOT_TAKEN 27 +#define POP_EXCEPT 28 +#define POP_ITER 29 +#define POP_TOP 30 +#define PUSH_EXC_INFO 31 +#define PUSH_NULL 32 +#define RETURN_GENERATOR 33 +#define RETURN_VALUE 34 +#define SETUP_ANNOTATIONS 35 +#define STORE_SLICE 36 +#define STORE_SUBSCR 37 +#define TO_BOOL 38 +#define UNARY_INVERT 39 +#define UNARY_NEGATIVE 40 +#define UNARY_NOT 41 +#define WITH_EXCEPT_START 42 +#define BINARY_OP 43 +#define BUILD_INTERPOLATION 44 +#define BUILD_LIST 45 +#define BUILD_MAP 46 +#define BUILD_SET 47 +#define BUILD_SLICE 48 +#define BUILD_STRING 49 +#define BUILD_TUPLE 50 +#define CALL 51 +#define CALL_INTRINSIC_1 52 +#define CALL_INTRINSIC_2 53 +#define CALL_KW 54 +#define COMPARE_OP 55 +#define CONTAINS_OP 56 +#define CONVERT_VALUE 57 +#define COPY 58 +#define COPY_FREE_VARS 59 +#define DELETE_ATTR 60 +#define DELETE_DEREF 61 +#define DELETE_FAST 62 +#define DELETE_GLOBAL 63 +#define DELETE_NAME 64 +#define DICT_MERGE 65 +#define DICT_UPDATE 66 +#define END_ASYNC_FOR 67 +#define EXTENDED_ARG 68 +#define FOR_ITER 69 +#define GET_AWAITABLE 70 +#define GET_ITER 71 +#define IMPORT_FROM 72 +#define IMPORT_NAME 73 +#define IS_OP 74 +#define JUMP_BACKWARD 75 +#define JUMP_BACKWARD_NO_INTERRUPT 76 +#define JUMP_FORWARD 77 +#define LIST_APPEND 78 +#define LIST_EXTEND 79 +#define LOAD_ATTR 80 +#define LOAD_COMMON_CONSTANT 81 +#define LOAD_CONST 82 +#define LOAD_DEREF 83 +#define LOAD_FAST 84 +#define LOAD_FAST_AND_CLEAR 85 +#define LOAD_FAST_BORROW 86 +#define LOAD_FAST_BORROW_LOAD_FAST_BORROW 87 +#define LOAD_FAST_CHECK 88 +#define LOAD_FAST_LOAD_FAST 89 +#define LOAD_FROM_DICT_OR_DEREF 90 +#define LOAD_FROM_DICT_OR_GLOBALS 91 +#define LOAD_GLOBAL 92 +#define LOAD_NAME 93 +#define LOAD_SMALL_INT 94 +#define LOAD_SPECIAL 95 +#define LOAD_SUPER_ATTR 96 +#define MAKE_CELL 97 +#define MAP_ADD 98 +#define MATCH_CLASS 99 +#define MATCH_CLASS_GET_OPT_ATTR 100 +#define POP_JUMP_IF_FALSE 101 +#define POP_JUMP_IF_NONE 102 +#define POP_JUMP_IF_NOT_NONE 103 +#define POP_JUMP_IF_TRUE 104 +#define RAISE_VARARGS 105 +#define RERAISE 106 +#define SEND 107 +#define SET_ADD 108 +#define SET_FUNCTION_ATTRIBUTE 109 +#define SET_UPDATE 110 +#define STORE_ATTR 111 +#define STORE_DEREF 112 +#define STORE_FAST 113 +#define STORE_FAST_LOAD_FAST 114 +#define STORE_FAST_STORE_FAST 115 +#define STORE_GLOBAL 116 +#define STORE_NAME 117 +#define SWAP 118 +#define UNPACK_EX 119 +#define UNPACK_SEQUENCE 120 +#define YIELD_VALUE 121 #define RESUME 128 #define BINARY_OP_ADD_FLOAT 129 #define BINARY_OP_ADD_INT 130 @@ -251,7 +253,7 @@ extern "C" { #define SETUP_WITH 265 #define STORE_FAST_MAYBE_NULL 266 -#define HAVE_ARGUMENT 41 +#define HAVE_ARGUMENT 42 #define MIN_SPECIALIZED_OPCODE 129 #define MIN_INSTRUMENTED_OPCODE 233 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index f5954e4372a980..2a2d8f00d9b310 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -240,104 +240,106 @@ LOAD_BUILD_CLASS=19, LOAD_LOCALS=20, MAKE_FUNCTION=21, - MATCH_KEYS=22, - MATCH_MAPPING=23, - MATCH_SEQUENCE=24, - NOP=25, - NOT_TAKEN=26, - POP_EXCEPT=27, - POP_ITER=28, - POP_TOP=29, - PUSH_EXC_INFO=30, - PUSH_NULL=31, - RETURN_GENERATOR=32, - RETURN_VALUE=33, - SETUP_ANNOTATIONS=34, - STORE_SLICE=35, - STORE_SUBSCR=36, - TO_BOOL=37, - UNARY_INVERT=38, - UNARY_NEGATIVE=39, - UNARY_NOT=40, - WITH_EXCEPT_START=41, - BINARY_OP=42, - BUILD_INTERPOLATION=43, - BUILD_LIST=44, - BUILD_MAP=45, - BUILD_SET=46, - BUILD_SLICE=47, - BUILD_STRING=48, - BUILD_TUPLE=49, - CALL=50, - CALL_INTRINSIC_1=51, - CALL_INTRINSIC_2=52, - CALL_KW=53, - COMPARE_OP=54, - CONTAINS_OP=55, - CONVERT_VALUE=56, - COPY=57, - COPY_FREE_VARS=58, - DELETE_ATTR=59, - DELETE_DEREF=60, - DELETE_FAST=61, - DELETE_GLOBAL=62, - DELETE_NAME=63, - DICT_MERGE=64, - DICT_UPDATE=65, - END_ASYNC_FOR=66, - EXTENDED_ARG=67, - FOR_ITER=68, - GET_AWAITABLE=69, - GET_ITER=70, - IMPORT_FROM=71, - IMPORT_NAME=72, - IS_OP=73, - JUMP_BACKWARD=74, - JUMP_BACKWARD_NO_INTERRUPT=75, - JUMP_FORWARD=76, - LIST_APPEND=77, - LIST_EXTEND=78, - LOAD_ATTR=79, - LOAD_COMMON_CONSTANT=80, - LOAD_CONST=81, - LOAD_DEREF=82, - LOAD_FAST=83, - LOAD_FAST_AND_CLEAR=84, - LOAD_FAST_BORROW=85, - LOAD_FAST_BORROW_LOAD_FAST_BORROW=86, - LOAD_FAST_CHECK=87, - LOAD_FAST_LOAD_FAST=88, - LOAD_FROM_DICT_OR_DEREF=89, - LOAD_FROM_DICT_OR_GLOBALS=90, - LOAD_GLOBAL=91, - LOAD_NAME=92, - LOAD_SMALL_INT=93, - LOAD_SPECIAL=94, - LOAD_SUPER_ATTR=95, - MAKE_CELL=96, - MAP_ADD=97, - MATCH_CLASS=98, - POP_JUMP_IF_FALSE=99, - POP_JUMP_IF_NONE=100, - POP_JUMP_IF_NOT_NONE=101, - POP_JUMP_IF_TRUE=102, - RAISE_VARARGS=103, - RERAISE=104, - SEND=105, - SET_ADD=106, - SET_FUNCTION_ATTRIBUTE=107, - SET_UPDATE=108, - STORE_ATTR=109, - STORE_DEREF=110, - STORE_FAST=111, - STORE_FAST_LOAD_FAST=112, - STORE_FAST_STORE_FAST=113, - STORE_GLOBAL=114, - STORE_NAME=115, - SWAP=116, - UNPACK_EX=117, - UNPACK_SEQUENCE=118, - YIELD_VALUE=119, + MATCH_CLASS_ISINSTANCE=22, + MATCH_KEYS=23, + MATCH_MAPPING=24, + MATCH_SEQUENCE=25, + NOP=26, + NOT_TAKEN=27, + POP_EXCEPT=28, + POP_ITER=29, + POP_TOP=30, + PUSH_EXC_INFO=31, + PUSH_NULL=32, + RETURN_GENERATOR=33, + RETURN_VALUE=34, + SETUP_ANNOTATIONS=35, + STORE_SLICE=36, + STORE_SUBSCR=37, + TO_BOOL=38, + UNARY_INVERT=39, + UNARY_NEGATIVE=40, + UNARY_NOT=41, + WITH_EXCEPT_START=42, + BINARY_OP=43, + BUILD_INTERPOLATION=44, + BUILD_LIST=45, + BUILD_MAP=46, + BUILD_SET=47, + BUILD_SLICE=48, + BUILD_STRING=49, + BUILD_TUPLE=50, + CALL=51, + CALL_INTRINSIC_1=52, + CALL_INTRINSIC_2=53, + CALL_KW=54, + COMPARE_OP=55, + CONTAINS_OP=56, + CONVERT_VALUE=57, + COPY=58, + COPY_FREE_VARS=59, + DELETE_ATTR=60, + DELETE_DEREF=61, + DELETE_FAST=62, + DELETE_GLOBAL=63, + DELETE_NAME=64, + DICT_MERGE=65, + DICT_UPDATE=66, + END_ASYNC_FOR=67, + EXTENDED_ARG=68, + FOR_ITER=69, + GET_AWAITABLE=70, + GET_ITER=71, + IMPORT_FROM=72, + IMPORT_NAME=73, + IS_OP=74, + JUMP_BACKWARD=75, + JUMP_BACKWARD_NO_INTERRUPT=76, + JUMP_FORWARD=77, + LIST_APPEND=78, + LIST_EXTEND=79, + LOAD_ATTR=80, + LOAD_COMMON_CONSTANT=81, + LOAD_CONST=82, + LOAD_DEREF=83, + LOAD_FAST=84, + LOAD_FAST_AND_CLEAR=85, + LOAD_FAST_BORROW=86, + LOAD_FAST_BORROW_LOAD_FAST_BORROW=87, + LOAD_FAST_CHECK=88, + LOAD_FAST_LOAD_FAST=89, + LOAD_FROM_DICT_OR_DEREF=90, + LOAD_FROM_DICT_OR_GLOBALS=91, + LOAD_GLOBAL=92, + LOAD_NAME=93, + LOAD_SMALL_INT=94, + LOAD_SPECIAL=95, + LOAD_SUPER_ATTR=96, + MAKE_CELL=97, + MAP_ADD=98, + MATCH_CLASS=99, + MATCH_CLASS_GET_OPT_ATTR=100, + POP_JUMP_IF_FALSE=101, + POP_JUMP_IF_NONE=102, + POP_JUMP_IF_NOT_NONE=103, + POP_JUMP_IF_TRUE=104, + RAISE_VARARGS=105, + RERAISE=106, + SEND=107, + SET_ADD=108, + SET_FUNCTION_ATTRIBUTE=109, + SET_UPDATE=110, + STORE_ATTR=111, + STORE_DEREF=112, + STORE_FAST=113, + STORE_FAST_LOAD_FAST=114, + STORE_FAST_STORE_FAST=115, + STORE_GLOBAL=116, + STORE_NAME=117, + SWAP=118, + UNPACK_EX=119, + UNPACK_SEQUENCE=120, + YIELD_VALUE=121, INSTRUMENTED_END_FOR=233, INSTRUMENTED_POP_ITER=234, INSTRUMENTED_END_SEND=235, @@ -371,5 +373,5 @@ STORE_FAST_MAYBE_NULL=266, ) -HAVE_ARGUMENT = 41 +HAVE_ARGUMENT = 42 MIN_INSTRUMENTED_OPCODE = 233 diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index e90998bb1e3b27..b22b6fd65cbeca 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -4134,12 +4134,13 @@ def testfunc(n): def test_match_class(self): def testfunc(n): class A: + __match_args__ = ("val",) val = 1 x = A() ret = 0 for _ in range(n): match x: - case A(): + case A(1): ret += x.val return ret @@ -4148,7 +4149,7 @@ class A: uops = get_opnames(ex) self.assertIn("_MATCH_CLASS", uops) - self.assertEqual(count_ops(ex, "_POP_TOP_NOP"), 4) + self.assertEqual(count_ops(ex, "_POP_TOP_NOP"), 5) def test_set_update(self): def testfunc(n): diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index f8bbcd35ca7c09..c41ca57cd026f5 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1039,7 +1039,8 @@ def test_widths(self): 'LOAD_FAST_BORROW_LOAD_FAST_BORROW', 'INSTRUMENTED_CALL_FUNCTION_EX', 'YIELD_FROM_CORO_CHECK', - 'ANNOTATIONS_PLACEHOLDER']) + 'ANNOTATIONS_PLACEHOLDER', + 'MATCH_CLASS_ISINSTANCE']) for op, opname in enumerate(dis.opname): if opname in long_opcodes or opname.startswith("INSTRUMENTED"): continue diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index e0cc010f15513b..267cf6139808e0 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -786,6 +786,14 @@ def test_static_swaps_match_mapping(self): self.assertNotInBytecode(code, "SWAP") def test_static_swaps_match_class(self): + swaps = { + "C(a=a, b=_, c=_)", + "C(a=a, b=_, c=c)", + "C(a=a, b=b, c=_)", + "C(a=a, b=b, c=c)", + "C(a=_, b=b, c=_)", + "C(a=_, b=b, c=c)", + } forms = [ "C({}, {}, {})", "C({}, {}, c={})", @@ -797,7 +805,12 @@ def test_static_swaps_match_class(self): pattern = form.format(a, b, c) with self.subTest(pattern): code = compile_pattern_with_fast_locals(pattern) - self.assertNotInBytecode(code, "SWAP") + if pattern in swaps: + # Swaps are expected here. Class patterns without + # positional sub-patterns are evaluated depth first. + self.assertInBytecode(code, "SWAP") + else: + self.assertNotInBytecode(code, "SWAP") def test_static_swaps_match_sequence(self): swaps = {"*_, b, c", "a, *_, c", "a, b, *_"} diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-09-17-22-12-38.gh-issue-138912.PijFSS.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-17-22-12-38.gh-issue-138912.PijFSS.rst new file mode 100644 index 00000000000000..0fbc17a6e4b59f --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-17-22-12-38.gh-issue-138912.PijFSS.rst @@ -0,0 +1,3 @@ +Add :opcode:`MATCH_CLASS_ISINSTANCE` and :opcode:`MATCH_CLASS_GET_OPT_ATTR` +to improve the performance of :keyword:`match` class patterns without any +positional sub-patterns by ~60%. Patch by Marc Mueller. diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index d5b3735eb2b64e..7ff720a3ecc670 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -10021,6 +10021,89 @@ DISPATCH(); } + TARGET(MATCH_CLASS_GET_OPT_ATTR) { + #if _Py_TAIL_CALL_INTERP + int opcode = MATCH_CLASS_GET_OPT_ATTR; + (void)(opcode); + #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(MATCH_CLASS_GET_OPT_ATTR); + _PyStackRef subject; + _PyStackRef attr; + _PyStackRef res; + subject = stack_pointer[-1]; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + assert(PyUnicode_CheckExact(name)); + PyObject *subject_o = PyStackRef_AsPyObjectBorrow(subject); + PyObject *attr_o; + _PyFrame_SetStackPointer(frame, stack_pointer); + (void)PyObject_GetOptionalAttr(subject_o, name, &attr_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (attr_o) { + assert(!_PyErr_Occurred(tstate)); + attr = PyStackRef_FromPyObjectSteal(attr_o); + res = PyStackRef_True; + } else { + if (_PyErr_Occurred(tstate)) { + JUMP_TO_LABEL(error); + } + attr = PyStackRef_FromPyObjectSteal(Py_None); + res = PyStackRef_False; + } + stack_pointer[0] = attr; + stack_pointer[1] = res; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + DISPATCH(); + } + + TARGET(MATCH_CLASS_ISINSTANCE) { + #if _Py_TAIL_CALL_INTERP + int opcode = MATCH_CLASS_ISINSTANCE; + (void)(opcode); + #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(MATCH_CLASS_ISINSTANCE); + _PyStackRef subject; + _PyStackRef type; + _PyStackRef res; + type = stack_pointer[-1]; + subject = stack_pointer[-2]; + PyObject *subject_o = PyStackRef_AsPyObjectBorrow(subject); + PyObject *type_o = PyStackRef_AsPyObjectBorrow(type); + if (!PyType_Check(type_o)) { + const char *e = "called match pattern must be a class"; + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyErr_Format(tstate, PyExc_TypeError, e); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(type); + stack_pointer = _PyFrame_GetStackPointer(frame); + JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + int retval = PyObject_IsInstance(subject_o, type_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(type); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (retval < 0) { + JUMP_TO_LABEL(error); + } + assert(!_PyErr_Occurred(tstate)); + res = retval ? PyStackRef_True : PyStackRef_False; + stack_pointer[0] = res; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + DISPATCH(); + } + TARGET(MATCH_KEYS) { #if _Py_TAIL_CALL_INTERP int opcode = MATCH_KEYS; diff --git a/Modules/_testinternalcapi/test_targets.h b/Modules/_testinternalcapi/test_targets.h index 48fe9c14f4e2dd..b222b72acf845c 100644 --- a/Modules/_testinternalcapi/test_targets.h +++ b/Modules/_testinternalcapi/test_targets.h @@ -22,6 +22,7 @@ static void *opcode_targets_table[256] = { &&TARGET_LOAD_BUILD_CLASS, &&TARGET_LOAD_LOCALS, &&TARGET_MAKE_FUNCTION, + &&TARGET_MATCH_CLASS_ISINSTANCE, &&TARGET_MATCH_KEYS, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, @@ -99,6 +100,7 @@ static void *opcode_targets_table[256] = { &&TARGET_MAKE_CELL, &&TARGET_MAP_ADD, &&TARGET_MATCH_CLASS, + &&TARGET_MATCH_CLASS_GET_OPT_ATTR, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_NONE, &&TARGET_POP_JUMP_IF_NOT_NONE, @@ -126,8 +128,6 @@ static void *opcode_targets_table[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_RESUME, &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_ADD_INT, @@ -379,8 +379,8 @@ static void *opcode_tracing_targets_table[256] = { &&TARGET_TRACE_RECORD, &&TARGET_TRACE_RECORD, &&TARGET_TRACE_RECORD, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, @@ -698,6 +698,8 @@ static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MAKE_CELL(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MAKE_FUNCTION(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MAP_ADD(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_CLASS(TAIL_CALL_PARAMS); +static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_CLASS_GET_OPT_ATTR(TAIL_CALL_PARAMS); +static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_CLASS_ISINSTANCE(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_KEYS(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_MAPPING(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_SEQUENCE(TAIL_CALL_PARAMS); @@ -939,6 +941,8 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [MAKE_FUNCTION] = _TAIL_CALL_MAKE_FUNCTION, [MAP_ADD] = _TAIL_CALL_MAP_ADD, [MATCH_CLASS] = _TAIL_CALL_MATCH_CLASS, + [MATCH_CLASS_GET_OPT_ATTR] = _TAIL_CALL_MATCH_CLASS_GET_OPT_ATTR, + [MATCH_CLASS_ISINSTANCE] = _TAIL_CALL_MATCH_CLASS_ISINSTANCE, [MATCH_KEYS] = _TAIL_CALL_MATCH_KEYS, [MATCH_MAPPING] = _TAIL_CALL_MATCH_MAPPING, [MATCH_SEQUENCE] = _TAIL_CALL_MATCH_SEQUENCE, @@ -1000,8 +1004,6 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE, [WITH_EXCEPT_START] = _TAIL_CALL_WITH_EXCEPT_START, [YIELD_VALUE] = _TAIL_CALL_YIELD_VALUE, - [120] = _TAIL_CALL_UNKNOWN_OPCODE, - [121] = _TAIL_CALL_UNKNOWN_OPCODE, [122] = _TAIL_CALL_UNKNOWN_OPCODE, [123] = _TAIL_CALL_UNKNOWN_OPCODE, [124] = _TAIL_CALL_UNKNOWN_OPCODE, @@ -1197,6 +1199,8 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { [MAKE_FUNCTION] = _TAIL_CALL_TRACE_RECORD, [MAP_ADD] = _TAIL_CALL_TRACE_RECORD, [MATCH_CLASS] = _TAIL_CALL_TRACE_RECORD, + [MATCH_CLASS_GET_OPT_ATTR] = _TAIL_CALL_TRACE_RECORD, + [MATCH_CLASS_ISINSTANCE] = _TAIL_CALL_TRACE_RECORD, [MATCH_KEYS] = _TAIL_CALL_TRACE_RECORD, [MATCH_MAPPING] = _TAIL_CALL_TRACE_RECORD, [MATCH_SEQUENCE] = _TAIL_CALL_TRACE_RECORD, @@ -1258,8 +1262,6 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { [UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_TRACE_RECORD, [WITH_EXCEPT_START] = _TAIL_CALL_TRACE_RECORD, [YIELD_VALUE] = _TAIL_CALL_TRACE_RECORD, - [120] = _TAIL_CALL_UNKNOWN_OPCODE, - [121] = _TAIL_CALL_UNKNOWN_OPCODE, [122] = _TAIL_CALL_UNKNOWN_OPCODE, [123] = _TAIL_CALL_UNKNOWN_OPCODE, [124] = _TAIL_CALL_UNKNOWN_OPCODE, diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index d550740b1105dd..dcb7ab8cc27546 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,19 +1,19 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { 227,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0, - 0,0,0,0,0,243,186,0,0,0,128,0,0,0,93,0, - 81,1,72,0,115,0,93,0,81,1,72,4,115,1,92,2, - 31,0,81,2,50,1,0,0,0,0,0,0,29,0,92,2, - 31,0,81,3,92,0,79,6,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,50,2,0,0,0,0, - 0,0,29,0,92,1,79,8,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,31,0,50,0,0,0, - 0,0,0,0,81,4,42,26,0,0,0,0,0,0,0,0, - 0,0,115,5,81,7,70,0,68,24,0,0,115,6,92,2, - 31,0,81,5,92,6,12,0,81,6,92,5,92,6,42,26, - 0,0,0,0,0,0,0,0,0,0,12,0,48,4,50,1, - 0,0,0,0,0,0,29,0,74,26,0,0,9,0,28,0, - 81,1,33,0,41,8,233,0,0,0,0,78,122,18,70,114, + 0,0,0,0,0,243,186,0,0,0,128,0,0,0,94,0, + 82,1,73,0,117,0,94,0,82,1,73,4,117,1,93,2, + 32,0,82,2,51,1,0,0,0,0,0,0,30,0,93,2, + 32,0,82,3,93,0,80,6,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,51,2,0,0,0,0, + 0,0,30,0,93,1,80,8,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,32,0,51,0,0,0, + 0,0,0,0,82,4,43,26,0,0,0,0,0,0,0,0, + 0,0,117,5,82,7,71,0,69,24,0,0,117,6,93,2, + 32,0,82,5,93,6,12,0,82,6,93,5,93,6,43,26, + 0,0,0,0,0,0,0,0,0,0,12,0,49,4,51,1, + 0,0,0,0,0,0,30,0,75,26,0,0,9,0,29,0, + 82,1,34,0,41,8,233,0,0,0,0,78,122,18,70,114, 111,122,101,110,32,72,101,108,108,111,32,87,111,114,108,100, 122,8,115,121,115,46,97,114,103,118,218,6,99,111,110,102, 105,103,122,7,99,111,110,102,105,103,32,122,2,58,32,41, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index a2c2eb55db9b3b..33de43be321924 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3337,6 +3337,39 @@ dummy_func( len = PyStackRef_FromPyObjectSteal(len_o); } + inst(MATCH_CLASS_ISINSTANCE, (subject, type -- subject, res)) { + PyObject *subject_o = PyStackRef_AsPyObjectBorrow(subject); + PyObject *type_o = PyStackRef_AsPyObjectBorrow(type); + if (!PyType_Check(type_o)) { + const char *e = "called match pattern must be a class"; + _PyErr_Format(tstate, PyExc_TypeError, e); + PyStackRef_CLOSE(type); + ERROR_IF(true); + } + int retval = PyObject_IsInstance(subject_o, type_o); + PyStackRef_CLOSE(type); + ERROR_IF(retval < 0); + assert(!_PyErr_Occurred(tstate)); + res = retval ? PyStackRef_True : PyStackRef_False; + } + + inst(MATCH_CLASS_GET_OPT_ATTR, (subject -- subject, attr, res)) { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + assert(PyUnicode_CheckExact(name)); + PyObject *subject_o = PyStackRef_AsPyObjectBorrow(subject); + PyObject *attr_o; + (void)PyObject_GetOptionalAttr(subject_o, name, &attr_o); + if (attr_o) { + assert(!_PyErr_Occurred(tstate)); // Success! + attr = PyStackRef_FromPyObjectSteal(attr_o); + res = PyStackRef_True; + } else { + ERROR_IF(_PyErr_Occurred(tstate)); // Error! + attr = PyStackRef_FromPyObjectSteal(Py_None); // No attribute found! + res = PyStackRef_False; + } + } + op(_MATCH_CLASS, (subject, type, names -- attrs, s, tp, n)) { // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. diff --git a/Python/ceval.c b/Python/ceval.c index cb25012ceda92c..f31a566f14d37c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -539,6 +539,7 @@ PyObject* _PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type, Py_ssize_t nargs, PyObject *kwargs) { + assert(nargs > 0); if (!PyType_Check(type)) { const char *e = "class pattern must refer to a class"; _PyErr_Format(tstate, PyExc_TypeError, e); diff --git a/Python/codegen.c b/Python/codegen.c index d300d77e0f73b0..01934b81a60b39 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -6076,6 +6076,64 @@ validate_kwd_attrs(compiler *c, asdl_identifier_seq *attrs, asdl_pattern_seq* pa return SUCCESS; } +static int +codegen_addop_name_match_class_attr(compiler *c, location loc, int opcode, + PyObject *name) +{ + // No name mangling for match attributes + Py_ssize_t arg = _PyCompile_DictAddObj(METADATA(c)->u_names, name); + if (arg < 0) { + return ERROR; + } + ADDOP_I(c, loc, opcode, arg); + return SUCCESS; +} + +static int +codegen_pattern_class_fast(compiler *c, pattern_ty p, pattern_context *pc) +{ + NEW_JUMP_TARGET_LABEL(c, end); + assert(p->kind == MatchClass_kind); + assert(!asdl_seq_LEN(p->v.MatchClass.patterns)); + asdl_identifier_seq *kwd_attrs = p->v.MatchClass.kwd_attrs; + asdl_pattern_seq *kwd_patterns = p->v.MatchClass.kwd_patterns; + Py_ssize_t nattrs = asdl_seq_LEN(kwd_attrs); + VISIT(c, expr, p->v.MatchClass.cls); + ADDOP(c, LOC(p), MATCH_CLASS_ISINSTANCE); + // TOS is now subject: + pc->on_top++; + RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); + if (!nattrs) { + ADDOP_JUMP(c, NO_LOCATION, JUMP, end); + } + + Py_ssize_t i; + identifier name; + pattern_ty pattern; + for (i = 0; i < nattrs; i++) { + name = asdl_seq_GET(kwd_attrs, i); + RETURN_IF_ERROR(codegen_addop_name_match_class_attr(c, LOC(p), + MATCH_CLASS_GET_OPT_ATTR, name)); + // TOS is now attribute: + pc->on_top++; + RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); + pc->on_top--; + + pattern = asdl_seq_GET(kwd_patterns, i); + if (WILDCARD_CHECK(pattern)) { + ADDOP(c, LOC(p), POP_TOP); + continue; + } + RETURN_IF_ERROR(codegen_pattern_subpattern(c, pattern, pc)); + } + + USE_LABEL(c, end); + pc->on_top--; + // Success! POP subject: + ADDOP(c, LOC(p), POP_TOP); + return SUCCESS; +} + static int codegen_pattern_class(compiler *c, pattern_ty p, pattern_context *pc) { @@ -6099,6 +6157,10 @@ codegen_pattern_class(compiler *c, pattern_ty p, pattern_context *pc) if (nattrs) { RETURN_IF_ERROR(validate_kwd_attrs(c, kwd_attrs, kwd_patterns)); } + if (!nargs) { + // Fast path if there are no positional sub-patterns + return codegen_pattern_class_fast(c, p, pc); + } VISIT(c, expr, p->v.MatchClass.cls); PyObject *attr_names = PyTuple_New(nattrs); if (attr_names == NULL) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 9de6e2850d773b..eaff05bc3b1b04 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -11446,6 +11446,104 @@ break; } + case _MATCH_CLASS_ISINSTANCE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef type; + _PyStackRef subject; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + type = _stack_item_1; + subject = _stack_item_0; + PyObject *subject_o = PyStackRef_AsPyObjectBorrow(subject); + PyObject *type_o = PyStackRef_AsPyObjectBorrow(type); + if (!PyType_Check(type_o)) { + const char *e = "called match pattern must be a class"; + stack_pointer[0] = subject; + stack_pointer[1] = type; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyErr_Format(tstate, PyExc_TypeError, e); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(type); + stack_pointer = _PyFrame_GetStackPointer(frame); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + stack_pointer[0] = subject; + stack_pointer[1] = type; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + int retval = PyObject_IsInstance(subject_o, type_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(type); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (retval < 0) { + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + assert(!_PyErr_Occurred(tstate)); + res = retval ? PyStackRef_True : PyStackRef_False; + _tos_cache1 = res; + _tos_cache0 = subject; + _tos_cache2 = PyStackRef_ZERO_BITS; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _MATCH_CLASS_GET_OPT_ATTR_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef subject; + _PyStackRef attr; + _PyStackRef res; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + subject = _stack_item_0; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + assert(PyUnicode_CheckExact(name)); + PyObject *subject_o = PyStackRef_AsPyObjectBorrow(subject); + PyObject *attr_o; + stack_pointer[0] = subject; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + (void)PyObject_GetOptionalAttr(subject_o, name, &attr_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (attr_o) { + assert(!_PyErr_Occurred(tstate)); + attr = PyStackRef_FromPyObjectSteal(attr_o); + res = PyStackRef_True; + } else { + if (_PyErr_Occurred(tstate)) { + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + attr = PyStackRef_FromPyObjectSteal(Py_None); + res = PyStackRef_False; + } + _tos_cache2 = res; + _tos_cache1 = attr; + _tos_cache0 = subject; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + case _MATCH_CLASS_r33: { CHECK_CURRENT_CACHED_VALUES(3); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e01b9292a5800b..b6782d68ba146b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -10019,6 +10019,89 @@ DISPATCH(); } + TARGET(MATCH_CLASS_GET_OPT_ATTR) { + #if _Py_TAIL_CALL_INTERP + int opcode = MATCH_CLASS_GET_OPT_ATTR; + (void)(opcode); + #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(MATCH_CLASS_GET_OPT_ATTR); + _PyStackRef subject; + _PyStackRef attr; + _PyStackRef res; + subject = stack_pointer[-1]; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + assert(PyUnicode_CheckExact(name)); + PyObject *subject_o = PyStackRef_AsPyObjectBorrow(subject); + PyObject *attr_o; + _PyFrame_SetStackPointer(frame, stack_pointer); + (void)PyObject_GetOptionalAttr(subject_o, name, &attr_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (attr_o) { + assert(!_PyErr_Occurred(tstate)); + attr = PyStackRef_FromPyObjectSteal(attr_o); + res = PyStackRef_True; + } else { + if (_PyErr_Occurred(tstate)) { + JUMP_TO_LABEL(error); + } + attr = PyStackRef_FromPyObjectSteal(Py_None); + res = PyStackRef_False; + } + stack_pointer[0] = attr; + stack_pointer[1] = res; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + DISPATCH(); + } + + TARGET(MATCH_CLASS_ISINSTANCE) { + #if _Py_TAIL_CALL_INTERP + int opcode = MATCH_CLASS_ISINSTANCE; + (void)(opcode); + #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(MATCH_CLASS_ISINSTANCE); + _PyStackRef subject; + _PyStackRef type; + _PyStackRef res; + type = stack_pointer[-1]; + subject = stack_pointer[-2]; + PyObject *subject_o = PyStackRef_AsPyObjectBorrow(subject); + PyObject *type_o = PyStackRef_AsPyObjectBorrow(type); + if (!PyType_Check(type_o)) { + const char *e = "called match pattern must be a class"; + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyErr_Format(tstate, PyExc_TypeError, e); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(type); + stack_pointer = _PyFrame_GetStackPointer(frame); + JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + int retval = PyObject_IsInstance(subject_o, type_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(type); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (retval < 0) { + JUMP_TO_LABEL(error); + } + assert(!_PyErr_Occurred(tstate)); + res = retval ? PyStackRef_True : PyStackRef_False; + stack_pointer[0] = res; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + DISPATCH(); + } + TARGET(MATCH_KEYS) { #if _Py_TAIL_CALL_INTERP int opcode = MATCH_KEYS; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 48fe9c14f4e2dd..b222b72acf845c 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -22,6 +22,7 @@ static void *opcode_targets_table[256] = { &&TARGET_LOAD_BUILD_CLASS, &&TARGET_LOAD_LOCALS, &&TARGET_MAKE_FUNCTION, + &&TARGET_MATCH_CLASS_ISINSTANCE, &&TARGET_MATCH_KEYS, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, @@ -99,6 +100,7 @@ static void *opcode_targets_table[256] = { &&TARGET_MAKE_CELL, &&TARGET_MAP_ADD, &&TARGET_MATCH_CLASS, + &&TARGET_MATCH_CLASS_GET_OPT_ATTR, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_NONE, &&TARGET_POP_JUMP_IF_NOT_NONE, @@ -126,8 +128,6 @@ static void *opcode_targets_table[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_RESUME, &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_ADD_INT, @@ -379,8 +379,8 @@ static void *opcode_tracing_targets_table[256] = { &&TARGET_TRACE_RECORD, &&TARGET_TRACE_RECORD, &&TARGET_TRACE_RECORD, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_TRACE_RECORD, + &&TARGET_TRACE_RECORD, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, @@ -698,6 +698,8 @@ static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MAKE_CELL(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MAKE_FUNCTION(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MAP_ADD(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_CLASS(TAIL_CALL_PARAMS); +static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_CLASS_GET_OPT_ATTR(TAIL_CALL_PARAMS); +static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_CLASS_ISINSTANCE(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_KEYS(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_MAPPING(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_MATCH_SEQUENCE(TAIL_CALL_PARAMS); @@ -939,6 +941,8 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [MAKE_FUNCTION] = _TAIL_CALL_MAKE_FUNCTION, [MAP_ADD] = _TAIL_CALL_MAP_ADD, [MATCH_CLASS] = _TAIL_CALL_MATCH_CLASS, + [MATCH_CLASS_GET_OPT_ATTR] = _TAIL_CALL_MATCH_CLASS_GET_OPT_ATTR, + [MATCH_CLASS_ISINSTANCE] = _TAIL_CALL_MATCH_CLASS_ISINSTANCE, [MATCH_KEYS] = _TAIL_CALL_MATCH_KEYS, [MATCH_MAPPING] = _TAIL_CALL_MATCH_MAPPING, [MATCH_SEQUENCE] = _TAIL_CALL_MATCH_SEQUENCE, @@ -1000,8 +1004,6 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE, [WITH_EXCEPT_START] = _TAIL_CALL_WITH_EXCEPT_START, [YIELD_VALUE] = _TAIL_CALL_YIELD_VALUE, - [120] = _TAIL_CALL_UNKNOWN_OPCODE, - [121] = _TAIL_CALL_UNKNOWN_OPCODE, [122] = _TAIL_CALL_UNKNOWN_OPCODE, [123] = _TAIL_CALL_UNKNOWN_OPCODE, [124] = _TAIL_CALL_UNKNOWN_OPCODE, @@ -1197,6 +1199,8 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { [MAKE_FUNCTION] = _TAIL_CALL_TRACE_RECORD, [MAP_ADD] = _TAIL_CALL_TRACE_RECORD, [MATCH_CLASS] = _TAIL_CALL_TRACE_RECORD, + [MATCH_CLASS_GET_OPT_ATTR] = _TAIL_CALL_TRACE_RECORD, + [MATCH_CLASS_ISINSTANCE] = _TAIL_CALL_TRACE_RECORD, [MATCH_KEYS] = _TAIL_CALL_TRACE_RECORD, [MATCH_MAPPING] = _TAIL_CALL_TRACE_RECORD, [MATCH_SEQUENCE] = _TAIL_CALL_TRACE_RECORD, @@ -1258,8 +1262,6 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { [UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_TRACE_RECORD, [WITH_EXCEPT_START] = _TAIL_CALL_TRACE_RECORD, [YIELD_VALUE] = _TAIL_CALL_TRACE_RECORD, - [120] = _TAIL_CALL_UNKNOWN_OPCODE, - [121] = _TAIL_CALL_UNKNOWN_OPCODE, [122] = _TAIL_CALL_UNKNOWN_OPCODE, [123] = _TAIL_CALL_UNKNOWN_OPCODE, [124] = _TAIL_CALL_UNKNOWN_OPCODE, diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 38831e4664247a..c1764452f8c8fa 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2726,6 +2726,26 @@ break; } + case _MATCH_CLASS_ISINSTANCE: { + JitOptRef res; + res = sym_new_not_null(ctx); + stack_pointer[-1] = res; + break; + } + + case _MATCH_CLASS_GET_OPT_ATTR: { + JitOptRef attr; + JitOptRef res; + attr = sym_new_not_null(ctx); + res = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(2); + stack_pointer[0] = attr; + stack_pointer[1] = res; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + break; + } + case _MATCH_CLASS: { JitOptRef names; JitOptRef type;