gh-128563: A new tail-calling interpreter (GH-128718)

Co-authored-by: Garrett Gu <garrettgu777@gmail.com>
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
This commit is contained in:
Ken Jin 2025-02-06 23:21:57 +08:00 committed by GitHub
parent 555dc50c81
commit cb640b659e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 3883 additions and 623 deletions

113
.github/workflows/tail-call.yml vendored Normal file
View file

@ -0,0 +1,113 @@
name: Tail calling interpreter
on:
pull_request:
paths:
- 'Python/bytecodes.c'
- 'Python/ceval.c'
- 'Python/ceval_macros.h'
push:
paths:
- 'Python/bytecodes.c'
- 'Python/ceval.c'
- 'Python/ceval_macros.h'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
FORCE_COLOR: 1
jobs:
tail-call:
name: ${{ matrix.target }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
target:
# Un-comment as we add support for more platforms for tail-calling interpreters.
# - i686-pc-windows-msvc/msvc
# - x86_64-pc-windows-msvc/msvc
# - aarch64-pc-windows-msvc/msvc
- x86_64-apple-darwin/clang
- aarch64-apple-darwin/clang
- x86_64-unknown-linux-gnu/gcc
- aarch64-unknown-linux-gnu/gcc
llvm:
- 19
include:
# - target: i686-pc-windows-msvc/msvc
# architecture: Win32
# runner: windows-latest
# - target: x86_64-pc-windows-msvc/msvc
# architecture: x64
# runner: windows-latest
# - target: aarch64-pc-windows-msvc/msvc
# architecture: ARM64
# runner: windows-latest
- target: x86_64-apple-darwin/clang
architecture: x86_64
runner: macos-13
- target: aarch64-apple-darwin/clang
architecture: aarch64
runner: macos-14
- target: x86_64-unknown-linux-gnu/gcc
architecture: x86_64
runner: ubuntu-24.04
- target: aarch64-unknown-linux-gnu/gcc
architecture: aarch64
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Native Windows (debug)
if: runner.os == 'Windows' && matrix.architecture != 'ARM64'
run: |
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
./PCbuild/build.bat --tail-call-interp -d -p ${{ matrix.architecture }}
./PCbuild/rt.bat -d -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
# No tests (yet):
- name: Emulated Windows (release)
if: runner.os == 'Windows' && matrix.architecture == 'ARM64'
run: |
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
./PCbuild/build.bat --tail-call-interp -p ${{ matrix.architecture }}
# The `find` line is required as a result of https://github.com/actions/runner-images/issues/9966.
# This is a bug in the macOS runner image where the pre-installed Python is installed in the same
# directory as the Homebrew Python, which causes the build to fail for macos-13. This line removes
# the symlink to the pre-installed Python so that the Homebrew Python is used instead.
- name: Native macOS (debug)
if: runner.os == 'macOS'
run: |
brew update
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
brew install llvm@${{ matrix.llvm }}
export SDKROOT="$(xcrun --show-sdk-path)"
export PATH="/opt/homebrew/opt/llvm/bin:$PATH"
export PATH="/usr/local/opt/llvm/bin:$PATH"
CC=clang-19 ./configure --with-tail-call-interp --with-pydebug
make all --jobs 4
./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
- name: Native Linux (release)
if: runner.os == 'Linux'
run: |
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
CC=clang-19 ./configure --with-tail-call-interp
make all --jobs 4
./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3

View file

@ -304,6 +304,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -322,6 +327,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -343,6 +353,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -365,6 +380,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -388,6 +408,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -414,6 +439,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -442,6 +472,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP1) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP1;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP1);
@ -453,12 +488,23 @@ class TestGeneratedCases(unittest.TestCase):
}
TARGET(OP3) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP3;
(void)(opcode);
_Py_CODEUNIT* const this_instr = next_instr;
(void)this_instr;
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP3);
static_assert(INLINE_CACHE_ENTRIES_OP1 == 0, "incorrect cache size");
_PyStackRef res;
DEOPT_IF(xxx, OP1);
if (xxx) {
UPDATE_MISS_STATS(OP1);
assert(_PyOpcode_Deopt[opcode] == (OP1));
JUMP_TO_PREDICTED(OP1);
}
res = Py_None;
stack_pointer[-1] = res;
DISPATCH();
@ -481,6 +527,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(A) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = A;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(A);
@ -498,6 +549,11 @@ class TestGeneratedCases(unittest.TestCase):
}
TARGET(B) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = B;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(B);
@ -535,11 +591,16 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
if (cond) {
goto label;
JUMP_TO_LABEL(label);
}
DISPATCH();
}
@ -554,11 +615,16 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
if (cond) {
goto label;
JUMP_TO_LABEL(label);
}
// Comment is ok
DISPATCH();
@ -577,6 +643,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -587,7 +658,7 @@ class TestGeneratedCases(unittest.TestCase):
left = stack_pointer[-2];
SPAM(left, right);
if (cond) {
goto pop_2_label;
JUMP_TO_LABEL(pop_2_label);
}
res = 0;
stack_pointer[-2] = res;
@ -608,6 +679,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -618,7 +694,7 @@ class TestGeneratedCases(unittest.TestCase):
left = stack_pointer[-2];
res = SPAM(left, right);
if (cond) {
goto pop_2_label;
JUMP_TO_LABEL(pop_2_label);
}
stack_pointer[-2] = res;
stack_pointer += -1;
@ -635,8 +711,14 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
_Py_CODEUNIT* const this_instr = next_instr;
(void)this_instr;
frame->instr_ptr = next_instr;
next_instr += 4;
INSTRUCTION_STATS(OP);
uint16_t counter = read_u16(&this_instr[1].cache);
@ -661,13 +743,18 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
goto somewhere;
JUMP_TO_LABEL(somewhere);
}
somewhere:
LABEL(somewhere)
{
}
@ -692,6 +779,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 6;
INSTRUCTION_STATS(OP);
@ -729,8 +821,14 @@ class TestGeneratedCases(unittest.TestCase):
}
TARGET(OP1) {
_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP1;
(void)(opcode);
_Py_CODEUNIT* const this_instr = next_instr;
(void)this_instr;
frame->instr_ptr = next_instr;
next_instr += 2;
INSTRUCTION_STATS(OP1);
_PyStackRef left;
@ -746,6 +844,11 @@ class TestGeneratedCases(unittest.TestCase):
}
TARGET(OP3) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP3;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 6;
INSTRUCTION_STATS(OP3);
@ -777,6 +880,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 4;
INSTRUCTION_STATS(OP);
@ -799,6 +907,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP1) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP1;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP1);
@ -818,6 +931,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP1) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP1;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP1);
@ -840,6 +958,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP1) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP1;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP1);
@ -847,6 +970,11 @@ class TestGeneratedCases(unittest.TestCase):
}
TARGET(OP2) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP2;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP2);
@ -864,6 +992,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -887,6 +1020,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -915,6 +1053,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -939,13 +1082,18 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
if (oparg == 0) {
stack_pointer += -1 - oparg;
assert(WITHIN_STACK_BOUNDS());
goto somewhere;
JUMP_TO_LABEL(somewhere);
}
stack_pointer += -1 - oparg;
assert(WITHIN_STACK_BOUNDS());
@ -965,6 +1113,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -1006,6 +1159,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(M) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = M;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(M);
@ -1050,6 +1208,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(M) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = M;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(M);
@ -1083,6 +1246,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -1104,6 +1272,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(M) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = M;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(M);
@ -1121,6 +1294,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -1139,6 +1317,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(M) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = M;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(M);
@ -1175,6 +1358,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -1197,6 +1385,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -1235,6 +1428,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(INST) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = INST;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(INST);
@ -1261,6 +1459,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(TEST) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = TEST;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(TEST);
@ -1301,6 +1504,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(TEST) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = TEST;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(TEST);
@ -1340,6 +1548,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(TEST) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = TEST;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(TEST);
@ -1388,6 +1601,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(TEST) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = TEST;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(TEST);
@ -1409,7 +1627,7 @@ class TestGeneratedCases(unittest.TestCase):
{
// Mark j and k as used
if (cond) {
goto pop_2_error;
JUMP_TO_LABEL(pop_2_error);
}
}
stack_pointer += -2;
@ -1436,6 +1654,11 @@ class TestGeneratedCases(unittest.TestCase):
output = """
TARGET(TEST) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = TEST;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(TEST);
@ -1453,7 +1676,7 @@ class TestGeneratedCases(unittest.TestCase):
stack_pointer[1] = b;
stack_pointer += 2;
assert(WITHIN_STACK_BOUNDS());
goto error;
JUMP_TO_LABEL(error);
}
}
stack_pointer[0] = a;
@ -1477,17 +1700,27 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP1) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP1;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP1);
goto here;
JUMP_TO_LABEL(here);
}
TARGET(OP2) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP2;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP2);
goto there;
JUMP_TO_LABEL(there);
}
"""
self.run_cases_test(input, output)
@ -1541,6 +1774,11 @@ class TestGeneratedCases(unittest.TestCase):
output = """
TARGET(BALANCED) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = BALANCED;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(BALANCED);
@ -1561,6 +1799,11 @@ class TestGeneratedCases(unittest.TestCase):
output = """
TARGET(BALANCED) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = BALANCED;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(BALANCED);
@ -1582,6 +1825,13 @@ class TestGeneratedCases(unittest.TestCase):
output = """
TARGET(BALANCED) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = BALANCED;
(void)(opcode);
_Py_CODEUNIT* const this_instr = next_instr;
(void)this_instr;
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(BALANCED);
@ -1602,6 +1852,11 @@ class TestGeneratedCases(unittest.TestCase):
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -1637,6 +1892,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -1671,6 +1931,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -1702,6 +1967,11 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
TARGET(OP) {
#if defined(Py_TAIL_CALL_INTERP)
int opcode;
#endif
opcode = OP;
(void)(opcode);
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP);
@ -1793,26 +2063,26 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
other_label:
LABEL(other_label)
{
}
other_label2:
LABEL(other_label2)
{
}
my_label:
LABEL(my_label)
{
// Comment
_PyFrame_SetStackPointer(frame, stack_pointer);
do_thing();
stack_pointer = _PyFrame_GetStackPointer(frame);
if (complex) {
goto other_label;
JUMP_TO_LABEL(other_label);
}
goto other_label2;
JUMP_TO_LABEL(other_label2);
}
"""
self.run_cases_test(input, output)
@ -1831,17 +2101,17 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
one:
LABEL(one)
{
/* STACK SPILLED */
stack_pointer = _PyFrame_GetStackPointer(frame);
goto two;
JUMP_TO_LABEL(two);
}
two:
LABEL(two)
{
_PyFrame_SetStackPointer(frame, stack_pointer);
goto one;
JUMP_TO_LABEL(one);
}
"""
self.run_cases_test(input, output)
@ -1887,20 +2157,26 @@ class TestGeneratedCases(unittest.TestCase):
"""
output = """
my_label_1:
LABEL(my_label_1)
{
// Comment
_PyFrame_SetStackPointer(frame, stack_pointer);
do_thing1();
goto my_label_2;
stack_pointer = _PyFrame_GetStackPointer(frame);
JUMP_TO_LABEL(my_label_2);
}
my_label_2:
LABEL(my_label_2)
{
// Comment
_PyFrame_SetStackPointer(frame, stack_pointer);
do_thing2();
goto my_label_1;
stack_pointer = _PyFrame_GetStackPointer(frame);
JUMP_TO_LABEL(my_label_1);
}
"""
self.run_cases_test(input, output)
class TestGeneratedAbstractCases(unittest.TestCase):
def setUp(self) -> None:

