Attachment "varflags.diff" to
ticket [1055216fff]
added by
msofer
2004-10-27 18:31:13.
Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcl/tcl/ChangeLog,v
retrieving revision 1.2345
diff -u -r1.2345 ChangeLog
--- ChangeLog 27 Oct 2004 09:36:58 -0000 1.2345
+++ ChangeLog 27 Oct 2004 11:22:48 -0000
@@ -1,3 +1,23 @@
+2004-10-27 Miguel Sofer <[email protected]>
+
+ * generic/tclCmdIL.c:
+ * generic/tclCompCmds.c:
+ * generic/tclCompile.c:
+ * generic/tclExecute.c:
+ * generic/tclInt.h:
+ * generic/tclProc.c:
+ * generic/tclVar.c: simplification of the variable logic; three
+ flag masks (VAR_SCALAR, VAR_UNDEFINED and VAR_ARGUMENT) are not
+ used any longer.
+
+ *** POTENTIAL INCOMPATIBILITY ***
+ Extensions that include tclInt.h and directly access the variable
+ flag values will definitely lose binary compatibility due to
+ changes in some macro definitions. Source compatibility may also
+ be affected depending on the details, and needs reviewing.
+ Extensions that might be impacted include procomp, tbcload, itcl and
+ xotcl.
+
2004-10-27 Donal K. Fellows <[email protected]>
* doc/[a-e]*.n: Many small general documentation fixes.
Index: generic/tclCmdIL.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCmdIL.c,v
retrieving revision 1.67
diff -u -r1.67 tclCmdIL.c
--- generic/tclCmdIL.c 25 Oct 2004 01:06:49 -0000 1.67
+++ generic/tclCmdIL.c 27 Oct 2004 11:22:50 -0000
@@ -534,6 +534,7 @@
Proc *procPtr;
CompiledLocal *localPtr;
Tcl_Obj *listObjPtr;
+ int argNum = 0;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "procname");
@@ -553,12 +554,11 @@
*/
listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
- for (localPtr = procPtr->firstLocalPtr; localPtr != NULL;
+ for (localPtr = procPtr->firstLocalPtr;
+ (argNum++ < procPtr->numArgs) && (localPtr != NULL);
localPtr = localPtr->nextPtr) {
- if (TclIsVarArgument(localPtr)) {
- Tcl_ListObjAppendElement(interp, listObjPtr,
- Tcl_NewStringObj(localPtr->name, -1));
- }
+ Tcl_ListObjAppendElement(interp, listObjPtr,
+ Tcl_NewStringObj(localPtr->name, -1));
}
Tcl_SetObjResult(interp, listObjPtr);
return TCL_OK;
@@ -909,6 +909,7 @@
Proc *procPtr;
CompiledLocal *localPtr;
Tcl_Obj *valueObjPtr;
+ int argNum = 0;
if (objc != 5) {
Tcl_WrongNumArgs(interp, 2, objv, "procname arg varname");
@@ -927,7 +928,7 @@
for (localPtr = procPtr->firstLocalPtr; localPtr != NULL;
localPtr = localPtr->nextPtr) {
- if (TclIsVarArgument(localPtr)
+ if ((argNum++ < procPtr->numArgs)
&& (strcmp(argName, localPtr->name) == 0)) {
if (localPtr->defValuePtr != NULL) {
valueObjPtr = Tcl_ObjSetVar2(interp, objv[4], NULL,
Index: generic/tclCompCmds.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompCmds.c,v
retrieving revision 1.59
diff -u -r1.59 tclCompCmds.c
--- generic/tclCompCmds.c 18 Oct 2004 21:15:37 -0000 1.59
+++ generic/tclCompCmds.c 27 Oct 2004 11:22:51 -0000
@@ -255,7 +255,7 @@
}
localIndex = TclFindCompiledLocal(nameTokenPtr[1].start,
nameTokenPtr[1].size, /*create*/ 1,
- /*flags*/ VAR_SCALAR, envPtr->procPtr);
+ /*flags*/ 0, envPtr->procPtr);
} else {
return TCL_OUT_LINE_COMPILE;
}
@@ -756,13 +756,13 @@
firstValueTemp = -1;
for (loopIndex = 0; loopIndex < numLists; loopIndex++) {
tempVar = TclFindCompiledLocal(NULL, /*nameChars*/ 0,
- /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);
+ /*create*/ 1, /*flags*/ 0, procPtr);
if (loopIndex == 0) {
firstValueTemp = tempVar;
}
}
loopCtTemp = TclFindCompiledLocal(NULL, /*nameChars*/ 0,
- /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);
+ /*create*/ 1, /*flags*/ 0, procPtr);
/*
* Create and initialize the ForeachInfo and ForeachVarList data
@@ -785,7 +785,7 @@
CONST char *varName = varvList[loopIndex][j];
int nameChars = strlen(varName);
varListPtr->varIndexes[j] = TclFindCompiledLocal(varName,
- nameChars, /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);
+ nameChars, /*create*/ 1, /*flags*/ 0, procPtr);
}
infoPtr->varLists[loopIndex] = varListPtr;
}
@@ -3492,7 +3492,7 @@
if ((envPtr->procPtr != NULL) && !hasNsQualifiers) {
localIndex = TclFindCompiledLocal(name, nameChars,
/*create*/ (flags & TCL_CREATE_VAR),
- /*flags*/ ((elName==NULL)? VAR_SCALAR : VAR_ARRAY),
+ /*flags*/ ((elName==NULL)? 0 : VAR_ARRAY),
envPtr->procPtr);
if ((flags & TCL_NO_LARGE_INDEX) && (localIndex > 255)) {
/* we'll push the name */
Index: generic/tclCompile.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompile.c,v
retrieving revision 1.78
diff -u -r1.78 tclCompile.c
--- generic/tclCompile.c 8 Oct 2004 15:39:52 -0000 1.78
+++ generic/tclCompile.c 27 Oct 2004 11:22:54 -0000
@@ -1777,8 +1777,8 @@
int create; /* If 1, allocate a local frame entry for
* the variable if it is new. */
int flags; /* Flag bits for the compiled local if
- * created. Only VAR_SCALAR, VAR_ARRAY, and
- * VAR_LINK make sense. */
+ * created. Only VAR_ARRAY, and VAR_LINK make
+ * sense, a scalar is created if flags is 0. */
register Proc *procPtr; /* Points to structure describing procedure
* containing the variable reference. */
{
@@ -1821,12 +1821,12 @@
procPtr->lastLocalPtr->nextPtr = localPtr;
procPtr->lastLocalPtr = localPtr;
}
+ localPtr->flags = flags;
localPtr->nextPtr = NULL;
localPtr->nameLength = nameBytes;
localPtr->frameIndex = localVar;
- localPtr->flags = flags | VAR_UNDEFINED;
if (name == NULL) {
- localPtr->flags |= VAR_TEMPORARY;
+ TclSetVarTemporary(localPtr);
}
localPtr->defValuePtr = NULL;
localPtr->resolveInfo = NULL;
@@ -1872,7 +1872,9 @@
Var *resolvedVarPtr;
ResolverScheme *resPtr;
int result;
-
+ int argNum = 0, numArgs = framePtr->procPtr->numArgs;
+ int resolversNeeded = (nsPtr->compiledVarResProc || iPtr->resolverPtr);
+
/*
* Initialize the array of local variables stored in the call frame.
* Some variables may have special resolution rules. In that case,
@@ -1882,75 +1884,77 @@
for (localPtr = framePtr->procPtr->firstLocalPtr;
localPtr != NULL;
- localPtr = localPtr->nextPtr) {
-
- /*
- * Check to see if this local is affected by namespace or
- * interp resolvers. The resolver to use is cached for the
- * next invocation of the procedure.
- */
-
- if (!(localPtr->flags & (VAR_ARGUMENT|VAR_TEMPORARY|VAR_RESOLVED))
- && (nsPtr->compiledVarResProc || iPtr->resolverPtr)) {
- resPtr = iPtr->resolverPtr;
-
- if (nsPtr->compiledVarResProc) {
- result = (*nsPtr->compiledVarResProc)(nsPtr->interp,
- localPtr->name, localPtr->nameLength,
- (Tcl_Namespace *) nsPtr, &vinfo);
- } else {
- result = TCL_CONTINUE;
- }
+ varPtr++, localPtr = localPtr->nextPtr) {
- while ((result == TCL_CONTINUE) && resPtr) {
- if (resPtr->compiledVarResProc) {
- result = (*resPtr->compiledVarResProc)(nsPtr->interp,
+ if (resolversNeeded) {
+ /*
+ * Check to see if this local is affected by namespace or
+ * interp resolvers. The resolver to use is cached for the
+ * next invocation of the procedure.
+ *
+ * Performance note: should this be an independent loop?
+ */
+
+ if ((argNum++ >= numArgs)
+ && !(localPtr->flags & (VAR_TEMPORARY|VAR_RESOLVED))) {
+ resPtr = iPtr->resolverPtr;
+
+ if (nsPtr->compiledVarResProc) {
+ result = (*nsPtr->compiledVarResProc)(nsPtr->interp,
localPtr->name, localPtr->nameLength,
(Tcl_Namespace *) nsPtr, &vinfo);
+ } else {
+ result = TCL_CONTINUE;
+ }
+
+ while ((result == TCL_CONTINUE) && resPtr) {
+ if (resPtr->compiledVarResProc) {
+ result = (*resPtr->compiledVarResProc)(nsPtr->interp,
+ localPtr->name, localPtr->nameLength,
+ (Tcl_Namespace *) nsPtr, &vinfo);
+ }
+ resPtr = resPtr->nextPtr;
}
- resPtr = resPtr->nextPtr;
+ if (result == TCL_OK) {
+ localPtr->resolveInfo = vinfo;
+ TclSetVarResolved(localPtr);
+ }
+ }
+
+ /*
+ * Now invoke the resolvers to determine the exact variables that
+ * should be used.
+ */
+
+ resVarInfo = localPtr->resolveInfo;
+ resolvedVarPtr = NULL;
+
+ if (resVarInfo && resVarInfo->fetchProc) {
+ resolvedVarPtr = (Var*) (*resVarInfo->fetchProc)(interp,
+ resVarInfo);
}
- if (result == TCL_OK) {
- localPtr->resolveInfo = vinfo;
- localPtr->flags |= VAR_RESOLVED;
+
+ if (resolvedVarPtr) {
+ TclSetVarLink(varPtr);
+ varPtr->value.linkPtr = resolvedVarPtr;
+ resolvedVarPtr->refCount++;
}
}
/*
- * Now invoke the resolvers to determine the exact variables that
- * should be used.
+ * Performance note: would it be better to memset all the
+ * varPtr fields to 0 outside the loop, and then iterate setting
+ * the names and resolvers?
*/
-
- resVarInfo = localPtr->resolveInfo;
- resolvedVarPtr = NULL;
-
- if (resVarInfo && resVarInfo->fetchProc) {
- resolvedVarPtr = (Var*) (*resVarInfo->fetchProc)(interp,
- resVarInfo);
- }
-
- if (resolvedVarPtr) {
- varPtr->name = localPtr->name; /* will be just '\0' if temp var */
- varPtr->nsPtr = NULL;
- varPtr->hPtr = NULL;
- varPtr->refCount = 0;
- varPtr->tracePtr = NULL;
- varPtr->searchPtr = NULL;
- varPtr->flags = 0;
- TclSetVarLink(varPtr);
- varPtr->value.linkPtr = resolvedVarPtr;
- resolvedVarPtr->refCount++;
- } else {
- varPtr->value.objPtr = NULL;
- varPtr->name = localPtr->name; /* will be just '\0' if temp var */
- varPtr->nsPtr = NULL;
- varPtr->hPtr = NULL;
- varPtr->refCount = 0;
- varPtr->tracePtr = NULL;
- varPtr->searchPtr = NULL;
- varPtr->flags = localPtr->flags;
- }
- varPtr++;
+
+ varPtr->value.objPtr = NULL;
+ varPtr->name = localPtr->name; /* will be just '\0' if temp var */
+ varPtr->nsPtr = NULL;
+ varPtr->hPtr = NULL;
+ varPtr->refCount = 0;
+ varPtr->tracePtr = NULL;
+ varPtr->searchPtr = NULL;
+ varPtr->flags = 0;
}
}
@@ -3029,12 +3033,12 @@
CompiledLocal *localPtr = procPtr->firstLocalPtr;
for (i = 0; i < numCompiledLocals; i++) {
fprintf(stdout, " slot %d%s%s%s%s%s%s", i,
- ((localPtr->flags & VAR_SCALAR)? ", scalar" : ""),
- ((localPtr->flags & VAR_ARRAY)? ", array" : ""),
- ((localPtr->flags & VAR_LINK)? ", link" : ""),
- ((localPtr->flags & VAR_ARGUMENT)? ", arg" : ""),
- ((localPtr->flags & VAR_TEMPORARY)? ", temp" : ""),
- ((localPtr->flags & VAR_RESOLVED)? ", resolved" : ""));
+ (TclIsVarScalar(localPtr)? ", scalar" : ""),
+ (TclIsVarArray(localPtr)? ", array" : ""),
+ (TclIsVarLink(localPtr)? ", link" : ""),
+ ((i < procPtr->numArgs)? ", arg" : ""),
+ (TclIsVarTemporary(localPtr)? ", temp" : ""),
+ (TclIsVarResolved(localPtr)? ", resolved" : ""));
if (TclIsVarTemporary(localPtr)) {
fprintf(stdout, "\n");
} else {
Index: generic/tclExecute.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclExecute.c,v
retrieving revision 1.162
diff -u -r1.162 tclExecute.c
--- generic/tclExecute.c 25 Oct 2004 20:24:12 -0000 1.162
+++ generic/tclExecute.c 27 Oct 2004 11:22:57 -0000
@@ -2106,9 +2106,6 @@
if (valuePtr != objResultPtr) {
if (valuePtr != NULL) {
TclDecrRefCount(valuePtr);
- } else {
- TclSetVarScalar(varPtr);
- TclClearVarUndefined(varPtr);
}
varPtr->value.objPtr = objResultPtr;
Tcl_IncrRefCount(objResultPtr);
@@ -4494,7 +4491,6 @@
Tcl_SetLongObj(oldValuePtr, -1);
}
TclSetVarScalar(iterVarPtr);
- TclClearVarUndefined(iterVarPtr);
TRACE(("%u => loop iter count temp %d\n",
opnd, iterTmpIndex));
}
@@ -4608,9 +4604,6 @@
if (valuePtr != value2Ptr) {
if (value2Ptr != NULL) {
TclDecrRefCount(value2Ptr);
- } else {
- TclSetVarScalar(varPtr);
- TclClearVarUndefined(varPtr);
}
varPtr->value.objPtr = valuePtr;
Tcl_IncrRefCount(valuePtr);
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.188
diff -u -r1.188 tclInt.h
--- generic/tclInt.h 26 Oct 2004 16:19:58 -0000 1.188
+++ generic/tclInt.h 27 Oct 2004 11:22:59 -0000
@@ -428,13 +428,12 @@
} Var;
/*
- * Flag bits for variables. The first three (VAR_SCALAR, VAR_ARRAY, and
- * VAR_LINK) are mutually exclusive and give the "type" of the variable.
- * VAR_UNDEFINED is independent of the variable's type.
- *
- * VAR_SCALAR - 1 means this is a scalar variable and not
- * an array or link. The "objPtr" field points
- * to the variable's value, a Tcl object.
+ * Flag bits for variables. The first two (VAR_ARRAY and VAR_LINK) are
+ * mutually exclusive and give the "type" of the variable; a scalar is
+ * neither an array nor a link.
+ *
+ * VAR_SCALAR - UNUSED since tcl8.5. A scalar variable is one
+ * where neither VAR_ARRAY or VAR_LINK are set.
* VAR_ARRAY - 1 means this is an array variable rather
* than a scalar variable or link. The
* "tablePtr" field points to the array's
@@ -446,12 +445,8 @@
* this come about through "upvar" and "global"
* commands, or through references to variables
* in enclosing namespaces.
- * VAR_UNDEFINED - 1 means that the variable is in the process
- * of being deleted. An undefined variable
- * logically does not exist and survives only
- * while it has a trace, or if it is a global
- * variable currently being used by some
- * procedure.
+ * VAR_UNDEFINED - UNUSED since tcl8.5. An undefined variable is
+ * one that has a NULL value field.
* VAR_IN_HASHTABLE - 1 means this variable is in a hashtable and
* the Var structure is malloced. 0 if it is
* a local variable that was assigned a slot
@@ -485,6 +480,24 @@
* name.
* VAR_RESOLVED - 1 if name resolution has been done for this
* variable.
+ *
+ * The following additional flags are used to speed up variable access by
+ * the bytecode engine. The information contained is already present in the
+ * other flag values and/or the fields of the Var structure. There is special
+ * code to maintain these flag values in synch with the rest.
+ *
+ * VAR_DIRECT_READABLE 1 means that TEBC can read this variable
+ * directly:
+ * - VAR_SCALAR is set
+ * - VAR_UNDEFINED is not set
+ * - tracePtr is NULL.
+ * VAR_DIRECT_WRITABLE 1 means that TEBC can write this variable
+ * directly:
+ * - one of {VAR_SCALAR,VAR_UNDEFINED} is set
+ * - tracePtr is NULL
+ * - VAR_IN_HASHTABLE is not set, or else hPtr
+ * is not NULL.
+ * THIS IS NOT YET IMPLEMENTED.
*/
#define VAR_SCALAR 0x1
@@ -500,6 +513,9 @@
#define VAR_TEMPORARY 0x200
#define VAR_RESOLVED 0x400
+#define VAR_DIRECT_READABLE 0x800
+#define VAR_DIRECT_WRITABLE 0x1000
+
/*
* Macros to ensure that various flag bits are set properly for variables.
* The ANSI C "prototypes" for these macros are:
@@ -513,22 +529,22 @@
*/
#define TclSetVarScalar(varPtr) \
- (varPtr)->flags = ((varPtr)->flags & ~(VAR_ARRAY|VAR_LINK)) | VAR_SCALAR
+ (varPtr)->flags = ((varPtr)->flags & ~(VAR_ARRAY|VAR_LINK))
#define TclSetVarArray(varPtr) \
- (varPtr)->flags = ((varPtr)->flags & ~(VAR_SCALAR|VAR_LINK)) | VAR_ARRAY
+ (varPtr)->flags = ((varPtr)->flags & ~(VAR_LINK)) | VAR_ARRAY
#define TclSetVarLink(varPtr) \
- (varPtr)->flags = ((varPtr)->flags & ~(VAR_SCALAR|VAR_ARRAY)) | VAR_LINK
+ (varPtr)->flags = ((varPtr)->flags & ~(VAR_ARRAY)) | VAR_LINK
#define TclSetVarArrayElement(varPtr) \
(varPtr)->flags = ((varPtr)->flags & ~VAR_ARRAY) | VAR_ARRAY_ELEMENT
#define TclSetVarUndefined(varPtr) \
- (varPtr)->flags |= VAR_UNDEFINED
+ (varPtr)->flags &= ~(VAR_ARRAY|VAR_LINK); \
+ (varPtr)->value.objPtr = NULL
-#define TclClearVarUndefined(varPtr) \
- (varPtr)->flags &= ~VAR_UNDEFINED
+#define TclClearVarUndefined(varPtr)
#define TclSetVarTraceActive(varPtr) \
(varPtr)->flags |= VAR_TRACE_ACTIVE
@@ -542,6 +558,12 @@
#define TclClearVarNamespaceVar(varPtr) \
(varPtr)->flags &= ~VAR_NAMESPACE_VAR
+#define TclSetVarTemporary(varPtr) \
+ (varPtr)->flags |= VAR_TEMPORARY
+
+#define TclSetVarResolved(varPtr) \
+ (varPtr)->flags |= VAR_RESOLVED
+
/*
* Macros to read various flag bits of variables.
* The ANSI C "prototypes" for these macros are:
@@ -552,12 +574,11 @@
* EXTERN int TclIsVarUndefined _ANSI_ARGS_((Var *varPtr));
* EXTERN int TclIsVarArrayElement _ANSI_ARGS_((Var *varPtr));
* EXTERN int TclIsVarTemporary _ANSI_ARGS_((Var *varPtr));
- * EXTERN int TclIsVarArgument _ANSI_ARGS_((Var *varPtr));
* EXTERN int TclIsVarResolved _ANSI_ARGS_((Var *varPtr));
*/
#define TclIsVarScalar(varPtr) \
- ((varPtr)->flags & VAR_SCALAR)
+ (!((varPtr)->flags & (VAR_ARRAY|VAR_LINK)))
#define TclIsVarLink(varPtr) \
((varPtr)->flags & VAR_LINK)
@@ -566,7 +587,7 @@
((varPtr)->flags & VAR_ARRAY)
#define TclIsVarUndefined(varPtr) \
- ((varPtr)->flags & VAR_UNDEFINED)
+ (varPtr->value.objPtr == NULL)
#define TclIsVarArrayElement(varPtr) \
((varPtr)->flags & VAR_ARRAY_ELEMENT)
@@ -577,9 +598,6 @@
#define TclIsVarTemporary(varPtr) \
((varPtr)->flags & VAR_TEMPORARY)
-#define TclIsVarArgument(varPtr) \
- ((varPtr)->flags & VAR_ARGUMENT)
-
#define TclIsVarResolved(varPtr) \
((varPtr)->flags & VAR_RESOLVED)
Index: generic/tclProc.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclProc.c,v
retrieving revision 1.63
diff -u -r1.63 tclProc.c
--- generic/tclProc.c 22 Oct 2004 13:48:58 -0000 1.63
+++ generic/tclProc.c 27 Oct 2004 11:23:00 -0000
@@ -410,13 +410,16 @@
* For the flags, we and out VAR_UNDEFINED to support bridging
* precompiled <= 8.3 code in 8.4 where this is now used as an
* optimization indicator. Yes, this is a hack. -- hobbs
+ *
+ * FIXME: VAR_UNDEFINED, VAR_SCALAR and VAR_ARGUMENT now not used
+ * in the core; what about older precompiled code? Tests in
+ * tesuite pass.
*/
if ((localPtr->nameLength != nameLength)
|| (strcmp(localPtr->name, fieldValues[0]))
|| (localPtr->frameIndex != i)
- || ((localPtr->flags & ~VAR_UNDEFINED)
- != (VAR_SCALAR | VAR_ARGUMENT))
+ /* || (localPtr->flags != VAR_ARGUMENT) */
|| ((localPtr->defValuePtr == NULL)
&& (fieldCount == 2))
|| ((localPtr->defValuePtr != NULL)
@@ -469,7 +472,7 @@
localPtr->nextPtr = NULL;
localPtr->nameLength = nameLength;
localPtr->frameIndex = i;
- localPtr->flags = VAR_SCALAR | VAR_ARGUMENT;
+ localPtr->flags = 0;
localPtr->resolveInfo = NULL;
if (fieldCount == 2) {
@@ -1000,11 +1003,6 @@
localPtr = procPtr->firstLocalPtr;
argCt = objc;
for (i = 1, argCt -= 1; i <= numArgs; i++, argCt--) {
- if (!TclIsVarArgument(localPtr)) {
- Tcl_Panic("TclObjInterpProc: local variable %s is not argument but should be",
- localPtr->name);
- return TCL_ERROR;
- }
if (TclIsVarTemporary(localPtr)) {
Tcl_Panic("TclObjInterpProc: local variable %d is temporary but should be an argument", i);
return TCL_ERROR;
@@ -1021,19 +1019,16 @@
Tcl_Obj *listPtr = Tcl_NewListObj(argCt, &(objv[i]));
varPtr->value.objPtr = listPtr;
Tcl_IncrRefCount(listPtr); /* local var is a reference */
- TclClearVarUndefined(varPtr);
argCt = 0;
break; /* done processing args */
} else if (argCt > 0) {
Tcl_Obj *objPtr = objv[i];
varPtr->value.objPtr = objPtr;
- TclClearVarUndefined(varPtr);
Tcl_IncrRefCount(objPtr); /* since the local variable now has
* another reference to object. */
} else if (localPtr->defValuePtr != NULL) {
Tcl_Obj *objPtr = localPtr->defValuePtr;
varPtr->value.objPtr = objPtr;
- TclClearVarUndefined(varPtr);
Tcl_IncrRefCount(objPtr); /* since the local variable now has
* another reference to object. */
} else {
Index: generic/tclVar.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclVar.c,v
retrieving revision 1.97
diff -u -r1.97 tclVar.c
--- generic/tclVar.c 26 Oct 2004 16:19:58 -0000 1.97
+++ generic/tclVar.c 27 Oct 2004 11:23:02 -0000
@@ -164,19 +164,19 @@
* variable structure for the array that contains the variable (or NULL
* if the variable is a scalar). If the variable can't be found and
* either createPart1 or createPart2 are 1, a new as-yet-undefined
- * (VAR_UNDEFINED) variable structure is created, entered into a hash
- * table, and returned.
+ * variable structure is created, entered into a hash table and
+ * returned.
*
* If the variable isn't found and creation wasn't specified, or some
* other error occurs, NULL is returned and an error message is left in
* the interp's result if TCL_LEAVE_ERR_MSG is set in flags.
*
- * Note: it's possible for the variable returned to be VAR_UNDEFINED
+ * Note: it's possible for the variable returned to be undefined
* even if createPart1 or createPart2 are 1 (these only cause the hash
* table entry or array to be created). For example, the variable might
* be a global that has been unset but is still referenced by a
* procedure, or a variable that has been unset but it only being kept
- * in existence (if VAR_UNDEFINED) by a trace.
+ * in existence by a trace.
*
* Side effects:
* New hashtable entries may be created if createPart1 or createPart2
@@ -313,19 +313,19 @@
* variable structure for the array that contains the variable (or NULL
* if the variable is a scalar). If the variable can't be found and
* either createPart1 or createPart2 are 1, a new as-yet-undefined
- * (VAR_UNDEFINED) variable structure is created, entered into a hash
- * table, and returned.
+ * variable structure is created, entered into a hash table, and
+ * returned.
*
* If the variable isn't found and creation wasn't specified, or some
* other error occurs, NULL is returned and an error message is left in
* the interp's result if TCL_LEAVE_ERR_MSG is set in flags.
*
- * Note: it's possible for the variable returned to be VAR_UNDEFINED
+ * Note: it's possible for the variable returned to be undefined
* even if createPart1 or createPart2 are 1 (these only cause the hash
* table entry or array to be created). For example, the variable might
* be a global that has been unset but is still referenced by a
* procedure, or a variable that has been unset but it only being kept
- * in existence (if VAR_UNDEFINED) by a trace.
+ * in existence by a trace.
*
* Side effects:
* New hashtable entries may be created if createPart1 or createPart2
@@ -625,8 +625,8 @@
* Results:
* The return value is a pointer to the variable structure indicated by
* varName, or NULL if the variable couldn't be found. If the variable
- * can't be found and create is 1, a new as-yet-undefined (VAR_UNDEFINED)
- * variable structure is created, entered into a hash table, and returned.
+ * can't be found and create is 1, a new as-yet-undefined variable
+ * structure is created, entered into a hash table, and returned.
*
* If the current CallFrame corresponds to a proc and the variable found is
* one of the compiledLocals, its index is placed in *indexPtr. Otherwise,
@@ -642,12 +642,11 @@
* other error occurs, NULL is returned and the corresponding error
* message is left in *errMsgPtr.
*
- * Note: it's possible for the variable returned to be VAR_UNDEFINED
+ * Note: it's possible for the variable returned to be undefined
* even if create is 1 (this only causes the hash table entry to be
* created). For example, the variable might be a global that has been
* unset but is still referenced by a procedure, or a variable that has
- * been unset but it only being kept in existence (if VAR_UNDEFINED) by
- * a trace.
+ * been unset but it only being kept in existence by a trace.
*
* Side effects:
* A new hashtable entry may be created if create is 1.
@@ -886,12 +885,12 @@
* created. Otherwise, NULL is returned and an error message is left in
* the interp's result if TCL_LEAVE_ERR_MSG is set in flags.
*
- * Note: it's possible for the variable returned to be VAR_UNDEFINED
+ * Note: it's possible for the variable returned to be undefined
* even if createPart1 or createPart2 are 1 (these only cause the hash
* table entry or array to be created). For example, the variable might
* be a global that has been unset but is still referenced by a
* procedure, or a variable that has been unset but it only being kept
- * in existence (if VAR_UNDEFINED) by a trace.
+ * in existence by a trace.
*
* Side effects:
* The variable at arrayPtr may be converted to be an array if
@@ -948,7 +947,6 @@
}
TclSetVarArray(arrayPtr);
- TclClearVarUndefined(arrayPtr);
arrayPtr->value.tablePtr =
(Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(arrayPtr->value.tablePtr, TCL_STRING_KEYS);
@@ -1602,8 +1600,8 @@
* is requested; this is only done in the core when lappending.
*/
- if ((flags & TCL_TRACE_READS) && ((varPtr->tracePtr != NULL)
- || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL)))) {
+ if ((flags & TCL_TRACE_READS) && (!TclIsVarUntraced(varPtr)
+ || ((arrayPtr != NULL) && !TclIsVarUntraced(arrayPtr)))) {
if (TCL_ERROR == TclCallVarTraces(iPtr, arrayPtr, varPtr, part1, part2,
TCL_TRACE_READS, (flags & TCL_LEAVE_ERR_MSG))) {
return NULL;
@@ -1618,17 +1616,14 @@
* "copy on write".
*/
- if (flags & TCL_LIST_ELEMENT && !(flags & TCL_APPEND_VALUE)) {
- TclSetVarUndefined(varPtr);
- }
oldValuePtr = varPtr->value.objPtr;
if (flags & (TCL_APPEND_VALUE|TCL_LIST_ELEMENT)) {
- if (TclIsVarUndefined(varPtr) && (oldValuePtr != NULL)) {
- Tcl_DecrRefCount(oldValuePtr); /* discard old value */
- varPtr->value.objPtr = NULL;
- oldValuePtr = NULL;
- }
if (flags & TCL_LIST_ELEMENT) { /* append list element */
+ if (!(flags & TCL_APPEND_VALUE) && oldValuePtr) {
+ Tcl_DecrRefCount(oldValuePtr); /* discard old value */
+ varPtr->value.objPtr = NULL;
+ oldValuePtr = NULL;
+ }
if (oldValuePtr == NULL) {
TclNewObj(oldValuePtr);
varPtr->value.objPtr = oldValuePtr;
@@ -1675,10 +1670,6 @@
}
}
TclSetVarScalar(varPtr);
- TclClearVarUndefined(varPtr);
- if (arrayPtr != NULL) {
- TclClearVarUndefined(arrayPtr);
- }
/*
* Invoke any write traces for the variable.
@@ -2187,8 +2178,6 @@
dummyVar = *varPtr;
TclSetVarUndefined(varPtr);
- TclSetVarScalar(varPtr);
- varPtr->value.objPtr = NULL; /* dummyVar points to any value object */
varPtr->tracePtr = NULL;
varPtr->searchPtr = NULL;
@@ -3296,7 +3285,6 @@
}
}
TclSetVarArray(varPtr);
- TclClearVarUndefined(varPtr);
varPtr->value.tablePtr =
(Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(varPtr->value.tablePtr, TCL_STRING_KEYS);
@@ -3464,7 +3452,6 @@
}
}
TclSetVarLink(varPtr);
- TclClearVarUndefined(varPtr);
varPtr->value.linkPtr = otherPtr;
otherPtr->refCount++;
return TCL_OK;
@@ -3942,7 +3929,7 @@
varPtr->refCount = 0;
varPtr->tracePtr = NULL;
varPtr->searchPtr = NULL;
- varPtr->flags = (VAR_SCALAR | VAR_UNDEFINED | VAR_IN_HASHTABLE);
+ varPtr->flags = VAR_IN_HASHTABLE;
return varPtr;
}
@@ -4234,17 +4221,14 @@
if (TclIsVarArray(varPtr)) {
DeleteArray(iPtr, Tcl_GetHashKey(tablePtr, hPtr), varPtr,
flags);
- varPtr->value.tablePtr = NULL;
}
if (TclIsVarScalar(varPtr) && (varPtr->value.objPtr != NULL)) {
objPtr = varPtr->value.objPtr;
TclDecrRefCount(objPtr);
- varPtr->value.objPtr = NULL;
}
varPtr->hPtr = NULL;
varPtr->tracePtr = NULL;
TclSetVarUndefined(varPtr);
- TclSetVarScalar(varPtr);
/*
* If the variable was a namespace variable, decrement its
@@ -4366,12 +4350,10 @@
}
if (TclIsVarScalar(varPtr) && (varPtr->value.objPtr != NULL)) {
TclDecrRefCount(varPtr->value.objPtr);
- varPtr->value.objPtr = NULL;
}
varPtr->hPtr = NULL;
varPtr->tracePtr = NULL;
TclSetVarUndefined(varPtr);
- TclSetVarScalar(varPtr);
varPtr++;
}
}
@@ -4444,7 +4426,6 @@
}
}
TclSetVarUndefined(elPtr);
- TclSetVarScalar(elPtr);
/*
* Even though array elements are not supposed to be namespace