summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2013-06-01 21:05:55 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2013-06-01 21:05:55 (GMT)
commitd09727e7ff46a2abd069caac727159c92f6c9436 (patch)
treef513d78c6d5a0417959e2f49d777012a853850e7 /generic
parent8d03d462d4d27ee4a2d6fec72a8d2efe9e90f94a (diff)
downloadtcl-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.c113
-rw-r--r--generic/tclCompile.c42
-rw-r--r--generic/tclCompile.h6
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);