mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Remove f_closure slot of frameobject and use f_localsplus instead.
This change eliminates an extra malloc/free when a frame with free variables is created. Any cell vars or free vars are stored in f_localsplus after the locals and before the stack. eval_code2() fills in the appropriate values after handling initialization of locals. To track the size the frame has an f_size member that tracks the total size of f_localsplus. It used to be implicitly f_nlocals + f_stacksize.
This commit is contained in:
		
							parent
							
								
									55087f0c35
								
							
						
					
					
						commit
						2b724da8d9
					
				
					 3 changed files with 33 additions and 28 deletions
				
			
		|  | @ -20,7 +20,6 @@ typedef struct _frame { | ||||||
|     PyObject *f_builtins;	/* builtin symbol table (PyDictObject) */ |     PyObject *f_builtins;	/* builtin symbol table (PyDictObject) */ | ||||||
|     PyObject *f_globals;	/* global symbol table (PyDictObject) */ |     PyObject *f_globals;	/* global symbol table (PyDictObject) */ | ||||||
|     PyObject *f_locals;		/* local symbol table (PyDictObject) */ |     PyObject *f_locals;		/* local symbol table (PyDictObject) */ | ||||||
|     PyObject *f_closure;        /* environment for free variables */ |  | ||||||
|     PyObject **f_valuestack;	/* points after the last local */ |     PyObject **f_valuestack;	/* points after the last local */ | ||||||
|     PyObject *f_trace;		/* Trace function */ |     PyObject *f_trace;		/* Trace function */ | ||||||
|     PyObject *f_exc_type, *f_exc_value, *f_exc_traceback; |     PyObject *f_exc_type, *f_exc_value, *f_exc_traceback; | ||||||
|  | @ -31,7 +30,10 @@ typedef struct _frame { | ||||||
| 				   in this scope */ | 				   in this scope */ | ||||||
|     int f_iblock;		/* index in f_blockstack */ |     int f_iblock;		/* index in f_blockstack */ | ||||||
|     PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */ |     PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */ | ||||||
|  |     int f_size;                 /* size of localsplus */ | ||||||
|     int f_nlocals;		/* number of locals */ |     int f_nlocals;		/* number of locals */ | ||||||
|  |     int f_ncells; | ||||||
|  |     int f_nfreevars; | ||||||
|     int f_stacksize;		/* size of value stack */ |     int f_stacksize;		/* size of value stack */ | ||||||
|     PyObject *f_localsplus[1];	/* locals+stack, dynamically sized */ |     PyObject *f_localsplus[1];	/* locals+stack, dynamically sized */ | ||||||
| } PyFrameObject; | } PyFrameObject; | ||||||
|  |  | ||||||
|  | @ -49,6 +49,7 @@ frame_setattr(PyFrameObject *f, char *name, PyObject *value) | ||||||
| 	f_back		next item on free list, or NULL | 	f_back		next item on free list, or NULL | ||||||
| 	f_nlocals	number of locals | 	f_nlocals	number of locals | ||||||
| 	f_stacksize	size of value stack | 	f_stacksize	size of value stack | ||||||
|  |         f_size          size of localsplus | ||||||
|    Note that the value and block stacks are preserved -- this can save |    Note that the value and block stacks are preserved -- this can save | ||||||
|    another malloc() call or two (and two free() calls as well!). |    another malloc() call or two (and two free() calls as well!). | ||||||
|    Also note that, unlike for integers, each frame object is a |    Also note that, unlike for integers, each frame object is a | ||||||
|  | @ -79,7 +80,6 @@ frame_dealloc(PyFrameObject *f) | ||||||
| 	Py_XDECREF(f->f_builtins); | 	Py_XDECREF(f->f_builtins); | ||||||
| 	Py_XDECREF(f->f_globals); | 	Py_XDECREF(f->f_globals); | ||||||
| 	Py_XDECREF(f->f_locals); | 	Py_XDECREF(f->f_locals); | ||||||
| 	Py_XDECREF(f->f_closure); |  | ||||||
| 	Py_XDECREF(f->f_trace); | 	Py_XDECREF(f->f_trace); | ||||||
| 	Py_XDECREF(f->f_exc_type); | 	Py_XDECREF(f->f_exc_type); | ||||||
| 	Py_XDECREF(f->f_exc_value); | 	Py_XDECREF(f->f_exc_value); | ||||||
|  | @ -114,7 +114,7 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, | ||||||
| 	static PyObject *builtin_object; | 	static PyObject *builtin_object; | ||||||
| 	PyFrameObject *f; | 	PyFrameObject *f; | ||||||
| 	PyObject *builtins; | 	PyObject *builtins; | ||||||
| 	int extras, ncells; | 	int extras, ncells, nfrees; | ||||||
| 
 | 
 | ||||||