View file

@ -0,0 +1 @@
A new type of interpreter has been added to CPython. This interpreter uses tail calls for its instruction handlers. Preliminary benchmark results suggest 7-11% geometric mean faster on pyperformance (depending on platform), and up to 30% faster on Python-intensive workloads. This interpreter currently only works on newer compilers, such as ``clang-19``. Other compilers will continue using the old interpreter. Patch by Ken Jin, with ideas on how to implement this in CPython by Mark Shannon, Garret Gu, Haoran Xu, and Josh Haberman.

View file

@ -1387,7 +1387,9 @@ dummy_func(
tier1 inst(CLEANUP_THROW, (sub_iter_st, last_sent_val_st, exc_value_st -- none, value)) {
PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st);
#ifndef Py_TAIL_CALL_INTERP
assert(throwflag);
#endif
assert(exc_value && PyExceptionInstance_Check(exc_value));
int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration);
@ -5305,6 +5307,9 @@ dummy_func(
}
#endif
RELOAD_STACK();
#ifdef Py_TAIL_CALL_INTERP
int opcode;
#endif
DISPATCH();
}
@ -5351,8 +5356,10 @@ dummy_func(
caller loses its exception */
assert(!_PyErr_Occurred(tstate));
#endif
RELOAD_STACK();
#ifdef Py_TAIL_CALL_INTERP
int opcode;
#endif
DISPATCH();
}

View file

@ -768,13 +768,18 @@ _PyObjectArray_Free(PyObject **array, PyObject **scratch)
#define PY_EVAL_C_STACK_UNITS 2
#ifdef Py_TAIL_CALL_INTERP
#include "opcode_targets.h"
#include "generated_cases.c.h"
#endif
PyObject* _Py_HOT_FUNCTION
_PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag)
{
_Py_EnsureTstateNotNULL(tstate);
CALL_STAT_INC(pyeval_calls);
#if USE_COMPUTED_GOTOS
#if USE_COMPUTED_GOTOS && !defined(Py_TAIL_CALL_INTERP)
/* Import the static jump table */
#include "opcode_targets.h"
#endif
@ -782,10 +787,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
#ifdef Py_STATS
int lastopcode = 0;
#endif
#ifndef Py_TAIL_CALL_INTERP
uint8_t opcode; /* Current opcode */
int oparg; /* Current opcode argument, if any */
_PyInterpreterFrame entry_frame;
#endif
_PyInterpreterFrame entry_frame;
if (_Py_EnterRecursiveCallTstate(tstate, "")) {
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
@ -845,7 +851,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
next_instr = frame->instr_ptr;
stack_pointer = _PyFrame_GetStackPointer(frame);
monitor_throw(tstate, frame, next_instr);
#ifdef Py_TAIL_CALL_INTERP
return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0);
#else
goto error;
#endif
}
#if defined(_Py_TIER2) && !defined(_Py_JIT)
@ -854,9 +864,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
const _PyUOpInstruction *next_uop = NULL;
#endif
#ifdef Py_TAIL_CALL_INTERP
return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0);
#else
goto start_frame;
#include "generated_cases.c.h"
# include "generated_cases.c.h"
#endif
#ifdef _Py_TIER2

View file

