diff options
author | andreas_kupries <akupries@shaw.ca> | 2009-07-14 16:34:08 (GMT) |
---|---|---|
committer | andreas_kupries <akupries@shaw.ca> | 2009-07-14 16:34:08 (GMT) |
commit | 08604cad04da0d67c84406f99bda814f6a416386 (patch) | |
tree | 96331345b305a3ee61ad9c1dfa7f37983ab71540 /generic/tclExecute.c | |
parent | 02457f7d6507f76fac8b308899e6592ab8214cb3 (diff) | |
download | tcl-08604cad04da0d67c84406f99bda814f6a416386.zip tcl-08604cad04da0d67c84406f99bda814f6a416386.tar.gz tcl-08604cad04da0d67c84406f99bda814f6a416386.tar.bz2 |
* generic/tclCompile.c (TclInitCompileEnv, EnterCmdWordIndex,
TclCleanupByteCode, TclCompileScript):
* generic/tclExecute.c (TclCompileObj, TclExecuteByteCode):
* tclCompile.h (ExtCmdLoc):
* tclInt.h (ExtIndex, CFWordBC, CmdFrame):
* tclBasic.c (DeleteInterpProc, TclArgumentBCEnter,
TclArgumentBCRelease, TclArgumentGet, SAVE_CONTEXT,
RESTORE_CONTEXT, NRCoroutineExitCallback, TclNRCoroutineObjCmd):
* generic/tclCmdAH.c (TclNRForObjCmd, TclNRForIterCallback,
ForNextCallback):
* generic/tclCmdMZ.c (TclNRWhileObjCmd):
Extended the bytecode compiler initialization to recognize the
compilation of whole files (NRE enabled 'source' command) and
switch to the counting of absolute lines in that case.
Further extended the bytecode compiler to track the start line in
the generated information, and modified the bytecode execution to
recompile an object if the location as per the calling context
doesn't match the location saved in the bytecode. This part could
be optimized more by using more memory to keep all possibilities
which occur around, or by just adjusting the location information
instead of a total recompile.
Reworked the handling of literal command arguments in bytecode to
be saved (compiler) and used (execution) per command (See the
TCL_INVOKE_STK* instructions), and not per the whole bytecode.
This, and the previous change remove the problems with location
data caused by literal sharing (across whole files, but also proc
bodies). Simplified the associated datastructures (ExtIndex is
gone, as is the function EnterCmdWordIndex).
The last change causes the hashtable 'lineLABCPtr' to be state
which has to be kept per coroutine, like the CmdFrame stack.
Reworked the coroutine support code to create, delete and switch
the information as needed. Further reworked the tailcall command
as well, it has to pop its own arguments when run in a bytecode
context to keep a proper stack in 'lineLABCPtr'.
Fixed the mishandling of line information in the NRE-enabled 'for'
and 'while' commands introduced when both were made to share their
iteration callbacks without taking into account that the loop body
is found in different words of the command. Introduced a separate
data structure to hold all the callback information, as we went
over the limit of 4 direct client-data values for NRE callbacks.
The above fixes [Bug 1605269].
Diffstat (limited to 'generic/tclExecute.c')
-rw-r--r-- | generic/tclExecute.c | 100 |
1 files changed, 94 insertions, 6 deletions
diff --git a/generic/tclExecute.c b/generic/tclExecute.c index aac36da..5139dad 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -14,7 +14,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclExecute.c,v 1.440 2009/07/12 18:04:33 dkf Exp $ + * RCS: @(#) $Id: tclExecute.c,v 1.441 2009/07/14 16:34:08 andreas_kupries Exp $ */ #include "tclInt.h" @@ -1517,6 +1517,91 @@ TclCompileObj( } /* + * #280. + * Literal sharing fix. This part of the fix is not required by 8.4 + * nor 8.5, because they eval-direct any literals, so just saving the + * argument locations per command in bytecode is enough, embedded + * 'eval' commands, etc. get the correct information. + * + * But in 8.6 all the embedded script are compiled, and the resulting + * bytecode stored in the literal. Now the shared literal has bytecode + * with location data for _one_ particular location this literal is + * found at. If we get executed from a different location the bytecode + * has to be recompiled to get the correct locations. Not doing this + * will execute the saved bytecode with data for a different location, + * causing 'info frame' to point to the wrong place in the sources. + * + * Future optimizations ... + * (1) Save the location data (ExtCmdLoc) keyed by start line. In that + * case we recompile once per location of the literal, but not + * continously, because the moment we have all locations we do not + * need to recompile any longer. + * + * (2) Alternative: Do not recompile, tell the execution engine the + * offset between saved starting line and actual one. Then modify + * the users to adjust the locations they have by this offset. + * + * (3) Alternative 2: Do not fully recompile, adjust just the location + * information. + */ + + { + Tcl_HashEntry *hePtr = Tcl_FindHashEntry(iPtr->lineBCPtr, + (char *) codePtr); + if (hePtr) { + ExtCmdLoc *eclPtr = Tcl_GetHashValue(hePtr); + int redo = 0; + + if (invoker) { + CmdFrame *ctxPtr = (CmdFrame *) + TclStackAlloc(interp, sizeof(CmdFrame)); + *ctxPtr = *invoker; + + if (invoker->type == TCL_LOCATION_BC) { + /* + * Note: Type BC => ctx.data.eval.path is not used. + * ctx.data.tebc.codePtr is used instead. + */ + + TclGetSrcInfoForPc(ctxPtr); + if (ctxPtr->type == TCL_LOCATION_SOURCE) { + /* + * The reference made by 'TclGetSrcInfoForPc' is dead. + */ + Tcl_DecrRefCount(ctxPtr->data.eval.path); + ctxPtr->data.eval.path = NULL; + } + } + + if (word < ctxPtr->nline) { + /* + * Note: We do not care if the line[word] is -1. This + * is a difference and requires a recompile (location + * changed from absolute to relative, literal is used + * fixed and through variable) + * + * Example: + * test info-32.0 using literal of info-24.8 + * (dict with ... vs set body ...). + */ + redo = + ((eclPtr->type == TCL_LOCATION_SOURCE) && + (eclPtr->start != ctxPtr->line[word])) || + ((eclPtr->type == TCL_LOCATION_BC) && + (ctxPtr->type == TCL_LOCATION_SOURCE)) + ; + } + + TclStackFree(interp, ctxPtr); + } + + if (redo) { + goto recompileObj; + } + } + } + + /* * Increment the code's ref count while it is being executed. If * afterwards no references to it remain, free the code. */ @@ -1940,14 +2025,12 @@ TclExecuteByteCode( bcFramePtr->nextPtr = iPtr->cmdFramePtr; bcFramePtr->nline = 0; bcFramePtr->line = NULL; - + bcFramePtr->litarg = NULL; bcFramePtr->data.tebc.codePtr = codePtr; bcFramePtr->data.tebc.pc = NULL; bcFramePtr->cmd.str.cmd = NULL; bcFramePtr->cmd.str.len = 0; - TclArgumentBCEnter((Tcl_Interp*) iPtr,codePtr,bcFramePtr); - if (iPtr->execEnvPtr->rewind) { result = TCL_ERROR; goto abnormalReturn; @@ -1962,6 +2045,8 @@ TclExecuteByteCode( NRE_ASSERT(iPtr->cmdFramePtr == bcFramePtr); iPtr->cmdFramePtr = bcFramePtr->nextPtr; + TclArgumentBCRelease((Tcl_Interp*) iPtr, bcFramePtr); + /* * If the CallFrame is marked as tailcalling, keep tailcalling */ @@ -2760,6 +2845,9 @@ TclExecuteByteCode( instructionCount = 1; + TclArgumentBCEnter((Tcl_Interp*) iPtr, objv, objc, + codePtr, bcFramePtr, pc - codePtr->codeStart); + DECACHE_STACK_INFO(); result = TclNREvalObjv(interp, objc, objv, @@ -2773,6 +2861,8 @@ TclExecuteByteCode( goto nonRecursiveCallStart; } + TclArgumentBCRelease((Tcl_Interp*) iPtr, bcFramePtr); + iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr; NRE_ASSERT(iPtr->cmdFramePtr == bcFramePtr->nextPtr); @@ -7794,8 +7884,6 @@ TclExecuteByteCode( } } - TclArgumentBCRelease((Tcl_Interp*) iPtr,codePtr); - oldBottomPtr = bottomPtr->prevBottomPtr; iPtr->cmdFramePtr = bcFramePtr->nextPtr; TclStackFree(interp, bottomPtr); /* free my stack */ |