Skip to content

Commit 6502499

Browse files
DinoVmeta-codesync[bot]
authored andcommitted
Add static opcode effects
Summary: This adds the static opcode effects and the support for consuming them and generating the final byte code using them. The instr size calculation changes to include the size of `EXTENDED_OPCODE` and we emit the `EXTENDED_OPCODE` before emitting the rest of the opcode. Reviewed By: jbower-fb Differential Revision: D83679256 fbshipit-source-id: 79e5c31abc25bdd6c5aa47b390646aa8817987d7
1 parent e755bc6 commit 6502499

5 files changed

Lines changed: 179 additions & 20 deletions

File tree

cinderx/PythonLib/cinderx/compiler/debug.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def dump_block(
6060
print(str_of_block_header(block))
6161
for instr in block.getInstructions():
6262
print(" ", str_of_block_instr(instr, pc, stack_effect))
63-
pc += graph.instrsize(instr.opname, instr.ioparg) * opcode.CODEUNIT_SIZE
63+
pc += graph.instrsize(instr, instr.ioparg) * opcode.CODEUNIT_SIZE
6464
return pc
6565

6666

cinderx/PythonLib/cinderx/compiler/opcodebase.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class Opcode:
2424

2525
HAVE_ARGUMENT = 90 # Opcodes from here have an argument:
2626
EXTENDED_ARG = 144
27+
EXTENDED_OPCODE = 126
2728
CODEUNIT_SIZE = 2
2829

2930
def __init__(self) -> None:

cinderx/PythonLib/cinderx/compiler/opcodes.py

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,9 @@
205205
FORMAT_VALUE=lambda oparg, jmp=0: -1 if (oparg & FVS_MASK) == FVS_HAVE_SPEC else 0,
206206
BUILD_CONST_KEY_MAP=lambda oparg, jmp=0: -oparg,
207207
BUILD_STRING=lambda oparg, jmp=0: 1 - oparg,
208-
INVOKE_METHOD=lambda oparg, jmp: -(oparg[1] + 1),
208+
INVOKE_METHOD=lambda oparg, jmp=0: -(oparg[1] + 1),
209209
LOAD_METHOD=1,
210-
CALL_METHOD=lambda oparg, jmp: -oparg - 1,
210+
CALL_METHOD=lambda oparg, jmp=0: -oparg - 1,
211211
LIST_EXTEND=-1,
212212
SET_UPDATE=-1,
213213
DICT_MERGE=-1,
@@ -467,6 +467,41 @@
467467
UNPACK_SEQUENCE_TWO_TUPLE=1,
468468
WITH_EXCEPT_START=5,
469469
YIELD_VALUE=1,
470+
# Static opcodes
471+
EXTENDED_OPCODE=0,
472+
LOAD_FIELD=1,
473+
STORE_FIELD=2,
474+
CAST=1,
475+
LOAD_LOCAL=0,
476+
STORE_LOCAL=1,
477+
PRIMITIVE_BOX=1,
478+
POP_JUMP_IF_ZERO=1,
479+
POP_JUMP_IF_NONZERO=1,
480+
PRIMITIVE_UNBOX=1,
481+
PRIMITIVE_BINARY_OP=2,
482+
PRIMITIVE_UNARY_OP=1,
483+
PRIMITIVE_COMPARE_OP=2,
484+
LOAD_ITERABLE_ARG=1,
485+
LOAD_MAPPING_ARG=lambda oparg, jmp=0: 3 if oparg == 3 else 2,
486+
INVOKE_METHOD=lambda oparg, jmp=0: (oparg[1] + 2),
487+
INVOKE_FUNCTION=lambda oparg, jmp=0: (oparg[1]),
488+
INVOKE_NATIVE=lambda oparg, jmp=0: (len(oparg[1]) - 1),
489+
JUMP_IF_ZERO_OR_POP=lambda oparg, jmp=0: 0 if jmp else -1,
490+
JUMP_IF_NONZERO_OR_POP=lambda oparg, jmp=0: 0 if jmp else -1,
491+
FAST_LEN=1,
492+
CONVERT_PRIMITIVE=1,
493+
LOAD_CLASS=0,
494+
BUILD_CHECKED_MAP=lambda oparg, jmp=0: 2 * oparg[1],
495+
SEQUENCE_GET=2,
496+
SEQUENCE_SET=3,
497+
LIST_DEL=2,
498+
REFINE_TYPE=1,
499+
PRIMITIVE_LOAD_CONST=0,
500+
RETURN_PRIMITIVE=1,
501+
TP_ALLOC=0,
502+
BUILD_CHECKED_LIST=lambda oparg, jmp=0: oparg[1],
503+
LOAD_TYPE=1,
504+
LOAD_METHOD_STATIC=1,
470505
)
471506

