Index: Include/ceval.h
===================================================================
RCS file: /cvsroot/python/python/dist/src/Include/ceval.h,v
retrieving revision 2.41
diff -u -r2.41 ceval.h
--- Include/ceval.h	2001/03/22 02:32:48	2.41
+++ Include/ceval.h	2001/03/27 04:42:52
@@ -10,6 +10,10 @@
 DL_IMPORT(PyObject *) PyEval_CallObjectWithKeywords
 	(PyObject *, PyObject *, PyObject *);
 
+struct _frame;
+
+DL_IMPORT(PyObject *) PyEval_EvalFrame(struct _frame *);
+
 /* DLL-level Backwards compatibility: */
 #undef PyEval_CallObject
 DL_IMPORT(PyObject *) PyEval_CallObject(PyObject *, PyObject *);
Index: Include/frameobject.h
===================================================================
RCS file: /cvsroot/python/python/dist/src/Include/frameobject.h,v
retrieving revision 2.31
diff -u -r2.31 frameobject.h
--- Include/frameobject.h	2001/03/13 01:58:21	2.31
+++ Include/frameobject.h	2001/03/27 04:42:53
@@ -21,6 +21,11 @@
     PyObject *f_globals;	/* global symbol table (PyDictObject) */
     PyObject *f_locals;		/* local symbol table (PyDictObject) */
     PyObject **f_valuestack;	/* points after the last local */
+    PyObject **f_stackbottom;	/* points to the last item on the stack if
+				   frame has been suspended. */
+    PyObject *f_suspendvalue;	/* set to v when f.suspend(v) is called.  ceval
+				   will then suspend execution of the frame and
+				   return v. */
     PyObject *f_trace;		/* Trace function */
     PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
     PyThreadState *f_tstate;
Index: Objects/frameobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/frameobject.c,v
retrieving revision 2.47
diff -u -r2.47 frameobject.c
--- Objects/frameobject.c	2001/03/21 16:43:45	2.47
+++ Objects/frameobject.c	2001/03/27 04:43:24
@@ -27,11 +27,73 @@
 };
 
 static PyObject *
