Tcl Source Code

Artifact [86885b3e0e]
Login

Artifact 86885b3e0e4c26ff79730ace71092eb953901ce9:

Attachment "TDRCpatch2" to ticket [1174551fff] added by msofer 2005-04-04 06:35:26.
? OOdiff
? TDRCpatch
? TDRCpatch2
? listPatch
? listPatch2
? varResProc
? generic/TMP
? generic/tclExecute.c.HEAD
? generic/tclExecute.c.UGLY
? generic/tclInt.h.HEAD
? generic/tclInt.h.NEW
? generic/tclInterp.c.HEAD
? generic/tclInterp.c.TEST
? generic/tclLiteral.c.NEW
? generic/tclLiteral.c.ORIG
? generic/tclObj.c.ORIG
? generic/tclProc.c.HEAD
? generic/tclProc.c.PEAPOD
? generic/tclProc.c.POD
? generic/tclVar.c.HEAD
? library/package.tcl.ORIG
? library/package.tcl.TEST
? unix/.log
? unix/.ofl
? unix/0valgrind
? unix/ERR
? unix/httpd_18808
? unix/httpd_3475
? unix/httpd_4488
? unix/httpd_5109
? unix/httpd_6241
? unix/httpd_6597
? unix/httpd_7124
? unix/httpd_7134
? unix/httpd_7387
? unix/httpd_7663
? unix/httpd_8205
? unix/httpd_8206
? unix/pkgIndex.tcl
? unix/refCount++
? unix/returnOpts
? unix/st2joIF5
? unix/st46HewM
? unix/stKG98X7
? unix/stdo1DJy
? unix/stepVhp5
? unix/tclConfig.h
? unix/tclsh0
? unix/tclsh1
? unix/tcltest-mem
? unix/x.log
? unix/x.ofl
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.219
diff -u -r1.219 tclInt.h
--- generic/tclInt.h	2 Apr 2005 02:08:37 -0000	1.219
+++ generic/tclInt.h	3 Apr 2005 22:58:27 -0000
@@ -2448,76 +2448,6 @@
 #  define TclIncrObjsFreed()
 #endif /* TCL_COMPILE_STATS */
 
-/*
- * All context references used in the object freeing code are pointers
- * to this structure; every thread will have its own structure
- * instance.  The purpose of this structure is to allow deeply nested
- * collections of Tcl_Objs to be freed without taking a vast depth of
- * C stack (which could cause all sorts of breakage.)
- */
-
-typedef struct PendingObjData {
-    int deletionCount;		/* Count of the number of invokations of
-				 * TclFreeObj() are on the stack (at least
-				 * conceptually; many are actually expanded
-				 * macros). */
-    Tcl_Obj *deletionStack;	/* Stack of objects that have had TclFreeObj()
-				 * invoked upon them but which can't be deleted
-				 * yet because they are in a nested invokation
-				 * of TclFreeObj(). By postponing this way, we
-				 * limit the maximum overall C stack depth when
-				 * deleting a complex object. The down-side is
-				 * that we alter the overall behaviour by
-				 * altering the order in which objects are
-				 * deleted, and we change the order in which
-				 * the string rep and the internal rep of an
-				 * object are deleted. Note that code which
-				 * assumes the previous behaviour in either of
-				 * these respects is unsafe anyway; it was
-				 * never documented as to exactly what would
-				 * happen in these cases, and the overall
-				 * contract of a user-level Tcl_DecrRefCount()
-				 * is still preserved (assuming that a
-				 * particular T_DRC would delete an object is
-				 * not very safe). */
-} PendingObjData;
-
-/*
- * These are separated out so that some semantic content is attached
- * to them.
- */
-#define TclObjDeletionLock(contextPtr)   (contextPtr)->deletionCount++
-#define TclObjDeletionUnlock(contextPtr) (contextPtr)->deletionCount--
-#define TclObjDeletePending(contextPtr)  (contextPtr)->deletionCount > 0
-#define TclObjOnStack(contextPtr)	 (contextPtr)->deletionStack != NULL
-#define TclPushObjToDelete(contextPtr,objPtr) \
-    /* Invalidate the string rep first so we can use the bytes value \
-     * for our pointer chain. */ \
-    if (((objPtr)->bytes != NULL) \
-	    && ((objPtr)->bytes != tclEmptyStringRep)) { \
-	ckfree((char *) (objPtr)->bytes); \
-    } \
-    /* Now push onto the head of the stack. */ \
-    (objPtr)->bytes = (char *) ((contextPtr)->deletionStack); \
-    (contextPtr)->deletionStack = (objPtr)
-#define TclPopObjToDelete(contextPtr,objPtrVar) \
-    (objPtrVar) = (contextPtr)->deletionStack; \
-    (contextPtr)->deletionStack = (Tcl_Obj *) (objPtrVar)->bytes
-
-/*
- * Macro to set up the local reference to the deletion context.
- */
-#ifndef TCL_THREADS
-MODULE_SCOPE PendingObjData tclPendingObjData;
-#define TclObjInitDeletionContext(contextPtr) \
-    PendingObjData *CONST contextPtr = &tclPendingObjData
-#else
-MODULE_SCOPE Tcl_ThreadDataKey tclPendingObjDataKey;
-#define TclObjInitDeletionContext(contextPtr) \
-    PendingObjData *CONST contextPtr = (PendingObjData *) \
-	    Tcl_GetThreadData(&tclPendingObjDataKey, sizeof(PendingObjData))
-#endif
-
 #ifndef TCL_MEM_DEBUG
 # define TclNewObj(objPtr) \
     TclIncrObjsAllocated(); \
