Skip to content

Commit bf19b03

Browse files
feat: execute jitted code in backward jumps (python#74)
* feat: execute jitted code in backward jumps * nit: fix typos
1 parent 81e84a4 commit bf19b03

File tree

4 files changed

+112
-25
lines changed

4 files changed

+112
-25
lines changed

Include/internal/pycore_code.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,11 @@ extern _PyTier2BBMetadata *_PyTier2_GenerateNextBB(
288288
int jumpby,
289289
_Py_CODEUNIT **tier1_fallback,
290290
char bb_flag);
291-
extern _Py_CODEUNIT *_PyTier2_LocateJumpBackwardsBB(
291+
extern _PyTier2BBMetadata *_PyTier2_LocateJumpBackwardsBB(
292292
struct _PyInterpreterFrame *frame, uint16_t bb_id, int jumpby,
293293
_Py_CODEUNIT **tier1_fallback, _Py_CODEUNIT *curr, int stacksize);
294294
extern void _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target);
295-
extern void _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *target);
295+
extern void _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *target, _PyTier2BBMetadata *meta);
296296
void _PyTier2TypeContext_Free(_PyTier2TypeContext *type_context);
297297
#ifdef Py_STATS
298298

Python/bytecodes.c

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1940,9 +1940,31 @@ dummy_func(
19401940
}
19411941

19421942
inst(JUMP_BACKWARD_QUICK, (unused/10 --)) {
1943+
_PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr;
19431944
assert((oparg - INLINE_CACHE_ENTRIES_JUMP_BACKWARD) < INSTR_OFFSET());
19441945
JUMPBY(-oparg);
1946+
JUMPBY(INLINE_CACHE_ENTRIES_JUMP_BACKWARD);
19451947
CHECK_EVAL_BREAKER();
1948+
_PyJITFunction trace = (_PyJITFunction)read_obj(cache->consequent_trace);
1949+
if (trace != NULL) {
1950+
// The following code is partially adapted from Brandt Bucher's https://github.com/brandtbucher/cpython/blob/justin/Python/bytecodes.c#L2175
1951+
_PyJITReturnCode status = ((_PyJITFunction)(trace))(tstate, frame, stack_pointer, next_instr);
1952+
frame = cframe.current_frame;
1953+
next_instr = frame->prev_instr;
1954+
stack_pointer = _PyFrame_GetStackPointer(frame);
1955+
switch (status) {
1956+
case _JUSTIN_RETURN_DEOPT:
1957+
NEXTOPARG();
1958+
opcode = _PyOpcode_Deopt[opcode];
1959+
DISPATCH_GOTO();
1960+
case _JUSTIN_RETURN_OK:
1961+
DISPATCH();
1962+
case _JUSTIN_RETURN_GOTO_ERROR:
1963+
goto error;
1964+
}
1965+
Py_UNREACHABLE();
1966+
}
1967+
DISPATCH();
19461968
}
19471969