472507
opcode.pushed.update(
@@ -711,6 +746,41 @@
711746
UNPACK_SEQUENCE_TWO_TUPLE=2,
712747
WITH_EXCEPT_START=6,
713748
YIELD_VALUE=1,
749+
# Static opcodes
750+
EXTENDED_OPCODE=0,
751+
LOAD_FIELD=1,
752+
STORE_FIELD=0,
753+
CAST=1,
754+
LOAD_LOCAL=1,
755+
STORE_LOCAL=0,
756+
PRIMITIVE_BOX=1,
757+
POP_JUMP_IF_ZERO=0,
758+
POP_JUMP_IF_NONZERO=0,
759+
PRIMITIVE_UNBOX=1,
760+
PRIMITIVE_BINARY_OP=1,
761+
PRIMITIVE_UNARY_OP=1,
762+
PRIMITIVE_COMPARE_OP=1,
763+
LOAD_ITERABLE_ARG=2,
764+
LOAD_MAPPING_ARG=1,
765+
INVOKE_METHOD=1,
766+
INVOKE_FUNCTION=1,
767+
INVOKE_NATIVE=1,
768+
JUMP_IF_ZERO_OR_POP=0,
769+
JUMP_IF_NONZERO_OR_POP=0,
770+
FAST_LEN=1,
771+
CONVERT_PRIMITIVE=1,
772+
LOAD_CLASS=1,
773+
BUILD_CHECKED_MAP=1,
774+
SEQUENCE_GET=1,
775+
SEQUENCE_SET=0,
776+
LIST_DEL=0,
777+
REFINE_TYPE=1,
778+
PRIMITIVE_LOAD_CONST=1,
779+
RETURN_PRIMITIVE=0,
780+
TP_ALLOC=1,
781+
BUILD_CHECKED_LIST=1,
782+
LOAD_TYPE=1,
783+
LOAD_METHOD_STATIC=2,
714784
)
715785
for opname, popped in opcode.popped.items():
716786
pushed = opcode.pushed[opname]
@@ -846,3 +916,40 @@ def find_op_idx(opname: str) -> int:
846916
return i
847917

848918
return -1
919+
920+
921+
STATIC_OPCODES = {
922+
"LOAD_FIELD",
923+
"STORE_FIELD",
924+
"CAST",
925+
"LOAD_LOCAL",
926+
"STORE_LOCAL",
927+
"PRIMITIVE_BOX",
928+
"POP_JUMP_IF_ZERO",
929+
"POP_JUMP_IF_NONZERO",
930+
"PRIMITIVE_UNBOX",
931+
"PRIMITIVE_BINARY_OP",
932+
"PRIMITIVE_UNARY_OP",
933+
"PRIMITIVE_COMPARE_OP",
934+
"LOAD_ITERABLE_ARG",
935+
"LOAD_MAPPING_ARG",
936+
"INVOKE_FUNCTION",
937+
"INVOKE_METHOD",
938+
"INVOKE_NATIVE",
939+
"JUMP_IF_ZERO_OR_POP",
940+
"JUMP_IF_NONZERO_OR_POP",
941+
"FAST_LEN",
942+
"CONVERT_PRIMITIVE",
943+
"LOAD_CLASS",
944+
"BUILD_CHECKED_MAP",
945+
"SEQUENCE_GET",
946+
"SEQUENCE_SET",
947+
"LIST_DEL",
948+
"REFINE_TYPE",
949+
"PRIMITIVE_LOAD_CONST",
950+
"RETURN_PRIMITIVE",
951+
"TP_ALLOC",
952+
"BUILD_CHECKED_LIST",
953+
"LOAD_TYPE",
954+
"LOAD_METHOD_STATIC",
955+
}

cinderx/PythonLib/cinderx/compiler/pyassem.py

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
)
4949
from .opcode_cinder import opcode as cinder_opcode
5050
from .opcodebase import Opcode
51-
from .opcodes import opcode as opcodes_opcode
51+
from .opcodes import opcode as opcodes_opcode, STATIC_OPCODES
5252
from .symbols import ClassScope, Scope
5353

5454

@@ -832,7 +832,7 @@ def compute_stack_depth(self) -> None:
832832
self.stacksize = self.stackdepth_walk(block)
833833
break
834834

835-
def instrsize(self, opname: str, oparg: int) -> int:
835+
def instrsize(self, instr: Instruction, oparg: int) -> int:
836836
if oparg <= 0xFF:
837837
return 1
838838
elif oparg <= 0xFFFF:
@@ -878,17 +878,17 @@ def flatten_graph(self) -> None:
878878

