Tcl Source Code

Artifact [a76b3c8b40]
Login

Artifact a76b3c8b40cd1b32bab6d24657ce42c9ee74a0f0:

Attachment "levels2.patch" to ticket [480896ffff] added by msofer 2001-11-13 03:13:54.
Index: generic/tclBasic.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBasic.c,v
retrieving revision 1.35
diff -u -r1.35 tclBasic.c
--- generic/tclBasic.c	2001/09/01 00:51:31	1.35
+++ generic/tclBasic.c	2001/11/12 20:07:40
@@ -2826,7 +2826,7 @@
     iPtr->numLevels++;
     if (iPtr->numLevels > iPtr->maxNestingDepth) {
 	Tcl_AppendToObj(Tcl_GetObjResult(interp),
-		"too many nested calls to Tcl_EvalObj (infinite loop?)", -1); 
+		"too many nested calls to Tcl_Eval (infinite loop?)", -1); 
 	result = TCL_ERROR;
 	goto done;
     }
@@ -2839,7 +2839,7 @@
     if (TclpCheckStackSpace() == 0) {
 	/*NOTREACHED*/
     	Tcl_AppendToObj(Tcl_GetObjResult(interp),
-		"too many nested calls to Tcl_EvalObj (infinite loop?)", -1);
+		"too many nested calls to Tcl_Eval (infinite loop?)", -1);
 	result = TCL_ERROR;
 	goto done;
     }
Index: generic/tclCompile.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompile.h,v
retrieving revision 1.17
diff -u -r1.17 tclCompile.h
--- generic/tclCompile.h	2001/10/15 20:26:57	1.17
+++ generic/tclCompile.h	2001/11/12 20:07:41
@@ -775,6 +775,9 @@
 EXTERN ExceptionRange *	TclGetExceptionRangeForPc _ANSI_ARGS_((
 			    unsigned char *pc, int catchOnly,
 			    ByteCode* codePtr));
