Skip to content

Commit 426daf1

Browse files
fix: add multiple jump target to metadata, special ops can be jump targets (python#40)
1 parent b6c0fc5 commit 426daf1

File tree

2 files changed

+105
-20
lines changed

2 files changed

+105
-20
lines changed

Python/tier2.c

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,7 +1312,7 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr,
13121312
// we can't handle are in IS_FORBIDDEN_OPCODE
13131313
#if BB_DEBUG
13141314
fprintf(stderr,
1315-
"emit_logical_branch unreachable opcode %d\n", _Py_OPCODE(branch));
1315+
"emit_logical_branch unreachable opcode %d\n", branch.op.code);
13161316
#endif
13171317
Py_UNREACHABLE();
13181318
}
@@ -1373,9 +1373,9 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr,
13731373
return write_curr;
13741374
}
13751375
else {
1376-
#if BB_DEBUG
1377-
fprintf(stderr, "emitted logical branch %p %d\n", write_curr,
1378-
_Py_OPCODE(branch));
1376+
#if BB_DEBUG && defined Py_DEBUG
1377+
fprintf(stderr, "emitted logical branch %p %s from original opcode %s\n", write_curr,
1378+
_PyOpcode_OpName[opcode], _PyOpcode_OpName[branch.op.code]);
13791379
#endif
13801380
_py_set_opcode(write_curr, requires_extended_arg ? EXTENDED_ARG : NOP);
13811381
write_curr->op.arg = (oparg >> 8) & 0xFF;
@@ -1519,6 +1519,9 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta,
15191519
int backwards_jump_target, _PyTier2TypeContext *starting_context,
15201520
_Py_CODEUNIT *tier1_start)
15211521
{
1522+
#if BB_DEBUG
1523+
fprintf(stderr, "Attempting to add jump id %d as jump target\n", meta->id);
1524+
#endif
15221525
// Locate where to insert the BB ID
15231526
int backward_jump_offset_index = 0;
15241527
bool found = false;
@@ -1536,6 +1539,9 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta,
15361539
for (; jump_i < MAX_BB_VERSIONS; jump_i++) {
15371540
if (t2_info->backward_jump_target_bb_pairs[backward_jump_offset_index][jump_i].id ==
15381541
-1) {
1542+
#if BB_DEBUG
1543+
fprintf(stderr, "Added jump id %d as jump target\n", meta->id);
1544+
#endif
15391545
t2_info->backward_jump_target_bb_pairs[backward_jump_offset_index][jump_i].id =
15401546
meta->id;
15411547
t2_info->backward_jump_target_bb_pairs[backward_jump_offset_index][jump_i].start_type_context = starting_context;
@@ -1811,6 +1817,13 @@ _PyTier2_Code_DetectAndEmitBB(
18111817
#define DISPATCH_GOTO() goto dispatch_opcode;
18121818
#define TYPECONST_GET_RAWTYPE(idx) Py_TYPE(PyTuple_GET_ITEM(consts, idx))
18131819
#define GET_CONST(idx) PyTuple_GET_ITEM(consts, idx)
1820+
#define CHECK_BACKWARDS_JUMP_TARGET() \
1821+
if (!checked_jump_target) { \
1822+
from_another_opcode = true;\
1823+
goto check_backwards_jump_target;\
1824+
}\
1825+
checked_jump_target = false; \
1826+
from_another_opcode = false; \
18141827

18151828
assert(co->_tier2_info != NULL);
18161829
// There are only two cases that a BB ends.
@@ -1834,6 +1847,8 @@ _PyTier2_Code_DetectAndEmitBB(
18341847
bool virtual_start = false;
18351848
_PyTier2TypeContext *start_type_context_copy = NULL;
18361849
_Py_CODEUNIT *virtual_tier1_start = NULL;
1850+
bool from_another_opcode = false;
1851+
bool checked_jump_target = false;
18371852

18381853
// A meta-interpreter for types.
18391854
Py_ssize_t i = (tier1_start - _PyCode_CODE(co));
@@ -1854,9 +1869,11 @@ _PyTier2_Code_DetectAndEmitBB(
18541869
#endif
18551870
switch (opcode) {
18561871
case RESUME:
1872+
CHECK_BACKWARDS_JUMP_TARGET();
18571873
opcode = specop = RESUME_QUICK;
18581874
DISPATCH();
18591875
case END_FOR:
1876+
CHECK_BACKWARDS_JUMP_TARGET();
18601877
// Assert that we are the start of a BB
18611878
assert(t2_start == write_i);
18621879

@@ -1869,6 +1886,7 @@ _PyTier2_Code_DetectAndEmitBB(
18691886
// Else, we do want to execute this.
18701887
DISPATCH();
18711888
case POP_TOP: {
1889+
CHECK_BACKWARDS_JUMP_TARGET();
18721890
// Read-only, only for us to inspect the types. DO NOT MODIFY HERE.
18731891
// ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES.
18741892
_Py_TYPENODE_t **type_stackptr = &starting_type_context->type_stack_ptr;
@@ -1879,6 +1897,7 @@ _PyTier2_Code_DetectAndEmitBB(
18791897
DISPATCH();
18801898
}
18811899
case COPY: {
1900+
CHECK_BACKWARDS_JUMP_TARGET();
18821901
// Read-only, only for us to inspect the types. DO NOT MODIFY HERE.
18831902
// ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES.
18841903
_Py_TYPENODE_t **type_stackptr = &starting_type_context->type_stack_ptr;
@@ -1889,6 +1908,7 @@ _PyTier2_Code_DetectAndEmitBB(
18891908
DISPATCH();
18901909
}
18911910
case LOAD_CONST: {
1911+
CHECK_BACKWARDS_JUMP_TARGET();
18921912
PyTypeObject *typ = TYPECONST_GET_RAWTYPE(oparg);
18931913
if (typ == &PyFloat_Type) {
18941914
write_i = emit_i(write_i, LOAD_CONST, curr->op.arg);
@@ -1916,6 +1936,7 @@ _PyTier2_Code_DetectAndEmitBB(
19161936
DISPATCH();
19171937
}
19181938
case LOAD_FAST: {
1939+
CHECK_BACKWARDS_JUMP_TARGET();
19191940
// Read-only, only for us to inspect the types. DO NOT MODIFY HERE.
19201941
// ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES.
19211942
_Py_TYPENODE_t *type_locals = starting_type_context->type_locals;
@@ -1944,6 +1965,7 @@ _PyTier2_Code_DetectAndEmitBB(
19441965
DISPATCH();
19451966
}
19461967
case LOAD_FAST_CHECK: {
1968+
CHECK_BACKWARDS_JUMP_TARGET();
19471969
// Read-only, only for us to inspect the types. DO NOT MODIFY HERE.
19481970
// ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES.
19491971
_Py_TYPENODE_t *type_locals = starting_type_context->type_locals;
@@ -1972,6 +1994,7 @@ _PyTier2_Code_DetectAndEmitBB(
19721994
DISPATCH();
19731995
}
19741996
case STORE_FAST: {
1997+
CHECK_BACKWARDS_JUMP_TARGET();
19751998
// Read-only, only for us to inspect the types. DO NOT MODIFY HERE.
19761999
// ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES.
19772000
_Py_TYPENODE_t *type_locals = starting_type_context->type_locals;
@@ -1999,13 +2022,17 @@ _PyTier2_Code_DetectAndEmitBB(
19992022
}
20002023
// Need to handle reboxing at these boundaries.
20012024
case CALL:
2025+
CHECK_BACKWARDS_JUMP_TARGET();
20022026
DISPATCH_REBOX(oparg + 2);
20032027
case BUILD_MAP:
2028+
CHECK_BACKWARDS_JUMP_TARGET();
20042029
DISPATCH_REBOX(oparg * 2);
20052030
case BUILD_STRING:
20062031
case BUILD_LIST:
2032+
CHECK_BACKWARDS_JUMP_TARGET();
20072033
DISPATCH_REBOX(oparg);
20082034
case BINARY_OP:
2035+
CHECK_BACKWARDS_JUMP_TARGET();
20092036
if (oparg == NB_ADD || oparg == NB_SUBTRACT || oparg == NB_MULTIPLY) {
20102037
// Add operation. Need to check if we can infer types.
20112038
_Py_CODEUNIT *possible_next = infer_BINARY_OP(t2_start,
@@ -2029,6 +2056,7 @@ _PyTier2_Code_DetectAndEmitBB(
20292056
}
20302057
DISPATCH_REBOX(2);
20312058
case BINARY_SUBSCR: {
2059+
CHECK_BACKWARDS_JUMP_TARGET();
20322060
_Py_CODEUNIT *possible_next = infer_BINARY_SUBSCR(
20332061
t2_start, oparg, &needs_guard,
20342062
*curr,
@@ -2049,6 +2077,7 @@ _PyTier2_Code_DetectAndEmitBB(
20492077
continue;
20502078
}
20512079
case STORE_SUBSCR: {
2080+
CHECK_BACKWARDS_JUMP_TARGET();
20522081
_Py_CODEUNIT *possible_next = infer_BINARY_SUBSCR(
20532082
t2_start, oparg, &needs_guard,
20542083
*curr,
@@ -2075,31 +2104,53 @@ _PyTier2_Code_DetectAndEmitBB(
20752104
case UNARY_INVERT:
20762105
case GET_LEN:
20772106
case UNPACK_SEQUENCE:
2107+
CHECK_BACKWARDS_JUMP_TARGET();
20782108
DISPATCH_REBOX(1);
20792109
case CALL_INTRINSIC_2:
20802110
case BINARY_SLICE:
2111+
CHECK_BACKWARDS_JUMP_TARGET();
20812112
DISPATCH_REBOX(2);
20822113
case STORE_SLICE:
2114+
CHECK_BACKWARDS_JUMP_TARGET();
20832115
DISPATCH_REBOX(4);
20842116
default:
20852117
#if BB_DEBUG && !TYPEPROP_DEBUG
20862118
fprintf(stderr, "offset: %Id\n", curr - _PyCode_CODE(co));
20872119
#endif
20882120
// This should be the end of another basic block, or the start of a new.
20892121
// Start of a new basic block, just ignore and continue.
2122+
start_virtual_bb:
20902123
if (virtual_start) {
2124+
checked_jump_target = true;
20912125
#if BB_DEBUG
20922126
fprintf(stderr, "Emitted virtual start of basic block\n");
20932127
#endif
2094-
starts_with_backwards_jump_target = true;
20952128
virtual_start = false;
20962129
start_type_context_copy = _PyTier2TypeContext_Copy(starting_type_context);
20972130
if (start_type_context_copy == NULL) {
20982131
_PyTier2TypeContext_Free(starting_type_context);
20992132
return NULL;
21002133
}
2134+
// Add the basic block to the jump ids
2135+
assert(start_type_context_copy != NULL);
2136+
assert(virtual_tier1_start != NULL);
2137+
if (add_metadata_to_jump_2d_array(t2_info, meta,
2138+
backwards_jump_target_offset, start_type_context_copy,
2139+
virtual_tier1_start) < 0) {
2140+
PyMem_Free(meta);
2141+
if (meta != temp_meta) {
2142+
PyMem_Free(temp_meta);
2143+
}
2144+
_PyTier2TypeContext_Free(starting_type_context);
2145+
return NULL;
2146+
}
2147+
if (from_another_opcode) {
2148+
DISPATCH_GOTO();
2149+
}
21012150
goto fall_through;
21022151
}
2152+
check_backwards_jump_target:
2153+
checked_jump_target = true;
21032154
if (IS_BACKWARDS_JUMP_TARGET(co, curr)) {
21042155
#if BB_DEBUG
21052156
fprintf(stderr, "Encountered a backward jump target\n");
@@ -2142,6 +2193,10 @@ _PyTier2_Code_DetectAndEmitBB(
21422193
DISPATCH_GOTO();
21432194
}
21442195
// Don't change opcode or oparg, let us handle it again.
2196+
goto start_virtual_bb;
2197+
}
2198+
if (from_another_opcode) {
2199+
from_another_opcode = false;
21452200
DISPATCH_GOTO();
21462201
}
21472202
fall_through:
@@ -2203,21 +2258,6 @@ _PyTier2_Code_DetectAndEmitBB(
22032258
if (meta == NULL) {
22042259
meta = temp_meta;
22052260
}
2206-
if (starts_with_backwards_jump_target) {
2207-
// Add the basic block to the jump ids
2208-
assert(start_type_context_copy != NULL);
2209-
assert(virtual_tier1_start != NULL);
2210-
if (add_metadata_to_jump_2d_array(t2_info, temp_meta,
2211-
backwards_jump_target_offset, start_type_context_copy,
2212-
virtual_tier1_start) < 0) {
2213-
PyMem_Free(meta);
2214-
if (meta != temp_meta) {
2215-
PyMem_Free(temp_meta);
2216-
}
2217-
_PyTier2TypeContext_Free(starting_type_context);
2218-
return NULL;
2219-
}
2220-
}
22212261
// Tell BB space the number of bytes we wrote.
22222262
// -1 becaues write_i points to the instruction AFTER the end
22232263
bb_space->water_level += (write_i - t2_start) * sizeof(_Py_CODEUNIT);
@@ -3025,6 +3065,9 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged
30253065
jump_offset_id = i;
30263066
for (int x = 0; x < MAX_BB_VERSIONS; x++) {
30273067
int target_bb_id = t2_info->backward_jump_target_bb_pairs[i][x].id;
3068+
#if BB_DEBUG
3069+
fprintf(stderr, "jump offset bb id considered: %d\n", target_bb_id);
3070+
#endif
30283071
if (target_bb_id >= 0) {
30293072
candidate_bb_id = target_bb_id;
30303073
candidate_bb_tier1_start = t2_info->backward_jump_target_bb_pairs[i][x].tier1_start;

tier2_test.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,48 @@ def f(x, items):
573573

574574
# As long as it doesn't crash, everything's good.
575575

576+
577+
with TestInfo("multiple jump targets in a single BB that could be jumped to"):
578+
# See https://github.com/pylbbv/pylbbv/issues/38 for more information.
579+
def f(x, l):
580+
if x == 1: # Trigger tier2 generation
581+
return x+x
582+
while True:
583+
for i in l:
584+
if i: break
585+
else:
586+
l = [True]
587+
continue
588+
break
589+
590+
for i in range(63): f(1, [])
591+
592+
f(0, [False])
593+
594+
# As long as it doesn't crash, everything's good
595+
596+
with TestInfo("a special op itself could also be a jump target"):
597+
# See https://github.com/pylbbv/pylbbv/issues/38 for more information.
598+
def f(x, items):
599+
if x == 0: # Trigger tier2 generation
600+
return x+x
601+
ret = "uwu"
602+
x = 1
603+
while True and x < 256:
604+
x += 1
605+
for item in items:
606+
if not item: break
607+
else:
608+
continue
609+
break
610+
return ret
611+
612+
for i in range(63): f(0, [])
613+
614+
f(1, [True])
615+
616+
# As long as it doesn't crash, everything's good
617+
576618
print("Regression tests...Done!")
577619

578620
print("Tests completed ^-^")

0 commit comments

Comments
 (0)