blob: a22193f86c50507b62be9ab097845f88eddbd2ca [file] [log] [blame]
Guido van Rossumf70e43a1991-02-19 12:39:46 +00001/***********************************************************
Guido van Rossum1d5735e1994-08-30 08:27:36 +00002Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
Guido van Rossum9bfef441993-03-29 10:43:31 +00003Amsterdam, The Netherlands.
Guido van Rossumf70e43a1991-02-19 12:39:46 +00004
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
Guido van Rossum3f5da241990-12-20 15:06:42 +000025/* 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
34#define OFF(x) offsetof(frameobject, x)
35
36static struct memberlist frame_memberlist[] = {
Guido van Rossum1d5735e1994-08-30 08:27:36 +000037 {"f_back", T_OBJECT, OFF(f_back), RO},
38 {"f_code", T_OBJECT, OFF(f_code), RO},
39 {"f_globals", T_OBJECT, OFF(f_globals), RO},
40 {"f_locals", T_OBJECT, OFF(f_locals), RO},
41 {"f_owner", T_OBJECT, OFF(f_owner), RO},
42/* {"f_fastlocals",T_OBJECT, OFF(f_fastlocals),RO}, /* XXX Unsafe */
43 {"f_localmap", T_OBJECT, OFF(f_localmap),RO},
44 {"f_lasti", T_INT, OFF(f_lasti), RO},
45 {"f_lineno", T_INT, OFF(f_lineno), RO},
46 {"f_trace", T_OBJECT, OFF(f_trace)},
Guido van Rossum3f5da241990-12-20 15:06:42 +000047 {NULL} /* Sentinel */
48};
49
50static object *
51frame_getattr(f, name)
52 frameobject *f;
53 char *name;
54{
Guido van Rossum1d5735e1994-08-30 08:27:36 +000055 if (strcmp(name, "f_locals") == 0)
56 fast_2_locals(f);
Guido van Rossum3f5da241990-12-20 15:06:42 +000057 return getmember((char *)f, frame_memberlist, name);
58}
59
Guido van Rossum1d5735e1994-08-30 08:27:36 +000060static int
61frame_setattr(f, name, value)
62 frameobject *f;
63 char *name;
64 object *value;
65{
66 return setmember((char *)f, frame_memberlist, name, value);
67}
68
Guido van Rossuma9e7dc11992-10-18 18:53:57 +000069/* Stack frames are allocated and deallocated at a considerable rate.
70 In an attempt to improve the speed of function calls, we maintain a
71 separate free list of stack frames (just like integers are
72 allocated in a special way -- see intobject.c). When a stack frame
73 is on the free list, only the following members have a meaning:
74 ob_type == &Frametype
75 f_back next item on free list, or NULL
76 f_nvalues size of f_valuestack
77 f_valuestack array of (f_nvalues+1) object pointers, or NULL
78 f_nblocks size of f_blockstack
79 f_blockstack array of (f_nblocks+1) blocks, or NULL
80 Note that the value and block stacks are preserved -- this can save
81 another malloc() call or two (and two free() calls as well!).
82 Also note that, unlike for integers, each frame object is a
83 malloc'ed object in its own right -- it is only the actual calls to
84 malloc() that we are trying to save here, not the administration.
85 After all, while a typical program may make millions of calls, a
86 call depth of more than 20 or 30 is probably already exceptional
87 unless the program contains run-away recursion. I hope.
88*/
89
90static frameobject *free_list = NULL;
91
Guido van Rossum3f5da241990-12-20 15:06:42 +000092static void
93frame_dealloc(f)
94 frameobject *f;
95{
96 XDECREF(f->f_back);
97 XDECREF(f->f_code);
98 XDECREF(f->f_globals);
99 XDECREF(f->f_locals);
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000100 XDECREF(f->f_owner);
Guido van Rossum8b17d6b1993-03-30 13:18:41 +0000101 XDECREF(f->f_fastlocals);
102 XDECREF(f->f_localmap);
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000103 XDECREF(f->f_trace);
Guido van Rossuma9e7dc11992-10-18 18:53:57 +0000104 f->f_back = free_list;
105 free_list = f;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000106}
107
108typeobject Frametype = {
109 OB_HEAD_INIT(&Typetype)
110 0,
111 "frame",
112 sizeof(frameobject),
113 0,
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000114 (destructor)frame_dealloc, /*tp_dealloc*/
Guido van Rossum3f5da241990-12-20 15:06:42 +0000115 0, /*tp_print*/
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000116 (getattrfunc)frame_getattr, /*tp_getattr*/
117 (setattrfunc)frame_setattr, /*tp_setattr*/
Guido van Rossum3f5da241990-12-20 15:06:42 +0000118 0, /*tp_compare*/
119 0, /*tp_repr*/
120 0, /*tp_as_number*/
121 0, /*tp_as_sequence*/
122 0, /*tp_as_mapping*/
123};
124
125frameobject *
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000126newframeobject(back, code, globals, locals, owner, nvalues, nblocks)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000127 frameobject *back;
128 codeobject *code;
129 object *globals;
130 object *locals;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000131 object *owner;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000132 int nvalues;
133 int nblocks;
134{
135 frameobject *f;
136 if ((back != NULL && !is_frameobject(back)) ||
137 code == NULL || !is_codeobject(code) ||
138 globals == NULL || !is_dictobject(globals) ||
139 locals == NULL || !is_dictobject(locals) ||
140 nvalues < 0 || nblocks < 0) {
141 err_badcall();
142 return NULL;
143 }
Guido van Rossuma9e7dc11992-10-18 18:53:57 +0000144 if (free_list == NULL) {
145 f = NEWOBJ(frameobject, &Frametype);
146 f->f_nvalues = f->f_nblocks = 0;
147 f->f_valuestack = NULL;
148 f->f_blockstack = NULL;
149 }
150 else {
151 f = free_list;
152 free_list = free_list->f_back;
Sjoerd Mullenderf64992e1993-08-03 15:11:36 +0000153 f->ob_type = &Frametype;
Guido van Rossuma9e7dc11992-10-18 18:53:57 +0000154 NEWREF(f);
155 }
Guido van Rossum3f5da241990-12-20 15:06:42 +0000156 if (f != NULL) {
157 if (back)
158 INCREF(back);
159 f->f_back = back;
160 INCREF(code);
161 f->f_code = code;
162 INCREF(globals);
163 f->f_globals = globals;
164 INCREF(locals);
165 f->f_locals = locals;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000166 XINCREF(owner);
167 f->f_owner = owner;
Guido van Rossum8b17d6b1993-03-30 13:18:41 +0000168 f->f_fastlocals = NULL;
169 f->f_localmap = NULL;
Guido van Rossuma9e7dc11992-10-18 18:53:57 +0000170 if (nvalues > f->f_nvalues || f->f_valuestack == NULL) {
171 XDEL(f->f_valuestack);
172 f->f_valuestack = NEW(object *, nvalues+1);
173 f->f_nvalues = nvalues;
174 }
175 if (nblocks > f->f_nblocks || f->f_blockstack == NULL) {
176 XDEL(f->f_blockstack);
177 f->f_blockstack = NEW(block, nblocks+1);
178 f->f_nblocks = nblocks;
179 }
Guido van Rossum3f5da241990-12-20 15:06:42 +0000180 f->f_iblock = 0;
Guido van Rossuma9e7dc11992-10-18 18:53:57 +0000181 f->f_lasti = 0;
182 f->f_lineno = -1;
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000183 f->f_trace = NULL;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000184 if (f->f_valuestack == NULL || f->f_blockstack == NULL) {
185 err_nomem();
186 DECREF(f);
187 f = NULL;
188 }
Guido van Rossum3f5da241990-12-20 15:06:42 +0000189 }
190 return f;
191}
192
Guido van Rossuma9e7dc11992-10-18 18:53:57 +0000193object **
194extend_stack(f, level, incr)
195 frameobject *f;
196 int level;
197 int incr;
198{
199 f->f_nvalues = level + incr + 10;
200 f->f_valuestack =
201 (object **) realloc((ANY *)f->f_valuestack,
202 sizeof(object *) * (f->f_nvalues + 1));
203 if (f->f_valuestack == NULL) {
204 err_nomem();
205 return NULL;
206 }
207 return f->f_valuestack + level;
208}
209
Guido van Rossum3f5da241990-12-20 15:06:42 +0000210/* Block management */
211
212void
213setup_block(f, type, handler, level)
214 frameobject *f;
215 int type;
216 int handler;
217 int level;
218{
219 block *b;
220 if (f->f_iblock >= f->f_nblocks) {
221 fprintf(stderr, "XXX block stack overflow\n");
222 abort();
223 }
224 b = &f->f_blockstack[f->f_iblock++];
225 b->b_type = type;
226 b->b_level = level;
227 b->b_handler = handler;
228}
229
230block *
231pop_block(f)
232 frameobject *f;
233{
234 block *b;
235 if (f->f_iblock <= 0) {
236 fprintf(stderr, "XXX block stack underflow\n");
237 abort();
238 }
239 b = &f->f_blockstack[--f->f_iblock];
240 return b;
241}
Guido van Rossum1d5735e1994-08-30 08:27:36 +0000242
243/* Convert between "fast" version of locals and dictionary version */
244
245void
246fast_2_locals(f)
247 frameobject *f;
248{
249 /* Merge f->f_fastlocals into f->f_locals */
250 object *locals, *fast, *map;
251 object *error_type, *error_value;
252 int j;
253 if (f == NULL)
254 return;
255 locals = f->f_locals;
256 fast = f->f_fastlocals;
257 map = f->f_localmap;
258 if (locals == NULL || fast == NULL || map == NULL)
259 return;
260 if (!is_dictobject(locals) || !is_listobject(fast) ||
261 !is_tupleobject(map))
262 return;
263 err_get(&error_type, &error_value);
264 for (j = gettuplesize(map); --j >= 0; ) {
265 object *key = gettupleitem(map, j);
266 object *value = getlistitem(fast, j);
267 if (value == NULL) {
268 err_clear();
269 if (dict2remove(locals, key) != 0)
270 err_clear();
271 }
272 else {
273 if (dict2insert(locals, key, value) != 0)
274 err_clear();
275 }
276 }
277 err_setval(error_type, error_value);
278}
279
280void
281locals_2_fast(f, clear)
282 frameobject *f;
283 int clear;
284{
285 /* Merge f->f_locals into f->f_fastlocals */
286 object *locals, *fast, *map;
287 object *error_type, *error_value;
288 int j;
289 if (f == NULL)
290 return;
291 locals = f->f_locals;
292 fast = f->f_fastlocals;
293 map = f->f_localmap;
294 if (locals == NULL || fast == NULL || map == NULL)
295 return;
296 if (!is_dictobject(locals) || !is_listobject(fast) ||
297 !is_tupleobject(map))
298 return;
299 err_get(&error_type, &error_value);
300 for (j = gettuplesize(map); --j >= 0; ) {
301 object *key = gettupleitem(map, j);
302 object *value = dict2lookup(locals, key);
303 if (value == NULL)
304 err_clear();
305 else
306 INCREF(value);
307 if (value != NULL || clear)
308 if (setlistitem(fast, j, value) != 0)
309 err_clear();
310 }
311 err_setval(error_type, error_value);
312}