@ -70,12 +70,41 @@
#define INSTRUCTION_STATS(op) ((void)0)
#endif
#if USE_COMPUTED_GOTOS
#define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, int oparg
#define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, oparg
#ifdef Py_TAIL_CALL_INTERP
// Note: [[clang::musttail]] works for GCC 15, but not __attribute__((musttail)) at the moment.
# define Py_MUSTTAIL [[clang::musttail]]
# define Py_PRESERVE_NONE_CC __attribute__((preserve_none))
Py_PRESERVE_NONE_CC typedef PyObject* (*py_tail_call_funcptr)(TAIL_CALL_PARAMS);
# define TARGET(op) Py_PRESERVE_NONE_CC PyObject *_TAIL_CALL_##op(TAIL_CALL_PARAMS)
# define DISPATCH_GOTO() \
do { \
Py_MUSTTAIL return (INSTRUCTION_TABLE[opcode])(TAIL_CALL_ARGS); \
} while (0)
# define JUMP_TO_LABEL(name) \
do { \
Py_MUSTTAIL return (_TAIL_CALL_##name)(TAIL_CALL_ARGS); \
} while (0)
# define JUMP_TO_PREDICTED(name) \
do { \
Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, oparg); \
} while (0)
# define LABEL(name) TARGET(name)
#elif USE_COMPUTED_GOTOS
# define TARGET(op) TARGET_##op:
# define DISPATCH_GOTO() goto *opcode_targets[opcode]
# define JUMP_TO_LABEL(name) goto name;
# define JUMP_TO_PREDICTED(name) goto PREDICTED_##name;
# define LABEL(name) name:
#else
# define TARGET(op) case op: TARGET_##op:
# define DISPATCH_GOTO() goto dispatch_opcode
# define JUMP_TO_LABEL(name) goto name;
# define JUMP_TO_PREDICTED(name) goto PREDICTED_##name;
# define LABEL(name) name:
#endif
/* PRE_DISPATCH_GOTO() does lltrace if enabled. Normally a no-op */
@ -92,7 +121,7 @@ do { \
int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS()); \
frame->lltrace = lltrace; \
if (lltrace < 0) { \
goto exit_unwind; \
JUMP_TO_LABEL(exit_unwind); \
} \
} while (0)
#else
@ -129,11 +158,11 @@ do { \
assert((NEW_FRAME)->previous == frame); \
frame = tstate->current_frame = (NEW_FRAME); \
CALL_STAT_INC(inlined_py_calls); \
goto start_frame; \
JUMP_TO_LABEL(start_frame); \
} while (0)
// Use this instead of 'goto error' so Tier 2 can go to a different label
#define GOTO_ERROR(LABEL) goto LABEL
#define GOTO_ERROR(LABEL) JUMP_TO_LABEL(LABEL)
/* Tuple access macros */
@ -236,14 +265,6 @@ GETITEM(PyObject *v, Py_ssize_t i) {
#define UPDATE_MISS_STATS(INSTNAME) ((void)0)
#endif
#define DEOPT_IF(COND, INSTNAME) \
if ((COND)) { \
/* This is only a single jump on release builds! */ \
UPDATE_MISS_STATS((INSTNAME)); \
assert(_PyOpcode_Deopt[opcode] == (INSTNAME)); \
goto PREDICTED_##INSTNAME; \
}
// Try to lock an object in the free threading build, if it's not already
// locked. Use with a DEOPT_IF() to deopt if the object is already locked.
@ -328,7 +349,7 @@ do { \
stack_pointer = _PyFrame_GetStackPointer(frame); \
if (next_instr == NULL) { \
next_instr = (dest)+1; \
goto error; \
JUMP_TO_LABEL(error); \
} \
} \
} while (0);

File diff suppressed because it is too large Load diff

505
Python/opcode_targets.h generated
View file

