Posted to tcl by cjo at Mon Sep 11 14:01:43 GMT 2017view pretty

diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index 5a33445..e5b09b8 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -6141,7 +6141,10 @@ TclNREvalObjEx(
 	    iPtr->varFramePtr = iPtr->rootFramePtr;
 	}
 	Tcl_IncrRefCount(objPtr);
-	codePtr = TclCompileObj(interp, objPtr, invoker, word);
+	ByteCodeGetIntRep(objPtr, &tclByteCodeType, codePtr);
+	if (codePtr == NULL) {
+	    codePtr = TclCompileObj(interp, objPtr, invoker, word);
+	}
 
 	TclNRAddCallback(interp, TEOEx_ByteCodeCallback, savedVarFramePtr,
 		objPtr, INT2PTR(allowExceptions), NULL);
diff --git a/generic/tclDecls.h b/generic/tclDecls.h
index 59d83b8..282e70b 100644
--- a/generic/tclDecls.h
+++ b/generic/tclDecls.h
@@ -1836,6 +1836,8 @@ EXTERN void		Tcl_StoreIntRep(Tcl_Obj *objPtr,
 				const Tcl_ObjIntRep *irPtr);
 /* 636 */
 EXTERN int		Tcl_HasStringRep(Tcl_Obj *objPtr);
