|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
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.0 (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
12: * this file.
13: *
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
20: * under the License."
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24: #ifdef KERNEL
25: #define OBJC_LOCK_ROUTINE _simple_lock
26: #else
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
29: ; a shared library.
30: .reference _moninitobjc
31: .const
32: .globl _objc_entryPoints
33: _objc_entryPoints:
34: .long _objc_msgSend
35: .long _objc_msgSendSuper
36: .long _objc_msgSendv
37: .long 0
38:
39: .globl _objc_exitPoints
40: _objc_exitPoints:
41: .long Lexit1
42: .long Lexit2
43: .long Lexit3
44: .long Lexit4
45: .long Lexit5
46: .long Lexit6
47: .long Lexit7
48: .long Lexit8
49: .long 0
50:
51: #define OBJC_LOCK_ROUTINE _spin_lock
52: #endif /* KERNEL */
53:
54: #define isa 0
55: #define cache 32
56: #define mask 0
57: #define buckets 8
58: #define method_name 0
59: #define method_imp 8
60:
61:
62: ; optimized for hppa: 20? clocks (best case) + 6 clocks / probe
63:
64: .text
65: .align 4
66: .globl _objc_msgSend
67:
68: _objc_msgSend:
69: ldil L`__objc_multithread_mask,%r1
70: ldw R`__objc_multithread_mask(%r1),%r19
71: and,= %r19,%r26,%r19
72: b,n L0 ; if (self & multi) goto normalcase
73: comiclr,= 0,%r26,0
74: b,n SendLocking ; else if (self) goto lockingcase
75: nop
76: bv 0(%r2) ; else return null
77: copy 0,%r28 ; <delay slot> return val = 0
78: L0:
79: ldw isa(0,%r26),%r19 ; class = self->isa;
80: ldw cache(0,%r19),%r20 ; cache = class->cache
81: ldw mask(0,%r20),%r21 ; mask = cache->mask
82: ldo buckets(%r20),%r20 ; buckets = cache->buckets
83: and %r21,%r25,%r22 ; index = selector & mask;
84: L1:
85: ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index];
86: comib,=,n 0,%r19,cacheMiss ; if (method == NULL)
87: ldw method_name(0,%r19),%r1 ;
88: addi 1,%r22,%r22 ; ++index
89: comb,<> %r1, %r25, L1 ; if (name!=sel) continue loop
90: and %r21,%r22,%r22 ; <delay slot> index &=mask
91: ldw method_imp(0,%r19),%r19
92: Lexit1:
93: bv,n 0(%r19) ; goto *imp; (nullify delay)
94:
95: #ifdef MONINIT
96: .space 128 ; /* area for moninitobjc to write */
97: #endif
98:
99: cacheMiss:
100: ; We have to save all the register based arguments (including floating
101: ; point) before calling _class_lookupMethodAndLoadCache. This is because
102: ; we do not know what arguments were passed to us, and the arguments are
103: ; not guaranteed to be saved across procedure calls (they are all caller-saved)
104: ; We also have to save the return address (since we did not save it on entry).
105:
106:
107: copy %r30,%r19
108: ldo 128(%r30),%r30 ; Allocate space on stack
109: stwm %r2,4(0,%r19) ; Save return pointer
110: stwm %r23,4(0,%r19) ; Save old args
111: stwm %r24,4(0,%r19) ;
112: stwm %r25,4(0,%r19) ;
113: stwm %r26,4(0,%r19) ;
114: #ifndef KERNEL
115: fstds,mb %fr4,4(0,%r19) ; Save floating point args
116: fstds,mb %fr5,8(0,%r19) ; mb (modify before) is used instead
117: fstds,mb %fr6,8(0,%r19) ; of ma (as is implicit in above
118: fstds,mb %fr7,8(0,%r19) ; stores) with an initial value of 4
119: ; so that doubles are aligned
120: ; to 8 byte boundaries.
121: ; Arg 1 (selector) is the same
122: #endif /* KERNEL */
123:
124: stw %r28,8(0,%r19) ; save return struct ptr
125: jbsr __class_lookupMethodAndLoadCache,%r2,0f
126: ldw isa(0,%r26),%r26 ; <delay slot> arg 0 = self->isa
127:
128: ldo -128(%r30),%r30 ; deallocate
129: copy %r30,%r19 ;
130: ldwm 4(0,%r19),%r2 ; restore everything
131: ldwm 4(0,%r19),%r23 ;
132: ldwm 4(0,%r19),%r24 ;
133: ldwm 4(0,%r19),%r25 ;
134: ldwm 4(0,%r19),%r26 ;
135: #ifndef KERNEL
136: fldds,mb 4(0,%r19),%fr4 ; see comment above about alignment
137: fldds,mb 8(0,%r19),%fr5 ;
138: fldds,mb 8(0,%r19),%fr6 ;
139: fldds,mb 8(0,%r19),%fr7 ;
140: #endif /* KERNEL */
141: ldw 8(0,%r19),%r20 ; get ret structure ptr
142:
143: copy %r28,%r19
144: copy %r20,%r28 ; restore ret structure ptr
145: Lexit2:
146: bv,n 0(%r19) ; goto *imp (nullify delay)
147:
148: ; stub for far call
149:
150: 0: ldil L`__class_lookupMethodAndLoadCache,%r1
151: ble,n R`__class_lookupMethodAndLoadCache(4,%r1)
152:
153: #ifdef MONINIT
154: .space 128 ; /* area for moninitobjc to write */
155: #endif
156:
157:
158:
159: ; Locking version of objc_msgSend
160: ; uses spin_lock() to lock the mutex.
161:
162: SendLocking:
163: copy %r30,%r19
164: ldo 128(%r30),%r30 ; Allocate space on stack
165: stwm %r2,4(0,%r19) ; Save return pointer
166: stwm %r23,4(0,%r19) ; Save old args
167: stwm %r24,4(0,%r19) ;
168: stwm %r25,4(0,%r19) ;
169: stwm %r26,4(0,%r19) ;
170: stwm %r28,4(0,%r19) ; save return struct ptr
171: #ifndef KERNEL
172: fstds,ma %fr4,8(0,%r19) ; Save floating point args
173: fstds,ma %fr5,8(0,%r19) ;
174: fstds,ma %fr6,8(0,%r19) ;
175: fstds,ma %fr7,8(0,%r19) ;
176: #endif /* KERNEL */
177:
178: ldil L`_messageLock,%r1
179: ldo R`_messageLock(%r1),%r26
180: ldil L`OBJC_LOCK_ROUTINE,%r1 ; call spin_lock() with _messageLock
181: ble R`OBJC_LOCK_ROUTINE(%sr4,%r1)
182: copy %r31,%r2
183: ldw -112(%r30),%r26 ; restore arg0
184: ldw -108(%r30),%r28 ; and ret0 (spin_lock doesnt
185: ; touch anything else important)
186: ldw isa(0,%r26),%r19 ; class = self->isa;
187: ldw cache(0,%r19),%r20 ; cache = class->cache
188: ldw mask(0,%r20),%r21 ; mask = cache->mask
189: ldo buckets(%r20),%r20 ; buckets = cache->buckets
190: and %r21,%r25,%r22 ; index = selector & mask;
191: LL1:
192: ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index];
193: comib,=,n 0,%r19,LL2 ; if (method == NULL)
194: ldw method_name(0,%r19),%r1 ;
195: addi 1,%r22,%r22 ; ++index
196: comb,<> %r1, %r25, LL1 ; if (name!=sel) continue loop
197: and %r21,%r22,%r22 ; <delay slot> index &=mask
198: ldw method_imp(0,%r19),%r19
199: #if KERNEL
200: ldil L`_messageLock,%r1
201: ldo R`_messageLock(%r1),%r20
202: addi 0xc,%r20,%r20
203: depi 0,31,4,%r20
204: zdepi 1,31,1,%r1
205: stw %r1,0(0,%r20)
206: #else
207: ldil L`_messageLock,%r1
208: stw %r0,R`_messageLock(%r1) ; unlock the lock
209: #endif
210: ldwm -128(%r30),%r2 ; restore original rp and deallocate
211: Lexit3:
212: bv,n 0(%r19) ; goto *imp; (nullify delay)
213:
214: #ifdef MONINIT
215: .space 128 ; /* area for moninitobjc to write */
216: #endif
217:
218: LL2:
219: jbsr __class_lookupMethodAndLoadCache,%r2,0f
220: ldw isa(0,%r26),%r26 ; <delay slot> arg 0 = self->isa
221:
222: ldo -128(%r30),%r30 ; deallocate
223: copy %r30,%r19 ;
224: ldwm 4(0,%r19),%r2 ; restore everything
225: ldwm 4(0,%r19),%r23 ;
226: ldwm 4(0,%r19),%r24 ;
227: ldwm 4(0,%r19),%r25 ;
228: ldwm 4(0,%r19),%r26 ;
229: ldwm 4(0,%r19),%r20 ; get ret structure ptr
230: #ifndef KERNEL
231: fldds,ma 8(0,%r19),%fr4 ;
232: fldds,ma 8(0,%r19),%fr5 ;
233: fldds,ma 8(0,%r19),%fr6 ;
234: fldds,ma 8(0,%r19),%fr7 ;
235: #endif /* KERNEL */
236:
237: copy %r28,%r19
238: copy %r20,%r28 ; restore ret structure ptr
239: #if KERNEL
240: ldil L`_messageLock,%r1
241: ldo R`_messageLock(%r1),%r20
242: addi 0xc,%r20,%r20
243: depi 0,31,4,%r20
244: zdepi 1,31,1,%r1
245: stw %r1,0(0,%r20)
246: #else
247: ldil L`_messageLock,%r1
248: stw %r0,R`_messageLock(%r1) ; unlock the lock
249: #endif
250: Lexit4:
251: bv,n 0(%r19) ; goto *imp (nullify delay)
252:
253: ; stub for far call
254:
255: 0: ldil L`__class_lookupMethodAndLoadCache,%r1
256: ble,n R`__class_lookupMethodAndLoadCache(4,%r1)
257:
258: #ifdef MONINIT
259: .space 128 ; /* area for moninitobjc to write */
260: #endif
261:
262:
263:
264:
265:
266: #define receiver 0
267: #define class 4
268:
269: .globl _objc_msgSendSuper
270: _objc_msgSendSuper:
271: ldil L`__objc_multithread_mask,%r1
272: ldw R`__objc_multithread_mask(%r1),%r19
273: combt,= %r0,%r19,SuperLocking ;
274: ldw class(0,%r26),%r19 ; class = caller->class;
275: ldw cache(0,%r19),%r20 ; cache = class->cache
276: ldw mask(0,%r20),%r21 ; mask = cache->mask
277: ldo buckets(%r20),%r20 ; buckets = cache->buckets
278: and %r21,%r25,%r22 ; index = selector & mask;
279: LS1: ;
280: ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index];
281: comib,=,n 0,%r19,LS2 ; if (method == NULL)
282: ldw method_name(0,%r19),%r1;
283: addi 1,%r22,%r22 ; ++index
284: comb,<> %r1, %r25, LS1 ; if (name!=sel) continue loop
285: and %r21,%r22,%r22 ; <delay slot> index &=mask
286: ldw method_imp(0,%r19),%r19
287: ldw receiver(0,%r26),%r26 ; self = caller->receiver;
288: Lexit5:
289: bv,n 0(%r19) ; goto *imp; (nullify delay)
290: #ifdef MONINIT
291: .space 128 ; /* area for moninitobjc to write */
292: #endif
293:
294: ;
295: LS2: ;
296: copy %r30,%r19
297: ldo 128(%r30),%r30 ; Allocate space on stack
298: stwm %r2,4(0,%r19) ; Save return pointer
299: stwm %r23,4(0,%r19) ; Save old args
300: stwm %r24,4(0,%r19) ;
301: stwm %r25,4(0,%r19) ;
302: stwm %r26,4(0,%r19) ;
303: #ifndef KERNEL
304: fstds,mb %fr4,4(0,%r19) ; Save floating point args
305: fstds,mb %fr5,8(0,%r19) ; mb (modify before) is used instead
306: fstds,mb %fr6,8(0,%r19) ; of ma (as is implicit in above
307: fstds,mb %fr7,8(0,%r19) ; stores) with an initial value of 4
308: ; so that doubles are aligned
309: ; to 8 byte boundaries.
310: ; Arg 1 (selector) is the same
311: #endif /* KERNEL */
312: stw %r28,8(0,%r19) ; save return struct ptr
313: jbsr __class_lookupMethodAndLoadCache,%r2,0f
314: ldw class(0,%r26),%r26 ; <delay slot> arg 0 = caller->class;
315: ldo -128(%r30),%r30 ; deallocate
316: copy %r30,%r19 ;
317: ldwm 4(0,%r19),%r2 ; restore everything
318: ldwm 4(0,%r19),%r23 ;
319: ldwm 4(0,%r19),%r24 ;
320: ldwm 4(0,%r19),%r25 ;
321: ldwm 4(0,%r19),%r26 ;
322: #ifndef KERNEL
323: fldds,mb 4(0,%r19),%fr4 ; see comment above about alignment
324: fldds,mb 8(0,%r19),%fr5 ;
325: fldds,mb 8(0,%r19),%fr6 ;
326: fldds,mb 8(0,%r19),%fr7 ;
327: #endif /* KERNEL */
328: ldw 8(0,%r19),%r20 ; get ret structure ptr
329: ldw receiver(0,%r26),%r26 ; self = caller->receiver;
330: copy %r28,%r19
331: copy %r20,%r28
332: Lexit6: bv,n 0(%r19) ; goto *imp (nullify delay)
333:
334: ; stub for far call
335:
336: 0: ldil L`__class_lookupMethodAndLoadCache,%r1
337: ble,n R`__class_lookupMethodAndLoadCache(4,%r1)
338:
339: #ifdef MONINIT
340: .space 128 ; /* area for moninitobjc to write */
341: #endif
342:
343:
344:
345:
346:
347: ; locking version of objc_msgSendSuper
348: ; uses spin_lock() to lock the lock.
349:
350:
351: SuperLocking:
352: copy %r30,%r19
353: ldo 128(%r30),%r30 ; Allocate space on stack
354: stwm %r2,4(0,%r19) ; Save return pointer
355: stwm %r23,4(0,%r19) ; Save old args
356: stwm %r24,4(0,%r19) ;
357: stwm %r25,4(0,%r19) ;
358: stwm %r26,4(0,%r19) ;
359: stwm %r28,4(0,%r19) ; save return struct ptr
360: #ifndef KERNEL
361: fstds,ma %fr4,8(0,%r19) ; Save floating point args
362: fstds,ma %fr5,8(0,%r19) ;
363: fstds,ma %fr6,8(0,%r19) ;
364: fstds,ma %fr7,8(0,%r19) ;
365: #endif /* KERNEL */
366: ldil L`_messageLock,%r1
367: ldo R`_messageLock(%r1),%r26
368: ldil L`OBJC_LOCK_ROUTINE,%r1 ; call spin_lock() with _messageLock
369: ble R`OBJC_LOCK_ROUTINE(%sr4,%r1)
370: copy %r31,%r2
371: ldw -112(%r30),%r26 ; restore arg0
372: ldw -108(%r30),%r28 ; and ret0 (spin_lock doesnt
373: ; touch anything else)
374: ldw class(0,%r26),%r19 ; class = caller->class;
375: ldw cache(0,%r19),%r20 ; cache = class->cache
376: ldw mask(0,%r20),%r21 ; mask = cache->mask
377: ldo buckets(%r20),%r20 ; buckets = cache->buckets
378: and %r21,%r25,%r22 ; index = selector & mask;
379: LLS1: ;
380: ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index];
381: comib,=,n 0,%r19,LLS2 ; if (method == NULL)
382: ldw method_name(0,%r19),%r1;
383: addi 1,%r22,%r22 ; ++index
384: comb,<> %r1, %r25, LLS1 ; if (name!=sel) continue loop
385: and %r21,%r22,%r22 ; <delay slot> index &=mask
386: ldw method_imp(0,%r19),%r19
387: ldw receiver(0,%r26),%r26 ; self = caller->receiver;
388: #if KERNEL
389: ldil L`_messageLock,%r1
390: ldo R`_messageLock(%r1),%r20
391: addi 0xc,%r20,%r20
392: depi 0,31,4,%r20
393: zdepi 1,31,1,%r1
394: stw %r1,0(0,%r20)
395: #else
396: ldil L`_messageLock,%r1
397: stw %r0,R`_messageLock(%r1) ; unlock the lock
398: #endif
399: ldwm -128(%r30),%r2 ; restore original rp and deallocate
400: Lexit7:
401: bv,n 0(%r19) ; goto *imp; (nullify delay)
402: #ifdef MONINIT
403: .space 128 ; /* area for moninitobjc to write */
404: #endif
405:
406: ;
407: LLS2: ;
408: jbsr __class_lookupMethodAndLoadCache,%r2,0f
409: ldw class(0,%r26),%r26 ; <delay slot> arg 0 = caller->class;
410: ldo -128(%r30),%r30 ; deallocate
411: copy %r30,%r19 ;
412: ldwm 4(0,%r19),%r2 ; restore everything
413: ldwm 4(0,%r19),%r23 ;
414: ldwm 4(0,%r19),%r24 ;
415: ldwm 4(0,%r19),%r25 ;
416: ldwm 4(0,%r19),%r26 ;
417: ldwm 4(0,%r19),%r20 ; get ret structure ptr
418: #ifndef KERNEL
419: fldds,ma 8(0,%r19),%fr4 ;
420: fldds,ma 8(0,%r19),%fr5 ;
421: fldds,ma 8(0,%r19),%fr6 ;
422: fldds,ma 8(0,%r19),%fr7 ;
423: #endif /* KERNEL */
424: ldw receiver(0,%r26),%r26 ; self = caller->receiver;
425: copy %r28,%r19
426: copy %r20,%r28
427: #if KERNEL
428: ldil L`_messageLock,%r1
429: ldo R`_messageLock(%r1),%r20
430: addi 0xc,%r20,%r20
431: depi 0,31,4,%r20
432: zdepi 1,31,1,%r1
433: stw %r1,0(0,%r20)
434: #else
435: ldil L`_messageLock,%r1
436: stw %r0,R`_messageLock(%r1) ; unlock the lock
437: #endif
438: Lexit8: bv,n 0(%r19) ; goto *imp (nullify delay)
439:
440: ; stub for far call
441:
442: 0: ldil L`__class_lookupMethodAndLoadCache,%r1
443: ble,n R`__class_lookupMethodAndLoadCache(4,%r1)
444:
445:
446: #ifdef MONINIT
447: .space 128 ; /* area for moninitobjc to write */
448: #endif
449:
450:
451:
452:
453: .objc_meth_var_names
454: .align 1
455: L30: .ascii "forward::\0"
456:
457: .objc_message_refs
458: .align 2
459: L31: .long L30
460:
461: .cstring
462: .align 1
463: L32: .ascii "Does not recognize selector %s\0"
464:
465: .text
466: .align 1
467: ;
468: ; NOTE: Because the stack grows from low mem to high mem on this machine
469: ; and the args go the other way, the marg_list pointer is to the first argument
470: ; and subsequent arguments are at NEGATIVE offsets from the marg_list.
471: ; This means that marg_getValue() and related macros will have to be adjusted
472: ; appropriately.
473: ;
474: .globl __objc_msgForward
475: __objc_msgForward:
476: stw %r2,-20(0,%r30) ; save rp
477: ldo 64(%r30),%r30 ; create frame area (no locals needed)
478: ldil L`L31,%r1
479: ldo R`L31(%r1),%r19
480: ldw 0(0,%r19),%r19
481: combt,=,n %r19, %r25,L34 ; if (sel==@selector(forward::))
482: ldo -112(%r30),%r20 ; ptr to arg3 homing area
483: stwm %r23,4(0,%r20) ; Mirror registers onto stack
484: stwm %r24,4(0,%r20) ;
485: stwm %r25,4(0,%r20) ;
486: stwm %r26,4(0,%r20) ;
487:
488: copy %r25,%r24
489: copy %r19,%r25 ; [self forward:sel :marg_list]
490:
491: bl _objc_msgSend,%r2
492: copy %r20,%r23 ; <delay slot> copy original sel
493:
494: ldo -64(%r30),%r30 ; deallocate
495: ldw -20(0,%r30),%r2 ; restore rp
496: bv,n 0(%r2) ; return
497: L34:
498: ldil L`L32,%r1
499: ldo R`L32(%r1),%r25
500: ldil L`__objc_error,%r1
501: be R`__objc_error(%sr4,%r1) ; __objc_error never returns, so no
502: copy %r19,%r24 ; need to clean up.
503:
504:
505: ; Algorithm is as follows:
506: ; . Calculate how much stack size is needed for any arguments not in the
507: ; general registers and allocate space on stack.
508: ; . Restore general argument regs from the bottom of the marg_list.
509: ; . Restore fp argument regs from the same area.
510: ; (The first two args in the marg list are always old obj and old SEL.)
511: ; . Call the new method.
512: .globl _objc_msgSendv
513: _objc_msgSendv:
514: ; objc_msgSendv(self, sel, size, margs)
515: stw %r2,-20(0,%r30) ; Save rp
516: stw %r4,-36(0,%r30) ; Save callee-saved r4
517: copy %r30,%r4 ; Save old sp vale
518: ldo 95(%r24),%r19 ; Calculate frame size, rounded
519: depi 0,31,6,%r19 ; up to 64 byte boundary...
520:
521: add %r19,%r30,%r30 ; Allocate frame area (no locals)
522: copy %r24,%r20 ; r20 now holds arg size
523: ldo -16(%r23),%r21 ; r21 now holds marg_list+16
524: ldws 0(0,%r21),%r23 ; Get old general register args (dont
525: ldws 4(0,%r21),%r24 ; need first two: always self & SEL)
526: #ifndef KERNEL
527: fldds 0(0,%r21),%fr7 ; Mirror to fp regs
528: fldws 4(0,%r21),%fr6 ;
529: #endif /* KERNEL */
530:
531: ldo -52(%r30),%r22 ; newly allocated stack area.
532: ldo -8(%r20),%r20 ; Size -= 8
533: comibf,<,n 0,%r20,L36
534: L35: ldws,mb -4(0,%r21),%r19 ; while(size>0)
535: addibf,<= -4,%r20,L35 ; { *(dest--) = *(src--); size-=4; }
536: stws,ma %r19,-4(0,%r22) ; <delay slot>
537: L36: bl _objc_msgSend,%r2
538: nop
539: copy %r4,%r30 ; deallocate
540: ldw -36(0,%r30), %r4
541: ldw -20(0,%r30), %r2
542: bv,n 0(%r2)
543:
544:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.