Skip to content

Commit befdc3f

Browse files
committed
Use slot offsets for opargs
1 parent 33f6e7c commit befdc3f

File tree

8 files changed

+169
-70
lines changed

8 files changed

+169
-70
lines changed

Include/cpython/object.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ typedef struct {
123123
binaryfunc nb_xor;
124124
binaryfunc nb_or;
125125
unaryfunc nb_int;
126-
void *nb_reserved; /* the slot formerly known as nb_long */
126+
unaryfunc nb_reserved; /* the slot formerly known as nb_long */
127127
unaryfunc nb_float;
128128

129129
binaryfunc nb_inplace_add;

Include/opcode.h

Lines changed: 62 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/dis.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from opcode import *
99
from opcode import __all__ as _opcodes_all
10-
from opcode import _nb_ops
10+
from opcode import _nb_slots
1111

1212
__all__ = ["code_info", "dis", "disassemble", "distb", "disco",
1313
"findlinestarts", "findlabels", "show_code",
@@ -30,12 +30,11 @@
3030
LOAD_CONST = opmap['LOAD_CONST']
3131

3232
BINARY_OP = opmap['BINARY_OP']
33-
BINARY_OPS = [name for _, name in _nb_ops]
34-
3533
INPLACE_OP = opmap['INPLACE_OP']
36-
INPLACE_OPS = [f"{name}=" for _, name in _nb_ops]
3734

38-
del _nb_ops
35+
NB_NAMES = {i: name for i, _, name in _nb_slots}
36+
37+
del _nb_slots
3938

4039
def _try_compile(source, name):
4140
"""Attempts to compile the given source, first as an expression and
@@ -455,10 +454,8 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
455454
elif op == MAKE_FUNCTION:
456455
argrepr = ', '.join(s for i, s in enumerate(MAKE_FUNCTION_FLAGS)
457456
if arg & (1<<i))
458-
elif op == BINARY_OP:
459-
argrepr = BINARY_OPS[arg]
460-
elif op == INPLACE_OP:
461-
argrepr = INPLACE_OPS[arg]
457+
elif op == BINARY_OP or op == INPLACE_OP:
458+
argrepr = NB_NAMES[arg]
462459
yield Instruction(opname[op], op,
463460
arg, argval, argrepr,
464461
offset, starts_line, is_jump_target, positions)

Lib/opcode.py

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -205,16 +205,43 @@ def jabs_op(name, op):
205205

206206
del def_op, name_op, jrel_op, jabs_op
207207

208-
_nb_ops = [
209-
("NB_AND", "&"),
210-
("NB_FLOOR_DIVIDE", "//"),
211-
("NB_LSHIFT", "<<"),
212-
("NB_MATRIX_MULTIPLY", "@"),
213-
("NB_OR", "|"),
214-
("NB_RSHIFT", ">>"),
215-
("NB_SUBTRACT", "-"),
216-
("NB_TRUE_DIVIDE", "/"),
217-
("NB_XOR", "^"),
208+
_nb_slots = [
209+
# nb_add
210+
(1, "nb_subtract", "-"),
211+
# nb_multiply
212+
# nb_remainder
213+
# nb_divmod
214+
# nb_power
215+
# nb_negative
216+
# nb_positive
217+
# nb_absolute
218+
# nb_bool
219+
# nb_invert
220+
(11, "nb_lshift", "<<"),
221+
(12, "nb_rshift", ">>"),
222+
(13, "nb_and", "&"),
223+
(14, "nb_xor", "^"),
224+
(15, "nb_or", "|"),
225+
# nb_int
226+
# nb_reserved
227+
# nb_float
228+
# nb_inplace_add
229+
(20, "nb_inplace_subtract", "-="),
230+
# nb_inplace_multiply
231+
# nb_inplace_remainder
232+
# nb_inplace_power
233+
(24, "nb_inplace_lshift", "<<="),
234+
(25, "nb_inplace_rshift", ">>="),
235+
(26, "nb_inplace_and", "&="),
236+
(27, "nb_inplace_xor", "^="),
237+
(28, "nb_inplace_or", "|="),
238+
(29, "nb_floor_divide", "//"),
239+
(30, "nb_true_divide", "/"),
240+
(31, "nb_inplace_floor_divide", "//="),
241+
(32, "nb_inplace_true_divide", "/="),
242+
# nb_index
243+
(34, "nb_matrix_multiply", "@"),
244+
(35, "nb_inplace_matrix_multiply", "@="),
218245
]
219246

220247
_specialized_instructions = [

Lib/test/test_dis.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ def bug42562():
285285
286286
%3d 2 LOAD_CONST 1 (1)
287287
4 LOAD_CONST 2 (0)
288-
--> 6 BINARY_OP 7 (/)
288+
--> 6 BINARY_OP 30 (/)
289289
8 POP_TOP
290290
291291
%3d 10 LOAD_FAST 1 (tb)
@@ -1060,7 +1060,7 @@ def _prepare_test_cases():
10601060
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None),
10611061
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=64, starts_line=13, is_jump_target=False, positions=None),
10621062
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=66, starts_line=None, is_jump_target=False, positions=None),
1063-
Instruction(opname='INPLACE_OP', opcode=123, arg=6, argval=6, argrepr='-=', offset=68, starts_line=None, is_jump_target=False, positions=None),
1063+
Instruction(opname='INPLACE_OP', opcode=123, arg=20, argval=20, argrepr='-=', offset=68, starts_line=None, is_jump_target=False, positions=None),
10641064
Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=70, starts_line=None, is_jump_target=False, positions=None),
10651065
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=72, starts_line=14, is_jump_target=False, positions=None),
10661066
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=74, starts_line=None, is_jump_target=False, positions=None),
@@ -1081,7 +1081,7 @@ def _prepare_test_cases():
10811081
Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=104, starts_line=20, is_jump_target=True, positions=None),
10821082
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=106, starts_line=21, is_jump_target=False, positions=None),
10831083
Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=108, starts_line=None, is_jump_target=False, positions=None),
1084-
Instruction(opname='BINARY_OP', opcode=122, arg=7, argval=7, argrepr='/', offset=110, starts_line=None, is_jump_target=False, positions=None),
1084+
Instruction(opname='BINARY_OP', opcode=122, arg=30, argval=30, argrepr='/', offset=110, starts_line=None, is_jump_target=False, positions=None),
10851085
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None),
10861086
Instruction(opname='JUMP_FORWARD', opcode=110, arg=15, argval=146, argrepr='to 146', offset=114, starts_line=None, is_jump_target=False, positions=None),
10871087
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=116, starts_line=None, is_jump_target=False, positions=None),

Objects/abstract.c

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,44 +1715,51 @@ PyNumber_ToBase(PyObject *n, int base)
17151715
return res;
17161716
}
17171717

1718-
typedef struct {
1719-
const int slot;
1720-
const char name[3];
1721-
const int islot;
1722-
const char iname[4];
1723-
} nb_info;
1724-
1725-
#define NB_INFO(name, slot) \
1726-
{NB_SLOT(nb_##slot), name, NB_SLOT(nb_inplace_##slot), name "="}
1727-
1728-
static nb_info nb_infos[] = {
1729-
[NB_AND] = NB_INFO("&", and),
1730-
[NB_FLOOR_DIVIDE] = NB_INFO("//", floor_divide),
1731-
[NB_LSHIFT] = NB_INFO("<<", lshift),
1732-
[NB_MATRIX_MULTIPLY] = NB_INFO("@", matrix_multiply),
1733-
[NB_OR] = NB_INFO("|", or),
1734-
[NB_RSHIFT] = NB_INFO(">>", rshift),
1735-
[NB_SUBTRACT] = NB_INFO("-", subtract),
1736-
[NB_TRUE_DIVIDE] = NB_INFO("/", true_divide),
1737-
[NB_XOR] = NB_INFO("^", xor),
1718+
#define NB_NAMES(op) \
1719+
[NB_##op] = NB_##op##_NAME, \
1720+
[NB_INPLACE_##op] = NB_INPLACE_##op##_NAME
1721+
1722+
static const char nb_names[][4] = {
1723+
NB_NAMES(AND),
1724+
NB_NAMES(FLOOR_DIVIDE),
1725+
NB_NAMES(LSHIFT),
1726+
NB_NAMES(MATRIX_MULTIPLY),
1727+
NB_NAMES(OR),
1728+
NB_NAMES(RSHIFT),
1729+
NB_NAMES(SUBTRACT),
1730+
NB_NAMES(TRUE_DIVIDE),
1731+
NB_NAMES(XOR),
17381732
};
17391733

1740-
#undef NB_INFO
1734+
#undef NB_NAMES
1735+
1736+
#define NB_BINSLOT(op) [NB_INPLACE_##op] = NB_##op
1737+
1738+
static const uint8_t nb_binary_slots[] = {
1739+
NB_BINSLOT(AND),
1740+
NB_BINSLOT(FLOOR_DIVIDE),
1741+
NB_BINSLOT(LSHIFT),
1742+
NB_BINSLOT(MATRIX_MULTIPLY),
1743+
NB_BINSLOT(OR),
1744+
NB_BINSLOT(RSHIFT),
1745+
NB_BINSLOT(SUBTRACT),
1746+
NB_BINSLOT(TRUE_DIVIDE),
1747+
NB_BINSLOT(XOR),
1748+
};
1749+
1750+
#undef NB_BINSLOT
17411751

17421752
PyObject *
17431753
_PyNumber_Op(PyObject *o1, PyObject *o2, unsigned op)
17441754
{
1745-
assert(op < sizeof(nb_infos) / sizeof(nb_info));
1746-
nb_info *ni = &nb_infos[op];
1747-
return binary_op(o1, o2, ni->slot, ni->name);
1755+
return binary_op(o1, o2, op * NB_SCALE, nb_names[op]);
17481756
}
17491757

17501758
PyObject *
17511759
_PyNumber_InPlaceOp(PyObject *o1, PyObject *o2, unsigned op)
17521760
{
1753-
assert(op < sizeof(nb_infos) / sizeof(nb_info));
1754-
nb_info *ni = &nb_infos[op];
1755-
return binary_iop(o1, o2, ni->islot, ni->slot, ni->iname);
1761+
return binary_iop(o1, o2, op * NB_SCALE, nb_binary_slots[op] * NB_SCALE,
1762+
nb_names[op]);
17561763
}
17571764

17581765

Python/compile.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3684,24 +3684,25 @@ unaryop(unaryop_ty op)
36843684
static int
36853685
addop_binary(struct compiler *c, operator_ty binop, bool inplace)
36863686
{
3687+
assert(HAVE_SANE_NB_OFFSETS);
36873688
int oparg;
36883689
switch (binop) {
36893690
case Add:
36903691
// Addition interacts with sq_concat:
36913692
ADDOP(c, inplace ? INPLACE_ADD : BINARY_ADD);
36923693
return 1;
36933694
case Sub:
3694-
oparg = NB_SUBTRACT;
3695+
oparg = inplace ? NB_INPLACE_SUBTRACT : NB_SUBTRACT;
36953696
break;
36963697
case Mult:
36973698
// Multiplication interacts with sq_repeat:
36983699
ADDOP(c, inplace ? INPLACE_MULTIPLY : BINARY_MULTIPLY);
36993700
return 1;
37003701
case MatMult:
3701-
oparg = NB_MATRIX_MULTIPLY;
3702+
oparg = inplace ? NB_INPLACE_MATRIX_MULTIPLY : NB_MATRIX_MULTIPLY;
37023703
break;
37033704
case Div:
3704-
oparg = NB_TRUE_DIVIDE;
3705+
oparg = inplace ? NB_INPLACE_TRUE_DIVIDE : NB_TRUE_DIVIDE;
37053706
break;
37063707
case Mod:
37073708
// Modulation contains a fast path for strings:
@@ -3712,22 +3713,22 @@ addop_binary(struct compiler *c, operator_ty binop, bool inplace)
37123713
ADDOP(c, inplace ? INPLACE_POWER : BINARY_POWER);
37133714
return 1;
37143715
case LShift:
3715-
oparg = NB_LSHIFT;
3716+
oparg = inplace ? NB_INPLACE_LSHIFT : NB_LSHIFT;
37163717
break;
37173718
case RShift:
3718-
oparg = NB_RSHIFT;
3719+
oparg = inplace ? NB_INPLACE_RSHIFT : NB_RSHIFT;
37193720
break;
37203721
case BitOr:
3721-
oparg = NB_OR;
3722+
oparg = inplace ? NB_INPLACE_OR : NB_OR;
37223723
break;
37233724
case BitXor:
3724-
oparg = NB_XOR;
3725+
oparg = inplace ? NB_INPLACE_XOR : NB_XOR;
37253726
break;
37263727
case BitAnd:
3727-
oparg = NB_AND;
3728+
oparg = inplace ? NB_INPLACE_AND : NB_AND;
37283729
break;
37293730
case FloorDiv:
3730-
oparg = NB_FLOOR_DIVIDE;
3731+
oparg = inplace ? NB_INPLACE_FLOOR_DIVIDE : NB_FLOOR_DIVIDE;
37313732
break;
37323733
default:
37333734
PyErr_Format(PyExc_SystemError, "%s op %d should not be possible",

Tools/scripts/generate_opcode_h.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@
1111
extern "C" {
1212
#endif
1313
14+
#include <stddef.h>
15+
1416
1517
/* Instruction opcodes for compiled code */
1618
""".lstrip()
1719

1820
footer = """
21+
#define NB_SCALE offsetof(PyNumberMethods, nb_subtract)
22+
1923
#define HAS_ARG(op) ((op) >= HAVE_ARGUMENT)
2024
2125
/* Reserve some bytecodes for internal use in the compiler.
@@ -86,8 +90,18 @@ def main(opcode_py, outfile='Include/opcode.h'):
8690
fobj.write("\n )\n")
8791

8892
fobj.write("\n")
89-
for i, (op, _) in enumerate(opcode["_nb_ops"]):
90-
fobj.write(DEFINE.format(op, i))
93+
for i, slot, _ in opcode["_nb_slots"]:
94+
fobj.write(DEFINE.format(slot.upper(), i))
95+
96+
fobj.write("\n")
97+
for _, slot, name in opcode["_nb_slots"]:
98+
fobj.write(DEFINE.format(f"{slot.upper()}_NAME", f'"{name}"'))
99+
100+
fobj.write("\n")
101+
fobj.write("#define HAVE_SANE_NB_OFFSETS ( \\\n")
102+
for _, slot, _ in opcode["_nb_slots"]:
103+
fobj.write(f" {slot.upper()} * NB_SCALE == offsetof(PyNumberMethods, {slot}) && \\\n")
104+
fobj.write(" true)\n")
91105

92106
fobj.write(footer)
93107

0 commit comments

Comments
 (0)