Skip to content

Commit 2acb294

Browse files
update for 3.14
1 parent eec7c30 commit 2acb294

3 files changed

Lines changed: 108 additions & 1 deletion

File tree

src/bytecode/concrete.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,18 @@
2828
_UNSET,
2929
BITFLAG2_OPCODES,
3030
BITFLAG_OPCODES,
31+
COMMON_CONSTANT_OPS,
3132
DUAL_ARG_OPCODES,
3233
DUAL_ARG_OPCODES_SINGLE_OPS,
3334
INTRINSIC,
3435
INTRINSIC_1OP,
3536
INTRINSIC_2OP,
3637
PLACEHOLDER_LABEL,
38+
SPECIAL_OPS,
3739
UNSET,
3840
BaseInstr,
3941
CellVar,
42+
CommonConstants,
4043
Compare,
4144
FreeVar,
4245
Instr,
@@ -46,6 +49,7 @@
4649
Intrinsic2Op,
4750
Label,
4851
SetLineno,
52+
SpecialMethod,
4953
TryBegin,
5054
TryEnd,
5155
_check_arg_int,
@@ -1082,6 +1086,10 @@ def to_bytecode(
10821086
arg = Intrinsic1Op(c_arg)
10831087
elif opcode in INTRINSIC_2OP:
10841088
arg = Intrinsic2Op(c_arg)
1089+
elif opcode in COMMON_CONSTANT_OPS:
1090+
arg = CommonConstants(c_arg)
1091+
elif opcode in SPECIAL_OPS:
1092+
arg = SpecialMethod(c_arg)
10851093
else:
10861094
arg = c_arg
10871095

src/bytecode/instr.py

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from typing_extensions import TypeGuard # type: ignore
1414

1515
import bytecode as _bytecode
16-
from bytecode.utils import PY311, PY312, PY313
16+
from bytecode.utils import PY311, PY312, PY313, PY314
1717

1818
# --- Instruction argument tools and
1919

@@ -31,11 +31,34 @@
3131

3232
BITFLAG2_OPCODES = (_opcode.opmap["LOAD_SUPER_ATTR"],) if PY312 else ()
3333

34+
# Binary op opcode which has a dedicated arg
35+
BINARY_OPS = (_opcode.opmap["BINARY_OP"],) if PY311 else ()
36+
3437
# Intrinsic related opcodes
3538
INTRINSIC_1OP = (_opcode.opmap["CALL_INTRINSIC_1"],) if PY312 else ()
3639
INTRINSIC_2OP = (_opcode.opmap["CALL_INTRINSIC_2"],) if PY312 else ()
3740
INTRINSIC = INTRINSIC_1OP + INTRINSIC_2OP
3841

42+
# Small integer related opcode
43+
SMALL_INT_OPS = (_opcode.opmap["LOAD_SMALL_INT"],) if PY314 else ()
44+
45+
# Special method loading related opcodes
46+
SPECIAL_OPS = (_opcode.opmap["LOAD_SPECIAL"],) if PY314 else ()
47+
48+
# Common constant loading related opcodes
49+
COMMON_CONSTANT_OPS = (_opcode.opmap["LOAD_COMMON_CONSTANT"],) if PY314 else ()
50+
51+
# Value formatting related opcodes (only handle CONVERT_VALUE and BUILD_INTERPOLATION)
52+
# XXX BUILD_INTERPOLATION in 314 need a bit shift and has 2 args
53+
FORMAT_VALUE_OPS = (
54+
(
55+
_opcode.opmap["CONVERT_VALUE"],
56+
_opcode.opmap["BUILD_INTERPOLATION"],
57+
)
58+
if PY314
59+
else ((_opcode.opmap["CONVERT_VALUE"],) if PY313 else ())
60+
)
61+
3962
HASJABS = () if PY313 else _opcode.hasjabs
4063
if sys.version_info >= (3, 13):
4164
HASJREL = _opcode.hasjump
@@ -51,6 +74,11 @@
5174
_opcode.opmap["STORE_FAST_LOAD_FAST"],
5275
_opcode.opmap["STORE_FAST_STORE_FAST"],
5376
)
77+
if PY314:
78+
DUAL_ARG_OPCODES = (
79+
*DUAL_ARG_OPCODES,
80+
_opcode.opmap["LOAD_FAST_BORROW_LOAD_FAST_BORROW"],
81+
)
5482
DUAL_ARG_OPCODES_SINGLE_OPS = {
5583
_opcode.opmap["LOAD_FAST_LOAD_FAST"]: ("LOAD_FAST", "LOAD_FAST"),
5684
_opcode.opmap["STORE_FAST_LOAD_FAST"]: ("STORE_FAST", "LOAD_FAST"),
@@ -129,6 +157,8 @@ class BinaryOp(enum.IntEnum):
129157
INPLACE_SUBTRACT = 23
130158
INPLACE_TRUE_DIVIDE = 24
131159
INPLACE_XOR = 25
160+
if PY314:
161+
SUBSCR = 26
132162

133163

134164
@enum.unique
@@ -156,6 +186,35 @@ class Intrinsic2Op(enum.IntEnum):
156186
INTRINSIC_SET_FUNCTION_TYPE_PARAMS = 4
157187

158188

189+
@enum.unique
190+
class FormatValue(enum.IntEnum):
191+
STR = 1
192+
REPR = 2
193+
ASCII = 3
194+
195+
196+
if PY314:
197+
198+
@enum.unique
199+
class SpecialMethod(enum.IntEnum):
200+
"""Special method names used with LOAD_SPECIAL"""
201+
202+
__ENTER__ = 0
203+
__EXIT__ = 1
204+
__AENTER__ = 2
205+
__AEXIT__ = 3
206+
207+
@enum.unique
208+
class CommonConstants(enum.IntEnum):
209+
"""Common constants names used with LOAD_COMMON_CONSTANT"""
210+
211+
ASSERTION_ERROR = 0
212+
NOT_IMPLEMENTED_ERROR = 1
213+
BUILTIN_TUPLE = 2
214+
BUILTIN_ALL = 3
215+
BUILTIN_ANY = 4
216+
217+
159218
# This make type checking happy but means it won't catch attempt to manipulate an unset
160219
# statically. We would need guard on object attribute narrowed down through methods
161220
class _UNSET(int):
@@ -357,6 +416,7 @@ def opcode_has_argument(opcode: int) -> bool:
357416
"FORMAT_SIMPLE": (-1, 1), # new in 3.13
358417
"FORMAT_SPEC": (-2, 1), # new in 3.13
359418
"TO_BOOL": (-1, 1), # new in 3.13
419+
"BUILD_TEMPLATE": (-2, 1), # new in 3.14
360420
}
361421