+EXTERN int		TclEvalObjvInternal _ANSI_ARGS_((Tcl_Interp *interp, int objc,
+			    Tcl_Obj *CONST objv[], char *command, int length,
+			    int flags));
 EXTERN int		TclExecuteByteCode _ANSI_ARGS_((Tcl_Interp *interp,
 			    ByteCode *codePtr));
 EXTERN void		TclExpandJumpFixupArray _ANSI_ARGS_((
Index: generic/tclExecute.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclExecute.c,v
retrieving revision 1.34
diff -u -r1.34 tclExecute.c
--- generic/tclExecute.c	2001/09/21 19:09:03	1.34
+++ generic/tclExecute.c	2001/11/12 20:07:44
@@ -220,10 +220,6 @@
  * Declarations for local procedures to this file:
  */
 
-static void		CallTraceProcedure _ANSI_ARGS_((Tcl_Interp *interp,
-			    Trace *tracePtr, Command *cmdPtr,
-			    char *command, int numChars,
-			    int objc, Tcl_Obj *objv[]));
 static void		DupCmdNameInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr,
 			    Tcl_Obj *copyPtr));
 static int		ExprAbsFunc _ANSI_ARGS_((Tcl_Interp *interp,
@@ -535,7 +531,7 @@
  *
  *----------------------------------------------------------------------
  */
-
+ 
 int
 TclExecuteByteCode(interp, codePtr)
     Tcl_Interp *interp;		/* Token for command interpreter. */
@@ -743,63 +739,64 @@
 	    {
 		int objc = opnd; /* The number of arguments. */
 		Tcl_Obj **objv;	 /* The array of argument objects. */
-		Command *cmdPtr; /* Points to command's Command struct. */
 		int newPcOffset; /* New inst offset for break, continue. */
 		Tcl_Obj **preservedStack;
 				 /* Reference to memory block containing
 				  * objv array (must be kept live throughout
 				  * trace and command invokations.) */
-#ifdef TCL_COMPILE_DEBUG
-		int isUnknownCmd = 0;
-		char cmdNameBuf[21];
-#endif /* TCL_COMPILE_DEBUG */
 
-		/*
-		 * If the interpreter was deleted, return an error.
-		 */
+		objv = &(stackPtr[stackTop - (objc-1)]);
 
-		if (iPtr->flags & DELETED) {
-		    Tcl_ResetResult(interp);
-		    Tcl_AppendToObj(Tcl_GetObjResult(interp),
-		            "attempt to call eval in deleted interpreter", -1);
-		    Tcl_SetErrorCode(interp, "CORE", "IDELETE",
-			    "attempt to call eval in deleted interpreter",
-			    (char *) NULL);
-		    result = TCL_ERROR;
-		    goto checkForCatch;
+#ifdef TCL_COMPILE_DEBUG
+		if (tclTraceExec >= 2) {
+		    if (traceInstructions) {
+			strncpy(cmdNameBuf, Tcl_GetString(objv[0]), 20);
+			TRACE(("%u => call ", objc));
+		    } else {
+			fprintf(stdout, "%d: (%u) invoking ",
+			        iPtr->numLevels,
+				(unsigned int)(pc - codePtr->codeStart));
+		    }
+		    for (i = 0;  i < objc;  i++) {
+			TclPrintObject(stdout, objv[i], 15);
+			fprintf(stdout, " ");
+		    }
+		    fprintf(stdout, "\n");
+		    fflush(stdout);
 		}
+#endif /*TCL_COMPILE_DEBUG*/
 
-		/*
-		 * Find the procedure to execute this command. If the
-		 * command is not found, handle it with the "unknown" proc.
+		/* 
+		 * If trace procedures will be called, we need a
+		 * command string to pass to TclEvalObjvInternal; note 
+		 * that a copy of the string will be made there to 
+		 * include the ending \0.
 		 */
 
-		objv = &(stackPtr[stackTop - (objc-1)]);
-		cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objv[0]);
-		if (cmdPtr == NULL) {
-		    cmdPtr = (Command *) Tcl_FindCommand(interp, "unknown",
-                            (Tcl_Namespace *) NULL, TCL_GLOBAL_ONLY);
-                    if (cmdPtr == NULL) {
-			Tcl_ResetResult(interp);
-			Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
-			        "invalid command name \"",
-				Tcl_GetString(objv[0]), "\"",
-				(char *) NULL);
-			TRACE(("%u => unknown proc not found: ", objc));
-			result = TCL_ERROR;
-			goto checkForCatch;
+		bytes = NULL;
+		length = 0;
+		if (iPtr->tracePtr != NULL) {
+		    Trace *tracePtr, *nextTracePtr;
+		    
+		    for (tracePtr = iPtr->tracePtr;  tracePtr != NULL;
+		            tracePtr = nextTracePtr) {
+			nextTracePtr = tracePtr->nextPtr;
+
+			/*
+			 * TclEvalObjvInternal will increment numLevels 
+			 * so use "<" rather than "<="
+			 */
+
+			if (iPtr->numLevels < tracePtr->level) {
+			    /*
+			     * Traces will be called: get command string
+			     */
+
+			    bytes = GetSrcInfoForPc(pc, codePtr, &length);
+			    break;
+			}
 		    }
-#ifdef TCL_COMPILE_DEBUG
-		    isUnknownCmd = 1;
-#endif /*TCL_COMPILE_DEBUG*/			
-		    stackTop++; /* need room for new inserted objv[0] */
-		    for (i = objc-1;  i >= 0;  i--) {
-			objv[i+1] = objv[i];
-		    }
-		    objc++;
-		    objv[0] = Tcl_NewStringObj("unknown", -1);
-		    Tcl_IncrRefCount(objv[0]);
-		}
+		}		
 
 		/*
 		 * A reference to part of the stack vector itself
@@ -813,64 +810,12 @@
 		Tcl_Preserve((ClientData)stackPtr);
 		preservedStack = stackPtr;
 
-		/*
-		 * Call any trace procedures.
-		 */
-
-		if (iPtr->tracePtr != NULL) {
-		    Trace *tracePtr, *nextTracePtr;
-		    
-		    for (tracePtr = iPtr->tracePtr;  tracePtr != NULL;
-		            tracePtr = nextTracePtr) {
-			nextTracePtr = tracePtr->nextPtr;
-			if (iPtr->numLevels <= tracePtr->level) {
-			    int numChars;
-			    char *cmd = GetSrcInfoForPc(pc, codePtr,
-				    &numChars);
-			    if (cmd != NULL) {
-				DECACHE_STACK_INFO();
-				CallTraceProcedure(interp, tracePtr, cmdPtr,
-				        cmd, numChars, objc, objv);
-				CACHE_STACK_INFO();
-			    }
-			}
-		    }
-		}
-
 		/*
-		 * Finally, invoke the command's Tcl_ObjCmdProc. First reset
-		 * the interpreter's string and object results to their
-		 * default empty values since they could have gotten changed
-		 * by earlier invocations.
+		 * Finally, let TclEvalObjvInternal handle the command.
 		 */
 
-		Tcl_ResetResult(interp);
-#ifdef TCL_COMPILE_DEBUG
-		if (tclTraceExec >= 2) {
-		    if (traceInstructions) {
-			strncpy(cmdNameBuf, Tcl_GetString(objv[0]), 20);
-			TRACE(("%u => call ", (isUnknownCmd? objc-1:objc)));
-		    } else {
-			fprintf(stdout, "%d: (%u) invoking ",
-			        iPtr->numLevels,
-				(unsigned int)(pc - codePtr->codeStart));
-		    }
-		    for (i = 0;  i < objc;  i++) {
-			TclPrintObject(stdout, objv[i], 15);
-			fprintf(stdout, " ");
-		    }
-		    fprintf(stdout, "\n");
-		    fflush(stdout);
-		}
-#endif /*TCL_COMPILE_DEBUG*/
-
-		iPtr->cmdCount++;
 		DECACHE_STACK_INFO();
-		result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp,
-					    objc, objv);
-		if (Tcl_AsyncReady()) {
-		    result = Tcl_AsyncInvoke(interp, result);
-		}
+		result = TclEvalObjvInternal(interp, objc, objv, bytes, length, 0);
 		CACHE_STACK_INFO();
 
 		/*
@@ -878,20 +823,8 @@
 		 * safe to do so now, since no references to objv are
 		 * going to be used from now on.
 		 */
-
-		Tcl_Release((ClientData)preservedStack);
-
-		/*
-		 * If the interpreter has a non-empty string result, the
-		 * result object is either empty or stale because some
-		 * procedure set interp->result directly. If so, move the
-		 * string result to the result object, then reset the
-		 * string result.
-		 */
 
-		if (*(iPtr->result) != 0) {
-		    (void) Tcl_GetObjResult(interp);
-		}
+		Tcl_Release((ClientData) preservedStack);
 		
 		/*
 		 * Pop the objc top stack elements and decrement their ref
@@ -3689,74 +3622,6 @@
 		msg, " as operand of \"", operatorStrings[opCode - INST_LOR],
 		"\"", (char *) NULL);
     }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CallTraceProcedure --
- *
- *	Invokes a trace procedure registered with an interpreter. These
- *	procedures trace command execution. Currently this trace procedure
- *	is called with the address of the string-based Tcl_CmdProc for the
- *	command, not the Tcl_ObjCmdProc.
- *
- * Results:
- *	None.
- *
- * Side effects:
- *	Those side effects made by the trace procedure.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-CallTraceProcedure(interp, tracePtr, cmdPtr, command, numChars, objc, objv)
-    Tcl_Interp *interp;		/* The current interpreter. */
-    register Trace *tracePtr;	/* Describes the trace procedure to call. */
-    Command *cmdPtr;		/* Points to command's Command struct. */
-    char *command;		/* Points to the first character of the
-				 * command's source before substitutions. */
-    int numChars;		/* The number of characters in the
-				 * command's source. */
-    register int objc;		/* Number of arguments for the command. */
-    Tcl_Obj *objv[];		/* Pointers to Tcl_Obj of each argument. */
-{
-    Interp *iPtr = (Interp *) interp;
-    register char **argv;
-    register int i;
-    int length;
-    char *p;
-
-    /*
-     * Get the string rep from the objv argument objects and place their
-     * pointers in argv. First make sure argv is large enough to hold the
-     * objc args plus 1 extra word for the zero end-of-argv word.
-     */
-    
-    argv = (char **) ckalloc((unsigned)(objc + 1) * sizeof(char *));
-    for (i = 0;  i < objc;  i++) {
-	argv[i] = Tcl_GetStringFromObj(objv[i], &length);
-    }
-    argv[objc] = 0;
-
-    /*
-     * Copy the command characters into a new string.
-     */
-
-    p = (char *) ckalloc((unsigned) (numChars + 1));
-    memcpy((VOID *) p, (VOID *) command, (size_t) numChars);
-    p[numChars] = '\0';
-    
-    /*
-     * Call the trace procedure then free allocated storage.
-     */
-    
-    (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
-                      p, cmdPtr->proc, cmdPtr->clientData, objc, argv);
-
-    ckfree((char *) argv);
-    ckfree((char *) p);
 }
 
 /*
Index: generic/tclParse.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclParse.c,v
retrieving revision 1.16
diff -u -r1.16 tclParse.c
--- generic/tclParse.c	2001/09/13 11:56:20	1.16
+++ generic/tclParse.c	2001/11/12 20:07:45
@@ -179,9 +179,6 @@
 			    int length));
 static int		ParseTokens _ANSI_ARGS_((char *src, int mask,
 			    Tcl_Parse *parsePtr));
-static int		EvalObjv _ANSI_ARGS_((Tcl_Interp *interp, int objc,
-			    Tcl_Obj *CONST objv[], char *command, int length,
-			    int flags));
 
 /*
  *----------------------------------------------------------------------
@@ -755,7 +752,7 @@
 /*
  *----------------------------------------------------------------------
  *
- * EvalObjv --
+ * TclEvalObjvInternal --
  *
  *	This procedure evaluates a Tcl command that has already been
  *	parsed into words, with one Tcl_Obj holding each word.
@@ -772,8 +769,8 @@
  *----------------------------------------------------------------------
  */
 
-static int
-EvalObjv(interp, objc, objv, command, length, flags)
+int
+TclEvalObjvInternal(interp, objc, objv, command, length, flags)
     Tcl_Interp *interp;		/* Interpreter in which to evaluate the
 				 * command.  Also used for error
 				 * reporting. */
@@ -785,7 +782,8 @@
 				 * is used for traces.  If the string
 				 * representation of the command is
 				 * unknown, an empty string should be
-				 * supplied. */
+				 * supplied. If it is NULL, no traces will
+				 * be called. */
     int length;			/* Number of bytes in command; if -1, all
 				 * characters up to the first null byte are
 				 * used. */
@@ -869,7 +867,7 @@
 		    (char *) NULL);
 	    code = TCL_ERROR;
 	} else {
-	    code = EvalObjv(interp, objc+1, newObjv, command, length, 0);
+	    code = TclEvalObjvInternal(interp, objc+1, newObjv, command, length, 0);
 	}
 	Tcl_DecrRefCount(newObjv[0]);
 	ckfree((char *) newObjv);
