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