362422

@@ -385,6 +445,7 @@ def opcode_has_argument(opcode: int) -> bool:
385445
"FORMAT_VALUE": lambda effect, arg, jump: (effect - 1, 1),
386446
# FOR_ITER needs TOS to be an iterator, hence a prerequisite of 1 on the stack
387447
"FOR_ITER": lambda effect, arg, jump: (effect, 0) if jump else (-1, 2),
448+
"BUILD_INTERPOLATION": lambda effect, arg, jump: (-(2 + (arg & 1)), 1),
388449
**{
389450
# Instr(UNPACK_* , n) pops 1 and pushes n
390451
k: lambda effect, arg, jump: (-1, effect + 1)
@@ -910,6 +971,28 @@ def _check_arg(self, name: str, opcode: int, arg: InstrArg) -> None:
910971
"Compare, got %s" % (name, type(arg).__name__)
911972
)
912973

974+
elif opcode in BINARY_OPS:
975+
if not isinstance(arg, BinaryOp):
976+
raise TypeError(
977+
"operation %s argument type must be "
978+
"BinaryOp, got %s" % (name, type(arg).__name__)
979+
)
980+
981+
# We do not enforce constant immortality since which constants are
982+
# immortal may differ between recompilation and execution.
983+
984+
elif opcode in SMALL_INT_OPS:
985+
if not isinstance(arg, int):
986+
raise TypeError(
987+
"operation %s argument type must be "
988+
"int, got %s" % (name, type(arg).__name__)
989+
)
990+
if arg < 0 or arg > 255:
991+
raise ValueError(
992+
"operation %s argument type must be an "
993+
"int between 0 and 255, got %s" % (name, arg)
994+
)
995+
913996
elif opcode in INTRINSIC_1OP:
914997
if not isinstance(arg, Intrinsic1Op):
915998
raise TypeError(
@@ -924,5 +1007,20 @@ def _check_arg(self, name: str, opcode: int, arg: InstrArg) -> None:
9241007
"Intrinsic2Op, got %s" % (name, type(arg).__name__)
9251008
)
9261009

1010+
elif opcode in SPECIAL_OPS:
1011+
if not isinstance(arg, SpecialMethod):
1012+
raise TypeError(
1013+
"operation %s argument type must be "
1014+
"SpecialMethod, got %s" % (name, type(arg).__name__)
1015+
)
1016+
elif opcode in COMMON_CONSTANT_OPS:
1017+
if not isinstance(arg, CommonConstants):
1018+
raise TypeError(
1019+
"operation %s argument type must be "
1020+
"CommonConstants, got %s" % (name, type(arg).__name__)
1021+
)
1022+
1023+
# XXX format value handling
1024+
9271025
elif opcode_has_argument(opcode):
9281026
_check_arg_int(arg, name)

src/bytecode/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
PY311: Final[bool] = sys.version_info >= (3, 11)
66
PY312: Final[bool] = sys.version_info >= (3, 12)
77
PY313: Final[bool] = sys.version_info >= (3, 13)
8+
PY314: Final[bool] = sys.version_info >= (3, 14)

0 commit comments

Comments
 (0)