From 6af51247c19f071e11ea3f2b27724643bb7e0d70 Mon Sep 17 00:00:00 2001 From: mig Date: Wed, 11 Dec 2013 13:49:20 +0000 Subject: simplifying: drop early the evaled script --- generic/tclCompCmds.c | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index cd43cfc..0a0aa8e 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -610,11 +610,10 @@ TclCompileCatchCmd( ExceptionRangeStarts(envPtr, range); TclEmitOpcode( INST_DUP, envPtr); TclEmitInvoke(envPtr, INST_EVAL_STK); + /* drop the script */ + TclEmitInstInt4( INST_REVERSE, 2, envPtr); + TclEmitOpcode( INST_POP, envPtr); } - /* Stack at this point: - * nonsimple: script result - * simple: result - */ if (resultIndex == -1) { /* @@ -632,14 +631,7 @@ TclCompileCatchCmd( TclEmitOpcode( INST_PUSH_RETURN_CODE, envPtr); ExceptionRangeEnds(envPtr, range); TclEmitOpcode( INST_END_CATCH, envPtr); - - /* - * Stack at this point: - * nonsimple: script returnCode - * simple: returnCode - */ - - goto dropScriptAtEnd; + return TCL_OK; } /* @@ -649,7 +641,6 @@ TclCompileCatchCmd( PushStringLiteral(envPtr, "0"); TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup); - /* Stack at this point: ?script? result TCL_OK */ /* * Emit the "error case" epilogue. Push the interpreter result and the @@ -658,7 +649,7 @@ TclCompileCatchCmd( TclAdjustStackDepth(-2, envPtr); ExceptionRangeTarget(envPtr, range, catchOffset); - /* Stack at this point: ?script? */ + /* Stack at this point is empty */ TclEmitOpcode( INST_PUSH_RESULT, envPtr); TclEmitOpcode( INST_PUSH_RETURN_CODE, envPtr); @@ -666,7 +657,7 @@ TclCompileCatchCmd( * Update the target of the jump after the "no errors" code. */ - /* Stack at this point: ?script? result returnCode */ + /* Stack at this point: result returnCode */ if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) { Tcl_Panic("TclCompileCatchCmd: bad jump distance %d", (int)(CurrentOffset(envPtr) - jumpFixup.codeOffset)); @@ -689,7 +680,7 @@ TclCompileCatchCmd( /* * At this point, the top of the stack is inconveniently ordered: - * ?script? result returnCode ?returnOptions? + * result returnCode ?returnOptions? * Reverse the stack to bring the result to the top. */ @@ -707,7 +698,7 @@ TclCompileCatchCmd( TclEmitOpcode( INST_POP, envPtr); /* - * Stack is now ?script? ?returnOptions? returnCode. + * Stack is now ?returnOptions? returnCode. * If the options dict has been requested, it is buried on the stack under * the return code. Reverse the stack to bring it to the top, store it and * remove it from the stack. @@ -719,18 +710,6 @@ TclCompileCatchCmd( TclEmitOpcode( INST_POP, envPtr); } - dropScriptAtEnd: - - /* - * Stack is now ?script? result. Get rid of the subst'ed script if it's - * hanging arond. - */ - - if (cmdTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - TclEmitInstInt4( INST_REVERSE, 2, envPtr); - TclEmitOpcode( INST_POP, envPtr); - } - return TCL_OK; } -- cgit v0.12 From 13a7f30bb1ad0a3bb814f20efe88d5eb02d9e453 Mon Sep 17 00:00:00 2001 From: mig Date: Wed, 11 Dec 2013 14:51:15 +0000 Subject: store options early: simplify compiler, reduce stack manipulations --- generic/tclCompCmds.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 0a0aa8e..65c50eb 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -614,6 +614,7 @@ TclCompileCatchCmd( TclEmitInstInt4( INST_REVERSE, 2, envPtr); TclEmitOpcode( INST_POP, envPtr); } + ExceptionRangeEnds(envPtr, range); if (resultIndex == -1) { /* @@ -669,47 +670,26 @@ TclCompileCatchCmd( if (optsIndex != -1) { TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr); + Emit14Inst( INST_STORE_SCALAR, optsIndex, envPtr); + TclEmitOpcode( INST_POP, envPtr); } /* * End the catch */ - ExceptionRangeEnds(envPtr, range); TclEmitOpcode( INST_END_CATCH, envPtr); /* * At this point, the top of the stack is inconveniently ordered: - * result returnCode ?returnOptions? - * Reverse the stack to bring the result to the top. - */ - - if (optsIndex != -1) { - TclEmitInstInt4( INST_REVERSE, 3, envPtr); - } else { - TclEmitInstInt4( INST_REVERSE, 2, envPtr); - } - - /* - * Store the result and remove it from the stack. + * result returnCode + * Reverse the stack to store the result. */ + TclEmitInstInt4( INST_REVERSE, 2, envPtr); Emit14Inst( INST_STORE_SCALAR, resultIndex, envPtr); TclEmitOpcode( INST_POP, envPtr); - /* - * Stack is now ?returnOptions? returnCode. - * If the options dict has been requested, it is buried on the stack under - * the return code. Reverse the stack to bring it to the top, store it and - * remove it from the stack. - */ - - if (optsIndex != -1) { - TclEmitInstInt4( INST_REVERSE, 2, envPtr); - Emit14Inst( INST_STORE_SCALAR, optsIndex, envPtr); - TclEmitOpcode( INST_POP, envPtr); - } - return TCL_OK; } -- cgit v0.12 From d83a8d3b91859aa6d510256f3b26c4a3d98bdd5d Mon Sep 17 00:00:00 2001 From: mig Date: Wed, 11 Dec 2013 15:16:20 +0000 Subject: simplify: remove the special case --- generic/tclCompCmds.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 65c50eb..dbc876a 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -616,25 +616,6 @@ TclCompileCatchCmd( } ExceptionRangeEnds(envPtr, range); - if (resultIndex == -1) { - /* - * Special case when neither result nor options are being saved. In - * that case, we can skip quite a bit of the command epilogue; all we - * have to do is drop the result and push the return code (and, of - * course, finish the catch context). - */ - - TclEmitOpcode( INST_POP, envPtr); - PushStringLiteral(envPtr, "0"); - TclEmitInstInt1( INST_JUMP1, 3, envPtr); - TclAdjustStackDepth(-1, envPtr); - ExceptionRangeTarget(envPtr, range, catchOffset); - TclEmitOpcode( INST_PUSH_RETURN_CODE, envPtr); - ExceptionRangeEnds(envPtr, range); - TclEmitOpcode( INST_END_CATCH, envPtr); - return TCL_OK; - } - /* * Emit the "no errors" epilogue: push "0" (TCL_OK) as the catch result, * and jump around the "error case" code. @@ -687,8 +668,10 @@ TclCompileCatchCmd( */ TclEmitInstInt4( INST_REVERSE, 2, envPtr); - Emit14Inst( INST_STORE_SCALAR, resultIndex, envPtr); - TclEmitOpcode( INST_POP, envPtr); + if (resultIndex != -1) { + Emit14Inst( INST_STORE_SCALAR, resultIndex, envPtr); + } + TclEmitOpcode( INST_POP, envPtr); return TCL_OK; } -- cgit v0.12 From c7d612f81758056c1d7511f1f4f8dff108ef76d7 Mon Sep 17 00:00:00 2001 From: mig Date: Wed, 11 Dec 2013 15:55:28 +0000 Subject: new test, and fix for bug --- generic/tclCompCmds.c | 15 +++++++++------ tests/compile.test | 30 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index dbc876a..7997efa 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -645,14 +645,8 @@ TclCompileCatchCmd( (int)(CurrentOffset(envPtr) - jumpFixup.codeOffset)); } - /* - * Push the return options if the caller wants them. - */ - if (optsIndex != -1) { TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr); - Emit14Inst( INST_STORE_SCALAR, optsIndex, envPtr); - TclEmitOpcode( INST_POP, envPtr); } /* @@ -662,6 +656,15 @@ TclCompileCatchCmd( TclEmitOpcode( INST_END_CATCH, envPtr); /* + * Push the return options if the caller wants them. + */ + + if (optsIndex != -1) { + Emit14Inst( INST_STORE_SCALAR, optsIndex, envPtr); + TclEmitOpcode( INST_POP, envPtr); + } + + /* * At this point, the top of the stack is inconveniently ordered: * result returnCode * Reverse the stack to store the result. diff --git a/tests/compile.test b/tests/compile.test index 36e24de..2852bf2 100644 --- a/tests/compile.test +++ b/tests/compile.test @@ -167,6 +167,36 @@ test compile-3.6 {TclCompileCatchCmd: error in storing result [Bug 3098302]} {*} -cleanup {namespace delete catchtest} } +test compile-3.7 {TclCompileCatchCmd: error in storing options [Bug 3098302]} {*}{ + -setup { + namespace eval catchtest { + variable options1 {} + } + trace add variable catchtest::options1 write catchtest::failtrace + proc catchtest::failtrace {n1 n2 op} { + return -code error "trace on $n1 fails by request" + } + } + -body { + proc catchtest::x {} { + variable options1 + set count 0 + for {set i 0} {$i < 10} {incr i} { + set status2 [catch { + set status1 [catch { + return -code error -level 0 "original failure" + } result1 options1] + } result2 options2] + incr count + } + list $count $result2 + } + catchtest::x + } + -result {10 {can't set "options1": trace on options1 fails by request}} + -cleanup {namespace delete catchtest} +} + test compile-4.1 {TclCompileForCmd: command substituted test expression} { set i 0 set j 0 -- cgit v0.12 From 1ef52b35f0c918fa1c081116f142afd4e244eaf1 Mon Sep 17 00:00:00 2001 From: mig Date: Wed, 11 Dec 2013 16:27:59 +0000 Subject: comments --- generic/tclCompCmds.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 7997efa..e071bbd 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -645,6 +645,11 @@ TclCompileCatchCmd( (int)(CurrentOffset(envPtr) - jumpFixup.codeOffset)); } + /* + * Push the return options if the caller wants them. This needs to happen + * before INST_END_CATCH + */ + if (optsIndex != -1) { TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr); } @@ -656,7 +661,8 @@ TclCompileCatchCmd( TclEmitOpcode( INST_END_CATCH, envPtr); /* - * Push the return options if the caller wants them. + * Save the result and return options if the caller wants them. This needs + * to happen after INST_END_CATCH (compile-3.6/7). */ if (optsIndex != -1) { -- cgit v0.12 From d2ffd68c98038a0690f6a6e2f9a32b6439a7fe7e Mon Sep 17 00:00:00 2001 From: mig Date: Wed, 11 Dec 2013 16:33:21 +0000 Subject: comments --- generic/tclCompCmds.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index e071bbd..43504bf 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -635,16 +635,13 @@ TclCompileCatchCmd( TclEmitOpcode( INST_PUSH_RESULT, envPtr); TclEmitOpcode( INST_PUSH_RETURN_CODE, envPtr); - /* - * Update the target of the jump after the "no errors" code. - */ - - /* Stack at this point: result returnCode */ if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) { Tcl_Panic("TclCompileCatchCmd: bad jump distance %d", (int)(CurrentOffset(envPtr) - jumpFixup.codeOffset)); } + /* Stack at this point: result returnCode */ + /* * Push the return options if the caller wants them. This needs to happen * before INST_END_CATCH -- cgit v0.12 From ee023de8d6942ebb02809d498f6dd46f634fa98d Mon Sep 17 00:00:00 2001 From: mig Date: Wed, 11 Dec 2013 16:43:26 +0000 Subject: comments --- generic/tclCompCmds.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 43504bf..72b338c 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -582,11 +582,7 @@ TclCompileCatchCmd( /* * We will compile the catch command. Declare the exception range that it * uses. - */ - - range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr); - - /* + * * If the body is a simple word, compile a BEGIN_CATCH instruction, * followed by the instructions to eval the body. * Otherwise, compile instructions to substitute the body text before @@ -599,6 +595,7 @@ TclCompileCatchCmd( * begin by undeflowing the stack below the mark set by BEGIN_CATCH4. */ + range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr); if (cmdTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr); ExceptionRangeStarts(envPtr, range); @@ -635,13 +632,13 @@ TclCompileCatchCmd( TclEmitOpcode( INST_PUSH_RESULT, envPtr); TclEmitOpcode( INST_PUSH_RETURN_CODE, envPtr); + /* Stack at this point on both branches: result returnCode */ + if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) { Tcl_Panic("TclCompileCatchCmd: bad jump distance %d", (int)(CurrentOffset(envPtr) - jumpFixup.codeOffset)); } - /* Stack at this point: result returnCode */ - /* * Push the return options if the caller wants them. This needs to happen * before INST_END_CATCH -- cgit v0.12