Tcl Source Code

Artifact [144d2859ee]
Login

Artifact 144d2859ee130a415ced590fdd0390a6cb449eae:

Attachment "alloc.patch" to ticket [1851832fff] added by msofer 2007-12-17 04:27:10.
Index: generic/tclAlloc.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclAlloc.c,v
retrieving revision 1.26
diff -u -r1.26 tclAlloc.c
--- generic/tclAlloc.c	13 Dec 2007 15:23:14 -0000	1.26
+++ generic/tclAlloc.c	16 Dec 2007 21:25:33 -0000
@@ -44,16 +44,6 @@
 #endif
 
 /*
- * Alignment for allocated memory.
- */
-
-#if defined(__APPLE__)
-#define ALLOCALIGN	16
-#else
-#define ALLOCALIGN	8
-#endif
-
-/*
  * The overhead on a block is at least 8 bytes. When free, this space contains
  * a pointer to the next free block, and the bottom two bits must be zero.
  * When in use, the first byte is set to MAGIC, and the second byte is the
@@ -66,7 +56,7 @@
 
 union overhead {
     union overhead *next;		/* when free */
-    unsigned char padding[ALLOCALIGN];	/* align struct to ALLOCALIGN bytes */
+    unsigned char padding[TCL_ALLOCALIGN];	/* align struct to TCL_ALLOCALIGN bytes */
     struct {
 	unsigned char magic0;		/* magic number */
 	unsigned char index;		/* bucket # */
@@ -110,7 +100,7 @@
  * precedes the data area returned to the user.
  */
 
-#define MINBLOCK	((sizeof(union overhead) + (ALLOCALIGN-1)) & ~(ALLOCALIGN-1))
+#define MINBLOCK	((sizeof(union overhead) + (TCL_ALLOCALIGN-1)) & ~(TCL_ALLOCALIGN-1))
 #define NBUCKETS	(13 - (MINBLOCK >> 4))
 #define MAXMALLOC	(1<<(NBUCKETS+2))
 static union overhead *nextf[NBUCKETS];
Index: generic/tclExecute.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclExecute.c,v
retrieving revision 1.357
diff -u -r1.357 tclExecute.c
--- generic/tclExecute.c	13 Dec 2007 15:23:16 -0000	1.357
+++ generic/tclExecute.c	16 Dec 2007 21:25:34 -0000
@@ -603,7 +603,7 @@
 static const char *	GetSrcInfoForPc(unsigned char *pc, ByteCode *codePtr,
 			    int *lengthPtr);
 static Tcl_Obj **	GrowEvaluationStack(ExecEnv *eePtr, int growth,
-			    int move);
+	                    int move, int align);
 static void		IllegalExprOperandType(Tcl_Interp *interp,
 			    unsigned char *pc, Tcl_Obj *opndPtr);
 static void		InitByteCodeExecution(Tcl_Interp *interp);
@@ -616,8 +616,8 @@
 #endif /* TCL_COMPILE_DEBUG */
 static void		DeleteExecStack(ExecStack *esPtr);
 /* Useful elsewhere, make available in tclInt.h or stubs? */
-static Tcl_Obj **	StackAllocWords(Tcl_Interp *interp, int numWords);
-static Tcl_Obj **	StackReallocWords(Tcl_Interp *interp, int numWords);
+static Tcl_Obj **	StackAllocWords(Tcl_Interp *interp, int numWords, int align);
+static Tcl_Obj **	StackReallocWords(Tcl_Interp *interp, int numWords, int align);
 
 /*
  *----------------------------------------------------------------------
@@ -854,37 +854,69 @@
  *----------------------------------------------------------------------
  */
 
