summaryrefslogtreecommitdiffstats
path: root/generic
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
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')
-rw-r--r--generic/tclCompCmds.c93
-rw-r--r--generic/tclCompCmdsSZ.c11
-rw-r--r--generic/tclCompile.c160
-rw-r--r--generic/tclCompile.h52
4 files changed, 235 insertions, 81 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
diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c
index 4f4286e..721f59a 100644
--- a/generic/tclCompCmdsSZ.c
+++ b/generic/tclCompCmdsSZ.c
@@ -834,7 +834,7 @@ TclSubstCompile(
}
envPtr->line = bline;
- catchRange = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ catchRange = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, catchRange);
ExceptionRangeStarts(envPtr, catchRange);
@@ -2302,7 +2302,7 @@ IssueTryInstructions(
* (and it's never called when there's a finally clause).
*/
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
BODY( bodyToken, 1);
@@ -2455,7 +2455,7 @@ IssueTryFinallyInstructions(
* (if any trap matches) and run a finally clause.
*/
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
envPtr->currStackDepth = savedStackDepth;
@@ -2522,7 +2522,7 @@ IssueTryFinallyInstructions(
*/
if (resultVars[i] >= 0 || handlerTokens[i]) {
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
}
@@ -2833,7 +2833,7 @@ TclCompileWhileCmd(
* implement break and continue.
*/
- range = DeclareExceptionRange(envPtr, LOOP_EXCEPTION_RANGE);
+ range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
/*
* Jump to the evaluation of the condition. This code uses the "loop
@@ -2917,6 +2917,7 @@ TclCompileWhileCmd(
envPtr->exceptArrayPtr[range].continueOffset = testCodeOffset;
envPtr->exceptArrayPtr[range].codeOffset = bodyCodeOffset;
ExceptionRangeTarget(envPtr, range, breakOffset);
+ TclFinalizeLoopExceptionRange(envPtr, range);
/*
* The while command's result is an empty string.
diff --git a/generic/tclCompile.c b/generic/tclCompile.c
index c56b67f..96f8683 100644
--- a/generic/tclCompile.c
+++ b/generic/tclCompile.c
@@ -1514,7 +1514,7 @@ TclInitCompileEnv(
envPtr->mallocedLiteralArray = 0;
envPtr->exceptArrayPtr = envPtr->staticExceptArraySpace;
- envPtr->exnStackDepthArrayPtr = envPtr->staticExnStackDepthArraySpace;
+ envPtr->exceptAuxArrayPtr = envPtr->staticExAuxArraySpace;
envPtr->exceptArrayNext = 0;
envPtr->exceptArrayEnd = COMPILEENV_INIT_EXCEPT_RANGES;
envPtr->mallocedExceptArray = 0;
@@ -1728,7 +1728,7 @@ TclFreeCompileEnv(
}
if (envPtr->mallocedExceptArray) {
ckfree(envPtr->exceptArrayPtr);
- ckfree(envPtr->exnStackDepthArrayPtr);
+ ckfree(envPtr->exceptAuxArrayPtr);
}
if (envPtr->mallocedCmdMap) {
ckfree(envPtr->cmdMapPtr);
@@ -3413,6 +3413,7 @@ TclCreateExceptRange(
* new ExceptionRange structure. */
{
register ExceptionRange *rangePtr;
+ register ExceptionAux *auxPtr;
int index = envPtr->exceptArrayNext;
if (index >= envPtr->exceptArrayEnd) {
@@ -3424,16 +3425,16 @@ TclCreateExceptRange(
size_t currBytes =
envPtr->exceptArrayNext * sizeof(ExceptionRange);
- size_t currBytes2 = envPtr->exceptArrayNext * sizeof(int);
+ size_t currBytes2 = envPtr->exceptArrayNext * sizeof(ExceptionAux);
int newElems = 2*envPtr->exceptArrayEnd;
size_t newBytes = newElems * sizeof(ExceptionRange);
- size_t newBytes2 = newElems * sizeof(int);
+ size_t newBytes2 = newElems * sizeof(ExceptionAux);
if (envPtr->mallocedExceptArray) {
envPtr->exceptArrayPtr =
ckrealloc(envPtr->exceptArrayPtr, newBytes);
- envPtr->exnStackDepthArrayPtr =
- ckrealloc(envPtr->exnStackDepthArrayPtr, newBytes2);
+ envPtr->exceptAuxArrayPtr =
+ ckrealloc(envPtr->exceptAuxArrayPtr, newBytes2);
} else {
/*
* envPtr->exceptArrayPtr isn't a ckalloc'd pointer, so we must
@@ -3441,12 +3442,12 @@ TclCreateExceptRange(
*/
ExceptionRange *newPtr = ckalloc(newBytes);
- int *newPtr2 = ckalloc(newBytes2);
+ ExceptionAux *newPtr2 = ckalloc(newBytes2);
memcpy(newPtr, envPtr->exceptArrayPtr, currBytes);
- memcpy(newPtr2, envPtr->exnStackDepthArrayPtr, currBytes2);
+ memcpy(newPtr2, envPtr->exceptAuxArrayPtr, currBytes2);
envPtr->exceptArrayPtr = newPtr;
- envPtr->exnStackDepthArrayPtr = newPtr2;
+ envPtr->exceptAuxArrayPtr = newPtr2;
envPtr->mallocedExceptArray = 1;
}
envPtr->exceptArrayEnd = newElems;
@@ -3461,7 +3462,14 @@ TclCreateExceptRange(
rangePtr->breakOffset = -1;
rangePtr->continueOffset = -1;
rangePtr->catchOffset = -1;
- envPtr->exnStackDepthArrayPtr[index] = envPtr->currStackDepth;
+ auxPtr = &envPtr->exceptAuxArrayPtr[index];
+ auxPtr->stackDepth = envPtr->currStackDepth;
+ auxPtr->numBreakTargets = 0;
+ auxPtr->breakTargets = NULL;
+ auxPtr->allocBreakTargets = 0;
+ auxPtr->numContinueTargets = 0;
+ auxPtr->continueTargets = NULL;
+ auxPtr->allocContinueTargets = 0;
return index;
}
@@ -3482,7 +3490,7 @@ TclCreateExceptRange(
ExceptionRange *
TclGetInnermostExceptionRange(
CompileEnv *envPtr,
- int *stackDepthPtr)
+ ExceptionAux **auxPtrPtr)
{
int exnIdx = -1, i;
@@ -3498,12 +3506,122 @@ TclGetInnermostExceptionRange(
if (exnIdx == -1) {
return NULL;
}
- if (stackDepthPtr) {
- *stackDepthPtr = envPtr->exnStackDepthArrayPtr[exnIdx];
+ if (auxPtrPtr) {
+ *auxPtrPtr = &envPtr->exceptAuxArrayPtr[exnIdx];
}
return &envPtr->exceptArrayPtr[exnIdx];
}
+void
+TclAddLoopBreakFixup(
+ CompileEnv *envPtr,
+ ExceptionAux *auxPtr)
+{
+ int range = auxPtr - envPtr->exceptAuxArrayPtr;
+
+ if (envPtr->exceptArrayPtr[range].type != LOOP_EXCEPTION_RANGE) {
+ Tcl_Panic("trying to add 'break' fixup to full exception range");
+ }
+
+ if (++auxPtr->numBreakTargets > auxPtr->allocBreakTargets) {
+ auxPtr->allocBreakTargets *= 2;
+ auxPtr->allocBreakTargets += 2;
+ if (auxPtr->breakTargets) {
+ auxPtr->breakTargets = ckrealloc(auxPtr->breakTargets,
+ sizeof(int) * auxPtr->allocBreakTargets);
+ } else {
+ auxPtr->breakTargets =
+ ckalloc(sizeof(int) * auxPtr->allocBreakTargets);
+ }
+ }
+ auxPtr->breakTargets[auxPtr->numBreakTargets - 1] = CurrentOffset(envPtr);
+}
+
+void
+TclAddLoopContinueFixup(
+ CompileEnv *envPtr,
+ ExceptionAux *auxPtr)
+{
+ int range = auxPtr - envPtr->exceptAuxArrayPtr;
+
+ if (envPtr->exceptArrayPtr[range].type != LOOP_EXCEPTION_RANGE) {
+ Tcl_Panic("trying to add 'continue' fixup to full exception range");
+ }
+
+ if (++auxPtr->numContinueTargets > auxPtr->allocContinueTargets) {
+ auxPtr->allocContinueTargets *= 2;
+ auxPtr->allocContinueTargets += 2;
+ if (auxPtr->continueTargets) {
+ auxPtr->continueTargets = ckrealloc(auxPtr->continueTargets,
+ sizeof(int) * auxPtr->allocContinueTargets);
+ } else {
+ auxPtr->continueTargets =
+ ckalloc(sizeof(int) * auxPtr->allocContinueTargets);
+ }
+ }
+ auxPtr->continueTargets[auxPtr->numContinueTargets - 1] =
+ CurrentOffset(envPtr);
+}
+
+void
+TclFinalizeLoopExceptionRange(
+ CompileEnv *envPtr,
+ int range)
+{
+ ExceptionRange *rangePtr = &envPtr->exceptArrayPtr[range];
+ ExceptionAux *auxPtr = &envPtr->exceptAuxArrayPtr[range];
+ int i, offset;
+ unsigned char *site;
+
+ if (rangePtr->type != LOOP_EXCEPTION_RANGE) {
+ Tcl_Panic("trying to finalize a loop exception range");
+ }
+
+ /*
+ * Do the jump fixups. Note that these are always issued as INST_JUMP4 so
+ * there is no need to fuss around with updating code offsets.
+ */
+
+ for (i=0 ; i<auxPtr->numBreakTargets ; i++) {
+ site = envPtr->codeStart + auxPtr->breakTargets[i];
+ offset = rangePtr->breakOffset - auxPtr->breakTargets[i];
+ TclUpdateInstInt4AtPc(INST_JUMP4, offset, site);
+ }
+ for (i=0 ; i<auxPtr->numContinueTargets ; i++) {
+ site = envPtr->codeStart + auxPtr->continueTargets[i];
+ if (rangePtr->continueOffset == -1) {
+ int j;
+
+ /*
+ * WTF? Can't bind, so revert to an INST_CONTINUE.
+ */
+
+ *site = INST_CONTINUE;
+ for (j=0 ; j<4 ; j++) {
+ *++site = INST_NOP;
+ }
+ } else {
+ offset = rangePtr->continueOffset - auxPtr->continueTargets[i];
+ TclUpdateInstInt4AtPc(INST_JUMP4, offset, site);
+ }
+ }
+
+ /*
+ * Drop the arrays we were holding the only reference to.
+ */
+
+ if (auxPtr->breakTargets) {
+ ckfree(auxPtr->breakTargets);
+ auxPtr->breakTargets = NULL;
+ auxPtr->numBreakTargets = 0;
+ }
+ if (auxPtr->continueTargets) {
+ ckfree(auxPtr->continueTargets);
+ auxPtr->continueTargets = NULL;
+ auxPtr->numContinueTargets = 0;
+ }
+}
+
/*
*----------------------------------------------------------------------
*
@@ -3864,6 +3982,22 @@ TclFixupForwardJump(
}
}
+ for (k = 0 ; k < envPtr->exceptArrayNext ; k++) {
+ ExceptionAux *auxPtr = &envPtr->exceptAuxArrayPtr[k];
+ int i;
+
+ for (i=0 ; i<auxPtr->numBreakTargets ; i++) {
+ if (jumpFixupPtr->codeOffset < auxPtr->breakTargets[i]) {
+ auxPtr->breakTargets[i] += 3;
+ }
+ }
+ for (i=0 ; i<auxPtr->numContinueTargets ; i++) {
+ if (jumpFixupPtr->codeOffset < auxPtr->continueTargets[i]) {
+ auxPtr->continueTargets[i] += 3;
+ }
+ }
+ }
+
/*
* TIP #280: Adjust the mapping from PC values to the per-command
* information about arguments and their line numbers.
diff --git a/generic/tclCompile.h b/generic/tclCompile.h
index c9cbbd4..8430da3 100644
--- a/generic/tclCompile.h
+++ b/generic/tclCompile.h
@@ -100,6 +100,38 @@ typedef struct ExceptionRange {
} ExceptionRange;
/*
+ * Auxiliary data used when issuing (currently just loop) exception ranges,
+ * but which is not required during execution.
+ */
+
+typedef struct ExceptionAux {
+ int stackDepth; /* The stack depth at the point where the
+ * exception range was created. This is used
+ * to calculate the number of POPs required to
+ * restore the stack to its prior state. */
+ int numBreakTargets; /* The number of [break]s that want to be
+ * targeted to the place where this loop
+ * exception will be bound to. */
+ int *breakTargets; /* The offsets of the INST_JUMP4 instructions
+ * issued by the [break]s that we must
+ * update. Note that resizing a jump (via
+ * TclFixupForwardJump) can cause the contents
+ * of this array to be updated. When
+ * numBreakTargets==0, this is NULL. */
+ int allocBreakTargets; /* The size of the breakTargets array. */
+ int numContinueTargets; /* The number of [continue]s that want to be
+ * targeted to the place where this loop
+ * exception will be bound to. */
+ int *continueTargets; /* The offsets of the INST_JUMP4 instructions
+ * issued by the [continue]s that we must
+ * update. Note that resizing a jump (via
+ * TclFixupForwardJump) can cause the contents
+ * of this array to be updated. When
+ * numContinueTargets==0, this is NULL. */
+ int allocContinueTargets; /* The size of the continueTargets array. */
+} ExceptionAux;
+
+/*
* Structure used to map between instruction pc and source locations. It
* defines for each compiled Tcl command its code's starting offset and its
* source's starting offset and length. Note that the code offset increases
@@ -275,9 +307,11 @@ typedef struct CompileEnv {
* entry. */
int mallocedExceptArray; /* 1 if ExceptionRange array was expanded and
* exceptArrayPtr points in heap, else 0. */
- int *exnStackDepthArrayPtr; /* Array of stack depths to restore to when
- * processing BREAK/CONTINUE exceptions. Must
- * be the same size as the exceptArrayPtr. */
+ ExceptionAux *exceptAuxArrayPtr;
+ /* Array of information used to restore the
+ * state when processing BREAK/CONTINUE
+ * exceptions. Must be the same size as the
+ * exceptArrayPtr. */
CmdLocation *cmdMapPtr; /* Points to start of CmdLocation array.
* numCommands is the index of the next entry
* to use; (numCommands-1) is the entry index
@@ -299,8 +333,8 @@ typedef struct CompileEnv {
/* Initial storage of LiteralEntry array. */
ExceptionRange staticExceptArraySpace[COMPILEENV_INIT_EXCEPT_RANGES];
/* Initial ExceptionRange array storage. */
- int staticExnStackDepthArraySpace[COMPILEENV_INIT_EXCEPT_RANGES];
- /* Initial static except stack depth array
+ ExceptionAux staticExAuxArraySpace[COMPILEENV_INIT_EXCEPT_RANGES];
+ /* Initial static except auxiliary info array
* storage. */
CmdLocation staticCmdMapSpace[COMPILEENV_INIT_CMD_MAP_SIZE];
/* Initial storage for cmd location map. */
@@ -995,7 +1029,13 @@ MODULE_SCOPE void TclInitCompileEnv(Tcl_Interp *interp,
MODULE_SCOPE void TclInitJumpFixupArray(JumpFixupArray *fixupArrayPtr);
MODULE_SCOPE void TclInitLiteralTable(LiteralTable *tablePtr);
MODULE_SCOPE ExceptionRange *TclGetInnermostExceptionRange(CompileEnv *envPtr,
- int *depthPtr);
+ ExceptionAux **auxPtrPtr);
+MODULE_SCOPE void TclAddLoopBreakFixup(CompileEnv *envPtr,
+ ExceptionAux *auxPtr);
+MODULE_SCOPE void TclAddLoopContinueFixup(CompileEnv *envPtr,
+ ExceptionAux *auxPtr);
+MODULE_SCOPE void TclFinalizeLoopExceptionRange(CompileEnv *envPtr,
+ int range);
#ifdef TCL_COMPILE_STATS
MODULE_SCOPE char * TclLiteralStats(LiteralTable *tablePtr);
MODULE_SCOPE int TclLog2(int value);