879879
for inst in b.getInstructions():
880880
insts.append(inst)
881-
pc += self.instrsize(inst.opname, inst.ioparg)
881+
pc += self.instrsize(inst, inst.ioparg)
882882

883883
pc = 0
884884
for inst in insts:
885-
pc += self.instrsize(inst.opname, inst.ioparg)
885+
pc += self.instrsize(inst, inst.ioparg)
886886
op = self.opcode.opmap[inst.opname]
887887
if self.opcode.has_jump(op):
888888
offset = self.flatten_jump(inst, pc)
889889

890-
if self.instrsize(inst.opname, inst.ioparg) != self.instrsize(
891-
inst.opname, offset
890+
if self.instrsize(inst, inst.ioparg) != self.instrsize(
891+
inst, offset
892892
):
893893
extended_arg_recompile = True
894894

@@ -1092,7 +1092,7 @@ def make_line_table(self) -> bytes:
10921092
lnotab.nextLine(t.lineno, prev_offset, offset)
10931093
prev_offset = offset
10941094

1095-
offset += self.instrsize(t.opname, t.ioparg) * self.opcode.CODEUNIT_SIZE
1095+
offset += self.instrsize(t, t.ioparg) * self.opcode.CODEUNIT_SIZE
10961096

10971097
# Since the linetable format writes the end offset of bytecodes, we can't commit the
10981098
# last write until all the instructions are iterated over.
@@ -2022,7 +2022,8 @@ def prepare_localsplus(self) -> int:
20222022
assert nlocalsplus >= 0
20232023
return nlocalsplus
20242024

2025-
def instrsize(self, opname: str, oparg: int) -> int:
2025+
def instrsize(self, instr: Instruction, oparg: int) -> int:
2026+
opname = instr.opname
20262027
opcode_index = opcodes_opcode.opmap[opname]
20272028
if opcode_index >= len(_inline_cache_entries):
20282029
# T190611021: This should never happen as we should remove pseudo
@@ -2133,7 +2134,7 @@ def make_line_table(self) -> bytes:
21332134
size = 0
21342135

21352136
# The size is in terms of code units
2136-
size += self.instrsize(t.opname, t.ioparg)
2137+
size += self.instrsize(t, t.ioparg)
21372138

21382139
# Since the linetable format writes the end offset of bytecodes, we can't commit the
21392140
# last write until all the instructions are iterated over.
@@ -2152,7 +2153,7 @@ def make_exception_table(self) -> bytes:
21522153
exception_table.emit_entry(start, ioffset, handler)
21532154
start = ioffset
21542155
handler = instr.exc_handler
2155-
ioffset += self.instrsize(instr.opname, instr.ioparg)
2156+
ioffset += self.instrsize(instr, instr.ioparg)
21562157
if handler:
21572158
exception_table.emit_entry(start, ioffset, handler)
21582159
return exception_table.getTable()
@@ -2356,6 +2357,9 @@ def flatten_jump(self, inst: Instruction, pc: int) -> int:
23562357
# sys.monitoring needs to be able to find the matching END_SEND
23572358
# but the target is the SEND, so we adjust it here.
23582359
res -= self.END_SEND_OFFSET
2360+
elif inst.opname in STATIC_OPCODES:
2361+
# Account for EXTENDED_OPCODE
2362+
res += 2
23592363

23602364
return res
23612365

@@ -2470,7 +2474,7 @@ def flatten_graph(self) -> None:
24702474
for b in self.getBlocksInOrder():
24712475
for inst in b.getInstructions():
24722476
if inst.is_jump(self.opcode):
2473-
assert inst.target is not None
2477+
assert inst.target is not None, inst
24742478
inst.ioparg = label_map[inst.target]
24752479

24762480
super().flatten_graph()
@@ -2543,8 +2547,23 @@ def _convert_compare_op(self: PyFlowGraph, arg: object) -> int:
25432547
"COMPARE_OP": _convert_compare_op,
25442548
}
25452549

2546-
def instrsize(self, opname: str, oparg: int) -> int:
2550+
def get_ext_oparg(self, inst: Instruction) -> int:
2551+
pushed = self.opcode.get_num_pushed(inst.opname, inst.oparg)
2552+
popped = self.opcode.get_num_popped(inst.opname, inst.oparg)
2553+
assert pushed < 4, pushed
2554+
return popped << 2 | pushed
2555+
2556+
def instrsize(self, instr: Instruction, oparg: int) -> int:
2557+
opname = instr.opname
25472558
base_size = _inline_cache_entries.get(opname, 0)
2559+
if opname in STATIC_OPCODES:
2560+
# extended opcode
2561+
base_size += 1
2562+
extoparg = self.get_ext_oparg(instr)
2563+
while extoparg >= 256:
2564+
extoparg >>= 8
2565+
base_size += 1
2566+
25482567
if oparg <= 0xFF:
25492568
return 1 + base_size
25502569
elif oparg <= 0xFFFF:
@@ -2554,6 +2573,43 @@ def instrsize(self, opname: str, oparg: int) -> int:
25542573
else:
25552574
return 4 + base_size
25562575

