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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\euser\epoc\arm\uc_utl.cia
23 #include <e32hashtab.h>
28 #if defined(__MEM_MACHINE_CODED__)
29 EXPORT_C __NAKED__ void Mem::Swap(TAny* /*aPtr1*/, TAny* /*aPtr2*/, TInt /*aLength*/)
31 Swaps a number of bytes of data between two specified locations.
33 The source and target areas can overlap.
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.
40 @panic USER 94 In debug builds only, if aLength is negative.
48 // Test for same alignment, if more than 16 bytes to swap
53 asm(" addlt r3,r3,#4");
55 asm(" beq same_aligned_swap");
57 asm(" stmfd sp!,{r4,lr}");
63 asm(" strb r3,[r1],#1");
64 asm(" strb r4,[r0],#1");
65 asm(" subs r2,r2,#1");
66 asm("beq swap_exit1 ");
70 asm(" strb r3,[r1],#1");
71 asm(" strb r4,[r0],#1");
72 asm(" subs r2,r2,#1");
73 asm("beq swap_exit1 ");
77 asm(" strb r3,[r1],#1");
78 asm(" strb r4,[r0],#1");
79 asm(" subs r2,r2,#1");
80 asm("beq swap_exit1 ");
84 asm(" strb r3,[r1],#1");
85 asm(" strb r4,[r0],#1");
86 asm(" subs r2,r2,#1");
87 asm(" bne swap_loop");
91 asm("same_aligned_swap:");
93 asm(" stmfd sp!,{r4-r10,lr}");
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
103 asm(" subs r3,r3,#1");
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
110 // Jumps here if 3 bytes to swap before word aligned
112 asm(" ldrb r4,[r0]");
113 asm(" ldrb ip,[r1]");
114 asm(" strb r4,[r1],#1");
115 asm(" strb ip,[r0],#1");
117 // Jumps here if 2 bytes to swap before word aligned
119 asm(" ldrb r4,[r0]");
120 asm(" ldrb ip,[r1]");
121 asm(" strb r4,[r1],#1");
122 asm(" strb ip,[r0],#1");
124 // Jumps here if 1 byte to swap before word aligned
126 asm(" ldrb r4,[r0]");
127 asm(" ldrb ip,[r1]");
128 asm(" strb r4,[r1],#1");
129 asm(" strb ip,[r0],#1");
131 // We are now word aligned. Fast swapping, here we come...
133 asm("word_aligned_swap:");
134 asm(" movs ip,r2,lsr #6"); // Number of 64 blocks to swap
135 asm(" beq its_smaller_swap");
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");
157 // Less than 64 bytes to go...
159 asm("its_smaller_swap:");
160 asm(" ands r2,r2,#63");
161 asm("beq swap_exit2 ");
163 asm(" blt finish_swap");
164 asm("final_swap_loop:");
167 asm(" str r3,[r0],#4");
168 asm(" str ip,[r1],#4");
169 asm(" subs r2,r2,#4");
171 asm(" bge final_swap_loop");
173 // Less than 4 bytes to go...
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");
187 asm(" ldrneb r3,[r0]");
188 asm(" ldrneb ip,[r1]");
189 asm(" strneb r3,[r1],#1");
190 asm(" strneb ip,[r0],#1");
197 #ifdef __REGIONS_MACHINE_CODED__
199 __NAKED__ GLDEF_C void AllocAnotherRect( TRegion * /*aRegion*/ )
201 // Returns with Z flag set to indicate error
203 asm("ldr r1, [r0, #4] "); // r1=iError
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
212 asm("b " CSM_ZN7TRegion10ForceErrorEv); // if so, ForceError()
213 asm("allocanother1: ");
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))
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()
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
242 asm("allocanother3: "); // come here if RRegion
243 asm("cmp r1, r12 "); // check if iCount==iAllocedRects
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
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
257 asm("b " CSM_ZN7TRegion10ForceErrorEv); // else ForceError()
261 __NAKED__ EXPORT_C void TRegion::ForceError()
263 // Returns with Z flag set to indicate error
265 asm("stmfd sp!, {r0,lr} ");
266 asm("bl " CSM_ZN7TRegion5ClearEv); // Clear()
267 asm("ldmfd sp!, {r0,lr} "); // restore r0,lr
269 asm("str r1, [r0, #4] "); // iError=ETrue
270 asm("return_error: ");
271 asm("movs r0, #0 "); // set Z flag to indicate error
277 __NAKED__ EXPORT_C TRect TRegion::BoundingRect() const
279 Gets the minimal rectangle that bounds the entire region.
281 @return The region's minimal bounding rectangle.
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} ");
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
311 asm("boundingrect0: ");
312 asm("mov r1, #0 "); // if list empty, bounds = 0,0,0,0
315 asm("stmia r0, {r1,r2,r3,r12} "); // store result
322 __NAKED__ EXPORT_C TBool TRegion::IsContainedBy(const TRect & /*aRect*/) const
324 Tests whether the region is fully enclosed within the specified rectangle.
326 @param aRect The specified rectangle.
328 @return True, if the region is fully enclosed within the rectangle (their sides
329 may touch); false, otherwise.
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
339 asm("ldr r0, [r0] "); // r0=iCount
340 asm("ldmia r1, {r4-r7} "); // aRect coordinates into r4-r7
342 asm("subs r0, r0, #1 "); // decrement it
343 asm("bmi iscontainedby2 "); // if iCount was zero, return TRUE
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
361 __NAKED__ EXPORT_C void TRegion::Copy(const TRegion & /*aRegion*/)
363 Copies another region to this region.
365 The state of the specified region's error flag is also copied.
367 @param aRegion The region to be copied.
370 asm("ldr r2, [r1, #4] "); // r2 = aRegion.iError
372 asm("bne " CSM_ZN7TRegion10ForceErrorEv); // if (aRegion.iError) ForceError();
373 asm("ldr r2, [r1] "); // r1 = aRegion.iCount
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
379 asm("ldr r2, [r0, #4] "); // r2 = iError
381 asm("blne " CSM_ZN7TRegion5ClearEv); // if (iError) Clear();
383 asm("ldr r1, [r4] "); // r1 = aRegion.iCount, r0 = this
384 asm("bl " CSM_ZN7TRegion11SetListSizeEi); // SetListSize(aRegion.iCount);
386 asm("beq copyregion_end ");
387 asm("ldr r3, [r4] "); // r3 = aRegion.iCount
389 asm("str r3, [r5] "); // iCount=aRegion.iCount
390 asm("beq copyregion_end ");
391 asm("ldr r0, [r5, #8] "); // r0 points to first rectangle
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
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 ");
407 asm("copyregion_end: ");
408 __POPRET("r0,r1,r4,r5,r6,");
414 __NAKED__ EXPORT_C void TRegion::Offset(const TPoint & /*anOffset*/)
416 Moves the region by adding a TPoint offset to the co-ordinates of its corners.
418 The size of the region is not changed.
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.
424 asm("ldmia r1, {r1,r2} "); // r1=anOffset.iX, r2=anOffset.iY
431 __NAKED__ EXPORT_C void TRegion::Offset(TInt /*xOffset*/,TInt /*yOffset*/)
433 Moves the region by adding X and Y offsets to the co-ordinates of its corners.
435 The size of the region is not changed.
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.
443 asm("ldr r12, [r0] "); // r12=iCount
446 asm("ldr r3, [r0, #8] "); // r0 points to first rectangle
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 ");
467 __NAKED__ EXPORT_C TBool TRegion::Contains(const TPoint & /*aPoint*/) const
469 Tests whether a point is located within the region.
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.
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.
477 @param aPoint The specified point.
479 @return True, if the point is within the region; false, otherwise.
482 asm("ldr r12, [r0] "); // r12 = iCount
483 asm("stmfd sp!, {r4,r5,lr} ");
485 asm("beq contains0 "); // if iCount=0, return FALSE
486 asm("ldr r3, [r0, #8] "); // r0 points to first rectangle
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
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
500 asm("subges r12, r12, #1 "); // if >=, aPoint is not contained in rect, so iterate
501 asm("bgt contains1 ");
503 asm("movne r0, #1 "); // if r12 non-zero, return TRUE else FALSE
505 asm("moveq r0, #0 ");
512 __NAKED__ EXPORT_C TBool TRegion::Intersects(const TRect &/*aRect*/) const
514 Tests whether where there is any intersection between this region and the specified rectangle.
516 @param aRect The specified rectangle.
518 @return True, if there is an intersection; false, otherwise.
521 asm("ldr r12, [r0] "); // r12 = iCount
522 asm("stmfd sp!, {r4-r7,lr} ");
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)
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 ");
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 ");
544 asm("intersects0: ");
545 asm("movge r0, #0 ");
546 asm("movlt r0, #1 ");
553 __NAKED__ void TRegion::DeleteRect(TRect * /*aRect*/)
555 // Delete a specific rectangle in the list.
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--;
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
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 ");
582 __NAKED__ EXPORT_C void TRegion::ClipRect(const TRect & /*aRect*/)
584 Clips the region to the specified rectangle.
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.
590 @param aRect The rectangle to which this region is to be clipped.
594 asm("ldr r12, [r0] "); // r12=iCount
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
601 asm("ldrcc r1, [r0, #16] "); // if RRegion
602 asm("addcs r1, r0, #20 "); // RRegionBuf
603 asm("submi r1, r1, #8 "); // TRegionFix
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] ");
611 asm("movlt r7, r3 ");
612 asm("strlt r3, [r1, #-12] ");
614 asm("movgt r8, r4 ");
615 asm("strgt r4, [r1, #-8] ");
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
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 ");
636 asm("movlt r7, r3 ");
638 asm("movgt r8, r4 ");
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
656 __NAKED__ EXPORT_C void TRegion::SubRect(const TRect& /*aRect*/,TRegion* /*aSubtractedRegion*/)
658 Removes a rectangle from this region.
660 If there is no intersection between the rectangle and this region, then this
661 region is unaffected.
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
669 asm("ldr r12, [r0] "); // r12=iCount=limit
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
678 asm("mov r3, #0 "); // r3=index
680 asm("ldr lr, [r0, #8] "); // lr points to first rectangle
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
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
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
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
732 asm("subrect_end: ");
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
742 asm("ldr r12, [r0] "); // r12=iCount
743 asm("ldr lr, [r0, #8] "); // lr points to first rectangle
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: ");
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
763 asm("ldr r12, [r0] "); // r12=iCount
764 asm("ldr lr, [r0, #8] "); // lr points to first rectangle
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
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
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
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
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
816 // aSubtractedRegion->AddRect(inter)
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,");
828 __NAKED__ EXPORT_C void TRegion::Intersection(const TRegion& /*aRegion1*/,const TRegion& /*aRegion2*/)
830 Replaces this region with the area of intersection between two specified regions.
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.
837 2. If this region's error flag is already set, then the function has no effect.
839 @param aRegion1 The first region.
840 @param aRegion2 The second region.
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
852 asm("cmpne r12, #0 ");
854 asm("stmfd sp!, {r3-r11,lr} ");
855 asm("ldr lr, [r1, #8] "); // r1 points to first rectangle of aRegion1 = pRect1
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
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 ");
878 asm("movgt r9, r5 ");
880 asm("movlt r10, r6 ");
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 ");
889 asm("ldr r12, [r0] "); // r12=iCount
890 asm("ldr lr, [r0, #8] "); // lr points to first rectangle
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
907 asm("intersection_end: ");
916 #ifdef __COBJECT_MACHINE_CODED__
917 __NAKED__ EXPORT_C CObject *CObjectIx::At(TInt /*aHandle*/,TInt /*aUniqueID*/)
919 Gets a pointer to the reference counting object with the specified handle
920 number and matching unique ID.
922 @param aHandle The handle number of the reference counting object.
923 @param aUniqueID The unique ID.
925 @return A pointer to the reference counting object. If there is no matching
926 object, then this is NULL.
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
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
950 __NAKED__ EXPORT_C CObject *CObjectIx::At(TInt aHandle)
952 Gets a pointer to the reference counting object with the specified
955 @param aHandle The handle number of the reference counting object.
957 @return A pointer to the reference counting object. If there is no matching
958 object, then this is NULL.
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
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
976 asm("__instanceMask: ");
977 asm(".word 0x3FFF0000 ");
983 GLREF_C void PanicCObjectIxIndexOutOfRange(void);
988 __NAKED__ EXPORT_C CObject* CObjectIx::operator[](TInt /*anIndex*/)
990 Gets a pointer to a reference counting object located at the specified offset
991 within the object index.
993 @param anIndex The offset of the reference counting object within the object
994 index. Offset is relative to zero.
996 @return A pointer to the reference counting object.
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
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
1017 asm("b " CSM_Z29PanicCObjectIxIndexOutOfRangev); // if anIndex<0 or iCount<=anIndex, panic
1023 GLREF_C void PanicCObjectConIndexOutOfRange(void);
1024 GLREF_C void PanicCObjectConFindBadHandle(void);
1025 GLREF_C void PanicCObjectConFindIndexOutOfRange(void);
1030 __NAKED__ EXPORT_C CObject *CObjectCon::operator[](TInt /*anIndex*/)
1032 Gets a pointer to the reference counting object located at the specified offset
1033 within the object container.
1035 @param anIndex The offset of the reference counting object within the object
1036 container. Offset is relative to zero.
1038 @return A pointer to the owning reference counting object.
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.
1044 // r0=this, r1=anIndex
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] ");
1057 asm("b " CSM_Z30PanicCObjectConIndexOutOfRangev);
1063 __NAKED__ EXPORT_C CObject *CObjectCon::At(TInt /*aFindHandle*/) const
1065 Gets a pointer to the reference counting object with the specified find-handle
1068 A find-handle number is an integer which uniquely identifies a reference
1069 counting object with respect to its object container.
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
1077 @return A pointer to the reference counting object.
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.
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] ");
1102 __NAKED__ EXPORT_C CObject *CObjectCon::AtL(TInt /*aFindHandle*/) const
1104 Gets a pointer to the reference counting object with the specified find-handle
1105 number, and leaves on error.
1107 A find-handle number is an integer which uniquely identifies a reference
1108 counting object with respect to its object container.
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
1116 @return A pointer to the reference counting object.
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.
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));
1130 asm("mov r1, r1, lsl #17 ");
1131 asm("cmp r2, r1, lsr #17 ");
1132 asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iObjects));
1134 asm("ldr r0, [r0, r1, lsr #15] ");
1136 // User::Leave tail called, so no annotations required since
1137 // current frame is reused by User::Leave
1139 asm("mvn r0, #7 "); // KErrBadHandle
1140 asm("b " CSM_ZN4User5LeaveEi);
1142 asm("mvn r0, #5 "); // KErrArgument
1143 asm("b " CSM_ZN4User5LeaveEi);
1147 #ifdef __CACTIVESCHEDULER_MACHINE_CODED__
1148 extern "C" void PanicStrayEvent();
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.
1157 Stop when aLoop becomes 'Inactive'
1159 __NAKED__ void CActiveScheduler::DoRunL(TLoopOwner* const volatile& aLoop, CActive* volatile & aCurrentObj, TCleanupBundle* aCleanupBundlePtr)
1161 asm("stmfd sp!, {r4-r8,lr} ");
1162 __EH_FRAME_PUSH2(r4-r8,lr)
1165 // need to copy aCleanupBundlePtr to somewhere else before it's clobbered by the next line.
1166 asm("mov r8, r3 "); // r8 = &aCleanupBundlePtr
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()
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
1180 __JUMP(ne, r6); // call WaitForAnyRequest() if still active
1181 __POPRET("r4-r8,"); // else return
1183 // get here when WaitForAnyRequest() returns
1185 asm("ldr r14, [r4, #0] "); // r14->first active object
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
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
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
1201 // have an active object to run
1203 __DATA_MEMORY_BARRIER_Z__(r3); // acquire semantics
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
1211 __JUMPL(3); // call RunL() (and continue)
1213 asm("adr lr, active_scheduler_loop "); // set lr (return address) to label, active_scheduler_loop
1214 __JUMP(,r3); // call RunL() (and loop)
1219 //check whether there's a cleanup stack installed:
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*)
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*)
1235 #ifdef __CSERVER_MACHINE_CODED__
1236 __NAKED__ EXPORT_C void CServer2::RunL()
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");
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 ");
1255 asm("adr lr, server2_run_postamble ");
1256 asm("ldrne pc, [r12, #%a0]" : : "i" (_CSESSION2_SERVICEL_OFFSET_)); // call CSession2::ServiceL(iMessage)
1259 asm("b " CSM_ZN8CServer212NotConnectedERK9RMessage2); // NULL session ptr means not connected
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: ");
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()
1286 asm("b " CSM_ZN8CServer210BadMessageERK9RMessage2); // Bad message
1290 EXPORT_C __NAKED__ void RFastLock::Wait()
1293 asm("add r0, r0, #4 "); // point to iCount
1295 #ifdef __CPU_ARM_HAS_LDREX_STREX
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
1305 __DATA_MEMORY_BARRIER__(r3); // no need to wait, but still need acquire barrier
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} ");
1324 EXPORT_C __NAKED__ void RFastLock::Signal()
1327 asm("add r0, r0, #4 "); // point to iCount
1329 #ifdef __CPU_ARM_HAS_LDREX_STREX
1331 __DATA_MEMORY_BARRIER_Z__(r3); // need release barrier
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
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} ");
1359 // Entry point stub to allow EKA1 binaries to be executed under EKA2
1360 // Only called when process is first loaded
1362 extern "C" TLinAddr GetEka1ExeEntryPoint();
1364 __NAKED__ TInt E32Loader::V7ExeEntryStub()
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
1375 __NAKED__ TInt E32Loader::V7DllEntryStub(TInt)
1382 // Hash an 8 bit string at aPtr, length aLen bytes.
1383 __NAKED__ TUint32 DefaultStringHash(const TUint8* /*aPtr*/, TInt /*aLen*/)
1385 asm("ldr r3, one_over_phi ");
1386 asm("subs r1, r1, #4 ");
1390 asm("ands r12, r2, #3 ");
1391 asm("bne hash_unal ");
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 ");
1399 asm("adds r1, r1, #4 ");
1402 asm("ldrb r12, [r2], #1 ");
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 ");
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 ");
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 ");
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 ");
1433 // Hash a 16 bit string at aPtr, length aLen bytes.
1434 __NAKED__ TUint32 DefaultWStringHash(const TUint16* /*aPtr*/, TInt /*aLen*/)
1436 asm("str lr, [sp, #-4]! ");
1437 asm("ldr r3, one_over_phi ");
1438 asm("subs r1, r1, #8 ");
1442 asm("ands r12, r2, #3 ");
1443 asm("bne whash_unal ");
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 ");
1452 asm("adds r1, r1, #8 ");
1455 asm("ldrh r12, [r2], #2 ");
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 ");
1466 asm("whash_unal: ");
1467 asm("add r2, r2, #2 "); // r2 must be 2 mod 4
1468 asm("ldr r14, [r2, #-4] ");
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 ");
1479 asm("adds r1, r1, #8 ");
1480 asm("subne r2, r2, #2 ");
1490 Calculate a 32 bit hash from a 32 bit integer.
1492 @param aInt The integer to be hashed.
1493 @return The calculated 32 bit hash value.
1495 EXPORT_C __NAKED__ TUint32 DefaultHash::Integer(const TInt& /*aInt*/)
1497 asm("ldr r0, [r0] ");
1498 asm("ldr r1, one_over_phi ");
1499 asm("umull r0, r2, r1, r0 ");
1501 asm("one_over_phi: ");
1502 asm(".word 0x9e3779b9 ");
1506 #ifdef __USERSIDE_THREAD_DATA__
1511 Get a pointer to the thread local user data stored in the thread ID register.
1513 __NAKED__ TLocalThreadData* LocalThreadData()