Python-checkins
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
December 2021
- 1 participants
- 354 discussions
https://github.com/python/cpython/commit/2985feac4e02d590bb78bcce9e30864be5…
commit: 2985feac4e02d590bb78bcce9e30864be53280ac
branch: main
author: Christian Heimes <christian(a)python.org>
committer: tiran <christian(a)python.org>
date: 2021-12-17T16:17:32+01:00
summary:
bpo-46114: Fix OpenSSL version check for 3.0.1 (GH-30170)
files:
A Misc/NEWS.d/next/Tests/2021-12-17-14-46-19.bpo-46114.9iyZ_9.rst
M .github/workflows/build.yml
M Lib/test/test_ssl.py
M Tools/ssl/multissltests.py
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 48671aa7a67cd..4504b29432cd2 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -220,7 +220,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- openssl_ver: [1.1.1l, 3.0.0]
+ openssl_ver: [1.1.1l, 3.0.1]
env:
OPENSSL_VER: ${{ matrix.openssl_ver }}
MULTISSL_DIR: ${{ github.workspace }}/multissl
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 981e2fe82ee46..f99a3e8da95f8 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -540,7 +540,11 @@ def test_openssl_version(self):
self.assertLessEqual(status, 15)
libressl_ver = f"LibreSSL {major:d}"
- openssl_ver = f"OpenSSL {major:d}.{minor:d}.{fix:d}"
+ if major >= 3:
+ # 3.x uses 0xMNN00PP0L
+ openssl_ver = f"OpenSSL {major:d}.{minor:d}.{patch:d}"
+ else:
+ openssl_ver = f"OpenSSL {major:d}.{minor:d}.{fix:d}"
self.assertTrue(
s.startswith((openssl_ver, libressl_ver)),
(s, t, hex(n))
diff --git a/Misc/NEWS.d/next/Tests/2021-12-17-14-46-19.bpo-46114.9iyZ_9.rst b/Misc/NEWS.d/next/Tests/2021-12-17-14-46-19.bpo-46114.9iyZ_9.rst
new file mode 100644
index 0000000000000..6878cea032387
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2021-12-17-14-46-19.bpo-46114.9iyZ_9.rst
@@ -0,0 +1 @@
+Fix test case for OpenSSL 3.0.1 version. OpenSSL 3.0 uses ``0xMNN00PP0L``.
diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py
index ba2663e9a399b..8fe5b5d0c2629 100755
--- a/Tools/ssl/multissltests.py
+++ b/Tools/ssl/multissltests.py
@@ -48,7 +48,7 @@
OPENSSL_RECENT_VERSIONS = [
"1.1.1l",
- "3.0.0"
+ "3.0.1"
]
LIBRESSL_OLD_VERSIONS = [
1
0
https://github.com/python/cpython/commit/efd6236d36b292c2c43540132c87cf8425…
commit: efd6236d36b292c2c43540132c87cf8425e8d627
branch: main
author: Mark Shannon <mark(a)hotpy.org>
committer: markshannon <mark(a)hotpy.org>
date: 2021-12-17T14:48:01Z
summary:
bpo-46072: Add top level stats struct (GH-30169)
files:
M Include/internal/pycore_code.h
M Lib/opcode.py
M Lib/test/test__opcode.py
M Python/ceval.c
M Python/specialize.c
M Tools/scripts/summarize_stats.py
diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h
index e9b1ad406496a..dfc75300315e2 100644
--- a/Include/internal/pycore_code.h
+++ b/Include/internal/pycore_code.h
@@ -281,20 +281,32 @@ void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
#define SPECIALIZATION_FAILURE_KINDS 30
-typedef struct _stats {
- uint64_t specialization_success;
- uint64_t specialization_failure;
+typedef struct _specialization_stats {
+ uint64_t success;
+ uint64_t failure;
uint64_t hit;
uint64_t deferred;
uint64_t miss;
uint64_t deopt;
- uint64_t unquickened;
- uint64_t specialization_failure_kinds[SPECIALIZATION_FAILURE_KINDS];
+ uint64_t failure_kinds[SPECIALIZATION_FAILURE_KINDS];
} SpecializationStats;
-extern SpecializationStats _specialization_stats[256];
-#define STAT_INC(opname, name) _specialization_stats[opname].name++
-#define STAT_DEC(opname, name) _specialization_stats[opname].name--
+typedef struct _opcode_stats {
+ SpecializationStats specialization;
+ uint64_t execution_count;
+ uint64_t pair_count[256];
+} OpcodeStats;
+
+typedef struct _stats {
+ OpcodeStats opcode_stats[256];
+} PyStats;
+
+extern PyStats _py_stats;
+
+#define STAT_INC(opname, name) _py_stats.opcode_stats[opname].specialization.name++
+#define STAT_DEC(opname, name) _py_stats.opcode_stats[opname].specialization.name--
+#define OPCODE_EXE_INC(opname) _py_stats.opcode_stats[opname].execution_count++
+
void _Py_PrintSpecializationStats(int to_file);
PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void);
@@ -302,6 +314,7 @@ PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void);
#else
#define STAT_INC(opname, name) ((void)0)
#define STAT_DEC(opname, name) ((void)0)
+#define OPCODE_EXE_INC(opname) ((void)0)
#endif
diff --git a/Lib/opcode.py b/Lib/opcode.py
index 7b69988f91315..e654a1088b7ea 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -288,11 +288,10 @@ def jabs_op(name, op):
"STORE_FAST__STORE_FAST",
]
_specialization_stats = [
- "specialization_success",
- "specialization_failure",
+ "success",
+ "failure",
"hit",
"deferred",
"miss",
"deopt",
- "unquickened",
]
diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py
index 6bbab539903ce..f6b6b3d3532bd 100644
--- a/Lib/test/test__opcode.py
+++ b/Lib/test/test__opcode.py
@@ -82,13 +82,13 @@ def test_specialization_stats(self):
self.assertCountEqual(stats.keys(), specialized_opcodes)
self.assertCountEqual(
stats['load_attr'].keys(),
- stat_names + ['specialization_failure_kinds'])
+ stat_names + ['failure_kinds'])
for sn in stat_names:
self.assertIsInstance(stats['load_attr'][sn], int)
self.assertIsInstance(
- stats['load_attr']['specialization_failure_kinds'],
+ stats['load_attr']['failure_kinds'],
tuple)
- for v in stats['load_attr']['specialization_failure_kinds']:
+ for v in stats['load_attr']['failure_kinds']:
self.assertIsInstance(v, int)
diff --git a/Python/ceval.c b/Python/ceval.c
index bac57ccb7cc75..9976bdeffbe96 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1290,13 +1290,17 @@ eval_frame_handle_pending(PyThreadState *tstate)
#define USE_COMPUTED_GOTOS 0
#endif
-#define INSTRUCTION_START() frame->f_lasti = INSTR_OFFSET(); next_instr++
+#ifdef Py_STATS
+#define INSTRUCTION_START(op) frame->f_lasti = INSTR_OFFSET(); next_instr++; OPCODE_EXE_INC(op);
+#else
+#define INSTRUCTION_START(op) frame->f_lasti = INSTR_OFFSET(); next_instr++
+#endif
#if USE_COMPUTED_GOTOS
-#define TARGET(op) TARGET_##op: INSTRUCTION_START();
+#define TARGET(op) TARGET_##op: INSTRUCTION_START(op);
#define DISPATCH_GOTO() goto *opcode_targets[opcode]
#else
-#define TARGET(op) case op: INSTRUCTION_START();
+#define TARGET(op) case op: INSTRUCTION_START(op);
#define DISPATCH_GOTO() goto dispatch_opcode
#endif
@@ -1416,7 +1420,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
opcode = _Py_OPCODE(word) | cframe.use_tracing OR_DTRACE_LINE; \
if (opcode == op) { \
oparg = _Py_OPARG(word); \
- INSTRUCTION_START(); \
+ INSTRUCTION_START(op); \
goto PREDICT_ID(op); \
} \
} while(0)
@@ -2186,7 +2190,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(BINARY_SUBSCR) {
PREDICTED(BINARY_SUBSCR);
- STAT_INC(BINARY_SUBSCR, unquickened);
PyObject *sub = POP();
PyObject *container = TOP();
PyObject *res = PyObject_GetItem(container, sub);
@@ -2214,7 +2217,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
cache->adaptive.counter--;
assert(cache->adaptive.original_oparg == 0);
/* No need to set oparg here; it isn't used by BINARY_SUBSCR */
- STAT_DEC(BINARY_SUBSCR, unquickened);
JUMP_TO_INSTRUCTION(BINARY_SUBSCR);
}
}
@@ -2339,7 +2341,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(STORE_SUBSCR) {
PREDICTED(STORE_SUBSCR);
- STAT_INC(STORE_SUBSCR, unquickened);
PyObject *sub = TOP();
PyObject *container = SECOND();
PyObject *v = THIRD();
@@ -2369,7 +2370,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
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);
}
}
@@ -2933,7 +2933,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(STORE_ATTR) {
PREDICTED(STORE_ATTR);
- STAT_INC(STORE_ATTR, unquickened);
PyObject *name = GETITEM(names, oparg);
PyObject *owner = TOP();
PyObject *v = SECOND();
@@ -3049,7 +3048,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(LOAD_GLOBAL) {
PREDICTED(LOAD_GLOBAL);
- STAT_INC(LOAD_GLOBAL, unquickened);
PyObject *name = GETITEM(names, oparg);
PyObject *v;
if (PyDict_CheckExact(GLOBALS())
@@ -3112,7 +3110,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
STAT_INC(LOAD_GLOBAL, deferred);
cache->adaptive.counter--;
oparg = cache->adaptive.original_oparg;
- STAT_DEC(LOAD_GLOBAL, unquickened);
JUMP_TO_INSTRUCTION(LOAD_GLOBAL);
}
}
@@ -3532,7 +3529,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(LOAD_ATTR) {
PREDICTED(LOAD_ATTR);
- STAT_INC(LOAD_ATTR, unquickened);
PyObject *name = GETITEM(names, oparg);
PyObject *owner = TOP();
PyObject *res = PyObject_GetAttr(owner, name);
@@ -3560,7 +3556,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
STAT_INC(LOAD_ATTR, deferred);
cache->adaptive.counter--;
oparg = cache->adaptive.original_oparg;
- STAT_DEC(LOAD_ATTR, unquickened);
JUMP_TO_INSTRUCTION(LOAD_ATTR);
}
}
@@ -3663,7 +3658,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
STAT_INC(STORE_ATTR, deferred);
cache->adaptive.counter--;
oparg = cache->adaptive.original_oparg;
- STAT_DEC(STORE_ATTR, unquickened);
JUMP_TO_INSTRUCTION(STORE_ATTR);
}
}
@@ -3754,7 +3748,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(COMPARE_OP) {
PREDICTED(COMPARE_OP);
- STAT_INC(COMPARE_OP, unquickened);
assert(oparg <= Py_GE);
PyObject *right = POP();
PyObject *left = TOP();
@@ -3783,7 +3776,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
STAT_INC(COMPARE_OP, deferred);
cache->adaptive.counter--;
oparg = cache->adaptive.original_oparg;
- STAT_DEC(COMPARE_OP, unquickened);
JUMP_TO_INSTRUCTION(COMPARE_OP);
}
}
@@ -4438,7 +4430,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(LOAD_METHOD) {
PREDICTED(LOAD_METHOD);
- STAT_INC(LOAD_METHOD, unquickened);
/* Designed to work in tandem with CALL_METHOD. */
PyObject *name = GETITEM(names, oparg);
PyObject *obj = TOP();
@@ -4491,7 +4482,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
STAT_INC(LOAD_METHOD, deferred);
cache->adaptive.counter--;
oparg = cache->adaptive.original_oparg;
- STAT_DEC(LOAD_METHOD, unquickened);
JUMP_TO_INSTRUCTION(LOAD_METHOD);
}
}
@@ -4617,7 +4607,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_NO_KW) {
PyObject *function;
PREDICTED(CALL_NO_KW);
- STAT_INC(CALL_NO_KW, unquickened);
kwnames = NULL;
oparg += extra_args;
nargs = oparg;
@@ -5186,7 +5175,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(BINARY_OP) {
PREDICTED(BINARY_OP);
- STAT_INC(BINARY_OP, unquickened);
PyObject *rhs = POP();
PyObject *lhs = TOP();
assert(0 <= oparg);
@@ -5216,7 +5204,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
STAT_INC(BINARY_OP, deferred);
cache->adaptive.counter--;
oparg = cache->adaptive.original_oparg;
- STAT_DEC(BINARY_OP, unquickened);
JUMP_TO_INSTRUCTION(BINARY_OP);
}
}
@@ -5301,7 +5288,6 @@ opname ## _miss: \
cache_backoff(cache); \
} \
oparg = cache->original_oparg; \
- STAT_DEC(opname, unquickened); \
JUMP_TO_INSTRUCTION(opname); \
}
@@ -5317,7 +5303,6 @@ opname ## _miss: \
next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, oparg); \
STAT_INC(opname, deopt); \
} \
- STAT_DEC(opname, unquickened); \
JUMP_TO_INSTRUCTION(opname); \
}
diff --git a/Python/specialize.c b/Python/specialize.c
index 1f168e31e6d3a..8991fa94f8e36 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -40,7 +40,7 @@
Py_ssize_t _Py_QuickenedCount = 0;
#ifdef Py_STATS
-SpecializationStats _specialization_stats[256] = { 0 };
+PyStats _py_stats = { 0 };
#define ADD_STAT_TO_DICT(res, field) \
do { \
@@ -64,20 +64,19 @@ stats_to_dict(SpecializationStats *stats)
if (res == NULL) {
return NULL;
}
- ADD_STAT_TO_DICT(res, specialization_success);
- ADD_STAT_TO_DICT(res, specialization_failure);
+ ADD_STAT_TO_DICT(res, success);
+ ADD_STAT_TO_DICT(res, failure);
ADD_STAT_TO_DICT(res, hit);
ADD_STAT_TO_DICT(res, deferred);
ADD_STAT_TO_DICT(res, miss);
ADD_STAT_TO_DICT(res, deopt);
- ADD_STAT_TO_DICT(res, unquickened);
PyObject *failure_kinds = PyTuple_New(SPECIALIZATION_FAILURE_KINDS);
if (failure_kinds == NULL) {
Py_DECREF(res);
return NULL;
}
for (int i = 0; i < SPECIALIZATION_FAILURE_KINDS; i++) {
- PyObject *stat = PyLong_FromUnsignedLongLong(stats->specialization_failure_kinds[i]);
+ PyObject *stat = PyLong_FromUnsignedLongLong(stats->failure_kinds[i]);
if (stat == NULL) {
Py_DECREF(res);
Py_DECREF(failure_kinds);
@@ -85,7 +84,7 @@ stats_to_dict(SpecializationStats *stats)
}
PyTuple_SET_ITEM(failure_kinds, i, stat);
}
- if (PyDict_SetItemString(res, "specialization_failure_kinds", failure_kinds)) {
+ if (PyDict_SetItemString(res, "failure_kinds", failure_kinds)) {
Py_DECREF(res);
Py_DECREF(failure_kinds);
return NULL;
@@ -101,7 +100,7 @@ add_stat_dict(
int opcode,
const char *name) {
- SpecializationStats *stats = &_specialization_stats[opcode];
+ SpecializationStats *stats = &_py_stats.opcode_stats[opcode].specialization;
PyObject *d = stats_to_dict(stats);
if (d == NULL) {
return -1;
@@ -137,25 +136,38 @@ _Py_GetSpecializationStats(void) {
#endif
-#define PRINT_STAT(name, field) fprintf(out, " %s." #field " : %" PRIu64 "\n", name, stats->field);
+#define PRINT_STAT(i, field) \
+ if (stats[i].field) { \
+ fprintf(out, " opcode[%d]." #field " : %" PRIu64 "\n", i, stats[i].field); \
+ }
static void
-print_stats(FILE *out, SpecializationStats *stats, const char *name)
+print_spec_stats(FILE *out, OpcodeStats *stats)
{
- PRINT_STAT(name, specialization_success);
- PRINT_STAT(name, specialization_failure);
- PRINT_STAT(name, hit);
- PRINT_STAT(name, deferred);
- PRINT_STAT(name, miss);
- PRINT_STAT(name, deopt);
- PRINT_STAT(name, unquickened);
- for (int i = 0; i < SPECIALIZATION_FAILURE_KINDS; i++) {
- fprintf(out, " %s.specialization_failure_kinds[%d] : %" PRIu64 "\n",
- name, i, stats->specialization_failure_kinds[i]);
+ for (int i = 0; i < 256; i++) {
+ PRINT_STAT(i, specialization.success);
+ PRINT_STAT(i, specialization.failure);
+ PRINT_STAT(i, specialization.hit);
+ PRINT_STAT(i, specialization.deferred);
+ PRINT_STAT(i, specialization.miss);
+ PRINT_STAT(i, specialization.deopt);
+ PRINT_STAT(i, execution_count);
+ for (int j = 0; j < SPECIALIZATION_FAILURE_KINDS; j++) {
+ uint64_t val = stats[i].specialization.failure_kinds[j];
+ if (val) {
+ fprintf(out, " opcode[%d].specialization.failure_kinds[%d] : %"
+ PRIu64 "\n", i, j, val);
+ }
+ }
}
}
#undef PRINT_STAT
+static void
+print_stats(FILE *out, PyStats *stats) {
+ print_spec_stats(out, stats->opcode_stats);
+}
+
void
_Py_PrintSpecializationStats(int to_file)
{
@@ -189,15 +201,7 @@ _Py_PrintSpecializationStats(int to_file)
else {
fprintf(out, "Specialization stats:\n");
}
- print_stats(out, &_specialization_stats[LOAD_ATTR], "load_attr");
- print_stats(out, &_specialization_stats[LOAD_GLOBAL], "load_global");
- print_stats(out, &_specialization_stats[LOAD_METHOD], "load_method");
- 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[CALL_NO_KW], "call_no_kw");
- print_stats(out, &_specialization_stats[BINARY_OP], "binary_op");
- print_stats(out, &_specialization_stats[COMPARE_OP], "compare_op");
+ print_stats(out, &_py_stats);
if (out != stderr) {
fclose(out);
}
@@ -205,7 +209,7 @@ _Py_PrintSpecializationStats(int to_file)
#ifdef Py_STATS
-#define SPECIALIZATION_FAIL(opcode, kind) _specialization_stats[opcode].specialization_failure_kinds[kind]++
+#define SPECIALIZATION_FAIL(opcode, kind) _py_stats.opcode_stats[opcode].specialization.failure_kinds[kind]++
#endif
@@ -775,12 +779,12 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
goto success;
}
fail:
- STAT_INC(LOAD_ATTR, specialization_failure);
+ STAT_INC(LOAD_ATTR, failure);
assert(!PyErr_Occurred());
cache_backoff(cache0);
return 0;
success:
- STAT_INC(LOAD_ATTR, specialization_success);
+ STAT_INC(LOAD_ATTR, success);
assert(!PyErr_Occurred());
cache0->counter = initial_counter_value();
return 0;
@@ -857,12 +861,12 @@ _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, S
goto success;
}
fail:
- STAT_INC(STORE_ATTR, specialization_failure);
+ STAT_INC(STORE_ATTR, failure);
assert(!PyErr_Occurred());
cache_backoff(cache0);
return 0;
success:
- STAT_INC(STORE_ATTR, specialization_success);
+ STAT_INC(STORE_ATTR, success);
assert(!PyErr_Occurred());
cache0->counter = initial_counter_value();
return 0;
@@ -1013,12 +1017,12 @@ _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name,
cache2->obj = descr;
// Fall through.
success:
- STAT_INC(LOAD_METHOD, specialization_success);
+ STAT_INC(LOAD_METHOD, success);
assert(!PyErr_Occurred());
cache0->counter = initial_counter_value();
return 0;
fail:
- STAT_INC(LOAD_METHOD, specialization_failure);
+ STAT_INC(LOAD_METHOD, failure);
assert(!PyErr_Occurred());
cache_backoff(cache0);
return 0;
@@ -1084,12 +1088,12 @@ _Py_Specialize_LoadGlobal(
*instr = _Py_MAKECODEUNIT(LOAD_GLOBAL_BUILTIN, _Py_OPARG(*instr));
goto success;
fail:
- STAT_INC(LOAD_GLOBAL, specialization_failure);
+ STAT_INC(LOAD_GLOBAL, failure);
assert(!PyErr_Occurred());
cache_backoff(cache0);
return 0;
success:
- STAT_INC(LOAD_GLOBAL, specialization_success);
+ STAT_INC(LOAD_GLOBAL, success);
assert(!PyErr_Occurred());
cache0->counter = initial_counter_value();
return 0;
@@ -1211,12 +1215,12 @@ _Py_Specialize_BinarySubscr(
SPECIALIZATION_FAIL(BINARY_SUBSCR,
binary_subscr_fail_kind(container_type, sub));
fail:
- STAT_INC(BINARY_SUBSCR, specialization_failure);
+ STAT_INC(BINARY_SUBSCR, failure);
assert(!PyErr_Occurred());
cache_backoff(cache0);
return 0;
success:
- STAT_INC(BINARY_SUBSCR, specialization_success);
+ STAT_INC(BINARY_SUBSCR, success);
assert(!PyErr_Occurred());
cache0->counter = initial_counter_value();
return 0;
@@ -1259,12 +1263,12 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
goto fail;
}
fail:
- STAT_INC(STORE_SUBSCR, specialization_failure);
+ STAT_INC(STORE_SUBSCR, failure);
assert(!PyErr_Occurred());
*instr = _Py_MAKECODEUNIT(_Py_OPCODE(*instr), ADAPTIVE_CACHE_BACKOFF);
return 0;
success:
- STAT_INC(STORE_SUBSCR, specialization_success);
+ STAT_INC(STORE_SUBSCR, success);
assert(!PyErr_Occurred());
return 0;
}
@@ -1518,12 +1522,12 @@ _Py_Specialize_CallNoKw(
}
_PyAdaptiveEntry *cache0 = &cache->adaptive;
if (fail) {
- STAT_INC(CALL_NO_KW, specialization_failure);
+ STAT_INC(CALL_NO_KW, failure);
assert(!PyErr_Occurred());
cache_backoff(cache0);
}
else {
- STAT_INC(CALL_NO_KW, specialization_success);
+ STAT_INC(CALL_NO_KW, success);
assert(!PyErr_Occurred());
cache0->counter = initial_counter_value();
}
@@ -1604,11 +1608,11 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
}
SPECIALIZATION_FAIL(BINARY_OP, SPEC_FAIL_OTHER);
failure:
- STAT_INC(BINARY_OP, specialization_failure);
+ STAT_INC(BINARY_OP, failure);
cache_backoff(adaptive);
return;
success:
- STAT_INC(BINARY_OP, specialization_success);
+ STAT_INC(BINARY_OP, success);
adaptive->counter = initial_counter_value();
}
@@ -1675,10 +1679,10 @@ _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs,
}
SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_OTHER);
failure:
- STAT_INC(COMPARE_OP, specialization_failure);
+ STAT_INC(COMPARE_OP, failure);
cache_backoff(adaptive);
return;
success:
- STAT_INC(COMPARE_OP, specialization_success);
+ STAT_INC(COMPARE_OP, success);
adaptive->counter = initial_counter_value();
}
diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py
index 15b1887415e44..a5a8e93c17392 100644
--- a/Tools/scripts/summarize_stats.py
+++ b/Tools/scripts/summarize_stats.py
@@ -4,29 +4,50 @@
import collections
import os.path
+import opcode
if os.name == "nt":
DEFAULT_DIR = "c:\\temp\\py_stats\\"
else:
DEFAULT_DIR = "/tmp/py_stats/"
+#Create list of all instruction names
+specialized = iter(opcode._specialized_instructions)
+opname = ["<0>"]
+for name in opcode.opname[1:]:
+ if name.startswith("<"):
+ try:
+ name = next(specialized)
+ except StopIteration:
+ pass
+ opname.append(name)
-TOTAL = "deferred", "hit", "miss", "unquickened"
-def print_stats(name, family_stats):
+TOTAL = "specialization.deferred", "specialization.hit", "specialization.miss", "execution_count"
+
+def print_specialization_stats(name, family_stats):
+ if "specialization.deferred" not in family_stats:
+ return
total = sum(family_stats[kind] for kind in TOTAL)
if total == 0:
return
print(name+":")
for key in sorted(family_stats):
- if not key.startswith("specialization"):
- print(f"{key:>12}:{family_stats[key]:>12} {100*family_stats[key]/total:0.1f}%")
- for key in ("specialization_success", "specialization_failure"):
- print(f" {key}:{family_stats[key]:>12}")
- total_failures = family_stats["specialization_failure"]
+ if key.startswith("specialization.failure_kinds"):
+ continue
+ if key.startswith("specialization."):
+ label = key[len("specialization."):]
+ elif key == "execution_count":
+ label = "unquickened"
+ if key not in ("specialization.success", "specialization.failure"):
+ print(f"{label:>12}:{family_stats[key]:>12} {100*family_stats[key]/total:0.1f}%")
+ for key in ("specialization.success", "specialization.failure"):
+ label = key[len("specialization."):]
+ print(f" {label}:{family_stats.get(key, 0):>12}")
+ total_failures = family_stats["specialization.failure"]
failure_kinds = [ 0 ] * 30
for key in family_stats:
- if not key.startswith("specialization_failure_kind"):
+ if not key.startswith("specialization.failure_kind"):
continue
_, index = key[:-1].split("[")
index = int(index)
@@ -36,18 +57,47 @@ def print_stats(name, family_stats):
continue
print(f" kind {index:>2}: {value:>8} {100*value/total_failures:0.1f}%")
-def main():
- stats = collections.defaultdict(collections.Counter)
+def gather_stats():
+ stats = collections.Counter()
for filename in os.listdir(DEFAULT_DIR):
- for line in open(os.path.join(DEFAULT_DIR, filename)):
- key, value = line.split(":")
- key = key.strip()
- family, stat = key.split(".")
- value = int(value.strip())
- stats[family][stat] += value
-
- for name in sorted(stats):
- print_stats(name, stats[name])
+ with open(os.path.join(DEFAULT_DIR, filename)) as fd:
+ for line in fd:
+ key, value = line.split(":")
+ key = key.strip()
+ value = int(value.strip())
+ stats[key] += value
+ return stats
+
+def extract_opcode_stats(stats):
+ opcode_stats = [ {} for _ in range(256) ]
+ for key, value in stats.items():
+ if not key.startswith("opcode"):
+ continue
+ n, _, rest = key[7:].partition("]")
+ opcode_stats[int(n)][rest.strip(".")] = value
+ return opcode_stats
+
+
+def main():
+ stats = gather_stats()
+ opcode_stats = extract_opcode_stats(stats)
+ print("Execution counts:")
+ counts = []
+ total = 0
+ for i, opcode_stat in enumerate(opcode_stats):
+ if "execution_count" in opcode_stat:
+ count = opcode_stat['execution_count']
+ counts.append((count, opname[i]))
+ total += count
+ counts.sort(reverse=True)
+ cummulative = 0
+ for (count, name) in counts:
+ cummulative += count
+ print(f"{name}: {count} {100*count/total:0.1f}% {100*cummulative/total:0.1f}%")
+ print("Specialization stats:")
+ for i, opcode_stat in enumerate(opcode_stats):
+ name = opname[i]
+ print_specialization_stats(name, opcode_stat)
if __name__ == "__main__":
main()
1
0
Dec. 17, 2021
https://github.com/python/cpython/commit/396b58345f81d4c8c5a52546d2288e666a…
commit: 396b58345f81d4c8c5a52546d2288e666a1b9b8b
branch: main
author: Irit Katriel <1055913+iritkatriel(a)users.noreply.github.com>
committer: markshannon <mark(a)hotpy.org>
date: 2021-12-17T14:46:22Z
summary:
bpo-45711: Remove type and traceback from exc_info (GH-30122)
* Do not PUSH/POP traceback or type to the stack as part of exc_info
* Remove exc_traceback and exc_type from _PyErr_StackItem
* Add to what's new, because this change breaks things like Cython
files:
A Misc/NEWS.d/next/Core and Builtins/2021-12-15-15-17-04.bpo-45711.QK4QrB.rst
M Doc/library/dis.rst
M Doc/whatsnew/3.11.rst
M Include/cpython/pystate.h
M Include/internal/pycore_pyerrors.h
M Lib/importlib/_bootstrap_external.py
M Lib/test/test_dis.py
M Lib/test/test_sys.py
M Modules/_asynciomodule.c
M Objects/genobject.c
M Python/ceval.c
M Python/compile.c
M Python/errors.c
M Python/pystate.c
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
index 35d9baadf6d16..ffade3c9bfe7c 100644
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -474,13 +474,15 @@ the original TOS1.
.. opcode:: END_ASYNC_FOR
Terminates an :keyword:`async for` loop. Handles an exception raised
- when awaiting a next item. If TOS is :exc:`StopAsyncIteration` pop 7
+ when awaiting a next item. If TOS is :exc:`StopAsyncIteration` pop 3
values from the stack and restore the exception state using the second
- three of them. Otherwise re-raise the exception using the three values
+ of them. Otherwise re-raise the exception using the value
from the stack. An exception handler block is removed from the block stack.
.. versionadded:: 3.8
+ .. versionchanged:: 3.11
+ Exception representation on the stack now consist of one, not three, items.
.. opcode:: BEFORE_ASYNC_WITH
@@ -561,8 +563,10 @@ iterations of the loop.
.. opcode:: POP_EXCEPT
- Pops three values from the stack, which are used to restore the exception state.
+ Pops a value from the stack, which is used to restore the exception state.
+ .. versionchanged:: 3.11
+ Exception representation on the stack now consist of one, not three, items.
.. opcode:: RERAISE
@@ -572,11 +576,13 @@ iterations of the loop.
.. versionadded:: 3.9
+ .. versionchanged:: 3.11
+ Exception representation on the stack now consist of one, not three, items.
.. opcode:: PUSH_EXC_INFO
- Pops the three values from the stack. Pushes the current exception to the top of the stack.
- Pushes the three values originally popped back to the stack.
+ Pops a value from the stack. Pushes the current exception to the top of the stack.
+ Pushes the value originally popped back to the stack.
Used in exception handlers.
.. versionadded:: 3.11
@@ -584,8 +590,8 @@ iterations of the loop.
.. opcode:: WITH_EXCEPT_START
- Calls the function in position 8 on the stack with the top three
- items on the stack as arguments.
+ Calls the function in position 4 on the stack with arguments (type, val, tb)
+ representing the exception at the top of the stack.
Used to implement the call ``context_manager.__exit__(*exc_info())`` when an exception
has occurred in a :keyword:`with` statement.
@@ -593,6 +599,9 @@ iterations of the loop.
.. versionchanged:: 3.11
The ``__exit__`` function is in position 8 of the stack rather than 7.
+ .. versionchanged:: 3.11
+ The ``__exit__`` function is in position 4 of the stack rather than 7.
+ Exception representation on the stack now consist of one, not three, items.
.. opcode:: POP_EXCEPT_AND_RERAISE
@@ -890,10 +899,9 @@ All of the following opcodes use their arguments.
Performs exception matching for ``except*``. Applies ``split(TOS)`` on
the exception group representing TOS1. Jumps if no match is found.
- Pops one item from the stack. If a match was found, pops the 3 items representing
- the exception and pushes the 3 items representing the non-matching part of
- the exception group, followed by the 3 items representing the matching part.
- In other words, in case of a match it pops 4 items and pushes 6.
+ Pops one item from the stack (the match type). If a match was found,
+ next item (the exception) and pushes the non-matching part of the
+ exception group followed by the matching part.
.. versionadded:: 3.11
@@ -903,8 +911,8 @@ All of the following opcodes use their arguments.
Combines the raised and reraised exceptions list from TOS, into an exception
group to propagate from a try-except* block. Uses the original exception
group from TOS1 to reconstruct the structure of reraised exceptions. Pops
- two items from the stack and pushes a triplet representing the exception to
- reraise or three ``None`` if there isn't one.
+ two items from the stack and pushes 0 (for lasti, which is unused) followed
+ by the exception to reraise or ``None`` if there isn't one.
.. versionadded:: 3.11
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index 3005d1d43f25b..5389ce8b258cf 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -195,6 +195,11 @@ Other CPython Implementation Changes
reflected in the re-raised exception.
(Contributed by Irit Katriel in :issue:`45711`.)
+* The interpreter state's representation of handled exceptions (a.k.a exc_info, or
+ _PyErr_StackItem) now has only the ``exc_value`` field, ``exc_type`` and ``exc_traceback``
+ have been removed as their values can be derived from ``exc_value``.
+ (Contributed by Irit Katriel in :issue:`45711`.)
+
New Modules
===========
diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h
index aa518281c80f5..c37123c4f6922 100644
--- a/Include/cpython/pystate.h
+++ b/Include/cpython/pystate.h
@@ -56,7 +56,7 @@ typedef struct _err_stackitem {
* This ensures that the exception state is not impacted by "yields"
* from an except handler.
*/
- PyObject *exc_type, *exc_value, *exc_traceback;
+ PyObject *exc_value;
struct _err_stackitem *previous_item;
diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h
index 5e8d2025dfaf0..b9fc36cf06760 100644
--- a/Include/internal/pycore_pyerrors.h
+++ b/Include/internal/pycore_pyerrors.h
@@ -24,16 +24,7 @@ static inline PyObject* _PyErr_Occurred(PyThreadState *tstate)
static inline void _PyErr_ClearExcState(_PyErr_StackItem *exc_state)
{
- PyObject *t, *v, *tb;
- t = exc_state->exc_type;
- v = exc_state->exc_value;
- tb = exc_state->exc_traceback;
- exc_state->exc_type = NULL;
- exc_state->exc_value = NULL;
- exc_state->exc_traceback = NULL;
- Py_XDECREF(t);
- Py_XDECREF(v);
- Py_XDECREF(tb);
+ Py_CLEAR(exc_state->exc_value);
}
PyAPI_FUNC(PyObject*) _PyErr_StackItemToExcInfoTuple(
@@ -114,6 +105,7 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc(
#define _Py_FatalRefcountError(message) _Py_FatalRefcountErrorFunc(__func__, message)
+
#ifdef __cplusplus
}
#endif
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
index 0c1078accc819..5ead6caf9f3c7 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -371,9 +371,10 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.11a3 3464 (bpo-45636: Merge numeric BINARY_*/INPLACE_* into
# BINARY_OP)
# Python 3.11a3 3465 (Add COPY_FREE_VARS opcode)
-# Python 3.11a3 3466 (bpo-45292: PEP-654 except*)
+# Python 3.11a4 3466 (bpo-45292: PEP-654 except*)
# Python 3.11a4 3467 (Change CALL_xxx opcodes)
# Python 3.11a4 3468 (Add SEND opcode)
+# Python 3.11a4 3469 (bpo-45711: remove type, traceback from exc_info)
#
# MAGIC must change whenever the bytecode emitted by the compiler may no
@@ -383,7 +384,7 @@ def _write_atomic(path, data, mode=0o666):
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated.
-MAGIC_NUMBER = (3468).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3469).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__'
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index c35f1d3ec8bd7..93b24da317575 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -310,33 +310,31 @@ def bug42562():
>> 14 PUSH_EXC_INFO
%3d 16 LOAD_GLOBAL 0 (Exception)
- 18 JUMP_IF_NOT_EXC_MATCH 26 (to 52)
- 20 POP_TOP
- 22 STORE_FAST 0 (e)
- 24 POP_TOP
-
-%3d 26 LOAD_FAST 0 (e)
- 28 LOAD_ATTR 1 (__traceback__)
- 30 STORE_FAST 1 (tb)
- 32 POP_EXCEPT
- 34 LOAD_CONST 0 (None)
- 36 STORE_FAST 0 (e)
- 38 DELETE_FAST 0 (e)
-
-%3d 40 LOAD_FAST 1 (tb)
- 42 RETURN_VALUE
- >> 44 LOAD_CONST 0 (None)
- 46 STORE_FAST 0 (e)
- 48 DELETE_FAST 0 (e)
- 50 RERAISE 1
-
-%3d >> 52 RERAISE 0
- >> 54 POP_EXCEPT_AND_RERAISE
+ 18 JUMP_IF_NOT_EXC_MATCH 24 (to 48)
+ 20 STORE_FAST 0 (e)
+
+%3d 22 LOAD_FAST 0 (e)
+ 24 LOAD_ATTR 1 (__traceback__)
+ 26 STORE_FAST 1 (tb)
+ 28 POP_EXCEPT
+ 30 LOAD_CONST 0 (None)
+ 32 STORE_FAST 0 (e)
+ 34 DELETE_FAST 0 (e)
+
+%3d 36 LOAD_FAST 1 (tb)
+ 38 RETURN_VALUE
+ >> 40 LOAD_CONST 0 (None)
+ 42 STORE_FAST 0 (e)
+ 44 DELETE_FAST 0 (e)
+ 46 RERAISE 1
+
+%3d >> 48 RERAISE 0
+ >> 50 POP_EXCEPT_AND_RERAISE
ExceptionTable:
2 to 8 -> 14 [0]
- 14 to 24 -> 54 [3] lasti
- 26 to 30 -> 44 [3] lasti
- 44 to 52 -> 54 [3] lasti
+ 14 to 20 -> 50 [1] lasti
+ 22 to 26 -> 40 [1] lasti
+ 40 to 48 -> 50 [1] lasti
""" % (TRACEBACK_CODE.co_firstlineno + 1,
TRACEBACK_CODE.co_firstlineno + 2,
TRACEBACK_CODE.co_firstlineno + 5,
@@ -395,7 +393,7 @@ def _tryfinallyconst(b):
>> 22 POP_EXCEPT_AND_RERAISE
ExceptionTable:
2 to 2 -> 12 [0]
- 12 to 20 -> 22 [3] lasti
+ 12 to 20 -> 22 [1] lasti
""" % (_tryfinally.__code__.co_firstlineno + 1,
_tryfinally.__code__.co_firstlineno + 2,
_tryfinally.__code__.co_firstlineno + 4,
@@ -418,7 +416,7 @@ def _tryfinallyconst(b):
22 RERAISE 0
>> 24 POP_EXCEPT_AND_RERAISE
ExceptionTable:
- 14 to 22 -> 24 [3] lasti
+ 14 to 22 -> 24 [1] lasti
""" % (_tryfinallyconst.__code__.co_firstlineno + 1,
_tryfinallyconst.__code__.co_firstlineno + 2,
_tryfinallyconst.__code__.co_firstlineno + 4,
@@ -864,7 +862,7 @@ async def async_def():
Positional-only arguments: 0
Kw-only arguments: 0
Number of locals: 2
-Stack size: 10
+Stack size: 6
Flags: OPTIMIZED, NEWLOCALS, COROUTINE
Constants:
0: None
@@ -1107,65 +1105,61 @@ def _prepare_test_cases():
Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=108, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=110, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_FORWARD', opcode=110, arg=14, argval=144, argrepr='to 144', offset=114, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_FORWARD', opcode=110, arg=12, argval=140, argrepr='to 140', offset=114, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=116, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=118, starts_line=22, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_IF_NOT_EXC_MATCH', opcode=121, arg=70, argval=140, argrepr='to 140', offset=120, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_IF_NOT_EXC_MATCH', opcode=121, arg=68, argval=136, argrepr='to 136', offset=120, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=122, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=124, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=126, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=128, starts_line=23, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=130, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=132, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=134, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_FORWARD', opcode=110, arg=32, argval=204, argrepr='to 204', offset=138, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=140, starts_line=22, is_jump_target=True, positions=None),
- Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=142, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=144, starts_line=25, is_jump_target=True, positions=None),
- Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=146, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=148, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=150, starts_line=26, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=152, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=154, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=156, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=158, starts_line=25, is_jump_target=False, positions=None),
- Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL_NO_KW', opcode=169, arg=3, argval=3, argrepr='', offset=164, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=192, argrepr='to 192', offset=168, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=90, argval=180, argrepr='to 180', offset=174, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RERAISE', opcode=119, arg=4, argval=4, argrepr='', offset=176, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=178, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=180, starts_line=None, is_jump_target=True, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=124, starts_line=23, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=126, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=128, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=130, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=132, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_FORWARD', opcode=110, arg=30, argval=196, argrepr='to 196', offset=134, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=136, starts_line=22, is_jump_target=True, positions=None),
+ Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=138, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=140, starts_line=25, is_jump_target=True, positions=None),
+ Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=142, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=144, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=146, starts_line=26, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=148, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=150, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=152, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=154, starts_line=25, is_jump_target=False, positions=None),
+ Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=156, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=158, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL_NO_KW', opcode=169, arg=3, argval=3, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_FORWARD', opcode=110, arg=9, argval=184, argrepr='to 184', offset=164, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=88, argval=176, argrepr='to 176', offset=170, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=172, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=174, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=176, starts_line=None, is_jump_target=True, positions=None),
+ Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=178, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=180, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=184, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=188, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=184, starts_line=28, is_jump_target=True, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=186, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=188, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=190, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=192, starts_line=28, is_jump_target=True, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=194, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=196, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=198, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=200, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=202, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=204, starts_line=23, is_jump_target=True, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=206, starts_line=28, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=208, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=214, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=220, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=222, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=224, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=226, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=228, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=230, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=192, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=194, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=196, starts_line=23, is_jump_target=True, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=198, starts_line=28, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=200, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=202, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=204, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=206, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=208, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=212, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=214, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=220, starts_line=None, is_jump_target=False, positions=None),
+ Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=222, starts_line=None, is_jump_target=False, positions=None),
]
# One last piece of inspect fodder to check the default line number handling
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 41ac03b920e64..96075cf3b3473 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -1340,7 +1340,7 @@ def bar(cls):
check(bar, size('PP'))
# generator
def get_gen(): yield 1
- check(get_gen(), size('P2PPP4P4c8P2iciP'))
+ check(get_gen(), size('P2P4P4c8P2iciP'))
# iterator
check(iter('abc'), size('lP'))
# callable-iterator
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-12-15-15-17-04.bpo-45711.QK4QrB.rst b/Misc/NEWS.d/next/Core and Builtins/2021-12-15-15-17-04.bpo-45711.QK4QrB.rst
new file mode 100644
index 0000000000000..717f89ff0e279
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-12-15-15-17-04.bpo-45711.QK4QrB.rst
@@ -0,0 +1 @@
+The interpreter state's representation of handled exceptions (a.k.a exc_info, or _PyErr_StackItem) now has only the ``exc_value`` field, ``exc_type`` and ``exc_traceback`` have been removed as their values can be derived from ``exc_value``.
\ No newline at end of file
diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c
index 267faacde8a17..978a1fdd0d852 100644
--- a/Modules/_asynciomodule.c
+++ b/Modules/_asynciomodule.c
@@ -810,9 +810,7 @@ FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg)
Py_VISIT(fut->dict);
_PyErr_StackItem *exc_state = &fut->fut_cancelled_exc_state;
- Py_VISIT(exc_state->exc_type);
Py_VISIT(exc_state->exc_value);
- Py_VISIT(exc_state->exc_traceback);
return 0;
}
@@ -1376,10 +1374,6 @@ _asyncio_Future__make_cancelled_error_impl(FutureObj *self)
PyException_SetContext(exc, Py_NewRef(exc_state->exc_value));
_PyErr_ClearExcState(exc_state);
}
- else {
- assert(exc_state->exc_type == NULL);
- assert(exc_state->exc_traceback == NULL);
- }
return exc;
}
@@ -2706,13 +2700,13 @@ task_step_impl(TaskObj *task, PyObject *exc)
PyErr_NormalizeException(&et, &ev, &tb);
if (tb != NULL) {
PyException_SetTraceback(ev, tb);
+ Py_DECREF(tb);
}
+ Py_XDECREF(et);
FutureObj *fut = (FutureObj*)task;
_PyErr_StackItem *exc_state = &fut->fut_cancelled_exc_state;
- exc_state->exc_type = et;
exc_state->exc_value = ev;
- exc_state->exc_traceback = tb;
return future_cancel(fut, NULL);
}
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 24a4e94bfc7a2..d093f3dd7de30 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -25,9 +25,7 @@ static const char *ASYNC_GEN_IGNORED_EXIT_MSG =
static inline int
exc_state_traverse(_PyErr_StackItem *exc_state, visitproc visit, void *arg)
{
- Py_VISIT(exc_state->exc_type);
Py_VISIT(exc_state->exc_value);
- Py_VISIT(exc_state->exc_traceback);
return 0;
}
@@ -886,9 +884,7 @@ make_gen(PyTypeObject *type, PyFunctionObject *func)
gen->gi_code = (PyCodeObject *)func->func_code;
Py_INCREF(gen->gi_code);
gen->gi_weakreflist = NULL;
- gen->gi_exc_state.exc_type = NULL;
gen->gi_exc_state.exc_value = NULL;
- gen->gi_exc_state.exc_traceback = NULL;
gen->gi_exc_state.previous_item = NULL;
if (func->func_name != NULL)
gen->gi_name = func->func_name;
@@ -975,9 +971,7 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
Py_INCREF(gen->gi_code);
Py_DECREF(f);
gen->gi_weakreflist = NULL;
- gen->gi_exc_state.exc_type = NULL;
gen->gi_exc_state.exc_value = NULL;
- gen->gi_exc_state.exc_traceback = NULL;
gen->gi_exc_state.previous_item = NULL;
if (name != NULL)
gen->gi_name = name;
diff --git a/Python/ceval.c b/Python/ceval.c
index 87d6a2288e0dd..bac57ccb7cc75 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1094,29 +1094,11 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type,
static int do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause);
static PyObject *do_reraise_star(PyObject *excs, PyObject *orig);
static int exception_group_match(
- PyObject *exc_type, PyObject* exc_value, PyObject *match_type,
+ PyObject* exc_value, PyObject *match_type,
PyObject **match, PyObject **rest);
static int unpack_iterable(PyThreadState *, PyObject *, int, int, PyObject **);
-#ifdef Py_DEBUG
-static void
-_assert_exception_type_is_redundant(PyObject* type, PyObject* val)
-{
- if (type == NULL || type == Py_None) {
- assert(val == type);
- }
- else {
- assert(PyExceptionInstance_Check(val));
- assert(PyExceptionInstance_Class(val) == type);
- }
-}
-
-#define ASSERT_EXC_TYPE_IS_REDUNDANT(t, v) _assert_exception_type_is_redundant(t, v)
-#else
-#define ASSERT_EXC_TYPE_IS_REDUNDANT(t, v)
-#endif
-
PyObject *
PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
{
@@ -2737,25 +2719,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
}
TARGET(POP_EXCEPT) {
- PyObject *type, *value, *traceback;
- _PyErr_StackItem *exc_info;
- exc_info = tstate->exc_info;
- type = exc_info->exc_type;
- value = exc_info->exc_value;
- traceback = exc_info->exc_traceback;
-
- exc_info->exc_type = POP();
+ _PyErr_StackItem *exc_info = tstate->exc_info;
+ PyObject *value = exc_info->exc_value;
exc_info->exc_value = POP();
- exc_info->exc_traceback = POP();
- ASSERT_EXC_TYPE_IS_REDUNDANT(exc_info->exc_type, exc_info->exc_value);
- Py_XDECREF(type);
Py_XDECREF(value);
- Py_XDECREF(traceback);
DISPATCH();
}
TARGET(POP_EXCEPT_AND_RERAISE) {
- PyObject *lasti = PEEK(4);
+ PyObject *lasti = PEEK(2);
if (PyLong_Check(lasti)) {
frame->f_lasti = PyLong_AsLong(lasti);
assert(!_PyErr_Occurred(tstate));
@@ -2764,31 +2736,24 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
_PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int");
goto error;
}
- PyObject *type, *value, *traceback;
- _PyErr_StackItem *exc_info;
- type = POP();
- value = POP();
- traceback = POP();
- ASSERT_EXC_TYPE_IS_REDUNDANT(type, value);
+ PyObject *value = POP();
+ assert(value);
+ assert(PyExceptionInstance_Check(value));
+ PyObject *type = Py_NewRef(PyExceptionInstance_Class(value));
+ PyObject *traceback = PyException_GetTraceback(value);
Py_DECREF(POP()); /* lasti */
_PyErr_Restore(tstate, type, value, traceback);
- exc_info = tstate->exc_info;
- type = exc_info->exc_type;
+
+ _PyErr_StackItem *exc_info = tstate->exc_info;
value = exc_info->exc_value;
- traceback = exc_info->exc_traceback;
- exc_info->exc_type = POP();
exc_info->exc_value = POP();
- exc_info->exc_traceback = POP();
- ASSERT_EXC_TYPE_IS_REDUNDANT(exc_info->exc_type, exc_info->exc_value);
- Py_XDECREF(type);
Py_XDECREF(value);
- Py_XDECREF(traceback);
goto exception_unwind;
}
TARGET(RERAISE) {
if (oparg) {
- PyObject *lasti = PEEK(oparg+3);
+ PyObject *lasti = PEEK(oparg + 1);
if (PyLong_Check(lasti)) {
frame->f_lasti = PyLong_AsLong(lasti);
assert(!_PyErr_Occurred(tstate));
@@ -2799,11 +2764,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
goto error;
}
}
- PyObject *exc = POP();
PyObject *val = POP();
- PyObject *tb = POP();
- ASSERT_EXC_TYPE_IS_REDUNDANT(exc, val);
- assert(PyExceptionClass_Check(exc));
+ assert(val && PyExceptionInstance_Check(val));
+ PyObject *exc = Py_NewRef(PyExceptionInstance_Class(val));
+ PyObject *tb = PyException_GetTraceback(val);
_PyErr_Restore(tstate, exc, val, tb);
goto exception_unwind;
}
@@ -2823,35 +2787,21 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
PyObject *lasti_unused = Py_NewRef(_PyLong_GetZero());
PUSH(lasti_unused);
- if (!Py_IsNone(val)) {
- PyObject *tb = PyException_GetTraceback(val);
- PUSH(tb ? tb : Py_NewRef(Py_None));
- PUSH(val);
- PUSH(Py_NewRef(Py_TYPE(val)));
- }
- else {
- // nothing to reraise
- PUSH(Py_NewRef(Py_None));
- PUSH(val);
- PUSH(Py_NewRef(Py_None));
- }
+ PUSH(val);
DISPATCH();
}
TARGET(END_ASYNC_FOR) {
- PyObject *exc = POP();
PyObject *val = POP();
- PyObject *tb = POP();
- ASSERT_EXC_TYPE_IS_REDUNDANT(exc, val);
- assert(PyExceptionClass_Check(exc));
- if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) {
- Py_DECREF(exc);
+ assert(val && PyExceptionInstance_Check(val));
+ if (PyErr_GivenExceptionMatches(val, PyExc_StopAsyncIteration)) {
Py_DECREF(val);
- Py_DECREF(tb);
Py_DECREF(POP());
DISPATCH();
}
else {
+ PyObject *exc = Py_NewRef(PyExceptionInstance_Class(val));
+ PyObject *tb = PyException_GetTraceback(val);
_PyErr_Restore(tstate, exc, val, tb);
goto exception_unwind;
}
@@ -3971,16 +3921,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(JUMP_IF_NOT_EG_MATCH) {
PyObject *match_type = POP();
- PyObject *exc_type = TOP();
- PyObject *exc_value = SECOND();
if (check_except_star_type_valid(tstate, match_type) < 0) {
Py_DECREF(match_type);
goto error;
}
+ PyObject *exc_value = TOP();
PyObject *match = NULL, *rest = NULL;
- int res = exception_group_match(exc_type, exc_value,
- match_type, &match, &rest);
+ int res = exception_group_match(exc_value, match_type,
+ &match, &rest);
Py_DECREF(match_type);
if (res < 0) {
goto error;
@@ -4001,46 +3950,21 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
else {
/* Total or partial match - update the stack from
- * [tb, val, exc]
+ * [val]
* to
- * [tb, rest, exc, tb, match, exc]
+ * [rest, match]
* (rest can be Py_None)
*/
+ PyObject *exc = TOP();
- PyObject *type = TOP();
- PyObject *val = SECOND();
- PyObject *tb = THIRD();
-
- if (!Py_IsNone(rest)) {
- /* tb remains the same */
- SET_TOP(Py_NewRef(Py_TYPE(rest)));
- SET_SECOND(Py_NewRef(rest));
- SET_THIRD(Py_NewRef(tb));
- }
- else {
- SET_TOP(Py_NewRef(Py_None));
- SET_SECOND(Py_NewRef(Py_None));
- SET_THIRD(Py_NewRef(Py_None));
- }
- /* Push match */
+ SET_TOP(rest);
+ PUSH(match);
- PUSH(Py_NewRef(tb));
- PUSH(Py_NewRef(match));
- PUSH(Py_NewRef(Py_TYPE(match)));
+ PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL);
- // set exc_info to the current match
- PyErr_SetExcInfo(
- Py_NewRef(Py_TYPE(match)),
- Py_NewRef(match),
- Py_NewRef(tb));
-
- Py_DECREF(tb);
- Py_DECREF(val);
- Py_DECREF(type);
+ Py_DECREF(exc);
- Py_DECREF(match);
- Py_DECREF(rest);
}
DISPATCH();
@@ -4048,8 +3972,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(JUMP_IF_NOT_EXC_MATCH) {
PyObject *right = POP();
- ASSERT_EXC_TYPE_IS_REDUNDANT(TOP(), SECOND());
- PyObject *left = SECOND();
+ PyObject *left = TOP();
assert(PyExceptionInstance_Check(left));
if (check_except_type_valid(tstate, right) < 0) {
Py_DECREF(right);
@@ -4465,26 +4388,24 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
}
TARGET(WITH_EXCEPT_START) {
- /* At the top of the stack are 8 values:
- - (TOP, SECOND, THIRD) = exc_info()
- - (FOURTH, FIFTH, SIXTH) = previous exception
- - SEVENTH: lasti of exception in exc_info()
- - EIGHTH: the context.__exit__ bound method
- We call EIGHTH(TOP, SECOND, THIRD).
- Then we push again the TOP exception and the __exit__
- return value.
+ /* At the top of the stack are 4 values:
+ - TOP = exc_info()
+ - SECOND = previous exception
+ - THIRD: lasti of exception in exc_info()
+ - FOURTH: the context.__exit__ bound method
+ We call FOURTH(type(TOP), TOP, GetTraceback(TOP)).
+ Then we push the __exit__ return value.
*/
PyObject *exit_func;
PyObject *exc, *val, *tb, *res;
- exc = TOP();
- val = SECOND();
- tb = THIRD();
- ASSERT_EXC_TYPE_IS_REDUNDANT(exc, val);
- assert(!Py_IsNone(exc));
- assert(!PyLong_Check(exc));
- assert(PyLong_Check(PEEK(7)));
- exit_func = PEEK(8);
+ val = TOP();
+ assert(val && PyExceptionInstance_Check(val));
+ exc = PyExceptionInstance_Class(val);
+ tb = PyException_GetTraceback(val);
+ Py_XDECREF(tb);
+ assert(PyLong_Check(PEEK(3)));
+ exit_func = PEEK(4);
PyObject *stack[4] = {NULL, exc, val, tb};
res = PyObject_Vectorcall(exit_func, stack + 1,
3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL);
@@ -4496,40 +4417,22 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
}
TARGET(PUSH_EXC_INFO) {
- PyObject *type = TOP();
- PyObject *value = SECOND();
- PyObject *tb = THIRD();
- ASSERT_EXC_TYPE_IS_REDUNDANT(type, value);
+ PyObject *value = TOP();
+
_PyErr_StackItem *exc_info = tstate->exc_info;
- SET_THIRD(exc_info->exc_traceback);
if (exc_info->exc_value != NULL) {
- SET_SECOND(exc_info->exc_value);
- }
- else {
- Py_INCREF(Py_None);
- SET_SECOND(Py_None);
- }
- if (exc_info->exc_type != NULL) {
- SET_TOP(exc_info->exc_type);
+ SET_TOP(exc_info->exc_value);
}
else {
Py_INCREF(Py_None);
SET_TOP(Py_None);
}
- Py_INCREF(tb);
- PUSH(tb);
- exc_info->exc_traceback = tb;
Py_INCREF(value);
PUSH(value);
assert(PyExceptionInstance_Check(value));
exc_info->exc_value = value;
- Py_INCREF(type);
- PUSH(type);
- assert(PyExceptionClass_Check(type));
- exc_info->exc_type = type;
-
DISPATCH();
}
@@ -5518,14 +5421,9 @@ MISS_WITH_OPARG_COUNTER(STORE_SUBSCR)
PyException_SetTraceback(val, tb);
else
PyException_SetTraceback(val, Py_None);
- if (tb == NULL) {
- tb = Py_None;
- Py_INCREF(Py_None);
- }
- PUSH(tb);
+ Py_XDECREF(tb);
+ Py_XDECREF(exc);
PUSH(val);
- PUSH(exc);
- ASSERT_EXC_TYPE_IS_REDUNDANT(exc, val);
JUMPTO(handler);
/* Resume normal execution */
frame->f_state = FRAME_EXECUTING;
@@ -6375,19 +6273,17 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause)
*/
static int
-exception_group_match(PyObject *exc_type, PyObject* exc_value,
- PyObject *match_type, PyObject **match, PyObject **rest)
+exception_group_match(PyObject* exc_value, PyObject *match_type,
+ PyObject **match, PyObject **rest)
{
- if (Py_IsNone(exc_type)) {
- assert(Py_IsNone(exc_value));
+ if (Py_IsNone(exc_value)) {
*match = Py_NewRef(Py_None);
*rest = Py_NewRef(Py_None);
return 0;
}
- assert(PyExceptionClass_Check(exc_type));
assert(PyExceptionInstance_Check(exc_value));
- if (PyErr_GivenExceptionMatches(exc_type, match_type)) {
+ if (PyErr_GivenExceptionMatches(exc_value, match_type)) {
/* Full match of exc itself */
bool is_eg = _PyBaseExceptionGroup_Check(exc_value);
if (is_eg) {
diff --git a/Python/compile.c b/Python/compile.c
index 6179ad980aade..8e90b1ab37037 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1048,9 +1048,9 @@ stack_effect(int opcode, int oparg, int jump)
case POP_BLOCK:
return 0;
case POP_EXCEPT:
- return -3;
+ return -1;
case POP_EXCEPT_AND_RERAISE:
- return -7;
+ return -3;
case STORE_NAME:
return -1;
@@ -1095,7 +1095,7 @@ stack_effect(int opcode, int oparg, int jump)
case JUMP_IF_NOT_EXC_MATCH:
return -1;
case JUMP_IF_NOT_EG_MATCH:
- return jump > 0 ? -1 : 2;
+ return jump > 0 ? -1 : 0;
case IMPORT_NAME:
return -1;
case IMPORT_FROM:
@@ -1120,25 +1120,25 @@ stack_effect(int opcode, int oparg, int jump)
/* Exception handling pseudo-instructions */
case SETUP_FINALLY:
/* 0 in the normal flow.
- * Restore the stack position and push 3 values before jumping to
+ * Restore the stack position and push 1 value before jumping to
* the handler if an exception be raised. */
- return jump ? 3 : 0;
+ return jump ? 1 : 0;
case SETUP_CLEANUP:
/* As SETUP_FINALLY, but pushes lasti as well */
- return jump ? 4 : 0;
+ return jump ? 2 : 0;
case SETUP_WITH:
/* 0 in the normal flow.
* Restore the stack position to the position before the result
- * of __(a)enter__ and push 4 values before jumping to the handler
+ * of __(a)enter__ and push 2 values before jumping to the handler
* if an exception be raised. */
- return jump ? -1 + 4 : 0;
+ return jump ? 1 : 0;
case PREP_RERAISE_STAR:
- return 2;
+ return 0;
case RERAISE:
- return -3;
+ return -1;
case PUSH_EXC_INFO:
- return 3;
+ return 1;
case WITH_EXCEPT_START:
return 1;
@@ -1199,7 +1199,7 @@ stack_effect(int opcode, int oparg, int jump)
case GET_YIELD_FROM_ITER:
return 0;
case END_ASYNC_FOR:
- return -4;
+ return -2;
case FORMAT_VALUE:
/* If there's a fmt_spec on the stack, we go from 2->1,
else 1->1. */
@@ -1888,13 +1888,11 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
case FINALLY_END:
if (preserve_tos) {
- ADDOP(c, ROT_FOUR);
+ ADDOP(c, ROT_TWO);
}
- ADDOP(c, POP_TOP);
- ADDOP(c, POP_TOP);
- ADDOP(c, POP_TOP);
+ ADDOP(c, POP_TOP); /* exc_value */
if (preserve_tos) {
- ADDOP(c, ROT_FOUR);
+ ADDOP(c, ROT_TWO);
}
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
@@ -1927,7 +1925,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
ADDOP(c, POP_BLOCK);
}
if (preserve_tos) {
- ADDOP(c, ROT_FOUR);
+ ADDOP(c, ROT_TWO);
}
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
@@ -3310,18 +3308,16 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s)
[] POP_BLOCK
[] JUMP_FORWARD L0
- [tb, val, exc] L1: <evaluate E1> )
- [tb, val, exc, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1
- [tb, val, exc] POP
- [tb, val] <assign to V1> (or POP if no V1)
- [tb] POP
+ [exc] L1: <evaluate E1> )
+ [exc, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1
+ [exc] <assign to V1> (or POP if no V1)
[] <code for S1>
JUMP_FORWARD L0
- [tb, val, exc] L2: <evaluate E2>
+ [exc] L2: <evaluate E2>
.............................etc.......................
- [tb, val, exc] Ln+1: RERAISE # re-raise exception
+ [exc] Ln+1: RERAISE # re-raise exception
[] L0: <next statement>
@@ -3372,7 +3368,6 @@ compiler_try_except(struct compiler *c, stmt_ty s)
ADDOP_JUMP(c, JUMP_IF_NOT_EXC_MATCH, except);
NEXT_BLOCK(c);
}
- ADDOP(c, POP_TOP);
if (handler->v.ExceptHandler.name) {
basicblock *cleanup_end, *cleanup_body;
@@ -3383,7 +3378,6 @@ compiler_try_except(struct compiler *c, stmt_ty s)
}
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
- ADDOP(c, POP_TOP);
/*
try:
@@ -3434,8 +3428,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
if (!cleanup_body)
return 0;
- ADDOP(c, POP_TOP);
- ADDOP(c, POP_TOP);
+ ADDOP(c, POP_TOP); /* exc_value */
compiler_use_next_block(c, cleanup_body);
if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL, NULL))
return 0;
@@ -3467,52 +3460,42 @@ compiler_try_except(struct compiler *c, stmt_ty s)
at the right; 'tb' is trace-back info, 'val' the exception instance,
and 'typ' the exception's type.)
- Value stack Label Instruction Argument
- [] SETUP_FINALLY L1
- [] <code for S>
- [] POP_BLOCK
- [] JUMP_FORWARD L0
+ Value stack Label Instruction Argument
+ [] SETUP_FINALLY L1
+ [] <code for S>
+ [] POP_BLOCK
+ [] JUMP_FORWARD L0
- [tb, val, typ] L1: DUP_TOP_TWO ) save a copy of the
- [tb, val, typ, orig, typ] POP_TOP ) original raised exception
- [tb, val, typ, orig] ROT_FOUR )
- [orig, tb, val, typ] BUILD_LIST ) list for raised/reraised
- [orig, tb, val, typ, res] ROT_FOUR ) exceptions ("result")
+ [exc] L1: DUP_TOP ) save copy of the original exception
+ [orig, exc] BUILD_LIST ) list for raised/reraised excs ("result")
+ [orig, exc, res] ROT_TWO
- [orig, res, tb, val, typ] <evaluate E1> )
- [orig, res, tb, val, typ, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1
+ [orig, res, exc] <evaluate E1>
+ [orig, res, exc, E1] JUMP_IF_NOT_EG_MATCH L2
- [orig, res, tb, rest, typ, tb, match, typ] POP
- [orig, res, tb, rest, typ, tb, match] <assign to V1> (or POP if no V1)
- [orig, res, tb, rest, typ, tb] POP
+ [orig, res, rest, match] <assign to V1> (or POP if no V1)
- [orig, res, tb, rest, typ] SETUP_FINALLY R1
- [orig, res, tb, rest, typ] <code for S1>
- [orig, res, tb, rest, typ] JUMP_FORWARD L2
+ [orig, res, rest] SETUP_FINALLY R1
+ [orig, res, rest] <code for S1>
+ [orig, res, rest] JUMP_FORWARD L2
- [orig, res, tb, rest, typ, i, tb, v, t] R1: POP ) exception raised in except* body
- [orig, res, tb, rest, typ, i, tb, v] LIST_APPEND 6 ) add it to res
- [orig, res, tb, rest, typ, i, tb] POP
- [orig, res, tb, rest, typ, i] POP
+ [orig, res, rest, i, v] R1: LIST_APPEND 3 ) exc raised in except* body - add to res
+ [orig, res, rest, i] POP
- [orig, res, tb, rest, typ] L2: <evaluate E2>
+ [orig, res, rest] L2: <evaluate E2>
.............................etc.......................
- [orig, res, tb, rest, typ] Ln+1: POP ) add unhandled exception
- [orig, res, tb, rest] LIST_APPEND 2 ) to res (could be None)
- [orig, res, tb] POP
+ [orig, res, rest] Ln+1: LIST_APPEND 1 ) add unhandled exc to res (could be None)
- [orig, res] PREP_RERAISE_STAR
- [i, tb, val, typ] POP_JUMP_IF_TRUE RER
- [i, tb, val, typ] POP
- [i, tb, val] POP
- [i, tb] POP
- [i] POP
- [] JUMP_FORWARD L0
+ [orig, res] PREP_RERAISE_STAR
+ [i, exc] POP_JUMP_IF_TRUE RER
+ [i, exc] POP
+ [i] POP
+ [] JUMP_FORWARD L0
- [i, tb, val, typ] RER: POP_EXCEPT_AND_RERAISE
+ [i, exc] RER: POP_EXCEPT_AND_RERAISE
- [] L0: <next statement>
+ [] L0: <next statement>
*/
static int
compiler_try_star_except(struct compiler *c, stmt_ty s)
@@ -3573,30 +3556,25 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
if (i == 0) {
/* Push the original EG into the stack */
/*
- [tb, val, exc] DUP_TOP_TWO
- [tb, val, exc, val, exc] POP_TOP
- [tb, val, exc, val] ROT_FOUR
- [val, tb, val, exc]
+ [exc] DUP_TOP
+ [orig, exc]
*/
- ADDOP(c, DUP_TOP_TWO);
- ADDOP(c, POP_TOP);
- ADDOP(c, ROT_FOUR);
+ ADDOP(c, DUP_TOP);
/* create empty list for exceptions raised/reraise in the except* blocks */
/*
- [val, tb, val, exc] BUILD_LIST
- [val, tb, val, exc, []] ROT_FOUR
- [val, [], tb, val, exc]
+ [orig, exc] BUILD_LIST
+ [orig, exc, []] ROT_TWO
+ [orig, [], exc]
*/
ADDOP_I(c, BUILD_LIST, 0);
- ADDOP(c, ROT_FOUR);
+ ADDOP(c, ROT_TWO);
}
if (handler->v.ExceptHandler.type) {
VISIT(c, expr, handler->v.ExceptHandler.type);
ADDOP_JUMP(c, JUMP_IF_NOT_EG_MATCH, except);
NEXT_BLOCK(c);
}
- ADDOP(c, POP_TOP); // exc_type
basicblock *cleanup_end = compiler_new_block(c);
if (cleanup_end == NULL) {
@@ -3611,9 +3589,8 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
}
else {
- ADDOP(c, POP_TOP); // val
+ ADDOP(c, POP_TOP); // exc
}
- ADDOP(c, POP_TOP); // tb
/*
try:
@@ -3657,9 +3634,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
}
/* add exception raised to the res list */
- ADDOP(c, POP_TOP); // type
- ADDOP_I(c, LIST_APPEND, 6); // exc
- ADDOP(c, POP_TOP); // tb
+ ADDOP_I(c, LIST_APPEND, 3); // exc
ADDOP(c, POP_TOP); // lasti
ADDOP_JUMP(c, JUMP_ABSOLUTE, except);
@@ -3667,9 +3642,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
if (i == n - 1) {
/* Add exc to the list (if not None it's the unhandled part of the EG) */
- ADDOP(c, POP_TOP);
- ADDOP_I(c, LIST_APPEND, 2);
- ADDOP(c, POP_TOP);
+ ADDOP_I(c, LIST_APPEND, 1);
ADDOP_JUMP(c, JUMP_FORWARD, reraise_star);
}
}
@@ -3690,8 +3663,6 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
/* Nothing to reraise - pop it */
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
- ADDOP(c, POP_TOP);
- ADDOP(c, POP_TOP);
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
ADDOP_JUMP(c, JUMP_FORWARD, end);
@@ -5449,13 +5420,11 @@ compiler_with_except_finish(struct compiler *c, basicblock * cleanup) {
return 0;
ADDOP_JUMP(c, POP_JUMP_IF_TRUE, exit);
NEXT_BLOCK(c);
- ADDOP_I(c, RERAISE, 4);
+ ADDOP_I(c, RERAISE, 2);
compiler_use_next_block(c, cleanup);
ADDOP(c, POP_EXCEPT_AND_RERAISE);
compiler_use_next_block(c, exit);
- ADDOP(c, POP_TOP);
- ADDOP(c, POP_TOP);
- ADDOP(c, POP_TOP);
+ ADDOP(c, POP_TOP); /* exc_value */
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
ADDOP(c, POP_TOP);
@@ -5587,7 +5556,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
E: WITH_EXCEPT_START (calls EXPR.__exit__)
POP_JUMP_IF_TRUE T:
RERAISE
- T: POP_TOP * 3 (remove exception from stack)
+ T: POP_TOP (remove exception from stack)
POP_EXCEPT
POP_TOP
EXIT:
@@ -7368,7 +7337,10 @@ assemble_emit_exception_table_entry(struct assembler *a, int start, int end, bas
int size = end-start;
assert(end > start);
int target = handler->b_offset;
- int depth = handler->b_preserve_lasti ? handler->b_startdepth-4 : handler->b_startdepth-3;
+ int depth = handler->b_startdepth - 1;
+ if (handler->b_preserve_lasti) {
+ depth -= 1;
+ }
assert(depth >= 0);
int depth_lasti = (depth<<1) | handler->b_preserve_lasti;
assemble_emit_exception_table_item(a, start, (1<<7));
diff --git a/Python/errors.c b/Python/errors.c
index 5be15e54db25b..6c5fe41142304 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -84,11 +84,8 @@ _PyErr_GetTopmostException(PyThreadState *tstate)
while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) &&
exc_info->previous_item != NULL)
{
- assert(exc_info->exc_type == NULL || exc_info->exc_type == Py_None);
exc_info = exc_info->previous_item;
}
- assert(exc_info->previous_item == NULL ||
- (exc_info->exc_type != NULL && exc_info->exc_type != Py_None));
return exc_info;
}
@@ -524,27 +521,17 @@ PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
void
PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback)
{
- PyObject *oldtype, *oldvalue, *oldtraceback;
PyThreadState *tstate = _PyThreadState_GET();
- oldtype = tstate->exc_info->exc_type;
- oldvalue = tstate->exc_info->exc_value;
- oldtraceback = tstate->exc_info->exc_traceback;
-
+ PyObject *oldvalue = tstate->exc_info->exc_value;
- tstate->exc_info->exc_type = get_exc_type(value);
- Py_XINCREF(tstate->exc_info->exc_type);
tstate->exc_info->exc_value = value;
- tstate->exc_info->exc_traceback = get_exc_traceback(value);
- Py_XINCREF(tstate->exc_info->exc_traceback);
/* These args are no longer used, but we still need to steal a ref */
Py_XDECREF(type);
Py_XDECREF(traceback);
- Py_XDECREF(oldtype);
Py_XDECREF(oldvalue);
- Py_XDECREF(oldtraceback);
}
@@ -629,9 +616,6 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info)
exc_info_given = 1;
}
- assert( (exc_info->exc_type == NULL || exc_info->exc_type == Py_None) ==
- (exc_info->exc_value == NULL || exc_info->exc_value == Py_None) );
-
if (exc_info->exc_value == NULL || exc_info->exc_value == Py_None) {
return;
}
diff --git a/Python/pystate.c b/Python/pystate.c
index 463b248f22336..0301ce676950b 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -1028,9 +1028,7 @@ PyThreadState_Clear(PyThreadState *tstate)
Py_CLEAR(tstate->curexc_value);
Py_CLEAR(tstate->curexc_traceback);
- Py_CLEAR(tstate->exc_state.exc_type);
Py_CLEAR(tstate->exc_state.exc_value);
- Py_CLEAR(tstate->exc_state.exc_traceback);
/* The stack of exception states should contain just this thread. */
if (verbose && tstate->exc_info != &tstate->exc_state) {
1
0
https://github.com/python/cpython/commit/62a0a2a25dbe3ba6f2973a37a3022d982f…
commit: 62a0a2a25dbe3ba6f2973a37a3022d982fdc163c
branch: main
author: Julien Palard <julien(a)palard.fr>
committer: JulienPalard <julien(a)palard.fr>
date: 2021-12-17T13:55:03+01:00
summary:
Doc: some rst linting. (GH-30149)
files:
M Doc/c-api/apiabiversion.rst
M Doc/library/types.rst
M Doc/whatsnew/3.6.rst
diff --git a/Doc/c-api/apiabiversion.rst b/Doc/c-api/apiabiversion.rst
index 53a42e7f28ef1..85b6e2f373877 100644
--- a/Doc/c-api/apiabiversion.rst
+++ b/Doc/c-api/apiabiversion.rst
@@ -63,7 +63,7 @@ See :ref:`stable` for a discussion of API and ABI stability across versions.
.. c:var:: const unsigned long Py_Version
The Python runtime version number encoded in a single constant integer, with
- the same format as the c:macro:`PY_VERSION_HEX` macro.
+ the same format as the :c:macro:`PY_VERSION_HEX` macro.
This contains the Python version used at run time.
.. versionadded:: 3.11
diff --git a/Doc/library/types.rst b/Doc/library/types.rst
index 5cd42f1fc2928..e0e77dfbfe7ed 100644
--- a/Doc/library/types.rst
+++ b/Doc/library/types.rst
@@ -239,7 +239,7 @@ Standard names are defined for the following types:
The :term:`loader` which loaded the module. Defaults to ``None``.
This attribute is to match :attr:`importlib.machinery.ModuleSpec.loader`
- as stored in the attr:`__spec__` object.
+ as stored in the :attr:`__spec__` object.
.. note::
A future version of Python may stop setting this attribute by default.
@@ -264,7 +264,7 @@ Standard names are defined for the following types:
:attr:`__name__` if the module is a package itself). Defaults to ``None``.
This attribute is to match :attr:`importlib.machinery.ModuleSpec.parent`
- as stored in the attr:`__spec__` object.
+ as stored in the :attr:`__spec__` object.
.. note::
A future version of Python may stop setting this attribute by default.
diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst
index d7884ea30d7d2..a56d7a592305f 100644
--- a/Doc/whatsnew/3.6.rst
+++ b/Doc/whatsnew/3.6.rst
@@ -1422,7 +1422,7 @@ The socket module now supports the address family
Victor Stinner.)
New Linux constants ``TCP_USER_TIMEOUT`` and ``TCP_CONGESTION`` were added.
-(Contributed by Omar Sandoval, issue:`26273`).
+(Contributed by Omar Sandoval, :issue:`26273`).
socketserver
1
0
bpo-45755: [typing] Reveal class attributes of generic in generic aliases in `dir()` (GH-29962)
by miss-islington Dec. 17, 2021
by miss-islington Dec. 17, 2021
Dec. 17, 2021
https://github.com/python/cpython/commit/87539cc716fab47cd4f501f2441c4ab8e8…
commit: 87539cc716fab47cd4f501f2441c4ab8e80bce6f
branch: 3.10
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: miss-islington <31488909+miss-islington(a)users.noreply.github.com>
date: 2021-12-17T03:33:07-08:00
summary:
bpo-45755: [typing] Reveal class attributes of generic in generic aliases in `dir()` (GH-29962)
(cherry picked from commit d6e13747161d7b634b47d2d3d212ed3be4a21fab)
Co-authored-by: Ken Jin <28750310+Fidget-Spinner(a)users.noreply.github.com>
files:
A Misc/NEWS.d/next/Library/2021-12-07-21-55-22.bpo-45755.bRqKGa.rst
M Lib/test/test_typing.py
M Lib/typing.py
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index fdec29ea58773..82b6f8c1c6406 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -4994,6 +4994,17 @@ def test_special_attrs2(self):
loaded = pickle.loads(s)
self.assertIs(SpecialAttrsP, loaded)
+ def test_genericalias_dir(self):
+ class Foo(Generic[T]):
+ def bar(self):
+ pass
+ baz = 3
+ # The class attributes of the original class should be visible even
+ # in dir() of the GenericAlias. See bpo-45755.
+ self.assertIn('bar', dir(Foo[int]))
+ self.assertIn('baz', dir(Foo[int]))
+
+
class AllTests(BaseTestCase):
"""Tests for __all__."""
diff --git a/Lib/typing.py b/Lib/typing.py
index b743d400c0e5f..25225470afbac 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -983,6 +983,9 @@ def __subclasscheck__(self, cls):
raise TypeError("Subscripted generics cannot be used with"
" class and instance checks")
+ def __dir__(self):
+ return list(set(super().__dir__()
+ + [attr for attr in dir(self.__origin__) if not _is_dunder(attr)]))
# Special typing constructs Union, Optional, Generic, Callable and Tuple
# use three special attributes for internal bookkeeping of generic types:
diff --git a/Misc/NEWS.d/next/Library/2021-12-07-21-55-22.bpo-45755.bRqKGa.rst b/Misc/NEWS.d/next/Library/2021-12-07-21-55-22.bpo-45755.bRqKGa.rst
new file mode 100644
index 0000000000000..e5201b0dfde2d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-12-07-21-55-22.bpo-45755.bRqKGa.rst
@@ -0,0 +1,3 @@
+:mod:`typing` generic aliases now reveal the class attributes of the
+original generic class when passed to ``dir()``. This was the behavior up to
+Python 3.6, but was changed in 3.7-3.9.
1
0
Dec. 17, 2021
https://github.com/python/cpython/commit/72225b5bdf5d2c70307dbad0d3a1caa39c…
commit: 72225b5bdf5d2c70307dbad0d3a1caa39c95a22a
branch: 3.9
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: miss-islington <31488909+miss-islington(a)users.noreply.github.com>
date: 2021-12-17T01:35:58-08:00
summary:
bpo-46111: Fix unittest tests in optimized mode (GH-30163)
(cherry picked from commit 95a922b3bb3af247ec141d73fcdfbf68bb1d32a5)
Co-authored-by: Serhiy Storchaka <storchaka(a)gmail.com>
files:
M Lib/unittest/test/test_case.py
M Lib/unittest/test/test_program.py
M Lib/unittest/test/testmock/testpatch.py
diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py
index 65dc0c65d5566..0ce23dd1a686f 100644
--- a/Lib/unittest/test/test_case.py
+++ b/Lib/unittest/test/test_case.py
@@ -611,6 +611,8 @@ def testShortDescriptionWithMultiLineDocstring(self):
'Tests shortDescription() for a method with a longer '
'docstring.')
+ @unittest.skipIf(sys.flags.optimize >= 2,
+ "Docstrings are omitted with -O2 and above")
def testShortDescriptionWhitespaceTrimming(self):
"""
Tests shortDescription() whitespace is trimmed, so that the first
diff --git a/Lib/unittest/test/test_program.py b/Lib/unittest/test/test_program.py
index 939af81b3b4cd..4746d71e0b603 100644
--- a/Lib/unittest/test/test_program.py
+++ b/Lib/unittest/test/test_program.py
@@ -58,9 +58,9 @@ def removeTest():
class FooBar(unittest.TestCase):
def testPass(self):
- assert True
+ pass
def testFail(self):
- assert False
+ raise AssertionError
class FooBarLoader(unittest.TestLoader):
"""Test loader that returns a suite containing FooBar."""
diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py
index d8c1515f8346c..233a5afffaed4 100644
--- a/Lib/unittest/test/testmock/testpatch.py
+++ b/Lib/unittest/test/testmock/testpatch.py
@@ -1875,9 +1875,10 @@ def foo(x=0):
self.assertEqual(foo(), 1)
self.assertEqual(foo(), 0)
+ orig_doc = foo.__doc__
with patch.object(foo, '__doc__', "FUN"):
self.assertEqual(foo.__doc__, "FUN")
- self.assertEqual(foo.__doc__, "TEST")
+ self.assertEqual(foo.__doc__, orig_doc)
with patch.object(foo, '__module__', "testpatch2"):
self.assertEqual(foo.__module__, "testpatch2")
1
0
Dec. 17, 2021
https://github.com/python/cpython/commit/9fe8fb74a1e21ab881c70111813266d67b…
commit: 9fe8fb74a1e21ab881c70111813266d67bfda016
branch: 3.10
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: miss-islington <31488909+miss-islington(a)users.noreply.github.com>
date: 2021-12-17T01:29:54-08:00
summary:
bpo-46111: Fix unittest tests in optimized mode (GH-30163)
(cherry picked from commit 95a922b3bb3af247ec141d73fcdfbf68bb1d32a5)
Co-authored-by: Serhiy Storchaka <storchaka(a)gmail.com>
files:
M Lib/unittest/test/test_case.py
M Lib/unittest/test/test_program.py
M Lib/unittest/test/testmock/testpatch.py
diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py
index 442651e1e4884..9b3a598ba6c85 100644
--- a/Lib/unittest/test/test_case.py
+++ b/Lib/unittest/test/test_case.py
@@ -611,6 +611,8 @@ def testShortDescriptionWithMultiLineDocstring(self):
'Tests shortDescription() for a method with a longer '
'docstring.')
+ @unittest.skipIf(sys.flags.optimize >= 2,
+ "Docstrings are omitted with -O2 and above")
def testShortDescriptionWhitespaceTrimming(self):
"""
Tests shortDescription() whitespace is trimmed, so that the first
diff --git a/Lib/unittest/test/test_program.py b/Lib/unittest/test/test_program.py
index 939af81b3b4cd..4746d71e0b603 100644
--- a/Lib/unittest/test/test_program.py
+++ b/Lib/unittest/test/test_program.py
@@ -58,9 +58,9 @@ def removeTest():
class FooBar(unittest.TestCase):
def testPass(self):
- assert True
+ pass
def testFail(self):
- assert False
+ raise AssertionError
class FooBarLoader(unittest.TestLoader):
"""Test loader that returns a suite containing FooBar."""
diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py
index d8c1515f8346c..233a5afffaed4 100644
--- a/Lib/unittest/test/testmock/testpatch.py
+++ b/Lib/unittest/test/testmock/testpatch.py
@@ -1875,9 +1875,10 @@ def foo(x=0):
self.assertEqual(foo(), 1)
self.assertEqual(foo(), 0)
+ orig_doc = foo.__doc__
with patch.object(foo, '__doc__', "FUN"):
self.assertEqual(foo.__doc__, "FUN")
- self.assertEqual(foo.__doc__, "TEST")
+ self.assertEqual(foo.__doc__, orig_doc)
with patch.object(foo, '__module__', "testpatch2"):
self.assertEqual(foo.__module__, "testpatch2")
1
0
Dec. 17, 2021
https://github.com/python/cpython/commit/95a922b3bb3af247ec141d73fcdfbf68bb…
commit: 95a922b3bb3af247ec141d73fcdfbf68bb1d32a5
branch: main
author: Serhiy Storchaka <storchaka(a)gmail.com>
committer: serhiy-storchaka <storchaka(a)gmail.com>
date: 2021-12-17T11:10:55+02:00
summary:
bpo-46111: Fix unittest tests in optimized mode (GH-30163)
files:
M Lib/unittest/test/test_case.py
M Lib/unittest/test/test_program.py
M Lib/unittest/test/testmock/testpatch.py
diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py
index ee4c0b354f72b..067ec8d458679 100644
--- a/Lib/unittest/test/test_case.py
+++ b/Lib/unittest/test/test_case.py
@@ -631,6 +631,8 @@ def testShortDescriptionWithMultiLineDocstring(self):
'Tests shortDescription() for a method with a longer '
'docstring.')
+ @unittest.skipIf(sys.flags.optimize >= 2,
+ "Docstrings are omitted with -O2 and above")
def testShortDescriptionWhitespaceTrimming(self):
"""
Tests shortDescription() whitespace is trimmed, so that the first
diff --git a/Lib/unittest/test/test_program.py b/Lib/unittest/test/test_program.py
index cc02b227e1da8..2bf7dd72ed21c 100644
--- a/Lib/unittest/test/test_program.py
+++ b/Lib/unittest/test/test_program.py
@@ -58,9 +58,9 @@ def removeTest():
class FooBar(unittest.TestCase):
def testPass(self):
- assert True
+ pass
def testFail(self):
- assert False
+ raise AssertionError
class FooBarLoader(unittest.TestLoader):
"""Test loader that returns a suite containing FooBar."""
diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py
index d8c1515f8346c..233a5afffaed4 100644
--- a/Lib/unittest/test/testmock/testpatch.py
+++ b/Lib/unittest/test/testmock/testpatch.py
@@ -1875,9 +1875,10 @@ def foo(x=0):
self.assertEqual(foo(), 1)
self.assertEqual(foo(), 0)
+ orig_doc = foo.__doc__
with patch.object(foo, '__doc__', "FUN"):
self.assertEqual(foo.__doc__, "FUN")
- self.assertEqual(foo.__doc__, "TEST")
+ self.assertEqual(foo.__doc__, orig_doc)
with patch.object(foo, '__module__', "testpatch2"):
self.assertEqual(foo.__module__, "testpatch2")
1
0
Dec. 17, 2021
https://github.com/python/cpython/commit/cbb4d4a642f7f58f0dc1a89a4af6fb4bc8…
commit: cbb4d4a642f7f58f0dc1a89a4af6fb4bc80db41b
branch: 3.10
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: gpshead <greg(a)krypto.org>
date: 2021-12-16T21:51:11-08:00
summary:
Fix a typo in the message from make_ssl_certs. (GH-30152) (GH-30161)
The file is utils.py not util.py.
Automerge-Triggered-By: GH:gpshead
(cherry picked from commit 69ef1b59983065ddb0b712dac3b04107c5059735)
Co-authored-by: Yilei "Dolee" Yang <yileiyang9(a)gmail.com>
files:
M Lib/test/make_ssl_certs.py
diff --git a/Lib/test/make_ssl_certs.py b/Lib/test/make_ssl_certs.py
index c62896f861dab..94a35a64ab1ab 100644
--- a/Lib/test/make_ssl_certs.py
+++ b/Lib/test/make_ssl_certs.py
@@ -307,6 +307,6 @@ def print_cert(path):
f.write(cert)
unmake_ca()
- print("update Lib/test/test_ssl.py and Lib/test/test_asyncio/util.py")
+ print("update Lib/test/test_ssl.py and Lib/test/test_asyncio/utils.py")
print_cert('keycert.pem')
print_cert('keycert3.pem')
1
0
Dec. 17, 2021
https://github.com/python/cpython/commit/212014d8c4eca546104a719938899a51bd…
commit: 212014d8c4eca546104a719938899a51bd497487
branch: 3.9
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: miss-islington <31488909+miss-islington(a)users.noreply.github.com>
date: 2021-12-16T21:49:37-08:00
summary:
Fix a typo in the message from make_ssl_certs. (GH-30152)
The file is utils.py not util.py.
Automerge-Triggered-By: GH:gpshead
(cherry picked from commit 69ef1b59983065ddb0b712dac3b04107c5059735)
Co-authored-by: Yilei "Dolee" Yang <yileiyang9(a)gmail.com>
files:
M Lib/test/make_ssl_certs.py
diff --git a/Lib/test/make_ssl_certs.py b/Lib/test/make_ssl_certs.py
index c62896f861dab..94a35a64ab1ab 100644
--- a/Lib/test/make_ssl_certs.py
+++ b/Lib/test/make_ssl_certs.py
@@ -307,6 +307,6 @@ def print_cert(path):
f.write(cert)
unmake_ca()
- print("update Lib/test/test_ssl.py and Lib/test/test_asyncio/util.py")
+ print("update Lib/test/test_ssl.py and Lib/test/test_asyncio/utils.py")
print_cert('keycert.pem')
print_cert('keycert3.pem')
1
0