| 	if (builtin_object == NULL) { | 	if (builtin_object == NULL) { | ||||||
| 		builtin_object = PyString_InternFromString("__builtins__"); | 		builtin_object = PyString_InternFromString("__builtins__"); | ||||||
|  | @ -128,8 +128,9 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, | ||||||
| 		PyErr_BadInternalCall(); | 		PyErr_BadInternalCall(); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
| 	extras = code->co_stacksize + code->co_nlocals; |  | ||||||
| 	ncells = PyTuple_GET_SIZE(code->co_cellvars); | 	ncells = PyTuple_GET_SIZE(code->co_cellvars); | ||||||
|  | 	nfrees = PyTuple_GET_SIZE(code->co_freevars); | ||||||
|  | 	extras = code->co_stacksize + code->co_nlocals + ncells + nfrees; | ||||||
| 	if (back == NULL || back->f_globals != globals) { | 	if (back == NULL || back->f_globals != globals) { | ||||||
| 		builtins = PyDict_GetItem(globals, builtin_object); | 		builtins = PyDict_GetItem(globals, builtin_object); | ||||||
| 		if (builtins != NULL && PyModule_Check(builtins)) | 		if (builtins != NULL && PyModule_Check(builtins)) | ||||||
|  | @ -150,19 +151,21 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, | ||||||
| 		if (f == NULL) | 		if (f == NULL) | ||||||
| 			return (PyFrameObject *)PyErr_NoMemory(); | 			return (PyFrameObject *)PyErr_NoMemory(); | ||||||
| 		PyObject_INIT(f, &PyFrame_Type); | 		PyObject_INIT(f, &PyFrame_Type); | ||||||
|  | 		f->f_size = extras; | ||||||
| 	} | 	} | ||||||
| 	else { | 	else { | ||||||
| 		f = free_list; | 		f = free_list; | ||||||
| 		free_list = free_list->f_back; | 		free_list = free_list->f_back; | ||||||
| 		if (f->f_nlocals + f->f_stacksize < extras) { | 		if (f->f_size < extras) { | ||||||
| 			f = (PyFrameObject *) | 			f = (PyFrameObject *) | ||||||
| 				PyObject_REALLOC(f, sizeof(PyFrameObject) + | 				PyObject_REALLOC(f, sizeof(PyFrameObject) + | ||||||
| 						 extras*sizeof(PyObject *)); | 						 extras*sizeof(PyObject *)); | ||||||
| 			if (f == NULL) | 			if (f == NULL) | ||||||
| 				return (PyFrameObject *)PyErr_NoMemory(); | 				return (PyFrameObject *)PyErr_NoMemory(); | ||||||
|  | 			f->f_size = extras; | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 			extras = f->f_nlocals + f->f_stacksize; | 			extras = f->f_size; | ||||||
| 		PyObject_INIT(f, &PyFrame_Type); | 		PyObject_INIT(f, &PyFrame_Type); | ||||||
| 	} | 	} | ||||||
| 	if (builtins == NULL) { | 	if (builtins == NULL) { | ||||||
|  | @ -199,22 +202,6 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, | ||||||
| 			locals = globals; | 			locals = globals; | ||||||
| 		Py_INCREF(locals); | 		Py_INCREF(locals); | ||||||
| 	} | 	} | ||||||
| 	if (closure || ncells) { |  | ||||||
| 		int i, size; |  | ||||||
| 		size = ncells; |  | ||||||
| 		if (closure) |  | ||||||
| 			size += PyTuple_GET_SIZE(closure); |  | ||||||
| 		f->f_closure = PyTuple_New(size); |  | ||||||
| 		for (i = 0; i < ncells; ++i) |  | ||||||
| 			PyTuple_SET_ITEM(f->f_closure, i, PyCell_New(NULL)); |  | ||||||
| 		for (i = ncells; i < size; ++i) { |  | ||||||
| 			PyObject *o = PyTuple_GET_ITEM(closure, i - ncells); |  | ||||||
| 			Py_INCREF(o); |  | ||||||
| 			PyTuple_SET_ITEM(f->f_closure, i, o); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 		f->f_closure = NULL; |  | ||||||
| 	f->f_locals = locals; | 	f->f_locals = locals; | ||||||
| 	f->f_trace = NULL; | 	f->f_trace = NULL; | ||||||
| 	f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL; | 	f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL; | ||||||
|  | @ -225,12 +212,14 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, | ||||||
| 	f->f_restricted = (builtins != tstate->interp->builtins); | 	f->f_restricted = (builtins != tstate->interp->builtins); | ||||||
| 	f->f_iblock = 0; | 	f->f_iblock = 0; | ||||||
| 	f->f_nlocals = code->co_nlocals; | 	f->f_nlocals = code->co_nlocals; | ||||||
| 	f->f_stacksize = extras - code->co_nlocals; | 	f->f_stacksize = code->co_stacksize; | ||||||
|  | 	f->f_ncells = ncells; | ||||||
|  | 	f->f_nfreevars = nfrees; | ||||||
| 
 | 
 | ||||||
| 	while (--extras >= 0) | 	while (--extras >= 0) | ||||||
| 		f->f_localsplus[extras] = NULL; | 		f->f_localsplus[extras] = NULL; | ||||||
| 
 | 
 | ||||||
| 	f->f_valuestack = f->f_localsplus + f->f_nlocals; | 	f->f_valuestack = f->f_localsplus + (f->f_nlocals + ncells + nfrees); | ||||||
| 
 | 
 | ||||||
| 	return f; | 	return f; | ||||||
| } | } | ||||||
|  | @ -261,6 +250,8 @@ PyFrame_BlockPop(PyFrameObject *f) | ||||||
| 
 | 
 | ||||||
| /* Convert between "fast" version of locals and dictionary version */ | /* Convert between "fast" version of locals and dictionary version */ | ||||||
| 
 | 
 | ||||||
|  | /* XXX should also copy free variables and cell variables */ | ||||||
|  | 
 | ||||||
| void | void | ||||||
| PyFrame_FastToLocals(PyFrameObject *f) | PyFrame_FastToLocals(PyFrameObject *f) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -368,7 +368,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, | ||||||
| 	register PyObject *t; | 	register PyObject *t; | ||||||
| 	register PyObject *stream = NULL;    /* for PRINT opcodes */ | 	register PyObject *stream = NULL;    /* for PRINT opcodes */ | ||||||
| 	register PyFrameObject *f; /* Current frame */ | 	register PyFrameObject *f; /* Current frame */ | ||||||
| 	register PyObject **fastlocals; | 	register PyObject **fastlocals, **freevars; | ||||||
| 	PyObject *retval = NULL;	/* Return value */ | 	PyObject *retval = NULL;	/* Return value */ | ||||||
| 	PyThreadState *tstate = PyThreadState_GET(); | 	PyThreadState *tstate = PyThreadState_GET(); | ||||||
| 	unsigned char *first_instr; | 	unsigned char *first_instr; | ||||||
|  | @ -439,6 +439,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, | ||||||
| 
 | 
 | ||||||
| 	tstate->frame = f; | 	tstate->frame = f; | ||||||
| 	fastlocals = f->f_localsplus; | 	fastlocals = f->f_localsplus; | ||||||
|  | 	freevars = f->f_localsplus + f->f_nlocals; | ||||||
| 
 | 
 | ||||||
| 	if (co->co_argcount > 0 || | 	if (co->co_argcount > 0 || | ||||||
| 	    co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { | 	    co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { | ||||||
|  | @ -572,6 +573,17 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, | ||||||
| 			goto fail; | 			goto fail; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	/* Allocate storage for cell vars and copy free vars into frame */  | ||||||
|  | 	if (f->f_ncells) { | ||||||
|  | 		int i; | ||||||
|  | 		for (i = 0; i < f->f_ncells; ++i) | ||||||
|  | 			freevars[i] = PyCell_New(NULL); | ||||||
|  | 	} | ||||||
|  | 	if (f->f_nfreevars) { | ||||||
|  | 		int i; | ||||||
|  | 		for (i = 0; i < f->f_nfreevars; ++i) | ||||||
|  | 			freevars[f->f_ncells + i] = PyTuple_GET_ITEM(closure, i); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (tstate->sys_tracefunc != NULL) { | 	if (tstate->sys_tracefunc != NULL) { | ||||||
| 		/* tstate->sys_tracefunc, if defined, is a function that
 | 		/* tstate->sys_tracefunc, if defined, is a function that
 | ||||||
|  | @ -1623,13 +1635,13 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		case LOAD_CLOSURE: | 		case LOAD_CLOSURE: | ||||||
| 			x = PyTuple_GET_ITEM(f->f_closure, oparg); | 			x = freevars[oparg]; | ||||||
| 			Py_INCREF(x); | 			Py_INCREF(x); | ||||||
| 			PUSH(x); | 			PUSH(x); | ||||||
| 			break; | 			break; | ||||||
| 
 | 
 | ||||||
| 		case LOAD_DEREF: | 		case LOAD_DEREF: | ||||||
| 			x = PyTuple_GET_ITEM(f->f_closure, oparg); | 			x = freevars[oparg]; | ||||||
| 			w = PyCell_Get(x); | 			w = PyCell_Get(x); | ||||||
| 			Py_INCREF(w); | 			Py_INCREF(w); | ||||||
| 			PUSH(w); | 			PUSH(w); | ||||||
|  | @ -1637,7 +1649,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, | ||||||
| 
 | 
 | ||||||
| 		case STORE_DEREF: | 		case STORE_DEREF: | ||||||
| 			w = POP(); | 			w = POP(); | ||||||
| 			x = PyTuple_GET_ITEM(f->f_closure, oparg); | 			x = freevars[oparg]; | ||||||
| 			PyCell_Set(x, w); | 			PyCell_Set(x, w); | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jeremy Hylton
						Jeremy Hylton