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.
diff --git a/Include/frameobject.h b/Include/frameobject.h
index c19f1d8..d1a310a 100644
--- a/Include/frameobject.h
+++ b/Include/frameobject.h
@@ -20,7 +20,6 @@
     PyObject *f_builtins;	/* builtin symbol table (PyDictObject) */
     PyObject *f_globals;	/* global 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_trace;		/* Trace function */
     PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
@@ -31,7 +30,10 @@
 				   in this scope */
     int f_iblock;		/* index in f_blockstack */
     PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
+    int f_size;                 /* size of localsplus */
     int f_nlocals;		/* number of locals */
+    int f_ncells;
+    int f_nfreevars;
     int f_stacksize;		/* size of value stack */
     PyObject *f_localsplus[1];	/* locals+stack, dynamically sized */
 } PyFrameObject;
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 0f6372b..18fb0b0 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -49,6 +49,7 @@
 	f_back		next item on free list, or NULL
 	f_nlocals	number of locals
 	f_stacksize	size of value stack
+        f_size          size of localsplus
    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
@@ -79,7 +80,6 @@
 	Py_XDECREF(f->f_builtins);
 	Py_XDECREF(f->f_globals);
 	Py_XDECREF(f->f_locals);
-	Py_XDECREF(f->f_closure);
 	Py_XDECREF(f->f_trace);
 	Py_XDECREF(f->f_exc_type);
 	Py_XDECREF(f->f_exc_value);
@@ -114,7 +114,7 @@
 	static PyObject *builtin_object;
 	PyFrameObject *f;
 	PyObject *builtins;
-	int extras, ncells;
+	int extras, ncells, nfrees;
 
 	if (builtin_object == NULL) {
 		builtin_object = PyString_InternFromString("__builtins__");
@@ -128,8 +128,9 @@
 		PyErr_BadInternalCall();
 		return NULL;
 	}
-	extras = code->co_stacksize + code->co_nlocals;
 	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) {
 		builtins = PyDict_GetItem(globals, builtin_object);
 		if (builtins != NULL && PyModule_Check(builtins))
@@ -150,19 +151,21 @@
 		if (f == NULL)
 			return (PyFrameObject *)PyErr_NoMemory();
 		PyObject_INIT(f, &PyFrame_Type);
+		f->f_size = extras;
 	}
 	else {
 		f = free_list;
 		free_list = free_list->f_back;
-		if (f->f_nlocals + f->f_stacksize < extras) {
+		if (f->f_size < extras) {
 			f = (PyFrameObject *)
 				PyObject_REALLOC(f, sizeof(PyFrameObject) +
 						 extras*sizeof(PyObject *));
 			if (f == NULL)
 				return (PyFrameObject *)PyErr_NoMemory();
+			f->f_size = extras;
 		}
 		else
-			extras = f->f_nlocals + f->f_stacksize;
+			extras = f->f_size;
 		PyObject_INIT(f, &PyFrame_Type);
 	}
 	if (builtins == NULL) {
@@ -199,22 +202,6 @@
 			locals = globals;
 		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_trace = NULL;
 	f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL;
@@ -225,12 +212,14 @@
 	f->f_restricted = (builtins != tstate->interp->builtins);
 	f->f_iblock = 0;
 	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)
 		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;
 }
@@ -261,6 +250,8 @@
 
 /* Convert between "fast" version of locals and dictionary version */
 
+/* XXX should also copy free variables and cell variables */
+
 void
 PyFrame_FastToLocals(PyFrameObject *f)
 {
diff --git a/Python/ceval.c b/Python/ceval.c
index c7b5696..5d593f2 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -368,7 +368,7 @@
 	register PyObject *t;
 	register PyObject *stream = NULL;    /* for PRINT opcodes */
 	register PyFrameObject *f; /* Current frame */
-	register PyObject **fastlocals;
+	register PyObject **fastlocals, **freevars;
 	PyObject *retval = NULL;	/* Return value */
 	PyThreadState *tstate = PyThreadState_GET();
 	unsigned char *first_instr;
@@ -439,6 +439,7 @@
 
 	tstate->frame = f;
 	fastlocals = f->f_localsplus;
+	freevars = f->f_localsplus + f->f_nlocals;
 
 	if (co->co_argcount > 0 ||
 	    co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) {
@@ -572,6 +573,17 @@
 			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) {
 		/* tstate->sys_tracefunc, if defined, is a function that
@@ -1623,13 +1635,13 @@
 			continue;
 
 		case LOAD_CLOSURE:
-			x = PyTuple_GET_ITEM(f->f_closure, oparg);
+			x = freevars[oparg];
 			Py_INCREF(x);
 			PUSH(x);
 			break;
 
 		case LOAD_DEREF:
-			x = PyTuple_GET_ITEM(f->f_closure, oparg);
+			x = freevars[oparg];
 			w = PyCell_Get(x);
 			Py_INCREF(w);
 			PUSH(w);
@@ -1637,7 +1649,7 @@
 
 		case STORE_DEREF:
 			w = POP();
-			x = PyTuple_GET_ITEM(f->f_closure, oparg);
+			x = freevars[oparg];
 			PyCell_Set(x, w);
 			continue;