| 
									
										
										
										
											1991-02-19 12:39:46 +00:00
										 |  |  | /***********************************************************
 | 
					
						
							| 
									
										
										
										
											1993-03-29 10:43:31 +00:00
										 |  |  | Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum, | 
					
						
							|  |  |  | Amsterdam, The Netherlands. | 
					
						
							| 
									
										
										
										
											1991-02-19 12:39:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                         All Rights Reserved | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Permission to use, copy, modify, and distribute this software and its  | 
					
						
							|  |  |  | documentation for any purpose and without fee is hereby granted,  | 
					
						
							|  |  |  | provided that the above copyright notice appear in all copies and that | 
					
						
							|  |  |  | both that copyright notice and this permission notice appear in  | 
					
						
							|  |  |  | supporting documentation, and that the names of Stichting Mathematisch | 
					
						
							|  |  |  | Centrum or CWI not be used in advertising or publicity pertaining to | 
					
						
							|  |  |  | distribution of the software without specific, written prior permission. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO | 
					
						
							|  |  |  | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | 
					
						
							|  |  |  | FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE | 
					
						
							|  |  |  | FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 
					
						
							|  |  |  | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 
					
						
							|  |  |  | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | 
					
						
							|  |  |  | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ******************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1990-12-20 15:06:42 +00:00
										 |  |  | /* Frame object implementation */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "allobjects.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "compile.h"
 | 
					
						
							|  |  |  | #include "frameobject.h"
 | 
					
						
							|  |  |  | #include "opcode.h"
 | 
					
						
							|  |  |  | #include "structmember.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define OFF(x) offsetof(frameobject, x)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct memberlist frame_memberlist[] = { | 
					
						
							|  |  |  | 	{"f_back",	T_OBJECT,	OFF(f_back)}, | 
					
						
							|  |  |  | 	{"f_code",	T_OBJECT,	OFF(f_code)}, | 
					
						
							|  |  |  | 	{"f_globals",	T_OBJECT,	OFF(f_globals)}, | 
					
						
							|  |  |  | 	{"f_locals",	T_OBJECT,	OFF(f_locals)}, | 
					
						
							| 
									
										
										
										
											1993-03-30 17:46:03 +00:00
										 |  |  | /*	{"f_fastlocals",T_OBJECT,	OFF(f_fastlocals)}, /* XXX Unsafe */ | 
					
						
							| 
									
										
										
										
											1993-03-30 13:18:41 +00:00
										 |  |  | 	{"f_localmap",	T_OBJECT,	OFF(f_localmap)}, | 
					
						
							| 
									
										
										
										
											1992-01-14 18:32:11 +00:00
										 |  |  | 	{"f_lasti",	T_INT,		OFF(f_lasti)}, | 
					
						
							|  |  |  | 	{"f_lineno",	T_INT,		OFF(f_lineno)}, | 
					
						
							| 
									
										
										
										
											1990-12-20 15:06:42 +00:00
										 |  |  | 	{NULL}	/* Sentinel */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static object * | 
					
						
							|  |  |  | frame_getattr(f, name) | 
					
						
							|  |  |  | 	frameobject *f; | 
					
						
							|  |  |  | 	char *name; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return getmember((char *)f, frame_memberlist, name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1992-10-18 18:53:57 +00:00
										 |  |  | /* Stack frames are allocated and deallocated at a considerable rate.
 | 
					
						
							|  |  |  |    In an attempt to improve the speed of function calls, we maintain a | 
					
						
							|  |  |  |    separate free list of stack frames (just like integers are | 
					
						
							|  |  |  |    allocated in a special way -- see intobject.c).  When a stack frame | 
					
						
							|  |  |  |    is on the free list, only the following members have a meaning: | 
					
						
							|  |  |  | 	ob_type		== &Frametype | 
					
						
							|  |  |  | 	f_back		next item on free list, or NULL | 
					
						
							|  |  |  | 	f_nvalues	size of f_valuestack | 
					
						
							|  |  |  | 	f_valuestack	array of (f_nvalues+1) object pointers, or NULL | 
					
						
							|  |  |  | 	f_nblocks	size of f_blockstack | 
					
						
							|  |  |  | 	f_blockstack	array of (f_nblocks+1) blocks, or NULL | 
					
						
							|  |  |  |    Note that the value and block stacks are preserved -- this can save | 
					
						
							|  |  |  |    another malloc() call or two (and two free() calls as well!). | 
					
						
							|  |  |  |    Also note that, unlike for integers, each frame object is a | 
					
						
							|  |  |  |    malloc'ed object in its own right -- it is only the actual calls to | 
					
						
							|  |  |  |    malloc() that we are trying to save here, not the administration. | 
					
						
							|  |  |  |    After all, while a typical program may make millions of calls, a | 
					
						
							|  |  |  |    call depth of more than 20 or 30 is probably already exceptional | 
					
						
							|  |  |  |    unless the program contains run-away recursion.  I hope. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static frameobject *free_list = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1990-12-20 15:06:42 +00:00
										 |  |  | static void | 
					
						
							|  |  |  | frame_dealloc(f) | 
					
						
							|  |  |  | 	frameobject *f; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	XDECREF(f->f_back); | 
					
						
							|  |  |  | 	XDECREF(f->f_code); | 
					
						
							|  |  |  | 	XDECREF(f->f_globals); | 
					
						
							|  |  |  | 	XDECREF(f->f_locals); | 
					
						
							| 
									
										
										
										
											1993-03-30 13:18:41 +00:00
										 |  |  | 	XDECREF(f->f_fastlocals); | 
					
						
							|  |  |  | 	XDECREF(f->f_localmap); | 
					
						
							| 
									
										
										
										
											1992-10-18 18:53:57 +00:00
										 |  |  | 	f->f_back = free_list; | 
					
						
							|  |  |  | 	free_list = f; | 
					
						
							| 
									
										
										
										
											1990-12-20 15:06:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typeobject Frametype = { | 
					
						
							|  |  |  | 	OB_HEAD_INIT(&Typetype) | 
					
						
							|  |  |  | 	0, | 
					
						
							|  |  |  | 	"frame", | 
					
						
							|  |  |  | 	sizeof(frameobject), | 
					
						
							|  |  |  | 	0, | 
					
						
							|  |  |  | 	frame_dealloc,	/*tp_dealloc*/ | 
					
						
							|  |  |  | 	0,		/*tp_print*/ | 
					
						
							|  |  |  | 	frame_getattr,	/*tp_getattr*/ | 
					
						
							|  |  |  | 	0,		/*tp_setattr*/ | 
					
						
							|  |  |  | 	0,		/*tp_compare*/ | 
					
						
							|  |  |  | 	0,		/*tp_repr*/ | 
					
						
							|  |  |  | 	0,		/*tp_as_number*/ | 
					
						
							|  |  |  | 	0,		/*tp_as_sequence*/ | 
					
						
							|  |  |  | 	0,		/*tp_as_mapping*/ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | frameobject * | 
					
						
							|  |  |  | newframeobject(back, code, globals, locals, nvalues, nblocks) | 
					
						
							|  |  |  | 	frameobject *back; | 
					
						
							|  |  |  | 	codeobject *code; | 
					
						
							|  |  |  | 	object *globals; | 
					
						
							|  |  |  | 	object *locals; | 
					
						
							|  |  |  | 	int nvalues; | 
					
						
							|  |  |  | 	int nblocks; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	frameobject *f; | 
					
						
							|  |  |  | 	if ((back != NULL && !is_frameobject(back)) || | 
					
						
							|  |  |  | 		code == NULL || !is_codeobject(code) || | 
					
						
							|  |  |  | 		globals == NULL || !is_dictobject(globals) || | 
					
						
							|  |  |  | 		locals == NULL || !is_dictobject(locals) || | 
					
						
							|  |  |  | 		nvalues < 0 || nblocks < 0) { | 
					
						
							|  |  |  | 		err_badcall(); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1992-10-18 18:53:57 +00:00
										 |  |  | 	if (free_list == NULL) { | 
					
						
							|  |  |  | 		f = NEWOBJ(frameobject, &Frametype); | 
					
						
							|  |  |  | 		f->f_nvalues = f->f_nblocks = 0; | 
					
						
							|  |  |  | 		f->f_valuestack = NULL; | 
					
						
							|  |  |  | 		f->f_blockstack = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		f = free_list; | 
					
						
							|  |  |  | 		free_list = free_list->f_back; | 
					
						
							|  |  |  | 		NEWREF(f); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1990-12-20 15:06:42 +00:00
										 |  |  | 	if (f != NULL) { | 
					
						
							|  |  |  | 		if (back) | 
					
						
							|  |  |  | 			INCREF(back); | 
					
						
							|  |  |  | 		f->f_back = back; | 
					
						
							|  |  |  | 		INCREF(code); | 
					
						
							|  |  |  | 		f->f_code = code; | 
					
						
							|  |  |  | 		INCREF(globals); | 
					
						
							|  |  |  | 		f->f_globals = globals; | 
					
						
							|  |  |  | 		INCREF(locals); | 
					
						
							|  |  |  | 		f->f_locals = locals; | 
					
						
							| 
									
										
										
										
											1993-03-30 13:18:41 +00:00
										 |  |  | 		f->f_fastlocals = NULL; | 
					
						
							|  |  |  | 		f->f_localmap = NULL; | 
					
						
							| 
									
										
										
										
											1992-10-18 18:53:57 +00:00
										 |  |  | 		if (nvalues > f->f_nvalues || f->f_valuestack == NULL) { | 
					
						
							|  |  |  | 			XDEL(f->f_valuestack); | 
					
						
							|  |  |  | 			f->f_valuestack = NEW(object *, nvalues+1); | 
					
						
							|  |  |  | 			f->f_nvalues = nvalues; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (nblocks > f->f_nblocks || f->f_blockstack == NULL) { | 
					
						
							|  |  |  | 			XDEL(f->f_blockstack); | 
					
						
							|  |  |  | 			f->f_blockstack = NEW(block, nblocks+1); | 
					
						
							|  |  |  | 			f->f_nblocks = nblocks; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											1990-12-20 15:06:42 +00:00
										 |  |  | 		f->f_iblock = 0; | 
					
						
							| 
									
										
										
										
											1992-10-18 18:53:57 +00:00
										 |  |  | 		f->f_lasti = 0; | 
					
						
							|  |  |  | 		f->f_lineno = -1; | 
					
						
							| 
									
										
										
										
											1990-12-20 15:06:42 +00:00
										 |  |  | 		if (f->f_valuestack == NULL || f->f_blockstack == NULL) { | 
					
						
							|  |  |  | 			err_nomem(); | 
					
						
							|  |  |  | 			DECREF(f); | 
					
						
							|  |  |  | 			f = NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return f; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1992-10-18 18:53:57 +00:00
										 |  |  | object ** | 
					
						
							|  |  |  | extend_stack(f, level, incr) | 
					
						
							|  |  |  | 	frameobject *f; | 
					
						
							|  |  |  | 	int level; | 
					
						
							|  |  |  | 	int incr; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	f->f_nvalues = level + incr + 10; | 
					
						
							|  |  |  | 	f->f_valuestack = | 
					
						
							|  |  |  | 		(object **) realloc((ANY *)f->f_valuestack, | 
					
						
							|  |  |  | 				    sizeof(object *) * (f->f_nvalues + 1)); | 
					
						
							|  |  |  | 	if (f->f_valuestack == NULL) { | 
					
						
							|  |  |  | 		err_nomem(); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return f->f_valuestack + level; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1990-12-20 15:06:42 +00:00
										 |  |  | /* Block management */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | setup_block(f, type, handler, level) | 
					
						
							|  |  |  | 	frameobject *f; | 
					
						
							|  |  |  | 	int type; | 
					
						
							|  |  |  | 	int handler; | 
					
						
							|  |  |  | 	int level; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	block *b; | 
					
						
							|  |  |  | 	if (f->f_iblock >= f->f_nblocks) { | 
					
						
							|  |  |  | 		fprintf(stderr, "XXX block stack overflow\n"); | 
					
						
							|  |  |  | 		abort(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	b = &f->f_blockstack[f->f_iblock++]; | 
					
						
							|  |  |  | 	b->b_type = type; | 
					
						
							|  |  |  | 	b->b_level = level; | 
					
						
							|  |  |  | 	b->b_handler = handler; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | block * | 
					
						
							|  |  |  | pop_block(f) | 
					
						
							|  |  |  | 	frameobject *f; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	block *b; | 
					
						
							|  |  |  | 	if (f->f_iblock <= 0) { | 
					
						
							|  |  |  | 		fprintf(stderr, "XXX block stack underflow\n"); | 
					
						
							|  |  |  | 		abort(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	b = &f->f_blockstack[--f->f_iblock]; | 
					
						
							|  |  |  | 	return b; | 
					
						
							|  |  |  | } |