frameobject.c revision b56933ed2e1e2f921b8a20a6e8b9a9431a5cb447
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_owner",	T_OBJECT,	OFF(f_owner),	RO},
51#if 0
52	{"f_fastlocals",T_OBJECT,	OFF(f_fastlocals),RO}, /* XXX Unsafe */
53#endif
54	{"f_lasti",	T_INT,		OFF(f_lasti),	RO},
55	{"f_lineno",	T_INT,		OFF(f_lineno),	RO},
56	{"f_restricted",T_INT,		OFF(f_restricted),RO},
57	{"f_trace",	T_OBJECT,	OFF(f_trace)},
58	{NULL}	/* Sentinel */
59};
60
61static object *
62frame_getattr(f, name)
63	frameobject *f;
64	char *name;
65{
66	if (strcmp(name, "f_locals") == 0)
67		fast_2_locals(f);
68	return getmember((char *)f, frame_memberlist, name);
69}
70
71static int
72frame_setattr(f, name, value)
73	frameobject *f;
74	char *name;
75	object *value;
76{
77	return setmember((char *)f, frame_memberlist, name, value);
78}
79
80/* Stack frames are allocated and deallocated at a considerable rate.
81   In an attempt to improve the speed of function calls, we maintain a
82   separate free list of stack frames (just like integers are
83   allocated in a special way -- see intobject.c).  When a stack frame
84   is on the free list, only the following members have a meaning:
85	ob_type		== &Frametype
86	f_back		next item on free list, or NULL
87	f_nvalues	size of f_valuestack
88	f_valuestack	array of (f_nvalues+1) object pointers, or NULL
89	f_nblocks	size of f_blockstack
90	f_blockstack	array of (f_nblocks+1) blocks, or NULL
91   Note that the value and block stacks are preserved -- this can save
92   another malloc() call or two (and two free() calls as well!).
93   Also note that, unlike for integers, each frame object is a
94   malloc'ed object in its own right -- it is only the actual calls to
95   malloc() that we are trying to save here, not the administration.
96   After all, while a typical program may make millions of calls, a
97   call depth of more than 20 or 30 is probably already exceptional
98   unless the program contains run-away recursion.  I hope.
99*/
100
101static frameobject *free_list = NULL;
102
103static void
104frame_dealloc(f)
105	frameobject *f;
106{
107	XDECREF(f->f_back);
108	XDECREF(f->f_code);
109	XDECREF(f->f_builtins);
110	XDECREF(f->f_globals);
111	XDECREF(f->f_locals);
112	XDECREF(f->f_owner);
113	XDECREF(f->f_fastlocals);
114	XDECREF(f->f_trace);
115	f->f_back = free_list;
116	free_list = f;
117}
118
119typeobject Frametype = {
120	OB_HEAD_INIT(&Typetype)
121	0,
122	"frame",
123	sizeof(frameobject),
124	0,
125	(destructor)frame_dealloc, /*tp_dealloc*/
126	0,		/*tp_print*/
127	(getattrfunc)frame_getattr, /*tp_getattr*/
128	(setattrfunc)frame_setattr, /*tp_setattr*/
129	0,		/*tp_compare*/
130	0,		/*tp_repr*/
131	0,		/*tp_as_number*/
132	0,		/*tp_as_sequence*/
133	0,		/*tp_as_mapping*/
134};
135
136frameobject *
137newframeobject(back, code, globals, locals, owner, nvalues, nblocks)
138	frameobject *back;
139	codeobject *code;
140	object *globals;
141	object *locals;
142	object *owner;
143	int nvalues;
144	int nblocks;
145{
146	static object *builtin_object;
147	frameobject *f;
148	object *builtins;
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		nvalues < 0 || nblocks < 0) {
159		err_badcall();
160		return NULL;
161	}
162	builtins = mappinglookup(globals, builtin_object);
163	if (builtins != NULL && is_moduleobject(builtins))
164		builtins = getmoduledict(builtins);
165	if (builtins == NULL || !is_mappingobject(builtins)) {
166		err_setstr(TypeError, "bad __builtins__ dictionary");
167		return NULL;
168	}
169	if (free_list == NULL) {
170		f = NEWOBJ(frameobject, &Frametype);
171		if (f == NULL)
172			return NULL;
173		f->f_nvalues = f->f_nblocks = 0;
174		f->f_valuestack = NULL;
175		f->f_blockstack = NULL;
176	}
177	else {
178		f = free_list;
179		free_list = free_list->f_back;
180		f->ob_type = &Frametype;
181		NEWREF(f);
182	}
183	XINCREF(back);
184	f->f_back = back;
185	INCREF(code);
186	f->f_code = code;
187	XINCREF(builtins);
188	f->f_builtins = builtins;
189	INCREF(globals);
190	f->f_globals = globals;
191	if (code->co_flags & CO_NEWLOCALS) {
192		if (code->co_flags & CO_OPTIMIZED)
193			locals = NULL; /* Let fast_2_locals handle it */
194		else {
195			locals = newdictobject();
196			if (locals == NULL) {
197				DECREF(f);
198				return NULL;
199			}
200		}
201	}
202	else {
203		if (locals == NULL)
204			locals = globals;
205		INCREF(locals);
206	}
207	f->f_locals = locals;
208	XINCREF(owner);
209	f->f_owner = owner;
210	f->f_fastlocals = NULL;
211	if (code->co_nlocals > 0) {
212		f->f_fastlocals = newlistobject(code->co_nlocals);
213		if (f->f_fastlocals == NULL) {
214			DECREF(f);
215			return NULL;
216		}
217	}
218	if (nvalues > f->f_nvalues || f->f_valuestack == NULL) {
219		XDEL(f->f_valuestack);
220		f->f_valuestack = NEW(object *, nvalues+1);
221		f->f_nvalues = nvalues;
222	}
223	if (nblocks > f->f_nblocks || f->f_blockstack == NULL) {
224		XDEL(f->f_blockstack);
225		f->f_blockstack = NEW(block, nblocks+1);
226		f->f_nblocks = nblocks;
227	}
228	f->f_iblock = 0;
229	f->f_lasti = 0;
230	f->f_lineno = -1;
231	f->f_restricted = (builtins != getbuiltindict());
232	f->f_trace = NULL;
233	if (f->f_valuestack == NULL || f->f_blockstack == NULL) {
234		err_nomem();
235		DECREF(f);
236		return NULL;
237	}
238	return f;
239}
240
241#if 0
242object **
243extend_stack(f, level, incr)
244	frameobject *f;
245	int level;
246	int incr;
247{
248	f->f_nvalues = level + incr + 10;
249	f->f_valuestack =
250		(object **) realloc((ANY *)f->f_valuestack,
251				    sizeof(object *) * (f->f_nvalues + 1));
252	if (f->f_valuestack == NULL) {
253		err_nomem();
254		return NULL;
255	}
256	return f->f_valuestack + level;
257}
258#endif
259
260/* Block management */
261
262void
263setup_block(f, type, handler, level)
264	frameobject *f;
265	int type;
266	int handler;
267	int level;
268{
269	block *b;
270	if (f->f_iblock >= f->f_nblocks)
271		fatal("XXX block stack overflow");
272	b = &f->f_blockstack[f->f_iblock++];
273	b->b_type = type;
274	b->b_level = level;
275	b->b_handler = handler;
276}
277
278block *
279pop_block(f)
280	frameobject *f;
281{
282	block *b;
283	if (f->f_iblock <= 0)
284		fatal("XXX block stack underflow");
285	b = &f->f_blockstack[--f->f_iblock];
286	return b;
287}
288
289/* Convert between "fast" version of locals and dictionary version */
290
291void
292fast_2_locals(f)
293	frameobject *f;
294{
295	/* Merge f->f_fastlocals into f->f_locals */
296	object *locals, *fast, *map;
297	object *error_type, *error_value, *error_traceback;
298	int j;
299	if (f == NULL)
300		return;
301	locals = f->f_locals;
302	if (locals == NULL) {
303		locals = f->f_locals = newdictobject();
304		if (locals == NULL) {
305			err_clear(); /* Can't report it :-( */
306			return;
307		}
308	}
309	fast = f->f_fastlocals;
310	if (fast == NULL || f->f_code->co_nlocals == 0)
311		return;
312	map = f->f_code->co_varnames;
313	if (!is_dictobject(locals) || !is_listobject(fast) ||
314	    !is_tupleobject(map))
315		return;
316	err_fetch(&error_type, &error_value, &error_traceback);
317	for (j = gettuplesize(map); --j >= 0; ) {
318		object *key = gettupleitem(map, j);
319		object *value = getlistitem(fast, j);
320		if (value == NULL) {
321			err_clear();
322			if (dict2remove(locals, key) != 0)
323				err_clear();
324		}
325		else {
326			if (dict2insert(locals, key, value) != 0)
327				err_clear();
328		}
329	}
330	err_restore(error_type, error_value, error_traceback);
331}
332
333void
334locals_2_fast(f, clear)
335	frameobject *f;
336	int clear;
337{
338	/* Merge f->f_locals into f->f_fastlocals */
339	object *locals, *fast, *map;
340	object *error_type, *error_value, *error_traceback;
341	int j;
342	if (f == NULL)
343		return;
344	locals = f->f_locals;
345	fast = f->f_fastlocals;
346	map = f->f_code->co_varnames;
347	if (locals == NULL || fast == NULL || f->f_code->co_nlocals == 0)
348		return;
349	if (!is_dictobject(locals) || !is_listobject(fast) ||
350	    !is_tupleobject(map))
351		return;
352	err_fetch(&error_type, &error_value, &error_traceback);
353	for (j = gettuplesize(map); --j >= 0; ) {
354		object *key = gettupleitem(map, j);
355		object *value = dict2lookup(locals, key);
356		if (value == NULL)
357			err_clear();
358		else
359			INCREF(value);
360		if (value != NULL || clear)
361			if (setlistitem(fast, j, value) != 0)
362				err_clear();
363	}
364	err_restore(error_type, error_value, error_traceback);
365}
366