From c74640849ef38c01a98a0a1338f72bbb56668d5e 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 0ee8df700b2b0e041c30126e5e5bd4e7c3b75e18 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 23d61a10c23d99df7ef3289f5cf35159e95426d9 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 8bd533d76ea3530028e7bc3c32ec981f3c78c683 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 1d99884b0866f09d7b19d0546818d426642d9494 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 a63563bd9a3985cd767a1869e44b18cdeae793fd 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 59f7320bdd532d9323ad4f80e78ffbac5514e8da 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 5f2f5b63c39411d4273ab4968713004cb1d0d6c8 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 27c5ada57e78e8de829d5e5d7dd0070b9b5a5279 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 f6f0891fffa23a7577553a42c1f2d16fbcb8170a 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 5f6b71f3f2fe180def995e4ff2beb35410b94303 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