Skip to content

Commit 2b94491

Browse files
committed
Convert CALL_ALLOC_AND_ENTER_INIT to micro-ops such that tier 2 supports it
1 parent ec4b278 commit 2b94491

File tree

10 files changed

+75
-123
lines changed

10 files changed

+75
-123
lines changed

Include/internal/pycore_frame.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,9 @@ static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *
134134
static inline void
135135
_PyFrame_Initialize(
136136
_PyInterpreterFrame *frame, PyFunctionObject *func,
137-
PyObject *locals, PyCodeObject *code, int null_locals_from)
137+
PyObject *locals, PyCodeObject *code, int null_locals_from, _PyInterpreterFrame *previous)
138138
{
139+
frame->previous = previous;
139140
frame->f_funcobj = (PyObject *)func;
140141
frame->f_executable = Py_NewRef(code);
141142
frame->f_builtins = func->func_builtins;
@@ -277,26 +278,27 @@ PyAPI_FUNC(void) _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFr
277278
* Must be guarded by _PyThreadState_HasStackSpace()
278279
* Consumes reference to func. */
279280
static inline _PyInterpreterFrame *
280-
_PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_locals_from)
281+
_PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_locals_from, _PyInterpreterFrame * previous)
281282
{
282283
CALL_STAT_INC(frames_pushed);
283284
PyCodeObject *code = (PyCodeObject *)func->func_code;
284285
_PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)tstate->datastack_top;
285286
tstate->datastack_top += code->co_framesize;
286287
assert(tstate->datastack_top < tstate->datastack_limit);
287-
_PyFrame_Initialize(new_frame, func, NULL, code, null_locals_from);
288+
_PyFrame_Initialize(new_frame, func, NULL, code, null_locals_from, previous);
288289
return new_frame;
289290
}
290291

291292
/* Pushes a trampoline frame without checking for space.
292293
* Must be guarded by _PyThreadState_HasStackSpace() */
293294
static inline _PyInterpreterFrame *
294-
_PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int stackdepth)
295+
_PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int stackdepth, _PyInterpreterFrame * previous)
295296
{
296297
CALL_STAT_INC(frames_pushed);
297298
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)tstate->datastack_top;
298299
tstate->datastack_top += code->co_framesize;
299300
assert(tstate->datastack_top < tstate->datastack_limit);
301+
frame->previous = previous;
300302
frame->f_funcobj = Py_None;
301303
frame->f_executable = Py_NewRef(code);
302304
#ifdef Py_DEBUG
@@ -315,7 +317,8 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int
315317
PyAPI_FUNC(_PyInterpreterFrame *)
316318
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
317319
PyObject *locals, _PyStackRef const* args,
318-
size_t argcount, PyObject *kwnames);
320+
size_t argcount, PyObject *kwnames,
321+
_PyInterpreterFrame *previous);
319322

320323
#ifdef __cplusplus
321324
}

Include/internal/pycore_opcode_metadata.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_ids.h

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Objects/frameobject.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,8 +1771,7 @@ init_frame(_PyInterpreterFrame *frame, PyFunctionObject *func, PyObject *locals)
17711771
{
17721772
PyCodeObject *code = (PyCodeObject *)func->func_code;
17731773
_PyFrame_Initialize(frame, (PyFunctionObject*)Py_NewRef(func),
1774-
Py_XNewRef(locals), code, 0);
1775-
frame->previous = NULL;
1774+
Py_XNewRef(locals), code, 0, NULL);
17761775
}
17771776

17781777
PyFrameObject*

Python/bytecodes.c

