frameobject.c revision 5b7f3cd3e17b96d3ef505cc46df169caab06c784
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_localmap",	T_OBJECT,	OFF(f_localmap),RO},
48	{"f_lasti",	T_INT,		OFF(f_lasti),	RO},
49	{"f_lineno",	T_INT,		OFF(f_lineno),	RO},
50	{"f_restricted",T_INT,		OFF(f_restricted),RO},
51	{"f_trace",	T_OBJECT,	OFF(f_trace)},
52	{NULL}	/* Sentinel */
53};
54
55static object *
56frame_getattr(f, name)
57	frameobject *f;
58	char *name;
59{
60	if (strcmp(name, "f_locals") == 0)
61		fast_2_locals(f);
62	return getmember((char *)f, frame_memberlist, name);
63}
64
65static int
66frame_setattr(f, name, value)
67	frameobject *f;
68	char *name;
69	object *value;
70{
71	return setmember((char *)f, frame_memberlist, name, value);
72}
73
74/* Stack frames are allocated and deallocated at a considerable rate.
75   In an attempt to improve the speed of function calls, we maintain a
76   separate free list of stack frames (just like integers are
77   allocated in a special way -- see intobject.c).  When a stack frame
78   is on the free list, only the following members have a meaning:
79	ob_type		== &Frametype
80	f_back		next item on free list, or NULL
81	f_nvalues	size of f_valuestack
82	f_valuestack	array of (f_nvalues+1) object pointers, or NULL
83	f_nblocks	size of f_blockstack
84	f_blockstack	array of (f_nblocks+1) blocks, or NULL
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_owner);
107	XDECREF(f->f_fastlocals);
108	XDECREF(f->f_localmap);
109	XDECREF(f->f_trace);
110	f->f_back = free_list;
111	free_list = f;
112}
113
114typeobject Frametype = {
115	OB_HEAD_INIT(&Typetype)
116	0,
117	"frame",
118	sizeof(frameobject),
119	0,
120	(destructor)frame_dealloc, /*tp_dealloc*/
121	0,		/*tp_print*/
122	(getattrfunc)frame_getattr, /*tp_getattr*/
123	(setattrfunc)frame_setattr, /*tp_setattr*/
124	0,		/*tp_compare*/
125	0,		/*tp_repr*/
126	0,		/*tp_as_number*/
127	0,		/*tp_as_sequence*/
128	0,		/*tp_as_mapping*/
129};
130
131frameobject *
132newframeobject(back, code, globals, locals, owner, nvalues, nblocks)
133	frameobject *back;
134	codeobject *code;
135	object *globals;
136	object *locals;
137	object *owner;
138	int nvalues;
139	int nblocks;
140{
141	static object *builtin_object;
142	frameobject *f;
143	object *builtins;
144	if (builtin_object == NULL) {
145		builtin_object = newstringobject("__builtins__");
146		if (builtin_object == NULL)
147			return NULL;
148	}
149	if ((back != NULL && !is_frameobject(back)) ||
150		code == NULL || !is_codeobject(code) ||
151		globals == NULL || !is_dictobject(globals) ||
152		locals == NULL || !is_dictobject(locals) ||
153		nvalues < 0 || nblocks < 0) {
154		err_badcall();
155		return NULL;
156	}
157	builtins = mappinglookup(globals, builtin_object);
158	if (builtins != NULL && is_moduleobject(builtins))
159		builtins = getmoduledict(builtins);
160	if (builtins == NULL || !is_mappingobject(builtins)) {
161		err_setstr(TypeError, "bad __builtins__ dictionary");
162		return NULL;
163	}
164	if (free_list == NULL) {
165		f = NEWOBJ(frameobject, &Frametype);
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	if (f != NULL) {
177		XINCREF(back);
178		f->f_back = back;
179		INCREF(code);
180		f->f_code = code;
181		XINCREF(builtins);
182		f->f_builtins = builtins;
183		INCREF(globals);
184		f->f_globals = globals;
185		INCREF(locals);
186		f->f_locals = locals;
187		XINCREF(owner);
188		f->f_owner = owner;
189		f->f_fastlocals = NULL;
190		f->f_localmap = NULL;
191		if (nvalues > f->f_nvalues || f->f_valuestack == NULL) {
192			XDEL(f->f_valuestack);
193			f->f_valuestack = NEW(object *, nvalues+1);
194			f->f_nvalues = nvalues;
195		}
196		if (nblocks > f->f_nblocks || f->f_blockstack == NULL) {
197			XDEL(f->f_blockstack);
198			f->f_blockstack = NEW(block, nblocks+1);
199			f->f_nblocks = nblocks;
200		}
201		f->f_iblock = 0;
202		f->f_lasti = 0;
203		f->f_lineno = -1;
204		f->f_restricted = (builtins != getbuiltindict());
205		f->f_trace = NULL;
206		if (f->f_valuestack == NULL || f->f_blockstack == NULL) {
207			err_nomem();
208			DECREF(f);
209			f = NULL;
210		}
211	}
212	return f;
213}
214
215object **
216extend_stack(f, level, incr)
217	frameobject *f;
218	int level;
219	int incr;
220{
221	f->f_nvalues = level + incr + 10;
222	f->f_valuestack =
223		(object **) realloc((ANY *)f->f_valuestack,
224				    sizeof(object *) * (f->f_nvalues + 1));
225	if (f->f_valuestack == NULL) {
226		err_nomem();
227		return NULL;
228	}
229	return f->f_valuestack + level;
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 >= f->f_nblocks)
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 f->f_fastlocals into f->f_locals */
268	object *locals, *fast, *map;
269	object *error_type, *error_value, *error_traceback;
270	int j;
271	if (f == NULL)
272		return;
273	locals = f->f_locals;
274	fast = f->f_fastlocals;
275	map = f->f_localmap;
276	if (locals == NULL || fast == NULL || map == NULL)
277		return;
278	if (!is_dictobject(locals) || !is_listobject(fast) ||
279	    !is_tupleobject(map))
280		return;
281	err_fetch(&error_type, &error_value, &error_traceback);
282	for (j = gettuplesize(map); --j >= 0; ) {
283		object *key = gettupleitem(map, j);
284		object *value = getlistitem(fast, j);
285		if (value == NULL) {
286			err_clear();
287			if (dict2remove(locals, key) != 0)
288				err_clear();
289		}
290		else {
291			if (dict2insert(locals, key, value) != 0)
292				err_clear();
293		}
294	}
295	err_restore(error_type, error_value, error_traceback);
296}
297
298void
299locals_2_fast(f, clear)
300	frameobject *f;
301	int clear;
302{
303	/* Merge f->f_locals into f->f_fastlocals */
304	object *locals, *fast, *map;
305	object *error_type, *error_value, *error_traceback;
306	int j;
307	if (f == NULL)
308		return;
309	locals = f->f_locals;
310	fast = f->f_fastlocals;
311	map = f->f_localmap;
312	if (locals == NULL || fast == NULL || map == NULL)
313		return;
314	if (!is_dictobject(locals) || !is_listobject(fast) ||
315	    !is_tupleobject(map))
316		return;
317	err_fetch(&error_type, &error_value, &error_traceback);
318	for (j = gettuplesize(map); --j >= 0; ) {
319		object *key = gettupleitem(map, j);
320		object *value = dict2lookup(locals, key);
321		if (value == NULL)
322			err_clear();
323		else
324			INCREF(value);
325		if (value != NULL || clear)
326			if (setlistitem(fast, j, value) != 0)
327				err_clear();
328	}
329	err_restore(error_type, error_value, error_traceback);
330}
331