@@ -879,45 +877,47 @@
     /*
      * Call trace procedures if needed.
      */
-
-    argv = NULL;
-    commandCopy = command;
-
-    for (tracePtr = iPtr->tracePtr; tracePtr != NULL; tracePtr = nextPtr) {
-	nextPtr = tracePtr->nextPtr;
-	if (iPtr->numLevels > tracePtr->level) {
-	    continue;
-	}
 
-	/*
-	 * This is a bit messy because we have to emulate the old trace
-	 * interface, which uses strings for everything.
-	 */
-
-	if (argv == NULL) {
-	    argv = (char **) ckalloc((unsigned) (objc + 1) * sizeof(char *));
-	    for (i = 0; i < objc; i++) {
-		argv[i] = Tcl_GetString(objv[i]);
+    if (command != NULL) {
+	argv = NULL;
+	commandCopy = command;
+
+	for (tracePtr = iPtr->tracePtr; tracePtr != NULL; tracePtr = nextPtr) {
+	    nextPtr = tracePtr->nextPtr;
+	    if (iPtr->numLevels > tracePtr->level) {
+		continue;
 	    }
-	    argv[objc] = 0;
 
-	    if (length < 0) {
-		length = strlen(command);
-	    } else if ((size_t)length < strlen(command)) {
-		commandCopy = (char *) ckalloc((unsigned) (length + 1));
-		strncpy(commandCopy, command, (size_t) length);
-		commandCopy[length] = 0;
+	    /*
+	     * This is a bit messy because we have to emulate the old trace
+	     * interface, which uses strings for everything.
+	     */
+	    
+	    if (argv == NULL) {
+		argv = (char **) ckalloc((unsigned) (objc + 1) * sizeof(char *));
+		for (i = 0; i < objc; i++) {
+		    argv[i] = Tcl_GetString(objv[i]);
+		}
+		argv[objc] = 0;
+		
+		if (length < 0) {
+		    length = strlen(command);
+		} else if ((size_t)length < strlen(command)) {
+		    commandCopy = (char *) ckalloc((unsigned) (length + 1));
+		    strncpy(commandCopy, command, (size_t) length);
+		    commandCopy[length] = 0;
+		}
 	    }
-	}
-	(*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
+	    (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
 			  commandCopy, cmdPtr->proc, cmdPtr->clientData,
 			  objc, argv);
-    }
-    if (argv != NULL) {
-	ckfree((char *) argv);
-    }
-    if (commandCopy != command) {
-	ckfree((char *) commandCopy);
+	}
+	if (argv != NULL) {
+	    ckfree((char *) argv);
+	}
+	if (commandCopy != command) {
+	    ckfree((char *) commandCopy);
+	}
     }
     
     /*
@@ -1016,7 +1016,7 @@
      */
     switch (code) {
 	case TCL_OK:
-	    code = EvalObjv(interp, objc, objv, cmdString, cmdLen, flags);
+	    code = TclEvalObjvInternal(interp, objc, objv, cmdString, cmdLen, flags);
 	    if (code == TCL_ERROR && cmdLen == 0)
 		goto cmdtraced;
 	    break;
@@ -1447,7 +1447,7 @@
 	     * Execute the command and free the objects for its words.
 	     */
     
-	    code = EvalObjv(interp, objectsUsed, objv, p, bytesLeft, 0);
+	    code = TclEvalObjvInternal(interp, objectsUsed, objv, p, bytesLeft, 0);
 	    if (code != TCL_OK) {
 		goto error;
 	    }
Index: generic/tclProc.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclProc.c,v
retrieving revision 1.31
diff -u -r1.31 tclProc.c
--- generic/tclProc.c	2001/10/15 22:25:45	1.31
+++ generic/tclProc.c	2001/11/12 20:07:46
@@ -1069,9 +1069,18 @@
     }
 #endif /*TCL_COMPILE_DEBUG*/
 
+    /*
+     * Tcl_EvalObjEx will increase the level count again while evaluating
+     * the body, resulting in a total level increase of 2; correct this 
+     * behaviour before evaling the body, restore afterwards.
+     */
+
+    iPtr->numLevels--;
+
     iPtr->returnCode = TCL_OK;
     procPtr->refCount++;
     result = Tcl_EvalObjEx(interp, procPtr->bodyPtr, 0);
+    iPtr->numLevels++;
     procPtr->refCount--;
     if (procPtr->refCount <= 0) {
 	TclProcCleanupProc(procPtr);
Index: tests/stack.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/stack.test,v
retrieving revision 1.11
diff -u -r1.11 stack.test
--- tests/stack.test	2001/09/11 18:26:27	1.11
+++ tests/stack.test	2001/11/12 20:07:46
@@ -43,7 +43,7 @@
     catch {recurse} rv
     rename recurse {}
     set rv
-} {too many nested calls to Tcl_EvalObj (infinite loop?)}
+} {too many nested calls to Tcl_Eval (infinite loop?)}
 
 test stack-2.1 {maxNestingDepth reached on infinite recursion} {minStack2400} {
     # do this in a slave to not mess with parent