Skip to content

Commit 8899015

Browse files
committed
gh--101799: implement PREP_RERAISE_STAR as an intrinsic function
1 parent e1aaded commit 8899015

12 files changed

+99
-69
lines changed

Doc/library/dis.rst

+12-10
Original file line numberDiff line numberDiff line change
@@ -768,16 +768,6 @@ iterations of the loop.
768768

769769
.. versionadded:: 3.11
770770

771-
.. opcode:: PREP_RERAISE_STAR
772-
773-
Combines the raised and reraised exceptions list from ``STACK[-1]``, into an
774-
exception group to propagate from a try-except* block. Uses the original exception
775-
group from ``STACK[-2]`` to reconstruct the structure of reraised exceptions. Pops
776-
two items from the stack and pushes the exception to reraise or ``None``
777-
if there isn't one.
778-
779-
.. versionadded:: 3.11
780-
781771
.. opcode:: WITH_EXCEPT_START
782772

783773
Calls the function in position 4 on the stack with arguments (type, val, tb)
@@ -1529,6 +1519,18 @@ iterations of the loop.
15291519

15301520
.. versionadded:: 3.12
15311521

1522+
.. opcode:: CALL_INTRINSIC_2
1523+
1524+
Calls an intrinsic function with two arguments. Passes ``STACK[-2]``, ``STACK[-1]`` as the
1525+
arguments and sets ``STACK[-1]`` to the result. Used to implement functionality that is necessary but not performance critical.
1526+
1527+
The operand determines which intrinsic function is called:
1528+
1529+
* ``0`` Not valid
1530+
* ``1`` Calculates the :exc:`ExceptionGroup` to raise from a ``try-except*``.
1531+
1532+
.. versionadded:: 3.12
1533+
15321534

15331535
**Pseudo-instructions**
15341536

Include/internal/pycore_intrinsics.h

+13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11

2+
/* Unary Functions: */
3+
24
#define INTRINSIC_PRINT 1
35
#define INTRINSIC_IMPORT_STAR 2
46
#define INTRINSIC_STOPITERATION_ERROR 3
@@ -8,6 +10,17 @@
810

911
#define MAX_INTRINSIC_1 6
1012

13+
14+
/* Binary Functions: */
15+
16+
#define INTRINSIC_PREP_RERAISE_STAR 1
17+
18+
#define MAX_INTRINSIC_2 1
19+
20+
1121
typedef PyObject *(*instrinsic_func1)(PyThreadState* tstate, PyObject *value);
22+
typedef PyObject *(*instrinsic_func2)(PyThreadState* tstate, PyObject *value1, PyObject *value2);
1223

1324
extern instrinsic_func1 _PyIntrinsics_UnaryFunctions[];
25+
extern instrinsic_func2 _PyIntrinsics_BinaryFunctions[];
26+

Include/internal/pycore_opcode.h

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/opcode.h

+9-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/importlib/_bootstrap_external.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ def _write_atomic(path, data, mode=0o666):
432432
# Python 3.12a5 3516 (Add COMPARE_AND_BRANCH instruction)
433433
# Python 3.12a5 3517 (Change YIELD_VALUE oparg to exception block depth)
434434
# Python 3.12a5 3518 (Add RETURN_CONST instruction)
435+
# Python 3.12a5 3519 (Remove PREP_RERAISE_STAR, add CALL_INTRINSIC2)
435436

436437
# Python 3.13 will start with 3550
437438

@@ -444,7 +445,7 @@ def _write_atomic(path, data, mode=0o666):
444445
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
445446
# in PC/launcher.c must also be updated.
446447

447-
MAGIC_NUMBER = (3518).to_bytes(2, 'little') + b'\r\n'
448+
MAGIC_NUMBER = (3519).to_bytes(2, 'little') + b'\r\n'
448449

449450
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
450451

Lib/opcode.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ def pseudo_op(name, op, real_ops):
127127

128128
def_op('SETUP_ANNOTATIONS', 85)
129129

130-
def_op('PREP_RERAISE_STAR', 88)
131130
def_op('POP_EXCEPT', 89)
132131