+#define WALLOCALIGN (TCL_ALLOCALIGN/sizeof(void *))
+
+
+/*
+ * This macro computes the correct offset to insure that the pointer returned
+ * is properly aligned.
+ * Note that we are only interested in the low bits of the address, so that
+ * the fact that PTR2INT may lose the high bits is irrelevant.
+ */
+
+#define COMPUTE_OFFSET(markerPtr, offset)	\
+    {\
+	int base = (PTR2UINT(markerPtr) & (WALLOCALIGN-1));\
+	int new  = (base + 2 + (WALLOCALIGN-1)) & ~(WALLOCALIGN-1);\
+	(offset) = (new - base);				   \
+    }
+
+
 static Tcl_Obj **
 GrowEvaluationStack(
     ExecEnv *eePtr,		/* Points to the ExecEnv with an evaluation
 				 * stack to enlarge. */
     int growth,			/* How much larger than the current used
 				 * size. */
-    int move)			/* 1 if move words since last marker. */
+    int move,			/* 1 if move words since last marker. */
+    int align)                  /* 1 if word alignment is not enough, align
+				 * according to TCL_ALLOCALIGN */
 {
     ExecStack *esPtr = eePtr->execStackPtr, *oldPtr = NULL;
     int newBytes, newElems, currElems;
     int needed = growth - (esPtr->endPtr - esPtr->tosPtr);
-    Tcl_Obj **markerPtr = esPtr->markerPtr;
+    Tcl_Obj **markerPtr = esPtr->markerPtr, **newMarkerPtr;
+    int offset = 2; /* default value */
 
     if (move) {
 	if (!markerPtr) {
 	    Tcl_Panic("STACK: Reallocating with no previous alloc");
 	}
+	offset = PTR2INT(*(markerPtr+1));	
 	if (needed <= 0) {
-	    return markerPtr + 1;
+	    return markerPtr + offset;
+	}
+    } else if (needed < -1) {
+	newMarkerPtr = (esPtr->tosPtr + 1);
+	if (align) {
+	    COMPUTE_OFFSET(newMarkerPtr, offset);
 	}
-    } else if (needed < 0) {
-	/*
-	 * Put a marker pointing to the previous marker in this stack, and
-	 * store it in esPtr as the current marker. Return a pointer to one
-	 * word past the marker.
-	 */
 
-	esPtr->markerPtr = ++esPtr->tosPtr;
-	*esPtr->markerPtr = (Tcl_Obj *) markerPtr;
-	return esPtr->markerPtr + 1;
+	if (needed + offset <= 0) {
+	    /*
+	     * Put a marker pointing to the previous marker in this stack, and 
+	     * store it in esPtr as the current marker. Return a pointer to
+	     * the word at (marker+offset).
+	     */
+
+	    esPtr->markerPtr = newMarkerPtr;
+	    *newMarkerPtr = (Tcl_Obj *) markerPtr;
+	    *(newMarkerPtr+1) = INT2PTR(offset);
+	    esPtr->tosPtr += offset;
+	    return newMarkerPtr + offset;
+	}
     }
+    offset = 2; /* reset to default */
 
     /*
      * Reset move to hold the number of words to be moved to new stack (if
@@ -894,7 +926,14 @@
     if (move) {
 	move = esPtr->tosPtr - markerPtr;
     }
-    needed = growth + move + 1; /* Add the marker. */
+
+    /*
+     * Add requirements for the marker and the offset; note that this is at
+     * most (WALLOCALIGN+1) words: one for the marker, one to store the
+     * offset, and at most an offset of (WALLOCALIGN-1)
+     */
+    
+    needed = growth + move + (align? (WALLOCALIGN+1) : 2);
 
     /*
      * Check if there is enough room in the next stack (if there is one, it
@@ -942,6 +981,10 @@
   newStackReady:
     eePtr->execStackPtr = esPtr;
 
+    if (align) {
+	COMPUTE_OFFSET(&esPtr->stackWords[0], offset);
+    }
+
     /*
      * Store a NULL marker at the beginning of the stack, to indicate that
      * this is the first marker in this stack and that rewinding to here
@@ -949,10 +992,12 @@
      */
 
     esPtr->stackWords[0] = NULL;
-    esPtr->markerPtr = esPtr->tosPtr = &esPtr->stackWords[0];
+    esPtr->stackWords[1] = INT2PTR(offset);
+    esPtr->markerPtr = &esPtr->stackWords[0];
+    esPtr->tosPtr = &esPtr->stackWords[offset-1];
 
     if (move) {
-	memcpy(&esPtr->stackWords[1], (markerPtr+1), move*sizeof(Tcl_Obj *));
+	memcpy(&esPtr->stackWords[offset], (markerPtr+PTR2INT(*(markerPtr+1))), move*sizeof(Tcl_Obj *));
 	esPtr->tosPtr += move;
 	oldPtr->markerPtr = (Tcl_Obj **) *markerPtr;
 	oldPtr->tosPtr = markerPtr-1;
@@ -966,7 +1011,7 @@
 	DeleteExecStack(oldPtr);
     }
 
-    return &esPtr->stackWords[1];
+    return &esPtr->stackWords[offset];
 }
 
 /*
@@ -990,7 +1035,8 @@
 static Tcl_Obj **
 StackAllocWords(
     Tcl_Interp *interp,
-    int numWords)
+    int numWords,
+    int align)
 {
     /*
      * Note that GrowEvaluationStack sets a marker in the stack. This marker
@@ -999,7 +1045,7 @@
 
     Interp *iPtr = (Interp *) interp;
     ExecEnv *eePtr = iPtr->execEnvPtr;
-    Tcl_Obj **resPtr = GrowEvaluationStack(eePtr, numWords, 0);
+    Tcl_Obj **resPtr = GrowEvaluationStack(eePtr, numWords, 0, align);
 
     eePtr->execStackPtr->tosPtr += numWords;
     return resPtr;
@@ -1008,11 +1054,12 @@
 static Tcl_Obj **
 StackReallocWords(
     Tcl_Interp *interp,
-    int numWords)
+    int numWords,
+    int align)
 {
     Interp *iPtr = (Interp *) interp;
     ExecEnv *eePtr = iPtr->execEnvPtr;
-    Tcl_Obj **resPtr = GrowEvaluationStack(eePtr, numWords, 1);
+    Tcl_Obj **resPtr = GrowEvaluationStack(eePtr, numWords, 1, align);
 
     eePtr->execStackPtr->tosPtr += numWords;
     return resPtr;
@@ -1043,7 +1090,7 @@
     esPtr = eePtr->execStackPtr;
     markerPtr = esPtr->markerPtr;
 
-    if ((markerPtr+1) != (Tcl_Obj **)freePtr) {
+    if (markerPtr + PTR2INT(*(markerPtr+1)) != (Tcl_Obj **)freePtr) {
 	Tcl_Panic("TclStackFree: incorrect freePtr. Call out of sequence?");
     }
 
@@ -1081,7 +1128,7 @@
 	return (void *) Tcl_Alloc(numBytes);
     }
 
-    return (void *) StackAllocWords(interp, numWords);
+    return (void *) StackAllocWords(interp, numWords, 1);
 }
 
 void *
@@ -1104,12 +1151,12 @@
     esPtr = eePtr->execStackPtr;
     markerPtr = esPtr->markerPtr;
 
-    if ((markerPtr+1) != (Tcl_Obj **)ptr) {
+    if ((markerPtr+PTR2INT(*(markerPtr+1))) != (Tcl_Obj **)ptr) {
 	Tcl_Panic("TclStackRealloc: incorrect ptr. Call out of sequence?");
     }
 
     numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *);
-    return (void *) StackReallocWords(interp, numWords);
+    return (void *) StackReallocWords(interp, numWords, 1);
 }
 
 /*
@@ -1617,7 +1664,7 @@
     catchTop = initCatchTop = (ptrdiff_t *) (
 	GrowEvaluationStack(iPtr->execEnvPtr,
 		codePtr->maxExceptDepth + sizeof(CmdFrame) +
-		    codePtr->maxStackDepth, 0) - 1);
+		codePtr->maxStackDepth, 0, 0) - 1);
     bcFramePtr = (CmdFrame *) (initCatchTop + codePtr->maxExceptDepth + 1);
     tosPtr = initTosPtr = ((Tcl_Obj **) (bcFramePtr + 1)) - 1;
     esPtr = iPtr->execEnvPtr->execStackPtr;
@@ -2100,7 +2147,7 @@
 
 	length = objc + (codePtr->maxStackDepth - TclGetInt4AtPtr(pc+1));
 	DECACHE_STACK_INFO();
-	moved = (GrowEvaluationStack(iPtr->execEnvPtr, length, 1) - 1)
+	moved = (GrowEvaluationStack(iPtr->execEnvPtr, length, 1, 0) - 1)
 		- (Tcl_Obj **) initCatchTop;
 
 	if (moved) {
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.358
diff -u -r1.358 tclInt.h
--- generic/tclInt.h	13 Dec 2007 15:23:18 -0000	1.358
+++ generic/tclInt.h	16 Dec 2007 21:25:36 -0000
@@ -2034,6 +2034,17 @@
 #define UCHAR(c) ((unsigned char) (c))
 
 /*
+ * This macro is used to properly align the memory allocated by Tcl, giving
+ * the same alignment as the native malloc
+ */
+
+#if defined(__APPLE__)
+#define TCL_ALLOCALIGN	16
+#else
+#define TCL_ALLOCALIGN	8
+#endif
+
+/*
  * This macro is used to determine the offset needed to safely allocate any
  * data structure in memory. Given a starting offset or size, it "rounds up"
  * or "aligns" the offset to the next 8-byte boundary so that any data
Index: generic/tclThreadAlloc.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclThreadAlloc.c,v
retrieving revision 1.24
diff -u -r1.24 tclThreadAlloc.c
--- generic/tclThreadAlloc.c	13 Dec 2007 15:23:20 -0000	1.24
+++ generic/tclThreadAlloc.c	16 Dec 2007 21:25:36 -0000
@@ -40,16 +40,6 @@
 #define NOBJHIGH	1200
 
 /*
- * Alignment for allocated memory.
- */
-
-#if defined(__APPLE__)
-#define ALLOCALIGN	16
-#else
-#define ALLOCALIGN	8
-#endif
-
-/*
  * The following union stores accounting information for each block including
  * two small magic numbers and a bucket number when in use or a next pointer
  * when free. The original requested size (not including the Block overhead)
@@ -69,7 +59,7 @@
 	} u;
 	size_t reqSize;			/* Requested allocation size. */
     } b;
-    unsigned char padding[ALLOCALIGN];
+    unsigned char padding[TCL_ALLOCALIGN];
 } Block;
 #define nextBlock	b.u.next
 #define sourceBucket	b.u.s.bucket
@@ -83,7 +73,7 @@
  * of buckets in the bucket cache.
  */
 
-#define MINALLOC	((sizeof(Block) + 8 + (ALLOCALIGN-1)) & ~(ALLOCALIGN-1))
+#define MINALLOC	((sizeof(Block) + 8 + (TCL_ALLOCALIGN-1)) & ~(TCL_ALLOCALIGN-1))
 #define NBUCKETS	(11 - (MINALLOC >> 5))
 #define MAXALLOC	(MINALLOC << (NBUCKETS - 1))