@ -1,3 +1,4 @@
#ifndef Py_TAIL_CALL_INTERP
static void *opcode_targets[256] = {
&&TARGET_CACHE,
&&TARGET_BINARY_SLICE,
@ -256,3 +257,507 @@ static void *opcode_targets[256] = {
&&TARGET_INSTRUMENTED_LINE,
&&TARGET_ENTER_EXECUTOR,
};
#else /* Py_TAIL_CALL_INTERP */
static py_tail_call_funcptr INSTRUCTION_TABLE[256];
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_4_error(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_3_error(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_2_error(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_1_error(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_error(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_exception_unwind(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_exit_unwind(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_start_frame(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_ADD_FLOAT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_ADD_INT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_ADD_UNICODE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_EXTEND(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_INPLACE_ADD_UNICODE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_MULTIPLY_FLOAT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_MULTIPLY_INT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBTRACT_FLOAT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBTRACT_INT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_SLICE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_SUBSCR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_SUBSCR_DICT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_SUBSCR_GETITEM(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_SUBSCR_LIST_INT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_SUBSCR_STR_INT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_SUBSCR_TUPLE_INT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_LIST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_MAP(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_SET(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_SLICE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_STRING(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_TUPLE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CACHE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_ALLOC_AND_ENTER_INIT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BOUND_METHOD_EXACT_ARGS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BOUND_METHOD_GENERAL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BUILTIN_CLASS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BUILTIN_FAST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BUILTIN_FAST_WITH_KEYWORDS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BUILTIN_O(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_FUNCTION_EX(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_INTRINSIC_1(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_INTRINSIC_2(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_ISINSTANCE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_KW(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_KW_BOUND_METHOD(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_KW_NON_PY(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_KW_PY(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_LEN(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_LIST_APPEND(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_METHOD_DESCRIPTOR_NOARGS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_METHOD_DESCRIPTOR_O(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_NON_PY_GENERAL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_PY_EXACT_ARGS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_PY_GENERAL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_STR_1(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_TUPLE_1(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_TYPE_1(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CHECK_EG_MATCH(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CHECK_EXC_MATCH(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CLEANUP_THROW(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COMPARE_OP(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COMPARE_OP_FLOAT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COMPARE_OP_INT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COMPARE_OP_STR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CONTAINS_OP(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CONTAINS_OP_DICT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CONTAINS_OP_SET(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CONVERT_VALUE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COPY(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COPY_FREE_VARS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_ATTR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_DEREF(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_FAST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_GLOBAL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_NAME(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_SUBSCR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DICT_MERGE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DICT_UPDATE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_END_ASYNC_FOR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_END_FOR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_END_SEND(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_ENTER_EXECUTOR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_EXIT_INIT_CHECK(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_EXTENDED_ARG(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FORMAT_SIMPLE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FORMAT_WITH_SPEC(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER_GEN(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER_LIST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER_RANGE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER_TUPLE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_AITER(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ANEXT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_AWAITABLE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ITER(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_LEN(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_YIELD_FROM_ITER(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_IMPORT_FROM(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_IMPORT_NAME(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_CALL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_CALL_FUNCTION_EX(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_CALL_KW(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_END_FOR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_END_SEND(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_FOR_ITER(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_INSTRUCTION(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_JUMP_BACKWARD(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_JUMP_FORWARD(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_LINE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_LOAD_SUPER_ATTR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_NOT_TAKEN(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_ITER(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_FALSE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NONE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NOT_NONE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_TRUE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_RESUME(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_RETURN_VALUE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_YIELD_VALUE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INTERPRETER_EXIT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_IS_OP(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_BACKWARD(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_BACKWARD_JIT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_BACKWARD_NO_INTERRUPT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_BACKWARD_NO_JIT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_FORWARD(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LIST_APPEND(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LIST_EXTEND(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_CLASS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_INSTANCE_VALUE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_METHOD_LAZY_DICT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_METHOD_NO_DICT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_METHOD_WITH_VALUES(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_MODULE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_NO_DICT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_PROPERTY(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_SLOT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_WITH_HINT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_BUILD_CLASS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_COMMON_CONSTANT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_CONST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_CONST_IMMORTAL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_CONST_MORTAL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_DEREF(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FAST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FAST_AND_CLEAR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FAST_CHECK(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FAST_LOAD_FAST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FROM_DICT_OR_DEREF(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FROM_DICT_OR_GLOBALS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_GLOBAL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_GLOBAL_BUILTIN(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_GLOBAL_MODULE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_LOCALS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_NAME(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SMALL_INT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SPECIAL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SUPER_ATTR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SUPER_ATTR_ATTR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SUPER_ATTR_METHOD(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MAKE_CELL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MAKE_FUNCTION(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MAP_ADD(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MATCH_CLASS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MATCH_KEYS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MATCH_MAPPING(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MATCH_SEQUENCE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_NOP(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_NOT_TAKEN(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_EXCEPT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_ITER(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_JUMP_IF_FALSE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_JUMP_IF_NONE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_JUMP_IF_NOT_NONE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_JUMP_IF_TRUE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_TOP(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_PUSH_EXC_INFO(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_PUSH_NULL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RAISE_VARARGS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RERAISE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RESERVED(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RESUME(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RESUME_CHECK(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RETURN_GENERATOR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RETURN_VALUE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SEND(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SEND_GEN(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SETUP_ANNOTATIONS(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SET_ADD(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SET_FUNCTION_ATTRIBUTE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SET_UPDATE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_ATTR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_ATTR_INSTANCE_VALUE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_ATTR_SLOT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_ATTR_WITH_HINT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_DEREF(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_FAST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_FAST_LOAD_FAST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_FAST_STORE_FAST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_GLOBAL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_NAME(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_SLICE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_SUBSCR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_SUBSCR_DICT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_SUBSCR_LIST_INT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SWAP(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_ALWAYS_TRUE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_BOOL(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_INT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_LIST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_NONE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_STR(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNARY_INVERT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNARY_NEGATIVE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNARY_NOT(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_EX(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_SEQUENCE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_SEQUENCE_LIST(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_SEQUENCE_TUPLE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_WITH_EXCEPT_START(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_YIELD_VALUE(TAIL_CALL_PARAMS);
Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNKNOWN_OPCODE(TAIL_CALL_PARAMS) {
int opcode = next_instr->op.code;
_PyErr_Format(tstate, PyExc_SystemError,
"%U:%d: unknown opcode %d",
_PyFrame_GetCode(frame)->co_filename,
PyUnstable_InterpreterFrame_GetLine(frame),
opcode);
JUMP_TO_LABEL(error);
}
static py_tail_call_funcptr INSTRUCTION_TABLE[256] = {
[BINARY_OP] = _TAIL_CALL_BINARY_OP,
[BINARY_OP_ADD_FLOAT] = _TAIL_CALL_BINARY_OP_ADD_FLOAT,
[BINARY_OP_ADD_INT] = _TAIL_CALL_BINARY_OP_ADD_INT,
[BINARY_OP_ADD_UNICODE] = _TAIL_CALL_BINARY_OP_ADD_UNICODE,
[BINARY_OP_EXTEND] = _TAIL_CALL_BINARY_OP_EXTEND,
[BINARY_OP_INPLACE_ADD_UNICODE] = _TAIL_CALL_BINARY_OP_INPLACE_ADD_UNICODE,
[BINARY_OP_MULTIPLY_FLOAT] = _TAIL_CALL_BINARY_OP_MULTIPLY_FLOAT,
[BINARY_OP_MULTIPLY_INT] = _TAIL_CALL_BINARY_OP_MULTIPLY_INT,
[BINARY_OP_SUBTRACT_FLOAT] = _TAIL_CALL_BINARY_OP_SUBTRACT_FLOAT,
[BINARY_OP_SUBTRACT_INT] = _TAIL_CALL_BINARY_OP_SUBTRACT_INT,
[BINARY_SLICE] = _TAIL_CALL_BINARY_SLICE,
[BINARY_SUBSCR] = _TAIL_CALL_BINARY_SUBSCR,
[BINARY_SUBSCR_DICT] = _TAIL_CALL_BINARY_SUBSCR_DICT,
[BINARY_SUBSCR_GETITEM] = _TAIL_CALL_BINARY_SUBSCR_GETITEM,
[BINARY_SUBSCR_LIST_INT] = _TAIL_CALL_BINARY_SUBSCR_LIST_INT,
[BINARY_SUBSCR_STR_INT] = _TAIL_CALL_BINARY_SUBSCR_STR_INT,
[BINARY_SUBSCR_TUPLE_INT] = _TAIL_CALL_BINARY_SUBSCR_TUPLE_INT,
[BUILD_LIST] = _TAIL_CALL_BUILD_LIST,
[BUILD_MAP] = _TAIL_CALL_BUILD_MAP,
[BUILD_SET] = _TAIL_CALL_BUILD_SET,
[BUILD_SLICE] = _TAIL_CALL_BUILD_SLICE,
[BUILD_STRING] = _TAIL_CALL_BUILD_STRING,
[BUILD_TUPLE] = _TAIL_CALL_BUILD_TUPLE,
[CACHE] = _TAIL_CALL_CACHE,
[CALL] = _TAIL_CALL_CALL,
[CALL_ALLOC_AND_ENTER_INIT] = _TAIL_CALL_CALL_ALLOC_AND_ENTER_INIT,
[CALL_BOUND_METHOD_EXACT_ARGS] = _TAIL_CALL_CALL_BOUND_METHOD_EXACT_ARGS,
[CALL_BOUND_METHOD_GENERAL] = _TAIL_CALL_CALL_BOUND_METHOD_GENERAL,
[CALL_BUILTIN_CLASS] = _TAIL_CALL_CALL_BUILTIN_CLASS,
[CALL_BUILTIN_FAST] = _TAIL_CALL_CALL_BUILTIN_FAST,
[CALL_BUILTIN_FAST_WITH_KEYWORDS] = _TAIL_CALL_CALL_BUILTIN_FAST_WITH_KEYWORDS,
[CALL_BUILTIN_O] = _TAIL_CALL_CALL_BUILTIN_O,
[CALL_FUNCTION_EX] = _TAIL_CALL_CALL_FUNCTION_EX,
[CALL_INTRINSIC_1] = _TAIL_CALL_CALL_INTRINSIC_1,
[CALL_INTRINSIC_2] = _TAIL_CALL_CALL_INTRINSIC_2,
[CALL_ISINSTANCE] = _TAIL_CALL_CALL_ISINSTANCE,
[CALL_KW] = _TAIL_CALL_CALL_KW,
[CALL_KW_BOUND_METHOD] = _TAIL_CALL_CALL_KW_BOUND_METHOD,
[CALL_KW_NON_PY] = _TAIL_CALL_CALL_KW_NON_PY,
[CALL_KW_PY] = _TAIL_CALL_CALL_KW_PY,
[CALL_LEN] = _TAIL_CALL_CALL_LEN,
[CALL_LIST_APPEND] = _TAIL_CALL_CALL_LIST_APPEND,
[CALL_METHOD_DESCRIPTOR_FAST] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST,
[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS,
[CALL_METHOD_DESCRIPTOR_NOARGS] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_NOARGS,
[CALL_METHOD_DESCRIPTOR_O] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_O,
[CALL_NON_PY_GENERAL] = _TAIL_CALL_CALL_NON_PY_GENERAL,
[CALL_PY_EXACT_ARGS] = _TAIL_CALL_CALL_PY_EXACT_ARGS,
[CALL_PY_GENERAL] = _TAIL_CALL_CALL_PY_GENERAL,
[CALL_STR_1] = _TAIL_CALL_CALL_STR_1,
[CALL_TUPLE_1] = _TAIL_CALL_CALL_TUPLE_1,
[CALL_TYPE_1] = _TAIL_CALL_CALL_TYPE_1,
[CHECK_EG_MATCH] = _TAIL_CALL_CHECK_EG_MATCH,
[CHECK_EXC_MATCH] = _TAIL_CALL_CHECK_EXC_MATCH,
[CLEANUP_THROW] = _TAIL_CALL_CLEANUP_THROW,
[COMPARE_OP] = _TAIL_CALL_COMPARE_OP,
[COMPARE_OP_FLOAT] = _TAIL_CALL_COMPARE_OP_FLOAT,
[COMPARE_OP_INT] = _TAIL_CALL_COMPARE_OP_INT,
[COMPARE_OP_STR] = _TAIL_CALL_COMPARE_OP_STR,
[CONTAINS_OP] = _TAIL_CALL_CONTAINS_OP,
[CONTAINS_OP_DICT] = _TAIL_CALL_CONTAINS_OP_DICT,
[CONTAINS_OP_SET] = _TAIL_CALL_CONTAINS_OP_SET,
[CONVERT_VALUE] = _TAIL_CALL_CONVERT_VALUE,
[COPY] = _TAIL_CALL_COPY,
[COPY_FREE_VARS] = _TAIL_CALL_COPY_FREE_VARS,
[DELETE_ATTR] = _TAIL_CALL_DELETE_ATTR,
[DELETE_DEREF] = _TAIL_CALL_DELETE_DEREF,
[DELETE_FAST] = _TAIL_CALL_DELETE_FAST,
[DELETE_GLOBAL] = _TAIL_CALL_DELETE_GLOBAL,
[DELETE_NAME] = _TAIL_CALL_DELETE_NAME,
[DELETE_SUBSCR] = _TAIL_CALL_DELETE_SUBSCR,
[DICT_MERGE] = _TAIL_CALL_DICT_MERGE,
[DICT_UPDATE] = _TAIL_CALL_DICT_UPDATE,
[END_ASYNC_FOR] = _TAIL_CALL_END_ASYNC_FOR,
[END_FOR] = _TAIL_CALL_END_FOR,
[END_SEND] = _TAIL_CALL_END_SEND,
[ENTER_EXECUTOR] = _TAIL_CALL_ENTER_EXECUTOR,
[EXIT_INIT_CHECK] = _TAIL_CALL_EXIT_INIT_CHECK,
[EXTENDED_ARG] = _TAIL_CALL_EXTENDED_ARG,
[FORMAT_SIMPLE] = _TAIL_CALL_FORMAT_SIMPLE,
[FORMAT_WITH_SPEC] = _TAIL_CALL_FORMAT_WITH_SPEC,
[FOR_ITER] = _TAIL_CALL_FOR_ITER,
[FOR_ITER_GEN] = _TAIL_CALL_FOR_ITER_GEN,
[FOR_ITER_LIST] = _TAIL_CALL_FOR_ITER_LIST,
[FOR_ITER_RANGE] = _TAIL_CALL_FOR_ITER_RANGE,
[FOR_ITER_TUPLE] = _TAIL_CALL_FOR_ITER_TUPLE,
[GET_AITER] = _TAIL_CALL_GET_AITER,
[GET_ANEXT] = _TAIL_CALL_GET_ANEXT,
[GET_AWAITABLE] = _TAIL_CALL_GET_AWAITABLE,
[GET_ITER] = _TAIL_CALL_GET_ITER,
[GET_LEN] = _TAIL_CALL_GET_LEN,
[GET_YIELD_FROM_ITER] = _TAIL_CALL_GET_YIELD_FROM_ITER,
[IMPORT_FROM] = _TAIL_CALL_IMPORT_FROM,
[IMPORT_NAME] = _TAIL_CALL_IMPORT_NAME,
[INSTRUMENTED_CALL] = _TAIL_CALL_INSTRUMENTED_CALL,
[INSTRUMENTED_CALL_FUNCTION_EX] = _TAIL_CALL_INSTRUMENTED_CALL_FUNCTION_EX,
[INSTRUMENTED_CALL_KW] = _TAIL_CALL_INSTRUMENTED_CALL_KW,
[INSTRUMENTED_END_FOR] = _TAIL_CALL_INSTRUMENTED_END_FOR,
[INSTRUMENTED_END_SEND] = _TAIL_CALL_INSTRUMENTED_END_SEND,
[INSTRUMENTED_FOR_ITER] = _TAIL_CALL_INSTRUMENTED_FOR_ITER,
[INSTRUMENTED_INSTRUCTION] = _TAIL_CALL_INSTRUMENTED_INSTRUCTION,
[INSTRUMENTED_JUMP_BACKWARD] = _TAIL_CALL_INSTRUMENTED_JUMP_BACKWARD,
[INSTRUMENTED_JUMP_FORWARD] = _TAIL_CALL_INSTRUMENTED_JUMP_FORWARD,
[INSTRUMENTED_LINE] = _TAIL_CALL_INSTRUMENTED_LINE,
[INSTRUMENTED_LOAD_SUPER_ATTR] = _TAIL_CALL_INSTRUMENTED_LOAD_SUPER_ATTR,
[INSTRUMENTED_NOT_TAKEN] = _TAIL_CALL_INSTRUMENTED_NOT_TAKEN,
[INSTRUMENTED_POP_ITER] = _TAIL_CALL_INSTRUMENTED_POP_ITER,
[INSTRUMENTED_POP_JUMP_IF_FALSE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_FALSE,
[INSTRUMENTED_POP_JUMP_IF_NONE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NONE,
[INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
[INSTRUMENTED_POP_JUMP_IF_TRUE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_TRUE,
[INSTRUMENTED_RESUME] = _TAIL_CALL_INSTRUMENTED_RESUME,
[INSTRUMENTED_RETURN_VALUE] = _TAIL_CALL_INSTRUMENTED_RETURN_VALUE,
[INSTRUMENTED_YIELD_VALUE] = _TAIL_CALL_INSTRUMENTED_YIELD_VALUE,
[INTERPRETER_EXIT] = _TAIL_CALL_INTERPRETER_EXIT,
[IS_OP] = _TAIL_CALL_IS_OP,
[JUMP_BACKWARD] = _TAIL_CALL_JUMP_BACKWARD,
[JUMP_BACKWARD_JIT] = _TAIL_CALL_JUMP_BACKWARD_JIT,
[JUMP_BACKWARD_NO_INTERRUPT] = _TAIL_CALL_JUMP_BACKWARD_NO_INTERRUPT,
[JUMP_BACKWARD_NO_JIT] = _TAIL_CALL_JUMP_BACKWARD_NO_JIT,
[JUMP_FORWARD] = _TAIL_CALL_JUMP_FORWARD,
[LIST_APPEND] = _TAIL_CALL_LIST_APPEND,
[LIST_EXTEND] = _TAIL_CALL_LIST_EXTEND,
[LOAD_ATTR] = _TAIL_CALL_LOAD_ATTR,
[LOAD_ATTR_CLASS] = _TAIL_CALL_LOAD_ATTR_CLASS,
[LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = _TAIL_CALL_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK,
[LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = _TAIL_CALL_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN,
[LOAD_ATTR_INSTANCE_VALUE] = _TAIL_CALL_LOAD_ATTR_INSTANCE_VALUE,
[LOAD_ATTR_METHOD_LAZY_DICT] = _TAIL_CALL_LOAD_ATTR_METHOD_LAZY_DICT,
[LOAD_ATTR_METHOD_NO_DICT] = _TAIL_CALL_LOAD_ATTR_METHOD_NO_DICT,
[LOAD_ATTR_METHOD_WITH_VALUES] = _TAIL_CALL_LOAD_ATTR_METHOD_WITH_VALUES,
[LOAD_ATTR_MODULE] = _TAIL_CALL_LOAD_ATTR_MODULE,
[LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = _TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_NO_DICT,
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = _TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES,
[LOAD_ATTR_PROPERTY] = _TAIL_CALL_LOAD_ATTR_PROPERTY,
[LOAD_ATTR_SLOT] = _TAIL_CALL_LOAD_ATTR_SLOT,
[LOAD_ATTR_WITH_HINT] = _TAIL_CALL_LOAD_ATTR_WITH_HINT,
[LOAD_BUILD_CLASS] = _TAIL_CALL_LOAD_BUILD_CLASS,
[LOAD_COMMON_CONSTANT] = _TAIL_CALL_LOAD_COMMON_CONSTANT,
[LOAD_CONST] = _TAIL_CALL_LOAD_CONST,
[LOAD_CONST_IMMORTAL] = _TAIL_CALL_LOAD_CONST_IMMORTAL,
[LOAD_CONST_MORTAL] = _TAIL_CALL_LOAD_CONST_MORTAL,
[LOAD_DEREF] = _TAIL_CALL_LOAD_DEREF,
[LOAD_FAST] = _TAIL_CALL_LOAD_FAST,
[LOAD_FAST_AND_CLEAR] = _TAIL_CALL_LOAD_FAST_AND_CLEAR,
[LOAD_FAST_CHECK] = _TAIL_CALL_LOAD_FAST_CHECK,
[LOAD_FAST_LOAD_FAST] = _TAIL_CALL_LOAD_FAST_LOAD_FAST,
[LOAD_FROM_DICT_OR_DEREF] = _TAIL_CALL_LOAD_FROM_DICT_OR_DEREF,
[LOAD_FROM_DICT_OR_GLOBALS] = _TAIL_CALL_LOAD_FROM_DICT_OR_GLOBALS,
[LOAD_GLOBAL] = _TAIL_CALL_LOAD_GLOBAL,
[LOAD_GLOBAL_BUILTIN] = _TAIL_CALL_LOAD_GLOBAL_BUILTIN,
[LOAD_GLOBAL_MODULE] = _TAIL_CALL_LOAD_GLOBAL_MODULE,
[LOAD_LOCALS] = _TAIL_CALL_LOAD_LOCALS,
[LOAD_NAME] = _TAIL_CALL_LOAD_NAME,
[LOAD_SMALL_INT] = _TAIL_CALL_LOAD_SMALL_INT,
[LOAD_SPECIAL] = _TAIL_CALL_LOAD_SPECIAL,
[LOAD_SUPER_ATTR] = _TAIL_CALL_LOAD_SUPER_ATTR,
[LOAD_SUPER_ATTR_ATTR] = _TAIL_CALL_LOAD_SUPER_ATTR_ATTR,
[LOAD_SUPER_ATTR_METHOD] = _TAIL_CALL_LOAD_SUPER_ATTR_METHOD,
[MAKE_CELL] = _TAIL_CALL_MAKE_CELL,
[MAKE_FUNCTION] = _TAIL_CALL_MAKE_FUNCTION,
[MAP_ADD] = _TAIL_CALL_MAP_ADD,
[MATCH_CLASS] = _TAIL_CALL_MATCH_CLASS,
[MATCH_KEYS] = _TAIL_CALL_MATCH_KEYS,
[MATCH_MAPPING] = _TAIL_CALL_MATCH_MAPPING,
[MATCH_SEQUENCE] = _TAIL_CALL_MATCH_SEQUENCE,
[NOP] = _TAIL_CALL_NOP,
[NOT_TAKEN] = _TAIL_CALL_NOT_TAKEN,
[POP_EXCEPT] = _TAIL_CALL_POP_EXCEPT,
[POP_ITER] = _TAIL_CALL_POP_ITER,
[POP_JUMP_IF_FALSE] = _TAIL_CALL_POP_JUMP_IF_FALSE,
[POP_JUMP_IF_NONE] = _TAIL_CALL_POP_JUMP_IF_NONE,
[POP_JUMP_IF_NOT_NONE] = _TAIL_CALL_POP_JUMP_IF_NOT_NONE,
[POP_JUMP_IF_TRUE] = _TAIL_CALL_POP_JUMP_IF_TRUE,
[POP_TOP] = _TAIL_CALL_POP_TOP,
[PUSH_EXC_INFO] = _TAIL_CALL_PUSH_EXC_INFO,
[PUSH_NULL] = _TAIL_CALL_PUSH_NULL,
[RAISE_VARARGS] = _TAIL_CALL_RAISE_VARARGS,
[RERAISE] = _TAIL_CALL_RERAISE,
[RESERVED] = _TAIL_CALL_RESERVED,
[RESUME] = _TAIL_CALL_RESUME,
[RESUME_CHECK] = _TAIL_CALL_RESUME_CHECK,
[RETURN_GENERATOR] = _TAIL_CALL_RETURN_GENERATOR,
[RETURN_VALUE] = _TAIL_CALL_RETURN_VALUE,
[SEND] = _TAIL_CALL_SEND,
[SEND_GEN] = _TAIL_CALL_SEND_GEN,
[SETUP_ANNOTATIONS] = _TAIL_CALL_SETUP_ANNOTATIONS,
[SET_ADD] = _TAIL_CALL_SET_ADD,
[SET_FUNCTION_ATTRIBUTE] = _TAIL_CALL_SET_FUNCTION_ATTRIBUTE,
[SET_UPDATE] = _TAIL_CALL_SET_UPDATE,
[STORE_ATTR] = _TAIL_CALL_STORE_ATTR,
[STORE_ATTR_INSTANCE_VALUE] = _TAIL_CALL_STORE_ATTR_INSTANCE_VALUE,
[STORE_ATTR_SLOT] = _TAIL_CALL_STORE_ATTR_SLOT,
[STORE_ATTR_WITH_HINT] = _TAIL_CALL_STORE_ATTR_WITH_HINT,
[STORE_DEREF] = _TAIL_CALL_STORE_DEREF,
[STORE_FAST] = _TAIL_CALL_STORE_FAST,
[STORE_FAST_LOAD_FAST] = _TAIL_CALL_STORE_FAST_LOAD_FAST,
[STORE_FAST_STORE_FAST] = _TAIL_CALL_STORE_FAST_STORE_FAST,
[STORE_GLOBAL] = _TAIL_CALL_STORE_GLOBAL,
[STORE_NAME] = _TAIL_CALL_STORE_NAME,
[STORE_SLICE] = _TAIL_CALL_STORE_SLICE,
[STORE_SUBSCR] = _TAIL_CALL_STORE_SUBSCR,
[STORE_SUBSCR_DICT] = _TAIL_CALL_STORE_SUBSCR_DICT,
[STORE_SUBSCR_LIST_INT] = _TAIL_CALL_STORE_SUBSCR_LIST_INT,
[SWAP] = _TAIL_CALL_SWAP,
[TO_BOOL] = _TAIL_CALL_TO_BOOL,
[TO_BOOL_ALWAYS_TRUE] = _TAIL_CALL_TO_BOOL_ALWAYS_TRUE,
[TO_BOOL_BOOL] = _TAIL_CALL_TO_BOOL_BOOL,
[TO_BOOL_INT] = _TAIL_CALL_TO_BOOL_INT,
[TO_BOOL_LIST] = _TAIL_CALL_TO_BOOL_LIST,
[TO_BOOL_NONE] = _TAIL_CALL_TO_BOOL_NONE,
[TO_BOOL_STR] = _TAIL_CALL_TO_BOOL_STR,
[UNARY_INVERT] = _TAIL_CALL_UNARY_INVERT,
[UNARY_NEGATIVE] = _TAIL_CALL_UNARY_NEGATIVE,
[UNARY_NOT] = _TAIL_CALL_UNARY_NOT,
[UNPACK_EX] = _TAIL_CALL_UNPACK_EX,
[UNPACK_SEQUENCE] = _TAIL_CALL_UNPACK_SEQUENCE,
[UNPACK_SEQUENCE_LIST] = _TAIL_CALL_UNPACK_SEQUENCE_LIST,
[UNPACK_SEQUENCE_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TUPLE,
[UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE,
[WITH_EXCEPT_START] = _TAIL_CALL_WITH_EXCEPT_START,
[YIELD_VALUE] = _TAIL_CALL_YIELD_VALUE,
[118] = _TAIL_CALL_UNKNOWN_OPCODE,
[119] = _TAIL_CALL_UNKNOWN_OPCODE,
[120] = _TAIL_CALL_UNKNOWN_OPCODE,
[121] = _TAIL_CALL_UNKNOWN_OPCODE,
[122] = _TAIL_CALL_UNKNOWN_OPCODE,
[123] = _TAIL_CALL_UNKNOWN_OPCODE,
[124] = _TAIL_CALL_UNKNOWN_OPCODE,
[125] = _TAIL_CALL_UNKNOWN_OPCODE,
[126] = _TAIL_CALL_UNKNOWN_OPCODE,
[127] = _TAIL_CALL_UNKNOWN_OPCODE,
[128] = _TAIL_CALL_UNKNOWN_OPCODE,
[129] = _TAIL_CALL_UNKNOWN_OPCODE,
[130] = _TAIL_CALL_UNKNOWN_OPCODE,
[131] = _TAIL_CALL_UNKNOWN_OPCODE,
[132] = _TAIL_CALL_UNKNOWN_OPCODE,
[133] = _TAIL_CALL_UNKNOWN_OPCODE,
[134] = _TAIL_CALL_UNKNOWN_OPCODE,
[135] = _TAIL_CALL_UNKNOWN_OPCODE,
[136] = _TAIL_CALL_UNKNOWN_OPCODE,
[137] = _TAIL_CALL_UNKNOWN_OPCODE,
[138] = _TAIL_CALL_UNKNOWN_OPCODE,
[139] = _TAIL_CALL_UNKNOWN_OPCODE,
[140] = _TAIL_CALL_UNKNOWN_OPCODE,
[141] = _TAIL_CALL_UNKNOWN_OPCODE,
[142] = _TAIL_CALL_UNKNOWN_OPCODE,
[143] = _TAIL_CALL_UNKNOWN_OPCODE,
[144] = _TAIL_CALL_UNKNOWN_OPCODE,
[145] = _TAIL_CALL_UNKNOWN_OPCODE,
[146] = _TAIL_CALL_UNKNOWN_OPCODE,
[147] = _TAIL_CALL_UNKNOWN_OPCODE,
[148] = _TAIL_CALL_UNKNOWN_OPCODE,
[232] = _TAIL_CALL_UNKNOWN_OPCODE,
[233] = _TAIL_CALL_UNKNOWN_OPCODE,
[234] = _TAIL_CALL_UNKNOWN_OPCODE,
};
#endif /* Py_TAIL_CALL_INTERP */

View file

@ -675,6 +675,7 @@ NON_ESCAPING_FUNCTIONS = (
"assert",
"backoff_counter_triggers",
"initial_temperature_backoff_counter",
"JUMP_TO_LABEL",
"maybe_lltrace_resume_frame",
"restart_backoff_counter",
)

View file

@ -1,5 +1,4 @@
from pathlib import Path
from typing import TextIO
from analyzer import (
Instruction,
@ -154,28 +153,31 @@ class Emitter:
storage: Storage,
inst: Instruction | None,
) -> bool:
self.out.emit_at("DEOPT_IF", tkn)
self.out.start_line()
self.out.emit("if (")
lparen = next(tkn_iter)
self.emit(lparen)
assert lparen.kind == "LPAREN"
first_tkn = tkn_iter.peek()
emit_to(self.out, tkn_iter, "RPAREN")
self.emit(") {\n")
next(tkn_iter) # Semi colon
self.out.emit(", ")
assert inst is not None
assert inst.family is not None
self.out.emit(inst.family.name)
self.out.emit(");\n")
family_name = inst.family.name
self.emit(f"UPDATE_MISS_STATS({family_name});\n")
self.emit(f"assert(_PyOpcode_Deopt[opcode] == ({family_name}));\n")
self.emit(f"JUMP_TO_PREDICTED({family_name});\n")
self.emit("}\n")
return not always_true(first_tkn)
exit_if = deopt_if
def goto_error(self, offset: int, label: str, storage: Storage) -> str:
if offset > 0:
return f"goto pop_{offset}_{label};"
return f"JUMP_TO_LABEL(pop_{offset}_{label});"
if offset < 0:
storage.copy().flush(self.out)
return f"goto {label};"
return f"JUMP_TO_LABEL({label});"
def error_if(
self,
@ -410,8 +412,10 @@ class Emitter:
self.emit_save(storage)
elif storage.spilled:
raise analysis_error("Cannot jump from spilled label without reloading the stack pointer", goto)
self.out.emit(goto)
self.out.start_line()
self.out.emit("JUMP_TO_LABEL(")
self.out.emit(label)
self.out.emit(")")
def emit_save(self, storage: Storage) -> None:
storage.save(self.out)
@ -603,7 +607,7 @@ class Emitter:
elif tkn.kind == "GOTO":
label_tkn = next(tkn_iter)
self.goto_label(tkn, label_tkn, storage)
reachable = False;
reachable = False
elif tkn.kind == "IDENTIFIER":
if tkn.text in self._replacers:
if not self._replacers[tkn.text](tkn, tkn_iter, uop, storage, inst):

View file

@ -13,6 +13,7 @@ from generators_common import (
DEFAULT_INPUT,
ROOT,
)
from tier1_generator import UNKNOWN_OPCODE_HANDLER
from cwriter import CWriter
@ -25,11 +26,49 @@ def write_opcode_targets(analysis: Analysis, out: CWriter) -> None:
for name, op in analysis.opmap.items():
if op < 256:
targets[op] = f"&&TARGET_{name},\n"
out.emit("#ifndef Py_TAIL_CALL_INTERP\n")
out.emit("static void *opcode_targets[256] = {\n")
for target in targets:
out.emit(target)
out.emit("};\n")
out.emit("#else /* Py_TAIL_CALL_INTERP */\n")
def function_proto(name: str) -> str:
return f"Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_{name}(TAIL_CALL_PARAMS)"
def write_tailcall_dispatch_table(analysis: Analysis, out: CWriter) -> None:
out.emit("static py_tail_call_funcptr INSTRUCTION_TABLE[256];\n")
out.emit("\n")
# Emit function prototypes for labels.
for name in analysis.labels:
out.emit(f"{function_proto(name)};\n")
out.emit("\n")
# Emit function prototypes for opcode handlers.
for name in sorted(analysis.instructions.keys()):
out.emit(f"{function_proto(name)};\n")
out.emit("\n")
# Emit unknown opcode handler.
out.emit(function_proto("UNKNOWN_OPCODE"))
out.emit(" {\n")
out.emit("int opcode = next_instr->op.code;\n")
out.emit(UNKNOWN_OPCODE_HANDLER)
out.emit("}\n")
out.emit("\n")
# Emit the dispatch table.
out.emit("static py_tail_call_funcptr INSTRUCTION_TABLE[256] = {\n")
for name in sorted(analysis.instructions.keys()):
out.emit(f"[{name}] = _TAIL_CALL_{name},\n")
named_values = analysis.opmap.values()
for rest in range(256):
if rest not in named_values:
out.emit(f"[{rest}] = _TAIL_CALL_UNKNOWN_OPCODE,\n")
out.emit("};\n")
outfile.write("#endif /* Py_TAIL_CALL_INTERP */\n")
arg_parser = argparse.ArgumentParser(
description="Generate the file with dispatch targets.",
@ -52,3 +91,4 @@ if __name__ == "__main__":
with open(args.output, "w") as outfile:
out = CWriter(outfile, 0, False)
write_opcode_targets(data, out)
write_tailcall_dispatch_table(data, out)

View file

@ -24,10 +24,9 @@ from generators_common import (
Emitter,
)
from cwriter import CWriter
from typing import TextIO
from typing import TextIO, Callable
from stack import Local, Stack, StackError, get_stack_effect, Storage
DEFAULT_OUTPUT = ROOT / "Python/generated_cases.c.h"
@ -129,31 +128,52 @@ def uses_this(inst: Instruction) -> bool:
for cache in uop.caches:
if cache.name != "unused":
return True
# Can't be merged into the loop above, because
# this must strictly be performed at the end.
for uop in inst.parts:
if not isinstance(uop, Uop):
continue
for tkn in uop.body:
if (tkn.kind == "IDENTIFIER"
and (tkn.text in {"DEOPT_IF", "EXIT_IF"})):
return True
return False
UNKNOWN_OPCODE_HANDLER ="""\
_PyErr_Format(tstate, PyExc_SystemError,
"%U:%d: unknown opcode %d",
_PyFrame_GetCode(frame)->co_filename,
PyUnstable_InterpreterFrame_GetLine(frame),
opcode);
JUMP_TO_LABEL(error);
"""
def generate_tier1(
filenames: list[str], analysis: Analysis, outfile: TextIO, lines: bool
) -> None:
write_header(__file__, filenames, outfile)
outfile.write(
f"""
outfile.write("""
#ifdef TIER_TWO
#error "This file is for Tier 1 only"
#endif
#define TIER_ONE 1
""")
outfile.write(f"""
#ifndef Py_TAIL_CALL_INTERP
#if !USE_COMPUTED_GOTOS
dispatch_opcode:
switch (opcode)
#endif
{{
#endif /* Py_TAIL_CALL_INTERP */
{INSTRUCTION_START_MARKER}
"""
)
generate_tier1_cases(analysis, outfile, lines)
outfile.write(f"""
{INSTRUCTION_END_MARKER}
#ifndef Py_TAIL_CALL_INTERP
#if USE_COMPUTED_GOTOS
_unknown_opcode:
#else
@ -162,41 +182,41 @@ def generate_tier1(
/* Tell C compilers not to hold the opcode variable in the loop.
next_instr points the current instruction without TARGET(). */
opcode = next_instr->op.code;
_PyErr_Format(tstate, PyExc_SystemError,
"%U:%d: unknown opcode %d",
_PyFrame_GetCode(frame)->co_filename,
PyUnstable_InterpreterFrame_GetLine(frame),
opcode);
goto error;
{UNKNOWN_OPCODE_HANDLER}
}}
/* This should never be reached. Every opcode should end with DISPATCH()
or goto error. */
Py_UNREACHABLE();
#endif /* Py_TAIL_CALL_INTERP */
{LABEL_START_MARKER}
""")
generate_tier1_labels(analysis, outfile, lines)
out = CWriter(outfile, 2, lines)
emitter = Emitter(out, analysis.labels)
generate_tier1_labels(analysis, emitter)
outfile.write(f"{LABEL_END_MARKER}\n")
outfile.write(FOOTER)
def generate_tier1_labels(
analysis: Analysis, outfile: TextIO, lines: bool
analysis: Analysis, emitter: Emitter
) -> None:
out = CWriter(outfile, 2, lines)
emitter = Emitter(out, analysis.labels)
out.emit("\n")
emitter.emit("\n")
# Emit tail-callable labels as function defintions
for name, label in analysis.labels.items():
out.emit(f"{name}:\n")
out.emit("{\n")
emitter.emit(f"LABEL({name})\n")
emitter.emit("{\n")
storage = Storage(Stack(), [], [], [])
if label.spilled:
storage.spilled = 1
out.emit("/* STACK SPILLED */\n")
emitter.emit("/* STACK SPILLED */\n")
emitter.emit_tokens(label, storage, None)
out.emit("\n")
out.emit("}\n")
out.emit("\n")
emitter.emit("\n")
emitter.emit("}\n")
emitter.emit("\n")
def generate_tier1_cases(
analysis: Analysis, outfile: TextIO, lines: bool
@ -205,20 +225,26 @@ def generate_tier1_cases(
emitter = Emitter(out, analysis.labels)
out.emit("\n")
for name, inst in sorted(analysis.instructions.items()):
needs_this = uses_this(inst)
out.emit("\n")
out.emit(f"TARGET({name}) {{\n")
# We need to ifdef it because this breaks platforms
# without computed gotos/tail calling.
out.emit(f"#if defined(Py_TAIL_CALL_INTERP)\n")
out.emit(f"int opcode;\n")
out.emit(f"#endif\n")
out.emit(f"opcode = {name};\n")
out.emit(f"(void)(opcode);\n")
needs_this = uses_this(inst)
unused_guard = "(void)this_instr;\n"
if inst.properties.needs_prev:
out.emit(f"_Py_CODEUNIT* const prev_instr = frame->instr_ptr;\n")
if needs_this and not inst.is_target:
if inst.properties.no_save_ip:
out.emit(f"_Py_CODEUNIT* const this_instr = next_instr;\n")
else:
out.emit(f"_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;\n")
out.emit(f"_Py_CODEUNIT* const this_instr = next_instr;\n")
out.emit(unused_guard)
elif not inst.properties.no_save_ip:
if not inst.properties.no_save_ip:
out.emit(f"frame->instr_ptr = next_instr;\n")
out.emit(f"next_instr += {inst.size};\n")
out.emit(f"INSTRUCTION_STATS({name});\n")
if inst.is_target:
@ -226,8 +252,6 @@ def generate_tier1_cases(
if needs_this:
out.emit(f"_Py_CODEUNIT* const this_instr = next_instr - {inst.size};\n")
out.emit(unused_guard)
if inst.properties.uses_opcode:
out.emit(f"opcode = {name};\n")
if inst.family is not None:
out.emit(
f"static_assert({inst.family.size} == {inst.size-1}"

View file

@ -32,14 +32,6 @@
#undef CURRENT_OPERAND1
#define CURRENT_OPERAND1() (_operand1)
#undef DEOPT_IF
#define DEOPT_IF(COND, INSTNAME) \
do { \
if ((COND)) { \
goto deoptimize; \
} \
} while (0)
#undef ENABLE_SPECIALIZATION
#define ENABLE_SPECIALIZATION (0)

48
configure generated vendored
View file

@ -1122,6 +1122,7 @@ with_platlibdir
with_wheel_pkg_dir
with_readline
with_computed_gotos
with_tail_call_interp
with_ensurepip
with_openssl
with_openssl_rpath
@ -1929,6 +1930,8 @@ Optional Packages:
use libedit for backend or disable readline module
--with-computed-gotos enable computed gotos in evaluation loop (enabled by
default on supported compilers)
--tail-call-interp enable tail-calling interpreter in evaluation loop
and rest of CPython
--with-ensurepip[=install|upgrade|no]
"install" or "upgrade" using bundled pip (default is
upgrade)
@ -29246,6 +29249,51 @@ printf "%s\n" "#define HAVE_COMPUTED_GOTOS 1" >>confdefs.h
esac
# Check for --with-tail-call-interp
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-tail-call-interp" >&5
printf %s "checking for --with-tail-call-interp... " >&6; }
# Check whether --with-tail-call-interp was given.
if test ${with_tail_call_interp+y}
then :
withval=$with_tail_call_interp;
if test "$withval" = yes
then
printf "%s\n" "#define Py_TAIL_CALL_INTERP 1" >>confdefs.h
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
fi
if test "$withval" = no
then
printf "%s\n" "#define Py_TAIL_CALL_INTERP 0" >>confdefs.h
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
fi
else case e in #(
e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5
printf "%s\n" "no value specified" >&6; } ;;
esac
fi
# Do not enable tail-calling interpreter if tier 2 is enabled.
if ${tier2_flags:+false} :
then :
case "$ac_cv_tail_call" in yes*)
printf "%s\n" "#define Py_TAIL_CALL_INTERP 1" >>confdefs.h
esac
fi
case $ac_sys_system in
AIX*)

View file

@ -7017,6 +7017,44 @@ case "$ac_cv_computed_gotos" in yes*)
[Define if the C compiler supports computed gotos.])
esac
# Check for --with-tail-call-interp
AC_MSG_CHECKING([for --with-tail-call-interp])
AC_ARG_WITH(
[tail-call-interp],
[AS_HELP_STRING(
[--tail-call-interp],
[enable tail-calling interpreter in evaluation loop and rest of CPython]
)],
[
if test "$withval" = yes
then
AC_DEFINE([Py_TAIL_CALL_INTERP], [1],
[Define if you want to use tail-calling interpreters in CPython.])
AC_MSG_RESULT([yes])
fi
if test "$withval" = no
then
AC_DEFINE([Py_TAIL_CALL_INTERP], [0],
[Define if you want to use tail-calling interpreters in CPython.])
AC_MSG_RESULT([no])
fi
],
[AC_MSG_RESULT([no value specified])])
# Do not enable tail-calling interpreter if tier 2 is enabled.
AS_VAR_IF(
[tier2_flags],
[],
[
case "$ac_cv_tail_call" in yes*)
AC_DEFINE([Py_TAIL_CALL_INTERP], [1],
[Define if the C compiler supports efficient proper tail calls.])
esac
],
[]
)
case $ac_sys_system in
AIX*)
AC_DEFINE([HAVE_BROKEN_PIPE_BUF], [1],

View file

@ -1718,6 +1718,9 @@
/* The version of SunOS/Solaris as reported by `uname -r' without the dot. */
#undef Py_SUNOS_VERSION
/* Define if the C compiler supports efficient proper tail calls. */
#undef Py_TAIL_CALL_INTERP
/* Define if you want to enable tracing references for debugging purpose */
#undef Py_TRACE_REFS