Tcl Source Code

Artifact [44771dbfcd]
Login

Artifact 44771dbfcdb1a1ea0002ce4bdab6c784a8653cf4:

Attachment "newTailcall.patch" to ticket [3048771fff] added by msofer 2010-08-21 21:12:53.
diff -ur ./generic/tclBasic.c ./generic/tclBasic.c
--- ./generic/tclBasic.c	2010-08-21 11:07:22.367173149 -0300
+++ ./generic/tclBasic.c	2010-08-20 20:11:12.105882211 -0300
@@ -167,10 +167,6 @@
 
 static void	        ClearTailcall(Tcl_Interp *interp,
 			    struct TEOV_callback *tailcallPtr);
-static int              SpliceTailcall(Tcl_Interp *interp,
-	                    struct TEOV_callback *tailcallPtr,
-                            int skip);
-
 
 MODULE_SCOPE const TclStubs tclStubs;
 
@@ -8291,30 +8287,10 @@
  * FIXME NRE!
  */
 
-void TclRemoveTailcall(
-    Tcl_Interp *interp)
-{
-    TEOV_callback *runPtr, *tailcallPtr;
-    
-    for (runPtr = TOP_CB(interp); runPtr->nextPtr; runPtr = runPtr->nextPtr) {
-        if (runPtr->nextPtr->procPtr == NRTailcallEval) {
-            break;
-        }
-    }
-    if (!runPtr->nextPtr) {
-        Tcl_Panic("TclRemoveTailcall did not find a tailcall");
-    }
-
-    tailcallPtr = runPtr->nextPtr;
-    runPtr->nextPtr = tailcallPtr->nextPtr;
-    ClearTailcall(interp, tailcallPtr);
-}
-
-static int
-SpliceTailcall(
+void
+TclSpliceTailcall(
     Tcl_Interp *interp,
-    TEOV_callback *tailcallPtr,
-    int skip)
+    TEOV_callback *tailcallPtr)
 {
     /*
      * Find the splicing spot: right before the NRCommand of the thing
@@ -8322,53 +8298,19 @@
      * (used by command redirectors).
      */
 
-    Interp *iPtr = (Interp *) interp;
     TEOV_callback *runPtr;
 
-    runPtr = TOP_CB(interp);
-    if (skip) {
-        while (runPtr && (runPtr != iPtr->varFramePtr->wherePtr)) {
-            if ((runPtr->procPtr) == TclNRBlockTailcall) {
-                ClearTailcall(interp, tailcallPtr);
-                Tcl_SetResult(interp,"tailcall called from within a catch environment",
-                        TCL_STATIC);
-                Tcl_SetErrorCode(interp, "TCL", "TAILCALL", "ILLEGAL",
-                        NULL);
-                return TCL_ERROR;
-            }
-            runPtr = runPtr->nextPtr;
-        }
-    }
-
-    restart:
-    for (; runPtr; runPtr = runPtr->nextPtr) {
+    for (runPtr = TOP_CB(interp); runPtr; runPtr = runPtr->nextPtr) {
 	if (((runPtr->procPtr) == NRCommand) && !runPtr->data[1]) {
             break;
         }
     }
     if (!runPtr) {
-	/*
-	 * If we are tailcalling out of a coroutine, the splicing spot is in
-	 * the caller's execEnv: go find it!
-	 */
-
-	CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
-
-	if (corPtr) {
-            runPtr = corPtr->callerEEPtr->callbackPtr;
-	    goto restart;
-	}
-        
-        Tcl_SetResult(interp,
-                "tailcall cannot find the right splicing spot: should not happen!",
-                TCL_STATIC);
-        Tcl_SetErrorCode(interp, "TCL", "TAILCALL", "UNKNOWN", NULL);
-        return TCL_ERROR;
+        Tcl_Panic("tailcall cannot find the right splicing spot: should not happen!");
     }
 
     tailcallPtr->nextPtr = runPtr->nextPtr;
     runPtr->nextPtr = tailcallPtr;
-    return TCL_OK;
 }
 
 int
@@ -8379,18 +8321,13 @@
     Tcl_Obj *const objv[])
 {
     Interp *iPtr = (Interp *) interp;
-    Tcl_Obj *listPtr, *nsObjPtr;
-    Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
-    Tcl_Namespace *ns1Ptr;
-    TEOV_callback *tailcallPtr;
 
-    if (objc < 2) {
-	Tcl_WrongNumArgs(interp, 1, objv, "command ?arg ...?");
+    if (objc < 1) {
+	Tcl_WrongNumArgs(interp, 1, objv, "?command? ?arg ...?");
 	return TCL_ERROR;
     }
 
-    if (!iPtr->varFramePtr->isProcCallFrame ||		/* is not a body */
-	    (iPtr->framePtr != iPtr->varFramePtr)) {	/* or is upleveled */
+    if (!iPtr->varFramePtr->isProcCallFrame) {	/* or is upleveled */
         Tcl_SetResult(interp,
                 "tailcall can only be called from a proc or lambda",
                 TCL_STATIC);
@@ -8398,33 +8335,45 @@
 	return TCL_ERROR;
     }
 
-    listPtr = Tcl_NewListObj(objc-1, objv+1);
-    Tcl_IncrRefCount(listPtr);
+    /*
+     * Invocation without args just clears a scheduled tailcall; invocation
+     * with an argument replaces any previously scheduled tailcall.
+     */
 
-    nsObjPtr = Tcl_NewStringObj(nsPtr->fullName, -1);
-    if ((TCL_OK != TclGetNamespaceFromObj(interp, nsObjPtr, &ns1Ptr))
-	    || (nsPtr != ns1Ptr)) {
-	Tcl_Panic("Tailcall failed to find the proper namespace");
+    if (iPtr->varFramePtr->tailcallPtr) {
+        ClearTailcall(interp, iPtr->varFramePtr->tailcallPtr);
+        iPtr->varFramePtr->tailcallPtr = NULL;
     }
-    Tcl_IncrRefCount(nsObjPtr);
-
+    
     /*
      * Create the callback to actually evaluate the tailcalled
-     * command, then pass it to tebc so that it is stashed at the proper
-     * place. Being lazy: exploit the TclNRAddCallBack macro to build the
-     * callback.
+     * command, then set it in the varFrame so that PopCallFrame can use it
+     * at the proper time. Being lazy: exploit the TclNRAddCallBack macro to
+     * build the callback.
      */
 
-    TclNRAddCallback(interp, NRTailcallEval, listPtr, nsObjPtr, NULL, NULL);
-    tailcallPtr = TOP_CB(interp);
-    TOP_CB(interp) = tailcallPtr->nextPtr;
+    if (objc > 1) {
+        Tcl_Obj *listPtr, *nsObjPtr;
+        Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
+        Tcl_Namespace *ns1Ptr;
+        TEOV_callback *tailcallPtr;
+        
+        listPtr = Tcl_NewListObj(objc-1, objv+1);
+        Tcl_IncrRefCount(listPtr);
+
+        nsObjPtr = Tcl_NewStringObj(nsPtr->fullName, -1);
+        if ((TCL_OK != TclGetNamespaceFromObj(interp, nsObjPtr, &ns1Ptr))
+                || (nsPtr != ns1Ptr)) {
+            Tcl_Panic("Tailcall failed to find the proper namespace");
+        }
+        Tcl_IncrRefCount(nsObjPtr);
 
-    if (SpliceTailcall(interp, tailcallPtr, 1) == TCL_ERROR) {
-        return TCL_ERROR;
+        TclNRAddCallback(interp, NRTailcallEval, listPtr, nsObjPtr, NULL, NULL);
+        tailcallPtr = TOP_CB(interp);
+        TOP_CB(interp) = tailcallPtr->nextPtr;
+        iPtr->varFramePtr->tailcallPtr = tailcallPtr;
     }
-    
-    iPtr->varFramePtr->isProcCallFrame |= FRAME_TAILCALLING;
-    return TCL_OK;
+    return TCL_RETURN;
 }
 
 int
@@ -8484,15 +8433,6 @@
     TCLNR_FREE(interp, tailcallPtr);
 }
 
-int
-TclNRBlockTailcall(
-    ClientData data[],
-    Tcl_Interp *interp,
-    int result)
-{
-    return result;
-}
-
 
 void
 Tcl_NRAddCallback(
@@ -8661,7 +8601,7 @@
     cbPtr = TOP_CB(interp);
     TOP_CB(interp) = cbPtr->nextPtr;
 
-    SpliceTailcall(interp, cbPtr, 0);
+    TclSpliceTailcall(interp, cbPtr);
     return TCL_OK;
 }
 
@@ -9042,7 +8982,6 @@
 
     TclNRAddCallback(interp, NRCoroutineExitCallback, corPtr,
 	    NULL, NULL, NULL);
-    iPtr->evalFlags |= TCL_EVAL_REDIRECT;
     iPtr->lookupNsPtr = nsPtr;
     TclNREvalObjEx(interp, cmdObjPtr, 0, NULL, 0);
 
diff -ur ./generic/tclBasic.c.orig ./generic/tclBasic.c.orig
--- ./generic/tclBasic.c.orig	2010-08-21 11:02:38.274171879 -0300
+++ ./generic/tclBasic.c.orig	2010-08-20 20:11:06.966884309 -0300
@@ -167,6 +167,10 @@
 
 static void	        ClearTailcall(Tcl_Interp *interp,
 			    struct TEOV_callback *tailcallPtr);
+static int              SpliceTailcall(Tcl_Interp *interp,
+	                    struct TEOV_callback *tailcallPtr,
+                            int skip);
+
 
 MODULE_SCOPE const TclStubs tclStubs;
 
@@ -8287,10 +8291,30 @@
  * FIXME NRE!
  */
 
-void
-TclSpliceTailcall(
+void TclRemoveTailcall(
+    Tcl_Interp *interp)
+{
+    TEOV_callback *runPtr, *tailcallPtr;
+
+    for (runPtr = TOP_CB(interp); runPtr->nextPtr; runPtr = runPtr->nextPtr) {
+        if (runPtr->nextPtr->procPtr == NRTailcallEval) {
+            break;
+        }
+    }
+    if (!runPtr->nextPtr) {
+        Tcl_Panic("TclRemoveTailcall did not find a tailcall");
+    }
+
+    tailcallPtr = runPtr->nextPtr;
+    runPtr->nextPtr = tailcallPtr->nextPtr;
+    ClearTailcall(interp, tailcallPtr);
+}
+
+static int
+SpliceTailcall(
     Tcl_Interp *interp,
-    TEOV_callback *tailcallPtr)
+    TEOV_callback *tailcallPtr,
+    int skip)
 {
     /*
      * Find the splicing spot: right before the NRCommand of the thing
@@ -8298,19 +8322,53 @@
      * (used by command redirectors).
      */
 
+    Interp *iPtr = (Interp *) interp;
     TEOV_callback *runPtr;
 
-    for (runPtr = TOP_CB(interp); runPtr; runPtr = runPtr->nextPtr) {
+    runPtr = TOP_CB(interp);
+    if (skip) {
+        while (runPtr && (runPtr != iPtr->varFramePtr->wherePtr)) {
+            if ((runPtr->procPtr) == TclNRBlockTailcall) {
+                ClearTailcall(interp, tailcallPtr);
+                Tcl_SetResult(interp,"tailcall called from within a catch environment",
+                        TCL_STATIC);
+                Tcl_SetErrorCode(interp, "TCL", "TAILCALL", "ILLEGAL",
+                        NULL);
+                return TCL_ERROR;
+            }
+            runPtr = runPtr->nextPtr;
+        }
+    }
+
+    restart:
+    for (; runPtr; runPtr = runPtr->nextPtr) {
 	if (((runPtr->procPtr) == NRCommand) && !runPtr->data[1]) {
             break;
         }
     }
     if (!runPtr) {
-        Tcl_Panic("tailcall cannot find the right splicing spot: should not happen!");
+	/*
+	 * If we are tailcalling out of a coroutine, the splicing spot is in
+	 * the caller's execEnv: go find it!
+	 */
+
+	CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
+
+	if (corPtr) {
+            runPtr = corPtr->callerEEPtr->callbackPtr;
+	    goto restart;
+	}
+
+        Tcl_SetResult(interp,
+                "tailcall cannot find the right splicing spot: should not happen!",
+                TCL_STATIC);
+        Tcl_SetErrorCode(interp, "TCL", "TAILCALL", "UNKNOWN", NULL);
+        return TCL_ERROR;
     }
 
     tailcallPtr->nextPtr = runPtr->nextPtr;
     runPtr->nextPtr = tailcallPtr;
+    return TCL_OK;
 }
 
 int
@@ -8344,7 +8402,7 @@
         ClearTailcall(interp, iPtr->varFramePtr->tailcallPtr);
         iPtr->varFramePtr->tailcallPtr = NULL;
     }
-
+    
     /*
      * Create the callback to actually evaluate the tailcalled
      * command, then set it in the varFrame so that PopCallFrame can use it
@@ -8357,7 +8415,7 @@
         Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
         Tcl_Namespace *ns1Ptr;
         TEOV_callback *tailcallPtr;
-
+        
         listPtr = Tcl_NewListObj(objc-1, objv+1);
         Tcl_IncrRefCount(listPtr);
 
@@ -8982,6 +9040,7 @@
 
     TclNRAddCallback(interp, NRCoroutineExitCallback, corPtr,
 	    NULL, NULL, NULL);
+    iPtr->evalFlags |= TCL_EVAL_REDIRECT;
     iPtr->lookupNsPtr = nsPtr;
     TclNREvalObjEx(interp, cmdObjPtr, 0, NULL, 0);
 
diff -ur ./generic/tclBasic.c.rej ./generic/tclBasic.c.rej
--- ./generic/tclBasic.c.rej	2010-08-21 11:02:31.871189303 -0300
+++ ./generic/tclBasic.c.rej	2010-08-20 20:11:12.105882211 -0300
@@ -1,33 +1,133 @@
 --- generic/tclBasic.c
 +++ generic/tclBasic.c
-@@ -8476,10 +8523,19 @@
+@@ -8319,56 +8261,63 @@
+     Tcl_Interp *interp,
+     int objc,
+     Tcl_Obj *const objv[])
+ {
+     Interp *iPtr = (Interp *) interp;
+-    Tcl_Obj *listPtr, *nsObjPtr;
+-    Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
+-    Tcl_Namespace *ns1Ptr;
+-    TEOV_callback *tailcallPtr;
+-
+-    if (objc < 2) {
+-	Tcl_WrongNumArgs(interp, 1, objv, "command ?arg ...?");
+-	return TCL_ERROR;
+-    }
+-
+-    if (!iPtr->varFramePtr->isProcCallFrame ||		/* is not a body */
+-	    (iPtr->framePtr != iPtr->varFramePtr)) {	/* or is upleveled */
++
++    if (objc < 1) {
++	Tcl_WrongNumArgs(interp, 1, objv, "?command? ?arg ...?");
++	return TCL_ERROR;
++    }
++
++    if (!iPtr->varFramePtr->isProcCallFrame) {	/* or is upleveled */
+         Tcl_SetResult(interp,
+                 "tailcall can only be called from a proc or lambda",
+                 TCL_STATIC);
+         Tcl_SetErrorCode(interp, "TCL", "TAILCALL", "ILLEGAL", NULL);
+ 	return TCL_ERROR;
+     }
+ 
+-    listPtr = Tcl_NewListObj(objc-1, objv+1);
+-    Tcl_IncrRefCount(listPtr);
+-
+-    nsObjPtr = Tcl_NewStringObj(nsPtr->fullName, -1);
+-    if ((TCL_OK != TclGetNamespaceFromObj(interp, nsObjPtr, &ns1Ptr))
+-	    || (nsPtr != ns1Ptr)) {
+-	Tcl_Panic("Tailcall failed to find the proper namespace");
+-    }
+-    Tcl_IncrRefCount(nsObjPtr);
++    /*
++     * Invocation without args just clears a scheduled tailcall; invocation
++     * with an argument replaces any previously scheduled tailcall.
++     */
++
++    if (iPtr->varFramePtr->tailcallPtr) {
++        ClearTailcall(interp, iPtr->varFramePtr->tailcallPtr);
++        iPtr->varFramePtr->tailcallPtr = NULL;
++    }
+ 
+     /*
+      * Create the callback to actually evaluate the tailcalled
+-     * command, then pass it to tebc so that it is stashed at the proper
+-     * place. Being lazy: exploit the TclNRAddCallBack macro to build the
+-     * callback.
+-     */
+-
+-    TclNRAddCallback(interp, NRTailcallEval, listPtr, nsObjPtr, NULL, NULL);
+-    tailcallPtr = TOP_CB(interp);
+-    TOP_CB(interp) = tailcallPtr->nextPtr;
+-
+-    if (SpliceTailcall(interp, tailcallPtr, 1) == TCL_ERROR) {
+-        return TCL_ERROR;
+-    }
+-
+-    iPtr->varFramePtr->isProcCallFrame |= FRAME_TAILCALLING;
+-    return TCL_OK;
++     * command, then set it in the varFrame so that PopCallFrame can use it
++     * at the proper time. Being lazy: exploit the TclNRAddCallBack macro to
++     * build the callback.
++     */
++
++    if (objc > 1) {
++        Tcl_Obj *listPtr, *nsObjPtr;
++        Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
++        Tcl_Namespace *ns1Ptr;
++        TEOV_callback *tailcallPtr;
++
++        listPtr = Tcl_NewListObj(objc-1, objv+1);
++        Tcl_IncrRefCount(listPtr);
++
++        nsObjPtr = Tcl_NewStringObj(nsPtr->fullName, -1);
++        if ((TCL_OK != TclGetNamespaceFromObj(interp, nsObjPtr, &ns1Ptr))
++                || (nsPtr != ns1Ptr)) {
++            Tcl_Panic("Tailcall failed to find the proper namespace");
++        }
++        Tcl_IncrRefCount(nsObjPtr);
++
++        TclNRAddCallback(interp, NRTailcallEval, listPtr, nsObjPtr, NULL, NULL);
++        tailcallPtr = TOP_CB(interp);
++        TOP_CB(interp) = tailcallPtr->nextPtr;
++        iPtr->varFramePtr->tailcallPtr = tailcallPtr;
++    }
++    return TCL_RETURN;
+ }
+ 
+ int
+ NRTailcallEval(
+     ClientData data[],
+@@ -8422,19 +8371,10 @@
      Tcl_Interp *interp,
      TEOV_callback *tailcallPtr)
  {
      TailcallCleanup(tailcallPtr->data, interp, TCL_OK);
      TCLNR_FREE(interp, tailcallPtr);
-+}
-+
-+int
-+TclNRBlockTailcall(
-+    ClientData data[],
-+    Tcl_Interp *interp,
-+    int result)
-+{
-+    return result;
+-}
+-
+-int
+-TclNRBlockTailcall(
+-    ClientData data[],
+-    Tcl_Interp *interp,
+-    int result)
+-{
+-    return result;
  }
  
  
  void
  Tcl_NRAddCallback(
-@@ -8646,11 +8702,11 @@
+@@ -8601,11 +8541,11 @@
  
      TclNRAddCallback(interp, NRTailcallEval, listPtr, nsPtr, NULL, NULL);
      cbPtr = TOP_CB(interp);
      TOP_CB(interp) = cbPtr->nextPtr;
  
--    TclSpliceTailcall(interp, cbPtr);
-+    SpliceTailcall(interp, cbPtr, 0);
+-    SpliceTailcall(interp, cbPtr, 0);
++    TclSpliceTailcall(interp, cbPtr);
      return TCL_OK;
  }
  
diff -ur ./generic/tclCmdAH.c ./generic/tclCmdAH.c
--- ./generic/tclCmdAH.c	2010-08-21 11:07:22.379171742 -0300
+++ ./generic/tclCmdAH.c	2010-08-20 20:11:12.113880923 -0300
@@ -292,8 +292,6 @@
 
     TclNRAddCallback(interp, CatchObjCmdCallback, INT2PTR(objc),
 	    varNamePtr, optionVarNamePtr, NULL);
-    TclNRAddCallback(interp, TclNRBlockTailcall, NULL, NULL, NULL,
-	    NULL);
 
     /*
      * TIP #280. Make invoking context available to caught script.
diff -ur ./generic/tclCmdMZ.c ./generic/tclCmdMZ.c
--- ./generic/tclCmdMZ.c	2010-08-21 11:07:22.387169406 -0300
+++ ./generic/tclCmdMZ.c	2010-08-20 20:11:12.125885940 -0300
@@ -4274,13 +4274,11 @@
     }
 
     /*
-     * Execute the body; block tailcalling out of it.
+     * Execute the body.
      */
 
     Tcl_NRAddCallback(interp, TryPostBody, handlersObj, finallyObj,
 	    (ClientData)objv, INT2PTR(objc));
-    TclNRAddCallback(interp, TclNRBlockTailcall, NULL, NULL, NULL,
-	    NULL);    
     return TclNREvalObjEx(interp, bodyObj, 0,
 	    ((Interp *) interp)->cmdFramePtr, 1);
 }
diff -ur ./generic/tclCmdMZ.c.orig ./generic/tclCmdMZ.c.orig
--- ./generic/tclCmdMZ.c.orig	2010-08-21 11:02:38.290170140 -0300
+++ ./generic/tclCmdMZ.c.orig	2010-08-20 20:11:06.990884428 -0300
@@ -4274,11 +4274,13 @@
     }
 
     /*
-     * Execute the body.
+     * Execute the body; block tailcalling out of it.
      */
 
     Tcl_NRAddCallback(interp, TryPostBody, handlersObj, finallyObj,
 	    (ClientData)objv, INT2PTR(objc));
