utilities/standaloneallocator/newallocator.cpp
changeset 16 3c88a81ff781
equal deleted inserted replaced
14:6aeb7a756187 16:3c88a81ff781
       
     1 /*
       
     2  * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3  *
       
     4  * This file is part of Qt Web Runtime.
       
     5  *
       
     6  * This library is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Lesser General Public License
       
     8  * version 2.1 as published by the Free Software Foundation.
       
     9  *
       
    10  * This library is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
       
    13  * Lesser General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU Lesser General Public
       
    16  * License along with this library; if not, write to the Free Software
       
    17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  */
       
    20 
       
    21 
       
    22 /****************************************************************************
       
    23  *
       
    24  * This file is part of the Symbian application wrapper of the Qt Toolkit.
       
    25  *
       
    26  * The memory allocator is backported from Symbian OS, and can eventually
       
    27  * be removed from Qt once it is built in to all supported OS versions.
       
    28  * The allocator is a composite of three allocators:
       
    29  *  - A page allocator, for large allocations
       
    30  *  - A slab allocator, for small allocations
       
    31  *  - Doug Lea's allocator, for medium size allocations
       
    32  *
       
    33  ***************************************************************************/
       
    34 
       
    35 
       
    36 #include <e32std.h>
       
    37 #include <e32cmn.h>
       
    38 #include <hal.h>
       
    39 #include <e32panic.h>
       
    40 
       
    41 #ifndef QT_SYMBIAN_HAVE_U32STD_H
       
    42 struct SThreadCreateInfo
       
    43     {
       
    44     TAny* iHandle;
       
    45     TInt iType;
       
    46     TThreadFunction iFunction;
       
    47     TAny* iPtr;
       
    48     TAny* iSupervisorStack;
       
    49     TInt iSupervisorStackSize;
       
    50     TAny* iUserStack;
       
    51     TInt iUserStackSize;
       
    52     TInt iInitialThreadPriority;
       
    53     TPtrC iName;
       
    54     TInt iTotalSize;    // Size including any extras (must be a multiple of 8 bytes)
       
    55     };
       
    56 
       
    57 struct SStdEpocThreadCreateInfo : public SThreadCreateInfo
       
    58     {
       
    59     RAllocator* iAllocator;
       
    60     TInt iHeapInitialSize;
       
    61     TInt iHeapMaxSize;
       
    62     TInt iPadding;      // Make structure size a multiple of 8 bytes
       
    63     };
       
    64 #else
       
    65 #include <u32std.h>
       
    66 #endif
       
    67 #include <e32svr.h>
       
    68 
       
    69 //Named local chunks require support from the kernel, which depends on Symbian^3
       
    70 #define NO_NAMED_LOCAL_CHUNKS
       
    71 //Reserving a minimum heap size is not supported, because the implementation does not know what type of
       
    72 //memory to use. DLA memory grows upwards, slab and page allocators grow downwards.
       
    73 //This would need kernel support to do properly.
       
    74 #define NO_RESERVE_MEMORY
       
    75 
       
    76 //The BTRACE debug framework requires Symbian OS 9.4 or higher.
       
    77 //Required header files are not included in S60 5.0 SDKs, but
       
    78 //they are available for open source versions of Symbian OS.
       
    79 //Note that although Symbian OS 9.3 supports BTRACE, the usage in this file
       
    80 //depends on 9.4 header files.
       
    81 
       
    82 //This debug flag uses BTRACE to emit debug traces to identify the heaps.
       
    83 //Note that it uses the ETest1 trace category which is not reserved
       
    84 //#define TRACING_HEAPS
       
    85 //This debug flag uses BTRACE to emit debug traces to aid with debugging
       
    86 //allocs, frees & reallocs. It should be used together with the KUSERHEAPTRACE
       
    87 //kernel trace flag to enable heap tracing.
       
    88 //#define TRACING_ALLOCS
       
    89 //This debug flag turns on tracing of the call stack for each alloc trace.
       
    90 //It is dependent on TRACING_ALLOCS.
       
    91 //#define TRACING_CALLSTACKS
       
    92 
       
    93 #if defined(TRACING_ALLOCS) || defined(TRACING_HEAPS)
       
    94 #include <e32btrace.h>
       
    95 #endif
       
    96 
       
    97 // Memory logging routines inherited from webkit allocator 9.2TB.
       
    98 // #define OOM_LOGGING
       
    99 // This debug flag logs error conditions when memory is unmapped/mapped from the system.
       
   100 // Also, exports routines to dump the internal state and memory usage of the DL allocator.
       
   101 // #define DL_CHUNK_MEM_DEBUG
       
   102 // Exports debug rouintes to assert/trace chunked memory access.
       
   103 #if defined(OOM_LOGGING) || defined(DL_CHUNK_MEM_DEBUG)
       
   104 #include "MemoryLogger.h"
       
   105 #endif
       
   106 
       
   107 
       
   108 #ifndef __WINS__
       
   109 #pragma push
       
   110 #pragma arm
       
   111 #endif
       
   112 
       
   113 #include "dla_p.h"
       
   114 #include "newallocator_p.h"
       
   115 
       
   116 // if non zero this causes the slabs to be configured only when the chunk size exceeds this level
       
   117 #define DELAYED_SLAB_THRESHOLD (64*1024)        // 64KB seems about right based on trace data
       
   118 #define SLAB_CONFIG (0xabe)
       
   119 
       
   120 _LIT(KDLHeapPanicCategory, "DL Heap");
       
   121 #define GET_PAGE_SIZE(x)            HAL::Get(HALData::EMemoryPageSize, x)
       
   122 #define __CHECK_CELL(p)
       
   123 #define __POWER_OF_2(x)             ((TUint32)((x)^((x)-1))>=(TUint32)(x))
       
   124 #define HEAP_PANIC(r)               Panic(r)
       
   125 
       
   126 LOCAL_C void Panic(TCdtPanic aPanic)
       
   127 // Panic the process with USER as the category.
       
   128     {
       
   129     User::Panic(_L("USER"),aPanic);
       
   130     }
       
   131 
       
   132     /* Purpose:     Map chunk memory pages from system RAM
       
   133  * Arguments:   tp - tchunkptr in which memmory should be mapped
       
   134  *              psize - incoming tchunk size
       
   135  * Return:      KErrNone if successful, else KErrNoMemory
       
   136  * Note:
       
   137  */
       
   138 TInt RNewAllocator::map_chunk_pages(tchunkptr tp, size_t psize)
       
   139 {
       
   140     if (page_not_in_memory(tp, psize)) {
       
   141         char *a_addr = tchunk_page_align(tp);
       
   142         size_t npages = tp->npages;
       
   143 
       
   144 #ifdef OOM_LOGGING
       
   145         // check that npages matches the psize
       
   146         size_t offset = address_offset(a_addr,tp);
       
   147         if (offset < psize && (psize - offset) >= mparams.page_size )
       
   148         {
       
   149             size_t tpages = ( psize - offset) >> pageshift;
       
   150             if (tpages != tp->npages) //assert condition
       
   151                 MEM_LOG("CHUNK_PAGE_ERROR:map_chunk_pages, error in npages");
       
   152         }
       
   153         else
       
   154             MEM_LOG("CHUNK_PAGE_ERROR::map_chunk_pages: - Incorrect page-in-memmory flag");
       
   155 #endif
       
   156 
       
   157         if (map(a_addr, npages*mparams.page_size)) {
       
   158             TRACE_DL_CHUNK_MAP(tp, psize, a_addr, npages*mparams.page_size);
       
   159             ASSERT_RCHUNK_SIZE();
       
   160             TRACE_UNMAPPED_CHUNK(-1*npages*mparams.page_size);
       
   161             return KErrNone;
       
   162         }
       
   163         else {
       
   164 #ifdef OOM_LOGGING
       
   165 
       
   166             MEM_LOGF(_L8("CHUNK_PAGE_ERROR:: map_chunk_pages - Failed to Commit RAM, page_addr=%x, npages=%d, chunk_size=%d"), a_addr, npages, psize);
       
   167             MEM_DUMP_OOM_LOGS(psize, "RSymbianDLHeap::map_chunk_pages - Failed to Commit RAM");
       
   168 #endif
       
   169             return KErrNoMemory;
       
   170         }
       
   171     }
       
   172     return KErrNone;
       
   173 }
       
   174 
       
   175 /* Purpose:     Map partial chunk memory pages from system RAM
       
   176  * Arguments:   tp - tchunkptr in which memmory should be mapped
       
   177  *              psize - incoming tchunk size
       
   178  *              r - remainder chunk pointer
       
   179  *              rsize - remainder chunk size
       
   180  * Return:      Number of unmapped pages from remainder chunk if successful (0 or more), else KErrNoMemory
       
   181  * Note:        Remainder chunk should be large enough to be mapped out (checked before invoking this function)
       
   182  *              pageout headers will be set from insert_large_chunk(), not here.
       
   183  */
       
   184 TInt RNewAllocator::map_chunk_pages_partial(tchunkptr tp, size_t psize, tchunkptr r, size_t rsize)
       
   185 {
       
   186     if (page_not_in_memory(tp, psize)) {
       
   187         size_t npages = tp->npages; // total no of pages unmapped in this chunk
       
   188         char *page_addr_map = tchunk_page_align(tp); // address to begin page map
       
   189         char *page_addr_rem = tchunk_page_align(r);  // address in remainder chunk to remain unmapped
       
   190         assert(address_offset(page_addr_rem, r) < rsize);
       
   191         size_t npages_map = address_offset(page_addr_rem, page_addr_map) >> pageshift; // no of pages to be mapped
       
   192         if (npages_map > 0) {
       
   193             if (map(page_addr_map, npages_map*mparams.page_size)) {
       
   194 #ifdef DL_CHUNK_MEM_DEBUG
       
   195                 TRACE_DL_CHUNK_MAP(tp, psize, page_addr_map, npages_map*mparams.page_size);
       
   196                 ASSERT_RCHUNK_SIZE();
       
   197                 TRACE_UNMAPPED_CHUNK(-1*npages_map*mparams.page_size);
       
   198 #endif
       
   199                 return (npages - npages_map);
       
   200             }
       
   201             else {
       
   202 #ifdef OOM_LOGGING
       
   203                 MEM_LOGF(_L8("CHUNK_PAGE_ERROR:: map_chunk_pages_partial - Failed to Commit RAM, page_addr=%x, npages=%d, chunk_size=%d"), page_addr_map, npages_map, psize);
       
   204                 MEM_DUMP_OOM_LOGS(psize, "RSymbianDLHeap::map_chunk_pages_partial - Failed to Commit RAM");
       
   205 #endif
       
   206                 return KErrNoMemory;
       
   207             }
       
   208         }
       
   209         else {
       
   210              // map not needed, first page is already mapped
       
   211              return npages;
       
   212         }
       
   213     }
       
   214 
       
   215     return 0;
       
   216 }
       
   217 
       
   218 
       
   219 /* Purpose:     Release (unmap) chunk memory pages to system RAM
       
   220  * Arguments:   tp - tchunkptr from which memmory may be released
       
   221  *              psize - incoming tchunk size
       
   222  *              prev_npages - number of pages that has been already unmapped from this chunk
       
   223  * Return:      total number of pages that has been unmapped from this chunk (new unmapped pages + prev_npages)
       
   224  * Note:        pageout headers will be set from insert_large_chunk(), not here.
       
   225  */
       
   226 TInt RNewAllocator::unmap_chunk_pages(tchunkptr tp, size_t psize, size_t prev_npages)
       
   227 {
       
   228     size_t npages = 0;
       
   229     char *a_addr = tchunk_page_align(tp);
       
   230     size_t offset = address_offset(a_addr,tp);
       
   231     if (offset < psize && (psize - offset) >= mparams.page_size)
       
   232     { /* check for new pages to decommit */
       
   233         npages = ( psize - offset) >> pageshift;
       
   234         if (npages > prev_npages) {
       
   235             unmap(a_addr, npages*mparams.page_size);    // assuming kernel takes care of already unmapped pages
       
   236             TRACE_DL_CHUNK_UNMAP(tp, psize, a_addr, npages*mparams.page_size);
       
   237             iChunkSize += prev_npages*mparams.page_size; //adjust actual chunk size
       
   238             ASSERT_RCHUNK_SIZE();
       
   239             TRACE_UNMAPPED_CHUNK((npages-prev_npages)*mparams.page_size);
       
   240             assert((a_addr + npages*mparams.page_size - 1) < (char*)next_chunk(tp));
       
   241         }
       
   242     }
       
   243 
       
   244 #ifdef OOM_LOGGING
       
   245     if (npages && (npages < prev_npages))
       
   246         MEM_LOG("CHUNK_PAGE_ERROR:unmap_chunk_pages, error in npages");
       
   247     if (npages > prev_npages) {
       
   248         /* check that end of decommited address lie within this chunk */
       
   249         if ((a_addr + npages*mparams.page_size - 1) >= (char*)next_chunk(tp))
       
   250             MEM_LOG("CHUNK_PAGE_ERROR:unmap_chunk_pages, error chunk boundary");
       
   251     }
       
   252 #endif
       
   253 #ifdef DL_CHUNK_MEM_DEBUG
       
   254     mchunkptr next = next_chunk(tp);
       
   255     do_check_any_chunk_access(next, chunksize(next));
       
   256     if (!npages)  do_check_any_chunk_access((mchunkptr)tp, psize);
       
   257 #endif
       
   258 
       
   259     return (npages);
       
   260 }
       
   261 
       
   262 /* Purpose:     Unmap all pages between previously unmapped and end of top chunk
       
   263                 and reset top to beginning of prev chunk
       
   264  * Arguments:   fm - global malloc state
       
   265  *              prev - previous chunk which has unmapped pages
       
   266  *              psize - size of previous chunk
       
   267  *              prev_npages - number of unmapped pages from previous chunk
       
   268  * Return:      nonzero if sucessful, else 0
       
   269  * Note:
       
   270  */
       
   271 TInt RNewAllocator::sys_trim_partial(mstate m, mchunkptr prev, size_t psize, size_t prev_npages)
       
   272 {
       
   273     size_t released = 0;
       
   274     size_t extra = 0;
       
   275     if (is_initialized(m)) {
       
   276       psize += m->topsize;
       
   277       char *a_addr = tchunk_page_align(prev); // includes space for TOP footer
       
   278       size_t addr_offset = address_offset(a_addr, prev);
       
   279       assert(addr_offset > TOP_FOOT_SIZE); //always assert?
       
   280       assert((char*)iTop >= a_addr); //always assert?
       
   281       if ((char*)iTop > a_addr)
       
   282           extra = address_offset(iTop, a_addr);
       
   283 
       
   284 #ifdef OOM_LOGGING
       
   285       if ((char*)iTop < a_addr)
       
   286           MEM_LOGF(_L8("RSymbianDLHeap::sys_trim_partial - incorrect iTop value, top=%x, iTop=%x"), m->top, iTop);
       
   287 #endif
       
   288         msegmentptr sp = segment_holding(m, (TUint8*)prev);
       
   289         if (!is_extern_segment(sp)) {
       
   290           if (is_mmapped_segment(sp)) {
       
   291             if (HAVE_MMAP &&  sp->size >= extra && !has_segment_link(m, sp)) { /* can't shrink if pinned */
       
   292              // size_t newsize = sp->size - extra;
       
   293               /* Prefer mremap, fall back to munmap */
       
   294               if ((CALL_MREMAP(sp->base, sp->size, sp->size - extra, 0) != MFAIL) ||
       
   295                   (CALL_MUNMAP(sp->base + sp->size - extra, extra) == 0)) {
       
   296                 released = extra;
       
   297               }
       
   298             }
       
   299           }
       
   300           else if (HAVE_MORECORE) {
       
   301             if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
       
   302                 extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - mparams.granularity;
       
   303             ACQUIRE_MORECORE_LOCK(m);
       
   304             {
       
   305               /* Make sure end of memory is where we last set it. */
       
   306               TUint8* old_br = (TUint8*)(CALL_MORECORE(0));
       
   307               if (old_br == sp->base + sp->size) {
       
   308                 TUint8* rel_br = (TUint8*)(CALL_MORECORE(-extra));
       
   309                 TUint8* new_br = (TUint8*)(CALL_MORECORE(0));
       
   310                 if (rel_br != CMFAIL && new_br < old_br)
       
   311                   released = old_br - new_br;
       
   312               }
       
   313             }
       
   314             RELEASE_MORECORE_LOCK(m);
       
   315           }
       
   316         }
       
   317 
       
   318         if (released != 0) {
       
   319           TRACE_DL_CHUNK_UNMAP(prev, psize, a_addr, released);
       
   320           iChunkSize += prev_npages*mparams.page_size; // prev_unmapped was already unmapped
       
   321           TRACE_UNMAPPED_CHUNK(-1*prev_npages*mparams.page_size);
       
   322           ASSERT_RCHUNK_SIZE();
       
   323           sp->size -= released;
       
   324           m->footprint -= released;
       
   325         }
       
   326 
       
   327         /* reset top to prev chunk */
       
   328         init_top(m, prev, addr_offset - TOP_FOOT_SIZE);
       
   329         check_top_chunk(m, m->top);
       
   330     }
       
   331 
       
   332     // DL region not initalized, do not reset top here
       
   333     return (released != 0)? 1 : 0;
       
   334 }
       
   335 
       
   336 
       
   337 #define STACKSIZE 32
       
   338 inline void RNewAllocator::TraceCallStack()
       
   339 {
       
   340 #ifdef TRACING_CALLSTACKS
       
   341     TUint32 filteredStack[STACKSIZE];
       
   342     TThreadStackInfo info;
       
   343     TUint32 *sp = (TUint32*)&sp;
       
   344     RThread().StackInfo(info);
       
   345     Lock();
       
   346     TInt i;
       
   347     for (i=0;i<STACKSIZE;i++) {
       
   348         if ((TLinAddr)sp>=info.iBase) break;
       
   349         while ((TLinAddr)sp < info.iBase) {
       
   350             TUint32 cur = *sp++;
       
   351             TUint32 range = cur & 0xF0000000;
       
   352             if (range == 0x80000000 || range == 0x70000000) {
       
   353                 filteredStack[i] = cur;
       
   354                 break;
       
   355             }
       
   356         }
       
   357     }
       
   358     Unlock();
       
   359     BTraceContextBig(BTrace::EHeap, BTrace::EHeapCallStack, (TUint32)this, filteredStack, i * 4);
       
   360 #endif
       
   361 }
       
   362 
       
   363 size_t getpagesize()
       
   364 {
       
   365     TInt size;
       
   366     TInt err = GET_PAGE_SIZE(size);
       
   367     if (err != KErrNone)
       
   368         return (size_t)0x1000;
       
   369     return (size_t)size;
       
   370 }
       
   371 
       
   372 #define gm  (&iGlobalMallocState)
       
   373 
       
   374 RNewAllocator::RNewAllocator(TInt aMaxLength, TInt aAlign, TBool aSingleThread)
       
   375 // constructor for a fixed heap. Just use DL allocator
       
   376     :iMinLength(aMaxLength), iMaxLength(aMaxLength), iOffset(0), iGrowBy(0), iChunkHandle(0),
       
   377     iNestingLevel(0), iAllocCount(0), iFailType(ENone), iTestData(NULL), iChunkSize(aMaxLength)
       
   378     {
       
   379 
       
   380     if ((TUint32)aAlign>=sizeof(TAny*) && __POWER_OF_2(iAlign))
       
   381         {
       
   382         iAlign = aAlign;
       
   383         }
       
   384     else
       
   385         {
       
   386         iAlign = 4;
       
   387         }
       
   388     iPageSize = 0;
       
   389     iFlags = aSingleThread ? (ESingleThreaded|EFixedSize) : EFixedSize;
       
   390 
       
   391     Init(0, 0, 0);
       
   392     }
       
   393 
       
   394 RNewAllocator::RNewAllocator(TInt aChunkHandle, TInt aOffset, TInt aMinLength, TInt aMaxLength, TInt aGrowBy,
       
   395             TInt aAlign, TBool aSingleThread)
       
   396         : iMinLength(aMinLength), iMaxLength(aMaxLength), iOffset(aOffset), iChunkHandle(aChunkHandle), iAlign(aAlign), iNestingLevel(0), iAllocCount(0),
       
   397             iFailType(ENone), iTestData(NULL), iChunkSize(aMinLength),iHighWaterMark(aMinLength)
       
   398     {
       
   399     iPageSize = malloc_getpagesize;
       
   400     __ASSERT_ALWAYS(aOffset >=0, User::Panic(KDLHeapPanicCategory, ETHeapNewBadOffset));
       
   401     iGrowBy = _ALIGN_UP(aGrowBy, iPageSize);
       
   402     iFlags = aSingleThread ? ESingleThreaded : 0;
       
   403 
       
   404     // Initialise
       
   405     // if the heap is created with aMinLength==aMaxLength then it cannot allocate slab or page memory
       
   406     // so these sub-allocators should be disabled. Otherwise initialise with default values
       
   407     if (aMinLength == aMaxLength)
       
   408         Init(0, 0, 0);
       
   409     else
       
   410         Init(0x3fff, 15, 0x10000);  // all slabs, page {32KB}, trim {64KB} // Andrew: Adopting Webkit config?
       
   411         //Init(0xabe, 16, iPageSize*4); // slabs {48, 40, 32, 24, 20, 16, 12, 8}, page {64KB}, trim {16KB}
       
   412 #ifdef TRACING_HEAPS
       
   413     RChunk chunk;
       
   414     chunk.SetHandle(iChunkHandle);
       
   415     TKName chunk_name;
       
   416     chunk.FullName(chunk_name);
       
   417     BTraceContextBig(BTrace::ETest1, 2, 22, chunk_name.Ptr(), chunk_name.Size());
       
   418 
       
   419     TUint32 traceData[4];
       
   420     traceData[0] = iChunkHandle;
       
   421     traceData[1] = iMinLength;
       
   422     traceData[2] = iMaxLength;
       
   423     traceData[3] = iAlign;
       
   424     BTraceContextN(BTrace::ETest1, 1, (TUint32)this, 11, traceData, sizeof(traceData));
       
   425 #endif
       
   426 
       
   427     }
       
   428 
       
   429 TAny* RNewAllocator::operator new(TUint aSize, TAny* aBase) __NO_THROW
       
   430     {
       
   431     __ASSERT_ALWAYS(aSize>=sizeof(RNewAllocator), HEAP_PANIC(ETHeapNewBadSize));
       
   432     RNewAllocator* h = (RNewAllocator*)aBase;
       
   433     h->iAlign = 0x80000000; // garbage value
       
   434     h->iBase = ((TUint8*)aBase) + aSize;
       
   435     return aBase;
       
   436     }
       
   437 
       
   438 void RNewAllocator::Init(TInt aBitmapSlab, TInt aPagePower, size_t aTrimThreshold)
       
   439     {
       
   440     __ASSERT_ALWAYS((TUint32)iAlign>=sizeof(TAny*) && __POWER_OF_2(iAlign), HEAP_PANIC(ETHeapNewBadAlignment));
       
   441 
       
   442     /*Moved code which does initialization */
       
   443     iTop = (TUint8*)this + iMinLength;
       
   444     spare_page = 0;
       
   445     iAllocCount = 0; // FIXME  -- not used anywhere - already initialized to 0 in constructor anyway
       
   446     memset(&mparams,0,sizeof(mparams));
       
   447 
       
   448     Init_Dlmalloc(iTop - iBase, 0, aTrimThreshold);
       
   449 
       
   450     slab_init(aBitmapSlab);
       
   451 
       
   452     /*10-1K,11-2K,12-4k,13-8K,14-16K,15-32K,16-64K*/
       
   453     paged_init(aPagePower);
       
   454 
       
   455 #ifdef TRACING_ALLOCS
       
   456         TUint32 traceData[3];
       
   457         traceData[0] = aBitmapSlab;
       
   458         traceData[1] = aPagePower;
       
   459         traceData[2] = aTrimThreshold;
       
   460         BTraceContextN(BTrace::ETest1, BTrace::EHeapAlloc, (TUint32)this, 0, traceData, sizeof(traceData));
       
   461 #endif
       
   462 
       
   463     }
       
   464 
       
   465 RNewAllocator::SCell* RNewAllocator::GetAddress(const TAny* aCell) const
       
   466 //
       
   467 // As much as possible, check a cell address and backspace it
       
   468 // to point at the cell header.
       
   469 //
       
   470     {
       
   471 
       
   472     TLinAddr m = TLinAddr(iAlign - 1);
       
   473     __ASSERT_ALWAYS(!(TLinAddr(aCell)&m), HEAP_PANIC(ETHeapBadCellAddress));
       
   474 
       
   475     SCell* pC = (SCell*)(((TUint8*)aCell)-EAllocCellSize);
       
   476     __CHECK_CELL(pC);
       
   477 
       
   478     return pC;
       
   479     }
       
   480 
       
   481 TInt RNewAllocator::AllocLen(const TAny* aCell) const
       
   482 {
       
   483     if (ptrdiff(aCell, this) >= 0)
       
   484     {
       
   485         mchunkptr m = mem2chunk(aCell);
       
   486         return chunksize(m) - CHUNK_OVERHEAD; // Andrew: Picking up webkit change.
       
   487     }
       
   488     if (lowbits(aCell, pagesize) > cellalign)
       
   489         return header_size(slab::slabfor(aCell)->header);
       
   490     if (lowbits(aCell, pagesize) == cellalign)
       
   491         return *(unsigned*)(offset(aCell,-int(cellalign)))-cellalign;
       
   492     return paged_descriptor(aCell)->size;
       
   493 }
       
   494 
       
   495 TAny* RNewAllocator::Alloc(TInt aSize)
       
   496 {
       
   497     __ASSERT_ALWAYS((TUint)aSize<(KMaxTInt/2),HEAP_PANIC(ETHeapBadAllocatedCellSize));
       
   498 
       
   499     TAny* addr;
       
   500 
       
   501 #ifdef TRACING_ALLOCS
       
   502     TInt aCnt=0;
       
   503 #endif
       
   504     Lock();
       
   505     if (aSize < slab_threshold)
       
   506     {
       
   507         TInt ix = sizemap[(aSize+3)>>2];
       
   508         ASSERT(ix != 0xff);
       
   509         addr = slab_allocate(slaballoc[ix]);
       
   510         if (addr) iTotalAllocSize += slaballoc[ix].size;
       
   511     }else if ((aSize >> page_threshold)==0)
       
   512         {
       
   513 #ifdef TRACING_ALLOCS
       
   514         aCnt=1;
       
   515 #endif
       
   516         addr = dlmalloc(aSize);
       
   517         }
       
   518     else
       
   519         {
       
   520 #ifdef TRACING_ALLOCS
       
   521         aCnt=2;
       
   522 #endif
       
   523         addr = paged_allocate(aSize);
       
   524         //attempt dlmalloc() if paged_allocate() fails. This can improve allocation chances if fragmentation is high in the heap.
       
   525         if (!addr) { // paged_allocator failed, try in dlmalloc
       
   526             addr = dlmalloc(aSize);
       
   527         }
       
   528     }
       
   529 
       
   530     if (addr) {
       
   531         iCellCount++;
       
   532         // Increment iTotalAllocSize in memory segment specific code for more accuracy
       
   533         //iTotalAllocSize += aSize;
       
   534     }
       
   535     Unlock();
       
   536 
       
   537 #ifdef TRACING_ALLOCS
       
   538     if (iFlags & ETraceAllocs)
       
   539         {
       
   540         TUint32 traceData[3];
       
   541         traceData[0] = AllocLen(addr);
       
   542         traceData[1] = aSize;
       
   543         traceData[2] = aCnt;
       
   544         BTraceContextN(BTrace::EHeap, BTrace::EHeapAlloc, (TUint32)this, (TUint32)addr, traceData, sizeof(traceData));
       
   545         TraceCallStack();
       
   546         }
       
   547 #endif
       
   548 
       
   549     return addr;
       
   550 }
       
   551 
       
   552 TInt RNewAllocator::Compress()
       
   553     {
       
   554     if (iFlags & EFixedSize)
       
   555         return 0;
       
   556 
       
   557     Lock();
       
   558     dlmalloc_trim(0);
       
   559     if (spare_page)
       
   560         {
       
   561         unmap(spare_page,pagesize);
       
   562         spare_page = 0;
       
   563         }
       
   564     Unlock();
       
   565     return 0;
       
   566     }
       
   567 
       
   568 void RNewAllocator::Free(TAny* aPtr)
       
   569 {
       
   570 
       
   571 #ifdef TRACING_ALLOCS
       
   572     TInt aCnt=0;
       
   573 #endif
       
   574 #ifdef ENABLE_DEBUG_TRACE
       
   575     RThread me;
       
   576     TBuf<100> thName;
       
   577     me.FullName(thName);
       
   578 #endif
       
   579     //if (!aPtr) return; //return in case of NULL pointer
       
   580 
       
   581     Lock();
       
   582 
       
   583     if (!aPtr)
       
   584         ;
       
   585     else if (ptrdiff(aPtr, this) >= 0)
       
   586         {
       
   587 #ifdef TRACING_ALLOCS
       
   588         aCnt = 1;
       
   589 #endif
       
   590         dlfree( aPtr);
       
   591         }
       
   592     else if (lowbits(aPtr, pagesize) <= cellalign)
       
   593         {
       
   594 #ifdef TRACING_ALLOCS
       
   595         aCnt = 2;
       
   596 #endif
       
   597         paged_free(aPtr);
       
   598         }
       
   599     else
       
   600         {
       
   601 #ifdef TRACING_ALLOCS
       
   602         aCnt = 0;
       
   603 #endif
       
   604         slab_free(aPtr);
       
   605         }
       
   606     iCellCount--;
       
   607     Unlock();
       
   608 
       
   609 #ifdef TRACING_ALLOCS
       
   610     if (iFlags & ETraceAllocs)
       
   611         {
       
   612         TUint32 traceData;
       
   613         traceData = aCnt;
       
   614         BTraceContextN(BTrace::EHeap, BTrace::EHeapFree, (TUint32)this, (TUint32)aPtr, &traceData, sizeof(traceData));
       
   615         TraceCallStack();
       
   616         }
       
   617 #endif
       
   618 }
       
   619 
       
   620 
       
   621 void RNewAllocator::Reset()
       
   622     {
       
   623     // TODO free everything
       
   624     User::Panic(_L("RNewAllocator"), 1); //this should never be called
       
   625     }
       
   626 
       
   627 #ifdef TRACING_ALLOCS
       
   628 inline void RNewAllocator::TraceReAlloc(TAny* aPtr, TInt aSize, TAny* aNewPtr, TInt aZone)
       
   629 {
       
   630     if (aNewPtr && (iFlags & ETraceAllocs)) {
       
   631         TUint32 traceData[3];
       
   632         traceData[0] = AllocLen(aNewPtr);
       
   633         traceData[1] = aSize;
       
   634         traceData[2] = (TUint32) aPtr;
       
   635         BTraceContextN(BTrace::EHeap, BTrace::EHeapReAlloc, (TUint32) this, (TUint32) aNewPtr,
       
   636             traceData, sizeof(traceData));
       
   637         TraceCallStack();
       
   638         //workaround for SAW not handling reallocs properly
       
   639         if (aZone >= 0 && aPtr != aNewPtr) {
       
   640             BTraceContextN(BTrace::EHeap, BTrace::EHeapFree, (TUint32) this, (TUint32) aPtr,
       
   641                 &aZone, sizeof(aZone));
       
   642             TraceCallStack();
       
   643         }
       
   644     }
       
   645 }
       
   646 #else
       
   647 //Q_UNUSED generates code that prevents the compiler optimising out the empty inline function
       
   648 inline void RNewAllocator::TraceReAlloc(TAny* , TInt , TAny* , TInt )
       
   649 {}
       
   650 #endif
       
   651 
       
   652 TAny* RNewAllocator::ReAlloc(TAny* aPtr, TInt aSize, TInt /*aMode = 0*/)
       
   653     {
       
   654     if (ptrdiff(aPtr,this)>=0)
       
   655     {
       
   656         // original cell is in DL zone
       
   657         if ((aSize>>page_threshold)==0 || aSize <= chunksize(mem2chunk(aPtr)) - CHUNK_OVERHEAD)
       
   658             {
       
   659             // new one is below page limit or smaller than old one (so can't be moved)
       
   660             Lock();
       
   661             TAny* addr = dlrealloc(aPtr,aSize);
       
   662             Unlock();
       
   663             TraceReAlloc(aPtr, aSize, addr, 2);
       
   664             return addr;
       
   665             }
       
   666     }
       
   667     else if (lowbits(aPtr,pagesize)<=cellalign)
       
   668     {
       
   669         // original cell is either NULL or in paged zone
       
   670         if (!aPtr)
       
   671             return Alloc(aSize);
       
   672 
       
   673         // either the new size is larger (in which case it will still be in paged zone)
       
   674         // or it is smaller, but we will never move a shrinking cell so in paged zone
       
   675         // must handle [rare] case that aSize == 0, as paged_[re]allocate() will panic
       
   676         if (aSize == 0)
       
   677             aSize = 1;
       
   678         Lock();
       
   679         TAny* addr = paged_reallocate(aPtr,aSize);
       
   680         Unlock();
       
   681         TraceReAlloc(aPtr, aSize, addr, 2);
       
   682         return addr;
       
   683     }
       
   684     else
       
   685     {
       
   686         // original cell is in slab zone
       
   687         // return original if new one smaller
       
   688         if (aSize <= header_size(slab::slabfor(aPtr)->header))
       
   689             return aPtr;
       
   690     }
       
   691     // can't do better than allocate/copy/free
       
   692     TAny* newp = Alloc(aSize);
       
   693     if (newp)
       
   694     {
       
   695         TInt oldsize = AllocLen(aPtr);
       
   696         memcpy(newp,aPtr,oldsize<aSize?oldsize:aSize);
       
   697         Free(aPtr);
       
   698     }
       
   699     return newp;
       
   700     }
       
   701 
       
   702 TInt RNewAllocator::Available(TInt& aBiggestBlock) const
       
   703 {
       
   704     //TODO: consider page and slab allocators
       
   705 
       
   706     //this gets free space in DL region - the C ported code doesn't respect const yet.
       
   707     RNewAllocator* self = const_cast<RNewAllocator*> (this);
       
   708     mallinfo info = self->dlmallinfo();
       
   709     aBiggestBlock = info.largestBlock;
       
   710     return info.fordblks;
       
   711 }
       
   712 TInt RNewAllocator::AllocSize(TInt& aTotalAllocSize) const
       
   713 {
       
   714     aTotalAllocSize = iTotalAllocSize;
       
   715     return iCellCount;
       
   716 }
       
   717 
       
   718 TInt RNewAllocator::DebugFunction(TInt aFunc, TAny* a1, TAny* /*a2*/)
       
   719     {
       
   720     TInt r = KErrNotSupported;
       
   721     TInt* a1int = reinterpret_cast<TInt*>(a1);
       
   722     switch (aFunc) {
       
   723     case RAllocator::ECount:
       
   724     {
       
   725         struct mallinfo mi = dlmallinfo();
       
   726         *a1int = mi.fordblks;
       
   727         r = mi.uordblks;
       
   728     }
       
   729         break;
       
   730     case RAllocator::EMarkStart:
       
   731     case RAllocator::EMarkEnd:
       
   732     case RAllocator::ESetFail:
       
   733     case RAllocator::ECheck:
       
   734         r = KErrNone;
       
   735         break;
       
   736     }
       
   737     return r;
       
   738     }
       
   739 
       
   740 TInt RNewAllocator::Extension_(TUint /* aExtensionId */, TAny*& /* a0 */, TAny* /* a1 */)
       
   741     {
       
   742     return KErrNotSupported;
       
   743     }
       
   744 
       
   745 ///////////////////////////////////////////////////////////////////////////////
       
   746 // imported from dla.cpp
       
   747 ///////////////////////////////////////////////////////////////////////////////
       
   748 
       
   749 //#include <unistd.h>
       
   750 //#define DEBUG_REALLOC
       
   751 #ifdef DEBUG_REALLOC
       
   752 #include <e32debug.h>
       
   753 #endif
       
   754 int RNewAllocator::init_mparams(size_t aTrimThreshold /*= DEFAULT_TRIM_THRESHOLD*/)
       
   755 {
       
   756     if (mparams.page_size == 0)
       
   757     {
       
   758         size_t s;
       
   759         mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
       
   760         mparams.trim_threshold = aTrimThreshold;
       
   761         #if MORECORE_CONTIGUOUS
       
   762             mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;
       
   763         #else  /* MORECORE_CONTIGUOUS */
       
   764             mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;
       
   765         #endif /* MORECORE_CONTIGUOUS */
       
   766 
       
   767             s = (size_t)0x58585858U;
       
   768         ACQUIRE_MAGIC_INIT_LOCK(&mparams);
       
   769         if (mparams.magic == 0) {
       
   770           mparams.magic = s;
       
   771           /* Set up lock for main malloc area */
       
   772           INITIAL_LOCK(&gm->mutex);
       
   773           gm->mflags = mparams.default_mflags;
       
   774         }
       
   775         RELEASE_MAGIC_INIT_LOCK(&mparams);
       
   776 
       
   777         mparams.page_size = malloc_getpagesize;
       
   778 
       
   779         mparams.granularity = ((DEFAULT_GRANULARITY != 0)?
       
   780                                DEFAULT_GRANULARITY : mparams.page_size);
       
   781 
       
   782         /* Sanity-check configuration:
       
   783            size_t must be unsigned and as wide as pointer type.
       
   784            ints must be at least 4 bytes.
       
   785            alignment must be at least 8.
       
   786            Alignment, min chunk size, and page size must all be powers of 2.
       
   787         */
       
   788 
       
   789         if ((sizeof(size_t) != sizeof(TUint8*)) ||
       
   790             (MAX_SIZE_T < MIN_CHUNK_SIZE)  ||
       
   791             (sizeof(int) < 4)  ||
       
   792             (MALLOC_ALIGNMENT < (size_t)8U) ||
       
   793             ((MALLOC_ALIGNMENT    & (MALLOC_ALIGNMENT-SIZE_T_ONE))    != 0) ||
       
   794             ((MCHUNK_SIZE         & (MCHUNK_SIZE-SIZE_T_ONE))         != 0) ||
       
   795             ((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) ||
       
   796             ((mparams.page_size   & (mparams.page_size-SIZE_T_ONE))   != 0))
       
   797           ABORT;
       
   798     }
       
   799     return 0;
       
   800 }
       
   801 
       
   802 void RNewAllocator::init_bins(mstate m) {
       
   803   /* Establish circular links for smallbins */
       
   804   bindex_t i;
       
   805   for (i = 0; i < NSMALLBINS; ++i) {
       
   806     sbinptr bin = smallbin_at(m,i);
       
   807     bin->fd = bin->bk = bin;
       
   808   }
       
   809 }
       
   810 /* ---------------------------- malloc support --------------------------- */
       
   811 
       
   812 /* allocate a large request from the best fitting chunk in a treebin */
       
   813 void* RNewAllocator::tmalloc_large(mstate m, size_t nb) {
       
   814   tchunkptr v = 0;
       
   815   size_t rsize = -nb; /* Unsigned negation */
       
   816   tchunkptr t;
       
   817   bindex_t idx;
       
   818   compute_tree_index(nb, idx);
       
   819 
       
   820   if ((t = *treebin_at(m, idx)) != 0) {
       
   821     /* Traverse tree for this bin looking for node with size == nb */
       
   822     size_t sizebits =
       
   823     nb <<
       
   824     leftshift_for_tree_index(idx);
       
   825     tchunkptr rst = 0;  /* The deepest untaken right subtree */
       
   826     for (;;) {
       
   827       tchunkptr rt;
       
   828       size_t trem = chunksize(t) - nb;
       
   829       if (trem < rsize) {
       
   830         v = t;
       
   831         if ((rsize = trem) == 0)
       
   832           break;
       
   833       }
       
   834       rt = t->child[1];
       
   835       t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
       
   836       if (rt != 0 && rt != t)
       
   837         rst = rt;
       
   838       if (t == 0) {
       
   839         t = rst; /* set t to least subtree holding sizes > nb */
       
   840         break;
       
   841       }
       
   842       sizebits <<= 1;
       
   843     }
       
   844   }
       
   845   if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
       
   846     binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
       
   847     if (leftbits != 0) {
       
   848       bindex_t i;
       
   849       binmap_t leastbit = least_bit(leftbits);
       
   850       compute_bit2idx(leastbit, i);
       
   851       t = *treebin_at(m, i);
       
   852     }
       
   853   }
       
   854   while (t != 0) { /* find smallest of tree or subtree */
       
   855     size_t trem = chunksize(t) - nb;
       
   856     if (trem < rsize) {
       
   857       rsize = trem;
       
   858       v = t;
       
   859     }
       
   860     t = leftmost_child(t);
       
   861   }
       
   862   /*  If dv is a better fit, return 0 so malloc will use it */
       
   863    if (v != 0) {
       
   864    if (RTCHECK(ok_address(m, v))) { /* split */
       
   865       mchunkptr r = chunk_plus_offset(v, nb);
       
   866       assert(chunksize(v) == rsize + nb);
       
   867 
       
   868       /* check for chunk memory page-in */
       
   869       size_t npages_out = 0;
       
   870       if (page_not_in_memory(v, chunksize(v))) {
       
   871           if (!is_small(rsize) && rsize>=CHUNK_PAGEOUT_THESHOLD) {
       
   872               // partial chunk page mapping
       
   873               TInt result = map_chunk_pages_partial(v, chunksize(v), (tchunkptr)r, rsize);
       
   874               if (result < 0) return 0; // Failed to Commit RAM
       
   875               else npages_out = (size_t)result;
       
   876           }
       
   877           else {
       
   878               // full chunk page map needed
       
   879               TInt err = map_chunk_pages(v, chunksize(v));
       
   880               if (err != KErrNone)  return 0; // Failed to Commit RAM
       
   881           }
       
   882       }
       
   883 
       
   884       if (RTCHECK(ok_next(v, r))) {
       
   885         unlink_large_chunk(m, v);
       
   886         if (rsize < free_chunk_threshold) // exaust if less than slab threshold
       
   887           set_inuse_and_pinuse(m, v, (rsize + nb));
       
   888         else {
       
   889           set_size_and_pinuse_of_inuse_chunk(m, v, nb);
       
   890           set_size_and_pinuse_of_free_chunk(r, rsize);
       
   891           insert_chunk(m, r, rsize, npages_out);
       
   892         }
       
   893         return chunk2mem(v);
       
   894       }
       
   895     }
       
   896 #if !INSECURE // conditional statement to keep compiler happy. code is reachable if RTCHECK evaluates to False
       
   897     CORRUPTION_ERROR_ACTION(m);
       
   898 #endif
       
   899   }
       
   900   return 0;
       
   901 }
       
   902 
       
   903 /* allocate a small request from the best fitting chunk in a treebin */
       
   904 void* RNewAllocator::tmalloc_small(mstate m, size_t nb) {
       
   905   tchunkptr t, v;
       
   906   size_t rsize;
       
   907   bindex_t i;
       
   908   binmap_t leastbit = least_bit(m->treemap);
       
   909   compute_bit2idx(leastbit, i);
       
   910 
       
   911   v = t = *treebin_at(m, i);
       
   912   rsize = chunksize(t) - nb;
       
   913 
       
   914   while ((t = leftmost_child(t)) != 0) {
       
   915     size_t trem = chunksize(t) - nb;
       
   916     if (trem < rsize) {
       
   917       rsize = trem;
       
   918       v = t;
       
   919     }
       
   920   }
       
   921 
       
   922   if (RTCHECK(ok_address(m, v))) {
       
   923     mchunkptr r = chunk_plus_offset(v, nb);
       
   924     assert(chunksize(v) == rsize + nb);
       
   925 
       
   926     /* check for chunk memory page-in */
       
   927       if (page_not_in_memory(v, chunksize(v))) {
       
   928           TInt err = map_chunk_pages(v, chunksize(v));
       
   929           if (err != KErrNone)  return 0; // Failed to Commit RAM
       
   930       }
       
   931 
       
   932     if (RTCHECK(ok_next(v, r))) {
       
   933       unlink_large_chunk(m, v);
       
   934       if (rsize < free_chunk_threshold) // exaust if less than slab threshold
       
   935         set_inuse_and_pinuse(m, v, (rsize + nb));
       
   936       else {
       
   937         set_size_and_pinuse_of_inuse_chunk(m, v, nb);
       
   938         set_size_and_pinuse_of_free_chunk(r, rsize);
       
   939         insert_chunk(m, r, rsize, 0);
       
   940       }
       
   941       return chunk2mem(v);
       
   942     }
       
   943   }
       
   944 #if !INSECURE // conditional statement to keep compiler happy. code is reachable if RTCHECK evaluates to False
       
   945   CORRUPTION_ERROR_ACTION(m);
       
   946   return 0;
       
   947 #endif
       
   948 }
       
   949 
       
   950 void RNewAllocator::init_top(mstate m, mchunkptr p, size_t psize)
       
   951 {
       
   952     /* Ensure alignment */
       
   953     size_t offset = align_offset(chunk2mem(p));
       
   954     p = (mchunkptr)((TUint8*)p + offset);
       
   955     psize -= offset;
       
   956     m->top = p;
       
   957     m->topsize = psize;
       
   958     p->head = psize | PINUSE_BIT;
       
   959     /* set size of fake trailing chunk holding overhead space only once */
       
   960     mchunkptr chunkPlusOff = chunk_plus_offset(p, psize);
       
   961     chunkPlusOff->head = TOP_FOOT_SIZE;
       
   962     m->trim_check = mparams.trim_threshold; /* reset on each update */
       
   963 }
       
   964 
       
   965 void* RNewAllocator::internal_realloc(mstate m, void* oldmem, size_t bytes)
       
   966 {
       
   967   if (bytes >= MAX_REQUEST) {
       
   968     MALLOC_FAILURE_ACTION;
       
   969     return 0;
       
   970   }
       
   971   if (!PREACTION(m)) {
       
   972     mchunkptr oldp = mem2chunk(oldmem);
       
   973     size_t oldsize = chunksize(oldp);
       
   974     mchunkptr next = chunk_plus_offset(oldp, oldsize);
       
   975     mchunkptr newp = 0;
       
   976     void* extra = 0;
       
   977 
       
   978     /* Try to either shrink or extend into top. Else malloc-copy-free */
       
   979 
       
   980     if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) &&
       
   981                 ok_next(oldp, next) && ok_pinuse(next))) {
       
   982       size_t nb = request2size(bytes);
       
   983       if (is_mmapped(oldp))
       
   984         newp = mmap_resize(m, oldp, nb);
       
   985       else
       
   986       if (oldsize >= nb) { /* already big enough */
       
   987         size_t rsize = oldsize - nb;
       
   988         newp = oldp;
       
   989         if (rsize >= free_chunk_threshold) {
       
   990           mchunkptr remainder = chunk_plus_offset(newp, nb);
       
   991           set_inuse(m, newp, nb);
       
   992           set_inuse(m, remainder, rsize);
       
   993           extra = chunk2mem(remainder);
       
   994           iTotalAllocSize -= rsize;
       
   995   }
       
   996       }
       
   997         /*AMOD: Modified to optimized*/
       
   998         else if (next == m->top && oldsize + m->topsize > nb)
       
   999         {
       
  1000             /* Expand into top */
       
  1001             if (oldsize + m->topsize > nb)
       
  1002             {
       
  1003                 size_t newsize = oldsize + m->topsize;
       
  1004                 size_t newtopsize = newsize - nb;
       
  1005                 mchunkptr newtop = chunk_plus_offset(oldp, nb);
       
  1006                 set_inuse(m, oldp, nb);
       
  1007                 newtop->head = newtopsize |PINUSE_BIT;
       
  1008                 m->top = newtop;
       
  1009                 m->topsize = newtopsize;
       
  1010                 iTotalAllocSize += nb - oldsize;
       
  1011                 newp = oldp;
       
  1012             }
       
  1013       }
       
  1014     }
       
  1015     else {
       
  1016       USAGE_ERROR_ACTION(m, oldmem);
       
  1017       POSTACTION(m);
       
  1018       return 0;
       
  1019     }
       
  1020 
       
  1021     POSTACTION(m);
       
  1022 
       
  1023     if (newp != 0) {
       
  1024       if (extra != 0) {
       
  1025         internal_free(m, extra);
       
  1026       }
       
  1027       check_inuse_chunk(m, newp);
       
  1028       return chunk2mem(newp);
       
  1029     }
       
  1030     else {
       
  1031       void* newmem = internal_malloc(m, bytes);
       
  1032       if (newmem != 0) {
       
  1033         size_t oc = oldsize - overhead_for(oldp);
       
  1034         memcpy(newmem, oldmem, (oc < bytes)? oc : bytes);
       
  1035         internal_free(m, oldmem);
       
  1036       }
       
  1037       return newmem;
       
  1038     }
       
  1039   }
       
  1040 #if USE_LOCKS // keep the compiler happy
       
  1041   return 0;
       
  1042 #endif
       
  1043 }
       
  1044 /* ----------------------------- statistics ------------------------------ */
       
  1045 mallinfo RNewAllocator::internal_mallinfo(mstate m) {
       
  1046   struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
       
  1047   TInt chunkCnt = 0;
       
  1048   if (!PREACTION(m)) {
       
  1049     check_malloc_state(m);
       
  1050     if (is_initialized(m)) {
       
  1051       size_t nfree = SIZE_T_ONE; /* top always free */
       
  1052       size_t mfree = m->topsize + TOP_FOOT_SIZE;
       
  1053       size_t sum = mfree;
       
  1054       msegmentptr s = &m->seg;
       
  1055       while (s != 0) {
       
  1056         mchunkptr q = align_as_chunk(s->base);
       
  1057         chunkCnt++;
       
  1058         while (segment_holds(s, q) &&
       
  1059                q != m->top && q->head != FENCEPOST_HEAD) {
       
  1060           size_t sz = chunksize(q);
       
  1061           sum += sz;
       
  1062           if (!cinuse(q)) {
       
  1063             if (sz > nm.largestBlock)
       
  1064               nm.largestBlock = sz;
       
  1065             mfree += sz;
       
  1066             ++nfree;
       
  1067           }
       
  1068           q = next_chunk(q);
       
  1069         }
       
  1070         s = s->next;
       
  1071       }
       
  1072       nm.arena    = sum;
       
  1073       nm.ordblks  = nfree;
       
  1074       nm.hblkhd   = m->footprint - sum;
       
  1075       nm.usmblks  = m->max_footprint;
       
  1076       nm.uordblks = m->footprint - mfree;
       
  1077       nm.fordblks = mfree;
       
  1078       nm.keepcost = m->topsize;
       
  1079       nm.cellCount= chunkCnt;/*number of chunks allocated*/
       
  1080     }
       
  1081     POSTACTION(m);
       
  1082   }
       
  1083   return nm;
       
  1084 }
       
  1085 
       
  1086 void  RNewAllocator::internal_malloc_stats(mstate m) {
       
  1087 if (!PREACTION(m)) {
       
  1088   size_t fp = 0;
       
  1089   size_t used = 0;
       
  1090   check_malloc_state(m);
       
  1091   if (is_initialized(m)) {
       
  1092     msegmentptr s = &m->seg;
       
  1093     //size_t maxfp = m->max_footprint;
       
  1094     fp = m->footprint;
       
  1095     used = fp - (m->topsize + TOP_FOOT_SIZE);
       
  1096 
       
  1097     while (s != 0) {
       
  1098       mchunkptr q = align_as_chunk(s->base);
       
  1099       while (segment_holds(s, q) &&
       
  1100              q != m->top && q->head != FENCEPOST_HEAD) {
       
  1101         if (!cinuse(q))
       
  1102           used -= chunksize(q);
       
  1103         q = next_chunk(q);
       
  1104       }
       
  1105       s = s->next;
       
  1106     }
       
  1107   }
       
  1108   POSTACTION(m);
       
  1109 }
       
  1110 }
       
  1111 /* support for mallopt */
       
  1112 int RNewAllocator::change_mparam(int param_number, int value) {
       
  1113   size_t val = (size_t)value;
       
  1114   init_mparams(DEFAULT_TRIM_THRESHOLD);
       
  1115   switch (param_number) {
       
  1116   case M_TRIM_THRESHOLD:
       
  1117     mparams.trim_threshold = val;
       
  1118     return 1;
       
  1119   case M_GRANULARITY:
       
  1120     if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
       
  1121       mparams.granularity = val;
       
  1122       return 1;
       
  1123     }
       
  1124     else
       
  1125       return 0;
       
  1126   case M_MMAP_THRESHOLD:
       
  1127     mparams.mmap_threshold = val;
       
  1128     return 1;
       
  1129   default:
       
  1130     return 0;
       
  1131   }
       
  1132 }
       
  1133 /* Get memory from system using MORECORE or MMAP */
       
  1134 void* RNewAllocator::sys_alloc(mstate m, size_t nb)
       
  1135 {
       
  1136     TUint8* tbase = CMFAIL;
       
  1137     size_t tsize = 0;
       
  1138     flag_t mmap_flag = 0;
       
  1139     //init_mparams();/*No need to do init_params here*/
       
  1140     /* Directly map large chunks */
       
  1141     if (use_mmap(m) && nb >= mparams.mmap_threshold)
       
  1142     {
       
  1143         void* mem = mmap_alloc(m, nb);
       
  1144         if (mem != 0)
       
  1145             return mem;
       
  1146     }
       
  1147   /*
       
  1148     Try getting memory in any of three ways (in most-preferred to
       
  1149     least-preferred order):
       
  1150     1. A call to MORECORE that can normally contiguously extend memory.
       
  1151        (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or
       
  1152        or main space is mmapped or a previous contiguous call failed)
       
  1153     2. A call to MMAP new space (disabled if not HAVE_MMAP).
       
  1154        Note that under the default settings, if MORECORE is unable to
       
  1155        fulfill a request, and HAVE_MMAP is true, then mmap is
       
  1156        used as a noncontiguous system allocator. This is a useful backup
       
  1157        strategy for systems with holes in address spaces -- in this case
       
  1158        sbrk cannot contiguously expand the heap, but mmap may be able to
       
  1159        find space.
       
  1160     3. A call to MORECORE that cannot usually contiguously extend memory.
       
  1161        (disabled if not HAVE_MORECORE)
       
  1162   */
       
  1163   /*Trying to allocate the memory*/
       
  1164     if (MORECORE_CONTIGUOUS && !use_noncontiguous(m))
       
  1165     {
       
  1166     TUint8* br = CMFAIL;
       
  1167     msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (TUint8*)m->top);
       
  1168     size_t asize = 0;
       
  1169     ACQUIRE_MORECORE_LOCK(m);
       
  1170     if (ss == 0)
       
  1171     {  /* First time through or recovery */
       
  1172         TUint8* base = (TUint8*)CALL_MORECORE(0);
       
  1173         if (base != CMFAIL)
       
  1174         {
       
  1175             asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);
       
  1176             /* Adjust to end on a page boundary */
       
  1177             if (!is_page_aligned(base))
       
  1178                 asize += (page_align((size_t)base) - (size_t)base);
       
  1179             /* Can't call MORECORE if size is negative when treated as signed */
       
  1180             if (asize < HALF_MAX_SIZE_T &&(br = (TUint8*)(CALL_MORECORE(asize))) == base)
       
  1181             {
       
  1182                 tbase = base;
       
  1183                 tsize = asize;
       
  1184             }
       
  1185         }
       
  1186     }
       
  1187     else
       
  1188     {
       
  1189       /* Subtract out existing available top space from MORECORE request. */
       
  1190         asize = granularity_align(nb - m->topsize + TOP_FOOT_SIZE + SIZE_T_ONE);
       
  1191     /* Use mem here only if it did continuously extend old space */
       
  1192       if (asize < HALF_MAX_SIZE_T &&
       
  1193           (br = (TUint8*)(CALL_MORECORE(asize))) == ss->base+ss->size) {
       
  1194         tbase = br;
       
  1195         tsize = asize;
       
  1196       }
       
  1197     }
       
  1198     if (tbase == CMFAIL) {    /* Cope with partial failure */
       
  1199       if (br != CMFAIL) {    /* Try to use/extend the space we did get */
       
  1200         if (asize < HALF_MAX_SIZE_T &&
       
  1201             asize < nb + TOP_FOOT_SIZE + SIZE_T_ONE) {
       
  1202           size_t esize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE - asize);
       
  1203           if (esize < HALF_MAX_SIZE_T) {
       
  1204             TUint8* end = (TUint8*)CALL_MORECORE(esize);
       
  1205             if (end != CMFAIL)
       
  1206               asize += esize;
       
  1207             else {            /* Can't use; try to release */
       
  1208               CALL_MORECORE(-asize);
       
  1209               br = CMFAIL;
       
  1210             }
       
  1211           }
       
  1212         }
       
  1213       }
       
  1214       if (br != CMFAIL) {    /* Use the space we did get */
       
  1215         tbase = br;
       
  1216         tsize = asize;
       
  1217       }
       
  1218       else
       
  1219         disable_contiguous(m); /* Don't try contiguous path in the future */
       
  1220     }
       
  1221     RELEASE_MORECORE_LOCK(m);
       
  1222   }
       
  1223   if (HAVE_MMAP && tbase == CMFAIL) {  /* Try MMAP */
       
  1224     size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE;
       
  1225     size_t rsize = granularity_align(req);
       
  1226     if (rsize > nb) { /* Fail if wraps around zero */
       
  1227       TUint8* mp = (TUint8*)(CALL_MMAP(rsize));
       
  1228       if (mp != CMFAIL) {
       
  1229         tbase = mp;
       
  1230         tsize = rsize;
       
  1231         mmap_flag = IS_MMAPPED_BIT;
       
  1232       }
       
  1233     }
       
  1234   }
       
  1235   if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
       
  1236     size_t asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);
       
  1237     if (asize < HALF_MAX_SIZE_T) {
       
  1238       TUint8* br = CMFAIL;
       
  1239       TUint8* end = CMFAIL;
       
  1240       ACQUIRE_MORECORE_LOCK(m);
       
  1241       br = (TUint8*)(CALL_MORECORE(asize));
       
  1242       end = (TUint8*)(CALL_MORECORE(0));
       
  1243       RELEASE_MORECORE_LOCK(m);
       
  1244       if (br != CMFAIL && end != CMFAIL && br < end) {
       
  1245         size_t ssize = end - br;
       
  1246         if (ssize > nb + TOP_FOOT_SIZE) {
       
  1247           tbase = br;
       
  1248           tsize = ssize;
       
  1249         }
       
  1250       }
       
  1251     }
       
  1252   }
       
  1253   if (tbase != CMFAIL) {
       
  1254     if ((m->footprint += tsize) > m->max_footprint)
       
  1255       m->max_footprint = m->footprint;
       
  1256     if (!is_initialized(m)) { /* first-time initialization */
       
  1257       m->seg.base = m->least_addr = tbase;
       
  1258       m->seg.size = tsize;
       
  1259       m->seg.sflags = mmap_flag;
       
  1260       m->magic = mparams.magic;
       
  1261       init_bins(m);
       
  1262       if (is_global(m))
       
  1263         init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
       
  1264       else {
       
  1265         /* Offset top by embedded malloc_state */
       
  1266         mchunkptr mn = next_chunk(mem2chunk(m));
       
  1267         init_top(m, mn, (size_t)((tbase + tsize) - (TUint8*)mn) -TOP_FOOT_SIZE);
       
  1268       }
       
  1269     }else {
       
  1270       /* Try to merge with an existing segment */
       
  1271       msegmentptr sp = &m->seg;
       
  1272       while (sp != 0 && tbase != sp->base + sp->size)
       
  1273         sp = sp->next;
       
  1274       if (sp != 0 && !is_extern_segment(sp) &&
       
  1275           (sp->sflags & IS_MMAPPED_BIT) == mmap_flag &&
       
  1276           segment_holds(sp, m->top))
       
  1277           { /* append */
       
  1278         sp->size += tsize;
       
  1279         init_top(m, m->top, m->topsize + tsize);
       
  1280       }
       
  1281       else {
       
  1282         if (tbase < m->least_addr)
       
  1283           m->least_addr = tbase;
       
  1284         sp = &m->seg;
       
  1285         while (sp != 0 && sp->base != tbase + tsize)
       
  1286           sp = sp->next;
       
  1287         if (sp != 0 &&
       
  1288             !is_extern_segment(sp) &&
       
  1289             (sp->sflags & IS_MMAPPED_BIT) == mmap_flag) {
       
  1290           TUint8* oldbase = sp->base;
       
  1291           sp->base = tbase;
       
  1292           sp->size += tsize;
       
  1293           return prepend_alloc(m, tbase, oldbase, nb);
       
  1294         }
       
  1295         else
       
  1296           add_segment(m, tbase, tsize, mmap_flag);
       
  1297       }
       
  1298     }
       
  1299     if (nb < m->topsize) { /* Allocate from new or extended top space */
       
  1300       size_t rsize = m->topsize -= nb;
       
  1301       mchunkptr p = m->top;
       
  1302       mchunkptr r = m->top = chunk_plus_offset(p, nb);
       
  1303       r->head = rsize | PINUSE_BIT;
       
  1304       set_size_and_pinuse_of_inuse_chunk(m, p, nb);
       
  1305       check_top_chunk(m, m->top);
       
  1306       check_malloced_chunk(m, chunk2mem(p), nb);
       
  1307       return chunk2mem(p);
       
  1308     }
       
  1309   }
       
  1310   /*need to check this*/
       
  1311   MEM_DUMP_OOM_LOGS(nb, "sys_alloc:: FAILED to get more memory");
       
  1312 
       
  1313   //errno = -1;
       
  1314   return 0;
       
  1315 }
       
  1316 msegmentptr RNewAllocator::segment_holding(mstate m, TUint8* addr) {
       
  1317   msegmentptr sp = &m->seg;
       
  1318   for (;;) {
       
  1319     if (addr >= sp->base && addr < sp->base + sp->size)
       
  1320       return sp;
       
  1321     if ((sp = sp->next) == 0)
       
  1322       return 0;
       
  1323   }
       
  1324 }
       
  1325 /* Unlink the first chunk from a smallbin */
       
  1326 inline void RNewAllocator::unlink_first_small_chunk(mstate M,mchunkptr B,mchunkptr P,bindex_t& I)
       
  1327 {
       
  1328   mchunkptr F = P->fd;
       
  1329   assert(P != B);
       
  1330   assert(P != F);
       
  1331   assert(chunksize(P) == small_index2size(I));
       
  1332   if (B == F)
       
  1333     clear_smallmap(M, I);
       
  1334   else if (RTCHECK(ok_address(M, F))) {
       
  1335     B->fd = F;
       
  1336     F->bk = B;
       
  1337   }
       
  1338   else {
       
  1339     CORRUPTION_ERROR_ACTION(M);
       
  1340   }
       
  1341 }
       
  1342 /* Link a free chunk into a smallbin  */
       
  1343 inline void RNewAllocator::insert_small_chunk(mstate M,mchunkptr P, size_t S)
       
  1344 {
       
  1345   bindex_t I  = small_index(S);
       
  1346   mchunkptr B = smallbin_at(M, I);
       
  1347   mchunkptr F = B;
       
  1348   assert(S >= MIN_CHUNK_SIZE);
       
  1349   if (!smallmap_is_marked(M, I))
       
  1350     mark_smallmap(M, I);
       
  1351   else if (RTCHECK(ok_address(M, B->fd)))
       
  1352     F = B->fd;
       
  1353   else {
       
  1354     CORRUPTION_ERROR_ACTION(M);
       
  1355   }
       
  1356   B->fd = P;
       
  1357   F->bk = P;
       
  1358   P->fd = F;
       
  1359   P->bk = B;
       
  1360 }
       
  1361 
       
  1362 
       
  1363 inline void RNewAllocator::insert_chunk(mstate M,mchunkptr P,size_t S,size_t NPAGES)
       
  1364 {
       
  1365     if (is_small(S))
       
  1366         insert_small_chunk(M, P, S);
       
  1367     else{
       
  1368         tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S, NPAGES);
       
  1369      }
       
  1370 }
       
  1371 
       
  1372 inline void RNewAllocator::unlink_large_chunk(mstate M,tchunkptr X)
       
  1373 {
       
  1374   tchunkptr XP = X->parent;
       
  1375   tchunkptr R;
       
  1376   reset_tchunk_mem_pageout(X); // clear chunk pageout flag
       
  1377   if (X->bk != X) {
       
  1378     tchunkptr F = X->fd;
       
  1379     R = X->bk;
       
  1380     if (RTCHECK(ok_address(M, F))) {
       
  1381       F->bk = R;
       
  1382       R->fd = F;
       
  1383     }
       
  1384     else {
       
  1385       CORRUPTION_ERROR_ACTION(M);
       
  1386     }
       
  1387   }
       
  1388   else {
       
  1389     tchunkptr* RP;
       
  1390     if (((R = *(RP = &(X->child[1]))) != 0) ||
       
  1391         ((R = *(RP = &(X->child[0]))) != 0)) {
       
  1392       tchunkptr* CP;
       
  1393       while ((*(CP = &(R->child[1])) != 0) ||
       
  1394              (*(CP = &(R->child[0])) != 0)) {
       
  1395         R = *(RP = CP);
       
  1396       }
       
  1397       if (RTCHECK(ok_address(M, RP)))
       
  1398         *RP = 0;
       
  1399       else {
       
  1400         CORRUPTION_ERROR_ACTION(M);
       
  1401       }
       
  1402     }
       
  1403   }
       
  1404   if (XP != 0) {
       
  1405     tbinptr* H = treebin_at(M, X->index);
       
  1406     if (X == *H) {
       
  1407       if ((*H = R) == 0)
       
  1408         clear_treemap(M, X->index);
       
  1409     }
       
  1410     else if (RTCHECK(ok_address(M, XP))) {
       
  1411       if (XP->child[0] == X)
       
  1412         XP->child[0] = R;
       
  1413       else
       
  1414         XP->child[1] = R;
       
  1415     }
       
  1416     else
       
  1417       CORRUPTION_ERROR_ACTION(M);
       
  1418     if (R != 0) {
       
  1419       if (RTCHECK(ok_address(M, R))) {
       
  1420         tchunkptr C0, C1;
       
  1421         R->parent = XP;
       
  1422         if ((C0 = X->child[0]) != 0) {
       
  1423           if (RTCHECK(ok_address(M, C0))) {
       
  1424             R->child[0] = C0;
       
  1425             C0->parent = R;
       
  1426           }
       
  1427           else
       
  1428             CORRUPTION_ERROR_ACTION(M);
       
  1429         }
       
  1430         if ((C1 = X->child[1]) != 0) {
       
  1431           if (RTCHECK(ok_address(M, C1))) {
       
  1432             R->child[1] = C1;
       
  1433             C1->parent = R;
       
  1434           }
       
  1435           else
       
  1436             CORRUPTION_ERROR_ACTION(M);
       
  1437         }
       
  1438       }
       
  1439       else
       
  1440         CORRUPTION_ERROR_ACTION(M);
       
  1441     }
       
  1442   }
       
  1443 }
       
  1444 
       
  1445 /* Unlink a chunk from a smallbin  */
       
  1446 inline void RNewAllocator::unlink_small_chunk(mstate M, mchunkptr P,size_t S)
       
  1447 {
       
  1448   mchunkptr F = P->fd;
       
  1449   mchunkptr B = P->bk;
       
  1450   bindex_t I = small_index(S);
       
  1451   assert(P != B);
       
  1452   assert(P != F);
       
  1453   assert(chunksize(P) == small_index2size(I));
       
  1454   if (F == B)
       
  1455     clear_smallmap(M, I);
       
  1456   else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&
       
  1457                    (B == smallbin_at(M,I) || ok_address(M, B)))) {
       
  1458     F->bk = B;
       
  1459     B->fd = F;
       
  1460   }
       
  1461   else {
       
  1462     CORRUPTION_ERROR_ACTION(M);
       
  1463   }
       
  1464 }
       
  1465 
       
  1466 inline void RNewAllocator::unlink_chunk(mstate M, mchunkptr P, size_t S)
       
  1467 {
       
  1468   if (is_small(S))
       
  1469     unlink_small_chunk(M, P, S);
       
  1470   else
       
  1471   {
       
  1472       tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP);
       
  1473   }
       
  1474 }
       
  1475 
       
  1476 inline void RNewAllocator::compute_tree_index(size_t S, bindex_t& I)
       
  1477 {
       
  1478   size_t X = S >> TREEBIN_SHIFT;
       
  1479   if (X == 0)
       
  1480     I = 0;
       
  1481   else if (X > 0xFFFF)
       
  1482     I = NTREEBINS-1;
       
  1483   else {
       
  1484     unsigned int Y = (unsigned int)X;
       
  1485     unsigned int N = ((Y - 0x100) >> 16) & 8;
       
  1486     unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;
       
  1487     N += K;
       
  1488     N += K = (((Y <<= K) - 0x4000) >> 16) & 2;
       
  1489     K = 14 - N + ((Y <<= K) >> 15);
       
  1490     I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));
       
  1491   }
       
  1492 }
       
  1493 
       
  1494 /* ------------------------- Operations on trees ------------------------- */
       
  1495 
       
  1496 /* Insert chunk into tree */
       
  1497 inline void RNewAllocator::insert_large_chunk(mstate M,tchunkptr X,size_t S,size_t NPAGES)
       
  1498 {
       
  1499   tbinptr* H;
       
  1500   bindex_t I;
       
  1501   compute_tree_index(S, I);
       
  1502   H = treebin_at(M, I);
       
  1503   X->index = I;
       
  1504   X->child[0] = X->child[1] = 0;
       
  1505 
       
  1506   if (NPAGES) { set_tchunk_mem_pageout(X, NPAGES) }
       
  1507   else  { reset_tchunk_mem_pageout(X) }
       
  1508 
       
  1509   if (!treemap_is_marked(M, I)) {
       
  1510     mark_treemap(M, I);
       
  1511     *H = X;
       
  1512     X->parent = (tchunkptr)H;
       
  1513     X->fd = X->bk = X;
       
  1514   }
       
  1515   else {
       
  1516     tchunkptr T = *H;
       
  1517     size_t K = S << leftshift_for_tree_index(I);
       
  1518     for (;;) {
       
  1519       if (chunksize(T) != S) {
       
  1520         tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);
       
  1521         K <<= 1;
       
  1522         if (*C != 0)
       
  1523           T = *C;
       
  1524         else if (RTCHECK(ok_address(M, C))) {
       
  1525           *C = X;
       
  1526           X->parent = T;
       
  1527           X->fd = X->bk = X;
       
  1528           break;
       
  1529         }
       
  1530         else {
       
  1531           CORRUPTION_ERROR_ACTION(M);
       
  1532           break;
       
  1533         }
       
  1534       }
       
  1535       else {
       
  1536         tchunkptr F = T->fd;
       
  1537         if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {
       
  1538           T->fd = F->bk = X;
       
  1539           X->fd = F;
       
  1540           X->bk = T;
       
  1541           X->parent = 0;
       
  1542           break;
       
  1543         }
       
  1544         else {
       
  1545           CORRUPTION_ERROR_ACTION(M);
       
  1546           break;
       
  1547         }
       
  1548       }
       
  1549     }
       
  1550   }
       
  1551 }
       
  1552 
       
  1553 /*
       
  1554   Unlink steps:
       
  1555 
       
  1556   1. If x is a chained node, unlink it from its same-sized fd/bk links
       
  1557      and choose its bk node as its replacement.
       
  1558   2. If x was the last node of its size, but not a leaf node, it must
       
  1559      be replaced with a leaf node (not merely one with an open left or
       
  1560      right), to make sure that lefts and rights of descendents
       
  1561      correspond properly to bit masks.  We use the rightmost descendent
       
  1562      of x.  We could use any other leaf, but this is easy to locate and
       
  1563      tends to counteract removal of leftmosts elsewhere, and so keeps
       
  1564      paths shorter than minimally guaranteed.  This doesn't loop much
       
  1565      because on average a node in a tree is near the bottom.
       
  1566   3. If x is the base of a chain (i.e., has parent links) relink
       
  1567      x's parent and children to x's replacement (or null if none).
       
  1568 */
       
  1569 
       
  1570 /* Replace dv node, binning the old one */
       
  1571 /* Used only when dvsize known to be small */
       
  1572 inline void RNewAllocator::replace_dv(mstate M, mchunkptr P, size_t S)
       
  1573 {
       
  1574   size_t DVS = M->dvsize;
       
  1575   if (DVS != 0) {
       
  1576     mchunkptr DV = M->dv;
       
  1577     assert(is_small(DVS));
       
  1578     insert_small_chunk(M, DV, DVS);
       
  1579   }
       
  1580   M->dvsize = S;
       
  1581   M->dv = P;
       
  1582 }
       
  1583 
       
  1584 inline void RNewAllocator::compute_bit2idx(binmap_t X,bindex_t& I)
       
  1585 {
       
  1586     unsigned int Y = X - 1;
       
  1587     unsigned int K = Y >> (16-4) & 16;
       
  1588     unsigned int N = K;        Y >>= K;
       
  1589     N += K = Y >> (8-3) &  8;  Y >>= K;
       
  1590     N += K = Y >> (4-2) &  4;  Y >>= K;
       
  1591     N += K = Y >> (2-1) &  2;  Y >>= K;
       
  1592     N += K = Y >> (1-0) &  1;  Y >>= K;
       
  1593     I = (bindex_t)(N + Y);
       
  1594 }
       
  1595 
       
  1596 void RNewAllocator::add_segment(mstate m, TUint8* tbase, size_t tsize, flag_t mmapped) {
       
  1597   /* Determine locations and sizes of segment, fenceposts, old top */
       
  1598   TUint8* old_top = (TUint8*)m->top;
       
  1599   msegmentptr oldsp = segment_holding(m, old_top);
       
  1600   TUint8* old_end = oldsp->base + oldsp->size;
       
  1601   size_t ssize = pad_request(sizeof(struct malloc_segment));
       
  1602   TUint8* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
       
  1603   size_t offset = align_offset(chunk2mem(rawsp));
       
  1604   TUint8* asp = rawsp + offset;
       
  1605   TUint8* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;
       
  1606   mchunkptr sp = (mchunkptr)csp;
       
  1607   msegmentptr ss = (msegmentptr)(chunk2mem(sp));
       
  1608   mchunkptr tnext = chunk_plus_offset(sp, ssize);
       
  1609   mchunkptr p = tnext;
       
  1610   int nfences = 0;
       
  1611 
       
  1612   /* reset top to new space */
       
  1613   init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
       
  1614 
       
  1615   /* Set up segment record */
       
  1616   assert(is_aligned(ss));
       
  1617   set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
       
  1618   *ss = m->seg; /* Push current record */
       
  1619   m->seg.base = tbase;
       
  1620   m->seg.size = tsize;
       
  1621   m->seg.sflags = mmapped;
       
  1622   m->seg.next = ss;
       
  1623 
       
  1624   /* Insert trailing fenceposts */
       
  1625   for (;;) {
       
  1626     mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
       
  1627     p->head = FENCEPOST_HEAD;
       
  1628     ++nfences;
       
  1629     if ((TUint8*)(&(nextp->head)) < old_end)
       
  1630       p = nextp;
       
  1631     else
       
  1632       break;
       
  1633   }
       
  1634   assert(nfences >= 2);
       
  1635 
       
  1636   /* Insert the rest of old top into a bin as an ordinary free chunk */
       
  1637   if (csp != old_top) {
       
  1638     mchunkptr q = (mchunkptr)old_top;
       
  1639     size_t psize = csp - old_top;
       
  1640     mchunkptr tn = chunk_plus_offset(q, psize);
       
  1641     set_free_with_pinuse(q, psize, tn);
       
  1642     insert_chunk(m, q, psize, 0);
       
  1643   }
       
  1644 
       
  1645   check_top_chunk(m, m->top);
       
  1646 }
       
  1647 
       
  1648 
       
  1649 void* RNewAllocator::prepend_alloc(mstate m, TUint8* newbase, TUint8* oldbase,
       
  1650                            size_t nb) {
       
  1651   mchunkptr p = align_as_chunk(newbase);
       
  1652   mchunkptr oldfirst = align_as_chunk(oldbase);
       
  1653   size_t psize = (TUint8*)oldfirst - (TUint8*)p;
       
  1654   mchunkptr q = chunk_plus_offset(p, nb);
       
  1655   size_t qsize = psize - nb;
       
  1656   set_size_and_pinuse_of_inuse_chunk(m, p, nb);
       
  1657 
       
  1658   assert((TUint8*)oldfirst > (TUint8*)q);
       
  1659   assert(pinuse(oldfirst));
       
  1660   assert(qsize >= MIN_CHUNK_SIZE);
       
  1661 
       
  1662   /* consolidate remainder with first chunk of old base */
       
  1663   if (oldfirst == m->top) {
       
  1664     size_t tsize = m->topsize += qsize;
       
  1665     m->top = q;
       
  1666     q->head = tsize | PINUSE_BIT;
       
  1667     check_top_chunk(m, q);
       
  1668   }
       
  1669   else {
       
  1670     if (!cinuse(oldfirst)) {
       
  1671       size_t nsize = chunksize(oldfirst);
       
  1672 
       
  1673       /* check for chunk memory page-in */
       
  1674       if (page_not_in_memory(oldfirst, nsize))
       
  1675         map_chunk_pages((tchunkptr)oldfirst, nsize);       //Err Ignored, branch not reachable.
       
  1676 
       
  1677       unlink_chunk(m, oldfirst, nsize);
       
  1678       oldfirst = chunk_plus_offset(oldfirst, nsize);
       
  1679       qsize += nsize;
       
  1680     }
       
  1681     set_free_with_pinuse(q, qsize, oldfirst);
       
  1682     insert_chunk(m, q, qsize, 0);
       
  1683     check_free_chunk(m, q);
       
  1684   }
       
  1685 
       
  1686   check_malloced_chunk(m, chunk2mem(p), nb);
       
  1687   return chunk2mem(p);
       
  1688 }
       
  1689 
       
  1690 void* RNewAllocator::mmap_alloc(mstate m, size_t nb) {
       
  1691   size_t mmsize = granularity_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
       
  1692   if (mmsize > nb) {     /* Check for wrap around 0 */
       
  1693     TUint8* mm = (TUint8*)(DIRECT_MMAP(mmsize));
       
  1694     if (mm != CMFAIL) {
       
  1695       size_t offset = align_offset(chunk2mem(mm));
       
  1696       size_t psize = mmsize - offset - MMAP_FOOT_PAD;
       
  1697       mchunkptr p = (mchunkptr)(mm + offset);
       
  1698       p->prev_foot = offset | IS_MMAPPED_BIT;
       
  1699       (p)->head = (psize|CINUSE_BIT);
       
  1700       mark_inuse_foot(m, p, psize);
       
  1701       chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;
       
  1702       chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;
       
  1703 
       
  1704       if (mm < m->least_addr)
       
  1705         m->least_addr = mm;
       
  1706       if ((m->footprint += mmsize) > m->max_footprint)
       
  1707         m->max_footprint = m->footprint;
       
  1708       assert(is_aligned(chunk2mem(p)));
       
  1709       check_mmapped_chunk(m, p);
       
  1710       return chunk2mem(p);
       
  1711     }
       
  1712   }
       
  1713   return 0;
       
  1714 }
       
  1715 
       
  1716     int RNewAllocator::sys_trim(mstate m, size_t pad)
       
  1717     {
       
  1718       size_t released = 0;
       
  1719       if (pad < MAX_REQUEST && is_initialized(m)) {
       
  1720         pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
       
  1721 
       
  1722         if (m->topsize > pad) {
       
  1723           /* Shrink top space in granularity-size units, keeping at least one */
       
  1724           size_t unit = mparams.granularity;
       
  1725                 size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - SIZE_T_ONE) * unit;
       
  1726           msegmentptr sp = segment_holding(m, (TUint8*)m->top);
       
  1727 
       
  1728           if (!is_extern_segment(sp)) {
       
  1729             if (is_mmapped_segment(sp)) {
       
  1730               if (HAVE_MMAP &&
       
  1731                   sp->size >= extra &&
       
  1732                   !has_segment_link(m, sp)) { /* can't shrink if pinned */
       
  1733                 /*size_t newsize = sp->size - extra; */
       
  1734                 /* Prefer mremap, fall back to munmap */
       
  1735                 if ((CALL_MREMAP(sp->base, sp->size, sp->size - extra, 0) != MFAIL) ||
       
  1736                     (CALL_MUNMAP(sp->base + sp->size - extra, extra) == 0)) {
       
  1737                   released = extra;
       
  1738                 }
       
  1739               }
       
  1740             }
       
  1741             else if (HAVE_MORECORE) {
       
  1742               if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
       
  1743                 extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
       
  1744               ACQUIRE_MORECORE_LOCK(m);
       
  1745               {
       
  1746                 /* Make sure end of memory is where we last set it. */
       
  1747                 TUint8* old_br = (TUint8*)(CALL_MORECORE(0));
       
  1748                 if (old_br == sp->base + sp->size) {
       
  1749                   TUint8* rel_br = (TUint8*)(CALL_MORECORE(-extra));
       
  1750                   TUint8* new_br = (TUint8*)(CALL_MORECORE(0));
       
  1751                   if (rel_br != CMFAIL && new_br < old_br)
       
  1752                     released = old_br - new_br;
       
  1753                 }
       
  1754               }
       
  1755               RELEASE_MORECORE_LOCK(m);
       
  1756             }
       
  1757           }
       
  1758 
       
  1759           if (released != 0) {
       
  1760             sp->size -= released;
       
  1761             m->footprint -= released;
       
  1762             init_top(m, m->top, m->topsize - released);
       
  1763             check_top_chunk(m, m->top);
       
  1764           }
       
  1765         }
       
  1766 
       
  1767         /* Unmap any unused mmapped segments */
       
  1768         if (HAVE_MMAP)
       
  1769           released += release_unused_segments(m);
       
  1770 
       
  1771         /* On failure, disable autotrim to avoid repeated failed future calls */
       
  1772         if (released == 0)
       
  1773           m->trim_check = MAX_SIZE_T;
       
  1774       }
       
  1775 
       
  1776       return (released != 0)? 1 : 0;
       
  1777     }
       
  1778 
       
  1779     inline int RNewAllocator::has_segment_link(mstate m, msegmentptr ss)
       
  1780     {
       
  1781       msegmentptr sp = &m->seg;
       
  1782       for (;;) {
       
  1783         if ((TUint8*)sp >= ss->base && (TUint8*)sp < ss->base + ss->size)
       
  1784           return 1;
       
  1785         if ((sp = sp->next) == 0)
       
  1786           return 0;
       
  1787       }
       
  1788     }
       
  1789 
       
  1790     /* Unmap and unlink any mmapped segments that don't contain used chunks */
       
  1791     size_t RNewAllocator::release_unused_segments(mstate m)
       
  1792     {
       
  1793       size_t released = 0;
       
  1794       msegmentptr pred = &m->seg;
       
  1795       msegmentptr sp = pred->next;
       
  1796       while (sp != 0) {
       
  1797         TUint8* base = sp->base;
       
  1798         size_t size = sp->size;
       
  1799         msegmentptr next = sp->next;
       
  1800         if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
       
  1801           mchunkptr p = align_as_chunk(base);
       
  1802           size_t psize = chunksize(p);
       
  1803           /* Can unmap if first chunk holds entire segment and not pinned */
       
  1804           if (!cinuse(p) && (TUint8*)p + psize >= base + size - TOP_FOOT_SIZE) {
       
  1805             tchunkptr tp = (tchunkptr)p;
       
  1806             size_t npages_out = tp->npages;
       
  1807             assert(segment_holds(sp, (TUint8*)sp));
       
  1808             unlink_large_chunk(m, tp);
       
  1809             if (CALL_MUNMAP(base, size) == 0) {
       
  1810               released += size;
       
  1811               m->footprint -= size;
       
  1812               /* unlink obsoleted record */
       
  1813               sp = pred;
       
  1814               sp->next = next;
       
  1815             }
       
  1816             else { /* back out if cannot unmap */
       
  1817               insert_large_chunk(m, tp, psize, npages_out);
       
  1818             }
       
  1819           }
       
  1820         }
       
  1821         pred = sp;
       
  1822         sp = next;
       
  1823       }/*End of while*/
       
  1824       return released;
       
  1825     }
       
  1826     /* Realloc using mmap */
       
  1827     inline  mchunkptr RNewAllocator::mmap_resize(mstate m, mchunkptr oldp, size_t nb)
       
  1828     {
       
  1829       size_t oldsize = chunksize(oldp);
       
  1830       if (is_small(nb)) /* Can't shrink mmap regions below small size */
       
  1831         return 0;
       
  1832       /* Keep old chunk if big enough but not too big */
       
  1833       if (oldsize >= nb + SIZE_T_SIZE &&
       
  1834           (oldsize - nb) <= (mparams.granularity << 1))
       
  1835         return oldp;
       
  1836       else {
       
  1837         size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT;
       
  1838         size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
       
  1839         size_t newmmsize = granularity_align(nb + SIX_SIZE_T_SIZES +
       
  1840                                              CHUNK_ALIGN_MASK);
       
  1841         TUint8* cp = (TUint8*)CALL_MREMAP((char*)oldp - offset,
       
  1842                                       oldmmsize, newmmsize, 1);
       
  1843         if (cp != CMFAIL) {
       
  1844           mchunkptr newp = (mchunkptr)(cp + offset);
       
  1845           size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
       
  1846           newp->head = (psize|CINUSE_BIT);
       
  1847           mark_inuse_foot(m, newp, psize);
       
  1848           chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
       
  1849           chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;
       
  1850 
       
  1851           if (cp < m->least_addr)
       
  1852             m->least_addr = cp;
       
  1853           if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
       
  1854             m->max_footprint = m->footprint;
       
  1855           check_mmapped_chunk(m, newp);
       
  1856           return newp;
       
  1857         }
       
  1858       }
       
  1859       return 0;
       
  1860     }
       
  1861 
       
  1862 
       
  1863 void RNewAllocator::Init_Dlmalloc(size_t capacity, int locked, size_t aTrimThreshold)
       
  1864     {
       
  1865         memset(gm,0,sizeof(malloc_state));
       
  1866         init_mparams(aTrimThreshold); /* Ensure pagesize etc initialized */
       
  1867         // The maximum amount that can be allocated can be calculated as:-
       
  1868         // 2^sizeof(size_t) - sizeof(malloc_state) - TOP_FOOT_SIZE - page size (all accordingly padded)
       
  1869         // If the capacity exceeds this, no allocation will be done.
       
  1870         gm->seg.base = gm->least_addr = iBase;
       
  1871         gm->seg.size = capacity;
       
  1872         gm->seg.sflags = !IS_MMAPPED_BIT;
       
  1873         set_lock(gm, locked);
       
  1874         gm->magic = mparams.magic;
       
  1875         init_bins(gm);
       
  1876         init_top(gm, (mchunkptr)iBase, capacity - TOP_FOOT_SIZE);
       
  1877     }
       
  1878 
       
  1879 void* RNewAllocator::dlmalloc(size_t bytes) {
       
  1880   /*
       
  1881      Basic algorithm:
       
  1882      If a small request (< 256 bytes minus per-chunk overhead):
       
  1883        1. If one exists, use a remainderless chunk in associated smallbin.
       
  1884           (Remainderless means that there are too few excess bytes to represent as a chunk.)
       
  1885        2. If one exists, split the smallest available chunk in a bin, saving remainder in bin.
       
  1886        4. If it is big enough, use the top chunk.
       
  1887        5. If available, get memory from system and use it
       
  1888      Otherwise, for a large request:
       
  1889        1. Find the smallest available binned chunk that fits, splitting if necessary.
       
  1890        3. If it is big enough, use the top chunk.
       
  1891        4. If request size >= mmap threshold, try to directly mmap this chunk.
       
  1892        5. If available, get memory from system and use it
       
  1893 
       
  1894      The ugly goto's here ensure that postaction occurs along all paths.
       
  1895   */
       
  1896   if (!PREACTION(gm)) {
       
  1897     void* mem;
       
  1898     size_t nb;
       
  1899     if (bytes <= MAX_SMALL_REQUEST) {
       
  1900       bindex_t idx;
       
  1901       binmap_t smallbits;
       
  1902       nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
       
  1903       idx = small_index(nb);
       
  1904       smallbits = gm->smallmap >> idx;
       
  1905 
       
  1906       if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
       
  1907         mchunkptr b, p;
       
  1908         idx += ~smallbits & 1;       /* Uses next bin if idx empty */
       
  1909         b = smallbin_at(gm, idx);
       
  1910         p = b->fd;
       
  1911         assert(chunksize(p) == small_index2size(idx));
       
  1912         unlink_first_small_chunk(gm, b, p, idx);
       
  1913         set_inuse_and_pinuse(gm, p, small_index2size(idx));
       
  1914         mem = chunk2mem(p);
       
  1915         check_malloced_chunk(gm, mem, nb);
       
  1916         goto postaction;
       
  1917       } else {
       
  1918         if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
       
  1919           mchunkptr b, p, r;
       
  1920           size_t rsize;
       
  1921           bindex_t i;
       
  1922           binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
       
  1923           binmap_t leastbit = least_bit(leftbits);
       
  1924           compute_bit2idx(leastbit, i);
       
  1925           b = smallbin_at(gm, i);
       
  1926           p = b->fd;
       
  1927           assert(chunksize(p) == small_index2size(i));
       
  1928           unlink_first_small_chunk(gm, b, p, i);
       
  1929           rsize = small_index2size(i) - nb;
       
  1930           /* Fit here cannot be remainderless if 4byte sizes */
       
  1931           if (rsize < free_chunk_threshold)
       
  1932             set_inuse_and_pinuse(gm, p, small_index2size(i));
       
  1933           else {
       
  1934             set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
       
  1935             r = chunk_plus_offset(p, nb);
       
  1936             set_size_and_pinuse_of_free_chunk(r, rsize);
       
  1937             insert_chunk(gm, r, rsize, 0);
       
  1938           }
       
  1939           mem = chunk2mem(p);
       
  1940           check_malloced_chunk(gm, mem, nb);
       
  1941           goto postaction;
       
  1942         }
       
  1943 
       
  1944         else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {
       
  1945           check_malloced_chunk(gm, mem, nb);
       
  1946           goto postaction;
       
  1947         }
       
  1948       }
       
  1949     } /* else - large alloc request */
       
  1950     else if (bytes >= MAX_REQUEST)
       
  1951       nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
       
  1952     else {
       
  1953       nb = pad_request(bytes);
       
  1954       if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
       
  1955         check_malloced_chunk(gm, mem, nb);
       
  1956         goto postaction;
       
  1957       }
       
  1958     }
       
  1959 
       
  1960     if (nb < gm->topsize) { /* Split top */
       
  1961       size_t rsize = gm->topsize -= nb;
       
  1962       mchunkptr p = gm->top;
       
  1963       mchunkptr r = gm->top = chunk_plus_offset(p, nb);
       
  1964       r->head = rsize | PINUSE_BIT;
       
  1965       set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
       
  1966       mem = chunk2mem(p);
       
  1967       check_top_chunk(gm, gm->top);
       
  1968       check_malloced_chunk(gm, mem, nb);
       
  1969       goto postaction;
       
  1970     }
       
  1971 
       
  1972     mem = sys_alloc(gm, nb);
       
  1973 
       
  1974   postaction:
       
  1975     POSTACTION(gm);
       
  1976 #ifdef DL_CHUNK_MEM_DEBUG
       
  1977     if (mem) {
       
  1978         mchunkptr pp = mem2chunk(mem);
       
  1979         do_check_any_chunk_access(pp, chunksize(pp));
       
  1980     }
       
  1981 #endif
       
  1982 
       
  1983     if (mem) {
       
  1984         mchunkptr pp = mem2chunk(mem);
       
  1985         iTotalAllocSize += chunksize(pp);
       
  1986     }
       
  1987 
       
  1988     return mem;
       
  1989   }
       
  1990 #if USE_LOCKS // keep the compiler happy
       
  1991   return 0;
       
  1992 #endif
       
  1993 }
       
  1994 
       
  1995 void RNewAllocator::dlfree(void* mem) {
       
  1996   /*
       
  1997      Consolidate freed chunks with preceeding or succeeding bordering
       
  1998      free chunks, if they exist, and then place in a bin.  Intermixed
       
  1999      with special cases for top, dv, mmapped chunks, and usage errors.
       
  2000   */
       
  2001 
       
  2002     if (mem != 0)
       
  2003     {
       
  2004         size_t unmapped_pages = 0;
       
  2005         int prev_chunk_unmapped = 0;
       
  2006         mchunkptr p  = mem2chunk(mem);
       
  2007 #if FOOTERS
       
  2008         mstate fm = get_mstate_for(p);
       
  2009         if (!ok_magic(fm))
       
  2010         {
       
  2011             USAGE_ERROR_ACTION(fm, p);
       
  2012             return;
       
  2013         }
       
  2014 #else /* FOOTERS */
       
  2015 #define fm gm
       
  2016 #endif /* FOOTERS */
       
  2017 
       
  2018         if (!PREACTION(fm))
       
  2019         {
       
  2020             check_inuse_chunk(fm, p);
       
  2021             if (RTCHECK(ok_address(fm, p) && ok_cinuse(p)))
       
  2022             {
       
  2023                 size_t psize = chunksize(p);
       
  2024                 iTotalAllocSize -= psize;
       
  2025                 mchunkptr next = chunk_plus_offset(p, psize);
       
  2026                 if (!pinuse(p))
       
  2027                 {
       
  2028                     size_t prevsize = p->prev_foot;
       
  2029                     if ((prevsize & IS_MMAPPED_BIT) != 0)
       
  2030                     {
       
  2031                         prevsize &= ~IS_MMAPPED_BIT;
       
  2032                         psize += prevsize + MMAP_FOOT_PAD;
       
  2033                             if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
       
  2034                                 fm->footprint -= psize;
       
  2035                             goto postaction;
       
  2036                     }
       
  2037                     else
       
  2038                     {
       
  2039                         mchunkptr prev = chunk_minus_offset(p, prevsize);
       
  2040                         if (page_not_in_memory(prev, prevsize)) {
       
  2041                             prev_chunk_unmapped = 1;
       
  2042                             unmapped_pages = ((tchunkptr)prev)->npages;
       
  2043                         }
       
  2044 
       
  2045                         psize += prevsize;
       
  2046                         p = prev;
       
  2047                         if (RTCHECK(ok_address(fm, prev)))
       
  2048                         { /* consolidate backward */
       
  2049                             unlink_chunk(fm, p, prevsize);
       
  2050                         }
       
  2051                         else
       
  2052                             goto erroraction;
       
  2053                     }
       
  2054                 }
       
  2055 
       
  2056                 if (RTCHECK(ok_next(p, next) && ok_pinuse(next)))
       
  2057                 {
       
  2058                     if (!cinuse(next))
       
  2059                     {  /* consolidate forward */
       
  2060                         if (next == fm->top)
       
  2061                         {
       
  2062                             if (prev_chunk_unmapped) { // previous chunk is unmapped
       
  2063                             /* unmap all pages between previously unmapped and end of top chunk
       
  2064                                and reset top to beginning of prev chunk - done in sys_trim_partial() */
       
  2065                                 sys_trim_partial(fm, p, psize, unmapped_pages);
       
  2066                                 do_check_any_chunk_access(fm->top, fm->topsize);
       
  2067                                 goto postaction;
       
  2068                             }
       
  2069                             else { // forward merge to top
       
  2070                                 size_t tsize = fm->topsize += psize;
       
  2071                                 fm->top = p;
       
  2072                                 p->head = tsize | PINUSE_BIT;
       
  2073                                 if (should_trim(fm, tsize))
       
  2074                                     sys_trim(fm, 0);
       
  2075                                 do_check_any_chunk_access(fm->top, fm->topsize);
       
  2076                                 goto postaction;
       
  2077                             }
       
  2078                         }
       
  2079                         else
       
  2080                         {
       
  2081                             size_t nsize = chunksize(next);
       
  2082                             //int next_chunk_unmapped = 0;
       
  2083                             if ( page_not_in_memory(next, nsize) ) {
       
  2084                                 //next_chunk_unmapped = 1;
       
  2085                                 unmapped_pages += ((tchunkptr)next)->npages;
       
  2086                             }
       
  2087 
       
  2088                             psize += nsize;
       
  2089                             unlink_chunk(fm, next, nsize);
       
  2090                             set_size_and_pinuse_of_free_chunk(p, psize);
       
  2091                         }
       
  2092                     }
       
  2093                     else
       
  2094                         set_free_with_pinuse(p, psize, next);
       
  2095 
       
  2096                     /* check if chunk memmory can be released */
       
  2097                     size_t npages_out = 0;
       
  2098                     if (!is_small(psize) && psize>=CHUNK_PAGEOUT_THESHOLD)
       
  2099                         npages_out = unmap_chunk_pages((tchunkptr)p, psize, unmapped_pages);
       
  2100 
       
  2101                     insert_chunk(fm, p, psize, npages_out);
       
  2102                     check_free_chunk(fm, p);
       
  2103                     do_chunk_page_release_check(p, psize, fm, npages_out);
       
  2104                     goto postaction;
       
  2105                 }
       
  2106             }
       
  2107 erroraction:
       
  2108         USAGE_ERROR_ACTION(fm, p);
       
  2109 postaction:
       
  2110         POSTACTION(fm);
       
  2111         }
       
  2112     }
       
  2113 #if !FOOTERS
       
  2114 #undef fm
       
  2115 #endif /* FOOTERS */
       
  2116 }
       
  2117 
       
  2118 void* RNewAllocator::dlrealloc(void* oldmem, size_t bytes) {
       
  2119   if (oldmem == 0)
       
  2120     return dlmalloc(bytes);
       
  2121 #ifdef REALLOC_ZERO_BYTES_FREES
       
  2122   if (bytes == 0) {
       
  2123     dlfree(oldmem);
       
  2124     return 0;
       
  2125   }
       
  2126 #endif /* REALLOC_ZERO_BYTES_FREES */
       
  2127   else {
       
  2128 #if ! FOOTERS
       
  2129     mstate m = gm;
       
  2130 #else /* FOOTERS */
       
  2131     mstate m = get_mstate_for(mem2chunk(oldmem));
       
  2132     if (!ok_magic(m)) {
       
  2133       USAGE_ERROR_ACTION(m, oldmem);
       
  2134       return 0;
       
  2135     }
       
  2136 #endif /* FOOTERS */
       
  2137     return internal_realloc(m, oldmem, bytes);
       
  2138   }
       
  2139 }
       
  2140 
       
  2141 
       
  2142 int RNewAllocator::dlmalloc_trim(size_t pad) {
       
  2143   int result = 0;
       
  2144   if (!PREACTION(gm)) {
       
  2145     result = sys_trim(gm, pad);
       
  2146     POSTACTION(gm);
       
  2147   }
       
  2148   return result;
       
  2149 }
       
  2150 
       
  2151 size_t RNewAllocator::dlmalloc_footprint(void) {
       
  2152   return gm->footprint;
       
  2153 }
       
  2154 
       
  2155 size_t RNewAllocator::dlmalloc_max_footprint(void) {
       
  2156   return gm->max_footprint;
       
  2157 }
       
  2158 
       
  2159 #if !NO_MALLINFO
       
  2160 struct mallinfo RNewAllocator::dlmallinfo(void) {
       
  2161   return internal_mallinfo(gm);
       
  2162 }
       
  2163 #endif /* NO_MALLINFO */
       
  2164 
       
  2165 void RNewAllocator::dlmalloc_stats() {
       
  2166   internal_malloc_stats(gm);
       
  2167 }
       
  2168 
       
  2169 int RNewAllocator::dlmallopt(int param_number, int value) {
       
  2170   return change_mparam(param_number, value);
       
  2171 }
       
  2172 
       
  2173 //inline slab* slab::slabfor(void* p)
       
  2174 slab* slab::slabfor( const void* p)
       
  2175 {
       
  2176 return (slab*)(floor(p, slabsize));
       
  2177 }
       
  2178 
       
  2179 
       
  2180 void RNewAllocator::tree_remove(slab* s)
       
  2181 {
       
  2182     slab** r = s->parent;
       
  2183     slab* c1 = s->child1;
       
  2184     slab* c2 = s->child2;
       
  2185     for (;;)
       
  2186     {
       
  2187         if (!c2)
       
  2188         {
       
  2189             *r = c1;
       
  2190             if (c1)
       
  2191                 c1->parent = r;
       
  2192             return;
       
  2193         }
       
  2194         if (!c1)
       
  2195         {
       
  2196             *r = c2;
       
  2197             c2->parent = r;
       
  2198             return;
       
  2199         }
       
  2200         if (c1 > c2)
       
  2201         {
       
  2202             slab* c3 = c1;
       
  2203             c1 = c2;
       
  2204             c2 = c3;
       
  2205         }
       
  2206         slab* newc2 = c1->child2;
       
  2207         *r = c1;
       
  2208         c1->parent = r;
       
  2209         c1->child2 = c2;
       
  2210         c2->parent = &c1->child2;
       
  2211         s = c1;
       
  2212         c1 = s->child1;
       
  2213         c2 = newc2;
       
  2214         r = &s->child1;
       
  2215     }
       
  2216 }
       
  2217 void RNewAllocator::tree_insert(slab* s,slab** r)
       
  2218     {
       
  2219         slab* n = *r;
       
  2220         for (;;)
       
  2221         {
       
  2222             if (!n)
       
  2223             {   // tree empty
       
  2224                 *r = s;
       
  2225                 s->parent = r;
       
  2226                 s->child1 = s->child2 = 0;
       
  2227                 break;
       
  2228             }
       
  2229             if (s < n)
       
  2230             {   // insert between parent and n
       
  2231                 *r = s;
       
  2232                 s->parent = r;
       
  2233                 s->child1 = n;
       
  2234                 s->child2 = 0;
       
  2235                 n->parent = &s->child1;
       
  2236                 break;
       
  2237             }
       
  2238             slab* c1 = n->child1;
       
  2239             slab* c2 = n->child2;
       
  2240             if ((c1 - 1) > (c2 - 1))
       
  2241             {
       
  2242                 r = &n->child1;
       
  2243                 n = c1;
       
  2244             }
       
  2245             else
       
  2246             {
       
  2247                 r = &n->child2;
       
  2248                 n = c2;
       
  2249             }
       
  2250         }
       
  2251     }
       
  2252 void* RNewAllocator::allocnewslab(slabset& allocator)
       
  2253 //
       
  2254 // Acquire and initialise a new slab, returning a cell from the slab
       
  2255 // The strategy is:
       
  2256 // 1. Use the lowest address free slab, if available. This is done by using the lowest slab
       
  2257 //    in the page at the root of the partial_page heap (which is address ordered). If the
       
  2258 //    is now fully used, remove it from the partial_page heap.
       
  2259 // 2. Allocate a new page for slabs if no empty slabs are available
       
  2260 //
       
  2261 {
       
  2262     page* p = page::pagefor(partial_page);
       
  2263     if (!p)
       
  2264         return allocnewpage(allocator);
       
  2265 
       
  2266     unsigned h = p->slabs[0].header;
       
  2267     unsigned pagemap = header_pagemap(h);
       
  2268     ASSERT(&p->slabs[hibit(pagemap)] == partial_page);
       
  2269 
       
  2270     unsigned slabix = lowbit(pagemap);
       
  2271     p->slabs[0].header = h &~ (0x100<<slabix);
       
  2272     if (!(pagemap &~ (1<<slabix)))
       
  2273     {
       
  2274         tree_remove(partial_page);  // last free slab in page
       
  2275     }
       
  2276     return allocator.initslab(&p->slabs[slabix]);
       
  2277 }
       
  2278 
       
  2279 /**Defination of this functionis not there in proto code***/
       
  2280 #if 0
       
  2281 void RNewAllocator::partial_insert(slab* s)
       
  2282     {
       
  2283         // slab has had first cell freed and needs to be linked back into partial tree
       
  2284         slabset& ss = slaballoc[sizemap[s->clz]];
       
  2285 
       
  2286         ASSERT(s->used == slabfull);
       
  2287         s->used = ss.fulluse - s->clz;      // full-1 loading
       
  2288         tree_insert(s,&ss.partial);
       
  2289         checktree(ss.partial);
       
  2290     }
       
  2291 /**Defination of this functionis not there in proto code***/
       
  2292 #endif
       
  2293 
       
  2294 void* RNewAllocator::allocnewpage(slabset& allocator)
       
  2295 //
       
  2296 // Acquire and initialise a new page, returning a cell from a new slab
       
  2297 // The partial_page tree is empty (otherwise we'd have used a slab from there)
       
  2298 // The partial_page link is put in the highest addressed slab in the page, and the
       
  2299 // lowest addressed slab is used to fulfill the allocation request
       
  2300 //
       
  2301 {
       
  2302     page* p  = spare_page;
       
  2303     if (p)
       
  2304         spare_page = 0;
       
  2305     else
       
  2306     {
       
  2307         p = static_cast<page*>(map(0,pagesize));
       
  2308         if (!p)
       
  2309             return 0;
       
  2310     }
       
  2311     ASSERT(p == floor(p,pagesize));
       
  2312     p->slabs[0].header = ((1<<3) + (1<<2) + (1<<1))<<8;     // set pagemap
       
  2313     p->slabs[3].parent = &partial_page;
       
  2314     p->slabs[3].child1 = p->slabs[3].child2 = 0;
       
  2315     partial_page = &p->slabs[3];
       
  2316     return allocator.initslab(&p->slabs[0]);
       
  2317 }
       
  2318 
       
  2319 void RNewAllocator::freepage(page* p)
       
  2320 //
       
  2321 // Release an unused page to the OS
       
  2322 // A single page is cached for reuse to reduce thrashing
       
  2323 // the OS allocator.
       
  2324 //
       
  2325 {
       
  2326     ASSERT(ceiling(p,pagesize) == p);
       
  2327     if (!spare_page)
       
  2328     {
       
  2329         spare_page = p;
       
  2330         return;
       
  2331     }
       
  2332     unmap(p,pagesize);
       
  2333 }
       
  2334 
       
  2335 void RNewAllocator::freeslab(slab* s)
       
  2336 //
       
  2337 // Release an empty slab to the slab manager
       
  2338 // The strategy is:
       
  2339 // 1. The page containing the slab is checked to see the state of the other slabs in the page by
       
  2340 //    inspecting the pagemap field in the header of the first slab in the page.
       
  2341 // 2. The pagemap is updated to indicate the new unused slab
       
  2342 // 3. If this is the only unused slab in the page then the slab header is used to add the page to
       
  2343 //    the partial_page tree/heap
       
  2344 // 4. If all the slabs in the page are now unused the page is release back to the OS
       
  2345 // 5. If this slab has a higher address than the one currently used to track this page in
       
  2346 //    the partial_page heap, the linkage is moved to the new unused slab
       
  2347 //
       
  2348 {
       
  2349     tree_remove(s);
       
  2350     checktree(*s->parent);
       
  2351     ASSERT(header_usedm4(s->header) == header_size(s->header)-4);
       
  2352     CHECK(s->header |= 0xFF00000);          // illegal value for debug purposes
       
  2353     page* p = page::pagefor(s);
       
  2354     unsigned h = p->slabs[0].header;
       
  2355     int slabix = s - &p->slabs[0];
       
  2356     unsigned pagemap = header_pagemap(h);
       
  2357     p->slabs[0].header = h | (0x100<<slabix);
       
  2358     if (pagemap == 0)
       
  2359     {   // page was full before, use this slab as link in empty heap
       
  2360         tree_insert(s, &partial_page);
       
  2361     }
       
  2362     else
       
  2363     {   // find the current empty-link slab
       
  2364         slab* sl = &p->slabs[hibit(pagemap)];
       
  2365         pagemap ^= (1<<slabix);
       
  2366         if (pagemap == 0xf)
       
  2367         {   // page is now empty so recycle page to os
       
  2368             tree_remove(sl);
       
  2369             freepage(p);
       
  2370             return;
       
  2371         }
       
  2372         // ensure the free list link is in highest address slab in page
       
  2373         if (s > sl)
       
  2374         {   // replace current link with new one. Address-order tree so position stays the same
       
  2375             slab** r = sl->parent;
       
  2376             slab* c1 = sl->child1;
       
  2377             slab* c2 = sl->child2;
       
  2378             s->parent = r;
       
  2379             s->child1 = c1;
       
  2380             s->child2 = c2;
       
  2381             *r = s;
       
  2382             if (c1)
       
  2383                 c1->parent = &s->child1;
       
  2384             if (c2)
       
  2385                 c2->parent = &s->child2;
       
  2386         }
       
  2387         CHECK(if (s < sl) s=sl);
       
  2388     }
       
  2389     ASSERT(header_pagemap(p->slabs[0].header) != 0);
       
  2390     ASSERT(hibit(header_pagemap(p->slabs[0].header)) == unsigned(s - &p->slabs[0]));
       
  2391 }
       
  2392 
       
  2393 void RNewAllocator::slab_init(unsigned slabbitmap)
       
  2394 {
       
  2395     ASSERT((slabbitmap & ~okbits) == 0);
       
  2396     ASSERT(maxslabsize <= 60);
       
  2397 
       
  2398     slab_threshold=0;
       
  2399     partial_page = 0;
       
  2400     unsigned char ix = 0xff;
       
  2401     unsigned bit = 1<<((maxslabsize>>2)-1);
       
  2402     for (int sz = maxslabsize; sz >= 0; sz -= 4, bit >>= 1)
       
  2403     {
       
  2404         if (slabbitmap & bit)
       
  2405         {
       
  2406             if (++ix == 0)
       
  2407                 slab_threshold=sz+1;
       
  2408             slabset& c = slaballoc[ix];
       
  2409             c.size = sz;
       
  2410             c.partial = 0;
       
  2411         }
       
  2412         sizemap[sz>>2] = ix;
       
  2413     }
       
  2414 
       
  2415     free_chunk_threshold = pad_request(slab_threshold);
       
  2416 }
       
  2417 
       
  2418 void* RNewAllocator::slab_allocate(slabset& ss)
       
  2419 //
       
  2420 // Allocate a cell from the given slabset
       
  2421 // Strategy:
       
  2422 // 1. Take the partially full slab at the top of the heap (lowest address).
       
  2423 // 2. If there is no such slab, allocate from a new slab
       
  2424 // 3. If the slab has a non-empty freelist, pop the cell from the front of the list and update the slab
       
  2425 // 4. Otherwise, if the slab is not full, return the cell at the end of the currently used region of
       
  2426 //    the slab, updating the slab
       
  2427 // 5. Otherwise, release the slab from the partial tree/heap, marking it as 'floating' and go back to
       
  2428 //    step 1
       
  2429 //
       
  2430 {
       
  2431     for (;;)
       
  2432     {
       
  2433         slab *s = ss.partial;
       
  2434         if (!s)
       
  2435             break;
       
  2436         unsigned h = s->header;
       
  2437         unsigned free = h & 0xff;       // extract free cell positiong
       
  2438         if (free)
       
  2439         {
       
  2440             ASSERT(((free<<2)-sizeof(slabhdr))%header_size(h) == 0);
       
  2441             void* p = offset(s,free<<2);
       
  2442             free = *(unsigned char*)p;  // get next pos in free list
       
  2443             h += (h&0x3C000)<<6;        // update usedm4
       
  2444             h &= ~0xff;
       
  2445             h |= free;                  // update freelist
       
  2446             s->header = h;
       
  2447             ASSERT(header_free(h) == 0 || ((header_free(h)<<2)-sizeof(slabhdr))%header_size(h) == 0);
       
  2448             ASSERT(header_usedm4(h) <= 0x3F8u);
       
  2449             ASSERT((header_usedm4(h)+4)%header_size(h) == 0);
       
  2450             return p;
       
  2451         }
       
  2452         unsigned h2 = h + ((h&0x3C000)<<6);
       
  2453         if (h2 < 0xfc00000)
       
  2454         {
       
  2455             ASSERT((header_usedm4(h2)+4)%header_size(h2) == 0);
       
  2456             s->header = h2;
       
  2457             return offset(s,(h>>18) + sizeof(unsigned) + sizeof(slabhdr));
       
  2458         }
       
  2459         h |= 0x80000000;                // mark the slab as full-floating
       
  2460         s->header = h;
       
  2461         tree_remove(s);
       
  2462         checktree(ss.partial);
       
  2463         // go back and try the next slab...
       
  2464     }
       
  2465     // no partial slabs found, so allocate from a new slab
       
  2466     return allocnewslab(ss);
       
  2467 }
       
  2468 
       
  2469 void RNewAllocator::slab_free(void* p)
       
  2470 //
       
  2471 // Free a cell from the slab allocator
       
  2472 // Strategy:
       
  2473 // 1. Find the containing slab (round down to nearest 1KB boundary)
       
  2474 // 2. Push the cell into the slab's freelist, and update the slab usage count
       
  2475 // 3. If this is the last allocated cell, free the slab to the main slab manager
       
  2476 // 4. If the slab was full-floating then insert the slab in it's respective partial tree
       
  2477 //
       
  2478 {
       
  2479     ASSERT(lowbits(p,3)==0);
       
  2480     slab* s = slab::slabfor(p);
       
  2481 
       
  2482     unsigned pos = lowbits(p, slabsize);
       
  2483     unsigned h = s->header;
       
  2484     ASSERT(header_usedm4(h) != 0x3fC);      // slab is empty already
       
  2485     ASSERT((pos-sizeof(slabhdr))%header_size(h) == 0);
       
  2486     *(unsigned char*)p = (unsigned char)h;
       
  2487     h &= ~0xFF;
       
  2488     h |= (pos>>2);
       
  2489     unsigned size = h & 0x3C000;
       
  2490     unsigned allocSize = (h & 0x3F000) >> 12; // size is stored in bits 12...17 in slabhdr
       
  2491     iTotalAllocSize -= allocSize;
       
  2492     if (int(h) >= 0)
       
  2493     {
       
  2494         h -= size<<6;
       
  2495         if (int(h)>=0)
       
  2496         {
       
  2497             s->header = h;
       
  2498             return;
       
  2499         }
       
  2500         freeslab(s);
       
  2501         return;
       
  2502     }
       
  2503     h -= size<<6;
       
  2504     h &= ~0x80000000;
       
  2505     s->header = h;
       
  2506     slabset& ss = slaballoc[sizemap[size>>14]];
       
  2507     tree_insert(s,&ss.partial);
       
  2508     checktree(ss.partial);
       
  2509 }
       
  2510 
       
  2511 void* slabset::initslab(slab* s)
       
  2512 //
       
  2513 // initialise an empty slab for this allocator and return the fist cell
       
  2514 // pre-condition: the slabset has no partial slabs for allocation
       
  2515 //
       
  2516 {
       
  2517     ASSERT(partial==0);
       
  2518     unsigned h = s->header & 0xF00; // preserve pagemap only
       
  2519     h |= (size<<12);                    // set size
       
  2520     h |= (size-4)<<18;                  // set usedminus4 to one object minus 4
       
  2521     s->header = h;
       
  2522     partial = s;
       
  2523     s->parent = &partial;
       
  2524     s->child1 = s->child2 = 0;
       
  2525     return offset(s,sizeof(slabhdr));
       
  2526 }
       
  2527 
       
  2528 TAny* RNewAllocator::SetBrk(TInt32 aDelta)
       
  2529 {
       
  2530     if (iFlags & EFixedSize)
       
  2531         return MFAIL;
       
  2532 
       
  2533     if (aDelta < 0)
       
  2534         {
       
  2535         unmap(offset(iTop, aDelta), -aDelta);
       
  2536         }
       
  2537     else if (aDelta > 0)
       
  2538         {
       
  2539         if (!map(iTop, aDelta))
       
  2540             return MFAIL;
       
  2541         }
       
  2542     void * p =iTop;
       
  2543     iTop = offset(iTop, aDelta);
       
  2544     return p;
       
  2545 }
       
  2546 
       
  2547 void* RNewAllocator::map(void* p,unsigned sz)
       
  2548 //
       
  2549 // allocate pages in the chunk
       
  2550 // if p is NULL, find and allocate the required number of pages (which must lie in the lower half)
       
  2551 // otherwise commit the pages specified
       
  2552 //
       
  2553 {
       
  2554 ASSERT(p == floor(p, pagesize));
       
  2555 ASSERT(sz == ceiling(sz, pagesize));
       
  2556 ASSERT(sz > 0);
       
  2557 
       
  2558     if (iChunkSize + sz > iMaxLength)
       
  2559         return 0;
       
  2560 
       
  2561     RChunk chunk;
       
  2562     chunk.SetHandle(iChunkHandle);
       
  2563     if (p)
       
  2564     {
       
  2565         TInt r = chunk.Commit(iOffset + ptrdiff(p, this),sz);
       
  2566         if (r < 0)
       
  2567             return 0;
       
  2568         iChunkSize += sz;
       
  2569         return p;
       
  2570     }
       
  2571 
       
  2572     TInt r = chunk.Allocate(sz);
       
  2573     if (r < 0)
       
  2574         return 0;
       
  2575     if (r > iOffset)
       
  2576     {
       
  2577         // can't allow page allocations in DL zone
       
  2578         chunk.Decommit(r, sz);
       
  2579         return 0;
       
  2580     }
       
  2581     iChunkSize += sz;
       
  2582 #ifdef TRACING_HEAPS
       
  2583     if (iChunkSize > iHighWaterMark)
       
  2584         {
       
  2585             iHighWaterMark = ceiling(iChunkSize,16*pagesize);
       
  2586 
       
  2587 
       
  2588             RChunk chunk;
       
  2589             chunk.SetHandle(iChunkHandle);
       
  2590             TKName chunk_name;
       
  2591             chunk.FullName(chunk_name);
       
  2592             BTraceContextBig(BTrace::ETest1, 4, 44, chunk_name.Ptr(), chunk_name.Size());
       
  2593 
       
  2594             TUint32 traceData[6];
       
  2595             traceData[0] = iChunkHandle;
       
  2596             traceData[1] = iMinLength;
       
  2597             traceData[2] = iMaxLength;
       
  2598             traceData[3] = sz;
       
  2599             traceData[4] = iChunkSize;
       
  2600             traceData[5] = iHighWaterMark;
       
  2601             BTraceContextN(BTrace::ETest1, 3, (TUint32)this, 33, traceData, sizeof(traceData));
       
  2602         }
       
  2603 #endif
       
  2604 
       
  2605     return offset(this, r - iOffset);
       
  2606     // code below does delayed initialisation of the slabs.
       
  2607     /*
       
  2608     if (iChunkSize >= slab_init_threshold)
       
  2609     {   // set up slab system now that heap is large enough
       
  2610         slab_config(slab_config_bits);
       
  2611         slab_init_threshold = KMaxTUint;
       
  2612     }
       
  2613     return p;
       
  2614     */
       
  2615 }
       
  2616 
       
  2617 void* RNewAllocator::remap(void* p,unsigned oldsz,unsigned sz)
       
  2618 {
       
  2619     if (oldsz > sz)
       
  2620         {   // shrink
       
  2621         unmap(offset(p,sz), oldsz-sz);
       
  2622         }
       
  2623     else if (oldsz < sz)
       
  2624         {   // grow, try and do this in place first
       
  2625         if (!map(offset(p, oldsz), sz-oldsz))
       
  2626             {
       
  2627             // need to allocate-copy-free
       
  2628             void* newp = map(0, sz);
       
  2629             if (newp) {
       
  2630                 memcpy(newp, p, oldsz);
       
  2631                 unmap(p,oldsz);
       
  2632             }
       
  2633             return newp;
       
  2634             }
       
  2635         }
       
  2636     return p;
       
  2637 }
       
  2638 
       
  2639 void RNewAllocator::unmap(void* p,unsigned sz)
       
  2640 {
       
  2641     ASSERT(p == floor(p, pagesize));
       
  2642     ASSERT(sz == ceiling(sz, pagesize));
       
  2643     ASSERT(sz > 0);
       
  2644 
       
  2645     RChunk chunk;
       
  2646     chunk.SetHandle(iChunkHandle);
       
  2647     TInt r = chunk.Decommit(ptrdiff(p, offset(this,-iOffset)), sz);
       
  2648     //TInt offset = (TUint8*)p-(TUint8*)chunk.Base();
       
  2649     //TInt r = chunk.Decommit(offset,sz);
       
  2650 
       
  2651     ASSERT(r >= 0);
       
  2652     iChunkSize -= sz;
       
  2653 #ifdef TRACING_HEAPS
       
  2654     if (iChunkSize > iHighWaterMark)
       
  2655         {
       
  2656             iHighWaterMark = ceiling(iChunkSize,16*pagesize);
       
  2657 
       
  2658 
       
  2659             RChunk chunk;
       
  2660             chunk.SetHandle(iChunkHandle);
       
  2661             TKName chunk_name;
       
  2662             chunk.FullName(chunk_name);
       
  2663             BTraceContextBig(BTrace::ETest1, 4, 44, chunk_name.Ptr(), chunk_name.Size());
       
  2664 
       
  2665             TUint32 traceData[6];
       
  2666             traceData[0] = iChunkHandle;
       
  2667             traceData[1] = iMinLength;
       
  2668             traceData[2] = iMaxLength;
       
  2669             traceData[3] = sz;
       
  2670             traceData[4] = iChunkSize;
       
  2671             traceData[5] = iHighWaterMark;
       
  2672             BTraceContextN(BTrace::ETest1, 3, (TUint32)this, 33, traceData, sizeof(traceData));
       
  2673         }
       
  2674 #endif
       
  2675 }
       
  2676 
       
  2677 void RNewAllocator::paged_init(unsigned pagepower)
       
  2678     {
       
  2679         if (pagepower == 0)
       
  2680             pagepower = 31;
       
  2681         else if (pagepower < minpagepower)
       
  2682             pagepower = minpagepower;
       
  2683         page_threshold = pagepower;
       
  2684         for (int i=0;i<npagecells;++i)
       
  2685         {
       
  2686             pagelist[i].page = 0;
       
  2687             pagelist[i].size = 0;
       
  2688         }
       
  2689     }
       
  2690 
       
  2691 void* RNewAllocator::paged_allocate(unsigned size)
       
  2692 {
       
  2693     unsigned nbytes = ceiling(size, pagesize);
       
  2694     if (nbytes < size + cellalign)
       
  2695     {   // not enough extra space for header and alignment, try and use cell list
       
  2696         for (pagecell *c = pagelist,*e = c + npagecells;c < e;++c)
       
  2697             if (c->page == 0)
       
  2698             {
       
  2699                 void* p = map(0, nbytes);
       
  2700                 if (!p)
       
  2701                     return 0;
       
  2702                 c->page = p;
       
  2703                 c->size = nbytes;
       
  2704                 iTotalAllocSize += nbytes;
       
  2705                 return p;
       
  2706             }
       
  2707     }
       
  2708     // use a cell header
       
  2709     nbytes = ceiling(size + cellalign, pagesize);
       
  2710     void* p = map(0, nbytes);
       
  2711     if (!p)
       
  2712         return 0;
       
  2713     *static_cast<unsigned*>(p) = nbytes;
       
  2714     iTotalAllocSize += nbytes;
       
  2715     return offset(p, cellalign);
       
  2716 }
       
  2717 
       
  2718 void* RNewAllocator::paged_reallocate(void* p, unsigned size)
       
  2719 {
       
  2720     if (lowbits(p, pagesize) == 0)
       
  2721     {   // continue using descriptor
       
  2722         pagecell* c = paged_descriptor(p);
       
  2723         unsigned nbytes = ceiling(size, pagesize);
       
  2724         void* newp = remap(p, c->size, nbytes);
       
  2725         if (!newp)
       
  2726             return 0;
       
  2727         c->page = newp;
       
  2728         c->size = nbytes;
       
  2729         iTotalAllocSize += nbytes-c->size;
       
  2730         return newp;
       
  2731     }
       
  2732     else
       
  2733     {   // use a cell header
       
  2734         ASSERT(lowbits(p,pagesize) == cellalign);
       
  2735         p = offset(p,-int(cellalign));
       
  2736         unsigned nbytes = ceiling(size + cellalign, pagesize);
       
  2737         unsigned obytes = *static_cast<unsigned*>(p);
       
  2738         void* newp = remap(p, obytes, nbytes);
       
  2739         if (!newp)
       
  2740             return 0;
       
  2741         *static_cast<unsigned*>(newp) = nbytes;
       
  2742         iTotalAllocSize += nbytes-obytes;
       
  2743         return offset(newp, cellalign);
       
  2744     }
       
  2745 }
       
  2746 
       
  2747 void RNewAllocator::paged_free(void* p)
       
  2748 {
       
  2749     if (lowbits(p,pagesize) == 0)
       
  2750     {   // check pagelist
       
  2751         pagecell* c = paged_descriptor(p);
       
  2752 
       
  2753         iTotalAllocSize -= c->size;
       
  2754 
       
  2755         unmap(p, c->size);
       
  2756         c->page = 0;
       
  2757         c->size = 0;
       
  2758     }
       
  2759     else
       
  2760     {   // check page header
       
  2761         unsigned* page = static_cast<unsigned*>(offset(p,-int(cellalign)));
       
  2762         unsigned size = *page;
       
  2763 
       
  2764         iTotalAllocSize -= size;
       
  2765 
       
  2766         unmap(page,size);
       
  2767     }
       
  2768 }
       
  2769 
       
  2770 pagecell* RNewAllocator::paged_descriptor(const void* p) const
       
  2771 {
       
  2772     ASSERT(lowbits(p,pagesize) == 0);
       
  2773     // Double casting to keep the compiler happy. Seems to think we can trying to
       
  2774     // change a non-const member (pagelist) in a const function
       
  2775     pagecell* c = (pagecell*)((void*)pagelist);
       
  2776 #ifdef _DEBUG
       
  2777     pagecell* e = c + npagecells;
       
  2778 #endif
       
  2779     for (;;)
       
  2780     {
       
  2781         ASSERT(c!=e);
       
  2782         if (c->page == p)
       
  2783             return c;
       
  2784         ++c;
       
  2785     }
       
  2786 }
       
  2787 
       
  2788 RNewAllocator* RNewAllocator::FixedHeap(TAny* aBase, TInt aMaxLength, TInt aAlign, TBool aSingleThread)
       
  2789 /**
       
  2790 Creates a fixed length heap at a specified location.
       
  2791 
       
  2792 On successful return from this function, aMaxLength bytes are committed by the chunk.
       
  2793 The heap cannot be extended.
       
  2794 
       
  2795 @param aBase         A pointer to the location where the heap is to be constructed.
       
  2796 @param aMaxLength    The length of the heap. If the supplied value is less
       
  2797                      than KMinHeapSize, it is discarded and the value KMinHeapSize
       
  2798                      is used instead.
       
  2799 @param aAlign        The alignment of heap cells.
       
  2800 @param aSingleThread Indicates whether single threaded or not.
       
  2801 
       
  2802 @return A pointer to the new heap, or NULL if the heap could not be created.
       
  2803 
       
  2804 @panic USER 56 if aMaxLength is negative.
       
  2805 */
       
  2806 //
       
  2807 // Force construction of the fixed memory.
       
  2808 //
       
  2809     {
       
  2810 
       
  2811     __ASSERT_ALWAYS(aMaxLength>=0, ::Panic(ETHeapMaxLengthNegative));
       
  2812     if (aMaxLength<KMinHeapSize)
       
  2813         aMaxLength=KMinHeapSize;
       
  2814 
       
  2815     RNewAllocator* h = new(aBase) RNewAllocator(aMaxLength, aAlign, aSingleThread);
       
  2816 
       
  2817     if (!aSingleThread)
       
  2818         {
       
  2819         TInt r = h->iLock.CreateLocal();
       
  2820         if (r!=KErrNone)
       
  2821             return NULL;
       
  2822         h->iHandles = (TInt*)&h->iLock;
       
  2823         h->iHandleCount = 1;
       
  2824         }
       
  2825     return h;
       
  2826     }
       
  2827 
       
  2828 RNewAllocator* RNewAllocator::ChunkHeap(const TDesC* aName, TInt aMinLength, TInt aMaxLength, TInt aGrowBy, TInt aAlign, TBool aSingleThread)
       
  2829 /**
       
  2830 Creates a heap in a local or global chunk.
       
  2831 
       
  2832 The chunk hosting the heap can be local or global.
       
  2833 
       
  2834 A local chunk is one which is private to the process creating it and is not
       
  2835 intended for access by other user processes.
       
  2836 A global chunk is one which is visible to all processes.
       
  2837 
       
  2838 The hosting chunk is local, if the pointer aName is NULL, otherwise
       
  2839 the hosting chunk is global and the descriptor *aName is assumed to contain
       
  2840 the name to be assigned to it.
       
  2841 
       
  2842 Ownership of the host chunk is vested in the current process.
       
  2843 
       
  2844 A minimum and a maximum size for the heap can be specified. On successful
       
  2845 return from this function, the size of the heap is at least aMinLength.
       
  2846 If subsequent requests for allocation of memory from the heap cannot be
       
  2847 satisfied by compressing the heap, the size of the heap is extended in
       
  2848 increments of aGrowBy until the request can be satisfied. Attempts to extend
       
  2849 the heap causes the size of the host chunk to be adjusted.
       
  2850 
       
  2851 Note that the size of the heap cannot be adjusted by more than aMaxLength.
       
  2852 
       
  2853 @param aName         If NULL, the function constructs a local chunk to host
       
  2854                      the heap.
       
  2855                      If not NULL, a pointer to a descriptor containing the name
       
  2856                      to be assigned to the global chunk hosting the heap.
       
  2857 @param aMinLength    The minimum length of the heap.
       
  2858 @param aMaxLength    The maximum length to which the heap can grow.
       
  2859                      If the supplied value is less than KMinHeapSize, then it
       
  2860                      is discarded and the value KMinHeapSize used instead.
       
  2861 @param aGrowBy       The increments to the size of the host chunk. If a value is
       
  2862                      not explicitly specified, the value KMinHeapGrowBy is taken
       
  2863                      by default
       
  2864 @param aAlign        The alignment of heap cells.
       
  2865 @param aSingleThread Indicates whether single threaded or not.
       
  2866 
       
  2867 @return A pointer to the new heap or NULL if the heap could not be created.
       
  2868 
       
  2869 @panic USER 41 if aMinLength is greater than the supplied value of aMaxLength.
       
  2870 @panic USER 55 if aMinLength is negative.
       
  2871 @panic USER 56 if aMaxLength is negative.
       
  2872 */
       
  2873 //
       
  2874 // Allocate a Chunk of the requested size and force construction.
       
  2875 //
       
  2876     {
       
  2877 
       
  2878     __ASSERT_ALWAYS(aMinLength>=0, ::Panic(ETHeapMinLengthNegative));
       
  2879     __ASSERT_ALWAYS(aMaxLength>=aMinLength, ::Panic(ETHeapCreateMaxLessThanMin));
       
  2880     if (aMaxLength<KMinHeapSize)
       
  2881         aMaxLength=KMinHeapSize;
       
  2882     RChunk c;
       
  2883     TInt r;
       
  2884     if (aName)
       
  2885         r = c.CreateDisconnectedGlobal(*aName, 0, 0, aMaxLength*2, aSingleThread ? EOwnerThread : EOwnerProcess);
       
  2886     else
       
  2887         r = c.CreateDisconnectedLocal(0, 0, aMaxLength*2, aSingleThread ? EOwnerThread : EOwnerProcess);
       
  2888     if (r!=KErrNone)
       
  2889         return NULL;
       
  2890 
       
  2891     RNewAllocator* h = ChunkHeap(c, aMinLength, aGrowBy, aMaxLength, aAlign, aSingleThread, UserHeap::EChunkHeapDuplicate);
       
  2892     c.Close();
       
  2893     return h;
       
  2894     }
       
  2895 
       
  2896 RNewAllocator* RNewAllocator::ChunkHeap(RChunk aChunk, TInt aMinLength, TInt aGrowBy, TInt aMaxLength, TInt aAlign, TBool aSingleThread, TUint32 aMode)
       
  2897 /**
       
  2898 Creates a heap in an existing chunk.
       
  2899 
       
  2900 This function is intended to be used to create a heap in a user writable code
       
  2901 chunk as created by a call to RChunk::CreateLocalCode().
       
  2902 This type of heap can be used to hold code fragments from a JIT compiler.
       
  2903 
       
  2904 The maximum length to which the heap can grow is the same as
       
  2905 the maximum size of the chunk.
       
  2906 
       
  2907 @param aChunk        The chunk that will host the heap.
       
  2908 @param aMinLength    The minimum length of the heap.
       
  2909 @param aGrowBy       The increments to the size of the host chunk.
       
  2910 @param aMaxLength    The maximum length to which the heap can grow.
       
  2911 @param aAlign        The alignment of heap cells.
       
  2912 @param aSingleThread Indicates whether single threaded or not.
       
  2913 @param aMode         Flags controlling the reallocation. The only bit which has any
       
  2914                      effect on reallocation is that defined by the enumeration
       
  2915                      ENeverMove of the enum RAllocator::TReAllocMode.
       
  2916                      If this is set, then any successful reallocation guarantees not
       
  2917                      to have changed the start address of the cell.
       
  2918                      By default, this parameter is zero.
       
  2919 
       
  2920 @return A pointer to the new heap or NULL if the heap could not be created.
       
  2921 */
       
  2922 //
       
  2923 // Construct a heap in an already existing chunk
       
  2924 //
       
  2925     {
       
  2926 
       
  2927     return OffsetChunkHeap(aChunk, aMinLength, 0, aGrowBy, aMaxLength, aAlign, aSingleThread, aMode);
       
  2928     }
       
  2929 
       
  2930 RNewAllocator* RNewAllocator::OffsetChunkHeap(RChunk aChunk, TInt aMinLength, TInt aOffset, TInt aGrowBy, TInt aMaxLength, TInt aAlign, TBool aSingleThread, TUint32 aMode)
       
  2931 /**
       
  2932 Creates a heap in an existing chunk, offset from the beginning of the chunk.
       
  2933 
       
  2934 This function is intended to be used to create a heap where a fixed amount of
       
  2935 additional data must be stored at a known location. The additional data can be
       
  2936 placed at the base address of the chunk, allowing it to be located without
       
  2937 depending on the internals of the heap structure.
       
  2938 
       
  2939 The maximum length to which the heap can grow is the maximum size of the chunk,
       
  2940 minus the offset.
       
  2941 
       
  2942 @param aChunk        The chunk that will host the heap.
       
  2943 @param aMinLength    The minimum length of the heap.
       
  2944 @param aOffset       The offset from the start of the chunk, to the start of the heap.
       
  2945 @param aGrowBy       The increments to the size of the host chunk.
       
  2946 @param aMaxLength    The maximum length to which the heap can grow.
       
  2947 @param aAlign        The alignment of heap cells.
       
  2948 @param aSingleThread Indicates whether single threaded or not.
       
  2949 @param aMode         Flags controlling the reallocation. The only bit which has any
       
  2950                      effect on reallocation is that defined by the enumeration
       
  2951                      ENeverMove of the enum RAllocator::TReAllocMode.
       
  2952                      If this is set, then any successful reallocation guarantees not
       
  2953                      to have changed the start address of the cell.
       
  2954                      By default, this parameter is zero.
       
  2955 
       
  2956 @return A pointer to the new heap or NULL if the heap could not be created.
       
  2957 */
       
  2958 //
       
  2959 // Construct a heap in an already existing chunk
       
  2960 //
       
  2961     {
       
  2962 
       
  2963     TInt page_size = malloc_getpagesize;
       
  2964     if (!aAlign)
       
  2965         aAlign = RNewAllocator::ECellAlignment;
       
  2966     TInt maxLength = aChunk.MaxSize();
       
  2967     TInt round_up = Max(aAlign, page_size);
       
  2968     TInt min_cell = _ALIGN_UP(Max((TInt)RNewAllocator::EAllocCellSize, (TInt)RNewAllocator::EFreeCellSize), aAlign);
       
  2969     aOffset = _ALIGN_UP(aOffset, 8);
       
  2970 
       
  2971 #ifdef NO_RESERVE_MEMORY
       
  2972 #ifdef TRACING_HEAPS
       
  2973     TKName chunk_name;
       
  2974     aChunk.FullName(chunk_name);
       
  2975     BTraceContextBig(BTrace::ETest1, 0xF, 0xFF, chunk_name.Ptr(), chunk_name.Size());
       
  2976 
       
  2977     TUint32 traceData[4];
       
  2978     traceData[0] = aChunk.Handle();
       
  2979     traceData[1] = aMinLength;
       
  2980     traceData[2] = aMaxLength;
       
  2981     traceData[3] = aAlign;
       
  2982     BTraceContextN(BTrace::ETest1, 0xE, 0xEE, 0xEE, traceData, sizeof(traceData));
       
  2983 #endif
       
  2984     //modifying the aMinLength because not all memory is the same in the new allocator. So it cannot reserve it properly
       
  2985     if ( aMinLength<aMaxLength)
       
  2986         aMinLength = 0;
       
  2987 #endif
       
  2988 
       
  2989     if (aMaxLength && aMaxLength+aOffset<maxLength)
       
  2990         maxLength = _ALIGN_UP(aMaxLength+aOffset, round_up);
       
  2991     __ASSERT_ALWAYS(aMinLength>=0, ::Panic(ETHeapMinLengthNegative));
       
  2992     __ASSERT_ALWAYS(maxLength>=aMinLength, ::Panic(ETHeapCreateMaxLessThanMin));
       
  2993     aMinLength = _ALIGN_UP(Max(aMinLength, (TInt)sizeof(RNewAllocator) + min_cell) + aOffset, round_up);
       
  2994 
       
  2995     // the new allocator uses a disconnected chunk so must commit the initial allocation
       
  2996     // with Commit() instead of Adjust()
       
  2997     //  TInt r=aChunk.Adjust(aMinLength);
       
  2998     //TInt r = aChunk.Commit(aOffset, aMinLength);
       
  2999 
       
  3000     aOffset = maxLength;
       
  3001     //TInt MORE_CORE_OFFSET = maxLength/2;
       
  3002     //TInt r = aChunk.Commit(MORE_CORE_OFFSET, aMinLength);
       
  3003     TInt r = aChunk.Commit(aOffset, aMinLength);
       
  3004 
       
  3005     if (r!=KErrNone)
       
  3006         return NULL;
       
  3007 
       
  3008     RNewAllocator* h = new (aChunk.Base() + aOffset) RNewAllocator(aChunk.Handle(), aOffset, aMinLength, maxLength, aGrowBy, aAlign, aSingleThread);
       
  3009     //RNewAllocator* h = new (aChunk.Base() + MORE_CORE_OFFSET) RNewAllocator(aChunk.Handle(), aOffset, aMinLength, maxLength, aGrowBy, aAlign, aSingleThread);
       
  3010 
       
  3011     TBool duplicateLock = EFalse;
       
  3012     if (!aSingleThread)
       
  3013         {
       
  3014         duplicateLock = aMode & UserHeap::EChunkHeapSwitchTo;
       
  3015         if (h->iLock.CreateLocal(duplicateLock ? EOwnerThread : EOwnerProcess)!=KErrNone)
       
  3016             {
       
  3017             h->iChunkHandle = 0;
       
  3018             return NULL;
       
  3019             }
       
  3020         }
       
  3021 
       
  3022     if (aMode & UserHeap::EChunkHeapSwitchTo)
       
  3023         User::SwitchHeap(h);
       
  3024 
       
  3025     h->iHandles = &h->iChunkHandle;
       
  3026     if (!aSingleThread)
       
  3027         {
       
  3028         // now change the thread-relative chunk/semaphore handles into process-relative handles
       
  3029         h->iHandleCount = 2;
       
  3030         if (duplicateLock)
       
  3031             {
       
  3032             RHandleBase s = h->iLock;
       
  3033             r = h->iLock.Duplicate(RThread());
       
  3034             s.Close();
       
  3035             }
       
  3036         if (r==KErrNone && (aMode & UserHeap::EChunkHeapDuplicate))
       
  3037             {
       
  3038             r = ((RChunk*)&h->iChunkHandle)->Duplicate(RThread());
       
  3039             if (r!=KErrNone)
       
  3040                 h->iLock.Close(), h->iChunkHandle=0;
       
  3041             }
       
  3042         }
       
  3043     else
       
  3044         {
       
  3045         h->iHandleCount = 1;
       
  3046         if (aMode & UserHeap::EChunkHeapDuplicate)
       
  3047             r = ((RChunk*)&h->iChunkHandle)->Duplicate(RThread(), EOwnerThread);
       
  3048         }
       
  3049 
       
  3050     // return the heap address
       
  3051     return (r==KErrNone) ? h : NULL;
       
  3052     }
       
  3053 
       
  3054     /* Only for debugging purpose - start*/
       
  3055 #ifdef DL_CHUNK_MEM_DEBUG
       
  3056 void RNewAllocator::debug_check_small_chunk_access(mchunkptr p, size_t psize)
       
  3057 {
       
  3058     size_t sz = chunksize(p);
       
  3059     char ch = *((char*)chunk_plus_offset(p, psize-1));
       
  3060 }
       
  3061 
       
  3062 void RNewAllocator::debug_check_any_chunk_access(mchunkptr p, size_t psize)
       
  3063 {
       
  3064     if (p==0 || psize==0) return;
       
  3065 
       
  3066     mchunkptr next = chunk_plus_offset(p, psize);
       
  3067     char* t = (char*)chunk_plus_offset(p, mparams.page_size);
       
  3068     char ch = *((char*)p);
       
  3069     while ((size_t)t<(size_t)next)
       
  3070     {
       
  3071         ch = *t;
       
  3072         t = (char*)chunk_plus_offset(t, mparams.page_size);
       
  3073     };
       
  3074 }
       
  3075 
       
  3076 void RNewAllocator::debug_check_large_chunk_access(tchunkptr p, size_t psize)
       
  3077 {
       
  3078     mchunkptr next = chunk_plus_offset(p, psize);
       
  3079     char* t = (char*)chunk_plus_offset(p, mparams.page_size);
       
  3080     char ch = *((char*)p);
       
  3081     while ((size_t)t<(size_t)next)
       
  3082     {
       
  3083         ch = *t;
       
  3084         t = (char*)chunk_plus_offset(t, mparams.page_size);
       
  3085     };
       
  3086 }
       
  3087 
       
  3088 void RNewAllocator::debug_chunk_page_release_check(mchunkptr p, size_t psize, mstate fm, int mem_released)
       
  3089 {
       
  3090     if (mem_released)
       
  3091     {
       
  3092         if (!page_not_in_memory(p, psize) )
       
  3093             MEM_LOG("CHUNK_PAGE_ERROR::dlfree, error - page_in_mem flag is corrupt");
       
  3094         if (chunk_plus_offset(p, psize) > fm->top)
       
  3095             MEM_LOG("CHUNK_PAGE_ERROR: error Top chunk address invalid");
       
  3096         if (fm->dv >= p && fm->dv < chunk_plus_offset(p, psize))
       
  3097             MEM_LOG("CHUNK_PAGE_ERROR: error DV chunk address invalid");
       
  3098     }
       
  3099 }
       
  3100 #endif
       
  3101 
       
  3102 #ifdef OOM_LOGGING
       
  3103 #include <hal.h>
       
  3104 void RNewAllocator::dump_large_chunk(mstate m, tchunkptr t) {
       
  3105     tchunkptr u = t;
       
  3106     bindex_t tindex = t->index;
       
  3107     size_t tsize = chunksize(t);
       
  3108     bindex_t idx;
       
  3109     compute_tree_index(tsize, idx);
       
  3110 
       
  3111     size_t free = 0;
       
  3112     int nfree = 0;
       
  3113     do
       
  3114         {   /* traverse through chain of same-sized nodes */
       
  3115         if (u->child[0] != 0)
       
  3116             {
       
  3117             dump_large_chunk(m, u->child[0]);
       
  3118             }
       
  3119 
       
  3120         if (u->child[1] != 0)
       
  3121             {
       
  3122             dump_large_chunk(m, u->child[1]);
       
  3123             }
       
  3124 
       
  3125         free += chunksize(u);
       
  3126         nfree++;
       
  3127         u = u->fd;
       
  3128         }
       
  3129     while (u != t);
       
  3130     C_LOGF(_L8("LARGE_BIN,%d,%d,%d"), tsize, free, nfree);
       
  3131 }
       
  3132 
       
  3133 void RNewAllocator::dump_dl_free_chunks()
       
  3134 {
       
  3135     C_LOG("");
       
  3136     C_LOG("------------ dump_dl_free_chunks start -------------");
       
  3137     C_LOG("BinType,BinSize,FreeSize,FreeCount");
       
  3138 
       
  3139     // dump small bins
       
  3140     for (int i = 0; i < NSMALLBINS; ++i)
       
  3141         {
       
  3142         sbinptr b = smallbin_at(gm, i);
       
  3143         unsigned int empty = (gm->smallmap & (1 << i)) == 0;
       
  3144         int nfree = 0;
       
  3145         if (!empty)
       
  3146             {
       
  3147             int nfree = 0;
       
  3148             size_t free = 0;
       
  3149             mchunkptr p = b->bk;
       
  3150             size_t size = chunksize(p);
       
  3151             for (; p != b; p = p->bk)
       
  3152                 {
       
  3153                 free += chunksize(p);
       
  3154                 nfree++;
       
  3155                 }
       
  3156 
       
  3157             C_LOGF(_L8("SMALL_BIN,%d,%d,%d"), size, free, nfree);
       
  3158             }
       
  3159         }
       
  3160 
       
  3161     // dump large bins
       
  3162     for (int i = 0; i < NTREEBINS; ++i)
       
  3163         {
       
  3164         tbinptr* tb = treebin_at(gm, i);
       
  3165         tchunkptr t = *tb;
       
  3166         int empty = (gm->treemap & (1 << i)) == 0;
       
  3167         if (!empty)
       
  3168             dump_large_chunk(gm, t);
       
  3169         }
       
  3170 
       
  3171     C_LOG("------------ dump_dl_free_chunks end -------------");
       
  3172     C_LOG("");
       
  3173     }
       
  3174 
       
  3175 void RNewAllocator::dump_heap_logs(size_t fail_size)
       
  3176 {
       
  3177     MEM_LOG("");
       
  3178     if (fail_size) {
       
  3179         MEM_LOG("MEMDEBUG::RSymbianDLHeap OOM Log dump *************** start");
       
  3180         MEM_LOGF(_L8("Failing to alloc size: %d"), fail_size);
       
  3181     }
       
  3182     else
       
  3183         MEM_LOG("MEMDEBUG::RSymbianDLHeap Log dump *************** start");
       
  3184 
       
  3185     TInt dl_chunk_size = ptrdiff(iTop,iBase);
       
  3186     TInt slabp_chunk_size = iChunkSize + iUnmappedChunkSize - dl_chunk_size;
       
  3187     TInt freeMem = 0;
       
  3188     HAL::Get(HALData::EMemoryRAMFree, freeMem);
       
  3189     MEM_LOGF(_L8("System Free RAM Size: %d"), freeMem);
       
  3190     MEM_LOGF(_L8("Allocator Commited Chunk Size: %d"), iChunkSize);
       
  3191     MEM_LOGF(_L8("DLHeap Arena Size=%d"), dl_chunk_size);
       
  3192     MEM_LOGF(_L8("DLHeap unmapped chunk size: %d"), iUnmappedChunkSize);
       
  3193     MEM_LOGF(_L8("Slab-Page Allocator Chunk Size=%d"), slabp_chunk_size);
       
  3194 
       
  3195     mallinfo info = dlmallinfo();
       
  3196     TUint heapAlloc = info.uordblks;
       
  3197     TUint heapFree = info.fordblks;
       
  3198     MEM_LOGF(_L8("DLHeap allocated size: %d"), heapAlloc);
       
  3199     MEM_LOGF(_L8("DLHeap free size: %d"), heapFree);
       
  3200 
       
  3201     if (fail_size) {
       
  3202         MEM_LOG("MEMDEBUG::RSymbianDLHeap OOM Log dump *************** end");
       
  3203     }else {
       
  3204         MEM_LOG("MEMDEBUG::RSymbianDLHeap Log dump *************** end");
       
  3205     }
       
  3206     MEM_LOG("");
       
  3207 }
       
  3208 
       
  3209 #endif
       
  3210 /* Only for debugging purpose - end*/
       
  3211 
       
  3212 
       
  3213 #define UserTestDebugMaskBit(bit) (TBool)(UserSvr::DebugMask(bit>>5) & (1<<(bit&31)))
       
  3214 
       
  3215 #ifndef NO_NAMED_LOCAL_CHUNKS
       
  3216 //this class requires Symbian^3 for ElocalNamed
       
  3217 
       
  3218 // Hack to get access to TChunkCreateInfo internals outside of the kernel
       
  3219 class TFakeChunkCreateInfo: public TChunkCreateInfo
       
  3220     {
       
  3221 public:
       
  3222      void SetThreadNewAllocator(TInt aInitialSize, TInt aMaxSize, const TDesC& aName)
       
  3223         {
       
  3224         iType = TChunkCreate::ENormal | TChunkCreate::EDisconnected | TChunkCreate::EData;
       
  3225         iMaxSize = aMaxSize * 2;
       
  3226 
       
  3227         iInitialBottom = 0;
       
  3228         iInitialTop = aInitialSize;
       
  3229         iAttributes = TChunkCreate::ELocalNamed;
       
  3230         iName = &aName;
       
  3231         iOwnerType = EOwnerThread;
       
  3232         }
       
  3233     };
       
  3234 #endif
       
  3235 
       
  3236 #ifndef NO_NAMED_LOCAL_CHUNKS
       
  3237 _LIT(KLitDollarHeap,"$HEAP");
       
  3238 #endif
       
  3239 TInt RNewAllocator::CreateThreadHeap(SStdEpocThreadCreateInfo& aInfo, RNewAllocator*& aHeap, TInt aAlign, TBool aSingleThread)
       
  3240 /**
       
  3241 @internalComponent
       
  3242 */
       
  3243 //
       
  3244 // Create a user-side heap
       
  3245 //
       
  3246     {
       
  3247     TInt page_size = malloc_getpagesize;
       
  3248     TInt minLength = _ALIGN_UP(aInfo.iHeapInitialSize, page_size);
       
  3249     TInt maxLength = Max(aInfo.iHeapMaxSize, minLength);
       
  3250 #ifdef TRACING_ALLOCS
       
  3251     if (UserTestDebugMaskBit(96)) // 96 == KUSERHEAPTRACE in nk_trace.h
       
  3252         aInfo.iFlags |= ETraceHeapAllocs;
       
  3253 #endif
       
  3254     // Create the thread's heap chunk.
       
  3255     RChunk c;
       
  3256 #ifndef NO_NAMED_LOCAL_CHUNKS
       
  3257     TFakeChunkCreateInfo createInfo;
       
  3258     createInfo.SetThreadNewAllocator(0, maxLength, KLitDollarHeap());   // Initialise with no memory committed.
       
  3259     TInt r = c.Create(createInfo);
       
  3260 #else
       
  3261     TInt r = c.CreateDisconnectedLocal(0, 0, maxLength * 2);
       
  3262 #endif
       
  3263     if (r!=KErrNone)
       
  3264         return r;
       
  3265     aHeap = ChunkHeap(c, minLength, page_size, maxLength, aAlign, aSingleThread, UserHeap::EChunkHeapSwitchTo|UserHeap::EChunkHeapDuplicate);
       
  3266     c.Close();
       
  3267     if (!aHeap)
       
  3268         return KErrNoMemory;
       
  3269 #ifdef TRACING_ALLOCS
       
  3270     if (aInfo.iFlags & ETraceHeapAllocs)
       
  3271         {
       
  3272         aHeap->iFlags |= RAllocator::ETraceAllocs;
       
  3273         BTraceContext8(BTrace::EHeap, BTrace::EHeapCreate,(TUint32)aHeap, RNewAllocator::EAllocCellSize);
       
  3274         TInt handle = aHeap->ChunkHandle();
       
  3275         TInt chunkId = ((RHandleBase&)handle).BTraceId();
       
  3276         BTraceContext8(BTrace::EHeap, BTrace::EHeapChunkCreate, (TUint32)aHeap, chunkId);
       
  3277         }
       
  3278 #endif
       
  3279     return KErrNone;
       
  3280     }
       
  3281 
       
  3282 /*
       
  3283  * \internal
       
  3284  * Called from the qtmain.lib application wrapper.
       
  3285  * Create a new heap as requested, but use the new allocator
       
  3286  */
       
  3287 TInt _symbian_SetupThreadHeap(TBool /*aNotFirst*/, SStdEpocThreadCreateInfo& aInfo)
       
  3288     {
       
  3289     TInt r = KErrNone;
       
  3290     if (!aInfo.iAllocator && aInfo.iHeapInitialSize>0)
       
  3291         {
       
  3292         // new heap required
       
  3293         RNewAllocator* pH = NULL;
       
  3294         r = RNewAllocator::CreateThreadHeap(aInfo, pH);
       
  3295         }
       
  3296     else if (aInfo.iAllocator)
       
  3297         {
       
  3298         // sharing a heap
       
  3299         RAllocator* pA = aInfo.iAllocator;
       
  3300         r = pA->Open();
       
  3301         if (r == KErrNone)
       
  3302             {
       
  3303             User::SwitchAllocator(pA);
       
  3304             }
       
  3305         }
       
  3306     return r;
       
  3307     }
       
  3308 
       
  3309 #ifndef __WINS__
       
  3310 #pragma pop
       
  3311 #endif