Tcl Source Code

Artifact [edcbbb2763]
Login

Artifact edcbbb2763f76031dd9e6b99999c3a6268f5657d:

Attachment "VarReform.diff.8.5" to ticket [1750051fff] added by msofer 2007-07-10 18:55:38.
? VarReform-showFlags.tcl
? VarReform.diff.1
? VarReform.diff.2
? VarReform.diff.2.1
? VarReform.diff.2.2
? VarReform.diff.2.3
? VarReform.diff.2.4
? VarReform.diff.2.5
? VarReform.diff.3
? VarReform.diff.3.1
? VarReform.diff.3.2
? VarReform.diff.3.3
? VarReform.diff.4.1
? VarReform.diff.4.2
? VarReform.diff.4.3
? VarReform.diff.5.1
? VarReform.diff.5.2
? VarReform.diff.5.3
? VarReform.diff.5.4
? VarReform.diff.5.5
? VarReform.diff.5.6
? VarReform.diff.7
? VarReform.diff.7.1
? VarReform.diff.7.2
? VarReform.diff.7.3
? VarReform.diff.7.4
? VarReform.diff.7.5
? VarReform.diff.7.6
? VarReform.diff.7.tmp
? VarReform.diff.8.0
? VarReform.diff.8.1
? VarReform.diff.8.2
? VarReform.diff.8.3
? VarReform.diff.8.4
? VarReform.diff.8.5
? VarReform_old
? lit
? refCount
? generic/VarReform.descr
? generic/VarReform.txt
? generic/VarReform2.txt
? generic/tclInt.h.7.5
? generic/tclInt.h.7.6
? generic/tclInt.h.8.0
? generic/tclInt.h.NEW
? generic/tclVar.c.7.5
? generic/tclVar.c.7.6
? generic/tclVar.c.CVS
? generic/tclVar.c.MOD
? generic/tclVar.c.OK
? unix/0valgrind
? unix/ERR
? unix/dltest.marker
? unix/httpd_17847
? unix/httpd_19974
? unix/httpd_25368
? unix/httpd_3272
? unix/searchPtr
? unix/tracePtr
? unix/value.objPtr
? unix/vgcore.20181
? unix/vgcore.20192
? unix/vgcore.20211
? unix/vgcore.25705
? unix/vgcore.25709
? unix/vgcore.3642
? unix/vgcore.3646
? unix/vgcore.3647
? unix/vgcore.3661
? unix/vgcore.3662
Index: generic/tcl.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tcl.h,v
retrieving revision 1.233
diff -u -r1.233 tcl.h
--- generic/tcl.h	2 Jul 2007 21:10:51 -0000	1.233
+++ generic/tcl.h	10 Jul 2007 11:53:10 -0000
@@ -870,6 +870,7 @@
     int dummy9;
     char *dummy10;
     char *dummy11;
+    char *dummy12;
 } Tcl_CallFrame;
 
 /*
Index: generic/tclBasic.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBasic.c,v
retrieving revision 1.262
diff -u -r1.262 tclBasic.c
--- generic/tclBasic.c	29 Jun 2007 03:16:01 -0000	1.262
+++ generic/tclBasic.c	10 Jul 2007 11:53:13 -0000
@@ -302,6 +302,19 @@
     { "eq", TclSortingOpCmd,  TclCompileStreqOpCmd,   0, NULL },
     { NULL, NULL,	      NULL,		      0, NULL }
 };
+
+/*
+ * Hash key type for the interp's var trace and search tables
+ */
+
+static Tcl_HashKeyType PtrHashKeyType = {
+    TCL_HASH_KEY_TYPE_VERSION,		/* version */
+    TCL_HASH_KEY_RANDOMIZE_HASH,	/* flags */
+    NULL,				/* hashKeyProc */
+    NULL, 			        /* compareKeysProc */
+    NULL,			        /* allocEntryProc */
+    NULL 			        /* freeEntryProc */
+};
 
 /*
  *----------------------------------------------------------------------
@@ -438,6 +451,17 @@
     iPtr->resultSpace[0] = 0;
     iPtr->threadId = Tcl_GetCurrentThread();
 
+    /*
+     * Initialise the tables for variable traces and searches *before*
+     * creating the global ns - so that the trace on errorInfo can be
+     * recorded. 
+     */
+    
+    Tcl_InitCustomHashTable(&iPtr->varTraces,
+	    TCL_CUSTOM_PTR_KEYS, &PtrHashKeyType);
+    Tcl_InitCustomHashTable(&iPtr->varSearches,
+	    TCL_CUSTOM_PTR_KEYS, &PtrHashKeyType);
+        
     iPtr->globalNsPtr = NULL;		/* Force creation of global ns below */
     iPtr->globalNsPtr = (Namespace *) Tcl_CreateNamespace(interp, "",
 	    (ClientData) NULL, NULL);
@@ -1332,6 +1356,10 @@
 	ckfree((char *) iPtr->lineBCPtr);
 	iPtr->lineBCPtr = NULL;
     }
+
+    Tcl_DeleteHashTable(&iPtr->varTraces);
+    Tcl_DeleteHashTable(&iPtr->varSearches);    
+    
     ckfree((char *) iPtr);
 }
 
Index: generic/tclCmdIL.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCmdIL.c,v
retrieving revision 1.121
diff -u -r1.121 tclCmdIL.c
--- generic/tclCmdIL.c	1 Jul 2007 14:49:43 -0000	1.121
+++ generic/tclCmdIL.c	10 Jul 2007 11:53:15 -0000
@@ -1033,8 +1033,8 @@
     varName = TclGetString(objv[1]);
     varPtr = TclVarTraceExists(interp, varName);
 
-    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
-	    ((varPtr != NULL) && !TclIsVarUndefined(varPtr))));
+    Tcl_SetObjResult(interp,
+	    Tcl_NewBooleanObj(varPtr && varPtr->value.objPtr));
     return TCL_OK;
 }
 
@@ -1417,7 +1417,7 @@
 
     listPtr = Tcl_NewListObj(0, NULL);
     if (pattern != NULL && TclMatchIsTrivial(pattern)) {
-	entryPtr = Tcl_FindHashEntry(&globalNsPtr->varTable, pattern);
+	entryPtr = Tcl_FindHashEntry((Tcl_HashTable *)&globalNsPtr->varTable, pattern);
 	if (entryPtr != NULL) {
 	    varPtr = (Var *) Tcl_GetHashValue(entryPtr);
 	    if (!TclIsVarUndefined(varPtr)) {
@@ -1426,14 +1426,14 @@
 	    }
 	}
     } else {
-	for (entryPtr = Tcl_FirstHashEntry(&globalNsPtr->varTable, &search);
+	for (entryPtr = Tcl_FirstHashEntry((Tcl_HashTable *)&globalNsPtr->varTable, &search);
 		entryPtr != NULL;
 		entryPtr = Tcl_NextHashEntry(&search)) {
 	    varPtr = (Var *) Tcl_GetHashValue(entryPtr);
 	    if (TclIsVarUndefined(varPtr)) {
 		continue;
 	    }
-	    varName = Tcl_GetHashKey(&globalNsPtr->varTable, entryPtr);
+	    varName = Tcl_GetHashKey((Tcl_HashTable *) &globalNsPtr->varTable, entryPtr);
 	    if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) {
 		Tcl_ListObjAppendElement(interp, listPtr,
 			Tcl_NewStringObj(varName, -1));
@@ -1732,7 +1732,7 @@
     CompiledLocal *localPtr;
     Var *varPtr;
     int i, localVarCt;
-    const char *varName;
+    char *varName, **varNames;
     Tcl_HashTable *localVarTablePtr;
     register Tcl_HashEntry *entryPtr;
     Tcl_HashSearch search;
@@ -1740,8 +1740,9 @@
     localPtr = iPtr->varFramePtr->procPtr->firstLocalPtr;
     localVarCt = iPtr->varFramePtr->numCompiledLocals;
     varPtr = iPtr->varFramePtr->compiledLocals;
-    localVarTablePtr = iPtr->varFramePtr->varTablePtr;
-
+    localVarTablePtr = (Tcl_HashTable *) iPtr->varFramePtr->varTablePtr;
+    varNames = localVarNames(iPtr->varFramePtr);
+    
     for (i = 0; i < localVarCt; i++) {
 	/*
 	 * Skip nameless (temporary) variables and undefined variables.
@@ -1749,7 +1750,7 @@
 
 	if (!TclIsVarTemporary(localPtr) && !TclIsVarUndefined(varPtr)
 		&& (includeLinks || !TclIsVarLink(varPtr))) {
-	    varName = varPtr->name;
+	    varName = varNames[i];
 	    if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) {
 		Tcl_ListObjAppendElement(interp, listPtr,
 			Tcl_NewStringObj(varName, -1));
@@ -2304,7 +2305,7 @@
 	     * If we can just do hash lookups, that simplifies things a lot.
 	     */
 
-	    entryPtr = Tcl_FindHashEntry(&nsPtr->varTable, simplePattern);
+	    entryPtr = Tcl_FindHashEntry((Tcl_HashTable *) &nsPtr->varTable, simplePattern);
 	    if (entryPtr != NULL) {
 		varPtr = (Var *) Tcl_GetHashValue(entryPtr);
 		if (!TclIsVarUndefined(varPtr)
@@ -2319,7 +2320,7 @@
 		    Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr);
 		}
 	    } else if ((nsPtr != globalNsPtr) && !specificNsInPattern) {
-		entryPtr = Tcl_FindHashEntry(&globalNsPtr->varTable,
+		entryPtr = Tcl_FindHashEntry((Tcl_HashTable *) &globalNsPtr->varTable,
 			simplePattern);
 		if (entryPtr != NULL) {
 		    varPtr = (Var *) Tcl_GetHashValue(entryPtr);
@@ -2335,12 +2336,12 @@
 	     * Have to scan the tables of variables.
 	     */
 
-	    entryPtr = Tcl_FirstHashEntry(&nsPtr->varTable, &search);
+	    entryPtr = Tcl_FirstHashEntry((Tcl_HashTable *) &nsPtr->varTable, &search);
 	    while (entryPtr != NULL) {
 		varPtr = (Var *) Tcl_GetHashValue(entryPtr);
 		if (!TclIsVarUndefined(varPtr)
 			|| TclIsVarNamespaceVar(varPtr)) {
-		    varName = Tcl_GetHashKey(&nsPtr->varTable, entryPtr);
+		    varName = Tcl_GetHashKey((Tcl_HashTable *) &nsPtr->varTable, entryPtr);
 		    if ((simplePattern == NULL)
 			    || Tcl_StringMatch(varName, simplePattern)) {
 			if (specificNsInPattern) {
@@ -2366,16 +2367,16 @@
 	     */
 
 	    if ((nsPtr != globalNsPtr) && !specificNsInPattern) {
-		entryPtr = Tcl_FirstHashEntry(&globalNsPtr->varTable,&search);
+		entryPtr = Tcl_FirstHashEntry((Tcl_HashTable *) &globalNsPtr->varTable,&search);
 		while (entryPtr != NULL) {
 		    varPtr = (Var *) Tcl_GetHashValue(entryPtr);
 		    if (!TclIsVarUndefined(varPtr)
 			    || TclIsVarNamespaceVar(varPtr)) {
-			varName = Tcl_GetHashKey(&globalNsPtr->varTable,
+			varName = Tcl_GetHashKey((Tcl_HashTable *) &globalNsPtr->varTable,
 				entryPtr);
 			if ((simplePattern == NULL)
 				|| Tcl_StringMatch(varName, simplePattern)) {
-			    if (Tcl_FindHashEntry(&nsPtr->varTable,
+			    if (Tcl_FindHashEntry((Tcl_HashTable *) &nsPtr->varTable,
 				    varName) == NULL) {
 				Tcl_ListObjAppendElement(interp, listPtr,
 					Tcl_NewStringObj(varName, -1));
Index: generic/tclCompCmds.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompCmds.c,v
retrieving revision 1.112
diff -u -r1.112 tclCompCmds.c
--- generic/tclCompCmds.c	28 Jun 2007 21:10:38 -0000	1.112
+++ generic/tclCompCmds.c	10 Jul 2007 11:53:18 -0000
@@ -403,8 +403,7 @@
 	    return TCL_ERROR;
 	}
 	resultIndex = TclFindCompiledLocal(resultNameTokenPtr[1].start,
-		resultNameTokenPtr[1].size, /*create*/ 1, VAR_SCALAR,
-		envPtr->procPtr);
+		resultNameTokenPtr[1].size, /*create*/ 1, envPtr->procPtr);
 
 	/* DKF */
 	if (parsePtr->numWords == 4) {
@@ -418,8 +417,7 @@
 		return TCL_ERROR;
 	    }
 	    optsIndex = TclFindCompiledLocal(optsNameTokenPtr[1].start,
-		    optsNameTokenPtr[1].size, /*create*/ 1, VAR_SCALAR,
-		    envPtr->procPtr);
+		    optsNameTokenPtr[1].size, /*create*/ 1, envPtr->procPtr);
 	}
     }
 
@@ -658,8 +656,7 @@
 	if (!TclIsLocalScalar(name, nameChars)) {
 	    return TCL_ERROR;
 	}
-	dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, VAR_SCALAR,
-		procPtr);
+	dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, procPtr);
 	for (i=1 ; i<numWords ; i++) {
 	    CompileWord(envPtr, tokenPtr, interp, i);
 	    tokenPtr = TokenAfter(tokenPtr);
@@ -705,8 +702,7 @@
 	if (!TclIsLocalScalar(name, nameChars)) {
 	    return TCL_ERROR;
 	}
-	dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, VAR_SCALAR,
-		procPtr);
+	dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, procPtr);
 	CompileWord(envPtr, keyTokenPtr, interp, 3);
 	TclEmitInstInt4( INST_DICT_INCR_IMM, incrAmount,	envPtr);
 	TclEmitInt4(	 dictVarIndex,				envPtr);
@@ -770,15 +766,13 @@
 	    ckfree((char *) argv);
 	    return TCL_ERROR;
 	}
-	keyVarIndex = TclFindCompiledLocal(argv[0], nameChars, 1, VAR_SCALAR,
-		procPtr);
+	keyVarIndex = TclFindCompiledLocal(argv[0], nameChars, 1, procPtr);
 	nameChars = strlen(argv[1]);
 	if (!TclIsLocalScalar(argv[1], nameChars)) {
 	    ckfree((char *) argv);
 	    return TCL_ERROR;
 	}
-	valueVarIndex = TclFindCompiledLocal(argv[1], nameChars, 1, VAR_SCALAR,
-		procPtr);
+	valueVarIndex = TclFindCompiledLocal(argv[1], nameChars, 1, procPtr);
 	ckfree((char *) argv);
 
 	/*
@@ -788,7 +782,7 @@
 	 * unset (at which point it should also have been finished with).
 	 */
 
-	infoIndex = TclFindCompiledLocal(NULL, 0, 1, VAR_SCALAR, procPtr);
+	infoIndex = TclFindCompiledLocal(NULL, 0, 1, procPtr);
 
 	/*
 	 * Preparation complete; issue instructions. Note that this code
@@ -934,8 +928,7 @@
 	if (!TclIsLocalScalar(name, nameChars)) {
 	    return TCL_ERROR;
 	}
-	dictIndex = TclFindCompiledLocal(name, nameChars, 1, VAR_SCALAR,
-		procPtr);
+	dictIndex = TclFindCompiledLocal(name, nameChars, 1, procPtr);
 
 	duiPtr = (DictUpdateInfo *)
 		ckalloc(sizeof(DictUpdateInfo) + sizeof(int) * (numVars - 1));
@@ -958,8 +951,8 @@
 		TclStackFree(interp, keyTokenPtrs);
 		return TCL_ERROR;
 	    }
-	    duiPtr->varIndices[i] = TclFindCompiledLocal(name, nameChars, 1,
-		    VAR_SCALAR, procPtr);
+	    duiPtr->varIndices[i] =
+		TclFindCompiledLocal(name, nameChars, 1, procPtr);
 	    tokenPtr = TokenAfter(tokenPtr);
 	}
 	if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
@@ -969,7 +962,7 @@
 	}
 	bodyTokenPtr = tokenPtr;
 
-	keyTmpIndex = TclFindCompiledLocal(NULL, 0, 1, VAR_SCALAR, procPtr);
+	keyTmpIndex = TclFindCompiledLocal(NULL, 0, 1, procPtr);
 
 	/*
 	 * The list of variables to bind is stored in auxiliary data so that
@@ -1040,8 +1033,7 @@
 	if (!TclIsLocalScalar(name, nameChars)) {
 	    return TCL_ERROR;
 	}
-	dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, VAR_SCALAR,
-		procPtr);
+	dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, procPtr);
 	for (i=1 ; i<numWords ; i++) {
 	    CompileWord(envPtr, tokenPtr, interp, i);
 	    tokenPtr = TokenAfter(tokenPtr);
@@ -1070,8 +1062,7 @@
 	if (!TclIsLocalScalar(name, nameChars)) {
 	    return TCL_ERROR;
 	}
-	dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, VAR_SCALAR,
-		procPtr);
+	dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, procPtr);
 	CompileWord(envPtr, keyTokenPtr, interp, 3);
 	CompileWord(envPtr, valueTokenPtr, interp, 4);
 	TclEmitInstInt4( INST_DICT_LAPPEND, dictVarIndex,	envPtr);
@@ -1514,13 +1505,13 @@
     firstValueTemp = -1;
     for (loopIndex = 0;  loopIndex < numLists;  loopIndex++) {
 	tempVar = TclFindCompiledLocal(NULL, /*nameChars*/ 0,
-		/*create*/ 1, VAR_SCALAR, procPtr);
+		/*create*/ 1, procPtr);
 	if (loopIndex == 0) {
 	    firstValueTemp = tempVar;
 	}
     }
     loopCtTemp = TclFindCompiledLocal(NULL, /*nameChars*/ 0,
-	    /*create*/ 1, VAR_SCALAR, procPtr);
+	    /*create*/ 1, procPtr);
 
     /*
      * Create and initialize the ForeachInfo and ForeachVarList data
@@ -1544,7 +1535,7 @@
 	    int nameChars = strlen(varName);
 
 	    varListPtr->varIndexes[j] = TclFindCompiledLocal(varName,
-		    nameChars, /*create*/ 1, VAR_SCALAR, procPtr);
+		    nameChars, /*create*/ 1, procPtr);
 	}
 	infoPtr->varLists[loopIndex] = varListPtr;
     }
@@ -4657,7 +4648,6 @@
 	if ((envPtr->procPtr != NULL) && !hasNsQualifiers) {
 	    localIndex = TclFindCompiledLocal(name, nameChars,
 		    /*create*/ flags & TCL_CREATE_VAR,
-		    /*flags*/ ((elName==NULL)? VAR_SCALAR : VAR_ARRAY),
 		    envPtr->procPtr);
 	    if ((flags & TCL_NO_LARGE_INDEX) && (localIndex > 255)) {
 		/*
@@ -4873,8 +4863,7 @@
 
 	return TCL_ERROR;
     } else {
-	int tmpIndex = TclFindCompiledLocal(NULL, 0, 1, VAR_SCALAR,
-		envPtr->procPtr);
+	int tmpIndex = TclFindCompiledLocal(NULL, 0, 1, envPtr->procPtr);
 	int words;
 
 	tokenPtr = TokenAfter(parsePtr->tokenPtr);
@@ -5328,7 +5317,6 @@
 
     localIndex = TclFindCompiledLocal(tailName, len,
 	    /*create*/ TCL_CREATE_VAR,
-	    /*flags*/  0,
 	    envPtr->procPtr);
     Tcl_DecrRefCount(tailPtr);
     return localIndex;
Index: generic/tclCompile.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompile.c,v
retrieving revision 1.123
diff -u -r1.123 tclCompile.c
--- generic/tclCompile.c	21 Jun 2007 18:41:16 -0000	1.123
+++ generic/tclCompile.c	10 Jul 2007 11:53:21 -0000
@@ -724,8 +724,9 @@
      * A single heap object holds the ByteCode structure and its code, object,
      * command location, and auxiliary data arrays. This means we only need to
      * 1) decrement the ref counts of the LiteralEntry's in its literal array,
-     * 2) call the free procs for the auxiliary data items, and 3) free the
-     * ByteCode structure's heap object.
+     * 2) call the free procs for the auxiliary data items, 3) free the
+     * localCache if it is unused, and finally 4) free the ByteCode
+     * structure's heap object. 
      *
      * The case for TCL_BYTECODE_PRECOMPILED (precompiled ByteCodes, like
      * those generated from tbcload) is special, as they doesn't make use of
@@ -806,6 +807,10 @@
 	}
     }
 
+    if (codePtr->localCachePtr && (--codePtr->localCachePtr->refCount == 0)) {
+	ckfree((char *) codePtr->localCachePtr);
+    }
+
     TclHandleRelease(codePtr->interpHandle);
     ckfree((char *) codePtr);
 }