+    TclNRAddCallback(interp, TclNRBlockTailcall, NULL, NULL, NULL,
+	    NULL);
     return TclNREvalObjEx(interp, bodyObj, 0,
 	    ((Interp *) interp)->cmdFramePtr, 1);
 }
diff -ur ./generic/tclExecute.c ./generic/tclExecute.c
--- ./generic/tclExecute.c	2010-08-21 11:07:22.439170361 -0300
+++ ./generic/tclExecute.c	2010-08-20 20:11:12.145882823 -0300
@@ -2901,25 +2901,6 @@
 	iPtr->cmdFramePtr = bcFramePtr->nextPtr;
 	TclArgumentBCRelease((Tcl_Interp *) iPtr, bcFramePtr);
 
-	/*
-	 * If the CallFrame is marked as tailcalling, keep tailcalling
-	 */
-
-	if (iPtr->varFramePtr->isProcCallFrame & FRAME_TAILCALLING) {
-	    if (catchTop == initCatchTop) {
-		goto abnormalReturn;
-	    }
-
-	    iPtr->varFramePtr->isProcCallFrame &= ~FRAME_TAILCALLING;
-	    TclRemoveTailcall(interp);
-	    Tcl_SetResult(interp,
-		    "tailcall called from within a catch environment",
-		    TCL_STATIC);
-	    Tcl_SetErrorCode(interp, "TCL", "TAILCALL", "ILLEGAL", NULL);
-	    pc--;
-	    goto gotError;
-	}
-
 	if (iPtr->execEnvPtr->rewind) {
 	    TRESULT = TCL_ERROR;
 	    goto abnormalReturn;
diff -ur ./generic/tclInt.h ./generic/tclInt.h
--- ./generic/tclInt.h	2010-08-21 11:07:22.487175765 -0300
+++ ./generic/tclInt.h	2010-08-20 20:11:12.153878950 -0300
@@ -1152,10 +1152,8 @@
 				 * meaning of the value is, which we do not
 				 * specify. */
     LocalCache *localCachePtr;
-    struct TEOV_callback *wherePtr;
-				/* The top of the callback stack when this
-				 * frame was pushed; used to find the spot
-				 * where to tailcall to. */
+    struct TEOV_callback *tailcallPtr;
+				/* NULL if no tailcall is scheduled */
 } CallFrame;
 
 #define FRAME_IS_PROC	0x1
