Tcl Source Code

Check-in [dbab97cbba]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Reduce use of Tcl_AppendElement, which is not (and can't be) a Tcl_Obj-aware API.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: dbab97cbba58a39c357af59d4ab96a4d419cc9d7
User & Date: dkf 2011-05-09 15:24:06
Context
2011-05-10
17:22
New internal routines TclScanElement() and TclConvertElement(). Rewritten guts of machinery to produ... check-in: 7720fbb825 user: dgp tags: trunk
2011-05-09
15:24
Reduce use of Tcl_AppendElement, which is not (and can't be) a Tcl_Obj-aware API. check-in: dbab97cbba user: dkf tags: trunk
13:58
Revise empty string tests so that we avoid potentially expensive string rep generations, especially ... check-in: c2d4899eeb user: dgp tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.








1
2
3
4
5
6
7







2011-05-09  Don Porter  <[email protected]>

	* generic/tclListObj.c:	Revise empty string tests so that we avoid
	potentially expensive string rep generations, especially for dicts.

2011-05-07  Donal K. Fellows  <[email protected]>

>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
2011-05-09  Donal K. Fellows  <[email protected]>

	* generic/tclNamesp.c (NamespacePathCmd): Convert to use Tcl_Obj API
	* generic/tclPkg.c (Tcl_PackageObjCmd):   for result generation in
	* generic/tclTimer.c (Tcl_AfterObjCmd):   [after info], [namespace
	path] and [package versions].

2011-05-09  Don Porter  <[email protected]>

	* generic/tclListObj.c:	Revise empty string tests so that we avoid
	potentially expensive string rep generations, especially for dicts.

2011-05-07  Donal K. Fellows  <[email protected]>

Changes to generic/tclNamesp.c.

3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971

3972
3973
3974
3975
3976
3977
3978
    }

    /*
     * If no path is given, return the current path.
     */

    if (objc == 1) {
	/*
	 * Not a very fast way to compute this, but easy to get right.
	 */

	for (i=0 ; i<nsPtr->commandPathLength ; i++) {
	    if (nsPtr->commandPathArray[i].nsPtr != NULL) {
		Tcl_AppendElement(interp,
			nsPtr->commandPathArray[i].nsPtr->fullName);
	    }
	}

	return TCL_OK;
    }

    /*
     * There is a path given, so parse it into an array of namespace pointers.
     */








|
<
<



|
|


>







3955
3956
3957
3958
3959
3960
3961
3962


3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
    }

    /*
     * If no path is given, return the current path.
     */

    if (objc == 1) {
        Tcl_Obj *resultObj = Tcl_NewObj();



	for (i=0 ; i<nsPtr->commandPathLength ; i++) {
	    if (nsPtr->commandPathArray[i].nsPtr != NULL) {
                Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj(
                        nsPtr->commandPathArray[i].nsPtr->fullName, -1));
	    }
	}
        Tcl_SetObjResult(interp, resultObj);
	return TCL_OK;
    }

    /*
     * There is a path given, so parse it into an array of namespace pointers.
     */

4840
4841
4842
4843
4844
4845
4846
4847
4848

4849
4850
4851
4852
4853
4854
4855
    Tcl_Interp *interp,		/* Interpreter in which to log information. */
    const char *script,		/* First character in script containing
				 * command (must be <= command). */
    const char *command,	/* First character in command that generated
				 * the error. */
    int length,			/* Number of bytes in command (-1 means use
				 * all bytes up to first null byte). */
    const unsigned char *pc,    /* current pc of bytecode execution context */
    Tcl_Obj **tosPtr)           /* current stack of bytecode execution context */

