Index: libcfa/src/heap.cfa
===================================================================
--- libcfa/src/heap.cfa	(revision cfbc703dfdcd257acc2437311c5a25ee33932766)
+++ libcfa/src/heap.cfa	(revision 76e21136a1c0bd25b9c248fb398e4bb5222916b9)
@@ -10,6 +10,6 @@
 // Created On       : Tue Dec 19 21:58:35 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Apr  1 15:59:53 2020
-// Update Count     : 692
+// Last Modified On : Sat Apr 18 08:17:53 2020
+// Update Count     : 716
 //
 
@@ -181,5 +181,5 @@
 				} fake; // FakeHeader
 			} kind; // Kind
-			uint32_t dimension;							// used by calloc-like to remember number of array elements
+			size_t size;								// allocation size in bytes
 		} header; // Header
 		char pad[libAlign() - sizeof( Header )];
@@ -265,8 +265,12 @@
 static unsigned long long int free_storage;
 static unsigned int free_calls;
+static unsigned long long int aalloc_storage;
+static unsigned int aalloc_calls;
 static unsigned long long int calloc_storage;
 static unsigned int calloc_calls;
 static unsigned long long int memalign_storage;
 static unsigned int memalign_calls;
+static unsigned long long int amemalign_storage;
+static unsigned int amemalign_calls;
 static unsigned long long int cmemalign_storage;
 static unsigned int cmemalign_calls;
