frameobject.c revision 3bb63a8dbe19592641330a8f1e12bec5dfd147d2
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_lasti", T_INT, OFF(f_lasti), RO}, 51 {"f_lineno", T_INT, OFF(f_lineno), RO}, 52 {"f_restricted",T_INT, OFF(f_restricted),RO}, 53 {"f_trace", T_OBJECT, OFF(f_trace)}, 54 {NULL} /* Sentinel */ 55}; 56 57static object * 58frame_getattr(f, name) 59 frameobject *f; 60 char *name; 61{ 62 if (strcmp(name, "f_locals") == 0) 63 fast_2_locals(f); 64 return getmember((char *)f, frame_memberlist, name); 65} 66 67static int 68frame_setattr(f, name, value) 69 frameobject *f; 70 char *name; 71 object *value; 72{ 73 return setmember((char *)f, frame_memberlist, name, value); 74} 75 76/* Stack frames are allocated and deallocated at a considerable rate. 77 In an attempt to improve the speed of function calls, we maintain a 78 separate free list of stack frames (just like integers are 79 allocated in a special way -- see intobject.c). When a stack frame 80 is on the free list, only the following members have a meaning: 81 ob_type == &Frametype 82 f_back next item on free list, or NULL 83 f_nlocals number of locals 84 f_stacksize size of value stack 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_trace); 107 f->f_back = free_list; 108 free_list = f; 109} 110 111typeobject Frametype = { 112 OB_HEAD_INIT(&Typetype) 113 0, 114 "frame", 115 sizeof(frameobject), 116 0, 117 (destructor)frame_dealloc, /*tp_dealloc*/ 118 0, /*tp_print*/ 119 (getattrfunc)frame_getattr, /*tp_getattr*/ 120 (setattrfunc)frame_setattr, /*tp_setattr*/ 121 0, /*tp_compare*/ 122 0, /*tp_repr*/ 123 0, /*tp_as_number*/ 124 0, /*tp_as_sequence*/ 125 0, /*tp_as_mapping*/ 126}; 127 128frameobject * 129newframeobject(back, code, globals, locals) 130 frameobject *back; 131 codeobject *code; 132 object *globals; 133 object *locals; 134{ 135 static object *builtin_object; 136 frameobject *f; 137 object *builtins; 138 int extras = code->co_stacksize + code->co_nlocals; 139 140 if (builtin_object == NULL) { 141 builtin_object = PyString_InternFromString("__builtins__"); 142 if (builtin_object == NULL) 143 return NULL; 144 } 145 if ((back != NULL && !is_frameobject(back)) || 146 code == NULL || !is_codeobject(code) || 147 globals == NULL || !is_dictobject(globals) || 148 (locals != NULL && !is_dictobject(locals))) { 149 err_badcall(); 150 return NULL; 151 } 152 builtins = mappinglookup(globals, builtin_object); 153 if (builtins != NULL && is_moduleobject(builtins)) 154 builtins = getmoduledict(builtins); 155 if (builtins == NULL || !is_mappingobject(builtins)) { 156 err_setstr(TypeError, "bad __builtins__ dictionary"); 157 return NULL; 158 } 159 if (free_list == NULL) { 160 f = (frameobject *) 161 malloc(sizeof(frameobject) + extras*sizeof(object *)); 162 if (f == NULL) 163 return (PyFrameObject *)err_nomem(); 164 f->ob_type = &Frametype; 165 NEWREF(f); 166 } 167 else { 168 f = free_list; 169 free_list = free_list->f_back; 170 if (f->f_nlocals + f->f_stacksize < extras) { 171 f = realloc(f, sizeof(frameobject) + extras*sizeof(object *)); 172 if (f == NULL) 173 return (PyFrameObject *)err_nomem(); 174 } 175 f->ob_type = &Frametype; 176 NEWREF(f); 177 } 178 XINCREF(back); 179 f->f_back = back; 180 INCREF(code); 181 f->f_code = code; 182 XINCREF(builtins); 183 f->f_builtins = builtins; 184 INCREF(globals); 185 f->f_globals = globals; 186 if (code->co_flags & CO_NEWLOCALS) { 187 if (code->co_flags & CO_OPTIMIZED) 188 locals = NULL; /* Let fast_2_locals handle it */ 189 else { 190 locals = newdictobject(); 191 if (locals == NULL) { 192 DECREF(f); 193 return NULL; 194 } 195 } 196 } 197 else { 198 if (locals == NULL) 199 locals = globals; 200 INCREF(locals); 201 } 202 f->f_locals = locals; 203 f->f_trace = NULL; 204 205 f->f_lasti = 0; 206 f->f_lineno = -1; 207 f->f_restricted = (builtins != getbuiltindict()); 208 f->f_iblock = 0; 209 f->f_nlocals = code->co_nlocals; 210 f->f_stacksize = code->co_stacksize; 211 212 while (--extras >= 0) 213 f->f_localsplus[extras] = NULL; 214 215 f->f_valuestack = f->f_localsplus + f->f_nlocals; 216 217 return f; 218} 219 220/* Block management */ 221 222void 223setup_block(f, type, handler, level) 224 frameobject *f; 225 int type; 226 int handler; 227 int level; 228{ 229 block *b; 230 if (f->f_iblock >= CO_MAXBLOCKS) 231 fatal("XXX block stack overflow"); 232 b = &f->f_blockstack[f->f_iblock++]; 233 b->b_type = type; 234 b->b_level = level; 235 b->b_handler = handler; 236} 237 238block * 239pop_block(f) 240 frameobject *f; 241{ 242 block *b; 243 if (f->f_iblock <= 0) 244 fatal("XXX block stack underflow"); 245 b = &f->f_blockstack[--f->f_iblock]; 246 return b; 247} 248 249/* Convert between "fast" version of locals and dictionary version */ 250 251void 252fast_2_locals(f) 253 frameobject *f; 254{ 255 /* Merge fast locals into f->f_locals */ 256 object *locals, *map; 257 object **fast; 258 object *error_type, *error_value, *error_traceback; 259 int j; 260 if (f == NULL) 261 return; 262 locals = f->f_locals; 263 if (locals == NULL) { 264 locals = f->f_locals = newdictobject(); 265 if (locals == NULL) { 266 err_clear(); /* Can't report it :-( */ 267 return; 268 } 269 } 270 if (f->f_nlocals == 0) 271 return; 272 map = f->f_code->co_varnames; 273 if (!is_dictobject(locals) || !is_tupleobject(map)) 274 return; 275 err_fetch(&error_type, &error_value, &error_traceback); 276 fast = f->f_localsplus; 277 j = gettuplesize(map); 278 if (j > f->f_nlocals) 279 j = f->f_nlocals; 280 for (; --j >= 0; ) { 281 object *key = gettupleitem(map, j); 282 object *value = fast[j]; 283 if (value == NULL) { 284 err_clear(); 285 if (dict2remove(locals, key) != 0) 286 err_clear(); 287 } 288 else { 289 if (dict2insert(locals, key, value) != 0) 290 err_clear(); 291 } 292 } 293 err_restore(error_type, error_value, error_traceback); 294} 295 296void 297locals_2_fast(f, clear) 298 frameobject *f; 299 int clear; 300{ 301 /* Merge f->f_locals into fast locals */ 302 object *locals, *map; 303 object **fast; 304 object *error_type, *error_value, *error_traceback; 305 int j; 306 if (f == NULL) 307 return; 308 locals = f->f_locals; 309 map = f->f_code->co_varnames; 310 if (locals == NULL || f->f_code->co_nlocals == 0) 311 return; 312 if (!is_dictobject(locals) || !is_tupleobject(map)) 313 return; 314 err_fetch(&error_type, &error_value, &error_traceback); 315 fast = f->f_localsplus; 316 j = gettuplesize(map); 317 if (j > f->f_nlocals) 318 j = f->f_nlocals; 319 for (; --j >= 0; ) { 320 object *key = gettupleitem(map, j); 321 object *value = dict2lookup(locals, key); 322 if (value == NULL) 323 err_clear(); 324 else 325 INCREF(value); 326 if (value != NULL || clear) { 327 XDECREF(fast[j]); 328 XINCREF(value); 329 fast[j] = value; 330 } 331 } 332 err_restore(error_type, error_value, error_traceback); 333} 334