+frame_suspend(PyFrameObject *f, PyObject *args)
+{
+	PyObject *v;
+	if (!PyArg_ParseTuple(args, "O:suspend", &v))
+		return NULL;
+	/*
+	if (f->f_stackbottom == NULL) {
+		PyErr_SetString(PyExc_ValueError, "frame not suspendable");
+		return NULL;
+	}
+	*/
+	Py_INCREF(v);
+	Py_XDECREF(f->f_suspendvalue);
+	f->f_suspendvalue = v;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+frame_resume(PyFrameObject *f, PyObject *args)
+{
+	PyThreadState *tstate = PyThreadState_GET();
+	PyObject *rvalue = NULL;
+	if (!PyArg_ParseTuple(args, "|O:resume", &rvalue))
+		return NULL;
+	if (f->f_stackbottom == NULL) {
+		PyErr_SetString(PyExc_ValueError, "frame not resumable");
+		return NULL;
+	}
+	f->f_back = tstate->frame;
+	/* don't run off the end of the code */
+	if (f->f_lasti >= PySequence_Size(f->f_code->co_code)) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+	if (rvalue) {
+		fprintf(stderr, "pushing new return value %p\n", rvalue);
+		/* pop old return value off stack and push new one */
+		if (f->f_stackbottom <= f->f_valuestack)
+			Py_FatalError("frame_resume: stack underflow");
+		Py_DECREF(*(f->f_stackbottom-1));
+		Py_INCREF(rvalue);
+		*(f->f_stackbottom-1) = rvalue;
+	}
+
+	Py_INCREF(f);
+	return PyEval_EvalFrame(f);
+}
+
+
+static struct PyMethodDef frame_methods[] = {
+	{"suspend",	(PyCFunction)frame_suspend, METH_VARARGS},
+	{"resume",	(PyCFunction)frame_resume, METH_VARARGS},
+	{NULL, 		NULL}	/* Sentinel */
+};
+
+static PyObject *
 frame_getattr(PyFrameObject *f, char *name)
 {
+	PyObject *res;
 	if (strcmp(name, "f_locals") == 0)
 		PyFrame_FastToLocals(f);
-	return PyMember_Get((char *)f, frame_memberlist, name);
+	res = PyMember_Get((char *)f, frame_memberlist, name);
+	if (res != NULL)
+		return res;
+	PyErr_Clear();
+	return Py_FindMethod(frame_methods, (PyObject *)f, name);
 }
 
 static int
@@ -67,6 +129,7 @@
 {
 	int i, slots;
 	PyObject **fastlocals;
+	PyObject **p;
 
 	Py_TRASHCAN_SAFE_BEGIN(f)
 	/* Kill all local variables */
@@ -75,7 +138,10 @@
 	for (i = slots; --i >= 0; ++fastlocals) {
 		Py_XDECREF(*fastlocals);
 	}
-
+	/* Free stack */
+	for (p = f->f_valuestack; p < f->f_stackbottom; p++) {
+		Py_XDECREF(*p);
+	}
 	Py_XDECREF(f->f_back);
 	Py_XDECREF(f->f_code);
 	Py_XDECREF(f->f_builtins);
@@ -85,6 +151,7 @@
 	Py_XDECREF(f->f_exc_type);
 	Py_XDECREF(f->f_exc_value);
 	Py_XDECREF(f->f_exc_traceback);
+	Py_XDECREF(f->f_suspendvalue);
 	f->f_back = free_list;
 	free_list = f;
 	Py_TRASHCAN_SAFE_END(f)
@@ -221,6 +288,8 @@
 		f->f_localsplus[extras] = NULL;
 
 	f->f_valuestack = f->f_localsplus + (f->f_nlocals + ncells + nfrees);
+	f->f_stackbottom = f->f_valuestack;
+	f->f_suspendvalue = NULL;
 
 	return f;
 }
Index: Python/ceval.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/ceval.c,v
retrieving revision 2.235
diff -u -r2.235 ceval.c
--- Python/ceval.c	2001/03/22 02:47:58	2.235
+++ Python/ceval.c	2001/03/27 04:43:38
@@ -322,6 +322,7 @@
 		WHY_EXCEPTION,	/* Exception occurred */
 		WHY_RERAISE,	/* Exception re-raised by 'finally' */
 		WHY_RETURN,	/* 'return' statement */
+		WHY_SUSPEND,	/* 'suspend' statement */
 		WHY_BREAK,	/* 'break' statement */
 		WHY_CONTINUE	/* 'continue' statement */
 };
@@ -341,13 +342,8 @@
 			  NULL);
 }
 
-
-/* Interpreter main loop */
-
-static PyObject *
-eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
-	   PyObject **args, int argcount, PyObject **kws, int kwcount,
-	   PyObject **defs, int defcount, PyObject *closure)
+PyObject *
+PyEval_EvalFrame(PyFrameObject *f)
 {
 #ifdef DXPAIRS
 	int lastopcode = 0;
@@ -364,10 +360,10 @@
 	register PyObject *u;
 	register PyObject *t;
 	register PyObject *stream = NULL;    /* for PRINT opcodes */
-	register PyFrameObject *f; /* Current frame */
 	register PyObject **fastlocals, **freevars;
 	PyObject *retval = NULL;	/* Return value */
-	PyThreadState *tstate = PyThreadState_GET();
+	PyThreadState *tstate = f->f_tstate;
+	PyCodeObject *co = f->f_code;
 	unsigned char *first_instr;
 #ifdef LLTRACE
 	int lltrace;
@@ -409,317 +405,83 @@
 #define GETLOCAL(i)	(fastlocals[i])
 #define SETLOCAL(i, value)	do { Py_XDECREF(GETLOCAL(i)); \
 				     GETLOCAL(i) = value; } while (0)
-
-/* Start of code */
-
-#ifdef USE_STACKCHECK
-	if (tstate->recursion_depth%10 == 0 && PyOS_CheckStack()) {
-		PyErr_SetString(PyExc_MemoryError, "Stack overflow");
-		return NULL;
-	}
-#endif
-
-	if (globals == NULL) {
-		PyErr_SetString(PyExc_SystemError, "eval_code2: NULL globals");
-		return NULL;
-	}
 
