diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2013-06-01 21:05:55 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2013-06-01 21:05:55 (GMT) |
commit | d09727e7ff46a2abd069caac727159c92f6c9436 (patch) | |
tree | f513d78c6d5a0417959e2f49d777012a853850e7 /generic | |
parent | 8d03d462d4d27ee4a2d6fec72a8d2efe9e90f94a (diff) | |
download | tcl-d09727e7ff46a2abd069caac727159c92f6c9436.zip tcl-d09727e7ff46a2abd069caac727159c92f6c9436.tar.gz tcl-d09727e7ff46a2abd069caac727159c92f6c9436.tar.bz2 |
Getting better at doing more efficient break/continue instruction handling.
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclCompCmds.c | 113 | ||||
-rw-r--r-- | generic/tclCompile.c | 42 | ||||
-rw-r--r-- | generic/tclCompile.h | 6 |
3 files changed, 111 insertions, 50 deletions
diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 1f99a22..6e5d187 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -480,7 +480,7 @@ TclCompileBreakCmd( * compiled. */ CompileEnv *envPtr) /* Holds resulting instructions. */ { - int i, exnIdx; + int depth; ExceptionRange *rangePtr; if (parsePtr->numWords != 1) { @@ -488,33 +488,40 @@ TclCompileBreakCmd( } /* - * Find the innermost exception range that contains this command. Relies - * on the fact that the range has a numCodeBytes = -1 when it is being - * populated and that inner ranges come after outer ranges. + * Find the innermost exception range that contains this command. */ - exnIdx = -1; - for (i=0 ; i<envPtr->exceptArrayNext ; i++) { - rangePtr = &envPtr->exceptArrayPtr[i]; - if (envPtr->codeStart+rangePtr->codeOffset <= envPtr->codeNext - && rangePtr->numCodeBytes == -1) { - exnIdx = i; + rangePtr = TclGetInnermostExceptionRange(envPtr, &depth); + if (rangePtr && rangePtr->type == LOOP_EXCEPTION_RANGE) { + int toPop = envPtr->currStackDepth - depth; + + /* + * Pop off the extra stack frames. + */ + + while (toPop > 0) { + TclEmitOpcode(INST_POP, envPtr); + toPop--; +#ifdef TCL_COMPILE_DEBUG + /* + * Instructions that raise exceptions don't really have to follow + * the usual stack management rules. But the checker wants them + * followed, so lie about stack usage to make it happy. + */ + TclAdjustStackDepth(1, envPtr); +#endif } - } - if (exnIdx != -1) { - rangePtr = &envPtr->exceptArrayPtr[exnIdx]; - if (rangePtr->type == LOOP_EXCEPTION_RANGE) { - int toPop = envPtr->currStackDepth - - envPtr->exnStackDepthArrayPtr[exnIdx]; + + if (envPtr->expandCount == 0 && rangePtr->breakOffset != -1) { + int offset = (rangePtr->breakOffset - CurrentOffset(envPtr)); /* - * Pop off the extra stack frames. + * Found the target! Also, no built-up expansion stack. No need + * for a nasty INST_BREAK here. */ - while (toPop > 0) { - TclEmitOpcode(INST_POP, envPtr); - toPop--; - } + TclEmitInstInt4(INST_JUMP4, offset, envPtr); + goto done; } } @@ -523,6 +530,8 @@ TclCompileBreakCmd( */ TclEmitOpcode(INST_BREAK, envPtr); + + done: #ifdef TCL_COMPILE_DEBUG /* * Instructions that raise exceptions don't really have to follow @@ -824,7 +833,7 @@ TclCompileContinueCmd( * compiled. */ CompileEnv *envPtr) /* Holds resulting instructions. */ { - int i, exnIdx; + int depth; ExceptionRange *rangePtr; /* @@ -837,45 +846,40 @@ TclCompileContinueCmd( /* * See if we can find a valid continueOffset (i.e., not -1) in the - * innermost containing exception range. Relies on the fact that the range - * has a numCodeBytes = -1 when it is being populated and that inner - * ranges come after outer ranges. + * innermost containing exception range. */ - exnIdx = -1; - for (i=0 ; i<envPtr->exceptArrayNext ; i++) { - rangePtr = &envPtr->exceptArrayPtr[i]; - if (envPtr->codeStart+rangePtr->codeOffset <= envPtr->codeNext - && rangePtr->numCodeBytes == -1) { - exnIdx = i; - } - } - if (exnIdx >= 0) { - rangePtr = &envPtr->exceptArrayPtr[exnIdx]; - if (rangePtr->type == LOOP_EXCEPTION_RANGE) { - int toPop = envPtr->currStackDepth - - envPtr->exnStackDepthArrayPtr[exnIdx]; + rangePtr = TclGetInnermostExceptionRange(envPtr, &depth); + if (rangePtr && rangePtr->type == LOOP_EXCEPTION_RANGE) { + int toPop = envPtr->currStackDepth - depth; + + /* + * Pop off the extra stack frames. + */ + while (toPop > 0) { + TclEmitOpcode(INST_POP, envPtr); + toPop--; +#ifdef TCL_COMPILE_DEBUG /* - * Pop off the extra stack frames. + * Instructions that raise exceptions don't really have to follow + * the usual stack management rules. But the checker wants them + * followed, so lie about stack usage to make it happy. */ - - while (toPop > 0) { - TclEmitOpcode(INST_POP, envPtr); - toPop--; - } + TclAdjustStackDepth(1, envPtr); +#endif } - if (rangePtr->type == LOOP_EXCEPTION_RANGE - && rangePtr->continueOffset != -1) { + + if (envPtr->expandCount == 0 && rangePtr->continueOffset != -1) { int offset = (rangePtr->continueOffset - CurrentOffset(envPtr)); /* - * Found the target! No need for a nasty INST_CONTINUE here. + * Found the target! Also, no built-up expansion stack. No need + * for a nasty INST_CONTINUE here. */ TclEmitInstInt4(INST_JUMP4, offset, envPtr); - PushStringLiteral(envPtr, ""); /* Evil hack! */ - return TCL_OK; + goto done; } } @@ -884,7 +888,16 @@ TclCompileContinueCmd( */ TclEmitOpcode(INST_CONTINUE, envPtr); - PushStringLiteral(envPtr, ""); /* Evil hack! */ + + done: +#ifdef TCL_COMPILE_DEBUG + /* + * Instructions that raise exceptions don't really have to follow + * the usual stack management rules. But the checker wants them + * followed, so lie about stack usage to make it happy. + */ + TclAdjustStackDepth(1, envPtr); +#endif return TCL_OK; } diff --git a/generic/tclCompile.c b/generic/tclCompile.c index 54946ee..c56b67f 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -1523,6 +1523,7 @@ TclInitCompileEnv( envPtr->cmdMapEnd = COMPILEENV_INIT_CMD_MAP_SIZE; envPtr->mallocedCmdMap = 0; envPtr->atCmdStart = 1; + envPtr->expandCount = 0; /* * TIP #280: Set up the extended command location information, based on @@ -2060,6 +2061,7 @@ TclCompileScript( if (expand) { TclEmitOpcode(INST_EXPAND_START, envPtr); + envPtr->expandCount++; } /* @@ -2279,6 +2281,7 @@ TclCompileScript( */ TclEmitOpcode(INST_INVOKE_EXPANDED, envPtr); + envPtr->expandCount--; TclAdjustStackDepth(1 - wordIdx, envPtr); } else if (wordIdx > 0) { /* @@ -3463,6 +3466,45 @@ TclCreateExceptRange( } /* + * --------------------------------------------------------------------- + * + * TclGetInnermostExceptionRange -- + * + * Returns the innermost exception range that covers the current code + * creation point, and (optionally) the stack depth that is expected at + * that point. Relies on the fact that the range has a numCodeBytes = -1 + * when it is being populated and that inner ranges come after outer + * ranges. + * + * --------------------------------------------------------------------- + */ + +ExceptionRange * +TclGetInnermostExceptionRange( + CompileEnv *envPtr, + int *stackDepthPtr) +{ + int exnIdx = -1, i; + + for (i=0 ; i<envPtr->exceptArrayNext ; i++) { + ExceptionRange *rangePtr = &envPtr->exceptArrayPtr[i]; + + if (CurrentOffset(envPtr) >= rangePtr->codeOffset && + (rangePtr->numCodeBytes == -1 || CurrentOffset(envPtr) < + rangePtr->codeOffset+rangePtr->numCodeBytes)) { + exnIdx = i; + } + } + if (exnIdx == -1) { + return NULL; + } + if (stackDepthPtr) { + *stackDepthPtr = envPtr->exnStackDepthArrayPtr[exnIdx]; + } + return &envPtr->exceptArrayPtr[exnIdx]; +} + +/* *---------------------------------------------------------------------- * * TclCreateAuxData -- diff --git a/generic/tclCompile.h b/generic/tclCompile.h index c380823..c9cbbd4 100644 --- a/generic/tclCompile.h +++ b/generic/tclCompile.h @@ -318,6 +318,10 @@ typedef struct CompileEnv { * inefficient. If set to 2, that instruction * should not be issued at all (by the generic * part of the command compiler). */ + int expandCount; /* Number of INST_EXPAND_START instructions + * encountered that have not yet been paired + * with a corresponding + * INST_INVOKE_EXPANDED. */ ContLineLoc *clLoc; /* If not NULL, the table holding the * locations of the invisible continuation * lines in the input script, to adjust the @@ -990,6 +994,8 @@ MODULE_SCOPE void TclInitCompileEnv(Tcl_Interp *interp, int numBytes, const CmdFrame *invoker, int word); MODULE_SCOPE void TclInitJumpFixupArray(JumpFixupArray *fixupArrayPtr); MODULE_SCOPE void TclInitLiteralTable(LiteralTable *tablePtr); +MODULE_SCOPE ExceptionRange *TclGetInnermostExceptionRange(CompileEnv *envPtr, + int *depthPtr); #ifdef TCL_COMPILE_STATS MODULE_SCOPE char * TclLiteralStats(LiteralTable *tablePtr); MODULE_SCOPE int TclLog2(int value); |