summaryrefslogtreecommitdiffstats
path: root/generic/tclCompCmds.c
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2013-06-02 17:41:14 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2013-06-02 17:41:14 (GMT)
commit8bd69e27f28e6a4927f6df9aacd29694d76c0dca (patch)
tree031fbf3482af67639284aac14150444c47c4b331 /generic/tclCompCmds.c
parentd09727e7ff46a2abd069caac727159c92f6c9436 (diff)
downloadtcl-8bd69e27f28e6a4927f6df9aacd29694d76c0dca.zip
tcl-8bd69e27f28e6a4927f6df9aacd29694d76c0dca.tar.gz
tcl-8bd69e27f28e6a4927f6df9aacd29694d76c0dca.tar.bz2
Many improvements to code generation of efficient break and continue.
Diffstat (limited to 'generic/tclCompCmds.c')
-rw-r--r--generic/tclCompCmds.c93
1 files changed, 36 insertions, 57 deletions
diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c
index 6e5d187..f2d2963 100644
--- a/generic/tclCompCmds.c
+++ b/generic/tclCompCmds.c
@@ -480,8 +480,8 @@ TclCompileBreakCmd(
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
- int depth;
ExceptionRange *rangePtr;
+ ExceptionAux *auxPtr;
if (parsePtr->numWords != 1) {
return TCL_ERROR;
@@ -491,9 +491,9 @@ TclCompileBreakCmd(
* Find the innermost exception range that contains this command.
*/
- rangePtr = TclGetInnermostExceptionRange(envPtr, &depth);
+ rangePtr = TclGetInnermostExceptionRange(envPtr, &auxPtr);
if (rangePtr && rangePtr->type == LOOP_EXCEPTION_RANGE) {
- int toPop = envPtr->currStackDepth - depth;
+ int toPop = envPtr->currStackDepth - auxPtr->stackDepth;
/*
* Pop off the extra stack frames.
@@ -501,26 +501,18 @@ TclCompileBreakCmd(
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
+ toPop--;
}
- if (envPtr->expandCount == 0 && rangePtr->breakOffset != -1) {
- int offset = (rangePtr->breakOffset - CurrentOffset(envPtr));
-
+ if (envPtr->expandCount == 0) {
/*
* Found the target! Also, no built-up expansion stack. No need
* for a nasty INST_BREAK here.
*/
- TclEmitInstInt4(INST_JUMP4, offset, envPtr);
+ TclAddLoopBreakFixup(envPtr, auxPtr);
+ TclEmitInstInt4(INST_JUMP4, 0, envPtr);
goto done;
}
}
@@ -532,14 +524,12 @@ TclCompileBreakCmd(
TclEmitOpcode(INST_BREAK, envPtr);
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.
+ * Instructions that raise exceptions don't really have to follow the
+ * usual stack management rules, but the cleanup code does.
*/
+
TclAdjustStackDepth(1, envPtr);
-#endif
return TCL_OK;
}
@@ -645,7 +635,7 @@ TclCompileCatchCmd(
* uses.
*/
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
/*
* If the body is a simple word, compile a BEGIN_CATCH instruction,
@@ -833,8 +823,8 @@ TclCompileContinueCmd(
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
- int depth;
ExceptionRange *rangePtr;
+ ExceptionAux *auxPtr;
/*
* There should be no argument after the "continue".
@@ -849,9 +839,9 @@ TclCompileContinueCmd(
* innermost containing exception range.
*/
- rangePtr = TclGetInnermostExceptionRange(envPtr, &depth);
+ rangePtr = TclGetInnermostExceptionRange(envPtr, &auxPtr);
if (rangePtr && rangePtr->type == LOOP_EXCEPTION_RANGE) {
- int toPop = envPtr->currStackDepth - depth;
+ int toPop = envPtr->currStackDepth - auxPtr->stackDepth;
/*
* Pop off the extra stack frames.
@@ -859,26 +849,18 @@ TclCompileContinueCmd(
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
+ toPop--;
}
- if (envPtr->expandCount == 0 && rangePtr->continueOffset != -1) {
- int offset = (rangePtr->continueOffset - CurrentOffset(envPtr));
-
+ if (envPtr->expandCount == 0) {
/*
* Found the target! Also, no built-up expansion stack. No need
* for a nasty INST_CONTINUE here.
*/
- TclEmitInstInt4(INST_JUMP4, offset, envPtr);
+ TclAddLoopContinueFixup(envPtr, auxPtr);
+ TclEmitInstInt4(INST_JUMP4, 0, envPtr);
goto done;
}
}
@@ -890,14 +872,12 @@ TclCompileContinueCmd(
TclEmitOpcode(INST_CONTINUE, envPtr);
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.
+ * Instructions that raise exceptions don't really have to follow the
+ * usual stack management rules, but the cleanup code does.
*/
+
TclAdjustStackDepth(1, envPtr);
-#endif
return TCL_OK;
}
@@ -1350,7 +1330,7 @@ TclCompileDictMergeCmd(
* For each of the remaining dictionaries...
*/
- outLoop = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ outLoop = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
TclEmitInstInt4( INST_BEGIN_CATCH4, outLoop, envPtr);
ExceptionRangeStarts(envPtr, outLoop);
for (i=2 ; i<parsePtr->numWords ; i++) {
@@ -1563,7 +1543,7 @@ CompileDictEachCmd(
* started by Tcl_DictObjFirst above.
*/
- catchRange = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ catchRange = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
TclEmitInstInt4( INST_BEGIN_CATCH4, catchRange, envPtr);
ExceptionRangeStarts(envPtr, catchRange);
@@ -1581,7 +1561,7 @@ CompileDictEachCmd(
* Set up the loop exception targets.
*/
- loopRange = DeclareExceptionRange(envPtr, LOOP_EXCEPTION_RANGE);
+ loopRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
ExceptionRangeStarts(envPtr, loopRange);
/*
@@ -1629,6 +1609,7 @@ CompileDictEachCmd(
*/
ExceptionRangeTarget(envPtr, loopRange, breakOffset);
+ TclFinalizeLoopExceptionRange(envPtr, loopRange);
TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
TclEmitInt4( infoIndex, envPtr);
TclEmitOpcode( INST_END_CATCH, envPtr);
@@ -1807,7 +1788,7 @@ TclCompileDictUpdateCmd(
TclEmitInstInt4( INST_DICT_UPDATE_START, dictIndex, envPtr);
TclEmitInt4( infoIndex, envPtr);
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr);
ExceptionRangeStarts(envPtr, range);
@@ -2164,7 +2145,7 @@ TclCompileDictWithCmd(
* Now the body of the [dict with].
*/
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr);
ExceptionRangeStarts(envPtr, range);
@@ -2446,15 +2427,6 @@ TclCompileForCmd(
}
/*
- * Create ExceptionRange records for the body and the "next" command. The
- * "next" command's ExceptionRange supports break but not continue (and
- * has a -1 continueOffset).
- */
-
- bodyRange = DeclareExceptionRange(envPtr, LOOP_EXCEPTION_RANGE);
- nextRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
-
- /*
* Inline compile the initial command.
*/
@@ -2480,6 +2452,7 @@ TclCompileForCmd(
* Compile the loop body.
*/
+ bodyRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
bodyCodeOffset = ExceptionRangeStarts(envPtr, bodyRange);
SetLineInformation(4);
CompileBody(envPtr, bodyTokenPtr, interp);
@@ -2488,9 +2461,12 @@ TclCompileForCmd(
TclEmitOpcode(INST_POP, envPtr);
/*
- * Compile the "next" subcommand.
+ * Compile the "next" subcommand. Note that this exception range will not
+ * have a continueOffset (other than -1) connected to it; it won't trap
+ * TCL_CONTINUE but rather just TCL_BREAK.
*/
+ nextRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
envPtr->currStackDepth = savedStackDepth;
nextCodeOffset = ExceptionRangeStarts(envPtr, nextRange);
SetLineInformation(3);
@@ -2538,6 +2514,8 @@ TclCompileForCmd(
ExceptionRangeTarget(envPtr, bodyRange, breakOffset);
ExceptionRangeTarget(envPtr, nextRange, breakOffset);
+ TclFinalizeLoopExceptionRange(envPtr, bodyRange);
+ TclFinalizeLoopExceptionRange(envPtr, nextRange);
/*
* The for command's result is an empty string.
@@ -2829,7 +2807,7 @@ CompileEachloopCmd(
* Create an exception record to handle [break] and [continue].
*/
- range = DeclareExceptionRange(envPtr, LOOP_EXCEPTION_RANGE);
+ range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
/*
* Evaluate then store each value list in the associated temporary.
@@ -2935,6 +2913,7 @@ CompileEachloopCmd(
*/
ExceptionRangeTarget(envPtr, range, breakOffset);
+ TclFinalizeLoopExceptionRange(envPtr, range);
/*
* The command's result is an empty string if not collecting, or the