{
    register const char *p;
    Interp *iPtr = (Interp *) interp;
    int overflow, limit = 150;
    Var *varPtr, *arrayPtr;

    if (iPtr->flags & ERR_ALREADY_LOGGED) {







|
|
>







4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
    Tcl_Interp *interp,		/* Interpreter in which to log information. */
    const char *script,		/* First character in script containing
				 * command (must be <= command). */
    const char *command,	/* First character in command that generated
				 * the error. */
    int length,			/* Number of bytes in command (-1 means use
				 * all bytes up to first null byte). */
    const unsigned char *pc,    /* Current pc of bytecode execution context */
    Tcl_Obj **tosPtr)           /* Current stack of bytecode execution
                                 * context */
{
    register const char *p;
    Interp *iPtr = (Interp *) interp;
    int overflow, limit = 150;
    Var *varPtr, *arrayPtr;

    if (iPtr->flags & ERR_ALREADY_LOGGED) {
4926
4927
4928
4929
4930
4931
4932


4933


4934
4935
4936
4937
4938
4939
4940

4941
4942
4943
4944

4945

4946
4947
4948
4949

4950

4951

4952

4953
4954
4955
4956
4957

4958


4959
4960
4961
4962
4963
4964
4965
        iPtr->errorStack = newObj;
    }
    if (iPtr->resetErrorStack) {
	int len;

        iPtr->resetErrorStack = 0;
	Tcl_ListObjLength(interp, iPtr->errorStack, &len);


        /* reset while keeping the list intrep as much as possible */


        Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
        if (pc != NULL) {
            Tcl_Obj *innerContext;

            innerContext = TclGetInnerContext(interp, pc, tosPtr);
            if (innerContext != NULL) {
                Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral);

                Tcl_ListObjAppendElement(NULL, iPtr->errorStack, innerContext);
            }
        } else if (command != NULL) {
            Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral);

            Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewStringObj(command, length));

        }
    } 

    if (!iPtr->framePtr->objc) {

        /* special frame, nothing to report */

    } else if (iPtr->varFramePtr != iPtr->framePtr) {

        /* uplevel case, [lappend errorstack UP $relativelevel] */


        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->upLiteral);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewIntObj(
		iPtr->framePtr->level - iPtr->varFramePtr->level));
    } else if (iPtr->framePtr != iPtr->rootFramePtr) {

        /* normal case, [lappend errorstack CALL [info level 0]] */


        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->callLiteral);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewListObj(
		iPtr->framePtr->objc, iPtr->framePtr->objv));
    }
}

/*







>
>
|
>
>






|
>



|
>
|
>




>
|
>

>
|
>





>
|
>
>







4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
        iPtr->errorStack = newObj;
    }
    if (iPtr->resetErrorStack) {
	int len;

        iPtr->resetErrorStack = 0;
	Tcl_ListObjLength(interp, iPtr->errorStack, &len);

        /*
         * Reset while keeping the list intrep as much as possible.
         */

        Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
        if (pc != NULL) {
            Tcl_Obj *innerContext;

            innerContext = TclGetInnerContext(interp, pc, tosPtr);
            if (innerContext != NULL) {
                Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
                        iPtr->innerLiteral);
                Tcl_ListObjAppendElement(NULL, iPtr->errorStack, innerContext);
            }
        } else if (command != NULL) {
            Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
                    iPtr->innerLiteral);
            Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
                    Tcl_NewStringObj(command, length));
        }
    } 

    if (!iPtr->framePtr->objc) {
        /*
         * Special frame, nothing to report.
         */
    } else if (iPtr->varFramePtr != iPtr->framePtr) {
        /*
         * uplevel case, [lappend errorstack UP $relativelevel]
         */

        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->upLiteral);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewIntObj(
		iPtr->framePtr->level - iPtr->varFramePtr->level));
    } else if (iPtr->framePtr != iPtr->rootFramePtr) {
        /*
         * normal case, [lappend errorstack CALL [info level 0]]
         */

        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->callLiteral);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewListObj(
		iPtr->framePtr->objc, iPtr->framePtr->objv));
    }
}

/*
4975
4976
4977
4978
4979
4980
4981


4982



4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998


4999


5000
5001
5002

5003
5004
5005
5006
5007
5008
5009
 *
 * Side effects:
 *	Reset errorstack if it needs be, and in that case remember the
 *	passed-in error message as inner context.
 *
 *----------------------------------------------------------------------
 */


void TclErrorStackResetIf(Tcl_Interp *interp, const char *msg, int length)



{
    Interp *iPtr = (Interp *) interp;

    if (Tcl_IsShared(iPtr->errorStack)) {
        Tcl_Obj *newObj;
            
        newObj = Tcl_DuplicateObj(iPtr->errorStack);
        Tcl_DecrRefCount(iPtr->errorStack);
        Tcl_IncrRefCount(newObj);
        iPtr->errorStack = newObj;
    }
    if (iPtr->resetErrorStack) {
	int len;

        iPtr->resetErrorStack = 0;
	Tcl_ListObjLength(interp, iPtr->errorStack, &len);


        /* reset while keeping the list intrep as much as possible */


        Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewStringObj(msg, length));

    } 
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_LogCommandInfo --







>
>
|
>
>
>
















>
>
|
>
>


|
>







4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
 *
 * Side effects:
 *	Reset errorstack if it needs be, and in that case remember the
 *	passed-in error message as inner context.
 *
 *----------------------------------------------------------------------
 */

