Merge p3yk branch with the trunk up to revision 45595. This breaks a fair
number of tests, all because of the codecs/_multibytecodecs issue described
here (it's not a Py3K issue, just something Py3K discovers):
http://mail.python.org/pipermail/python-dev/2006-April/064051.html

Hye-Shik Chang promised to look for a fix, so no need to fix it here. The
tests that are expected to break are:

test_codecencodings_cn
test_codecencodings_hk
test_codecencodings_jp
test_codecencodings_kr
test_codecencodings_tw
test_codecs
test_multibytecodec

This merge fixes an actual test failure (test_weakref) in this branch,
though, so I believe merging is the right thing to do anyway.
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 3f6ef85..15e53dd 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -5,11 +5,13 @@
 #include "genobject.h"
 #include "ceval.h"
 #include "structmember.h"
+#include "opcode.h"
 
 static int
 gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
 {
-	return visit((PyObject *)gen->gi_frame, arg);
+	Py_VISIT((PyObject *)gen->gi_frame);
+	return 0;
 }
 
 static void
@@ -20,12 +22,11 @@
 	_PyObject_GC_UNTRACK(gen);
 
 	if (gen->gi_weakreflist != NULL)
-		PyObject_ClearWeakRefs((PyObject *) gen);
-
+		PyObject_ClearWeakRefs(self);
 
 	_PyObject_GC_TRACK(self);
 
-	if (gen->gi_frame->f_stacktop!=NULL) {
+	if (gen->gi_frame != NULL && gen->gi_frame->f_stacktop != NULL) {
 		/* Generator is paused, so we need to close */
 		gen->ob_type->tp_del(self);
 		if (self->ob_refcnt > 0)
@@ -33,7 +34,7 @@
 	}
 
 	_PyObject_GC_UNTRACK(self);
-	Py_XDECREF(gen->gi_frame);
+	Py_CLEAR(gen->gi_frame);
 	PyObject_GC_Del(gen);
 }
 
@@ -50,16 +51,18 @@
 				"generator already executing");
 		return NULL;
 	}
-	if ((PyObject *)f == Py_None || f->f_stacktop == NULL) {
+	if (f==NULL || f->f_stacktop == NULL) {
 		/* Only set exception if called from send() */
-		if (arg && !exc) PyErr_SetNone(PyExc_StopIteration);
+		if (arg && !exc)
+			PyErr_SetNone(PyExc_StopIteration);
 		return NULL;
 	}
 
 	if (f->f_lasti == -1) {
 		if (arg && arg != Py_None) {
 			PyErr_SetString(PyExc_TypeError,
-				"can't send non-None value to a just-started generator");
+					"can't send non-None value to a "
+					"just-started generator");
 			return NULL;
 		}
 	} else {
@@ -91,21 +94,22 @@
 		Py_DECREF(result);
 		result = NULL;
 		/* Set exception if not called by gen_iternext() */
-		if (arg) PyErr_SetNone(PyExc_StopIteration);
+		if (arg)
+			PyErr_SetNone(PyExc_StopIteration);
 	}
 
 	if (!result || f->f_stacktop == NULL) {
 		/* generator can't be rerun, so release the frame */
 		Py_DECREF(f);
-		gen->gi_frame = (PyFrameObject *)Py_None;
-		Py_INCREF(Py_None);
+		gen->gi_frame = NULL;
 	}
 
 	return result;
 }
 
 PyDoc_STRVAR(send_doc,
-"send(arg) -> send 'arg' into generator, return next yielded value or raise StopIteration.");
+"send(arg) -> send 'arg' into generator,\n\
+return next yielded value or raise StopIteration.");
 
 static PyObject *
 gen_send(PyGenObject *gen, PyObject *arg)
@@ -125,11 +129,11 @@
 	if (retval) {
 		Py_DECREF(retval);
 		PyErr_SetString(PyExc_RuntimeError,
-			"generator ignored GeneratorExit");
+				"generator ignored GeneratorExit");
 		return NULL;
 	}
