Assorted patches from Armin Rigo:

[ 617309 ] getframe hook (Psyco #1)
[ 617311 ] Tiny profiling info (Psyco #2)
[ 617312 ] debugger-controlled jumps (Psyco #3)

These are forward ports from 2.2.2.
diff --git a/Include/pystate.h b/Include/pystate.h
index 9b61ad7..d4233bf 100644
--- a/Include/pystate.h
+++ b/Include/pystate.h
@@ -67,6 +67,8 @@
 
     PyObject *dict;
 
+    int tick_counter;
+
     /* XXX signal handlers should also be here */
 
 } PyThreadState;
@@ -105,6 +107,9 @@
 PyAPI_FUNC(PyThreadState *) PyInterpreterState_ThreadHead(PyInterpreterState *);
 PyAPI_FUNC(PyThreadState *) PyThreadState_Next(PyThreadState *);
 
+/* hook for PyEval_GetFrame(), requested for Psyco */
+PyAPI_DATA(unaryfunc) _PyThreadState_GetFrame;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c
index 2009b225..f74751b 100644
--- a/Modules/pyexpat.c
+++ b/Modules/pyexpat.c
@@ -304,7 +304,7 @@
     f = PyFrame_New(
                     tstate,			/*back*/
                     c,				/*code*/
-                    tstate->frame->f_globals,	/*globals*/
+                    PyEval_GetGlobals(),	/*globals*/
                     NULL			/*locals*/
                     );
     if (f == NULL)
diff --git a/Python/ceval.c b/Python/ceval.c
index 09b88a6..1c95cb9 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -51,7 +51,7 @@
 static void call_trace_protected(Py_tracefunc, PyObject *,
 				 PyFrameObject *, int);
 static void call_exc_trace(Py_tracefunc, PyObject *, PyFrameObject *);
-static void maybe_call_line_trace(int, Py_tracefunc, PyObject *, 
+static void maybe_call_line_trace(Py_tracefunc, PyObject *, 
 				  PyFrameObject *, int *, int *);
 
 static PyObject *apply_slice(PyObject *, PyObject *, PyObject *);
@@ -599,24 +599,6 @@
 	}
 
 	tstate->frame = f;
-	co = f->f_code;
-	names = co->co_names;
-	consts = co->co_consts;
-	fastlocals = f->f_localsplus;
-	freevars = f->f_localsplus + f->f_nlocals;
-	_PyCode_GETCODEPTR(co, &first_instr);
-	/* An explanation is in order for the next line.
-
-	   f->f_lasti now refers to the index of the last instruction
-	   executed.  You might think this was obvious from the name, but
-	   this wasn't always true before 2.3!  PyFrame_New now sets
-	   f->f_lasti to -1 (i.e. the index *before* the first instruction)
-	   and YIELD_VALUE doesn't fiddle with f_lasti any more.  So this
-	   does work.  Promise. */
-	next_instr = first_instr + f->f_lasti + 1;
-	stack_pointer = f->f_stacktop;
-	assert(stack_pointer != NULL);
-	f->f_stacktop = NULL;	/* remains NULL unless yield suspends frame */
 
 	if (tstate->use_tracing) {
 		if (tstate->c_tracefunc != NULL) {
@@ -655,6 +637,25 @@
 		}
 	}
 
+	co = f->f_code;
+	names = co->co_names;
+	consts = co->co_consts;
+	fastlocals = f->f_localsplus;
+	freevars = f->f_localsplus + f->f_nlocals;
+	_PyCode_GETCODEPTR(co, &first_instr);
+	/* An explanation is in order for the next line.
+
+	   f->f_lasti now refers to the index of the last instruction
+	   executed.  You might think this was obvious from the name, but
+	   this wasn't always true before 2.3!  PyFrame_New now sets
+	   f->f_lasti to -1 (i.e. the index *before* the first instruction)
+	   and YIELD_VALUE doesn't fiddle with f_lasti any more.  So this
+	   does work.  Promise. */
+	next_instr = first_instr + f->f_lasti + 1;
+	stack_pointer = f->f_stacktop;
+	assert(stack_pointer != NULL);
+	f->f_stacktop = NULL;	/* remains NULL unless yield suspends frame */
+
 #ifdef LLTRACE
 	lltrace = PyDict_GetItemString(f->f_globals,"__lltrace__") != NULL;
 #endif
@@ -681,6 +682,7 @@
 
 		if (--_Py_Ticker < 0) {
 			_Py_Ticker = _Py_CheckInterval;
+			tstate->tick_counter++;
 			if (things_to_do) {
 				if (Py_MakePendingCalls() < 0) {
 					why = WHY_EXCEPTION;
@@ -716,10 +718,26 @@
 		}
 
 	fast_next_opcode:
-		/* Extract opcode and argument */
-
 		f->f_lasti = INSTR_OFFSET();
 
+		/* line-by-line tracing support */
+
+		if (tstate->c_tracefunc != NULL && !tstate->tracing) {
+			/* see maybe_call_line_trace
+			   for expository comments */
+			f->f_stacktop = stack_pointer;
+			maybe_call_line_trace(tstate->c_tracefunc,
+					      tstate->c_traceobj,
+					      f, &instr_lb, &instr_ub);
+			/* Reload possibly changed frame fields */
+			JUMPTO(f->f_lasti);
+			stack_pointer = f->f_stacktop;
+			assert(stack_pointer != NULL);
+			f->f_stacktop = NULL;
+		}
+
+		/* Extract opcode and argument */
+
 		opcode = NEXTOP();
 		if (HAS_ARG(opcode))
 			oparg = NEXTARG();
@@ -747,17 +765,6 @@
 		}
 #endif
 
-		/* line-by-line tracing support */
-
-		if (tstate->c_tracefunc != NULL && !tstate->tracing) {
-			/* see maybe_call_line_trace
-			   for expository comments */
-			maybe_call_line_trace(opcode, 
-					      tstate->c_tracefunc,
-					      tstate->c_traceobj,
-					      f, &instr_lb, &instr_ub);
-		}
-
 		/* Main switch on opcode */
 
 		switch (opcode) {
@@ -2866,7 +2873,7 @@
 }
 
 static void
-maybe_call_line_trace(int opcode, Py_tracefunc func, PyObject *obj, 
+maybe_call_line_trace(Py_tracefunc func, PyObject *obj, 
 		      PyFrameObject *frame, int *instr_lb, int *instr_ub)
 {
 	/* The theory of SET_LINENO-less tracing.
@@ -3025,10 +3032,9 @@
 PyObject *
 PyEval_GetBuiltins(void)
 {
-	PyThreadState *tstate = PyThreadState_Get();
-	PyFrameObject *current_frame = tstate->frame;
+	PyFrameObject *current_frame = (PyFrameObject *)PyEval_GetFrame();
 	if (current_frame == NULL)
-		return tstate->interp->builtins;
+		return PyThreadState_Get()->interp->builtins;
 	else
 		return current_frame->f_builtins;
 }
@@ -3036,7 +3042,7 @@
 PyObject *
 PyEval_GetLocals(void)
 {
-	PyFrameObject *current_frame = PyThreadState_Get()->frame;
+	PyFrameObject *current_frame = (PyFrameObject *)PyEval_GetFrame();
 	if (current_frame == NULL)
 		return NULL;
 	PyFrame_FastToLocals(current_frame);
@@ -3046,7 +3052,7 @@
 PyObject *
 PyEval_GetGlobals(void)
 {
-	PyFrameObject *current_frame = PyThreadState_Get()->frame;
+	PyFrameObject *current_frame = (PyFrameObject *)PyEval_GetFrame();
 	if (current_frame == NULL)
 		return NULL;
 	else
@@ -3056,21 +3062,21 @@
 PyObject *
 PyEval_GetFrame(void)
 {
-	PyFrameObject *current_frame = PyThreadState_Get()->frame;
-	return (PyObject *)current_frame;
+	PyThreadState *tstate = PyThreadState_Get();
+	return _PyThreadState_GetFrame((PyObject *)tstate);
 }
 
 int
 PyEval_GetRestricted(void)
 {
-	PyFrameObject *current_frame = PyThreadState_Get()->frame;
+	PyFrameObject *current_frame = (PyFrameObject *)PyEval_GetFrame();
 	return current_frame == NULL ? 0 : current_frame->f_restricted;
 }
 
 int
 PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
 {
-	PyFrameObject *current_frame = PyThreadState_Get()->frame;
+	PyFrameObject *current_frame = (PyFrameObject *)PyEval_GetFrame();
 	int result = 0;
 
 	if (current_frame != NULL) {
diff --git a/Python/pystate.c b/Python/pystate.c
index ad92dde..707e43e 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -35,6 +35,7 @@
 static PyInterpreterState *interp_head = NULL;
 
 PyThreadState *_PyThreadState_Current = NULL;
+unaryfunc _PyThreadState_GetFrame = NULL;
 
 
 PyInterpreterState *
@@ -113,10 +114,19 @@
 }
 
 
+/* Default implementation for _PyThreadState_GetFrame */
+static struct _frame *
+threadstate_getframe(PyThreadState *self)
+{
+	return self->frame;
+}
+
 PyThreadState *
 PyThreadState_New(PyInterpreterState *interp)
 {
 	PyThreadState *tstate = PyMem_NEW(PyThreadState, 1);
+	if (_PyThreadState_GetFrame == NULL)
+		_PyThreadState_GetFrame = (unaryfunc)threadstate_getframe;
 
 	if (tstate != NULL) {
 		tstate->interp = interp;
@@ -125,6 +135,7 @@
 		tstate->recursion_depth = 0;
 		tstate->tracing = 0;
 		tstate->use_tracing = 0;
+		tstate->tick_counter = 0;
 
 		tstate->dict = NULL;