kernel/eka/common/arm/cheap.cia
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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:
// e32\common\arm\cheap.cia
// 
//

#include <e32cia.h>
#include "../common.h"

#if defined(__HEAP_MACHINE_CODED__) && !defined(_DEBUG)
GLREF_C void RHeap_PanicBadAllocatedCellSize();
GLREF_C void RHeap_PanicBadNextCell();
GLREF_C void RHeap_PanicBadPrevCell();
GLREF_C void RHeap_PanicBadCellAddress();

IMPORT_D extern const TInt KHeapShrinkHysRatio;


__NAKED__ RHeap::SCell* RHeap::DoAlloc(TInt /*aSize*/, SCell*& /*aLastFree*/)
//
// Allocate a cell.
//
	{
	asm("stmfd sp!, {r4,r5,lr} ");
	asm("mov r4, r0 ");										// r4=this
	asm("add r3, r0, #%a0" : : "i" _FOFF(RHeap,iFree));		// r3=pP=&iFree
	asm("ldr r0, [r3, #4] ");								// r0=pC=pP->next
	asm("cmp r0, #0 ");
	asm("beq 0f ");								// if no free cells, alloc failed

	// optimised unfolded scanning loop
	asm("2: ");
	asm("ldmia r0, {r12,r14} ");				// r12=pC->size, r14=pC->next
	asm("cmp r1, r12 ");						// compare aSize to size
	asm("movhi r3, r0 ");						// if aSize>size, pP=pC
	asm("movhis r0, r14 ");						// and pC=pC->next
#ifndef __CPU_ARMV6 // don't unroll on armv6
	asm("ldmhiia r0, {r12,r14} ");				// r12=pC->size, r14=pC->next
	asm("cmphi r1, r12 ");						// compare aSize to size
	asm("movhi r3, r0 ");						// if aSize>size, pP=pC
	asm("movhis r0, r14 ");						// and pC=pC->next
#endif
	asm("bhi 2b ");								// branch back if scan not finished
	
	asm("1: ");
	asm("subs r5, r12, r1 ");					// r5 = pC->len - aSize
	asm("ldrhs r2, [r4, #%a0]" : : "i" _FOFF(RHeap,iMinCell));		// if big enough, r2=iMinCell
	asm("blo 0f ");								// branch if no free cell was big enough
	asm("cmp r5, r2 ");							// leftover big enough?
	asm("movlo r1, r12 ");						// if not, aSize=pC->len ...
	asm("strlo r14, [r3, #4] ");				// ... and pP->next = pC->next
	asm("addhs r2, r0, r1 ");					// else r2 = pE = address of new free cell ...
	asm("stmhsia r2, {r5, r14} ");				// ... pE->len = pC->len - aSize, pE->next = pC->next ...
	asm("strhs r2, [r3, #4] ");					// ... and pP->next = pE
	asm("str r1, [r0] ");						// pC->len = aSize
	__POPRET("r4,r5,");							// restore and exit, return pC

	asm("0: ");
	asm("str r3, [r2] ");						// alloc failed - aLastFree=pP
	asm("mov r0, #0 ");							// return NULL
	__POPRET("r4,r5,");
	}