133132
HAVE_ARGUMENT = 90 # real opcodes from here have an argument:
@@ -224,6 +223,7 @@ def pseudo_op(name, op, real_ops):
224223
def_op('KW_NAMES', 172)
225224
hasconst.append(172)
226225
def_op('CALL_INTRINSIC_1', 173)
226+
def_op('CALL_INTRINSIC_2', 174)
227227

228228
hasarg.extend([op for op in opmap.values() if op >= HAVE_ARGUMENT])
229229

Python/bytecodes.c

+9-11
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,14 @@ dummy_func(
501501
inst(CALL_INTRINSIC_1, (value -- res)) {
502502
assert(oparg <= MAX_INTRINSIC_1);
503503
res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value);
504-
Py_DECREF(value);
504+
DECREF_INPUTS();
505+
ERROR_IF(res == NULL, error);
506+
}
507+
508+
inst(CALL_INTRINSIC_2, (value2, value1 -- res)) {
509+
assert(oparg <= MAX_INTRINSIC_2);
510+
res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1);
511+
DECREF_INPUTS();
505512
ERROR_IF(res == NULL, error);
506513
}
507514

@@ -773,15 +780,6 @@ dummy_func(
773780
goto exception_unwind;
774781
}
775782

776-
inst(PREP_RERAISE_STAR, (orig, excs -- val)) {
777-
assert(PyList_Check(excs));
778-
779-
val = _PyExc_PrepReraiseStar(orig, excs);
780-
DECREF_INPUTS();
781-
782-
ERROR_IF(val == NULL, error);
783-
}
784-
785783
inst(END_ASYNC_FOR, (awaitable, exc -- )) {
786784
assert(exc && PyExceptionInstance_Check(exc));
787785
if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) {
@@ -2367,7 +2365,7 @@ dummy_func(
23672365
}
23682366

23692367
// Cache layout: counter/1, func_version/2, min_args/1
2370-
// Neither CALL_INTRINSIC_1 nor CALL_FUNCTION_EX are members!
2368+
// Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members!
23712369
family(call, INLINE_CACHE_ENTRIES_CALL) = {
23722370
CALL,
23732371
CALL_BOUND_METHOD_EXACT_ARGS,

Python/compile.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -3429,7 +3429,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
34293429
34303430
[orig, res, rest] Ln+1: LIST_APPEND 1 ) add unhandled exc to res (could be None)
34313431
3432-
[orig, res] PREP_RERAISE_STAR
3432+
[orig, res] CALL_INTRINSIC_2 PREP_RERAISE_STAR
34333433
[exc] COPY 1
34343434
[exc, exc] POP_JUMP_IF_NOT_NONE RER
34353435
[exc] POP_TOP
@@ -3578,7 +3578,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
35783578
NEW_JUMP_TARGET_LABEL(c, reraise);
35793579

35803580
USE_LABEL(c, reraise_star);
3581-
ADDOP(c, NO_LOCATION, PREP_RERAISE_STAR);
3581+
ADDOP_I(c, NO_LOCATION, CALL_INTRINSIC_2, INTRINSIC_PREP_RERAISE_STAR);
35823582
ADDOP_I(c, NO_LOCATION, COPY, 1);
35833583
ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_NOT_NONE, reraise);
35843584

Python/generated_cases.c.h

+14-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/intrinsics.c

+18
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "pycore_pyerrors.h"
1010

1111

12+
/******** Unary functions ********/
1213

1314
static PyObject *
1415
no_intrinsic(PyThreadState* tstate, PyObject *unused)
@@ -208,3 +209,20 @@ _PyIntrinsics_UnaryFunctions[] = {
208209
[INTRINSIC_UNARY_POSITIVE] = unary_pos,
209210
[INTRINSIC_LIST_TO_TUPLE] = list_to_tuple,
210211
};
212+
213+
214+
/******** Binary functions ********/
215+
216+
217+
static PyObject *
218+
prep_reraise_star(PyThreadState* unused, PyObject *orig, PyObject *excs)
219+
{
220+
assert(PyList_Check(excs));
221+
return _PyExc_PrepReraiseStar(orig, excs);
222+
}
223+
224+
instrinsic_func2
225+
_PyIntrinsics_BinaryFunctions[] = {
226+
[INTRINSIC_PREP_RERAISE_STAR] = prep_reraise_star,
227+
};
228+

0 commit comments

Comments
 (0)