@@ -1650,7 +1655,7 @@
 	    localVar = -1;
 	    if (localVarName != -1) {
 		localVar = TclFindCompiledLocal(name, nameBytes, localVarName,
-			/*flags*/ 0, envPtr->procPtr);
+			envPtr->procPtr);
 	    }
 	    if (localVar < 0) {
 		TclEmitPush(TclRegisterNewLiteral(envPtr, name, nameBytes),
@@ -2059,6 +2064,8 @@
     Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->lineBCPtr, (char *) codePtr,
 	    &new), envPtr->extCmdMapPtr);
     envPtr->extCmdMapPtr = NULL;
+
+    codePtr->localCachePtr = NULL;
 }
 
 /*
@@ -2094,9 +2101,6 @@
     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 flags,			/* Flag bits for the compiled local if
-				 * created. Only VAR_SCALAR, VAR_ARRAY, and
-				 * VAR_LINK make sense. */
     register Proc *procPtr)	/* Points to structure describing procedure
 				 * containing the variable reference. */
 {
@@ -2144,7 +2148,7 @@
 	localPtr->nextPtr = NULL;
 	localPtr->nameLength = nameBytes;
 	localPtr->frameIndex = localVar;
-	localPtr->flags = flags | VAR_UNDEFINED;
+	localPtr->flags = 0;
 	if (name == NULL) {
 	    localPtr->flags |= VAR_TEMPORARY;
 	}
@@ -3310,7 +3314,7 @@
 	    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|VAR_LINK)) ? "" : ", scalar",
 			(localPtr->flags & VAR_ARRAY) ? ", array" : "",
 			(localPtr->flags & VAR_LINK) ? ", link" : "",
 			(localPtr->flags & VAR_ARGUMENT) ? ", arg" : "",
Index: generic/tclCompile.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompile.h,v
retrieving revision 1.74
diff -u -r1.74 tclCompile.h
--- generic/tclCompile.h	21 Jun 2007 12:43:18 -0000	1.74
+++ generic/tclCompile.h	10 Jul 2007 11:53:22 -0000
@@ -416,6 +416,9 @@
 				 * code deltas. Source lengths are always
 				 * positive. This sequence is just after the
 				 * last byte in the source delta sequence. */
+    LocalCache *localCachePtr;  /* Pointer to the start of the cached variable
+				 * names and initialisation data for local
+				 * variables. */
 #ifdef TCL_COMPILE_STATS
     Tcl_Time createTime;	/* Absolute time when the ByteCode was
 				 * created. */
@@ -859,7 +862,7 @@
 			    ByteCode *codePtr);
 MODULE_SCOPE void	TclFinalizeAuxDataTypeTable(void);
 MODULE_SCOPE int	TclFindCompiledLocal(CONST char *name, int nameChars,
-			    int create, int flags, Proc *procPtr);
+			    int create, Proc *procPtr);
 MODULE_SCOPE LiteralEntry * TclLookupLiteralEntry(Tcl_Interp *interp,
 			    Tcl_Obj *objPtr);
 MODULE_SCOPE int	TclFixupForwardJump(CompileEnv *envPtr,
Index: generic/tclExecute.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclExecute.c,v
retrieving revision 1.305
diff -u -r1.305 tclExecute.c
--- generic/tclExecute.c	28 Jun 2007 21:24:56 -0000	1.305
+++ generic/tclExecute.c	10 Jul 2007 11:53:25 -0000
@@ -410,6 +410,7 @@
     NULL, NULL, NULL, NULL
 };
 
+
 /*
  * Declarations for local procedures to this file:
  */
@@ -597,6 +598,7 @@
 
     TclDecrRefCount(eePtr->constants[0]);
     TclDecrRefCount(eePtr->constants[1]);
+
     ckfree((char *) eePtr);
 }
 
@@ -1403,6 +1405,7 @@
     Tcl_Obj **initTosPtr;	/* Stack top at start of execution. */
     ptrdiff_t *initCatchTop;	/* Catch stack top at start of execution. */
     Var *compiledLocals;
+    char **varNames;
     Namespace *namespacePtr;
     CmdFrame *bcFramePtr;	/* TIP #280: Structure for tracking lines. */
     Tcl_Obj **constants = &iPtr->execEnvPtr->constants[0];
@@ -1497,6 +1500,15 @@
 
     namespacePtr = iPtr->varFramePtr->nsPtr;
     compiledLocals = iPtr->varFramePtr->compiledLocals;