@@ -1168,8 +1166,6 @@
 				 * field contains an Object reference that has
 				 * been confirmed to refer to a class. Part of
 				 * TIP#257. */
-#define FRAME_TAILCALLING 0x10  /* Flag is set while the CallFrame is winding
-				 * down to process a tailcall */
 
 /*
  * TIP #280
@@ -2758,10 +2754,8 @@
 MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldmObjCmd;
 MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldToObjCmd;
 
-MODULE_SCOPE void       TclRemoveTailcall(Tcl_Interp *interp);
-
-MODULE_SCOPE Tcl_NRPostProc TclNRBlockTailcall;
-
+MODULE_SCOPE void  TclSpliceTailcall(Tcl_Interp *interp,
+	               struct TEOV_callback *tailcallPtr);
 
 /*
  * This structure holds the data for the various iteration callbacks used to
diff -ur ./generic/tclNamesp.c ./generic/tclNamesp.c
--- ./generic/tclNamesp.c	2010-08-21 11:07:22.511173997 -0300
+++ ./generic/tclNamesp.c	2010-08-19 21:24:56.464581828 -0300
@@ -313,18 +313,7 @@
     framePtr->compiledLocals = NULL;
     framePtr->clientData = NULL;
     framePtr->localCachePtr = NULL;
-
-    /*
-     * Record the top of the callback stack, so that tailcall can identify
-     * the spot where to splice the new command.
-     */
-
-    if (iPtr->execEnvPtr) {
-        framePtr->wherePtr = TOP_CB(interp);
-    } else {
-        framePtr->wherePtr = NULL;
-    }
-    
+    framePtr->tailcallPtr = NULL;
     
     /*
      * Push the new call frame onto the interpreter's stack of procedure call
@@ -403,6 +392,10 @@
 	Tcl_DeleteNamespace((Tcl_Namespace *) nsPtr);
     }
     framePtr->nsPtr = NULL;
+
+    if (framePtr->tailcallPtr) {
+        TclSpliceTailcall(interp, framePtr->tailcallPtr);
+    }
 }
 
 /*
diff -ur ./generic/tclNamesp.c.rej ./generic/tclNamesp.c.rej
--- ./generic/tclNamesp.c.rej	2010-08-21 11:02:31.906173360 -0300
+++ ./generic/tclNamesp.c.rej	2010-08-20 20:11:12.181880341 -0300
@@ -1,15 +1,39 @@
 --- generic/tclNamesp.c
 +++ generic/tclNamesp.c
-@@ -401,14 +412,10 @@
+@@ -311,22 +311,11 @@
+     framePtr->varTablePtr = NULL;	/* and no local variables */
+     framePtr->numCompiledLocals = 0;
+     framePtr->compiledLocals = NULL;
+     framePtr->clientData = NULL;
+     framePtr->localCachePtr = NULL;
+-
+-    /*
+-     * Record the top of the callback stack, so that tailcall can identify
+-     * the spot where to splice the new command.
+-     */
+-
+-    if (iPtr->execEnvPtr) {
+-        framePtr->wherePtr = TOP_CB(interp);
+-    } else {
+-        framePtr->wherePtr = NULL;
+-    }
+-
++    framePtr->tailcallPtr = NULL;
+ 
+     /*
+      * Push the new call frame onto the interpreter's stack of procedure call
+      * frames making it the current frame.
+      */
+@@ -401,10 +390,14 @@
      if ((nsPtr->flags & NS_DYING)
  	    && (nsPtr->activationCount - (nsPtr == iPtr->globalNsPtr) == 0)) {
  	Tcl_DeleteNamespace((Tcl_Namespace *) nsPtr);
      }
      framePtr->nsPtr = NULL;