Lines changed: 17 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,7 @@ dummy_func(
774774
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize));
775775
STAT_INC(BINARY_SUBSCR, hit);
776776
Py_INCREF(getitem);
777-
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, getitem, 2);
777+
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame);
778778
STACK_SHRINK(2);
779779
new_frame->localsplus[0] = container_st;
780780
new_frame->localsplus[1] = sub_st;
@@ -1125,6 +1125,8 @@ dummy_func(
11251125
tstate->exc_info = &gen->gi_exc_state;
11261126
assert(next_instr - this_instr + oparg <= UINT16_MAX);
11271127
frame->return_offset = (uint16_t)(next_instr - this_instr + oparg);
1128+
assert(gen_frame->previous == NULL);
1129+
gen_frame->previous = frame;
11281130
DISPATCH_INLINED(gen_frame);
11291131
}
11301132
if (PyStackRef_Is(v, PyStackRef_None) && PyIter_Check(receiver_o)) {
@@ -1168,6 +1170,8 @@ dummy_func(
11681170
tstate->exc_info = &gen->gi_exc_state;
11691171
assert(next_instr - this_instr + oparg <= UINT16_MAX);
11701172
frame->return_offset = (uint16_t)(next_instr - this_instr + oparg);
1173+
gen_frame->previous = frame;
1174+
DISPATCH_INLINED(gen_frame);
11711175
DISPATCH_INLINED(gen_frame);
11721176
}
11731177

@@ -2282,7 +2286,7 @@ dummy_func(
22822286
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize));
22832287
STAT_INC(LOAD_ATTR, hit);
22842288
Py_INCREF(fget);
2285-
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 1);
2289+
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 1, frame);
22862290
// Manipulate stack directly because we exit with DISPATCH_INLINED().
22872291
STACK_SHRINK(1);
22882292
new_frame->localsplus[0] = owner;
@@ -2309,7 +2313,7 @@ dummy_func(
23092313

23102314
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
23112315
Py_INCREF(f);
2312-
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2);
2316+
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2, frame);
23132317
// Manipulate stack directly because we exit with DISPATCH_INLINED().
23142318
STACK_SHRINK(1);
23152319
new_frame->localsplus[0] = owner;
@@ -3091,6 +3095,7 @@ dummy_func(
30913095
gen->gi_frame_state = FRAME_EXECUTING;
30923096
gen->gi_exc_state.previous_item = tstate->exc_info;
30933097
tstate->exc_info = &gen->gi_exc_state;
3098+
gen_frame->previous = frame;
30943099
// oparg is the return offset from the next instruction.
30953100
frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_FOR_ITER + oparg);
30963101
}
@@ -3368,7 +3373,7 @@ dummy_func(
33683373
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
33693374
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
33703375
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
3371-
args, total_args, NULL
3376+
args, total_args, NULL, frame
33723377
);
33733378
// Manipulate stack directly since we leave using DISPATCH_INLINED().
33743379
STACK_SHRINK(oparg + 2);
@@ -3438,7 +3443,7 @@ dummy_func(
34383443
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
34393444
new_frame = _PyEvalFramePushAndInit(
34403445
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
3441-
args, total_args, NULL
3446+
args, total_args, NULL, frame
34423447
);
34433448
// The frame has stolen all the arguments from the stack,
34443449
// so there is no need to clean them up.
@@ -3581,7 +3586,7 @@ dummy_func(
35813586
int has_self = !PyStackRef_IsNull(self_or_null);
35823587
STAT_INC(CALL, hit);
35833588
PyFunctionObject *func = (PyFunctionObject *)callable_o;
3584-
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self);
3589+
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self, frame);
35853590
_PyStackRef *first_non_self_local = new_frame->localsplus + has_self;
35863591
new_frame->localsplus[0] = self_or_null;
35873592
for (int i = 0; i < oparg; i++) {
@@ -3595,7 +3600,7 @@ dummy_func(
35953600
assert(tstate->interp->eval_frame == NULL);
35963601
SYNC_SP();
35973602
_PyFrame_SetStackPointer(frame, stack_pointer);
3598-
new_frame->previous = frame;
3603+
assert(new_frame->previous == frame || new_frame->previous->previous == frame);
35993604
CALL_STAT_INC(inlined_py_calls);
36003605
frame = tstate->current_frame = new_frame;
36013606
tstate->py_recursion_remaining--;
@@ -3699,22 +3704,19 @@ dummy_func(
36993704

37003705
op(_CREATE_INIT_FRAME, (self, init, args[oparg] -- init_frame: _PyInterpreterFrame *)) {
37013706
_PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked(
3702-
tstate, (PyCodeObject *)&_Py_InitCleanup, 1);
3707+
tstate, (PyCodeObject *)&_Py_InitCleanup, 1, frame);
37033708
assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[0].op.code == EXIT_INIT_CHECK);
37043709
/* Push self onto stack of shim */
37053710
shim->localsplus[0] = PyStackRef_DUP(self);
37063711
PyFunctionObject *init_func = (PyFunctionObject *)PyStackRef_AsPyObjectSteal(init);
3707-
init_frame = _PyFrame_PushUnchecked(tstate, init_func, oparg+1);
3712+
init_frame = _PyFrame_PushUnchecked(tstate, init_func, oparg+1, shim);
37083713
/* Copy self followed by args to __init__ frame */
37093714
init_frame->localsplus[0] = self;
37103715
for (int i = 0; i < oparg; i++) {
37113716
init_frame->localsplus[i+1] = args[i];
37123717
}
37133718
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
37143719
SYNC_SP();
3715-
/* Link shim frame */
3716-
shim->previous = frame;
3717-
frame = shim;
37183720
/* Account for pushing the extra frame.
37193721
* We don't check recursion depth here,
37203722
* as it will be checked after start_frame */
@@ -3723,62 +3725,11 @@ dummy_func(
37233725

37243726
macro(CALL_ALLOC_AND_ENTER_INIT) =
37253727
unused/1 +
3728+
_CHECK_PEP_523 +
37263729
_CHECK_AND_ALLOCATE_OBJECT +
37273730
_CREATE_INIT_FRAME +
37283731
_PUSH_FRAME;
37293732

3730-
inst(CALL_ALLOC_AND_ENTER_INIT, (unused/1, unused/2, callable, null, args[oparg] -- unused)) {
3731-
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
3732-
/* This instruction does the following:
3733-
* 1. Creates the object (by calling ``object.__new__``)
3734-
* 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``)
3735-
* 3. Pushes the frame for ``__init__`` to the frame stack
3736-
* */
3737-
_PyCallCache *cache = (_PyCallCache *)&this_instr[1];
3738-
DEOPT_IF(!PyStackRef_IsNull(null));
3739-
DEOPT_IF(!PyType_Check(callable_o));
3740-
PyTypeObject *tp = (PyTypeObject *)callable_o;
3741-
DEOPT_IF(tp->tp_version_tag != read_u32(cache->func_version));
3742-
assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES);
3743-
PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o;
3744-
PyFunctionObject *init = (PyFunctionObject *)cls->_spec_cache.init;
3745-
PyCodeObject *code = (PyCodeObject *)init->func_code;
3746-
DEOPT_IF(code->co_argcount != oparg+1);
3747-
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize));
3748-
STAT_INC(CALL, hit);
3749-
PyObject *self = _PyType_NewManagedObject(tp);
3750-
if (self == NULL) {
3751-
ERROR_NO_POP();
3752-
}
3753-
PyStackRef_CLOSE(callable);
3754-
_PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked(
3755-
tstate, (PyCodeObject *)&_Py_InitCleanup, 1);
3756-
assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[0].op.code == EXIT_INIT_CHECK);
3757-
/* Push self onto stack of shim */
3758-
Py_INCREF(self);
3759-
shim->localsplus[0] = PyStackRef_FromPyObjectSteal(self);
3760-
Py_INCREF(init);
3761-
_PyInterpreterFrame *init_frame = _PyFrame_PushUnchecked(tstate, init, oparg+1);
3762-
/* Copy self followed by args to __init__ frame */
3763-
init_frame->localsplus[0] = PyStackRef_FromPyObjectSteal(self);
3764-
for (int i = 0; i < oparg; i++) {
3765-
init_frame->localsplus[i+1] = args[i];
3766-
}
3767-
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
3768-
STACK_SHRINK(oparg+2);
3769-
_PyFrame_SetStackPointer(frame, stack_pointer);
3770-
/* Link frames */
3771-
init_frame->previous = shim;
3772-
shim->previous = frame;
3773-
frame = tstate->current_frame = init_frame;
3774-
CALL_STAT_INC(inlined_py_calls);
3775-
/* Account for pushing the extra frame.
3776-
* We don't check recursion depth here,
3777-
* as it will be checked after start_frame */
3778-
tstate->py_recursion_remaining--;
3779-
goto start_frame;
3780-
}
3781-
37823733
inst(EXIT_INIT_CHECK, (should_be_none -- )) {
37833734
assert(STACK_LEVEL() == 2);
37843735
if (!PyStackRef_Is(should_be_none, PyStackRef_None)) {
@@ -4229,7 +4180,7 @@ dummy_func(
42294180
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
42304181
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
42314182
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
4232-
args, positional_args, kwnames_o
4183+
args, positional_args, kwnames_o, frame
42334184
);
42344185
PyStackRef_CLOSE(kwnames);
42354186
// Manipulate stack directly since we leave using DISPATCH_INLINED().
@@ -4344,7 +4295,7 @@ dummy_func(
43444295

43454296
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(tstate,
43464297
(PyFunctionObject *)PyStackRef_AsPyObjectSteal(func_st), locals,
4347-
nargs, callargs, kwargs);
4298+
nargs, callargs, kwargs, frame);
43484299
// Need to manually shrink the stack since we exit with DISPATCH_INLINED.
43494300
STACK_SHRINK(oparg + 3);
43504301
if (new_frame == NULL) {

Python/ceval.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg
252252
static int get_exception_handler(PyCodeObject *, int, int*, int*, int*);
253253
static _PyInterpreterFrame *
254254
_PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func,
255-
PyObject *locals, Py_ssize_t nargs, PyObject *callargs, PyObject *kwargs);
255+
PyObject *locals, Py_ssize_t nargs, PyObject *callargs, PyObject *kwargs, _PyInterpreterFrame *previous);
256256

257257
#ifdef HAVE_ERRNO_H
258258
#include <errno.h>
@@ -1736,15 +1736,15 @@ _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame)
17361736
_PyInterpreterFrame *
17371737
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
17381738
PyObject *locals, _PyStackRef const* args,
1739-
size_t argcount, PyObject *kwnames)
1739+
size_t argcount, PyObject *kwnames, _PyInterpreterFrame *previous)
17401740
{
17411741
PyCodeObject * code = (PyCodeObject *)func->func_code;
17421742
CALL_STAT_INC(frames_pushed);
17431743
_PyInterpreterFrame *frame = _PyThreadState_PushFrame(tstate, code->co_framesize);
17441744
if (frame == NULL) {
17451745
goto fail;
17461746
}
1747-
_PyFrame_Initialize(frame, func, locals, code, 0);
1747+
_PyFrame_Initialize(frame, func, locals, code, 0, previous);
17481748
if (initialize_locals(tstate, func, frame->localsplus, args, argcount, kwnames)) {
17491749
assert(frame->owner == FRAME_OWNED_BY_THREAD);
17501750
clear_thread_frame(tstate, frame);
@@ -1771,7 +1771,7 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
17711771
static _PyInterpreterFrame *
17721772
_PyEvalFramePushAndInit_UnTagged(PyThreadState *tstate, PyFunctionObject *func,
17731773
PyObject *locals, PyObject *const* args,
1774-
size_t argcount, PyObject *kwnames)
1774+
size_t argcount, PyObject *kwnames, _PyInterpreterFrame *previous)
17751775
{
17761776
#if defined(Py_GIL_DISABLED)
17771777
size_t kw_count = kwnames == NULL ? 0 : PyTuple_GET_SIZE(kwnames);
@@ -1787,11 +1787,11 @@ _PyEvalFramePushAndInit_UnTagged(PyThreadState *tstate, PyFunctionObject *func,
17871787
for (size_t i = 0; i < kw_count; i++) {
17881788
tagged_args_buffer[argcount + i] = PyStackRef_FromPyObjectSteal(args[argcount + i]);
17891789
}
1790-
_PyInterpreterFrame *res = _PyEvalFramePushAndInit(tstate, func, locals, (_PyStackRef const *)tagged_args_buffer, argcount, kwnames);
1790+
_PyInterpreterFrame *res = _PyEvalFramePushAndInit(tstate, func, locals, (_PyStackRef const *)tagged_args_buffer, argcount, kwnames, previous);
17911791
PyMem_Free(tagged_args_buffer);
17921792
return res;
17931793
#else
1794-
return _PyEvalFramePushAndInit(tstate, func, locals, (_PyStackRef const *)args, argcount, kwnames);
1794+
return _PyEvalFramePushAndInit(tstate, func, locals, (_PyStackRef const *)args, argcount, kwnames, previous);
17951795
#endif
17961796
}
17971797

@@ -1800,7 +1800,7 @@ _PyEvalFramePushAndInit_UnTagged(PyThreadState *tstate, PyFunctionObject *func,
18001800
*/
18011801
static _PyInterpreterFrame *
18021802
_PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func,
1803-
PyObject *locals, Py_ssize_t nargs, PyObject *callargs, PyObject *kwargs)
1803+
PyObject *locals, Py_ssize_t nargs, PyObject *callargs, PyObject *kwargs, _PyInterpreterFrame *previous)
18041804
{
18051805
bool has_dict = (kwargs != NULL && PyDict_GET_SIZE(kwargs) > 0);
18061806
PyObject *kwnames = NULL;
@@ -1821,7 +1821,7 @@ _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func,
18211821
}
18221822
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_UnTagged(
18231823
tstate, (PyFunctionObject *)func, locals,
1824-
newargs, nargs, kwnames
1824+
newargs, nargs, kwnames, previous
18251825
);
18261826
if (has_dict) {
18271827
_PyStack_UnpackDict_FreeNoDecRef(newargs, kwnames);
@@ -1858,7 +1858,7 @@ _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func,
18581858
}
18591859
}
18601860
_PyInterpreterFrame *frame = _PyEvalFramePushAndInit_UnTagged(
1861-
tstate, func, locals, args, argcount, kwnames);
1861+
tstate, func, locals, args, argcount, kwnames, NULL);
18621862
if (frame == NULL) {
18631863
return NULL;
18641864
}

Python/ceval_macros.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ do { \
124124
do { \
125125
assert(tstate->interp->eval_frame == NULL); \
126126
_PyFrame_SetStackPointer(frame, stack_pointer); \
127-
(NEW_FRAME)->previous = frame; \
127+
assert((NEW_FRAME)->previous == frame); \
128128
frame = tstate->current_frame = (NEW_FRAME); \
129129
CALL_STAT_INC(inlined_py_calls); \
130130
goto start_frame; \

0 commit comments

Comments
 (0)