+/* 637 */
+EXTERN void		Tcl_FreeOtherIntReps(Tcl_Obj *objPtr, const Tcl_ObjType *typePtr);
 
 typedef struct {
     const struct TclPlatStubs *tclPlatStubs;
@@ -2508,6 +2510,7 @@ typedef struct TclStubs {
     Tcl_ObjIntRep * (*tcl_FetchIntRep) (Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 634 */
     void (*tcl_StoreIntRep) (Tcl_Obj *objPtr, const Tcl_ObjType *typePtr, const Tcl_ObjIntRep *irPtr); /* 635 */
     int (*tcl_HasStringRep) (Tcl_Obj *objPtr); /* 636 */
+    void (*tcl_FreeOtherIntReps) (Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 637 */
 } TclStubs;
 
 extern const TclStubs *tclStubsPtr;
@@ -3812,6 +3815,8 @@ extern const TclStubs *tclStubsPtr;
 	(tclStubsPtr->tcl_StoreIntRep) /* 635 */
 #define Tcl_HasStringRep \
 	(tclStubsPtr->tcl_HasStringRep) /* 636 */
+#define Tcl_FreeOtherIntReps \
+	(tclStubsPtr->tcl_FreeOtherIntReps) /* 636 */
 
 #endif /* defined(USE_TCL_STUBS) */
 
diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c
index f4e15a6..e4b06bc 100644
--- a/generic/tclDictObj.c
+++ b/generic/tclDictObj.c
@@ -959,6 +959,7 @@ Tcl_DictObjPut(
 	return TCL_ERROR;
     }
 
+    Tcl_FreeOtherIntReps(dictPtr, &tclDictType);
     TclInvalidateStringRep(dictPtr);
     hPtr = CreateChainEntry(dict, keyPtr, &isNew);
     Tcl_IncrRefCount(valuePtr);
diff --git a/generic/tclExecute.c b/generic/tclExecute.c
index 8389bef..728e52c 100644
--- a/generic/tclExecute.c
+++ b/generic/tclExecute.c
@@ -9742,8 +9742,13 @@ TclGetSrcInfoForPc(
 	ECL *locPtr = NULL;
 	int srcOffset, i;
 	Interp *iPtr = (Interp *) *codePtr->interpHandle;
-	Tcl_HashEntry *hePtr =
-		Tcl_FindHashEntry(iPtr->lineBCPtr, codePtr);
+	Tcl_HashEntry *hePtr;
+
+	if (!iPtr->lineBCPtr) {
+	    fprintf(stderr, "TclGetSrcInfoForPc: iPtr->lineBCPtr is invalid\n");
+	    return;
+	}
+	hePtr = Tcl_FindHashEntry(iPtr->lineBCPtr, codePtr);
 
 	if (!hePtr) {
 	    return;
diff --git a/generic/tclListObj.c b/generic/tclListObj.c
index c33b95e..6e81a23 100644
--- a/generic/tclListObj.c
+++ b/generic/tclListObj.c
@@ -66,7 +66,13 @@ const Tcl_ObjType tclListType = {
     } while (0)
 
 #define ListResetIntRep(objPtr, listRepPtr) \
-    Tcl_FetchIntRep((objPtr), &tclListType)->twoPtrValue.ptr1 = (listRepPtr)
+    do {								\
+	Tcl_ObjIntRep *irPtr;						\
+	Tcl_FreeOtherIntReps((objPtr), &tclListType);			\
+	irPtr = Tcl_FetchIntRep((objPtr), &tclListType);		\
+	irPtr->twoPtrValue.ptr1 = (listRepPtr);				\
+	irPtr->twoPtrValue.ptr2 = NULL;					\
+    } while (0)
 
 #ifndef TCL_MIN_ELEMENT_GROWTH
 #define TCL_MIN_ELEMENT_GROWTH TCL_MIN_GROWTH/sizeof(Tcl_Obj *)
@@ -1257,7 +1263,7 @@ TclLindexFlat(
 	int index, listLen = 0;
 	Tcl_Obj **elemPtrs = NULL, *sublistCopy;
 
-	/*
+	/* TODO hydra: is this still necessary if shimmering is no longer an issue?
 	 * Here we make a private copy of the current sublist, so we avoid any
 	 * shimmering issues that might invalidate the elemPtr array below
 	 * while we are still using it. See test lindex-8.4.
diff --git a/generic/tclObj.c b/generic/tclObj.c
index 6e4011e..8bf69ce 100644
--- a/generic/tclObj.c
+++ b/generic/tclObj.c
@@ -206,6 +206,10 @@ static Tcl_ThreadDataKey pendingObjDataKey;
  * Prototypes for functions defined later in this file:
  */
 
+static void		FreeHydra(Tcl_Obj *objPtr);
+static void		DupHydra(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
+static void		UpdateStringOfHydra(Tcl_Obj *objPtr);
+static int		SetHydraFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
 static int		ParseBoolean(Tcl_Obj *objPtr);
 static int		SetDoubleFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
 static int		SetIntFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
@@ -243,6 +247,26 @@ static int		SetCmdNameFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
  * implementations.
  */
 
+#define MAX_HYDRA_CLIENTS	5
+static const Tcl_ObjType tclHydraType = {
+    "hydra",			/* name */
+    FreeHydra,			/* freeIntRepProc */
+    DupHydra,			/* dupIntRepProc */
+    UpdateStringOfHydra,	/* updateStringProc */
+    SetHydraFromAny		/* setFromAnyProc */
+};
+
+#define HydraGetIntRep(objPtr, hydraPtr) \
+    (hydraPtr) = (Hydra *)((objPtr)->internalRep.twoPtrValue.ptr1)
+
+typedef struct HydraClient {
+    const Tcl_ObjType	*typePtr;
+    Tcl_ObjIntRep	internalRep;
+} HydraClient;
+typedef struct Hydra {
+    HydraClient		client[MAX_HYDRA_CLIENTS];
+} Hydra;
+
 static const Tcl_ObjType oldBooleanType = {
     "boolean",			/* name */
     NULL,			/* freeIntRepProc */
@@ -1694,6 +1718,175 @@ Tcl_GetStringFromObj(
     return objPtr->bytes;
 }
 
+static void
+FreeHydra(
+    Tcl_Obj *objPtr)
+{
+    int i;
+    Hydra *hydraPtr;
+    Tcl_Obj fakeObj;
+
+    memset(&fakeObj, 0, sizeof(fakeObj));
+    fakeObj.refCount = 10;
+    HydraGetIntRep(objPtr, hydraPtr);
+
+    for (i=0; i<MAX_HYDRA_CLIENTS; i++) {
+	HydraClient *clientPtr = &hydraPtr->client[i];
+
+	if (clientPtr->typePtr) {
+	    if (clientPtr->typePtr->freeIntRepProc) {
+		fakeObj.internalRep = hydraPtr->client[i].internalRep;
+		fakeObj.typePtr = hydraPtr->client[i].typePtr;
+		Tcl_FreeIntRep(&fakeObj);
+
+		if (fakeObj.refCount != 10) {
+		    Tcl_Panic("Invalid reference taken to fakeObj while "
+			    "freeing intrep for %s",
+			    hydraPtr->client[i].typePtr->name);
+		}
+	    }
+
+	    hydraPtr->client[i].typePtr = NULL;
+	    memset(&hydraPtr->client[i].internalRep, 0, sizeof(hydraPtr->client[i].internalRep));
+	}
+    }
+
+    Tcl_Free((char *)hydraPtr);
+    hydraPtr = objPtr->internalRep.twoPtrValue.ptr1 = NULL;
+}
+
+static void
+DupHydra(
+    Tcl_Obj *srcPtr,
+    Tcl_Obj *copyPtr)
+{
+    int i;
+    Hydra *hydraPtr;
+    Hydra *hydraCopyPtr;
+    Tcl_Obj fakeSrcObj, fakeCopyObj;
+
+    if (Tcl_HasStringRep(srcPtr) && srcPtr->bytes == &tclEmptyString) {
+	return;
+    }
+
+    memset(&fakeSrcObj, 0, sizeof(fakeSrcObj));
+    fakeSrcObj.refCount = 10;
+    memset(&fakeCopyObj, 0, sizeof(fakeCopyObj));
+    fakeCopyObj.refCount = 10;
+
+    HydraGetIntRep(srcPtr, hydraPtr);
+
+    hydraCopyPtr = (Hydra *)Tcl_Alloc(sizeof(Hydra));
+    memset(hydraCopyPtr, 0, sizeof(*hydraCopyPtr));
+
+    for (i=0; i<MAX_HYDRA_CLIENTS; i++) {
+	HydraClient *clientPtr     = &hydraPtr->client[i];
+	HydraClient *clientCopyPtr = &hydraCopyPtr->client[i];
+
+	if (clientPtr->typePtr) {
+	    if (clientPtr->typePtr->dupIntRepProc) {
+		fakeCopyObj.typePtr = NULL;
+		fakeSrcObj.internalRep  = hydraPtr->client[i].internalRep;
+		fakeSrcObj.typePtr      = hydraPtr->client[i].typePtr;
+
+		fakeSrcObj.typePtr->dupIntRepProc(&fakeSrcObj, &fakeCopyObj);
+
+		if (fakeSrcObj.refCount != 10) {
+		    Tcl_Panic("Invalid reference taken to fakeSrcObj while "
+			    "duplicating intrep for %s",
+			    hydraPtr->client[i].typePtr->name);
+		}
+		if (fakeCopyObj.refCount != 10) {
+		    Tcl_Panic("Invalid reference taken to fakeCopyObj while "
+			    "duplicating intrep for %s",
+			    hydraPtr->client[i].typePtr->name);
+		}
+
+		if (clientCopyPtr->internalRep.twoPtrValue.ptr1 || clientCopyPtr->internalRep.twoPtrValue.ptr2) {
+		    clientCopyPtr->internalRep = fakeCopyObj.internalRep;
+		    clientCopyPtr->typePtr     = fakeCopyObj.typePtr;
+		}
+	    }
+	}
+    }
+
+    TclFreeIntRep(copyPtr);	/* Paranoia? */
+    copyPtr->internalRep.twoPtrValue.ptr1 = hydraPtr;
+    copyPtr->typePtr = &tclHydraType;
+}
+
+static void
+UpdateStringOfHydra(
+    Tcl_Obj *objPtr)
+{
+    int i;
+    Hydra *hydraPtr;
+    Tcl_Obj fakeObj;
+
+    memset(&fakeObj, 0, sizeof(fakeObj));
+    fakeObj.refCount = 10;
+
+    HydraGetIntRep(objPtr, hydraPtr);
+
+    for (i=0; i<MAX_HYDRA_CLIENTS; i++) {
+	HydraClient *clientPtr = &hydraPtr->client[i];
+
+	if (clientPtr->typePtr) {
+	    if (clientPtr->typePtr->updateStringProc) {
+		fakeObj.internalRep = hydraPtr->client[i].internalRep;
+		fakeObj.typePtr = hydraPtr->client[i].typePtr;
+		/* Don't know if this is necessary */
+		fakeObj.bytes = NULL;
+		fakeObj.length = 0;
+
+		fakeObj.typePtr->updateStringProc(&fakeObj);
+
+		if (fakeObj.refCount != 10) {
+		    Tcl_Panic("Invalid reference taken to fakeObj while "
+			    "updating string rep using %s",
+			    hydraPtr->client[i].typePtr->name);
+		}
+
+		if (TclHasStringRep(&fakeObj)) {  /* Not sure about this */
+		    objPtr->bytes = fakeObj.bytes;
+		    objPtr->length = fakeObj.length;
+		    fakeObj.bytes = NULL;
+		    fakeObj.length = 0;
+		    return;
+		}
+	    }
+	}
+    }
+
+    /* TODO: what? */
+    Tcl_Panic("Could not update string rep of hydra: %s",
+	    "No clients capable of regenerating string rep found");
+}
+
+static int
+SetHydraFromAny(
+    Tcl_Interp *interp,
+    Tcl_Obj *objPtr)
+{
+    Hydra *hydraPtr;
+
+    if (objPtr->typePtr == &tclHydraType) {
+	return TCL_OK;
+    }
+
+    hydraPtr = (Hydra *)Tcl_Alloc(sizeof(Hydra));
+    memset(hydraPtr, 0, sizeof(Hydra));
+
+    hydraPtr->client[0].typePtr = objPtr->typePtr;
+    hydraPtr->client[0].internalRep = objPtr->internalRep;
+
+    objPtr->internalRep.twoPtrValue.ptr1 = hydraPtr;
+    objPtr->internalRep.twoPtrValue.ptr2 = NULL;
+    objPtr->typePtr = &tclHydraType;
+
+    return TCL_OK;
+}
+
 /*
  *----------------------------------------------------------------------
  *
@@ -1852,16 +2045,125 @@ Tcl_StoreIntRep(
     const Tcl_ObjType *typePtr,	/* New type for the object */
     const Tcl_ObjIntRep *irPtr)	/* New IntRep for the object */
 {
-    /* Clear out any existing IntRep ( "shimmer" ) */
-    TclFreeIntRep(objPtr);
+    int i;
+    Hydra *hydraPtr;
 
-    /* When irPtr == NULL, just leave objPtr with no IntRep for typePtr */
-    if (irPtr) {
-	/* Copy the new IntRep into place */
+    if (objPtr->typePtr == NULL) {
+	/* Special case - updating (or clearing) a pure string object */
+	TclFreeIntRep(objPtr);
 	objPtr->internalRep = *irPtr;
-
-	/* Set the type to match */
 	objPtr->typePtr = typePtr;
+	return;
+    }
+
+    if (objPtr->typePtr == typePtr) {
+	/* Special case - updating (or clearing) an object's existing intrep */
+	TclFreeIntRep(objPtr);
+	if (irPtr) {
+	    objPtr->internalRep = *irPtr;
+	} else {
+	    memset(&objPtr->internalRep, 0, sizeof(objPtr->internalRep));
+	}
+	return;
+    }
+
+    if (objPtr->typePtr != &tclHydraType) {
+	SetHydraFromAny(NULL, objPtr);
+    }
+
+    HydraGetIntRep(objPtr, hydraPtr);
+
+    if (irPtr) {
+	int firstAvailableSlot = -1;
+
+	/* If we have an existing client with a matching type, we need to
+	 * update that intrep even if there is an open slot before it */
+	for (i=0; i<MAX_HYDRA_CLIENTS; i++) {
+	    HydraClient *clientPtr = &hydraPtr->client[i];
+
+	    if (clientPtr->typePtr == typePtr) {
+		if (irPtr) {
+		    /* In the case where we are updating an intrep for a type we
+		    * already have, take that as a sign that the value has changed
+		    * ([incr], [lset], [append], etc), and free all the others.
+		    * Since we will be left with a single intrep, drop back to a
+		    * simple object (non-hydra) */
+		    Tcl_FreeIntRep(objPtr);
+		    objPtr->internalRep = *irPtr;
+		    objPtr->typePtr = typePtr;
+		} else {
+		    if (clientPtr->typePtr->freeIntRepProc) {
+			/* Free the matching client intrep, using a fake obj */
+			Tcl_Obj fakeObj;
+
+			memset(&fakeObj, 0, sizeof(fakeObj));
+			fakeObj.refCount = 10;
+			fakeObj.typePtr = typePtr;
+			fakeObj.internalRep = clientPtr->internalRep;
+			TclFreeIntRep(&fakeObj);
+
+			if (fakeObj.refCount != 10) {
+			    Tcl_Panic("Invalid reference taken to fakeObj while "
+				    "freeing hydra client interp for %s",
+				    typePtr->name);
+			}
+		    }
+
+		    /* Mark the client slot as available */
+		    clientPtr->typePtr = NULL;
+		    memset(&clientPtr->internalRep, 0, sizeof(clientPtr->internalRep));
+		    return;
+		}
+		return;
+	    } else if (firstAvailableSlot == -1 && clientPtr->typePtr == NULL) {
+		/* Record the first available slot in case we need to add this
+		 * intrep there */
+		firstAvailableSlot = i;
+	    }
+	}
+
+	if (firstAvailableSlot > -1) {
+	    HydraClient *clientPtr = &hydraPtr->client[firstAvailableSlot];
+
+	    if (clientPtr->typePtr == NULL) {
+		/* Found available slot, put this intrep there */
+		clientPtr->internalRep = *irPtr;
+		clientPtr->typePtr = typePtr;
+		return;
+	    }
+	}
+
+	/* No available client slots.  Upconvert to linked list? */
+	Tcl_Panic("Unable to add client intrep for %s to hydra: "
+		"No slots available", typePtr->name);
+    } else {
+	for (i=0; i<MAX_HYDRA_CLIENTS; i++) {
+	    HydraClient *clientPtr = &hydraPtr->client[i];
+
+	    if (clientPtr->typePtr == typePtr) {
+		if (clientPtr->typePtr->freeIntRepProc) {
+		    /* Free the matching client intrep, using a fake obj */
+		    Tcl_Obj fakeObj;
+
+		    memset(&fakeObj, 0, sizeof(fakeObj));
+		    fakeObj.refCount = 10;
+		    fakeObj.typePtr = typePtr;
+		    fakeObj.internalRep = clientPtr->internalRep;
+		    TclFreeIntRep(&fakeObj);
+
+		    if (fakeObj.refCount != 10) {
+			Tcl_Panic("Invalid reference taken to fakeObj while "
+				"freeing hydra client interp for %s",
+				typePtr->name);
+		    }
+		}
+
+		/* Mark the client slot as available */
+		clientPtr->typePtr = NULL;
+		memset(&clientPtr->internalRep, 0, sizeof(clientPtr->internalRep));
+		return;
+	    }
+	}
     }
 }
 
@@ -1878,8 +2180,7 @@ Tcl_StoreIntRep(
  *	NULL if no such internal representation exists.
  *
  * Side effects:
- *	Calls the freeIntRepProc of the current Tcl_ObjType, if any.
- *	Sets the internalRep and typePtr fields to the submitted values.
+ *	None.
  *
  *----------------------------------------------------------------------
  */
@@ -1889,13 +2190,27 @@ Tcl_FetchIntRep(
     Tcl_Obj *objPtr,		/* Object to fetch from. */
     const Tcl_ObjType *typePtr)	/* Requested type */
 {
-    /* If objPtr type doesn't match request, nothing can be fetched */
-    if (objPtr->typePtr != typePtr) {
-	return NULL;
+    if (objPtr->typePtr == typePtr) {
+	/* Type match! objPtr IntRep is the one sought. */
+	return &(objPtr->internalRep);
     }
 
-    /* Type match! objPtr IntRep is the one sought. */
-    return &(objPtr->internalRep);
+    if (objPtr->typePtr == &tclHydraType) {
+	int i;
+	Hydra *hydraPtr;
+
+	HydraGetIntRep(objPtr, hydraPtr);
+
+	for (i=0; i<MAX_HYDRA_CLIENTS; i++) {
+	    HydraClient *clientPtr = &hydraPtr->client[i];
+
+	    if (clientPtr->typePtr == typePtr) {
+		return &(clientPtr->internalRep);
+	    }
+	}
+    }
+
+    return NULL;
 }
 
 /*
@@ -1922,6 +2237,43 @@ Tcl_FreeIntRep(
     TclFreeIntRep(objPtr);
 }
 
+void
+Tcl_FreeOtherIntReps(
+    Tcl_Obj *objPtr,
+    const Tcl_ObjType *typePtr)
+{
+    if (objPtr->typePtr == NULL || objPtr->typePtr == typePtr) {
+	return;
+    }
+
+    if (objPtr->typePtr == &tclHydraType) {
+	int i;
+	Hydra *hydraPtr;
+	Tcl_Obj fakeObj;
+
+	HydraGetIntRep(objPtr, hydraPtr);
+	memset(&fakeObj, 0, sizeof(fakeObj));
+
+	for (i=0; i<MAX_HYDRA_CLIENTS; i++) {
+	    HydraClient *clientPtr = &hydraPtr->client[i];
+
+	    if (clientPtr->typePtr != NULL && clientPtr->typePtr != typePtr) {
+		if (clientPtr->typePtr->freeIntRepProc) {
+		    fakeObj.typePtr = clientPtr->typePtr;
+		    fakeObj.internalRep = clientPtr->internalRep;
+		    fakeObj.typePtr->freeIntRepProc(&fakeObj);
+		}
+		clientPtr->typePtr = NULL;
+		memset(&clientPtr->internalRep, 0, sizeof(clientPtr->internalRep));
+	    }
+	}
+
+	/* Convert back to a plain object of type typePtr */
+	objPtr->internalRep = fakeObj.internalRep;
+	objPtr->typePtr = typePtr;
+	Tcl_Free((char *)hydraPtr);
+    }
+}
 /*
  *----------------------------------------------------------------------
  *
@@ -4694,6 +5046,32 @@ Tcl_RepresentationCmd(
 	Tcl_AppendToObj(descObj, ", no string representation", -1);
     }
 
+    if (objv[1]->typePtr == &tclHydraType) {
+	int i;
+	Hydra *hydraPtr;
+
+	Tcl_AppendToObj(descObj, ", with client representations:", -1);
+	HydraGetIntRep(objv[1], hydraPtr);
+	for (i=0; i<MAX_HYDRA_CLIENTS; i++) {
+	    HydraClient *clientPtr = &hydraPtr->client[i];
+
+	    if (clientPtr->typePtr == NULL) {
+		continue;
+	    }
+
+	    Tcl_AppendPrintfToObj(descObj, "\n\t%d: %s", i, clientPtr->typePtr->name);
+
+	    if (clientPtr->typePtr == &tclDoubleType) {
+		Tcl_AppendPrintfToObj(descObj, ", internal representation %g",
+			clientPtr->internalRep.doubleValue);
+	    } else {
+		Tcl_AppendPrintfToObj(descObj, ", internal representation %p:%p",
+			(void *) clientPtr->internalRep.twoPtrValue.ptr1,
+			(void *) clientPtr->internalRep.twoPtrValue.ptr2);
+	    }
+	}
+    }
+
     Tcl_SetObjResult(interp, descObj);
     return TCL_OK;
 }
diff --git a/generic/tclStringRep.h b/generic/tclStringRep.h
index 1ef1957..506d2f7 100644
--- a/generic/tclStringRep.h
+++ b/generic/tclStringRep.h
@@ -84,9 +84,21 @@ typedef struct {
 #define stringAttemptRealloc(ptr, numChars) \
     (String *) attemptckrealloc((ptr), STRING_SIZE(numChars))
 #define GET_STRING(objPtr) \
-    ((String *) (objPtr)->internalRep.twoPtrValue.ptr1)
+    ((String *) ((Tcl_FetchIntRep((objPtr), &tclStringType))->twoPtrValue.ptr1))
 #define SET_STRING(objPtr, stringPtr) \
-    ((objPtr)->internalRep.twoPtrValue.ptr1 = (void *) (stringPtr))
+    do {								\
+	Tcl_ObjIntRep *irPtr;						\
+	Tcl_FreeOtherIntReps((objPtr), &tclStringType);			\
+	irPtr = Tcl_FetchIntRep((objPtr), &tclStringType);		\
+	if (irPtr == NULL) {						\
+	    Tcl_ObjIntRep newIr;					\
+	    newIr.twoPtrValue.ptr1 = (void *) (stringPtr);		\
+	    newIr.twoPtrValue.ptr2 = NULL;				\
+	    Tcl_StoreIntRep((objPtr), &tclStringType, &newIr);		\
+	} else {							\
+	    irPtr->twoPtrValue.ptr1 = (void *) (stringPtr);		\
+	}								\
+    } while (0)
 
 /*
  * Local Variables:
diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c
index 8ff6291..449464a 100644
--- a/generic/tclStubInit.c
+++ b/generic/tclStubInit.c
@@ -1531,6 +1531,7 @@ const TclStubs tclStubs = {
     Tcl_FetchIntRep, /* 634 */
     Tcl_StoreIntRep, /* 635 */
     Tcl_HasStringRep, /* 636 */
+    Tcl_FreeOtherIntReps, /* 637 */
 };
 
 /* !END!: Do not edit above this line. */
diff --git a/generic/tclVar.c b/generic/tclVar.c
index 4c3d4a1..fa65be4 100644
--- a/generic/tclVar.c
+++ b/generic/tclVar.c
@@ -5564,10 +5564,13 @@ DupLocalVarName(
     Tcl_Obj *namePtr;
 
     LocalGetIntRep(srcPtr, index, namePtr);
-    if (!namePtr) {
-	namePtr = srcPtr;
+    if (namePtr) {
+	LocalSetIntRep(dupPtr, index, namePtr);
+    } else {
+	dupPtr->typePtr = NULL;
+	dupPtr->internalRep.twoPtrValue.ptr1 = NULL;
+	dupPtr->internalRep.twoPtrValue.ptr2 = NULL;
     }
-    LocalSetIntRep(dupPtr, index, namePtr);
 }
 
 /*