--
--    if (framePtr->tailcallPtr) {
--        TclSpliceTailcall(interp, framePtr->tailcallPtr);
--    }
++
++    if (framePtr->tailcallPtr) {
++        TclSpliceTailcall(interp, framePtr->tailcallPtr);
++    }
  }
  
  /*
diff -ur ./manifest ./manifest
--- ./manifest	2010-08-21 11:07:24.814170394 -0300
+++ ./manifest	2010-08-20 18:35:12.913880290 -0300
@@ -1,5 +1,5 @@
-C cvs\sup
-D 2010-08-19T16:23:14
+C fix\stailcall/coroutine\sinteraction
+D 2010-08-20T21:18:04
 F CVS/Entries 597b70c680e553eccfb15eb474e405f9e8a4556c
 F CVS/Repository eb85e7cec80466bd7ab394699b847104d772ceef
 F CVS/Root cae9b1a9e5129ffcc3247889f1eed9a98d1df4a7
@@ -334,13 +334,13 @@
 F generic/tcl.h ccede7be24ce976e22f8b72f4092353a8750bf84
 F generic/tclAlloc.c 626b42befebd88ba8c89d6c1ab3159bd81088c83
 F generic/tclAsync.c 515bda8c56e140d4fb91a322005a8a9570c2937d
-F generic/tclBasic.c a78e5c123fa673402c4e00e48f05336d885f2c5d
+F generic/tclBasic.c b4becfa98922576fc4f7de418c835bb916cbcf02
 F generic/tclBinary.c aa87910a0bcc20dec630eb821bc5570348ed1ade
 F generic/tclCkalloc.c d67ae01c9bb387faacaa92453c2896512cdea29b
 F generic/tclClock.c 17d98509d104ecd6b46fc3a358f1e68e6a25fa67
-F generic/tclCmdAH.c fc993681108128276d828b51ec1b97f74f843ef8
+F generic/tclCmdAH.c 8356cd0548b0bf131376f6b8c31f65a34bfb7d96
 F generic/tclCmdIL.c ebe1a0be188c5e9faeab2c335f53f031162a1c84
-F generic/tclCmdMZ.c dafd4c6e7e97af79179b9b560c2cd61c2dcdb52e
+F generic/tclCmdMZ.c 0b825b9641fd366852627bc17d4c603b477f84f2
 F generic/tclCompCmds.c 14c3400c39ef05aabf08962b4025f30470386702
 F generic/tclCompCmdsSZ.c 1911404dd005784ac681fcb7a93560982833b2d4
 F generic/tclCompExpr.c 0dc5352389d0a4f52f20458c7a1f54379d495182
@@ -355,7 +355,7 @@
 F generic/tclEnsemble.c 3e40b3e2411e3bec988c48018ab009ca24773a70
 F generic/tclEnv.c 3dc53ec308081ecb7c95f54599b992a748d60adc
 F generic/tclEvent.c 45cc17789dc0788473395e08837861025c787526
-F generic/tclExecute.c 090893fc456293f58cae044781ab1b85b2ea29fe
+F generic/tclExecute.c 460aac699bcb596d6eb02633b958063f680ef91c
 F generic/tclFCmd.c 9c00cb49faa05999a7feca4650fe620939281abc
 F generic/tclFileName.c da7c1c5e45670b8b37f007984832048d2f28a359
 F generic/tclFileSystem.h d4f216a9e2730002fd1af099a65e73ed916ccc2d
@@ -373,7 +373,7 @@
 F generic/tclIOUtil.c cd73741dbef929e1331cef3ff2a7b400dc0c619b
 F generic/tclIndexObj.c f928158016b735c3c315acb339600ce1e7d15536
 F generic/tclInt.decls 2ac6a7a2c31ddad7f4f8891e6f137aa7a93d55fc
-F generic/tclInt.h d39d56aeaa3596e890c85c7040f6e3c994176c02
+F generic/tclInt.h 6b4ab99d66a6b8b8c99b7327a908067f4d6aacaf
 F generic/tclIntDecls.h 1753341b9a7a5962461c8c19e8a1cfd2edc55ab9
 F generic/tclIntPlatDecls.h 457725d51c64ed8d75605e72c6594f44cadcc207
 F generic/tclInterp.c 347cfb4a96cd2d5937d51285181b42d1c3086176
@@ -383,7 +383,7 @@
 F generic/tclLoad.c 274f42b159e4786b5271029326ae24cb0debc3ba
 F generic/tclLoadNone.c 2a48baef148baacc62b4180783feeaf667075111
 F generic/tclMain.c b0385368173adda1780a817f4a0fa0219bb1b3a4
-F generic/tclNamesp.c 0e3bcd3989ff163262109abb827e6b6c63921936
+F generic/tclNamesp.c 7f47af2dbd8178f64e1796ce18092e161b27604c
 F generic/tclNotify.c 7dedac02ab69206020503dd391fc8f0e67f3f3de
 F generic/tclOO.c 9104b7e12b2ac5a167550d835c0ccb84b3dcbdff
 F generic/tclOO.decls 0ab615db563412d6f6fa786debee9a2a856671a8
@@ -1771,7 +1771,7 @@
 F tests/stringObj.test e19f96b35493c731ce128e268c0424536af81af5
 F tests/subst.test 3737c54505570471e016e6ca24bff21bff9f5e6c
 F tests/switch.test d174239e10e1bd4ef7500ef57227fba695e354de
-F tests/tailcall.test 610ade339213c979802d99f758facfbcf755a8d9
+F tests/tailcall.test b4746ce50429a219a06fb646b3ffac0979493ac4
 F tests/tcltest.test 509db07b117b7d51162550e3ef7fc2e82cfcbd7e x
 F tests/thread.test 6aae18f9c7387c3864850af6a5a73caaf730679a
 F tests/timer.test 015b0cc07940d0120e23f2e2e80306ff454a25bb
@@ -2022,7 +2022,7 @@
 F win/tclooConfig.sh ba4b58a2db009475f7cc5a6b985ab0af0febbd2d
 F win/tclsh.ico 54ce97ad2c00398e7e4bfb15a8f6aea3a2e7a7de
 F win/tclsh.rc 25bfab3c518f473f96a7d399d1f68d8778c4dce9
-P 3c5081d4e83f5b7db134a6675ec2731acc41e132
-R 6f9f04568599c84fc137257c51a64bdf
+P 5b5c0416869447440291e2f9642a84b27d0ca49e
+R 5bfca76d9dd99f75e4a51b8a2c5c357c
 U mig
-Z df5b9d23d77d28637145160871e27b55
+Z adc58f841c8f12211aa66628bec88d76
diff -ur ./manifest.uuid ./manifest.uuid
--- ./manifest.uuid	2010-08-21 11:07:24.818167340 -0300
+++ ./manifest.uuid	2010-08-20 18:35:12.921878445 -0300
@@ -1 +1 @@
-17ac7d08a76ec30730903eeabb454aa69032979d
+af27f155bafb13628c80786c0964a7f5cc73b1ec
diff -ur ./tests/tailcall.test ./tests/tailcall.test
--- ./tests/tailcall.test	2010-08-21 11:07:24.318177537 -0300
+++ ./tests/tailcall.test	2010-08-20 20:11:12.189881636 -0300
@@ -384,6 +384,20 @@
     unset -nocomplain ::x
 } -match glob -result *tailcall* -returnCodes error
 
+test tailcall-11c {tailcall and uplevel} -setup {
+    proc a {} {
+	uplevel 1 {tailcall lappend ::x 2}
+	set ::x 1
+    }
+    proc b {} {set ::x 0; a; lappend ::x 3}
+} -body {
+    list [b] $::x
+} -cleanup {
+    rename a {}
+    rename b {}
+    unset -nocomplain ::x
+} -result {{0 3 2} {0 3 2}}
+
 test tailcall-12.1 {[Bug 2649975]} -setup {
     proc dump {{text {}}} {
 	set text [uplevel 1 [list subst $text]]
@@ -545,29 +559,75 @@
 1: exiting from foo's alpha
 }
 
-test tailcall-12.3a {[Bug 2695587]} {
+test tailcall-12.3a0 {[Bug 2695587]} -body {
+    apply {{} {
+	catch [list tailcall foo]
+    }}
+} -returnCodes 1 -result {invalid command name "foo"}
+
+test tailcall-12.3a1 {[Bug 2695587]} -body {
+    apply {{} {
+	catch [list tailcall foo]
+	tailcall
+    }}
+} -result {}
+
+test tailcall-12.3a2 {[Bug 2695587]} -body {
+    apply {{} {
+	catch [list tailcall foo]
+	tailcall moo
+    }}
+} -returnCodes 1 -result {invalid command name "moo"}
+
+test tailcall-12.3a3 {[Bug 2695587]} -body {
+    set x 0
+    apply {{} {
+	catch [list tailcall foo]
+	tailcall lappend x 1
+    }}
+    set x
+} -cleanup {
+    unset x
+} -result {0 1} 
+
+test tailcall-12.3b0 {[Bug 2695587]} -body {
     apply {{} {
-	list [catch [list tailcall foo] msg opt] $msg [errorcode $opt]
+	set catch catch
+	$catch [list tailcall foo]
     }}
-} {1 {tailcall called from within a catch environment} {TCL TAILCALL ILLEGAL}}
+} -returnCodes 1 -result {invalid command name "foo"}
 
-test tailcall-12.3b {[Bug 2695587]} {
+test tailcall-12.3b1 {[Bug 2695587]} -body {
     apply {{} {
-	list [catch {tailcall foo} msg opt] $msg [errorcode $opt]
+	set catch catch
+	$catch [list tailcall foo]
+	tailcall
     }}
-} {1 {tailcall called from within a catch environment} {TCL TAILCALL ILLEGAL}}
+} -result {}
 
-test tailcall-12.3c {[Bug 3046594]} {
+test tailcall-12.3b2 {[Bug 2695587]} -body {
     apply {{} {
-	list [[subst catch] {tailcall foo} msg opt] $msg [errorcode $opt]
+	set catch catch
+	$catch [list tailcall foo]
+	tailcall moo
     }}
-} {1 {tailcall called from within a catch environment} {TCL TAILCALL ILLEGAL}}
+} -returnCodes 1 -result {invalid command name "moo"}
 
-test tailcall-12.3d {[Bug 3046594]} {
+test tailcall-12.3b3 {[Bug 2695587]} -body {
+    set x 0
     apply {{} {
-	list [[subst catch] [list tailcall foo] msg opt] $msg [errorcode $opt]
+	set catch catch
+	$catch [list tailcall foo]
+	tailcall lappend x 1
     }}
-} {1 {tailcall called from within a catch environment} {TCL TAILCALL ILLEGAL}}
+    set x
+} -cleanup {
+    unset x
+} -result {0 1} 
+
+# MORE VARIANTS MISSING: bc'ed caught script vs (bc'ed, not-bc'ed)
+# catch. Actually superfluous now, as tailcall just returns TCL_RETURN so that
+# standard catch behaviour is required.
 
 test tailcall-13.1 {tailcall and coroutine} -setup {
     set lambda {i {
@@ -582,8 +642,8 @@
 } -body {
     coroutine moo ::apply $::lambda 0
 } -cleanup {
-    unset lambda 
-} -result {0 0 0 0 0 0}
+    unset lambda
+} -result {0 0 0 0 0 0} 
 
 test tailcall-14.1 {directly tailcalling the tailcall command is ok} {
     list [catch {