2576+
def make_byte_code(self) -> bytes:
2577+
assert self.stage == FLAT, self.stage
2578+
2579+
code: bytearray = bytearray()
2580+
2581+
def addCode(opcode: int, oparg: int) -> None:
2582+
assert opcode < 256, opcode
2583+
assert oparg < 256, oparg
2584+
code.append(opcode)
2585+
code.append(oparg)
2586+
2587+
for t in self.insts:
2588+
if t.opname in STATIC_OPCODES:
2589+
extoparg = self.get_ext_oparg(t)
2590+
2591+
if extoparg > 0xFFFFFF:
2592+
addCode(self.opcode.EXTENDED_ARG, (extoparg >> 24) & 0xFF)
2593+
if extoparg > 0xFFFF:
2594+
addCode(self.opcode.EXTENDED_ARG, (extoparg >> 16) & 0xFF)
2595+
if extoparg > 0xFF:
2596+
addCode(self.opcode.EXTENDED_ARG, (extoparg >> 8) & 0xFF)
2597+
addCode(self.opcode.EXTENDED_OPCODE, extoparg & 0xFF)
2598+
2599+
oparg = t.ioparg
2600+
assert 0 <= oparg <= 0xFFFFFFFF, oparg
2601+
if oparg > 0xFFFFFF:
2602+
addCode(self.opcode.EXTENDED_ARG, (oparg >> 24) & 0xFF)
2603+
if oparg > 0xFFFF:
2604+
addCode(self.opcode.EXTENDED_ARG, (oparg >> 16) & 0xFF)
2605+
if oparg > 0xFF:
2606+
addCode(self.opcode.EXTENDED_ARG, (oparg >> 8) & 0xFF)
2607+
addCode(self.opcode.opmap[t.opname], oparg & 0xFF)
2608+
self.emit_inline_cache(t.opname, addCode)
2609+
2610+
self.stage = DONE
2611+
return bytes(code)
2612+
25572613
def emit_inline_cache(
25582614
self, opcode: str, addCode: Callable[[int, int], None]
25592615
) -> None:

cinderx/TestScripts/3.14-opt-failures.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ test_cinderx.test_compiler.test_static.context_decorator
1818
test_cinderx.test_compiler.test_static.crange
1919
test_cinderx.test_compiler.test_static.dataclass
2020
test_cinderx.test_compiler.test_static.decl_visitor
21-
test_cinderx.test_compiler.test_static.dependencies
2221
test_cinderx.test_compiler.test_static.double
2322
test_cinderx.test_compiler.test_static.dynamic_return
2423
test_cinderx.test_compiler.test_static.elide_type_checks
@@ -36,11 +35,9 @@ test_cinderx.test_compiler.test_static.non_static_inheritance
3635
test_cinderx.test_compiler.test_static.obj_creation
3736
test_cinderx.test_compiler.test_static.overrides
3837
test_cinderx.test_compiler.test_static.patch
39-
test_cinderx.test_compiler.test_static.perf_lint
4038
test_cinderx.test_compiler.test_static.primitives
4139
test_cinderx.test_compiler.test_static.property
4240
test_cinderx.test_compiler.test_static.refine_fields
43-
test_cinderx.test_compiler.test_static.reflection
4441
test_cinderx.test_compiler.test_static.return_cast_insertion
4542
test_cinderx.test_compiler.test_static.runtime
4643
test_cinderx.test_compiler.test_static.sequence
@@ -49,9 +46,7 @@ test_cinderx.test_compiler.test_static.subclass
4946
test_cinderx.test_compiler.test_static.super
5047
test_cinderx.test_compiler.test_static.sys_hexversion
5148
test_cinderx.test_compiler.test_static.type_alias
52-
test_cinderx.test_compiler.test_static.type_params
5349
test_cinderx.test_compiler.test_static.union
54-
test_cinderx.test_compiler.test_static.unknown_names
5550
test_cinderx.test_compiler.test_static.variadic_arg
5651
test_cinderx.test_compiler.test_static.walrus_operator
5752
test_cinderx.test_compiler.test_strict

0 commit comments

Comments
 (0)