Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Python/frame.c
12 views
1
2
#define _PY_INTERPRETER
3
4
#include "Python.h"
5
#include "frameobject.h"
6
#include "pycore_code.h" // stats
7
#include "pycore_frame.h"
8
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
9
#include "opcode.h"
10
11
int
12
_PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg)
13
{
14
Py_VISIT(frame->frame_obj);
15
Py_VISIT(frame->f_locals);
16
Py_VISIT(frame->f_funcobj);
17
Py_VISIT(_PyFrame_GetCode(frame));
18
/* locals */
19
PyObject **locals = _PyFrame_GetLocalsArray(frame);
20
int i = 0;
21
/* locals and stack */
22
for (; i <frame->stacktop; i++) {
23
Py_VISIT(locals[i]);
24
}
25
return 0;
26
}
27
28
PyFrameObject *
29
_PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame)
30
{
31
assert(frame->frame_obj == NULL);
32
PyObject *exc = PyErr_GetRaisedException();
33
34
PyFrameObject *f = _PyFrame_New_NoTrack(_PyFrame_GetCode(frame));
35
if (f == NULL) {
36
Py_XDECREF(exc);
37
return NULL;
38
}
39
PyErr_SetRaisedException(exc);
40
if (frame->frame_obj) {
41
// GH-97002: How did we get into this horrible situation? Most likely,
42
// allocating f triggered a GC collection, which ran some code that
43
// *also* created the same frame... while we were in the middle of
44
// creating it! See test_sneaky_frame_object in test_frame.py for a
45
// concrete example.
46
//
47
// Regardless, just throw f away and use that frame instead, since it's
48
// already been exposed to user code. It's actually a bit tricky to do
49
// this, since we aren't backed by a real _PyInterpreterFrame anymore.
50
// Just pretend that we have an owned, cleared frame so frame_dealloc
51
// doesn't make the situation worse:
52
f->f_frame = (_PyInterpreterFrame *)f->_f_frame_data;
53
f->f_frame->owner = FRAME_CLEARED;
54
f->f_frame->frame_obj = f;
55
Py_DECREF(f);
56
return frame->frame_obj;
57
}
58
assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
59
assert(frame->owner != FRAME_CLEARED);
60
f->f_frame = frame;
61
frame->frame_obj = f;
62
return f;
63
}
64
65
void
66
_PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest)
67
{
68
assert(src->stacktop >= _PyFrame_GetCode(src)->co_nlocalsplus);
69
Py_ssize_t size = ((char*)&src->localsplus[src->stacktop]) - (char *)src;
70
memcpy(dest, src, size);
71
// Don't leave a dangling pointer to the old frame when creating generators
72
// and coroutines:
73
dest->previous = NULL;
74
}
75
76
77
static void
78
take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
79
{
80
assert(frame->owner != FRAME_OWNED_BY_CSTACK);
81
assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
82
assert(frame->owner != FRAME_CLEARED);
83
Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame;
84
Py_INCREF(_PyFrame_GetCode(frame));
85
memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size);
86
frame = (_PyInterpreterFrame *)f->_f_frame_data;
87
f->f_frame = frame;
88
frame->owner = FRAME_OWNED_BY_FRAME_OBJECT;
89
if (_PyFrame_IsIncomplete(frame)) {
90
// This may be a newly-created generator or coroutine frame. Since it's
91
// dead anyways, just pretend that the first RESUME ran:
92
PyCodeObject *code = _PyFrame_GetCode(frame);
93
frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable;
94
}
95
assert(!_PyFrame_IsIncomplete(frame));
96
assert(f->f_back == NULL);
97
_PyInterpreterFrame *prev = _PyFrame_GetFirstComplete(frame->previous);
98
frame->previous = NULL;
99
if (prev) {
100
assert(prev->owner != FRAME_OWNED_BY_CSTACK);
101
/* Link PyFrameObjects.f_back and remove link through _PyInterpreterFrame.previous */
102
PyFrameObject *back = _PyFrame_GetFrameObject(prev);
103
if (back == NULL) {
104
/* Memory error here. */
105
assert(PyErr_ExceptionMatches(PyExc_MemoryError));
106
/* Nothing we can do about it */
107
PyErr_Clear();
108
}
109
else {
110
f->f_back = (PyFrameObject *)Py_NewRef(back);
111
}
112
}
113
if (!_PyObject_GC_IS_TRACKED((PyObject *)f)) {
114
_PyObject_GC_TRACK((PyObject *)f);
115
}
116
}
117
118
void
119
_PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)
120
{
121
/* It is the responsibility of the owning generator/coroutine
122
* to have cleared the enclosing generator, if any. */
123
assert(frame->owner != FRAME_OWNED_BY_GENERATOR ||
124
_PyFrame_GetGenerator(frame)->gi_frame_state == FRAME_CLEARED);
125
// GH-99729: Clearing this frame can expose the stack (via finalizers). It's
126
// crucial that this frame has been unlinked, and is no longer visible:
127
assert(_PyThreadState_GET()->cframe->current_frame != frame);
128
if (frame->frame_obj) {
129
PyFrameObject *f = frame->frame_obj;
130
frame->frame_obj = NULL;
131
if (Py_REFCNT(f) > 1) {
132
take_ownership(f, frame);
133
Py_DECREF(f);
134
return;
135
}
136
Py_DECREF(f);
137
}
138
assert(frame->stacktop >= 0);
139
for (int i = 0; i < frame->stacktop; i++) {
140
Py_XDECREF(frame->localsplus[i]);
141
}
142
Py_XDECREF(frame->frame_obj);
143
Py_XDECREF(frame->f_locals);
144
Py_DECREF(frame->f_funcobj);
145
}
146
147
/* Unstable API functions */
148
149
PyObject *
150
PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)
151
{
152
PyObject *code = frame->f_executable;
153
Py_INCREF(code);
154
return code;
155
}
156
157
int
158
PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)
159
{
160
return _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
161
}
162
163
int
164
PyUnstable_InterpreterFrame_GetLine(_PyInterpreterFrame *frame)
165
{
166
int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
167
return PyCode_Addr2Line(_PyFrame_GetCode(frame), addr);
168
}
169
170
const PyTypeObject *const PyUnstable_ExecutableKinds[PY_EXECUTABLE_KINDS+1] = {
171
[PY_EXECUTABLE_KIND_SKIP] = &_PyNone_Type,
172
[PY_EXECUTABLE_KIND_PY_FUNCTION] = &PyCode_Type,
173
[PY_EXECUTABLE_KIND_BUILTIN_FUNCTION] = &PyMethod_Type,
174
[PY_EXECUTABLE_KIND_METHOD_DESCRIPTOR] = &PyMethodDescr_Type,
175
[PY_EXECUTABLE_KINDS] = NULL,
176
};
177
178