Ignore:
Timestamp:
Jan 7, 2021, 3:27:00 PM (5 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
2b4daf2, 64aeca0
Parents:
3c64c668 (diff), eef8dfb (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into park_unpark

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    r3c64c668 r58fe85a  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // heap.c --
     7// heap.cfa --
    88//
    99// Author           : Peter A. Buhr
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 10:04:51 2020
    13 // Update Count     : 648
     12// Last Modified On : Wed Dec 16 12:28:25 2020
     13// Update Count     : 1023
    1414//
    1515
    1616#include <unistd.h>                                                                             // sbrk, sysconf
     17#include <stdlib.h>                                                                             // EXIT_FAILURE
    1718#include <stdbool.h>                                                                    // true, false
    1819#include <stdio.h>                                                                              // snprintf, fileno
    1920#include <errno.h>                                                                              // errno
    2021#include <string.h>                                                                             // memset, memcpy
    21 extern "C" {
     22#include <limits.h>                                                                             // ULONG_MAX
     23#include <malloc.h>                                                                             // memalign, malloc_usable_size
    2224#include <sys/mman.h>                                                                   // mmap, munmap
    23 } // extern "C"
    24 
    25 // #comment TD : Many of these should be merged into math I believe
    26 #include "bits/align.hfa"                                                               // libPow2
     25
     26#include "bits/align.hfa"                                                               // libAlign
    2727#include "bits/defs.hfa"                                                                // likely, unlikely
    2828#include "bits/locks.hfa"                                                               // __spinlock_t
    2929#include "startup.hfa"                                                                  // STARTUP_PRIORITY_MEMORY
    30 //#include "stdlib.hfa"                                                                 // bsearchl
    31 #include "malloc.h"
    32 
    33 #define MIN(x, y) (y > x ? x : y)
     30#include "math.hfa"                                                                             // ceiling
     31#include "bitmanip.hfa"                                                                 // is_pow2, ceiling2
    3432
    3533static bool traceHeap = false;
     
    7472        // Define the default extension heap amount in units of bytes. When the uC++ supplied heap reaches the brk address,
    7573        // the brk address is extended by the extension amount.
    76         __CFA_DEFAULT_HEAP_EXPANSION__ = (1 * 1024 * 1024),
     74        __CFA_DEFAULT_HEAP_EXPANSION__ = (10 * 1024 * 1024),
    7775
    7876        // Define the mmap crossover point during allocation. Allocations less than this amount are allocated from buckets;
     
    9189
    9290#ifdef __CFA_DEBUG__
    93 static unsigned int allocFree;                                                  // running total of allocations minus frees
     91static size_t allocUnfreed;                                                             // running total of allocations minus frees
    9492
    9593static void prtUnfreed() {
    96         if ( allocFree != 0 ) {
     94        if ( allocUnfreed != 0 ) {
    9795                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    9896                char helpText[512];
    99                 int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %u(0x%x) bytes of storage allocated but not freed.\n"
     97                int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %zu(0x%zx) bytes of storage allocated but not freed.\n"
    10098                                                        "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
    101                                                         (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid
     99                                                        (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid
    102100                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    103101        } // if
     
    106104extern "C" {
    107105        void heapAppStart() {                                                           // called by __cfaabi_appready_startup
    108                 allocFree = 0;
     106                allocUnfreed = 0;
    109107        } // heapAppStart
    110108
     
    118116
    119117// statically allocated variables => zero filled.
    120 static size_t pageSize;                                                                 // architecture pagesize
     118size_t __page_size;                                                                             // architecture pagesize
     119int __map_prot;                                                                                 // common mmap/mprotect protection
    121120static size_t heapExpand;                                                               // sbrk advance
    122121static size_t mmapStart;                                                                // cross over point for mmap
     
    127126#define LOCKFREE 1
    128127#define BUCKETLOCK SPINLOCK
    129 #if BUCKETLOCK == LOCKFREE
    130 #include <uStackLF.h>
     128#if BUCKETLOCK == SPINLOCK
     129#elif BUCKETLOCK == LOCKFREE
     130#include <stackLockFree.hfa>
     131#else
     132        #error undefined lock type for bucket lock
    131133#endif // LOCKFREE
    132134
     
    136138
    137139struct HeapManager {
    138 //      struct FreeHeader;                                                                      // forward declaration
    139 
    140140        struct Storage {
    141141                struct Header {                                                                 // header
     
    145145                                                struct {                                                // 4-byte word => 8-byte header, 8-byte word => 16-byte header
    146146                                                        #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4
    147                                                         uint32_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
     147                                                        uint64_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
    148148                                                        #endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4
    149149
    150150                                                        union {
    151 //                                                              FreeHeader * home;              // allocated block points back to home locations (must overlay alignment)
     151                                                                // FreeHeader * home;           // allocated block points back to home locations (must overlay alignment)
     152                                                                // 2nd low-order bit => zero filled
    152153                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
    153154                                                                size_t blockSize;               // size for munmap (must overlay alignment)
    154                                                                 #if BUCKLOCK == SPINLOCK
     155                                                                #if BUCKETLOCK == SPINLOCK
    155156                                                                Storage * next;                 // freed block points next freed block of same size
    156157                                                                #endif // SPINLOCK
    157158                                                        };
     159                                                        size_t size;                            // allocation size in bytes
    158160
    159161                                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4
    160                                                         uint32_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
     162                                                        uint64_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
    161163                                                        #endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4
    162164                                                };
    163                                                 // future code
    164                                                 #if BUCKLOCK == LOCKFREE
    165                                                 Stack<Storage>::Link next;              // freed block points next freed block of same size (double-wide)
     165                                                #if BUCKETLOCK == LOCKFREE
     166                                                Link(Storage) next;                             // freed block points next freed block of same size (double-wide)
    166167                                                #endif // LOCKFREE
    167168                                        };
    168169                                } real; // RealHeader
     170
    169171                                struct FakeHeader {
    170172                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    171                                         uint32_t alignment;                                     // low-order bits of home/blockSize used for tricks
     173                                        uint32_t alignment;                                     // 1st low-order bit => fake header & alignment
    172174                                        #endif // __ORDER_LITTLE_ENDIAN__
    173175
     
    187189
    188190        struct FreeHeader {
    189                 #if BUCKLOCK == SPINLOCK
     191                #if BUCKETLOCK == SPINLOCK
    190192                __spinlock_t lock;                                                              // must be first field for alignment
    191193                Storage * freeList;
    192                 #elif BUCKLOCK == LOCKFREE
    193                 // future code
    194                 StackLF<Storage> freeList;
    195194                #else
    196                         #error undefined lock type for bucket lock
    197                 #endif // SPINLOCK
     195                StackLF(Storage) freeList;
     196                #endif // BUCKETLOCK
    198197                size_t blockSize;                                                               // size of allocations on this list
    199198        }; // FreeHeader
     
    208207}; // HeapManager
    209208
     209#if BUCKETLOCK == LOCKFREE
     210static inline {
     211        Link(HeapManager.Storage) * ?`next( HeapManager.Storage * this ) { return &this->header.kind.real.next; }
     212        void ?{}( HeapManager.FreeHeader & ) {}
     213        void ^?{}( HeapManager.FreeHeader & ) {}
     214} // distribution
     215#endif // LOCKFREE
     216
    210217static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; }
    211218
     
    214221#define __STATISTICS__
    215222
    216 // Bucket size must be multiple of 16.
    217 // Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size.
     223// Size of array must harmonize with NoBucketSizes and individual bucket sizes must be multiple of 16.
     224// Smaller multiples of 16 and powers of 2 are common allocation sizes, so make them generate the minimum required bucket size.
     225// malloc(0) returns 0p, so no bucket is necessary for 0 bytes returning an address that can be freed.
    218226static const unsigned int bucketSizes[] @= {                    // different bucket sizes
    219         16, 32, 48, 64 + sizeof(HeapManager.Storage), // 4
    220         96, 112, 128 + sizeof(HeapManager.Storage), // 3
     227        16 + sizeof(HeapManager.Storage), 32 + sizeof(HeapManager.Storage), 48 + sizeof(HeapManager.Storage), 64 + sizeof(HeapManager.Storage), // 4
     228        96 + sizeof(HeapManager.Storage), 112 + sizeof(HeapManager.Storage), 128 + sizeof(HeapManager.Storage), // 3
    221229        160, 192, 224, 256 + sizeof(HeapManager.Storage), // 4
    222230        320, 384, 448, 512 + sizeof(HeapManager.Storage), // 4
     
    236244};
    237245
    238 static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0]), "size of bucket array wrong" );
     246static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0] ), "size of bucket array wrong" );
    239247
    240248#ifdef FASTLOOKUP
     
    243251#endif // FASTLOOKUP
    244252
    245 static int mmapFd = -1;                                                                 // fake or actual fd for anonymous file
     253static const off_t mmapFd = -1;                                                 // fake or actual fd for anonymous file
    246254#ifdef __CFA_DEBUG__
    247255static bool heapBoot = 0;                                                               // detect recursion during boot
    248256#endif // __CFA_DEBUG__
     257
     258// The constructor for heapManager is called explicitly in memory_startup.
    249259static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing
    250260
     
    252262#ifdef __STATISTICS__
    253263// Heap statistics counters.
     264static unsigned int malloc_calls;
     265static unsigned long long int malloc_storage;
     266static unsigned int aalloc_calls;
     267static unsigned long long int aalloc_storage;
     268static unsigned int calloc_calls;
     269static unsigned long long int calloc_storage;
     270static unsigned int memalign_calls;
     271static unsigned long long int memalign_storage;
     272static unsigned int amemalign_calls;
     273static unsigned long long int amemalign_storage;
     274static unsigned int cmemalign_calls;
     275static unsigned long long int cmemalign_storage;
     276static unsigned int resize_calls;
     277static unsigned long long int resize_storage;
     278static unsigned int realloc_calls;
     279static unsigned long long int realloc_storage;
     280static unsigned int free_calls;
     281static unsigned long long int free_storage;
     282static unsigned int mmap_calls;
    254283static unsigned long long int mmap_storage;
    255 static unsigned int mmap_calls;
     284static unsigned int munmap_calls;
    256285static unsigned long long int munmap_storage;
    257 static unsigned int munmap_calls;
     286static unsigned int sbrk_calls;
    258287static unsigned long long int sbrk_storage;
    259 static unsigned int sbrk_calls;
    260 static unsigned long long int malloc_storage;
    261 static unsigned int malloc_calls;
    262 static unsigned long long int free_storage;
    263 static unsigned int free_calls;
    264 static unsigned long long int calloc_storage;
    265 static unsigned int calloc_calls;
    266 static unsigned long long int memalign_storage;
    267 static unsigned int memalign_calls;
    268 static unsigned long long int cmemalign_storage;
    269 static unsigned int cmemalign_calls;
    270 static unsigned long long int realloc_storage;
    271 static unsigned int realloc_calls;
    272288// Statistics file descriptor (changed by malloc_stats_fd).
    273 static int statfd = STDERR_FILENO;                                              // default stderr
     289static int stat_fd = STDERR_FILENO;                                             // default stderr
    274290
    275291// Use "write" because streams may be shutdown when calls are made.
    276292static void printStats() {
    277         char helpText[512];
     293        char helpText[1024];
    278294        __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
    279295                                                                        "\nHeap statistics:\n"
    280296                                                                        "  malloc: calls %u / storage %llu\n"
     297                                                                        "  aalloc: calls %u / storage %llu\n"
    281298                                                                        "  calloc: calls %u / storage %llu\n"
    282299                                                                        "  memalign: calls %u / storage %llu\n"
     300                                                                        "  amemalign: calls %u / storage %llu\n"
    283301                                                                        "  cmemalign: calls %u / storage %llu\n"
     302                                                                        "  resize: calls %u / storage %llu\n"
    284303                                                                        "  realloc: calls %u / storage %llu\n"
    285304                                                                        "  free: calls %u / storage %llu\n"
     
    288307                                                                        "  sbrk: calls %u / storage %llu\n",
    289308                                                                        malloc_calls, malloc_storage,
     309                                                                        aalloc_calls, aalloc_storage,
    290310                                                                        calloc_calls, calloc_storage,
    291311                                                                        memalign_calls, memalign_storage,
     312                                                                        amemalign_calls, amemalign_storage,
    292313                                                                        cmemalign_calls, cmemalign_storage,
     314                                                                        resize_calls, resize_storage,
    293315                                                                        realloc_calls, realloc_storage,
    294316                                                                        free_calls, free_storage,
     
    300322
    301323static int printStatsXML( FILE * stream ) {                             // see malloc_info
    302         char helpText[512];
     324        char helpText[1024];
    303325        int len = snprintf( helpText, sizeof(helpText),
    304326                                                "<malloc version=\"1\">\n"
     
    307329                                                "</sizes>\n"
    308330                                                "<total type=\"malloc\" count=\"%u\" size=\"%llu\"/>\n"
     331                                                "<total type=\"aalloc\" count=\"%u\" size=\"%llu\"/>\n"
    309332                                                "<total type=\"calloc\" count=\"%u\" size=\"%llu\"/>\n"
    310333                                                "<total type=\"memalign\" count=\"%u\" size=\"%llu\"/>\n"
     334                                                "<total type=\"amemalign\" count=\"%u\" size=\"%llu\"/>\n"
    311335                                                "<total type=\"cmemalign\" count=\"%u\" size=\"%llu\"/>\n"
     336                                                "<total type=\"resize\" count=\"%u\" size=\"%llu\"/>\n"
    312337                                                "<total type=\"realloc\" count=\"%u\" size=\"%llu\"/>\n"
    313338                                                "<total type=\"free\" count=\"%u\" size=\"%llu\"/>\n"
     
    317342                                                "</malloc>",
    318343                                                malloc_calls, malloc_storage,
     344                                                aalloc_calls, aalloc_storage,
    319345                                                calloc_calls, calloc_storage,
    320346                                                memalign_calls, memalign_storage,
     347                                                amemalign_calls, amemalign_storage,
    321348                                                cmemalign_calls, cmemalign_storage,
     349                                                resize_calls, resize_storage,
    322350                                                realloc_calls, realloc_storage,
    323351                                                free_calls, free_storage,
     
    332360
    333361
    334 // static inline void noMemory() {
    335 //      abort( "Heap memory exhausted at %zu bytes.\n"
    336 //                 "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",
    337 //                 ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
    338 // } // noMemory
    339 
    340 
    341 static inline void checkAlign( size_t alignment ) {
    342         if ( alignment < libAlign() || ! libPow2( alignment ) ) {
    343                 abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() );
    344         } // if
    345 } // checkAlign
    346 
    347 
    348 static inline bool setHeapExpand( size_t value ) {
    349   if ( heapExpand < pageSize ) return true;
    350         heapExpand = value;
    351         return false;
    352 } // setHeapExpand
    353 
    354 
    355362// thunk problem
    356363size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) {
     
    369376
    370377static inline bool setMmapStart( size_t value ) {               // true => mmapped, false => sbrk
    371   if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;
     378  if ( value < __page_size || bucketSizes[NoBucketSizes - 1] < value ) return false;
    372379        mmapStart = value;                                                                      // set global
    373380
     
    376383        assert( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
    377384        assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
    378         return false;
     385        return true;
    379386} // setMmapStart
     387
     388
     389// <-------+----------------------------------------------------> bsize (bucket size)
     390// |header |addr
     391//==================================================================================
     392//                   align/offset |
     393// <-----------------<------------+-----------------------------> bsize (bucket size)
     394//                   |fake-header | addr
     395#define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
     396#define realHeader( header ) ((HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset))
     397
     398// <-------<<--------------------- dsize ---------------------->> bsize (bucket size)
     399// |header |addr
     400//==================================================================================
     401//                   align/offset |
     402// <------------------------------<<---------- dsize --------->>> bsize (bucket size)
     403//                   |fake-header |addr
     404#define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header ))
     405
     406
     407static inline void checkAlign( size_t alignment ) {
     408        if ( alignment < libAlign() || ! is_pow2( alignment ) ) {
     409                abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() );
     410        } // if
     411} // checkAlign
    380412
    381413
     
    391423static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & alignment ) {
    392424        if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?
    393                 size_t offset = header->kind.fake.offset;
    394425                alignment = header->kind.fake.alignment & -2;   // remove flag from value
    395426                #ifdef __CFA_DEBUG__
    396427                checkAlign( alignment );                                                // check alignment
    397428                #endif // __CFA_DEBUG__
    398                 header = (HeapManager.Storage.Header *)((char *)header - offset);
     429                header = realHeader( header );                                  // backup from fake to real header
     430        } else {
     431                alignment = libAlign();                                                 // => no fake header
    399432        } // if
    400433} // fakeHeader
    401434
    402435
    403 // <-------+----------------------------------------------------> bsize (bucket size)
    404 // |header |addr
    405 //==================================================================================
    406 //                                | alignment
    407 // <-----------------<------------+-----------------------------> bsize (bucket size)
    408 //                   |fake-header | addr
    409 #define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
    410 
    411 // <-------<<--------------------- dsize ---------------------->> bsize (bucket size)
    412 // |header |addr
    413 //==================================================================================
    414 //                                | alignment
    415 // <------------------------------<<---------- dsize --------->>> bsize (bucket size)
    416 //                   |fake-header |addr
    417 #define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header ))
    418 
    419 
    420 static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) {
     436static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem,
     437                                                        size_t & size, size_t & alignment ) with( heapManager ) {
    421438        header = headerAddr( addr );
    422439
    423         if ( unlikely( heapEnd < addr ) ) {                                     // mmapped ?
     440  if ( unlikely( addr < heapBegin || heapEnd < addr ) ) { // mmapped ?
    424441                fakeHeader( header, alignment );
    425442                size = header->kind.real.blockSize & -3;                // mmap size
     
    428445
    429446        #ifdef __CFA_DEBUG__
    430         checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
     447        checkHeader( header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
    431448        #endif // __CFA_DEBUG__
    432449
     
    449466} // headers
    450467
    451 
    452 static inline void * extend( size_t size ) with ( heapManager ) {
     468#ifdef __CFA_DEBUG__
     469#if __SIZEOF_POINTER__ == 4
     470#define MASK 0xdeadbeef
     471#else
     472#define MASK 0xdeadbeefdeadbeef
     473#endif
     474#define STRIDE size_t
     475
     476static void * Memset( void * addr, STRIDE size ) {              // debug only
     477        if ( size % sizeof(STRIDE) != 0 ) abort( "Memset() : internal error, size %zd not multiple of %zd.", size, sizeof(STRIDE) );
     478        if ( (STRIDE)addr % sizeof(STRIDE) != 0 ) abort( "Memset() : internal error, addr %p not multiple of %zd.", addr, sizeof(STRIDE) );
     479
     480        STRIDE * end = (STRIDE *)addr + size / sizeof(STRIDE);
     481        for ( STRIDE * p = (STRIDE *)addr; p < end; p += 1 ) *p = MASK;
     482        return addr;
     483} // Memset
     484#endif // __CFA_DEBUG__
     485
     486
     487#define NO_MEMORY_MSG "insufficient heap memory available for allocating %zd new bytes."
     488
     489static inline void * extend( size_t size ) with( heapManager ) {
    453490        lock( extlock __cfaabi_dbg_ctx2 );
    454491        ptrdiff_t rem = heapRemaining - size;
     
    456493                // If the size requested is bigger than the current remaining storage, increase the size of the heap.
    457494
    458                 size_t increase = libCeiling( size > heapExpand ? size : heapExpand, libAlign() );
    459                 if ( sbrk( increase ) == (void *)-1 ) {
     495                size_t increase = ceiling2( size > heapExpand ? size : heapExpand, __page_size );
     496                // Do not call abort or strerror( errno ) as they may call malloc.
     497                if ( sbrk( increase ) == (void *)-1 ) {                 // failed, no memory ?
    460498                        unlock( extlock );
    461                         errno = ENOMEM;
    462                         return 0p;
     499                        __cfaabi_bits_print_nolock( STDERR_FILENO, NO_MEMORY_MSG, size );
     500                        _exit( EXIT_FAILURE );
     501                } // if
     502                if ( mprotect( (char *)heapEnd + heapRemaining, increase, __map_prot ) ) {
     503                        unlock( extlock );
     504                        __cfaabi_bits_print_nolock( STDERR_FILENO, "extend() : internal error, mprotect failure, heapEnd:%p size:%zd, errno:%d.\n", heapEnd, increase, errno );
     505                        _exit( EXIT_FAILURE );
    463506                } // if
    464507                #ifdef __STATISTICS__
     
    468511                #ifdef __CFA_DEBUG__
    469512                // Set new memory to garbage so subsequent uninitialized usages might fail.
    470                 memset( (char *)heapEnd + heapRemaining, '\377', increase );
     513                memset( (char *)heapEnd + heapRemaining, '\xde', increase );
     514                //Memset( (char *)heapEnd + heapRemaining, increase );
    471515                #endif // __CFA_DEBUG__
    472516                rem = heapRemaining + increase - size;
     
    481525
    482526
    483 static inline void * doMalloc( size_t size ) with ( heapManager ) {
     527static inline void * doMalloc( size_t size ) with( heapManager ) {
    484528        HeapManager.Storage * block;                                            // pointer to new block of storage
    485529
     
    487531        // along with the block and is a multiple of the alignment size.
    488532
    489   if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0p;
     533  if ( unlikely( size > ULONG_MAX - sizeof(HeapManager.Storage) ) ) return 0p;
    490534        size_t tsize = size + sizeof(HeapManager.Storage);
    491535        if ( likely( tsize < mmapStart ) ) {                            // small size => sbrk
     
    497541                        posn = Bsearchl( (unsigned int)tsize, bucketSizes, (size_t)maxBucketsUsed );
    498542                HeapManager.FreeHeader * freeElem = &freeLists[posn];
    499                 // #ifdef FASTLOOKUP
    500                 // if ( tsize < LookupSizes )
    501                 //      freeElem = &freeLists[lookup[tsize]];
    502                 // else
    503                 // #endif // FASTLOOKUP
    504                 //      freeElem = bsearchl( tsize, freeLists, (size_t)maxBucketsUsed ); // binary search
    505                 // HeapManager.FreeHeader * freeElem =
    506                 //      #ifdef FASTLOOKUP
    507                 //      tsize < LookupSizes ? &freeLists[lookup[tsize]] :
    508                 //      #endif // FASTLOOKUP
    509                 //      bsearchl( tsize, freeLists, (size_t)maxBucketsUsed ); // binary search
    510                 assert( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ?
    511                 assert( tsize <= freeElem->blockSize );                 // search failure ?
     543                verify( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ?
     544                verify( tsize <= freeElem->blockSize );                 // search failure ?
    512545                tsize = freeElem->blockSize;                                    // total space needed for request
    513546
    514547                // Spin until the lock is acquired for this particular size of block.
    515548
    516                 #if defined( SPINLOCK )
     549                #if BUCKETLOCK == SPINLOCK
    517550                lock( freeElem->lock __cfaabi_dbg_ctx2 );
    518551                block = freeElem->freeList;                                             // remove node from stack
    519552                #else
    520                 block = freeElem->freeList.pop();
    521                 #endif // SPINLOCK
     553                block = pop( freeElem->freeList );
     554                #endif // BUCKETLOCK
    522555                if ( unlikely( block == 0p ) ) {                                // no free block ?
    523                         #if defined( SPINLOCK )
     556                        #if BUCKETLOCK == SPINLOCK
    524557                        unlock( freeElem->lock );
    525                         #endif // SPINLOCK
     558                        #endif // BUCKETLOCK
    526559
    527560                        // Freelist for that size was empty, so carve it out of the heap if there's enough left, or get some more
     
    529562
    530563                        block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call
    531   if ( unlikely( block == 0p ) ) return 0p;
    532                 #if defined( SPINLOCK )
     564                #if BUCKETLOCK == SPINLOCK
    533565                } else {
    534566                        freeElem->freeList = block->header.kind.real.next;
    535567                        unlock( freeElem->lock );
    536                 #endif // SPINLOCK
     568                #endif // BUCKETLOCK
    537569                } // if
    538570
    539571                block->header.kind.real.home = freeElem;                // pointer back to free list of apropriate size
    540572        } else {                                                                                        // large size => mmap
    541   if ( unlikely( size > ~0ul - pageSize ) ) return 0p;
    542                 tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
     573  if ( unlikely( size > ULONG_MAX - __page_size ) ) return 0p;
     574                tsize = ceiling2( tsize, __page_size );                 // must be multiple of page size
    543575                #ifdef __STATISTICS__
    544576                __atomic_add_fetch( &mmap_calls, 1, __ATOMIC_SEQ_CST );
    545577                __atomic_add_fetch( &mmap_storage, tsize, __ATOMIC_SEQ_CST );
    546578                #endif // __STATISTICS__
    547                 block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
    548                 if ( block == (HeapManager.Storage *)MAP_FAILED ) {
     579
     580                block = (HeapManager.Storage *)mmap( 0, tsize, __map_prot, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
     581                if ( block == (HeapManager.Storage *)MAP_FAILED ) { // failed ?
     582                        if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory
    549583                        // Do not call strerror( errno ) as it may call malloc.
    550                         abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu error:%d.", &heapManager, tsize, errno );
    551                 } // if
     584                        abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu errno:%d.", &heapManager, tsize, errno );
     585                } //if
    552586                #ifdef __CFA_DEBUG__
    553587                // Set new memory to garbage so subsequent uninitialized usages might fail.
    554                 memset( block, '\377', tsize );
     588                memset( block, '\xde', tsize );
     589                //Memset( block, tsize );
    555590                #endif // __CFA_DEBUG__
    556591                block->header.kind.real.blockSize = tsize;              // storage size for munmap
    557592        } // if
    558593
     594        block->header.kind.real.size = size;                            // store allocation size
    559595        void * addr = &(block->data);                                           // adjust off header to user bytes
     596        verify( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
    560597
    561598        #ifdef __CFA_DEBUG__
    562         assert( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
    563         __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST );
     599        __atomic_add_fetch( &allocUnfreed, tsize, __ATOMIC_SEQ_CST );
    564600        if ( traceHeap() ) {
    565601                enum { BufferSize = 64 };
    566602                char helpText[BufferSize];
    567603                int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", addr, size, tsize );
    568                 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", addr, size );
    569604                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    570605        } // if
     
    575610
    576611
    577 static inline void doFree( void * addr ) with ( heapManager ) {
     612static inline void doFree( void * addr ) with( heapManager ) {
    578613        #ifdef __CFA_DEBUG__
    579614        if ( unlikely( heapManager.heapBegin == 0p ) ) {
     
    592627                #endif // __STATISTICS__
    593628                if ( munmap( header, size ) == -1 ) {
    594                         #ifdef __CFA_DEBUG__
    595629                        abort( "Attempt to deallocate storage %p not allocated or with corrupt header.\n"
    596630                                   "Possible cause is invalid pointer.",
    597631                                   addr );
    598                         #endif // __CFA_DEBUG__
    599632                } // if
    600633        } else {
    601634                #ifdef __CFA_DEBUG__
    602635                // Set free memory to garbage so subsequent usages might fail.
    603                 memset( ((HeapManager.Storage *)header)->data, '\377', freeElem->blockSize - sizeof( HeapManager.Storage ) );
     636                memset( ((HeapManager.Storage *)header)->data, '\xde', freeElem->blockSize - sizeof( HeapManager.Storage ) );
     637                //Memset( ((HeapManager.Storage *)header)->data, freeElem->blockSize - sizeof( HeapManager.Storage ) );
    604638                #endif // __CFA_DEBUG__
    605639
     
    607641                free_storage += size;
    608642                #endif // __STATISTICS__
    609                 #if defined( SPINLOCK )
     643                #if BUCKETLOCK == SPINLOCK
    610644                lock( freeElem->lock __cfaabi_dbg_ctx2 );               // acquire spin lock
    611645                header->kind.real.next = freeElem->freeList;    // push on stack
     
    613647                unlock( freeElem->lock );                                               // release spin lock
    614648                #else
    615                 freeElem->freeList.push( *(HeapManager.Storage *)header );
    616                 #endif // SPINLOCK
     649                push( freeElem->freeList, *(HeapManager.Storage *)header );
     650                #endif // BUCKETLOCK
    617651        } // if
    618652
    619653        #ifdef __CFA_DEBUG__
    620         __atomic_add_fetch( &allocFree, -size, __ATOMIC_SEQ_CST );
     654        __atomic_add_fetch( &allocUnfreed, -size, __ATOMIC_SEQ_CST );
    621655        if ( traceHeap() ) {
    622                 enum { BufferSize = 64 };
    623                 char helpText[BufferSize];
     656                char helpText[64];
    624657                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    625658                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     
    629662
    630663
    631 size_t prtFree( HeapManager & manager ) with ( manager ) {
     664size_t prtFree( HeapManager & manager ) with( manager ) {
    632665        size_t total = 0;
    633666        #ifdef __STATISTICS__
     
    641674                #endif // __STATISTICS__
    642675
    643                 #if defined( SPINLOCK )
     676                #if BUCKETLOCK == SPINLOCK
    644677                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
    645678                #else
    646                 for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0p; p = p->header.kind.real.next.top ) {
    647                 #endif // SPINLOCK
     679                        for(;;) {
     680//              for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
     681//              for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {
     682//                      HeapManager.Storage * temp = p->header.kind.real.next.top; // FIX ME: direct assignent fails, initialization works`
     683//                      typeof(p) temp = (( p )`next)->top;                     // FIX ME: direct assignent fails, initialization works`
     684//                      p = temp;
     685                #endif // BUCKETLOCK
    648686                        total += size;
    649687                        #ifdef __STATISTICS__
     
    665703
    666704
    667 static void ?{}( HeapManager & manager ) with ( manager ) {
    668         pageSize = sysconf( _SC_PAGESIZE );
     705static void ?{}( HeapManager & manager ) with( manager ) {
     706        __page_size = sysconf( _SC_PAGESIZE );
     707        __map_prot = PROT_READ | PROT_WRITE | PROT_EXEC;
    669708
    670709        for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists
     
    680719        #endif // FASTLOOKUP
    681720
    682         if ( setMmapStart( default_mmap_start() ) ) {
     721        if ( ! setMmapStart( default_mmap_start() ) ) {
    683722                abort( "HeapManager : internal error, mmap start initialization failure." );
    684723        } // if
     
    686725
    687726        char * end = (char *)sbrk( 0 );
    688         sbrk( (char *)libCeiling( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
    689         heapBegin = heapEnd = sbrk( 0 );                                        // get new start point
     727        heapBegin = heapEnd = sbrk( (char *)ceiling2( (long unsigned int)end, __page_size ) - end ); // move start of heap to multiple of alignment
    690728} // HeapManager
    691729
     
    695733        if ( traceHeapTerm() ) {
    696734                printStats();
    697                 // if ( prtfree() ) prtFree( heapManager, true );
     735                // prtUnfreed() called in heapAppStop()
    698736        } // if
    699737        #endif // __STATISTICS__
     
    704742void memory_startup( void ) {
    705743        #ifdef __CFA_DEBUG__
    706         if ( unlikely( heapBoot ) ) {                                           // check for recursion during system boot
    707                 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
     744        if ( heapBoot ) {                                                                       // check for recursion during system boot
    708745                abort( "boot() : internal error, recursively invoked during system boot." );
    709746        } // if
     
    711748        #endif // __CFA_DEBUG__
    712749
    713         //assert( heapManager.heapBegin != 0 );
     750        //verify( heapManager.heapBegin != 0 );
    714751        //heapManager{};
    715         if ( heapManager.heapBegin == 0p ) heapManager{};
     752        if ( heapManager.heapBegin == 0p ) heapManager{};       // sanity check
    716753} // memory_startup
    717754
     
    723760
    724761static inline void * mallocNoStats( size_t size ) {             // necessary for malloc statistics
    725         //assert( heapManager.heapBegin != 0 );
    726         if ( unlikely( heapManager.heapBegin == 0p ) ) heapManager{}; // called before memory_startup ?
    727         void * addr = doMalloc( size );
    728         if ( unlikely( addr == 0p ) ) errno = ENOMEM;           // POSIX
    729         return addr;
     762        verify( heapManager.heapBegin != 0p );                          // called before memory_startup ?
     763  if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
     764
     765#if __SIZEOF_POINTER__ == 8
     766        verify( size < ((typeof(size_t))1 << 48) );
     767#endif // __SIZEOF_POINTER__ == 8
     768        return doMalloc( size );
    730769} // mallocNoStats
    731770
    732771
    733 static inline void * callocNoStats( size_t noOfElems, size_t elemSize ) {
    734         size_t size = noOfElems * elemSize;
     772static inline void * callocNoStats( size_t dim, size_t elemSize ) {
     773        size_t size = dim * elemSize;
     774  if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
    735775        char * addr = (char *)mallocNoStats( size );
    736   if ( unlikely( addr == 0p ) ) return 0p;
    737776
    738777        HeapManager.Storage.Header * header;
    739778        HeapManager.FreeHeader * freeElem;
    740779        size_t bsize, alignment;
    741         bool mapped __attribute__(( unused )) = headers( "calloc", addr, header, freeElem, bsize, alignment );
    742780        #ifndef __CFA_DEBUG__
     781        bool mapped =
     782        #endif // __CFA_DEBUG__
     783                headers( "calloc", addr, header, freeElem, bsize, alignment );
     784        #ifndef __CFA_DEBUG__
     785
    743786        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    744787        if ( ! mapped )
    745788        #endif // __CFA_DEBUG__
    746                 // Zero entire data space even when > than size => realloc without a new allocation and zero fill works.
    747                 // <-------00000000000000000000000000000000000000000000000000000> bsize (bucket size)
     789                // <-------0000000000000000000000000000UUUUUUUUUUUUUUUUUUUUUUUUU> bsize (bucket size) U => undefined
    748790                // `-header`-addr                      `-size
    749                 memset( addr, '\0', bsize - sizeof(HeapManager.Storage) ); // set to zeros
     791                memset( addr, '\0', size );                                             // set to zeros
    750792
    751793        header->kind.real.blockSize |= 2;                                       // mark as zero filled
     
    754796
    755797
    756 static inline void * memalignNoStats( size_t alignment, size_t size ) { // necessary for malloc statistics
     798static inline void * memalignNoStats( size_t alignment, size_t size ) {
     799  if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
     800
    757801        #ifdef __CFA_DEBUG__
    758802        checkAlign( alignment );                                                        // check alignment
     
    772816        // add sizeof(Storage) for fake header
    773817        char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
    774   if ( unlikely( addr == 0p ) ) return addr;
    775818
    776819        // address in the block of the "next" alignment address
    777         char * user = (char *)libCeiling( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
     820        char * user = (char *)ceiling2( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
    778821
    779822        // address of header from malloc
    780823        HeapManager.Storage.Header * realHeader = headerAddr( addr );
     824        realHeader->kind.real.size = size;                                      // correct size to eliminate above alignment offset
    781825        // address of fake header * before* the alignment location
    782826        HeapManager.Storage.Header * fakeHeader = headerAddr( user );
     
    790834
    791835
    792 static inline void * cmemalignNoStats( size_t alignment, size_t noOfElems, size_t elemSize ) {
    793         size_t size = noOfElems * elemSize;
     836static inline void * cmemalignNoStats( size_t alignment, size_t dim, size_t elemSize ) {
     837        size_t size = dim * elemSize;
     838  if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
    794839        char * addr = (char *)memalignNoStats( alignment, size );
    795   if ( unlikely( addr == 0p ) ) return 0p;
     840
    796841        HeapManager.Storage.Header * header;
    797842        HeapManager.FreeHeader * freeElem;
    798843        size_t bsize;
    799         bool mapped __attribute__(( unused )) = headers( "cmemalign", addr, header, freeElem, bsize, alignment );
    800844        #ifndef __CFA_DEBUG__
     845        bool mapped =
     846        #endif // __CFA_DEBUG__
     847                headers( "cmemalign", addr, header, freeElem, bsize, alignment );
     848
    801849        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
     850        #ifndef __CFA_DEBUG__
    802851        if ( ! mapped )
    803852        #endif // __CFA_DEBUG__
    804                 memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros
    805         header->kind.real.blockSize |= 2;                               // mark as zero filled
    806 
     853                // <-------0000000000000000000000000000UUUUUUUUUUUUUUUUUUUUUUUUU> bsize (bucket size) U => undefined
     854                // `-header`-addr                      `-size
     855                memset( addr, '\0', size );                                             // set to zeros
     856
     857        header->kind.real.blockSize |= 2;                                       // mark as zero filled
    807858        return addr;
    808859} // cmemalignNoStats
    809860
    810861
    811 // supported mallopt options
    812 #ifndef M_MMAP_THRESHOLD
    813 #define M_MMAP_THRESHOLD (-1)
    814 #endif // M_TOP_PAD
    815 #ifndef M_TOP_PAD
    816 #define M_TOP_PAD (-2)
    817 #endif // M_TOP_PAD
    818 
    819 
    820862extern "C" {
    821         // The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not
    822         // initialized. If size is 0, then malloc() returns either 0p, or a unique pointer value that can later be
    823         // successfully passed to free().
     863        // Allocates size bytes and returns a pointer to the allocated memory.  The contents are undefined. If size is 0,
     864        // then malloc() returns a unique pointer value that can later be successfully passed to free().
    824865        void * malloc( size_t size ) {
    825866                #ifdef __STATISTICS__
     
    831872        } // malloc
    832873
    833         // The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to
    834         // the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either 0p, or a
    835         // unique pointer value that can later be successfully passed to free().
    836         void * calloc( size_t noOfElems, size_t elemSize ) {
     874
     875        // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes.
     876        void * aalloc( size_t dim, size_t elemSize ) {
     877                size_t size = dim * elemSize;
     878                #ifdef __STATISTICS__
     879                __atomic_add_fetch( &aalloc_calls, 1, __ATOMIC_SEQ_CST );
     880                __atomic_add_fetch( &aalloc_storage, size, __ATOMIC_SEQ_CST );
     881                #endif // __STATISTICS__
     882
     883                return mallocNoStats( size );
     884        } // aalloc
     885
     886
     887        // Same as aalloc() with memory set to zero.
     888        void * calloc( size_t dim, size_t elemSize ) {
    837889                #ifdef __STATISTICS__
    838890                __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );
    839                 __atomic_add_fetch( &calloc_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
    840                 #endif // __STATISTICS__
    841 
    842                 return callocNoStats( noOfElems, elemSize );
     891                __atomic_add_fetch( &calloc_storage, dim * elemSize, __ATOMIC_SEQ_CST );
     892                #endif // __STATISTICS__
     893
     894                return callocNoStats( dim, elemSize );
    843895        } // calloc
    844896
    845         // The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be
    846         // unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size
    847         // is larger than the old size, the added memory will not be initialized.  If ptr is 0p, then the call is
    848         // equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not 0p, then the call
    849         // is equivalent to free(ptr). Unless ptr is 0p, it must have been returned by an earlier call to malloc(),
    850         // calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.
    851         void * realloc( void * oaddr, size_t size ) {
    852                 #ifdef __STATISTICS__
    853                 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
     897
     898        // Change the size of the memory block pointed to by oaddr to size bytes. The contents are undefined.  If oaddr is
     899        // 0p, then the call is equivalent to malloc(size), for all values of size; if size is equal to zero, and oaddr is
     900        // not 0p, then the call is equivalent to free(oaddr). Unless oaddr is 0p, it must have been returned by an earlier
     901        // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done.
     902        void * resize( void * oaddr, size_t size ) {
     903                #ifdef __STATISTICS__
     904                __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
    854905                #endif // __STATISTICS__
    855906
    856907                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    857           if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
    858           if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
     908          if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
     909          if ( unlikely( oaddr == 0p ) ) {
     910                        #ifdef __STATISTICS__
     911                        __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
     912                        #endif // __STATISTICS__
     913                        return mallocNoStats( size );
     914                } // if
    859915
    860916                HeapManager.Storage.Header * header;
    861917                HeapManager.FreeHeader * freeElem;
    862                 size_t bsize, oalign = 0;
     918                size_t bsize, oalign;
     919                headers( "resize", oaddr, header, freeElem, bsize, oalign );
     920                size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
     921
     922                // same size, DO NOT preserve STICKY PROPERTIES.
     923                if ( oalign == libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
     924                        header->kind.real.blockSize &= -2;                      // no alignment and turn off 0 fill
     925                        header->kind.real.size = size;                          // reset allocation size
     926                        return oaddr;
     927                } // if
     928
     929                #ifdef __STATISTICS__
     930                __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
     931                #endif // __STATISTICS__
     932
     933                // change size, DO NOT preserve STICKY PROPERTIES.
     934                free( oaddr );
     935                return mallocNoStats( size );                                   // create new area
     936        } // resize
     937
     938
     939        // Same as resize() but the contents are unchanged in the range from the start of the region up to the minimum of
     940        // the old and new sizes.
     941        void * realloc( void * oaddr, size_t size ) {
     942                #ifdef __STATISTICS__
     943                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
     944                #endif // __STATISTICS__
     945
     946                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
     947          if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
     948          if ( unlikely( oaddr == 0p ) ) {
     949                        #ifdef __STATISTICS__
     950                        __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
     951                        #endif // __STATISTICS__
     952                        return mallocNoStats( size );
     953                } // if
     954
     955                HeapManager.Storage.Header * header;
     956                HeapManager.FreeHeader * freeElem;
     957                size_t bsize, oalign;
    863958                headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    864959
    865960                size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    866           if ( size <= odsize && odsize <= size * 2 ) { // allow up to 50% wasted storage in smaller size
    867                         // Do not know size of original allocation => cannot do 0 fill for any additional space because do not know
    868                         // where to start filling, i.e., do not overwrite existing values in space.
    869                         //
    870                         // This case does not result in a new profiler entry because the previous one still exists and it must match with
    871                         // the free for this memory.  Hence, this realloc does not appear in the profiler output.
     961                size_t osize = header->kind.real.size;                  // old allocation size
     962                bool ozfill = (header->kind.real.blockSize & 2); // old allocation zero filled
     963          if ( unlikely( size <= odsize ) && odsize <= size * 2 ) { // allow up to 50% wasted storage
     964                        header->kind.real.size = size;                          // reset allocation size
     965                        if ( unlikely( ozfill ) && size > osize ) {     // previous request zero fill and larger ?
     966                                memset( (char *)oaddr + osize, '\0', size - osize ); // initialize added storage
     967                        } // if
    872968                        return oaddr;
    873969                } // if
    874970
    875971                #ifdef __STATISTICS__
    876                 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
     972                __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    877973                #endif // __STATISTICS__
    878974
     
    880976
    881977                void * naddr;
    882                 if ( unlikely( oalign != 0 ) ) {                                // previous request memalign?
    883                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    884                                 naddr = cmemalignNoStats( oalign, 1, size ); // create new aligned area
    885                         } else {
    886                                 naddr = memalignNoStats( oalign, size ); // create new aligned area
     978                if ( likely( oalign == libAlign() ) ) {                 // previous request not aligned ?
     979                        naddr = mallocNoStats( size );                          // create new area
     980                } else {
     981                        naddr = memalignNoStats( oalign, size );        // create new aligned area
     982                } // if
     983
     984                headers( "realloc", naddr, header, freeElem, bsize, oalign );
     985                memcpy( naddr, oaddr, min( osize, size ) );             // copy bytes
     986                free( oaddr );
     987
     988                if ( unlikely( ozfill ) ) {                                             // previous request zero fill ?
     989                        header->kind.real.blockSize |= 2;                       // mark new request as zero filled
     990                        if ( size > osize ) {                                           // previous request larger ?
     991                                memset( (char *)naddr + osize, '\0', size - osize ); // initialize added storage
    887992                        } // if
    888                 } else {
    889                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    890                                 naddr = callocNoStats( 1, size );               // create new area
    891                         } else {
    892                                 naddr = mallocNoStats( size );                  // create new area
    893                         } // if
    894                 } // if
    895           if ( unlikely( naddr == 0p ) ) return 0p;
    896 
    897                 headers( "realloc", naddr, header, freeElem, bsize, oalign );
    898                 size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
    899                 // To preserve prior fill, the entire bucket must be copied versus the size.
    900                 memcpy( naddr, oaddr, MIN( odsize, ndsize ) );  // copy bytes
    901                 free( oaddr );
     993                } // if
    902994                return naddr;
    903995        } // realloc
    904996
    905         // The obsolete function memalign() allocates size bytes and returns a pointer to the allocated memory. The memory
    906         // address will be a multiple of alignment, which must be a power of two.
     997
     998        // Same as malloc() except the memory address is a multiple of alignment, which must be a power of two. (obsolete)
    907999        void * memalign( size_t alignment, size_t size ) {
    9081000                #ifdef __STATISTICS__
     
    9151007
    9161008
    917         // The cmemalign() function is the same as calloc() with memory alignment.
    918         void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {
     1009        // Same as aalloc() with memory alignment.
     1010        void * amemalign( size_t alignment, size_t dim, size_t elemSize ) {
     1011                size_t size = dim * elemSize;
    9191012                #ifdef __STATISTICS__
    9201013                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    921                 __atomic_add_fetch( &cmemalign_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
    922                 #endif // __STATISTICS__
    923 
    924                 return cmemalignNoStats( alignment, noOfElems, elemSize );
     1014                __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST );
     1015                #endif // __STATISTICS__
     1016
     1017                return memalignNoStats( alignment, size );
     1018        } // amemalign
     1019
     1020
     1021        // Same as calloc() with memory alignment.
     1022        void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) {
     1023                #ifdef __STATISTICS__
     1024                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
     1025                __atomic_add_fetch( &cmemalign_storage, dim * elemSize, __ATOMIC_SEQ_CST );
     1026                #endif // __STATISTICS__
     1027
     1028                return cmemalignNoStats( alignment, dim, elemSize );
    9251029        } // cmemalign
    9261030
    927         // The function aligned_alloc() is the same as memalign(), except for the added restriction that size should be a
    928         // multiple of alignment.
     1031
     1032        // Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple
     1033    // of alignment. This requirement is universally ignored.
    9291034        void * aligned_alloc( size_t alignment, size_t size ) {
    9301035                return memalign( alignment, size );
     
    9321037
    9331038
    934         // The function posix_memalign() allocates size bytes and places the address of the allocated memory in *memptr. The
    935         // address of the allocated memory will be a multiple of alignment, which must be a power of two and a multiple of
    936         // sizeof(void *). If size is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later
    937         // be successfully passed to free(3).
     1039        // Allocates size bytes and places the address of the allocated memory in *memptr. The address of the allocated
     1040        // memory shall be a multiple of alignment, which must be a power of two and a multiple of sizeof(void *). If size
     1041        // is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later be successfully passed to
     1042        // free(3).
    9381043        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    939           if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
     1044          if ( alignment < libAlign() || ! is_pow2( alignment ) ) return EINVAL; // check alignment
    9401045                * memptr = memalign( alignment, size );
    941           if ( unlikely( * memptr == 0p ) ) return ENOMEM;
    9421046                return 0;
    9431047        } // posix_memalign
    9441048
    945         // The obsolete function valloc() allocates size bytes and returns a pointer to the allocated memory. The memory
    946         // address will be a multiple of the page size.  It is equivalent to memalign(sysconf(_SC_PAGESIZE),size).
     1049
     1050        // Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of the
     1051        // page size.  It is equivalent to memalign(sysconf(_SC_PAGESIZE),size).
    9471052        void * valloc( size_t size ) {
    948                 return memalign( pageSize, size );
     1053                return memalign( __page_size, size );
    9491054        } // valloc
    9501055
    9511056
    952         // The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to
    953         // malloc(), calloc() or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behavior
    954         // occurs. If ptr is 0p, no operation is performed.
     1057        // Same as valloc but rounds size to multiple of page size.
     1058        void * pvalloc( size_t size ) {
     1059                return memalign( __page_size, ceiling2( size, __page_size ) );
     1060        } // pvalloc
     1061
     1062
     1063        // Frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc()
     1064        // or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behaviour occurs. If ptr is
     1065        // 0p, no operation is performed.
    9551066        void free( void * addr ) {
    9561067                #ifdef __STATISTICS__
     
    9731084
    9741085
    975         // The malloc_alignment() function returns the alignment of the allocation.
     1086        // Returns the alignment of an allocation.
    9761087        size_t malloc_alignment( void * addr ) {
    9771088          if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
     
    9801091                        return header->kind.fake.alignment & -2;        // remove flag from value
    9811092                } else {
    982                         return libAlign ();                                                     // minimum alignment
     1093                        return libAlign();                                                      // minimum alignment
    9831094                } // if
    9841095        } // malloc_alignment
    9851096
    9861097
    987         // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc().
     1098        // Set the alignment for an the allocation and return previous alignment or 0 if no alignment.
     1099        size_t $malloc_alignment_set( void * addr, size_t alignment ) {
     1100          if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
     1101                size_t ret;
     1102                HeapManager.Storage.Header * header = headerAddr( addr );
     1103                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     1104                        ret = header->kind.fake.alignment & -2;         // remove flag from old value
     1105                        header->kind.fake.alignment = alignment | 1; // add flag to new value
     1106                } else {
     1107                        ret = 0;                                                                        // => no alignment to change
     1108                } // if
     1109                return ret;
     1110        } // $malloc_alignment_set
     1111
     1112
     1113        // Returns true if the allocation is zero filled, e.g., allocated by calloc().
    9881114        bool malloc_zero_fill( void * addr ) {
    9891115          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    9901116                HeapManager.Storage.Header * header = headerAddr( addr );
    9911117                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    992                         header = (HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset);
    993                 } // if
    994                 return (header->kind.real.blockSize & 2) != 0;  // zero filled (calloc/cmemalign) ?
     1118                        header = realHeader( header );                          // backup from fake to real header
     1119                } // if
     1120                return (header->kind.real.blockSize & 2) != 0;  // zero filled ?
    9951121        } // malloc_zero_fill
    9961122
    997 
    998         // The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer to
    999         // a block of memory allocated by malloc(3) or a related function.
     1123        // Set allocation is zero filled and return previous zero filled.
     1124        bool $malloc_zero_fill_set( void * addr ) {
     1125          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
     1126                HeapManager.Storage.Header * header = headerAddr( addr );
     1127                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     1128                        header = realHeader( header );                          // backup from fake to real header
     1129                } // if
     1130                bool ret = (header->kind.real.blockSize & 2) != 0; // zero filled ?
     1131                header->kind.real.blockSize |= 2;                               // mark as zero filled
     1132                return ret;
     1133        } // $malloc_zero_fill_set
     1134
     1135
     1136        // Returns original total allocation size (not bucket size) => array size is dimension * sizeif(T).
     1137        size_t malloc_size( void * addr ) {
     1138          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has zero size
     1139                HeapManager.Storage.Header * header = headerAddr( addr );
     1140                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     1141                        header = realHeader( header );                          // backup from fake to real header
     1142                } // if
     1143                return header->kind.real.size;
     1144        } // malloc_size
     1145
     1146        // Set allocation size and return previous size.
     1147        size_t $malloc_size_set( void * addr, size_t size ) {
     1148          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
     1149                HeapManager.Storage.Header * header = headerAddr( addr );
     1150                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     1151                        header = realHeader( header );                          // backup from fake to real header
     1152                } // if
     1153                size_t ret = header->kind.real.size;
     1154                header->kind.real.size = size;
     1155                return ret;
     1156        } // $malloc_size_set
     1157
     1158
     1159        // Returns the number of usable bytes in the block pointed to by ptr, a pointer to a block of memory allocated by
     1160        // malloc or a related function.
    10001161        size_t malloc_usable_size( void * addr ) {
    10011162          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
     
    10051166
    10061167                headers( "malloc_usable_size", addr, header, freeElem, bsize, alignment );
    1007                 return dataStorage( bsize, addr, header );      // data storage in bucket
     1168                return dataStorage( bsize, addr, header );              // data storage in bucket
    10081169        } // malloc_usable_size
    10091170
    10101171
    1011         // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and
    1012         // related functions.
     1172        // Prints (on default standard error) statistics about memory allocated by malloc and related functions.
    10131173        void malloc_stats( void ) {
    10141174                #ifdef __STATISTICS__
     
    10181178        } // malloc_stats
    10191179
    1020         // The malloc_stats_fd() function changes the file descripter where malloc_stats() writes the statistics.
     1180
     1181        // Changes the file descripter where malloc_stats() writes statistics.
    10211182        int malloc_stats_fd( int fd __attribute__(( unused )) ) {
    10221183                #ifdef __STATISTICS__
    1023                 int temp = statfd;
    1024                 statfd = fd;
     1184                int temp = stat_fd;
     1185                stat_fd = fd;
    10251186                return temp;
    10261187                #else
     
    10301191
    10311192
    1032         // The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see
    1033         // malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that
    1034         // parameter.
     1193        // Adjusts parameters that control the behaviour of the memory-allocation functions (see malloc). The param argument
     1194        // specifies the parameter to be modified, and value specifies the new value for that parameter.
    10351195        int mallopt( int option, int value ) {
    10361196                choose( option ) {
    10371197                  case M_TOP_PAD:
    1038                         if ( setHeapExpand( value ) ) return 1;
     1198                        heapExpand = ceiling2( value, __page_size ); return 1;
    10391199                  case M_MMAP_THRESHOLD:
    10401200                        if ( setMmapStart( value ) ) return 1;
     1201                        break;
    10411202                } // switch
    10421203                return 0;                                                                               // error, unsupported
    10431204        } // mallopt
    10441205
    1045         // The malloc_trim() function attempts to release free memory at the top of the heap (by calling sbrk(2) with a
    1046         // suitable argument).
     1206
     1207        // Attempt to release free memory at the top of the heap (by calling sbrk with a suitable argument).
    10471208        int malloc_trim( size_t ) {
    10481209                return 0;                                                                               // => impossible to release memory
     
    10501211
    10511212
    1052         // The malloc_info() function exports an XML string that describes the current state of the memory-allocation
    1053         // implementation in the caller.  The string is printed on the file stream stream.  The exported string includes
    1054         // information about all arenas (see malloc(3)).
     1213        // Exports an XML string that describes the current state of the memory-allocation implementation in the caller.
     1214        // The string is printed on the file stream stream.  The exported string includes information about all arenas (see
     1215        // malloc).
    10551216        int malloc_info( int options, FILE * stream ) {
    1056                 if ( options != 0 ) { errno = EINVAL; return -1; }
     1217          if ( options != 0 ) { errno = EINVAL; return -1; }
     1218                #ifdef __STATISTICS__
    10571219                return printStatsXML( stream );
     1220                #else
     1221                return 0;                                                                               // unsupported
     1222                #endif // __STATISTICS__
    10581223        } // malloc_info
    10591224
    10601225
    1061         // The malloc_get_state() function records the current state of all malloc(3) internal bookkeeping variables (but
    1062         // not the actual contents of the heap or the state of malloc_hook(3) functions pointers).  The state is recorded in
    1063         // a system-dependent opaque data structure dynamically allocated via malloc(3), and a pointer to that data
    1064         // structure is returned as the function result.  (It is the caller's responsibility to free(3) this memory.)
     1226        // Records the current state of all malloc internal bookkeeping variables (but not the actual contents of the heap
     1227        // or the state of malloc_hook functions pointers).  The state is recorded in a system-dependent opaque data
     1228        // structure dynamically allocated via malloc, and a pointer to that data structure is returned as the function
     1229        // result.  (The caller must free this memory.)
    10651230        void * malloc_get_state( void ) {
    10661231                return 0p;                                                                              // unsupported
     
    10681233
    10691234
    1070         // The malloc_set_state() function restores the state of all malloc(3) internal bookkeeping variables to the values
    1071         // recorded in the opaque data structure pointed to by state.
    1072         int malloc_set_state( void * ptr ) {
     1235        // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data
     1236        // structure pointed to by state.
     1237        int malloc_set_state( void * ) {
    10731238                return 0;                                                                               // unsupported
    10741239        } // malloc_set_state
     
    10771242
    10781243// Must have CFA linkage to overload with C linkage realloc.
    1079 void * realloc( void * oaddr, size_t nalign, size_t size ) {
     1244void * resize( void * oaddr, size_t nalign, size_t size ) {
    10801245        #ifdef __STATISTICS__
    1081         __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
     1246        __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
    10821247        #endif // __STATISTICS__
    10831248
    1084         // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1085   if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
    1086   if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
    1087 
    1088         if ( unlikely( nalign == 0 ) ) nalign = libAlign();     // reset alignment to minimum
     1249        if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum
    10891250        #ifdef __CFA_DEBUG__
    10901251        else
     
    10921253        #endif // __CFA_DEBUG__
    10931254
    1094         HeapManager.Storage.Header * header;
    1095         HeapManager.FreeHeader * freeElem;
    1096         size_t bsize, oalign = 0;
    1097         headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    1098         size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    1099 
    1100   if ( oalign != 0 && (uintptr_t)oaddr % nalign == 0 ) { // has alignment and just happens to work out
    1101                 headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1102                 return realloc( oaddr, size );
     1255        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
     1256  if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
     1257  if ( unlikely( oaddr == 0p ) ) {
     1258                #ifdef __STATISTICS__
     1259                __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
     1260                #endif // __STATISTICS__
     1261                return memalignNoStats( nalign, size );
     1262        } // if
     1263
     1264        // Attempt to reuse existing alignment.
     1265        HeapManager.Storage.Header * header = headerAddr( oaddr );
     1266        bool isFakeHeader = header->kind.fake.alignment & 1; // old fake header ?
     1267        size_t oalign;
     1268        if ( isFakeHeader ) {
     1269                oalign = header->kind.fake.alignment & -2;              // old alignment
     1270                if ( (uintptr_t)oaddr % nalign == 0                             // lucky match ?
     1271                         && ( oalign <= nalign                                          // going down
     1272                                  || (oalign >= nalign && oalign <= 256) ) // little alignment storage wasted ?
     1273                        ) {
     1274                        headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
     1275                        HeapManager.FreeHeader * freeElem;
     1276                        size_t bsize, oalign;
     1277                        headers( "resize", oaddr, header, freeElem, bsize, oalign );
     1278                        size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
     1279
     1280                        if ( size <= odsize && odsize <= size * 2 ) { // allow 50% wasted data storage
     1281                                headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
     1282
     1283                                header->kind.real.blockSize &= -2;              // turn off 0 fill
     1284                                header->kind.real.size = size;                  // reset allocation size
     1285                                return oaddr;
     1286                        } // if
     1287                } // if
     1288        } else if ( ! isFakeHeader                                                      // old real header (aligned on libAlign) ?
     1289                                && nalign == libAlign() ) {                             // new alignment also on libAlign => no fake header needed
     1290                return resize( oaddr, size );                                   // duplicate special case checks
    11031291        } // if
    11041292
    11051293        #ifdef __STATISTICS__
     1294        __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
     1295        #endif // __STATISTICS__
     1296
     1297        // change size, DO NOT preserve STICKY PROPERTIES.
     1298        free( oaddr );
     1299        return memalignNoStats( nalign, size );                         // create new aligned area
     1300} // resize
     1301
     1302
     1303void * realloc( void * oaddr, size_t nalign, size_t size ) {
     1304        if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum
     1305        #ifdef __CFA_DEBUG__
     1306        else
     1307                checkAlign( nalign );                                                   // check alignment
     1308        #endif // __CFA_DEBUG__
     1309
     1310        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
     1311  if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
     1312  if ( unlikely( oaddr == 0p ) ) {
     1313                #ifdef __STATISTICS__
     1314                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
     1315                __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
     1316                #endif // __STATISTICS__
     1317                return memalignNoStats( nalign, size );
     1318        } // if
     1319
     1320        // Attempt to reuse existing alignment.
     1321        HeapManager.Storage.Header * header = headerAddr( oaddr );
     1322        bool isFakeHeader = header->kind.fake.alignment & 1; // old fake header ?
     1323        size_t oalign;
     1324        if ( isFakeHeader ) {
     1325                oalign = header->kind.fake.alignment & -2;              // old alignment
     1326                if ( (uintptr_t)oaddr % nalign == 0                             // lucky match ?
     1327                         && ( oalign <= nalign                                          // going down
     1328                                  || (oalign >= nalign && oalign <= 256) ) // little alignment storage wasted ?
     1329                        ) {
     1330                        headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
     1331                        return realloc( oaddr, size );                          // duplicate alignment and special case checks
     1332                } // if
     1333        } else if ( ! isFakeHeader                                                      // old real header (aligned on libAlign) ?
     1334                                && nalign == libAlign() )                               // new alignment also on libAlign => no fake header needed
     1335                return realloc( oaddr, size );                                  // duplicate alignment and special case checks
     1336
     1337        #ifdef __STATISTICS__
     1338        __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    11061339        __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    11071340        #endif // __STATISTICS__
    11081341
     1342        HeapManager.FreeHeader * freeElem;
     1343        size_t bsize;
     1344        headers( "realloc", oaddr, header, freeElem, bsize, oalign );
     1345
    11091346        // change size and copy old content to new storage
    11101347
    1111         void * naddr;
    1112         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    1113                 naddr = cmemalignNoStats( nalign, 1, size );    // create new aligned area
    1114         } else {
    1115                 naddr = memalignNoStats( nalign, size );                // create new aligned area
    1116         } // if
     1348        size_t osize = header->kind.real.size;                          // old allocation size
     1349        bool ozfill = (header->kind.real.blockSize & 2);        // old allocation zero filled
     1350
     1351        void * naddr = memalignNoStats( nalign, size );         // create new aligned area
    11171352
    11181353        headers( "realloc", naddr, header, freeElem, bsize, oalign );
    1119         size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
    1120         // To preserve prior fill, the entire bucket must be copied versus the size.
    1121         memcpy( naddr, oaddr, MIN( odsize, ndsize ) );          // copy bytes
     1354        memcpy( naddr, oaddr, min( osize, size ) );                     // copy bytes
    11221355        free( oaddr );
     1356
     1357        if ( unlikely( ozfill ) ) {                                                     // previous request zero fill ?
     1358                header->kind.real.blockSize |= 2;                               // mark new request as zero filled
     1359                if ( size > osize ) {                                                   // previous request larger ?
     1360                        memset( (char *)naddr + osize, '\0', size - osize ); // initialize added storage
     1361                } // if
     1362        } // if
    11231363        return naddr;
    11241364} // realloc
Note: See TracChangeset for help on using the changeset viewer.