From 6af366a7dcf18d187e53d5e58264b34675b31d22 Mon Sep 17 00:00:00 2001 From: dkf Date: Fri, 2 Aug 2013 14:58:58 +0000 Subject: [9d61624b3d]: Stop crashes when emptying the superclass slot. --- generic/tclOODefineCmds.c | 48 ++++++++++++++++++++++++++++------------------- tests/oo.test | 17 +++++++++++++++++ 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/generic/tclOODefineCmds.c b/generic/tclOODefineCmds.c index bacab38..1a5058c 100644 --- a/generic/tclOODefineCmds.c +++ b/generic/tclOODefineCmds.c @@ -2206,29 +2206,39 @@ ClassSuperSet( /* * Parse the arguments to get the class to use as superclasses. + * + * Note that zero classes is special, as it is equivalent to just the + * class of objects. [Bug 9d61624b3d] */ - for (i=0 ; ifPtr->objectCls; + superc = 1; + } else { + for (i=0 ; iclassPtr, superclasses[i])) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "attempt to form circular dependency graph", -1)); - Tcl_SetErrorCode(interp, "TCL", "OO", "CIRCULARITY", NULL); - failedAfterAlloc: - ckfree((char *) superclasses); - return TCL_ERROR; + for (j=0 ; jclassPtr, superclasses[i])) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to form circular dependency graph", -1)); + Tcl_SetErrorCode(interp, "TCL", "OO", "CIRCULARITY", NULL); + failedAfterAlloc: + ckfree((char *) superclasses); + return TCL_ERROR; + } } } diff --git a/tests/oo.test b/tests/oo.test index 49fe150..6f16a8d 100644 --- a/tests/oo.test +++ b/tests/oo.test @@ -3374,6 +3374,23 @@ test oo-34.8 {TIP 380: slots - presence} { test oo-34.9 {TIP 380: slots - presence} { getMethods oo::objdefine::variable } {{-append -clear -set} {Get Set}} + +test oo-35.1 {Bug 9d61624b3d: Empty superclass must not cause crash} -setup { + oo::class create fruit { + method eat {} {} + } + set result {} +} -body { + lappend result [fruit create ::apple] [info class superclasses fruit] + oo::define fruit superclass + lappend result [info class superclasses fruit] \ + [info object class apple oo::object] \ + [info class call fruit destroy] \ + [catch { apple }] +} -cleanup { + unset -nocomplain result + fruit destroy +} -result {::apple ::oo::object ::oo::object 1 {{method destroy ::oo::object {core method: "destroy"}}} 1} cleanupTests return -- cgit v0.12 From ed2e06d4526c12d6cb4c559b6746216396ca4a10 Mon Sep 17 00:00:00 2001 From: dkf Date: Fri, 2 Aug 2013 20:19:44 +0000 Subject: Deal with the elaborate rip-apart-a-metaclass case as well. --- ChangeLog | 11 ++++++++--- generic/tclOODefineCmds.c | 3 +++ tests/oo.test | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index b794da5..a82dbfd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,13 @@ +2013-08-02 Donal Fellows + + * generic/tclOODefineCmds.c (ClassSuperSet): Bug [9d61624b3d]: Stop + crashes when emptying the superclass slot, even when doing elaborate + things with metaclasses. + 2013-08-01 Harald Oehlmann - * tclUnixNotify.c Tcl_InitNotifier: Bug [a0bc856dcd] - Start notifier thread again if we were forked, to solve Rivet bug - 55153. + * tclUnixNotify.c (Tcl_InitNotifier): Bug [a0bc856dcd]: Start notifier + thread again if we were forked, to solve Rivet bug 55153. 2013-07-05 Kevin B. Kenny diff --git a/generic/tclOODefineCmds.c b/generic/tclOODefineCmds.c index 1a5058c..f0983cc 100644 --- a/generic/tclOODefineCmds.c +++ b/generic/tclOODefineCmds.c @@ -2215,6 +2215,9 @@ ClassSuperSet( superclasses = ckrealloc(superclasses, sizeof(Class *)); superclasses[0] = oPtr->fPtr->objectCls; superc = 1; + if (TclOOIsReachable(oPtr->fPtr->classCls, oPtr->classPtr)) { + superclasses[0] = oPtr->fPtr->classCls; + } } else { for (i=0 ; i Date: Sat, 3 Aug 2013 15:27:40 +0000 Subject: [3611643fff]: Support TclOO in autoload mechanism. --- ChangeLog | 5 +++++ library/auto.tcl | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/ChangeLog b/ChangeLog index a82dbfd..ddde893 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-08-03 Donal Fellows + + * library/auto.tcl: [Patch 3611643]: Allow TclOO classes to be found + by the autoloading mechanism. + 2013-08-02 Donal Fellows * generic/tclOODefineCmds.c (ClassSuperSet): Bug [9d61624b3d]: Stop diff --git a/library/auto.tcl b/library/auto.tcl index 0848bb1..78c219e 100644 --- a/library/auto.tcl +++ b/library/auto.tcl @@ -617,4 +617,18 @@ auto_mkindex_parser::command namespace {op args} { } } +# AUTO MKINDEX: oo::class create name ?definition? +# Adds an entry to the auto index list for the given class name. +foreach cmd {oo::class class} { + auto_mkindex_parser::command $cmd {ecmd name {body ""}} { + if {$cmd eq "create"} { + variable index + variable scriptFile + append index [format "set %s \[list source \[%s]]\n" \ + [list auto_index([fullname $name])] \ + [list file join $dir {*}[file split $scriptFile]]] + } + } +} + return -- cgit v0.12 From 4fa8d0b58071c8c666a320ef21813e12303c3564 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 5 Aug 2013 21:58:21 +0000 Subject: Mark unixforkevent-1.1 nonPortable, until proven on more platforms. --- tests/unixForkEvent.test | 2 +- unix/tclUnixTest.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unixForkEvent.test b/tests/unixForkEvent.test index cbe582e..120f362 100644 --- a/tests/unixForkEvent.test +++ b/tests/unixForkEvent.test @@ -16,7 +16,7 @@ testConstraint testfork [llength [info commands testfork]] # Test if the notifier thread is well initialized in a forked interpreter # by Tcl_InitNotifier test unixforkevent-1.1 {fork and test writeable event} \ - -constraints testfork \ + -constraints {testfork nonPortable} \ -body { set myFolder [makeDirectory unixtestfork] set pid [testfork] diff --git a/unix/tclUnixTest.c b/unix/tclUnixTest.c index 2fc1647..d2b729d 100644 --- a/unix/tclUnixTest.c +++ b/unix/tclUnixTest.c @@ -574,8 +574,8 @@ TestforkObjCmd( "Cannot fork", NULL); return TCL_ERROR; } -#ifndef HAVE_PTHREAD_ATFORK - /* Only needed when pthread_atfork is not present. */ +#if !defined(HAVE_PTHREAD_ATFORK) || defined(MAC_OSX_TCL) + /* Only needed when pthread_atfork is not present or on OSX. */ if (pid==0) { Tcl_InitNotifier(); } -- cgit v0.12 From b3b497f42cfe1a533488c23fb8dfd706e7bb59a6 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 6 Aug 2013 04:15:16 +0000 Subject: The value TCL_LOCATION_EVAL_LIST in the type field of a CmdFrame appears to exist only for the sake of taking great pains to make sure that pure list values remain pure list values. The value of pure list values is no longer what it once was. For a long long time now, any canonical list values have been equally good. This branch is Work In Progress eliminating the complication of the additional type value. Currently some minor botches are breaking execution tracing tests. --- generic/tclBasic.c | 67 ++++++++++++++++++---------------------------------- generic/tclCmdIL.c | 25 ++++---------------- generic/tclCompile.c | 2 +- generic/tclInt.h | 41 +++++++++++++++----------------- 4 files changed, 48 insertions(+), 87 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 82affb0..280835c 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -128,7 +128,7 @@ static Tcl_ObjCmdProc ExprSrandFunc; static Tcl_ObjCmdProc ExprUnaryFunc; static Tcl_ObjCmdProc ExprWideFunc; static Tcl_Obj * GetCommandSource(Interp *iPtr, int objc, - Tcl_Obj *const objv[], int lookup); + Tcl_Obj *const objv[]); static void MathFuncWrongNumArgs(Tcl_Interp *interp, int expected, int actual, Tcl_Obj *const *objv); static Tcl_NRPostProc NRCoroutineCallerCallback; @@ -3358,15 +3358,6 @@ CancelEvalProc( * This function returns a Tcl_Obj with the full source string for the * command. This insures that traces get a correct NUL-terminated command * string. The Tcl_Obj has refCount==1. - * - * *** MAINTAINER WARNING *** - * The returned Tcl_Obj is all wrong for any purpose but getting the - * source string for an objc/objv command line in the stringRep (no - * stringRep if no source is available) and the corresponding substituted - * version in the List intrep. - * This means that the intRep and stringRep DO NOT COINCIDE! Using these - * Tcl_Objs normally is likely to break things. - * *---------------------------------------------------------------------- */ @@ -3374,37 +3365,27 @@ static Tcl_Obj * GetCommandSource( Interp *iPtr, int objc, - Tcl_Obj *const objv[], - int lookup) + Tcl_Obj *const objv[]) { - Tcl_Obj *objPtr, *obj2Ptr; + Tcl_Obj *objPtr = NULL; CmdFrame *cfPtr = iPtr->cmdFramePtr; - const char *command = NULL; - int numChars; - objPtr = Tcl_NewListObj(objc, objv); - if (lookup && cfPtr && (cfPtr->numLevels == iPtr->numLevels-1)) { + if (cfPtr && (cfPtr->numLevels == iPtr->numLevels-1)) { switch (cfPtr->type) { case TCL_LOCATION_EVAL: case TCL_LOCATION_SOURCE: - command = cfPtr->cmd.str.cmd; - numChars = cfPtr->cmd.str.len; + objPtr = Tcl_NewStringObj(cfPtr->cmd.str.cmd, cfPtr->cmd.str.len); break; case TCL_LOCATION_BC: - case TCL_LOCATION_PREBC: - command = TclGetSrcInfoForCmd(iPtr, &numChars); - break; - case TCL_LOCATION_EVAL_LIST: - /* Got it already */ + case TCL_LOCATION_PREBC: { + int numChars; + objPtr = Tcl_NewStringObj(TclGetSrcInfoForCmd(iPtr, &numChars), + numChars); break; } - if (command) { - obj2Ptr = Tcl_NewStringObj(command, numChars); - objPtr->bytes = obj2Ptr->bytes; - objPtr->length = numChars; - obj2Ptr->bytes = NULL; - Tcl_DecrRefCount(obj2Ptr); } + } else { + objPtr = Tcl_NewListObj(objc, objv); } Tcl_IncrRefCount(objPtr); return objPtr; @@ -4692,7 +4673,7 @@ TEOV_RunEnterTraces( int length; Tcl_Obj *commandPtr; - commandPtr = GetCommandSource(iPtr, objc, objv, 1); + commandPtr = GetCommandSource(iPtr, objc, objv); command = Tcl_GetStringFromObj(commandPtr, &length); /* @@ -4731,7 +4712,7 @@ TEOV_RunEnterTraces( */ TclNRAddCallback(interp, TEOV_RunLeaveTraces, INT2PTR(traceCode), - commandPtr, cmdPtr, NULL); + commandPtr, cmdPtr, Tcl_NewListObj(objc, objv)); cmdPtr->refCount++; } else { Tcl_DecrRefCount(commandPtr); @@ -4752,10 +4733,11 @@ TEOV_RunLeaveTraces( int traceCode = PTR2INT(data[0]); Tcl_Obj *commandPtr = data[1]; Command *cmdPtr = data[2]; + Tcl_Obj *wordsPtr = data[3]; command = Tcl_GetStringFromObj(commandPtr, &length); - if (TCL_OK != Tcl_ListObjGetElements(interp, commandPtr, &objc, &objv)) { - Tcl_Panic("Who messed with commandPtr?"); + if (TCL_OK != Tcl_ListObjGetElements(interp, wordsPtr, &objc, &objv)) { + Tcl_Panic("What happened with wordsPtr?!"); } if (!(cmdPtr->flags & CMD_IS_DELETED)) { @@ -4769,6 +4751,7 @@ TEOV_RunLeaveTraces( } } Tcl_DecrRefCount(commandPtr); + Tcl_DecrRefCount(wordsPtr); /* * As cmdPtr is set, TclNRRunCallbacks is about to reduce the numlevels. @@ -5974,13 +5957,12 @@ TclNREvalObjEx( */ if (TclListObjIsCanonical(objPtr)) { - Tcl_Obj *listPtr = objPtr; CmdFrame *eoFramePtr = NULL; int objc; - Tcl_Obj **objv; + Tcl_Obj *listPtr, **objv; /* - * Pure List Optimization (no string representation). In this case, we + * Canonical List Optimization: In this case, we * can safely use Tcl_EvalObjv instead and get an appreciable * improvement in execution speed. This is because it allows us to * avoid a setFromAny step that would just pack everything into a @@ -5988,11 +5970,6 @@ TclNREvalObjEx( * * This also preserves any associations between list elements and * location information for such elements. - * - * This restriction has been relaxed a bit by storing in lists whether - * they are "canonical" or not (a canonical list being one that is - * either pure or that has its string rep derived by - * UpdateStringOfList from the internal rep). */ /* @@ -6001,6 +5978,7 @@ TclNREvalObjEx( * we always make a copy. The callback takes care od the refCounts for * both listPtr and objPtr. * + * TODO: Create a test to demo this need, or eliminate it. * FIXME OPT: preserve just the internal rep? */ @@ -6030,14 +6008,15 @@ TclNREvalObjEx( eoFramePtr->nline = 0; eoFramePtr->line = NULL; - eoFramePtr->type = TCL_LOCATION_EVAL_LIST; + eoFramePtr->type = TCL_LOCATION_EVAL; eoFramePtr->level = (iPtr->cmdFramePtr == NULL? 1 : iPtr->cmdFramePtr->level + 1); eoFramePtr->numLevels = iPtr->numLevels; eoFramePtr->framePtr = iPtr->framePtr; eoFramePtr->nextPtr = iPtr->cmdFramePtr; - eoFramePtr->cmd.listPtr = listPtr; + eoFramePtr->cmd.str.cmd = Tcl_GetStringFromObj(listPtr, + &(eoFramePtr->cmd.str.len)); eoFramePtr->data.eval.path = NULL; iPtr->cmdFramePtr = eoFramePtr; diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c index 0e33392..4046903 100644 --- a/generic/tclCmdIL.c +++ b/generic/tclCmdIL.c @@ -1302,30 +1302,15 @@ TclInfoFrame( */ ADD_PAIR("type", Tcl_NewStringObj(typeString[framePtr->type], -1)); - ADD_PAIR("line", Tcl_NewIntObj(framePtr->line[0])); + if (framePtr->line) { + ADD_PAIR("line", Tcl_NewIntObj(framePtr->line[0])); + } else { + ADD_PAIR("line", Tcl_NewIntObj(1)); + } ADD_PAIR("cmd", Tcl_NewStringObj(framePtr->cmd.str.cmd, framePtr->cmd.str.len)); break; - case TCL_LOCATION_EVAL_LIST: - /* - * List optimized evaluation. Type, line, cmd, the latter through - * listPtr, possibly a frame. - */ - - ADD_PAIR("type", Tcl_NewStringObj(typeString[framePtr->type], -1)); - ADD_PAIR("line", Tcl_NewIntObj(1)); - - /* - * We put a duplicate of the command list obj into the result to - * ensure that the 'pure List'-property of the command itself is not - * destroyed. Otherwise the query here would disable the list - * optimization path in Tcl_EvalObjEx. - */ - - ADD_PAIR("cmd", Tcl_DuplicateObj(framePtr->cmd.listPtr)); - break; - case TCL_LOCATION_PREBC: /* * Precompiled. Result contains the type as signal, nothing else. diff --git a/generic/tclCompile.c b/generic/tclCompile.c index 772ce22..618b6fa 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -1375,7 +1375,7 @@ TclInitCompileEnv( envPtr->extCmdMapPtr->nuloc = 0; envPtr->extCmdMapPtr->path = NULL; - if ((invoker == NULL) || (invoker->type == TCL_LOCATION_EVAL_LIST)) { + if (invoker == NULL) { /* * Initialize the compiler for relative counting in case of a * dynamic context. diff --git a/generic/tclInt.h b/generic/tclInt.h index da09366..1df09b3 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -1175,29 +1175,27 @@ typedef struct CmdFrame { * * EXECUTION CONTEXTS and usage of CmdFrame * - * Field TEBC EvalEx EvalObjEx - * ======= ==== ====== ========= - * level yes yes yes - * type BC/PREBC SRC/EVAL EVAL_LIST - * line0 yes yes yes - * framePtr yes yes yes - * ======= ==== ====== ========= + * Field TEBC EvalEx + * ======= ==== ====== + * level yes yes + * type BC/PREBC SRC/EVAL + * line0 yes yes + * framePtr yes yes + * ======= ==== ====== * - * ======= ==== ====== ========= union data - * line1 - yes - - * line3 - yes - - * path - yes - - * ------- ---- ------ --------- - * codePtr yes - - - * pc yes - - - * ======= ==== ====== ========= + * ======= ==== ========= union data + * line1 - yes + * line3 - yes + * path - yes + * ------- ---- ------ + * codePtr yes - + * pc yes - + * ======= ==== ====== * - * ======= ==== ====== ========= | union cmd - * listPtr - - yes | - * ------- ---- ------ --------- | - * cmd yes yes - | - * cmdlen yes yes - | - * ------- ---- ------ --------- | + * ======= ==== ========= union cmd + * str.cmd yes yes + * str.len yes yes + * ------- ---- ------ */ union { @@ -1215,7 +1213,6 @@ typedef struct CmdFrame { const char *cmd; /* The executed command, if possible... */ int len; /* ... and its length. */ } str; - Tcl_Obj *listPtr; /* Tcl_EvalObjEx, cmd list. */ } cmd; int numLevels; /* Value of interp's numLevels when the frame * was pushed. */ -- cgit v0.12 From 90aed79bb65a5df8dfc953a51ed832a8da563df4 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 6 Aug 2013 13:08:54 +0000 Subject: Revert the changes that went too far and broke things. --- generic/tclBasic.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 280835c..ea08f88 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -3358,6 +3358,15 @@ CancelEvalProc( * This function returns a Tcl_Obj with the full source string for the * command. This insures that traces get a correct NUL-terminated command * string. The Tcl_Obj has refCount==1. + * + * *** MAINTAINER WARNING *** + * The returned Tcl_Obj is all wrong for any purpose but getting the + * source string for an objc/objv command line in the stringRep (no + * stringRep if no source is available) and the corresponding substituted + * version in the List intrep. + * This means that the intRep and stringRep DO NOT COINCIDE! Using these + * Tcl_Objs normally is likely to break things. + * *---------------------------------------------------------------------- */ @@ -3367,25 +3376,31 @@ GetCommandSource( int objc, Tcl_Obj *const objv[]) { - Tcl_Obj *objPtr = NULL; + Tcl_Obj *objPtr, *obj2Ptr; CmdFrame *cfPtr = iPtr->cmdFramePtr; + const char *command = NULL; + int numChars; + objPtr = Tcl_NewListObj(objc, objv); if (cfPtr && (cfPtr->numLevels == iPtr->numLevels-1)) { switch (cfPtr->type) { case TCL_LOCATION_EVAL: case TCL_LOCATION_SOURCE: - objPtr = Tcl_NewStringObj(cfPtr->cmd.str.cmd, cfPtr->cmd.str.len); + command = cfPtr->cmd.str.cmd; + numChars = cfPtr->cmd.str.len; break; case TCL_LOCATION_BC: - case TCL_LOCATION_PREBC: { - int numChars; - objPtr = Tcl_NewStringObj(TclGetSrcInfoForCmd(iPtr, &numChars), - numChars); + case TCL_LOCATION_PREBC: + command = TclGetSrcInfoForCmd(iPtr, &numChars); break; } + if (command) { + obj2Ptr = Tcl_NewStringObj(command, numChars); + objPtr->bytes = obj2Ptr->bytes; + objPtr->length = numChars; + obj2Ptr->bytes = NULL; + Tcl_DecrRefCount(obj2Ptr); } - } else { - objPtr = Tcl_NewListObj(objc, objv); } Tcl_IncrRefCount(objPtr); return objPtr; @@ -4712,7 +4727,7 @@ TEOV_RunEnterTraces( */ TclNRAddCallback(interp, TEOV_RunLeaveTraces, INT2PTR(traceCode), - commandPtr, cmdPtr, Tcl_NewListObj(objc, objv)); + commandPtr, cmdPtr, NULL); cmdPtr->refCount++; } else { Tcl_DecrRefCount(commandPtr); @@ -4733,11 +4748,10 @@ TEOV_RunLeaveTraces( int traceCode = PTR2INT(data[0]); Tcl_Obj *commandPtr = data[1]; Command *cmdPtr = data[2]; - Tcl_Obj *wordsPtr = data[3]; command = Tcl_GetStringFromObj(commandPtr, &length); - if (TCL_OK != Tcl_ListObjGetElements(interp, wordsPtr, &objc, &objv)) { - Tcl_Panic("What happened with wordsPtr?!"); + if (TCL_OK != Tcl_ListObjGetElements(interp, commandPtr, &objc, &objv)) { + Tcl_Panic("Who messed with commandPtr?"); } if (!(cmdPtr->flags & CMD_IS_DELETED)) { @@ -4751,7 +4765,6 @@ TEOV_RunLeaveTraces( } } Tcl_DecrRefCount(commandPtr); - Tcl_DecrRefCount(wordsPtr); /* * As cmdPtr is set, TclNRRunCallbacks is about to reduce the numlevels. -- cgit v0.12 From 2fa3c7789bf50168600e5ba432c5bcb1ea3a5c81 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 6 Aug 2013 13:20:36 +0000 Subject: Eliminate the union that is no longer needed. --- generic/tclBasic.c | 13 ++++++------- generic/tclCmdIL.c | 9 +++------ generic/tclExecute.c | 14 +++++++------- generic/tclInt.h | 8 ++------ generic/tclOOMethod.c | 8 ++++---- generic/tclProc.c | 8 ++++---- 6 files changed, 26 insertions(+), 34 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index ea08f88..baa2f2c 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -3386,8 +3386,8 @@ GetCommandSource( switch (cfPtr->type) { case TCL_LOCATION_EVAL: case TCL_LOCATION_SOURCE: - command = cfPtr->cmd.str.cmd; - numChars = cfPtr->cmd.str.len; + command = cfPtr->cmd; + numChars = cfPtr->len; break; case TCL_LOCATION_BC: case TCL_LOCATION_PREBC: @@ -5246,12 +5246,12 @@ TclEvalEx( * have been executed. */ - eeFramePtr->cmd.str.cmd = parsePtr->commandStart; - eeFramePtr->cmd.str.len = parsePtr->commandSize; + eeFramePtr->cmd = parsePtr->commandStart; + eeFramePtr->len = parsePtr->commandSize; if (parsePtr->term == parsePtr->commandStart + parsePtr->commandSize - 1) { - eeFramePtr->cmd.str.len--; + eeFramePtr->len--; } eeFramePtr->nline = objectsUsed; @@ -6028,8 +6028,7 @@ TclNREvalObjEx( eoFramePtr->framePtr = iPtr->framePtr; eoFramePtr->nextPtr = iPtr->cmdFramePtr; - eoFramePtr->cmd.str.cmd = Tcl_GetStringFromObj(listPtr, - &(eoFramePtr->cmd.str.len)); + eoFramePtr->cmd = Tcl_GetStringFromObj(listPtr, &(eoFramePtr->len)); eoFramePtr->data.eval.path = NULL; iPtr->cmdFramePtr = eoFramePtr; diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c index 4046903..180d814 100644 --- a/generic/tclCmdIL.c +++ b/generic/tclCmdIL.c @@ -1307,8 +1307,7 @@ TclInfoFrame( } else { ADD_PAIR("line", Tcl_NewIntObj(1)); } - ADD_PAIR("cmd", Tcl_NewStringObj(framePtr->cmd.str.cmd, - framePtr->cmd.str.len)); + ADD_PAIR("cmd", Tcl_NewStringObj(framePtr->cmd, framePtr->len)); break; case TCL_LOCATION_PREBC: @@ -1356,8 +1355,7 @@ TclInfoFrame( Tcl_DecrRefCount(fPtr->data.eval.path); } - ADD_PAIR("cmd", - Tcl_NewStringObj(fPtr->cmd.str.cmd, fPtr->cmd.str.len)); + ADD_PAIR("cmd", Tcl_NewStringObj(fPtr->cmd, fPtr->len)); TclStackFree(interp, fPtr); break; } @@ -1376,8 +1374,7 @@ TclInfoFrame( * the result list object. */ - ADD_PAIR("cmd", Tcl_NewStringObj(framePtr->cmd.str.cmd, - framePtr->cmd.str.len)); + ADD_PAIR("cmd", Tcl_NewStringObj(framePtr->cmd, framePtr->len)); break; case TCL_LOCATION_PROC: diff --git a/generic/tclExecute.c b/generic/tclExecute.c index f8ed667..11e9920 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2006,8 +2006,8 @@ TclNRExecuteByteCode( bcFramePtr->litarg = NULL; bcFramePtr->data.tebc.codePtr = codePtr; bcFramePtr->data.tebc.pc = NULL; - bcFramePtr->cmd.str.cmd = NULL; - bcFramePtr->cmd.str.len = 0; + bcFramePtr->cmd = NULL; + bcFramePtr->len = 0; #ifdef TCL_COMPILE_STATS iPtr->stats.numExecutions++; @@ -8774,13 +8774,13 @@ TclGetSrcInfoForPc( { ByteCode *codePtr = (ByteCode *) cfPtr->data.tebc.codePtr; - if (cfPtr->cmd.str.cmd == NULL) { - cfPtr->cmd.str.cmd = GetSrcInfoForPc( + if (cfPtr->cmd == NULL) { + cfPtr->cmd = GetSrcInfoForPc( (unsigned char *) cfPtr->data.tebc.pc, codePtr, - &cfPtr->cmd.str.len, NULL, NULL); + &cfPtr->len, NULL, NULL); } - if (cfPtr->cmd.str.cmd != NULL) { + if (cfPtr->cmd != NULL) { /* * We now have the command. We can get the srcOffset back and from * there find the list of word locations for this command. @@ -8797,7 +8797,7 @@ TclGetSrcInfoForPc( return; } - srcOffset = cfPtr->cmd.str.cmd - codePtr->source; + srcOffset = cfPtr->cmd - codePtr->source; eclPtr = Tcl_GetHashValue(hePtr); for (i=0; i < eclPtr->nuloc; i++) { diff --git a/generic/tclInt.h b/generic/tclInt.h index 1df09b3..d398591 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -1208,12 +1208,8 @@ typedef struct CmdFrame { const char *pc; /* ... and instruction pointer. */ } tebc; } data; - union { - struct { - const char *cmd; /* The executed command, if possible... */ - int len; /* ... and its length. */ - } str; - } cmd; + const char *cmd; /* The executed command, if possible... */ + int len; /* ... and its length. */ int numLevels; /* Value of interp's numLevels when the frame * was pushed. */ const struct CFWordBC *litarg; diff --git a/generic/tclOOMethod.c b/generic/tclOOMethod.c index 98b4078..b91fdfd 100644 --- a/generic/tclOOMethod.c +++ b/generic/tclOOMethod.c @@ -513,8 +513,8 @@ TclOOMakeProcInstanceMethod( cfPtr->data.eval.path = context.data.eval.path; Tcl_IncrRefCount(cfPtr->data.eval.path); - cfPtr->cmd.str.cmd = NULL; - cfPtr->cmd.str.len = 0; + cfPtr->cmd = NULL; + cfPtr->len = 0; hPtr = Tcl_CreateHashEntry(iPtr->linePBodyPtr, (char *) procPtr, &isNew); @@ -626,8 +626,8 @@ TclOOMakeProcMethod( cfPtr->data.eval.path = context.data.eval.path; Tcl_IncrRefCount(cfPtr->data.eval.path); - cfPtr->cmd.str.cmd = NULL; - cfPtr->cmd.str.len = 0; + cfPtr->cmd = NULL; + cfPtr->len = 0; hPtr = Tcl_CreateHashEntry(iPtr->linePBodyPtr, (char *) procPtr, &isNew); diff --git a/generic/tclProc.c b/generic/tclProc.c index 18985a1..1314719 100644 --- a/generic/tclProc.c +++ b/generic/tclProc.c @@ -271,8 +271,8 @@ Tcl_ProcObjCmd( cfPtr->data.eval.path = contextPtr->data.eval.path; Tcl_IncrRefCount(cfPtr->data.eval.path); - cfPtr->cmd.str.cmd = NULL; - cfPtr->cmd.str.len = 0; + cfPtr->cmd = NULL; + cfPtr->len = 0; hePtr = Tcl_CreateHashEntry(iPtr->linePBodyPtr, procPtr, &isNew); @@ -2595,8 +2595,8 @@ SetLambdaFromAny( cfPtr->data.eval.path = contextPtr->data.eval.path; Tcl_IncrRefCount(cfPtr->data.eval.path); - cfPtr->cmd.str.cmd = NULL; - cfPtr->cmd.str.len = 0; + cfPtr->cmd = NULL; + cfPtr->len = 0; } /* -- cgit v0.12 From c13bb10d72906770febda3135e8407326a24663c Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 6 Aug 2013 13:30:36 +0000 Subject: Drop TCL_LOCATION_EVAL_LIST now that it is unused. --- generic/tclInt.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/generic/tclInt.h b/generic/tclInt.h index d398591..cd4ab7d 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -1275,8 +1275,6 @@ typedef struct ContLineLoc { * location data referenced via the 'baseLocPtr'. * * TCL_LOCATION_EVAL : Frame is for a script evaluated by EvalEx. - * TCL_LOCATION_EVAL_LIST : Frame is for a script evaluated by the list - * optimization path of EvalObjEx. * TCL_LOCATION_BC : Frame is for bytecode. * TCL_LOCATION_PREBC : Frame is for precompiled bytecode. * TCL_LOCATION_SOURCE : Frame is for a script evaluated by EvalEx, from a @@ -1288,8 +1286,6 @@ typedef struct ContLineLoc { */ #define TCL_LOCATION_EVAL (0) /* Location in a dynamic eval script. */ -#define TCL_LOCATION_EVAL_LIST (1) /* Location in a dynamic eval script, - * list-path. */ #define TCL_LOCATION_BC (2) /* Location in byte code. */ #define TCL_LOCATION_PREBC (3) /* Location in precompiled byte code, no * location. */ -- cgit v0.12 From f56c89a9c1633b26c4f2ef5a898a92e0331ce678 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 6 Aug 2013 16:20:59 +0000 Subject: Add assertions that will guide and protect more discovery of dead code for elimination. --- generic/tclBasic.c | 2 ++ generic/tclExecute.c | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index baa2f2c..1889dfd 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -6109,6 +6109,8 @@ TclNREvalObjEx( ContLineLoc *saveCLLocPtr = iPtr->scriptCLLocPtr; ContLineLoc *clLocPtr = TclContinuationsGet(objPtr); + assert(invoker == NULL); + if (clLocPtr) { iPtr->scriptCLLocPtr = clLocPtr; Tcl_Preserve(iPtr->scriptCLLocPtr); diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 11e9920..f6072a1 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -8774,13 +8774,15 @@ TclGetSrcInfoForPc( { ByteCode *codePtr = (ByteCode *) cfPtr->data.tebc.codePtr; - if (cfPtr->cmd == NULL) { + assert(cfPtr->type == TCL_LOCATION_BC); + assert(cfPtr->cmd == NULL); + cfPtr->cmd = GetSrcInfoForPc( (unsigned char *) cfPtr->data.tebc.pc, codePtr, &cfPtr->len, NULL, NULL); - } - if (cfPtr->cmd != NULL) { + assert(cfPtr->cmd != NULL); + { /* * We now have the command. We can get the srcOffset back and from * there find the list of word locations for this command. -- cgit v0.12 From 854ba0e8ca16a91d958a52579e03b86d868fc8ca Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 6 Aug 2013 17:24:40 +0000 Subject: All use of the evalFlag value TCL_EVAL_CTX is unused by the code and unreachable by extensions. This checkin removes all the code supporting that flag value. The consequence is that all the calls to TclNREvalObjEx() and its callers that are currently choosing not to pass the TCL_EVAL_DIRECT flag in when they pass in a non-NULL invoker will no longer be free to change their mind. That might be reason not to adopt this change. --- generic/tclBasic.c | 98 ++++++------------------------------------------------ generic/tclInt.h | 1 - 2 files changed, 11 insertions(+), 88 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 1889dfd..00ae24e 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -5011,12 +5011,11 @@ TclEvalEx( /* * TIP #280 Initialize tracking. Do not push on the frame stack yet. * - * We may continue counting based on a specific context (CTX), or open a - * new context, either for a sourced script, or 'eval'. For sourced files - * we always have a path object, even if nothing was specified in the - * interp itself. That makes code using it simpler as NULL checks can be - * left out. Sourced file without path in the 'scriptFile' is possible - * during Tcl initialization. + * We open a new context, either for a sourced script, or 'eval'. + * For sourced files we always have a path object, even if nothing was + * specified in the interp itself. That makes code using it simpler as + * NULL checks can be left out. Sourced file without path in the + * 'scriptFile' is possible during Tcl initialization. */ eeFramePtr->level = iPtr->cmdFramePtr ? iPtr->cmdFramePtr->level + 1 : 1; @@ -5027,15 +5026,7 @@ TclEvalEx( eeFramePtr->line = NULL; iPtr->cmdFramePtr = eeFramePtr; - if (iPtr->evalFlags & TCL_EVAL_CTX) { - /* - * Path information comes out of the context. - */ - - eeFramePtr->type = TCL_LOCATION_SOURCE; - eeFramePtr->data.eval.path = iPtr->invokeCmdFramePtr->data.eval.path; - Tcl_IncrRefCount(eeFramePtr->data.eval.path); - } else if (iPtr->evalFlags & TCL_EVAL_FILE) { + if (iPtr->evalFlags & TCL_EVAL_FILE) { /* * Set up for a sourced file. */ @@ -6076,14 +6067,6 @@ TclNREvalObjEx( * We're not supposed to use the compiler or byte-code * interpreter. Let Tcl_EvalEx evaluate the command directly (and * probably more slowly). - * - * TIP #280. Propagate context as much as we can. Especially if the - * script to evaluate is a single literal it makes sense to look if - * our context is one with absolute line numbers we can then track - * into the literal itself too. - * - * See also tclCompile.c, TclInitCompileEnv, for the equivalent code - * in the bytecode compiler. */ const char *script; @@ -6104,6 +6087,8 @@ TclNREvalObjEx( * Another important action is to save (and later restore) the * continuation line information of the caller, in case we are * executing nested commands in the eval/direct path. + * + * TODO: Get test coverage in here. */ ContLineLoc *saveCLLocPtr = iPtr->scriptCLLocPtr; @@ -6119,71 +6104,11 @@ TclNREvalObjEx( } Tcl_IncrRefCount(objPtr); - if (invoker == NULL) { - /* - * No context, force opening of our own. - */ - script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); - result = Tcl_EvalEx(interp, script, numSrcBytes, flags); - } else { - /* - * We have an invoker, describing the command asking for the - * evaluation of a subordinate script. This script may originate - * in a literal word, or from a variable, etc. Using the line - * array we now check if we have good line information for the - * relevant word. The type of context is relevant as well. In a - * non-'source' context we don't have to try tracking lines. - * - * First see if the word exists and is a literal. If not we go - * through the easy dynamic branch. No need to perform more - * complex invokations. - */ + script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); + result = Tcl_EvalEx(interp, script, numSrcBytes, flags); - int pc = 0; - CmdFrame *ctxPtr = TclStackAlloc(interp, sizeof(CmdFrame)); - - *ctxPtr = *invoker; - if (invoker->type == TCL_LOCATION_BC) { - /* - * Note: Type BC => ctxPtr->data.eval.path is not used. - * ctxPtr->data.tebc.codePtr is used instead. - */ - - TclGetSrcInfoForPc(ctxPtr); - pc = 1; - } - - script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); - - if ((invoker->nline <= word) || - (invoker->line[word] < 0) || - (ctxPtr->type != TCL_LOCATION_SOURCE)) { - /* - * Dynamic script, or dynamic context, force our own context. - */ - - result = Tcl_EvalEx(interp, script, numSrcBytes, flags); - } else { - /* - * Absolute context to reuse. - */ - - iPtr->invokeCmdFramePtr = ctxPtr; - iPtr->evalFlags |= TCL_EVAL_CTX; - - result = TclEvalEx(interp, script, numSrcBytes, flags, - ctxPtr->line[word], NULL, script); - } - if (pc && (ctxPtr->type == TCL_LOCATION_SOURCE)) { - /* - * Death of SrcInfo reference. - */ - - Tcl_DecrRefCount(ctxPtr->data.eval.path); - } - TclStackFree(interp, ctxPtr); - } + TclDecrRefCount(objPtr); /* * Now release the lock on the continuation line information, if any, @@ -6194,7 +6119,6 @@ TclNREvalObjEx( Tcl_Release(iPtr->scriptCLLocPtr); } iPtr->scriptCLLocPtr = saveCLLocPtr; - TclDecrRefCount(objPtr); return result; } } diff --git a/generic/tclInt.h b/generic/tclInt.h index cd4ab7d..99f1305 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2201,7 +2201,6 @@ typedef struct Interp { #define TCL_ALLOW_EXCEPTIONS 4 #define TCL_EVAL_FILE 2 -#define TCL_EVAL_CTX 8 /* * Flag bits for Interp structures: -- cgit v0.12 From 47750cf97411377b0562db3816394c12707d8590 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 7 Aug 2013 12:44:42 +0000 Subject: Add comment stating new limitation on Tcl(NR)EvalObjEx() interface. --- generic/tclBasic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 00ae24e..8ba3825 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -5893,6 +5893,11 @@ Tcl_GlobalEvalObj( * compiled into bytecodes if necessary, unless TCL_EVAL_DIRECT is * specified. * + * If the flag TCL_EVAL_DIRECT is passed in, the value of invoker + * must be NULL. Support for non-NULL invokers in that mode has + * been removed since it was unused and untested. Failure to + * follow this limitation will lead to an assertion panic. + * * Results: * The return value is one of the return codes defined in tcl.h (such as * TCL_OK), and the interpreter's result contains a value to supplement -- cgit v0.12 From 9923dc2908c517db587b6cbb398398ab3e45ec16 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 7 Aug 2013 14:41:46 +0000 Subject: Replace potentially memleak creating safety check of a "cannot happen" condition with an assertion. --- generic/tclParse.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/generic/tclParse.c b/generic/tclParse.c index 6723d39..c5cb1d1 100644 --- a/generic/tclParse.c +++ b/generic/tclParse.c @@ -13,6 +13,7 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ +#include #include "tclInt.h" #include "tclParse.h" @@ -1578,16 +1579,13 @@ Tcl_ParseVar( * At this point we should have an object containing the value of a * variable. Just return the string from that object. * - * This should have returned the object for the user to manage, but - * instead we have some weak reference to the string value in the object, - * which is why we make sure the object exists after resetting the result. - * This isn't ideal, but it's the best we can do with the current - * documented interface. -- hobbs + * Since TclSubstTokens above returned TCL_OK, we know that objPtr + * is shared. It is in both the interp result and the value of the + * variable. Returning the string relies on that to be true. */ - if (!Tcl_IsShared(objPtr)) { - Tcl_IncrRefCount(objPtr); - } + assert( Tcl_IsShared(objPtr) ); + Tcl_ResetResult(interp); return TclGetString(objPtr); } -- cgit v0.12 From fd31090a583e76ccb81747a37f56e865669aebae Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 7 Aug 2013 16:01:53 +0000 Subject: Test for TclContinuationsGet() usage, and simplifications. --- generic/tclBasic.c | 18 +----------------- tests/parse.test | 6 ++++++ 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 8ba3825..7110025 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -6092,21 +6092,13 @@ TclNREvalObjEx( * Another important action is to save (and later restore) the * continuation line information of the caller, in case we are * executing nested commands in the eval/direct path. - * - * TODO: Get test coverage in here. */ ContLineLoc *saveCLLocPtr = iPtr->scriptCLLocPtr; - ContLineLoc *clLocPtr = TclContinuationsGet(objPtr); assert(invoker == NULL); - if (clLocPtr) { - iPtr->scriptCLLocPtr = clLocPtr; - Tcl_Preserve(iPtr->scriptCLLocPtr); - } else { - iPtr->scriptCLLocPtr = NULL; - } + iPtr->scriptCLLocPtr = TclContinuationsGet(objPtr); Tcl_IncrRefCount(objPtr); @@ -6115,14 +6107,6 @@ TclNREvalObjEx( TclDecrRefCount(objPtr); - /* - * Now release the lock on the continuation line information, if any, - * and restore the caller's settings. - */ - - if (iPtr->scriptCLLocPtr) { - Tcl_Release(iPtr->scriptCLLocPtr); - } iPtr->scriptCLLocPtr = saveCLLocPtr; return result; } diff --git a/tests/parse.test b/tests/parse.test index 9f2d50b..01443c9 100644 --- a/tests/parse.test +++ b/tests/parse.test @@ -1118,6 +1118,12 @@ test parse-21.0 {Bug 1884496} testevent { testevent queue a head $::script vwait done } {} +test parse-21.1 {TCL_EVAL_DIRECT coverage} testevent { + testevent queue a head {testevent delete a; \ + set ::done [dict get [info frame 0] line]} + vwait done + set ::done +} 2 cleanupTests } -- cgit v0.12 From 77c1bfb88bf69b0a55d43eca6a0029d82458a377 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 7 Aug 2013 16:44:03 +0000 Subject: Remove Tcl_Preserve support for ContLineLoc values. It's not needed. This allows the clLoc field of CompileEnv struct to go away too. --- generic/tclCompile.c | 19 ++----------------- generic/tclCompile.h | 4 ---- generic/tclObj.c | 38 +++----------------------------------- 3 files changed, 5 insertions(+), 56 deletions(-) diff --git a/generic/tclCompile.c b/generic/tclCompile.c index 618b6fa..f5c8d41 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -713,9 +713,7 @@ TclSetByteCodeFromAny( clLocPtr = TclContinuationsGet(objPtr); if (clLocPtr) { - compEnv.clLoc = clLocPtr; - compEnv.clNext = &compEnv.clLoc->loc[0]; - Tcl_Preserve(compEnv.clLoc); + compEnv.clNext = &clLocPtr->loc[0]; } TclCompileScript(interp, stringPtr, length, &compEnv); @@ -742,9 +740,7 @@ TclSetByteCodeFromAny( TclInitCompileEnv(interp, &compEnv, stringPtr, length, iPtr->invokeCmdFramePtr, iPtr->invokeWord); if (clLocPtr) { - compEnv.clLoc = clLocPtr; - compEnv.clNext = &compEnv.clLoc->loc[0]; - Tcl_Preserve(compEnv.clLoc); + compEnv.clNext = &clLocPtr->loc[0]; } compEnv.atCmdStart = 2; /* The disabling magic. */ TclCompileScript(interp, stringPtr, length, &compEnv); @@ -1489,7 +1485,6 @@ TclInitCompileEnv( * data is available. */ - envPtr->clLoc = NULL; envPtr->clNext = NULL; envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace; @@ -1574,16 +1569,6 @@ TclFreeCompileEnv( ReleaseCmdWordData(envPtr->extCmdMapPtr); envPtr->extCmdMapPtr = NULL; } - - /* - * If we used data about invisible continuation lines, then now is the - * time to release on our hold on it. The lock was set in function - * TclSetByteCodeFromAny(), found in this file. - */ - - if (envPtr->clLoc) { - Tcl_Release(envPtr->clLoc); - } } /* diff --git a/generic/tclCompile.h b/generic/tclCompile.h index beb28fd..5660055 100644 --- a/generic/tclCompile.h +++ b/generic/tclCompile.h @@ -365,10 +365,6 @@ typedef struct CompileEnv { * 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 - * line counter. */ int *clNext; /* If not NULL, it refers to the next slot in * clLoc to check for an invisible * continuation line. */ diff --git a/generic/tclObj.c b/generic/tclObj.c index 542d6d1..930e1fd 100644 --- a/generic/tclObj.c +++ b/generic/tclObj.c @@ -97,7 +97,6 @@ typedef struct ThreadSpecificData { static Tcl_ThreadDataKey dataKey; -static void ContLineLocFree(char *clientData); static void TclThreadFinalizeContLines(ClientData clientData); static ThreadSpecificData *TclGetContLineTable(void); @@ -805,14 +804,7 @@ TclThreadFinalizeContLines( for (hPtr = Tcl_FirstHashEntry(tsdPtr->lineCLPtr, &hSearch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { - /* - * We are not using Tcl_EventuallyFree (as in TclFreeObj()) because - * here we can be sure that the compiler will not hold references to - * the data in the hashtable, and using TEF might bork the - * finalization sequence. - */ - - ContLineLocFree(Tcl_GetHashValue(hPtr)); + ckfree(Tcl_GetHashValue(hPtr)); Tcl_DeleteHashEntry(hPtr); } Tcl_DeleteHashTable(tsdPtr->lineCLPtr); @@ -821,30 +813,6 @@ TclThreadFinalizeContLines( } /* - *---------------------------------------------------------------------- - * - * ContLineLocFree -- - * - * The freProc for continuation line location tables. - * - * Results: - * None. - * - * Side effects: - * Releases memory. - * - * TIP #280 - *---------------------------------------------------------------------- - */ - -static void -ContLineLocFree( - char *clientData) -{ - ckfree(clientData); -} - -/* *-------------------------------------------------------------- * * Tcl_RegisterObjType -- @@ -1405,7 +1373,7 @@ TclFreeObj( if (tsdPtr->lineCLPtr) { hPtr = Tcl_FindHashEntry(tsdPtr->lineCLPtr, objPtr); if (hPtr) { - Tcl_EventuallyFree(Tcl_GetHashValue(hPtr), ContLineLocFree); + ckfree(Tcl_GetHashValue(hPtr)); Tcl_DeleteHashEntry(hPtr); } } @@ -1496,7 +1464,7 @@ TclFreeObj( if (tsdPtr->lineCLPtr) { hPtr = Tcl_FindHashEntry(tsdPtr->lineCLPtr, objPtr); if (hPtr) { - Tcl_EventuallyFree(Tcl_GetHashValue(hPtr), ContLineLocFree); + ckfree(Tcl_GetHashValue(hPtr)); Tcl_DeleteHashEntry(hPtr); } } -- cgit v0.12 From 4536322b256c1539a134ea7ecc4a7c32e7b05451 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 7 Aug 2013 19:45:13 +0000 Subject: Give (objc, objv) their own ride from enter to leave traces. --- generic/tclBasic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 7110025..067da63 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -4727,7 +4727,7 @@ TEOV_RunEnterTraces( */ TclNRAddCallback(interp, TEOV_RunLeaveTraces, INT2PTR(traceCode), - commandPtr, cmdPtr, NULL); + commandPtr, cmdPtr, Tcl_NewListObj(objc, objv)); cmdPtr->refCount++; } else { Tcl_DecrRefCount(commandPtr); @@ -4748,11 +4748,10 @@ TEOV_RunLeaveTraces( int traceCode = PTR2INT(data[0]); Tcl_Obj *commandPtr = data[1]; Command *cmdPtr = data[2]; + Tcl_Obj *wordsPtr = data[3]; command = Tcl_GetStringFromObj(commandPtr, &length); - if (TCL_OK != Tcl_ListObjGetElements(interp, commandPtr, &objc, &objv)) { - Tcl_Panic("Who messed with commandPtr?"); - } + Tcl_ListObjGetElements(NULL, wordsPtr, &objc, &objv); if (!(cmdPtr->flags & CMD_IS_DELETED)) { if ((cmdPtr->flags & CMD_HAS_EXEC_TRACES) && traceCode == TCL_OK){ @@ -4765,6 +4764,7 @@ TEOV_RunLeaveTraces( } } Tcl_DecrRefCount(commandPtr); + Tcl_DecrRefCount(wordsPtr); /* * As cmdPtr is set, TclNRRunCallbacks is about to reduce the numlevels. -- cgit v0.12 From dddbd100aedbc995c1a203715479978f79e82ba6 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 7 Aug 2013 20:27:30 +0000 Subject: Revise GetCommandSource() to return a normal Tcl_Obj value. --- generic/tclBasic.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 067da63..6542726 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -3358,15 +3358,6 @@ CancelEvalProc( * This function returns a Tcl_Obj with the full source string for the * command. This insures that traces get a correct NUL-terminated command * string. The Tcl_Obj has refCount==1. - * - * *** MAINTAINER WARNING *** - * The returned Tcl_Obj is all wrong for any purpose but getting the - * source string for an objc/objv command line in the stringRep (no - * stringRep if no source is available) and the corresponding substituted - * version in the List intrep. - * This means that the intRep and stringRep DO NOT COINCIDE! Using these - * Tcl_Objs normally is likely to break things. - * *---------------------------------------------------------------------- */ @@ -3376,13 +3367,13 @@ GetCommandSource( int objc, Tcl_Obj *const objv[]) { - Tcl_Obj *objPtr, *obj2Ptr; + Tcl_Obj *objPtr = NULL; CmdFrame *cfPtr = iPtr->cmdFramePtr; - const char *command = NULL; - int numChars; - objPtr = Tcl_NewListObj(objc, objv); if (cfPtr && (cfPtr->numLevels == iPtr->numLevels-1)) { + const char *command = NULL; + int numChars; + switch (cfPtr->type) { case TCL_LOCATION_EVAL: case TCL_LOCATION_SOURCE: @@ -3395,13 +3386,12 @@ GetCommandSource( break; } if (command) { - obj2Ptr = Tcl_NewStringObj(command, numChars); - objPtr->bytes = obj2Ptr->bytes; - objPtr->length = numChars; - obj2Ptr->bytes = NULL; - Tcl_DecrRefCount(obj2Ptr); + objPtr = Tcl_NewStringObj(command, numChars); } } + if (objPtr == NULL) { + objPtr = Tcl_NewListObj(objc, objv); + } Tcl_IncrRefCount(objPtr); return objPtr; } -- cgit v0.12 From fec32bb50c597bfbb21ad55211339355034f6d55 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 9 Aug 2013 16:48:30 +0000 Subject: Revised GetCommandSource() can (and thus should) return a normal zero refcount value. --- generic/tclBasic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 6542726..9755a21 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -3357,7 +3357,7 @@ CancelEvalProc( * * This function returns a Tcl_Obj with the full source string for the * command. This insures that traces get a correct NUL-terminated command - * string. The Tcl_Obj has refCount==1. + * string. *---------------------------------------------------------------------- */ @@ -3392,7 +3392,6 @@ GetCommandSource( if (objPtr == NULL) { objPtr = Tcl_NewListObj(objc, objv); } - Tcl_IncrRefCount(objPtr); return objPtr; } -- cgit v0.12 From de857ca207e4dceea586bf2dbfe497df4d9d02c8 Mon Sep 17 00:00:00 2001 From: dgp Date: Sat, 10 Aug 2013 05:16:38 +0000 Subject: Arrange for both execution traces and [info frame] to get their pre-subst source strings from a common routine, with care taken to reduce copying by that routine. --- generic/tclBasic.c | 41 +++++++++++++++-------------------------- generic/tclCmdIL.c | 25 ++++++++++++++++++++++--- generic/tclExecute.c | 19 +++++++++++++++++-- generic/tclInt.h | 5 +++++ 4 files changed, 59 insertions(+), 31 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 9755a21..1cd2eae 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -3367,32 +3367,12 @@ GetCommandSource( int objc, Tcl_Obj *const objv[]) { - Tcl_Obj *objPtr = NULL; CmdFrame *cfPtr = iPtr->cmdFramePtr; - if (cfPtr && (cfPtr->numLevels == iPtr->numLevels-1)) { - const char *command = NULL; - int numChars; - - switch (cfPtr->type) { - case TCL_LOCATION_EVAL: - case TCL_LOCATION_SOURCE: - command = cfPtr->cmd; - numChars = cfPtr->len; - break; - case TCL_LOCATION_BC: - case TCL_LOCATION_PREBC: - command = TclGetSrcInfoForCmd(iPtr, &numChars); - break; - } - if (command) { - objPtr = Tcl_NewStringObj(command, numChars); - } + if (cfPtr && (cfPtr->numLevels != iPtr->numLevels-1)) { + cfPtr = NULL; } - if (objPtr == NULL) { - objPtr = Tcl_NewListObj(objc, objv); - } - return objPtr; + return TclGetSourceFromFrame(cfPtr, objc, objv); } /* @@ -4678,6 +4658,7 @@ TEOV_RunEnterTraces( Tcl_Obj *commandPtr; commandPtr = GetCommandSource(iPtr, objc, objv); + Tcl_IncrRefCount(commandPtr); command = Tcl_GetStringFromObj(commandPtr, &length); /* @@ -5013,6 +4994,7 @@ TclEvalEx( eeFramePtr->nextPtr = iPtr->cmdFramePtr; eeFramePtr->nline = 0; eeFramePtr->line = NULL; + eeFramePtr->cmdObj = NULL; iPtr->cmdFramePtr = eeFramePtr; if (iPtr->evalFlags & TCL_EVAL_FILE) { @@ -5243,6 +5225,10 @@ TclEvalEx( eeFramePtr->line = NULL; eeFramePtr->nline = 0; + if (eeFramePtr->cmdObj) { + Tcl_DecrRefCount(eeFramePtr->cmdObj); + eeFramePtr->cmdObj = NULL; + } if (code != TCL_OK) { goto error; @@ -5983,7 +5969,6 @@ TclNREvalObjEx( Tcl_IncrRefCount(objPtr); listPtr = TclListObjCopy(interp, objPtr); Tcl_IncrRefCount(listPtr); - TclDecrRefCount(objPtr); if (word != INT_MIN) { /* @@ -6013,7 +5998,9 @@ TclNREvalObjEx( eoFramePtr->framePtr = iPtr->framePtr; eoFramePtr->nextPtr = iPtr->cmdFramePtr; - eoFramePtr->cmd = Tcl_GetStringFromObj(listPtr, &(eoFramePtr->len)); + eoFramePtr->cmdObj = objPtr; + eoFramePtr->cmd = NULL; + eoFramePtr->len = 0; eoFramePtr->data.eval.path = NULL; iPtr->cmdFramePtr = eoFramePtr; @@ -6021,7 +6008,7 @@ TclNREvalObjEx( TclMarkTailcall(interp); TclNRAddCallback(interp, TEOEx_ListCallback, listPtr, eoFramePtr, - NULL, NULL); + objPtr, NULL); ListObjGetElements(listPtr, objc, objv); return TclNREvalObjv(interp, objc, objv, flags, NULL); @@ -6156,6 +6143,7 @@ TEOEx_ListCallback( Interp *iPtr = (Interp *) interp; Tcl_Obj *listPtr = data[0]; CmdFrame *eoFramePtr = data[1]; + Tcl_Obj *objPtr = data[2]; /* * Remove the cmdFrame @@ -6165,6 +6153,7 @@ TEOEx_ListCallback( iPtr->cmdFramePtr = eoFramePtr->nextPtr; TclStackFree(interp, eoFramePtr); } + TclDecrRefCount(objPtr); TclDecrRefCount(listPtr); return result; diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c index 180d814..da9edd6 100644 --- a/generic/tclCmdIL.c +++ b/generic/tclCmdIL.c @@ -1266,6 +1266,25 @@ InfoFrameCmd( */ Tcl_Obj * +TclGetSourceFromFrame( + CmdFrame *cfPtr, + int objc, + Tcl_Obj *const objv[]) +{ + if (cfPtr == NULL) { + return Tcl_NewListObj(objc, objv); + } + if (cfPtr->cmdObj == NULL) { + if (cfPtr->cmd == NULL) { + cfPtr->cmd = TclGetSrcInfoForCmdFrame(cfPtr, &cfPtr->len); + } + cfPtr->cmdObj = Tcl_NewStringObj(cfPtr->cmd, cfPtr->len); + Tcl_IncrRefCount(cfPtr->cmdObj); + } + return cfPtr->cmdObj; +} + +Tcl_Obj * TclInfoFrame( Tcl_Interp *interp, /* Current interpreter. */ CmdFrame *framePtr) /* Frame to get info for. */ @@ -1307,7 +1326,7 @@ TclInfoFrame( } else { ADD_PAIR("line", Tcl_NewIntObj(1)); } - ADD_PAIR("cmd", Tcl_NewStringObj(framePtr->cmd, framePtr->len)); + ADD_PAIR("cmd", TclGetSourceFromFrame(framePtr, 0, NULL)); break; case TCL_LOCATION_PREBC: @@ -1355,7 +1374,7 @@ TclInfoFrame( Tcl_DecrRefCount(fPtr->data.eval.path); } - ADD_PAIR("cmd", Tcl_NewStringObj(fPtr->cmd, fPtr->len)); + ADD_PAIR("cmd", TclGetSourceFromFrame(fPtr, 0, NULL)); TclStackFree(interp, fPtr); break; } @@ -1374,7 +1393,7 @@ TclInfoFrame( * the result list object. */ - ADD_PAIR("cmd", Tcl_NewStringObj(framePtr->cmd, framePtr->len)); + ADD_PAIR("cmd", TclGetSourceFromFrame(framePtr, 0, NULL)); break; case TCL_LOCATION_PROC: diff --git a/generic/tclExecute.c b/generic/tclExecute.c index f6072a1..d8ccf40 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2006,6 +2006,7 @@ TclNRExecuteByteCode( bcFramePtr->litarg = NULL; bcFramePtr->data.tebc.codePtr = codePtr; bcFramePtr->data.tebc.pc = NULL; + bcFramePtr->cmdObj = NULL; bcFramePtr->cmd = NULL; bcFramePtr->len = 0; @@ -2130,6 +2131,11 @@ TEBCresume( result = TCL_ERROR; } NRE_ASSERT(iPtr->cmdFramePtr == bcFramePtr); + if (bcFramePtr->cmdObj) { + Tcl_DecrRefCount(bcFramePtr->cmdObj); + bcFramePtr->cmdObj = NULL; + bcFramePtr->cmd = NULL; + } iPtr->cmdFramePtr = bcFramePtr->nextPtr; if (iPtr->flags & INTERP_DEBUG_FRAME) { TclArgumentBCRelease((Tcl_Interp *) iPtr, bcFramePtr); @@ -8761,7 +8767,14 @@ TclGetSrcInfoForCmd( Interp *iPtr, int *lenPtr) { - CmdFrame *cfPtr = iPtr->cmdFramePtr; + return TclGetSrcInfoForCmdFrame(iPtr->cmdFramePtr, lenPtr); +} + +const char * +TclGetSrcInfoForCmdFrame( + CmdFrame *cfPtr, + int *lenPtr) +{ ByteCode *codePtr = (ByteCode *) cfPtr->data.tebc.codePtr; return GetSrcInfoForPc((unsigned char *) cfPtr->data.tebc.pc, @@ -8775,11 +8788,13 @@ TclGetSrcInfoForPc( ByteCode *codePtr = (ByteCode *) cfPtr->data.tebc.codePtr; assert(cfPtr->type == TCL_LOCATION_BC); - assert(cfPtr->cmd == NULL); + + if (cfPtr->cmd == NULL) { cfPtr->cmd = GetSrcInfoForPc( (unsigned char *) cfPtr->data.tebc.pc, codePtr, &cfPtr->len, NULL, NULL); + } assert(cfPtr->cmd != NULL); { diff --git a/generic/tclInt.h b/generic/tclInt.h index 99f1305..161d166 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -1208,6 +1208,7 @@ typedef struct CmdFrame { const char *pc; /* ... and instruction pointer. */ } tebc; } data; + Tcl_Obj *cmdObj; const char *cmd; /* The executed command, if possible... */ int len; /* ... and its length. */ int numLevels; /* Value of interp's numLevels when the frame @@ -2907,7 +2908,11 @@ MODULE_SCOPE int TclGetOpenModeEx(Tcl_Interp *interp, const char *modeString, int *seekFlagPtr, int *binaryPtr); MODULE_SCOPE Tcl_Obj * TclGetProcessGlobalValue(ProcessGlobalValue *pgvPtr); +MODULE_SCOPE Tcl_Obj * TclGetSourceFromFrame(CmdFrame *cfPtr, int objc, + Tcl_Obj *const objv[]); MODULE_SCOPE const char *TclGetSrcInfoForCmd(Interp *iPtr, int *lenPtr); +MODULE_SCOPE const char *TclGetSrcInfoForCmdFrame(CmdFrame *cfPtr, + int *lenPtr); MODULE_SCOPE int TclGlob(Tcl_Interp *interp, char *pattern, Tcl_Obj *unquotedPrefix, int globFlags, Tcl_GlobTypeData *types); -- cgit v0.12 From 420294d3ed2faf23f5b57ed32e1bf869c4f71b8f Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 11 Aug 2013 14:41:10 +0000 Subject: Never guess non-existing timezone name "America/Brasilia" on Windows. Reported by Arnulf Wiedemann --- library/clock.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/clock.tcl b/library/clock.tcl index 49aad23..1f83716 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -325,7 +325,7 @@ proc ::tcl::clock::Initialize {} { {-10800 0 3600 0 2 0 2 2 0 0 0 0 10 0 3 2 0 0 0} :America/Sao_Paulo {-10800 0 3600 0 10 0 5 2 0 0 0 0 4 0 1 2 0 0 0} :America/Godthab {-10800 0 3600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} :America/Buenos_Aires - {-10800 0 3600 0 2 0 5 2 0 0 0 0 11 0 1 2 0 0 0} :America/Brasilia + {-10800 0 3600 0 2 0 5 2 0 0 0 0 11 0 1 2 0 0 0} :America/Bahia {-10800 0 3600 0 3 0 2 2 0 0 0 0 10 0 1 2 0 0 0} :America/Montevideo {-7200 0 3600 0 9 0 5 2 0 0 0 0 3 0 5 2 0 0 0} :America/Noronha {-3600 0 3600 0 10 0 5 3 0 0 0 0 3 0 5 2 0 0 0} :Atlantic/Azores -- cgit v0.12 From 9d7666659bb7ba5dcf54394bb4c2a555b2f46f7c Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 12 Aug 2013 20:00:14 +0000 Subject: Use a new flag value TCL_EVAL_SOURCE_IN_FRAME passed in by callers to determine whether the pre-subst source information in a CmdFrame is to be used. This takes the place of numLevels cross checking, so that field is removed. Routines are consolidated as well. --- generic/tclBasic.c | 43 +++++++++---------------------------------- generic/tclExecute.c | 13 ++----------- generic/tclInt.h | 8 +++----- 3 files changed, 14 insertions(+), 50 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 1cd2eae..b6c6f38 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -127,8 +127,6 @@ static Tcl_ObjCmdProc ExprSqrtFunc; static Tcl_ObjCmdProc ExprSrandFunc; static Tcl_ObjCmdProc ExprUnaryFunc; static Tcl_ObjCmdProc ExprWideFunc; -static Tcl_Obj * GetCommandSource(Interp *iPtr, int objc, - Tcl_Obj *const objv[]); static void MathFuncWrongNumArgs(Tcl_Interp *interp, int expected, int actual, Tcl_Obj *const *objv); static Tcl_NRPostProc NRCoroutineCallerCallback; @@ -149,7 +147,7 @@ static inline Command * TEOV_LookupCmdFromObj(Tcl_Interp *interp, static int TEOV_NotFound(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Namespace *lookupNsPtr); static int TEOV_RunEnterTraces(Tcl_Interp *interp, - Command **cmdPtrPtr, int objc, + Command **cmdPtrPtr, Tcl_Obj *commandPtr, int objc, Tcl_Obj *const objv[], Namespace *lookupNsPtr); static Tcl_NRPostProc RewindCoroutineCallback; static Tcl_NRPostProc TailcallCleanup; @@ -3353,31 +3351,6 @@ CancelEvalProc( /* *---------------------------------------------------------------------- * - * GetCommandSource -- - * - * This function returns a Tcl_Obj with the full source string for the - * command. This insures that traces get a correct NUL-terminated command - * string. - *---------------------------------------------------------------------- - */ - -static Tcl_Obj * -GetCommandSource( - Interp *iPtr, - int objc, - Tcl_Obj *const objv[]) -{ - CmdFrame *cfPtr = iPtr->cmdFramePtr; - - if (cfPtr && (cfPtr->numLevels != iPtr->numLevels-1)) { - cfPtr = NULL; - } - return TclGetSourceFromFrame(cfPtr, objc, objv); -} - -/* - *---------------------------------------------------------------------- - * * TclCleanupCommand -- * * This function frees up a Command structure unless it is still @@ -4230,7 +4203,9 @@ TclNREvalObjv( * necessary. */ - result = TEOV_RunEnterTraces(interp, &cmdPtr, objc, objv, lookupNsPtr); + result = TEOV_RunEnterTraces(interp, &cmdPtr, TclGetSourceFromFrame( + flags & TCL_EVAL_SOURCE_IN_FRAME ? iPtr->cmdFramePtr : NULL, + objc, objv), objc, objv, lookupNsPtr); if (!cmdPtr) { return TEOV_NotFound(interp, objc, objv, lookupNsPtr); } @@ -4644,6 +4619,7 @@ static int TEOV_RunEnterTraces( Tcl_Interp *interp, Command **cmdPtrPtr, + Tcl_Obj *commandPtr, int objc, Tcl_Obj *const objv[], Namespace *lookupNsPtr) @@ -4655,9 +4631,7 @@ TEOV_RunEnterTraces( int newEpoch; const char *command; int length; - Tcl_Obj *commandPtr; - commandPtr = GetCommandSource(iPtr, objc, objv); Tcl_IncrRefCount(commandPtr); command = Tcl_GetStringFromObj(commandPtr, &length); @@ -4989,7 +4963,6 @@ TclEvalEx( */ eeFramePtr->level = iPtr->cmdFramePtr ? iPtr->cmdFramePtr->level + 1 : 1; - eeFramePtr->numLevels = iPtr->numLevels; eeFramePtr->framePtr = iPtr->framePtr; eeFramePtr->nextPtr = iPtr->cmdFramePtr; eeFramePtr->nline = 0; @@ -5220,7 +5193,8 @@ TclEvalEx( eeFramePtr->line = lines; TclArgumentEnter(interp, objv, objectsUsed, eeFramePtr); - code = Tcl_EvalObjv(interp, objectsUsed, objv, TCL_EVAL_NOERR); + code = Tcl_EvalObjv(interp, objectsUsed, objv, + TCL_EVAL_NOERR | TCL_EVAL_SOURCE_IN_FRAME); TclArgumentRelease(interp, objv, objectsUsed); eeFramePtr->line = NULL; @@ -5994,7 +5968,6 @@ TclNREvalObjEx( eoFramePtr->type = TCL_LOCATION_EVAL; eoFramePtr->level = (iPtr->cmdFramePtr == NULL? 1 : iPtr->cmdFramePtr->level + 1); - eoFramePtr->numLevels = iPtr->numLevels; eoFramePtr->framePtr = iPtr->framePtr; eoFramePtr->nextPtr = iPtr->cmdFramePtr; @@ -6004,6 +5977,8 @@ TclNREvalObjEx( eoFramePtr->data.eval.path = NULL; iPtr->cmdFramePtr = eoFramePtr; + + flags |= TCL_EVAL_SOURCE_IN_FRAME; } TclMarkTailcall(interp); diff --git a/generic/tclExecute.c b/generic/tclExecute.c index d8ccf40..58e4d3d 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -1998,7 +1998,6 @@ TclNRExecuteByteCode( bcFramePtr->type = ((codePtr->flags & TCL_BYTECODE_PRECOMPILED) ? TCL_LOCATION_PREBC : TCL_LOCATION_BC); bcFramePtr->level = (iPtr->cmdFramePtr ? iPtr->cmdFramePtr->level+1 : 1); - bcFramePtr->numLevels = iPtr->numLevels; bcFramePtr->framePtr = iPtr->framePtr; bcFramePtr->nextPtr = iPtr->cmdFramePtr; bcFramePtr->nline = 0; @@ -2906,7 +2905,7 @@ TEBCresume( pc += pcAdjustment; TEBC_YIELD(); return TclNREvalObjv(interp, objc, objv, - TCL_EVAL_NOERR, NULL); + TCL_EVAL_NOERR | TCL_EVAL_SOURCE_IN_FRAME, NULL); #if TCL_SUPPORT_84_BYTECODE case INST_CALL_BUILTIN_FUNC1: @@ -8741,7 +8740,7 @@ IllegalExprOperandType( /* *---------------------------------------------------------------------- * - * TclGetSrcInfoForPc, GetSrcInfoForPc, TclGetSrcInfoForCmd -- + * TclGetSrcInfoForPc, GetSrcInfoForPc, TclGetSrcInfoForCmdFrame -- * * Given a program counter value, finds the closest command in the * bytecode code unit's CmdLocation array and returns information about @@ -8763,14 +8762,6 @@ IllegalExprOperandType( */ const char * -TclGetSrcInfoForCmd( - Interp *iPtr, - int *lenPtr) -{ - return TclGetSrcInfoForCmdFrame(iPtr->cmdFramePtr, lenPtr); -} - -const char * TclGetSrcInfoForCmdFrame( CmdFrame *cfPtr, int *lenPtr) diff --git a/generic/tclInt.h b/generic/tclInt.h index 161d166..19cd883 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -1211,8 +1211,6 @@ typedef struct CmdFrame { Tcl_Obj *cmdObj; const char *cmd; /* The executed command, if possible... */ int len; /* ... and its length. */ - int numLevels; /* Value of interp's numLevels when the frame - * was pushed. */ const struct CFWordBC *litarg; /* Link to set of literal arguments which have * ben pushed on the lineLABCPtr stack by @@ -2200,8 +2198,9 @@ typedef struct Interp { * other than these should be turned into errors. */ -#define TCL_ALLOW_EXCEPTIONS 4 -#define TCL_EVAL_FILE 2 +#define TCL_ALLOW_EXCEPTIONS 0x04 +#define TCL_EVAL_FILE 0x02 +#define TCL_EVAL_SOURCE_IN_FRAME 0x10 /* * Flag bits for Interp structures: @@ -2910,7 +2909,6 @@ MODULE_SCOPE int TclGetOpenModeEx(Tcl_Interp *interp, MODULE_SCOPE Tcl_Obj * TclGetProcessGlobalValue(ProcessGlobalValue *pgvPtr); MODULE_SCOPE Tcl_Obj * TclGetSourceFromFrame(CmdFrame *cfPtr, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE const char *TclGetSrcInfoForCmd(Interp *iPtr, int *lenPtr); MODULE_SCOPE const char *TclGetSrcInfoForCmdFrame(CmdFrame *cfPtr, int *lenPtr); MODULE_SCOPE int TclGlob(Tcl_Interp *interp, char *pattern, -- cgit v0.12 From 9c15217967a7614ac17d324144b8e39d788b6eef Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 14 Aug 2013 04:13:21 +0000 Subject: Only schedule leave traces if enter traces complete successfully. This avoids a memleak, and opens a data slot, so we can pass objc, objv without the need to copy them into a list value. --- generic/tclBasic.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index b6c6f38..f852b44 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -4665,13 +4665,13 @@ TEOV_RunEnterTraces( *cmdPtrPtr = cmdPtr; } - if (cmdPtr) { + if (cmdPtr && (traceCode == TCL_OK)) { /* * Command was found: push a record to schedule the leave traces. */ - TclNRAddCallback(interp, TEOV_RunLeaveTraces, INT2PTR(traceCode), - commandPtr, cmdPtr, Tcl_NewListObj(objc, objv)); + TclNRAddCallback(interp, TEOV_RunLeaveTraces, INT2PTR(objc), + commandPtr, cmdPtr, objv); cmdPtr->refCount++; } else { Tcl_DecrRefCount(commandPtr); @@ -4686,19 +4686,18 @@ TEOV_RunLeaveTraces( int result) { Interp *iPtr = (Interp *) interp; - const char *command; - int length, objc; - Tcl_Obj **objv; - int traceCode = PTR2INT(data[0]); + int traceCode = TCL_OK; + int objc = PTR2INT(data[0]); Tcl_Obj *commandPtr = data[1]; Command *cmdPtr = data[2]; - Tcl_Obj *wordsPtr = data[3]; + Tcl_Obj **objv = data[3]; - command = Tcl_GetStringFromObj(commandPtr, &length); - Tcl_ListObjGetElements(NULL, wordsPtr, &objc, &objv); if (!(cmdPtr->flags & CMD_IS_DELETED)) { - if ((cmdPtr->flags & CMD_HAS_EXEC_TRACES) && traceCode == TCL_OK){ + int length; + const char *command = Tcl_GetStringFromObj(commandPtr, &length); + + if (cmdPtr->flags & CMD_HAS_EXEC_TRACES){ traceCode = TclCheckExecutionTraces(interp, command, length, cmdPtr, result, TCL_TRACE_LEAVE_EXEC, objc, objv); } @@ -4708,7 +4707,6 @@ TEOV_RunLeaveTraces( } } Tcl_DecrRefCount(commandPtr); - Tcl_DecrRefCount(wordsPtr); /* * As cmdPtr is set, TclNRRunCallbacks is about to reduce the numlevels. -- cgit v0.12 From b2d7315f923bd7c0eae390595466fcf0ff1388ac Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 14 Aug 2013 12:15:59 +0000 Subject: Consolidate some helper routines. --- generic/tclCmdIL.c | 19 ------------------- generic/tclExecute.c | 27 +++++++++++++++++++-------- generic/tclInt.h | 2 -- 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c index da9edd6..fa4ead4 100644 --- a/generic/tclCmdIL.c +++ b/generic/tclCmdIL.c @@ -1266,25 +1266,6 @@ InfoFrameCmd( */ Tcl_Obj * -TclGetSourceFromFrame( - CmdFrame *cfPtr, - int objc, - Tcl_Obj *const objv[]) -{ - if (cfPtr == NULL) { - return Tcl_NewListObj(objc, objv); - } - if (cfPtr->cmdObj == NULL) { - if (cfPtr->cmd == NULL) { - cfPtr->cmd = TclGetSrcInfoForCmdFrame(cfPtr, &cfPtr->len); - } - cfPtr->cmdObj = Tcl_NewStringObj(cfPtr->cmd, cfPtr->len); - Tcl_IncrRefCount(cfPtr->cmdObj); - } - return cfPtr->cmdObj; -} - -Tcl_Obj * TclInfoFrame( Tcl_Interp *interp, /* Current interpreter. */ CmdFrame *framePtr) /* Frame to get info for. */ diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 58e4d3d..d066476 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -8740,7 +8740,7 @@ IllegalExprOperandType( /* *---------------------------------------------------------------------- * - * TclGetSrcInfoForPc, GetSrcInfoForPc, TclGetSrcInfoForCmdFrame -- + * TclGetSrcInfoForPc, GetSrcInfoForPc, TclGetSourceFromFrame -- * * Given a program counter value, finds the closest command in the * bytecode code unit's CmdLocation array and returns information about @@ -8761,15 +8761,26 @@ IllegalExprOperandType( *---------------------------------------------------------------------- */ -const char * -TclGetSrcInfoForCmdFrame( +Tcl_Obj * +TclGetSourceFromFrame( CmdFrame *cfPtr, - int *lenPtr) + int objc, + Tcl_Obj *const objv[]) { - ByteCode *codePtr = (ByteCode *) cfPtr->data.tebc.codePtr; - - return GetSrcInfoForPc((unsigned char *) cfPtr->data.tebc.pc, - codePtr, lenPtr, NULL, NULL); + if (cfPtr == NULL) { + return Tcl_NewListObj(objc, objv); + } + if (cfPtr->cmdObj == NULL) { + if (cfPtr->cmd == NULL) { + ByteCode *codePtr = (ByteCode *) cfPtr->data.tebc.codePtr; + + cfPtr->cmd = GetSrcInfoForPc((unsigned char *) + cfPtr->data.tebc.pc, codePtr, &cfPtr->len, NULL, NULL); + } + cfPtr->cmdObj = Tcl_NewStringObj(cfPtr->cmd, cfPtr->len); + Tcl_IncrRefCount(cfPtr->cmdObj); + } + return cfPtr->cmdObj; } void diff --git a/generic/tclInt.h b/generic/tclInt.h index 19cd883..6056119 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2909,8 +2909,6 @@ MODULE_SCOPE int TclGetOpenModeEx(Tcl_Interp *interp, MODULE_SCOPE Tcl_Obj * TclGetProcessGlobalValue(ProcessGlobalValue *pgvPtr); MODULE_SCOPE Tcl_Obj * TclGetSourceFromFrame(CmdFrame *cfPtr, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE const char *TclGetSrcInfoForCmdFrame(CmdFrame *cfPtr, - int *lenPtr); MODULE_SCOPE int TclGlob(Tcl_Interp *interp, char *pattern, Tcl_Obj *unquotedPrefix, int globFlags, Tcl_GlobTypeData *types); -- cgit v0.12