os/kernelhwsrv/kernel/eka/euser/epoc/arm/uc_utl.cia
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32\euser\epoc\arm\uc_utl.cia
    15 // 
    16 //
    17 
    18 #include <e32cia.h>
    19 #include <u32std.h>
    20 #include <e32base.h>
    21 #include <e32rom.h>
    22 #include <e32svr.h>
    23 #include <e32hashtab.h>
    24 #include <u32exec.h>
    25 #include "uc_std.h"
    26 
    27 
    28 #if defined(__MEM_MACHINE_CODED__)
    29 EXPORT_C __NAKED__ void Mem::Swap(TAny* /*aPtr1*/, TAny* /*aPtr2*/, TInt /*aLength*/)
    30 /**
    31 Swaps a number of bytes of data between two specified locations.
    32 
    33 The source and target areas can overlap.
    34 
    35 @param aPtr1   A pointer to the first location taking part in the swap. 
    36 @param aPtr2   A pointer to second location taking part in the swap. 
    37 @param aLength The number of bytes to be swapped between the two locations. 
    38                This value must not be negative.
    39 
    40 @panic USER 94 In debug builds only, if aLength is negative.
    41 */
    42     {
    43 
    44     asm("   cmp      r0,r1");
    45     asm("   cmpne    r2,#0");
    46 	__JUMP(eq,lr);
    47 //
    48 // Test for same alignment, if more than 16 bytes to swap
    49 //
    50     asm("   and      r3,r0,#3");
    51     asm("   and      ip,r1,#3");
    52     asm("   cmp      r2,#16");
    53     asm("   addlt    r3,r3,#4");
    54     asm("   cmp      r3,ip");
    55     asm("   beq      same_aligned_swap");
    56 
    57     asm("   stmfd    sp!,{r4,lr}");
    58 
    59     asm("swap_loop:");
    60 
    61     asm("   ldrb     r3,[r0]");
    62     asm("   ldrb     r4,[r1]");
    63     asm("   strb     r3,[r1],#1");
    64     asm("   strb     r4,[r0],#1");
    65     asm("   subs     r2,r2,#1");
    66 	asm("beq swap_exit1 ");
    67 
    68     asm("   ldrb     r3,[r0]");
    69     asm("   ldrb     r4,[r1]");
    70     asm("   strb     r3,[r1],#1");
    71     asm("   strb     r4,[r0],#1");
    72     asm("   subs     r2,r2,#1");
    73 	asm("beq swap_exit1 ");
    74 
    75     asm("   ldrb     r3,[r0]");
    76     asm("   ldrb     r4,[r1]");
    77     asm("   strb     r3,[r1],#1");
    78     asm("   strb     r4,[r0],#1");
    79     asm("   subs     r2,r2,#1");
    80 	asm("beq swap_exit1 ");
    81 
    82     asm("   ldrb     r3,[r0]");
    83     asm("   ldrb     r4,[r1]");
    84     asm("   strb     r3,[r1],#1");
    85     asm("   strb     r4,[r0],#1");
    86     asm("   subs     r2,r2,#1");
    87     asm("   bne      swap_loop");
    88 	asm("swap_exit1: ");
    89 	__POPRET("r4,");
    90 
    91     asm("same_aligned_swap:");
    92 
    93     asm("   stmfd    sp!,{r4-r10,lr}");
    94 //
    95 // r3 contains the byte offset from word alignment, 0,1,2 or 3
    96 // subtract 1 to get -1,0,1 or 2, and if -1 make it 3
    97 // that gives us 0,1,2 or 3 if the alignment is 3,2,1 or 0 respectively
    98 // We can use that to jump directly to the appropriate place for
    99 // swapping the relevent number of bytes to achieve word alignment
   100 // r4 is set to 3-r3 to correct the length for the number of bytes
   101 // swapped
   102 //
   103     asm("   subs     r3,r3,#1");
   104     asm("   movmi    r3,#3");
   105     asm("   rsb      r4,r3,#3");
   106     asm("   sub      r2,r2,r4");
   107 	asm("   add      pc,pc,r3,asl #4");
   108 	asm("	nop ");	// never executed
   109 //
   110 // Jumps here if 3 bytes to swap before word aligned
   111 //
   112     asm("   ldrb     r4,[r0]");
   113     asm("   ldrb     ip,[r1]");
   114     asm("   strb     r4,[r1],#1");
   115     asm("   strb     ip,[r0],#1");
   116 //
   117 // Jumps here if 2 bytes to swap before word aligned
   118 //
   119     asm("   ldrb     r4,[r0]");
   120     asm("   ldrb     ip,[r1]");
   121     asm("   strb     r4,[r1],#1");
   122     asm("   strb     ip,[r0],#1");
   123 //
   124 // Jumps here if 1 byte to swap before word aligned
   125 //
   126     asm("   ldrb     r4,[r0]");
   127     asm("   ldrb     ip,[r1]");
   128     asm("   strb     r4,[r1],#1");
   129     asm("   strb     ip,[r0],#1");
   130 //
   131 // We are now word aligned. Fast swapping, here we come...
   132 //
   133     asm("word_aligned_swap:");
   134     asm("   movs     ip,r2,lsr #6"); // Number of 64 blocks to swap
   135     asm("   beq      its_smaller_swap");
   136 
   137     asm("swap_64_bytes:");
   138     asm("   ldmia    r1,{r3-r6}");
   139     asm("   ldmia    r0,{r7-r10}");
   140     asm("   stmia    r1!,{r7-r10}");
   141     asm("   stmia    r0!,{r3-r6}");
   142     asm("   ldmia    r1,{r3-r6}");
   143     asm("   ldmia    r0,{r7-r10}");
   144     asm("   stmia    r1!,{r7-r10}");
   145     asm("   stmia    r0!,{r3-r6}");
   146     asm("   ldmia    r1,{r3-r6}");
   147     asm("   ldmia    r0,{r7-r10}");
   148     asm("   stmia    r1!,{r7-r10}");
   149     asm("   stmia    r0!,{r3-r6}");
   150     asm("   ldmia    r1,{r3-r6}");
   151     asm("   ldmia    r0,{r7-r10}");
   152     asm("   stmia    r1!,{r7-r10}");
   153     asm("   stmia    r0!,{r3-r6}");
   154     asm("   subs     ip,ip,#1");
   155     asm("   bne      swap_64_bytes");
   156 //
   157 // Less than 64 bytes to go...
   158 //
   159     asm("its_smaller_swap:");
   160     asm("   ands     r2,r2,#63");
   161 	asm("beq swap_exit2 ");
   162     asm("   cmp      r2,#4");
   163     asm("   blt      finish_swap");
   164     asm("final_swap_loop:");
   165     asm("   ldr      r3,[r1]");
   166     asm("   ldr      ip,[r0]");
   167     asm("   str      r3,[r0],#4");
   168     asm("   str      ip,[r1],#4");
   169     asm("   subs     r2,r2,#4");
   170     asm("   cmp      r2,#4");
   171     asm("   bge      final_swap_loop");
   172 //
   173 // Less than 4 bytes to go...
   174 //
   175     asm("finish_swap:");
   176     asm("   tst      r2,#2");
   177     asm("   ldrneb   r3,[r0]");
   178     asm("   ldrneb   ip,[r1]");
   179     asm("   strneb   r3,[r1],#1");
   180     asm("   strneb   ip,[r0],#1");
   181     asm("   ldrneb   r3,[r0]");
   182     asm("   ldrneb   ip,[r1]");
   183     asm("   strneb   r3,[r1],#1");
   184     asm("   strneb   ip,[r0],#1");
   185 
   186     asm("   tst      r2,#1");
   187     asm("   ldrneb   r3,[r0]");
   188     asm("   ldrneb   ip,[r1]");
   189     asm("   strneb   r3,[r1],#1");
   190     asm("   strneb   ip,[r0],#1");
   191 
   192 	asm("swap_exit2: ");
   193 	__POPRET("r4-r10,");
   194     }
   195 #endif
   196 
   197 #ifdef __REGIONS_MACHINE_CODED__
   198 
   199 __NAKED__ GLDEF_C void AllocAnotherRect( TRegion * /*aRegion*/ )
   200 	{
   201 	// Returns with Z flag set to indicate error
   202 	
   203 	asm("ldr r1, [r0, #4] ");			// r1=iError
   204 	asm("cmp r1, #0 ");
   205 	asm("bne return_error ");
   206 	asm("ldr r1, [r0, #8] ");			// r1=iAllocedRects
   207 	asm("ldr r12, [r0] ");				// r12=iCount
   208 	asm("tst r1, #0x40000000 ");		// test ERRegionBuf
   209 	asm("beq allocanother1 ");			// don't branch if TRegionFix
   210 	asm("cmn r1, r12 ");				// test if iCount==-iAllocedRects
   211 	__JUMP(ne,lr);
   212 	asm("b  " CSM_ZN7TRegion10ForceErrorEv);		// if so, ForceError()
   213 	asm("allocanother1: ");
   214 	asm("cmp r1, #0 ");
   215 	asm("bpl allocanother3 ");			// branch if RRegion, continue if RRegionBuf
   216 	asm("orr r2, r1, #0x40000000 ");	// r2=iAllocedRects|ERRegionBuf
   217 	asm("cmn r2, r12 ");				// check if iCount==(-(iAllocedRects|ERRegionBuf))
   218 	__JUMP(ne,lr);
   219 	asm("ldr r2, [r0, #12] ");			// r2=iGranularity
   220 	asm("add r1, r12, r2 ");			// iAllocedRects=iCount+iGranularity - change into RRegion
   221 	asm("str r1, [r0, #8] ");
   222 	asm("stmfd sp!, {r0,r1,r12,lr} ");	// save registers used in function call
   223 	asm("mov r0, r1, lsl #4 ");			// number of bytes to allocate
   224 	asm("bl  " CSM_ZN4User5AllocEi);			// User::Alloc
   225 	asm("movs r2, r0 ");				// returned pointer into r2
   226 	asm("ldmfd sp!, {r0,r1,r12,lr} ");	// restore registers
   227 	asm("add r3, r0, #20 ");			// r3=address of first rectangle
   228 	asm("str r2, [r0, #16] ");			// iRectangleList=returned pointer
   229 	asm("beq  " CSM_ZN7TRegion10ForceErrorEv);	// if pointer null, ForceError()
   230 	asm("cmp r12, #0 ");
   231 	asm("beq return_success ");
   232 	asm("stmfd sp!, {r4,r5} ");
   233 	asm("allocanother2: ");
   234 	asm("ldmia r3!, {r0,r1,r4,r5} ");	// copy data to new area
   235 	asm("subs r12, r12, #1 ");
   236 	asm("stmia r2!, {r0,r1,r4,r5} ");
   237 	asm("bne allocanother2 ");
   238 	asm("ldmfd sp!, {r4,r5} ");
   239 	asm("return_success: ");
   240 	asm("movs r0, #1 ");				// clear Z flag to indicate success
   241 	__JUMP(,lr);
   242 	asm("allocanother3: ");				// come here if RRegion
   243 	asm("cmp r1, r12 ");				// check if iCount==iAllocedRects
   244 	__JUMP(ne,lr);
   245 	asm("ldr r2, [r0, #12] ");			// r2 = iGranularity
   246 	asm("add r1, r1, r2 ");				// iAllocedRects+=iGranularity
   247 	asm("str r1, [r0, #8] ");
   248 	asm("stmfd sp!, {r0,lr} ");			// preserve r0,lr across function call
   249 	asm("ldr r0, [r0, #16] ");			// r0=address of current cell
   250 	asm("mov r1, r1, lsl #4 ");			// r1=number of bytes to allocate
   251 	asm("mov r2, #0 ");
   252 	asm("bl  " CSM_ZN4User7ReAllocEPvii);		// User::ReAlloc
   253 	asm("movs r2, r0 ");				// returned pointer into r2
   254 	asm("ldmfd sp!, {r0,lr} ");			// restore r0,lr
   255 	asm("strne r2, [r0, #16] ");		// if returned ptr not null, iRectangleList=returned ptr
   256 	__JUMP(ne,lr);
   257 	asm("b  " CSM_ZN7TRegion10ForceErrorEv);		// else ForceError()
   258 	}
   259 
   260 
   261 __NAKED__ EXPORT_C void TRegion::ForceError()
   262 	{
   263 	// Returns with Z flag set to indicate error
   264 	
   265 	asm("stmfd sp!, {r0,lr} ");
   266 	asm("bl " CSM_ZN7TRegion5ClearEv);	// Clear()
   267 	asm("ldmfd sp!, {r0,lr} ");			// restore r0,lr
   268 	asm("mov r1, #1 ");
   269 	asm("str r1, [r0, #4] ");			// iError=ETrue
   270 	asm("return_error: ");
   271 	asm("movs r0, #0 ");				// set Z flag to indicate error
   272 	__JUMP(,lr);
   273 	}
   274 
   275 
   276 
   277 __NAKED__ EXPORT_C TRect TRegion::BoundingRect() const
   278 /**
   279 Gets the minimal rectangle that bounds the entire region.
   280 
   281 @return The region's minimal bounding rectangle.
   282 */
   283 	{
   284 	asm("ldr r2, [r1] ");			// r2=iCount
   285 	asm("cmp r2, #0 ");				// list empty?
   286 	asm("beq boundingrect0 ");		// branch if empty
   287 	asm("ldr r3, [r1, #8] ");			// if not empty, r3 points to first rectangle
   288 	asm("stmfd sp!, {r4-r8,lr} ");
   289 	asm("cmn r3, r3 ");
   290 	asm("ldrcc r3, [r1, #16] ");		// if RRegion
   291 	asm("addcs r3, r1, #20 ");			// RRegionBuf
   292 	asm("submi r3, r3, #8 ");			// TRegionFix
   293 	asm("ldmia r3!, {r4-r7} ");			// if not empty bounds = first rectangle
   294 	asm("b boundingrect2 ");			// if not empty go and check rest of list
   295 	asm("boundingrect1: ");
   296 	asm("ldmia r3!, {r1,r8,r12,lr} ");	// fetch next rectangle
   297 	asm("cmp r1, r4 ");					// if next.iTl.iX<bounds.iTl.iX
   298 	asm("movlt r4, r1 ");				//		bounds.iTl.iX=next.iTl.iX
   299 	asm("cmp r8, r5 ");					// if next.iTl.iY<bounds.iTl.iY
   300 	asm("movlt r5, r8 ");				//		bounds.iTl.iY=next.iTl.iY
   301 	asm("cmp r12, r6 ");				// if next.iBr.iX>bounds.iBr.iX
   302 	asm("movgt r6, r12 ");				//		bounds.iBr.iX=next.iBr.iX
   303 	asm("cmp lr, r7 ");					// if next.iBr.iY>bounds.iBr.iY
   304 	asm("movgt r7, lr ");				//		bounds.iBr.iY=next.iBr.iY
   305 	asm("boundingrect2: ");
   306 	asm("subs r2, r2, #1 ");			// decrement count
   307 	asm("bne boundingrect1 ");			// repeat for all rectangles
   308 	asm("stmia r0, {r4-r7} ");			// store result
   309 	__POPRET("r4-r8,");
   310 
   311 	asm("boundingrect0: ");
   312 	asm("mov r1, #0 ");					// if list empty, bounds = 0,0,0,0
   313 	asm("mov r3, #0 ");
   314 	asm("mov r12, #0 ");
   315 	asm("stmia r0, {r1,r2,r3,r12} ");	// store result
   316 	__JUMP(,lr);
   317 	}
   318 
   319 
   320 
   321 
   322 __NAKED__ EXPORT_C TBool TRegion::IsContainedBy(const TRect & /*aRect*/) const
   323 /**
   324 Tests whether the region is fully enclosed within the specified rectangle.
   325 
   326 @param aRect The specified rectangle.
   327  
   328 @return True, if the region is fully enclosed within the rectangle (their sides 
   329         may touch); false, otherwise.
   330 */
   331 	{
   332 	asm("ldr r12, [r0, #8] ");			// r12 points to first rectangle
   333 	asm("stmfd sp!, {r4-r7,lr} ");	
   334 	asm("cmn r12, r12 ");
   335 	asm("ldrcc r12, [r0, #16] ");		// if RRegion
   336 	asm("addcs r12, r0, #20 ");			// RRegionBuf
   337 	asm("submi r12, r12, #8 ");			// TRegionFix
   338 
   339 	asm("ldr r0, [r0] ");				// r0=iCount
   340 	asm("ldmia r1, {r4-r7} ");			// aRect coordinates into r4-r7
   341 	
   342 	asm("subs r0, r0, #1 ");			// decrement it
   343 	asm("bmi iscontainedby2 ");			// if iCount was zero, return TRUE
   344 	
   345 	asm("iscontainedby1: ");
   346 	asm("ldmia r12!, {r1,r2,r3,lr} ");	// coordinates of next rectangle
   347 	asm("cmp r1, r4 ");					// compare next.iTl.iX with aRect.iTl.iX
   348 	asm("cmpge r2, r5 ");				// if >=, compare next.iTl.iY with aRect.iTl.iY
   349 	asm("cmpge r6, r3 ");				// if >=, compare aRect.Br.iX with next.iBr.iX
   350 	asm("cmpge r7, lr ");				// if >=, compare aRect.Br.iY with next.iBr.iY
   351 	asm("subges r0, r0, #1 ");			// if >=, next is contained in aRect, so iterate
   352 	asm("bge iscontainedby1 ");			// will drop through if r0<0 or if next exceeds aRect
   353 	asm("iscontainedby2: ");
   354 	asm("mov r0, r0, lsr #31 ");		// return 1 if r0<0, 0 if r0>=0
   355 	__POPRET("r4-r7,");
   356 	}
   357 
   358 
   359 
   360 
   361 __NAKED__ EXPORT_C void TRegion::Copy(const TRegion & /*aRegion*/)
   362 /**
   363 Copies another region to this region.
   364 
   365 The state of the specified region's error flag is also copied.
   366 
   367 @param aRegion The region to be copied.
   368 */
   369 	{
   370 	asm("ldr r2, [r1, #4] ");					// r2 = aRegion.iError
   371 	asm("cmp r2, #0 ");
   372 	asm("bne  " CSM_ZN7TRegion10ForceErrorEv);	// if (aRegion.iError) ForceError();
   373 	asm("ldr r2, [r1] ");						// r1 = aRegion.iCount
   374 	asm("cmp r2, #0 ");
   375 	asm("beq " CSM_ZN7TRegion5ClearEv);			// region to copy is empty so simply clear our buffer
   376 	asm("stmfd sp!, {r0,r1,r4,r5,r6,lr} ");		// preserve r0,r1,lr across function calls
   377 	asm("mov r4, r1 ");
   378 	asm("mov r5, r0 ");
   379 	asm("ldr r2, [r0, #4] ");					// r2 = iError
   380 	asm("cmp r2, #0 ");
   381 	asm("blne  " CSM_ZN7TRegion5ClearEv);		// if (iError) Clear();
   382 	asm("mov r0, r5 ");
   383 	asm("ldr r1, [r4] ");						// r1 = aRegion.iCount, r0 = this
   384 	asm("bl	 " CSM_ZN7TRegion11SetListSizeEi);	// SetListSize(aRegion.iCount);
   385 	asm("cmp r0, #0 ");
   386 	asm("beq copyregion_end ");
   387 	asm("ldr r3, [r4] ");						// r3 = aRegion.iCount
   388 	asm("cmp r3, #0 ");
   389 	asm("str r3, [r5] ");						// iCount=aRegion.iCount
   390 	asm("beq copyregion_end ");
   391 	asm("ldr r0, [r5, #8] ");					// r0 points to first rectangle
   392 	asm("cmn r0, r0 ");
   393 	asm("ldrcc r0, [r5, #16] ");				// if RRegion
   394 	asm("addcs r0, r5, #20 ");					// RRegionBuf
   395 	asm("submi r0, r0, #8 ");					// TRegionFix
   396 	asm("ldr r1, [r4, #8] ");					// r1 points to first rectangle
   397 	asm("cmn r1, r1 ");
   398 	asm("ldrcc r1, [r4, #16] ");				// if RRegion
   399 	asm("addcs r1, r4, #20 ");					// RRegionBuf
   400 	asm("submi r1, r1, #8 ");					// TRegionFix
   401 	asm("copyregion1: ");
   402 	asm("ldmia r1!, {r2,r4,r5,r12} ");			// copy aRegion.iRectangleList to iRectangleList
   403 	asm("subs r3, r3, #1 ");
   404 	asm("stmia r0!, {r2,r4,r5,r12} ");
   405 	asm("bne copyregion1 ");
   406 
   407 	asm("copyregion_end: ");
   408 	__POPRET("r0,r1,r4,r5,r6,");
   409 	}
   410 
   411 
   412 
   413 
   414 __NAKED__ EXPORT_C void TRegion::Offset(const TPoint & /*anOffset*/)
   415 /**
   416 Moves the region by adding a TPoint offset to the co-ordinates of its corners.
   417 	
   418 The size of the region is not changed.
   419 	
   420 @param aOffset The offset by which the region is moved. The region is moved 
   421                horizontally by aOffset.iX pixels and vertically by aOffset.iY pixels.
   422 */
   423 	{
   424 	asm("ldmia r1, {r1,r2} ");		// r1=anOffset.iX, r2=anOffset.iY
   425 	// fall through...
   426 	}
   427 
   428 
   429 
   430 
   431 __NAKED__ EXPORT_C void TRegion::Offset(TInt /*xOffset*/,TInt /*yOffset*/)
   432 /**
   433 Moves the region by adding X and Y offsets to the co-ordinates of its corners.
   434 	
   435 The size of the region is not changed.
   436 	
   437 @param aXoffset The number of pixels by which to move the region horizontally. 
   438                 If negative, the region moves leftwards. 
   439 @param aYoffset The number of pixels by which to move the region vertically. 
   440                 If negative, the region moves upwards.
   441 */
   442 	{
   443 	asm("ldr r12, [r0] ");			// r12=iCount
   444 	asm("cmp r12, #0 ");
   445 	__JUMP(eq,lr);
   446 	asm("ldr r3, [r0, #8] ");		// r0 points to first rectangle
   447 	asm("cmn r3, r3 ");
   448 	asm("ldrcc r0, [r0, #16] ");	// if RRegion
   449 	asm("addcs r0, r0, #20 ");		// RRegionBuf
   450 	asm("submi r0, r0, #8 ");		// TRegionFix
   451 	asm("stmfd sp!, {r4,r5,lr} ");
   452 	asm("offsetregion2: ");
   453 	asm("ldmia r0, {r3-r5,lr} ");	// r3-r5,lr = next rectangle coordinates
   454 	asm("subs r12, r12, #1 ");
   455 	asm("add r3, r3, r1 ");			// Tl.iX += anOffset.iX
   456 	asm("add r4, r4, r2 ");			// Tl.iY += anOffset.iY
   457 	asm("add r5, r5, r1 ");			// Br.iX += anOffset.iX
   458 	asm("add lr, lr, r2 ");			// Br.iY += anOffset.iY
   459 	asm("stmia r0!, {r3-r5,lr} ");	// store new coordinates
   460 	asm("bne offsetregion2 ");
   461 	__POPRET("r4,r5,");
   462 	}
   463 
   464 
   465 
   466 
   467 __NAKED__ EXPORT_C TBool TRegion::Contains(const TPoint & /*aPoint*/) const
   468 /**
   469 Tests whether a point is located within the region.
   470 
   471 If the point is located on the top or left hand side of any rectangle in the 
   472 region, it is considered to be within that rectangle and within the region. 
   473 
   474 If the point is located on the right hand side or bottom of a rectangle, it 
   475 is considered to be outside that rectangle, and may be outside the region.
   476 
   477 @param aPoint The specified point. 
   478 
   479 @return True, if the point is within the region; false, otherwise.
   480 */
   481 	{
   482 	asm("ldr r12, [r0] ");			// r12 = iCount
   483 	asm("stmfd sp!, {r4,r5,lr} ");
   484 	asm("cmp r12, #0 ");
   485 	asm("beq contains0 ");			// if iCount=0, return FALSE
   486 	asm("ldr r3, [r0, #8] ");		// r0 points to first rectangle
   487 	asm("cmn r3, r3 ");
   488 	asm("ldrcc r0, [r0, #16] ");	// if RRegion
   489 	asm("addcs r0, r0, #20 ");		// RRegionBuf
   490 	asm("submi r0, r0, #8 ");		// TRegionFix
   491 	asm("ldmia r1, {r1, r2} ");		// r1=aPoint.iX, r2=aPoint.iY
   492 	asm("contains1: ");
   493 	asm("ldmia r0!, {r3-r5,lr} ");	// coordinates of next rectangle into r3-r5,lr
   494 	asm("cmp r3, r1 ");				// compare next.iTl.iX with aPoint.iX
   495 	asm("cmple r4, r2 ");			// if <=, compare next.iTl.iY with aPoint.iY
   496 	asm("bgt contains2 ");			// if >, aPoint is not contained in rectangle, so iterate
   497 	asm("cmp r1, r5 ");				// compare aPoint.iX with next.iBr.iX
   498 	asm("cmplt r2, lr ");			// if <, compare aPoint.iY with next.iBr.iY
   499 	asm("contains2: ");
   500 	asm("subges r12, r12, #1 ");	// if >=, aPoint is not contained in rect, so iterate
   501 	asm("bgt contains1 ");
   502 	asm("cmp r12, #0 ");
   503 	asm("movne r0, #1 ");			// if r12 non-zero, return TRUE else FALSE
   504 	asm("contains0: ");
   505 	asm("moveq r0, #0 ");
   506 	__POPRET("r4,r5,");
   507 	}
   508 
   509 
   510 
   511 
   512 __NAKED__ EXPORT_C TBool TRegion::Intersects(const TRect &/*aRect*/) const
   513 /**
   514 Tests whether where there is any intersection between this region and the specified rectangle.
   515 
   516 @param aRect The specified rectangle.
   517  
   518 @return True, if there is an intersection; false, otherwise.
   519 */
   520 	{
   521 	asm("ldr    r12, [r0] ");		// r12 = iCount
   522 	asm("stmfd  sp!, {r4-r7,lr} ");
   523 	asm("cmp    r12, #0 ");
   524 	asm("beq    intersects0 ");		// if iCount=0, return FALSE
   525 	asm("ldr    lr, [r0, #8] ");	// r0 points to first rectangle	
   526 	asm("ldmia  r1, {r1-r4} ");		// (load aRect into r1 - r4)
   527 	asm("cmn    lr, lr ");
   528 	asm("ldrcc  r0, [r0, #16] ");	// if RRegion
   529 	asm("addcs  r0, r0, #20 ");		// RRegionBuf
   530 	asm("submi  r0, r0, #8 ");		// TRegionFix
   531 	asm("cmp    r1, r3 ");			// check if aRect is empty
   532 	asm("cmplt  r2, r4 ");
   533 	asm("bge    intersects0 ");
   534 	
   535 	asm("intersects1: ");
   536 	asm("ldmia  r0!, {r5-r7,lr} ");	// coordinates of next rectangle into r5-r7,lr	
   537 	asm("cmp    r1, r7 ");			// check if they intersect
   538 	asm("cmplt  r2, lr ");
   539 	asm("cmplt  r5, r3 ");
   540 	asm("cmplt  r6, r4 ");
   541 	asm("subges r12, r12, #1 ");	// if not then decrement and loop
   542 	asm("bgt    intersects1 ");
   543 	
   544 	asm("intersects0: ");
   545 	asm("movge  r0, #0 ");
   546 	asm("movlt  r0, #1 ");
   547 	__POPRET("r4-r7,");
   548 	}
   549 
   550 
   551 
   552 
   553 __NAKED__ void TRegion::DeleteRect(TRect * /*aRect*/)
   554 //
   555 // Delete a specific rectangle in the list.
   556 //
   557 	{
   558 	asm("ldr r12, [r0] ");			// r12=iCount
   559 	asm("ldr r3, [r0, #8] ");		// r0 points to first rectangle
   560 	asm("subs r12, r12, #1 ");		// decrement it
   561 	asm("str r12, [r0] ");			// iCount--;
   562 	asm("cmn r3, r3 ");
   563 	asm("ldrcc r0, [r0, #16] ");	// if RRegion
   564 	asm("addcs r0, r0, #20 ");		// RRegionBuf
   565 	asm("submi r0, r0, #8 ");		// TRegionFix
   566 	asm("sub r2, r1, r0 ");			// r2=offset of aRect from iRectangleList
   567 	asm("subs r12, r12, r2, lsr #4 ");	// r12 now equals number of rectangles requiring moving
   568 	__JUMP(eq,lr);
   569 	asm("add r0, r1, #16 ");			// r0 = aRect+1
   570 	asm("stmfd sp!, {r4,lr} ");
   571 	asm("deleterect1: ");
   572 	asm("ldmia r0!, {r2-r4,lr} ");		// move rectangles following aRect back by one place
   573 	asm("subs r12, r12, #1 ");
   574 	asm("stmia r1!, {r2-r4,lr} ");
   575 	asm("bne deleterect1 ");
   576 	__POPRET("r4,");
   577 	}
   578 
   579 
   580 
   581 
   582 __NAKED__ EXPORT_C void TRegion::ClipRect(const TRect & /*aRect*/)
   583 /**
   584 Clips the region to the specified rectangle.
   585 
   586 The resulting region is the area of overlap between the region and the rectangle. 
   587 If there is no overlap, all rectangles within this region are deleted and 
   588 the resulting region is empty.
   589 
   590 @param aRect The rectangle to which this region is to be clipped.
   591 */
   592 // Can not fail.
   593 	{
   594 	asm("ldr r12, [r0] ");				// r12=iCount
   595 	asm("cmp r12, #0 ");
   596 	__JUMP(eq,lr);
   597 	asm("stmfd sp!, {r4-r10,lr} ");
   598 	asm("ldmia r1, {r2-r5} ");			// get coordinates of aRect into r2-r5
   599 	asm("ldr r1, [r0, #8] ");			// r1 points to first rectangle
   600 	asm("cmn r1, r1 ");
   601 	asm("ldrcc r1, [r0, #16] ");		// if RRegion
   602 	asm("addcs r1, r0, #20 ");			// RRegionBuf
   603 	asm("submi r1, r1, #8 ");			// TRegionFix
   604 
   605 	asm("cliprect1: ");
   606 	asm("ldmia r1!, {r6-r9} ");			// next rectangle coordinates into r6-r9
   607 	asm("cmp r6, r2 ");					// clip the rectangle to aRect
   608 	asm("movlt r6, r2 ");	
   609 	asm("strlt r2, [r1, #-16] ");
   610 	asm("cmp r7, r3 ");
   611 	asm("movlt r7, r3 ");
   612 	asm("strlt r3, [r1, #-12] ");
   613 	asm("cmp r8, r4 ");
   614 	asm("movgt r8, r4 ");
   615 	asm("strgt r4, [r1, #-8] ");
   616 	asm("cmp r9, r5 ");
   617 	asm("movgt r9, r5 ");
   618 	asm("strgt r5, [r1, #-4] ");
   619 	asm("cmp r6, r8 ");					// check if clipped rect is empty
   620 	asm("cmplt r7, r9 ");				// empty if r6>=r8 or r7>=r9
   621 	asm("bge cliprect_delete ");		// if empty, branch to other loop to delete rect 
   622 	asm("subs r12, r12, #1 ");			// decrement loop counter
   623 	asm("bne cliprect1 ");				// loop if any more rectangles to do
   624 	__POPRET("r4-r10,");
   625 
   626 	asm("cliprect_delete: ");			// (enter loop here)
   627 	asm("ldr lr, [r0] ");				// lr=iCount, updateed if we delete rects
   628 	asm("sub r10, r1, #16 ");			// r1 -> next rect, r10 -> previous deleted rect
   629 	asm("subs r12, r12, #1 ");			// decrement loop counter
   630 	asm("beq cliprect_move_end ");	
   631 	asm("cliprect_move: ");
   632 	asm("ldmia r1!, {r6-r9} ");			// next rectangle coordinates into r6-r9
   633 	asm("cmp r6, r2 ");					// clip the rectangle to aRect
   634 	asm("movlt r6, r2 ");
   635 	asm("cmp r7, r3 ");
   636 	asm("movlt r7, r3 ");
   637 	asm("cmp r8, r4 ");
   638 	asm("movgt r8, r4 ");
   639 	asm("cmp r9, r5 ");
   640 	asm("movgt r9, r5 ");
   641 	asm("cmp r6, r8 ");					// check if clipped rect is empty
   642 	asm("cmplt r7, r9 ");				// empty if r6>=r8 or r7>=r9
   643 	asm("stmltia r10!, {r6-r9} ");		// if non-empty then store the rect
   644 	asm("subge lr, lr, #1 ");			// else decrement rect count	
   645 	asm("subs r12, r12, #1 ");			// decrement loop counter
   646 	asm("bne cliprect_move ");			// loop if any more rectangles to do
   647 	asm("cliprect_move_end: ");	
   648 	asm("sub lr, lr, #1 ");				// decrement count for first deleted rect
   649 	asm("str lr, [r0] ");				// store updated iCount
   650 	__POPRET("r4-r10,");	
   651 	}
   652 
   653 
   654 
   655 	
   656 __NAKED__ EXPORT_C void TRegion::SubRect(const TRect& /*aRect*/,TRegion* /*aSubtractedRegion*/)
   657 /**
   658 Removes a rectangle from this region.
   659 
   660 If there is no intersection between the rectangle and this region, then this 
   661 region is unaffected. 
   662 
   663 @param aRect             The rectangular area to be removed from this region. 
   664 @param aSubtractedRegion A pointer to a region. If this is supplied, the
   665                          removed rectangle is added to it. By default this
   666                          pointer is NULL.
   667 */
   668 	{
   669 	asm("ldr r12, [r0] ");			// r12=iCount=limit
   670 	asm("cmp r12, #0 ");
   671 	__JUMP(eq,lr);
   672 	asm("stmfd sp!, {r3-r11,lr} ");
   673 	asm("ldmia r1, {r4-r7} ");		// r4-r7 = coordinates of aRect
   674 	asm("cmp r4, r6 ");				// check if aRect is empty i.e. (r4>=r6 || r5>=r7)
   675 	asm("cmplt r5, r7 ");
   676 	asm("bge subrect_end ");		// if aRect is empty nothing to do
   677 
   678 	asm("mov r3, #0 ");				// r3=index
   679 	asm("subrect1: ");
   680 	asm("ldr lr, [r0, #8] ");		// lr points to first rectangle
   681 	asm("cmn lr, lr ");
   682 	asm("ldrcc lr, [r0, #16] ");	// if RRegion
   683 	asm("addcs lr, r0, #20 ");		// RRegionBuf
   684 	asm("submi lr, lr, #8 ");		// TRegionFix
   685 	asm("add lr, lr, r3, lsl #4 ");	// lr=iRectangleList+index
   686 //	asm("ldmia r1, {r4-r7} ");		// r4-r7 = coordinates of aRect
   687 	asm("ldmia lr, {r8-r11} ");		// r8-r11 = coordinates of next rectangle in region
   688 	asm("cmp r10, r4 ");			// compare next.iBr.iX with aRect.iTl.iX
   689 	asm("cmpgt r11, r5 ");			// if >, compare next.iBr.iY with aRect.iTl.iY
   690 	asm("cmpgt r6, r8 ");			// if >, compare aRect.iBr.iX with next.iTl.iX
   691 	asm("cmpgt r7, r9 ");			// if >, compare aRect.iBr.iY with next.iTl.iY
   692 	asm("addle r3, r3, #1 ");		// if empty intersection, increment index
   693 	asm("ble subrect2 ");			// if <=, next and aRect have empty intersection, so skip
   694 	asm("add r4, lr, #16 ");		// r4 = source pointer for copy, lr = dest
   695 	asm("ldr r5, [r0] ");			// r5 = iCount
   696 	asm("sub r5, r5, #1 ");			// decrement iCount
   697 	asm("str r5, [r0] ");
   698 	asm("sub r12, r12, #1 ");		// decrement limit
   699 	asm("subs r5, r5, r3 ");		// loop count for copy = iCount-index
   700 	asm("beq subrect4 ");			// if loop count zero, skip the copy
   701 	asm("stmfd sp!, {r8,r9} ");		// preserve r8,r9
   702 	asm("subrect3: ");
   703 	asm("ldmia r4!, {r6-r9} ");		// remove the current rectangle
   704 	asm("stmia lr!, {r6-r9} ");
   705 	asm("subs r5, r5, #1 ");
   706 	asm("bne subrect3 ");
   707 	asm("ldmfd sp!, {r8-r9} ");		// restore r8,r9
   708 	asm("subrect4: ");
   709 	asm("ldmia r1, {r4-r7} ");		// restore coordinates of aRect into r4-r7
   710 	asm("cmp r7, r11 ");			// compare aRect.iBr.iY with rect.iBr.iY
   711 	asm("movgt r7, r11 ");			// r7=inter.iBr.iY
   712 	asm("bllt subrectapp1 ");		// if <, append 1st subrectangle
   713 	asm("cmp r5, r9 ");				// compare aRect.iTl.iY with rect.iTl.iY
   714 	asm("movlt r5, r9 ");			// r5=inter.iTl.iY
   715 	asm("blgt subrectapp2 ");		// if >, append 2nd subrectangle
   716 	asm("cmp r6, r10 ");			// compare aRect.iBr.iX with rect.iBr.iX
   717 	asm("movgt r6, r10 ");			// r6=inter.iBr.iX
   718 	asm("bllt subrectapp3 ");		// if <, append 3rd subrectangle
   719 	asm("cmp r4, r8 ");				// compare aRect.iTl.iX with rect.iTl.iX
   720 	asm("movlt r4, r8 ");			// r4=inter.iTl.iX
   721 	asm("blgt subrectapp4 ");		// if >, append 4th subrectangle
   722 	asm("ldr lr, [r0, #4] ");		// lr=iError
   723 	asm("cmp lr, #0 ");				// check for an error
   724 	asm("bne subrect_end ");
   725 	asm("cmp r2, #0 ");				// check if aSubtractedRegion!=NULL
   726 	asm("blne subrectadd ");		// if non-null, add inter to aSubtractedRegion
   727 	asm("subrect2: ");
   728 	asm("cmp r3, r12 ");			// compare index to limit
   729 	asm("ldmltia r1, {r4-r7} ");	// if index<limit, r4-r7 = coordinates of aRect
   730 	asm("blt subrect1 ");			// if index<limit, loop again
   731 
   732 	asm("subrect_end: ");
   733 	__POPRET("r3-r11,");
   734 
   735 	// AppendRect(TRect(rect.iTl.iX,inter.iBr.iY,rect.iBr.iX,rect.iBr.iY))
   736 	asm("subrectapp1: ");
   737 	asm("stmfd sp!, {r0-r3,r12,lr} ");			// preserve registers across function call
   738 	asm("bl  " CSM_Z16AllocAnotherRectP7TRegion);
   739 	asm("ldmfd sp!, {r0-r3} ");
   740 	asm("beq subrectapp1_end ");		// exit if error
   741 
   742 	asm("ldr r12, [r0] ");				// r12=iCount
   743 	asm("ldr lr, [r0, #8] ");		// lr points to first rectangle
   744 	asm("cmn lr, lr ");
   745 	asm("ldrcc lr, [r0, #16] ");	// if RRegion
   746 	asm("addcs lr, r0, #20 ");		// RRegionBuf
   747 	asm("submi lr, lr, #8 ");		// TRegionFix
   748 	asm("add lr, lr, r12, lsl #4 ");	// lr=&(iRectangleList[iCount])
   749 	asm("add r12, r12, #1 ");			// increment iCount
   750 	asm("str r12, [r0] ");				//
   751 	asm("stmia lr!, {r8} ");			// append rectangle - rect.iTl.iX
   752 	asm("stmia lr!, {r7,r10,r11} ");	// inter.iBr.iY, rect.iBr.iX, rect.iBr.iY
   753 	asm("subrectapp1_end: ");
   754 	__POPRET("r12,");
   755 
   756 	// AppendRect(TRect(rect.iTl.iX,rect.iTl.iY,rect.iBr.iX,inter.iTl.iY))
   757 	asm("subrectapp2: ");
   758 	asm("stmfd sp!, {r0-r3,r12,lr} ");			// preserve registers across function call
   759 	asm("bl  " CSM_Z16AllocAnotherRectP7TRegion);
   760 	asm("ldmfd sp!, {r0-r3} ");
   761 	asm("beq subrectapp1_end ");		// exit if error
   762 
   763 	asm("ldr r12, [r0] ");				// r12=iCount
   764 	asm("ldr lr, [r0, #8] ");		// lr points to first rectangle
   765 	asm("cmn lr, lr ");
   766 	asm("ldrcc lr, [r0, #16] ");	// if RRegion
   767 	asm("addcs lr, r0, #20 ");		// RRegionBuf
   768 	asm("submi lr, lr, #8 ");		// TRegionFix
   769 	asm("add lr, lr, r12, lsl #4 ");	// lr=&(iRectangleList[iCount])
   770 	asm("add r12, r12, #1 ");			// increment iCount
   771 	asm("str r12, [r0] ");				//
   772 	asm("stmia lr!, {r8,r9,r10} ");		// append rectangle - rect.iTl.iX,rect.iTl.iY,rect.iBr.iX
   773 	asm("stmia lr!, {r5} ");			// inter.iTl.iY
   774 	__POPRET("r12,");
   775 
   776 	// AppendRect(TRect(inter.iBr.iX,inter.iTl.iY,rect.iBr.iX,inter.iBr.iY))
   777 	asm("subrectapp3: ");
   778 	asm("stmfd sp!, {r0-r3,r12,lr} ");			// preserve registers across function call
   779 	asm("bl  " CSM_Z16AllocAnotherRectP7TRegion);
   780 	asm("ldmfd sp!, {r0-r3} ");
   781 	asm("beq subrectapp1_end ");		// exit if error
   782 	asm("ldr r12, [r0] ");				// r12=iCount
   783 	asm("ldr lr, [r0, #8] ");		// lr points to first rectangle
   784 	asm("cmn lr, lr ");
   785 	asm("ldrcc lr, [r0, #16] ");	// if RRegion
   786 	asm("addcs lr, r0, #20 ");		// RRegionBuf
   787 	asm("submi lr, lr, #8 ");		// TRegionFix
   788 	asm("add lr, lr, r12, lsl #4 ");	// lr=&(iRectangleList[iCount])
   789 	asm("add r12, r12, #1 ");			// increment iCount
   790 	asm("str r12, [r0] ");				//
   791 	asm("stmia lr!, {r6} ");			// append rectangle - inter.iBr.iX
   792 	asm("stmia lr!, {r5,r10} ");		// inter.iTl.iY, rect.iBr.iX
   793 	asm("stmia lr!, {r7} ");			// inter.iBr.iY
   794 	__POPRET("r12,");
   795 
   796 	// AppendRect(TRect(rect.iTl.iX,inter.iTl.iY,inter.iTl.iX,inter.iBr.iY))
   797 	asm("subrectapp4: ");
   798 	asm("stmfd sp!, {r0-r3,r12,lr} ");			// preserve registers across function call
   799 	asm("bl  " CSM_Z16AllocAnotherRectP7TRegion);
   800 	asm("ldmfd sp!, {r0-r3} ");
   801 	asm("beq subrectapp1_end ");		// exit if error
   802 	asm("ldr r12, [r0] ");				// r12=iCount
   803 	asm("ldr lr, [r0, #8] ");		// lr points to first rectangle
   804 	asm("cmn lr, lr ");
   805 	asm("ldrcc lr, [r0, #16] ");	// if RRegion
   806 	asm("addcs lr, r0, #20 ");		// RRegionBuf
   807 	asm("submi lr, lr, #8 ");		// TRegionFix
   808 	asm("add lr, lr, r12, lsl #4 ");	// lr=&(iRectangleList[iCount])
   809 	asm("add r12, r12, #1 ");			// increment iCount
   810 	asm("str r12, [r0] ");				//
   811 	asm("stmia lr!, {r8} ");			// append rectangle - rect.iTl.iX
   812 	asm("stmia lr!, {r5} ");			// inter.iTl.iY
   813 	asm("stmia lr!, {r4,r7} ");			// inter.iTl.iX, inter.iBr.iY
   814 	__POPRET("r12,");
   815 
   816 	// aSubtractedRegion->AddRect(inter)
   817 	asm("subrectadd: ");
   818 	asm("stmfd sp!, {r0-r7,r12,lr} ");	// preserve registers and put inter onto stack
   819 	asm("mov r0, r2 ");					// this = aSubtractedRegion
   820 	asm("add r1, sp, #16 ");			// inter is 16 bytes above sp
   821 	asm("bl  " CSM_ZN7TRegion7AddRectERK5TRect);	// call TRegion::AddRect
   822 	__POPRET("r0-r7,r12,");
   823 	}
   824 
   825 
   826 
   827 
   828 __NAKED__ EXPORT_C void TRegion::Intersection(const TRegion& /*aRegion1*/,const TRegion& /*aRegion2*/)
   829 /**
   830 Replaces this region with the area of intersection between two specified regions.
   831 	
   832 Notes:
   833 	
   834 1. If the error flag of either of the two specified regions is set, then this 
   835    region is cleared and its error flag is set. This frees up allocated memory.
   836 	
   837 2. If this region's error flag is already set, then the function has no effect.
   838 	
   839 @param aRegion1 The first region. 
   840 @param aRegion2 The second region.
   841 */
   842 	{
   843 	// r0=this, r1=&aRegion1, r2=&aRegion2
   844 	asm("ldr r3, [r1, #4] ");			// r3=aRegion1.iError
   845 	asm("ldr r12, [r2, #4] ");			// r12=aRegion2.iError
   846 	asm("orrs r3, r3, r12 ");
   847 	asm("bne  " CSM_ZN7TRegion10ForceErrorEv);	// if either set, ForceError()
   848 	asm("str r3, [r0] ");				// iCount=0
   849 	asm("ldr r3, [r1] ");				// r3=aRegion1.iCount
   850 	asm("ldr r12, [r2] ");				// r12=aRegion2.iCount
   851 	asm("cmp r3, #0 ");
   852 	asm("cmpne r12, #0 ");
   853 	__JUMP(eq,lr);
   854 	asm("stmfd sp!, {r3-r11,lr} ");
   855 	asm("ldr lr, [r1, #8] ");			// r1 points to first rectangle of aRegion1 = pRect1
   856 	asm("cmn lr, lr ");
   857 	asm("ldrcc r1, [r1, #16] ");		// if RRegion
   858 	asm("addcs r1, r1, #20 ");			// RRegionBuf
   859 	asm("submi r1, r1, #8 ");			// TRegionFix
   860 	asm("intersection1: ");
   861 	asm("ldr lr, [r2, #8] ");			// lr points to first rectangle of aRegion2
   862 	asm("cmn lr, lr ");
   863 	asm("ldrcc lr, [r2, #16] ");		// if RRegion
   864 	asm("addcs lr, r2, #20 ");			// RRegionBuf
   865 	asm("submi lr, lr, #8 ");			// TRegionFix
   866 	asm("ldr r12, [r2] ");				// r12=aRegion2.iCount
   867 	asm("intersection2: ");
   868 	asm("ldmia r1, {r4-r7} ");			// r4-r7 = *pRect1
   869 	asm("ldmia lr!, {r8-r11} ");		// r8-r11 = *pRect2++
   870 	asm("cmp r6, r8 ");					// compare pRect1->iBr.iX with pRect2->iTl.iX
   871 	asm("cmpgt r7, r9 ");				// if >, compare pRect1->iBr.iY with pRect2->iTl.iY
   872 	asm("cmpgt r10, r4 ");				// if >, compare pRect2->iBr.iX with pRect1->iTl.iX
   873 	asm("cmpgt r11, r5 ");				// if >, compare pRect2->iBr.iY with pRect1->iTl.iY
   874 	asm("ble intersection3 ");			// if <=, rectangles have empty intersection, so iterate
   875 	asm("cmp r4, r8 ");					// compute intersection and place in r8-r11
   876 	asm("movgt r8, r4 ");
   877 	asm("cmp r5, r9 ");
   878 	asm("movgt r9, r5 ");
   879 	asm("cmp r6, r10 ");
   880 	asm("movlt r10, r6 ");
   881 	asm("cmp r7, r11 ");
   882 	asm("movlt r11, r7 ");
   883 	asm("stmfd sp!, {r0-r3,r12,lr} ");	// preserve registers across function call
   884 	asm("bl  " CSM_Z16AllocAnotherRectP7TRegion);
   885 	asm("ldmfd sp!, {r0-r3} ");
   886 	asm("ldmeqfd sp!, {r12,lr} ");		// exit if error
   887 	asm("beq intersection_end ");
   888 
   889 	asm("ldr r12, [r0] ");				// r12=iCount
   890 	asm("ldr lr, [r0, #8] ");			// lr points to first rectangle
   891 	asm("cmn lr, lr ");
   892 	asm("ldrcc lr, [r0, #16] ");		// if RRegion
   893 	asm("addcs lr, r0, #20 ");			// RRegionBuf
   894 	asm("submi lr, lr, #8 ");			// TRegionFix
   895 	asm("add lr, lr, r12, lsl #4 ");	// lr=&(iRectangleList[iCount])
   896 	asm("add r12, r12, #1 ");			// increment iCount
   897 	asm("str r12, [r0] ");				//
   898 	asm("stmia lr!, {r8-r11} ");		// append intersection of rectangles
   899 	asm("ldmfd sp!, {r12,lr} ");		// restore registers
   900 	asm("intersection3: ");
   901 	asm("subs r12, r12, #1 ");
   902 	asm("bne intersection2 ");			// loop for all values of pRect2
   903 	asm("add r1, r1, #16 ");			// increment pRect1
   904 	asm("subs r3, r3, #1 ");
   905 	asm("bne intersection1 ");			// loop for all values of pRect1
   906 
   907 	asm("intersection_end: ");
   908 	__POPRET("r3-r11,");
   909 	}
   910 	
   911 #endif
   912 
   913 
   914 
   915 
   916 #ifdef __COBJECT_MACHINE_CODED__
   917 __NAKED__ EXPORT_C CObject *CObjectIx::At(TInt /*aHandle*/,TInt /*aUniqueID*/)
   918 /**
   919 Gets a pointer to the reference counting object with the specified handle
   920 number and matching unique ID.
   921 
   922 @param aHandle   The handle number of the reference counting object.
   923 @param aUniqueID The unique ID.
   924 
   925 @return A pointer to the reference counting object. If there is no matching 
   926         object, then this is NULL.
   927 */
   928 	{
   929 	// r0=this, r1=aHandle, r2=aUniqueID
   930 	asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iHighWaterMark));	// r3=iHighWaterMark
   931 	asm("ldr r0, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iObjects));	// r0=iObjects
   932 	asm("mov r12, r1, lsl #17 ");		// r12=r1<<17 = index(aHandle)<<17
   933 	asm("cmp r3, r12, lsr #17 ");		// compare iHighWaterMark with index(aHandle)
   934 	asm("movle r0, #0 ");				// if hwm<=index, return NULL
   935 	__JUMP(le,lr);
   936 	asm("add r0, r0, r12, lsr #14 ");	// r0=iObjects+index(Handle)=pS
   937 	asm("ldr r3, [r0] ");				// r3=pS->uniqueID:pS->instance
   938 	asm("mov r1, r1, lsl #2 ");			// r1=instance(Handle)<<18
   939 	asm("mov r1, r1, lsr #18 ");		// r1=instance(Handle)
   940 	asm("orr r1, r1, r2, lsl #16 ");	// r1=aUniqueID:instance(Handle)
   941 	asm("cmp r1, r3 ");					// check uniqueID and instance
   942 	asm("movne r0, #0 ");				// if wrong, return 0
   943 	asm("ldreq r0, [r0, #4] ");			// else return pointer to CObject
   944 	__JUMP(,lr);
   945 	}
   946 
   947 
   948 
   949 
   950 __NAKED__ EXPORT_C CObject *CObjectIx::At(TInt aHandle)
   951 /**
   952 Gets a pointer to the reference counting object with the specified
   953 handle number.
   954 
   955 @param aHandle The handle number of the reference counting object.
   956 
   957 @return A pointer to the reference counting object. If there is no matching 
   958         object, then this is NULL.
   959 */
   960 	{
   961 	// r0=this, r1=aHandle
   962 	asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iHighWaterMark));	// r3=iHighWaterMark
   963 	asm("ldr r0, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iObjects));	// r0=iObjects
   964 	asm("mov r12, r1, lsl #17 ");		// r12=r1<<17 = index(aHandle)<<17
   965 	asm("cmp r3, r12, lsr #17 ");		// compare iHighWaterMark with index(aHandle)
   966 	asm("movle r0, #0 ");				// if hwm<=index, return NULL
   967 	__JUMP(le,lr);
   968 	asm("add r0, r0, r12, lsr #14 ");	// r0=iObjects+index(Handle)=pS
   969 	asm("ldr r3, [r0] ");				// r3=pS->uniqueID:pS->instance
   970 	asm("ldr r2, __instanceMask ");
   971 	asm("and r1, r1, r2 ");				// r1=instance(Handle)<<16
   972 	asm("cmp r1, r3, lsl #16 ");		// check instance
   973 	asm("movne r0, #0 ");				// if wrong, return 0
   974 	asm("ldreq r0, [r0, #4] ");			// else return pointer to CObject
   975 	__JUMP(,lr);
   976 	asm("__instanceMask: ");
   977 	asm(".word 0x3FFF0000 ");
   978 	}
   979 
   980 
   981 
   982 
   983 GLREF_C void PanicCObjectIxIndexOutOfRange(void);
   984 
   985 
   986 
   987 
   988 __NAKED__ EXPORT_C CObject* CObjectIx::operator[](TInt /*anIndex*/)
   989 /**
   990 Gets a pointer to a reference counting object located at the specified offset 
   991 within the object index.
   992 
   993 @param anIndex The offset of the reference counting object within the object 
   994                index. Offset is relative to zero. 
   995                
   996 @return A pointer to the reference counting object.
   997 
   998 @panic E32USER-CBase 21 if the value of anIndex is negative or is greater than
   999                         or equal to the total number of objects held by
  1000                         the index.
  1001 */
  1002 	{
  1003 	// r0=this, r1=anIndex
  1004 	asm("cmp r1, #0 ");								// check anIndex>=0
  1005 	asm("ldrge r3, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iHighWaterMark));	// if so, r3=iHighWaterMark
  1006 	asm("cmpge r3, r1 ");							// and compare iHighWaterMark to anIndex
  1007 	asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iObjects));	// if OK, r0=iObjects
  1008 	asm("addgt r0, r0, r1, lsl #3 ");				// r0=iObjects+anIndex
  1009 	asm("ldrgt r0, [r0, #4] ");						// r0=pointer to CObject
  1010 #ifdef __CPU_ARMV6
  1011 	asm("ble 1f ");
  1012 	__JUMP(,lr);
  1013 #else
  1014 	__JUMP(gt,lr);
  1015 #endif
  1016 	asm("1: ");
  1017 	asm("b  " CSM_Z29PanicCObjectIxIndexOutOfRangev);	// if anIndex<0 or iCount<=anIndex, panic
  1018 	}
  1019 
  1020 
  1021 
  1022 
  1023 GLREF_C void PanicCObjectConIndexOutOfRange(void);
  1024 GLREF_C void PanicCObjectConFindBadHandle(void);
  1025 GLREF_C void PanicCObjectConFindIndexOutOfRange(void);
  1026 
  1027 
  1028 
  1029 
  1030 __NAKED__ EXPORT_C CObject *CObjectCon::operator[](TInt /*anIndex*/)
  1031 /**
  1032 Gets a pointer to the reference counting object located at the specified offset 
  1033 within the object container.
  1034 
  1035 @param anIndex The offset of the reference counting object within the object 
  1036                container. Offset is relative to zero.
  1037 
  1038 @return A pointer to the owning reference counting object.
  1039 
  1040 @panic E32USER-CBase 21 if anIndex is negative or is greater than or equal to
  1041                         the total number of objects held by the container.
  1042 */
  1043 	{
  1044 	// r0=this, r1=anIndex
  1045 	asm("cmp r1, #0 ");
  1046 	asm("ldrge r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iCount));
  1047 	asm("cmpge r2, r1 ");
  1048 	asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iObjects));
  1049 	asm("ldrgt r0, [r0, r1, lsl #2] ");
  1050 #ifdef __CPU_ARMV6
  1051 	asm("ble 1f ");
  1052 	__JUMP(,lr);
  1053 #else
  1054 	__JUMP(gt,lr);
  1055 #endif
  1056 	asm("1: ");
  1057 	asm("b  " CSM_Z30PanicCObjectConIndexOutOfRangev);
  1058 	}
  1059 
  1060 
  1061 
  1062 
  1063 __NAKED__ EXPORT_C CObject *CObjectCon::At(TInt /*aFindHandle*/) const
  1064 /**
  1065 Gets a pointer to the reference counting object with the specified find-handle 
  1066 number.
  1067 
  1068 A find-handle number is an integer which uniquely identifies a reference
  1069 counting object with respect to its object container.
  1070 
  1071 @param aFindHandle The find-handle number of the reference counting object. 
  1072                    The unique Id part of this number must be the same as the
  1073                    unique Id of this container.
  1074                    The index part of the find-handle number must be
  1075                    a valid index. 
  1076 
  1077 @return A pointer to the reference counting object.
  1078 
  1079 @panic E32User-CBase 38 if the unique Id part of aFindHandle is not the same as
  1080                         the unique Id of this container.
  1081 @panic E32User-CBase 39 if the index part of aFindHandle is negative or greater
  1082                         than or equal to the total number of reference counting
  1083                         objects held by this object container.
  1084 */
  1085 	{
  1086 	// r0=this, r1=aFindHandle
  1087 	asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iUniqueID));
  1088 	asm("cmp r2, r1, lsr #16 ");
  1089 	asm("ldreq r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iCount));
  1090 	asm("bne  " CSM_Z28PanicCObjectConFindBadHandlev);
  1091 	asm("mov r1, r1, lsl #17 ");
  1092 	asm("cmp r2, r1, lsr #17 ");
  1093 	asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iObjects));
  1094 	asm("ble  " CSM_Z34PanicCObjectConFindIndexOutOfRangev);
  1095 	asm("ldr r0, [r0, r1, lsr #15] ");
  1096 	__JUMP(,lr);
  1097 	}
  1098 
  1099 
  1100 
  1101 
  1102 __NAKED__ EXPORT_C CObject *CObjectCon::AtL(TInt /*aFindHandle*/) const
  1103 /**
  1104 Gets a pointer to the reference counting object with the specified find-handle 
  1105 number, and leaves on error.
  1106 
  1107 A find-handle number is an integer which uniquely identifies a reference
  1108 counting object with respect to its object container.
  1109 
  1110 @param aFindHandle The find-handle number of the reference counting object. 
  1111                    The unique Id part of this number must be the same as
  1112                    the unique Id of this container.
  1113                    The index part of the find-handle number must be
  1114                    a valid index. 
  1115 
  1116 @return A pointer to the reference counting object.
  1117 
  1118 @leave KErrBadHandle if the unique Id part of aFindHandle is not the same as
  1119                      the unique Id of this container.
  1120 @leave KErrArgument if the index part of aFindHandle is negative or greater
  1121                     than or equal to the total number of reference counting
  1122                     objects held by this object container.
  1123 */
  1124 	{
  1125 	// r0=this, r1=aFindHandle
  1126 	asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iUniqueID));
  1127 	asm("cmp r2, r1, lsr #16 ");
  1128 	asm("ldreq r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iCount));
  1129 	asm("bne 1f ");
  1130 	asm("mov r1, r1, lsl #17 ");
  1131 	asm("cmp r2, r1, lsr #17 ");
  1132 	asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iObjects));
  1133 	asm("ble 2f ");
  1134 	asm("ldr r0, [r0, r1, lsr #15] ");
  1135 	__JUMP(,lr);
  1136 	// User::Leave tail called, so no annotations required since
  1137 	// current frame is reused by User::Leave
  1138 	asm("1: ");
  1139 	asm("mvn r0, #7 "); // KErrBadHandle
  1140 	asm("b  " CSM_ZN4User5LeaveEi);
  1141 	asm("2: ");
  1142 	asm("mvn r0, #5 "); // KErrArgument
  1143 	asm("b  " CSM_ZN4User5LeaveEi);
  1144 	}
  1145 #endif
  1146 
  1147 #ifdef __CACTIVESCHEDULER_MACHINE_CODED__
  1148 extern "C" void PanicStrayEvent();
  1149 
  1150 /**
  1151 @internalComponent
  1152 
  1153 The inner active scheduler loop. This repeatedly waits for a signal and then
  1154 dispatches the highest priority ready active object. The loop terminates either
  1155 if one of the RunL()s stops the current active scheduler level or leaves.
  1156 
  1157 Stop when aLoop becomes 'Inactive'
  1158 */
  1159 __NAKED__ void CActiveScheduler::DoRunL(TLoopOwner* const volatile& aLoop, CActive* volatile & aCurrentObj, TCleanupBundle* aCleanupBundlePtr)
  1160 	{
  1161 	asm("stmfd sp!, {r4-r8,lr} ");
  1162 	__EH_FRAME_PUSH2(r4-r8,lr)
  1163 	
  1164 #ifdef _DEBUG
  1165 	// need to copy aCleanupBundlePtr to somewhere else before it's clobbered by the next line.
  1166 	asm("mov r8, r3 ");														// r8 = &aCleanupBundlePtr
  1167 #endif
  1168 	
  1169 	asm("ldr r3, [r0, #%a0]" : : "i" (_CBASE_VPTR_OFFSET_));				// r3 = vptr
  1170 	asm("add r4, r0, #%a0" : : "i" _FOFF(CActiveScheduler,iActiveQ));		// r4 = &iActiveQ
  1171 	asm("mov r5, r1 ");														// r5 = &aLoop
  1172 	asm("mov r7, r2 ");														// r7 = &aCurrentObj
  1173 	asm("ldr r6, [r3, #%a0]" : : "i" (_CACTIVESCHEDULER_WAIT_OFFSET_));		// r6 = &WaitForAnyRequest()
  1174 
  1175 	asm("active_scheduler_loop: ");
  1176 	asm("ldr r1, [r5] ");													// r1 = aLoop
  1177 	asm("adr lr, 1f ");														// return address
  1178 	asm("sub r0, r4, #%a0 " : : "i" _FOFF(CActiveScheduler,iActiveQ));		// this
  1179 	asm("cmp r1, #0 ");
  1180 	__JUMP(ne, r6);															// call WaitForAnyRequest() if still active
  1181 	__POPRET("r4-r8,");														// else return
  1182 
  1183 	// get here when WaitForAnyRequest() returns
  1184 	asm("1: ");
  1185 	asm("ldr r14, [r4, #0] ");												// r14->first active object
  1186 
  1187 	asm("2: ");
  1188 	asm("cmp r14, r4 ");													// end of queue?
  1189 	asm("sub r0, r14, #%a0" : : "i" _FOFF(CActive,iLink));					// r0->CActive
  1190 	asm("ldmneda r14, {r2, r12, r14} ");									// r2=iStatus, r12=iStatus.iFlags (old iActive), r14 = next object
  1191 	asm("beq PanicStrayEvent ");											// if end of queue, panic
  1192 #ifdef _DEBUG
  1193 	asm("ands r3, r12, #%a0" : : "i" ((TInt)(TRequestStatus::EActive|TRequestStatus::ERequestPending)));	// only active bit and request-pending bit
  1194 	asm("cmpne r3, #%a0" : : "i" ((TInt)(TRequestStatus::EActive|TRequestStatus::ERequestPending)));		// active bit == request pending bit
  1195 	asm("bne PanicStrayEvent ");											// if active bit != request pending bit, panic
  1196 #endif
  1197 	asm("cmp r2, #%a0" : : "i" ((TInt)KRequestPending));					// test if iStatus!=KRequestPending
  1198 	asm("andnes r3, r12, #%a0" : : "i" ((TInt)TRequestStatus::EActive));	// if so, test iActive
  1199 	asm("beq 2b ");															// if not active or still pending, do next CActive
  1200 
  1201 	// have an active object to run
  1202 #ifdef __SMP__
  1203 	__DATA_MEMORY_BARRIER_Z__(r3);											// acquire semantics
  1204 #endif
  1205 	asm("ldr r3, [r0, #%a0]" : : "i" (_CBASE_VPTR_OFFSET_));				// r3=CActive->vptr
  1206 	asm("bic r12, r12, #%a0" : : "i" ((TInt)(TRequestStatus::EActive|TRequestStatus::ERequestPending)));
  1207 	asm("ldr r3, [r3, #%a0]" : : "i" (_CACTIVE_RUNL_OFFSET_));				// r3 = &CActive::RunL()
  1208 	asm("str r12, [r0, #%a0]" : : "i" (_FOFF(CActive,iStatus)+_FOFF(TRequestStatus,iFlags)));	// iActive=EFalse
  1209 	asm("str r0, [r7] ");													// save active object in aCurrentObj in case RunL leaves
  1210 #ifdef _DEBUG
  1211 	__JUMPL(3);															// call RunL() (and continue)
  1212 #else
  1213 	asm("adr lr, active_scheduler_loop ");								// set lr (return address) to label, active_scheduler_loop
  1214 	__JUMP(,r3);														// call RunL() (and loop)
  1215 #endif
  1216 	
  1217 	
  1218 #ifdef _DEBUG
  1219 	//check whether there's a cleanup stack installed:
  1220 
  1221 	asm("cmp r8, #0");															// check CleanupBundle* == NULL
  1222 	asm("beq active_scheduler_loop ");											// If r8 == NULL, branch to label, active_scheduler_loop
  1223 	asm("ldr r0, [r8, #%a0]" : : "i" _FOFF(TCleanupBundle,iCleanupPtr)); 		// r0 = CCleanup* (load the CCleanup*)
  1224 
  1225 	//there is a cleanupstack installed:
  1226 	asm("add r1, r8, #%a0" : : "i" _FOFF(TCleanupBundle,iDummyInt)); 			// r1 = iDummyInt* (load the TInt*)
  1227 	asm("adr lr, active_scheduler_loop ");										// set lr (return address) to label, active_scheduler_loop
  1228 	asm("b  " CSM_ZN8CCleanup5CheckEPv); 										// call CCleanup::Check(iDummyInt*)
  1229 #endif
  1230 	
  1231 	}
  1232 #endif
  1233 
  1234 
  1235 #ifdef __CSERVER_MACHINE_CODED__
  1236 __NAKED__ EXPORT_C void CServer2::RunL()
  1237 	{
  1238 	asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(CServer2,iMessage.iFunction)); // r2=Message().Function()
  1239 	asm("stmfd sp!, {r4, lr}");			// save regs
  1240 	__EH_FRAME_PUSH2(r4,lr)
  1241 	asm("cmp r2, #0");					// check for Connect/Disconnect message
  1242 	asm("bmi server2_con_dis");
  1243 
  1244 	// Service the message
  1245 	asm("mov r4, r0 ");						// r4=this
  1246 	asm("ldr r0, [r4, #%a0]" : : "i" _FOFF(CServer2,iMessage.iSessionPtr)); // r0=session
  1247 	asm("add r1, r4, #%a0" : : "i" (_FOFF(CServer2,iMessage)));	// r1=&iServer.Message()
  1248 	asm("cmp r0, #0");  // Check for NULL session
  1249 	asm("ldrne r12, [r0, #%a0]" : : "i" (_CBASE_VPTR_OFFSET_));			// r12=CSession2::vptr
  1250 #ifdef __SUPPORT_THUMB_INTERWORKING
  1251 	asm("ldrne r3, [r12, #%a0]" : : "i" (_CSESSION2_SERVICEL_OFFSET_));	// call CSession2::ServiceL(iMessage)
  1252 	asm("adr lr, server2_run_postamble ");
  1253 	asm("bxne r3 ");
  1254 #else
  1255 	asm("adr lr, server2_run_postamble ");
  1256 	asm("ldrne pc, [r12, #%a0]" : : "i" (_CSESSION2_SERVICEL_OFFSET_));	// call CSession2::ServiceL(iMessage)
  1257 #endif
  1258 	asm("mov r0, r1");
  1259 	asm("b  " CSM_ZN8CServer212NotConnectedERK9RMessage2); // NULL session ptr means not connected
  1260 
  1261 	// Do this after processing any message
  1262 	asm("server2_run_postamble: ");
  1263 	asm("ldr r2, [r4, #%a0]" : : "i" (_FOFF(CServer2,iStatus)+_FOFF(TRequestStatus,iFlags)));	// r2=iStatus.iFlags (old iActive)
  1264 	asm("mov r0, #0x80000001 ");								// r0=KRequestPending
  1265 	asm("ands r1, r2, #%a0" : : "i" ((TInt)TRequestStatus::EActive));
  1266 	asm("bne server2_run_end ");							// if already active, finished
  1267 	asm("orr r2, r2, #%a0" : : "i" ((TInt)(TRequestStatus::EActive|TRequestStatus::ERequestPending)));
  1268 	asm("add r1, r4, #%a0" : : "i" _FOFF(CActive,iStatus));		// r1->iStatus
  1269 	asm("stmia r1, {r0,r2} "); // set iStatus=KRequestPending, set active bit, set request pending bit
  1270 	asm("add r2, r4, #%a0" : : "i" _FOFF(CServer2,iMessage));	// r2->iServer.Message()
  1271 	asm("ldr r0, [r4, #%a0]" : : "i" _FOFF(CServer2,iServer));	// r0=iServer.iHandle
  1272 	asm("bl  " CSM_ZN4Exec13ServerReceiveEiR14TRequestStatusPv);// call Exec::ServerReceive
  1273 	asm("server2_run_end: ");
  1274 	__POPRET("r4,");
  1275 
  1276 	// Deal with Connect and Disconnect messages
  1277 	asm("server2_con_dis:");	
  1278 	asm("mov r4, r0 ");					// r4=this
  1279 	asm("add r1, r0, #%a0" : : "i" _FOFF(CServer2,iMessage)); // r1=&iServer.Message()
  1280 	asm("adr lr, server2_run_postamble "); // return address for after any processing
  1281 	asm("cmp r2, #%a0" : : "i" (RMessage2::EConnect));
  1282 	asm("beq  " CSM_ZN8CServer27ConnectERK9RMessage2); // Do Connect()
  1283 	asm("cmp r2, #%a0" : : "i" (RMessage2::EDisConnect));
  1284 	asm("beq  " CSM_ZN8CServer210DisconnectERK9RMessage2); // Do Disconnect()
  1285 	asm("mov r0, r1");
  1286 	asm("b  " CSM_ZN8CServer210BadMessageERK9RMessage2); // Bad message
  1287 	}
  1288 #endif
  1289 
  1290 EXPORT_C __NAKED__ void RFastLock::Wait()
  1291 	{
  1292 	asm("1: ");
  1293 	asm("add	r0, r0, #4 ");					// point to iCount
  1294 
  1295 #ifdef __CPU_ARM_HAS_LDREX_STREX
  1296 	asm("2:		");
  1297 	LDREX(		2, 0);							// read
  1298 	asm("subs	r1, r2, #1 ");					// decrement
  1299 	STREX(		3, 1, 0);						// write
  1300 	asm("teq	r3, #0 ");						// success?
  1301 	asm("bne	2b ");							// no!
  1302 	asm("sub	r0, r0, #4 ");					// r0 = this
  1303 	asm("bcs "	CSM_ZN10RSemaphore4WaitEv);		// if no borrow from decrement wait on semaphore
  1304 #ifdef __SMP__
  1305 	__DATA_MEMORY_BARRIER__(r3);				// no need to wait, but still need acquire barrier
  1306 #endif
  1307 	__JUMP(,	lr );
  1308 #else
  1309 	asm("mov	r1, #1 ");						// 'looking' value
  1310 	asm("swp	r1, r1, [r0] ");				// write looking value, read original
  1311 	asm("subs	r1, r1, #1 ");					// decrement count
  1312 	asm("strlt	r1, [r0] ");					// if it becomes negative, no-one was looking
  1313 	__JUMP(cc,	lr);							// if borrow, was originally zero so we are finished
  1314 	asm("sub	r0, r0, #4 ");					// r0=this
  1315 	asm("blt "	CSM_ZN10RSemaphore4WaitEv);		// lock held so wait on semaphore
  1316 	asm("stmfd	sp!, {r0,lr} ");				// otherwise save registers
  1317 	asm("mov	r0, #1000 ");					// someone was looking, so wait 1ms and try again
  1318 	asm("bl "	CSM_ZN4User12AfterHighResE27TTimeIntervalMicroSeconds32);
  1319 	asm("ldmfd	sp!, {r0,lr} ");
  1320 	asm("b		1b ");
  1321 #endif
  1322 	}
  1323 
  1324 EXPORT_C __NAKED__ void RFastLock::Signal()
  1325 	{
  1326 	asm("1: ");
  1327 	asm("add	r0, r0, #4 ");					// point to iCount
  1328 
  1329 #ifdef __CPU_ARM_HAS_LDREX_STREX
  1330 #ifdef __SMP__
  1331 	__DATA_MEMORY_BARRIER_Z__(r3);				// need release barrier
  1332 #endif
  1333 	asm("2:		");
  1334 	LDREX(		2, 0);							// read
  1335 	asm("adds	r1, r2, #1 ");					// increment
  1336 	STREX(		3, 1, 0);						// write
  1337 	asm("teq	r3, #0 ");						// success?
  1338 	asm("bne	2b ");							// no!
  1339 	asm("sub	r0, r0, #4 ");					// r0 = this
  1340 	asm("bcc "	CSM_ZN10RSemaphore6SignalEv);	// if no carry from increment, signal semaphore
  1341 	__JUMP(,	lr );
  1342 #else
  1343 	asm("mov	r1, #1 ");						// 'looking' value
  1344 	asm("swp	r1, r1, [r0] ");				// write looking value, read original
  1345 	asm("adds	r1, r1, #1 ");					// increment count
  1346 	asm("strle	r1, [r0] ");					// if still <=0, no-one was looking
  1347 	__JUMP(eq,	lr);							// if it's now zero, no-one is waiting so we are finished
  1348 	asm("sub	r0, r0, #4 ");					// r0=this
  1349 	asm("blt "	CSM_ZN10RSemaphore6SignalEv);	// someone is waiting so signal semaphore
  1350 	asm("stmfd	sp!, {r0,lr} ");				// otherwise save registers
  1351 	asm("mov	r0, #1000 ");					// someone was looking, so wait 1ms and try again
  1352 	asm("bl "	CSM_ZN4User12AfterHighResE27TTimeIntervalMicroSeconds32);
  1353 	asm("ldmfd	sp!, {r0,lr} ");
  1354 	asm("b		1b ");
  1355 #endif
  1356 	}
  1357 
  1358 
  1359 // Entry point stub to allow EKA1 binaries to be executed under EKA2
  1360 // Only called when process is first loaded
  1361 
  1362 extern "C" TLinAddr GetEka1ExeEntryPoint();
  1363 
  1364 __NAKED__ TInt E32Loader::V7ExeEntryStub()
  1365 	{
  1366 	// Process entry point
  1367 	// R4 = entry reason
  1368 	// SP points to information block
  1369 	asm("cmp r4, #%a0" : : "i" ((TInt)KModuleEntryReasonProcessInit) );
  1370 	asm("bne " CSM_ZN4User9InvariantEv );	// invalid entry reason
  1371 	asm("bl GetEka1ExeEntryPoint ");		// load the entry stub and return its address
  1372 	__JUMP(,r0);							// jump to the entry stub with R4, SP unchanged
  1373 	}
  1374 
  1375 __NAKED__ TInt E32Loader::V7DllEntryStub(TInt)
  1376 	{
  1377 
  1378 	__JUMP(,lr);
  1379 	}
  1380 
  1381 
  1382 // Hash an 8 bit string at aPtr, length aLen bytes.
  1383 __NAKED__ TUint32 DefaultStringHash(const TUint8* /*aPtr*/, TInt /*aLen*/)
  1384 	{
  1385 	asm("ldr r3, one_over_phi ");
  1386 	asm("subs r1, r1, #4 ");
  1387 	asm("mov r2, r0 ");
  1388 	asm("mov r0, #0 ");
  1389 	asm("blo 1f ");
  1390 	asm("ands r12, r2, #3 ");
  1391 	asm("bne hash_unal ");
  1392 	asm("2: ");
  1393 	asm("ldr r12, [r2], #4 ");
  1394 	asm("subs r1, r1, #4 ");
  1395 	asm("eor r0, r0, r12 ");
  1396 	asm("umull r0, r12, r3, r0 ");
  1397 	asm("bcs 2b ");
  1398 	asm("1: ");
  1399 	asm("adds r1, r1, #4 ");
  1400 	__JUMP(eq,lr);
  1401 	asm("4: ");
  1402 	asm("ldrb r12, [r2], #1 ");
  1403 	asm("cmp r1, #2 ");
  1404 	asm("eor r0, r0, r12 ");
  1405 	asm("ldrcsb r12, [r2], #1 ");
  1406 	asm("eorcs r0, r0, r12, lsl #8 ");
  1407 	asm("ldrhib r12, [r2], #1 ");
  1408 	asm("eorhi r0, r0, r12, lsl #16 ");
  1409 	asm("umull r0, r12, r3, r0 ");
  1410 	__JUMP(,lr);
  1411 
  1412 	asm("hash_unal: ");
  1413 	asm("bic r2, r2, #3 ");
  1414 	asm("stmfd sp!, {r4,r5,lr} ");
  1415 	asm("mov r12, r12, lsl #3 ");
  1416 	asm("rsb r14, r12, #32 ");
  1417 	asm("ldr r4, [r2], #4 ");
  1418 	asm("3: ");
  1419 	asm("eor r0, r0, r4, lsr r12 ");
  1420 	asm("ldr r4, [r2], #4 ");
  1421 	asm("subs r1, r1, #4 ");
  1422 	asm("eor r0, r0, r4, lsl r14 ");
  1423 	asm("umull r0, r5, r3, r0 ");
  1424 	asm("bcs 3b ");
  1425 	asm("adds r1, r1, #4 ");
  1426 	asm("ldmfd sp!, {r4,r5,lr} ");
  1427 	asm("subne r2, r2, #4 ");
  1428 	asm("addne r2, r2, r12, lsr #3 ");
  1429 	asm("bne 4b ");
  1430 	__JUMP(,lr);
  1431 	}
  1432 
  1433 // Hash a 16 bit string at aPtr, length aLen bytes.
  1434 __NAKED__ TUint32 DefaultWStringHash(const TUint16* /*aPtr*/, TInt /*aLen*/)
  1435 	{
  1436 	asm("str lr, [sp, #-4]! ");
  1437 	asm("ldr r3, one_over_phi ");
  1438 	asm("subs r1, r1, #8 ");
  1439 	asm("mov r2, r0 ");
  1440 	asm("mov r0, #0 ");
  1441 	asm("blo 1f ");
  1442 	asm("ands r12, r2, #3 ");
  1443 	asm("bne whash_unal ");
  1444 	asm("2: ");
  1445 	asm("ldmia r2!, {r12,r14} ");
  1446 	asm("subs r1, r1, #8 ");
  1447 	asm("eor r0, r0, r12 ");
  1448 	asm("eor r0, r0, r14, ror #24 ");
  1449 	asm("umull r0, r12, r3, r0 ");
  1450 	asm("bcs 2b ");
  1451 	asm("1: ");
  1452 	asm("adds r1, r1, #8 ");
  1453 	asm("beq 8f ");
  1454 	asm("4: ");
  1455 	asm("ldrh r12, [r2], #2 ");
  1456 	asm("cmp r1, #4 ");
  1457 	asm("eor r0, r0, r12 ");
  1458 	asm("ldrcsh r12, [r2], #2 ");
  1459 	asm("eorcs r0, r0, r12, lsl #16 ");
  1460 	asm("ldrhih r12, [r2], #2 ");
  1461 	asm("eorhi r0, r0, r12, ror #24 ");
  1462 	asm("umull r0, r12, r3, r0 ");
  1463 	asm("8: ");
  1464 	__POPRET("");
  1465 
  1466 	asm("whash_unal: ");
  1467 	asm("add r2, r2, #2 ");				// r2 must be 2 mod 4
  1468 	asm("ldr r14, [r2, #-4] ");
  1469 	asm("3: ");
  1470 	asm("eor r0, r0, r14, lsr #16 ");	// char 0 goes into bytes 0,1
  1471 	asm("ldmia r2!, {r12,r14} ");
  1472 	asm("subs r1, r1, #8 ");
  1473 	asm("eor r0, r0, r12, lsl #16 ");	// char 1 goes into bytes 2,3
  1474 	asm("mov r12, r12, lsr #16 ");
  1475 	asm("orr r12, r12, r14, lsl #16 ");	// r12 = char3:char2
  1476 	asm("eor r0, r0, r12, ror #24 ");	// char 2 into bytes 1,2 ; char 3 into bytes 3,0
  1477 	asm("umull r0, r12, r3, r0 ");
  1478 	asm("bcs 3b ");
  1479 	asm("adds r1, r1, #8 ");
  1480 	asm("subne r2, r2, #2 ");
  1481 	asm("bne 4b ");
  1482 	__POPRET("");
  1483 	}
  1484 
  1485 
  1486 /**
  1487 @publishedAll
  1488 @released
  1489 
  1490 Calculate a 32 bit hash from a 32 bit integer.
  1491 
  1492 @param	aInt	The integer to be hashed.
  1493 @return			The calculated 32 bit hash value.
  1494 */
  1495 EXPORT_C __NAKED__ TUint32 DefaultHash::Integer(const TInt& /*aInt*/)
  1496 	{
  1497 	asm("ldr r0, [r0] ");
  1498 	asm("ldr r1, one_over_phi ");
  1499 	asm("umull r0, r2, r1, r0 ");
  1500 	__JUMP(,lr);
  1501 	asm("one_over_phi: ");
  1502 	asm(".word 0x9e3779b9 ");
  1503 	}
  1504 
  1505 
  1506 #ifdef __USERSIDE_THREAD_DATA__
  1507 
  1508 /**
  1509 @internalComponent
  1510 
  1511 Get a pointer to the thread local user data stored in the thread ID register.
  1512 */
  1513 __NAKED__ TLocalThreadData* LocalThreadData()
  1514 	{
  1515 	GET_RWRW_TID(,r0);
  1516 	__JUMP(,lr);	
  1517 	}
  1518 
  1519 #endif