frameobject.c revision 7582bfb60a7027b57d79c44a5e8531a31d1a8f2a
1/***********************************************************
2Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
4
5                        All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI or Corporation for National Research Initiatives or
13CNRI not be used in advertising or publicity pertaining to
14distribution of the software without specific, written prior
15permission.
16
17While CWI is the initial source for this software, a modified version
18is made available by the Corporation for National Research Initiatives
19(CNRI) at the Internet address ftp://ftp.python.org.
20
21STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28PERFORMANCE OF THIS SOFTWARE.
29
30******************************************************************/
31
32/* Frame object implementation */
33
34#include "allobjects.h"
35
36#include "compile.h"
37#include "frameobject.h"
38#include "opcode.h"
39#include "structmember.h"
40#include "bltinmodule.h"
41
42#define OFF(x) offsetof(frameobject, x)
43
44static struct memberlist frame_memberlist[] = {
45	{"f_back",	T_OBJECT,	OFF(f_back),	RO},
46	{"f_code",	T_OBJECT,	OFF(f_code),	RO},
47	{"f_builtins",	T_OBJECT,	OFF(f_builtins),RO},
48	{"f_globals",	T_OBJECT,	OFF(f_globals),	RO},
49	{"f_locals",	T_OBJECT,	OFF(f_locals),	RO},
50	{"f_lasti",	T_INT,		OFF(f_lasti),	RO},
51	{"f_lineno",	T_INT,		OFF(f_lineno),	RO},
52	{"f_restricted",T_INT,		OFF(f_restricted),RO},
53	{"f_trace",	T_OBJECT,	OFF(f_trace)},
54	{NULL}	/* Sentinel */
55};
56
57static object *
58frame_getattr(f, name)
59	frameobject *f;
60	char *name;
61{
62	if (strcmp(name, "f_locals") == 0)
63		fast_2_locals(f);
64	return getmember((char *)f, frame_memberlist, name);
65}
66
67static int
68frame_setattr(f, name, value)
69	frameobject *f;
70	char *name;
71	object *value;
72{
73	return setmember((char *)f, frame_memberlist, name, value);
74}
75
76/* Stack frames are allocated and deallocated at a considerable rate.
77   In an attempt to improve the speed of function calls, we maintain a
78   separate free list of stack frames (just like integers are
79   allocated in a special way -- see intobject.c).  When a stack frame
80   is on the free list, only the following members have a meaning:
81	ob_type		== &Frametype
82	f_back		next item on free list, or NULL
83	f_nlocals	number of locals
84	f_stacksize	size of value stack
85   Note that the value and block stacks are preserved -- this can save
86   another malloc() call or two (and two free() calls as well!).
87   Also note that, unlike for integers, each frame object is a
88   malloc'ed object in its own right -- it is only the actual calls to
89   malloc() that we are trying to save here, not the administration.
90   After all, while a typical program may make millions of calls, a
91   call depth of more than 20 or 30 is probably already exceptional
92   unless the program contains run-away recursion.  I hope.
93*/
94
95static frameobject *free_list = NULL;
96
97static void
98frame_dealloc(f)
99	frameobject *f;
100{
101	int i;
102	PyObject **fastlocals;
103
104	/* Kill all local variables */
105	fastlocals = f->f_localsplus;
106	for (i = f->f_nlocals; --i >= 0; ++fastlocals) {
107		XDECREF(*fastlocals);
108	}
109
110	XDECREF(f->f_back);
111	XDECREF(f->f_code);
112	XDECREF(f->f_builtins);
113	XDECREF(f->f_globals);
114	XDECREF(f->f_locals);
115	XDECREF(f->f_trace);
116	f->f_back = free_list;
117	free_list = f;
118}
119
120typeobject Frametype = {
121	OB_HEAD_INIT(&Typetype)
122	0,
123	"frame",
124	sizeof(frameobject),
125	0,
126	(destructor)frame_dealloc, /*tp_dealloc*/
127	0,		/*tp_print*/
128	(getattrfunc)frame_getattr, /*tp_getattr*/
129	(setattrfunc)frame_setattr, /*tp_setattr*/
130	0,		/*tp_compare*/
131	0,		/*tp_repr*/
132	0,		/*tp_as_number*/
133	0,		/*tp_as_sequence*/
134	0,		/*tp_as_mapping*/
135};
136
137frameobject *
138newframeobject(back, code, globals, locals)
139	frameobject *back;
140	codeobject *code;
141	object *globals;
142	object *locals;
143{
144	static object *builtin_object;
145	frameobject *f;
146	object *builtins;
147	int extras = code->co_stacksize + code->co_nlocals;
148
149	if (builtin_object == NULL) {
150		builtin_object = PyString_InternFromString("__builtins__");
151		if (builtin_object == NULL)
152			return NULL;
153	}
154	if ((back != NULL && !is_frameobject(back)) ||
155	    code == NULL || !is_codeobject(code) ||
156	    globals == NULL || !is_dictobject(globals) ||
157	    (locals != NULL && !is_dictobject(locals))) {
158		err_badcall();
159		return NULL;
160	}
161	builtins = mappinglookup(globals, builtin_object);
162	if (builtins != NULL && is_moduleobject(builtins))
163		builtins = getmoduledict(builtins);
164	if (builtins == NULL || !is_mappingobject(builtins)) {
165		err_setstr(TypeError, "bad __builtins__ dictionary");
166		return NULL;
167	}
168	if (free_list == NULL) {
169		f = (frameobject *)
170			malloc(sizeof(frameobject) + extras*sizeof(object *));
171		if (f == NULL)
172			return (PyFrameObject *)err_nomem();
173		f->ob_type = &Frametype;
174		NEWREF(f);
175	}
176	else {
177		f = free_list;
178		free_list = free_list->f_back;
179		if (f->f_nlocals + f->f_stacksize < extras) {
180			f = realloc(f, sizeof(frameobject) +
181				       extras*sizeof(object *));
182			if (f == NULL)
183				return (PyFrameObject *)err_nomem();
184		}
185		else
186			extras = f->f_nlocals + f->f_stacksize;
187		f->ob_type = &Frametype;
188		NEWREF(f);
189	}
190	XINCREF(back);
191	f->f_back = back;
192	INCREF(code);
193	f->f_code = code;
194	XINCREF(builtins);
195	f->f_builtins = builtins;
196	INCREF(globals);
197	f->f_globals = globals;
198	if (code->co_flags & CO_NEWLOCALS) {
199		if (code->co_flags & CO_OPTIMIZED)
200			locals = NULL; /* Let fast_2_locals handle it */
201		else {
202			locals = newdictobject();
203			if (locals == NULL) {
204				DECREF(f);
205				return NULL;
206			}
207		}
208	}
209	else {
210		if (locals == NULL)
211			locals = globals;
212		INCREF(locals);
213	}
214	f->f_locals = locals;
215	f->f_trace = NULL;
216
217	f->f_lasti = 0;
218	f->f_lineno = code->co_firstlineno;
219	f->f_restricted = (builtins != getbuiltindict());
220	f->f_iblock = 0;
221	f->f_nlocals = code->co_nlocals;
222	f->f_stacksize = extras - code->co_nlocals;
223
224	while (--extras >= 0)
225		f->f_localsplus[extras] = NULL;
226
227	f->f_valuestack = f->f_localsplus + f->f_nlocals;
228
229	return f;
230}
231
232/* Block management */
233
234void
235setup_block(f, type, handler, level)
236	frameobject *f;
237	int type;
238	int handler;
239	int level;
240{
241	block *b;
242	if (f->f_iblock >= CO_MAXBLOCKS)
243		fatal("XXX block stack overflow");
244	b = &f->f_blockstack[f->f_iblock++];
245	b->b_type = type;
246	b->b_level = level;
247	b->b_handler = handler;
248}
249
250block *
251pop_block(f)
252	frameobject *f;
253{
254	block *b;
255	if (f->f_iblock <= 0)
256		fatal("XXX block stack underflow");
257	b = &f->f_blockstack[--f->f_iblock];
258	return b;
259}
260
261/* Convert between "fast" version of locals and dictionary version */
262
263void
264fast_2_locals(f)
265	frameobject *f;
266{
267	/* Merge fast locals into f->f_locals */
268	object *locals, *map;
269	object **fast;
270	object *error_type, *error_value, *error_traceback;
271	int j;
272	if (f == NULL)
273		return;
274	locals = f->f_locals;
275	if (locals == NULL) {
276		locals = f->f_locals = newdictobject();
277		if (locals == NULL) {
278			err_clear(); /* Can't report it :-( */
279			return;
280		}
281	}
282	if (f->f_nlocals == 0)
283		return;
284	map = f->f_code->co_varnames;
285	if (!is_dictobject(locals) || !is_tupleobject(map))
286		return;
287	err_fetch(&error_type, &error_value, &error_traceback);
288	fast = f->f_localsplus;
289	j = gettuplesize(map);
290	if (j > f->f_nlocals)
291		j = f->f_nlocals;
292	for (; --j >= 0; ) {
293		object *key = gettupleitem(map, j);
294		object *value = fast[j];
295		if (value == NULL) {
296			err_clear();
297			if (dict2remove(locals, key) != 0)
298				err_clear();
299		}
300		else {
301			if (dict2insert(locals, key, value) != 0)
302				err_clear();
303		}
304	}
305	err_restore(error_type, error_value, error_traceback);
306}
307
308void
309locals_2_fast(f, clear)
310	frameobject *f;
311	int clear;
312{
313	/* Merge f->f_locals into fast locals */
314	object *locals, *map;
315	object **fast;
316	object *error_type, *error_value, *error_traceback;
317	int j;
318	if (f == NULL)
319		return;
320	locals = f->f_locals;
321	map = f->f_code->co_varnames;
322	if (locals == NULL || f->f_code->co_nlocals == 0)
323		return;
324	if (!is_dictobject(locals) || !is_tupleobject(map))
325		return;
326	err_fetch(&error_type, &error_value, &error_traceback);
327	fast = f->f_localsplus;
328	j = gettuplesize(map);
329	if (j > f->f_nlocals)
330		j = f->f_nlocals;
331	for (; --j >= 0; ) {
332		object *key = gettupleitem(map, j);
333		object *value = dict2lookup(locals, key);
334		if (value == NULL)
335			err_clear();
336		else
337			INCREF(value);
338		if (value != NULL || clear) {
339			XDECREF(fast[j]);
340			XINCREF(value);
341			fast[j] = value;
342		}
343	}
344	err_restore(error_type, error_value, error_traceback);
345}
346