19481970
inst(POP_JUMP_IF_FALSE, (cond -- )) {
@@ -3554,18 +3576,37 @@ dummy_func(
35543576
_Py_CODEUNIT *t2_nextinstr = NULL;
35553577
_PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr;
35563578
_Py_CODEUNIT *tier1_fallback = NULL;
3557-
3558-
t2_nextinstr = _PyTier2_LocateJumpBackwardsBB(
3579+
_PyTier2BBMetadata *meta = _PyTier2_LocateJumpBackwardsBB(
35593580
frame, cache->bb_id_tagged, -oparg, &tier1_fallback, curr,
35603581
STACK_LEVEL());
3561-
if (t2_nextinstr == NULL) {
3582+
if (meta == NULL) {
35623583
// Fall back to tier 1.
35633584
next_instr = tier1_fallback;
35643585
}
3565-
next_instr = t2_nextinstr;
3586+
else {
3587+
next_instr = meta->tier2_start;
3588+
}
35663589

35673590
// Rewrite self
3568-
_PyTier2_RewriteBackwardJump(curr, next_instr);
3591+
_PyTier2_RewriteBackwardJump(curr, next_instr, meta);
3592+
if (meta != NULL && meta->machine_code != NULL) {
3593+
// The following code is partially adapted from Brandt Bucher's https://github.com/brandtbucher/cpython/blob/justin/Python/bytecodes.c#L2175
3594+
_PyJITReturnCode status = ((_PyJITFunction)(meta->machine_code))(tstate, frame, stack_pointer, next_instr);
3595+
frame = cframe.current_frame;
3596+
next_instr = frame->prev_instr;
3597+
stack_pointer = _PyFrame_GetStackPointer(frame);
3598+
switch (status) {
3599+
case _JUSTIN_RETURN_DEOPT:
3600+
NEXTOPARG();
3601+
opcode = _PyOpcode_Deopt[opcode];
3602+
DISPATCH_GOTO();
3603+
case _JUSTIN_RETURN_OK:
3604+
DISPATCH();
3605+
case _JUSTIN_RETURN_GOTO_ERROR:
3606+
goto error;
3607+
}
3608+
Py_UNREACHABLE();
3609+
}
35693610
DISPATCH();
35703611
}
35713612

Python/generated_cases.c.h

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

Python/tier2.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ jit_compile(
107107
written++;
108108
i += caches;
109109
}
110-
// Nothing to compile...
111-
if (written == 0) {
110+
// Nothing to compile, or too short to make it worth it!
111+
if (written <= 2) {
112112
PyMem_Free(trace);
113113
return 0;
114114
}
@@ -1239,6 +1239,7 @@ IS_FORBIDDEN_OPCODE(int opcode, int nextop)
12391239
case GET_ANEXT:
12401240
case BEFORE_ASYNC_WITH:
12411241
case END_ASYNC_FOR:
1242+
case GET_YIELD_FROM_ITER:
12421243
// Raise keyword
12431244
case RAISE_VARARGS:
12441245
// Exceptions, we could support these theoretically.
@@ -1638,7 +1639,7 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, int target_bb_id,
16381639
_Py_CODEUNIT *tier1_start)
16391640
{
16401641
#if BB_DEBUG
1641-
fprintf(stderr, "Attempting to add jump id %d as jump target\n", meta->id);
1642+
fprintf(stderr, "Attempting to add jump id %d as jump target\n", target_bb_id);
16421643
#endif
16431644
// Locate where to insert the BB ID
16441645
int backward_jump_offset_index = 0;
@@ -1658,7 +1659,7 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, int target_bb_id,
16581659
if (t2_info->backward_jump_target_bb_pairs[backward_jump_offset_index][jump_i].id ==
16591660
-1) {
16601661
#if BB_DEBUG
1661-
fprintf(stderr, "Added jump id %d as jump target\n", meta->id);
1662+
fprintf(stderr, "Added jump id %d as jump target\n", target_bb_id);
16621663
#endif
16631664
t2_info->backward_jump_target_bb_pairs[backward_jump_offset_index][jump_i].id = target_bb_id;
16641665
t2_info->backward_jump_target_bb_pairs[backward_jump_offset_index][jump_i].start_type_context = starting_context;
@@ -2383,8 +2384,8 @@ _PyTier2_Code_DetectAndEmitBB(
23832384
// Tell BB space the number of bytes we wrote.
23842385
bb_space->water_level += (write_i - t2_start) * sizeof(_Py_CODEUNIT);
23852386
#if BB_DEBUG
2386-
fprintf(stderr, "Generated BB T2 Start: %p, T1 offset: %zu\n", meta->tier2_start,
2387-
meta->tier1_end - _PyCode_CODE(co));
2387+
fprintf(stderr, "Generated BB T2 Start: %p, T1 offset: %zu\n", metas[0]->tier2_start,
2388+
metas[0]->tier1_end - _PyCode_CODE(co));
23882389
#endif
23892390
assert(metas_size >= 0);
23902391
// JIT compile the bb
@@ -3137,9 +3138,9 @@ diff_typecontext(_PyTier2TypeContext *ctx1, _PyTier2TypeContext *ctx2)
31373138
* @param tier1_fallback Signals the tier 1 instruction to fall back to should generation fail.
31383139
* @param curr Current executing instruction
31393140
* @param stacklevel The stack level of the operand stack.
3140-
* @return The next tier 2 instruction to execute.
3141+
* @return The target BB's metadata.
31413142
*/
3142-
_Py_CODEUNIT *
3143+
_PyTier2BBMetadata *
31433144
_PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged, int jumpby,
31443145
_Py_CODEUNIT **tier1_fallback,
31453146
_Py_CODEUNIT *curr, int stacklevel)
@@ -3265,15 +3266,15 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged
32653266
}
32663267
}
32673268
assert(found);
3268-
return meta->tier2_start;
3269+
return meta;
32693270
}
32703271
assert(matching_bb_id >= 0);
32713272
assert(matching_bb_id <= t2_info->bb_data_curr);
32723273
#if BB_DEBUG
32733274
fprintf(stderr, "Using jump target BB ID: %d\n", matching_bb_id);
32743275
#endif
32753276
_PyTier2BBMetadata *target_metadata = t2_info->bb_data[matching_bb_id];
3276-
return target_metadata->tier2_start;
3277+
return target_metadata;
32773278
}
32783279

32793280

@@ -3325,7 +3326,7 @@ _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target)
33253326

33263327

33273328
/**
3328-
* @brief Rewrites a BB_dD_LAZY to a more efficient standard BACKWARD_JUMP.
3329+
* @brief Rewrites a BB_JUMP_BACKWARD_LAZY to a more efficient standard BACKWARD_JUMP.
33293330
*
33303331
* Before:
33313332
*
@@ -3343,9 +3344,10 @@ _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target)
33433344
*
33443345
* @param jump_backward_lazy The backwards jump instruction.
33453346
* @param target The target we're jumping to.
3347+
* @param meta The target's BB metadata.
33463348
*/
33473349
void
3348-
_PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *target)
3350+
_PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *target, _PyTier2BBMetadata *meta)
33493351
{
33503352
_Py_CODEUNIT *write_curr = jump_backward_lazy - 1;
33513353
_Py_CODEUNIT *prev = jump_backward_lazy - 1;
@@ -3379,6 +3381,11 @@ _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *tar
33793381
? JUMP_BACKWARD_QUICK
33803382
: JUMP_FORWARD);
33813383
write_curr->op.arg = oparg & 0xFF;
3384+
write_curr++;
3385+
_PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr;
3386+
if (meta != NULL && is_backwards_jump) {
3387+
write_obj(cache->consequent_trace, (PyObject *)meta->machine_code);
3388+
}
33823389
return;
33833390
}
33843391

0 commit comments

Comments
 (0)