frameobject.c revision 3bb63a8dbe19592641330a8f1e12bec5dfd147d2
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	XDECREF(f->f_back);
102	XDECREF(f->f_code);
103	XDECREF(f->f_builtins);
104	XDECREF(f->f_globals);
105	XDECREF(f->f_locals);
106	XDECREF(f->f_trace);
107	f->f_back = free_list;
108	free_list = f;
109}
110
111typeobject Frametype = {
112	OB_HEAD_INIT(&Typetype)
113	0,
114	"frame",
115	sizeof(frameobject),
116	0,
117	(destructor)frame_dealloc, /*tp_dealloc*/
118	0,		/*tp_print*/
119	(getattrfunc)frame_getattr, /*tp_getattr*/
120	(setattrfunc)frame_setattr, /*tp_setattr*/
121	0,		/*tp_compare*/
122	0,		/*tp_repr*/
123	0,		/*tp_as_number*/
124	0,		/*tp_as_sequence*/
125	0,		/*tp_as_mapping*/
126};
127
128frameobject *
129newframeobject(back, code, globals, locals)
130	frameobject *back;
131	codeobject *code;
132	object *globals;
133	object *locals;
134{
135	static object *builtin_object;
136	frameobject *f;
137	object *builtins;
138	int extras = code->co_stacksize + code->co_nlocals;
139
140	if (builtin_object == NULL) {
141		builtin_object = PyString_InternFromString("__builtins__");
142		if (builtin_object == NULL)
143			return NULL;
144	}
145	if ((back != NULL && !is_frameobject(back)) ||
146	    code == NULL || !is_codeobject(code) ||
147	    globals == NULL || !is_dictobject(globals) ||
148	    (locals != NULL && !is_dictobject(locals))) {
149		err_badcall();
150		return NULL;
151	}
152	builtins = mappinglookup(globals, builtin_object);
153	if (builtins != NULL && is_moduleobject(builtins))
154		builtins = getmoduledict(builtins);
155	if (builtins == NULL || !is_mappingobject(builtins)) {
156		err_setstr(TypeError, "bad __builtins__ dictionary");
157		return NULL;
158	}
159	if (free_list == NULL) {
160		f = (frameobject *)
161			malloc(sizeof(frameobject) + extras*sizeof(object *));
162		if (f == NULL)
163			return (PyFrameObject *)err_nomem();
164		f->ob_type = &Frametype;
165		NEWREF(f);
166	}
167	else {
168		f = free_list;
169		free_list = free_list->f_back;
170		if (f->f_nlocals + f->f_stacksize < extras) {
171			f = realloc(f, sizeof(frameobject) + extras*sizeof(object *));
172			if (f == NULL)
173				return (PyFrameObject *)err_nomem();
174		}
175		f->ob_type = &Frametype;
176		NEWREF(f);
177	}
178	XINCREF(back);
179	f->f_back = back;
180	INCREF(code);
181	f->f_code = code;
182	XINCREF(builtins);
183	f->f_builtins = builtins;
184	INCREF(globals);
185	f->f_globals = globals;
186	if (code->co_flags & CO_NEWLOCALS) {
187		if (code->co_flags & CO_OPTIMIZED)
188			locals = NULL; /* Let fast_2_locals handle it */
189		else {
190			locals = newdictobject();
191			if (locals == NULL) {
192				DECREF(f);
193				return NULL;
194			}
195		}
196	}
197	else {
198		if (locals == NULL)
199			locals = globals;
200		INCREF(locals);
201	}
202	f->f_locals = locals;
203	f->f_trace = NULL;
204
205	f->f_lasti = 0;
206	f->f_lineno = -1;
207	f->f_restricted = (builtins != getbuiltindict());
208	f->f_iblock = 0;
209	f->f_nlocals = code->co_nlocals;
210	f->f_stacksize = code->co_stacksize;
211
212	while (--extras >= 0)
213		f->f_localsplus[extras] = NULL;
214
215	f->f_valuestack = f->f_localsplus + f->f_nlocals;
216
217	return f;
218}
219
220/* Block management */
221
222void
223setup_block(f, type, handler, level)
224	frameobject *f;
225	int type;
226	int handler;
227	int level;
228{
229	block *b;
230	if (f->f_iblock >= CO_MAXBLOCKS)
231		fatal("XXX block stack overflow");
232	b = &f->f_blockstack[f->f_iblock++];
233	b->b_type = type;
234	b->b_level = level;
235	b->b_handler = handler;
236}
237
238block *
239pop_block(f)
240	frameobject *f;
241{
242	block *b;
243	if (f->f_iblock <= 0)
244		fatal("XXX block stack underflow");
245	b = &f->f_blockstack[--f->f_iblock];
246	return b;
247}
248
249/* Convert between "fast" version of locals and dictionary version */
250
251void
252fast_2_locals(f)
253	frameobject *f;
254{
255	/* Merge fast locals into f->f_locals */
256	object *locals, *map;
257	object **fast;
258	object *error_type, *error_value, *error_traceback;
259	int j;
260	if (f == NULL)
261		return;
262	locals = f->f_locals;
263	if (locals == NULL) {
264		locals = f->f_locals = newdictobject();
265		if (locals == NULL) {
266			err_clear(); /* Can't report it :-( */
267			return;
268		}
269	}
270	if (f->f_nlocals == 0)
271		return;
272	map = f->f_code->co_varnames;
273	if (!is_dictobject(locals) || !is_tupleobject(map))
274		return;
275	err_fetch(&error_type, &error_value, &error_traceback);
276	fast = f->f_localsplus;
277	j = gettuplesize(map);
278	if (j > f->f_nlocals)
279		j = f->f_nlocals;
280	for (; --j >= 0; ) {
281		object *key = gettupleitem(map, j);
282		object *value = fast[j];
283		if (value == NULL) {
284			err_clear();
285			if (dict2remove(locals, key) != 0)
286				err_clear();
287		}
288		else {
289			if (dict2insert(locals, key, value) != 0)
290				err_clear();
291		}
292	}
293	err_restore(error_type, error_value, error_traceback);
294}
295
296void
297locals_2_fast(f, clear)
298	frameobject *f;
299	int clear;
300{
301	/* Merge f->f_locals into fast locals */
302	object *locals, *map;
303	object **fast;
304	object *error_type, *error_value, *error_traceback;
305	int j;
306	if (f == NULL)
307		return;
308	locals = f->f_locals;
309	map = f->f_code->co_varnames;
310	if (locals == NULL || f->f_code->co_nlocals == 0)
311		return;
312	if (!is_dictobject(locals) || !is_tupleobject(map))
313		return;
314	err_fetch(&error_type, &error_value, &error_traceback);
315	fast = f->f_localsplus;
316	j = gettuplesize(map);
317	if (j > f->f_nlocals)
318		j = f->f_nlocals;
319	for (; --j >= 0; ) {
320		object *key = gettupleitem(map, j);
321		object *value = dict2lookup(locals, key);
322		if (value == NULL)
323			err_clear();
324		else
325			INCREF(value);
326		if (value != NULL || clear) {
327			XDECREF(fast[j]);
328			XINCREF(value);
329			fast[j] = value;
330		}
331	}
332	err_restore(error_type, error_value, error_traceback);
333}
334