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