Align Python 3.15 bytecode tooling (#9344)

Extract independent bytecode tooling from the Python 3.15 integration. Decode packed import-name arguments without changing older-interpreter fallback behavior, validate canonical opcode numbering, bound deoptimization families to the enum, and reuse parsed CPython analysis.

Validated generators reproduce tracked metadata exactly; normal, lazy and eager import fallback matches canonical disassembly. No interpreter, generated metadata or test changes.

Assisted-by: OpenAI Codex: model version unavailable
This commit is contained in:
youknowdot authored and GitHub committed 2026-10-25 15:11:10 +09:00
1 parent db4878080a
commit 65ee7bae8b
3 files changed
+27 -3

No files matched your search

+11 -1
View File
@@ -170,12 +170,22 @@ def _resolve_arg_fallback(code, opname, arg):
"LOAD_ATTR",
"STORE_ATTR",
"DELETE_ATTR",
"IMPORT_NAME",
"IMPORT_FROM",
"LOAD_FROM_DICT_OR_GLOBALS",
):
if 0 <= arg < len(code.co_names):
return code.co_names[arg]
elif opname == "IMPORT_NAME":
name_idx, policy = arg, 0
if sys.version_info >= (3, 15):
name_idx, policy = arg >> 2, arg & 3
if 0 <= name_idx < len(code.co_names):
name = code.co_names[name_idx]
if policy & 1 and name:
return f"{name} + lazy"
if policy & 2 and name:
return f"{name} + eager"
return name
elif opname == "LOAD_SUPER_ATTR":
name_idx = arg >> 2
if 0 <= name_idx < len(code.co_names):
+2
View File
@@ -1,3 +1,4 @@
import functools
import os
import pathlib
import sys
@@ -18,6 +19,7 @@ from analyzer import SKIP_PROPERTIES, Analysis, Family, Properties, analyze_file
from stack import get_stack_effect
@functools.cache
def get_analysis() -> Analysis:
from generators_common import DEFAULT_INPUT
+14 -2
View File
@@ -33,10 +33,11 @@ class OpcodeInfo:
for member in family.members:
member_name = to_pascal_case(member.name)
if member.name == family_name:
if member_name == family_name or member_name not in names:
continue
res[family_name].append(member_name)
if member_name not in res[family_name]:
res[family_name].append(member_name)
return dict(res)
@@ -76,6 +77,17 @@ def iter_opcodes(text: str, override_confs: OverrideConfs) -> Iterable[Opcode]:
opcode = Opcode.from_str(entry)
rust_name = opcode.rust_name
# Shared opcodes use CPython's wire-format IDs; RustPython-only
# instructions must occupy an otherwise unused slot.
expected_id = analysis.opmap.get(opcode.cpython_name)
if expected_id is not None and opcode.id != expected_id:
raise ValueError(
f"{rust_name} has opcode ID {opcode.id}; CPython requires {expected_id}"
)
if expected_id is None and opcode.id in analysis.opmap.values():
raise ValueError(
f"RustPython-only opcode {rust_name} collides with CPython ID {opcode.id}"
)
override = override_confs.get(rust_name, SKIP_OVERRIDE)
cpython_name = opcode.cpython_name