Skip to content

Commit b6c0fc5

Browse files
fix: handle when a single BB may have multiple jump targets (python#39)
* fix: handle when a single BB may have multiple jump targets * nit: remove wrong comment
1 parent 5261ecc commit b6c0fc5

File tree

4 files changed

+49
-6
lines changed

4 files changed

+49
-6
lines changed

Lib/dis.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@
6464
_bb_jumps.append(uop_opcode)
6565
_inline_cache_entries[uop_opcode] = 2
6666
_uop_hasoparg.append(uop_opcode)
67+
if uop.startswith('BB_TEST_ITER'):
68+
_inline_cache_entries[uop_opcode] = 1
6769

6870
deoptmap = {
6971
specialized: base for base, family in _specializations.items() for specialized in family

Python/ceval.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
751751
entry_frame.stacktop = 0;
752752
entry_frame.owner = FRAME_OWNED_BY_CSTACK;
753753
entry_frame.yield_offset = 0;
754+
entry_frame.is_tier2 = false;
754755
/* Push frame */
755756
entry_frame.previous = prev_cframe->current_frame;
756757
frame->previous = &entry_frame;

Python/tier2.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,7 @@ emit_scope_exit(_Py_CODEUNIT *write_curr, _Py_CODEUNIT exit,
14431443
static inline _Py_CODEUNIT *
14441444
emit_i(_Py_CODEUNIT *write_curr, int opcode, int oparg)
14451445
{
1446+
assert(opcode != JUMP_FORWARD);
14461447
if (oparg > 0xFF) {
14471448
_py_set_opcode(write_curr, EXTENDED_ARG);
14481449
write_curr->op.arg = (oparg >> 8) & 0xFF;
@@ -1858,9 +1859,14 @@ _PyTier2_Code_DetectAndEmitBB(
18581859
case END_FOR:
18591860
// Assert that we are the start of a BB
18601861
assert(t2_start == write_i);
1861-
// Though we want to emit this, we don't want to start execution from END_FOR.
1862-
// So we tell the BB to skip over it.
1863-
t2_start++;
1862+
1863+
if (_PyOpcode_Deopt[(curr - 1)->op.code] == JUMP_BACKWARD) {
1864+
// If this follows a JUMP_BACKWARDS,
1865+
// Though we want to emit this, we don't want to start execution from END_FOR.
1866+
// So we tell the BB to skip over it.
1867+
t2_start++;
1868+
}
1869+
// Else, we do want to execute this.
18641870
DISPATCH();
18651871
case POP_TOP: {
18661872
// Read-only, only for us to inspect the types. DO NOT MODIFY HERE.
@@ -2108,7 +2114,9 @@ _PyTier2_Code_DetectAndEmitBB(
21082114
if (type_context_copy == NULL) {
21092115
return NULL;
21102116
}
2111-
meta = _PyTier2_AllocateBBMetaData(co,
2117+
// We can't unconditionally overwrite the first bb
2118+
// because we might have multiple jump targets in a single BB.
2119+
meta = meta != NULL ? meta : _PyTier2_AllocateBBMetaData(co,
21122120
t2_start, _PyCode_CODE(co) + i, type_context_copy);
21132121
if (meta == NULL) {
21142122
_PyTier2TypeContext_Free(type_context_copy);
@@ -3008,9 +3016,12 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged
30083016
#endif
30093017
for (int i = 0; i < t2_info->backward_jump_count; i++) {
30103018
#if BB_DEBUG
3011-
fprintf(stderr, "jump offset checked: %d\n", t2_info->backward_jump_offsets[i]);
3019+
fprintf(stderr, "jump offset considered: %d\n", t2_info->backward_jump_offsets[i]);
30123020
#endif
30133021
if (t2_info->backward_jump_offsets[i] == jump_offset) {
3022+
#if BB_DEBUG
3023+
fprintf(stderr, "jump offset matched: %d\n", t2_info->backward_jump_offsets[i]);
3024+
#endif
30143025
jump_offset_id = i;
30153026
for (int x = 0; x < MAX_BB_VERSIONS; x++) {
30163027
int target_bb_id = t2_info->backward_jump_target_bb_pairs[i][x].id;
@@ -3150,12 +3161,14 @@ _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target)
31503161
* EXTENDED_ARG/NOP
31513162
* BB_JUMP_BACKWARD_LAZY
31523163
* CACHE
3164+
* CACHE
31533165
*
31543166
* After:
31553167
*
31563168
* EXTENDED_ARG (if needed, else NOP)
31573169
* JUMP_BACKWARD_QUICK
31583170
* END_FOR
3171+
* NOP
31593172
*
31603173
* @param jump_backward_lazy The backwards jump instruction.
31613174
* @param target The target we're jumping to.
@@ -3198,6 +3211,8 @@ _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *tar
31983211
write_curr++;
31993212
_py_set_opcode(write_curr, END_FOR);
32003213
write_curr++;
3214+
write_curr->op.code = NOP;
3215+
write_curr++;
32013216
return;
32023217
}
32033218

tier2_test.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def writeinst(opc:str, arg:int=0):
3939

4040
return bytes(inst)
4141

42-
42+
print("General feature tests...")
4343
################################################
4444
# Type prop tests: TYPE_SET and TYPE_OVERWRITE #
4545
################################################
@@ -446,6 +446,9 @@ def test_iter_tuple(a):
446446
assert jmp_target.opname == "NOP" # Space for an EXTENDED_ARG
447447
assert insts[instidx + 1].opname == "BB_TEST_ITER_TUPLE" # The loop predicate
448448

449+
print("General feature tests...Done!")
450+
451+
print("Regression tests...")
449452
######################################################################
450453
# Tests for: Tier 2 backward jump type context compatiblity check #
451454
######################################################################
@@ -550,4 +553,26 @@ def f(x):
550553

551554
# As long as it doesn't crash, everything's good.
552555

556+
with TestInfo("multiple jump targets in a single BB"):
557+
# See https://github.com/pylbbv/pylbbv/issues/38 for more information.
558+
def f(x, items):
559+
if x == 0: # Trigger tier2 generation
560+
return x+x
561+
ret = "uwu"
562+
while True:
563+
for item in items:
564+
if item: break
565+
else:
566+
continue
567+
break
568+
return ret
569+
570+
for i in range(63): f(0, [])
571+
572+
f(1, [True])
573+
574+
# As long as it doesn't crash, everything's good.
575+
576+
print("Regression tests...Done!")
577+
553578
print("Tests completed ^-^")

0 commit comments

Comments
 (0)