-	if ( PyErr_ExceptionMatches(PyExc_StopIteration) 
-	     || PyErr_ExceptionMatches(PyExc_GeneratorExit) ) 
+	if (PyErr_ExceptionMatches(PyExc_StopIteration)
+	    || PyErr_ExceptionMatches(PyExc_GeneratorExit))
 	{
 		PyErr_Clear();	/* ignore these errors */
 		Py_INCREF(Py_None);
@@ -145,7 +149,7 @@
         PyObject *error_type, *error_value, *error_traceback;
 	PyGenObject *gen = (PyGenObject *)self;
 
-	if ((PyObject *)gen->gi_frame == Py_None || gen->gi_frame->f_stacktop==NULL)
+	if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL)
 		/* Generator isn't paused, so no need to close */
 		return;
 
@@ -156,10 +160,10 @@
         /* Save the current exception, if any. */
         PyErr_Fetch(&error_type, &error_value, &error_traceback);
 
-	res = gen_close((PyGenObject *)self, NULL);
+	res = gen_close(gen, NULL);
 
 	if (res == NULL)
-		PyErr_WriteUnraisable((PyObject *)self);
+		PyErr_WriteUnraisable(self);
 	else
 		Py_DECREF(res);
 
@@ -181,7 +185,7 @@
                 _Py_NewReference(self);
                 self->ob_refcnt = refcnt;
         }
-        assert(!PyType_IS_GC(self->ob_type) ||
+        assert(PyType_IS_GC(self->ob_type) &&
                _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED);
 
         /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
@@ -202,10 +206,11 @@
 
 
 PyDoc_STRVAR(throw_doc,
-"throw(typ[,val[,tb]]) -> raise exception in generator, return next yielded value or raise StopIteration.");
+"throw(typ[,val[,tb]]) -> raise exception in generator,\n\
+return next yielded value or raise StopIteration.");
 
 static PyObject *
-gen_throw(PyGenObject *gen, PyObject *args) 
+gen_throw(PyGenObject *gen, PyObject *args)
 {
 	PyObject *typ;
 	PyObject *tb = NULL;
@@ -216,10 +221,8 @@
 
 	/* First, check the traceback argument, replacing None with
 	   NULL. */
-	if (tb == Py_None) {
-		Py_DECREF(tb);
+	if (tb == Py_None)
 		tb = NULL;
-	}
 	else if (tb != NULL && !PyTraceBack_Check(tb)) {
 		PyErr_SetString(PyExc_TypeError,
 			"throw() third argument must be a traceback object");
@@ -249,7 +252,10 @@
 			Py_INCREF(typ);
 		}
 	}
-	else {
+
+	/* Allow raising builtin string exceptions */
+
+	else if (!PyString_CheckExact(typ)) {
 		/* Not something you can raise.  throw() fails. */
 		PyErr_Format(PyExc_TypeError,
 			     "exceptions must be classes, or instances, not %s",
@@ -257,7 +263,7 @@
 			goto failed_throw;
 	}
 
-	PyErr_Restore(typ,val,tb);
+	PyErr_Restore(typ, val, tb);
 	return gen_send_ex(gen, Py_None, 1);
 
 failed_throw:
@@ -324,7 +330,7 @@
 	0,					/* tp_getset */
 	0,					/* tp_base */
 	0,					/* tp_dict */
-        
+
 	0,					/* tp_descr_get */
 	0,					/* tp_descr_set */
 	0,					/* tp_dictoffset */
@@ -355,3 +361,23 @@
 	_PyObject_GC_TRACK(gen);
 	return (PyObject *)gen;
 }
+
+int
+PyGen_NeedsFinalizing(PyGenObject *gen)
+{
+	int i;
+	PyFrameObject *f = gen->gi_frame;
+
+	if (f == NULL || f->f_stacktop == NULL || f->f_iblock <= 0)
+		return 0; /* no frame or empty blockstack == no finalization */
+
+	/* Any block type besides a loop requires cleanup. */
+	i = f->f_iblock;
+	while (--i >= 0) {
+		if (f->f_blockstack[i].b_type != SETUP_LOOP)
+			return 1;
+	}
+
+	/* No blocks except loops, it's safe to skip finalization. */
+	return 0;
+}