void
TclErrorStackResetIf(
    Tcl_Interp *interp,
    const char *msg,
    int length)
{
    Interp *iPtr = (Interp *) interp;

    if (Tcl_IsShared(iPtr->errorStack)) {
        Tcl_Obj *newObj;
            
        newObj = Tcl_DuplicateObj(iPtr->errorStack);
        Tcl_DecrRefCount(iPtr->errorStack);
        Tcl_IncrRefCount(newObj);
        iPtr->errorStack = newObj;
    }
    if (iPtr->resetErrorStack) {
	int len;

        iPtr->resetErrorStack = 0;
	Tcl_ListObjLength(interp, iPtr->errorStack, &len);

        /*
         * Reset while keeping the list intrep as much as possible.
         */

        Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
                Tcl_NewStringObj(msg, length));
    } 
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_LogCommandInfo --

Changes to generic/tclPkg.c.

878
879
880
881
882
883
884


885

886
887
888
889
890

891
892


893
894
895
896

897
898
899
900
901
902
903
	DupBlock(availPtr->script, argv4, (unsigned) length + 1);
	break;
    }
    case PKG_NAMES:
	if (objc != 2) {
	    Tcl_WrongNumArgs(interp, 2, objv, NULL);
	    return TCL_ERROR;


	}

	tablePtr = &iPtr->packageTable;
	for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL;
		hPtr = Tcl_NextHashEntry(&search)) {
	    pkgPtr = Tcl_GetHashValue(hPtr);
	    if ((pkgPtr->version != NULL) || (pkgPtr->availPtr != NULL)) {

		Tcl_AppendElement(interp, Tcl_GetHashKey(tablePtr, hPtr));
	    }


	}
	break;
    case PKG_PRESENT: {
	const char *name;

	if (objc < 3) {
	    goto require;
	}
	argv2 = TclGetString(objv[2]);
	if ((argv2[0] == '-') && (strcmp(argv2, "-exact") == 0)) {
	    if (objc != 5) {
		goto requireSyntax;







>
>
|
>
|
|
|
|
|
>
|
|
>
>




>







878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
	DupBlock(availPtr->script, argv4, (unsigned) length + 1);
	break;
    }
    case PKG_NAMES:
	if (objc != 2) {
	    Tcl_WrongNumArgs(interp, 2, objv, NULL);
	    return TCL_ERROR;
	} else {
	    Tcl_Obj *resultObj;

	    resultObj = Tcl_NewObj();
	    tablePtr = &iPtr->packageTable;
	    for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL;
		    hPtr = Tcl_NextHashEntry(&search)) {
		pkgPtr = Tcl_GetHashValue(hPtr);
		if ((pkgPtr->version != NULL) || (pkgPtr->availPtr != NULL)) {
		    Tcl_ListObjAppendElement(NULL,resultObj, Tcl_NewStringObj(
			    Tcl_GetHashKey(tablePtr, hPtr), -1));
		}
	    }
	    Tcl_SetObjResult(interp, resultObj);
	}
	break;
    case PKG_PRESENT: {
	const char *name;

	if (objc < 3) {
	    goto require;
	}
	argv2 = TclGetString(objv[2]);
	if ((argv2[0] == '-') && (strcmp(argv2, "-exact") == 0)) {
	    if (objc != 5) {
		goto requireSyntax;
1094
1095
1096
1097
1098
1099
1100


1101
1102
1103
1104
1105
1106
1107

1108
1109


1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
	ckfree(iva);
	ckfree(ivb);
	break;
    case PKG_VERSIONS:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "package");
	    return TCL_ERROR;


	}
	argv2 = TclGetString(objv[2]);
	hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2);
	if (hPtr != NULL) {
	    pkgPtr = Tcl_GetHashValue(hPtr);
	    for (availPtr = pkgPtr->availPtr; availPtr != NULL;
		    availPtr = availPtr->nextPtr) {

		Tcl_AppendElement(interp, availPtr->version);
	    }


	}
	break;
    case PKG_VSATISFIES: {
	char *argv2i = NULL;

	if (objc < 4) {
	    Tcl_WrongNumArgs(interp, 2, objv,
		    "version ?requirement ...?");
	    return TCL_ERROR;
	}

	argv2 = TclGetString(objv[2]);
	if (CheckVersionAndConvert(interp, argv2, &argv2i, NULL) != TCL_OK) {
	    return TCL_ERROR;
	} else if (CheckAllRequirements(interp, objc-3, objv+3) != TCL_OK) {







>
>
|
|
|
|
|
|
|
>
|
|
>
>






|
<







1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128

1129
1130
1131
1132
1133
1134
1135
	ckfree(iva);
	ckfree(ivb);
	break;
    case PKG_VERSIONS:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "package");
	    return TCL_ERROR;
	} else {
	    Tcl_Obj *resultObj = Tcl_NewObj();

	    argv2 = TclGetString(objv[2]);
	    hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2);
	    if (hPtr != NULL) {
		pkgPtr = Tcl_GetHashValue(hPtr);
		for (availPtr = pkgPtr->availPtr; availPtr != NULL;
			availPtr = availPtr->nextPtr) {
		    Tcl_ListObjAppendElement(NULL, resultObj,
			    Tcl_NewStringObj(availPtr->version, -1));
		}
	    }
	    Tcl_SetObjResult(interp, resultObj);
	}
	break;
    case PKG_VSATISFIES: {
	char *argv2i = NULL;

	if (objc < 4) {
	    Tcl_WrongNumArgs(interp, 2, objv, "version ?requirement ...?");

	    return TCL_ERROR;
	}

	argv2 = TclGetString(objv[2]);
	if (CheckVersionAndConvert(interp, argv2, &argv2i, NULL) != TCL_OK) {
	    return TCL_ERROR;
	} else if (CheckAllRequirements(interp, objc-3, objv+3) != TCL_OK) {

Changes to generic/tclTimer.c.

789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
{
    Tcl_WideInt ms = 0;		/* Number of milliseconds to wait */
    Tcl_Time wakeup;
    AfterInfo *afterPtr;
    AfterAssocData *assocPtr;
    int length;
    int index;
    char buf[16 + TCL_INTEGER_SPACE];
    static const char *const afterSubCmds[] = {
	"cancel", "idle", "info", NULL
    };
    enum afterSubCmds {AFTER_CANCEL, AFTER_IDLE, AFTER_INFO};
    ThreadSpecificData *tsdPtr = InitTimer();

    if (objc < 2) {







<







789
790
791
792
793
794
795

796
797
798
799
800
801
802
{
    Tcl_WideInt ms = 0;		/* Number of milliseconds to wait */
    Tcl_Time wakeup;
    AfterInfo *afterPtr;
    AfterAssocData *assocPtr;
    int length;
    int index;

    static const char *const afterSubCmds[] = {
	"cancel", "idle", "info", NULL
    };
    enum afterSubCmds {AFTER_CANCEL, AFTER_IDLE, AFTER_INFO};
    ThreadSpecificData *tsdPtr = InitTimer();

    if (objc < 2) {
948
949
950
951
952
953
954


955
956
957

958
959
960
961

962
963
964
965
966
967
968
	afterPtr->nextPtr = assocPtr->firstAfterPtr;
	assocPtr->firstAfterPtr = afterPtr;
	Tcl_DoWhenIdle(AfterProc, afterPtr);
	Tcl_SetObjResult(interp, Tcl_ObjPrintf("after#%d", afterPtr->id));
	break;
    case AFTER_INFO:
	if (objc == 2) {


	    for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL;
		    afterPtr = afterPtr->nextPtr) {
		if (assocPtr->interp == interp) {

		    sprintf(buf, "after#%d", afterPtr->id);
		    Tcl_AppendElement(interp, buf);
		}
	    }

	    return TCL_OK;
	}
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?id?");
	    return TCL_ERROR;
	}
	afterPtr = GetAfterEvent(assocPtr, objv[2]);







>
>



>
|
<


>







947
948
949
950
951
952
953
954
955
956
957
958
959
960

961
962
963
964
965
966
967
968
969
970
	afterPtr->nextPtr = assocPtr->firstAfterPtr;
	assocPtr->firstAfterPtr = afterPtr;
	Tcl_DoWhenIdle(AfterProc, afterPtr);
	Tcl_SetObjResult(interp, Tcl_ObjPrintf("after#%d", afterPtr->id));
	break;
    case AFTER_INFO:
	if (objc == 2) {
            Tcl_Obj *resultObj = Tcl_NewObj();

	    for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL;
		    afterPtr = afterPtr->nextPtr) {
		if (assocPtr->interp == interp) {
                    Tcl_ListObjAppendElement(NULL, resultObj, Tcl_ObjPrintf(
                            "after#%d", afterPtr->id));

		}
	    }
            Tcl_SetObjResult(interp, resultObj);
	    return TCL_OK;
	}
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?id?");
	    return TCL_ERROR;
	}
	afterPtr = GetAfterEvent(assocPtr, objv[2]);