kernel/eka/common/heap_hybrid.cpp
changeset 109 b3a1d9898418
child 200 73ea206103e6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/common/heap_hybrid.cpp	Fri May 14 17:13:29 2010 +0300
@@ -0,0 +1,3319 @@
+// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// kernel\eka\common\heap_hybrid.cpp
+// 
+// Uses malloc (aka dlmalloc) written by Doug Lea version 2.8.4
+//
+
+#include "common.h"
+#ifdef __KERNEL_MODE__
+#include <kernel/kern_priv.h>
+#endif
+#include "dla.h"
+#ifndef __KERNEL_MODE__
+#include "slab.h"
+#include "page_alloc.h"
+#endif
+#include "heap_hybrid.h"
+
+// enables btrace code compiling into 
+#define ENABLE_BTRACE
+
+// if non zero this causes the iSlabs to be configured only when the chunk size exceeds this level
+#define DELAYED_SLAB_THRESHOLD (64*1024)		// 64KB seems about right based on trace data
+#define SLAB_CONFIG 0xabe						// Use slabs of size 48, 40, 32, 24, 20, 16, 12, and 8 bytes
+
+#ifdef _DEBUG
+#define __SIMULATE_ALLOC_FAIL(s)	if (CheckForSimulatedAllocFail()) {s}
+#define __ALLOC_DEBUG_HEADER(s)  	(s += EDebugHdrSize)
+#define __SET_DEBUG_DATA(p,n,c)   	(((SDebugCell*)(p))->nestingLevel = (n), ((SDebugCell*)(p))->allocCount = (c))
+#define __GET_USER_DATA_BFR(p)   	((p!=0) ? (TUint8*)(p) + EDebugHdrSize : NULL)
+#define __GET_DEBUG_DATA_BFR(p)   	((p!=0) ? (TUint8*)(p) - EDebugHdrSize : NULL)
+#define	__ZAP_CELL(p)				memset( (TUint8*)p, 0xde, (AllocLen(__GET_USER_DATA_BFR(p))+EDebugHdrSize))
+#define __DEBUG_SAVE(p)				TInt dbgNestLevel = ((SDebugCell*)p)->nestingLevel
+#define __DEBUG_RESTORE(p)			if (p) {((SDebugCell*)p)->nestingLevel = dbgNestLevel;}
+#define __DEBUG_HDR_SIZE			EDebugHdrSize
+#define __REMOVE_DBG_HDR(n) 		(n*EDebugHdrSize)
+#define __GET_AVAIL_BLOCK_SIZE(s)   ( (s<EDebugHdrSize) ? 0 : s-EDebugHdrSize )
+#define __UPDATE_ALLOC_COUNT(o,n,c)	if (o!=n && n) {((SDebugCell*)n)->allocCount = (c);}
+#define __INIT_COUNTERS(i)	        iCellCount=i,iTotalAllocSize=i
+#define __INCREMENT_COUNTERS(p)	    iCellCount++, iTotalAllocSize += AllocLen(p)
+#define __DECREMENT_COUNTERS(p)	    iCellCount--, iTotalAllocSize -= AllocLen(p)
+#define __UPDATE_TOTAL_ALLOC(p,s)	iTotalAllocSize += (AllocLen(__GET_USER_DATA_BFR(p)) - s)
+
+#else
+#define __SIMULATE_ALLOC_FAIL(s)
+#define __ALLOC_DEBUG_HEADER(s)
+#define __SET_DEBUG_DATA(p,n,c)
+#define __GET_USER_DATA_BFR(p)  (p)
+#define __GET_DEBUG_DATA_BFR(p) (p)
+#define	__ZAP_CELL(p)
+#define __DEBUG_SAVE(p)			
+#define __DEBUG_RESTORE(p)
+#define __DEBUG_HDR_SIZE		0
+#define __REMOVE_DBG_HDR(n) 	0
+#define __GET_AVAIL_BLOCK_SIZE(s)   (s)
+#define __UPDATE_ALLOC_COUNT(o,n,c)	
+#define __INIT_COUNTERS(i)	        iCellCount=i,iTotalAllocSize=i
+#define __INCREMENT_COUNTERS(p)
+#define __DECREMENT_COUNTERS(p)
+#define __UPDATE_TOTAL_ALLOC(p,s)
+
+#endif
+
+
+#define MEMORY_MONITORED  (iFlags & EMonitorMemory)
+#define GM  (&iGlobalMallocState)
+#define IS_FIXED_HEAP  (iFlags & EFixedSize)
+#define __INIT_COUNTERS(i)	iCellCount=i,iTotalAllocSize=i
+#define __POWER_OF_2(x)		(!((x)&((x)-1)))
+
+#define __DL_BFR_CHECK(M,P) \
+		  if ( MEMORY_MONITORED ) \
+             if ( !IS_ALIGNED(P) || ((TUint8*)(P)<M->iSeg.iBase) || ((TUint8*)(P)>(M->iSeg.iBase+M->iSeg.iSize))) \
+                  BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)P, (TUint32)0), HEAP_PANIC(ETHeapBadCellAddress); \
+			 else DoCheckInuseChunk(M, MEM2CHUNK(P)) 
+
+#ifndef __KERNEL_MODE__
+
+#define __SLAB_BFR_CHECK(S,P,B) \
+	  if ( MEMORY_MONITORED ) \
+		  if ( ((TUint32)P & 0x3) || ((TUint8*)P<iMemBase) || ((TUint8*)(P)>(TUint8*)this))  \
+			   BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)P, (TUint32)S), HEAP_PANIC(ETHeapBadCellAddress); \
+		  else DoCheckSlab(S, EPartialFullSlab, P), BuildPartialSlabBitmap(B,S,P) 					  
+#define __PAGE_BFR_CHECK(P) \
+		if ( MEMORY_MONITORED ) \
+			if ( ((TUint32)P &  ((1 << iPageSize)-1)) || ((TUint8*)P<iMemBase) || ((TUint8*)(P)>(TUint8*)this))  \
+				BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)P, (TUint32)0), HEAP_PANIC(ETHeapBadCellAddress)
+
+#endif
+
+#ifdef _MSC_VER
+// This is required while we are still using VC6 to compile, so as to avoid warnings that cannot be fixed
+// without having to edit the original Doug Lea source.  The 4146 warnings are due to the original code having
+// a liking for negating unsigned numbers and the 4127 warnings are due to the original code using the RTCHECK
+// macro with values that are always defined as 1.  It is better to turn these warnings off than to introduce
+// diffs between the original Doug Lea implementation and our adaptation of it
+#pragma warning( disable : 4146 ) /* unary minus operator applied to unsigned type, result still unsigned */
+#pragma warning( disable : 4127 ) /* conditional expression is constant */
+#endif // _MSC_VER
+
+
+/**
+@SYMPatchable
+@publishedPartner
+@released
+
+Defines the minimum cell size of  a heap.
+
+The constant can be changed at ROM build time using patchdata OBY keyword.
+
+@deprecated Patching this constant no longer has any effect.
+*/
+#ifdef __X86GCC__	// For X86GCC we dont use the proper data import attribute
+#undef IMPORT_D		// since the constants are not really imported. GCC doesn't 
+#define IMPORT_D	// allow imports from self.
+#endif
+IMPORT_D extern const TInt KHeapMinCellSize;
+
+/**
+@SYMPatchable
+@publishedPartner
+@released
+
+This constant defines the ratio that determines the amount of hysteresis between heap growing and heap
+shrinking.
+It is a 32-bit fixed point number where the radix point is defined to be
+between bits 7 and 8 (where the LSB is bit 0) i.e. using standard notation, a Q8 or a fx24.8
+fixed point number.  For example, for a ratio of 2.0, set KHeapShrinkHysRatio=0x200.
+
+The heap shrinking hysteresis value is calculated to be:
+@code
+KHeapShrinkHysRatio*(iGrowBy>>8)
+@endcode
+where iGrowBy is a page aligned value set by the argument, aGrowBy, to the RHeap constructor.
+The default hysteresis value is iGrowBy bytes i.e. KHeapShrinkHysRatio=2.0.
+
+Memory usage may be improved by reducing the heap shrinking hysteresis
+by setting 1.0 < KHeapShrinkHysRatio < 2.0.  Heap shrinking hysteresis is disabled/removed
+when KHeapShrinkHysRatio <= 1.0.
+
+The constant can be changed at ROM build time using patchdata OBY keyword.
+*/
+IMPORT_D extern const TInt KHeapShrinkHysRatio;
+
+UEXPORT_C TInt RHeap::AllocLen(const TAny* aCell) const
+{
+	const MAllocator* m = this;
+	return m->AllocLen(aCell);
+}
+
+UEXPORT_C TAny* RHeap::Alloc(TInt aSize)
+{
+	const MAllocator* m = this;
+	return ((MAllocator*)m)->Alloc(aSize);
+}
+
+UEXPORT_C void RHeap::Free(TAny* aCell)
+{
+	const MAllocator* m = this;
+	((MAllocator*)m)->Free(aCell);
+}
+
+UEXPORT_C TAny* RHeap::ReAlloc(TAny* aCell, TInt aSize, TInt aMode)
+{
+	const MAllocator* m = this;
+	return ((MAllocator*)m)->ReAlloc(aCell, aSize, aMode);
+}
+
+UEXPORT_C TInt RHeap::DebugFunction(TInt aFunc, TAny* a1, TAny* a2)
+{
+	const MAllocator* m = this;
+	return ((MAllocator*)m)->DebugFunction(aFunc, a1, a2);
+}
+
+UEXPORT_C TInt RHeap::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
+{
+	const MAllocator* m = this;
+	return ((MAllocator*)m)->Extension_(aExtensionId, a0, a1);
+}
+
+#ifndef __KERNEL_MODE__
+
+EXPORT_C TInt RHeap::AllocSize(TInt& aTotalAllocSize) const
+{
+	const MAllocator* m = this;
+	return m->AllocSize(aTotalAllocSize);
+}
+
+EXPORT_C TInt RHeap::Available(TInt& aBiggestBlock) const
+{
+	const MAllocator* m = this;
+	return m->Available(aBiggestBlock);
+}
+
+EXPORT_C void RHeap::Reset()
+{
+	const MAllocator* m = this;
+	((MAllocator*)m)->Reset();
+}
+
+EXPORT_C TInt RHeap::Compress()
+{
+	const MAllocator* m = this;
+	return ((MAllocator*)m)->Compress();
+}
+#endif
+
+RHybridHeap::RHybridHeap()
+	{
+	// This initialisation cannot be done in RHeap() for compatibility reasons
+	iMaxLength = iChunkHandle = iNestingLevel = 0;
+	iTop = NULL;
+	iFailType = ENone;
+	iTestData = NULL;
+	}
+
+void RHybridHeap::operator delete(TAny*, TAny*) 
+/**
+Called if constructor issued by operator new(TUint aSize, TAny* aBase) throws exception.
+This is dummy as corresponding new operator does not allocate memory.
+*/
+{}
+
+
+#ifndef __KERNEL_MODE__
+void RHybridHeap::Lock() const
+   /**
+   @internalComponent
+*/
+   {((RFastLock&)iLock).Wait();}
+
+
+void RHybridHeap::Unlock() const
+   /**
+   @internalComponent
+*/
+   {((RFastLock&)iLock).Signal();}
+
+
+TInt RHybridHeap::ChunkHandle() const
+   /**
+   @internalComponent
+*/
+{
+	return iChunkHandle;
+}
+
+#else
+//
+//  This method is implemented in kheap.cpp
+//
+//void RHybridHeap::Lock() const
+   /**
+   @internalComponent
+*/
+//   {;}
+
+
+
+//
+//  This method is implemented in kheap.cpp
+//
+//void RHybridHeap::Unlock() const
+   /**
+   @internalComponent
+*/
+//   {;}
+
+
+TInt RHybridHeap::ChunkHandle() const
+   /**
+   @internalComponent
+*/
+{
+	return 0;
+}
+#endif
+
+RHybridHeap::RHybridHeap(TInt aChunkHandle, TInt aOffset, TInt aMinLength, TInt aMaxLength, TInt aGrowBy, TInt aAlign, TBool aSingleThread, TBool aDLOnly, TBool aUseAdjust)
+/**
+Constructor for a non fixed heap.  Unlike the fixed heap, this heap is quite flexible in terms of its minimum and
+maximum lengths and in that it can use the hybrid allocator if all of its requirements are met.
+*/
+	: iOffset(aOffset), iChunkSize(aMinLength)
+	{
+	__ASSERT_ALWAYS(iOffset>=0, HEAP_PANIC(ETHeapNewBadOffset));	
+
+	iChunkHandle = aChunkHandle;
+	iMinLength = aMinLength;
+	iMaxLength = aMaxLength;
+
+	// If the user has explicitly specified 0 as the aGrowBy value, set it to 1 so that it will be rounded up to the nearst page size
+	if (aGrowBy == 0)
+		aGrowBy = 1;
+	GET_PAGE_SIZE(iPageSize);
+	iGrowBy = _ALIGN_UP(aGrowBy, iPageSize);
+
+	Construct(aSingleThread, aDLOnly, aUseAdjust, aAlign);
+	}
+
+RHybridHeap::RHybridHeap(TInt aMaxLength, TInt aAlign, TBool aSingleThread)
+/**
+Constructor for a fixed heap.  We have restrictions in that we have fixed minimum and maximum lengths and cannot grow
+and we only use DL allocator.
+*/
+	: iOffset(0), iChunkSize(aMaxLength)
+	{
+	iChunkHandle = NULL;
+	iMinLength = aMaxLength;
+	iMaxLength = aMaxLength;
+	iGrowBy = 0;
+
+	Construct(aSingleThread, ETrue, ETrue, aAlign);
+	}
+
+TAny* RHybridHeap::operator new(TUint aSize, TAny* aBase) __NO_THROW
+{
+	__ASSERT_ALWAYS(aSize>=sizeof(RHybridHeap), HEAP_PANIC(ETHeapNewBadSize));
+	RHybridHeap* h = (RHybridHeap*)aBase;
+	h->iBase = ((TUint8*)aBase) + aSize;
+	return aBase;
+}
+
+void RHybridHeap::Construct(TBool aSingleThread, TBool aDLOnly, TBool aUseAdjust, TInt aAlign)
+{
+	iAlign = aAlign ? aAlign : RHybridHeap::ECellAlignment;
+	__ASSERT_ALWAYS((TUint32)iAlign>=sizeof(TAny*) && __POWER_OF_2(iAlign), HEAP_PANIC(ETHeapNewBadAlignment));
+
+	// This initialisation cannot be done in RHeap() for compatibility reasons
+	iTop = NULL;
+	iFailType = ENone;
+	iNestingLevel = 0;
+	iTestData = NULL;
+
+	iHighWaterMark = iMinLength;
+	iAllocCount = 0;
+	iFlags = aSingleThread ? ESingleThreaded : 0;
+	iGrowBy = _ALIGN_UP(iGrowBy, iPageSize);
+	
+	if ( iMinLength == iMaxLength )
+		{
+		iFlags |= EFixedSize;
+		aDLOnly = ETrue;
+		}
+#ifndef __KERNEL_MODE__
+#ifdef DELAYED_SLAB_THRESHOLD
+	iSlabInitThreshold = DELAYED_SLAB_THRESHOLD;
+#else
+	iSlabInitThreshold = 0;
+#endif // DELAYED_SLAB_THRESHOLD
+	iUseAdjust = aUseAdjust;
+	iDLOnly    = aDLOnly;
+#else
+	(void)aUseAdjust;	
+#endif 
+	// Initialise suballocators
+	// if DL only is required then it cannot allocate slab or page memory
+	// so these sub-allocators should be disabled. Otherwise initialise with default values
+	if ( aDLOnly )
+		{
+		Init(0, 0);
+		}
+	else
+		{
+		Init(SLAB_CONFIG, 16);
+		}
+	
+#ifdef ENABLE_BTRACE
+	
+	TUint32 traceData[4];
+	traceData[0] = iMinLength;
+	traceData[1] = iMaxLength;
+	traceData[2] = iGrowBy;
+	traceData[3] = iAlign;
+	BTraceContextN(BTrace::ETest1, 90, (TUint32)this, 11, traceData, sizeof(traceData));
+#endif
+	
+}
+
+#ifndef __KERNEL_MODE__
+TInt RHybridHeap::ConstructLock(TUint32 aMode)
+{
+	TBool duplicateLock = EFalse;
+	TInt r = KErrNone;
+	if (!(iFlags & ESingleThreaded))
+		{
+		duplicateLock = aMode & UserHeap::EChunkHeapSwitchTo;
+		r = iLock.CreateLocal(duplicateLock ? EOwnerThread : EOwnerProcess);
+		if( r != KErrNone)
+			{
+			iChunkHandle = 0;
+			return r;
+			}
+		}
+	
+	if ( aMode & UserHeap::EChunkHeapSwitchTo )
+		User::SwitchHeap(this);
+	
+	iHandles = &iChunkHandle;
+	if (!(iFlags & ESingleThreaded))
+		{
+		// now change the thread-relative chunk/semaphore handles into process-relative handles
+		iHandleCount = 2;
+		if(duplicateLock)
+			{
+			RHandleBase s = iLock;
+			r = iLock.Duplicate(RThread());
+			s.Close();
+			}
+		if (r==KErrNone && (aMode & UserHeap::EChunkHeapDuplicate))
+			{
+			r = ((RChunk*)&iChunkHandle)->Duplicate(RThread());
+			if (r!=KErrNone)
+				iLock.Close(), iChunkHandle=0;
+			}
+		}
+	else
+		{
+		iHandleCount = 1;
+		if (aMode & UserHeap::EChunkHeapDuplicate)
+			r = ((RChunk*)&iChunkHandle)->Duplicate(RThread(), EOwnerThread);
+		}
+	
+	return r;
+}
+#endif
+
+void RHybridHeap::Init(TInt aBitmapSlab, TInt aPagePower)
+{
+	/*Moved code which does initilization */
+	iTop  = (TUint8*)this + iMinLength;
+	iBase = Ceiling(iBase, ECellAlignment);	// Align iBase address 
+	
+    __INIT_COUNTERS(0);
+	//	memset(&mparams,0,sizeof(mparams));
+	
+	InitDlMalloc(iTop - iBase, 0);
+	
+#ifndef __KERNEL_MODE__	
+	SlabInit();
+	iSlabConfigBits = aBitmapSlab;
+	if ( iChunkSize > iSlabInitThreshold )
+		{
+		iSlabInitThreshold = KMaxTInt32;
+		SlabConfig(aBitmapSlab);   // Delayed slab configuration done
+		}
+	if ( aPagePower )
+		{
+		RChunk chunk;
+		chunk.SetHandle(iChunkHandle);
+		iMemBase = chunk.Base();    // Store base address for paged allocator
+		}
+
+	/*10-1K,11-2K,12-4k,13-8K,14-16K,15-32K,16-64K*/
+	PagedInit(aPagePower);
+
+#ifdef ENABLE_BTRACE
+	TUint32 traceData[3];
+	traceData[0] = aBitmapSlab;
+	traceData[1] = aPagePower;
+	traceData[2] = GM->iTrimCheck;
+	BTraceContextN(BTrace::ETest1, 90, (TUint32)this, 0, traceData, sizeof(traceData));
+#endif
+#else
+	(void)aBitmapSlab;
+	(void)aPagePower;
+#endif	// __KERNEL_MODE__
+	
+}
+
+
+TInt RHybridHeap::AllocLen(const TAny* aCell) const
+{
+	aCell = __GET_DEBUG_DATA_BFR(aCell);
+	
+	if (PtrDiff(aCell, this) >= 0)
+		{
+		mchunkptr m = MEM2CHUNK(aCell);
+		return CHUNKSIZE(m) - OVERHEAD_FOR(m) - __DEBUG_HDR_SIZE;
+		}
+#ifndef __KERNEL_MODE__		
+	if ( aCell )
+		{
+		if (LowBits(aCell, iPageSize) )
+			return SlabHeaderSize(slab::SlabFor(aCell)->iHeader) - __DEBUG_HDR_SIZE;
+		
+		return PagedSize((void*)aCell) - __DEBUG_HDR_SIZE;
+		}
+#endif	
+	return 0; // NULL pointer situation, should PANIC !!
+}
+
+#ifdef __KERNEL_MODE__
+TAny* RHybridHeap::Alloc(TInt aSize)
+{
+	__CHECK_THREAD_STATE;
+	__ASSERT_ALWAYS((TUint)aSize<(KMaxTInt/2),HEAP_PANIC(ETHeapBadAllocatedCellSize));
+	__SIMULATE_ALLOC_FAIL(return NULL;)
+	Lock();
+	__ALLOC_DEBUG_HEADER(aSize);
+	TAny* addr = DlMalloc(aSize);
+	if ( addr )
+		{
+//		iCellCount++;
+		__SET_DEBUG_DATA(addr, iNestingLevel, ++iAllocCount);
+		addr = __GET_USER_DATA_BFR(addr);
+		__INCREMENT_COUNTERS(addr);
+		memclr(addr, AllocLen(addr));
+		}
+	Unlock();
+#ifdef ENABLE_BTRACE
+	if (iFlags & ETraceAllocs)
+		{
+		if ( addr )
+			{
+			TUint32 traceData[3];
+			traceData[0] = AllocLen(addr);
+			traceData[1] = aSize - __DEBUG_HDR_SIZE;
+			traceData[2] = 0;
+			BTraceContextN(BTrace::EHeap, BTrace::EHeapAlloc, (TUint32)this, (TUint32)addr, traceData, sizeof(traceData));
+			}
+		else
+			BTraceContext8(BTrace::EHeap, BTrace::EHeapAllocFail, (TUint32)this, (TUint32)(aSize - __DEBUG_HDR_SIZE));			
+		}
+#endif
+	return addr;
+}
+#else
+
+TAny* RHybridHeap::Alloc(TInt aSize)
+{
+	__ASSERT_ALWAYS((TUint)aSize<(KMaxTInt/2),HEAP_PANIC(ETHeapBadAllocatedCellSize));
+	__SIMULATE_ALLOC_FAIL(return NULL;)
+			
+	TAny* addr;
+#ifdef ENABLE_BTRACE
+	TInt aSubAllocator=0;
+#endif
+	
+	Lock();
+	
+	__ALLOC_DEBUG_HEADER(aSize);
+	
+	if (aSize < iSlabThreshold)
+		{
+		TInt ix = iSizeMap[(aSize+3)>>2];
+		HEAP_ASSERT(ix != 0xff);
+		addr = SlabAllocate(iSlabAlloc[ix]);
+		if ( !addr )
+			{ // Slab allocation has failed, try to allocate from DL
+			addr = DlMalloc(aSize);
+			}
+#ifdef ENABLE_BTRACE
+		else
+			aSubAllocator=1;
+#endif
+		}else if((aSize >> iPageThreshold)==0)
+			{
+			addr = DlMalloc(aSize);
+			}
+		else
+			{
+			addr = PagedAllocate(aSize);
+			if ( !addr )
+				{ // Page allocation has failed, try to allocate from DL
+				addr = DlMalloc(aSize);
+				}
+#ifdef ENABLE_BTRACE
+			else
+	      		aSubAllocator=2;
+#endif
+			}
+	
+	if ( addr )
+		{
+//		iCellCount++;
+		__SET_DEBUG_DATA(addr, iNestingLevel, ++iAllocCount);
+		addr = __GET_USER_DATA_BFR(addr);
+		__INCREMENT_COUNTERS(addr);
+		}
+	Unlock();
+	
+#ifdef ENABLE_BTRACE
+	if (iFlags & ETraceAllocs)
+		{
+		if ( addr )
+			{
+		    TUint32 traceData[3];
+		    traceData[0] = AllocLen(addr);
+		    traceData[1] = aSize - __DEBUG_HDR_SIZE;
+			traceData[2] = aSubAllocator;
+		    BTraceContextN(BTrace::EHeap, BTrace::EHeapAlloc, (TUint32)this, (TUint32)addr, traceData, sizeof(traceData));
+			}
+		else
+			BTraceContext8(BTrace::EHeap, BTrace::EHeapAllocFail, (TUint32)this, (TUint32)(aSize - __DEBUG_HDR_SIZE));			
+		}
+#endif
+	
+	return addr;
+}
+#endif // __KERNEL_MODE__
+
+#ifndef __KERNEL_MODE__
+TInt RHybridHeap::Compress()
+{
+	if ( IS_FIXED_HEAP )
+		return 0;
+	
+	Lock();
+	TInt Reduced = SysTrim(GM, 0);
+	if (iSparePage)
+		{
+		Unmap(iSparePage, iPageSize);
+		iSparePage = 0;
+		Reduced += iPageSize;
+		}
+	Unlock();
+	return Reduced;
+}
+#endif
+
+void RHybridHeap::Free(TAny* aPtr)
+{
+	__CHECK_THREAD_STATE;
+	if ( !aPtr )
+		return;
+#ifdef ENABLE_BTRACE
+	TInt aSubAllocator=0;
+#endif
+	Lock();
+	
+	aPtr = __GET_DEBUG_DATA_BFR(aPtr);
+
+#ifndef __KERNEL_MODE__				
+	if (PtrDiff(aPtr, this) >= 0)
+		{
+#endif
+		__DL_BFR_CHECK(GM, aPtr);
+		__DECREMENT_COUNTERS(__GET_USER_DATA_BFR(aPtr));
+		__ZAP_CELL(aPtr);		
+		DlFree( aPtr);
+#ifndef __KERNEL_MODE__			
+		}
+
+	else if ( LowBits(aPtr, iPageSize) == 0 )
+		{
+#ifdef ENABLE_BTRACE
+		aSubAllocator = 2;
+#endif
+		__PAGE_BFR_CHECK(aPtr);	
+		__DECREMENT_COUNTERS(__GET_USER_DATA_BFR(aPtr));
+		PagedFree(aPtr);
+		}
+	else
+		{
+#ifdef ENABLE_BTRACE
+		aSubAllocator = 1;
+#endif
+		TUint32 bm[4];   		
+		__SLAB_BFR_CHECK(slab::SlabFor(aPtr),aPtr,bm);
+		__DECREMENT_COUNTERS(__GET_USER_DATA_BFR(aPtr));  
+		__ZAP_CELL(aPtr);		
+		SlabFree(aPtr);
+		}
+#endif  // __KERNEL_MODE__	
+//	iCellCount--;
+	Unlock();
+#ifdef ENABLE_BTRACE
+	if (iFlags & ETraceAllocs)
+		{
+		TUint32 traceData;
+		traceData = aSubAllocator;
+		BTraceContextN(BTrace::EHeap, BTrace::EHeapFree, (TUint32)this, (TUint32)__GET_USER_DATA_BFR(aPtr), &traceData, sizeof(traceData));
+		}
+#endif
+}
+
+#ifndef __KERNEL_MODE__
+void RHybridHeap::Reset()
+/**
+Frees all allocated cells on this heap.
+*/
+{
+	Lock();
+	if ( !IS_FIXED_HEAP )
+		{
+		if ( GM->iSeg.iSize > (iMinLength - sizeof(*this)) )
+			Unmap(GM->iSeg.iBase + (iMinLength - sizeof(*this)), (GM->iSeg.iSize - (iMinLength - sizeof(*this))));
+		ResetBitmap();
+		if ( !iDLOnly )
+			Init(iSlabConfigBits, iPageThreshold);
+		else
+			Init(0,0);		
+		}
+	else Init(0,0);
+	Unlock();	
+}
+#endif
+
+TAny* RHybridHeap::ReAllocImpl(TAny* aPtr, TInt aSize, TInt aMode)
+{
+	// First handle special case of calling reallocate with NULL aPtr
+	if (!aPtr)
+		{
+		if (( aMode & ENeverMove ) == 0 )
+			{
+			aPtr = Alloc(aSize - __DEBUG_HDR_SIZE);
+			aPtr = __GET_DEBUG_DATA_BFR(aPtr);
+			}
+		return aPtr;
+		}
+	
+	TInt oldsize = AllocLen(__GET_USER_DATA_BFR(aPtr)) + __DEBUG_HDR_SIZE;
+	
+	// Insist on geometric growth when reallocating memory, this reduces copying and fragmentation
+	// generated during arithmetic growth of buffer/array/vector memory
+	// Experiments have shown that 25% is a good threshold for this policy
+	if (aSize <= oldsize)
+		{
+		if (aSize >= oldsize - (oldsize>>2))
+			return aPtr;		// don't change if >75% original size
+		}
+	else
+		{
+		__SIMULATE_ALLOC_FAIL(return NULL;)
+		if (aSize < oldsize + (oldsize>>2))
+			{
+			aSize = _ALIGN_UP(oldsize + (oldsize>>2), 4);	// grow to at least 125% original size
+			}
+		}
+	__DEBUG_SAVE(aPtr);		
+	
+	TAny* newp;
+#ifdef __KERNEL_MODE__
+	Lock();
+	__DL_BFR_CHECK(GM, aPtr);				
+	newp = DlRealloc(aPtr, aSize, aMode);
+	Unlock();
+	if ( newp )
+		{
+	    if ( aSize > oldsize )
+			memclr(((TUint8*)newp) + oldsize, (aSize-oldsize)); // Buffer has grown in place, clear extra
+		__DEBUG_RESTORE(newp);
+		__UPDATE_ALLOC_COUNT(aPtr, newp, ++iAllocCount);
+		__UPDATE_TOTAL_ALLOC(newp, oldsize);
+		}
+#else
+	// Decide how to reallocate based on (a) the current cell location, (b) the mode requested and (c) the new size
+	if ( PtrDiff(aPtr, this) >= 0 )
+		{	// current cell in Doug Lea iArena
+		if ( (aMode & ENeverMove) 
+			 ||
+			 (!(aMode & EAllowMoveOnShrink) && (aSize < oldsize))
+			 ||
+			 ((aSize >= iSlabThreshold) && ((aSize >> iPageThreshold) == 0)) )
+			{
+			Lock();
+			__DL_BFR_CHECK(GM, aPtr);			
+			newp = DlRealloc(aPtr, aSize, aMode);			// old and new in DL allocator
+			Unlock();
+			__DEBUG_RESTORE(newp);
+			__UPDATE_ALLOC_COUNT(aPtr,newp, ++iAllocCount);
+			__UPDATE_TOTAL_ALLOC(newp, oldsize);
+			return newp;
+			}
+		}
+	else if (LowBits(aPtr, iPageSize) == 0)
+		{	// current cell in paged iArena
+		if ( (aMode & ENeverMove)     
+			 ||
+			 (!(aMode & EAllowMoveOnShrink) && (aSize < oldsize)) 
+			 ||
+			 ((aSize >> iPageThreshold) != 0) )
+			{
+			Lock();
+			__PAGE_BFR_CHECK(aPtr);			
+			newp = PagedReallocate(aPtr, aSize, aMode);		// old and new in paged allocator
+			Unlock();
+			__DEBUG_RESTORE(newp);
+			__UPDATE_ALLOC_COUNT(aPtr,newp, ++iAllocCount);
+			__UPDATE_TOTAL_ALLOC(newp, oldsize);
+			return newp;
+			}
+		}
+	else
+		{	// current cell in slab iArena
+		TUint32 bm[4];
+		Lock();
+		__SLAB_BFR_CHECK(slab::SlabFor(aPtr), aPtr, bm);
+		Unlock();
+		if ( aSize <= oldsize)
+			return aPtr;
+		if (aMode & ENeverMove)
+			return NULL;		// cannot grow in slab iArena
+		// just use alloc/copy/free...
+		}
+	
+	// fallback to allocate and copy
+	// shouldn't get here if we cannot move the cell
+	//  	__ASSERT(mode == emobile || (mode==efixshrink && size>oldsize));
+	
+	newp = Alloc(aSize - __DEBUG_HDR_SIZE);
+	newp = __GET_DEBUG_DATA_BFR(newp);
+	if (newp)
+		{
+		memcpy(newp, aPtr, oldsize<aSize ? oldsize : aSize);
+		__DEBUG_RESTORE(newp);
+		Free(__GET_USER_DATA_BFR(aPtr));
+		}
+	
+#endif	// __KERNEL_MODE__
+	return newp;
+}
+
+
+TAny* RHybridHeap::ReAlloc(TAny* aPtr, TInt aSize, TInt aMode )
+{
+	
+	aPtr = __GET_DEBUG_DATA_BFR(aPtr);
+	__ALLOC_DEBUG_HEADER(aSize);
+	
+	TAny* retval = ReAllocImpl(aPtr, aSize, aMode);
+	
+	retval = __GET_USER_DATA_BFR(retval);
+	
+#ifdef ENABLE_BTRACE
+	if (iFlags & ETraceAllocs)
+		{
+		if ( retval )
+			{
+			TUint32 traceData[3];
+			traceData[0] = AllocLen(retval);
+			traceData[1] = aSize - __DEBUG_HDR_SIZE;
+			traceData[2] = (TUint32)aPtr;
+			BTraceContextN(BTrace::EHeap, BTrace::EHeapReAlloc,(TUint32)this, (TUint32)retval, traceData, sizeof(traceData));
+			}
+  		else
+  		    BTraceContext12(BTrace::EHeap, BTrace::EHeapReAllocFail, (TUint32)this, (TUint32)aPtr, (TUint32)(aSize - __DEBUG_HDR_SIZE));
+		}
+#endif
+	return retval;
+}
+
+#ifndef __KERNEL_MODE__
+TInt RHybridHeap::Available(TInt& aBiggestBlock) const
+/**
+Gets the total free space currently available on the heap and the space
+available in the largest free block.
+
+Note that this function exists mainly for compatibility reasons.  In a modern
+heap implementation such as that present in Symbian it is not appropriate to
+concern oneself with details such as the amount of free memory available on a
+heap and its largeset free block, because the way that a modern heap implmentation
+works is not simple.  The amount of available virtual memory != physical memory
+and there are multiple allocation strategies used internally, which makes all
+memory usage figures "fuzzy" at best.
+
+In short, if you want to see if there is enough memory available to allocate a
+block of memory, call Alloc() and if it succeeds then there is enough memory!
+Messing around with functions like this is somewhat pointless with modern heap
+allocators.
+
+@param aBiggestBlock On return, contains the space available in the largest
+                     free block on the heap.  Due to the internals of modern
+                     heap implementations, you can probably still allocate a
+                     block larger than this!
+
+@return The total free space currently available on the heap.  Again, you can
+        probably still allocate more than this!
+*/
+{
+	struct HeapInfo info;
+	Lock();
+	TInt Biggest  = GetInfo(&info);
+	aBiggestBlock = __GET_AVAIL_BLOCK_SIZE(Biggest);
+	Unlock();
+	return __GET_AVAIL_BLOCK_SIZE(info.iFreeBytes);
+	
+}
+
+TInt RHybridHeap::AllocSize(TInt& aTotalAllocSize) const
+   /**
+   Gets the number of cells allocated on this heap, and the total space 
+   allocated to them.
+   
+   @param aTotalAllocSize On return, contains the total space allocated
+   to the cells.
+   
+   @return The number of cells allocated on this heap.
+*/   
+{
+	struct HeapInfo info;
+	Lock();
+	GetInfo(&info);
+	aTotalAllocSize = info.iAllocBytes - __REMOVE_DBG_HDR(info.iAllocN);
+	Unlock();
+	return info.iAllocN;
+}
+
+#endif
+
+TInt RHybridHeap::Extension_(TUint /* aExtensionId */, TAny*& /* a0 */, TAny* /* a1 */)
+{
+	return KErrNotSupported;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// imported from dla.cpp
+///////////////////////////////////////////////////////////////////////////////
+
+//#include <unistd.h>
+//#define DEBUG_REALLOC
+#ifdef DEBUG_REALLOC
+#include <e32debug.h>
+#endif
+
+inline void RHybridHeap::InitBins(mstate m)
+{
+	/* Establish circular links for iSmallBins */
+	bindex_t i;
+	for (i = 0; i < NSMALLBINS; ++i) {
+		sbinptr bin = SMALLBIN_AT(m,i);
+		bin->iFd = bin->iBk = bin;
+		}
+	}
+/* ---------------------------- malloc support --------------------------- */
+
+/* allocate a large request from the best fitting chunk in a treebin */
+void* RHybridHeap::TmallocLarge(mstate m, size_t nb) {
+	tchunkptr v = 0;
+	size_t rsize = -nb; /* Unsigned negation */
+	tchunkptr t;
+	bindex_t idx;
+	ComputeTreeIndex(nb, idx);
+	
+	if ((t = *TREEBIN_AT(m, idx)) != 0)
+		{
+		/* Traverse tree for this bin looking for node with size == nb */
+		size_t sizebits = nb << LEFTSHIFT_FOR_TREE_INDEX(idx);
+		tchunkptr rst = 0;  /* The deepest untaken right subtree */
+		for (;;)
+			{
+			tchunkptr rt;
+			size_t trem = CHUNKSIZE(t) - nb;
+			if (trem < rsize)
+				{
+				v = t;
+				if ((rsize = trem) == 0)
+					break;
+				}
+			rt = t->iChild[1];
+			t = t->iChild[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+			if (rt != 0 && rt != t)
+				rst = rt;
+			if (t == 0)
+				{
+				t = rst; /* set t to least subtree holding sizes > nb */
+				break;
+				}
+			sizebits <<= 1;
+			}
+		}
+	if (t == 0 && v == 0)
+		{ /* set t to root of next non-empty treebin */
+		binmap_t leftbits = LEFT_BITS(IDX2BIT(idx)) & m->iTreeMap;
+		if (leftbits != 0)
+			{
+			bindex_t i;
+			binmap_t leastbit = LEAST_BIT(leftbits);
+			ComputeBit2idx(leastbit, i);
+			t = *TREEBIN_AT(m, i);
+			}
+		}
+	while (t != 0)
+		{ /* Find smallest of tree or subtree */
+		size_t trem = CHUNKSIZE(t) - nb;
+		if (trem < rsize) {
+			rsize = trem;
+			v = t;
+			}
+		t = LEFTMOST_CHILD(t);
+		}
+	/*  If iDv is a better fit, return 0 so malloc will use it */
+	if (v != 0 && rsize < (size_t)(m->iDvSize - nb))
+		{
+		if (RTCHECK(OK_ADDRESS(m, v)))
+			{ /* split */
+			mchunkptr r = CHUNK_PLUS_OFFSET(v, nb);
+			HEAP_ASSERT(CHUNKSIZE(v) == rsize + nb);
+			if (RTCHECK(OK_NEXT(v, r)))
+				{
+				UnlinkLargeChunk(m, v);
+				if (rsize < MIN_CHUNK_SIZE)
+					SET_INUSE_AND_PINUSE(m, v, (rsize + nb));
+				else
+					{
+					SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(m, v, nb);
+					SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(r, rsize);
+					InsertChunk(m, r, rsize);
+					}
+				return CHUNK2MEM(v);
+				}
+			}
+		//    CORRUPTION_ERROR_ACTION(m);
+		}
+	return 0;
+	}
+
+/* allocate a small request from the best fitting chunk in a treebin */
+void* RHybridHeap::TmallocSmall(mstate m, size_t nb)
+{
+	tchunkptr t, v;
+	size_t rsize;
+	bindex_t i;
+	binmap_t leastbit = LEAST_BIT(m->iTreeMap);
+	ComputeBit2idx(leastbit, i);
+	
+	v = t = *TREEBIN_AT(m, i);
+	rsize = CHUNKSIZE(t) - nb;
+	
+	while ((t = LEFTMOST_CHILD(t)) != 0)
+		{
+		size_t trem = CHUNKSIZE(t) - nb;
+		if (trem < rsize)
+			{
+			rsize = trem;
+			v = t;
+			}
+		}
+	
+	if (RTCHECK(OK_ADDRESS(m, v)))
+		{
+		mchunkptr r = CHUNK_PLUS_OFFSET(v, nb);
+		HEAP_ASSERT(CHUNKSIZE(v) == rsize + nb);
+		if (RTCHECK(OK_NEXT(v, r)))
+			{
+			UnlinkLargeChunk(m, v);
+			if (rsize < MIN_CHUNK_SIZE)
+				SET_INUSE_AND_PINUSE(m, v, (rsize + nb));
+			else
+				{
+				SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(m, v, nb);
+				SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(r, rsize);
+				ReplaceDv(m, r, rsize);
+				}
+			return CHUNK2MEM(v);
+			}
+		}
+	//  CORRUPTION_ERROR_ACTION(m);
+	//  return 0;
+	}
+
+inline void RHybridHeap::InitTop(mstate m, mchunkptr p, size_t psize)
+{
+	/* Ensure alignment */
+	size_t offset = ALIGN_OFFSET(CHUNK2MEM(p));
+	p = (mchunkptr)((TUint8*)p + offset);
+	psize -= offset;
+	m->iTop = p;
+	m->iTopSize = psize;
+	p->iHead = psize | PINUSE_BIT;
+	/* set size of fake trailing chunk holding overhead space only once */
+	mchunkptr chunkPlusOff = CHUNK_PLUS_OFFSET(p, psize);
+	chunkPlusOff->iHead = TOP_FOOT_SIZE;
+	m->iTrimCheck = KHeapShrinkHysRatio*(iGrowBy>>8);
+}
+
+
+/* Unlink the first chunk from a smallbin */
+inline void RHybridHeap::UnlinkFirstSmallChunk(mstate M,mchunkptr B,mchunkptr P,bindex_t& I)
+{
+	mchunkptr F = P->iFd;
+	HEAP_ASSERT(P != B);
+	HEAP_ASSERT(P != F);
+	HEAP_ASSERT(CHUNKSIZE(P) == SMALL_INDEX2SIZE(I));
+	if (B == F)
+		CLEAR_SMALLMAP(M, I);
+	else if (RTCHECK(OK_ADDRESS(M, F)))
+		{
+		B->iFd = F;
+		F->iBk = B;
+		}
+	else
+		{
+		CORRUPTION_ERROR_ACTION(M);
+		}
+}
+/* Link a free chunk into a smallbin  */
+inline void RHybridHeap::InsertSmallChunk(mstate M,mchunkptr P, size_t S)
+{
+	bindex_t I  = SMALL_INDEX(S);
+	mchunkptr B = SMALLBIN_AT(M, I);
+	mchunkptr F = B;
+	HEAP_ASSERT(S >= MIN_CHUNK_SIZE);
+	if (!SMALLMAP_IS_MARKED(M, I))
+		MARK_SMALLMAP(M, I);
+	else if (RTCHECK(OK_ADDRESS(M, B->iFd)))
+		F = B->iFd;
+	else
+		{
+		CORRUPTION_ERROR_ACTION(M);
+		}
+	B->iFd = P;
+	F->iBk = P;
+	P->iFd = F;
+	P->iBk = B;
+}
+
+
+inline void RHybridHeap::InsertChunk(mstate M,mchunkptr P,size_t S)
+{
+	if (IS_SMALL(S))
+		InsertSmallChunk(M, P, S);
+	else
+		{
+		tchunkptr TP = (tchunkptr)(P); InsertLargeChunk(M, TP, S);
+		}
+}
+
+inline void RHybridHeap::UnlinkLargeChunk(mstate M,tchunkptr X)
+{
+	tchunkptr XP = X->iParent;
+	tchunkptr R;
+	if (X->iBk != X)
+		{
+		tchunkptr F = X->iFd;
+		R = X->iBk;
+		if (RTCHECK(OK_ADDRESS(M, F)))
+			{
+			F->iBk = R;
+			R->iFd = F;
+			}
+		else
+			{
+			CORRUPTION_ERROR_ACTION(M);
+			}
+		}
+	else
+		{
+		tchunkptr* RP;
+		if (((R = *(RP = &(X->iChild[1]))) != 0) ||
+			  ((R = *(RP = &(X->iChild[0]))) != 0))
+			{
+			tchunkptr* CP;
+			while ((*(CP = &(R->iChild[1])) != 0) ||
+				   (*(CP = &(R->iChild[0])) != 0))
+				{
+				R = *(RP = CP);
+				}
+			if (RTCHECK(OK_ADDRESS(M, RP)))
+				*RP = 0;
+			else
+				{
+				CORRUPTION_ERROR_ACTION(M);
+				}
+			}
+		}
+	if (XP != 0)
+		{
+		tbinptr* H = TREEBIN_AT(M, X->iIndex);
+		if (X == *H)
+			{
+			if ((*H = R) == 0)
+				CLEAR_TREEMAP(M, X->iIndex);
+			}
+		else if (RTCHECK(OK_ADDRESS(M, XP)))
+			{
+			if (XP->iChild[0] == X)
+				XP->iChild[0] = R;
+			else
+				XP->iChild[1] = R;
+			}
+		else
+			CORRUPTION_ERROR_ACTION(M);
+		if (R != 0)
+			{
+			if (RTCHECK(OK_ADDRESS(M, R)))
+				{
+				tchunkptr C0, C1;
+				R->iParent = XP;
+				if ((C0 = X->iChild[0]) != 0)
+					{
+					if (RTCHECK(OK_ADDRESS(M, C0)))
+						{
+						R->iChild[0] = C0;
+						C0->iParent = R;
+						}
+					else
+						CORRUPTION_ERROR_ACTION(M);
+					}
+				if ((C1 = X->iChild[1]) != 0)
+					{
+					if (RTCHECK(OK_ADDRESS(M, C1)))
+						{
+						R->iChild[1] = C1;
+						C1->iParent = R;
+						}
+					else
+						CORRUPTION_ERROR_ACTION(M);
+					}
+				}
+			else
+				CORRUPTION_ERROR_ACTION(M);
+			}
+		}
+}
+
+/* Unlink a chunk from a smallbin  */
+inline void RHybridHeap::UnlinkSmallChunk(mstate M, mchunkptr P,size_t S)
+{
+	mchunkptr F = P->iFd;
+	mchunkptr B = P->iBk;
+	bindex_t I = SMALL_INDEX(S);
+	HEAP_ASSERT(P != B);
+	HEAP_ASSERT(P != F);
+	HEAP_ASSERT(CHUNKSIZE(P) == SMALL_INDEX2SIZE(I));
+	if (F == B)
+		CLEAR_SMALLMAP(M, I);
+	else if (RTCHECK((F == SMALLBIN_AT(M,I) || OK_ADDRESS(M, F)) &&
+					 (B == SMALLBIN_AT(M,I) || OK_ADDRESS(M, B))))
+		{
+		F->iBk = B;
+		B->iFd = F;
+		}
+	else
+		{
+		CORRUPTION_ERROR_ACTION(M);
+		}
+}
+
+inline void RHybridHeap::UnlinkChunk(mstate M, mchunkptr P, size_t S)
+{
+	if (IS_SMALL(S))
+		UnlinkSmallChunk(M, P, S);
+	else
+		{
+		tchunkptr TP = (tchunkptr)(P); UnlinkLargeChunk(M, TP);
+		}
+}
+
+// For DL debug functions
+void RHybridHeap::DoComputeTreeIndex(size_t S, bindex_t& I)
+{
+	ComputeTreeIndex(S, I);
+}	
+
+inline void RHybridHeap::ComputeTreeIndex(size_t S, bindex_t& I)
+{
+	size_t X = S >> TREEBIN_SHIFT;
+	if (X == 0)
+		I = 0;
+	else if (X > 0xFFFF)
+		I = NTREEBINS-1;
+	else
+		{
+		unsigned int Y = (unsigned int)X;
+		unsigned int N = ((Y - 0x100) >> 16) & 8;
+		unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;
+		N += K;
+		N += K = (((Y <<= K) - 0x4000) >> 16) & 2;
+		K = 14 - N + ((Y <<= K) >> 15);
+		I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));
+		}
+}
+
+/* ------------------------- Operations on trees ------------------------- */
+
+/* Insert chunk into tree */
+inline void RHybridHeap::InsertLargeChunk(mstate M,tchunkptr X,size_t S)
+{
+	tbinptr* H;
+	bindex_t I;
+	ComputeTreeIndex(S, I);
+	H = TREEBIN_AT(M, I);
+	X->iIndex = I;
+	X->iChild[0] = X->iChild[1] = 0;
+	if (!TREEMAP_IS_MARKED(M, I))
+		{
+		MARK_TREEMAP(M, I);
+		*H = X;
+		X->iParent = (tchunkptr)H;
+		X->iFd = X->iBk = X;
+		}
+	else
+		{
+		tchunkptr T = *H;
+		size_t K = S << LEFTSHIFT_FOR_TREE_INDEX(I);
+		for (;;)
+			{
+			if (CHUNKSIZE(T) != S) {
+				tchunkptr* C = &(T->iChild[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);
+				K <<= 1;
+				if (*C != 0)
+					T = *C;
+				else if (RTCHECK(OK_ADDRESS(M, C)))
+					{
+					*C = X;
+					X->iParent = T;
+					X->iFd = X->iBk = X;
+					break;
+					}
+				else
+					{
+					CORRUPTION_ERROR_ACTION(M);
+					break;
+					}
+				}
+			else
+				{
+				tchunkptr F = T->iFd;
+				if (RTCHECK(OK_ADDRESS(M, T) && OK_ADDRESS(M, F)))
+					{
+					T->iFd = F->iBk = X;
+					X->iFd = F;
+					X->iBk = T;
+					X->iParent = 0;
+					break;
+					}
+				else
+					{
+					CORRUPTION_ERROR_ACTION(M);
+					break;
+					}
+				}
+			}
+		}
+}
+
+/*
+Unlink steps:
+
+1. If x is a chained node, unlink it from its same-sized iFd/iBk links
+and choose its iBk node as its replacement.
+2. If x was the last node of its size, but not a leaf node, it must
+be replaced with a leaf node (not merely one with an open left or
+right), to make sure that lefts and rights of descendents
+correspond properly to bit masks.  We use the rightmost descendent
+of x.  We could use any other leaf, but this is easy to locate and
+tends to counteract removal of leftmosts elsewhere, and so keeps
+paths shorter than minimally guaranteed.  This doesn't loop much
+because on average a node in a tree is near the bottom.
+3. If x is the base of a chain (i.e., has iParent links) relink
+x's iParent and children to x's replacement (or null if none).
+*/
+
+/* Replace iDv node, binning the old one */
+/* Used only when iDvSize known to be small */
+inline void RHybridHeap::ReplaceDv(mstate M, mchunkptr P, size_t S)
+{
+	size_t DVS = M->iDvSize;
+	if (DVS != 0)
+		{
+		mchunkptr DV = M->iDv;
+		HEAP_ASSERT(IS_SMALL(DVS));
+		InsertSmallChunk(M, DV, DVS);
+		}
+	M->iDvSize = S;
+	M->iDv = P;
+}
+
+
+inline void RHybridHeap::ComputeBit2idx(binmap_t X,bindex_t& I)
+{
+	unsigned int Y = X - 1;
+	unsigned int K = Y >> (16-4) & 16;
+	unsigned int N = K;        Y >>= K;
+	N += K = Y >> (8-3) &  8;  Y >>= K;
+	N += K = Y >> (4-2) &  4;  Y >>= K;
+	N += K = Y >> (2-1) &  2;  Y >>= K;
+	N += K = Y >> (1-0) &  1;  Y >>= K;
+	I = (bindex_t)(N + Y);
+}
+
+
+
+int RHybridHeap::SysTrim(mstate m, size_t pad)
+{
+	size_t extra = 0;
+	
+	if ( IS_INITIALIZED(m) )
+		{
+		pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
+		
+		if (m->iTopSize > pad)
+			{
+			extra = Floor(m->iTopSize - pad, iPageSize);
+			if ( (m->iSeg.iSize - extra) < (iMinLength - sizeof(*this)) )			  
+				{
+				if ( m->iSeg.iSize > (iMinLength - sizeof(*this)) )				  
+					extra = Floor(m->iSeg.iSize - (iMinLength - sizeof(*this)), iPageSize); /* do not shrink heap below min length */
+				else extra = 0;
+				}
+			
+			if ( extra )
+				{
+				Unmap(m->iSeg.iBase + m->iSeg.iSize - extra, extra);
+				
+				m->iSeg.iSize -= extra;
+				InitTop(m, m->iTop, m->iTopSize - extra);
+				CHECK_TOP_CHUNK(m, m->iTop);
+				}
+			}
+		
+		}
+	
+	return extra;
+}
+
+/* Get memory from system using MORECORE */
+
+void* RHybridHeap::SysAlloc(mstate m, size_t nb)
+{
+	HEAP_ASSERT(m->iTop);
+	/* Subtract out existing available iTop space from MORECORE request. */
+//	size_t asize = _ALIGN_UP(nb - m->iTopSize + TOP_FOOT_SIZE + SIZE_T_ONE, iGrowBy);  
+  	TInt asize = _ALIGN_UP(nb - m->iTopSize + SYS_ALLOC_PADDING, iGrowBy);  // From DLA version 2.8.4
+	
+	char* br = (char*)Map(m->iSeg.iBase+m->iSeg.iSize, asize);
+	if (!br)
+		return 0;
+	HEAP_ASSERT(br == (char*)m->iSeg.iBase+m->iSeg.iSize);
+	
+	/* Merge with an existing segment */
+	m->iSeg.iSize += asize;
+	InitTop(m, m->iTop, m->iTopSize + asize);
+	
+	if (nb < m->iTopSize)
+		{ /* Allocate from new or extended iTop space */
+		size_t rsize = m->iTopSize -= nb;
+		mchunkptr p = m->iTop;
+		mchunkptr r = m->iTop = CHUNK_PLUS_OFFSET(p, nb);
+		r->iHead = rsize | PINUSE_BIT;
+		SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(m, p, nb);
+		CHECK_TOP_CHUNK(m, m->iTop);
+		CHECK_MALLOCED_CHUNK(m, CHUNK2MEM(p), nb);
+		return CHUNK2MEM(p);
+		}
+	
+	return 0;
+}	
+
+
+void RHybridHeap::InitDlMalloc(size_t capacity, int /*locked*/)
+{
+	memset(GM,0,sizeof(malloc_state));
+	// The maximum amount that can be allocated can be calculated as:-
+	// 2^sizeof(size_t) - sizeof(malloc_state) - TOP_FOOT_SIZE - page Size(all accordingly padded)
+	// If the capacity exceeds this, no allocation will be done.
+	GM->iSeg.iBase = iBase;
+	GM->iSeg.iSize = capacity;
+	InitBins(GM);
+	InitTop(GM, (mchunkptr)iBase, capacity - TOP_FOOT_SIZE);
+}
+
+void* RHybridHeap::DlMalloc(size_t bytes) 
+{
+	/*
+	Basic algorithm:
+	If a small request (< 256 bytes minus per-chunk overhead):
+	1. If one exists, use a remainderless chunk in associated smallbin.
+	(Remainderless means that there are too few excess bytes to
+	represent as a chunk.)
+	2. If it is big enough, use the iDv chunk, which is normally the
+	chunk adjacent to the one used for the most recent small request.
+	3. If one exists, split the smallest available chunk in a bin,
+	saving remainder in iDv.
+	4. If it is big enough, use the iTop chunk.
+	5. If available, get memory from system and use it
+	Otherwise, for a large request:
+	1. Find the smallest available binned chunk that fits, and use it
+	if it is better fitting than iDv chunk, splitting if necessary.
+	2. If better fitting than any binned chunk, use the iDv chunk.
+	3. If it is big enough, use the iTop chunk.
+	4. If request size >= mmap threshold, try to directly mmap this chunk.
+	5. If available, get memory from system and use it
+*/
+	void* mem;
+	size_t nb;
+	if (bytes <= MAX_SMALL_REQUEST)
+		{
+		bindex_t idx;
+		binmap_t smallbits;
+		nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : PAD_REQUEST(bytes);
+		idx = SMALL_INDEX(nb);
+		smallbits = GM->iSmallMap >> idx;
+		
+		if ((smallbits & 0x3U) != 0)
+			{ /* Remainderless fit to a smallbin. */
+			mchunkptr b, p;
+			idx += ~smallbits & 1;			 /* Uses next bin if idx empty */
+			b = SMALLBIN_AT(GM, idx);
+			p = b->iFd;
+			HEAP_ASSERT(CHUNKSIZE(p) == SMALL_INDEX2SIZE(idx));
+			UnlinkFirstSmallChunk(GM, b, p, idx);
+			SET_INUSE_AND_PINUSE(GM, p, SMALL_INDEX2SIZE(idx));
+			mem = CHUNK2MEM(p);
+			CHECK_MALLOCED_CHUNK(GM, mem, nb);
+			return mem;
+			}
+		
+		else if (nb > GM->iDvSize)
+			{
+			if (smallbits != 0)
+				{ /* Use chunk in next nonempty smallbin */
+				mchunkptr b, p, r;
+				size_t rsize;
+				bindex_t i;
+				binmap_t leftbits = (smallbits << idx) & LEFT_BITS(IDX2BIT(idx));
+				binmap_t leastbit = LEAST_BIT(leftbits);
+				ComputeBit2idx(leastbit, i);
+				b = SMALLBIN_AT(GM, i);
+				p = b->iFd;
+				HEAP_ASSERT(CHUNKSIZE(p) == SMALL_INDEX2SIZE(i));
+				UnlinkFirstSmallChunk(GM, b, p, i);
+				rsize = SMALL_INDEX2SIZE(i) - nb;
+				/* Fit here cannot be remainderless if 4byte sizes */
+				if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+					SET_INUSE_AND_PINUSE(GM, p, SMALL_INDEX2SIZE(i));
+				else
+					{
+					SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(GM, p, nb);
+					r = CHUNK_PLUS_OFFSET(p, nb);
+					SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(r, rsize);
+					ReplaceDv(GM, r, rsize);
+					}
+				mem = CHUNK2MEM(p);
+				CHECK_MALLOCED_CHUNK(GM, mem, nb);
+				return mem;
+				}
+			
+			else if (GM->iTreeMap != 0 && (mem = TmallocSmall(GM, nb)) != 0)
+				{
+				CHECK_MALLOCED_CHUNK(GM, mem, nb);
+				return mem;
+				}
+			}
+		}
+	else if (bytes >= MAX_REQUEST)
+		nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+	else
+		{
+		nb = PAD_REQUEST(bytes);
+		if (GM->iTreeMap != 0 && (mem = TmallocLarge(GM, nb)) != 0)
+			{
+			CHECK_MALLOCED_CHUNK(GM, mem, nb);
+			return mem;
+			}
+		}
+	
+	if (nb <= GM->iDvSize)
+		{
+		size_t rsize = GM->iDvSize - nb;
+		mchunkptr p = GM->iDv;
+		if (rsize >= MIN_CHUNK_SIZE)
+			{ /* split iDv */
+			mchunkptr r = GM->iDv = CHUNK_PLUS_OFFSET(p, nb);
+			GM->iDvSize = rsize;
+			SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(r, rsize);
+			SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(GM, p, nb);
+			}
+		else
+			{ /* exhaust iDv */
+			size_t dvs = GM->iDvSize;
+			GM->iDvSize = 0;
+			GM->iDv = 0;
+			SET_INUSE_AND_PINUSE(GM, p, dvs);
+			}
+		mem = CHUNK2MEM(p);
+		CHECK_MALLOCED_CHUNK(GM, mem, nb);
+		return mem;
+		}
+	
+	else if (nb < GM->iTopSize)
+		{ /* Split iTop */
+		size_t rsize = GM->iTopSize -= nb;
+		mchunkptr p = GM->iTop;
+		mchunkptr r = GM->iTop = CHUNK_PLUS_OFFSET(p, nb);
+		r->iHead = rsize | PINUSE_BIT;
+		SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(GM, p, nb);
+		mem = CHUNK2MEM(p);
+		CHECK_TOP_CHUNK(GM, GM->iTop);
+		CHECK_MALLOCED_CHUNK(GM, mem, nb);
+		return mem;
+		}
+	
+	return SysAlloc(GM, nb);
+}
+
+
+void RHybridHeap::DlFree(void* mem)
+{
+	/*
+	Consolidate freed chunks with preceeding or succeeding bordering
+	free chunks, if they exist, and then place in a bin.	Intermixed
+	with special cases for iTop, iDv, mmapped chunks, and usage errors.
+*/
+	mchunkptr p	= MEM2CHUNK(mem);
+	CHECK_INUSE_CHUNK(GM, p);
+	if (RTCHECK(OK_ADDRESS(GM, p) && OK_CINUSE(p)))
+		{
+		size_t psize = CHUNKSIZE(p);
+		mchunkptr next = CHUNK_PLUS_OFFSET(p, psize);
+		if (!PINUSE(p))
+			{
+			size_t prevsize = p->iPrevFoot;
+			mchunkptr prev = CHUNK_MINUS_OFFSET(p, prevsize);
+			psize += prevsize;
+			p = prev;
+			if (RTCHECK(OK_ADDRESS(GM, prev)))
+				{ /* consolidate backward */
+				if (p != GM->iDv)
+					{
+					UnlinkChunk(GM, p, prevsize);
+					}
+				else if ((next->iHead & INUSE_BITS) == INUSE_BITS)
+					{
+					GM->iDvSize = psize;
+					SET_FREE_WITH_PINUSE(p, psize, next);
+					return;
+					}
+				}
+			else
+				{
+				USAGE_ERROR_ACTION(GM, p);
+				return;
+				}
+			}
+		
+		if (RTCHECK(OK_NEXT(p, next) && OK_PINUSE(next)))
+			{
+			if (!CINUSE(next))
+				{	/* consolidate forward */
+				if (next == GM->iTop)
+					{
+					size_t tsize = GM->iTopSize += psize;
+					GM->iTop = p;
+					p->iHead = tsize | PINUSE_BIT;
+					if (p == GM->iDv)
+						{
+						GM->iDv = 0;
+						GM->iDvSize = 0;
+						}
+					if ( !IS_FIXED_HEAP && SHOULD_TRIM(GM, tsize)  )					
+						SysTrim(GM, 0);
+					return;
+					}
+				else if (next == GM->iDv)
+					{
+					size_t dsize = GM->iDvSize += psize;
+					GM->iDv = p;
+					SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(p, dsize);
+					return;
+					}
+				else
+					{
+					size_t nsize = CHUNKSIZE(next);
+					psize += nsize;
+					UnlinkChunk(GM, next, nsize);
+					SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(p, psize);
+					if (p == GM->iDv)
+						{
+						GM->iDvSize = psize;
+						return;
+						}
+					}
+				}
+			else
+				SET_FREE_WITH_PINUSE(p, psize, next);
+			InsertChunk(GM, p, psize);
+			CHECK_FREE_CHUNK(GM, p);
+			return;
+			}
+		}
+}
+
+
+void* RHybridHeap::DlRealloc(void* oldmem, size_t bytes, TInt mode)
+{
+	mchunkptr oldp = MEM2CHUNK(oldmem);
+	size_t oldsize = CHUNKSIZE(oldp);
+	mchunkptr next = CHUNK_PLUS_OFFSET(oldp, oldsize);
+	mchunkptr newp = 0;
+	void* extra = 0;
+	
+	/* Try to either shrink or extend into iTop. Else malloc-copy-free */
+	
+	if (RTCHECK(OK_ADDRESS(GM, oldp) && OK_CINUSE(oldp) &&
+				OK_NEXT(oldp, next) && OK_PINUSE(next)))
+		{
+		size_t nb = REQUEST2SIZE(bytes);
+		if (oldsize >= nb) { /* already big enough */
+			size_t rsize = oldsize - nb;
+			newp = oldp;
+			if (rsize >= MIN_CHUNK_SIZE)
+				{     
+				mchunkptr remainder = CHUNK_PLUS_OFFSET(newp, nb);
+				SET_INUSE(GM, newp, nb);
+//				SET_INUSE(GM, remainder, rsize);
+ 				SET_INUSE_AND_PINUSE(GM, remainder, rsize);  // corrected in original DLA version V2.8.4
+				extra = CHUNK2MEM(remainder);
+				}
+			}
+		else if (next == GM->iTop && oldsize + GM->iTopSize > nb)
+			{
+			/* Expand into iTop */
+			size_t newsize = oldsize + GM->iTopSize;
+			size_t newtopsize = newsize - nb;
+			mchunkptr newtop = CHUNK_PLUS_OFFSET(oldp, nb);
+			SET_INUSE(GM, oldp, nb);
+			newtop->iHead = newtopsize |PINUSE_BIT;
+			GM->iTop = newtop;
+			GM->iTopSize = newtopsize;
+			newp = oldp;
+			}
+		}
+	else
+		{
+		USAGE_ERROR_ACTION(GM, oldmem);
+		}
+	
+	if (newp != 0)
+		{
+		if (extra != 0)
+			{
+			DlFree(extra);
+			}
+		CHECK_INUSE_CHUNK(GM, newp);
+		return CHUNK2MEM(newp);
+		}
+	else
+		{
+		if ( mode & ENeverMove )
+			return 0;		// cannot move
+		void* newmem = DlMalloc(bytes);
+		if (newmem != 0)
+			{
+			size_t oc = oldsize - OVERHEAD_FOR(oldp);
+			memcpy(newmem, oldmem, (oc < bytes)? oc : bytes);
+			DlFree(oldmem);
+			}
+		return newmem;
+		}
+	//	return 0;
+}
+
+size_t RHybridHeap::DlInfo(struct HeapInfo* i, SWalkInfo* wi) const
+{
+	TInt max = ((GM->iTopSize-1) & ~CHUNK_ALIGN_MASK) - CHUNK_OVERHEAD;
+	if ( max < 0 )
+		max = 0;
+	else ++i->iFreeN;			// iTop always free
+	i->iFreeBytes += max;
+	
+	Walk(wi, GM->iTop, max, EGoodFreeCell, EDougLeaAllocator); // Introduce DL iTop buffer to the walk function 
+	
+	for (mchunkptr q = ALIGN_AS_CHUNK(GM->iSeg.iBase); q != GM->iTop; q = NEXT_CHUNK(q))
+		{
+		TInt sz = CHUNKSIZE(q);
+		if (!CINUSE(q))
+			{
+			if ( sz > max )
+				max = sz;
+			i->iFreeBytes += sz;
+			++i->iFreeN;
+			Walk(wi, CHUNK2MEM(q), sz, EGoodFreeCell, EDougLeaAllocator); // Introduce DL free buffer to the walk function 
+			}
+		else
+			{
+			i->iAllocBytes += sz - CHUNK_OVERHEAD;
+			++i->iAllocN;
+			Walk(wi, CHUNK2MEM(q), (sz- CHUNK_OVERHEAD), EGoodAllocatedCell, EDougLeaAllocator); // Introduce DL allocated buffer to the walk function 
+			}
+		}
+	return max;  // return largest available chunk size
+}
+
+//
+// get statistics about the state of the allocator
+//
+TInt RHybridHeap::GetInfo(struct HeapInfo* i, SWalkInfo* wi) const
+{
+	memset(i,0,sizeof(HeapInfo));
+	i->iFootprint = iChunkSize;
+	i->iMaxSize = iMaxLength;
+#ifndef __KERNEL_MODE__		
+	PagedInfo(i, wi);
+	SlabInfo(i, wi);
+#endif	
+	return DlInfo(i,wi);
+}
+
+//
+// Methods to commit/decommit memory pages from chunk
+//
+
+
+void* RHybridHeap::Map(void* p, TInt sz)
+//
+// allocate pages in the chunk
+// if p is NULL, Find an allocate the required number of pages (which must lie in the lower half)
+// otherwise commit the pages specified
+//
+{
+	HEAP_ASSERT(sz > 0);
+
+	if ( iChunkSize + sz > iMaxLength)
+		return 0;
+
+#ifdef __KERNEL_MODE__
+
+	TInt r = ((DChunk*)iChunkHandle)->Adjust(iChunkSize + iOffset + sz);
+	if (r < 0)
+		return 0;
+
+	iChunkSize += sz;
+	
+#else	
+
+	RChunk chunk;
+	chunk.SetHandle(iChunkHandle);
+	if ( p )
+		{
+		TInt r;
+		if ( iUseAdjust )
+			r = chunk.Adjust(iChunkSize + sz);
+		else
+			{
+			HEAP_ASSERT(sz == Ceiling(sz, iPageSize));
+			HEAP_ASSERT(p == Floor(p, iPageSize));
+			r = chunk.Commit(iOffset + PtrDiff(p, this),sz);
+			}			
+		if (r < 0)
+			return 0;
+		}
+	else
+		{
+		TInt r = chunk.Allocate(sz);
+		if (r < 0)
+			return 0;
+		if (r > iOffset)
+			{
+			// can't allow page allocations in DL zone
+			chunk.Decommit(r, sz);
+			return 0;
+			}
+		p = Offset(this, r - iOffset);
+		}
+	iChunkSize += sz;
+	
+	if (iChunkSize >= iSlabInitThreshold)
+		{	// set up slab system now that heap is large enough
+		SlabConfig(iSlabConfigBits);
+		iSlabInitThreshold = KMaxTInt32;
+		}
+
+#endif //	__KERNEL_MODE__
+	
+#ifdef ENABLE_BTRACE
+	if(iChunkSize > iHighWaterMark)
+		{
+		iHighWaterMark = Ceiling(iChunkSize,16*iPageSize);
+		TUint32 traceData[6];
+		traceData[0] = iChunkHandle;
+		traceData[1] = iMinLength;
+		traceData[2] = iMaxLength;
+		traceData[3] = sz;
+		traceData[4] = iChunkSize;
+		traceData[5] = iHighWaterMark;
+		BTraceContextN(BTrace::ETest1, 90, (TUint32)this, 33, traceData, sizeof(traceData));
+		}
+#endif
+
+	return p;
+}
+
+void RHybridHeap::Unmap(void* p, TInt sz)
+{
+	HEAP_ASSERT(sz > 0);
+	
+#ifdef __KERNEL_MODE__
+	
+	(void)p;
+	HEAP_ASSERT(sz == Ceiling(sz, iPageSize));
+#if defined(_DEBUG)		
+	TInt r =
+#endif				
+   ((DChunk*)iChunkHandle)->Adjust(iChunkSize + iOffset - sz);
+	HEAP_ASSERT(r >= 0);
+	
+#else
+
+	RChunk chunk;
+	chunk.SetHandle(iChunkHandle);
+	if ( iUseAdjust )
+		{
+		HEAP_ASSERT(sz == Ceiling(sz, iPageSize));
+#if defined(_DEBUG)		
+		TInt r =
+#endif				
+		chunk.Adjust(iChunkSize - sz);
+		HEAP_ASSERT(r >= 0);		
+		}
+	else
+		{
+		HEAP_ASSERT(sz == Ceiling(sz, iPageSize));
+		HEAP_ASSERT(p == Floor(p, iPageSize));
+#if defined(_DEBUG)		
+		TInt r =
+#endif
+		chunk.Decommit(PtrDiff(p, Offset(this,-iOffset)), sz);
+		HEAP_ASSERT(r >= 0);				
+		}			
+#endif  // __KERNEL_MODE__
+	
+	iChunkSize -= sz;
+}
+
+
+#ifndef __KERNEL_MODE__
+//
+// Slab allocator code
+//
+
+//inline slab* slab::SlabFor(void* p)
+slab* slab::SlabFor( const void* p)
+{
+	return (slab*)(Floor(p, SLABSIZE));
+}
+
+//
+// Remove slab s from its tree/heap (not necessarily the root), preserving the address order
+// invariant of the heap
+//
+void RHybridHeap::TreeRemove(slab* s)
+{
+	slab** r = s->iParent;
+	slab* c1 = s->iChild1;
+	slab* c2 = s->iChild2;
+	for (;;)
+		{
+		if (!c2)
+			{
+			*r = c1;
+			if (c1)
+				c1->iParent = r;
+			return;
+			}
+		if (!c1)
+			{
+			*r = c2;
+			c2->iParent = r;
+			return;
+			}
+		if (c1 > c2)
+			{
+			slab* c3 = c1;
+			c1 = c2;
+			c2 = c3;
+			}
+		slab* newc2 = c1->iChild2;
+		*r = c1;
+		c1->iParent = r;
+		c1->iChild2 = c2;
+		c2->iParent = &c1->iChild2;
+		s = c1;
+		c1 = s->iChild1;
+		c2 = newc2;
+		r = &s->iChild1;
+		}
+}
+//
+// Insert slab s into the tree/heap rooted at r, preserving the address ordering
+// invariant of the heap
+//
+void RHybridHeap::TreeInsert(slab* s,slab** r)
+{
+	slab* n = *r;
+	for (;;)
+		{
+		if (!n)
+			{	// tree empty
+			*r = s;
+			s->iParent = r;
+			s->iChild1 = s->iChild2 = 0;
+			break;
+			}
+		if (s < n)
+			{	// insert between iParent and n
+			*r = s;
+			s->iParent = r;
+			s->iChild1 = n;
+			s->iChild2 = 0;
+			n->iParent = &s->iChild1;
+			break;
+			}
+		slab* c1 = n->iChild1;
+		slab* c2 = n->iChild2;
+		if ((c1 - 1) > (c2 - 1))
+			{
+			r = &n->iChild1;
+			n = c1;
+			}
+		else
+			{
+			r = &n->iChild2;
+			n = c2;
+			}
+		}
+}
+
+void* RHybridHeap::AllocNewSlab(slabset& allocator)
+//
+// Acquire and initialise a new slab, returning a cell from the slab
+// The strategy is:
+// 1. Use the lowest address free slab, if available. This is done by using the lowest slab
+//    in the page at the root of the iPartialPage heap (which is address ordered). If the
+//    is now fully used, remove it from the iPartialPage heap.
+// 2. Allocate a new page for iSlabs if no empty iSlabs are available
+//
+{
+	page* p = page::PageFor(iPartialPage);
+	if (!p)
+		return AllocNewPage(allocator);
+	
+	unsigned h = p->iSlabs[0].iHeader;
+	unsigned pagemap = SlabHeaderPagemap(h);
+	HEAP_ASSERT(&p->iSlabs[HIBIT(pagemap)] == iPartialPage);
+	
+	unsigned slabix = LOWBIT(pagemap);
+	p->iSlabs[0].iHeader = h &~ (0x100<<slabix);
+	if (!(pagemap &~ (1<<slabix)))
+		{
+		TreeRemove(iPartialPage);	// last free slab in page
+		}
+	
+	return InitNewSlab(allocator, &p->iSlabs[slabix]);
+}
+
+/**Defination of this functionis not there in proto code***/
+#if 0
+void RHybridHeap::partial_insert(slab* s)
+{
+	// slab has had first cell freed and needs to be linked back into iPartial tree
+	slabset& ss = iSlabAlloc[iSizeMap[s->clz]];
+	
+	HEAP_ASSERT(s->used == slabfull);
+	s->used = ss.fulluse - s->clz;		// full-1 loading
+	TreeInsert(s,&ss.iPartial);
+	CHECKTREE(&ss.iPartial);
+}
+/**Defination of this functionis not there in proto code***/
+#endif
+
+void* RHybridHeap::AllocNewPage(slabset& allocator)
+//
+// Acquire and initialise a new page, returning a cell from a new slab
+// The iPartialPage tree is empty (otherwise we'd have used a slab from there)
+// The iPartialPage link is put in the highest addressed slab in the page, and the
+// lowest addressed slab is used to fulfill the allocation request
+//
+{
+	page* p	 = iSparePage;
+	if (p)
+		iSparePage = 0;
+	else
+		{
+		p = static_cast<page*>(Map(0, iPageSize));
+		if (!p)
+			return 0;
+		}
+	HEAP_ASSERT(p == Floor(p, iPageSize));
+	// Store page allocated for slab into paged_bitmap (for RHybridHeap::Reset())
+	if (!PagedSetSize(p, iPageSize))
+		{
+		Unmap(p, iPageSize);
+		return 0;
+		}
+	p->iSlabs[0].iHeader = ((1<<3) + (1<<2) + (1<<1))<<8;		// set pagemap
+	p->iSlabs[3].iParent = &iPartialPage;
+	p->iSlabs[3].iChild1 = p->iSlabs[3].iChild2 = 0;
+	iPartialPage = &p->iSlabs[3];
+	return InitNewSlab(allocator,&p->iSlabs[0]);
+}
+
+void RHybridHeap::FreePage(page* p)
+//
+// Release an unused page to the OS
+// A single page is cached for reuse to reduce thrashing
+// the OS allocator.
+//
+{
+	HEAP_ASSERT(Ceiling(p, iPageSize) == p);
+	if (!iSparePage)
+		{
+		iSparePage = p;
+		return;
+		}
+	
+	// unmapped slab page must be cleared from paged_bitmap, too
+	PagedZapSize(p, iPageSize);		// clear page map
+	
+	Unmap(p, iPageSize);
+}
+
+void RHybridHeap::FreeSlab(slab* s)
+//
+// Release an empty slab to the slab manager
+// The strategy is:
+// 1. The page containing the slab is checked to see the state of the other iSlabs in the page by
+//    inspecting the pagemap field in the iHeader of the first slab in the page.
+// 2. The pagemap is updated to indicate the new unused slab
+// 3. If this is the only unused slab in the page then the slab iHeader is used to add the page to
+//    the iPartialPage tree/heap
+// 4. If all the iSlabs in the page are now unused the page is release back to the OS
+// 5. If this slab has a higher address than the one currently used to track this page in
+//    the iPartialPage heap, the linkage is moved to the new unused slab
+//
+{
+	TreeRemove(s);
+	CHECKTREE(s->iParent);
+	HEAP_ASSERT(SlabHeaderUsedm4(s->iHeader) == SlabHeaderSize(s->iHeader)-4);
+
+	page* p = page::PageFor(s);
+	unsigned h = p->iSlabs[0].iHeader;
+	int slabix = s - &p->iSlabs[0];
+	unsigned pagemap = SlabHeaderPagemap(h);
+	p->iSlabs[0].iHeader = h | (0x100<<slabix);
+	if (pagemap == 0)
+		{	// page was full before, use this slab as link in empty heap
+		TreeInsert(s, &iPartialPage);
+		}
+	else
+		{	// Find the current empty-link slab
+		slab* sl = &p->iSlabs[HIBIT(pagemap)];
+		pagemap ^= (1<<slabix);
+		if (pagemap == 0xf)
+			{	// page is now empty so recycle page to os
+			TreeRemove(sl);
+			FreePage(p);
+			return;
+			}
+		// ensure the free list link is in highest address slab in page
+		if (s > sl)
+			{	// replace current link with new one. Address-order tree so position stays the same
+			slab** r = sl->iParent;
+			slab* c1 = sl->iChild1;
+			slab* c2 = sl->iChild2;
+			s->iParent = r;
+			s->iChild1 = c1;
+			s->iChild2 = c2;
+			*r = s;
+			if (c1)
+				c1->iParent = &s->iChild1;
+			if (c2)
+				c2->iParent = &s->iChild2;
+			}
+		CHECK(if (s < sl) s=sl);
+		}
+	HEAP_ASSERT(SlabHeaderPagemap(p->iSlabs[0].iHeader) != 0);
+	HEAP_ASSERT(HIBIT(SlabHeaderPagemap(p->iSlabs[0].iHeader)) == unsigned(s - &p->iSlabs[0]));
+}
+
+
+void RHybridHeap::SlabInit()
+{
+	iSlabThreshold=0;
+	iPartialPage = 0;
+	iFullSlab = 0;
+	iSparePage = 0;
+	memset(&iSizeMap[0],0xff,sizeof(iSizeMap));
+	memset(&iSlabAlloc[0],0,sizeof(iSlabAlloc));
+}
+
+void RHybridHeap::SlabConfig(unsigned slabbitmap)
+{
+	HEAP_ASSERT((slabbitmap & ~EOkBits) == 0);
+	HEAP_ASSERT(MAXSLABSIZE <= 60);
+	
+	unsigned int ix = 0xff;
+	unsigned int bit = 1<<((MAXSLABSIZE>>2)-1);
+	for (int sz = MAXSLABSIZE; sz >= 0; sz -= 4, bit >>= 1)
+		{
+		if (slabbitmap & bit)
+			{
+			if (ix == 0xff)
+				iSlabThreshold=sz+1;
+			ix = (sz>>2)-1;
+			}
+		iSizeMap[sz>>2] = (TUint8) ix;
+		}
+}
+
+
+void* RHybridHeap::SlabAllocate(slabset& ss)
+//
+// Allocate a cell from the given slabset
+// Strategy:
+// 1. Take the partially full slab at the iTop of the heap (lowest address).
+// 2. If there is no such slab, allocate from a new slab
+// 3. If the slab has a non-empty freelist, pop the cell from the front of the list and update the slab
+// 4. Otherwise, if the slab is not full, return the cell at the end of the currently used region of
+//    the slab, updating the slab
+// 5. Otherwise, release the slab from the iPartial tree/heap, marking it as 'floating' and go back to
+//    step 1
+//
+{
+	for (;;)
+		{
+		slab *s = ss.iPartial;
+		if (!s)
+			break;
+		unsigned h = s->iHeader;
+		unsigned free = h & 0xff;		// extract free cell positioning
+		if (free)
+			{
+			HEAP_ASSERT(((free<<2)-sizeof(slabhdr))%SlabHeaderSize(h) == 0);
+			void* p = Offset(s,free<<2);
+			free = *(unsigned char*)p;	// get next pos in free list
+			h += (h&0x3C000)<<6;		// update usedm4
+			h &= ~0xff;
+			h |= free;					// update freelist
+			s->iHeader = h;
+			HEAP_ASSERT(SlabHeaderFree(h) == 0 || ((SlabHeaderFree(h)<<2)-sizeof(slabhdr))%SlabHeaderSize(h) == 0);
+			HEAP_ASSERT(SlabHeaderUsedm4(h) <= 0x3F8u);
+			HEAP_ASSERT((SlabHeaderUsedm4(h)+4)%SlabHeaderSize(h) == 0);
+			return p;
+			}
+		unsigned h2 = h + ((h&0x3C000)<<6);
+//		if (h2 < 0xfc00000)
+  		if (h2 < MAXUSEDM4BITS)		
+			{
+			HEAP_ASSERT((SlabHeaderUsedm4(h2)+4)%SlabHeaderSize(h2) == 0);
+			s->iHeader = h2;
+			return Offset(s,(h>>18) + sizeof(unsigned) + sizeof(slabhdr));
+			}
+		h |= FLOATING_BIT;				// mark the slab as full-floating
+		s->iHeader = h;
+		TreeRemove(s);
+		slab* c = iFullSlab;			// add to full list
+		iFullSlab = s;
+		s->iParent = &iFullSlab;
+		s->iChild1 = c;
+		s->iChild2 = 0;
+		if (c)
+			c->iParent = &s->iChild1;
+		
+		CHECKTREE(&ss.iPartial);
+		// go back and try the next slab...
+		}
+	// no iPartial iSlabs found, so allocate from a new slab
+	return AllocNewSlab(ss);
+}
+
+void RHybridHeap::SlabFree(void* p)
+//
+// Free a cell from the slab allocator
+// Strategy:
+// 1. Find the containing slab (round down to nearest 1KB boundary)
+// 2. Push the cell into the slab's freelist, and update the slab usage count
+// 3. If this is the last allocated cell, free the slab to the main slab manager
+// 4. If the slab was full-floating then insert the slab in it's respective iPartial tree
+//
+{
+	HEAP_ASSERT(LowBits(p,3)==0);
+	slab* s = slab::SlabFor(p);
+	CHECKSLAB(s,ESlabAllocator,p);
+	CHECKSLABBFR(s,p);	
+
+	unsigned pos = LowBits(p, SLABSIZE);
+	unsigned h = s->iHeader;
+	HEAP_ASSERT(SlabHeaderUsedm4(h) != 0x3fC);		// slab is empty already
+	HEAP_ASSERT((pos-sizeof(slabhdr))%SlabHeaderSize(h) == 0);
+	*(unsigned char*)p = (unsigned char)h;
+	h &= ~0xFF;
+	h |= (pos>>2);
+	unsigned size = h & 0x3C000;
+	if (int(h) >= 0)
+		{
+		h -= size<<6;
+		if (int(h)>=0)
+			{
+			s->iHeader = h;
+			return;
+			}
+		FreeSlab(s);
+		return;
+		}
+	h -= size<<6;
+    h &= ~FLOATING_BIT;	
+	s->iHeader = h;
+	slab** full = s->iParent;		// remove from full list
+	slab* c = s->iChild1;
+	*full = c;
+	if (c)
+		c->iParent = full;
+	
+	slabset& ss = iSlabAlloc[iSizeMap[size>>14]];
+	TreeInsert(s,&ss.iPartial);
+	CHECKTREE(&ss.iPartial);
+}
+
+void* RHybridHeap::InitNewSlab(slabset& allocator, slab* s)
+//
+// initialise an empty slab for this allocator and return the fist cell
+// pre-condition: the slabset has no iPartial iSlabs for allocation
+//
+{
+	HEAP_ASSERT(allocator.iPartial==0);
+	TInt size = 4 + ((&allocator-&iSlabAlloc[0])<<2);	// infer size from slab allocator address
+	unsigned h = s->iHeader & 0xF00;	// preserve pagemap only
+	h |= (size<<12);					// set size
+	h |= (size-4)<<18;					// set usedminus4 to one object minus 4
+	s->iHeader = h;
+	allocator.iPartial = s;
+	s->iParent = &allocator.iPartial;
+	s->iChild1 = s->iChild2 = 0;
+	return Offset(s,sizeof(slabhdr));
+}
+
+const unsigned char slab_bitcount[16] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
+
+const unsigned char slab_ext_frag[16] =
+{
+	0,
+	16 + (1008 % 4),
+	16 + (1008 % 8),
+	16 + (1008 % 12),
+	16 + (1008 % 16),
+	16 + (1008 % 20),
+	16 + (1008 % 24),
+	16 + (1008 % 28),
+	16 + (1008 % 32),
+	16 + (1008 % 36),
+	16 + (1008 % 40),
+	16 + (1008 % 44),
+	16 + (1008 % 48),
+	16 + (1008 % 52),
+	16 + (1008 % 56),
+	16 + (1008 % 60)
+};
+
+void RHybridHeap::TreeWalk(slab* const* root, void (*f)(slab*, struct HeapInfo*, SWalkInfo*), struct HeapInfo* i, SWalkInfo* wi)
+{
+	// iterative walk around the tree at root
+	
+	slab* s = *root;
+	if (!s)
+		return;
+	
+	for (;;)
+		{
+		slab* c;
+		while ((c = s->iChild1) != 0)
+			s = c;		// walk down left side to end
+		for (;;)
+			{
+			f(s, i, wi);
+			c = s->iChild2;
+			if (c)
+				{	// one step down right side, now try and walk down left
+				s = c;
+				break;
+				}
+			for (;;)
+				{	// loop to walk up right side
+				slab** pp = s->iParent;
+				if (pp == root)
+					return;
+				s = slab::SlabFor(pp);
+				if (pp == &s->iChild1)
+					break;
+				}
+			}
+		}
+}
+
+void RHybridHeap::SlabEmptyInfo(slab* s, struct HeapInfo* i, SWalkInfo* wi)
+{
+	Walk(wi, s, SLABSIZE, EGoodFreeCell, EEmptySlab); // Introduce an empty slab to the walk function 
+	int nslab = slab_bitcount[SlabHeaderPagemap(page::PageFor(s)->iSlabs[0].iHeader)];
+	i->iFreeN += nslab;
+	i->iFreeBytes += nslab << SLABSHIFT;
+}
+
+void RHybridHeap::SlabPartialInfo(slab* s, struct HeapInfo* i, SWalkInfo* wi)
+{
+	Walk(wi, s, SLABSIZE, EGoodAllocatedCell, EPartialFullSlab); // Introduce a full slab to the walk function 
+	unsigned h = s->iHeader;
+	unsigned used = SlabHeaderUsedm4(h)+4;
+	unsigned size = SlabHeaderSize(h);
+	unsigned free = 1024 - slab_ext_frag[size>>2] - used;
+	i->iFreeN += (free/size);
+	i->iFreeBytes += free;
+	i->iAllocN += (used/size);
+	i->iAllocBytes += used;
+}
+
+void RHybridHeap::SlabFullInfo(slab* s, struct HeapInfo* i, SWalkInfo* wi)
+{
+	Walk(wi, s, SLABSIZE, EGoodAllocatedCell, EFullSlab); // Introduce a full slab to the walk function 
+	unsigned h = s->iHeader;
+	unsigned used = SlabHeaderUsedm4(h)+4;
+	unsigned size = SlabHeaderSize(h);
+	HEAP_ASSERT(1024 - slab_ext_frag[size>>2] - used == 0);
+	i->iAllocN += (used/size);
+	i->iAllocBytes += used;
+}
+
+void RHybridHeap::SlabInfo(struct HeapInfo* i, SWalkInfo* wi) const
+{
+	if (iSparePage)
+		{
+		i->iFreeBytes += iPageSize;
+		i->iFreeN = 4;
+		Walk(wi, iSparePage, iPageSize, EGoodFreeCell, ESlabSpare); // Introduce Slab spare page to the walk function 
+		}
+	TreeWalk(&iFullSlab, &SlabFullInfo, i, wi);
+	for (int ix = 0; ix < (MAXSLABSIZE>>2); ++ix)
+		TreeWalk(&iSlabAlloc[ix].iPartial, &SlabPartialInfo, i, wi);
+	TreeWalk(&iPartialPage, &SlabEmptyInfo, i, wi);
+}
+
+
+//
+// Bitmap class implementation for large page allocator 
+//
+inline unsigned char* paged_bitmap::Addr() const {return iBase;}
+inline unsigned paged_bitmap::Size() const {return iNbits;}
+//
+
+void paged_bitmap::Init(unsigned char* p, unsigned size, unsigned bit)
+{
+	iBase = p;
+	iNbits=size;
+	int bytes=Ceiling(size,8)>>3;
+	memset(p,bit?0xff:0,bytes);
+}
+
+inline void paged_bitmap::Set(unsigned ix, unsigned bit)
+{
+	if (bit)
+		iBase[ix>>3] |= (1<<(ix&7));
+	else
+		iBase[ix>>3] &= ~(1<<(ix&7));
+}
+
+inline unsigned paged_bitmap::operator[](unsigned ix) const
+{
+	return 1U&(iBase[ix>>3] >> (ix&7));
+}
+
+void paged_bitmap::Setn(unsigned ix, unsigned len, unsigned bit)
+{
+	int l=len;
+	while (--l>=0)
+		Set(ix++,bit);
+}
+
+void paged_bitmap::Set(unsigned ix, unsigned len, unsigned val)
+{
+	int l=len;
+	while (--l>=0)
+		{
+		Set(ix++,val&1);
+		val>>=1;
+		}
+}
+
+unsigned paged_bitmap::Bits(unsigned ix, unsigned len) const
+{
+	int l=len;
+	unsigned val=0;
+	unsigned bit=0;
+	while (--l>=0)
+		val |= (*this)[ix++]<<bit++;
+	return val;
+}
+
+bool paged_bitmap::Is(unsigned ix, unsigned len, unsigned bit) const
+{
+	unsigned i2 = ix+len;
+	if (i2 > iNbits)
+		return false;
+	for (;;)
+		{
+		if ((*this)[ix] != bit)
+			return false;
+		if (++ix==i2)
+			return true;
+		}
+}
+
+int paged_bitmap::Find(unsigned start, unsigned bit) const
+{
+	if (start<iNbits) do
+		{
+		if ((*this)[start]==bit)
+			return start;
+		} while (++start<iNbits);
+	return -1;
+}
+
+
+//
+// Page allocator code
+//
+void RHybridHeap::PagedInit(TInt aPagePower)
+{
+	if (aPagePower > 0)
+		{
+		if (aPagePower < MINPAGEPOWER)
+			aPagePower = MINPAGEPOWER;
+		}
+	else aPagePower = 31;
+
+	iPageThreshold = aPagePower;
+	/*-------------------------------------------------------------
+	 * Initialize page bitmap
+	 *-------------------------------------------------------------*/
+	iPageMap.Init((unsigned char*)&iBitMapBuffer, MAXSMALLPAGEBITS, 0);
+}
+
+void* RHybridHeap::PagedAllocate(unsigned size)
+{
+	TInt nbytes = Ceiling(size, iPageSize);
+	void* p = Map(0, nbytes);
+	if (!p)
+		return 0;
+	if (!PagedSetSize(p, nbytes))
+		{
+		Unmap(p, nbytes);
+		return 0;
+		}
+	return p;
+}
+
+void* RHybridHeap::PagedReallocate(void* p, unsigned size, TInt mode)
+{
+	
+	HEAP_ASSERT(Ceiling(p, iPageSize) == p);
+	unsigned nbytes = Ceiling(size, iPageSize);
+	
+	unsigned osize = PagedSize(p);
+	if ( nbytes == 0 )  // Special case to handle shrinking below min page threshold 
+		nbytes = Min((1 << MINPAGEPOWER), osize);
+	
+	if (osize == nbytes)
+		return p;
+	
+	if (nbytes < osize)
+		{	// shrink in place, unmap final pages and rewrite the pagemap
+		Unmap(Offset(p, nbytes), osize-nbytes);
+		// zap old code and then write new code (will not fail)
+		PagedZapSize(p, osize);
+
+		TBool check = PagedSetSize(p, nbytes);
+        __ASSERT_ALWAYS(check, HEAP_PANIC(ETHeapBadCellAddress));
+		
+		return p;
+		}
+	
+	// nbytes > osize
+	// try and extend current region first
+			
+	void* newp = Map(Offset(p, osize), nbytes-osize);
+	if (newp)
+		{	// In place growth. Possibility that pagemap may have to grow AND then fails
+		if (!PagedSetSize(p, nbytes))
+			{	// must release extra mapping
+			Unmap(Offset(p, osize), nbytes-osize);
+			return 0;
+			}
+		// if successful, the new length code will have overwritten the old one (it is at least as long)
+		return p;
+		}
+	
+	// fallback to  allocate/copy/free
+	if (mode & ENeverMove)
+		return 0;		// not allowed to move cell
+	
+	newp = PagedAllocate(nbytes);
+	if (!newp)
+		return 0;
+	memcpy(newp, p, osize);
+	PagedFree(p);
+	return newp;
+}
+
+void RHybridHeap::PagedFree(void* p)
+{
+	HEAP_ASSERT(Ceiling(p, iPageSize) == p);
+
+	
+	unsigned size = PagedSize(p);
+	
+	PagedZapSize(p, size);		// clear page map
+	Unmap(p, size);
+}
+
+void RHybridHeap::PagedInfo(struct HeapInfo* i, SWalkInfo* wi) const
+{
+	for (int ix = 0;(ix = iPageMap.Find(ix,1)) >= 0;)
+		{
+		int npage = PagedDecode(ix);
+		// Introduce paged buffer to the walk function 
+		TAny* bfr = Bitmap2addr(ix);
+		int len = npage << PAGESHIFT;
+		if ( len > iPageSize )
+			{ // If buffer is not larger than one page it must be a slab page mapped into bitmap
+			i->iAllocBytes += len;
+			++i->iAllocN;
+			Walk(wi, bfr, len, EGoodAllocatedCell, EPageAllocator);
+			}
+		ix += (npage<<1);
+		}
+}
+
+void RHybridHeap::ResetBitmap()
+/*---------------------------------------------------------
+ * Go through paged_bitmap and unmap all buffers to system
+ * This method is called from RHybridHeap::Reset() to unmap all page
+ * allocated - and slab pages which are stored in bitmap, too
+ *---------------------------------------------------------*/ 
+{
+	unsigned iNbits = iPageMap.Size();
+	if ( iNbits )
+		{
+		for (int ix = 0;(ix = iPageMap.Find(ix,1)) >= 0;)
+			{
+			int npage = PagedDecode(ix);
+			void* p = Bitmap2addr(ix);
+			unsigned size = PagedSize(p);
+			PagedZapSize(p, size);		// clear page map
+			Unmap(p, size);
+			ix += (npage<<1);
+			}
+		if ( (TInt)iNbits > MAXSMALLPAGEBITS )
+			{
+			// unmap page reserved for enlarged bitmap
+			Unmap(iPageMap.Addr(), (iNbits >> 3) );
+			}
+		}
+}
+
+TBool RHybridHeap::CheckBitmap(void* aBfr, TInt aSize, TUint32& aDummy, TInt& aNPages)
+/*---------------------------------------------------------
+ * If aBfr = NULL
+ *   Go through paged_bitmap and unmap all buffers to system
+ *   and assure that by reading the first word of each page of aBfr
+ *   that aBfr is still accessible
+ * else  
+ *   Assure that specified buffer is mapped with correct length in
+ *   page map
+ *---------------------------------------------------------*/ 
+{
+	TBool ret;
+	if ( aBfr )
+		{
+		__ASSERT_ALWAYS((Ceiling(aBfr, iPageSize) == aBfr), HEAP_PANIC(ETHeapBadCellAddress));		
+        ret = ( aSize == (TInt)PagedSize(aBfr));
+		}
+	else
+		{
+		ret = ETrue;
+		unsigned iNbits = iPageMap.Size();
+		if ( iNbits )
+			{
+			TInt npage;
+			aNPages = 0;
+			for (int ix = 0;(ix = iPageMap.Find(ix,1)) >= 0;)
+				{
+				npage = PagedDecode(ix);
+				aNPages += npage;
+				void* p = Bitmap2addr(ix);
+				__ASSERT_ALWAYS((Ceiling(p, iPageSize) == p), HEAP_PANIC(ETHeapBadCellAddress));						
+				unsigned s = PagedSize(p);
+				__ASSERT_ALWAYS((Ceiling(s, iPageSize) == s), HEAP_PANIC(ETHeapBadCellAddress));	
+				while ( s )
+					{
+					aDummy += *(TUint32*)((TUint8*)p + (s-iPageSize));
+					s -= iPageSize;
+					}
+				ix += (npage<<1);
+				}
+			if ( (TInt)iNbits > MAXSMALLPAGEBITS )
+				{
+				// add enlarged bitmap page(s) to total page count
+                npage = (iNbits >> 3); 
+				__ASSERT_ALWAYS((Ceiling(npage, iPageSize) == npage), HEAP_PANIC(ETHeapBadCellAddress));
+				aNPages += (npage / iPageSize);
+				}
+			}
+		}
+	
+	return ret;
+}
+
+
+// The paged allocations are tracked in a bitmap which has 2 bits per page
+// this allows us to store allocations as small as 4KB
+// The presence and size of an allocation is encoded as follows:
+// let N = number of pages in the allocation, then
+// 10            : N = 1			// 4KB
+// 110n			 : N = 2 + n		// 8-12KB
+// 1110nnnn      : N = nnnn			// 16-60KB
+// 1111n[18]	 : N = n[18]		// 64KB-1GB
+
+const struct etab { unsigned char offset, len, codelen, code;} encode_table[] =
+{
+	{1,2,2,0x1},
+	{2,4,3,0x3},
+	{0,8,4,0x7},
+	{0,22,4,0xf}
+};
+
+// Return code length for specified allocation Size(assumed to be aligned to pages)
+inline unsigned paged_codelen(unsigned size, unsigned pagesz)
+{
+	HEAP_ASSERT(size == Ceiling(size, pagesz));
+	
+	if (size == pagesz)
+		return 2;
+	else if (size < 4*pagesz)
+		return 4;
+	else if (size < 16*pagesz)
+		return 8;
+	else
+		return 22;
+}
+
+inline const etab& paged_coding(unsigned npage)
+{
+	if (npage < 4)
+		return encode_table[npage>>1];
+	else if (npage < 16)
+		return encode_table[2];
+	else
+		return encode_table[3];
+}
+
+bool RHybridHeap::PagedEncode(unsigned pos, unsigned npage)
+{
+	const etab& e = paged_coding(npage);
+	if (pos + e.len > iPageMap.Size())
+		{
+		// need to grow the page bitmap to fit the cell length into the map
+		// if we outgrow original bitmap buffer in RHybridHeap metadata, then just get enough pages to cover the full space:
+		// * initial 68 byte bitmap mapped (68*8*4kB):2 = 1,1MB
+		// * 4KB can Map(4096*8*4kB):2 = 64MB
+		unsigned maxsize = Ceiling(iMaxLength, iPageSize);
+		unsigned mapbits = maxsize >> (PAGESHIFT-1);
+		maxsize = Ceiling(mapbits>>3, iPageSize);
+		void* newb = Map(0, maxsize);
+		if (!newb)
+			return false;
+		
+		unsigned char* oldb = iPageMap.Addr();
+		iPageMap.Init((unsigned char*)newb, (maxsize<<3), 0);
+		memcpy(newb, oldb, Ceiling(MAXSMALLPAGEBITS,8)>>3);
+		}
+	// encode the allocation block size into the bitmap, starting at the bit for the start page
+	unsigned bits = e.code;
+	bits |= (npage - e.offset) << e.codelen;
+	iPageMap.Set(pos, e.len, bits);
+	return true;
+}
+
+unsigned RHybridHeap::PagedDecode(unsigned pos) const
+{
+	__ASSERT_ALWAYS(pos + 2 <= iPageMap.Size(), HEAP_PANIC(ETHeapBadCellAddress));
+	
+	unsigned bits = iPageMap.Bits(pos,2);
+	__ASSERT_ALWAYS(bits & 1, HEAP_PANIC(ETHeapBadCellAddress));
+	bits >>= 1;
+	if (bits == 0)
+		return 1;
+	__ASSERT_ALWAYS(pos + 4 <= iPageMap.Size(), HEAP_PANIC(ETHeapBadCellAddress));
+	bits = iPageMap.Bits(pos+2,2);
+	if ((bits & 1) == 0)
+		return 2 + (bits>>1);
+	else if ((bits>>1) == 0)
+		{
+		__ASSERT_ALWAYS(pos + 8 <= iPageMap.Size(), HEAP_PANIC(ETHeapBadCellAddress));
+		return iPageMap.Bits(pos+4, 4);
+		}
+	else
+		{
+		__ASSERT_ALWAYS(pos + 22 <= iPageMap.Size(), HEAP_PANIC(ETHeapBadCellAddress));
+		return iPageMap.Bits(pos+4, 18);
+		}
+}
+
+inline void RHybridHeap::PagedZapSize(void* p, unsigned size)
+{iPageMap.Setn(PtrDiff(p, iMemBase) >> (PAGESHIFT-1), paged_codelen(size, iPageSize) ,0);}
+
+inline unsigned RHybridHeap::PagedSize(void* p) const
+   { return PagedDecode(PtrDiff(p, iMemBase) >> (PAGESHIFT-1)) << PAGESHIFT; }
+
+inline bool RHybridHeap::PagedSetSize(void* p, unsigned size)
+{ return PagedEncode(PtrDiff(p, iMemBase) >> (PAGESHIFT-1), size >> PAGESHIFT); }
+
+inline void* RHybridHeap::Bitmap2addr(unsigned pos) const
+   { return iMemBase + (1 << (PAGESHIFT-1))*pos; }
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+/**
+Constructor where minimum and maximum length of the heap can be defined.
+It defaults the chunk heap to be created to have use a new local chunk, 
+to have a grow by value of KMinHeapGrowBy, to be unaligned, not to be 
+single threaded and not to have any mode flags set.
+
+@param aMinLength    The minimum length of the heap to be created.
+@param aMaxLength    The maximum length to which the heap to be created can grow.
+                     If the supplied value is less than a page size, then it
+                     is discarded and the page size is used instead.
+*/
+EXPORT_C TChunkHeapCreateInfo::TChunkHeapCreateInfo(TInt aMinLength, TInt aMaxLength) :
+   iVersionNumber(EVersion0), iMinLength(aMinLength), iMaxLength(aMaxLength),
+iAlign(0), iGrowBy(1), iSingleThread(EFalse), 
+iOffset(0), iPaging(EUnspecified), iMode(0), iName(NULL)
+{
+}
+
+
+/**
+Sets the chunk heap to create a new chunk with the specified name.
+
+This overriddes any previous call to TChunkHeapCreateInfo::SetNewChunkHeap() or
+TChunkHeapCreateInfo::SetExistingChunkHeap() for this TChunkHeapCreateInfo object.
+
+@param aName	The name to be given to the chunk heap to be created
+If NULL, the function constructs a local chunk to host the heap.
+If not NULL, a pointer to a descriptor containing the name to be 
+assigned to the global chunk hosting the heap.
+*/
+EXPORT_C void TChunkHeapCreateInfo::SetCreateChunk(const TDesC* aName)
+{
+	iName = (TDesC*)aName;
+	iChunk.SetHandle(KNullHandle);
+}
+
+
+/**
+Sets the chunk heap to be created to use the chunk specified.
+
+This overriddes any previous call to TChunkHeapCreateInfo::SetNewChunkHeap() or
+TChunkHeapCreateInfo::SetExistingChunkHeap() for this TChunkHeapCreateInfo object.
+
+@param aChunk	A handle to the chunk to use for the heap.
+*/
+EXPORT_C void TChunkHeapCreateInfo::SetUseChunk(const RChunk aChunk)
+{
+	iName = NULL;
+	iChunk = aChunk;
+}
+
+EXPORT_C RHeap* UserHeap::FixedHeap(TAny* aBase, TInt aMaxLength, TInt aAlign, TBool aSingleThread)
+/**
+Creates a fixed length heap at a specified location.
+
+On successful return from this function, the heap is ready to use.  This assumes that
+the memory pointed to by aBase is mapped and able to be used.  You must ensure that you
+pass in a large enough value for aMaxLength.  Passing in a value that is too small to
+hold the metadata for the heap (~1 KB) will result in the size being rounded up and the
+heap thereby running over the end of the memory assigned to it.  But then if you were to
+pass in such as small value then you would not be able to do any allocations from the
+heap anyway.  Moral of the story: Use a sensible value for aMaxLength!
+
+@param aBase         A pointer to the location where the heap is to be constructed.
+@param aMaxLength    The maximum length in bytes to which the heap can grow.  If the
+                     supplied value is too small to hold the heap's metadata, it
+                     will be increased.
+@param aAlign        From Symbian^4 onwards, this value is ignored but EABI 8
+                     byte alignment is guaranteed for all allocations 8 bytes or
+                     more in size.  4 byte allocations will be aligned to a 4
+                     byte boundary.  Best to pass in zero.
+@param aSingleThread ETrue if the heap is to be accessed from multiple threads.
+                     This will cause internal locks to be created, guaranteeing
+                     thread safety.
+
+@return A pointer to the new heap, or NULL if the heap could not be created.
+
+@panic USER 56 if aMaxLength is negative.
+*/
+{
+	__ASSERT_ALWAYS( aMaxLength>=0, ::Panic(ETHeapMaxLengthNegative));
+	if ( aMaxLength < (TInt)sizeof(RHybridHeap) )
+		aMaxLength = sizeof(RHybridHeap);
+	
+	RHybridHeap* h = new(aBase) RHybridHeap(aMaxLength, aAlign, aSingleThread);
+	
+	if (!aSingleThread)
+		{
+		TInt r = h->iLock.CreateLocal();
+		if (r!=KErrNone)
+			return NULL; // No need to delete the RHybridHeap instance as the new above is only a placement new
+		h->iHandles = (TInt*)&h->iLock;
+		h->iHandleCount = 1;
+		}
+	return h;
+}
+
+/**
+Creates a chunk heap of the type specified by the parameter aCreateInfo.
+
+@param aCreateInfo	A reference to a TChunkHeapCreateInfo object specifying the
+type of chunk heap to create.
+
+@return A pointer to the new heap or NULL if the heap could not be created.
+
+@panic USER 41 if the heap's specified minimum length is greater than the specified maximum length.
+@panic USER 55 if the heap's specified minimum length is negative.
+@panic USER 172 if the heap's specified alignment is not a power of 2 or is less than the size of a TAny*.
+*/
+EXPORT_C RHeap* UserHeap::ChunkHeap(const TChunkHeapCreateInfo& aCreateInfo)
+{
+	// aCreateInfo must have been configured to use a new chunk or an exiting chunk.
+	__ASSERT_ALWAYS(!(aCreateInfo.iMode & (TUint32)~EChunkHeapMask), ::Panic(EHeapCreateInvalidMode));
+	RHeap* h = NULL;
+	
+	if (aCreateInfo.iChunk.Handle() == KNullHandle)
+		{
+		// A new chunk is to be created for this heap.
+		
+		__ASSERT_ALWAYS(aCreateInfo.iMinLength >= 0, ::Panic(ETHeapMinLengthNegative));
+		__ASSERT_ALWAYS(aCreateInfo.iMaxLength >= aCreateInfo.iMinLength, ::Panic(ETHeapCreateMaxLessThanMin));
+
+		TInt maxLength = aCreateInfo.iMaxLength;
+		TInt page_size;
+		GET_PAGE_SIZE(page_size);
+
+		if (maxLength < page_size)
+			maxLength = page_size;
+		
+		TChunkCreateInfo chunkInfo;
+#if USE_HYBRID_HEAP
+		if ( aCreateInfo.iOffset )
+			chunkInfo.SetNormal(0, maxLength);  // Create DL only heap
+		else
+			{
+			maxLength = 2*maxLength;
+			chunkInfo.SetDisconnected(0, 0, maxLength); // Create hybrid heap
+			}
+#else
+		chunkInfo.SetNormal(0, maxLength);  // Create DL only heap		
+#endif			
+		chunkInfo.SetOwner((aCreateInfo.iSingleThread)? EOwnerThread : EOwnerProcess);
+		if (aCreateInfo.iName)
+			chunkInfo.SetGlobal(*aCreateInfo.iName);
+		// Set the paging attributes of the chunk.
+		if (aCreateInfo.iPaging == TChunkHeapCreateInfo::EPaged)
+			chunkInfo.SetPaging(TChunkCreateInfo::EPaged);
+		if (aCreateInfo.iPaging == TChunkHeapCreateInfo::EUnpaged)
+			chunkInfo.SetPaging(TChunkCreateInfo::EUnpaged);
+		// Create the chunk.
+		RChunk chunk;
+		if (chunk.Create(chunkInfo) != KErrNone)
+			return NULL;
+		// Create the heap using the new chunk.
+		TUint mode = aCreateInfo.iMode | EChunkHeapDuplicate;	// Must duplicate the handle.
+		h = OffsetChunkHeap(chunk, aCreateInfo.iMinLength, aCreateInfo.iOffset,
+							aCreateInfo.iGrowBy, maxLength, aCreateInfo.iAlign,
+							aCreateInfo.iSingleThread, mode);
+		chunk.Close();
+		}
+	else
+		{
+		h = OffsetChunkHeap(aCreateInfo.iChunk, aCreateInfo.iMinLength, aCreateInfo.iOffset,
+							aCreateInfo.iGrowBy, aCreateInfo.iMaxLength, aCreateInfo.iAlign,
+							aCreateInfo.iSingleThread, aCreateInfo.iMode);
+		}
+	return h;
+}
+
+
+
+EXPORT_C RHeap* UserHeap::ChunkHeap(const TDesC* aName, TInt aMinLength, TInt aMaxLength, TInt aGrowBy, TInt aAlign, TBool aSingleThread)
+/**
+Creates a heap in a local or global chunk.
+
+The chunk hosting the heap can be local or global.
+
+A local chunk is one which is private to the process creating it and is not
+intended for access by other user processes.  A global chunk is one which is
+visible to all processes.
+
+The hosting chunk is local, if the pointer aName is NULL, otherwise the
+hosting chunk is global and the descriptor *aName is assumed to contain
+the name to be assigned to it.
+
+Ownership of the host chunk is vested in the current process.
+
+A minimum and a maximum size for the heap can be specified. On successful
+return from this function, the size of the heap is at least aMinLength.
+If subsequent requests for allocation of memory from the heap cannot be
+satisfied by compressing the heap, the size of the heap is extended in
+increments of aGrowBy until the request can be satisfied.  Attempts to extend
+the heap causes the size of the host chunk to be adjusted.
+
+Note that the size of the heap cannot be adjusted by more than aMaxLength.
+
+@param aName         If NULL, the function constructs a local chunk to host
+                     the heap.  If not NULL, a pointer to a descriptor containing
+                     the name to be assigned to the global chunk hosting the heap.
+@param aMinLength    The minimum length of the heap in bytes.  This will be
+                     rounded up to the nearest page size by the allocator.
+@param aMaxLength    The maximum length in bytes to which the heap can grow.  This
+                     will be rounded up to the nearest page size by the allocator.
+@param aGrowBy       The number of bytes by which the heap will grow when more
+                     memory is required.  This will be rounded up to the nearest
+                     page size by the allocator.  If a value is not explicitly
+                     specified, the page size is taken by default.
+@param aAlign        From Symbian^4 onwards, this value is ignored but EABI 8
+                     byte alignment is guaranteed for all allocations 8 bytes or
+                     more in size.  4 byte allocations will be aligned to a 4
+                     byte boundary.  Best to pass in zero.
+@param aSingleThread ETrue if the heap is to be accessed from multiple threads.
+                     This will cause internal locks to be created, guaranteeing
+                     thread safety.
+
+@return A pointer to the new heap or NULL if the heap could not be created.
+
+@panic USER 41 if aMaxLength is < aMinLength.
+@panic USER 55 if aMinLength is negative.
+@panic USER 56 if aMaxLength is negative.
+*/
+	{
+	TInt page_size;
+	GET_PAGE_SIZE(page_size);
+	TInt minLength = _ALIGN_UP(aMinLength, page_size);
+	TInt maxLength = Max(aMaxLength, minLength);
+
+	TChunkHeapCreateInfo createInfo(minLength, maxLength);
+	createInfo.SetCreateChunk(aName);
+	createInfo.SetGrowBy(aGrowBy);
+	createInfo.SetAlignment(aAlign);
+	createInfo.SetSingleThread(aSingleThread);
+
+	return ChunkHeap(createInfo);
+	}
+
+EXPORT_C RHeap* UserHeap::ChunkHeap(RChunk aChunk, TInt aMinLength, TInt aGrowBy, TInt aMaxLength, TInt aAlign, TBool aSingleThread, TUint32 aMode)
+/**
+Creates a heap in an existing chunk.
+
+This function is intended to be used to create a heap in a user writable code
+chunk as created by a call to RChunk::CreateLocalCode().  This type of heap can
+be used to hold code fragments from a JIT compiler.
+
+@param aChunk        The chunk that will host the heap.
+@param aMinLength    The minimum length of the heap in bytes.  This will be
+                     rounded up to the nearest page size by the allocator.
+@param aGrowBy       The number of bytes by which the heap will grow when more
+                     memory is required.  This will be rounded up to the nearest
+                     page size by the allocator.  If a value is not explicitly
+                     specified, the page size is taken by default.
+@param aMaxLength    The maximum length in bytes to which the heap can grow.  This
+                     will be rounded up to the nearest page size by the allocator.
+                     If 0 is passed in, the maximum lengt of the chunk is used.
+@param aAlign        From Symbian^4 onwards, this value is ignored but EABI 8
+                     byte alignment is guaranteed for all allocations 8 bytes or
+                     more in size.  4 byte allocations will be aligned to a 4
+                     byte boundary.  Best to pass in zero.
+@param aSingleThread ETrue if the heap is to be accessed from multiple threads.
+                     This will cause internal locks to be created, guaranteeing
+                     thread safety.
+@param aMode         Flags controlling the heap creation.  See RAllocator::TFlags.
+
+@return A pointer to the new heap or NULL if the heap could not be created.
+
+@see UserHeap::OffsetChunkHeap()
+*/
+	{
+	return OffsetChunkHeap(aChunk, aMinLength, 0, aGrowBy, aMaxLength, aAlign, aSingleThread, aMode);
+	}
+
+EXPORT_C RHeap* UserHeap::OffsetChunkHeap(RChunk aChunk, TInt aMinLength, TInt aOffset, TInt aGrowBy, TInt aMaxLength, TInt aAlign, TBool aSingleThread, TUint32 aMode)
+/**
+Creates a heap in an existing chunk, offset from the beginning of the chunk.
+
+This function is intended to be used to create a heap using a chunk which has
+some of its memory already used, at the start of that that chunk.  The maximum
+length to which the heap can grow is the maximum size of the chunk, minus the
+data at the start of the chunk.
+
+The offset at which to create the heap is passed in as the aOffset parameter.
+Legacy heap implementations always respected the aOffset value, however more
+modern heap implementations are more sophisticated and cannot necessarily respect
+this value.  Therefore, if possible, you should always use an aOffset of 0 unless
+you have a very explicit requirement for using a non zero value.  Using a non zero
+value will result in a less efficient heap algorithm being used in order to respect
+the offset.
+
+Another issue to consider when using this function is the type of the chunk passed
+in.  In order for the most efficient heap algorithms to be used, the chunk passed
+in should always be a disconnected chunk.  Passing in a non disconnected chunk will
+again result in a less efficient heap algorithm being used.
+
+Finally, another requirement for the most efficient heap algorithms to be used is
+for the heap to be able to expand.  Therefore, unless you have a specific reason to
+do so, always specify aMaxLength > aMinLength.
+
+So, if possible, use aOffset == zero, aMaxLength > aMinLength and a disconnected
+chunk for best results!
+
+@param aChunk        The chunk that will host the heap.
+@param aMinLength    The minimum length of the heap in bytes.  This will be
+                     rounded up to the nearest page size by the allocator.
+@param aOffset       The offset in bytes from the start of the chunk at which to
+                     create the heap.  If used (and it shouldn't really be!)
+                     then it will be rounded up to a multiple of 8, to respect
+                     EABI 8 byte alignment requirements.
+@param aGrowBy       The number of bytes by which the heap will grow when more
+                     memory is required.  This will be rounded up to the nearest
+                     page size by the allocator.  If a value is not explicitly
+                     specified, the page size is taken by default.
+@param aMaxLength    The maximum length in bytes to which the heap can grow.  This
+                     will be rounded up to the nearest page size by the allocator.
+                     If 0 is passed in, the maximum length of the chunk is used.
+@param aAlign        From Symbian^4 onwards, this value is ignored but EABI 8
+                     byte alignment is guaranteed for all allocations 8 bytes or
+                     more in size.  4 byte allocations will be aligned to a 4
+                     byte boundary.  Best to pass in zero.
+@param aSingleThread ETrue if the heap is to be accessed from multiple threads.
+                     This will cause internal locks to be created, guaranteeing
+                     thread safety.
+@param aMode         Flags controlling the heap creation.  See RAllocator::TFlags.
+
+@return A pointer to the new heap or NULL if the heap could not be created.
+
+@panic USER 41 if aMaxLength is < aMinLength.
+@panic USER 55 if aMinLength is negative.
+@panic USER 56 if aMaxLength is negative.
+@panic USER 168 if aOffset is negative.
+*/
+	{
+	TBool dlOnly = EFalse;
+	TInt pageSize;
+	GET_PAGE_SIZE(pageSize);
+	TInt align = RHybridHeap::ECellAlignment; // Always use EABI 8 byte alignment
+
+	__ASSERT_ALWAYS(aMinLength>=0, ::Panic(ETHeapMinLengthNegative));
+	__ASSERT_ALWAYS(aMaxLength>=0, ::Panic(ETHeapMaxLengthNegative));
+
+	if ( aMaxLength > 0 ) 
+		__ASSERT_ALWAYS(aMaxLength>=aMinLength, ::Panic(ETHeapCreateMaxLessThanMin));
+
+	// Stick to EABI alignment for the start offset, if any
+	aOffset = _ALIGN_UP(aOffset, align);
+
+	// Using an aOffset > 0 means that we can't use the hybrid allocator and have to revert to Doug Lea only
+	if (aOffset > 0)
+		dlOnly = ETrue;
+
+	// Ensure that the minimum length is enough to hold the RHybridHeap object itself
+	TInt minCell = _ALIGN_UP(Max((TInt)RHybridHeap::EAllocCellSize, (TInt)RHybridHeap::EFreeCellSize), align);
+	TInt hybridHeapSize = (sizeof(RHybridHeap) + minCell);
+	if (aMinLength < hybridHeapSize)
+		aMinLength = hybridHeapSize;
+
+	// Round the minimum length up to a multiple of the page size, taking into account that the
+	// offset takes up a part of the chunk's memory
+	aMinLength = _ALIGN_UP((aMinLength + aOffset), pageSize);
+
+	// If aMaxLength is 0 then use the entire chunk
+	TInt chunkSize = aChunk.MaxSize();
+	if (aMaxLength == 0)
+		{
+		aMaxLength = chunkSize;
+		}
+	// Otherwise round the maximum length up to a multiple of the page size, taking into account that
+	// the offset takes up a part of the chunk's memory.  We also clip the maximum length to the chunk
+	// size, so the user may get a little less than requested if the chunk size is not large enough
+	else
+		{
+		aMaxLength = _ALIGN_UP((aMaxLength + aOffset), pageSize);
+		if (aMaxLength > chunkSize)
+			aMaxLength = chunkSize;
+		}
+	
+	// If the rounded up values don't make sense then a crazy aMinLength or aOffset must have been passed
+	// in, so fail the heap creation
+	if (aMinLength > aMaxLength)
+		return NULL;
+
+	// Adding the offset into the minimum and maximum length was only necessary for ensuring a good fit of
+	// the heap into the chunk.  Re-adjust them now back to non offset relative sizes
+	aMinLength -= aOffset;
+	aMaxLength -= aOffset;
+
+	// If we are still creating the hybrid allocator (call parameter
+	// aOffset is 0 and aMaxLength > aMinLength), we must reduce heap
+	// aMaxLength size to the value aMaxLength/2 and set the aOffset to point in the middle of chunk.
+	TInt offset = aOffset;
+	TInt maxLength = aMaxLength;
+	if (!dlOnly && (aMaxLength > aMinLength))
+		maxLength = offset = _ALIGN_UP(aMaxLength >> 1, pageSize);
+
+	// Try to use commit to map aMinLength physical memory for the heap, taking into account the offset.  If
+	// the operation fails, suppose that the chunk is not a disconnected heap and try to map physical memory
+	// with adjust.  In this case, we also can't use the hybrid allocator and have to revert to Doug Lea only
+	TBool useAdjust = EFalse;
+	TInt r = aChunk.Commit(offset, aMinLength);
+	if (r == KErrGeneral)
+		{
+		dlOnly = useAdjust = ETrue;
+		r = aChunk.Adjust(aMinLength);
+		if (r != KErrNone)
+			return NULL;
+		}
+	else if (r == KErrNone)
+		{
+		// We have a disconnected chunk reset aOffset and aMaxlength
+		aOffset = offset;
+		aMaxLength = maxLength;
+		}
+
+	else
+		return NULL;
+
+	// Parameters have been mostly verified and we know whether to use the hybrid allocator or Doug Lea only.  The
+	// constructor for the hybrid heap will automatically drop back to Doug Lea if it determines that aMinLength
+	// == aMaxLength, so no need to worry about that requirement here.  The user specified alignment is not used but
+	// is passed in so that it can be sanity checked in case the user is doing something totally crazy with it
+	RHybridHeap* h = new (aChunk.Base() + aOffset) RHybridHeap(aChunk.Handle(), aOffset, aMinLength, aMaxLength,
+		aGrowBy, aAlign, aSingleThread, dlOnly, useAdjust);
+
+	if (h->ConstructLock(aMode) != KErrNone)
+		return NULL;
+
+	// Return the heap address
+	return h;
+	}
+
+#define UserTestDebugMaskBit(bit) (TBool)(UserSvr::DebugMask(bit>>5) & (1<<(bit&31)))
+
+_LIT(KLitDollarHeap,"$HEAP");
+EXPORT_C TInt UserHeap::CreateThreadHeap(SStdEpocThreadCreateInfo& aInfo, RHeap*& aHeap, TInt aAlign, TBool aSingleThread)
+/**
+@internalComponent
+*/
+//
+// Create a user-side heap
+//
+{
+	TInt page_size;
+	GET_PAGE_SIZE(page_size);
+	TInt minLength = _ALIGN_UP(aInfo.iHeapInitialSize, page_size);
+	TInt maxLength = Max(aInfo.iHeapMaxSize, minLength);
+	if (UserTestDebugMaskBit(96)) // 96 == KUSERHEAPTRACE in nk_trace.h
+		aInfo.iFlags |= ETraceHeapAllocs;
+	// Create the thread's heap chunk.
+	RChunk c;
+	TChunkCreateInfo createInfo;
+
+	createInfo.SetThreadHeap(0, maxLength, KLitDollarHeap());	// Initialise with no memory committed.	
+#if USE_HYBRID_HEAP
+	//
+	// Create disconnected chunk for hybrid heap with double max length value
+	//
+	maxLength = 2*maxLength;
+	createInfo.SetDisconnected(0, 0, maxLength);
+#endif	
+	// Set the paging policy of the heap chunk based on the thread's paging policy.
+	TUint pagingflags = aInfo.iFlags & EThreadCreateFlagPagingMask;
+	switch (pagingflags)
+		{
+		case EThreadCreateFlagPaged:
+			createInfo.SetPaging(TChunkCreateInfo::EPaged);
+			break;
+		case EThreadCreateFlagUnpaged:
+			createInfo.SetPaging(TChunkCreateInfo::EUnpaged);
+			break;
+		case EThreadCreateFlagPagingUnspec:
+			// Leave the chunk paging policy unspecified so the process's 
+			// paging policy is used.
+			break;
+		}
+	
+	TInt r = c.Create(createInfo);
+	if (r!=KErrNone)
+		return r;
+	
+	aHeap = ChunkHeap(c, minLength, page_size, maxLength, aAlign, aSingleThread, EChunkHeapSwitchTo|EChunkHeapDuplicate);
+	c.Close();
+	
+	if ( !aHeap )
+		return KErrNoMemory;
+	
+	if (aInfo.iFlags & ETraceHeapAllocs)
+		{
+		aHeap->iFlags |= RHeap::ETraceAllocs;
+    	BTraceContext8(BTrace::EHeap, BTrace::EHeapCreate,(TUint32)aHeap, RHybridHeap::EAllocCellSize);
+		TInt chunkId = ((RHandleBase&)((RHybridHeap*)aHeap)->iChunkHandle).BTraceId();
+		BTraceContext8(BTrace::EHeap, BTrace::EHeapChunkCreate, (TUint32)aHeap, chunkId);
+		}
+	if (aInfo.iFlags & EMonitorHeapMemory)
+		aHeap->iFlags |= RHeap::EMonitorMemory;
+	
+	return KErrNone;
+}
+
+#endif  // __KERNEL_MODE__