Skip to content

Commit fb72fcd

Browse files
sorta working
1 parent 2443f21 commit fb72fcd

File tree

6 files changed

+34157
-62
lines changed

6 files changed

+34157
-62
lines changed

Python/bytecodes.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,7 @@ dummy_func(
10181018
}
10191019

10201020
tier1 inst(INTERPRETER_EXIT, (retval --)) {
1021-
assert(frame == &entry_frame);
1021+
assert(frame == entry_frame);
10221022
assert(_PyFrame_IsIncomplete(frame));
10231023
/* Restore previous frame and return. */
10241024
tstate->current_frame = frame->previous;
@@ -1034,7 +1034,7 @@ dummy_func(
10341034
// is pushed to a different frame, the callers' frame.
10351035
inst(RETURN_VALUE, (retval -- res)) {
10361036
#if TIER_ONE
1037-
assert(frame != &entry_frame);
1037+
assert(frame != entry_frame);
10381038
#endif
10391039
_PyStackRef temp = retval;
10401040
DEAD(retval);
@@ -1133,7 +1133,7 @@ dummy_func(
11331133
PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver);
11341134

11351135
PyObject *retval_o;
1136-
assert(frame != &entry_frame);
1136+
assert(frame != entry_frame);
11371137
if ((tstate->interp->eval_frame == NULL) &&
11381138
(Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) &&
11391139
((PyGenObject *)receiver_o)->gi_frame_state < FRAME_EXECUTING)
@@ -1207,7 +1207,7 @@ dummy_func(
12071207
// The compiler treats any exception raised here as a failed close()
12081208
// or throw() call.
12091209
#if TIER_ONE
1210-
assert(frame != &entry_frame);
1210+
assert(frame != entry_frame);
12111211
#endif
12121212
frame->instr_ptr++;
12131213
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame);
@@ -1303,7 +1303,7 @@ dummy_func(
13031303

13041304
tier1 inst(CLEANUP_THROW, (sub_iter_st, last_sent_val_st, exc_value_st -- none, value)) {
13051305
PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st);
1306-
assert(throwflag);
1306+
// assert(throwflag);
13071307
assert(exc_value && PyExceptionInstance_Check(exc_value));
13081308

13091309
int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration);

Python/ceval.c

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -781,13 +781,33 @@ _PyObjectArray_Free(PyObject **array, PyObject **scratch)
781781
/* This setting is reversed below following _PyEval_EvalFrameDefault */
782782
#endif
783783

784+
#ifdef Py_TAIL_CALL_INTERP
785+
#include "generated_cases_tail_call.c.h"
786+
#endif
787+
788+
#ifdef LLTRACE
789+
PyObject *
790+
_TAIL_CALL_shim(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer,
791+
PyThreadState *tstate, _Py_CODEUNIT *next_instr, int oparg, _PyInterpreterFrame* entry_frame, int lltrace)
792+
{
793+
return (INSTRUCTION_TABLE[next_instr->op.code])(frame, stack_pointer, tstate, next_instr, next_instr->op.arg, entry_frame, lltrace);
794+
}
795+
#else
796+
PyObject *
797+
_TAIL_CALL_shim(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer,
798+
PyThreadState *tstate, _Py_CODEUNIT *next_instr, int oparg, _PyInterpreterFrame* entry_frame)
799+
{
800+
return (INSTRUCTION_TABLE[next_instr->op.code])(frame, stack_pointer, tstate, next_instr, next_instr->op.arg, entry_frame);
801+
}
802+
#endif
803+
784804
PyObject* _Py_HOT_FUNCTION
785805
_PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag)
786806
{
787807
_Py_EnsureTstateNotNULL(tstate);
788808
CALL_STAT_INC(pyeval_calls);
789809

790-
#if USE_COMPUTED_GOTOS
810+
#if USE_COMPUTED_GOTOS && !defined(Py_TAIL_CALL_INTERP)
791811
/* Import the static jump table */
792812
#include "opcode_targets.h"
793813
#endif
@@ -801,27 +821,28 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
801821
int lltrace = 0;
802822
#endif
803823

804-
_PyInterpreterFrame entry_frame;
824+
_PyInterpreterFrame e;
825+
_PyInterpreterFrame *entry_frame = &e;
805826

806827

807828

808829
#if defined(Py_DEBUG) && !defined(Py_STACKREF_DEBUG)
809830
/* Set these to invalid but identifiable values for debugging. */
810-
entry_frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0};
811-
entry_frame.f_locals = (PyObject*)0xaaa1;
812-
entry_frame.frame_obj = (PyFrameObject*)0xaaa2;
813-
entry_frame.f_globals = (PyObject*)0xaaa3;
814-
entry_frame.f_builtins = (PyObject*)0xaaa4;
831+
e.f_funcobj = (_PyStackRef){.bits = 0xaaa0};
832+
e.f_locals = (PyObject*)0xaaa1;
833+
e.frame_obj = (PyFrameObject*)0xaaa2;
834+
e.f_globals = (PyObject*)0xaaa3;
835+
e.f_builtins = (PyObject*)0xaaa4;
815836
#endif
816-
entry_frame.f_executable = PyStackRef_None;
817-
entry_frame.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS + 1;
818-
entry_frame.stackpointer = entry_frame.localsplus;
819-
entry_frame.owner = FRAME_OWNED_BY_CSTACK;
820-
entry_frame.visited = 0;
821-
entry_frame.return_offset = 0;
837+
e.f_executable = PyStackRef_None;
838+
e.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS + 1;
839+
e.stackpointer = e.localsplus;
840+
e.owner = FRAME_OWNED_BY_CSTACK;
841+
e.visited = 0;
842+
e.return_offset = 0;
822843
/* Push frame */
823-
entry_frame.previous = tstate->current_frame;
824-
frame->previous = &entry_frame;
844+
e.previous = tstate->current_frame;
845+
frame->previous = entry_frame;
825846
tstate->current_frame = frame;
826847

827848
tstate->c_recursion_remaining -= (PY_EVAL_C_STACK_UNITS - 1);
@@ -878,7 +899,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
878899
stack_pointer = _PyFrame_GetStackPointer(frame);
879900

880901
#ifdef LLTRACE
881-
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
902+
lltrace = maybe_lltrace_resume_frame(frame, entry_frame, GLOBALS());
882903
if (lltrace < 0) {
883904
goto exit_unwind;
884905
}
@@ -891,18 +912,26 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
891912
assert(!_PyErr_Occurred(tstate));
892913
#endif
893914

915+
#ifdef Py_TAIL_CALL_INTERP
916+
#ifdef LLTRACE
917+
return _TAIL_CALL_shim(frame, stack_pointer, tstate, next_instr, 0, entry_frame, lltrace);
918+
#else
919+
return _TAIL_CALL_shim(frame, stack_pointer, tstate, next_instr, 0, entry_frame);
920+
#endif
921+
#else
894922
DISPATCH();
923+
#endif
895924

896925
{
897926
/* Start instructions */
898-
#if !USE_COMPUTED_GOTOS
927+
#if !USE_COMPUTED_GOTOS && !defined(Py_TAIL_CALL_INTERP)
899928
dispatch_opcode:
900929
switch (opcode)
901930
#endif
902931
{
903-
932+
#ifndef Py_TAIL_CALL_INTERP
904933
#include "generated_cases.c.h"
905-
934+
#endif
906935

907936
#if USE_COMPUTED_GOTOS
908937
_unknown_opcode:
@@ -945,7 +974,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
945974
#endif
946975

947976
/* Log traceback info. */
948-
assert(frame != &entry_frame);
977+
assert(frame != entry_frame);
949978
if (!_PyFrame_IsIncomplete(frame)) {
950979
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
951980
if (f != NULL) {
@@ -1004,20 +1033,29 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
10041033
lltrace_resume_frame(frame);
10051034
}
10061035
#endif
1036+
1037+
#ifdef Py_TAIL_CALL_INTERP
1038+
#ifdef LLTRACE
1039+
return _TAIL_CALL_shim(frame, stack_pointer, tstate, next_instr, 0, entry_frame, lltrace);
1040+
#else
1041+
return _TAIL_CALL_shim(frame, stack_pointer, tstate, next_instr, 0, entry_frame);
1042+
#endif
1043+
#else
10071044
DISPATCH();
1045+
#endif
10081046
}
10091047
}
10101048

10111049
exit_unwind:
10121050
assert(_PyErr_Occurred(tstate));
10131051
_Py_LeaveRecursiveCallPy(tstate);
1014-
assert(frame != &entry_frame);
1052+
assert(frame != entry_frame);
10151053
// GH-99729: We need to unlink the frame *before* clearing it:
10161054
_PyInterpreterFrame *dying = frame;
10171055
frame = tstate->current_frame = dying->previous;
10181056
_PyEval_FrameClearAndPop(tstate, dying);
10191057
frame->return_offset = 0;
1020-
if (frame == &entry_frame) {
1058+
if (frame == entry_frame) {
10211059
/* Restore previous frame and exit */
10221060
tstate->current_frame = frame->previous;
10231061
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;

Python/ceval_macros.h

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,26 @@
7070
#define INSTRUCTION_STATS(op) ((void)0)
7171
#endif
7272

73-
#if USE_COMPUTED_GOTOS
73+
#ifdef Py_TAIL_CALL_INTERP
74+
#ifdef LLTRACE
75+
__attribute__((preserve_none))
76+
typedef PyObject* (*py_tail_call_funcptr)(_PyInterpreterFrame *, _PyStackRef *, PyThreadState *tstate, _Py_CODEUNIT *, int, _PyInterpreterFrame *, int);
77+
#else
78+
__attribute__((preserve_none))
79+
typedef PyObject* (*py_tail_call_funcptr)(_PyInterpreterFrame *, _PyStackRef *, PyThreadState *tstate, _Py_CODEUNIT *, int, _PyInterpreterFrame *);
80+
#endif
81+
#ifdef LLTRACE
82+
#define DISPATCH_GOTO() do { \
83+
__attribute__((musttail)) \
84+
return (INSTRUCTION_TABLE[opcode])(frame, stack_pointer, tstate, next_instr, oparg, entry_frame, lltrace); \
85+
} while (0)
86+
#else
87+
#define DISPATCH_GOTO() do { \
88+
__attribute__((musttail)) \
89+
return (INSTRUCTION_TABLE[opcode])(frame, stack_pointer, tstate, next_instr, entry_frame, oparg); \
90+
} while (0)
91+
#endif
92+
#elif USE_COMPUTED_GOTOS
7493
# define TARGET(op) TARGET_##op:
7594
# define DISPATCH_GOTO() goto *opcode_targets[opcode]
7695
#else
@@ -89,7 +108,7 @@
89108
#if LLTRACE
90109
#define LLTRACE_RESUME_FRAME() \
91110
do { \
92-
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); \
111+
lltrace = maybe_lltrace_resume_frame(frame, entry_frame, GLOBALS()); \
93112
if (lltrace < 0) { \
94113
goto exit_unwind; \
95114
} \
@@ -121,6 +140,46 @@ do { \
121140
DISPATCH_GOTO(); \
122141
}
123142

143+
#ifdef Py_TAIL_CALL_INTERP
144+
#ifdef LLTRACE
145+
#define DISPATCH_INLINED(NEW_FRAME) \
146+
do { \
147+
assert(tstate->interp->eval_frame == NULL); \
148+
_PyFrame_SetStackPointer(frame, stack_pointer); \
149+
assert((NEW_FRAME)->previous == frame); \
150+
frame = tstate->current_frame = (NEW_FRAME); \
151+
CALL_STAT_INC(inlined_py_calls); \
152+
if (_Py_EnterRecursivePy(tstate)) {\
153+
goto exit_unwind;\
154+
} \
155+
next_instr = frame->instr_ptr; \
156+
stack_pointer = _PyFrame_GetStackPointer(frame); \
157+
lltrace = maybe_lltrace_resume_frame(frame, entry_frame, GLOBALS()); \
158+
if (lltrace < 0) { \
159+
goto exit_unwind; \
160+
} \
161+
NEXTOPARG(); \
162+
__attribute__((musttail)) \
163+
return (INSTRUCTION_TABLE[opcode])(frame, stack_pointer, tstate, next_instr, oparg, entry_frame, lltrace); \
164+
} while (0)
165+
#else
166+
do { \
167+
assert(tstate->interp->eval_frame == NULL); \
168+
_PyFrame_SetStackPointer(frame, stack_pointer); \
169+
assert((NEW_FRAME)->previous == frame); \
170+
frame = tstate->current_frame = (NEW_FRAME); \
171+
CALL_STAT_INC(inlined_py_calls); \
172+
if (_Py_EnterRecursivePy(tstate)) {\
173+
goto exit_unwind;\
174+
} \
175+
next_instr = frame->instr_ptr; \
176+
stack_pointer = _PyFrame_GetStackPointer(frame); \
177+
NEXTOPARG(); \
178+
__attribute__((musttail)) \
179+
return (INSTRUCTION_TABLE[opcode])(frame, stack_pointer, tstate, next_instr, oparg, entry_frame, lltrace); \
180+
} while (0)
181+
#endif
182+
#else
124183
#define DISPATCH_INLINED(NEW_FRAME) \
125184
do { \
126185
assert(tstate->interp->eval_frame == NULL); \
@@ -130,6 +189,7 @@ do { \
130189
CALL_STAT_INC(inlined_py_calls); \
131190
goto start_frame; \
132191
} while (0)
192+
#endif
133193

134194
// Use this instead of 'goto error' so Tier 2 can go to a different label
135195
#define GOTO_ERROR(LABEL) goto LABEL
@@ -238,7 +298,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
238298
#endif
239299

240300
#define WITHIN_STACK_BOUNDS() \
241-
(frame == &entry_frame || (STACK_LEVEL() >= 0 && STACK_LEVEL() <= STACK_SIZE()))
301+
(frame == entry_frame || (STACK_LEVEL() >= 0 && STACK_LEVEL() <= STACK_SIZE()))
242302

243303
/* Data access macros */
244304
#define FRAME_CO_CONSTS (_PyFrame_GetCode(frame)->co_consts)
@@ -258,8 +318,21 @@ GETITEM(PyObject *v, Py_ssize_t i) {
258318
#define SETLOCAL(i, value) do { _PyStackRef tmp = GETLOCAL(i); \
259319
GETLOCAL(i) = value; \
260320
PyStackRef_XCLOSE(tmp); } while (0)
261-
321+
#ifdef Py_TAIL_CALL_INTERP
322+
#ifdef LLTRACE
323+
#define GO_TO_INSTRUCTION(op) do { \
324+
__attribute__((musttail)) \
325+
return (INSTRUCTION_TABLE[op])(frame, stack_pointer, tstate, next_instr - 1 - _PyOpcode_Caches[_PyOpcode_Deopt[op]], oparg, entry_frame, lltrace); \
326+
} while (0)
327+
#else
328+
#define GO_TO_INSTRUCTION(op) do { \
329+
__attribute__((musttail)) \
330+
return (INSTRUCTION_TABLE[op])(frame, stack_pointer, tstate, next_instr - 1 - _PyOpcode_Caches[_PyOpcode_Deopt[op]], oparg, entry_frame); \
331+
} while (0)
332+
#endif
333+
#else
262334
#define GO_TO_INSTRUCTION(op) goto PREDICT_ID(op)
335+
#endif
263336

264337
#ifdef Py_STATS
265338
#define UPDATE_MISS_STATS(INSTNAME) \

0 commit comments

Comments
 (0)