@@ -280,10 +284,12 @@
 // Use "write" because streams may be shutdown when calls are made.
 static void printStats() {
-	char helpText[512];
+	char helpText[1024];
 	__cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
 									"\nHeap statistics:\n"
 									"  malloc: calls %u / storage %llu\n"
+									"  aalloc: calls %u / storage %llu\n"
 									"  calloc: calls %u / storage %llu\n"
 									"  memalign: calls %u / storage %llu\n"
+									"  amemalign: calls %u / storage %llu\n"
 									"  cmemalign: calls %u / storage %llu\n"
 									"  resize: calls %u / storage %llu\n"
@@ -294,6 +300,8 @@
 									"  sbrk: calls %u / storage %llu\n",
 									malloc_calls, malloc_storage,
+									aalloc_calls, calloc_storage,
 									calloc_calls, calloc_storage,
 									memalign_calls, memalign_storage,
+									amemalign_calls, amemalign_storage,
 									cmemalign_calls, cmemalign_storage,
 									resize_calls, resize_storage,
@@ -307,5 +315,5 @@
 
 static int printStatsXML( FILE * stream ) {				// see malloc_info
-	char helpText[512];
+	char helpText[1024];
 	int len = snprintf( helpText, sizeof(helpText),
 						"<malloc version=\"1\">\n"
@@ -314,6 +322,8 @@
 						"</sizes>\n"
 						"<total type=\"malloc\" count=\"%u\" size=\"%llu\"/>\n"
+						"<total type=\"aalloc\" count=\"%u\" size=\"%llu\"/>\n"
 						"<total type=\"calloc\" count=\"%u\" size=\"%llu\"/>\n"
 						"<total type=\"memalign\" count=\"%u\" size=\"%llu\"/>\n"
+						"<total type=\"amemalign\" count=\"%u\" size=\"%llu\"/>\n"
 						"<total type=\"cmemalign\" count=\"%u\" size=\"%llu\"/>\n"
 						"<total type=\"resize\" count=\"%u\" size=\"%llu\"/>\n"
@@ -325,6 +335,8 @@
 						"</malloc>",
 						malloc_calls, malloc_storage,
+						aalloc_calls, aalloc_storage,
 						calloc_calls, calloc_storage,
 						memalign_calls, memalign_storage,
+						amemalign_calls, amemalign_storage,
 						cmemalign_calls, cmemalign_storage,
 						resize_calls, resize_storage,
@@ -566,4 +578,5 @@
 	} // if
 
+	block->header.size = size;							// store allocation size
 	void * addr = &(block->data);						// adjust off header to user bytes
 
@@ -734,4 +747,7 @@
 	//assert( heapManager.heapBegin != 0 );
 	if ( unlikely( heapManager.heapBegin == 0p ) ) heapManager{}; // called before memory_startup ?
+#if __SIZEOF_POINTER__ == 8
+	verify( size < ((typeof(size_t))1 << 48) );
+#endif // __SIZEOF_POINTER__ == 8
 	void * addr = doMalloc( size );
 	if ( unlikely( addr == 0p ) ) errno = ENOMEM;		// POSIX
@@ -740,6 +756,6 @@
 
 
-static inline void * callocNoStats( size_t noOfElems, size_t elemSize ) {
-	size_t size = noOfElems * elemSize;
+static inline void * callocNoStats( size_t dim, size_t elemSize ) {
+	size_t size = dim * elemSize;
 	char * addr = (char *)mallocNoStats( size );
   if ( unlikely( addr == 0p ) ) return 0p;
@@ -758,6 +774,4 @@
 		memset( addr, '\0', bsize - sizeof(HeapManager.Storage) ); // set to zeros
 
-	assert( noOfElems <= UINT32_MAX );
-	header->dimension = noOfElems;						// store number of array elements
 	header->kind.real.blockSize |= 2;					// mark as zero filled
 	return addr;
@@ -801,6 +815,6 @@
 
 
-static inline void * cmemalignNoStats( size_t alignment, size_t noOfElems, size_t elemSize ) {
-	size_t size = noOfElems * elemSize;
+static inline void * cmemalignNoStats( size_t alignment, size_t dim, size_t elemSize ) {
+	size_t size = dim * elemSize;
 	char * addr = (char *)memalignNoStats( alignment, size );
   if ( unlikely( addr == 0p ) ) return 0p;
@@ -815,6 +829,4 @@
 		memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros
 
-	assert( noOfElems <= UINT32_MAX );
-	header->dimension = noOfElems;						// store initial array size
 	header->kind.real.blockSize |= 2;					// mark as zero filled
 	return addr;
@@ -843,14 +855,36 @@
 	} // malloc
 
-	// Allocate memory for an array of nmemb elements of size bytes each and returns a pointer to the allocated
-	// memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either 0p, or a unique pointer
-	// value that can later be successfully passed to free().
-	void * calloc( size_t noOfElems, size_t elemSize ) {
+
+	// Allocate memory for an array of dim elements of size bytes each and returns a pointer to the allocated memory. If
+	// dim or size is 0, then calloc() returns either 0p, or a unique pointer value that can later be successfully
+	// passed to free().
+	void * aalloc( size_t dim, size_t elemSize ) {
+		#ifdef __STATISTICS__
+		__atomic_add_fetch( &aalloc_calls, 1, __ATOMIC_SEQ_CST );
+		__atomic_add_fetch( &aalloc_storage, dim * elemSize, __ATOMIC_SEQ_CST );
+		#endif // __STATISTICS__
+
+		size_t size = dim * elemSize;
+		char * addr = (char *)mallocNoStats( size );
+	  if ( unlikely( addr == 0p ) ) return 0p;
+
+		HeapManager.Storage.Header * header;
+		HeapManager.FreeHeader * freeElem;
+		size_t bsize, alignment;
+		headers( "aalloc", addr, header, freeElem, bsize, alignment );
+
+		header->kind.real.blockSize |= 2;				// mark as zero filled
+		return addr;
+	} // aalloc
+
+
+	// Same as aalloc() with memory is set to zero.
+	void * calloc( size_t dim, size_t elemSize ) {
 		#ifdef __STATISTICS__
 		__atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );
-		__atomic_add_fetch( &calloc_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
-		#endif // __STATISTICS__
-
-		return callocNoStats( noOfElems, elemSize );
+		__atomic_add_fetch( &calloc_storage, dim * elemSize, __ATOMIC_SEQ_CST );
+		#endif // __STATISTICS__
+
+		return callocNoStats( dim, elemSize );
 	} // calloc
 
@@ -874,8 +908,8 @@
 		size_t bsize, oalign = 0;
 		headers( "resize", oaddr, header, freeElem, bsize, oalign );
+
 		size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
-
 		// same size, DO NOT preserve STICKY PROPERTIES.
-		if ( oalign == 0 && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
+	  if ( oalign == 0 && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
 			header->kind.real.blockSize &= -2;			// no alignment and turn off 0 fill
 			return oaddr;
@@ -951,12 +985,32 @@
 
 
+	// Same as aalloc() with memory alignment.
+	void * amemalign( size_t alignment, size_t dim, size_t elemSize ) {
+		#ifdef __STATISTICS__
+		__atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
+		__atomic_add_fetch( &cmemalign_storage, dim * elemSize, __ATOMIC_SEQ_CST );
+		#endif // __STATISTICS__
+
+		size_t size = dim * elemSize;
+		char * addr = (char *)memalignNoStats( alignment, size );
+	  if ( unlikely( addr == 0p ) ) return 0p;
+		HeapManager.Storage.Header * header;
+		HeapManager.FreeHeader * freeElem;
+		size_t bsize;
+		headers( "amemalign", addr, header, freeElem, bsize, alignment );
+
+		header->kind.real.blockSize |= 2;				// mark as zero filled
+		return addr;
+	} // amemalign
+
+
 	// Same as calloc() with memory alignment.
-	void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {
+	void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) {
 		#ifdef __STATISTICS__
 		__atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
-		__atomic_add_fetch( &cmemalign_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
-		#endif // __STATISTICS__
-
-		return cmemalignNoStats( alignment, noOfElems, elemSize );
+		__atomic_add_fetch( &cmemalign_storage, dim * elemSize, __ATOMIC_SEQ_CST );
+		#endif // __STATISTICS__
+
+		return cmemalignNoStats( alignment, dim, elemSize );
 	} // cmemalign
 
@@ -1015,5 +1069,5 @@
 
 
-	// Returns the alignment of the allocation.
+	// Returns the alignment of an allocation.
 	size_t malloc_alignment( void * addr ) {
 	  if ( unlikely( addr == 0p ) ) return libAlign();	// minimum alignment
@@ -1026,6 +1080,20 @@
 	} // malloc_alignment
 
-
-	// Returns true if the allocation is zero filled, i.e., initially allocated by calloc().
+	// Set the alignment for an the allocation and return previous alignment or 0 if no alignment.
+	size_t $malloc_alignment_set( void * addr, size_t alignment ) {
+	  if ( unlikely( addr == 0p ) ) return libAlign();	// minimum alignment
+		size_t ret;
+		HeapManager.Storage.Header * header = headerAddr( addr );
+		if ( (header->kind.fake.alignment & 1) == 1 ) {	// fake header ?
+			ret = header->kind.fake.alignment & -2;		// remove flag from old value
+			header->kind.fake.alignment = alignment | 1; // add flag to new value
+		} else {
+			ret = 0;									// => no alignment to change
+		} // if
+		return ret;
+	} // $malloc_alignment_set
+
+
+	// Returns true if the allocation is zero filled, e.g., allocated by calloc().
 	bool malloc_zero_fill( void * addr ) {
 	  if ( unlikely( addr == 0p ) ) return false;		// null allocation is not zero fill
@@ -1034,10 +1102,9 @@
 			header = realHeader( header );				// backup from fake to real header
 		} // if
-		return (header->kind.real.blockSize & 2) != 0;	// zero filled (calloc/cmemalign) ?
+		return (header->kind.real.blockSize & 2) != 0;	// zero filled ?
 	} // malloc_zero_fill
 
-
-	// Returns number of elements if the allocation is for an array, i.e., by calloc().
-	size_t malloc_dimension( void * addr ) {
+	// Set allocation is zero filled and return previous zero filled.
+	bool $malloc_zero_fill_set( void * addr ) {
 	  if ( unlikely( addr == 0p ) ) return false;		// null allocation is not zero fill
 		HeapManager.Storage.Header * header = headerAddr( addr );
@@ -1045,6 +1112,31 @@
 			header = realHeader( header );				// backup from fake to real header
 		} // if
-		return header->dimension;						// array (calloc/cmemalign)
-	} // malloc_zero_fill
+		bool ret = (header->kind.real.blockSize & 2) != 0; // zero filled ?
+		header->kind.real.blockSize |= 2;				// mark as zero filled
+		return ret;
+	} // $malloc_zero_fill_set
+
+
+	// Returns original total allocation size (not bucket size) => array size is dimension * sizeif(T).
+	size_t malloc_size( void * addr ) {
+	  if ( unlikely( addr == 0p ) ) return false;		// null allocation is not zero fill
+		HeapManager.Storage.Header * header = headerAddr( addr );
+		if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
+			header = realHeader( header );				// backup from fake to real header
+		} // if
+		return header->size;
+	} // malloc_size
+
+	// Set allocation size and return previous size.
+	size_t $malloc_size_set( void * addr, size_t size ) {
+	  if ( unlikely( addr == 0p ) ) return false;		// null allocation is not zero fill
+		HeapManager.Storage.Header * header = headerAddr( addr );
+		if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
+			header = realHeader( header );				// backup from fake to real header
+		} // if
+		size_t ret = header->size;
+		header->size = size;
+		return ret;
+	} // $malloc_size_set
 
 