@@ -2529,52 +2459,18 @@
 
 # define TclDecrRefCount(objPtr) \
     if (--(objPtr)->refCount <= 0) { \
-	TclObjInitDeletionContext(contextPtr); \
-	if (TclObjDeletePending(contextPtr)) { \
-	    TclPushObjToDelete(contextPtr,objPtr); \
+	if ((objPtr)->typePtr && (objPtr)->typePtr->freeIntRepProc) { \
+	    TclFreeObj(objPtr); \
 	} else { \
-	    TclFreeObjMacro(contextPtr,objPtr); \
+	    if ((objPtr)->bytes \
+                    && ((objPtr)->bytes != tclEmptyStringRep)) { \
+		ckfree((char *) (objPtr)->bytes); \
+	    } \
+	    TclFreeObjStorage(objPtr); \
+	    TclIncrObjsFreed(); \
 	} \
     }
-
-/*
- * Note that the contents of the while loop assume that the string rep
- * has already been freed and we don't want to do anything fancy with
- * adding to the queue inside ourselves. Must take care to unstack the
- * object first since freeing the internal rep can add further objects
- * to the stack. The code assumes that it is the first thing in a
- * block; all current usages in the core satisfy this.
- *
- * Optimization opportunity: Allocate the context once in a large
- * function (e.g. TclExecuteByteCode) and use it directly instead of
- * looking it up each time.
- */
-#define TclFreeObjMacro(contextPtr,objPtr) \
-    if (((objPtr)->typePtr != NULL) \
-	    && ((objPtr)->typePtr->freeIntRepProc != NULL)) { \
-	TclObjDeletionLock(contextPtr); \
-	(objPtr)->typePtr->freeIntRepProc(objPtr); \
-	TclObjDeletionUnlock(contextPtr); \
-    } \
-    if (((objPtr)->bytes != NULL) \
-	    && ((objPtr)->bytes != tclEmptyStringRep)) { \
-	ckfree((char *) (objPtr)->bytes); \
-    } \
-    TclFreeObjStorage(objPtr); \
-    TclIncrObjsFreed(); \
-    TclObjDeletionLock(contextPtr); \
-    while (TclObjOnStack(contextPtr)) { \
-	Tcl_Obj *objToFree; \
-	TclPopObjToDelete(contextPtr,objToFree); \
-	if ((objToFree->typePtr != NULL) \
-		&& (objToFree->typePtr->freeIntRepProc != NULL)) { \
-	    objToFree->typePtr->freeIntRepProc(objToFree); \
-	} \
-	TclFreeObjStorage(objToFree); \
-	TclIncrObjsFreed(); \
-    } \
-    TclObjDeletionUnlock(contextPtr)
-
+	    
 #if defined(PURIFY)
 
 /*
Index: generic/tclObj.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclObj.c,v
retrieving revision 1.74
diff -u -r1.74 tclObj.c
--- generic/tclObj.c	1 Apr 2005 15:17:25 -0000	1.74
+++ generic/tclObj.c	3 Apr 2005 22:58:29 -0000
@@ -61,29 +61,80 @@
 static Tcl_ThreadDataKey dataKey;
 #endif /* TCL_MEM_DEBUG && TCL_THREADS */
 
-/*
- * Nested Tcl_Obj deletion management support.  Note that the code
- * that implements all this is written as macros in tclInt.h
- */
-
-#ifdef TCL_THREADS
 
 /*
- * Lookup key for the thread-local data used in the implementation in
- * tclInt.h.
- */
-Tcl_ThreadDataKey tclPendingObjDataKey;
-
+ * Nested Tcl_Obj deletion management support
+ *
+ * All context references used in the object freeing code are pointers
+ * to this structure; every thread will have its own structure
+ * instance.  The purpose of this structure is to allow deeply nested
+ * collections of Tcl_Objs to be freed without taking a vast depth of
+ * C stack (which could cause all sorts of breakage.)
+ */
+
+typedef struct PendingObjData {
+    int deletionCount;		/* Count of the number of invokations of
+				 * TclFreeObj() are on the stack (at least
+				 * conceptually; many are actually expanded
+				 * macros). */
+    Tcl_Obj *deletionStack;	/* Stack of objects that have had TclFreeObj()
+				 * invoked upon them but which can't be deleted
+				 * yet because they are in a nested invokation
+				 * of TclFreeObj(). By postponing this way, we
+				 * limit the maximum overall C stack depth when
+				 * deleting a complex object. The down-side is
+				 * that we alter the overall behaviour by
+				 * altering the order in which objects are
+				 * deleted, and we change the order in which
+				 * the string rep and the internal rep of an
+				 * object are deleted. Note that code which
+				 * assumes the previous behaviour in either of
+				 * these respects is unsafe anyway; it was
+				 * never documented as to exactly what would
+				 * happen in these cases, and the overall
+				 * contract of a user-level Tcl_DecrRefCount()
+				 * is still preserved (assuming that a
+				 * particular T_DRC would delete an object is
+				 * not very safe). */
+} PendingObjData;
+
+/*
+ * These are separated out so that some semantic content is attached
+ * to them.
+ */
+#define ObjDeletionLock(contextPtr)   (contextPtr)->deletionCount++
+#define ObjDeletionUnlock(contextPtr) (contextPtr)->deletionCount--
+#define ObjDeletePending(contextPtr)  (contextPtr)->deletionCount > 0
+#define ObjOnStack(contextPtr)	 (contextPtr)->deletionStack != NULL
+#define PushObjToDelete(contextPtr,objPtr) \
+    /* Invalidate the string rep first so we can use the bytes value \
+     * for our pointer chain. */ \
+    if (((objPtr)->bytes != NULL) \
+	    && ((objPtr)->bytes != tclEmptyStringRep)) { \
+	ckfree((char *) (objPtr)->bytes); \
+    } \
+    /* Now push onto the head of the stack. */ \
+    (objPtr)->bytes = (char *) ((contextPtr)->deletionStack); \
+    (contextPtr)->deletionStack = (objPtr)
+#define PopObjToDelete(contextPtr,objPtrVar) \
+    (objPtrVar) = (contextPtr)->deletionStack; \
+    (contextPtr)->deletionStack = (Tcl_Obj *) (objPtrVar)->bytes
+
+/*
+ * Macro to set up the local reference to the deletion context.
+ */
+#ifndef TCL_THREADS
+PendingObjData pendingObjData;
+#define ObjInitDeletionContext(contextPtr) \
+    PendingObjData *CONST contextPtr = &pendingObjData
 #else
-
-/*
- * Declaration of the singleton structure referenced in the
- * implementation in tclInt.h.
- */
-PendingObjData tclPendingObjData = { 0, NULL };
-
+Tcl_ThreadDataKey pendingObjDataKey;
+#define ObjInitDeletionContext(contextPtr) \
+    PendingObjData *CONST contextPtr = (PendingObjData *) \
+	    Tcl_GetThreadData(&pendingObjDataKey, sizeof(PendingObjData))
 #endif
 
+
 /*
  * Prototypes for procedures defined later in this file:
  */
@@ -775,19 +826,19 @@
     /*
      * This macro declares a variable, so must come here...
      */
-    TclObjInitDeletionContext(context);
+    ObjInitDeletionContext(context);
 
     if (objPtr->refCount < -1) {
 	Tcl_Panic("Reference count for %lx was negative", objPtr);
     }
 
-    if (TclObjDeletePending(context)) {
-	TclPushObjToDelete(context, objPtr);
+    if (ObjDeletePending(context)) {
+	PushObjToDelete(context, objPtr);
     } else {
 	if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
-	    TclObjDeletionLock(context);
+	    ObjDeletionLock(context);
 	    typePtr->freeIntRepProc(objPtr);
-	    TclObjDeletionUnlock(context);
+	    ObjDeletionUnlock(context);
 	}
 	Tcl_InvalidateStringRep(objPtr);
 
@@ -797,11 +848,11 @@
 #ifdef TCL_COMPILE_STATS
 	tclObjsFreed++;
 #endif /* TCL_COMPILE_STATS */
-	TclObjDeletionLock(context);
-	while (TclObjOnStack(context)) {
+	ObjDeletionLock(context);
+	while (ObjOnStack(context)) {
 	    Tcl_Obj *objToFree;
 
-	    TclPopObjToDelete(context,objToFree);
+	    PopObjToDelete(context,objToFree);
 	    TclFreeIntRep(objToFree);
 
 	    Tcl_MutexLock(&tclObjMutex);
@@ -811,7 +862,7 @@
 	    tclObjsFreed++;
 #endif /* TCL_COMPILE_STATS */
 	}
-	TclObjDeletionUnlock(context);
+	ObjDeletionUnlock(context);
     }
 }
 #else /* TCL_MEM_DEBUG */
@@ -820,11 +871,58 @@
 TclFreeObj(objPtr)
     register Tcl_Obj *objPtr;	/* The object to be freed. */
 {
-    TclObjInitDeletionContext(context);
-    if (TclObjDeletePending(context)) {
-	TclPushObjToDelete(context, objPtr);
+    if (!objPtr->typePtr || !objPtr->typePtr->freeIntRepProc) {
+	/*
+	 * objPtr can be freed safely, as it will not attempt to free any
+	 * other objects: it will not cause recursive calls to this function.
+	 */
+
+	if (objPtr->bytes && (objPtr->bytes != tclEmptyStringRep)) {	    
+	    ckfree((char *) objPtr->bytes);
+	}
+	TclFreeObjStorage(objPtr);
+	TclIncrObjsFreed();	
     } else {
-	TclFreeObjMacro(context, objPtr);
+	/*
+	 * This macro declares a variable, so must come here...
+	 */
+	ObjInitDeletionContext(context);
+	
+	if (ObjDeletePending(context)) {
+	    PushObjToDelete(context, objPtr);
+	} else {	
+	    /*
+	     * Note that the contents of the while loop assume that the string
+	     * rep has already been freed and we don't want to do anything
+	     * fancy with adding to the queue inside ourselves. Must take care
+	     * to unstack the object first since freeing the internal rep can
+	     * add further objects to the stack. The code assumes that it is
+	     * the first thing in a block; all current usages in the core
+	     * satisfy this.  
+	     */
+	    
+	    ObjDeletionLock(context); 
+	    objPtr->typePtr->freeIntRepProc(objPtr); 
+	    ObjDeletionUnlock(context); 
+
+	    if (objPtr->bytes && (objPtr->bytes != tclEmptyStringRep)) { 
+		ckfree((char *) objPtr->bytes); 
+	    } 
+	    TclFreeObjStorage(objPtr); 
+	    TclIncrObjsFreed(); 
+	    ObjDeletionLock(context); 
+	    while (ObjOnStack(context)) { 
+		Tcl_Obj *objToFree; 
+		PopObjToDelete(context,objToFree); 
+		if ((objToFree->typePtr != NULL) 
+			&& (objToFree->typePtr->freeIntRepProc != NULL)) { 
+		    objToFree->typePtr->freeIntRepProc(objToFree); 
+		} 
+		TclFreeObjStorage(objToFree); 
+		TclIncrObjsFreed(); 
+	    } 
+	    ObjDeletionUnlock(context);
+	}
     }
 }
 #endif