From 916f1716f3f7dcdc6dc158c684aac96698e9e726 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 9 Dec 2014 20:29:09 +0000 Subject: [e711ffb458] Replace TclIsLocalScalar() (which does the wrong thing).... with PushVarNameWord() (which doesn't) in the compiler for [dict lappend]. --- generic/tclCompCmds.c | 18 ++++++------------ generic/tclCompile.c | 4 ++-- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index c8ca828..7ecdc9b 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -1284,32 +1284,26 @@ TclCompileDictLappendCmd( * compiled. */ CompileEnv *envPtr) /* Holds resulting instructions. */ { - Proc *procPtr = envPtr->procPtr; - DefineLineInformation; /* TIP #280 */ Tcl_Token *varTokenPtr, *keyTokenPtr, *valueTokenPtr; - int dictVarIndex, nameChars; - const char *name; + int isSimple, dictVarIndex = -1, isScalar = 0; + DefineLineInformation; /* TIP #280 */ /* * There must be three arguments after the command. */ - if (parsePtr->numWords != 4 || procPtr == NULL) { + if (parsePtr->numWords != 4) { return TCL_ERROR; } varTokenPtr = TokenAfter(parsePtr->tokenPtr); keyTokenPtr = TokenAfter(varTokenPtr); valueTokenPtr = TokenAfter(keyTokenPtr); - if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; - } - name = varTokenPtr[1].start; - nameChars = varTokenPtr[1].size; - if (!TclIsLocalScalar(name, nameChars)) { + PushVarNameWord(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, + &dictVarIndex, &isSimple, &isScalar, 1); + if (!isScalar || dictVarIndex < 0) { return TCL_ERROR; } - dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, procPtr); CompileWord(envPtr, keyTokenPtr, interp, 2); CompileWord(envPtr, valueTokenPtr, interp, 3); TclEmitInstInt4( INST_DICT_LAPPEND, dictVarIndex, envPtr); diff --git a/generic/tclCompile.c b/generic/tclCompile.c index f982359..5030f89 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -2288,8 +2288,8 @@ TclFindCompiledLocal( * scalar or array variable. If NULL, a * temporary var should be created. */ int nameBytes, /* Number of bytes in the name. */ - int create, /* If 1, allocate a local frame entry for the - * variable if it is new. */ + int create, /* If non-zero, allocate a local frame entry + * for the variable if it is new. */ register Proc *procPtr) /* Points to structure describing procedure * containing the variable reference. */ { -- cgit v0.12 From 2d415cbf59016e2af60ee20e8b75f9cb26103aed Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 9 Dec 2014 20:45:30 +0000 Subject: [e711ffb458] Replace TclIsLocalScalar() with PushVarNameWord() in the compiler for [dict set]. --- generic/tclCompCmds.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 7ecdc9b..ec22f65 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -683,17 +683,15 @@ TclCompileDictSetCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Token *tokenPtr; - Proc *procPtr = envPtr->procPtr; - DefineLineInformation; /* TIP #280 */ Tcl_Token *varTokenPtr; - int i, dictVarIndex, nameChars; - const char *name; + int i, isSimple, isScalar = 0, dictVarIndex = -1; + DefineLineInformation; /* TIP #280 */ /* - * There must be at least one argument after the command. + * There must be at least three arguments after the (sub-)command. */ - if (parsePtr->numWords < 4 || procPtr == NULL) { + if (parsePtr->numWords < 4) { return TCL_ERROR; } @@ -704,15 +702,11 @@ TclCompileDictSetCmd( */ varTokenPtr = TokenAfter(parsePtr->tokenPtr); - if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; - } - name = varTokenPtr[1].start; - nameChars = varTokenPtr[1].size; - if (!TclIsLocalScalar(name, nameChars)) { + PushVarNameWord(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, + &dictVarIndex, &isSimple, &isScalar, 1); + if (!isScalar || dictVarIndex < 0) { return TCL_ERROR; } - dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, procPtr); /* * Remaining words (key path and value to set) can be handled normally. -- cgit v0.12 From 26326004c63514e3b84d7a3268d5177bf0d18894 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 11 Dec 2014 14:40:02 +0000 Subject: [e711ffb458] Same conversion for [catch] compiler. --- generic/tclCompCmds.c | 43 +++++++------------------------------------ 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index ec22f65..10cba39 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -379,8 +379,7 @@ TclCompileCatchCmd( { JumpFixup jumpFixup; Tcl_Token *cmdTokenPtr, *resultNameTokenPtr, *optsNameTokenPtr; - const char *name; - int resultIndex, optsIndex, nameChars, range; + int resultIndex, optsIndex, isSimple, isScalar, range; int initStackDepth = envPtr->currStackDepth; int savedStackDepth; DefineLineInformation; /* TIP #280 */ @@ -395,15 +394,6 @@ TclCompileCatchCmd( } /* - * If variables were specified and the catch command is at global level - * (not in a procedure), don't compile it inline: the payoff is too small. - */ - - if ((parsePtr->numWords >= 3) && (envPtr->procPtr == NULL)) { - return TCL_ERROR; - } - - /* * Make sure the variable names, if any, have no substitutions and just * refer to local scalars. */ @@ -412,36 +402,17 @@ TclCompileCatchCmd( cmdTokenPtr = TokenAfter(parsePtr->tokenPtr); if (parsePtr->numWords >= 3) { resultNameTokenPtr = TokenAfter(cmdTokenPtr); - /* DGP */ - if (resultNameTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { + PushVarNameWord(interp, resultNameTokenPtr, envPtr, TCL_CREATE_VAR, + &resultIndex, &isSimple, &isScalar, 2); + if (!isScalar || resultIndex < 0) { return TCL_ERROR; } - name = resultNameTokenPtr[1].start; - nameChars = resultNameTokenPtr[1].size; - if (!TclIsLocalScalar(name, nameChars)) { - return TCL_ERROR; - } - resultIndex = TclFindCompiledLocal(resultNameTokenPtr[1].start, - resultNameTokenPtr[1].size, /*create*/ 1, envPtr->procPtr); - if (resultIndex < 0) { - return TCL_ERROR; - } - - /* DKF */ if (parsePtr->numWords == 4) { optsNameTokenPtr = TokenAfter(resultNameTokenPtr); - if (optsNameTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; - } - name = optsNameTokenPtr[1].start; - nameChars = optsNameTokenPtr[1].size; - if (!TclIsLocalScalar(name, nameChars)) { - return TCL_ERROR; - } - optsIndex = TclFindCompiledLocal(optsNameTokenPtr[1].start, - optsNameTokenPtr[1].size, /*create*/ 1, envPtr->procPtr); - if (optsIndex < 0) { + PushVarNameWord(interp, optsNameTokenPtr, envPtr, TCL_CREATE_VAR, + &optsIndex, &isSimple, &isScalar, 2); + if (!isScalar || resultIndex < 0) { return TCL_ERROR; } } -- cgit v0.12 From a417c667a52117af242053c93f3526069187ef95 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 11 Dec 2014 14:41:09 +0000 Subject: Get the word number right, even though it has no effect. --- generic/tclCompCmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 10cba39..e0dee13 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -411,7 +411,7 @@ TclCompileCatchCmd( if (parsePtr->numWords == 4) { optsNameTokenPtr = TokenAfter(resultNameTokenPtr); PushVarNameWord(interp, optsNameTokenPtr, envPtr, TCL_CREATE_VAR, - &optsIndex, &isSimple, &isScalar, 2); + &optsIndex, &isSimple, &isScalar, 3); if (!isScalar || resultIndex < 0) { return TCL_ERROR; } -- cgit v0.12 From 8e80c62f6f65a921aa7f69158b13f2e849f17439 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 11 Dec 2014 15:19:38 +0000 Subject: Similar revisions to [dict incr] compiler. --- generic/tclCompCmds.c | 60 +++++++++++++++++++-------------------------------- 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index e0dee13..33598e7 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -707,20 +707,31 @@ TclCompileDictIncrCmd( * compiled. */ CompileEnv *envPtr) /* Holds resulting instructions. */ { - Proc *procPtr = envPtr->procPtr; - DefineLineInformation; /* TIP #280 */ Tcl_Token *varTokenPtr, *keyTokenPtr; - int dictVarIndex, nameChars, incrAmount; - const char *name; + int dictVarIndex, incrAmount, isScalar, isSimple; + DefineLineInformation; /* TIP #280 */ /* * There must be at least two arguments after the command. */ - if (parsePtr->numWords < 3 || parsePtr->numWords > 4 || procPtr == NULL) { + if (parsePtr->numWords < 3 || parsePtr->numWords > 4) { return TCL_ERROR; } + + /* + * The dictionary variable must be a local scalar that is knowable at + * compile time; anything else exceeds the complexity of the opcode. So + * discover what the index is. + */ + varTokenPtr = TokenAfter(parsePtr->tokenPtr); + PushVarNameWord(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, + &dictVarIndex, &isSimple, &isScalar, 1); + if (!isScalar || dictVarIndex < 0) { + return TCL_ERROR; + } + keyTokenPtr = TokenAfter(varTokenPtr); /* @@ -728,23 +739,12 @@ TclCompileDictIncrCmd( */ if (parsePtr->numWords == 4) { - const char *word; - int numBytes, code; - Tcl_Token *incrTokenPtr; - Tcl_Obj *intObj; - - incrTokenPtr = TokenAfter(keyTokenPtr); - if (incrTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; - } - word = incrTokenPtr[1].start; - numBytes = incrTokenPtr[1].size; - - intObj = Tcl_NewStringObj(word, numBytes); - Tcl_IncrRefCount(intObj); - code = TclGetIntFromObj(NULL, intObj, &incrAmount); - TclDecrRefCount(intObj); - if (code != TCL_OK) { + Tcl_Token *incrTokenPtr = TokenAfter(keyTokenPtr); + Tcl_Obj *intObj = Tcl_NewObj(); + int fail = (!TclWordKnownAtCompileTime(incrTokenPtr, intObj) + || TCL_ERROR == TclGetIntFromObj(NULL, intObj, &incrAmount)); + Tcl_DecrRefCount(intObj); + if (fail) { return TCL_ERROR; } } else { @@ -752,22 +752,6 @@ TclCompileDictIncrCmd( } /* - * The dictionary variable must be a local scalar that is knowable at - * compile time; anything else exceeds the complexity of the opcode. So - * discover what the index is. - */ - - if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; - } - name = varTokenPtr[1].start; - nameChars = varTokenPtr[1].size; - if (!TclIsLocalScalar(name, nameChars)) { - return TCL_ERROR; - } - dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, procPtr); - - /* * Emit the key and the code to actually do the increment. */ -- cgit v0.12 From 604faa265f3f4197582673cddb2acd4c7a0ef6a5 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 11 Dec 2014 15:45:16 +0000 Subject: Similar conversion for [dict update] compiler. --- generic/tclCompCmds.c | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 33598e7..0c5b19d 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -818,7 +818,7 @@ TclCompileDictForCmd( Tcl_DString buffer; /* - * There must be at least three argument after the command. + * There must be exactly three arguments after the command. */ if (parsePtr->numWords != 4 || procPtr == NULL) { @@ -1004,21 +1004,11 @@ TclCompileDictUpdateCmd( * compiled. */ CompileEnv *envPtr) /* Holds resulting instructions. */ { - Proc *procPtr = envPtr->procPtr; - DefineLineInformation; /* TIP #280 */ - const char *name; - int i, nameChars, dictIndex, numVars, range, infoIndex; + int i, dictIndex, numVars, range, infoIndex, isSimple, isScalar; Tcl_Token **keyTokenPtrs, *dictVarTokenPtr, *bodyTokenPtr, *tokenPtr; DictUpdateInfo *duiPtr; JumpFixup jumpFixup; - - /* - * There must be at least one argument after the command. - */ - - if (parsePtr->numWords < 5 || procPtr == NULL) { - return TCL_ERROR; - } + DefineLineInformation; /* TIP #280 */ /* * Parse the command. Expect the following: @@ -1029,6 +1019,9 @@ TclCompileDictUpdateCmd( return TCL_ERROR; } numVars = (parsePtr->numWords - 3) / 2; + if (numVars < 1) { + return TCL_ERROR; + } /* * The dictionary variable must be a local scalar that is knowable at @@ -1037,15 +1030,11 @@ TclCompileDictUpdateCmd( */ dictVarTokenPtr = TokenAfter(parsePtr->tokenPtr); - if (dictVarTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; - } - name = dictVarTokenPtr[1].start; - nameChars = dictVarTokenPtr[1].size; - if (!TclIsLocalScalar(name, nameChars)) { + PushVarNameWord(interp, dictVarTokenPtr, envPtr, TCL_CREATE_VAR, + &dictIndex, &isSimple, &isScalar, 1); + if (!isScalar || dictIndex < 0) { return TCL_ERROR; } - dictIndex = TclFindCompiledLocal(name, nameChars, 1, procPtr); /* * Assemble the instruction metadata. This is complex enough that it is @@ -1061,6 +1050,8 @@ TclCompileDictUpdateCmd( tokenPtr = TokenAfter(dictVarTokenPtr); for (i=0 ; itype != TCL_TOKEN_SIMPLE_WORD) { - ckfree((char *) duiPtr); - TclStackFree(interp, keyTokenPtrs); - return TCL_ERROR; - } - name = tokenPtr[1].start; - nameChars = tokenPtr[1].size; - if (!TclIsLocalScalar(name, nameChars)) { + PushVarNameWord(interp, tokenPtr, envPtr, TCL_CREATE_VAR, + &index, &isSimple, &isScalar, 1); + if (!isScalar || index < 0) { ckfree((char *) duiPtr); TclStackFree(interp, keyTokenPtrs); return TCL_ERROR; @@ -1089,8 +1075,7 @@ TclCompileDictUpdateCmd( * Stash the index in the auxiliary data. */ - duiPtr->varIndices[i] = - TclFindCompiledLocal(name, nameChars, 1, procPtr); + duiPtr->varIndices[i] = index; tokenPtr = TokenAfter(tokenPtr); } if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { -- cgit v0.12 From ee5c231ff5dde87b4436f0de5fa6a6059df4b774 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 11 Dec 2014 16:00:19 +0000 Subject: Similar conversion of the [dict append] compiler. --- generic/tclCompCmds.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 0c5b19d..a0f493c 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -1156,18 +1156,17 @@ TclCompileDictAppendCmd( * compiled. */ CompileEnv *envPtr) /* Holds resulting instructions. */ { - Proc *procPtr = envPtr->procPtr; - DefineLineInformation; /* TIP #280 */ Tcl_Token *tokenPtr; - int i, dictVarIndex; + int i, isSimple, isScalar, dictVarIndex; + DefineLineInformation; /* TIP #280 */ /* - * There must be at least two argument after the command. And we impose an - * (arbirary) safe limit; anyone exceeding it should stop worrying about - * speed quite so much. ;-) + * There must be at least two argument after the command. Since we + * implement using INST_CONCAT1, make sure the number of arguments + * stays within its range. */ - if (parsePtr->numWords<4 || parsePtr->numWords>100 || procPtr==NULL) { + if (parsePtr->numWords<4 || parsePtr->numWords>258) { return TCL_ERROR; } @@ -1176,16 +1175,10 @@ TclCompileDictAppendCmd( */ tokenPtr = TokenAfter(parsePtr->tokenPtr); - if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { + PushVarNameWord(interp, tokenPtr, envPtr, TCL_CREATE_VAR, + &dictVarIndex, &isSimple, &isScalar, 1); + if (!isScalar || dictVarIndex < 0) { return TCL_ERROR; - } else { - register const char *name = tokenPtr[1].start; - register int nameChars = tokenPtr[1].size; - - if (!TclIsLocalScalar(name, nameChars)) { - return TCL_ERROR; - } - dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, procPtr); } /* -- cgit v0.12 From d7a9d635208125f64de188de24122509d0c624dc Mon Sep 17 00:00:00 2001 From: oehhar Date: Wed, 17 Dec 2014 08:22:23 +0000 Subject: Documented "fconfigure $h -connecting" on socket man page --- doc/socket.n | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/socket.n b/doc/socket.n index b7a4a45..492ca66 100644 --- a/doc/socket.n +++ b/doc/socket.n @@ -97,6 +97,10 @@ writable channel event on the socket to get notified when the asynchronous connection has succeeded or failed. See the \fBvwait\fR and the \fBchan\fR commands for more details on the event loop and channel events. +.PP +The \fBchan configure\fR option \fB-connecting\fR may be used to check if the connect is still running. To verify a successful connect, the option \fB-error\fR may be checked when \fB-connecting\fR returned 0. +.PP +Operation without the event queue requires at the moment calls to \fBchan configure\fR to advance the internal state machine. .RE .SH "SERVER SOCKETS" .PP @@ -186,6 +190,11 @@ sockets, this option returns a list of three elements; these are the address, the host name and the port to which the peer socket is connected or bound. If the host name cannot be computed, the second element of the list is identical to the address, its first element. +.RE +.TP +\fB\-connecting\fR +. +This option is not supported by server sockets. For client sockets, this option returns 1 if an asyncroneous connect is still in progress, 0 otherwise. .PP .SH "EXAMPLES" .PP -- cgit v0.12 From 3b7664e77fa5643a858e66e21458dc0eaeaffeb6 Mon Sep 17 00:00:00 2001 From: oehhar Date: Wed, 17 Dec 2014 08:42:24 +0000 Subject: Include option -connecting in test iocmd-8.15.1 --- tests/ioCmd.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ioCmd.test b/tests/ioCmd.test index 57f8d47..4fbc380 100644 --- a/tests/ioCmd.test +++ b/tests/ioCmd.test @@ -294,7 +294,7 @@ test iocmd-8.15.1 {fconfigure command / tcp channel} -constraints {socket unixOr close $srv unset cli srv port rename iocmdSRV {} -} -returnCodes error -result {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, -peername, or -sockname} +} -returnCodes error -result {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, -connecting, -peername, or -sockname} test iocmd-8.16 {fconfigure command / tcp channel} -constraints socket -setup { set srv [socket -server iocmdSRV -myaddr 127.0.0.1 0] set port [lindex [fconfigure $srv -sockname] 2] -- cgit v0.12 From 68b5780dde6d75819809b071fb27d935cee69fdc Mon Sep 17 00:00:00 2001 From: oehhar Date: Wed, 17 Dec 2014 11:21:16 +0000 Subject: changes for TIP427 --- changes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changes b/changes index 1decfe2..79a242d 100644 --- a/changes +++ b/changes @@ -8491,3 +8491,5 @@ include ::oo::class (fellows) 2014-11-06 (bug)[5adc35] Stop forcing EOF to be permanent (porter) --- Released 8.6.3, November 12, 2014 --- http://core.tcl.tk/tcl/ for details + +2014-12-17 (TIP 427) [fconfigure $h -connecting, -peername, -sockname] (oehlmann,rmax) -- cgit v0.12 From e942227f6e2651032ec7a070d1562c4b050de9b3 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 17 Dec 2014 19:57:40 +0000 Subject: Revise encoding finalization so that it does a more complete job of restoring the pre-initialized state. This makes finalization errors more repeatable and cross-platform. --- generic/tclEncoding.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/generic/tclEncoding.c b/generic/tclEncoding.c index d246cb2..95c59c0 100644 --- a/generic/tclEncoding.c +++ b/generic/tclEncoding.c @@ -180,9 +180,9 @@ TCL_DECLARE_MUTEX(encodingMutex) * the system encoding will be used to perform the conversion. */ -static Tcl_Encoding defaultEncoding; -static Tcl_Encoding systemEncoding; -Tcl_Encoding tclIdentityEncoding; +static Tcl_Encoding defaultEncoding = NULL; +static Tcl_Encoding systemEncoding = NULL; +Tcl_Encoding tclIdentityEncoding = NULL; /* * The following variable is used in the sparse matrix code for a @@ -652,7 +652,10 @@ TclFinalizeEncodingSubsystem(void) Tcl_MutexLock(&encodingMutex); encodingsInitialized = 0; FreeEncoding(systemEncoding); + systemEncoding = NULL; + defaultEncoding = NULL; FreeEncoding(tclIdentityEncoding); + tclIdentityEncoding = NULL; hPtr = Tcl_FirstHashEntry(&encodingTable, &search); while (hPtr != NULL) { @@ -2960,7 +2963,9 @@ TableFreeProc( */ ckfree(dataPtr->toUnicode); + dataPtr->toUnicode = NULL; ckfree(dataPtr->fromUnicode); + dataPtr->fromUnicode = NULL; ckfree(dataPtr); } @@ -3433,6 +3438,7 @@ EscapeFreeProc( subTablePtr = dataPtr->subTables; for (i = 0; i < dataPtr->numSubTables; i++) { FreeEncoding((Tcl_Encoding) subTablePtr->encodingPtr); + subTablePtr->encodingPtr = NULL; subTablePtr++; } } -- cgit v0.12 From 955507f6352c466740d348d8d89adb8de24de9fd Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 17 Dec 2014 20:47:58 +0000 Subject: Rework the *FinalizeThread*() routines so that the quick exit preference is respected without need to run afoul of encoding finalizations. tests pass now. All changes are fully internal. --- generic/tclEvent.c | 14 +++++++++++--- generic/tclInt.h | 2 +- generic/tclThread.c | 4 ++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/generic/tclEvent.c b/generic/tclEvent.c index 3985767..6ca22a6 100644 --- a/generic/tclEvent.c +++ b/generic/tclEvent.c @@ -119,6 +119,7 @@ static char * VwaitVarProc(ClientData clientData, Tcl_Interp *interp, const char *name1, const char *name2, int flags); static void InvokeExitHandlers(void); +static void FinalizeThread(int quick); /* *---------------------------------------------------------------------- @@ -983,7 +984,7 @@ Tcl_Exit( * Tcl_Channels that may have data enqueued. */ - Tcl_FinalizeThread(); + FinalizeThread(/* quick */ 1); } TclpExit(status); Tcl_Panic("OS exit failed!"); @@ -1183,7 +1184,7 @@ Tcl_Finalize(void) * This fixes the Tcl Bug #990552. */ - TclFinalizeThreadData(); + TclFinalizeThreadData(/* quick */ 0); /* * Now we can free constants for conversions to/from double. @@ -1269,6 +1270,13 @@ Tcl_Finalize(void) void Tcl_FinalizeThread(void) { + FinalizeThread(/* quick */ 0); +} + +void +FinalizeThread( + int quick) +{ ExitHandler *exitPtr; ThreadSpecificData *tsdPtr; @@ -1309,7 +1317,7 @@ Tcl_FinalizeThread(void) * * Fix [Bug #571002] */ - TclFinalizeThreadData(); + TclFinalizeThreadData(quick); } /* diff --git a/generic/tclInt.h b/generic/tclInt.h index c989eda..995da48 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2927,7 +2927,7 @@ MODULE_SCOPE void TclFinalizePreserve(void); MODULE_SCOPE void TclFinalizeSynchronization(void); MODULE_SCOPE void TclFinalizeThreadAlloc(void); MODULE_SCOPE void TclFinalizeThreadAllocThread(void); -MODULE_SCOPE void TclFinalizeThreadData(void); +MODULE_SCOPE void TclFinalizeThreadData(int quick); MODULE_SCOPE void TclFinalizeThreadObjects(void); MODULE_SCOPE double TclFloor(const mp_int *a); MODULE_SCOPE void TclFormatNaN(double value, char *buffer); diff --git a/generic/tclThread.c b/generic/tclThread.c index 5ac6a8d..198fa6a 100644 --- a/generic/tclThread.c +++ b/generic/tclThread.c @@ -353,11 +353,11 @@ Tcl_ConditionFinalize( */ void -TclFinalizeThreadData(void) +TclFinalizeThreadData(int quick) { TclFinalizeThreadDataThread(); #if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) - if ((!TclInExit())||TclFullFinalizationRequested()) { + if (!quick) { /* * Quick exit principle makes it useless to terminate allocators */ -- cgit v0.12 From 559113cc4c38b5bc99f503e300671df52b991d13 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 18 Dec 2014 18:06:51 +0000 Subject: [7c187a3773] Fix error in managing inStatePtr->inQueueTail value in the byte-moving optimized path of [chan copy]. Thanks to Benno. --- generic/tclIO.c | 3 +++ tests/io.test | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/generic/tclIO.c b/generic/tclIO.c index 2025742..8a35aee 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -9215,6 +9215,9 @@ MBWrite( } outStatePtr->outQueueTail = tail; inStatePtr->inQueueHead = bufPtr; + if (inStatePtr->inQueueTail == tail) { + inStatePtr->inQueueTail = bufPtr; + } if (bufPtr == NULL) { inStatePtr->inQueueTail = NULL; } diff --git a/tests/io.test b/tests/io.test index b09d55a..cd8b014 100644 --- a/tests/io.test +++ b/tests/io.test @@ -7900,6 +7900,44 @@ test io-53.16 {[ed29c4da21] MBRead: fblocked seen as error} -setup { close $c removeFile out } -result 100 +test io-53.17 {[7c187a3773] MBWrite: proper inQueueTail handling} -setup { + proc driver {cmd args} { + variable buffer + variable index + set chan [lindex $args 0] + switch -- $cmd { + initialize { + set index($chan) 0 + set buffer($chan) [encoding convertto utf-8 \ + line\n[string repeat a 100]line\n] + return {initialize finalize watch read} + } + finalize { + unset index($chan) buffer($chan) + return + } + watch {} + read { + set n [lindex $args 1] + set new [expr {$index($chan) + $n}] + set result [string range $buffer($chan) $index($chan) $new-1] + set index($chan) $new + return $result + } + } + } + set c [chan create read [namespace which driver]] + chan configure $c -encoding utf-8 -translation lf -buffersize 107 + set out [makeFile {} out] + set outChan [open $out w] + chan configure $outChan -encoding utf-8 -translation lf +} -body { + list [gets $c] [chan copy $c $outChan -size 100] [gets $c] +} -cleanup { + close $outChan + close $c + removeFile out +} -result {line 100 line} test io-54.1 {Recursive channel events} {socket fileevent} { # This test checks to see if file events are delivered during recursive -- cgit v0.12 From d56e61b246f06cd10844c54a54f2d04aa4d47ade Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 18 Dec 2014 19:21:31 +0000 Subject: Shift the allocation of AuxData earlier in the [foreach] compiler. --- generic/tclCompCmds.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index a0f493c..f07b19f 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -1536,7 +1536,7 @@ TclCompileForeachCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Proc *procPtr = envPtr->procPtr; - ForeachInfo *infoPtr; /* Points to the structure describing this + ForeachInfo *infoPtr = NULL;/* Points to the structure describing this * foreach command. Stored in a AuxData * record in the ByteCode. */ int firstValueTemp; /* Index of the first temp var in the frame @@ -1599,6 +1599,16 @@ TclCompileForeachCmd( memset((char*) varvList, 0, numLists * sizeof(const char **)); /* + * Create and initialize the ForeachInfo and ForeachVarList data + * structures describing this command. Then create a AuxData record + * pointing to the ForeachInfo structure. + */ + + infoPtr = (ForeachInfo *) ckalloc((unsigned) + sizeof(ForeachInfo) + numLists*sizeof(ForeachVarList *)); + infoPtr->numLists = 0; /* Count this up as we go */ + + /* * Break up each var list and set the varcList and varvList arrays. Don't * compile the foreach inline if any var name needs substitutions or isn't * a scalar, or if any var list needs substitutions. @@ -1609,6 +1619,7 @@ TclCompileForeachCmd( i < numWords-1; i++, tokenPtr = TokenAfter(tokenPtr)) { Tcl_DString varList; + ForeachVarList *varListPtr; if (i%2 != 1) { continue; @@ -1634,6 +1645,12 @@ TclCompileForeachCmd( } numVars = varcList[loopIndex]; + varListPtr = (ForeachVarList *) ckalloc((unsigned) + sizeof(ForeachVarList) + numVars*sizeof(int)); + varListPtr->numVars = numVars; + infoPtr->varLists[loopIndex] = varListPtr; + infoPtr->numLists++; + /* * If the variable list is empty, we can enter an infinite loop when * the interpreted version would not. Take care to ensure this does @@ -1678,23 +1695,11 @@ TclCompileForeachCmd( loopCtTemp = TclFindCompiledLocal(NULL, /*nameChars*/ 0, /*create*/ 1, procPtr); - /* - * Create and initialize the ForeachInfo and ForeachVarList data - * structures describing this command. Then create a AuxData record - * pointing to the ForeachInfo structure. - */ - - infoPtr = (ForeachInfo *) ckalloc((unsigned) - sizeof(ForeachInfo) + numLists*sizeof(ForeachVarList *)); - infoPtr->numLists = numLists; infoPtr->firstValueTemp = firstValueTemp; infoPtr->loopCtTemp = loopCtTemp; for (loopIndex = 0; loopIndex < numLists; loopIndex++) { - ForeachVarList *varListPtr; - numVars = varcList[loopIndex]; - varListPtr = (ForeachVarList *) ckalloc((unsigned) - sizeof(ForeachVarList) + numVars*sizeof(int)); - varListPtr->numVars = numVars; + ForeachVarList *varListPtr = infoPtr->varLists[loopIndex]; + numVars = varListPtr->numVars; for (j = 0; j < numVars; j++) { const char *varName = varvList[loopIndex][j]; int nameChars = strlen(varName); @@ -1702,7 +1707,6 @@ TclCompileForeachCmd( varListPtr->varIndexes[j] = TclFindCompiledLocal(varName, nameChars, /*create*/ 1, procPtr); } - infoPtr->varLists[loopIndex] = varListPtr; } infoIndex = TclCreateAuxData(infoPtr, &tclForeachInfoType, envPtr); @@ -1816,6 +1820,11 @@ TclCompileForeachCmd( envPtr->currStackDepth = savedStackDepth + 1; done: + if (code == TCL_ERROR) { + if (infoPtr) { + FreeForeachInfo(infoPtr); + } + } for (loopIndex = 0; loopIndex < numLists; loopIndex++) { if (varvList[loopIndex] != NULL) { ckfree((char *) varvList[loopIndex]); -- cgit v0.12 From f664d633e6a5f16b3af12c6b9fa406636711068c Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 18 Dec 2014 20:34:12 +0000 Subject: With that shift, varcList is no longer needed. --- generic/tclCompCmds.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index f07b19f..739bf21 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -1553,11 +1553,9 @@ TclCompileForeachCmd( /* * We parse the variable list argument words and create two arrays: - * varcList[i] is number of variables in i-th var list. * varvList[i] points to array of var names in i-th var list. */ - int *varcList; const char ***varvList; /* @@ -1592,8 +1590,6 @@ TclCompileForeachCmd( */ numLists = (numWords - 2)/2; - varcList = (int *) TclStackAlloc(interp, numLists * sizeof(int)); - memset(varcList, 0, numLists * sizeof(int)); varvList = (const char ***) TclStackAlloc(interp, numLists * sizeof(const char **)); memset((char*) varvList, 0, numLists * sizeof(const char **)); @@ -1637,13 +1633,12 @@ TclCompileForeachCmd( Tcl_DStringInit(&varList); Tcl_DStringAppend(&varList, tokenPtr[1].start, tokenPtr[1].size); code = Tcl_SplitList(interp, Tcl_DStringValue(&varList), - &varcList[loopIndex], &varvList[loopIndex]); + &numVars, &varvList[loopIndex]); Tcl_DStringFree(&varList); if (code != TCL_OK) { code = TCL_ERROR; goto done; } - numVars = varcList[loopIndex]; varListPtr = (ForeachVarList *) ckalloc((unsigned) sizeof(ForeachVarList) + numVars*sizeof(int)); @@ -1831,7 +1826,6 @@ TclCompileForeachCmd( } } TclStackFree(interp, (void *)varvList); - TclStackFree(interp, varcList); return code; } -- cgit v0.12 From 89e6a65411bda475baf46fcc2b3cf36c2eb81b4c Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 18 Dec 2014 20:38:53 +0000 Subject: Simplify creation and storage of temporaries --- generic/tclCompCmds.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 739bf21..d2d14f0 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -1539,10 +1539,6 @@ TclCompileForeachCmd( ForeachInfo *infoPtr = NULL;/* Points to the structure describing this * foreach command. Stored in a AuxData * record in the ByteCode. */ - int firstValueTemp; /* Index of the first temp var in the frame - * used to point to a value list. */ - int loopCtTemp; /* Index of temp var holding the loop's - * iteration count. */ Tcl_Token *tokenPtr, *bodyTokenPtr; unsigned char *jumpPc; JumpFixup jumpFalseFixup; @@ -1679,19 +1675,14 @@ TclCompileForeachCmd( */ code = TCL_OK; - firstValueTemp = -1; - for (loopIndex = 0; loopIndex < numLists; loopIndex++) { - tempVar = TclFindCompiledLocal(NULL, /*nameChars*/ 0, - /*create*/ 1, procPtr); - if (loopIndex == 0) { - firstValueTemp = tempVar; - } + + tempVar = TclFindCompiledLocal(NULL, 0, 1, procPtr); + infoPtr->firstValueTemp = tempVar; + for (loopIndex = 1; loopIndex < numLists; loopIndex++) { + TclFindCompiledLocal(NULL, 0, 1, procPtr); } - loopCtTemp = TclFindCompiledLocal(NULL, /*nameChars*/ 0, - /*create*/ 1, procPtr); + infoPtr->loopCtTemp = TclFindCompiledLocal(NULL, 0, 1, procPtr); - infoPtr->firstValueTemp = firstValueTemp; - infoPtr->loopCtTemp = loopCtTemp; for (loopIndex = 0; loopIndex < numLists; loopIndex++) { ForeachVarList *varListPtr = infoPtr->varLists[loopIndex]; numVars = varListPtr->numVars; @@ -1722,14 +1713,13 @@ TclCompileForeachCmd( if ((i%2 == 0) && (i > 0)) { SetLineInformation (i); CompileTokens(envPtr, tokenPtr, interp); - tempVar = (firstValueTemp + loopIndex); if (tempVar <= 255) { TclEmitInstInt1(INST_STORE_SCALAR1, tempVar, envPtr); } else { TclEmitInstInt4(INST_STORE_SCALAR4, tempVar, envPtr); } TclEmitOpcode(INST_POP, envPtr); - loopIndex++; + loopIndex++; tempVar++; } } -- cgit v0.12 From 24817641b1ed1c0c461993db32e92d2a947319de Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 18 Dec 2014 21:08:53 +0000 Subject: Replace use of TclIsLocalScalar() and late setting of varIndexes with an earlier setting of varIndexes using PushVarNameWord(). --- generic/tclCompCmds.c | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index d2d14f0..bae1fd1 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -1545,6 +1545,7 @@ TclCompileForeachCmd( int jumpBackDist, jumpBackOffset, infoIndex, range; int numWords, numLists, numVars, loopIndex, tempVar, i, j, code; int savedStackDepth = envPtr->currStackDepth; + Tcl_Obj *varListObj = NULL; DefineLineInformation; /* TIP #280 */ /* @@ -1607,6 +1608,7 @@ TclCompileForeachCmd( */ loopIndex = 0; + varListObj = Tcl_NewObj(); for (i = 0, tokenPtr = parsePtr->tokenPtr; i < numWords-1; i++, tokenPtr = TokenAfter(tokenPtr)) { @@ -1616,7 +1618,16 @@ TclCompileForeachCmd( if (i%2 != 1) { continue; } - if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { + + /* + * If the variable list is empty, we can enter an infinite loop when + * the interpreted version would not. Take care to ensure this does + * not happen. [Bug 1671138] + */ + + if (!TclWordKnownAtCompileTime(tokenPtr, varListObj) || + TCL_OK != Tcl_ListObjLength(NULL, varListObj, &numVars) || + numVars == 0) { code = TCL_ERROR; goto done; } @@ -1642,25 +1653,23 @@ TclCompileForeachCmd( infoPtr->varLists[loopIndex] = varListPtr; infoPtr->numLists++; - /* - * If the variable list is empty, we can enter an infinite loop when - * the interpreted version would not. Take care to ensure this does - * not happen. [Bug 1671138] - */ - - if (numVars == 0) { - code = TCL_ERROR; - goto done; - } - for (j = 0; j < numVars; j++) { - const char *varName = varvList[loopIndex][j]; - - if (!TclIsLocalScalar(varName, (int) strlen(varName))) { + Tcl_Obj *varNameObj; + Tcl_Token token; + int varIndex, isSimple, isScalar; + + Tcl_ListObjIndex(NULL, varListObj, j, &varNameObj); + token.start = Tcl_GetStringFromObj(varNameObj, &token.size); + PushVarNameWord(interp, &token, envPtr, TCL_CREATE_VAR, + &varIndex, &isSimple, &isScalar, 0 /* ignored */); + if (!isScalar || varIndex < 0) { code = TCL_ERROR; goto done; } + varListPtr->varIndexes[j] = varIndex; } + + Tcl_SetObjLength(varListObj, 0); loopIndex++; } @@ -1683,6 +1692,7 @@ TclCompileForeachCmd( } infoPtr->loopCtTemp = TclFindCompiledLocal(NULL, 0, 1, procPtr); +#if 0 for (loopIndex = 0; loopIndex < numLists; loopIndex++) { ForeachVarList *varListPtr = infoPtr->varLists[loopIndex]; numVars = varListPtr->numVars; @@ -1694,6 +1704,7 @@ TclCompileForeachCmd( nameChars, /*create*/ 1, procPtr); } } +#endif infoIndex = TclCreateAuxData(infoPtr, &tclForeachInfoType, envPtr); /* @@ -1810,6 +1821,9 @@ TclCompileForeachCmd( FreeForeachInfo(infoPtr); } } + if (varListObj) { + Tcl_DecrRefCount(varListObj); + } for (loopIndex = 0; loopIndex < numLists; loopIndex++) { if (varvList[loopIndex] != NULL) { ckfree((char *) varvList[loopIndex]); -- cgit v0.12 From 893c9c730286e9cdb5d98d190d4ff5877fd47efb Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 18 Dec 2014 21:29:07 +0000 Subject: Fix up the token array passed to PushVarNameWord. Remove string list parse. --- generic/tclCompCmds.c | 39 ++++++--------------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index bae1fd1..6fa1e71 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -1543,7 +1543,7 @@ TclCompileForeachCmd( unsigned char *jumpPc; JumpFixup jumpFalseFixup; int jumpBackDist, jumpBackOffset, infoIndex, range; - int numWords, numLists, numVars, loopIndex, tempVar, i, j, code; + int numWords, numLists, numVars, loopIndex, tempVar, i, j, code = TCL_OK; int savedStackDepth = envPtr->currStackDepth; Tcl_Obj *varListObj = NULL; DefineLineInformation; /* TIP #280 */ @@ -1612,7 +1612,6 @@ TclCompileForeachCmd( for (i = 0, tokenPtr = parsePtr->tokenPtr; i < numWords-1; i++, tokenPtr = TokenAfter(tokenPtr)) { - Tcl_DString varList; ForeachVarList *varListPtr; if (i%2 != 1) { @@ -1632,21 +1631,6 @@ TclCompileForeachCmd( goto done; } - /* - * Lots of copying going on here. Need a ListObj wizard to show a - * better way. - */ - - Tcl_DStringInit(&varList); - Tcl_DStringAppend(&varList, tokenPtr[1].start, tokenPtr[1].size); - code = Tcl_SplitList(interp, Tcl_DStringValue(&varList), - &numVars, &varvList[loopIndex]); - Tcl_DStringFree(&varList); - if (code != TCL_OK) { - code = TCL_ERROR; - goto done; - } - varListPtr = (ForeachVarList *) ckalloc((unsigned) sizeof(ForeachVarList) + numVars*sizeof(int)); varListPtr->numVars = numVars; @@ -1655,12 +1639,14 @@ TclCompileForeachCmd( for (j = 0; j < numVars; j++) { Tcl_Obj *varNameObj; - Tcl_Token token; + Tcl_Token token[2]; int varIndex, isSimple, isScalar; Tcl_ListObjIndex(NULL, varListObj, j, &varNameObj); - token.start = Tcl_GetStringFromObj(varNameObj, &token.size); - PushVarNameWord(interp, &token, envPtr, TCL_CREATE_VAR, + token[0].type = TCL_TOKEN_SIMPLE_WORD; + token[0].numComponents = 1; + token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); + PushVarNameWord(interp, token, envPtr, TCL_CREATE_VAR, &varIndex, &isSimple, &isScalar, 0 /* ignored */); if (!isScalar || varIndex < 0) { code = TCL_ERROR; @@ -1692,19 +1678,6 @@ TclCompileForeachCmd( } infoPtr->loopCtTemp = TclFindCompiledLocal(NULL, 0, 1, procPtr); -#if 0 - for (loopIndex = 0; loopIndex < numLists; loopIndex++) { - ForeachVarList *varListPtr = infoPtr->varLists[loopIndex]; - numVars = varListPtr->numVars; - for (j = 0; j < numVars; j++) { - const char *varName = varvList[loopIndex][j]; - int nameChars = strlen(varName); - - varListPtr->varIndexes[j] = TclFindCompiledLocal(varName, - nameChars, /*create*/ 1, procPtr); - } - } -#endif infoIndex = TclCreateAuxData(infoPtr, &tclForeachInfoType, envPtr); /* -- cgit v0.12 From f65cb994d8c1ae7358d383f10c983758eb59fdf0 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 18 Dec 2014 22:00:08 +0000 Subject: No need for varvList any more. --- generic/tclCompCmds.c | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 6fa1e71..1bafbe2 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -1549,13 +1549,6 @@ TclCompileForeachCmd( DefineLineInformation; /* TIP #280 */ /* - * We parse the variable list argument words and create two arrays: - * varvList[i] points to array of var names in i-th var list. - */ - - const char ***varvList; - - /* * If the foreach command isn't in a procedure, don't compile it inline: * the payoff is too small. */ @@ -1583,26 +1576,18 @@ TclCompileForeachCmd( } /* - * Allocate storage for the varcList and varvList arrays if necessary. - */ - - numLists = (numWords - 2)/2; - varvList = (const char ***) TclStackAlloc(interp, - numLists * sizeof(const char **)); - memset((char*) varvList, 0, numLists * sizeof(const char **)); - - /* * Create and initialize the ForeachInfo and ForeachVarList data * structures describing this command. Then create a AuxData record * pointing to the ForeachInfo structure. */ + numLists = (numWords - 2)/2; infoPtr = (ForeachInfo *) ckalloc((unsigned) sizeof(ForeachInfo) + numLists*sizeof(ForeachVarList *)); infoPtr->numLists = 0; /* Count this up as we go */ /* - * Break up each var list and set the varcList and varvList arrays. Don't + * Parse each var list into sequence of var names. Don't * compile the foreach inline if any var name needs substitutions or isn't * a scalar, or if any var list needs substitutions. */ @@ -1669,8 +1654,6 @@ TclCompileForeachCmd( * nonoverlapping foreach loops, they don't share any temps. */ - code = TCL_OK; - tempVar = TclFindCompiledLocal(NULL, 0, 1, procPtr); infoPtr->firstValueTemp = tempVar; for (loopIndex = 1; loopIndex < numLists; loopIndex++) { @@ -1797,12 +1780,6 @@ TclCompileForeachCmd( if (varListObj) { Tcl_DecrRefCount(varListObj); } - for (loopIndex = 0; loopIndex < numLists; loopIndex++) { - if (varvList[loopIndex] != NULL) { - ckfree((char *) varvList[loopIndex]); - } - } - TclStackFree(interp, (void *)varvList); return code; } -- cgit v0.12 From aed72bee30f449ec04643ceb42df9d45b635892e Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 18 Dec 2014 22:13:11 +0000 Subject: No need for a loopIndex. --- generic/tclCompCmds.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 1bafbe2..0030f62 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -1543,7 +1543,7 @@ TclCompileForeachCmd( unsigned char *jumpPc; JumpFixup jumpFalseFixup; int jumpBackDist, jumpBackOffset, infoIndex, range; - int numWords, numLists, numVars, loopIndex, tempVar, i, j, code = TCL_OK; + int numWords, numLists, numVars, tempVar, i, j, code = TCL_OK; int savedStackDepth = envPtr->currStackDepth; Tcl_Obj *varListObj = NULL; DefineLineInformation; /* TIP #280 */ @@ -1592,7 +1592,6 @@ TclCompileForeachCmd( * a scalar, or if any var list needs substitutions. */ - loopIndex = 0; varListObj = Tcl_NewObj(); for (i = 0, tokenPtr = parsePtr->tokenPtr; i < numWords-1; @@ -1619,7 +1618,7 @@ TclCompileForeachCmd( varListPtr = (ForeachVarList *) ckalloc((unsigned) sizeof(ForeachVarList) + numVars*sizeof(int)); varListPtr->numVars = numVars; - infoPtr->varLists[loopIndex] = varListPtr; + infoPtr->varLists[i/2] = varListPtr; infoPtr->numLists++; for (j = 0; j < numVars; j++) { @@ -1641,7 +1640,6 @@ TclCompileForeachCmd( } Tcl_SetObjLength(varListObj, 0); - loopIndex++; } /* @@ -1656,7 +1654,7 @@ TclCompileForeachCmd( tempVar = TclFindCompiledLocal(NULL, 0, 1, procPtr); infoPtr->firstValueTemp = tempVar; - for (loopIndex = 1; loopIndex < numLists; loopIndex++) { + for (i= 1; i < numLists; i++) { TclFindCompiledLocal(NULL, 0, 1, procPtr); } infoPtr->loopCtTemp = TclFindCompiledLocal(NULL, 0, 1, procPtr); @@ -1673,7 +1671,6 @@ TclCompileForeachCmd( * Evaluate then store each value list in the associated temporary. */ - loopIndex = 0; for (i = 0, tokenPtr = parsePtr->tokenPtr; i < numWords-1; i++, tokenPtr = TokenAfter(tokenPtr)) { @@ -1686,7 +1683,7 @@ TclCompileForeachCmd( TclEmitInstInt4(INST_STORE_SCALAR4, tempVar, envPtr); } TclEmitOpcode(INST_POP, envPtr); - loopIndex++; tempVar++; + tempVar++; } } -- cgit v0.12 From ad195509092cfe037495a4817597fccf012bf686 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 18 Dec 2014 22:25:27 +0000 Subject: A bit more tidying... --- generic/tclCompCmds.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 0030f62..002012e 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -1540,6 +1540,7 @@ TclCompileForeachCmd( * foreach command. Stored in a AuxData * record in the ByteCode. */ Tcl_Token *tokenPtr, *bodyTokenPtr; + Tcl_Token token[2]; unsigned char *jumpPc; JumpFixup jumpFalseFixup; int jumpBackDist, jumpBackOffset, infoIndex, range; @@ -1593,6 +1594,8 @@ TclCompileForeachCmd( */ varListObj = Tcl_NewObj(); + token[0].type = TCL_TOKEN_SIMPLE_WORD; + token[0].numComponents = 1; for (i = 0, tokenPtr = parsePtr->tokenPtr; i < numWords-1; i++, tokenPtr = TokenAfter(tokenPtr)) { @@ -1623,12 +1626,9 @@ TclCompileForeachCmd( for (j = 0; j < numVars; j++) { Tcl_Obj *varNameObj; - Tcl_Token token[2]; int varIndex, isSimple, isScalar; Tcl_ListObjIndex(NULL, varListObj, j, &varNameObj); - token[0].type = TCL_TOKEN_SIMPLE_WORD; - token[0].numComponents = 1; token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); PushVarNameWord(interp, token, envPtr, TCL_CREATE_VAR, &varIndex, &isSimple, &isScalar, 0 /* ignored */); @@ -1638,13 +1638,11 @@ TclCompileForeachCmd( } varListPtr->varIndexes[j] = varIndex; } - Tcl_SetObjLength(varListObj, 0); } /* - * We will compile the foreach command. Reserve (numLists + 1) temporary - * variables: + * Reserve (numLists + 1) temporary variables: * - numLists temps to hold each value list * - 1 temp for the loop counter (index of next element in each list) * -- cgit v0.12 From 88ec3c9772a4b3e03d7e18067452ae8b67a7b3c7 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 19 Dec 2014 03:31:09 +0000 Subject: Narrow scope of numVars. --- generic/tclCompCmds.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 002012e..48eafe5 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -1544,7 +1544,7 @@ TclCompileForeachCmd( unsigned char *jumpPc; JumpFixup jumpFalseFixup; int jumpBackDist, jumpBackOffset, infoIndex, range; - int numWords, numLists, numVars, tempVar, i, j, code = TCL_OK; + int numWords, numLists, tempVar, i, j, code = TCL_OK; int savedStackDepth = envPtr->currStackDepth; Tcl_Obj *varListObj = NULL; DefineLineInformation; /* TIP #280 */ @@ -1600,6 +1600,7 @@ TclCompileForeachCmd( i < numWords-1; i++, tokenPtr = TokenAfter(tokenPtr)) { ForeachVarList *varListPtr; + int numVars; if (i%2 != 1) { continue; -- cgit v0.12 From baf649278ac11f772a6921121574bb6fe65ed127 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 19 Dec 2014 14:17:03 +0000 Subject: Replace TclIsLocalScalar() with PushVarNameWord() in [dict for] compiler. --- generic/tclCompCmds.c | 53 ++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 48eafe5..9ccfcb6 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -806,16 +806,17 @@ TclCompileDictForCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Proc *procPtr = envPtr->procPtr; - DefineLineInformation; /* TIP #280 */ Tcl_Token *varsTokenPtr, *dictTokenPtr, *bodyTokenPtr; - int keyVarIndex, valueVarIndex, nameChars, loopRange, catchRange; + int keyVarIndex, valueVarIndex, loopRange, catchRange; int infoIndex, jumpDisplacement, bodyTargetOffset, emptyTargetOffset; - int numVars, endTargetOffset; + int numVars, endTargetOffset, isSimple, isScalar; int savedStackDepth = envPtr->currStackDepth; /* Needed because jumps confuse the stack * space calculator. */ - const char **argv; - Tcl_DString buffer; + Tcl_Obj *varNameObj, *varListObj = NULL; + Tcl_Token token[2] = {{TCL_TOKEN_SIMPLE_WORD, NULL, 0, 1}, + {TCL_TOKEN_TEXT, NULL, 0, 0}}; + DefineLineInformation; /* TIP #280 */ /* * There must be exactly three arguments after the command. @@ -828,8 +829,8 @@ TclCompileDictForCmd( varsTokenPtr = TokenAfter(parsePtr->tokenPtr); dictTokenPtr = TokenAfter(varsTokenPtr); bodyTokenPtr = TokenAfter(dictTokenPtr); - if (varsTokenPtr->type != TCL_TOKEN_SIMPLE_WORD || - bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { + + if (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { return TCL_ERROR; } @@ -838,33 +839,33 @@ TclCompileDictForCmd( * Then extract their indices in the LVT. */ - Tcl_DStringInit(&buffer); - Tcl_DStringAppend(&buffer, varsTokenPtr[1].start, varsTokenPtr[1].size); - if (Tcl_SplitList(NULL, Tcl_DStringValue(&buffer), &numVars, - &argv) != TCL_OK) { - Tcl_DStringFree(&buffer); - return TCL_ERROR; - } - Tcl_DStringFree(&buffer); - if (numVars != 2) { - ckfree((char *) argv); + varListObj = Tcl_NewObj(); + if (!TclWordKnownAtCompileTime(varsTokenPtr, varListObj) || + TCL_OK != Tcl_ListObjLength(NULL, varListObj, &numVars) || + numVars != 2) { + Tcl_DecrRefCount(varListObj); return TCL_ERROR; } - nameChars = strlen(argv[0]); - if (!TclIsLocalScalar(argv[0], nameChars)) { - ckfree((char *) argv); + Tcl_ListObjIndex(NULL, varListObj, 0, &varNameObj); + token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); + PushVarNameWord(interp, token, envPtr, TCL_CREATE_VAR, + &keyVarIndex, &isSimple, &isScalar, 0 /* ignored */); + if (!isScalar || keyVarIndex < 0) { + Tcl_DecrRefCount(varListObj); return TCL_ERROR; } - keyVarIndex = TclFindCompiledLocal(argv[0], nameChars, 1, procPtr); - nameChars = strlen(argv[1]); - if (!TclIsLocalScalar(argv[1], nameChars)) { - ckfree((char *) argv); + Tcl_ListObjIndex(NULL, varListObj, 1, &varNameObj); + token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); + PushVarNameWord(interp, token, envPtr, TCL_CREATE_VAR, + &valueVarIndex, &isSimple, &isScalar, 0 /* ignored */); + if (!isScalar || valueVarIndex < 0) { + Tcl_DecrRefCount(varListObj); return TCL_ERROR; } - valueVarIndex = TclFindCompiledLocal(argv[1], nameChars, 1, procPtr); - ckfree((char *) argv); + + Tcl_DecrRefCount(varListObj); /* * Allocate a temporary variable to store the iterator reference. The -- cgit v0.12 From 18131f9c09f735616d65001add027710eee6ad27 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 19 Dec 2014 14:21:42 +0000 Subject: With no callers left, TclIsLocalScalar() is removed. --- generic/tclInt.h | 1 - generic/tclParse.c | 50 -------------------------------------------------- 2 files changed, 51 deletions(-) diff --git a/generic/tclInt.h b/generic/tclInt.h index 255ee23..18574c3 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2606,7 +2606,6 @@ MODULE_SCOPE void TclInitNotifier(void); MODULE_SCOPE void TclInitObjSubsystem(void); MODULE_SCOPE void TclInitSubsystems(void); MODULE_SCOPE int TclInterpReady(Tcl_Interp *interp); -MODULE_SCOPE int TclIsLocalScalar(const char *src, int len); MODULE_SCOPE int TclIsSpaceProc(char byte); MODULE_SCOPE int TclIsBareword(char byte); MODULE_SCOPE int TclJoinThread(Tcl_ThreadId id, int *result); diff --git a/generic/tclParse.c b/generic/tclParse.c index 025304c..c07336f 100644 --- a/generic/tclParse.c +++ b/generic/tclParse.c @@ -2563,56 +2563,6 @@ TclObjCommandComplete( } /* - *---------------------------------------------------------------------- - * - * TclIsLocalScalar -- - * - * Check to see if a given string is a legal scalar variable name with no - * namespace qualifiers or substitutions. - * - * Results: - * Returns 1 if the variable is a local scalar. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TclIsLocalScalar( - const char *src, - int len) -{ - const char *p; - const char *lastChar = src + (len - 1); - - for (p=src ; p<=lastChar ; p++) { - if ((CHAR_TYPE(*p) != TYPE_NORMAL) && - (CHAR_TYPE(*p) != TYPE_COMMAND_END)) { - /* - * TCL_COMMAND_END is returned for the last character of the - * string. By this point we know it isn't an array or namespace - * reference. - */ - - return 0; - } - if (*p == '(') { - if (*lastChar == ')') { /* We have an array element */ - return 0; - } - } else if (*p == ':') { - if ((p != lastChar) && *(p+1) == ':') { /* qualified name */ - return 0; - } - } - } - - return 1; -} - -/* * Local Variables: * mode: c * c-basic-offset: 4 -- cgit v0.12 From 2613112a13e8acb4974fb7006cc44581299dd3ce Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 19 Dec 2014 15:13:11 +0000 Subject: Use interp==NULL argument to PushVarName to signal that only an index into the CLT is sought, and no time should be wasted compiling other cases which the caller is just going to discard. --- generic/tclCompCmds.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 9ccfcb6..7577bd3 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -402,7 +402,7 @@ TclCompileCatchCmd( cmdTokenPtr = TokenAfter(parsePtr->tokenPtr); if (parsePtr->numWords >= 3) { resultNameTokenPtr = TokenAfter(cmdTokenPtr); - PushVarNameWord(interp, resultNameTokenPtr, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, resultNameTokenPtr, envPtr, TCL_CREATE_VAR, &resultIndex, &isSimple, &isScalar, 2); if (!isScalar || resultIndex < 0) { return TCL_ERROR; @@ -410,7 +410,7 @@ TclCompileCatchCmd( if (parsePtr->numWords == 4) { optsNameTokenPtr = TokenAfter(resultNameTokenPtr); - PushVarNameWord(interp, optsNameTokenPtr, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, optsNameTokenPtr, envPtr, TCL_CREATE_VAR, &optsIndex, &isSimple, &isScalar, 3); if (!isScalar || resultIndex < 0) { return TCL_ERROR; @@ -673,7 +673,7 @@ TclCompileDictSetCmd( */ varTokenPtr = TokenAfter(parsePtr->tokenPtr); - PushVarNameWord(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, varTokenPtr, envPtr, TCL_CREATE_VAR, &dictVarIndex, &isSimple, &isScalar, 1); if (!isScalar || dictVarIndex < 0) { return TCL_ERROR; @@ -726,7 +726,7 @@ TclCompileDictIncrCmd( */ varTokenPtr = TokenAfter(parsePtr->tokenPtr); - PushVarNameWord(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, varTokenPtr, envPtr, TCL_CREATE_VAR, &dictVarIndex, &isSimple, &isScalar, 1); if (!isScalar || dictVarIndex < 0) { return TCL_ERROR; @@ -849,7 +849,7 @@ TclCompileDictForCmd( Tcl_ListObjIndex(NULL, varListObj, 0, &varNameObj); token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); - PushVarNameWord(interp, token, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, token, envPtr, TCL_CREATE_VAR, &keyVarIndex, &isSimple, &isScalar, 0 /* ignored */); if (!isScalar || keyVarIndex < 0) { Tcl_DecrRefCount(varListObj); @@ -858,7 +858,7 @@ TclCompileDictForCmd( Tcl_ListObjIndex(NULL, varListObj, 1, &varNameObj); token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); - PushVarNameWord(interp, token, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, token, envPtr, TCL_CREATE_VAR, &valueVarIndex, &isSimple, &isScalar, 0 /* ignored */); if (!isScalar || valueVarIndex < 0) { Tcl_DecrRefCount(varListObj); @@ -1031,7 +1031,7 @@ TclCompileDictUpdateCmd( */ dictVarTokenPtr = TokenAfter(parsePtr->tokenPtr); - PushVarNameWord(interp, dictVarTokenPtr, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, dictVarTokenPtr, envPtr, TCL_CREATE_VAR, &dictIndex, &isSimple, &isScalar, 1); if (!isScalar || dictIndex < 0) { return TCL_ERROR; @@ -1064,7 +1064,7 @@ TclCompileDictUpdateCmd( */ tokenPtr = TokenAfter(tokenPtr); - PushVarNameWord(interp, tokenPtr, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, tokenPtr, envPtr, TCL_CREATE_VAR, &index, &isSimple, &isScalar, 1); if (!isScalar || index < 0) { ckfree((char *) duiPtr); @@ -1176,7 +1176,7 @@ TclCompileDictAppendCmd( */ tokenPtr = TokenAfter(parsePtr->tokenPtr); - PushVarNameWord(interp, tokenPtr, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, tokenPtr, envPtr, TCL_CREATE_VAR, &dictVarIndex, &isSimple, &isScalar, 1); if (!isScalar || dictVarIndex < 0) { return TCL_ERROR; @@ -1227,7 +1227,7 @@ TclCompileDictLappendCmd( varTokenPtr = TokenAfter(parsePtr->tokenPtr); keyTokenPtr = TokenAfter(varTokenPtr); valueTokenPtr = TokenAfter(keyTokenPtr); - PushVarNameWord(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, varTokenPtr, envPtr, TCL_CREATE_VAR, &dictVarIndex, &isSimple, &isScalar, 1); if (!isScalar || dictVarIndex < 0) { return TCL_ERROR; @@ -1632,7 +1632,7 @@ TclCompileForeachCmd( Tcl_ListObjIndex(NULL, varListObj, j, &varNameObj); token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); - PushVarNameWord(interp, token, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, token, envPtr, TCL_CREATE_VAR, &varIndex, &isSimple, &isScalar, 0 /* ignored */); if (!isScalar || varIndex < 0) { code = TCL_ERROR; @@ -4805,7 +4805,7 @@ PushVarName( elemTokenCount = 1; } } - } else if (((n = varTokenPtr->numComponents) > 1) + } else if (interp && ((n = varTokenPtr->numComponents) > 1) && (varTokenPtr[1].type == TCL_TOKEN_TEXT) && (varTokenPtr[n].type == TCL_TOKEN_TEXT) && (varTokenPtr[n].start[varTokenPtr[n].size - 1] == ')')) { @@ -4907,7 +4907,7 @@ PushVarName( localIndex = -1; } } - if (localIndex < 0) { + if (interp && localIndex < 0) { PushLiteral(envPtr, name, nameChars); } @@ -4915,7 +4915,7 @@ PushVarName( * Compile the element script, if any. */ - if (elName != NULL) { + if (interp && elName != NULL) { if (elNameChars) { envPtr->line = line; envPtr->clNext = clNext; @@ -4924,7 +4924,7 @@ PushVarName( PushLiteral(envPtr, "", 0); } } - } else { + } else if (interp) { /* * The var name isn't simple: compile and push it. */ @@ -5708,7 +5708,7 @@ TclCompileUpvarCmd( localTokenPtr = TokenAfter(otherTokenPtr); CompileWord(envPtr, otherTokenPtr, interp, i); - PushVarNameWord(interp, localTokenPtr, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, localTokenPtr, envPtr, TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar, i+1); if((localIndex < 0) || !isScalar) { @@ -5800,7 +5800,7 @@ TclCompileNamespaceCmd( localTokenPtr = TokenAfter(otherTokenPtr); CompileWord(envPtr, otherTokenPtr, interp, i); - PushVarNameWord(interp, localTokenPtr, envPtr, TCL_CREATE_VAR, + PushVarNameWord(NULL, localTokenPtr, envPtr, TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar, i+1); if((localIndex < 0) || !isScalar) { -- cgit v0.12 From cfefe7127b6d560629dbcfee782578099e42d895 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 19 Dec 2014 15:55:21 +0000 Subject: New utility routine GetLocalScalarIndex() reduces common caller boilerplate (and fixes a bug!) --- generic/tclCompCmds.c | 112 ++++++++++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 7577bd3..6821637 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -152,6 +152,8 @@ static void FreeJumptableInfo(ClientData clientData); static void PrintJumptableInfo(ClientData clientData, Tcl_Obj *appendObj, ByteCode *codePtr, unsigned int pcOffset); +static int GetLocalScalarIndex(Tcl_Token *tokenPtr, + CompileEnv *envPtr, int *indexPtr); static int PushVarName(Tcl_Interp *interp, Tcl_Token *varTokenPtr, CompileEnv *envPtr, int flags, int *localIndexPtr, @@ -379,7 +381,7 @@ TclCompileCatchCmd( { JumpFixup jumpFixup; Tcl_Token *cmdTokenPtr, *resultNameTokenPtr, *optsNameTokenPtr; - int resultIndex, optsIndex, isSimple, isScalar, range; + int resultIndex, optsIndex, range; int initStackDepth = envPtr->currStackDepth; int savedStackDepth; DefineLineInformation; /* TIP #280 */ @@ -402,17 +404,13 @@ TclCompileCatchCmd( cmdTokenPtr = TokenAfter(parsePtr->tokenPtr); if (parsePtr->numWords >= 3) { resultNameTokenPtr = TokenAfter(cmdTokenPtr); - PushVarNameWord(NULL, resultNameTokenPtr, envPtr, TCL_CREATE_VAR, - &resultIndex, &isSimple, &isScalar, 2); - if (!isScalar || resultIndex < 0) { + if (!GetLocalScalarIndex(resultNameTokenPtr, envPtr, &resultIndex)) { return TCL_ERROR; } if (parsePtr->numWords == 4) { optsNameTokenPtr = TokenAfter(resultNameTokenPtr); - PushVarNameWord(NULL, optsNameTokenPtr, envPtr, TCL_CREATE_VAR, - &optsIndex, &isSimple, &isScalar, 3); - if (!isScalar || resultIndex < 0) { + if (!GetLocalScalarIndex(optsNameTokenPtr, envPtr, &optsIndex)) { return TCL_ERROR; } } @@ -653,9 +651,8 @@ TclCompileDictSetCmd( * compiled. */ CompileEnv *envPtr) /* Holds resulting instructions. */ { - Tcl_Token *tokenPtr; - Tcl_Token *varTokenPtr; - int i, isSimple, isScalar = 0, dictVarIndex = -1; + Tcl_Token *tokenPtr, *varTokenPtr; + int i, dictVarIndex; DefineLineInformation; /* TIP #280 */ /* @@ -673,9 +670,7 @@ TclCompileDictSetCmd( */ varTokenPtr = TokenAfter(parsePtr->tokenPtr); - PushVarNameWord(NULL, varTokenPtr, envPtr, TCL_CREATE_VAR, - &dictVarIndex, &isSimple, &isScalar, 1); - if (!isScalar || dictVarIndex < 0) { + if (!GetLocalScalarIndex(varTokenPtr, envPtr, &dictVarIndex)) { return TCL_ERROR; } @@ -708,7 +703,7 @@ TclCompileDictIncrCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr, *keyTokenPtr; - int dictVarIndex, incrAmount, isScalar, isSimple; + int dictVarIndex, incrAmount; DefineLineInformation; /* TIP #280 */ /* @@ -726,9 +721,7 @@ TclCompileDictIncrCmd( */ varTokenPtr = TokenAfter(parsePtr->tokenPtr); - PushVarNameWord(NULL, varTokenPtr, envPtr, TCL_CREATE_VAR, - &dictVarIndex, &isSimple, &isScalar, 1); - if (!isScalar || dictVarIndex < 0) { + if (!GetLocalScalarIndex(varTokenPtr, envPtr, &dictVarIndex)) { return TCL_ERROR; } @@ -809,7 +802,7 @@ TclCompileDictForCmd( Tcl_Token *varsTokenPtr, *dictTokenPtr, *bodyTokenPtr; int keyVarIndex, valueVarIndex, loopRange, catchRange; int infoIndex, jumpDisplacement, bodyTargetOffset, emptyTargetOffset; - int numVars, endTargetOffset, isSimple, isScalar; + int numVars, endTargetOffset; int savedStackDepth = envPtr->currStackDepth; /* Needed because jumps confuse the stack * space calculator. */ @@ -849,18 +842,14 @@ TclCompileDictForCmd( Tcl_ListObjIndex(NULL, varListObj, 0, &varNameObj); token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); - PushVarNameWord(NULL, token, envPtr, TCL_CREATE_VAR, - &keyVarIndex, &isSimple, &isScalar, 0 /* ignored */); - if (!isScalar || keyVarIndex < 0) { + if (!GetLocalScalarIndex(token, envPtr, &keyVarIndex)) { Tcl_DecrRefCount(varListObj); return TCL_ERROR; } Tcl_ListObjIndex(NULL, varListObj, 1, &varNameObj); token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); - PushVarNameWord(NULL, token, envPtr, TCL_CREATE_VAR, - &valueVarIndex, &isSimple, &isScalar, 0 /* ignored */); - if (!isScalar || valueVarIndex < 0) { + if (!GetLocalScalarIndex(token, envPtr, &valueVarIndex)) { Tcl_DecrRefCount(varListObj); return TCL_ERROR; } @@ -1005,7 +994,7 @@ TclCompileDictUpdateCmd( * compiled. */ CompileEnv *envPtr) /* Holds resulting instructions. */ { - int i, dictIndex, numVars, range, infoIndex, isSimple, isScalar; + int i, dictIndex, numVars, range, infoIndex; Tcl_Token **keyTokenPtrs, *dictVarTokenPtr, *bodyTokenPtr, *tokenPtr; DictUpdateInfo *duiPtr; JumpFixup jumpFixup; @@ -1031,9 +1020,7 @@ TclCompileDictUpdateCmd( */ dictVarTokenPtr = TokenAfter(parsePtr->tokenPtr); - PushVarNameWord(NULL, dictVarTokenPtr, envPtr, TCL_CREATE_VAR, - &dictIndex, &isSimple, &isScalar, 1); - if (!isScalar || dictIndex < 0) { + if (!GetLocalScalarIndex(dictVarTokenPtr, envPtr, &dictIndex)) { return TCL_ERROR; } @@ -1064,9 +1051,7 @@ TclCompileDictUpdateCmd( */ tokenPtr = TokenAfter(tokenPtr); - PushVarNameWord(NULL, tokenPtr, envPtr, TCL_CREATE_VAR, - &index, &isSimple, &isScalar, 1); - if (!isScalar || index < 0) { + if (!GetLocalScalarIndex(tokenPtr, envPtr, &index)) { ckfree((char *) duiPtr); TclStackFree(interp, keyTokenPtrs); return TCL_ERROR; @@ -1158,7 +1143,7 @@ TclCompileDictAppendCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Token *tokenPtr; - int i, isSimple, isScalar, dictVarIndex; + int i, dictVarIndex; DefineLineInformation; /* TIP #280 */ /* @@ -1176,9 +1161,7 @@ TclCompileDictAppendCmd( */ tokenPtr = TokenAfter(parsePtr->tokenPtr); - PushVarNameWord(NULL, tokenPtr, envPtr, TCL_CREATE_VAR, - &dictVarIndex, &isSimple, &isScalar, 1); - if (!isScalar || dictVarIndex < 0) { + if (!GetLocalScalarIndex(tokenPtr, envPtr, &dictVarIndex)) { return TCL_ERROR; } @@ -1213,7 +1196,7 @@ TclCompileDictLappendCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr, *keyTokenPtr, *valueTokenPtr; - int isSimple, dictVarIndex = -1, isScalar = 0; + int dictVarIndex; DefineLineInformation; /* TIP #280 */ /* @@ -1227,9 +1210,7 @@ TclCompileDictLappendCmd( varTokenPtr = TokenAfter(parsePtr->tokenPtr); keyTokenPtr = TokenAfter(varTokenPtr); valueTokenPtr = TokenAfter(keyTokenPtr); - PushVarNameWord(NULL, varTokenPtr, envPtr, TCL_CREATE_VAR, - &dictVarIndex, &isSimple, &isScalar, 1); - if (!isScalar || dictVarIndex < 0) { + if (!GetLocalScalarIndex(varTokenPtr, envPtr, &dictVarIndex)) { return TCL_ERROR; } CompileWord(envPtr, keyTokenPtr, interp, 2); @@ -1628,17 +1609,14 @@ TclCompileForeachCmd( for (j = 0; j < numVars; j++) { Tcl_Obj *varNameObj; - int varIndex, isSimple, isScalar; Tcl_ListObjIndex(NULL, varListObj, j, &varNameObj); token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); - PushVarNameWord(NULL, token, envPtr, TCL_CREATE_VAR, - &varIndex, &isSimple, &isScalar, 0 /* ignored */); - if (!isScalar || varIndex < 0) { + if (!GetLocalScalarIndex(token, envPtr, + varListPtr->varIndexes + j)) { code = TCL_ERROR; goto done; } - varListPtr->varIndexes[j] = varIndex; } Tcl_SetObjLength(varListObj, 0); } @@ -4717,6 +4695,38 @@ TclCompileWhileCmd( /* *---------------------------------------------------------------------- * + * GetLocalScalarIndex -- + * + * Procedure used in the compiling where pushing a variable name is + * necessary (append, lappend, set). + * + * Results: + * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer + * evaluation to runtime. + * + * Side effects: + * Instructions are added to envPtr to execute the "set" command at + * runtime. + * + *---------------------------------------------------------------------- + */ + +static int +GetLocalScalarIndex( + Tcl_Token *tokenPtr, + CompileEnv *envPtr, + int *indexPtr) +{ + int isSimple, isScalar; + + PushVarName(NULL, tokenPtr, envPtr, TCL_CREATE_VAR, indexPtr, + &isSimple, &isScalar, 0 /* ignored */, NULL /* ignored */); + return (isScalar && *indexPtr >= 0); +} + +/* + *---------------------------------------------------------------------- + * * PushVarName -- * * Procedure used in the compiling where pushing a variable name is @@ -5645,7 +5655,7 @@ TclCompileUpvarCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr; - int simpleVarName, isScalar, localIndex, numWords, i; + int localIndex, numWords, i; DefineLineInformation; /* TIP #280 */ Tcl_Obj *objPtr; @@ -5708,10 +5718,7 @@ TclCompileUpvarCmd( localTokenPtr = TokenAfter(otherTokenPtr); CompileWord(envPtr, otherTokenPtr, interp, i); - PushVarNameWord(NULL, localTokenPtr, envPtr, TCL_CREATE_VAR, - &localIndex, &simpleVarName, &isScalar, i+1); - - if((localIndex < 0) || !isScalar) { + if (!GetLocalScalarIndex(localTokenPtr, envPtr, &localIndex)) { return TCL_ERROR; } TclEmitInstInt4(INST_UPVAR, localIndex, envPtr); @@ -5755,7 +5762,7 @@ TclCompileNamespaceCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr; - int simpleVarName, isScalar, localIndex, numWords, i; + int localIndex, numWords, i; DefineLineInformation; /* TIP #280 */ if (envPtr->procPtr == NULL) { @@ -5800,10 +5807,7 @@ TclCompileNamespaceCmd( localTokenPtr = TokenAfter(otherTokenPtr); CompileWord(envPtr, otherTokenPtr, interp, i); - PushVarNameWord(NULL, localTokenPtr, envPtr, TCL_CREATE_VAR, - &localIndex, &simpleVarName, &isScalar, i+1); - - if((localIndex < 0) || !isScalar) { + if (!GetLocalScalarIndex(localTokenPtr, envPtr, &localIndex)) { return TCL_ERROR; } TclEmitInstInt4(INST_NSUPVAR, localIndex, envPtr); -- cgit v0.12 From f6d6b394ebc2f2b0bfc50edf3a14fb5e4414e8f7 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 19 Dec 2014 17:09:32 +0000 Subject: Revise name and interface of new utility routines to match work already in place on the trunk. --- generic/tclCompCmds.c | 105 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 38 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 6821637..b3568e8 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -152,8 +152,10 @@ static void FreeJumptableInfo(ClientData clientData); static void PrintJumptableInfo(ClientData clientData, Tcl_Obj *appendObj, ByteCode *codePtr, unsigned int pcOffset); -static int GetLocalScalarIndex(Tcl_Token *tokenPtr, - CompileEnv *envPtr, int *indexPtr); +static int LocalScalarFromToken(Tcl_Token *tokenPtr, + CompileEnv *envPtr); +static int LocalScalar(const char *bytes, int numBytes, + CompileEnv *envPtr); static int PushVarName(Tcl_Interp *interp, Tcl_Token *varTokenPtr, CompileEnv *envPtr, int flags, int *localIndexPtr, @@ -404,13 +406,15 @@ TclCompileCatchCmd( cmdTokenPtr = TokenAfter(parsePtr->tokenPtr); if (parsePtr->numWords >= 3) { resultNameTokenPtr = TokenAfter(cmdTokenPtr); - if (!GetLocalScalarIndex(resultNameTokenPtr, envPtr, &resultIndex)) { + resultIndex = LocalScalarFromToken(resultNameTokenPtr, envPtr); + if (resultIndex < 0) { return TCL_ERROR; } if (parsePtr->numWords == 4) { optsNameTokenPtr = TokenAfter(resultNameTokenPtr); - if (!GetLocalScalarIndex(optsNameTokenPtr, envPtr, &optsIndex)) { + optsIndex = LocalScalarFromToken(optsNameTokenPtr, envPtr); + if (optsIndex < 0) { return TCL_ERROR; } } @@ -670,7 +674,8 @@ TclCompileDictSetCmd( */ varTokenPtr = TokenAfter(parsePtr->tokenPtr); - if (!GetLocalScalarIndex(varTokenPtr, envPtr, &dictVarIndex)) { + dictVarIndex = LocalScalarFromToken(varTokenPtr, envPtr); + if (dictVarIndex < 0) { return TCL_ERROR; } @@ -721,7 +726,8 @@ TclCompileDictIncrCmd( */ varTokenPtr = TokenAfter(parsePtr->tokenPtr); - if (!GetLocalScalarIndex(varTokenPtr, envPtr, &dictVarIndex)) { + dictVarIndex = LocalScalarFromToken(varTokenPtr, envPtr); + if (dictVarIndex < 0) { return TCL_ERROR; } @@ -802,13 +808,12 @@ TclCompileDictForCmd( Tcl_Token *varsTokenPtr, *dictTokenPtr, *bodyTokenPtr; int keyVarIndex, valueVarIndex, loopRange, catchRange; int infoIndex, jumpDisplacement, bodyTargetOffset, emptyTargetOffset; - int numVars, endTargetOffset; + int numVars, endTargetOffset, numBytes; + const char *bytes; int savedStackDepth = envPtr->currStackDepth; /* Needed because jumps confuse the stack * space calculator. */ Tcl_Obj *varNameObj, *varListObj = NULL; - Tcl_Token token[2] = {{TCL_TOKEN_SIMPLE_WORD, NULL, 0, 1}, - {TCL_TOKEN_TEXT, NULL, 0, 0}}; DefineLineInformation; /* TIP #280 */ /* @@ -841,15 +846,17 @@ TclCompileDictForCmd( } Tcl_ListObjIndex(NULL, varListObj, 0, &varNameObj); - token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); - if (!GetLocalScalarIndex(token, envPtr, &keyVarIndex)) { + bytes = Tcl_GetStringFromObj(varNameObj, &numBytes); + keyVarIndex = LocalScalar(bytes, numBytes, envPtr); + if (keyVarIndex < 0) { Tcl_DecrRefCount(varListObj); return TCL_ERROR; } Tcl_ListObjIndex(NULL, varListObj, 1, &varNameObj); - token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); - if (!GetLocalScalarIndex(token, envPtr, &valueVarIndex)) { + bytes = Tcl_GetStringFromObj(varNameObj, &numBytes); + valueVarIndex = LocalScalar(bytes, numBytes, envPtr); + if (valueVarIndex < 0) { Tcl_DecrRefCount(varListObj); return TCL_ERROR; } @@ -1020,7 +1027,8 @@ TclCompileDictUpdateCmd( */ dictVarTokenPtr = TokenAfter(parsePtr->tokenPtr); - if (!GetLocalScalarIndex(dictVarTokenPtr, envPtr, &dictIndex)) { + dictIndex = LocalScalarFromToken(dictVarTokenPtr, envPtr); + if (dictIndex < 0) { return TCL_ERROR; } @@ -1051,7 +1059,8 @@ TclCompileDictUpdateCmd( */ tokenPtr = TokenAfter(tokenPtr); - if (!GetLocalScalarIndex(tokenPtr, envPtr, &index)) { + index = LocalScalarFromToken(tokenPtr, envPtr); + if (index < 0) { ckfree((char *) duiPtr); TclStackFree(interp, keyTokenPtrs); return TCL_ERROR; @@ -1161,7 +1170,8 @@ TclCompileDictAppendCmd( */ tokenPtr = TokenAfter(parsePtr->tokenPtr); - if (!GetLocalScalarIndex(tokenPtr, envPtr, &dictVarIndex)) { + dictVarIndex = LocalScalarFromToken(tokenPtr, envPtr); + if (dictVarIndex < 0) { return TCL_ERROR; } @@ -1210,7 +1220,8 @@ TclCompileDictLappendCmd( varTokenPtr = TokenAfter(parsePtr->tokenPtr); keyTokenPtr = TokenAfter(varTokenPtr); valueTokenPtr = TokenAfter(keyTokenPtr); - if (!GetLocalScalarIndex(varTokenPtr, envPtr, &dictVarIndex)) { + dictVarIndex = LocalScalarFromToken(varTokenPtr, envPtr); + if (dictVarIndex < 0) { return TCL_ERROR; } CompileWord(envPtr, keyTokenPtr, interp, 2); @@ -1522,7 +1533,6 @@ TclCompileForeachCmd( * foreach command. Stored in a AuxData * record in the ByteCode. */ Tcl_Token *tokenPtr, *bodyTokenPtr; - Tcl_Token token[2]; unsigned char *jumpPc; JumpFixup jumpFalseFixup; int jumpBackDist, jumpBackOffset, infoIndex, range; @@ -1576,8 +1586,6 @@ TclCompileForeachCmd( */ varListObj = Tcl_NewObj(); - token[0].type = TCL_TOKEN_SIMPLE_WORD; - token[0].numComponents = 1; for (i = 0, tokenPtr = parsePtr->tokenPtr; i < numWords-1; i++, tokenPtr = TokenAfter(tokenPtr)) { @@ -1609,11 +1617,13 @@ TclCompileForeachCmd( for (j = 0; j < numVars; j++) { Tcl_Obj *varNameObj; + int numBytes; + const char *bytes; Tcl_ListObjIndex(NULL, varListObj, j, &varNameObj); - token[1].start = Tcl_GetStringFromObj(varNameObj, &token[1].size); - if (!GetLocalScalarIndex(token, envPtr, - varListPtr->varIndexes + j)) { + bytes = Tcl_GetStringFromObj(varNameObj, &numBytes); + varListPtr->varIndexes[j] = LocalScalar(bytes, numBytes, envPtr); + if (varListPtr->varIndexes[j] < 0) { code = TCL_ERROR; goto done; } @@ -4695,33 +4705,50 @@ TclCompileWhileCmd( /* *---------------------------------------------------------------------- * - * GetLocalScalarIndex -- + * LocalScalar(FromToken) -- * - * Procedure used in the compiling where pushing a variable name is - * necessary (append, lappend, set). + * Get the index into the table of compiled locals that corresponds + * to a local scalar variable name. * * Results: - * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer - * evaluation to runtime. + * Returns the non-negative integer index value into the table of + * compiled locals corresponding to a local scalar variable name. + * If the arguments passed in do not identify a local scalar variable + * then return -1. * * Side effects: - * Instructions are added to envPtr to execute the "set" command at - * runtime. + * May add an entry into the table of compiled locals. * *---------------------------------------------------------------------- */ static int -GetLocalScalarIndex( +LocalScalarFromToken( Tcl_Token *tokenPtr, - CompileEnv *envPtr, - int *indexPtr) + CompileEnv *envPtr) { - int isSimple, isScalar; + int isSimple, isScalar, index; - PushVarName(NULL, tokenPtr, envPtr, TCL_CREATE_VAR, indexPtr, + PushVarName(NULL, tokenPtr, envPtr, TCL_CREATE_VAR, &index, &isSimple, &isScalar, 0 /* ignored */, NULL /* ignored */); - return (isScalar && *indexPtr >= 0); + if (!isScalar) { + index = -1; + } + return index; +} + +static int +LocalScalar( + const char *bytes, + int numBytes, + CompileEnv *envPtr) +{ + Tcl_Token token[2] = {{TCL_TOKEN_SIMPLE_WORD, NULL, 0, 1}, + {TCL_TOKEN_TEXT, NULL, 0, 0}}; + + token[1].start = bytes; + token[1].size = numBytes; + return LocalScalarFromToken(token, envPtr); } /* @@ -5718,7 +5745,8 @@ TclCompileUpvarCmd( localTokenPtr = TokenAfter(otherTokenPtr); CompileWord(envPtr, otherTokenPtr, interp, i); - if (!GetLocalScalarIndex(localTokenPtr, envPtr, &localIndex)) { + localIndex = LocalScalarFromToken(localTokenPtr, envPtr); + if (localIndex < 0) { return TCL_ERROR; } TclEmitInstInt4(INST_UPVAR, localIndex, envPtr); @@ -5807,7 +5835,8 @@ TclCompileNamespaceCmd( localTokenPtr = TokenAfter(otherTokenPtr); CompileWord(envPtr, otherTokenPtr, interp, i); - if (!GetLocalScalarIndex(localTokenPtr, envPtr, &localIndex)) { + localIndex = LocalScalarFromToken(localTokenPtr, envPtr); + if (localIndex < 0) { return TCL_ERROR; } TclEmitInstInt4(INST_NSUPVAR, localIndex, envPtr); -- cgit v0.12 From 13667e8096fd5ac12f24949644396d9eb0a12620 Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 22 Dec 2014 15:35:47 +0000 Subject: One more (interp==NULL) shortcut. --- generic/tclCompCmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index b3568e8..106c293 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -4826,7 +4826,7 @@ PushVarName( } } - if ((elName != NULL) && elNameChars) { + if (interp && (elName != NULL) && elNameChars) { /* * An array element, the element name is a simple string: * assemble the corresponding token. -- cgit v0.12 From 3faf4cc3b890c8295557932ae4d896c6624e6af7 Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 22 Dec 2014 19:57:36 +0000 Subject: More complete use of the TCL_NO_ELEMENT flag to suppress useless actions. --- generic/tclCompCmds.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 30c1318..ee9209a 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -3313,7 +3313,7 @@ TclPushVarName( } } - if ((elName != NULL) && elNameChars) { + if (!(flags & TCL_NO_ELEMENT) && (elName != NULL) && elNameChars) { /* * An array element, the element name is a simple string: * assemble the corresponding token. @@ -3366,7 +3366,8 @@ TclPushVarName( remainingChars = (varTokenPtr[2].start - p) - 1; elNameChars = (varTokenPtr[n].start-p) + varTokenPtr[n].size - 1; - if (remainingChars) { + if (!(flags & TCL_NO_ELEMENT)) { + if (remainingChars) { /* * Make a first token with the extra characters in the first * token. @@ -3386,13 +3387,14 @@ TclPushVarName( memcpy(elemTokenPtr+1, varTokenPtr+2, (n-1) * sizeof(Tcl_Token)); - } else { + } else { /* * Use the already available tokens. */ elemTokenPtr = &varTokenPtr[2]; elemTokenCount = n - 1; + } } } } -- cgit v0.12 From 7ac39417f17cf6027ca26576c86d3cf9147ad1e7 Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 22 Dec 2014 20:13:29 +0000 Subject: Use (interp == NULL) argument to TclPushVarName() to signal that no compiling is desired. Only a lookup of an index into the compiled variable table. --- generic/tclCompCmds.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index ee9209a..18071b1 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -3328,7 +3328,7 @@ TclPushVarName( elemTokenCount = 1; } } - } else if (((n = varTokenPtr->numComponents) > 1) + } else if (interp && ((n = varTokenPtr->numComponents) > 1) && (varTokenPtr[1].type == TCL_TOKEN_TEXT) && (varTokenPtr[n].type == TCL_TOKEN_TEXT) && (varTokenPtr[n].start[varTokenPtr[n].size - 1] == ')')) { @@ -3429,7 +3429,7 @@ TclPushVarName( localIndex = -1; } } - if (localIndex < 0) { + if (interp && localIndex < 0) { PushLiteral(envPtr, name, nameChars); } @@ -3446,7 +3446,7 @@ TclPushVarName( PushStringLiteral(envPtr, ""); } } - } else { + } else if (interp) { /* * The var name isn't simple: compile and push it. */ -- cgit v0.12 From 2cbec4bf44fad8591fa06185d8cf3f28dd1526a2 Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 22 Dec 2014 20:27:14 +0000 Subject: Convert the LocalScalar*() macros to rest on TclPushVarName rather than on TclIsLocalScalar(). --- generic/tclCompCmds.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ generic/tclCompile.h | 10 ++++++---- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 18071b1..bde07bb 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -3234,6 +3234,54 @@ TclCompileFormatCmd( /* *---------------------------------------------------------------------- * + * TclLocalScalarFromToken -- + * + * Get the index into the table of compiled locals that corresponds + * to a local scalar variable name. + * + * Results: + * Returns the non-negative integer index value into the table of + * compiled locals corresponding to a local scalar variable name. + * If the arguments passed in do not identify a local scalar variable + * then return -1. + * + * Side effects: + * May add an entery into the table of compiled locals. + * + *---------------------------------------------------------------------- + */ + +int +TclLocalScalarFromToken( + Tcl_Token *tokenPtr, + CompileEnv *envPtr) +{ + int isScalar, index; + + TclPushVarName(NULL, tokenPtr, envPtr, TCL_NO_ELEMENT, &index, &isScalar); + if (!isScalar) { + index = -1; + } + return index; +} + +int +TclLocalScalar( + const char *bytes, + int numBytes, + CompileEnv *envPtr) +{ + Tcl_Token token[2] = {{TCL_TOKEN_SIMPLE_WORD, NULL, 0, 1}, + {TCL_TOKEN_TEXT, NULL, 0, 0}}; + + token[1].start = bytes; + token[1].size = numBytes; + return TclLocalScalarFromToken(token, envPtr); +} + +/* + *---------------------------------------------------------------------- + * * TclPushVarName -- * * Procedure used in the compiling where pushing a variable name is diff --git a/generic/tclCompile.h b/generic/tclCompile.h index 51f0b34..c6c7a7c 100644 --- a/generic/tclCompile.h +++ b/generic/tclCompile.h @@ -1151,6 +1151,10 @@ MODULE_SCOPE void TclFinalizeLoopExceptionRange(CompileEnv *envPtr, MODULE_SCOPE char * TclLiteralStats(LiteralTable *tablePtr); MODULE_SCOPE int TclLog2(int value); #endif +MODULE_SCOPE int TclLocalScalar(const char *bytes, int numBytes, + CompileEnv *envPtr); +MODULE_SCOPE int TclLocalScalarFromToken(Tcl_Token *tokenPtr, + CompileEnv *envPtr); MODULE_SCOPE void TclOptimizeBytecode(void *envPtr); #ifdef TCL_COMPILE_DEBUG MODULE_SCOPE void TclPrintByteCodeObj(Tcl_Interp *interp, @@ -1678,11 +1682,9 @@ MODULE_SCOPE int TclPushProcCallFrame(ClientData clientData, #define AnonymousLocal(envPtr) \ (TclFindCompiledLocal(NULL, /*nameChars*/ 0, /*create*/ 1, (envPtr))) #define LocalScalar(chars,len,envPtr) \ - (!TclIsLocalScalar((chars), (len)) ? -1 : \ - TclFindCompiledLocal((chars), (len), /*create*/ 1, (envPtr))) + TclLocalScalar(chars, len, envPtr) #define LocalScalarFromToken(tokenPtr,envPtr) \ - ((tokenPtr)->type != TCL_TOKEN_SIMPLE_WORD ? -1 : \ - LocalScalar((tokenPtr)[1].start, (tokenPtr)[1].size, (envPtr))) + TclLocalScalarFromToken(tokenPtr, envPtr) /* * Flags bits used by TclPushVarName. -- cgit v0.12 From 49e7d0262bb9fcc94ce092927df43261350e319a Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 23 Dec 2014 01:28:30 +0000 Subject: Revise CompileEachloopCmd() to use LocalScalar() in place of TclIsLocalScalar(). --- generic/tclCompCmds.c | 119 +++++++++++++++++--------------------------------- 1 file changed, 40 insertions(+), 79 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index bde07bb..ec398b6 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -2527,25 +2527,17 @@ CompileEachloopCmd( * (TCL_EACH_*) */ { Proc *procPtr = envPtr->procPtr; - ForeachInfo *infoPtr; /* Points to the structure describing this + ForeachInfo *infoPtr=NULL; /* Points to the structure describing this * foreach command. Stored in a AuxData * record in the ByteCode. */ Tcl_Token *tokenPtr, *bodyTokenPtr; int jumpBackOffset, infoIndex, range; - int numWords, numLists, numVars, loopIndex, i, j, code; + int numWords, numLists, i, j, code = TCL_OK; + Tcl_Obj *varListObj = NULL; DefineLineInformation; /* TIP #280 */ /* - * We parse the variable list argument words and create two arrays: - * varcList[i] is number of variables in i-th var list. - * varvList[i] points to array of var names in i-th var list. - */ - - int *varcList; - const char ***varvList; - - /* * If the foreach command isn't in a procedure, don't compile it inline: * the payoff is too small. */ @@ -2573,105 +2565,73 @@ CompileEachloopCmd( } /* - * Allocate storage for the varcList and varvList arrays if necessary. + * Create and initialize the ForeachInfo and ForeachVarList data + * structures describing this command. Then create a AuxData record + * pointing to the ForeachInfo structure. */ numLists = (numWords - 2)/2; - varcList = TclStackAlloc(interp, numLists * sizeof(int)); - memset(varcList, 0, numLists * sizeof(int)); - varvList = (const char ***) TclStackAlloc(interp, - numLists * sizeof(const char **)); - memset((char*) varvList, 0, numLists * sizeof(const char **)); + infoPtr = ckalloc(sizeof(ForeachInfo) + + (numLists - 1) * sizeof(ForeachVarList *)); + infoPtr->numLists = 0; /* Count this up as we go */ /* - * Break up each var list and set the varcList and varvList arrays. Don't + * Parse each var list into sequence of var names. Don't * compile the foreach inline if any var name needs substitutions or isn't * a scalar, or if any var list needs substitutions. */ - loopIndex = 0; + varListObj = Tcl_NewObj(); for (i = 0, tokenPtr = parsePtr->tokenPtr; i < numWords-1; i++, tokenPtr = TokenAfter(tokenPtr)) { - Tcl_DString varList; + ForeachVarList *varListPtr; + int numVars; if (i%2 != 1) { continue; } - if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - code = TCL_ERROR; - goto done; - } - - /* - * Lots of copying going on here. Need a ListObj wizard to show a - * better way. - */ - - Tcl_DStringInit(&varList); - TclDStringAppendToken(&varList, &tokenPtr[1]); - code = Tcl_SplitList(NULL, Tcl_DStringValue(&varList), - &varcList[loopIndex], &varvList[loopIndex]); - Tcl_DStringFree(&varList); - if (code != TCL_OK) { - code = TCL_ERROR; - goto done; - } - numVars = varcList[loopIndex]; /* * If the variable list is empty, we can enter an infinite loop when - * the interpreted version would not. Take care to ensure this does - * not happen. [Bug 1671138] + * the interpreted version would not. Take care to ensure this does + * not happen. [Bug 1671138] */ - if (numVars == 0) { + if (!TclWordKnownAtCompileTime(tokenPtr, varListObj) || + TCL_OK != Tcl_ListObjLength(NULL, varListObj, &numVars) || + numVars == 0) { code = TCL_ERROR; goto done; } - for (j = 0; j < numVars; j++) { - const char *varName = varvList[loopIndex][j]; + varListPtr = ckalloc(sizeof(ForeachVarList) + + (numVars - 1) * sizeof(int)); + varListPtr->numVars = numVars; + infoPtr->varLists[i/2] = varListPtr; + infoPtr->numLists++; - if (!TclIsLocalScalar(varName, (int) strlen(varName))) { + for (j = 0; j < numVars; j++) { + Tcl_Obj *varNameObj; + const char *bytes; + int numBytes, varIndex; + + Tcl_ListObjIndex(NULL, varListObj, j, &varNameObj); + bytes = Tcl_GetStringFromObj(varNameObj, &numBytes); + varIndex = LocalScalar(bytes, numBytes, envPtr); + if (varIndex < 0) { code = TCL_ERROR; goto done; } + varListPtr->varIndexes[j] = varIndex; } - loopIndex++; + Tcl_SetObjLength(varListObj, 0); } /* * We will compile the foreach command. */ - code = TCL_OK; - - /* - * Create and initialize the ForeachInfo and ForeachVarList data - * structures describing this command. Then create a AuxData record - * pointing to the ForeachInfo structure. - */ - - infoPtr = ckalloc(sizeof(ForeachInfo) - + (numLists - 1) * sizeof(ForeachVarList *)); - infoPtr->numLists = numLists; - for (loopIndex = 0; loopIndex < numLists; loopIndex++) { - ForeachVarList *varListPtr; - - numVars = varcList[loopIndex]; - varListPtr = ckalloc(sizeof(ForeachVarList) - + (numVars - 1) * sizeof(int)); - varListPtr->numVars = numVars; - for (j = 0; j < numVars; j++) { - const char *varName = varvList[loopIndex][j]; - int nameChars = strlen(varName); - - varListPtr->varIndexes[j] = TclFindCompiledLocal(varName, - nameChars, /*create*/ 1, envPtr); - } - infoPtr->varLists[loopIndex] = varListPtr; - } infoIndex = TclCreateAuxData(infoPtr, &tclNewForeachInfoType, envPtr); /* @@ -2743,13 +2703,14 @@ CompileEachloopCmd( } done: - for (loopIndex = 0; loopIndex < numLists; loopIndex++) { - if (varvList[loopIndex] != NULL) { - ckfree(varvList[loopIndex]); + if (code == TCL_ERROR) { + if (infoPtr) { + FreeForeachInfo(infoPtr); } } - TclStackFree(interp, (void *)varvList); - TclStackFree(interp, varcList); + if (varListObj) { + Tcl_DecrRefCount(varListObj); + } return code; } -- cgit v0.12 From b0078c812949591757520d79106eae38f21d33f0 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 23 Dec 2014 02:12:59 +0000 Subject: Eliminate TclIsLocalScalar(). No callers left. --- generic/tclInt.h | 1 - generic/tclParse.c | 50 -------------------------------------------------- 2 files changed, 51 deletions(-) diff --git a/generic/tclInt.h b/generic/tclInt.h index 995da48..3f84717 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2985,7 +2985,6 @@ MODULE_SCOPE void TclInitNotifier(void); MODULE_SCOPE void TclInitObjSubsystem(void); MODULE_SCOPE void TclInitSubsystems(void); MODULE_SCOPE int TclInterpReady(Tcl_Interp *interp); -MODULE_SCOPE int TclIsLocalScalar(const char *src, int len); MODULE_SCOPE int TclIsSpaceProc(char byte); MODULE_SCOPE int TclIsBareword(char byte); MODULE_SCOPE Tcl_Obj * TclJoinPath(int elements, Tcl_Obj * const objv[]); diff --git a/generic/tclParse.c b/generic/tclParse.c index ca12be5..5524979 100644 --- a/generic/tclParse.c +++ b/generic/tclParse.c @@ -2526,56 +2526,6 @@ TclObjCommandComplete( } /* - *---------------------------------------------------------------------- - * - * TclIsLocalScalar -- - * - * Check to see if a given string is a legal scalar variable name with no - * namespace qualifiers or substitutions. - * - * Results: - * Returns 1 if the variable is a local scalar. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TclIsLocalScalar( - const char *src, - int len) -{ - const char *p; - const char *lastChar = src + (len - 1); - - for (p=src ; p<=lastChar ; p++) { - if ((CHAR_TYPE(*p) != TYPE_NORMAL) - && (CHAR_TYPE(*p) != TYPE_COMMAND_END)) { - /* - * TCL_COMMAND_END is returned for the last character of the - * string. By this point we know it isn't an array or namespace - * reference. - */ - - return 0; - } - if (*p == '(') { - if (*lastChar == ')') { /* We have an array element */ - return 0; - } - } else if (*p == ':') { - if ((p != lastChar) && *(p+1) == ':') { /* qualified name */ - return 0; - } - } - } - - return 1; -} - -/* * Local Variables: * mode: c * c-basic-offset: 4 -- cgit v0.12 From ef6f1ba2c34bd3243b54d46d23d37392d7bf34ba Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 23 Dec 2014 02:41:54 +0000 Subject: Use more suitable variable name pushers. --- generic/tclCompCmds.c | 6 +++--- generic/tclCompCmdsGR.c | 16 ++++++---------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index ec398b6..6a22a30 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -177,9 +177,9 @@ TclCompileAppendCmd( */ varTokenPtr = TokenAfter(parsePtr->tokenPtr); - PushVarNameWord(interp, varTokenPtr, envPtr, TCL_NO_ELEMENT, - &localIndex, &isScalar, 1); - if (!isScalar || localIndex < 0) { + + localIndex = LocalScalarFromToken(varTokenPtr, envPtr); + if (localIndex < 0) { return TCL_ERROR; } diff --git a/generic/tclCompCmdsGR.c b/generic/tclCompCmdsGR.c index 98407f7..e2fb43d 100644 --- a/generic/tclCompCmdsGR.c +++ b/generic/tclCompCmdsGR.c @@ -2044,7 +2044,7 @@ TclCompileNamespaceUpvarCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr; - int isScalar, localIndex, numWords, i; + int localIndex, numWords, i; DefineLineInformation; /* TIP #280 */ if (envPtr->procPtr == NULL) { @@ -2079,10 +2079,8 @@ TclCompileNamespaceUpvarCmd( localTokenPtr = TokenAfter(otherTokenPtr); CompileWord(envPtr, otherTokenPtr, interp, i); - PushVarNameWord(interp, localTokenPtr, envPtr, 0, - &localIndex, &isScalar, i+1); - - if ((localIndex < 0) || !isScalar) { + localIndex = LocalScalarFromToken(localTokenPtr, envPtr); + if (localIndex < 0) { return TCL_ERROR; } TclEmitInstInt4( INST_NSUPVAR, localIndex, envPtr); @@ -2763,7 +2761,7 @@ TclCompileUpvarCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr; - int isScalar, localIndex, numWords, i; + int localIndex, numWords, i; DefineLineInformation; /* TIP #280 */ Tcl_Obj *objPtr; @@ -2826,10 +2824,8 @@ TclCompileUpvarCmd( localTokenPtr = TokenAfter(otherTokenPtr); CompileWord(envPtr, otherTokenPtr, interp, i); - PushVarNameWord(interp, localTokenPtr, envPtr, 0, - &localIndex, &isScalar, i+1); - - if ((localIndex < 0) || !isScalar) { + localIndex = LocalScalarFromToken(localTokenPtr, envPtr); + if (localIndex < 0) { return TCL_ERROR; } TclEmitInstInt4( INST_UPVAR, localIndex, envPtr); -- cgit v0.12