cinap_lenrekadd hg and python4bb9e2215 years agoHistory
4351 lines · 104.0 KB · C
RawDownload
					PyErr_Fetch(&exc, &val, &tb);					if (val == NULL) {						val = Py_None;						Py_INCREF(val);					}					/* Make the raw exception data					   available to the handler,					   so a program can emulate the					   Python main loop.  Don't do					   this for 'finally'. */					if (b->b_type == SETUP_EXCEPT) {						PyErr_NormalizeException(							&exc, &val, &tb);						set_exc_info(tstate,							     exc, val, tb);					}					if (tb == NULL) {						Py_INCREF(Py_None);						PUSH(Py_None);					} else						PUSH(tb);					PUSH(val);					PUSH(exc);				}				else {					if (why & (WHY_RETURN | WHY_CONTINUE))						PUSH(retval);					v = PyInt_FromLong((long)why);					PUSH(v);				}				why = WHY_NOT;				JUMPTO(b->b_handler);				break;			}		} /* unwind stack */ 		/* End the loop if we still have an error (or return) */ 		if (why != WHY_NOT)			break;		READ_TIMESTAMP(loop1); 	} /* main loop */ 	assert(why != WHY_YIELD);	/* Pop remaining stack entries. */	while (!EMPTY()) {		v = POP();		Py_XDECREF(v);	} 	if (why != WHY_RETURN)		retval = NULL; fast_yield:	if (tstate->use_tracing) {		if (tstate->c_tracefunc) {			if (why == WHY_RETURN || why == WHY_YIELD) {				if (call_trace(tstate->c_tracefunc,					       tstate->c_traceobj, f,					       PyTrace_RETURN, retval)) {					Py_XDECREF(retval);					retval = NULL;					why = WHY_EXCEPTION;				}			}			else if (why == WHY_EXCEPTION) {				call_trace_protected(tstate->c_tracefunc,						     tstate->c_traceobj, f,						     PyTrace_RETURN, NULL);			}		}		if (tstate->c_profilefunc) {			if (why == WHY_EXCEPTION)				call_trace_protected(tstate->c_profilefunc,						     tstate->c_profileobj, f,						     PyTrace_RETURN, NULL);			else if (call_trace(tstate->c_profilefunc,					    tstate->c_profileobj, f,					    PyTrace_RETURN, retval)) {				Py_XDECREF(retval);				retval = NULL;				why = WHY_EXCEPTION;			}		}	} 	if (tstate->frame->f_exc_type != NULL)		reset_exc_info(tstate);	else {		assert(tstate->frame->f_exc_value == NULL);		assert(tstate->frame->f_exc_traceback == NULL);	} 	/* pop frame */    exit_eval_frame:	Py_LeaveRecursiveCall();	tstate->frame = f->f_back; 	return retval;} /* This is gonna seem *real weird*, but if you put some other code between   PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust   the test in the if statements in Misc/gdbinit (pystack and pystackv). */ PyObject *PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,	   PyObject **args, int argcount, PyObject **kws, int kwcount,	   PyObject **defs, int defcount, PyObject *closure){	register PyFrameObject *f;	register PyObject *retval = NULL;	register PyObject **fastlocals, **freevars;	PyThreadState *tstate = PyThreadState_GET();	PyObject *x, *u; 	if (globals == NULL) {		PyErr_SetString(PyExc_SystemError,				"PyEval_EvalCodeEx: NULL globals");		return NULL;	} 	assert(tstate != NULL);	assert(globals != NULL);	f = PyFrame_New(tstate, co, globals, locals);	if (f == NULL)		return NULL; 	fastlocals = f->f_localsplus;	freevars = f->f_localsplus + co->co_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 (PyTuple_GET_SIZE(co->co_cellvars)) {		int i, j, 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++; 		/* Initialize each cell var, taking into account		   cell vars that are initialized from arguments. 		   Should arrange for the compiler to put cellvars		   that are arguments at the beginning of the cellvars		   list so that we can march over it more efficiently?		*/		for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) {			cellname = PyString_AS_STRING(				PyTuple_GET_ITEM(co->co_cellvars, i));			found = 0;			for (j = 0; j < nargs; j++) {				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(co->co_nlocals + i) = c;					found = 1;					break;				}			}			if (found == 0) {				c = PyCell_New(NULL);				if (c == NULL)					goto fail;				SETLOCAL(co->co_nlocals + i, c);			}		}	}	if (PyTuple_GET_SIZE(co->co_freevars)) {		int i;		for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) {			PyObject *o = PyTuple_GET_ITEM(closure, i);			Py_INCREF(o);			freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;		}	} 	if (co->co_flags & CO_GENERATOR) {		/* Don't need to keep the reference to f_back, it will be set		 * when the generator is resumed. */		Py_XDECREF(f->f_back);		f->f_back = NULL; 		PCALL(PCALL_GENERATOR); 		/* Create a new generator that owns the ready to run frame		 * and return that as the value. */		return PyGen_New(f);	}         retval = PyEval_EvalFrameEx(f,0);   fail: /* Jump here from prelude on failure */ 	/* decref'ing the frame can cause __del__ methods to get invoked,	   which can call back into Python.  While we're done with the	   current Python frame (f), the associated C stack is still in use,	   so recursion_depth must be boosted for the duration.	*/	assert(tstate != NULL);	++tstate->recursion_depth;        Py_DECREF(f);	--tstate->recursion_depth;	return retval;}  /* Implementation notes for set_exc_info() and reset_exc_info(): - Below, 'exc_ZZZ' stands for 'exc_type', 'exc_value' and  'exc_traceback'.  These always travel together. - tstate->curexc_ZZZ is the "hot" exception that is set by  PyErr_SetString(), cleared by PyErr_Clear(), and so on. - Once an exception is caught by an except clause, it is transferred  from tstate->curexc_ZZZ to tstate->exc_ZZZ, from which sys.exc_info()  can pick it up.  This is the primary task of set_exc_info().  XXX That can't be right:  set_exc_info() doesn't look at tstate->curexc_ZZZ. - Now let me explain the complicated dance with frame->f_exc_ZZZ.   Long ago, when none of this existed, there were just a few globals:  one set corresponding to the "hot" exception, and one set  corresponding to sys.exc_ZZZ.  (Actually, the latter weren't C  globals; they were simply stored as sys.exc_ZZZ.  For backwards  compatibility, they still are!)  The problem was that in code like  this:      try:	"something that may fail"     except "some exception":	"do something else first"	"print the exception from sys.exc_ZZZ."   if "do something else first" invoked something that raised and caught  an exception, sys.exc_ZZZ were overwritten.  That was a frequent  cause of subtle bugs.  I fixed this by changing the semantics as  follows:     - Within one frame, sys.exc_ZZZ will hold the last exception caught      *in that frame*.     - But initially, and as long as no exception is caught in a given      frame, sys.exc_ZZZ will hold the last exception caught in the      previous frame (or the frame before that, etc.).   The first bullet fixed the bug in the above example.  The second  bullet was for backwards compatibility: it was (and is) common to  have a function that is called when an exception is caught, and to  have that function access the caught exception via sys.exc_ZZZ.  (Example: traceback.print_exc()).   At the same time I fixed the problem that sys.exc_ZZZ weren't  thread-safe, by introducing sys.exc_info() which gets it from tstate;  but that's really a separate improvement.   The reset_exc_info() function in ceval.c restores the tstate->exc_ZZZ  variables to what they were before the current frame was called.  The  set_exc_info() function saves them on the frame so that  reset_exc_info() can restore them.  The invariant is that  frame->f_exc_ZZZ is NULL iff the current frame never caught an  exception (where "catching" an exception applies only to successful  except clauses); and if the current frame ever caught an exception,  frame->f_exc_ZZZ is the exception that was stored in tstate->exc_ZZZ  at the start of the current frame. */ static voidset_exc_info(PyThreadState *tstate,	     PyObject *type, PyObject *value, PyObject *tb){	PyFrameObject *frame = tstate->frame;	PyObject *tmp_type, *tmp_value, *tmp_tb; 	assert(type != NULL);	assert(frame != NULL);	if (frame->f_exc_type == NULL) {		assert(frame->f_exc_value == NULL);		assert(frame->f_exc_traceback == NULL);		/* This frame didn't catch an exception before. */		/* Save previous exception of this thread in this frame. */		if (tstate->exc_type == NULL) {			/* XXX Why is this set to Py_None? */			Py_INCREF(Py_None);			tstate->exc_type = Py_None;		}		Py_INCREF(tstate->exc_type);		Py_XINCREF(tstate->exc_value);		Py_XINCREF(tstate->exc_traceback);		frame->f_exc_type = tstate->exc_type;		frame->f_exc_value = tstate->exc_value;		frame->f_exc_traceback = tstate->exc_traceback;	}	/* Set new exception for this thread. */	tmp_type = tstate->exc_type;	tmp_value = tstate->exc_value;	tmp_tb = tstate->exc_traceback;	Py_INCREF(type);	Py_XINCREF(value);	Py_XINCREF(tb);	tstate->exc_type = type;	tstate->exc_value = value;	tstate->exc_traceback = tb;	Py_XDECREF(tmp_type);	Py_XDECREF(tmp_value);	Py_XDECREF(tmp_tb);	/* For b/w compatibility */	PySys_SetObject("exc_type", type);	PySys_SetObject("exc_value", value);	PySys_SetObject("exc_traceback", tb);} static voidreset_exc_info(PyThreadState *tstate){	PyFrameObject *frame;	PyObject *tmp_type, *tmp_value, *tmp_tb; 	/* It's a precondition that the thread state's frame caught an	 * exception -- verify in a debug build.	 */	assert(tstate != NULL);	frame = tstate->frame;	assert(frame != NULL);	assert(frame->f_exc_type != NULL); 	/* Copy the frame's exception info back to the thread state. */	tmp_type = tstate->exc_type;	tmp_value = tstate->exc_value;	tmp_tb = tstate->exc_traceback;	Py_INCREF(frame->f_exc_type);	Py_XINCREF(frame->f_exc_value);	Py_XINCREF(frame->f_exc_traceback);	tstate->exc_type = frame->f_exc_type;	tstate->exc_value = frame->f_exc_value;	tstate->exc_traceback = frame->f_exc_traceback;	Py_XDECREF(tmp_type);	Py_XDECREF(tmp_value);	Py_XDECREF(tmp_tb); 	/* For b/w compatibility */	PySys_SetObject("exc_type", frame->f_exc_type);	PySys_SetObject("exc_value", frame->f_exc_value);	PySys_SetObject("exc_traceback", frame->f_exc_traceback); 	/* Clear the frame's exception info. */	tmp_type = frame->f_exc_type;	tmp_value = frame->f_exc_value;	tmp_tb = frame->f_exc_traceback;	frame->f_exc_type = NULL;	frame->f_exc_value = NULL;	frame->f_exc_traceback = NULL;	Py_DECREF(tmp_type);	Py_XDECREF(tmp_value);	Py_XDECREF(tmp_tb);} /* Logic for the raise statement (too complicated for inlining).

Lines 2501–3000 of 4351. Previous lines