kernel/eka/euser/epoc/arm/uc_utl.cia
changeset 0 a41df078684a
child 177 a232af6b0b1f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/euser/epoc/arm/uc_utl.cia	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1519 @@
+// Copyright (c) 1995-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\euser\epoc\arm\uc_utl.cia
+// 
+//
+
+#include <e32cia.h>
+#include <u32std.h>
+#include <e32base.h>
+#include <e32rom.h>
+#include <e32svr.h>
+#include <e32hashtab.h>
+#include <u32exec.h>
+#include "uc_std.h"
+
+
+#if defined(__MEM_MACHINE_CODED__)
+EXPORT_C __NAKED__ void Mem::Swap(TAny* /*aPtr1*/, TAny* /*aPtr2*/, TInt /*aLength*/)
+/**
+Swaps a number of bytes of data between two specified locations.
+
+The source and target areas can overlap.
+
+@param aPtr1   A pointer to the first location taking part in the swap. 
+@param aPtr2   A pointer to second location taking part in the swap. 
+@param aLength The number of bytes to be swapped between the two locations. 
+               This value must not be negative.
+
+@panic USER 94 In debug builds only, if aLength is negative.
+*/
+    {
+
+    asm("   cmp      r0,r1");
+    asm("   cmpne    r2,#0");
+	__JUMP(eq,lr);
+//
+// Test for same alignment, if more than 16 bytes to swap
+//
+    asm("   and      r3,r0,#3");
+    asm("   and      ip,r1,#3");
+    asm("   cmp      r2,#16");
+    asm("   addlt    r3,r3,#4");
+    asm("   cmp      r3,ip");
+    asm("   beq      same_aligned_swap");
+
+    asm("   stmfd    sp!,{r4,lr}");
+
+    asm("swap_loop:");
+
+    asm("   ldrb     r3,[r0]");
+    asm("   ldrb     r4,[r1]");
+    asm("   strb     r3,[r1],#1");
+    asm("   strb     r4,[r0],#1");
+    asm("   subs     r2,r2,#1");
+	asm("beq swap_exit1 ");
+
+    asm("   ldrb     r3,[r0]");
+    asm("   ldrb     r4,[r1]");
+    asm("   strb     r3,[r1],#1");
+    asm("   strb     r4,[r0],#1");
+    asm("   subs     r2,r2,#1");
+	asm("beq swap_exit1 ");
+
+    asm("   ldrb     r3,[r0]");
+    asm("   ldrb     r4,[r1]");
+    asm("   strb     r3,[r1],#1");
+    asm("   strb     r4,[r0],#1");
+    asm("   subs     r2,r2,#1");
+	asm("beq swap_exit1 ");
+
+    asm("   ldrb     r3,[r0]");
+    asm("   ldrb     r4,[r1]");
+    asm("   strb     r3,[r1],#1");
+    asm("   strb     r4,[r0],#1");
+    asm("   subs     r2,r2,#1");
+    asm("   bne      swap_loop");
+	asm("swap_exit1: ");
+	__POPRET("r4,");
+
+    asm("same_aligned_swap:");
+
+    asm("   stmfd    sp!,{r4-r10,lr}");
+//
+// r3 contains the byte offset from word alignment, 0,1,2 or 3
+// subtract 1 to get -1,0,1 or 2, and if -1 make it 3
+// that gives us 0,1,2 or 3 if the alignment is 3,2,1 or 0 respectively
+// We can use that to jump directly to the appropriate place for
+// swapping the relevent number of bytes to achieve word alignment
+// r4 is set to 3-r3 to correct the length for the number of bytes
+// swapped
+//
+    asm("   subs     r3,r3,#1");
+    asm("   movmi    r3,#3");
+    asm("   rsb      r4,r3,#3");
+    asm("   sub      r2,r2,r4");
+	asm("   add      pc,pc,r3,asl #4");
+	asm("	nop ");	// never executed
+//
+// Jumps here if 3 bytes to swap before word aligned
+//
+    asm("   ldrb     r4,[r0]");
+    asm("   ldrb     ip,[r1]");
+    asm("   strb     r4,[r1],#1");
+    asm("   strb     ip,[r0],#1");
+//
+// Jumps here if 2 bytes to swap before word aligned
+//
+    asm("   ldrb     r4,[r0]");
+    asm("   ldrb     ip,[r1]");
+    asm("   strb     r4,[r1],#1");
+    asm("   strb     ip,[r0],#1");
+//
+// Jumps here if 1 byte to swap before word aligned
+//
+    asm("   ldrb     r4,[r0]");
+    asm("   ldrb     ip,[r1]");
+    asm("   strb     r4,[r1],#1");
+    asm("   strb     ip,[r0],#1");
+//
+// We are now word aligned. Fast swapping, here we come...
+//
+    asm("word_aligned_swap:");
+    asm("   movs     ip,r2,lsr #6"); // Number of 64 blocks to swap
+    asm("   beq      its_smaller_swap");
+
+    asm("swap_64_bytes:");
+    asm("   ldmia    r1,{r3-r6}");
+    asm("   ldmia    r0,{r7-r10}");
+    asm("   stmia    r1!,{r7-r10}");
+    asm("   stmia    r0!,{r3-r6}");
+    asm("   ldmia    r1,{r3-r6}");
+    asm("   ldmia    r0,{r7-r10}");
+    asm("   stmia    r1!,{r7-r10}");
+    asm("   stmia    r0!,{r3-r6}");
+    asm("   ldmia    r1,{r3-r6}");
+    asm("   ldmia    r0,{r7-r10}");
+    asm("   stmia    r1!,{r7-r10}");
+    asm("   stmia    r0!,{r3-r6}");
+    asm("   ldmia    r1,{r3-r6}");
+    asm("   ldmia    r0,{r7-r10}");
+    asm("   stmia    r1!,{r7-r10}");
+    asm("   stmia    r0!,{r3-r6}");
+    asm("   subs     ip,ip,#1");
+    asm("   bne      swap_64_bytes");
+//
+// Less than 64 bytes to go...
+//
+    asm("its_smaller_swap:");
+    asm("   ands     r2,r2,#63");
+	asm("beq swap_exit2 ");
+    asm("   cmp      r2,#4");
+    asm("   blt      finish_swap");
+    asm("final_swap_loop:");
+    asm("   ldr      r3,[r1]");
+    asm("   ldr      ip,[r0]");
+    asm("   str      r3,[r0],#4");
+    asm("   str      ip,[r1],#4");
+    asm("   subs     r2,r2,#4");
+    asm("   cmp      r2,#4");
+    asm("   bge      final_swap_loop");
+//
+// Less than 4 bytes to go...
+//
+    asm("finish_swap:");
+    asm("   tst      r2,#2");
+    asm("   ldrneb   r3,[r0]");
+    asm("   ldrneb   ip,[r1]");
+    asm("   strneb   r3,[r1],#1");
+    asm("   strneb   ip,[r0],#1");
+    asm("   ldrneb   r3,[r0]");
+    asm("   ldrneb   ip,[r1]");
+    asm("   strneb   r3,[r1],#1");
+    asm("   strneb   ip,[r0],#1");
+
+    asm("   tst      r2,#1");
+    asm("   ldrneb   r3,[r0]");
+    asm("   ldrneb   ip,[r1]");
+    asm("   strneb   r3,[r1],#1");
+    asm("   strneb   ip,[r0],#1");
+
+	asm("swap_exit2: ");
+	__POPRET("r4-r10,");
+    }
+#endif
+
+#ifdef __REGIONS_MACHINE_CODED__
+
+__NAKED__ GLDEF_C void AllocAnotherRect( TRegion * /*aRegion*/ )
+	{
+	// Returns with Z flag set to indicate error
+	
+	asm("ldr r1, [r0, #4] ");			// r1=iError
+	asm("cmp r1, #0 ");
+	asm("bne return_error ");
+	asm("ldr r1, [r0, #8] ");			// r1=iAllocedRects
+	asm("ldr r12, [r0] ");				// r12=iCount
+	asm("tst r1, #0x40000000 ");		// test ERRegionBuf
+	asm("beq allocanother1 ");			// don't branch if TRegionFix
+	asm("cmn r1, r12 ");				// test if iCount==-iAllocedRects
+	__JUMP(ne,lr);
+	asm("b  " CSM_ZN7TRegion10ForceErrorEv);		// if so, ForceError()
+	asm("allocanother1: ");
+	asm("cmp r1, #0 ");
+	asm("bpl allocanother3 ");			// branch if RRegion, continue if RRegionBuf
+	asm("orr r2, r1, #0x40000000 ");	// r2=iAllocedRects|ERRegionBuf
+	asm("cmn r2, r12 ");				// check if iCount==(-(iAllocedRects|ERRegionBuf))
+	__JUMP(ne,lr);
+	asm("ldr r2, [r0, #12] ");			// r2=iGranularity
+	asm("add r1, r12, r2 ");			// iAllocedRects=iCount+iGranularity - change into RRegion
+	asm("str r1, [r0, #8] ");
+	asm("stmfd sp!, {r0,r1,r12,lr} ");	// save registers used in function call
+	asm("mov r0, r1, lsl #4 ");			// number of bytes to allocate
+	asm("bl  " CSM_ZN4User5AllocEi);			// User::Alloc
+	asm("movs r2, r0 ");				// returned pointer into r2
+	asm("ldmfd sp!, {r0,r1,r12,lr} ");	// restore registers
+	asm("add r3, r0, #20 ");			// r3=address of first rectangle
+	asm("str r2, [r0, #16] ");			// iRectangleList=returned pointer
+	asm("beq  " CSM_ZN7TRegion10ForceErrorEv);	// if pointer null, ForceError()
+	asm("cmp r12, #0 ");
+	asm("beq return_success ");
+	asm("stmfd sp!, {r4,r5} ");
+	asm("allocanother2: ");
+	asm("ldmia r3!, {r0,r1,r4,r5} ");	// copy data to new area
+	asm("subs r12, r12, #1 ");
+	asm("stmia r2!, {r0,r1,r4,r5} ");
+	asm("bne allocanother2 ");
+	asm("ldmfd sp!, {r4,r5} ");
+	asm("return_success: ");
+	asm("movs r0, #1 ");				// clear Z flag to indicate success
+	__JUMP(,lr);
+	asm("allocanother3: ");				// come here if RRegion
+	asm("cmp r1, r12 ");				// check if iCount==iAllocedRects
+	__JUMP(ne,lr);
+	asm("ldr r2, [r0, #12] ");			// r2 = iGranularity
+	asm("add r1, r1, r2 ");				// iAllocedRects+=iGranularity
+	asm("str r1, [r0, #8] ");
+	asm("stmfd sp!, {r0,lr} ");			// preserve r0,lr across function call
+	asm("ldr r0, [r0, #16] ");			// r0=address of current cell
+	asm("mov r1, r1, lsl #4 ");			// r1=number of bytes to allocate
+	asm("mov r2, #0 ");
+	asm("bl  " CSM_ZN4User7ReAllocEPvii);		// User::ReAlloc
+	asm("movs r2, r0 ");				// returned pointer into r2
+	asm("ldmfd sp!, {r0,lr} ");			// restore r0,lr
+	asm("strne r2, [r0, #16] ");		// if returned ptr not null, iRectangleList=returned ptr
+	__JUMP(ne,lr);
+	asm("b  " CSM_ZN7TRegion10ForceErrorEv);		// else ForceError()
+	}
+
+
+__NAKED__ EXPORT_C void TRegion::ForceError()
+	{
+	// Returns with Z flag set to indicate error
+	
+	asm("stmfd sp!, {r0,lr} ");
+	asm("bl " CSM_ZN7TRegion5ClearEv);	// Clear()
+	asm("ldmfd sp!, {r0,lr} ");			// restore r0,lr
+	asm("mov r1, #1 ");
+	asm("str r1, [r0, #4] ");			// iError=ETrue
+	asm("return_error: ");
+	asm("movs r0, #0 ");				// set Z flag to indicate error
+	__JUMP(,lr);
+	}
+
+
+
+__NAKED__ EXPORT_C TRect TRegion::BoundingRect() const
+/**
+Gets the minimal rectangle that bounds the entire region.
+
+@return The region's minimal bounding rectangle.
+*/
+	{
+	asm("ldr r2, [r1] ");			// r2=iCount
+	asm("cmp r2, #0 ");				// list empty?
+	asm("beq boundingrect0 ");		// branch if empty
+	asm("ldr r3, [r1, #8] ");			// if not empty, r3 points to first rectangle
+	asm("stmfd sp!, {r4-r8,lr} ");
+	asm("cmn r3, r3 ");
+	asm("ldrcc r3, [r1, #16] ");		// if RRegion
+	asm("addcs r3, r1, #20 ");			// RRegionBuf
+	asm("submi r3, r3, #8 ");			// TRegionFix
+	asm("ldmia r3!, {r4-r7} ");			// if not empty bounds = first rectangle
+	asm("b boundingrect2 ");			// if not empty go and check rest of list
+	asm("boundingrect1: ");
+	asm("ldmia r3!, {r1,r8,r12,lr} ");	// fetch next rectangle
+	asm("cmp r1, r4 ");					// if next.iTl.iX<bounds.iTl.iX
+	asm("movlt r4, r1 ");				//		bounds.iTl.iX=next.iTl.iX
+	asm("cmp r8, r5 ");					// if next.iTl.iY<bounds.iTl.iY
+	asm("movlt r5, r8 ");				//		bounds.iTl.iY=next.iTl.iY
+	asm("cmp r12, r6 ");				// if next.iBr.iX>bounds.iBr.iX
+	asm("movgt r6, r12 ");				//		bounds.iBr.iX=next.iBr.iX
+	asm("cmp lr, r7 ");					// if next.iBr.iY>bounds.iBr.iY
+	asm("movgt r7, lr ");				//		bounds.iBr.iY=next.iBr.iY
+	asm("boundingrect2: ");
+	asm("subs r2, r2, #1 ");			// decrement count
+	asm("bne boundingrect1 ");			// repeat for all rectangles
+	asm("stmia r0, {r4-r7} ");			// store result
+	__POPRET("r4-r8,");
+
+	asm("boundingrect0: ");
+	asm("mov r1, #0 ");					// if list empty, bounds = 0,0,0,0
+	asm("mov r3, #0 ");
+	asm("mov r12, #0 ");
+	asm("stmia r0, {r1,r2,r3,r12} ");	// store result
+	__JUMP(,lr);
+	}
+
+
+
+
+__NAKED__ EXPORT_C TBool TRegion::IsContainedBy(const TRect & /*aRect*/) const
+/**
+Tests whether the region is fully enclosed within the specified rectangle.
+
+@param aRect The specified rectangle.
+ 
+@return True, if the region is fully enclosed within the rectangle (their sides 
+        may touch); false, otherwise.
+*/
+	{
+	asm("ldr r12, [r0, #8] ");			// r12 points to first rectangle
+	asm("stmfd sp!, {r4-r7,lr} ");	
+	asm("cmn r12, r12 ");
+	asm("ldrcc r12, [r0, #16] ");		// if RRegion
+	asm("addcs r12, r0, #20 ");			// RRegionBuf
+	asm("submi r12, r12, #8 ");			// TRegionFix
+
+	asm("ldr r0, [r0] ");				// r0=iCount
+	asm("ldmia r1, {r4-r7} ");			// aRect coordinates into r4-r7
+	
+	asm("subs r0, r0, #1 ");			// decrement it
+	asm("bmi iscontainedby2 ");			// if iCount was zero, return TRUE
+	
+	asm("iscontainedby1: ");
+	asm("ldmia r12!, {r1,r2,r3,lr} ");	// coordinates of next rectangle
+	asm("cmp r1, r4 ");					// compare next.iTl.iX with aRect.iTl.iX
+	asm("cmpge r2, r5 ");				// if >=, compare next.iTl.iY with aRect.iTl.iY
+	asm("cmpge r6, r3 ");				// if >=, compare aRect.Br.iX with next.iBr.iX
+	asm("cmpge r7, lr ");				// if >=, compare aRect.Br.iY with next.iBr.iY
+	asm("subges r0, r0, #1 ");			// if >=, next is contained in aRect, so iterate
+	asm("bge iscontainedby1 ");			// will drop through if r0<0 or if next exceeds aRect
+	asm("iscontainedby2: ");
+	asm("mov r0, r0, lsr #31 ");		// return 1 if r0<0, 0 if r0>=0
+	__POPRET("r4-r7,");
+	}
+
+
+
+
+__NAKED__ EXPORT_C void TRegion::Copy(const TRegion & /*aRegion*/)
+/**
+Copies another region to this region.
+
+The state of the specified region's error flag is also copied.
+
+@param aRegion The region to be copied.
+*/
+	{
+	asm("ldr r2, [r1, #4] ");					// r2 = aRegion.iError
+	asm("cmp r2, #0 ");
+	asm("bne  " CSM_ZN7TRegion10ForceErrorEv);	// if (aRegion.iError) ForceError();
+	asm("ldr r2, [r1] ");						// r1 = aRegion.iCount
+	asm("cmp r2, #0 ");
+	asm("beq " CSM_ZN7TRegion5ClearEv);			// region to copy is empty so simply clear our buffer
+	asm("stmfd sp!, {r0,r1,r4,r5,r6,lr} ");		// preserve r0,r1,lr across function calls
+	asm("mov r4, r1 ");
+	asm("mov r5, r0 ");
+	asm("ldr r2, [r0, #4] ");					// r2 = iError
+	asm("cmp r2, #0 ");
+	asm("blne  " CSM_ZN7TRegion5ClearEv);		// if (iError) Clear();
+	asm("mov r0, r5 ");
+	asm("ldr r1, [r4] ");						// r1 = aRegion.iCount, r0 = this
+	asm("bl	 " CSM_ZN7TRegion11SetListSizeEi);	// SetListSize(aRegion.iCount);
+	asm("cmp r0, #0 ");
+	asm("beq copyregion_end ");
+	asm("ldr r3, [r4] ");						// r3 = aRegion.iCount
+	asm("cmp r3, #0 ");
+	asm("str r3, [r5] ");						// iCount=aRegion.iCount
+	asm("beq copyregion_end ");
+	asm("ldr r0, [r5, #8] ");					// r0 points to first rectangle
+	asm("cmn r0, r0 ");
+	asm("ldrcc r0, [r5, #16] ");				// if RRegion
+	asm("addcs r0, r5, #20 ");					// RRegionBuf
+	asm("submi r0, r0, #8 ");					// TRegionFix
+	asm("ldr r1, [r4, #8] ");					// r1 points to first rectangle
+	asm("cmn r1, r1 ");
+	asm("ldrcc r1, [r4, #16] ");				// if RRegion
+	asm("addcs r1, r4, #20 ");					// RRegionBuf
+	asm("submi r1, r1, #8 ");					// TRegionFix
+	asm("copyregion1: ");
+	asm("ldmia r1!, {r2,r4,r5,r12} ");			// copy aRegion.iRectangleList to iRectangleList
+	asm("subs r3, r3, #1 ");
+	asm("stmia r0!, {r2,r4,r5,r12} ");
+	asm("bne copyregion1 ");
+
+	asm("copyregion_end: ");
+	__POPRET("r0,r1,r4,r5,r6,");
+	}
+
+
+
+
+__NAKED__ EXPORT_C void TRegion::Offset(const TPoint & /*anOffset*/)
+/**
+Moves the region by adding a TPoint offset to the co-ordinates of its corners.
+	
+The size of the region is not changed.
+	
+@param aOffset The offset by which the region is moved. The region is moved 
+               horizontally by aOffset.iX pixels and vertically by aOffset.iY pixels.
+*/
+	{
+	asm("ldmia r1, {r1,r2} ");		// r1=anOffset.iX, r2=anOffset.iY
+	// fall through...
+	}
+
+
+
+
+__NAKED__ EXPORT_C void TRegion::Offset(TInt /*xOffset*/,TInt /*yOffset*/)
+/**
+Moves the region by adding X and Y offsets to the co-ordinates of its corners.
+	
+The size of the region is not changed.
+	
+@param aXoffset The number of pixels by which to move the region horizontally. 
+                If negative, the region moves leftwards. 
+@param aYoffset The number of pixels by which to move the region vertically. 
+                If negative, the region moves upwards.
+*/
+	{
+	asm("ldr r12, [r0] ");			// r12=iCount
+	asm("cmp r12, #0 ");
+	__JUMP(eq,lr);
+	asm("ldr r3, [r0, #8] ");		// r0 points to first rectangle
+	asm("cmn r3, r3 ");
+	asm("ldrcc r0, [r0, #16] ");	// if RRegion
+	asm("addcs r0, r0, #20 ");		// RRegionBuf
+	asm("submi r0, r0, #8 ");		// TRegionFix
+	asm("stmfd sp!, {r4,r5,lr} ");
+	asm("offsetregion2: ");
+	asm("ldmia r0, {r3-r5,lr} ");	// r3-r5,lr = next rectangle coordinates
+	asm("subs r12, r12, #1 ");
+	asm("add r3, r3, r1 ");			// Tl.iX += anOffset.iX
+	asm("add r4, r4, r2 ");			// Tl.iY += anOffset.iY
+	asm("add r5, r5, r1 ");			// Br.iX += anOffset.iX
+	asm("add lr, lr, r2 ");			// Br.iY += anOffset.iY
+	asm("stmia r0!, {r3-r5,lr} ");	// store new coordinates
+	asm("bne offsetregion2 ");
+	__POPRET("r4,r5,");
+	}
+
+
+
+
+__NAKED__ EXPORT_C TBool TRegion::Contains(const TPoint & /*aPoint*/) const
+/**
+Tests whether a point is located within the region.
+
+If the point is located on the top or left hand side of any rectangle in the 
+region, it is considered to be within that rectangle and within the region. 
+
+If the point is located on the right hand side or bottom of a rectangle, it 
+is considered to be outside that rectangle, and may be outside the region.
+
+@param aPoint The specified point. 
+
+@return True, if the point is within the region; false, otherwise.
+*/
+	{
+	asm("ldr r12, [r0] ");			// r12 = iCount
+	asm("stmfd sp!, {r4,r5,lr} ");
+	asm("cmp r12, #0 ");
+	asm("beq contains0 ");			// if iCount=0, return FALSE
+	asm("ldr r3, [r0, #8] ");		// r0 points to first rectangle
+	asm("cmn r3, r3 ");
+	asm("ldrcc r0, [r0, #16] ");	// if RRegion
+	asm("addcs r0, r0, #20 ");		// RRegionBuf
+	asm("submi r0, r0, #8 ");		// TRegionFix
+	asm("ldmia r1, {r1, r2} ");		// r1=aPoint.iX, r2=aPoint.iY
+	asm("contains1: ");
+	asm("ldmia r0!, {r3-r5,lr} ");	// coordinates of next rectangle into r3-r5,lr
+	asm("cmp r3, r1 ");				// compare next.iTl.iX with aPoint.iX
+	asm("cmple r4, r2 ");			// if <=, compare next.iTl.iY with aPoint.iY
+	asm("bgt contains2 ");			// if >, aPoint is not contained in rectangle, so iterate
+	asm("cmp r1, r5 ");				// compare aPoint.iX with next.iBr.iX
+	asm("cmplt r2, lr ");			// if <, compare aPoint.iY with next.iBr.iY
+	asm("contains2: ");
+	asm("subges r12, r12, #1 ");	// if >=, aPoint is not contained in rect, so iterate
+	asm("bgt contains1 ");
+	asm("cmp r12, #0 ");
+	asm("movne r0, #1 ");			// if r12 non-zero, return TRUE else FALSE
+	asm("contains0: ");
+	asm("moveq r0, #0 ");
+	__POPRET("r4,r5,");
+	}
+
+
+
+
+__NAKED__ EXPORT_C TBool TRegion::Intersects(const TRect &/*aRect*/) const
+/**
+Tests whether where there is any intersection between this region and the specified rectangle.
+
+@param aRect The specified rectangle.
+ 
+@return True, if there is an intersection; false, otherwise.
+*/
+	{
+	asm("ldr    r12, [r0] ");		// r12 = iCount
+	asm("stmfd  sp!, {r4-r7,lr} ");
+	asm("cmp    r12, #0 ");
+	asm("beq    intersects0 ");		// if iCount=0, return FALSE
+	asm("ldr    lr, [r0, #8] ");	// r0 points to first rectangle	
+	asm("ldmia  r1, {r1-r4} ");		// (load aRect into r1 - r4)
+	asm("cmn    lr, lr ");
+	asm("ldrcc  r0, [r0, #16] ");	// if RRegion
+	asm("addcs  r0, r0, #20 ");		// RRegionBuf
+	asm("submi  r0, r0, #8 ");		// TRegionFix
+	asm("cmp    r1, r3 ");			// check if aRect is empty
+	asm("cmplt  r2, r4 ");
+	asm("bge    intersects0 ");
+	
+	asm("intersects1: ");
+	asm("ldmia  r0!, {r5-r7,lr} ");	// coordinates of next rectangle into r5-r7,lr	
+	asm("cmp    r1, r7 ");			// check if they intersect
+	asm("cmplt  r2, lr ");
+	asm("cmplt  r5, r3 ");
+	asm("cmplt  r6, r4 ");
+	asm("subges r12, r12, #1 ");	// if not then decrement and loop
+	asm("bgt    intersects1 ");
+	
+	asm("intersects0: ");
+	asm("movge  r0, #0 ");
+	asm("movlt  r0, #1 ");
+	__POPRET("r4-r7,");
+	}
+
+
+
+
+__NAKED__ void TRegion::DeleteRect(TRect * /*aRect*/)
+//
+// Delete a specific rectangle in the list.
+//
+	{
+	asm("ldr r12, [r0] ");			// r12=iCount
+	asm("ldr r3, [r0, #8] ");		// r0 points to first rectangle
+	asm("subs r12, r12, #1 ");		// decrement it
+	asm("str r12, [r0] ");			// iCount--;
+	asm("cmn r3, r3 ");
+	asm("ldrcc r0, [r0, #16] ");	// if RRegion
+	asm("addcs r0, r0, #20 ");		// RRegionBuf
+	asm("submi r0, r0, #8 ");		// TRegionFix
+	asm("sub r2, r1, r0 ");			// r2=offset of aRect from iRectangleList
+	asm("subs r12, r12, r2, lsr #4 ");	// r12 now equals number of rectangles requiring moving
+	__JUMP(eq,lr);
+	asm("add r0, r1, #16 ");			// r0 = aRect+1
+	asm("stmfd sp!, {r4,lr} ");
+	asm("deleterect1: ");
+	asm("ldmia r0!, {r2-r4,lr} ");		// move rectangles following aRect back by one place
+	asm("subs r12, r12, #1 ");
+	asm("stmia r1!, {r2-r4,lr} ");
+	asm("bne deleterect1 ");
+	__POPRET("r4,");
+	}
+
+
+
+
+__NAKED__ EXPORT_C void TRegion::ClipRect(const TRect & /*aRect*/)
+/**
+Clips the region to the specified rectangle.
+
+The resulting region is the area of overlap between the region and the rectangle. 
+If there is no overlap, all rectangles within this region are deleted and 
+the resulting region is empty.
+
+@param aRect The rectangle to which this region is to be clipped.
+*/
+// Can not fail.
+	{
+	asm("ldr r12, [r0] ");				// r12=iCount
+	asm("cmp r12, #0 ");
+	__JUMP(eq,lr);
+	asm("stmfd sp!, {r4-r10,lr} ");
+	asm("ldmia r1, {r2-r5} ");			// get coordinates of aRect into r2-r5
+	asm("ldr r1, [r0, #8] ");			// r1 points to first rectangle
+	asm("cmn r1, r1 ");
+	asm("ldrcc r1, [r0, #16] ");		// if RRegion
+	asm("addcs r1, r0, #20 ");			// RRegionBuf
+	asm("submi r1, r1, #8 ");			// TRegionFix
+
+	asm("cliprect1: ");
+	asm("ldmia r1!, {r6-r9} ");			// next rectangle coordinates into r6-r9
+	asm("cmp r6, r2 ");					// clip the rectangle to aRect
+	asm("movlt r6, r2 ");	
+	asm("strlt r2, [r1, #-16] ");
+	asm("cmp r7, r3 ");
+	asm("movlt r7, r3 ");
+	asm("strlt r3, [r1, #-12] ");
+	asm("cmp r8, r4 ");
+	asm("movgt r8, r4 ");
+	asm("strgt r4, [r1, #-8] ");
+	asm("cmp r9, r5 ");
+	asm("movgt r9, r5 ");
+	asm("strgt r5, [r1, #-4] ");
+	asm("cmp r6, r8 ");					// check if clipped rect is empty
+	asm("cmplt r7, r9 ");				// empty if r6>=r8 or r7>=r9
+	asm("bge cliprect_delete ");		// if empty, branch to other loop to delete rect 
+	asm("subs r12, r12, #1 ");			// decrement loop counter
+	asm("bne cliprect1 ");				// loop if any more rectangles to do
+	__POPRET("r4-r10,");
+
+	asm("cliprect_delete: ");			// (enter loop here)
+	asm("ldr lr, [r0] ");				// lr=iCount, updateed if we delete rects
+	asm("sub r10, r1, #16 ");			// r1 -> next rect, r10 -> previous deleted rect
+	asm("subs r12, r12, #1 ");			// decrement loop counter
+	asm("beq cliprect_move_end ");	
+	asm("cliprect_move: ");
+	asm("ldmia r1!, {r6-r9} ");			// next rectangle coordinates into r6-r9
+	asm("cmp r6, r2 ");					// clip the rectangle to aRect
+	asm("movlt r6, r2 ");
+	asm("cmp r7, r3 ");
+	asm("movlt r7, r3 ");
+	asm("cmp r8, r4 ");
+	asm("movgt r8, r4 ");
+	asm("cmp r9, r5 ");
+	asm("movgt r9, r5 ");
+	asm("cmp r6, r8 ");					// check if clipped rect is empty
+	asm("cmplt r7, r9 ");				// empty if r6>=r8 or r7>=r9
+	asm("stmltia r10!, {r6-r9} ");		// if non-empty then store the rect
+	asm("subge lr, lr, #1 ");			// else decrement rect count	
+	asm("subs r12, r12, #1 ");			// decrement loop counter
+	asm("bne cliprect_move ");			// loop if any more rectangles to do
+	asm("cliprect_move_end: ");	
+	asm("sub lr, lr, #1 ");				// decrement count for first deleted rect
+	asm("str lr, [r0] ");				// store updated iCount
+	__POPRET("r4-r10,");	
+	}
+
+
+
+	
+__NAKED__ EXPORT_C void TRegion::SubRect(const TRect& /*aRect*/,TRegion* /*aSubtractedRegion*/)
+/**
+Removes a rectangle from this region.
+
+If there is no intersection between the rectangle and this region, then this 
+region is unaffected. 
+
+@param aRect             The rectangular area to be removed from this region. 
+@param aSubtractedRegion A pointer to a region. If this is supplied, the
+                         removed rectangle is added to it. By default this
+                         pointer is NULL.
+*/
+	{
+	asm("ldr r12, [r0] ");			// r12=iCount=limit
+	asm("cmp r12, #0 ");
+	__JUMP(eq,lr);
+	asm("stmfd sp!, {r3-r11,lr} ");
+	asm("ldmia r1, {r4-r7} ");		// r4-r7 = coordinates of aRect
+	asm("cmp r4, r6 ");				// check if aRect is empty i.e. (r4>=r6 || r5>=r7)
+	asm("cmplt r5, r7 ");
+	asm("bge subrect_end ");		// if aRect is empty nothing to do
+
+	asm("mov r3, #0 ");				// r3=index
+	asm("subrect1: ");
+	asm("ldr lr, [r0, #8] ");		// lr points to first rectangle
+	asm("cmn lr, lr ");
+	asm("ldrcc lr, [r0, #16] ");	// if RRegion
+	asm("addcs lr, r0, #20 ");		// RRegionBuf
+	asm("submi lr, lr, #8 ");		// TRegionFix
+	asm("add lr, lr, r3, lsl #4 ");	// lr=iRectangleList+index
+//	asm("ldmia r1, {r4-r7} ");		// r4-r7 = coordinates of aRect
+	asm("ldmia lr, {r8-r11} ");		// r8-r11 = coordinates of next rectangle in region
+	asm("cmp r10, r4 ");			// compare next.iBr.iX with aRect.iTl.iX
+	asm("cmpgt r11, r5 ");			// if >, compare next.iBr.iY with aRect.iTl.iY
+	asm("cmpgt r6, r8 ");			// if >, compare aRect.iBr.iX with next.iTl.iX
+	asm("cmpgt r7, r9 ");			// if >, compare aRect.iBr.iY with next.iTl.iY
+	asm("addle r3, r3, #1 ");		// if empty intersection, increment index
+	asm("ble subrect2 ");			// if <=, next and aRect have empty intersection, so skip
+	asm("add r4, lr, #16 ");		// r4 = source pointer for copy, lr = dest
+	asm("ldr r5, [r0] ");			// r5 = iCount
+	asm("sub r5, r5, #1 ");			// decrement iCount
+	asm("str r5, [r0] ");
+	asm("sub r12, r12, #1 ");		// decrement limit
+	asm("subs r5, r5, r3 ");		// loop count for copy = iCount-index
+	asm("beq subrect4 ");			// if loop count zero, skip the copy
+	asm("stmfd sp!, {r8,r9} ");		// preserve r8,r9
+	asm("subrect3: ");
+	asm("ldmia r4!, {r6-r9} ");		// remove the current rectangle
+	asm("stmia lr!, {r6-r9} ");
+	asm("subs r5, r5, #1 ");
+	asm("bne subrect3 ");
+	asm("ldmfd sp!, {r8-r9} ");		// restore r8,r9
+	asm("subrect4: ");
+	asm("ldmia r1, {r4-r7} ");		// restore coordinates of aRect into r4-r7
+	asm("cmp r7, r11 ");			// compare aRect.iBr.iY with rect.iBr.iY
+	asm("movgt r7, r11 ");			// r7=inter.iBr.iY
+	asm("bllt subrectapp1 ");		// if <, append 1st subrectangle
+	asm("cmp r5, r9 ");				// compare aRect.iTl.iY with rect.iTl.iY
+	asm("movlt r5, r9 ");			// r5=inter.iTl.iY
+	asm("blgt subrectapp2 ");		// if >, append 2nd subrectangle
+	asm("cmp r6, r10 ");			// compare aRect.iBr.iX with rect.iBr.iX
+	asm("movgt r6, r10 ");			// r6=inter.iBr.iX
+	asm("bllt subrectapp3 ");		// if <, append 3rd subrectangle
+	asm("cmp r4, r8 ");				// compare aRect.iTl.iX with rect.iTl.iX
+	asm("movlt r4, r8 ");			// r4=inter.iTl.iX
+	asm("blgt subrectapp4 ");		// if >, append 4th subrectangle
+	asm("ldr lr, [r0, #4] ");		// lr=iError
+	asm("cmp lr, #0 ");				// check for an error
+	asm("bne subrect_end ");
+	asm("cmp r2, #0 ");				// check if aSubtractedRegion!=NULL
+	asm("blne subrectadd ");		// if non-null, add inter to aSubtractedRegion
+	asm("subrect2: ");
+	asm("cmp r3, r12 ");			// compare index to limit
+	asm("ldmltia r1, {r4-r7} ");	// if index<limit, r4-r7 = coordinates of aRect
+	asm("blt subrect1 ");			// if index<limit, loop again
+
+	asm("subrect_end: ");
+	__POPRET("r3-r11,");
+
+	// AppendRect(TRect(rect.iTl.iX,inter.iBr.iY,rect.iBr.iX,rect.iBr.iY))
+	asm("subrectapp1: ");
+	asm("stmfd sp!, {r0-r3,r12,lr} ");			// preserve registers across function call
+	asm("bl  " CSM_Z16AllocAnotherRectP7TRegion);
+	asm("ldmfd sp!, {r0-r3} ");
+	asm("beq subrectapp1_end ");		// exit if error
+
+	asm("ldr r12, [r0] ");				// r12=iCount
+	asm("ldr lr, [r0, #8] ");		// lr points to first rectangle
+	asm("cmn lr, lr ");
+	asm("ldrcc lr, [r0, #16] ");	// if RRegion
+	asm("addcs lr, r0, #20 ");		// RRegionBuf
+	asm("submi lr, lr, #8 ");		// TRegionFix
+	asm("add lr, lr, r12, lsl #4 ");	// lr=&(iRectangleList[iCount])
+	asm("add r12, r12, #1 ");			// increment iCount
+	asm("str r12, [r0] ");				//
+	asm("stmia lr!, {r8} ");			// append rectangle - rect.iTl.iX
+	asm("stmia lr!, {r7,r10,r11} ");	// inter.iBr.iY, rect.iBr.iX, rect.iBr.iY
+	asm("subrectapp1_end: ");
+	__POPRET("r12,");
+
+	// AppendRect(TRect(rect.iTl.iX,rect.iTl.iY,rect.iBr.iX,inter.iTl.iY))
+	asm("subrectapp2: ");
+	asm("stmfd sp!, {r0-r3,r12,lr} ");			// preserve registers across function call
+	asm("bl  " CSM_Z16AllocAnotherRectP7TRegion);
+	asm("ldmfd sp!, {r0-r3} ");
+	asm("beq subrectapp1_end ");		// exit if error
+
+	asm("ldr r12, [r0] ");				// r12=iCount
+	asm("ldr lr, [r0, #8] ");		// lr points to first rectangle
+	asm("cmn lr, lr ");
+	asm("ldrcc lr, [r0, #16] ");	// if RRegion
+	asm("addcs lr, r0, #20 ");		// RRegionBuf
+	asm("submi lr, lr, #8 ");		// TRegionFix
+	asm("add lr, lr, r12, lsl #4 ");	// lr=&(iRectangleList[iCount])
+	asm("add r12, r12, #1 ");			// increment iCount
+	asm("str r12, [r0] ");				//
+	asm("stmia lr!, {r8,r9,r10} ");		// append rectangle - rect.iTl.iX,rect.iTl.iY,rect.iBr.iX
+	asm("stmia lr!, {r5} ");			// inter.iTl.iY
+	__POPRET("r12,");
+
+	// AppendRect(TRect(inter.iBr.iX,inter.iTl.iY,rect.iBr.iX,inter.iBr.iY))
+	asm("subrectapp3: ");
+	asm("stmfd sp!, {r0-r3,r12,lr} ");			// preserve registers across function call
+	asm("bl  " CSM_Z16AllocAnotherRectP7TRegion);
+	asm("ldmfd sp!, {r0-r3} ");
+	asm("beq subrectapp1_end ");		// exit if error
+	asm("ldr r12, [r0] ");				// r12=iCount
+	asm("ldr lr, [r0, #8] ");		// lr points to first rectangle
+	asm("cmn lr, lr ");
+	asm("ldrcc lr, [r0, #16] ");	// if RRegion
+	asm("addcs lr, r0, #20 ");		// RRegionBuf
+	asm("submi lr, lr, #8 ");		// TRegionFix
+	asm("add lr, lr, r12, lsl #4 ");	// lr=&(iRectangleList[iCount])
+	asm("add r12, r12, #1 ");			// increment iCount
+	asm("str r12, [r0] ");				//
+	asm("stmia lr!, {r6} ");			// append rectangle - inter.iBr.iX
+	asm("stmia lr!, {r5,r10} ");		// inter.iTl.iY, rect.iBr.iX
+	asm("stmia lr!, {r7} ");			// inter.iBr.iY
+	__POPRET("r12,");
+
+	// AppendRect(TRect(rect.iTl.iX,inter.iTl.iY,inter.iTl.iX,inter.iBr.iY))
+	asm("subrectapp4: ");
+	asm("stmfd sp!, {r0-r3,r12,lr} ");			// preserve registers across function call
+	asm("bl  " CSM_Z16AllocAnotherRectP7TRegion);
+	asm("ldmfd sp!, {r0-r3} ");
+	asm("beq subrectapp1_end ");		// exit if error
+	asm("ldr r12, [r0] ");				// r12=iCount
+	asm("ldr lr, [r0, #8] ");		// lr points to first rectangle
+	asm("cmn lr, lr ");
+	asm("ldrcc lr, [r0, #16] ");	// if RRegion
+	asm("addcs lr, r0, #20 ");		// RRegionBuf
+	asm("submi lr, lr, #8 ");		// TRegionFix
+	asm("add lr, lr, r12, lsl #4 ");	// lr=&(iRectangleList[iCount])
+	asm("add r12, r12, #1 ");			// increment iCount
+	asm("str r12, [r0] ");				//
+	asm("stmia lr!, {r8} ");			// append rectangle - rect.iTl.iX
+	asm("stmia lr!, {r5} ");			// inter.iTl.iY
+	asm("stmia lr!, {r4,r7} ");			// inter.iTl.iX, inter.iBr.iY
+	__POPRET("r12,");
+
+	// aSubtractedRegion->AddRect(inter)
+	asm("subrectadd: ");
+	asm("stmfd sp!, {r0-r7,r12,lr} ");	// preserve registers and put inter onto stack
+	asm("mov r0, r2 ");					// this = aSubtractedRegion
+	asm("add r1, sp, #16 ");			// inter is 16 bytes above sp
+	asm("bl  " CSM_ZN7TRegion7AddRectERK5TRect);	// call TRegion::AddRect
+	__POPRET("r0-r7,r12,");
+	}
+
+
+
+
+__NAKED__ EXPORT_C void TRegion::Intersection(const TRegion& /*aRegion1*/,const TRegion& /*aRegion2*/)
+/**
+Replaces this region with the area of intersection between two specified regions.
+	
+Notes:
+	
+1. If the error flag of either of the two specified regions is set, then this 
+   region is cleared and its error flag is set. This frees up allocated memory.
+	
+2. If this region's error flag is already set, then the function has no effect.
+	
+@param aRegion1 The first region. 
+@param aRegion2 The second region.
+*/
+	{
+	// r0=this, r1=&aRegion1, r2=&aRegion2
+	asm("ldr r3, [r1, #4] ");			// r3=aRegion1.iError
+	asm("ldr r12, [r2, #4] ");			// r12=aRegion2.iError
+	asm("orrs r3, r3, r12 ");
+	asm("bne  " CSM_ZN7TRegion10ForceErrorEv);	// if either set, ForceError()
+	asm("str r3, [r0] ");				// iCount=0
+	asm("ldr r3, [r1] ");				// r3=aRegion1.iCount
+	asm("ldr r12, [r2] ");				// r12=aRegion2.iCount
+	asm("cmp r3, #0 ");
+	asm("cmpne r12, #0 ");
+	__JUMP(eq,lr);
+	asm("stmfd sp!, {r3-r11,lr} ");
+	asm("ldr lr, [r1, #8] ");			// r1 points to first rectangle of aRegion1 = pRect1
+	asm("cmn lr, lr ");
+	asm("ldrcc r1, [r1, #16] ");		// if RRegion
+	asm("addcs r1, r1, #20 ");			// RRegionBuf
+	asm("submi r1, r1, #8 ");			// TRegionFix
+	asm("intersection1: ");
+	asm("ldr lr, [r2, #8] ");			// lr points to first rectangle of aRegion2
+	asm("cmn lr, lr ");
+	asm("ldrcc lr, [r2, #16] ");		// if RRegion
+	asm("addcs lr, r2, #20 ");			// RRegionBuf
+	asm("submi lr, lr, #8 ");			// TRegionFix
+	asm("ldr r12, [r2] ");				// r12=aRegion2.iCount
+	asm("intersection2: ");
+	asm("ldmia r1, {r4-r7} ");			// r4-r7 = *pRect1
+	asm("ldmia lr!, {r8-r11} ");		// r8-r11 = *pRect2++
+	asm("cmp r6, r8 ");					// compare pRect1->iBr.iX with pRect2->iTl.iX
+	asm("cmpgt r7, r9 ");				// if >, compare pRect1->iBr.iY with pRect2->iTl.iY
+	asm("cmpgt r10, r4 ");				// if >, compare pRect2->iBr.iX with pRect1->iTl.iX
+	asm("cmpgt r11, r5 ");				// if >, compare pRect2->iBr.iY with pRect1->iTl.iY
+	asm("ble intersection3 ");			// if <=, rectangles have empty intersection, so iterate
+	asm("cmp r4, r8 ");					// compute intersection and place in r8-r11
+	asm("movgt r8, r4 ");
+	asm("cmp r5, r9 ");
+	asm("movgt r9, r5 ");
+	asm("cmp r6, r10 ");
+	asm("movlt r10, r6 ");
+	asm("cmp r7, r11 ");
+	asm("movlt r11, r7 ");
+	asm("stmfd sp!, {r0-r3,r12,lr} ");	// preserve registers across function call
+	asm("bl  " CSM_Z16AllocAnotherRectP7TRegion);
+	asm("ldmfd sp!, {r0-r3} ");
+	asm("ldmeqfd sp!, {r12,lr} ");		// exit if error
+	asm("beq intersection_end ");
+
+	asm("ldr r12, [r0] ");				// r12=iCount
+	asm("ldr lr, [r0, #8] ");			// lr points to first rectangle
+	asm("cmn lr, lr ");
+	asm("ldrcc lr, [r0, #16] ");		// if RRegion
+	asm("addcs lr, r0, #20 ");			// RRegionBuf
+	asm("submi lr, lr, #8 ");			// TRegionFix
+	asm("add lr, lr, r12, lsl #4 ");	// lr=&(iRectangleList[iCount])
+	asm("add r12, r12, #1 ");			// increment iCount
+	asm("str r12, [r0] ");				//
+	asm("stmia lr!, {r8-r11} ");		// append intersection of rectangles
+	asm("ldmfd sp!, {r12,lr} ");		// restore registers
+	asm("intersection3: ");
+	asm("subs r12, r12, #1 ");
+	asm("bne intersection2 ");			// loop for all values of pRect2
+	asm("add r1, r1, #16 ");			// increment pRect1
+	asm("subs r3, r3, #1 ");
+	asm("bne intersection1 ");			// loop for all values of pRect1
+
+	asm("intersection_end: ");
+	__POPRET("r3-r11,");
+	}
+	
+#endif
+
+
+
+
+#ifdef __COBJECT_MACHINE_CODED__
+__NAKED__ EXPORT_C CObject *CObjectIx::At(TInt /*aHandle*/,TInt /*aUniqueID*/)
+/**
+Gets a pointer to the reference counting object with the specified handle
+number and matching unique ID.
+
+@param aHandle   The handle number of the reference counting object.
+@param aUniqueID The unique ID.
+
+@return A pointer to the reference counting object. If there is no matching 
+        object, then this is NULL.
+*/
+	{
+	// r0=this, r1=aHandle, r2=aUniqueID
+	asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iHighWaterMark));	// r3=iHighWaterMark
+	asm("ldr r0, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iObjects));	// r0=iObjects
+	asm("mov r12, r1, lsl #17 ");		// r12=r1<<17 = index(aHandle)<<17
+	asm("cmp r3, r12, lsr #17 ");		// compare iHighWaterMark with index(aHandle)
+	asm("movle r0, #0 ");				// if hwm<=index, return NULL
+	__JUMP(le,lr);
+	asm("add r0, r0, r12, lsr #14 ");	// r0=iObjects+index(Handle)=pS
+	asm("ldr r3, [r0] ");				// r3=pS->uniqueID:pS->instance
+	asm("mov r1, r1, lsl #2 ");			// r1=instance(Handle)<<18
+	asm("mov r1, r1, lsr #18 ");		// r1=instance(Handle)
+	asm("orr r1, r1, r2, lsl #16 ");	// r1=aUniqueID:instance(Handle)
+	asm("cmp r1, r3 ");					// check uniqueID and instance
+	asm("movne r0, #0 ");				// if wrong, return 0
+	asm("ldreq r0, [r0, #4] ");			// else return pointer to CObject
+	__JUMP(,lr);
+	}
+
+
+
+
+__NAKED__ EXPORT_C CObject *CObjectIx::At(TInt aHandle)
+/**
+Gets a pointer to the reference counting object with the specified
+handle number.
+
+@param aHandle The handle number of the reference counting object.
+
+@return A pointer to the reference counting object. If there is no matching 
+        object, then this is NULL.
+*/
+	{
+	// r0=this, r1=aHandle
+	asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iHighWaterMark));	// r3=iHighWaterMark
+	asm("ldr r0, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iObjects));	// r0=iObjects
+	asm("mov r12, r1, lsl #17 ");		// r12=r1<<17 = index(aHandle)<<17
+	asm("cmp r3, r12, lsr #17 ");		// compare iHighWaterMark with index(aHandle)
+	asm("movle r0, #0 ");				// if hwm<=index, return NULL
+	__JUMP(le,lr);
+	asm("add r0, r0, r12, lsr #14 ");	// r0=iObjects+index(Handle)=pS
+	asm("ldr r3, [r0] ");				// r3=pS->uniqueID:pS->instance
+	asm("ldr r2, __instanceMask ");
+	asm("and r1, r1, r2 ");				// r1=instance(Handle)<<16
+	asm("cmp r1, r3, lsl #16 ");		// check instance
+	asm("movne r0, #0 ");				// if wrong, return 0
+	asm("ldreq r0, [r0, #4] ");			// else return pointer to CObject
+	__JUMP(,lr);
+	asm("__instanceMask: ");
+	asm(".word 0x3FFF0000 ");
+	}
+
+
+
+
+GLREF_C void PanicCObjectIxIndexOutOfRange(void);
+
+
+
+
+__NAKED__ EXPORT_C CObject* CObjectIx::operator[](TInt /*anIndex*/)
+/**
+Gets a pointer to a reference counting object located at the specified offset 
+within the object index.
+
+@param anIndex The offset of the reference counting object within the object 
+               index. Offset is relative to zero. 
+               
+@return A pointer to the reference counting object.
+
+@panic E32USER-CBase 21 if the value of anIndex is negative or is greater than
+                        or equal to the total number of objects held by
+                        the index.
+*/
+	{
+	// r0=this, r1=anIndex
+	asm("cmp r1, #0 ");								// check anIndex>=0
+	asm("ldrge r3, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iHighWaterMark));	// if so, r3=iHighWaterMark
+	asm("cmpge r3, r1 ");							// and compare iHighWaterMark to anIndex
+	asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iObjects));	// if OK, r0=iObjects
+	asm("addgt r0, r0, r1, lsl #3 ");				// r0=iObjects+anIndex
+	asm("ldrgt r0, [r0, #4] ");						// r0=pointer to CObject
+#ifdef __CPU_ARMV6
+	asm("ble 1f ");
+	__JUMP(,lr);
+#else
+	__JUMP(gt,lr);
+#endif
+	asm("1: ");
+	asm("b  " CSM_Z29PanicCObjectIxIndexOutOfRangev);	// if anIndex<0 or iCount<=anIndex, panic
+	}
+
+
+
+
+GLREF_C void PanicCObjectConIndexOutOfRange(void);
+GLREF_C void PanicCObjectConFindBadHandle(void);
+GLREF_C void PanicCObjectConFindIndexOutOfRange(void);
+
+
+
+
+__NAKED__ EXPORT_C CObject *CObjectCon::operator[](TInt /*anIndex*/)
+/**
+Gets a pointer to the reference counting object located at the specified offset 
+within the object container.
+
+@param anIndex The offset of the reference counting object within the object 
+               container. Offset is relative to zero.
+
+@return A pointer to the owning reference counting object.
+
+@panic E32USER-CBase 21 if anIndex is negative or is greater than or equal to
+                        the total number of objects held by the container.
+*/
+	{
+	// r0=this, r1=anIndex
+	asm("cmp r1, #0 ");
+	asm("ldrge r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iCount));
+	asm("cmpge r2, r1 ");
+	asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iObjects));
+	asm("ldrgt r0, [r0, r1, lsl #2] ");
+#ifdef __CPU_ARMV6
+	asm("ble 1f ");
+	__JUMP(,lr);
+#else
+	__JUMP(gt,lr);
+#endif
+	asm("1: ");
+	asm("b  " CSM_Z30PanicCObjectConIndexOutOfRangev);
+	}
+
+
+
+
+__NAKED__ EXPORT_C CObject *CObjectCon::At(TInt /*aFindHandle*/) const
+/**
+Gets a pointer to the reference counting object with the specified find-handle 
+number.
+
+A find-handle number is an integer which uniquely identifies a reference
+counting object with respect to its object container.
+
+@param aFindHandle The find-handle number of the reference counting object. 
+                   The unique Id part of this number must be the same as the
+                   unique Id of this container.
+                   The index part of the find-handle number must be
+                   a valid index. 
+
+@return A pointer to the reference counting object.
+
+@panic E32User-CBase 38 if the unique Id part of aFindHandle is not the same as
+                        the unique Id of this container.
+@panic E32User-CBase 39 if the index part of aFindHandle is negative or greater
+                        than or equal to the total number of reference counting
+                        objects held by this object container.
+*/
+	{
+	// r0=this, r1=aFindHandle
+	asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iUniqueID));
+	asm("cmp r2, r1, lsr #16 ");
+	asm("ldreq r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iCount));
+	asm("bne  " CSM_Z28PanicCObjectConFindBadHandlev);
+	asm("mov r1, r1, lsl #17 ");
+	asm("cmp r2, r1, lsr #17 ");
+	asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iObjects));
+	asm("ble  " CSM_Z34PanicCObjectConFindIndexOutOfRangev);
+	asm("ldr r0, [r0, r1, lsr #15] ");
+	__JUMP(,lr);
+	}
+
+
+
+
+__NAKED__ EXPORT_C CObject *CObjectCon::AtL(TInt /*aFindHandle*/) const
+/**
+Gets a pointer to the reference counting object with the specified find-handle 
+number, and leaves on error.
+
+A find-handle number is an integer which uniquely identifies a reference
+counting object with respect to its object container.
+
+@param aFindHandle The find-handle number of the reference counting object. 
+                   The unique Id part of this number must be the same as
+                   the unique Id of this container.
+                   The index part of the find-handle number must be
+                   a valid index. 
+
+@return A pointer to the reference counting object.
+
+@leave KErrBadHandle if the unique Id part of aFindHandle is not the same as
+                     the unique Id of this container.
+@leave KErrArgument if the index part of aFindHandle is negative or greater
+                    than or equal to the total number of reference counting
+                    objects held by this object container.
+*/
+	{
+	// r0=this, r1=aFindHandle
+	asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iUniqueID));
+	asm("cmp r2, r1, lsr #16 ");
+	asm("ldreq r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iCount));
+	asm("bne 1f ");
+	asm("mov r1, r1, lsl #17 ");
+	asm("cmp r2, r1, lsr #17 ");
+	asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iObjects));
+	asm("ble 2f ");
+	asm("ldr r0, [r0, r1, lsr #15] ");
+	__JUMP(,lr);
+	// User::Leave tail called, so no annotations required since
+	// current frame is reused by User::Leave
+	asm("1: ");
+	asm("mvn r0, #7 "); // KErrBadHandle
+	asm("b  " CSM_ZN4User5LeaveEi);
+	asm("2: ");
+	asm("mvn r0, #5 "); // KErrArgument
+	asm("b  " CSM_ZN4User5LeaveEi);
+	}
+#endif
+
+#ifdef __CACTIVESCHEDULER_MACHINE_CODED__
+extern "C" void PanicStrayEvent();
+
+/**
+@internalComponent
+
+The inner active scheduler loop. This repeatedly waits for a signal and then
+dispatches the highest priority ready active object. The loop terminates either
+if one of the RunL()s stops the current active scheduler level or leaves.
+
+Stop when aLoop becomes 'Inactive'
+*/
+__NAKED__ void CActiveScheduler::DoRunL(TLoopOwner* const volatile& aLoop, CActive* volatile & aCurrentObj, TCleanupBundle* aCleanupBundlePtr)
+	{
+	asm("stmfd sp!, {r4-r8,lr} ");
+	__EH_FRAME_PUSH2(r4-r8,lr)
+	
+#ifdef _DEBUG
+	// need to copy aCleanupBundlePtr to somewhere else before it's clobbered by the next line.
+	asm("mov r8, r3 ");														// r8 = &aCleanupBundlePtr
+#endif
+	
+	asm("ldr r3, [r0, #%a0]" : : "i" (_CBASE_VPTR_OFFSET_));				// r3 = vptr
+	asm("add r4, r0, #%a0" : : "i" _FOFF(CActiveScheduler,iActiveQ));		// r4 = &iActiveQ
+	asm("mov r5, r1 ");														// r5 = &aLoop
+	asm("mov r7, r2 ");														// r7 = &aCurrentObj
+	asm("ldr r6, [r3, #%a0]" : : "i" (_CACTIVESCHEDULER_WAIT_OFFSET_));		// r6 = &WaitForAnyRequest()
+
+	asm("active_scheduler_loop: ");
+	asm("ldr r1, [r5] ");													// r1 = aLoop
+	asm("adr lr, 1f ");														// return address
+	asm("sub r0, r4, #%a0 " : : "i" _FOFF(CActiveScheduler,iActiveQ));		// this
+	asm("cmp r1, #0 ");
+	__JUMP(ne, r6);															// call WaitForAnyRequest() if still active
+	__POPRET("r4-r8,");														// else return
+
+	// get here when WaitForAnyRequest() returns
+	asm("1: ");
+	asm("ldr r14, [r4, #0] ");												// r14->first active object
+
+	asm("2: ");
+	asm("cmp r14, r4 ");													// end of queue?
+	asm("sub r0, r14, #%a0" : : "i" _FOFF(CActive,iLink));					// r0->CActive
+	asm("ldmneda r14, {r2, r12, r14} ");									// r2=iStatus, r12=iStatus.iFlags (old iActive), r14 = next object
+	asm("beq PanicStrayEvent ");											// if end of queue, panic
+#ifdef _DEBUG
+	asm("ands r3, r12, #%a0" : : "i" ((TInt)(TRequestStatus::EActive|TRequestStatus::ERequestPending)));	// only active bit and request-pending bit
+	asm("cmpne r3, #%a0" : : "i" ((TInt)(TRequestStatus::EActive|TRequestStatus::ERequestPending)));		// active bit == request pending bit
+	asm("bne PanicStrayEvent ");											// if active bit != request pending bit, panic
+#endif
+	asm("cmp r2, #%a0" : : "i" ((TInt)KRequestPending));					// test if iStatus!=KRequestPending
+	asm("andnes r3, r12, #%a0" : : "i" ((TInt)TRequestStatus::EActive));	// if so, test iActive
+	asm("beq 2b ");															// if not active or still pending, do next CActive
+
+	// have an active object to run
+#ifdef __SMP__
+	__DATA_MEMORY_BARRIER_Z__(r3);											// acquire semantics
+#endif
+	asm("ldr r3, [r0, #%a0]" : : "i" (_CBASE_VPTR_OFFSET_));				// r3=CActive->vptr
+	asm("bic r12, r12, #%a0" : : "i" ((TInt)(TRequestStatus::EActive|TRequestStatus::ERequestPending)));
+	asm("ldr r3, [r3, #%a0]" : : "i" (_CACTIVE_RUNL_OFFSET_));				// r3 = &CActive::RunL()
+	asm("str r12, [r0, #%a0]" : : "i" (_FOFF(CActive,iStatus)+_FOFF(TRequestStatus,iFlags)));	// iActive=EFalse
+	asm("str r0, [r7] ");													// save active object in aCurrentObj in case RunL leaves
+#ifdef _DEBUG
+	__JUMPL(3);															// call RunL() (and continue)
+#else
+	asm("adr lr, active_scheduler_loop ");								// set lr (return address) to label, active_scheduler_loop
+	__JUMP(,r3);														// call RunL() (and loop)
+#endif
+	
+	
+#ifdef _DEBUG
+	//check whether there's a cleanup stack installed:
+
+	asm("cmp r8, #0");															// check CleanupBundle* == NULL
+	asm("beq active_scheduler_loop ");											// If r8 == NULL, branch to label, active_scheduler_loop
+	asm("ldr r0, [r8, #%a0]" : : "i" _FOFF(TCleanupBundle,iCleanupPtr)); 		// r0 = CCleanup* (load the CCleanup*)
+
+	//there is a cleanupstack installed:
+	asm("add r1, r8, #%a0" : : "i" _FOFF(TCleanupBundle,iDummyInt)); 			// r1 = iDummyInt* (load the TInt*)
+	asm("adr lr, active_scheduler_loop ");										// set lr (return address) to label, active_scheduler_loop
+	asm("b  " CSM_ZN8CCleanup5CheckEPv); 										// call CCleanup::Check(iDummyInt*)
+#endif
+	
+	}
+#endif
+
+
+#ifdef __CSERVER_MACHINE_CODED__
+__NAKED__ EXPORT_C void CServer2::RunL()
+	{
+	asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(CServer2,iMessage.iFunction)); // r2=Message().Function()
+	asm("stmfd sp!, {r4, lr}");			// save regs
+	__EH_FRAME_PUSH2(r4,lr)
+	asm("cmp r2, #0");					// check for Connect/Disconnect message
+	asm("bmi server2_con_dis");
+
+	// Service the message
+	asm("mov r4, r0 ");						// r4=this
+	asm("ldr r0, [r4, #%a0]" : : "i" _FOFF(CServer2,iMessage.iSessionPtr)); // r0=session
+	asm("add r1, r4, #%a0" : : "i" (_FOFF(CServer2,iMessage)));	// r1=&iServer.Message()
+	asm("cmp r0, #0");  // Check for NULL session
+	asm("ldrne r12, [r0, #%a0]" : : "i" (_CBASE_VPTR_OFFSET_));			// r12=CSession2::vptr
+#ifdef __SUPPORT_THUMB_INTERWORKING
+	asm("ldrne r3, [r12, #%a0]" : : "i" (_CSESSION2_SERVICEL_OFFSET_));	// call CSession2::ServiceL(iMessage)
+	asm("adr lr, server2_run_postamble ");
+	asm("bxne r3 ");
+#else
+	asm("adr lr, server2_run_postamble ");
+	asm("ldrne pc, [r12, #%a0]" : : "i" (_CSESSION2_SERVICEL_OFFSET_));	// call CSession2::ServiceL(iMessage)
+#endif
+	asm("mov r0, r1");
+	asm("b  " CSM_ZN8CServer212NotConnectedERK9RMessage2); // NULL session ptr means not connected
+
+	// Do this after processing any message
+	asm("server2_run_postamble: ");
+	asm("ldr r2, [r4, #%a0]" : : "i" (_FOFF(CServer2,iStatus)+_FOFF(TRequestStatus,iFlags)));	// r2=iStatus.iFlags (old iActive)
+	asm("mov r0, #0x80000001 ");								// r0=KRequestPending
+	asm("ands r1, r2, #%a0" : : "i" ((TInt)TRequestStatus::EActive));
+	asm("bne server2_run_end ");							// if already active, finished
+	asm("orr r2, r2, #%a0" : : "i" ((TInt)(TRequestStatus::EActive|TRequestStatus::ERequestPending)));
+	asm("add r1, r4, #%a0" : : "i" _FOFF(CActive,iStatus));		// r1->iStatus
+	asm("stmia r1, {r0,r2} "); // set iStatus=KRequestPending, set active bit, set request pending bit
+	asm("add r2, r4, #%a0" : : "i" _FOFF(CServer2,iMessage));	// r2->iServer.Message()
+	asm("ldr r0, [r4, #%a0]" : : "i" _FOFF(CServer2,iServer));	// r0=iServer.iHandle
+	asm("bl  " CSM_ZN4Exec13ServerReceiveEiR14TRequestStatusPv);// call Exec::ServerReceive
+	asm("server2_run_end: ");
+	__POPRET("r4,");
+
+	// Deal with Connect and Disconnect messages
+	asm("server2_con_dis:");	
+	asm("mov r4, r0 ");					// r4=this
+	asm("add r1, r0, #%a0" : : "i" _FOFF(CServer2,iMessage)); // r1=&iServer.Message()
+	asm("adr lr, server2_run_postamble "); // return address for after any processing
+	asm("cmp r2, #%a0" : : "i" (RMessage2::EConnect));
+	asm("beq  " CSM_ZN8CServer27ConnectERK9RMessage2); // Do Connect()
+	asm("cmp r2, #%a0" : : "i" (RMessage2::EDisConnect));
+	asm("beq  " CSM_ZN8CServer210DisconnectERK9RMessage2); // Do Disconnect()
+	asm("mov r0, r1");
+	asm("b  " CSM_ZN8CServer210BadMessageERK9RMessage2); // Bad message
+	}
+#endif
+
+EXPORT_C __NAKED__ void RFastLock::Wait()
+	{
+	asm("1: ");
+	asm("add	r0, r0, #4 ");					// point to iCount
+
+#ifdef __CPU_ARM_HAS_LDREX_STREX
+	asm("2:		");
+	LDREX(		2, 0);							// read
+	asm("subs	r1, r2, #1 ");					// decrement
+	STREX(		3, 1, 0);						// write
+	asm("teq	r3, #0 ");						// success?
+	asm("bne	2b ");							// no!
+	asm("sub	r0, r0, #4 ");					// r0 = this
+	asm("bcs "	CSM_ZN10RSemaphore4WaitEv);		// if no borrow from decrement wait on semaphore
+#ifdef __SMP__
+	__DATA_MEMORY_BARRIER__(r3);				// no need to wait, but still need acquire barrier
+#endif
+	__JUMP(,	lr );
+#else
+	asm("mov	r1, #1 ");						// 'looking' value
+	asm("swp	r1, r1, [r0] ");				// write looking value, read original
+	asm("subs	r1, r1, #1 ");					// decrement count
+	asm("strlt	r1, [r0] ");					// if it becomes negative, no-one was looking
+	__JUMP(cc,	lr);							// if borrow, was originally zero so we are finished
+	asm("sub	r0, r0, #4 ");					// r0=this
+	asm("blt "	CSM_ZN10RSemaphore4WaitEv);		// lock held so wait on semaphore
+	asm("stmfd	sp!, {r0,lr} ");				// otherwise save registers
+	asm("mov	r0, #1000 ");					// someone was looking, so wait 1ms and try again
+	asm("bl "	CSM_ZN4User12AfterHighResE27TTimeIntervalMicroSeconds32);
+	asm("ldmfd	sp!, {r0,lr} ");
+	asm("b		1b ");
+#endif
+	}
+
+EXPORT_C __NAKED__ void RFastLock::Signal()
+	{
+	asm("1: ");
+	asm("add	r0, r0, #4 ");					// point to iCount
+
+#ifdef __CPU_ARM_HAS_LDREX_STREX
+#ifdef __SMP__
+	__DATA_MEMORY_BARRIER_Z__(r3);				// need release barrier
+#endif
+	asm("2:		");
+	LDREX(		2, 0);							// read
+	asm("adds	r1, r2, #1 ");					// increment
+	STREX(		3, 1, 0);						// write
+	asm("teq	r3, #0 ");						// success?
+	asm("bne	2b ");							// no!
+	asm("sub	r0, r0, #4 ");					// r0 = this
+	asm("bcc "	CSM_ZN10RSemaphore6SignalEv);	// if no carry from increment, signal semaphore
+	__JUMP(,	lr );
+#else
+	asm("mov	r1, #1 ");						// 'looking' value
+	asm("swp	r1, r1, [r0] ");				// write looking value, read original
+	asm("adds	r1, r1, #1 ");					// increment count
+	asm("strle	r1, [r0] ");					// if still <=0, no-one was looking
+	__JUMP(eq,	lr);							// if it's now zero, no-one is waiting so we are finished
+	asm("sub	r0, r0, #4 ");					// r0=this
+	asm("blt "	CSM_ZN10RSemaphore6SignalEv);	// someone is waiting so signal semaphore
+	asm("stmfd	sp!, {r0,lr} ");				// otherwise save registers
+	asm("mov	r0, #1000 ");					// someone was looking, so wait 1ms and try again
+	asm("bl "	CSM_ZN4User12AfterHighResE27TTimeIntervalMicroSeconds32);
+	asm("ldmfd	sp!, {r0,lr} ");
+	asm("b		1b ");
+#endif
+	}
+
+
+// Entry point stub to allow EKA1 binaries to be executed under EKA2
+// Only called when process is first loaded
+
+extern "C" TLinAddr GetEka1ExeEntryPoint();
+
+__NAKED__ TInt E32Loader::V7ExeEntryStub()
+	{
+	// Process entry point
+	// R4 = entry reason
+	// SP points to information block
+	asm("cmp r4, #%a0" : : "i" ((TInt)KModuleEntryReasonProcessInit) );
+	asm("bne " CSM_ZN4User9InvariantEv );	// invalid entry reason
+	asm("bl GetEka1ExeEntryPoint ");		// load the entry stub and return its address
+	__JUMP(,r0);							// jump to the entry stub with R4, SP unchanged
+	}
+
+__NAKED__ TInt E32Loader::V7DllEntryStub(TInt)
+	{
+
+	__JUMP(,lr);
+	}
+
+
+// Hash an 8 bit string at aPtr, length aLen bytes.
+__NAKED__ TUint32 DefaultStringHash(const TUint8* /*aPtr*/, TInt /*aLen*/)
+	{
+	asm("ldr r3, one_over_phi ");
+	asm("subs r1, r1, #4 ");
+	asm("mov r2, r0 ");
+	asm("mov r0, #0 ");
+	asm("blo 1f ");
+	asm("ands r12, r2, #3 ");
+	asm("bne hash_unal ");
+	asm("2: ");
+	asm("ldr r12, [r2], #4 ");
+	asm("subs r1, r1, #4 ");
+	asm("eor r0, r0, r12 ");
+	asm("umull r0, r12, r3, r0 ");
+	asm("bcs 2b ");
+	asm("1: ");
+	asm("adds r1, r1, #4 ");
+	__JUMP(eq,lr);
+	asm("4: ");
+	asm("ldrb r12, [r2], #1 ");
+	asm("cmp r1, #2 ");
+	asm("eor r0, r0, r12 ");
+	asm("ldrcsb r12, [r2], #1 ");
+	asm("eorcs r0, r0, r12, lsl #8 ");
+	asm("ldrhib r12, [r2], #1 ");
+	asm("eorhi r0, r0, r12, lsl #16 ");
+	asm("umull r0, r12, r3, r0 ");
+	__JUMP(,lr);
+
+	asm("hash_unal: ");
+	asm("bic r2, r2, #3 ");
+	asm("stmfd sp!, {r4,r5,lr} ");
+	asm("mov r12, r12, lsl #3 ");
+	asm("rsb r14, r12, #32 ");
+	asm("ldr r4, [r2], #4 ");
+	asm("3: ");
+	asm("eor r0, r0, r4, lsr r12 ");
+	asm("ldr r4, [r2], #4 ");
+	asm("subs r1, r1, #4 ");
+	asm("eor r0, r0, r4, lsl r14 ");
+	asm("umull r0, r5, r3, r0 ");
+	asm("bcs 3b ");
+	asm("adds r1, r1, #4 ");
+	asm("ldmfd sp!, {r4,r5,lr} ");
+	asm("subne r2, r2, #4 ");
+	asm("addne r2, r2, r12, lsr #3 ");
+	asm("bne 4b ");
+	__JUMP(,lr);
+	}
+
+// Hash a 16 bit string at aPtr, length aLen bytes.
+__NAKED__ TUint32 DefaultWStringHash(const TUint16* /*aPtr*/, TInt /*aLen*/)
+	{
+	asm("str lr, [sp, #-4]! ");
+	asm("ldr r3, one_over_phi ");
+	asm("subs r1, r1, #8 ");
+	asm("mov r2, r0 ");
+	asm("mov r0, #0 ");
+	asm("blo 1f ");
+	asm("ands r12, r2, #3 ");
+	asm("bne whash_unal ");
+	asm("2: ");
+	asm("ldmia r2!, {r12,r14} ");
+	asm("subs r1, r1, #8 ");
+	asm("eor r0, r0, r12 ");
+	asm("eor r0, r0, r14, ror #24 ");
+	asm("umull r0, r12, r3, r0 ");
+	asm("bcs 2b ");
+	asm("1: ");
+	asm("adds r1, r1, #8 ");
+	asm("beq 8f ");
+	asm("4: ");
+	asm("ldrh r12, [r2], #2 ");
+	asm("cmp r1, #4 ");
+	asm("eor r0, r0, r12 ");
+	asm("ldrcsh r12, [r2], #2 ");
+	asm("eorcs r0, r0, r12, lsl #16 ");
+	asm("ldrhih r12, [r2], #2 ");
+	asm("eorhi r0, r0, r12, ror #24 ");
+	asm("umull r0, r12, r3, r0 ");
+	asm("8: ");
+	__POPRET("");
+
+	asm("whash_unal: ");
+	asm("add r2, r2, #2 ");				// r2 must be 2 mod 4
+	asm("ldr r14, [r2, #-4] ");
+	asm("3: ");
+	asm("eor r0, r0, r14, lsr #16 ");	// char 0 goes into bytes 0,1
+	asm("ldmia r2!, {r12,r14} ");
+	asm("subs r1, r1, #8 ");
+	asm("eor r0, r0, r12, lsl #16 ");	// char 1 goes into bytes 2,3
+	asm("mov r12, r12, lsr #16 ");
+	asm("orr r12, r12, r14, lsl #16 ");	// r12 = char3:char2
+	asm("eor r0, r0, r12, ror #24 ");	// char 2 into bytes 1,2 ; char 3 into bytes 3,0
+	asm("umull r0, r12, r3, r0 ");
+	asm("bcs 3b ");
+	asm("adds r1, r1, #8 ");
+	asm("subne r2, r2, #2 ");
+	asm("bne 4b ");
+	__POPRET("");
+	}
+
+
+/**
+@publishedAll
+@released
+
+Calculate a 32 bit hash from a 32 bit integer.
+
+@param	aInt	The integer to be hashed.
+@return			The calculated 32 bit hash value.
+*/
+EXPORT_C __NAKED__ TUint32 DefaultHash::Integer(const TInt& /*aInt*/)
+	{
+	asm("ldr r0, [r0] ");
+	asm("ldr r1, one_over_phi ");
+	asm("umull r0, r2, r1, r0 ");
+	__JUMP(,lr);
+	asm("one_over_phi: ");
+	asm(".word 0x9e3779b9 ");
+	}
+
+
+#ifdef __USERSIDE_THREAD_DATA__
+
+/**
+@internalComponent
+
+Get a pointer to the thread local user data stored in the thread ID register.
+*/
+__NAKED__ TLocalThreadData* LocalThreadData()
+	{
+	GET_RWRW_TID(,r0);
+	__JUMP(,lr);	
+	}
+
+#endif