__NAKED__ void RHeap::DoFree(SCell* /*pC*/)
//
// Free a cell.
//
	{
	asm("add r2, r0, #%a0" : : "i" _FOFF(RHeap,iFree));	// r2=pP=&iFree
	asm("ldr r3, [r2, #4] ");					// r3=pE=pP->next
	asm("stmfd sp!, {r4, r5} ");

	asm("1: ");
	asm("cmp r3, #0 ");						// check if pE=NULL
	asm("cmphi r1, r3 ");					// if not, check if pC>pE
	asm("movhi r2, r3 ");					// if so, pP=pE
	asm("ldrhi r3, [r3, #4] ");				// and pE=pE->next
#ifndef __CPU_ARMV6    // don't unroll on armv6
	asm("cmphi r3, #0 ");					// check if pE=NULL
	asm("cmphi r1, r3 ");					// if not, check if pC>pE
	asm("movhi r2, r3 ");					// if so, pP=pE
	asm("ldrhi r3, [r3, #4] ");				// and pE=pE->next
#endif
	asm("bhi 1b ");							// loop if free cell position not found

	asm("ldr r4, [r1, #0] ");				// r4=pC->len
	asm("cmp r3, #0 ");						// is there a following free cell ?
	asm("streq r3, [r1, #4] ");				// if not, pC->next=NULL
	asm("beq 2f ");							// and skip next section
	asm("add r5, r1, r4 ");					// r5=pN=pC + pC->len (cell after pC)
	asm("cmp r5, r3 ");						// compare pN with pE
	asm("ldmeqia r3, {r5, r12} ");			// if pN==pE, r5=pE->len, r12=pE->next
	asm("bhi " CSM_Z22RHeap_PanicBadNextCellv );	// if pN>pE, panic
	asm("strne r3, [r1, #4] ");				// if pN<pE, pC->next=pE
	asm("addeq r4, r4, r5 ");				// if pN==pE r4 = pC->len + pE->len
	asm("stmeqia r1, {r4,r12} ");			// if pN==pE pC->len+=pE->len, pC->next=pE->next
	asm("2: ");
	asm("ldr r3, [r2, #0] ");				// r3=pP->len
	asm("sub r5, r1, r2 ");					// r5=pC-pP (gap between preceding free cell and this one)
	asm("cmp r5, r3 ");						// compare gap with predecessor length
	asm("ldreq r12, [r1, #4] ");			// if predecessor is adjacent, r12=pC->next
	asm("blo RHeap_PanicBadPrevCell__Fv ");	// if predecessor overlaps, panic
	asm("addeq r4, r4, r3 ");				// if predecessor is adjacent, r4=pC->len + pP->len
	asm("stmeqia r2, {r4,r12} ");			// if predecessor is adjacent, pP->len+=pC->len, pP->next=pC->next
	asm("strne r1, [r2, #4] ");				// else pP->next = pC
	asm("moveq r1, r2 ");					// if predecessor is adjacent, pC=pP (final amalgamated free cell)
	asm("3: ");
	asm("ldr r12, [r0, #%a0]" : : "i" _FOFF(RHeap,iTop));	// r12=iTop
	asm("add r3, r1, r4 ");					// end of amalgamated free cell
	asm("cmp r3, r12 ");					// end of amalgamated free cell = iTop ?
	asm("ldmneia sp!, {r4,r5} ");			// restore registers
	__JUMP(ne,lr);							// if not, finished
	asm("ldr r12, [r0, #%a0]" : : "i" _FOFF(RHeap,iFlags));	// r12=iFlags
	asm("tst r12, #%a0" : : "i" ((TInt)RAllocator::EFixedSize));	// check fixed size flag
	asm("ldmneia sp!, {r4,r5} ");			// restore registers
	__JUMP(ne,lr);							// if set, finished
	asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(RHeap,iGrowBy));	// r2=iGrowBy
	asm("mov r3, r2, LSR #8");				// r3=iGrowBy>>8
	asm("ldr r2, const_addr");				// r2=&KHeapShrinkHysRatio
	asm("ldr r5, [r2]");					// r5=KHeapShrinkHysRatio
	asm("mul r2, r5, r3");					// r2=KHeapShrinkHysRatio*(iGrowBy>>8) - low order bits
	asm("cmp r4, r2");						// compare len(r4) to (iGrowBy>>8)*KHeapShrinkHysRatio(r2)
	asm("ldmia sp!, {r4,r5} ");				// restore registers
	__JUMP(lo,lr);							// if less, finished
	asm("b Reduce__5RHeapPQ25RHeap5SCell ");	// else reduce heap
	
	asm("const_addr:");
	asm(".word %a0" : : "i" ((TInt)&KHeapShrinkHysRatio));	
	}
#endif