diff options
author | Miguel Sofer <miguel.sofer@gmail.com> | 2007-06-10 23:15:05 (GMT) |
---|---|---|
committer | Miguel Sofer <miguel.sofer@gmail.com> | 2007-06-10 23:15:05 (GMT) |
commit | 57ba79b9aa406ba55b5987ac6bf3556cce00d9df (patch) | |
tree | 9e526ad2806f8efeac869fbd387fcf300f74d7ea /generic/tclBasic.c | |
parent | 78cbf63f6981c799426895c68d288d6ab57f0d01 (diff) | |
download | tcl-57ba79b9aa406ba55b5987ac6bf3556cce00d9df.zip tcl-57ba79b9aa406ba55b5987ac6bf3556cce00d9df.tar.gz tcl-57ba79b9aa406ba55b5987ac6bf3556cce00d9df.tar.bz2 |
* generic/tclBasic.c: Further TEOvI split, creating a new
* generic/tclCompile.h: TclEvalObjvKnownCommand() function to
* generic/tclExecute.c: handle commands that are already known
and are not traced. INST_INVOKE now calls into this function
instead of inlining parts of TEOvI. Same perf, better isolation.
Diffstat (limited to 'generic/tclBasic.c')
-rw-r--r-- | generic/tclBasic.c | 136 |
1 files changed, 76 insertions, 60 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c index a06b203..8be21cc 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclBasic.c,v 1.248 2007/06/10 21:14:41 hobbs Exp $ + * RCS: @(#) $Id: tclBasic.c,v 1.249 2007/06/10 23:15:05 msofer Exp $ */ #include "tclInt.h" @@ -3383,12 +3383,21 @@ TclInterpReady( /* *---------------------------------------------------------------------- * - * TclEvalObjvInternal -- + * TclEvalObjvInternal, FullEvalObjvInternal, TclEvalObjvKnownCommand -- * - * This function evaluates a Tcl command that has already been parsed + * These functions evaluate a Tcl command that has already been parsed * into words, with one Tcl_Obj holding each word. The caller is * responsible for managing the iPtr->numLevels. * + * TclEvalObjvInternal is the backend for Tcl_EvalObjv, the other two are + * separate backends for TclEvalObjvInternal: + * - FullEvalObjvInternal is the full implementation, with [unknown] and + * trace handling. + * - TclEvalObjvKnownCommand is a fast implementation for known untraced + * commands. + * The bytecode engine calls directly into both TclEvalObjvInternal and + * TclEvalObjvKnownCommand. + * * Results: * The return value is a standard Tcl completion code such as TCL_OK or * TCL_ERROR. A result or error message is left in interp's result. If an @@ -3681,6 +3690,56 @@ FullEvalObjvInternal( } int +TclEvalObjvKnownCommand( + Tcl_Interp *interp, /* Interpreter in which to evaluate the + * command. Also used for error reporting. */ + int objc, /* Number of words in command. */ + Tcl_Obj *const objv[], /* An array of pointers to objects that are + * the words that make up the command. */ + Command *cmdPtr) /* The already determined valid command */ +{ + Interp *iPtr = (Interp *) interp; + int code = TCL_OK; + + /* + * Finally, invoke the command's Tcl_ObjCmdProc. + */ + + cmdPtr->refCount++; + iPtr->cmdCount++; + + if (!TclLimitExceeded(iPtr->limit)) { + code = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv); + } + if (Tcl_AsyncReady()) { + code = Tcl_AsyncInvoke(interp, code); + } + if (code == TCL_OK && TclLimitReady(iPtr->limit)) { + code = Tcl_LimitCheck(interp); + } + + /* + * Decrement the reference count of cmdPtr and deallocate it if it has + * dropped to zero. + */ + + TclCleanupCommandMacro(cmdPtr); + + /* + * If the interpreter has a non-empty string result, the result object is + * either empty or stale because some function 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); + } + + return code; +} + +int TclEvalObjvInternal( Tcl_Interp *interp, /* Interpreter in which to evaluate the * command. Also used for error reporting. */ @@ -3702,9 +3761,7 @@ TclEvalObjvInternal( { Command *cmdPtr; Interp *iPtr = (Interp *) interp; - CallFrame *savedVarFramePtr = NULL; CallFrame *varFramePtr = iPtr->varFramePtr; - int code = TCL_OK; Namespace *savedNsPtr = NULL; Namespace *lookupNsPtr = iPtr->lookupNsPtr; @@ -3729,11 +3786,12 @@ TclEvalObjvInternal( } else { varFramePtr->nsPtr = iPtr->globalNsPtr; } - } else if ((flags & TCL_EVAL_GLOBAL) && (varFramePtr != iPtr->rootFramePtr) - && !savedVarFramePtr) { - varFramePtr = iPtr->rootFramePtr; - savedVarFramePtr = iPtr->varFramePtr; - iPtr->varFramePtr = varFramePtr; + } else if ((flags & TCL_EVAL_GLOBAL) && (varFramePtr != iPtr->rootFramePtr)) { + /* + * Use the full version, so that this one can do optimised tail calls. + */ + + return FullEvalObjvInternal(interp, objc, objv, command, length, flags); } } @@ -3746,65 +3804,23 @@ TclEvalObjvInternal( if (savedNsPtr) { varFramePtr->nsPtr = savedNsPtr; } - - if ((cmdPtr == NULL) || (iPtr->tracePtr != NULL) || - (cmdPtr->flags & CMD_HAS_EXEC_TRACES)) { + + if ((cmdPtr && !iPtr->tracePtr && !(cmdPtr->flags & CMD_HAS_EXEC_TRACES))) { + if (!(flags & TCL_EVAL_INVOKE) && + (iPtr->ensembleRewrite.sourceObjs != NULL)) { + iPtr->ensembleRewrite.sourceObjs = NULL; + } + return TclEvalObjvKnownCommand(interp, objc, objv, cmdPtr); + } else { /* * Need the full version: command is either unknown or traced */ - if (savedVarFramePtr) { - iPtr->varFramePtr = savedVarFramePtr; - } if (lookupNsPtr) { iPtr->lookupNsPtr = lookupNsPtr; } return FullEvalObjvInternal(interp, objc, objv, command, length, flags); } - - /* - * Finally, invoke the command's Tcl_ObjCmdProc. - */ - - cmdPtr->refCount++; - iPtr->cmdCount++; - - if (!TclLimitExceeded(iPtr->limit)) { - if (!(flags & TCL_EVAL_INVOKE) && - (iPtr->ensembleRewrite.sourceObjs != NULL)) { - iPtr->ensembleRewrite.sourceObjs = NULL; - } - code = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv); - } - if (Tcl_AsyncReady()) { - code = Tcl_AsyncInvoke(interp, code); - } - if (code == TCL_OK && TclLimitReady(iPtr->limit)) { - code = Tcl_LimitCheck(interp); - } - - /* - * Decrement the reference count of cmdPtr and deallocate it if it has - * dropped to zero. - */ - - TclCleanupCommandMacro(cmdPtr); - - /* - * If the interpreter has a non-empty string result, the result object is - * either empty or stale because some function 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); - } - - if (savedVarFramePtr) { - iPtr->varFramePtr = savedVarFramePtr; - } - return code; } /* |