+/* suspend macros */
+#define CHECK_SUSPEND() if (f->f_suspendvalue != NULL) { \
+				retval = f->f_suspendvalue; \
+				f->f_suspendvalue = NULL; \
+				why = WHY_SUSPEND; \
+				goto on_error; }
+			
 #ifdef LLTRACE
-	lltrace = PyDict_GetItemString(globals, "__lltrace__") != NULL;
+	lltrace = PyDict_GetItemString(f->f_globals, "__lltrace__") != NULL;
 #endif
 
-	f = PyFrame_New(tstate,			/*back*/
-			co,			/*code*/
-			globals, locals);
-	if (f == NULL)
-		return NULL;
-
+	_PyCode_GETCODEPTR(co, &first_instr);
+	next_instr = first_instr + f->f_lasti;
+	stack_pointer = f->f_stackbottom;
+	f->f_stackbottom = NULL; /* make frame no-resumable while executing */
 	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)) {
-		int i;
-		int n = argcount;
-		PyObject *kwdict = NULL;
-		if (co->co_flags & CO_VARKEYWORDS) {
-			kwdict = PyDict_New();
-			if (kwdict == NULL)
-				goto fail;
-			i = co->co_argcount;
-			if (co->co_flags & CO_VARARGS)
-				i++;
-			SETLOCAL(i, kwdict);
-		}
-		if (argcount > co->co_argcount) {
-			if (!(co->co_flags & CO_VARARGS)) {
-				PyErr_Format(PyExc_TypeError,
-				    "%.200s() takes %s %d "
-				    "%sargument%s (%d given)",
-				    PyString_AsString(co->co_name),
-				    defcount ? "at most" : "exactly",
-				    co->co_argcount,
-				    kwcount ? "non-keyword " : "",
-				    co->co_argcount == 1 ? "" : "s",
-				    argcount);
-				goto fail;
-			}
-			n = co->co_argcount;
-		}
-		for (i = 0; i < n; i++) {
-			x = args[i];
-			Py_INCREF(x);
-			SETLOCAL(i, x);
-		}
-		if (co->co_flags & CO_VARARGS) {
-			u = PyTuple_New(argcount - n);
-			if (u == NULL)
-				goto fail;
-			SETLOCAL(co->co_argcount, u);
-			for (i = n; i < argcount; i++) {
-				x = args[i];
-				Py_INCREF(x);
-				PyTuple_SET_ITEM(u, i-n, x);
-			}
-		}
-		for (i = 0; i < kwcount; i++) {
-			PyObject *keyword = kws[2*i];
-			PyObject *value = kws[2*i + 1];
-			int j;
-			if (keyword == NULL || !PyString_Check(keyword)) {
-				PyErr_Format(PyExc_TypeError,
-				    "%.200s() keywords must be strings",
-				    PyString_AsString(co->co_name));
-				goto fail;
-			}
-			/* XXX slow -- speed up using dictionary? */
-			for (j = 0; j < co->co_argcount; j++) {
-				PyObject *nm = PyTuple_GET_ITEM(
-					co->co_varnames, j);
-				int cmp = PyObject_RichCompareBool(
-					keyword, nm, Py_EQ);
-				if (cmp > 0)
-					break;
-				else if (cmp < 0)
-					goto fail;
-			}
-			/* Check errors from Compare */
-			if (PyErr_Occurred())
-				goto fail;
-			if (j >= co->co_argcount) {
-				if (kwdict == NULL) {
-					PyErr_Format(PyExc_TypeError,
-					    "%.200s() got an unexpected "
-					    "keyword argument '%.400s'",
-					    PyString_AsString(co->co_name),
-					    PyString_AsString(keyword));
-					goto fail;
-				}
-				PyDict_SetItem(kwdict, keyword, value);
-			}
-			else {
-				if (GETLOCAL(j) != NULL) {
-					PyErr_Format(PyExc_TypeError,
-					     "%.200s() got multiple "
-					     "values for keyword "
-					     "argument '%.400s'",
-					     PyString_AsString(co->co_name),
-					     PyString_AsString(keyword));
-					goto fail;
-				}
-				Py_INCREF(value);
-				SETLOCAL(j, value);
-			}
-		}
-		if (argcount < co->co_argcount) {
-			int m = co->co_argcount - defcount;
-			for (i = argcount; i < m; i++) {
-				if (GETLOCAL(i) == NULL) {
-					PyErr_Format(PyExc_TypeError,
-					    "%.200s() takes %s %d "
-					    "%sargument%s (%d given)",
-					    PyString_AsString(co->co_name),
-					    ((co->co_flags & CO_VARARGS) ||
-					     defcount) ? "at least"
-						       : "exactly",
-					    m, kwcount ? "non-keyword " : "",
-					    m == 1 ? "" : "s", i);
-					goto fail;
+	why = WHY_NOT;
+	err = 0;
+	x = Py_None;	/* Not a reference, just anything non-NULL */
+	w = NULL;
+
+	for (;;) {
+		/* Do periodic things.  Doing this every time through
+		   the loop would add too much overhead, so we do it
+		   only every Nth instruction.  We also do it if
+		   ``things_to_do'' is set, i.e. when an asynchronous
+		   event needs attention (e.g. a signal handler or
+		   async I/O handler); see Py_AddPendingCall() and
+		   Py_MakePendingCalls() above. */
+
+		if (things_to_do || --tstate->ticker < 0) {
+			tstate->ticker = tstate->interp->checkinterval;
+			if (things_to_do) {
+				if (Py_MakePendingCalls() < 0) {
+					why = WHY_EXCEPTION;
+					goto on_error;
 				}
 			}
-			if (n > m)
-				i = n - m;
-			else
-				i = 0;
-			for (; i < defcount; i++) {
-				if (GETLOCAL(m+i) == NULL) {
-					PyObject *def = defs[i];
-					Py_INCREF(def);
-					SETLOCAL(m+i, def);
-				}
+#if !defined(HAVE_SIGNAL_H) || defined(macintosh)
+			/* If we have true signals, the signal handler
+			   will call Py_AddPendingCall() so we don't
+			   have to call sigcheck().  On the Mac and
+			   DOS, alas, we have to call it. */
+			if (PyErr_CheckSignals()) {
+				why = WHY_EXCEPTION;
+				goto on_error;
 			}
-		}
-	}
-	else {
-		if (argcount > 0 || kwcount > 0) {
-			PyErr_Format(PyExc_TypeError,
-				     "%.200s() takes no arguments (%d given)",
-				     PyString_AsString(co->co_name),
-				     argcount + kwcount);
-			goto fail;
-		}
-	}
-	/* Allocate and initialize storage for cell vars, and copy free
-	   vars into frame.  This isn't too efficient right now. */
-	if (f->f_ncells) {
-		int i = 0, j = 0, nargs, found;
-		char *cellname, *argname;
-		PyObject *c;
+#endif
 
-		nargs = co->co_argcount;
-		if (co->co_flags & CO_VARARGS)
-			nargs++;
-		if (co->co_flags & CO_VARKEYWORDS)
-			nargs++;
+#ifdef WITH_THREAD
+			if (interpreter_lock) {
+				/* Give another thread a chance */
 
-		/* Check for cells that shadow args */
-		for (i = 0; i < f->f_ncells && j < nargs; ++i) {
-			cellname = PyString_AS_STRING(
-				PyTuple_GET_ITEM(co->co_cellvars, i));
-			found = 0;
-			while (j < nargs) {
-				argname = PyString_AS_STRING(
-					PyTuple_GET_ITEM(co->co_varnames, j));
-				if (strcmp(cellname, argname) == 0) {
-					c = PyCell_New(GETLOCAL(j));
-					if (c == NULL)
-						goto fail;
-					GETLOCAL(f->f_nlocals + i) = c;
-					found = 1;
-					break;
-				}
-				j++;
-			}
-			if (found == 0) {
-				c = PyCell_New(NULL);
-				if (c == NULL)
-					goto fail;
-				SETLOCAL(f->f_nlocals + i, c);
+				if (PyThreadState_Swap(NULL) != tstate)
+					Py_FatalError("ceval: tstate mix-up");
+				PyThread_release_lock(interpreter_lock);
+
+				/* Other threads may run now */
+
+				PyThread_acquire_lock(interpreter_lock, 1);
+				if (PyThreadState_Swap(tstate) != NULL)
+					Py_FatalError("ceval: orphan tstate");
 			}
-		}
-		/* Initialize any that are left */
-		while (i < f->f_ncells) {
-			c = PyCell_New(NULL);
-			if (c == NULL)
-				goto fail;
-			SETLOCAL(f->f_nlocals + i, c);
-			i++;
+#endif
 		}
-	}
-	if (f->f_nfreevars) {
-		int i;
-		for (i = 0; i < f->f_nfreevars; ++i) {
-			PyObject *o = PyTuple_GET_ITEM(closure, i);
-			Py_INCREF(o);
-			freevars[f->f_ncells + i] = o;
+
+                if (f->f_suspendvalue != NULL) {
+			why = WHY_SUSPEND;
+			retval = f->f_suspendvalue;
+			f->f_suspendvalue = NULL;
+			goto on_error;
 		}
-	}
 
-	if (tstate->sys_tracefunc != NULL) {
-		/* tstate->sys_tracefunc, if defined, is a function that
-		   will be called  on *every* entry to a code block.
-		   Its return value, if not None, is a function that
-		   will be called at the start of each executed line
-		   of code.  (Actually, the function must return
-		   itself in order to continue tracing.)
-		   The trace functions are called with three arguments:
-		   a pointer to the current frame, a string indicating
-		   why the function is called, and an argument which
-		   depends on the situation.  The global trace function
-		   (sys.trace) is also called whenever an exception
-		   is detected. */
-		if (call_trace(&tstate->sys_tracefunc,
-			       &f->f_trace, f, "call",
-			       Py_None/*XXX how to compute arguments now?*/)) {
-			/* Trace function raised an error */
-			goto fail;
-		}
-	}
-
-	if (tstate->sys_profilefunc != NULL) {
-		/* Similar for sys_profilefunc, except it needn't return
-		   itself and isn't called for "line" events */
-		if (call_trace(&tstate->sys_profilefunc,
-			       (PyObject**)0, f, "call",
-			       Py_None/*XXX*/)) {
-			goto fail;
-		}
-	}
-
-	if (++tstate->recursion_depth > recursion_limit) {
-		--tstate->recursion_depth;
-		PyErr_SetString(PyExc_RuntimeError,
-				"maximum recursion depth exceeded");
-		tstate->frame = f->f_back;
-		Py_DECREF(f);
-		return NULL;
-	}
-
-	_PyCode_GETCODEPTR(co, &first_instr);
-	next_instr = first_instr;
-	stack_pointer = f->f_valuestack;
-
-	why = WHY_NOT;
-	err = 0;
-	x = Py_None;	/* Not a reference, just anything non-NULL */
-	w = NULL;
-
-	for (;;) {
-		/* Do periodic things.  Doing this every time through
-		   the loop would add too much overhead, so we do it
-		   only every Nth instruction.  We also do it if
-		   ``things_to_do'' is set, i.e. when an asynchronous
-		   event needs attention (e.g. a signal handler or
-		   async I/O handler); see Py_AddPendingCall() and
-		   Py_MakePendingCalls() above. */
-
-		if (things_to_do || --tstate->ticker < 0) {
-			tstate->ticker = tstate->interp->checkinterval;
-			if (things_to_do) {
-				if (Py_MakePendingCalls() < 0) {
-					why = WHY_EXCEPTION;
-					goto on_error;
-				}
-			}
-#if !defined(HAVE_SIGNAL_H) || defined(macintosh)
-			/* If we have true signals, the signal handler
-			   will call Py_AddPendingCall() so we don't
-			   have to call sigcheck().  On the Mac and
-			   DOS, alas, we have to call it. */
-			if (PyErr_CheckSignals()) {
-				why = WHY_EXCEPTION;
-				goto on_error;
-			}
-#endif
-
-#ifdef WITH_THREAD
-			if (interpreter_lock) {
-				/* Give another thread a chance */
-
-				if (PyThreadState_Swap(NULL) != tstate)
-					Py_FatalError("ceval: tstate mix-up");
-				PyThread_release_lock(interpreter_lock);
-
-				/* Other threads may run now */
-
-				PyThread_acquire_lock(interpreter_lock, 1);
-				if (PyThreadState_Swap(tstate) != NULL)
-					Py_FatalError("ceval: orphan tstate");
-			}
-#endif
-		}
-
 		/* Extract opcode and argument */
 
 #if defined(Py_DEBUG) || defined(LLTRACE)
@@ -1968,8 +1730,10 @@
 			    Py_DECREF(w);
 		    }
 		    PUSH(x);
-		    if (x != NULL)
+		    if (x != NULL) {
+		            CHECK_SUSPEND();
 			    continue;
+		    }
 		    break;
 		}
 
@@ -2010,8 +1774,9 @@
 			    Py_DECREF(w);
 		    }
 		    PUSH(x);
-		    if (x != NULL)
+		    if (x != NULL) {
 			    continue;
+		    }
 		    break;
 		}
 
@@ -2175,7 +1940,7 @@
 
 		/* Unwind stacks if a (pseudo) exception occurred */
 
-		while (why != WHY_NOT && f->f_iblock > 0) {
+		while (why != WHY_NOT && why != WHY_SUSPEND && f->f_iblock > 0) {
 			PyTryBlock *b = PyFrame_BlockPop(f);
 
 			if (b->b_type == SETUP_LOOP && why == WHY_CONTINUE) {
@@ -2189,9 +1954,11 @@
 				break;
 			}
 
-			while (STACK_LEVEL() > b->b_level) {
-				v = POP();
-				Py_XDECREF(v);
+			if (why != WHY_RETURN) {
+				while (STACK_LEVEL() > b->b_level) {
+					v = POP();
+					Py_XDECREF(v);
+				}
 			}
 			if (b->b_type == SETUP_LOOP && why == WHY_BREAK) {
 				why = WHY_NOT;
@@ -2245,12 +2012,14 @@
 
 	/* Pop remaining stack entries */
 
+	/*
 	while (!EMPTY()) {
 		v = POP();
 		Py_XDECREF(v);
 	}
+	*/
 
-	if (why != WHY_RETURN)
+	if (why != WHY_RETURN && why != WHY_SUSPEND)
 		retval = NULL;
 
 	if (f->f_trace) {
@@ -2277,6 +2046,285 @@
 
 	--tstate->recursion_depth;
 
+	if (why == WHY_SUSPEND) {
+		/* make frame resumable */
+		f->f_stackbottom = stack_pointer;
+		f->f_lasti = INSTR_OFFSET();
+	} else {
+		f->f_stackbottom = NULL; 
+	}
+
+	/* Restore previous frame and release the current one */
+	tstate->frame = f->f_back;
+	Py_DECREF(f);
+
+	return retval;
+}
+
+/* Interpreter main loop */
+
+static PyObject *
+eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
+	   PyObject **args, int argcount, PyObject **kws, int kwcount,
+	   PyObject **defs, int defcount, PyObject *closure)
+{
+	register PyFrameObject *f; /* Current frame */
+	register PyObject **fastlocals, **freevars;
+	PyThreadState *tstate = PyThreadState_GET();
+	PyObject *x, *u;
+
+
+/* Start of code */
+
+#ifdef USE_STACKCHECK
+	if (tstate->recursion_depth%10 == 0 && PyOS_CheckStack()) {
+		PyErr_SetString(PyExc_MemoryError, "Stack overflow");
+		return NULL;
+	}
+#endif
+
+	if (globals == NULL) {
+		PyErr_SetString(PyExc_SystemError, "eval_code2: NULL globals");
+		return NULL;
+	}
+
+	f = PyFrame_New(tstate,			/*back*/
+			co,			/*code*/
+			globals, locals);
+	if (f == NULL)
+		return NULL;
+
+	fastlocals = f->f_localsplus;
+	freevars = f->f_localsplus + f->f_nlocals;
+
+	if (co->co_argcount > 0 ||
+	    co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) {
+		int i;
+		int n = argcount;
+		PyObject *kwdict = NULL;
+		if (co->co_flags & CO_VARKEYWORDS) {
+			kwdict = PyDict_New();
+			if (kwdict == NULL)
+				goto fail;
+			i = co->co_argcount;
+			if (co->co_flags & CO_VARARGS)
+				i++;
+			SETLOCAL(i, kwdict);
+		}
+		if (argcount > co->co_argcount) {
+			if (!(co->co_flags & CO_VARARGS)) {
+				PyErr_Format(PyExc_TypeError,
+				    "%.200s() takes %s %d "
+				    "%sargument%s (%d given)",
+				    PyString_AsString(co->co_name),
+				    defcount ? "at most" : "exactly",
+				    co->co_argcount,
+				    kwcount ? "non-keyword " : "",
+				    co->co_argcount == 1 ? "" : "s",
+				    argcount);
+				goto fail;
+			}
+			n = co->co_argcount;
+		}
+		for (i = 0; i < n; i++) {
+			x = args[i];
+			Py_INCREF(x);
+			SETLOCAL(i, x);
+		}
+		if (co->co_flags & CO_VARARGS) {
+			u = PyTuple_New(argcount - n);
+			if (u == NULL)
+				goto fail;
+			SETLOCAL(co->co_argcount, u);
+			for (i = n; i < argcount; i++) {
+				x = args[i];
+				Py_INCREF(x);
+				PyTuple_SET_ITEM(u, i-n, x);
+			}
+		}
+		for (i = 0; i < kwcount; i++) {
+			PyObject *keyword = kws[2*i];
+			PyObject *value = kws[2*i + 1];
+			int j;
+			if (keyword == NULL || !PyString_Check(keyword)) {
+				PyErr_Format(PyExc_TypeError,
+				    "%.200s() keywords must be strings",
+				    PyString_AsString(co->co_name));
+				goto fail;
+			}
+			/* XXX slow -- speed up using dictionary? */
+			for (j = 0; j < co->co_argcount; j++) {
+				PyObject *nm = PyTuple_GET_ITEM(
+					co->co_varnames, j);
+				int cmp = PyObject_RichCompareBool(
+					keyword, nm, Py_EQ);
+				if (cmp > 0)
+					break;
+				else if (cmp < 0)
+					goto fail;
+			}
+			/* Check errors from Compare */
+			if (PyErr_Occurred())
+				goto fail;
+			if (j >= co->co_argcount) {
+				if (kwdict == NULL) {
+					PyErr_Format(PyExc_TypeError,
+					    "%.200s() got an unexpected "
+					    "keyword argument '%.400s'",
+					    PyString_AsString(co->co_name),
+					    PyString_AsString(keyword));
+					goto fail;
+				}
+				PyDict_SetItem(kwdict, keyword, value);
+			}
+			else {
+				if (GETLOCAL(j) != NULL) {
+					PyErr_Format(PyExc_TypeError,
+					     "%.200s() got multiple "
+					     "values for keyword "
+					     "argument '%.400s'",
+					     PyString_AsString(co->co_name),
+					     PyString_AsString(keyword));
+					goto fail;
+				}
+				Py_INCREF(value);
+				SETLOCAL(j, value);
+			}
+		}
+		if (argcount < co->co_argcount) {
+			int m = co->co_argcount - defcount;
+			for (i = argcount; i < m; i++) {
+				if (GETLOCAL(i) == NULL) {
+					PyErr_Format(PyExc_TypeError,
+					    "%.200s() takes %s %d "
+					    "%sargument%s (%d given)",
+					    PyString_AsString(co->co_name),
+					    ((co->co_flags & CO_VARARGS) ||
+					     defcount) ? "at least"
+						       : "exactly",
+					    m, kwcount ? "non-keyword " : "",
+					    m == 1 ? "" : "s", i);
+					goto fail;
+				}
+			}
+			if (n > m)
+				i = n - m;
+			else
+				i = 0;
+			for (; i < defcount; i++) {
+				if (GETLOCAL(m+i) == NULL) {
+					PyObject *def = defs[i];
+					Py_INCREF(def);
+					SETLOCAL(m+i, def);
+				}
+			}
+		}
+	}
+	else {
+		if (argcount > 0 || kwcount > 0) {
+			PyErr_Format(PyExc_TypeError,
+				     "%.200s() takes no arguments (%d given)",
+				     PyString_AsString(co->co_name),
+				     argcount + kwcount);
+			goto fail;
+		}
+	}
+	/* Allocate and initialize storage for cell vars, and copy free
+	   vars into frame.  This isn't too efficient right now. */
+	if (f->f_ncells) {
+		int i = 0, j = 0, nargs, found;
+		char *cellname, *argname;
+		PyObject *c;
+
+		nargs = co->co_argcount;
+		if (co->co_flags & CO_VARARGS)
+			nargs++;
+		if (co->co_flags & CO_VARKEYWORDS)
+			nargs++;
+
+		/* Check for cells that shadow args */
+		for (i = 0; i < f->f_ncells && j < nargs; ++i) {
+			cellname = PyString_AS_STRING(
+				PyTuple_GET_ITEM(co->co_cellvars, i));
+			found = 0;
+			while (j < nargs) {
+				argname = PyString_AS_STRING(
+					PyTuple_GET_ITEM(co->co_varnames, j));
+				if (strcmp(cellname, argname) == 0) {
+					c = PyCell_New(GETLOCAL(j));
+					if (c == NULL)
+						goto fail;
+					GETLOCAL(f->f_nlocals + i) = c;
+					found = 1;
+					break;
+				}
+				j++;
+			}
+			if (found == 0) {
+				c = PyCell_New(NULL);
+				if (c == NULL)
+					goto fail;
+				SETLOCAL(f->f_nlocals + i, c);
+			}
+		}
+		/* Initialize any that are left */
+		while (i < f->f_ncells) {
+			c = PyCell_New(NULL);
+			if (c == NULL)
+				goto fail;
+			SETLOCAL(f->f_nlocals + i, c);
+			i++;
+		}
+	}
+	if (f->f_nfreevars) {
+		int i;
+		for (i = 0; i < f->f_nfreevars; ++i) {
+			PyObject *o = PyTuple_GET_ITEM(closure, i);
+			Py_INCREF(o);
+			freevars[f->f_ncells + i] = o;
+		}
+	}
+
+	if (tstate->sys_tracefunc != NULL) {
+		/* tstate->sys_tracefunc, if defined, is a function that
+		   will be called  on *every* entry to a code block.
+		   Its return value, if not None, is a function that
+		   will be called at the start of each executed line
+		   of code.  (Actually, the function must return
+		   itself in order to continue tracing.)
+		   The trace functions are called with three arguments:
+		   a pointer to the current frame, a string indicating
+		   why the function is called, and an argument which
+		   depends on the situation.  The global trace function
+		   (sys.trace) is also called whenever an exception
+		   is detected. */
+		if (call_trace(&tstate->sys_tracefunc,
+			       &f->f_trace, f, "call",
+			       Py_None/*XXX how to compute arguments now?*/)) {
+			/* Trace function raised an error */
+			goto fail;
+		}
+	}
+
+	if (tstate->sys_profilefunc != NULL) {
+		/* Similar for sys_profilefunc, except it needn't return
+		   itself and isn't called for "line" events */
+		if (call_trace(&tstate->sys_profilefunc,
+			       (PyObject**)0, f, "call",
+			       Py_None/*XXX*/)) {
+			goto fail;
+		}
+	}
+
+	if (++tstate->recursion_depth > recursion_limit) {
+		--tstate->recursion_depth;
+		PyErr_SetString(PyExc_RuntimeError,
+				"maximum recursion depth exceeded");
+		goto fail;
+	}
+
+	return PyEval_EvalFrame(f);
+
   fail: /* Jump here from prelude on failure */
 
 	/* Restore previous frame and release the current one */
@@ -2284,7 +2332,7 @@
 	tstate->frame = f->f_back;
 	Py_DECREF(f);
 
-	return retval;
+	return NULL;
 }
 
 static void
