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