+    if (iPtr->varFramePtr->procPtr) {
+	varNames = localVarNames(iPtr->varFramePtr);
+    } else {
+	/*
+	 * If there is no proc pointer, there should be no local variables either
+	 */
+	
+	varNames = NULL;
+    }
 
     /*
      * Loop executing instructions until a "done" instruction, a TCL_RETURN,
@@ -2256,14 +2268,13 @@
      */
     {
 	int opnd, pcAdjustment;
-	char *part1, *part2;
+	const char *part1, *part2;
 	Var *varPtr, *arrayPtr;
 	Tcl_Obj *objPtr;
 
     case INST_LOAD_SCALAR1:
 	opnd = TclGetUInt1AtPtr(pc+1);
 	varPtr = &(compiledLocals[opnd]);
-	part1 = varPtr->name;
 	while (TclIsVarLink(varPtr)) {
 	    varPtr = varPtr->value.linkPtr;
 	}
@@ -2280,13 +2291,13 @@
 	pcAdjustment = 2;
 	cleanup = 0;
 	arrayPtr = NULL;
+	part1 = varNames[opnd];
 	part2 = NULL;
 	goto doCallPtrGetVar;
 
     case INST_LOAD_SCALAR4:
 	opnd = TclGetUInt4AtPtr(pc+1);
 	varPtr = &(compiledLocals[opnd]);
-	part1 = varPtr->name;
 	while (TclIsVarLink(varPtr)) {
 	    varPtr = varPtr->value.linkPtr;
 	}
@@ -2303,6 +2314,7 @@
 	pcAdjustment = 5;
 	cleanup = 0;
 	arrayPtr = NULL;
+	part1 = varNames[opnd];
 	part2 = NULL;
 	goto doCallPtrGetVar;
 
@@ -2326,7 +2338,7 @@
 		"read", /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr);
 	if (varPtr) {
 	    if (TclIsVarDirectReadable(varPtr)
-		    && ((arrayPtr == NULL) || TclIsVarUntraced(arrayPtr))) {
+		    && ((arrayPtr == NULL) || !TclIsVarTraced(arrayPtr))) {
 		/*
 		 * No errors, no traces: just get the value.
 		 */
@@ -2354,16 +2366,16 @@
     doLoadArray:
 	part2 = TclGetString(OBJ_AT_TOS);
 	arrayPtr = &(compiledLocals[opnd]);
-	part1 = arrayPtr->name;
+	part1 = varNames[opnd];
 	while (TclIsVarLink(arrayPtr)) {
 	    arrayPtr = arrayPtr->value.linkPtr;
 	}
 	TRACE(("%u \"%.30s\" => ", opnd, part2));
 	if (!TclIsVarUndefined(arrayPtr)
 		&& TclIsVarArray(arrayPtr)
-		&& TclIsVarUntraced(arrayPtr)) {
-	    Tcl_HashEntry *hPtr = Tcl_FindHashEntry(arrayPtr->value.tablePtr,
-		    part2);
+		&& !TclIsVarTraced(arrayPtr)) {
+	    Tcl_HashEntry *hPtr = Tcl_FindHashEntry(
+		(Tcl_HashTable *) arrayPtr->value.tablePtr,part2);
 	    if (hPtr) {
 		varPtr = (Var *) Tcl_GetHashValue(hPtr);
 	    } else {
@@ -2381,7 +2393,7 @@
 	    }
 	}
 	if (TclIsVarDirectReadable(varPtr)
-		&& ((arrayPtr == NULL) || TclIsVarUntraced(arrayPtr))) {
+		&& ((arrayPtr == NULL) || !TclIsVarTraced(arrayPtr))) {
 	    /*
 	     * No errors, no traces: just get the value.
 	     */
@@ -2429,7 +2441,7 @@
 
     {
 	int opnd, pcAdjustment, storeFlags;
-	char *part1, *part2;
+	const char *part1, *part2;
 	Var *varPtr, *arrayPtr;
 	Tcl_Obj *objPtr, *valuePtr;
 
@@ -2535,7 +2547,7 @@
 	valuePtr = OBJ_AT_TOS;
 	part2 = TclGetString(OBJ_UNDER_TOS);
 	arrayPtr = &(compiledLocals[opnd]);
-	part1 = arrayPtr->name;
+	part1 = varNames[opnd];
 	cleanup = 2;
 	TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, part2, O2S(valuePtr)));
 	while (TclIsVarLink(arrayPtr)) {
@@ -2543,11 +2555,11 @@
 	}
 	if (!TclIsVarUndefined(arrayPtr)
 		&& TclIsVarArray(arrayPtr)
-		&& TclIsVarUntraced(arrayPtr)) {
-	    Tcl_HashEntry *hPtr = Tcl_FindHashEntry(arrayPtr->value.tablePtr,
-		    part2);
+		&& !TclIsVarTraced(arrayPtr)) {
+	    Tcl_HashEntry *hPtr = Tcl_FindHashEntry(
+		(Tcl_HashTable *) arrayPtr->value.tablePtr, part2);
 	    if (hPtr) {
-		varPtr = (Var *) Tcl_GetHashValue(hPtr);
+		varPtr = Tcl_GetHashValue(hPtr);
 		goto doCallPtrSetVar;
 	    }
 	}
@@ -2601,19 +2613,19 @@
     doStoreScalar:
 	valuePtr = OBJ_AT_TOS;
 	varPtr = &(compiledLocals[opnd]);
-	part1 = varPtr->name;
 	TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
 	while (TclIsVarLink(varPtr)) {
 	    varPtr = varPtr->value.linkPtr;
 	}
 	cleanup = 1;
 	arrayPtr = NULL;
+	part1 = varNames[opnd];
 	part2 = NULL;
 
     doCallPtrSetVar:
 	if ((storeFlags == TCL_LEAVE_ERR_MSG)
 		&& TclIsVarDirectWritable(varPtr)
-		&& ((arrayPtr == NULL) || TclIsVarUntraced(arrayPtr))) {
+		&& ((arrayPtr == NULL) || !TclIsVarTraced(arrayPtr))) {
 	    /*
 	     * No traces, no errors, plain 'set': we can safely inline. The
 	     * value *will* be set to what's requested, so that the stack top
@@ -2685,7 +2697,7 @@
 	Tcl_WideInt w;
 #endif
 	long i;
-	char *part1, *part2;
+	const char *part1, *part2;
 	Var *varPtr, *arrayPtr;
 
     case INST_INCR_SCALAR1:
@@ -2753,7 +2765,7 @@
     doIncrArray:
 	part2 = TclGetString(OBJ_AT_TOS);
 	arrayPtr = &(compiledLocals[opnd]);
-	part1 = arrayPtr->name;
+	part1 = varNames[opnd];
 	cleanup = 1;
 	while (TclIsVarLink(arrayPtr)) {
 	    arrayPtr = arrayPtr->value.linkPtr;
@@ -2780,7 +2792,7 @@
 	    varPtr = varPtr->value.linkPtr;
 	}
 
-	if (TclIsVarDirectReadable(varPtr)) {
+	if (TclIsVarDirectReadable(varPtr) && TclIsVarDirectWritable(varPtr)) {
 	    ClientData ptr;
 	    int type;
 
@@ -2898,7 +2910,7 @@
 
     doIncrScalar:
 	varPtr = &(compiledLocals[opnd]);
-	part1 = varPtr->name;
+	part1 = varNames[opnd];
 	while (TclIsVarLink(varPtr)) {
 	    varPtr = varPtr->value.linkPtr;
 	}
@@ -2908,8 +2920,8 @@
 	TRACE(("%u %ld => ", opnd, i));
 
     doIncrVar:
-	if (TclIsVarDirectReadable(varPtr)
-		&& ((arrayPtr == NULL) || TclIsVarUntraced(arrayPtr))) {
+	if (TclIsVarDirectReadable(varPtr) && TclIsVarDirectWritable(varPtr)
+		&& ((arrayPtr == NULL) || !TclIsVarTraced(arrayPtr))) {
 	    objPtr = varPtr->value.objPtr;
 	    if (Tcl_IsShared(objPtr)) {
 		objPtr->refCount--;	/* We know it's shared */
@@ -2998,7 +3010,7 @@
 
 	    if (!TclIsVarNamespaceVar(otherPtr)) {
 		TclSetVarNamespaceVar(otherPtr);
-		otherPtr->refCount++;
+		VarHashRefCount(otherPtr)++;
 	    }
 	    result = TCL_OK;
 	    goto doLinkVars;
@@ -3051,7 +3063,7 @@
 
 	opnd = TclGetInt4AtPtr(pc+1);;
 	varPtr = &(compiledLocals[opnd]);
-	if ((varPtr != otherPtr) && (varPtr->tracePtr == NULL)
+	if ((varPtr != otherPtr) && !TclIsVarTraced(varPtr)
 		&& (TclIsVarUndefined(varPtr) || TclIsVarLink(varPtr))) {
 	    if (!TclIsVarUndefined(varPtr)) {
 		/* Then it is a defined link */
@@ -3059,15 +3071,19 @@
 		if (linkPtr == otherPtr) {
 		    goto doLinkVarsDone;
 		}
-		linkPtr->refCount--;
-		if (TclIsVarUndefined(linkPtr)) {
-		    TclCleanupVar(linkPtr, NULL);
+		if (TclIsVarInHash(linkPtr)) {
+		    VarHashRefCount(linkPtr)--;
+		    if (TclIsVarUndefined(linkPtr)) {
+			TclCleanupVar(linkPtr, NULL);
+		    }
 		}
 	    }
 	    TclSetVarLink(varPtr);
 	    TclClearVarUndefined(varPtr);
 	    varPtr->value.linkPtr = otherPtr;
-	    otherPtr->refCount++;
+	    if (TclIsVarInHash(otherPtr)) {
+		VarHashRefCount(otherPtr)++;
+	    }
 	} else {
 	    result = TclPtrMakeUpvar(interp, otherPtr, NULL, 0, opnd);
 	    if (result != TCL_OK) {
@@ -5712,7 +5728,7 @@
 	int iterNum, listTmpIndex, listLen, numVars;
 	int varIndex, valIndex, continueLoop, j;
 	long i;
-	char *part1;
+	const char *part1;
 
 	opnd = TclGetUInt4AtPtr(pc+1);
 	infoPtr = (ForeachInfo *) codePtr->auxDataArrayPtr[opnd].clientData;
@@ -5782,7 +5798,6 @@
 
 		    varIndex = varListPtr->varIndexes[j];
 		    varPtr = &(compiledLocals[varIndex]);
-		    part1 = varPtr->name;
 		    while (TclIsVarLink(varPtr)) {
 			varPtr = varPtr->value.linkPtr;
 		    }
@@ -5799,6 +5814,7 @@
 			    Tcl_IncrRefCount(valuePtr);
 			}
 		    } else {
+			part1 = varNames[varIndex];
 			DECACHE_STACK_INFO();
 			value2Ptr = TclPtrSetVar(interp, varPtr, NULL, part1,
 				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
@@ -5887,7 +5903,7 @@
 	int opnd, opnd2, allocateDict;
 	Tcl_Obj *dictPtr, *valPtr;
 	Var *varPtr;
-	char *part1;
+	const char *part1;
 
     case INST_DICT_GET:
 	opnd = TclGetUInt4AtPtr(pc+1);
@@ -5932,7 +5948,6 @@
 	opnd2 = TclGetUInt4AtPtr(pc+5);
 
 	varPtr = &(compiledLocals[opnd2]);
-	part1 = varPtr->name;
 	while (TclIsVarLink(varPtr)) {
 	    varPtr = varPtr->value.linkPtr;
 	}
@@ -5940,6 +5955,7 @@
 	if (TclIsVarDirectReadable(varPtr)) {
 	    dictPtr = varPtr->value.objPtr;
 	} else {
+	    part1 = varNames[opnd2];
 	    DECACHE_STACK_INFO();
 	    dictPtr = TclPtrGetVar(interp, varPtr, NULL, part1, NULL, 0);
 	    CACHE_STACK_INFO();
@@ -6019,6 +6035,7 @@
 	    objResultPtr = dictPtr;
 	} else {
 	    Tcl_IncrRefCount(dictPtr);
+	    part1 = varNames[opnd2];	    
 	    DECACHE_STACK_INFO();
 	    objResultPtr = TclPtrSetVar(interp, varPtr, NULL, part1, NULL,
 		    dictPtr, TCL_LEAVE_ERR_MSG);
@@ -6045,7 +6062,6 @@
 	cleanup = 2;
 
 	varPtr = &(compiledLocals[opnd]);
-	part1 = varPtr->name;
 	while (TclIsVarLink(varPtr)) {
 	    varPtr = varPtr->value.linkPtr;
 	}
@@ -6053,6 +6069,7 @@
 	if (TclIsVarDirectReadable(varPtr)) {
 	    dictPtr = varPtr->value.objPtr;
 	} else {
+	    part1 = varNames[opnd];
 	    DECACHE_STACK_INFO();
 	    dictPtr = TclPtrGetVar(interp, varPtr, NULL, part1, NULL, 0);
 	    CACHE_STACK_INFO();
@@ -6141,6 +6158,7 @@
 	    objResultPtr = dictPtr;
 	} else {
 	    Tcl_IncrRefCount(dictPtr);
+	    part1 = varNames[opnd];
 	    DECACHE_STACK_INFO();
 	    objResultPtr = TclPtrSetVar(interp, varPtr, NULL, part1, NULL,
 		    dictPtr, TCL_LEAVE_ERR_MSG);
@@ -6184,7 +6202,7 @@
 	statePtr->typePtr = &dictIteratorType;
 	statePtr->internalRep.twoPtrValue.ptr1 = (void *) searchPtr;
 	statePtr->internalRep.twoPtrValue.ptr2 = (void *) dictPtr;
-	varPtr = compiledLocals + opnd;
+	varPtr = (compiledLocals + opnd);
 	if (varPtr->value.objPtr == NULL) {
 	    TclSetVarScalar(compiledLocals + opnd);
 	    TclClearVarUndefined(compiledLocals + opnd);
@@ -6261,14 +6279,13 @@
 	Tcl_Obj **keyPtrPtr, *dictPtr;
 	DictUpdateInfo *duiPtr;
 	Var *varPtr;
-	char *part1;
+	const char *part1;
 
     case INST_DICT_UPDATE_START:
 	opnd = TclGetUInt4AtPtr(pc+1);
 	opnd2 = TclGetUInt4AtPtr(pc+5);
 	varPtr = &(compiledLocals[opnd]);
 	duiPtr = codePtr->auxDataArrayPtr[opnd2].clientData;
-	part1 = varPtr->name;
 	while (TclIsVarLink(varPtr)) {
 	    varPtr = varPtr->value.linkPtr;
 	}
@@ -6276,6 +6293,7 @@
 	if (TclIsVarDirectReadable(varPtr)) {
 	    dictPtr = varPtr->value.objPtr;
 	} else {
+	    part1 = varNames[opnd];
 	    DECACHE_STACK_INFO();
 	    dictPtr = TclPtrGetVar(interp, varPtr, NULL, part1, NULL,
 		    TCL_LEAVE_ERR_MSG);
@@ -6299,7 +6317,7 @@
 		goto dictUpdateStartFailed;
 	    }
 	    varPtr = &(compiledLocals[duiPtr->varIndices[i]]);
-	    part1 = varPtr->name;
+	    part1 = varNames[duiPtr->varIndices[i]];
 	    while (TclIsVarLink(varPtr)) {
 		varPtr = varPtr->value.linkPtr;
 	    }
@@ -6323,7 +6341,6 @@
 	opnd2 = TclGetUInt4AtPtr(pc+5);
 	varPtr = &(compiledLocals[opnd]);
 	duiPtr = codePtr->auxDataArrayPtr[opnd2].clientData;
-	part1 = varPtr->name;
 	while (TclIsVarLink(varPtr)) {
 	    varPtr = varPtr->value.linkPtr;
 	}
@@ -6331,6 +6348,7 @@
 	if (TclIsVarDirectReadable(varPtr)) {
 	    dictPtr = varPtr->value.objPtr;
 	} else {
+	    part1 = varNames[opnd];
 	    DECACHE_STACK_INFO();
 	    dictPtr = TclPtrGetVar(interp, varPtr, NULL, part1, NULL, 0);
 	    CACHE_STACK_INFO();
@@ -6355,13 +6373,13 @@
 	    char *part1a;
 
 	    var2Ptr = &(compiledLocals[duiPtr->varIndices[i]]);
-	    part1a = var2Ptr->name;
 	    while (TclIsVarLink(var2Ptr)) {
 		var2Ptr = var2Ptr->value.linkPtr;
 	    }
 	    if (TclIsVarDirectReadable(var2Ptr)) {
 		valPtr = var2Ptr->value.objPtr;
 	    } else {
+		part1a = varNames[duiPtr->varIndices[i]];
 		DECACHE_STACK_INFO();
 		valPtr = TclPtrGetVar(interp, var2Ptr, NULL, part1a, NULL, 0);
 		CACHE_STACK_INFO();
@@ -6377,6 +6395,7 @@
 	    Tcl_DecrRefCount(varPtr->value.objPtr);
 	    varPtr->value.objPtr = dictPtr;
 	} else {
+	    part1 = varNames[opnd];
 	    DECACHE_STACK_INFO();
 	    objResultPtr = TclPtrSetVar(interp, varPtr, NULL, part1, NULL,
 		    dictPtr, TCL_LEAVE_ERR_MSG);
Index: generic/tclHash.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclHash.c,v
retrieving revision 1.31
diff -u -r1.31 tclHash.c
--- generic/tclHash.c	2 Jul 2007 21:10:52 -0000	1.31
+++ generic/tclHash.c	10 Jul 2007 11:53:26 -0000
@@ -343,6 +343,7 @@
     } else {
 	hPtr = (Tcl_HashEntry *) ckalloc((unsigned) sizeof(Tcl_HashEntry));
 	hPtr->key.oneWordValue = (char *) key;
+	hPtr->clientData = 0;
     }
 
     hPtr->tablePtr = tablePtr;
@@ -355,7 +356,6 @@
     hPtr->nextPtr = *hPtr->bucketPtr;
     *hPtr->bucketPtr = hPtr;
 #endif
-    hPtr->clientData = 0;
     tablePtr->numEntries++;
 
     /*
Index: generic/tclInt.decls
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.decls,v
retrieving revision 1.110
diff -u -r1.110 tclInt.decls
--- generic/tclInt.decls	20 Jun 2007 18:46:13 -0000	1.110
+++ generic/tclInt.decls	10 Jul 2007 11:53:26 -0000
@@ -73,7 +73,7 @@
     void TclDeleteCompiledLocalVars(Interp *iPtr, CallFrame *framePtr)
 }
 declare 12 generic {
-    void TclDeleteVars(Interp *iPtr, Tcl_HashTable *tablePtr)
+    void TclDeleteVars(Interp *iPtr, TclVarHashTable *tablePtr)
 }
 # Removed in 8.5
 #declare 13 generic {
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.323
diff -u -r1.323 tclInt.h
--- generic/tclInt.h	2 Jul 2007 17:32:09 -0000	1.323
+++ generic/tclInt.h	10 Jul 2007 11:53:28 -0000
@@ -191,6 +191,19 @@
 typedef struct NamespacePathEntry NamespacePathEntry;
 
 /*
+ * Special hashtable for variables: this is just a Tcl_HashTable with an nsPtr
+ * field added at the end: in this way variables can find their namespace
+ * without having to copy a pointer in their struct: they can access it via
+ * their hPtr->tablePtr. 
+ */
+
+typedef struct TclVarHashTable {
+    Tcl_HashTable table;
+    struct Namespace *nsPtr;
+} TclVarHashTable;
+
+
+/*
  * The structure below defines a namespace.
  * Note: the first five fields must match exactly the fields in a
  * Tcl_Namespace structure (see tcl.h). If you change one, be sure to change
@@ -234,7 +247,7 @@
 				 * ImportedCmdRef structure) to the Command
 				 * structure in the source namespace's command
 				 * table. */
-    Tcl_HashTable varTable;	/* Contains all the (global) variables
+    TclVarHashTable varTable;	/* Contains all the (global) variables
 				 * currently in this namespace. Indexed by
 				 * strings; values have type (Var *). */
     char **exportArrayPtr;	/* Points to an array of string patterns
@@ -497,10 +510,12 @@
  */
 
 typedef struct Var {
+    int flags;			/* Miscellaneous bits of information about
+				 * variable. See below for definitions. */
     union {
 	Tcl_Obj *objPtr;	/* The variable's object value. Used for
 				 * scalar variables and array elements. */
-	Tcl_HashTable *tablePtr;/* For array variables, this points to
+	TclVarHashTable *tablePtr;/* For array variables, this points to
 				 * information about the hash table used to
 				 * implement the associative array. Points to
 				 * ckalloc-ed data. */
@@ -509,48 +524,30 @@
 				 * "upvar", this field points to the
 				 * referenced variable's Var struct. */
     } value;
-    char *name;			/* NULL if the variable is in a hashtable,
-				 * otherwise points to the variable's name. It
-				 * is used, e.g., by TclLookupVar and "info
-				 * locals". The storage for the characters of
-				 * the name is not owned by the Var and must
-				 * not be freed when freeing the Var. */
-    Namespace *nsPtr;		/* Points to the namespace that contains this
-				 * variable or NULL if the variable is a local
-				 * variable in a Tcl procedure. */
-    Tcl_HashEntry *hPtr;	/* If variable is in a hashtable, either the
-				 * hash table entry that refers to this
-				 * variable or NULL if the variable has been
-				 * detached from its hash table (e.g. an array
-				 * is deleted, but some of its elements are
-				 * still referred to in upvars). NULL if the
-				 * variable is not in a hashtable. This is
-				 * used to delete an variable from its
-				 * hashtable if it is no longer needed. */
-    int refCount;		/* Counts number of active uses of this
-				 * variable, not including its entry in the
-				 * call frame or the hash table: 1 for each
-				 * additional variable whose linkPtr points
-				 * here, 1 for each nested trace active on
-				 * variable, and 1 if the variable is a
-				 * namespace variable. This record can't be
-				 * deleted until refCount becomes 0. */
-    VarTrace *tracePtr;		/* First in list of all traces set for this
-				 * variable. */
-    ArraySearch *searchPtr;	/* First in list of all searches active for
-				 * this variable, or NULL if none. */
-    int flags;			/* Miscellaneous bits of information about
-				 * variable. See below for definitions. */
 } 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.
+typedef struct VarInHash {
+    Var var;                    
+    int refCount;		/* Counts number of active uses of this
+				 * variable: 1 for the entry in the hash
+				 * table, 1 for each additional variable whose
+				 * linkPtr points here, 1 for each nested
+				 * trace active on variable, and 1 if the
+				 * variable is a namespace variable. This
+				 * record can't be deleted until refCount
+				 * becomes 0. */ 
+    Tcl_HashEntry entry;	/* The hash table entry that refers to this
+				 * variable. This is used to find the name of
+				 * the variable and to delete it from its 
+				 * hashtable if it is no longer needed. It
+				 * also holds the variable's name. */
+} VarInHash;
+
+/*
+ * Flag bits for variables. The first two (VAR_ARRAY and VAR_LINK) are
+ * mutually exclusive and give the "type" of the variable. If none is set,
+ * this is a scalar variable.
+ *
  * VAR_ARRAY -			1 means this is an array variable rather than
  *				a scalar variable or link. The "tablePtr"
  *				field points to the array's hashtable for its
@@ -562,21 +559,17 @@
  *				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.
+ *
+ * Flags that indicate the type and status of storage; none is set for
+ * compiled local variables (Var structs).
+ *
  * 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 in a
  *				procedure frame by the compiler so the Var
  *				storage is part of the call frame.
- * VAR_TRACE_ACTIVE -		1 means that trace processing is currently
- *				underway for a read or write access, so new
- *				read or write accesses should not cause trace
- *				procedures to be called and the variable can't
- *				be deleted.
+ * VAR_DEAD_HASH                1 means that this var's entry in the hashtable
+ *                              has already been deleted.
  * VAR_ARRAY_ELEMENT -		1 means that this variable is an array
  *				element, so it is not legal for it to be an
  *				array itself (the VAR_ARRAY flag had better
@@ -590,6 +583,19 @@
  *				incremented to reflect the "reference" from
  *				its namespace.
  *
+ * Flag values relating to the variable's trace and search status.
+ *
+ * VAR_TRACED_READ
+ * VAR_TRACED_WRITE
+ * VAR_TRACED_UNSET
+ * VAR_TRACED_ARRAY
+ * VAR_TRACE_ACTIVE -		1 means that trace processing is currently
+ *				underway for a read or write access, so new
+ *				read or write accesses should not cause trace
+ *				procedures to be called and the variable can't
+ *				be deleted.
+ * VAR_SEARCH_ACTIVE
+ *
  * The following additional flags are used with the CompiledLocal type defined
  * below:
  *
@@ -600,21 +606,49 @@
  *				name.
  * VAR_RESOLVED -		1 if name resolution has been done for this
  *				variable.
+ * VAR_IS_ARGS                  1 if this variable is the last argument and is
+ *                              named "args".
+ */
+
+/* FLAGS RENUMBERED: everything breaks already, make things simpler.
+ * 
+ * IMPORTANT: skip the values 0x10, 0x20, 0x40, 0x800 corresponding to
+ * TCL_TRACE_(READS/WRITES/UNSETS/ARRAY): makes code simpler in tclTrace.c  
+ *
+ * Keep the flag values for VAR_ARGUMENT and VAR_TEMPORARY so that old values
+ * in precompiled scripts keep working. 
  */
 
-#define VAR_SCALAR		0x1
-#define VAR_ARRAY		0x2
-#define VAR_LINK		0x4
-#define VAR_UNDEFINED		0x8
-#define VAR_IN_HASHTABLE	0x10
-#define VAR_TRACE_ACTIVE	0x20
-#define VAR_ARRAY_ELEMENT	0x40
-#define VAR_NAMESPACE_VAR	0x80
-
-#define VAR_ARGUMENT		0x100
-#define VAR_TEMPORARY		0x200
-#define VAR_RESOLVED		0x400
-#define VAR_IS_ARGS		0x800
+
+/* Type of value (0 is scalar) */
+#define VAR_ARRAY		0x1
+#define VAR_LINK		0x2
+
+/* Type of storage (0 is compiled local) */
+#define VAR_IN_HASHTABLE	0x4
+#define VAR_DEAD_HASH           0x8
+#define VAR_ARRAY_ELEMENT	0x1000
+#define VAR_NAMESPACE_VAR	0x2000
+
+#define VAR_ALL_HASH (VAR_IN_HASHTABLE|VAR_DEAD_HASH|VAR_NAMESPACE_VAR|VAR_ARRAY_ELEMENT)
+
+/* Trace and search state */
+
+#define VAR_TRACED_READ        0x10       /* TCL_TRACE_READS  */
+#define VAR_TRACED_WRITE       0x20       /* TCL_TRACE_WRITES */
+#define VAR_TRACED_UNSET       0x40       /* TCL_TRACE_UNSETS */
+#define VAR_TRACED_ARRAY       0x800      /* TCL_TRACE_ARRAY  */
+#define VAR_TRACE_ACTIVE       0x80
+#define VAR_SEARCH_ACTIVE      0x4000
+#define VAR_ALL_TRACES \
+   (VAR_TRACED_READ|VAR_TRACED_WRITE|VAR_TRACED_ARRAY|VAR_TRACED_UNSET)
+
+
+/* Special handling on initialisation (only CompiledLocal) */
+#define VAR_ARGUMENT		0x100     /* KEEP OLD VALUE! See tclProc.c */
+#define VAR_TEMPORARY		0x200     /* KEEP OLD VALUE! See tclProc.c */
+#define VAR_IS_ARGS		0x400     
+#define VAR_RESOLVED		0x8000
 
 /*
  * Macros to ensure that various flag bits are set properly for variables.
@@ -629,22 +663,22 @@
  */
 
 #define TclSetVarScalar(varPtr) \
-    (varPtr)->flags = ((varPtr)->flags & ~(VAR_ARRAY|VAR_LINK)) | VAR_SCALAR
+    (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
@@ -673,7 +707,7 @@
  */
 
 #define TclIsVarScalar(varPtr) \
-    ((varPtr)->flags & VAR_SCALAR)
+    !((varPtr)->flags & (VAR_ARRAY|VAR_LINK))
 
 #define TclIsVarLink(varPtr) \
     ((varPtr)->flags & VAR_LINK)
@@ -682,7 +716,7 @@
     ((varPtr)->flags & VAR_ARRAY)
 
 #define TclIsVarUndefined(varPtr) \
-    ((varPtr)->flags & VAR_UNDEFINED)
+    ((varPtr)->value.objPtr == NULL)
 
 #define TclIsVarArrayElement(varPtr) \
     ((varPtr)->flags & VAR_ARRAY_ELEMENT)
@@ -702,24 +736,34 @@
 #define TclIsVarTraceActive(varPtr) \
     ((varPtr)->flags & VAR_TRACE_ACTIVE)
 
-#define TclIsVarUntraced(varPtr) \
-    ((varPtr)->tracePtr == NULL)
+#define TclIsVarTraced(varPtr) \
+   ((varPtr)->flags & VAR_ALL_TRACES)
+
+#define TclIsVarInHash(varPtr) \
+    ((varPtr)->flags & VAR_IN_HASHTABLE)
+
+#define TclIsVarDeadHash(varPtr) \
+    (((varPtr)->flags & VAR_IN_HASHTABLE) && ((varPtr)->flags & VAR_DEAD_HASH))
+
+#define TclGetVarNsPtr(varPtr) \
+    (TclIsVarInHash(varPtr) \
+         ? ((TclVarHashTable *) ((((VarInHash *) (varPtr))->entry.tablePtr)))->nsPtr \
+	 : NULL)
+
+#define VarHashRefCount(varPtr) \
+    ((VarInHash *) (varPtr))->refCount
 
 /*
  * Macros for direct variable access by TEBC
  */
 
 #define TclIsVarDirectReadable(varPtr) \
-	(TclIsVarScalar(varPtr) \
-    && !TclIsVarUndefined(varPtr) \
-    && TclIsVarUntraced(varPtr))
+    (   !((varPtr)->flags & (VAR_ARRAY|VAR_LINK|VAR_TRACED_READ)) \
+    &&  (varPtr)->value.objPtr)
 
 #define TclIsVarDirectWritable(varPtr) \
-    (   !(((varPtr)->flags & VAR_IN_HASHTABLE) \
-		&& ((varPtr)->hPtr == NULL)) \
-     && TclIsVarUntraced(varPtr) \
-     && (TclIsVarScalar(varPtr) \
-	     || TclIsVarUndefined(varPtr)))
+    !((varPtr)->flags & (VAR_ARRAY|VAR_LINK|VAR_TRACED_WRITE|VAR_DEAD_HASH))
+
 
 /*
  *----------------------------------------------------------------
@@ -900,6 +944,19 @@
  * Tcl_CallFrame structure in tcl.h. If you change one, change the other.
  */
 
+/*
+ * Will be grown to contain: pointers to the varnames (allocated at the end),
+ * plus the init values for each variable (suitable to be memcopied on init)
+ */
+
+typedef struct LocalCache {
+    int refCount;
+    char *varName0;
+} LocalCache;
+
+#define localVarNames(framePtr) \
+    (&(framePtr)->localCachePtr->varName0)
+
 typedef struct CallFrame {
     Namespace *nsPtr;		/* Points to the namespace used to resolve
 				 * commands and global variables. */
@@ -933,7 +990,8 @@
 				 * the number of compiled local variables
 				 * (local variables assigned entries ["slots"]
 				 * in the compiledLocals array below). */
-    Tcl_HashTable *varTablePtr;	/* Hash table containing local variables not
+    TclVarHashTable *varTablePtr;
+                                /* Hash table containing local variables not
 				 * recognized by the compiler, or created at
 				 * execution time through, e.g., upvar.
 				 * Initially NULL and created if needed. */
@@ -952,6 +1010,7 @@
 				 * have some means of discovering what the
 				 * meaning of the value is, which we do not
 				 * specify. */
+    LocalCache *localCachePtr;
 } CallFrame;
 
 #define FRAME_IS_PROC   0x1
@@ -1736,6 +1795,14 @@
     int packagePrefer;          /* Current package selection mode. */
 
     /*
+     * Hashtables for variable traces and searches
+     */
+
+    Tcl_HashTable varTraces;   /* Hashtable holding the start of a variable's
+				 * active trace list; varPtr is the key. */
+    Tcl_HashTable varSearches; /* Hashtable holding the start of a variable's
+				 * active searches list; varPtr is the key */
+    /*
      * Statistical information about the bytecode compiler and interpreter's
      * operation.
      */
@@ -2307,6 +2374,8 @@
 MODULE_SCOPE void	TclInitNamespaceSubsystem(void);
 MODULE_SCOPE void	TclInitNotifier(void);
 MODULE_SCOPE void	TclInitObjSubsystem(void);
+MODULE_SCOPE void       TclInitVarHashTable(TclVarHashTable *tablePtr,
+                        Namespace *nsPtr);
 MODULE_SCOPE void	TclInitSubsystems(void);
 MODULE_SCOPE int	TclInterpReady(Tcl_Interp *interp);
 MODULE_SCOPE int	TclIsLocalScalar(CONST char *src, int len);
Index: generic/tclIntDecls.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclIntDecls.h,v
retrieving revision 1.101
diff -u -r1.101 tclIntDecls.h
--- generic/tclIntDecls.h	20 Jun 2007 18:46:13 -0000	1.101
+++ generic/tclIntDecls.h	10 Jul 2007 11:53:30 -0000
@@ -123,7 +123,7 @@
 #define TclDeleteVars_TCL_DECLARED
 /* 12 */
 EXTERN void		TclDeleteVars (Interp * iPtr, 
-				Tcl_HashTable * tablePtr);
+				TclVarHashTable * tablePtr);
 #endif
 /* Slot 13 is reserved */
 #ifndef TclDumpMemoryInfo_TCL_DECLARED
@@ -1066,7 +1066,7 @@
 #endif /* __WIN32__ */
     int (*tclCreateProc) (Tcl_Interp * interp, Namespace * nsPtr, CONST char * procName, Tcl_Obj * argsPtr, Tcl_Obj * bodyPtr, Proc ** procPtrPtr); /* 10 */
     void (*tclDeleteCompiledLocalVars) (Interp * iPtr, CallFrame * framePtr); /* 11 */
-    void (*tclDeleteVars) (Interp * iPtr, Tcl_HashTable * tablePtr); /* 12 */
+    void (*tclDeleteVars) (Interp * iPtr, TclVarHashTable * tablePtr); /* 12 */
     void *reserved13;
     void (*tclDumpMemoryInfo) (FILE * outFile); /* 14 */
     void *reserved15;
Index: generic/tclNamesp.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclNamesp.c,v
retrieving revision 1.146
diff -u -r1.146 tclNamesp.c
--- generic/tclNamesp.c	5 Jul 2007 12:03:27 -0000	1.146
+++ generic/tclNamesp.c	10 Jul 2007 11:53:33 -0000
@@ -404,7 +404,8 @@
     framePtr->numCompiledLocals = 0;
     framePtr->compiledLocals = NULL;
     framePtr->clientData = NULL;
-
+    framePtr->localCachePtr = NULL;
+    
     /*
      * Push the new call frame onto the interpreter's stack of procedure call
      * frames making it the current frame.
@@ -725,7 +726,7 @@
     Tcl_DString *namePtr, *buffPtr;
     int newEntry, nameLen;
     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
+    
     /*
      * If there is no active namespace, the interpreter is being initialized.
      */
@@ -793,7 +794,7 @@
     nsPtr->activationCount = 0;
     nsPtr->refCount = 0;
     Tcl_InitHashTable(&nsPtr->cmdTable, TCL_STRING_KEYS);
-    Tcl_InitHashTable(&nsPtr->varTable, TCL_STRING_KEYS);
+    TclInitVarHashTable(&nsPtr->varTable, nsPtr);
     nsPtr->exportArrayPtr = NULL;
     nsPtr->numExportPatterns = 0;
     nsPtr->maxExportPatterns = 0;
@@ -1056,7 +1057,7 @@
      */
 
     TclDeleteNamespaceVars(nsPtr);
-    Tcl_InitHashTable(&nsPtr->varTable, TCL_STRING_KEYS);
+    TclInitVarHashTable(&nsPtr->varTable, nsPtr);
 
     /*
      * Delete all commands in this namespace. Be careful when traversing the
@@ -2490,129 +2491,6 @@
 /*
  *----------------------------------------------------------------------
  *
- * Tcl_FindNamespaceVar --
- *
- *	Searches for a namespace variable, a variable not local to a
- *	procedure. The variable can be either a scalar or an array, but may
- *	not be an element of an array.
- *
- * Results:
- *	Returns a token for the variable if it is found. Otherwise, if it
- *	can't be found or there is an error, returns NULL and leaves an error
- *	message in the interpreter's result object if "flags" contains
- *	TCL_LEAVE_ERR_MSG.
- *
- * Side effects:
- *	None.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Var
-Tcl_FindNamespaceVar(
-    Tcl_Interp *interp,		/* The interpreter in which to find the
-				 * variable. */
-    const char *name,		/* Variable's name. If it starts with "::",
-				 * will be looked up in global namespace.
-				 * Else, looked up first in contextNsPtr
-				 * (current namespace if contextNsPtr is
-				 * NULL), then in global namespace. */
-    Tcl_Namespace *contextNsPtr,/* Ignored if TCL_GLOBAL_ONLY flag set.
-				 * Otherwise, points to namespace in which to
-				 * resolve name. If NULL, look up name in the
-				 * current namespace. */
-    int flags)			/* An OR'd combination of flags:
-				 * TCL_GLOBAL_ONLY (look up name only in
-				 * global namespace), TCL_NAMESPACE_ONLY (look
-				 * up only in contextNsPtr, or the current
-				 * namespace if contextNsPtr is NULL), and
-				 * TCL_LEAVE_ERR_MSG. If both TCL_GLOBAL_ONLY
-				 * and TCL_NAMESPACE_ONLY are given,
-				 * TCL_GLOBAL_ONLY is ignored. */
-{
-    Interp *iPtr = (Interp *) interp;
-    ResolverScheme *resPtr;
-    Namespace *nsPtr[2], *cxtNsPtr;
-    const char *simpleName;
-    Tcl_HashEntry *entryPtr;
-    Var *varPtr;
-    register int search;
-    int result;
-    Tcl_Var var;
-
-    /*
-     * If this namespace has a variable resolver, then give it first crack at
-     * the variable resolution. It may return a Tcl_Var value, it may signal
-     * to continue onward, or it may signal an error.
-     */
-
-    if ((flags & TCL_GLOBAL_ONLY) != 0) {
-	cxtNsPtr = (Namespace *) TclGetGlobalNamespace(interp);
-    } else if (contextNsPtr != NULL) {
-	cxtNsPtr = (Namespace *) contextNsPtr;
-    } else {
-	cxtNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
-    }
-
-    if (cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) {
-	resPtr = iPtr->resolverPtr;
-
-	if (cxtNsPtr->varResProc) {
-	    result = (*cxtNsPtr->varResProc)(interp, name,
-		    (Tcl_Namespace *) cxtNsPtr, flags, &var);
-	} else {
-	    result = TCL_CONTINUE;
-	}
-
-	while (result == TCL_CONTINUE && resPtr) {
-	    if (resPtr->varResProc) {
-		result = (*resPtr->varResProc)(interp, name,
-			(Tcl_Namespace *) cxtNsPtr, flags, &var);
-	    }
-	    resPtr = resPtr->nextPtr;
-	}
-
-	if (result == TCL_OK) {
-	    return var;
-	} else if (result != TCL_CONTINUE) {
-	    return (Tcl_Var) NULL;
-	}
-    }
-
-    /*
-     * Find the namespace(s) that contain the variable.
-     */
-
-    TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr,
-	    flags, &nsPtr[0], &nsPtr[1], &cxtNsPtr, &simpleName);
-
-    /*
-     * Look for the variable in the variable table of its namespace. Be sure
-     * to check both possible search paths: from the specified namespace
-     * context and from the global namespace.
-     */
-
-    varPtr = NULL;
-    for (search = 0;  (search < 2) && (varPtr == NULL);  search++) {
-	if ((nsPtr[search] != NULL) && (simpleName != NULL)) {
-	    entryPtr = Tcl_FindHashEntry(&nsPtr[search]->varTable, simpleName);
-	    if (entryPtr != NULL) {
-		varPtr = (Var *) Tcl_GetHashValue(entryPtr);
-	    }
-	}
-    }
-    if (varPtr != NULL) {
-	return (Tcl_Var) varPtr;
-    } else if (flags & TCL_LEAVE_ERR_MSG) {
-	Tcl_ResetResult(interp);
-	Tcl_AppendResult(interp, "unknown variable \"", name, "\"", NULL);
-    }
-    return (Tcl_Var) NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
  * TclResetShadowedCmdRefs --
  *
  *	Called when a command is added to a namespace to check for existing
@@ -6996,25 +6874,30 @@
 
     varPtr = TclObjLookupVar(interp, iPtr->eiVar, NULL, TCL_GLOBAL_ONLY,
 	    NULL, 0, 0, &arrayPtr);
-    if ((varPtr == NULL) || (varPtr->tracePtr == NULL)) {
+    if ((varPtr == NULL) || !TclIsVarTraced(varPtr)) {
 	/*
 	 * Should not happen.
 	 */
 
 	return;
-    }
-    if (varPtr->tracePtr->traceProc != EstablishErrorInfoTraces) {
-	/*
-	 * The most recent trace set on ::errorInfo is not the one the core
-	 * itself puts on last. This means some other code is tracing the
-	 * variable, and the additional trace(s) might be write traces that
-	 * expect the timing of writes to ::errorInfo that existed Tcl
-	 * releases before 8.5. To satisfy that compatibility need, we write
-	 * the current -errorinfo value to the ::errorInfo variable.
-	 */
+    } else {
+	Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&iPtr->varTraces,
+		(char *) varPtr);
+	VarTrace *tracePtr = (VarTrace *) Tcl_GetHashValue(hPtr);
 
-	Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL,
-		iPtr->errorInfo, TCL_GLOBAL_ONLY);
+	if (tracePtr->traceProc != EstablishErrorInfoTraces) {
+	    /*
+	     * The most recent trace set on ::errorInfo is not the one the core
+	     * itself puts on last. This means some other code is tracing the
+	     * variable, and the additional trace(s) might be write traces that
+	     * expect the timing of writes to ::errorInfo that existed Tcl
+	     * releases before 8.5. To satisfy that compatibility need, we write
+	     * the current -errorinfo value to the ::errorInfo variable.
+	     */
+	    
+	    Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL,
+		    iPtr->errorInfo, TCL_GLOBAL_ONLY);
+	}
     }
 }
 
Index: generic/tclObj.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclObj.c,v
retrieving revision 1.130
diff -u -r1.130 tclObj.c
--- generic/tclObj.c	5 Jul 2007 12:03:27 -0000	1.130
+++ generic/tclObj.c	10 Jul 2007 11:53:34 -0000
@@ -3288,7 +3288,8 @@
     hPtr = (Tcl_HashEntry *) ckalloc((unsigned) (sizeof(Tcl_HashEntry)));
     hPtr->key.oneWordValue = (char *) objPtr;
     Tcl_IncrRefCount(objPtr);
-
+    hPtr->clientData = NULL;
+    
     return hPtr;
 }
 
Index: generic/tclProc.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclProc.c,v
retrieving revision 1.125
diff -u -r1.125 tclProc.c
--- generic/tclProc.c	20 Jun 2007 18:46:14 -0000	1.125
+++ generic/tclProc.c	10 Jul 2007 11:53:41 -0000
@@ -527,13 +527,17 @@
 	     * 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! Is this right? It does depend on VAR_ARGUMENT not
+	     * changing. Note that a change of VAR_TEMPORARY would not be so
+	     * important, as there are no variable names in precompiled
+	     * bytecodes anyway - right? 
 	     */
 
 	    if ((localPtr->nameLength != nameLength)
 		    || (strcmp(localPtr->name, fieldValues[0]))
 		    || (localPtr->frameIndex != i)
-		    || ((localPtr->flags & ~VAR_UNDEFINED)
-			    != (VAR_SCALAR | VAR_ARGUMENT))
+		    || !(localPtr->flags & VAR_ARGUMENT) /* /// CHECK HERE! */
 		    || (localPtr->defValuePtr == NULL && fieldCount == 2)
 		    || (localPtr->defValuePtr != NULL && fieldCount != 2)) {
 		Tcl_SetObjResult(interp, Tcl_ObjPrintf(
@@ -588,7 +592,7 @@
 	    localPtr->nextPtr = NULL;
 	    localPtr->nameLength = nameLength;
 	    localPtr->frameIndex = i;
-	    localPtr->flags = VAR_SCALAR | VAR_ARGUMENT;
+	    localPtr->flags = VAR_ARGUMENT;
 	    localPtr->resolveInfo = NULL;
 
 	    if (fieldCount == 2) {
@@ -1050,12 +1054,66 @@
     const char *final;
 
     /*
+     * Make sure that the local cache of variable names and initial values has
+     * been initialised properly .
+     */
+
+    localCt = procPtr->numCompiledLocals;
+    if (localCt == 0) {
+	framePtr->localCachePtr = NULL;
+    } else if (codePtr->localCachePtr) {
+	framePtr->localCachePtr = codePtr->localCachePtr;
+	framePtr->localCachePtr->refCount++;
+    } else {	
+	/*
+	 * Cache the names and initial values of local variables; store the
+	 * cache in both the framePtr for this execution and in the codePtr
+	 * for future calls.
+	 */
+
+	char *name, **namePtr;
+	LocalCache *localCachePtr;
+	int stringLen = 0;
+	
+	localPtr = codePtr->procPtr->firstLocalPtr;
+	while (localPtr) {
+	    stringLen += (localPtr->nameLength + 1);
+	    localPtr = localPtr->nextPtr;
+	}
+	
+	localCachePtr = (LocalCache *) ckalloc(sizeof(LocalCache)
+		+ (localCt-1)*sizeof(char *)
+		+ localCt*sizeof(Var)
+		+ stringLen*sizeof(char));
+	
+	namePtr = &localCachePtr->varName0;	
+	varPtr = (Var *) (namePtr + localCt);
+	name = (char *) (varPtr + localCt);
+	
+	localPtr = codePtr->procPtr->firstLocalPtr;
+	while (localPtr) {
+	    *namePtr = name;
+	    varPtr->flags = (localPtr->flags & VAR_TEMPORARY);
+	    varPtr->value.objPtr = localPtr->defValuePtr;
+	    strncpy(name, localPtr->name, localPtr->nameLength);
+	    name += localPtr->nameLength;
+	    
+	    *name++ = '\0';
+	    namePtr++;
+	    varPtr++;
+	    localPtr=localPtr->nextPtr;
+	}
+	codePtr->localCachePtr = localCachePtr;
+	framePtr->localCachePtr = localCachePtr;
+	localCachePtr->refCount = 2;
+    }
+    
+    /*
      * Create the "compiledLocals" array. Make sure it is large enough to hold
      * all the procedure's compiled local variables, including its formal
      * parameters.
      */
 
-    localCt = procPtr->numCompiledLocals;
     compiledLocals = (Var*) TclStackAlloc(interp, (int)(localCt*sizeof(Var)));
     framePtr->numCompiledLocals = localCt;
     framePtr->compiledLocals = compiledLocals;
@@ -1089,15 +1147,9 @@
 
 	Tcl_Obj *objPtr = argObjs[i];
 
+	varPtr->flags = 0;
 	varPtr->value.objPtr = objPtr;
 	Tcl_IncrRefCount(objPtr);	/* Local var is a reference. */
-	varPtr->name = localPtr->name;
-	varPtr->nsPtr = NULL;
-	varPtr->hPtr = NULL;
-	varPtr->refCount = 0;
-	varPtr->tracePtr = NULL;
-	varPtr->searchPtr = NULL;
-	varPtr->flags = localPtr->flags;
 	varPtr++;
 	localPtr = localPtr->nextPtr;
     }
@@ -1110,15 +1162,9 @@
 	if (localPtr->defValuePtr != NULL) {
 	    Tcl_Obj *objPtr = localPtr->defValuePtr;
 
+	    varPtr->flags = 0;
 	    varPtr->value.objPtr = objPtr;
 	    Tcl_IncrRefCount(objPtr);	/* Local var is a reference. */
-	    varPtr->name = localPtr->name;
-	    varPtr->nsPtr = NULL;
-	    varPtr->hPtr = NULL;
-	    varPtr->refCount = 0;
-	    varPtr->tracePtr = NULL;
-	    varPtr->searchPtr = NULL;
-	    varPtr->flags = localPtr->flags;
 	    varPtr++;
 	    localPtr = localPtr->nextPtr;
 	} else {
@@ -1150,13 +1196,7 @@
 	goto incorrectArgs;
     }
 
-    varPtr->name = localPtr->name;
-    varPtr->nsPtr = NULL;
-    varPtr->hPtr = NULL;
-    varPtr->refCount = 0;
-    varPtr->tracePtr = NULL;
-    varPtr->searchPtr = NULL;
-    varPtr->flags = localPtr->flags;
+    varPtr->flags = 0;
 
     localPtr = localPtr->nextPtr;
     varPtr++;
@@ -1255,7 +1295,14 @@
     Interp *iPtr = (Interp *) interp;
     int haveResolvers = (nsPtr->compiledVarResProc || iPtr->resolverPtr);
     CompiledLocal *firstLocalPtr;
+    
+    /*
+        //FIXME: old bytecompiled code: drop whatever flags are coming in (except
+        //maybe for VAR_TEMPORARY? Who cares really?) A job for tbcload, not us.
 
+	// memcpy from the cache ... or drop that from the cache, unused.
+    */
+    
     if (!(haveResolvers && (codePtr->flags & TCL_BYTECODE_RESOLVE_VARS))) {
 	/*
 	 * Initialize the array of local variables stored in the call frame.
@@ -1267,30 +1314,16 @@
     doInitCompiledLocals:
 	if (!haveResolvers) {
 	    for (; localPtr != NULL; varPtr++, localPtr = localPtr->nextPtr) {
-		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->value.objPtr = NULL;
 	    }
 	    return;
 	} else {
 	    Tcl_ResolvedVarInfo *resVarInfo;
 
 	    for (; localPtr != NULL; varPtr++, localPtr = localPtr->nextPtr) {
-		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->value.objPtr = NULL;
 
 		/*
 		 * Now invoke the resolvers to determine the exact variables
@@ -1302,9 +1335,9 @@
 		    Var *resolvedVarPtr = (Var *)
 			    (*resVarInfo->fetchProc)(interp, resVarInfo);
 		    if (resolvedVarPtr) {
-			resolvedVarPtr->refCount++;
-			varPtr->value.linkPtr = resolvedVarPtr;
+			VarHashRefCount(resolvedVarPtr)++;
 			varPtr->flags = VAR_LINK;
+			varPtr->value.linkPtr = resolvedVarPtr;
 		    }
 		}
 	    }
@@ -1437,7 +1470,8 @@
     Namespace *nsPtr = procPtr->cmdPtr->nsPtr;
     CallFrame *framePtr, **framePtrPtr;
     int result;
-
+    ByteCode *codePtr;
+    
     /*
      * If necessary (i.e. if we haven't got a suitable compilation already
      * cached) compile the procedure's body. The compiler will allocate frame
@@ -1448,7 +1482,6 @@
 
     if (procPtr->bodyPtr->typePtr == &tclByteCodeType) {
 	Interp *iPtr = (Interp *) interp;
-	ByteCode *codePtr = procPtr->bodyPtr->internalRep.otherValuePtr;
 
 	/*
 	 * When we've got bytecode, this is the check for validity. That is,
@@ -1459,6 +1492,7 @@
 	 * commands and/or resolver changes are considered).
 	 */
 
+	codePtr = procPtr->bodyPtr->internalRep.otherValuePtr;
  	if (((Interp *) *codePtr->interpHandle != iPtr)
 		|| (codePtr->compileEpoch != iPtr->compileEpoch)
 		|| (codePtr->nsPtr != nsPtr)
@@ -1494,7 +1528,9 @@
     framePtr->objc = objc;
     framePtr->objv = objv;
     framePtr->procPtr = procPtr;
-
+    
+    codePtr = procPtr->bodyPtr->internalRep.otherValuePtr;
+    
     return TCL_OK;
 }
 
@@ -1566,6 +1602,8 @@
     register Proc *procPtr = ((Interp *)interp)->varFramePtr->procPtr;
     int result;
     CallFrame *freePtr;
+    register ByteCode *codePtr =
+	    procPtr->bodyPtr->internalRep.otherValuePtr;
 
     result = InitArgsAndLocals(interp, procNameObj, skip);
     if (result != TCL_OK) {
@@ -1601,9 +1639,6 @@
     if (TclInterpReady(interp) == TCL_ERROR) {
 	result = TCL_ERROR;
     } else {
-	register ByteCode *codePtr =
-		procPtr->bodyPtr->internalRep.otherValuePtr;
-
 	codePtr->refCount++;
 	result = TclExecuteByteCode(interp, codePtr);
 	codePtr->refCount--;
@@ -1674,15 +1709,23 @@
 
   procDone:
     /*
-     * Free the stack-allocated compiled locals and CallFrame. It is important
-     * to pop the call frame without freeing it first: the compiledLocals
-     * cannot be freed before the frame is popped, as the local variables must
-     * be deleted. But the compiledLocals must be freed first, as they were
-     * allocated later on the stack.
+     * Free the stack-allocated compiled locals and CallFrame. The order of
+     * these operations is important:
+     *  1. Pop the call frame. This deletes the local variables, so that they
+     *     cannot be freed before this. As traces may access the local names,
+     *     the localCache has to be valid too. It can be freed immediately
+     *     after popping. The proc cannot go before that, as the localCache
+     *     refers to its localVars.
+     *  2. Free the compiledLocals and the framePtr in reverse order of their
+     *     allocation.
      */
 
     freePtr = ((Interp *)interp)->framePtr;
     Tcl_PopCallFrame(interp);		/* Pop but do not free. */
+    if (freePtr->localCachePtr && (--freePtr->localCachePtr->refCount == 0)) {
+	ckfree ((char *) freePtr->localCachePtr);
+    }
+
     TclStackFree(interp, freePtr->compiledLocals);
 					/* Free compiledLocals. */
     TclStackFree(interp, freePtr);	/* Free CallFrame. */
Index: generic/tclThreadStorage.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclThreadStorage.c,v
retrieving revision 1.12
diff -u -r1.12 tclThreadStorage.c
--- generic/tclThreadStorage.c	13 Nov 2006 22:39:56 -0000	1.12
+++ generic/tclThreadStorage.c	10 Jul 2007 11:53:41 -0000
@@ -136,7 +136,8 @@
 
     hPtr = (Tcl_HashEntry *) TclpSysAlloc(sizeof(Tcl_HashEntry), 0);
     hPtr->key.oneWordValue = keyPtr;
-
+    hPtr->clientData = NULL;
+    
     return hPtr;
 }
 
Index: generic/tclTrace.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclTrace.c,v
retrieving revision 1.41
diff -u -r1.41 tclTrace.c
--- generic/tclTrace.c	28 Jun 2007 21:10:38 -0000	1.41
+++ generic/tclTrace.c	10 Jul 2007 11:53:41 -0000
@@ -2441,8 +2441,8 @@
 	return NULL;
     }
 
-    if ((varPtr->tracePtr != NULL)
-	    || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
+    if ((varPtr->flags & VAR_TRACED_READ)
+	    || (arrayPtr && (arrayPtr->flags & VAR_TRACED_READ))) {
 	TclCallVarTraces((Interp *)interp, arrayPtr, varPtr, varName, NULL,
 		TCL_TRACE_READS, /* leaveErrMsg */ 0);
     }
@@ -2508,7 +2508,9 @@
     int code = TCL_OK;
     int disposeFlags = 0;
     Tcl_InterpState state = NULL;
-
+    Tcl_HashEntry *hPtr;
+    int traceflags = flags & VAR_ALL_TRACES;
+    
     /*
      * If there are already similar trace functions active for the variable,
      * don't call them again.
@@ -2518,9 +2520,11 @@
 	return code;
     }
     TclSetVarTraceActive(varPtr);
-    varPtr->refCount++;
-    if (arrayPtr != NULL) {
-	arrayPtr->refCount++;
+    if (TclIsVarInHash(varPtr)) {
+	VarHashRefCount(varPtr)++;
+    }
+    if (arrayPtr && TclIsVarInHash(arrayPtr)) {
+	VarHashRefCount(arrayPtr)++;
     }
 
     /*
@@ -2572,10 +2576,12 @@
     active.nextPtr = iPtr->activeVarTracePtr;
     iPtr->activeVarTracePtr = &active;
     Tcl_Preserve((ClientData) iPtr);
-    if (arrayPtr != NULL && !TclIsVarTraceActive(arrayPtr)) {
+    if (arrayPtr && !TclIsVarTraceActive(arrayPtr) && (arrayPtr->flags & traceflags)) {
+	hPtr = Tcl_FindHashEntry(&iPtr->varTraces,
+		(char *) arrayPtr);
 	active.varPtr = arrayPtr;
-	for (tracePtr = arrayPtr->tracePtr;  tracePtr != NULL;
-		tracePtr = active.nextTracePtr) {
+	for (tracePtr = (VarTrace *) Tcl_GetHashValue(hPtr);
+	     tracePtr != NULL; tracePtr = active.nextTracePtr) {
 	    active.nextTracePtr = tracePtr->nextPtr;
 	    if (!(tracePtr->flags & flags)) {
 		continue;
@@ -2616,36 +2622,40 @@
 	flags |= TCL_TRACE_DESTROYED;
     }
     active.varPtr = varPtr;
-    for (tracePtr = varPtr->tracePtr; tracePtr != NULL;
-	    tracePtr = active.nextTracePtr) {
-	active.nextTracePtr = tracePtr->nextPtr;
-	if (!(tracePtr->flags & flags)) {
-	    continue;
-	}
-	Tcl_Preserve((ClientData) tracePtr);
-	if (state == NULL) {
-	    state = Tcl_SaveInterpState((Tcl_Interp *)iPtr, code);
-	}
-	if (Tcl_InterpDeleted((Tcl_Interp *)iPtr)) {
-	    flags |= TCL_INTERP_DESTROYED;
-	}
-	result = (*tracePtr->traceProc)(tracePtr->clientData,
-		(Tcl_Interp *) iPtr, part1, part2, flags);
-	if (result != NULL) {
-	    if (flags & TCL_TRACE_UNSETS) {
-		/*
-		 * Ignore errors in unset traces.
-		 */
-
-		DisposeTraceResult(tracePtr->flags, result);
-	    } else {
-		disposeFlags = tracePtr->flags;
-		code = TCL_ERROR;
+    if (varPtr->flags & traceflags) {
+	hPtr = Tcl_FindHashEntry(&iPtr->varTraces,
+		(char *) varPtr);
+	for (tracePtr = (VarTrace *) Tcl_GetHashValue(hPtr);
+	     tracePtr != NULL; tracePtr = active.nextTracePtr) {
+	    active.nextTracePtr = tracePtr->nextPtr;
+	    if (!(tracePtr->flags & flags)) {
+		continue;
+	    }
+	    Tcl_Preserve((ClientData) tracePtr);
+	    if (state == NULL) {
+		state = Tcl_SaveInterpState((Tcl_Interp *)iPtr, code);
+	    }
+	    if (Tcl_InterpDeleted((Tcl_Interp *)iPtr)) {
+		flags |= TCL_INTERP_DESTROYED;
+	    }
+	    result = (*tracePtr->traceProc)(tracePtr->clientData,
+		    (Tcl_Interp *) iPtr, part1, part2, flags);
+	    if (result != NULL) {
+		if (flags & TCL_TRACE_UNSETS) {
+		    /*
+		     * Ignore errors in unset traces.
+		     */
+		    
+		    DisposeTraceResult(tracePtr->flags, result);
+		} else {
+		    disposeFlags = tracePtr->flags;
+		    code = TCL_ERROR;
+		}
+	    }
+	    Tcl_Release((ClientData) tracePtr);
+	    if (code == TCL_ERROR) {
+		goto done;
 	    }
-	}
-	Tcl_Release((ClientData) tracePtr);
-	if (code == TCL_ERROR) {
-	    goto done;
 	}
     }
 
@@ -2718,14 +2728,16 @@
 	}
     }
 
-    if (arrayPtr != NULL) {
-	arrayPtr->refCount--;
+    if (arrayPtr && TclIsVarInHash(arrayPtr)) {
+	VarHashRefCount(arrayPtr)--;
     }
     if (copiedName) {
 	Tcl_DStringFree(&nameCopy);
     }
     TclClearVarTraceActive(varPtr);
-    varPtr->refCount--;
+    if (TclIsVarInHash(varPtr)) {
+	VarHashRefCount(varPtr)--;
+    }
     iPtr->activeVarTracePtr = active.nextPtr;
     Tcl_Release((ClientData) iPtr);
     return code;
@@ -2827,11 +2839,12 @@
     ClientData clientData)	/* Arbitrary argument to pass to proc. */
 {
     register VarTrace *tracePtr;
-    VarTrace *prevPtr;
+    VarTrace *prevPtr, *nextPtr;
     Var *varPtr, *arrayPtr;
     Interp *iPtr = (Interp *) interp;
     ActiveVarTrace *activePtr;
-    int flagMask;
+    int flagMask, allFlags = 0;
+    Tcl_HashEntry *hPtr;
 
     /*
      * Set up a mask to mask out the parts of the flags that we are not
@@ -2856,15 +2869,19 @@
     flagMask |= TCL_TRACE_OLD_STYLE;
 #endif
     flags &= flagMask;
-    for (tracePtr = varPtr->tracePtr, prevPtr = NULL; ;
+
+    hPtr = Tcl_FindHashEntry(&iPtr->varTraces,
+	    (char *) varPtr);
+    for (tracePtr = (VarTrace *) Tcl_GetHashValue(hPtr), prevPtr = NULL; ;
 	    prevPtr = tracePtr, tracePtr = tracePtr->nextPtr) {
 	if (tracePtr == NULL) {
-	    return;
+	    goto updateFlags;
 	}
 	if ((tracePtr->traceProc == proc) && (tracePtr->flags == flags)
 		&& (tracePtr->clientData == clientData)) {
 	    break;
 	}
+	allFlags |= tracePtr->flags;
     }
 
     /*
@@ -2879,19 +2896,32 @@
 	    activePtr->nextTracePtr = tracePtr->nextPtr;
 	}
     }
+    nextPtr = tracePtr->nextPtr;
     if (prevPtr == NULL) {
-	varPtr->tracePtr = tracePtr->nextPtr;
+	if (nextPtr) {
+	    Tcl_SetHashValue(hPtr, nextPtr);
+	} else {
+	    Tcl_DeleteHashEntry(hPtr);
+	}
     } else {
-	prevPtr->nextPtr = tracePtr->nextPtr;
+	prevPtr->nextPtr = nextPtr;
     }
     Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC);
 
-    /*
-     * If this is the last trace on the variable, and the variable is unset
-     * and unused, then free up the variable.
-     */
-
-    if (TclIsVarUndefined(varPtr)) {
+    for (tracePtr = nextPtr; tracePtr != NULL;
+	    tracePtr = tracePtr->nextPtr) {
+	allFlags |= tracePtr->flags;
+    }
+    
+    updateFlags:
+    varPtr->flags &= ~VAR_ALL_TRACES;
+    if (allFlags & VAR_ALL_TRACES) {
+	varPtr->flags |= (allFlags & VAR_ALL_TRACES);
+    } else if (TclIsVarUndefined(varPtr)) {
+	/*
+	 * If this is the last trace on the variable, and the variable is
+	 * unset and unused, then free up the variable.
+	 */
 	TclCleanupVar(varPtr, NULL);
     }
 }
@@ -2968,8 +2998,10 @@
 				 * next trace after that one. If NULL, this
 				 * call will return the first trace. */
 {
+    Interp *iPtr = (Interp *) interp;
     register VarTrace *tracePtr;
     Var *varPtr, *arrayPtr;
+    Tcl_HashEntry *hPtr;
 
     varPtr = TclLookupVar(interp, part1, part2,
 	    flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY), /*msg*/ NULL,
@@ -2982,19 +3014,25 @@
      * Find the relevant trace, if any, and return its clientData.
      */
 
-    tracePtr = varPtr->tracePtr;
-    if (prevClientData != NULL) {
-	for ( ;  tracePtr != NULL;  tracePtr = tracePtr->nextPtr) {
-	    if ((tracePtr->clientData == prevClientData)
-		    && (tracePtr->traceProc == proc)) {
-		tracePtr = tracePtr->nextPtr;
-		break;
+    hPtr = Tcl_FindHashEntry(&iPtr->varTraces,
+	    (char *) varPtr);
+
+    if (hPtr) {
+	tracePtr = Tcl_GetHashValue(hPtr);
+
+	if (prevClientData != NULL) {
+	    for ( ;  tracePtr != NULL;  tracePtr = tracePtr->nextPtr) {
+		if ((tracePtr->clientData == prevClientData)
+			&& (tracePtr->traceProc == proc)) {
+		    tracePtr = tracePtr->nextPtr;
+		    break;
+		}
 	    }
 	}
-    }
-    for (; tracePtr!=NULL ; tracePtr=tracePtr->nextPtr) {
-	if (tracePtr->traceProc == proc) {
-	    return tracePtr->clientData;
+	for (; tracePtr!=NULL ; tracePtr=tracePtr->nextPtr) {
+	    if (tracePtr->traceProc == proc) {
+		return tracePtr->clientData;
+	    }
 	}
     }
     return NULL;
@@ -3016,6 +3054,7 @@
  *	A trace is set up on the variable given by varName, such that future
  *	references to the variable will be intermediated by proc. See the
  *	manual entry for complete details on the calling sequence for proc.
+ *      The variable's flags are updated.
  *
  *----------------------------------------------------------------------
  */
@@ -3053,7 +3092,7 @@
  *	A trace is set up on the variable given by part1 and part2, such that
  *	future references to the variable will be intermediated by proc. See
  *	the manual entry for complete details on the calling sequence for
- *	proc.
+ *	proc. The variable's flags are updated.
  *
  *----------------------------------------------------------------------
  */
@@ -3126,8 +3165,11 @@
 				 * caller to free if this function returns
 				 * TCL_ERROR. */
 {
+    Interp *iPtr = (Interp *) interp;
     Var *varPtr, *arrayPtr;
     int flagMask;
+    Tcl_HashEntry *hPtr;
+    int new;
 
     /*
      * We strip 'flags' down to just the parts which are relevant to
@@ -3164,8 +3206,18 @@
     flagMask |= TCL_TRACE_OLD_STYLE;
 #endif
     tracePtr->flags = tracePtr->flags & flagMask;
-    tracePtr->nextPtr = varPtr->tracePtr;
-    varPtr->tracePtr = tracePtr;
+
+    hPtr = Tcl_CreateHashEntry(&iPtr->varTraces,
+	    (char *) varPtr, &new);
+    if (new) {
+	tracePtr->nextPtr = NULL;
+    } else {
+	tracePtr->nextPtr = (VarTrace *) Tcl_GetHashValue(hPtr);
+    }
+    Tcl_SetHashValue(hPtr, (char *) tracePtr);
+
+    varPtr->flags |= (tracePtr->flags & VAR_ALL_TRACES);
+
     return TCL_OK;
 }
 
Index: generic/tclVar.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclVar.c,v
retrieving revision 1.144
diff -u -r1.144 tclVar.c
--- generic/tclVar.c	28 Jun 2007 13:56:21 -0000	1.144
+++ generic/tclVar.c	10 Jul 2007 11:53:41 -0000
@@ -11,6 +11,7 @@
  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  * Copyright (c) 1998-1999 by Scriptics Corporation.
  * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved.
+ * Copyright (c) 2007 Miguel Sofer
  *
  * See the file "license.terms" for information on usage and redistribution of
  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -20,6 +21,85 @@
 
 #include "tclInt.h"
 
+ /*
+  * Prototypes for the variable hash key methods.
+  */
+
+static Tcl_HashEntry *	AllocVarEntry(Tcl_HashTable *tablePtr,
+			    VOID *keyPtr);
+static void		FreeVarEntry(Tcl_HashEntry *hPtr);
+static int		CompareVarKeys(VOID *keyPtr, Tcl_HashEntry *hPtr);
+static unsigned int	HashVarKey(Tcl_HashTable *tablePtr, VOID *keyPtr);
+
+Tcl_HashKeyType tclVarHashKeyType = {
+    TCL_HASH_KEY_TYPE_VERSION,		/* version */
+    0,					/* flags */
+    HashVarKey,			        /* hashKeyProc */
+    CompareVarKeys,			/* compareKeysProc */
+    AllocVarEntry,			/* allocEntryProc */
+    FreeVarEntry			/* freeEntryProc */
+};
+
+static Var *
+VarHashCreateVar(TclVarHashTable *tablePtr, const char *key, int *newPtr)
+{
+    Tcl_HashEntry *hPtr = Tcl_CreateHashEntry((Tcl_HashTable *) tablePtr, key, newPtr);
+    if (hPtr) {
+	return (Var *) Tcl_GetHashValue(hPtr);
+    } else {
+	return (Var *) NULL;
+    }
+}
+
+#define VarHashFindVar(tablePtr, key) \
+    VarHashCreateVar((tablePtr), (key), NULL)
+
+#define VarHashInvalidateEntry(varPtr) \
+    ((varPtr)->flags |= VAR_DEAD_HASH)
+
+#define VarHashDeleteEntry(varPtr) \
+    Tcl_DeleteHashEntry(&(((VarInHash *) varPtr)->entry))
+
+static Var *
+VarHashFirstVar(TclVarHashTable *tablePtr, Tcl_HashSearch *searchPtr)
+{
+    Tcl_HashEntry *hPtr = Tcl_FirstHashEntry((Tcl_HashTable *)tablePtr, searchPtr);
+    if (hPtr) {
+	return (Var *) Tcl_GetHashValue(hPtr);
+    } else {
+	return (Var *) NULL;
+    }
+}
+
+static Var *
+VarHashNextVar(Tcl_HashSearch *searchPtr)
+{
+    Tcl_HashEntry *hPtr = Tcl_NextHashEntry(searchPtr);
+    if (hPtr) {
+	return (Var *) Tcl_GetHashValue(hPtr);
+    } else {
+	return (Var *) NULL;
+    }
+}
+
+#define VarHashGetKey(varPtr) \
+	((char *) Tcl_GetHashKey(\
+		(Tcl_HashTable *)((((VarInHash *) (varPtr))->entry.tablePtr)), \
+		&((VarInHash *) (varPtr))->entry))
+
+#define VarHashDeleteTable(tablePtr) \
+    Tcl_DeleteHashTable((Tcl_HashTable *) (tablePtr))
+
+#define VarHashGetValue(hPtr) \
+    Tcl_GetHashValue((hPtr))
+
+#define VarHashFirstEntry(tablePtr, searchPtr) \
+    Tcl_FirstHashEntry((Tcl_HashTable *) (tablePtr), (searchPtr))
+
+#define VarHashNextEntry(searchPtr) \
+    Tcl_NextHashEntry((searchPtr))
+
+
 /*
  * The strings below are used to indicate what went wrong when a variable
  * access is denied.
@@ -37,7 +117,8 @@
 static const char *missingName =	"missing variable name";
 static const char *isArrayElement =
 	"name refers to an element in an array";
- 
+
+
 /*
  * A test to see if we are in a call frame that has local variables. This is
  * true if we are inside a procedure body.
@@ -49,19 +130,18 @@
  * Forward references to functions defined later in this file:
  */
 
-static void		DeleteSearches(Var *arrayVarPtr);
+static void		DeleteSearches(Interp *iPtr, Var *arrayVarPtr);
 static void		DeleteArray(Interp *iPtr, const char *arrayName,
 			    Var *varPtr, int flags);
 static int		ObjMakeUpvar(Tcl_Interp *interp,
 			    CallFrame *framePtr, Tcl_Obj *otherP1Ptr,
 			    const char *otherP2, const int otherFlags,
 			    const char *myName, int myFlags, int index);
-static Var *		NewVar(void);
 static ArraySearch *	ParseSearchId(Tcl_Interp *interp, const Var *varPtr,
 			    const char *varName, Tcl_Obj *handleObj);
 static void		UnsetVarStruct(Var *varPtr, Var *arrayPtr,
 			    Interp *iPtr, const char *part1,
-			    const char *part2, int flags, int reachable);
+			    const char *part2, int flags);
 static int		SetArraySearchObj(Tcl_Interp *interp, Tcl_Obj *objPtr);
 
 /*
@@ -145,6 +225,7 @@
     "array search",
     NULL, NULL, NULL, SetArraySearchObj
 };
+
 
 /*
  *----------------------------------------------------------------------
@@ -404,16 +485,17 @@
 
     if (typePtr == &localVarNameType) {
 	int localIndex = (int) part1Ptr->internalRep.longValue;
-
+	
 	if (HasLocalVars(varFramePtr)
 		&& !(flags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY))
 		&& (localIndex < varFramePtr->numCompiledLocals)) {
 	    /*
 	     * use the cached index if the names coincide.
 	     */
+	    char *name = localVarNames(iPtr->varFramePtr)[localIndex];
 
-	    varPtr = &(varFramePtr->compiledLocals[localIndex]);
-	    if ((varPtr->name != NULL) && (strcmp(part1, varPtr->name) == 0)) {
+	    if (name && (strcmp(part1, name) == 0)) {
+		varPtr = (Var *) &(varFramePtr->compiledLocals[localIndex]);
 		goto donePart1;
 	    }
 	}
@@ -438,14 +520,14 @@
 		 */
 		!TclIsVarUndefined(varPtr))));
 
-	if (useReference && (varPtr->hPtr != NULL)) {
+	if (useReference && !TclIsVarDeadHash(varPtr)) {
 	    /*
 	     * A straight global or namespace reference, use it. It isn't so
 	     * simple to deal with 'implicit' namespace references, i.e.,
 	     * those where the reference could be to either a namespace or a
 	     * global variable. Those we lookup again.
 	     *
-	     * If (varPtr->hPtr == NULL), this might be a reference to a
+	     * If TclIsVarDeadHash(varPtr), this might be a reference to a
 	     * variable in a deleted namespace, kept alive by e.g. part1Ptr.
 	     * We could conceivably be so unlucky that a new namespace was
 	     * created at the same address as the deleted one, so to be safe
@@ -676,14 +758,13 @@
 				 * variables are currently in use. Same as the
 				 * current procedure's frame, if any, unless
 				 * an "uplevel" is executing. */
-    Tcl_HashTable *tablePtr;	/* Points to the hashtable, if any, in which
+    TclVarHashTable *tablePtr;	/* Points to the hashtable, if any, in which
 				 * to look up the variable. */
     Tcl_Var var;		/* Used to search for global names. */
     Var *varPtr;		/* Points to the Var structure returned for
 				 * the variable. */
     Namespace *varNsPtr, *cxtNsPtr, *dummy1Ptr, *dummy2Ptr;
     ResolverScheme *resPtr;
-    Tcl_HashEntry *hPtr;
     int new, i, result;
 
     varPtr = NULL;
@@ -771,13 +852,9 @@
 	 * otherwise generate our own error!
 	 */
 
-	var = Tcl_FindNamespaceVar(interp, varName, (Tcl_Namespace *) cxtNsPtr,
+	varPtr = (Var *) Tcl_FindNamespaceVar(interp, varName, (Tcl_Namespace *) cxtNsPtr,
 		flags & ~TCL_LEAVE_ERR_MSG);
 
-	if (var != (Tcl_Var) NULL) {
-	    varPtr = (Var *) var;
-	}
-
 	if (varPtr == NULL) {
 	    if (create) {	/* var wasn't found so create it */
 		TclGetNamespaceForQualName(interp, varName, cxtNsPtr,
@@ -790,11 +867,7 @@
 		    *errMsgPtr = missingName;
 		    return NULL;
 		}
-		hPtr = Tcl_CreateHashEntry(&varNsPtr->varTable, tail, &new);
-		varPtr = NewVar();
-		Tcl_SetHashValue(hPtr, varPtr);
-		varPtr->hPtr = hPtr;
-		varPtr->nsPtr = varNsPtr;
+		varPtr = VarHashCreateVar(&varNsPtr->varTable, tail, &new);
 		if (lookGlobal) {
 		    /*
 		     * The variable was created starting from the global
@@ -815,49 +888,36 @@
 	Proc *procPtr = varFramePtr->procPtr;
 	int localCt = procPtr->numCompiledLocals;
 	CompiledLocal *localPtr = procPtr->firstLocalPtr;
-	Var *localVarPtr = varFramePtr->compiledLocals;
 	int varNameLen = strlen(varName);
 
 	for (i=0 ; i<localCt ; i++) {
 	    if (!TclIsVarTemporary(localPtr)) {
-		register char *localName = localVarPtr->name;
+		char *localName = localPtr->name;
 		if ((varName[0] == localName[0])
 			&& (varNameLen == localPtr->nameLength)
 			&& (strcmp(varName, localName) == 0)) {
 		    *indexPtr = i;
-		    return localVarPtr;
+		    return (Var *) &varFramePtr->compiledLocals[i];
 		}
 	    }
-	    localVarPtr++;
 	    localPtr = localPtr->nextPtr;
 	}
 	tablePtr = varFramePtr->varTablePtr;
 	if (create) {
 	    if (tablePtr == NULL) {
-		tablePtr = (Tcl_HashTable *)
-		    ckalloc(sizeof(Tcl_HashTable));
-		Tcl_InitHashTable(tablePtr, TCL_STRING_KEYS);
+		tablePtr = (TclVarHashTable *) ckalloc(sizeof(TclVarHashTable));
+		TclInitVarHashTable(tablePtr, NULL);
 		varFramePtr->varTablePtr = tablePtr;
 	    }
-	    hPtr = Tcl_CreateHashEntry(tablePtr, varName, &new);
-	    if (new) {
-		varPtr = NewVar();
-		Tcl_SetHashValue(hPtr, varPtr);
-		varPtr->hPtr = hPtr;
-		varPtr->nsPtr = NULL;	/* a local variable */
-	    } else {
-		varPtr = (Var *) Tcl_GetHashValue(hPtr);
-	    }
+	    varPtr = VarHashCreateVar(tablePtr, varName, &new);
 	} else {
-	    hPtr = NULL;
+	    varPtr = NULL;
 	    if (tablePtr != NULL) {
-		hPtr = Tcl_FindHashEntry(tablePtr, varName);
+		varPtr = VarHashFindVar(tablePtr, varName);
 	    }
-	    if (hPtr == NULL) {
+	    if (varPtr == NULL) {
 		*errMsgPtr = noSuchVar;
-		return NULL;
 	    }
-	    varPtr = (Var *) Tcl_GetHashValue(hPtr);
 	}
     }
     return varPtr;
@@ -918,10 +978,11 @@
 				 * return error if it doesn't exist. */
     Var *arrayPtr)		/* Pointer to the array's Var structure. */
 {
-    Tcl_HashEntry *hPtr;
     int new;
     Var *varPtr;
-
+    TclVarHashTable *tablePtr;
+    Namespace *nsPtr;
+    
     /*
      * We're dealing with an array element. Make sure the variable is an array
      * and look up the element (create the element if desired).
@@ -940,7 +1001,7 @@
 	 * deleted namespace!
 	 */
 
-	if ((arrayPtr->flags & VAR_IN_HASHTABLE) && (arrayPtr->hPtr == NULL)) {
+	if (TclIsVarDeadHash(arrayPtr)) {
 	    if (flags & TCL_LEAVE_ERR_MSG) {
 		TclVarErrMsg(interp, arrayName, elName, msg, danglingVar);
 	    }
@@ -949,9 +1010,15 @@
 
 	TclSetVarArray(arrayPtr);
 	TclClearVarUndefined(arrayPtr);
-	arrayPtr->value.tablePtr = (Tcl_HashTable *)
-		ckalloc(sizeof(Tcl_HashTable));
-	Tcl_InitHashTable(arrayPtr->value.tablePtr, TCL_STRING_KEYS);
+	tablePtr = (TclVarHashTable *) ckalloc(sizeof(TclVarHashTable));	
+	arrayPtr->value.tablePtr = tablePtr;	    
+	
+	if (TclIsVarInHash(arrayPtr) && TclGetVarNsPtr(arrayPtr)) {
+	    nsPtr = TclGetVarNsPtr(arrayPtr);
+	} else {
+	    nsPtr = NULL;
+	}
+	TclInitVarHashTable(arrayPtr->value.tablePtr, nsPtr);
     } else if (!TclIsVarArray(arrayPtr)) {
 	if (flags & TCL_LEAVE_ERR_MSG) {
 	    TclVarErrMsg(interp, arrayName, elName, msg, needArray);
@@ -960,29 +1027,24 @@
     }
 
     if (createElem) {
-	hPtr = Tcl_CreateHashEntry(arrayPtr->value.tablePtr, elName, &new);
+	varPtr = VarHashCreateVar(arrayPtr->value.tablePtr, elName, &new);
 	if (new) {
-	    if (arrayPtr->searchPtr != NULL) {
-		DeleteSearches(arrayPtr);
+	    if (arrayPtr->flags & VAR_SEARCH_ACTIVE) {
+		DeleteSearches((Interp *) interp, arrayPtr);
 	    }
-	    varPtr = NewVar();
-	    Tcl_SetHashValue(hPtr, varPtr);
-	    varPtr->hPtr = hPtr;
-	    varPtr->nsPtr = arrayPtr->nsPtr;
 	    TclSetVarArrayElement(varPtr);
 	}
     } else {
-	hPtr = Tcl_FindHashEntry(arrayPtr->value.tablePtr, elName);
-	if (hPtr == NULL) {
+	varPtr = VarHashFindVar(arrayPtr->value.tablePtr, elName);
+	if (varPtr == NULL) {
 	    if (flags & TCL_LEAVE_ERR_MSG) {
 		TclVarErrMsg(interp, arrayName, elName, msg, noSuchElement);
 		Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ELEMENT", elName,
 			NULL);
 	    }
-	    return NULL;
 	}
     }
-    return (Var *) Tcl_GetHashValue(hPtr);
+    return varPtr;
 }
 
 /*
@@ -1203,11 +1265,11 @@
     const char *msg;
 
     /*
-     * Invoke any traces that have been set for the variable.
+     * Invoke any read traces that have been set for the variable.
      */
 
-    if ((varPtr->tracePtr != NULL)
-	    || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
+    if ((varPtr->flags & VAR_TRACED_READ)
+	    || (arrayPtr && (arrayPtr->flags & VAR_TRACED_READ))) {
 	if (TCL_ERROR == TclCallVarTraces(iPtr, arrayPtr, varPtr, part1, part2,
 		(flags & (TCL_NAMESPACE_ONLY|TCL_GLOBAL_ONLY))
 		| TCL_TRACE_READS, (flags & TCL_LEAVE_ERR_MSG))) {
@@ -1224,7 +1286,7 @@
     }
 
     if (flags & TCL_LEAVE_ERR_MSG) {
-	if (TclIsVarUndefined(varPtr) && (arrayPtr != NULL)
+	if (TclIsVarUndefined(varPtr) && arrayPtr
 		&& !TclIsVarUndefined(arrayPtr)) {
 	    msg = noSuchElement;
 	} else if (TclIsVarArray(varPtr)) {
@@ -1577,7 +1639,7 @@
      * allocation and is meaningless anyway).
      */
 
-    if ((varPtr->flags & VAR_IN_HASHTABLE) && (varPtr->hPtr == NULL)) {
+    if (TclIsVarDeadHash(varPtr)) {
 	if (flags & TCL_LEAVE_ERR_MSG) {
 	    if (TclIsVarArrayElement(varPtr)) {
 		TclVarErrMsg(interp, part1, part2, "set", danglingElement);
@@ -1605,8 +1667,8 @@
      * instructions.
      */
 
-    if ((flags & TCL_TRACE_READS) && ((varPtr->tracePtr != NULL)
-	    || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL)))) {
+    if ((flags & TCL_TRACE_READS) && ((varPtr->flags & VAR_TRACED_READ)
+	    || (arrayPtr && (arrayPtr->flags & VAR_TRACED_READ)))) {
 	if (TCL_ERROR == TclCallVarTraces(iPtr, arrayPtr, varPtr, part1, part2,
 		TCL_TRACE_READS, (flags & TCL_LEAVE_ERR_MSG))) {
 	    goto earlyError;
@@ -1620,10 +1682,10 @@
      * otherwise we must create a new copy to modify: this is "copy on write".
      */
 
+    oldValuePtr = varPtr->value.objPtr;
     if (flags & TCL_LIST_ELEMENT && !(flags & TCL_APPEND_VALUE)) {
-	TclSetVarUndefined(varPtr);
+	varPtr->value.objPtr = NULL;
     }
-    oldValuePtr = varPtr->value.objPtr;
     if (flags & (TCL_APPEND_VALUE|TCL_LIST_ELEMENT)) {
 	if (TclIsVarUndefined(varPtr) && (oldValuePtr != NULL)) {
 	    TclDecrRefCount(oldValuePtr);	/* discard old value */
@@ -1682,20 +1744,16 @@
 	}
     }
     TclSetVarScalar(varPtr);
-    TclClearVarUndefined(varPtr);
-    if (arrayPtr != NULL) {
-	TclClearVarUndefined(arrayPtr);
-    }
-
+    
     /*
      * Invoke any write traces for the variable.
      */
 
-    if ((varPtr->tracePtr != NULL)
-	    || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
+    if ((varPtr->flags & VAR_TRACED_WRITE)
+	    || (arrayPtr && (arrayPtr->flags & VAR_TRACED_WRITE))) {
 	if (TCL_ERROR == TclCallVarTraces(iPtr, arrayPtr, varPtr, part1, part2,
-		(flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY))
-		| TCL_TRACE_WRITES, (flags & TCL_LEAVE_ERR_MSG))) {
+	        (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY))|TCL_TRACE_WRITES,
+		(flags & TCL_LEAVE_ERR_MSG))) {
 	    goto cleanup;
 	}
     }
@@ -1843,9 +1901,13 @@
     register Tcl_Obj *varValuePtr, *newValuePtr = NULL;
     int duplicated, code;
 
-    varPtr->refCount++;
+    if (TclIsVarInHash(varPtr)) {
+	VarHashRefCount(varPtr)++;
+    }
     varValuePtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2, flags);
-    varPtr->refCount--;
+    if (TclIsVarInHash(varPtr)) {
+	VarHashRefCount(varPtr)--;
+    }
     if (varValuePtr == NULL) {
 	varValuePtr = Tcl_NewIntObj(0);
     }
@@ -1996,9 +2058,11 @@
      * the variable's name.
      */
 
-    varPtr->refCount++;
+    if (TclIsVarInHash(varPtr)) {
+	VarHashRefCount(varPtr)++;
+    }
 
-    UnsetVarStruct(varPtr, arrayPtr, iPtr, part1, part2, flags, 1);
+    UnsetVarStruct(varPtr, arrayPtr, iPtr, part1, part2, flags);
 
     /*
      * It's an error to unset an undefined variable.
@@ -2030,8 +2094,10 @@
      * its value object, if any, was decremented above.
      */
 
-    varPtr->refCount--;
-    TclCleanupVar(varPtr, arrayPtr);
+    if (TclIsVarInHash(varPtr)) {
+	VarHashRefCount(varPtr)--;
+	TclCleanupVar(varPtr, arrayPtr);
+    }
     return result;
 }
 
@@ -2062,20 +2128,19 @@
     const char *part1,  /* NULL if it is to be computed on demand, only for
 			 * variables in a hashtable */
     const char *part2,
-    int flags,
-    int reachable)      /* indicates if the variable is accessible by name */
+    int flags)
 {
     Var dummyVar;
-    Var *dummyVarPtr;
-    ActiveVarTrace *activePtr;
-    Tcl_Obj *part1Ptr = NULL;
-    int traced = !TclIsVarUntraced(varPtr)
-	    || (arrayPtr && !TclIsVarUntraced(arrayPtr));
-
-    if (arrayPtr && arrayPtr->searchPtr) {
-	DeleteSearches(arrayPtr);
+    int traced = TclIsVarTraced(varPtr)
+	    || (arrayPtr && (arrayPtr->flags & VAR_TRACED_UNSET));
+    
+    if (arrayPtr && (arrayPtr->flags & VAR_SEARCH_ACTIVE)) {
+	DeleteSearches(iPtr, arrayPtr);
+    } else if (varPtr->flags & VAR_SEARCH_ACTIVE) {
+	DeleteSearches(iPtr, varPtr);
     }
 
+
     /*
      * The code below is tricky, because of the possibility that a trace
      * function might try to access a variable being deleted. To handle this
@@ -2088,18 +2153,10 @@
      *    gotten recreated by a trace).
      */
 
-    if (reachable && (traced || TclIsVarArray(varPtr))) {
-	dummyVar = *varPtr;
-	dummyVarPtr = &dummyVar;
-	TclSetVarUndefined(varPtr);
-	TclSetVarScalar(varPtr);
-	varPtr->value.objPtr = NULL; /* dummyVar points to any value object */
-	varPtr->tracePtr = NULL;
-	varPtr->searchPtr = NULL;
-    } else {
-	dummyVarPtr = varPtr;
-    }
-
+    dummyVar = *varPtr;
+    dummyVar.flags &= ~VAR_ALL_HASH;
+    TclSetVarUndefined(varPtr);
+        
     /*
      * Call trace functions for the variable being deleted. Then delete its
      * traces. Be sure to abort any other traces for the variable that are
@@ -2111,65 +2168,85 @@
      */
 
     if (traced) {
-	/*
-	 * Get the variable's name if NULL was passed;
-	 */
+	VarTrace *tracePtr = NULL;
+	Tcl_HashEntry *tPtr = NULL;
 
-	if (part1 == NULL) {
-	    Tcl_Interp *interp = (Tcl_Interp *) iPtr;
-	    TclNewObj(part1Ptr);
-	    Tcl_IncrRefCount(part1Ptr);
-	    Tcl_GetVariableFullName(interp, (Tcl_Var) dummyVarPtr, part1Ptr);
-	    part1 = TclGetString(part1Ptr);
+	if (TclIsVarTraced(&dummyVar)) {
+	    /*
+	     * Transfer any existing traces on var, IF there are unset
+	     * traces. Otherwise just delete them.
+	     */	
+
+	    int new;
+	    Tcl_HashEntry *tPtr =
+		Tcl_FindHashEntry(&iPtr->varTraces, (char *) varPtr);
+
+	    tracePtr = Tcl_GetHashValue(tPtr);
+	    varPtr->flags &= ~VAR_ALL_TRACES;
+	    Tcl_DeleteHashEntry(tPtr);
+	    if (dummyVar.flags & VAR_TRACED_UNSET) {
+		tPtr = Tcl_CreateHashEntry(&iPtr->varTraces, (char *) &dummyVar, &new);
+		Tcl_SetHashValue(tPtr, tracePtr);
+	    } else {
+		tPtr = NULL;
+	    }
 	}
+
+	if ((dummyVar.flags & VAR_TRACED_UNSET) || (arrayPtr->flags & VAR_TRACED_UNSET)) {
+	    Tcl_Obj *part1Ptr = NULL;
+	    
+	    if (part1 == NULL) {
+		/*
+		 * Get the variable's name
+		 */
+	    
+		Tcl_Interp *interp = (Tcl_Interp *) iPtr;
+		TclNewObj(part1Ptr);
+		Tcl_IncrRefCount(part1Ptr);
+		Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, part1Ptr);
+		part1 = TclGetString(part1Ptr);
+	    }
 	
-	dummyVarPtr->flags &= ~VAR_TRACE_ACTIVE;
-	TclCallVarTraces(iPtr, arrayPtr, dummyVarPtr, part1, part2, (flags
-		& (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY))
-		| TCL_TRACE_UNSETS, /* leaveErrMsg */ 0);
-	while (dummyVarPtr->tracePtr != NULL) {
-	    VarTrace *tracePtr = dummyVarPtr->tracePtr;
-	    dummyVarPtr->tracePtr = tracePtr->nextPtr;
-	    Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC);
-	}
-	for (activePtr = iPtr->activeVarTracePtr;  activePtr != NULL;
-		activePtr = activePtr->nextPtr) {
-	    if (activePtr->varPtr == varPtr) {
-		activePtr->nextTracePtr = NULL;
+	    dummyVar.flags &= ~VAR_TRACE_ACTIVE;
+	    TclCallVarTraces(iPtr, arrayPtr, (Var *) &dummyVar, part1, part2,
+		    (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY))| TCL_TRACE_UNSETS,
+		    /* leaveErrMsg */ 0);
+	    
+	    if (part1Ptr) {
+		Tcl_DecrRefCount(part1Ptr);
+		part1 = NULL;
+	    }
+	    if (tPtr) {
+		Tcl_DeleteHashEntry(tPtr);
 	    }
 	}
-	if (part1Ptr) {
-	    Tcl_DecrRefCount(part1Ptr);
-	    part1 = NULL;
+
+	if (tracePtr) {
+	    ActiveVarTrace *activePtr;
+	    
+	    while (tracePtr) {
+		VarTrace *prevPtr = tracePtr;
+		tracePtr = tracePtr->nextPtr;
+		Tcl_EventuallyFree((ClientData) prevPtr, TCL_DYNAMIC);
+	    }
+	    for (activePtr = iPtr->activeVarTracePtr;  activePtr != NULL;
+		 activePtr = activePtr->nextPtr) {
+		if (activePtr->varPtr == varPtr) {
+		    activePtr->nextTracePtr = NULL;
+		}
+	    }
 	}
     }
+    
 
-    if (TclIsVarScalar(dummyVarPtr)
-	    && (dummyVarPtr->value.objPtr != NULL)) {
+    if (TclIsVarScalar(&dummyVar) && (dummyVar.value.objPtr != NULL)) {
 	/*
 	 * Decrement the ref count of the var's value
 	 */
 	
-	Tcl_Obj *objPtr = dummyVarPtr->value.objPtr;
+	Tcl_Obj *objPtr = dummyVar.value.objPtr;
 	TclDecrRefCount(objPtr);
-	dummyVarPtr->value.objPtr = NULL;
-    } else if (TclIsVarLink(varPtr)) {
-	/*
-	 * For global/upvar variables referenced in procedures, decrement the 
-	 * reference count on the variable referred to, and free the
-	 * referenced variable if it's no longer needed.
-	 */
-	Var *linkPtr = varPtr->value.linkPtr;
-	linkPtr->refCount--;
-	if ((linkPtr->refCount == 0) && TclIsVarUndefined(linkPtr)
-		&& (linkPtr->tracePtr == NULL)
-		&& (linkPtr->flags & VAR_IN_HASHTABLE)) {
-	    if (linkPtr->hPtr != NULL) {
-		Tcl_DeleteHashEntry(linkPtr->hPtr);
-	    }
-	    ckfree((char *) linkPtr);
-	}
-    } else if (TclIsVarArray(dummyVarPtr) && !TclIsVarUndefined(dummyVarPtr)) {
+    } else if (TclIsVarArray(&dummyVar) && !TclIsVarUndefined(&dummyVar)) {
 	/*
 	 * If the variable is an array, delete all of its elements. This must
 	 * be done after calling and deleting the traces on the array, above
@@ -2178,16 +2255,22 @@
 	 * computed at DeleteArray.  
 	 */
 	
-	DeleteArray(iPtr, part1, dummyVarPtr, (flags 
+	DeleteArray(iPtr, part1, (Var *) &dummyVar, (flags 
 		& (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY))
 		| TCL_TRACE_UNSETS);
+    } else if (TclIsVarLink(&dummyVar)) {
+	/*
+	 * For global/upvar variables referenced in procedures, decrement the 
+	 * reference count on the variable referred to, and free the
+	 * referenced variable if it's no longer needed.
+	 */
+	Var *linkPtr = dummyVar.value.linkPtr;
+	if (TclIsVarInHash(linkPtr)) {
+	    VarHashRefCount(linkPtr)--;
+	    TclCleanupVar(linkPtr, NULL);
+	}
     }
 
-    if (dummyVarPtr == varPtr) {
-	TclSetVarUndefined(varPtr);
-	TclSetVarScalar(varPtr);
-    }
-    
     /*
      * If the variable was a namespace variable, decrement its reference
      * count.
@@ -2195,7 +2278,7 @@
 
     if (TclIsVarNamespaceVar(varPtr)) {
 	TclClearVarNamespaceVar(varPtr);
-	varPtr->refCount--;
+	VarHashRefCount(varPtr)--;
     }
 }
 
@@ -2414,16 +2497,20 @@
 	if (varPtr == NULL) {
 	    return TCL_ERROR;
 	}
-	varPtr->refCount++;
-	if (arrayPtr != NULL) {
-	    arrayPtr->refCount++;
+	if (TclIsVarInHash(varPtr)) {
+	    VarHashRefCount(varPtr)++;
+	}
+	if (arrayPtr && TclIsVarInHash(arrayPtr)) {
+	    VarHashRefCount(arrayPtr)++;
 	}
 	part1 = TclGetString(objv[1]);
 	varValuePtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1, NULL,
 		TCL_LEAVE_ERR_MSG);
-	varPtr->refCount--;
-	if (arrayPtr != NULL) {
-	    arrayPtr->refCount--;
+	if (TclIsVarInHash(varPtr)) {
+	    VarHashRefCount(varPtr)--;
+	}
+	if (arrayPtr && TclIsVarInHash(arrayPtr)) {
+	    VarHashRefCount(arrayPtr)--;
 	}
 
 	if (varValuePtr == NULL) {
@@ -2546,7 +2633,7 @@
      * array get, etc.
      */
 
-    if (varPtr != NULL && varPtr->tracePtr != NULL
+    if (varPtr && (varPtr->flags & VAR_TRACED_ARRAY)
 	    && (TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr))) {
 	if (TCL_ERROR == TclCallVarTraces(iPtr, arrayPtr, varPtr, varName,
 		NULL, (TCL_LEAVE_ERR_MSG|TCL_NAMESPACE_ONLY|TCL_GLOBAL_ONLY|
@@ -2586,7 +2673,7 @@
 	    Var *varPtr2;
 
 	    if (searchPtr->nextEntry != NULL) {
-		varPtr2 = (Var *) Tcl_GetHashValue(searchPtr->nextEntry);
+		varPtr2 = VarHashGetValue(searchPtr->nextEntry);
 		if (!TclIsVarUndefined(varPtr2)) {
 		    break;
 		}
@@ -2614,10 +2701,16 @@
 	if (searchPtr == NULL) {
 	    return TCL_ERROR;
 	}
-	if (varPtr->searchPtr == searchPtr) {
-	    varPtr->searchPtr = searchPtr->nextPtr;
+	hPtr = Tcl_FindHashEntry(&iPtr->varSearches,(char *) varPtr);
+	if (searchPtr == Tcl_GetHashValue(hPtr)) {
+	    if (searchPtr->nextPtr) {
+		Tcl_SetHashValue(hPtr, searchPtr->nextPtr);
+	    } else {
+		varPtr->flags &= ~VAR_SEARCH_ACTIVE;
+		Tcl_DeleteHashEntry(hPtr);	    
+	    }
 	} else {
-	    for (prevPtr=varPtr->searchPtr ;; prevPtr=prevPtr->nextPtr) {
+	    for (prevPtr=Tcl_GetHashValue(hPtr) ;; prevPtr=prevPtr->nextPtr) {
 		if (prevPtr->nextPtr == searchPtr) {
 		    prevPtr->nextPtr = searchPtr->nextPtr;
 		    break;
@@ -2630,6 +2723,7 @@
     case ARRAY_NEXTELEMENT: {
 	ArraySearch *searchPtr;
 	Tcl_HashEntry *hPtr;
+	Var *varPtr2;
 
 	if (objc != 4) {
 	    Tcl_WrongNumArgs(interp, 2, objv, "arrayName searchId");
@@ -2643,8 +2737,6 @@
 	    return TCL_ERROR;
 	}
 	while (1) {
-	    Var *varPtr2;
-
 	    hPtr = searchPtr->nextEntry;
 	    if (hPtr == NULL) {
 		hPtr = Tcl_NextHashEntry(&searchPtr->search);
@@ -2654,17 +2746,18 @@
 	    } else {
 		searchPtr->nextEntry = NULL;
 	    }
-	    varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
+	    varPtr2 = VarHashGetValue(hPtr);
 	    if (!TclIsVarUndefined(varPtr2)) {
 		break;
 	    }
 	}
 	Tcl_SetObjResult(interp, Tcl_NewStringObj(
-		Tcl_GetHashKey(varPtr->value.tablePtr, hPtr), -1));
+		VarHashGetKey(varPtr2), -1));
 	break;
     }
     case ARRAY_STARTSEARCH: {
 	ArraySearch *searchPtr;
+	int new;
 
 	if (objc != 3) {
 	    Tcl_WrongNumArgs(interp, 2, objv, "arrayName");
@@ -2674,21 +2767,25 @@
 	    goto error;
 	}
 	searchPtr = (ArraySearch *) ckalloc(sizeof(ArraySearch));
-	if (varPtr->searchPtr == NULL) {
+	hPtr = Tcl_CreateHashEntry(&iPtr->varSearches,
+		(char *) varPtr, &new);
+	if (new) {
 	    searchPtr->id = 1;
 	    Tcl_AppendResult(interp, "s-1-", varName, NULL);
+	    varPtr->flags |= VAR_SEARCH_ACTIVE;
+	    searchPtr->nextPtr = NULL;
 	} else {
 	    char string[TCL_INTEGER_SPACE];
 
-	    searchPtr->id = varPtr->searchPtr->id + 1;
+	    searchPtr->id = ((ArraySearch *) Tcl_GetHashValue(hPtr))->id + 1;
 	    TclFormatInt(string, searchPtr->id);
 	    Tcl_AppendResult(interp, "s-", string, "-", varName, NULL);
+	    searchPtr->nextPtr = Tcl_GetHashValue(hPtr);
 	}
 	searchPtr->varPtr = varPtr;
-	searchPtr->nextEntry = Tcl_FirstHashEntry(varPtr->value.tablePtr,
+	searchPtr->nextEntry = VarHashFirstEntry(varPtr->value.tablePtr,
 		&searchPtr->search);
-	searchPtr->nextPtr = varPtr->searchPtr;
-	varPtr->searchPtr = searchPtr;
+	Tcl_SetHashValue(hPtr, searchPtr);
 	break;
     }
 
@@ -2725,11 +2822,10 @@
 	TclNewObj(nameLstPtr);
 	Tcl_IncrRefCount(nameLstPtr);
 	if ((pattern != NULL) && TclMatchIsTrivial(pattern)) {
-	    hPtr = Tcl_FindHashEntry(varPtr->value.tablePtr, pattern);
-	    if (hPtr == NULL) {
+	    varPtr2 = VarHashFindVar(varPtr->value.tablePtr, pattern);
+	    if (varPtr2 == NULL) {
 		goto searchDone;
 	    }
-	    varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
 	    if (TclIsVarUndefined(varPtr2)) {
 		goto searchDone;
 	    }
@@ -2741,13 +2837,12 @@
 	    }
 	    goto searchDone;
 	}
-	for (hPtr=Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
-		hPtr!=NULL ; hPtr=Tcl_NextHashEntry(&search)) {
-	    varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
+	for (varPtr2=VarHashFirstVar(varPtr->value.tablePtr, &search);
+		varPtr2!=NULL ; varPtr2=VarHashNextVar(&search)) {
 	    if (TclIsVarUndefined(varPtr2)) {
 		continue;
 	    }
-	    name = Tcl_GetHashKey(varPtr->value.tablePtr, hPtr);
+	    name = VarHashGetKey(varPtr2);
 	    if ((objc == 4) && !Tcl_StringMatch(name, pattern)) {
 		continue;	/* element name doesn't match pattern */
 	    }
@@ -2767,7 +2862,9 @@
 	 * while we're working.
 	 */
 
-	varPtr->refCount++;
+	if (TclIsVarInHash(varPtr)) {
+	    VarHashRefCount(varPtr)++;
+	}
 
 	/*
 	 * Get the array values corresponding to each element name
@@ -2808,13 +2905,17 @@
 		goto errorInArrayGet;
 	    }
 	}
-	varPtr->refCount--;
+	if (TclIsVarInHash(varPtr)) {
+	    VarHashRefCount(varPtr)--;
+	}
 	Tcl_SetObjResult(interp, tmpResPtr);
 	TclDecrRefCount(nameLstPtr);
 	break;
 
     errorInArrayGet:
-	varPtr->refCount--;
+	if (TclIsVarInHash(varPtr)) {
+	    VarHashRefCount(varPtr)--;
+	}
 	TclDecrRefCount(nameLstPtr);
 	TclDecrRefCount(tmpResPtr);	/* free unneeded temp result */
 	return result;
@@ -2852,9 +2953,9 @@
 	TclNewObj(resultPtr);
 	if (((enum options) mode)==OPT_GLOB && pattern!=NULL &&
 		TclMatchIsTrivial(pattern)) {
-	    hPtr = Tcl_FindHashEntry(varPtr->value.tablePtr, pattern);
-	    if ((hPtr != NULL) &&
-		    !TclIsVarUndefined((Var *) Tcl_GetHashValue(hPtr))) {
+	    varPtr2 = VarHashFindVar(varPtr->value.tablePtr, pattern);
+	    if ((varPtr2 != NULL) &&
+		    !TclIsVarUndefined(varPtr2)) {
 		result = Tcl_ListObjAppendElement(interp, resultPtr,
 			Tcl_NewStringObj(pattern, -1));
 		if (result != TCL_OK) {
@@ -2865,13 +2966,12 @@
 	    Tcl_SetObjResult(interp, resultPtr);
 	    return TCL_OK;
 	}
-	for (hPtr=Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
-		hPtr!=NULL ; hPtr=Tcl_NextHashEntry(&search)) {
-	    varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
+	for (varPtr2=VarHashFirstVar(varPtr->value.tablePtr, &search);
+		varPtr2!=NULL ; varPtr2=VarHashNextVar(&search)) {
 	    if (TclIsVarUndefined(varPtr2)) {
 		continue;
 	    }
-	    name = Tcl_GetHashKey(varPtr->value.tablePtr, hPtr);
+	    name = VarHashGetKey(varPtr2);
 	    if (objc > 3) {
 		switch ((enum options) mode) {
 		case OPT_EXACT:
@@ -2934,20 +3034,19 @@
 	} else {
 	    pattern = TclGetString(objv[3]);
 	    if (TclMatchIsTrivial(pattern)) {
-		hPtr = Tcl_FindHashEntry(varPtr->value.tablePtr, pattern);
-		if (hPtr != NULL &&
-			!TclIsVarUndefined((Var *)Tcl_GetHashValue(hPtr))){
+		varPtr2 = VarHashFindVar(varPtr->value.tablePtr, pattern);
+		if (varPtr2 != NULL &&
+			!TclIsVarUndefined(varPtr2)) {
 		    return TclObjUnsetVar2(interp, varNamePtr, pattern, 0);
 		}
 		return TCL_OK;
 	    }
-	    for (hPtr=Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
-		    hPtr!=NULL ; hPtr=Tcl_NextHashEntry(&search)) {
-		varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
+	    for (varPtr2=VarHashFirstVar(varPtr->value.tablePtr, &search);
+		    varPtr2!=NULL ; varPtr2=VarHashNextVar(&search)) {
 		if (TclIsVarUndefined(varPtr2)) {
 		    continue;
 		}
-		name = Tcl_GetHashKey(varPtr->value.tablePtr, hPtr);
+		name = VarHashGetKey(varPtr2);
 		if (Tcl_StringMatch(name, pattern) &&
 			TclObjUnsetVar2(interp, varNamePtr, name,
 				0) != TCL_OK) {
@@ -2975,9 +3074,8 @@
 	 */
 
 	if (!notArray) {
-	    for (hPtr=Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
-		    hPtr!=NULL ; hPtr=Tcl_NextHashEntry(&search)) {
-		varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
+	    for (varPtr2=VarHashFirstVar(varPtr->value.tablePtr, &search);
+		    varPtr2!=NULL ; varPtr2=VarHashNextVar(&search)) {
 		if (TclIsVarUndefined(varPtr2)) {
 		    continue;
 		}
@@ -2995,7 +3093,7 @@
 	    goto error;
 	}
 
-	stats = Tcl_HashStats(varPtr->value.tablePtr);
+	stats = Tcl_HashStats((Tcl_HashTable *) varPtr->value.tablePtr);
 	if (stats != NULL) {
 	    Tcl_SetObjResult(interp, Tcl_NewStringObj(stats, -1));
 	    ckfree((void *)stats);
@@ -3180,9 +3278,9 @@
     }
     TclSetVarArray(varPtr);
     TclClearVarUndefined(varPtr);
-    varPtr->value.tablePtr = (Tcl_HashTable *)
-	    ckalloc(sizeof(Tcl_HashTable));
-    Tcl_InitHashTable(varPtr->value.tablePtr, TCL_STRING_KEYS);
+    varPtr->value.tablePtr = (TclVarHashTable *)
+	    ckalloc(sizeof(TclVarHashTable));    
+    TclInitVarHashTable(varPtr->value.tablePtr, TclGetVarNsPtr(varPtr));
     return TCL_OK;
 }
 
@@ -3259,7 +3357,9 @@
      */
 
     if (index < 0) {
-	if (((arrayPtr ? arrayPtr->nsPtr : otherPtr->nsPtr) == NULL)
+	if (((arrayPtr
+		     ? (TclIsVarInHash(arrayPtr) && TclGetVarNsPtr(arrayPtr))
+		     : (TclIsVarInHash(otherPtr) && TclGetVarNsPtr(otherPtr))) == 0)
 		&& ((myFlags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY))
 			|| (varFramePtr == NULL)
 			|| !HasLocalVars(varFramePtr)
@@ -3316,8 +3416,8 @@
 	if (!HasLocalVars(varFramePtr)) {
 	    Tcl_Panic("ObjMakeUpvar called with an index outside from a proc");
 	}
-	varPtr = &(varFramePtr->compiledLocals[index]);
-	myName = varPtr->name;
+	varPtr = (Var *) &(varFramePtr->compiledLocals[index]);
+	myName = localVarNames(iPtr->varFramePtr)[index];
     } else {
 	/*
 	 * Do not permit the new variable to look like an array reference, as
@@ -3364,7 +3464,7 @@
 	return TCL_ERROR;
     }
 
-    if (varPtr->tracePtr != NULL) {
+    if (TclIsVarTraced(varPtr)) {
 	Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName,
 		"\" has traces: can't use for upvar", NULL);
 	return TCL_ERROR;
@@ -3381,9 +3481,11 @@
 	    if (linkPtr == otherPtr) {
 		return TCL_OK;
 	    }
-	    linkPtr->refCount--;
-	    if (TclIsVarUndefined(linkPtr)) {
-		TclCleanupVar(linkPtr, NULL);
+	    if (TclIsVarInHash(linkPtr)) {
+		VarHashRefCount(linkPtr)--;		
+		if (TclIsVarUndefined(linkPtr)) {
+		    TclCleanupVar(linkPtr, NULL);
+		}
 	    }
 	} else {
 	    Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName,
@@ -3394,7 +3496,9 @@
     TclSetVarLink(varPtr);
     TclClearVarUndefined(varPtr);
     varPtr->value.linkPtr = otherPtr;
-    otherPtr->refCount++;
+    if (TclIsVarInHash(otherPtr)) {
+	VarHashRefCount(otherPtr)++;
+    }
     return TCL_OK;
 }
 
@@ -3514,24 +3618,31 @@
     Interp *iPtr = (Interp *) interp;
     register Var *varPtr = (Var *) variable;
     char *name;
+    Namespace *nsPtr;
 
     /*
      * Add the full name of the containing namespace (if any), followed by the
      * "::" separator, then the variable name.
      */
 
-    if (varPtr != NULL) {
+    if (varPtr) {
 	if (!TclIsVarArrayElement(varPtr)) {
-	    if (varPtr->nsPtr != NULL) {
-		Tcl_AppendToObj(objPtr, varPtr->nsPtr->fullName, -1);
-		if (varPtr->nsPtr != iPtr->globalNsPtr) {
+	    nsPtr = TclGetVarNsPtr(varPtr);
+	    if (nsPtr) {
+		Tcl_AppendToObj(objPtr, nsPtr->fullName, -1);
+		if (nsPtr != iPtr->globalNsPtr) {
 		    Tcl_AppendToObj(objPtr, "::", 2);
 		}
 	    }
-	    if (varPtr->name != NULL) {
-		Tcl_AppendToObj(objPtr, varPtr->name, -1);
-	    } else if (varPtr->hPtr != NULL) {
-		name = Tcl_GetHashKey(varPtr->hPtr->tablePtr, varPtr->hPtr);
+	    if (TclIsVarInHash(varPtr)) {
+		if (!TclIsVarDeadHash(varPtr)) {
+		    name = VarHashGetKey(varPtr);
+		    Tcl_AppendToObj(objPtr, name, -1);
+		}
+	    } else if (iPtr->varFramePtr->procPtr) {
+		int index = varPtr - iPtr->varFramePtr->compiledLocals;
+
+		name = localVarNames(iPtr->varFramePtr)[index];;
 		Tcl_AppendToObj(objPtr, name, -1);
 	    }
 	}
@@ -3705,7 +3816,7 @@
 
 	if (!TclIsVarNamespaceVar(varPtr)) {
 	    TclSetVarNamespaceVar(varPtr);
-	    varPtr->refCount++;
+	    VarHashRefCount(varPtr)++;
 	}
 
 	/*
@@ -3832,44 +3943,6 @@
 /*
  *----------------------------------------------------------------------
  *
- * NewVar --
- *
- *	Create a new heap-allocated variable that will eventually be entered
- *	into a hashtable.
- *
- * Results:
- *	The return value is a pointer to the new variable structure. It is
- *	marked as a scalar variable (and not a link or array variable). Its
- *	value initially is NULL. The variable is not part of any hash table
- *	yet. Since it will be in a hashtable and not in a call frame, its name
- *	field is set NULL. It is initially marked as undefined.
- *
- * Side effects:
- *	Storage gets allocated.
- *
- *----------------------------------------------------------------------
- */
-
-static Var *
-NewVar(void)
-{
-    register Var *varPtr;
-
-    varPtr = (Var *) ckalloc(sizeof(Var));
-    varPtr->value.objPtr = NULL;
-    varPtr->name = NULL;
-    varPtr->nsPtr = NULL;
-    varPtr->hPtr = NULL;
-    varPtr->refCount = 0;
-    varPtr->tracePtr = NULL;
-    varPtr->searchPtr = NULL;
-    varPtr->flags = (VAR_SCALAR | VAR_UNDEFINED | VAR_IN_HASHTABLE);
-    return varPtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
  * SetArraySearchObj --
  *
  *	This function converts the given tcl object into one that has the
@@ -3966,10 +4039,12 @@
 				 * decimal number and "var" is a variable
 				 * name. */
 {
+    Interp *iPtr = (Interp *) interp;
     register char *string;
     register size_t offset;
     int id;
     ArraySearch *searchPtr;
+    
 
     /*
      * Parse the id.
@@ -4012,10 +4087,15 @@
      * this list every time.
      */
 
-    for (searchPtr = varPtr->searchPtr; searchPtr != NULL;
-	    searchPtr = searchPtr->nextPtr) {
-	if (searchPtr->id == id) {
-	    return searchPtr;
+    if (varPtr->flags & VAR_SEARCH_ACTIVE) {
+	Tcl_HashEntry *hPtr =
+	        Tcl_FindHashEntry(&iPtr->varSearches,(char *) varPtr);
+	
+	for (searchPtr = (ArraySearch *) Tcl_GetHashValue(hPtr);
+	         searchPtr != NULL; searchPtr = searchPtr->nextPtr) {
+	    if (searchPtr->id == id) {
+		return searchPtr;
+	    }
 	}
     }
     Tcl_AppendResult(interp, "couldn't find search \"", string, "\"", NULL);
@@ -4042,16 +4122,23 @@
 
 static void
 DeleteSearches(
+    Interp *iPtr,
     register Var *arrayVarPtr)	/* Variable whose searches are to be
 				 * deleted. */
 {
-    ArraySearch *searchPtr;
+    ArraySearch *searchPtr, *nextPtr;
+    Tcl_HashEntry *sPtr;
 
-    while (arrayVarPtr->searchPtr != NULL) {
-	searchPtr = arrayVarPtr->searchPtr;
-	arrayVarPtr->searchPtr = searchPtr->nextPtr;
-	ckfree((char *) searchPtr);
-    }
+    if (arrayVarPtr->flags & VAR_SEARCH_ACTIVE) {
+	sPtr = Tcl_FindHashEntry(&iPtr->varSearches, (char *) arrayVarPtr);
+	for (searchPtr = (ArraySearch *) Tcl_GetHashValue(sPtr);
+	         searchPtr != NULL; searchPtr = nextPtr) {
+	    nextPtr = searchPtr->nextPtr;
+	    ckfree((char *) searchPtr);
+	}
+	arrayVarPtr->flags &= ~VAR_SEARCH_ACTIVE;
+	Tcl_DeleteHashEntry(sPtr);
+    }	
 }
 
 /*
@@ -4076,12 +4163,12 @@
 TclDeleteNamespaceVars(
     Namespace *nsPtr)
 {
-    Tcl_HashTable *tablePtr = &nsPtr->varTable;
+    TclVarHashTable *tablePtr = &nsPtr->varTable;
     Tcl_Interp *interp = nsPtr->interp;
     Interp *iPtr = (Interp *)interp;
     Tcl_HashSearch search;
-    Tcl_HashEntry *hPtr;
     int flags = 0;
+    Var *varPtr;
 
     /*
      * Determine what flags to pass to the trace callback functions.
@@ -4093,30 +4180,36 @@
 	flags = TCL_NAMESPACE_ONLY;
     }
 
-    for (hPtr = Tcl_FirstHashEntry(tablePtr, &search);  hPtr != NULL;
-	 hPtr = Tcl_FirstHashEntry(tablePtr, &search)) {
-	register Var *varPtr = (Var *) Tcl_GetHashValue(hPtr);
-	varPtr->refCount++;	/* Make sure we get to remove from hash */
-	UnsetVarStruct(varPtr, NULL, iPtr, /* part1 */ NULL, NULL, flags, 1);
-	varPtr->refCount--;
+    for (varPtr = VarHashFirstVar(tablePtr, &search);  varPtr != NULL;
+	 varPtr = VarHashFirstVar(tablePtr, &search)) {
+	VarHashRefCount(varPtr)++;	/* Make sure we get to remove from hash */
+	UnsetVarStruct(varPtr, NULL, iPtr, /* part1 */ NULL, NULL, flags);
 
 	/*
 	 * Remove the variable from the table and force it undefined in case
 	 * an unset trace brought it back from the dead.
 	 */
 
-	Tcl_DeleteHashEntry(hPtr);
-	varPtr->hPtr = NULL;
+	VarHashDeleteEntry(varPtr);
 	TclSetVarUndefined(varPtr);
 	TclSetVarScalar(varPtr);
-	while (varPtr->tracePtr != NULL) {
-	    VarTrace *tracePtr = varPtr->tracePtr;
-	    varPtr->tracePtr = tracePtr->nextPtr;
-	    Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC);
+	if (TclIsVarTraced(varPtr)) {
+	    Tcl_HashEntry *tPtr = Tcl_FindHashEntry(&iPtr->varTraces,
+		    (char *) varPtr);
+	    VarTrace *tracePtr = (VarTrace *) Tcl_GetHashValue(tPtr);
+	    while (tracePtr) {
+		VarTrace *prevPtr = tracePtr;
+
+		tracePtr = tracePtr->nextPtr;
+		Tcl_EventuallyFree((ClientData) prevPtr, TCL_DYNAMIC);
+	    }
+	    Tcl_DeleteHashEntry(tPtr);
+	    varPtr->flags &= ~VAR_ALL_TRACES;
 	}
+	VarHashRefCount(varPtr)--;
 	TclCleanupVar(varPtr, NULL);
     }
-    Tcl_DeleteHashTable(tablePtr);
+    VarHashDeleteTable(tablePtr);
 }
 
 /*
@@ -4142,12 +4235,11 @@
 void
 TclDeleteVars(
     Interp *iPtr,		/* Interpreter to which variables belong. */
-    Tcl_HashTable *tablePtr)	/* Hash table containing variables to
+    TclVarHashTable *tablePtr)	/* Hash table containing variables to
 				 * delete. */
 {
     Tcl_Interp *interp = (Tcl_Interp *) iPtr;
     Tcl_HashSearch search;
-    Tcl_HashEntry *hPtr;
     register Var *varPtr;
     int flags;
     Namespace *currNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
@@ -4163,24 +4255,17 @@
 	flags |= TCL_NAMESPACE_ONLY;
     }
 
-    for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL;
-	    hPtr = Tcl_NextHashEntry(&search)) {
-	varPtr = (Var *) Tcl_GetHashValue(hPtr);
-
-	UnsetVarStruct(varPtr, NULL, iPtr, NULL, NULL, flags, 0);
-	varPtr->hPtr = NULL;
-
+    for (varPtr = VarHashFirstVar(tablePtr, &search); varPtr != NULL;
+	    varPtr = VarHashNextVar(&search)) {
 	/*
-	 * Recycle the variable's memory space if there aren't any upvar's
-	 * pointing to it. If there are upvars to this variable, then the
-	 * variable will get freed when the last upvar goes away.
+	 * Lie about the validity of the hashtable entry. In this way the
+	 * variables will be deleted by VarHashDeleteTable.
 	 */
-
-	if (varPtr->refCount == 0) {
-	    ckfree((char *) varPtr); /* this Var must be VAR_IN_HASHTABLE */
-	}
+	
+	VarHashInvalidateEntry(varPtr);
+	UnsetVarStruct(varPtr, NULL, iPtr, NULL, NULL, flags);
     }
-    Tcl_DeleteHashTable(tablePtr);
+    VarHashDeleteTable(tablePtr);
 }
 
 /*
@@ -4213,77 +4298,15 @@
 {
     register Var *varPtr;
     int numLocals, i;
-
+    char *name;
+    
     numLocals = framePtr->numCompiledLocals;
     varPtr = framePtr->compiledLocals;
+    name = localVarNames(framePtr)[0];
     for (i=0 ; i<numLocals ; i++) {
-#if 1
-	UnsetVarStruct(varPtr, NULL, iPtr, varPtr->name, NULL, TCL_TRACE_UNSETS, 0);
+	UnsetVarStruct(varPtr, NULL, iPtr, name, NULL, TCL_TRACE_UNSETS);
 	varPtr++;
-#else
-    if (!TclIsVarUntraced(varPtr)) {
-	ActiveVarTrace *activePtr;
-	
-	varPtr->flags &= ~VAR_TRACE_ACTIVE;
-	TclCallVarTraces(iPtr, NULL, varPtr, varPtr->name, NULL,
-		TCL_TRACE_UNSETS, /* leaveErrMsg */ 0);
-	while (varPtr->tracePtr != NULL) {
-	    VarTrace *tracePtr = varPtr->tracePtr;
-	    varPtr->tracePtr = tracePtr->nextPtr;
-	    Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC);
-	}
-	for (activePtr = iPtr->activeVarTracePtr;  activePtr != NULL;
-		activePtr = activePtr->nextPtr) {
-	    if (activePtr->varPtr == varPtr) {
-		activePtr->nextTracePtr = NULL;
-	    }
-	}
-    }
-
-    if (TclIsVarScalar(varPtr)
-	    && (varPtr->value.objPtr != NULL)) {
-	/*
-	 * Decrement the ref count of the var's value
-	 */
-	
-	Tcl_Obj *objPtr = varPtr->value.objPtr;
-	TclDecrRefCount(objPtr);
-	varPtr->value.objPtr = NULL;
-    } else if (TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) {
-	/*
-	 * If the variable is an array, delete all of its elements. This must
-	 * be done after calling the traces on the array, above (that's the
-	 * way traces are defined). If the array is traced, its name is
-	 * already in part1. If not, and the name is required for some
-	 * element, it will be computed at DeleteArray. 
-	 */
-	
-	DeleteArray(iPtr, varPtr->name, varPtr, TCL_TRACE_UNSETS);
-    } else if (TclIsVarLink(varPtr)) {
-	/*
-	 * For global/upvar variables referenced in procedures, decrement the 
-	 * reference count on the variable referred to, and free the
-	 * referenced variable if it's no longer needed.
-	 */
-	Var *linkPtr = varPtr->value.linkPtr;
-	linkPtr->refCount--;
-	if ((linkPtr->refCount == 0) && TclIsVarUndefined(linkPtr)
-		&& (linkPtr->tracePtr == NULL)
-		&& (linkPtr->flags & VAR_IN_HASHTABLE)) {
-	    if (linkPtr->hPtr != NULL) {
-		Tcl_DeleteHashEntry(linkPtr->hPtr);
-	    }
-	    ckfree((char *) linkPtr);
-	}
-    }
-
-    TclSetVarUndefined(varPtr);
-    TclSetVarScalar(varPtr);
-    varPtr->tracePtr = NULL;
-    varPtr->searchPtr = NULL;
-
-    varPtr++;
-#endif
+	name++;
     }
 }
 
@@ -4319,44 +4342,57 @@
 				 * TCL_NAMESPACE_ONLY or TCL_GLOBAL_ONLY. */
 {
     Tcl_HashSearch search;
-    register Tcl_HashEntry *hPtr;
+    Tcl_HashEntry *tPtr;
     register Var *elPtr;
     ActiveVarTrace *activePtr;
     Tcl_Obj *objPtr, *arrayNamePtr = NULL;
+    VarTrace *tracePtr;
 
-    DeleteSearches(varPtr);
-    for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
-	    hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
-	elPtr = (Var *) Tcl_GetHashValue(hPtr);
+    if (varPtr->flags & VAR_SEARCH_ACTIVE) {
+	DeleteSearches(iPtr, varPtr);
+    }
+    for (elPtr = VarHashFirstVar(varPtr->value.tablePtr, &search);
+	    elPtr != NULL; elPtr = VarHashNextVar(&search)) {
 	if (TclIsVarScalar(elPtr) && (elPtr->value.objPtr != NULL)) {
 	    objPtr = elPtr->value.objPtr;
 	    TclDecrRefCount(objPtr);
 	    elPtr->value.objPtr = NULL;
 	}
-	elPtr->hPtr = NULL;
-	if (elPtr->tracePtr != NULL) {
+
+	/*
+	 * Lie about the validity of the hashtable entry. In this way the
+	 * variables will be deleted by VarHashDeleteTable.
+	 */
+	
+	VarHashInvalidateEntry(elPtr);
+	if (TclIsVarTraced(elPtr)) {
 	    /*
 	     * Compute the array name if it was not supplied
 	     */
 
-	    if (arrayName == NULL) {
-		Tcl_Interp *interp = varPtr->nsPtr->interp;
-		TclNewObj(arrayNamePtr);
-		Tcl_IncrRefCount(arrayNamePtr);
-		Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, arrayNamePtr);
-		arrayName = TclGetString(arrayNamePtr);
-	    }
-	    
-	    elPtr->flags &= ~VAR_TRACE_ACTIVE;
-	    TclCallVarTraces(iPtr, NULL, elPtr, arrayName,
-		    Tcl_GetHashKey(varPtr->value.tablePtr, hPtr), flags,
-		    /* leaveErrMsg */ 0);
-	    while (elPtr->tracePtr != NULL) {
-		VarTrace *tracePtr = elPtr->tracePtr;
+	    if (elPtr->flags & VAR_TRACED_UNSET) {
+		elPtr->flags &= ~VAR_TRACE_ACTIVE;
+		if (arrayName == NULL) {
+		    Tcl_Interp *interp = (Tcl_Interp *) iPtr;;
+		    TclNewObj(arrayNamePtr);
+		    Tcl_IncrRefCount(arrayNamePtr);
+		    Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, arrayNamePtr);
+		    arrayName = TclGetString(arrayNamePtr);
+		}
+		TclCallVarTraces(iPtr, NULL, elPtr, arrayName,
+			VarHashGetKey(elPtr), flags,
+			/* leaveErrMsg */ 0);
+	    }
+	    tPtr = Tcl_FindHashEntry(&iPtr->varTraces, (char *) elPtr);
+	    tracePtr = (VarTrace *) Tcl_GetHashValue(tPtr);
+	    while (tracePtr) {
+		VarTrace *prevPtr = tracePtr;
 
-		elPtr->tracePtr = tracePtr->nextPtr;
-		Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC);
+		tracePtr = tracePtr->nextPtr;
+		Tcl_EventuallyFree((ClientData) prevPtr, TCL_DYNAMIC);
 	    }
+	    Tcl_DeleteHashEntry(tPtr);
+	    elPtr->flags &= ~VAR_ALL_TRACES;
 	    for (activePtr = iPtr->activeVarTracePtr; activePtr != NULL;
 		    activePtr = activePtr->nextPtr) {
 		if (activePtr->varPtr == elPtr) {
@@ -4376,16 +4412,13 @@
 
 	if (TclIsVarNamespaceVar(elPtr)) {
 	    TclClearVarNamespaceVar(elPtr);
-	    elPtr->refCount--;
-	}
-	if (elPtr->refCount == 0) {
-	    ckfree((char *) elPtr); /* element Vars are VAR_IN_HASHTABLE */
+	    VarHashRefCount(elPtr)--;
 	}
     }
     if (arrayNamePtr) {
 	Tcl_DecrRefCount(arrayNamePtr);
     }
-    Tcl_DeleteHashTable(varPtr->value.tablePtr);
+    VarHashDeleteTable(varPtr->value.tablePtr);
     ckfree((char *) varPtr->value.tablePtr);
 }
 
@@ -4418,25 +4451,28 @@
     Var *arrayPtr)		/* Array that contains the variable, or NULL
 				 * if this variable isn't an array element. */
 {
-    if (TclIsVarUndefined(varPtr) && (varPtr->refCount == 0)
-	    && (varPtr->tracePtr == NULL)
-	    && (varPtr->flags & VAR_IN_HASHTABLE)) {
-	if (varPtr->hPtr != NULL) {
-	    Tcl_DeleteHashEntry(varPtr->hPtr);
+    if (TclIsVarUndefined(varPtr) && TclIsVarInHash(varPtr)
+	    && !TclIsVarTraced(varPtr)
+	    && (VarHashRefCount(varPtr) == (TclIsVarDeadHash(varPtr) == 0))) {
+	if (VarHashRefCount(varPtr) == 0) {
+	    ckfree((char *) varPtr);
+	} else {
+	    VarHashDeleteEntry(varPtr);
 	}
-	ckfree((char *) varPtr);
     }
     if (arrayPtr != NULL) {
-	if (TclIsVarUndefined(arrayPtr) && (arrayPtr->refCount == 0)
-		&& (arrayPtr->tracePtr == NULL)
-		&& (arrayPtr->flags & VAR_IN_HASHTABLE)) {
-	    if (arrayPtr->hPtr != NULL) {
-		Tcl_DeleteHashEntry(arrayPtr->hPtr);
+	if (TclIsVarUndefined(arrayPtr) && TclIsVarInHash(arrayPtr)
+		&& !TclIsVarTraced(arrayPtr)
+		&& (VarHashRefCount(arrayPtr) == (TclIsVarDeadHash(arrayPtr) == 0))) {
+	    if (VarHashRefCount(arrayPtr) == 0) {
+		ckfree((char *) arrayPtr);
+	    } else {
+		VarHashDeleteEntry(arrayPtr);
 	    }
-	    ckfree((char *) arrayPtr);
 	}
     }
 }
+
 /*
  *----------------------------------------------------------------------
  *
@@ -4534,9 +4570,11 @@
 {
     register Var *varPtr = objPtr->internalRep.twoPtrValue.ptr2;
 
-    varPtr->refCount--;
-    if (TclIsVarUndefined(varPtr) && (varPtr->refCount == 0)) {
-	TclCleanupVar(varPtr, NULL);
+    if (TclIsVarInHash(varPtr)) {
+	varPtr->refCount--;
+	if (TclIsVarUndefined(varPtr) && (varPtr->refCount == 0)) {
+	    TclCleanupVar(varPtr, NULL);
+	}
     }
 }
 
@@ -4550,7 +4588,9 @@
 
     dupPtr->internalRep.twoPtrValue.ptr1 = nsPtr;
     dupPtr->internalRep.twoPtrValue.ptr2 = varPtr;
-    varPtr->refCount++;
+    if (TclIsVarInHash(varPtr)) {
+	varPtr->refCount++;
+    }
     dupPtr->typePtr = &tclNsVarNameType;
 }
 #endif
@@ -4636,6 +4676,223 @@
 }
 
 /*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_FindNamespaceVar -- MOVED OVER from tclNamesp.c
+ *
+ *	Searches for a namespace variable, a variable not local to a
+ *	procedure. The variable can be either a scalar or an array, but may
+ *	not be an element of an array.
+ *
+ * Results:
+ *	Returns a token for the variable if it is found. Otherwise, if it
+ *	can't be found or there is an error, returns NULL and leaves an error
+ *	message in the interpreter's result object if "flags" contains
+ *	TCL_LEAVE_ERR_MSG.
+ *
+ * Side effects:
+ *	None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tcl_Var
+Tcl_FindNamespaceVar(
+    Tcl_Interp *interp,		/* The interpreter in which to find the
+				 * variable. */
+    const char *name,		/* Variable's name. If it starts with "::",
+				 * will be looked up in global namespace.
+				 * Else, looked up first in contextNsPtr
+				 * (current namespace if contextNsPtr is
+				 * NULL), then in global namespace. */
+    Tcl_Namespace *contextNsPtr,/* Ignored if TCL_GLOBAL_ONLY flag set.
+				 * Otherwise, points to namespace in which to
+				 * resolve name. If NULL, look up name in the
+				 * current namespace. */
+    int flags)			/* An OR'd combination of flags:
+				 * TCL_GLOBAL_ONLY (look up name only in
+				 * global namespace), TCL_NAMESPACE_ONLY (look
+				 * up only in contextNsPtr, or the current
+				 * namespace if contextNsPtr is NULL), and
+				 * TCL_LEAVE_ERR_MSG. If both TCL_GLOBAL_ONLY
+				 * and TCL_NAMESPACE_ONLY are given,
+				 * TCL_GLOBAL_ONLY is ignored. */
+{
+    Interp *iPtr = (Interp *) interp;
+    ResolverScheme *resPtr;
+    Namespace *nsPtr[2], *cxtNsPtr;
+    const char *simpleName;
+    Var *varPtr;
+    register int search;
+    int result;
+    Tcl_Var var;
+
+    /*
+     * If this namespace has a variable resolver, then give it first crack at
+     * the variable resolution. It may return a Tcl_Var value, it may signal
+     * to continue onward, or it may signal an error.
+     */
+
+    if ((flags & TCL_GLOBAL_ONLY) != 0) {
+	cxtNsPtr = (Namespace *) TclGetGlobalNamespace(interp);
+    } else if (contextNsPtr != NULL) {
+	cxtNsPtr = (Namespace *) contextNsPtr;
+    } else {
+	cxtNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
+    }
+
+    if (cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) {
+	resPtr = iPtr->resolverPtr;
+
+	if (cxtNsPtr->varResProc) {
+	    result = (*cxtNsPtr->varResProc)(interp, name,
+		    (Tcl_Namespace *) cxtNsPtr, flags, &var);
+	} else {
+	    result = TCL_CONTINUE;
+	}
+
+	while (result == TCL_CONTINUE && resPtr) {
+	    if (resPtr->varResProc) {
+		result = (*resPtr->varResProc)(interp, name,
+			(Tcl_Namespace *) cxtNsPtr, flags, &var);
+	    }
+	    resPtr = resPtr->nextPtr;
+	}
+
+	if (result == TCL_OK) {
+	    return var;
+	} else if (result != TCL_CONTINUE) {
+	    return (Tcl_Var) NULL;
+	}
+    }
+
+    /*
+     * Find the namespace(s) that contain the variable.
+     */
+
+    TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr,
+	    flags, &nsPtr[0], &nsPtr[1], &cxtNsPtr, &simpleName);
+
+    /*
+     * Look for the variable in the variable table of its namespace. Be sure
+     * to check both possible search paths: from the specified namespace
+     * context and from the global namespace.
+     */
+
+    varPtr = NULL;
+    for (search = 0;  (search < 2) && (varPtr == NULL);  search++) {
+	if ((nsPtr[search] != NULL) && (simpleName != NULL)) {
+	    varPtr = VarHashFindVar(&nsPtr[search]->varTable, simpleName);
+	}
+    }
+    if (varPtr != NULL) {
+	return (Tcl_Var) varPtr;
+    } else if (flags & TCL_LEAVE_ERR_MSG) {
+	Tcl_ResetResult(interp);
+	Tcl_AppendResult(interp, "unknown variable \"", name, "\"", NULL);
+    }
+    return (Tcl_Var) NULL;
+}
+
+/*
+ * Hash table implementation - first, just copy string key stuff
+ */
+
+void
+TclInitVarHashTable(
+    TclVarHashTable *tablePtr,
+    Namespace *nsPtr)
+{
+    Tcl_InitCustomHashTable(&tablePtr->table,
+	    TCL_CUSTOM_TYPE_KEYS, &tclVarHashKeyType);
+    tablePtr->nsPtr = nsPtr;
+}
+
+static Tcl_HashEntry *
+AllocVarEntry(
+    Tcl_HashTable *tablePtr,	/* Hash table. */
+    VOID *keyPtr)		/* Key to store in the hash table entry. */
+{
+    const char *string = (const char *) keyPtr;
+    Tcl_HashEntry *hPtr;
+    unsigned int size;
+    Var *varPtr;
+
+    size = sizeof(VarInHash) + strlen(string) - 3; /* add \0, remove 4 already in */
+    if (size < sizeof(VarInHash)) {
+	size = sizeof(VarInHash);
+    }
+    varPtr = (Var *) ckalloc(size);
+    varPtr->flags = VAR_IN_HASHTABLE;
+    varPtr->value.objPtr = NULL;
+    VarHashRefCount(varPtr) = 1;
+    hPtr = &(((VarInHash *)varPtr)->entry);
+    Tcl_SetHashValue(hPtr, varPtr);
+    strcpy(hPtr->key.string, string);
+
+    return hPtr;
+}
+
+static void
+FreeVarEntry(Tcl_HashEntry *hPtr)
+{
+    Var *varPtr = VarHashGetValue(hPtr);
+
+    if (TclIsVarUndefined(varPtr) && !TclIsVarTraced(varPtr)
+	    && (VarHashRefCount(varPtr) == 1)) {
+	ckfree((char *) varPtr);
+    } else {
+	VarHashInvalidateEntry(varPtr);
+	VarHashRefCount(varPtr)--;
+    }
+}
+
+static int
+CompareVarKeys(
+    VOID *keyPtr,		/* New key to compare. */
+    Tcl_HashEntry *hPtr)	/* Existing key to compare. */
+{
+    register const char *p1 = (const char *) keyPtr;
+    register const char *p2 = (const char *) hPtr->key.string;
+
+    return !strcmp(p1, p2);
+}
+
+static unsigned int
+HashVarKey(
+    Tcl_HashTable *tablePtr,	/* Hash table. */
+    VOID *keyPtr)		/* Key from which to compute hash value. */
+{
+    register const char *string = (const char *) keyPtr;
+    register unsigned int result;
+    register int c;
+
+    /*
+     * I tried a zillion different hash functions and asked many other people
+     * for advice. Many people had their own favorite functions, all
+     * different, but no-one had much idea why they were good ones. I chose
+     * the one below (multiply by 9 and add new character) because of the
+     * following reasons:
+     *
+     * 1. Multiplying by 10 is perfect for keys that are decimal strings, and
+     *	  multiplying by 9 is just about as good.
+     * 2. Times-9 is (shift-left-3) plus (old). This means that each
+     *	  character's bits hang around in the low-order bits of the hash value
+     *	  for ever, plus they spread fairly rapidly up to the high-order bits
+     *	  to fill out the hash value. This seems works well both for decimal
+     *	  and non-decimal strings, but isn't strong against maliciously-chosen
+     *	  keys.
+     */
+
+    result = 0;
+
+    for (c=*string++ ; c ; c=*string++) {
+	result += (result<<3) + c;
+    }
+    return result;
+}
+
+/*
  * Local Variables:
  * mode: c
  * c-basic-offset: 4