summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormig <mig>2013-12-23 11:28:12 (GMT)
committermig <mig>2013-12-23 11:28:12 (GMT)
commit3b06f70775be10c7547c05c27e55d4ef0a65ee0c (patch)
tree24228faa92eef9ebab05dc24c7c6a8bd63aeb9ae
parent4c7d267ddb333ab1d5b6caddfdd8803def611dd0 (diff)
downloadtcl-3b06f70775be10c7547c05c27e55d4ef0a65ee0c.zip
tcl-3b06f70775be10c7547c05c27e55d4ef0a65ee0c.tar.gz
tcl-3b06f70775be10c7547c05c27e55d4ef0a65ee0c.tar.bz2
Added new tools for managing and verifying the stack depth during compilation. Used it in some spots in the compiler and in TclCompileCatchCommand.
-rw-r--r--generic/tclCompCmds.c10
-rw-r--r--generic/tclCompile.c34
-rw-r--r--generic/tclCompile.h15
3 files changed, 48 insertions, 11 deletions
diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c
index c774a5e..323aa87 100644
--- a/generic/tclCompCmds.c
+++ b/generic/tclCompCmds.c
@@ -532,7 +532,8 @@ TclCompileCatchCmd(
Tcl_Token *cmdTokenPtr, *resultNameTokenPtr, *optsNameTokenPtr;
int resultIndex, optsIndex, range, dropScript = 0;
DefineLineInformation; /* TIP #280 */
-
+ int depth = TclGetStackDepth(envPtr);
+
/*
* If syntax does not match what we expect for [catch], do not compile.
* Let runtime checks determine if syntax has changed.
@@ -611,11 +612,13 @@ TclCompileCatchCmd(
}
ExceptionRangeEnds(envPtr, range);
+
/*
* Emit the "no errors" epilogue: push "0" (TCL_OK) as the catch result,
* and jump around the "error case" code.
*/
+ TclCheckStackDepth(depth+1, envPtr);
PushStringLiteral(envPtr, "0");
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
@@ -624,12 +627,14 @@ TclCompileCatchCmd(
* return code.
*/
- TclAdjustStackDepth(-2 + dropScript, envPtr);
ExceptionRangeTarget(envPtr, range, catchOffset);
+ TclSetStackDepth(depth + dropScript, envPtr);
+
if (dropScript) {
TclEmitOpcode( INST_POP, envPtr);
}
+
/* Stack at this point is empty */
TclEmitOpcode( INST_PUSH_RESULT, envPtr);
TclEmitOpcode( INST_PUSH_RETURN_CODE, envPtr);
@@ -678,6 +683,7 @@ TclCompileCatchCmd(
}
TclEmitOpcode( INST_POP, envPtr);
+ TclCheckStackDepth(depth+1, envPtr);
return TCL_OK;
}
diff --git a/generic/tclCompile.c b/generic/tclCompile.c
index 525571d..f3e9db3 100644
--- a/generic/tclCompile.c
+++ b/generic/tclCompile.c
@@ -1722,7 +1722,7 @@ TclCompileInvocation(
int numWords,
CompileEnv *envPtr)
{
- int wordIdx = 0;
+ int wordIdx = 0, depth = TclGetStackDepth(envPtr);
DefineLineInformation;
if (cmdObj) {
@@ -1755,6 +1755,7 @@ TclCompileInvocation(
} else {
TclEmitInvoke(envPtr, INST_INVOKE_STK4, wordIdx);
}
+ TclCheckStackDepth(depth+1, envPtr);
}
static void
@@ -1767,7 +1768,8 @@ CompileExpanded(
{
int wordIdx = 0;
DefineLineInformation;
-
+ int depth = TclGetStackDepth(envPtr);
+
StartExpanding(envPtr);
if (cmdObj) {
CompileCmdLiteral(interp, cmdObj, envPtr);
@@ -1813,6 +1815,7 @@ CompileExpanded(
*/
TclEmitInvoke(envPtr, INST_INVOKE_EXPANDED, wordIdx);
+ TclCheckStackDepth(depth+1, envPtr);
}
static int
@@ -1824,6 +1827,7 @@ CompileCmdCompileProc(
{
int unwind = 0, incrOffset = -1;
DefineLineInformation;
+ int depth = TclGetStackDepth(envPtr);
/*
* Emit of the INST_START_CMD instruction is controlled by the value of
@@ -1871,6 +1875,7 @@ CompileCmdCompileProc(
TclStoreInt4AtPtr(envPtr->codeNext - startPtr, startPtr + 1);
}
}
+ TclCheckStackDepth(depth+1, envPtr);
return TCL_OK;
}
@@ -1913,7 +1918,8 @@ CompileCommandTokens(
int *clNext = envPtr->clNext;
int cmdIdx = envPtr->numCommands;
int startCodeOffset = envPtr->codeNext - envPtr->codeStart;
-
+ int depth = TclGetStackDepth(envPtr);
+
assert (parsePtr->numWords > 0);
/* Pre-Compile */
@@ -2004,6 +2010,7 @@ CompileCommandTokens(
eclPtr->loc[wlineat].line = wlines;
eclPtr->loc[wlineat].next = NULL;
+ TclCheckStackDepth(depth, envPtr);
return cmdIdx;
}
@@ -2023,6 +2030,7 @@ TclCompileScript(
* Initial value of -1 indicates this routine
* has not yet generated any bytecode. */
const char *p = script; /* Where we are in our compile. */
+ int depth = TclGetStackDepth(envPtr);
if (envPtr->iPtr == NULL) {
Tcl_Panic("TclCompileScript() called on uninitialized CompileEnv");
@@ -2134,6 +2142,7 @@ TclCompileScript(
envPtr->codeNext--;
envPtr->currStackDepth++;
}
+ TclCheckStackDepth(depth+1, envPtr);
}
/*
@@ -2244,6 +2253,7 @@ TclCompileTokens(
#define NUM_STATIC_POS 20
int isLiteral, maxNumCL, numCL;
int *clPosition = NULL;
+ int depth = TclGetStackDepth(envPtr);
/*
* For the handling of continuation lines in literals we first check if
@@ -2421,6 +2431,7 @@ TclCompileTokens(
if (maxNumCL) {
ckfree(clPosition);
}
+ TclCheckStackDepth(depth+1, envPtr);
}
/*
@@ -3936,7 +3947,8 @@ TclEmitInvoke(
ExceptionAux *auxBreakPtr, *auxContinuePtr;
int arg1, arg2, wordCount = 0, expandCount = 0;
int loopRange = 0, breakRange = 0, continueRange = 0;
-
+ int cleanup, depth = TclGetStackDepth(envPtr);
+
/*
* Parse the arguments.
*/
@@ -3944,30 +3956,31 @@ TclEmitInvoke(
va_start(argList, opcode);
switch (opcode) {
case INST_INVOKE_STK1:
- wordCount = arg1 = va_arg(argList, int);
+ wordCount = arg1 = cleanup = va_arg(argList, int);
arg2 = 0;
break;
case INST_INVOKE_STK4:
- wordCount = arg1 = va_arg(argList, int);
+ wordCount = arg1 = cleanup = va_arg(argList, int);
arg2 = 0;
break;
case INST_INVOKE_REPLACE:
arg1 = va_arg(argList, int);
arg2 = va_arg(argList, int);
wordCount = arg1 + arg2 - 1;
+ cleanup = arg1 + 1;
break;
default:
Tcl_Panic("unexpected opcode");
case INST_EVAL_STK:
- wordCount = 1;
+ wordCount = cleanup = 1;
arg1 = arg2 = 0;
break;
case INST_RETURN_STK:
- wordCount = 2;
+ wordCount = cleanup = 2;
arg1 = arg2 = 0;
break;
case INST_INVOKE_EXPANDED:
- wordCount = arg1 = va_arg(argList, int);
+ wordCount = arg1 = cleanup = va_arg(argList, int);
arg2 = 0;
expandCount = 1;
break;
@@ -4070,6 +4083,7 @@ TclEmitInvoke(
ExceptionRangeTarget(envPtr, loopRange, breakOffset);
TclCleanupStackForBreakContinue(envPtr, auxBreakPtr);
TclAddLoopBreakFixup(envPtr, auxBreakPtr);
+ TclAdjustStackDepth(1, envPtr);
envPtr->currStackDepth = savedStackDepth;
envPtr->expandCount = savedExpandCount;
@@ -4081,6 +4095,7 @@ TclEmitInvoke(
ExceptionRangeTarget(envPtr, loopRange, continueOffset);
TclCleanupStackForBreakContinue(envPtr, auxContinuePtr);
TclAddLoopContinueFixup(envPtr, auxContinuePtr);
+ TclAdjustStackDepth(1, envPtr);
envPtr->currStackDepth = savedStackDepth;
envPtr->expandCount = savedExpandCount;
@@ -4089,6 +4104,7 @@ TclEmitInvoke(
TclFinalizeLoopExceptionRange(envPtr, loopRange);
TclFixupForwardJumpToHere(envPtr, &nonTrapFixup, 127);
}
+ TclCheckStackDepth(depth+1-cleanup, envPtr);
}
/*
diff --git a/generic/tclCompile.h b/generic/tclCompile.h
index 287ab1d..b3c8442 100644
--- a/generic/tclCompile.h
+++ b/generic/tclCompile.h
@@ -1169,6 +1169,21 @@ MODULE_SCOPE Tcl_Obj *TclNewInstNameObj(unsigned char inst);
(envPtr)->currStackDepth += (delta); \
} while (0)
+#define TclGetStackDepth(envPtr) \
+ ((envPtr)->currStackDepth)
+
+#define TclSetStackDepth(depth, envPtr) \
+ (envPtr)->currStackDepth = (depth)
+
+#define TclCheckStackDepth(depth, envPtr) \
+ do { \
+ int dd = (depth); \
+ if (dd != (envPtr)->currStackDepth) { \
+ Tcl_Panic("bad stack depth computations: is %i, should be %i", \
+ (envPtr)->currStackDepth, dd); \
+ } \
+ } while (0)
+
/*
* Macro used to update the stack requirements. It is called by the macros
* TclEmitOpCode, TclEmitInst1 and TclEmitInst4.