2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 #define OBJC_LOCK_ROUTINE _simple_lock
27 ; _objc_entryPoints and _objc_exitPoints are used by moninitobjc() to setup
28 ; objective-C messages for profiling. The are made private_externs when in
30 .reference _moninitobjc
33 .globl _objc_entryPoints
36 .long _objc_msgSendSuper
40 .globl _objc_exitPoints
52 #define OBJC_LOCK_ROUTINE _spin_lock
63 ; optimized for hppa: 20? clocks (best case) + 6 clocks / probe
70 ldil L`__objc_multithread_mask,%r1
71 ldw R`__objc_multithread_mask(%r1),%r19
73 b,n L0 ; if (self & multi) goto normalcase
75 b,n LSendLocking ; else if (self) goto lockingcase
77 bv 0(%r2) ; else return null
78 copy 0,%r28 ; <delay slot> return val = 0
80 ldw isa(0,%r26),%r19 ; class = self->isa;
81 ldw cache(0,%r19),%r20 ; cache = class->cache
82 ldw mask(0,%r20),%r21 ; mask = cache->mask
83 ldo buckets(%r20),%r20 ; buckets = cache->buckets
84 and %r21,%r25,%r22 ; index = selector & mask;
86 ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index];
87 comib,=,n 0,%r19,LcacheMiss ; if (method == NULL)
88 ldw method_name(0,%r19),%r1 ;
89 addi 1,%r22,%r22 ; ++index
90 comb,<> %r1, %r25, L1 ; if (name!=sel) continue loop
91 and %r21,%r22,%r22 ; <delay slot> index &=mask
92 ldw method_imp(0,%r19),%r19
94 bv,n 0(%r19) ; goto *imp; (nullify delay)
97 .space 128 ; /* area for moninitobjc to write */
101 ; We have to save all the register based arguments (including floating
102 ; point) before calling _class_lookupMethodAndLoadCache. This is because
103 ; we do not know what arguments were passed to us, and the arguments are
104 ; not guaranteed to be saved across procedure calls (they are all caller-saved)
105 ; We also have to save the return address (since we did not save it on entry).
109 ldo 128(%r30),%r30 ; Allocate space on stack
110 stwm %r2,4(0,%r19) ; Save return pointer
111 stwm %r23,4(0,%r19) ; Save old args
112 stwm %r24,4(0,%r19) ;
113 stwm %r25,4(0,%r19) ;
114 stwm %r26,4(0,%r19) ;
116 fstds,mb %fr4,4(0,%r19) ; Save floating point args
117 fstds,mb %fr5,8(0,%r19) ; mb (modify before) is used instead
118 fstds,mb %fr6,8(0,%r19) ; of ma (as is implicit in above
119 fstds,mb %fr7,8(0,%r19) ; stores) with an initial value of 4
120 ; so that doubles are aligned
121 ; to 8 byte boundaries.
122 ; Arg 1 (selector) is the same
125 stw %r28,8(0,%r19) ; save return struct ptr
126 ldw isa(0,%r26),%r26 ; <delay slot> arg 0 = self->isa
127 CALL_EXTERN(__class_lookupMethodAndLoadCache)
129 ldo -128(%r30),%r30 ; deallocate
131 ldwm 4(0,%r19),%r2 ; restore everything
132 ldwm 4(0,%r19),%r23 ;
133 ldwm 4(0,%r19),%r24 ;
134 ldwm 4(0,%r19),%r25 ;
135 ldwm 4(0,%r19),%r26 ;
137 fldds,mb 4(0,%r19),%fr4 ; see comment above about alignment
138 fldds,mb 8(0,%r19),%fr5 ;
139 fldds,mb 8(0,%r19),%fr6 ;
140 fldds,mb 8(0,%r19),%fr7 ;
142 ldw 8(0,%r19),%r20 ; get ret structure ptr
145 copy %r20,%r28 ; restore ret structure ptr
147 bv,n 0(%r19) ; goto *imp (nullify delay)
150 .space 128 ; /* area for moninitobjc to write */
155 ; Locking version of objc_msgSend
156 ; uses spin_lock() to lock the mutex.
160 ldo 128(%r30),%r30 ; Allocate space on stack
161 stwm %r2,4(0,%r19) ; Save return pointer
162 stwm %r23,4(0,%r19) ; Save old args
163 stwm %r24,4(0,%r19) ;
164 stwm %r25,4(0,%r19) ;
165 stwm %r26,4(0,%r19) ;
166 stwm %r28,4(0,%r19) ; save return struct ptr
168 fstds,ma %fr4,8(0,%r19) ; Save floating point args
169 fstds,ma %fr5,8(0,%r19) ;
170 fstds,ma %fr6,8(0,%r19) ;
171 fstds,ma %fr7,8(0,%r19) ;
174 ldil L`_messageLock,%r1
175 ldo R`_messageLock(%r1),%r26
176 ldil L`OBJC_LOCK_ROUTINE,%r1 ; call spin_lock() with _messageLock
177 ble R`OBJC_LOCK_ROUTINE(%sr4,%r1)
179 ldw -112(%r30),%r26 ; restore arg0
180 ldw -108(%r30),%r28 ; and ret0 (spin_lock doesnt
181 ; touch anything else important)
182 ldw isa(0,%r26),%r19 ; class = self->isa;
183 ldw cache(0,%r19),%r20 ; cache = class->cache
184 ldw mask(0,%r20),%r21 ; mask = cache->mask
185 ldo buckets(%r20),%r20 ; buckets = cache->buckets
186 and %r21,%r25,%r22 ; index = selector & mask;
188 ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index];
189 comib,=,n 0,%r19,LL2 ; if (method == NULL)
190 ldw method_name(0,%r19),%r1 ;
191 addi 1,%r22,%r22 ; ++index
192 comb,<> %r1, %r25, LL1 ; if (name!=sel) continue loop
193 and %r21,%r22,%r22 ; <delay slot> index &=mask
194 ldw method_imp(0,%r19),%r19
196 ldil L`_messageLock,%r1
197 ldo R`_messageLock(%r1),%r20
203 ldil L`_messageLock,%r1
204 stw %r0,R`_messageLock(%r1) ; unlock the lock
206 ldwm -128(%r30),%r2 ; restore original rp and deallocate
208 bv,n 0(%r19) ; goto *imp; (nullify delay)
211 .space 128 ; /* area for moninitobjc to write */
215 ldw isa(0,%r26),%r26 ; arg 0 = self->isa
216 CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache)
218 ldo -128(%r30),%r30 ; deallocate
220 ldwm 4(0,%r19),%r2 ; restore everything
221 ldwm 4(0,%r19),%r23 ;
222 ldwm 4(0,%r19),%r24 ;
223 ldwm 4(0,%r19),%r25 ;
224 ldwm 4(0,%r19),%r26 ;
225 ldwm 4(0,%r19),%r20 ; get ret structure ptr
227 fldds,ma 8(0,%r19),%fr4 ;
228 fldds,ma 8(0,%r19),%fr5 ;
229 fldds,ma 8(0,%r19),%fr6 ;
230 fldds,ma 8(0,%r19),%fr7 ;
234 copy %r20,%r28 ; restore ret structure ptr
236 ldil L`_messageLock,%r1
237 ldo R`_messageLock(%r1),%r20
243 ldil L`_messageLock,%r1
244 stw %r0,R`_messageLock(%r1) ; unlock the lock
247 bv,n 0(%r19) ; goto *imp (nullify delay)
250 .space 128 ; /* area for moninitobjc to write */
260 .globl _objc_msgSendSuper
262 ldil L`__objc_multithread_mask,%r1
263 ldw R`__objc_multithread_mask(%r1),%r19
264 combt,= %r0,%r19,LSuperLocking ;
265 ldw class(0,%r26),%r19 ; class = caller->class;
266 ldw cache(0,%r19),%r20 ; cache = class->cache
267 ldw mask(0,%r20),%r21 ; mask = cache->mask
268 ldo buckets(%r20),%r20 ; buckets = cache->buckets
269 and %r21,%r25,%r22 ; index = selector & mask;
271 ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index];
272 comib,=,n 0,%r19,LS2 ; if (method == NULL)
273 ldw method_name(0,%r19),%r1;
274 addi 1,%r22,%r22 ; ++index
275 comb,<> %r1, %r25, LS1 ; if (name!=sel) continue loop
276 and %r21,%r22,%r22 ; <delay slot> index &=mask
277 ldw method_imp(0,%r19),%r19
278 ldw receiver(0,%r26),%r26 ; self = caller->receiver;
280 bv,n 0(%r19) ; goto *imp; (nullify delay)
282 .space 128 ; /* area for moninitobjc to write */
288 ldo 128(%r30),%r30 ; Allocate space on stack
289 stwm %r2,4(0,%r19) ; Save return pointer
290 stwm %r23,4(0,%r19) ; Save old args
291 stwm %r24,4(0,%r19) ;
292 stwm %r25,4(0,%r19) ;
293 stwm %r26,4(0,%r19) ;
295 fstds,mb %fr4,4(0,%r19) ; Save floating point args
296 fstds,mb %fr5,8(0,%r19) ; mb (modify before) is used instead
297 fstds,mb %fr6,8(0,%r19) ; of ma (as is implicit in above
298 fstds,mb %fr7,8(0,%r19) ; stores) with an initial value of 4
299 ; so that doubles are aligned
300 ; to 8 byte boundaries.
301 ; Arg 1 (selector) is the same
303 stw %r28,8(0,%r19) ; save return struct ptr
304 ldw class(0,%r26),%r26 ; arg 0 = caller->class;
305 CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache)
306 ldo -128(%r30),%r30 ; deallocate
308 ldwm 4(0,%r19),%r2 ; restore everything
309 ldwm 4(0,%r19),%r23 ;
310 ldwm 4(0,%r19),%r24 ;
311 ldwm 4(0,%r19),%r25 ;
312 ldwm 4(0,%r19),%r26 ;
314 fldds,mb 4(0,%r19),%fr4 ; see comment above about alignment
315 fldds,mb 8(0,%r19),%fr5 ;
316 fldds,mb 8(0,%r19),%fr6 ;
317 fldds,mb 8(0,%r19),%fr7 ;
319 ldw 8(0,%r19),%r20 ; get ret structure ptr
320 ldw receiver(0,%r26),%r26 ; self = caller->receiver;
323 Lexit6: bv,n 0(%r19) ; goto *imp (nullify delay)
326 .space 128 ; /* area for moninitobjc to write */
333 ; locking version of objc_msgSendSuper
334 ; uses spin_lock() to lock the lock.
339 ldo 128(%r30),%r30 ; Allocate space on stack
340 stwm %r2,4(0,%r19) ; Save return pointer
341 stwm %r23,4(0,%r19) ; Save old args
342 stwm %r24,4(0,%r19) ;
343 stwm %r25,4(0,%r19) ;
344 stwm %r26,4(0,%r19) ;
345 stwm %r28,4(0,%r19) ; save return struct ptr
347 fstds,ma %fr4,8(0,%r19) ; Save floating point args
348 fstds,ma %fr5,8(0,%r19) ;
349 fstds,ma %fr6,8(0,%r19) ;
350 fstds,ma %fr7,8(0,%r19) ;
352 ldil L`_messageLock,%r1
353 ldo R`_messageLock(%r1),%r26
354 ldil L`OBJC_LOCK_ROUTINE,%r1 ; call spin_lock() with _messageLock
355 ble R`OBJC_LOCK_ROUTINE(%sr4,%r1)
357 ldw -112(%r30),%r26 ; restore arg0
358 ldw -108(%r30),%r28 ; and ret0 (spin_lock doesnt
359 ; touch anything else)
360 ldw class(0,%r26),%r19 ; class = caller->class;
361 ldw cache(0,%r19),%r20 ; cache = class->cache
362 ldw mask(0,%r20),%r21 ; mask = cache->mask
363 ldo buckets(%r20),%r20 ; buckets = cache->buckets
364 and %r21,%r25,%r22 ; index = selector & mask;
366 ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index];
367 comib,=,n 0,%r19,LLS2 ; if (method == NULL)
368 ldw method_name(0,%r19),%r1;
369 addi 1,%r22,%r22 ; ++index
370 comb,<> %r1, %r25, LLS1 ; if (name!=sel) continue loop
371 and %r21,%r22,%r22 ; <delay slot> index &=mask
372 ldw method_imp(0,%r19),%r19
373 ldw receiver(0,%r26),%r26 ; self = caller->receiver;
375 ldil L`_messageLock,%r1
376 ldo R`_messageLock(%r1),%r20
382 ldil L`_messageLock,%r1
383 stw %r0,R`_messageLock(%r1) ; unlock the lock
385 ldwm -128(%r30),%r2 ; restore original rp and deallocate
387 bv,n 0(%r19) ; goto *imp; (nullify delay)
389 .space 128 ; /* area for moninitobjc to write */
394 ldw class(0,%r26),%r26 ; <delay slot> arg 0 = caller->class;
395 CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache)
396 ldo -128(%r30),%r30 ; deallocate
398 ldwm 4(0,%r19),%r2 ; restore everything
399 ldwm 4(0,%r19),%r23 ;
400 ldwm 4(0,%r19),%r24 ;
401 ldwm 4(0,%r19),%r25 ;
402 ldwm 4(0,%r19),%r26 ;
403 ldwm 4(0,%r19),%r20 ; get ret structure ptr
405 fldds,ma 8(0,%r19),%fr4 ;
406 fldds,ma 8(0,%r19),%fr5 ;
407 fldds,ma 8(0,%r19),%fr6 ;
408 fldds,ma 8(0,%r19),%fr7 ;
410 ldw receiver(0,%r26),%r26 ; self = caller->receiver;
414 ldil L`_messageLock,%r1
415 ldo R`_messageLock(%r1),%r20
421 ldil L`_messageLock,%r1
422 stw %r0,R`_messageLock(%r1) ; unlock the lock
424 Lexit8: bv,n 0(%r19) ; goto *imp (nullify delay)
427 .space 128 ; /* area for moninitobjc to write */
435 L30: .ascii "forward::\0"
443 L32: .ascii "Does not recognize selector %s\0"
448 ; NOTE: Because the stack grows from low mem to high mem on this machine
449 ; and the args go the other way, the marg_list pointer is to the first argument
450 ; and subsequent arguments are at NEGATIVE offsets from the marg_list.
451 ; This means that marg_getValue() and related macros will have to be adjusted
454 .globl __objc_msgForward
456 stw %r2,-20(0,%r30) ; save rp
457 ldo 64(%r30),%r30 ; create frame area (no locals needed)
461 combt,=,n %r19, %r25,L34 ; if (sel==@selector(forward::))
462 ldo -112(%r30),%r20 ; ptr to arg3 homing area
463 stwm %r23,4(0,%r20) ; Mirror registers onto stack
464 stwm %r24,4(0,%r20) ;
465 stwm %r25,4(0,%r20) ;
466 stwm %r26,4(0,%r20) ;
469 copy %r19,%r25 ; [self forward:sel :marg_list]
472 copy %r20,%r23 ; <delay slot> copy original sel
474 ldo -64(%r30),%r30 ; deallocate
475 ldw -20(0,%r30),%r2 ; restore rp
481 BRANCH_EXTERN(__objc_error)
484 ; Algorithm is as follows:
485 ; . Calculate how much stack size is needed for any arguments not in the
486 ; general registers and allocate space on stack.
487 ; . Restore general argument regs from the bottom of the marg_list.
488 ; . Restore fp argument regs from the same area.
489 ; (The first two args in the marg list are always old obj and old SEL.)
490 ; . Call the new method.
491 .globl _objc_msgSendv
493 ; objc_msgSendv(self, sel, size, margs)
494 stw %r2,-20(0,%r30) ; Save rp
495 stw %r4,-36(0,%r30) ; Save callee-saved r4
496 copy %r30,%r4 ; Save old sp vale
497 ldo 95(%r24),%r19 ; Calculate frame size, rounded
498 depi 0,31,6,%r19 ; up to 64 byte boundary...
500 add %r19,%r30,%r30 ; Allocate frame area (no locals)
501 copy %r24,%r20 ; r20 now holds arg size
502 ldo -16(%r23),%r21 ; r21 now holds marg_list+16
503 ldws 0(0,%r21),%r23 ; Get old general register args (dont
504 ldws 4(0,%r21),%r24 ; need first two: always self & SEL)
506 fldds 0(0,%r21),%fr7 ; Mirror to fp regs
507 fldws 4(0,%r21),%fr6 ;
510 ldo -52(%r30),%r22 ; newly allocated stack area.
511 ldo -8(%r20),%r20 ; Size -= 8
512 comibf,<,n 0,%r20,L36
513 L35: ldws,mb -4(0,%r21),%r19 ; while(size>0)
514 addibf,<= -4,%r20,L35 ; { *(dest--) = *(src--); size-=4; }
515 stws,ma %r19,-4(0,%r22) ; <delay slot>
516 L36: bl _objc_msgSend,%r2
518 copy %r4,%r30 ; deallocate