|
|
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 DYLIB
25: #error Building of SPARC dynashlib not supported yet!
26: #endif
27:
28: #ifdef KERNEL
29: #define OBJC_LOCK_ROUTINE _simple_lock
30: #else
31: #define OBJC_LOCK_ROUTINE _spin_lock
32: #endif /* KERNEL */
33:
34: #define CLEARLOW22 0xffc00000 /* mask to clear off low 22 bits */
35:
36:
37: #define isa 0
38: #define cache 32
39: #define mask 0
40: #define buckets 8
41: #define method_name 0
42: #define method_imp 8
43: #define receiver 0
44: #define class 4
45:
46: ! optimized for sparc: 26 clocks (best case) + 7 clocks/probe
47:
48: .text
49: .globl _objc_msgSend
50:
51: ! ObjC message send:
52: ! Arguments: %i0 - receiver (self)
53: ! %i1 - selector
54: ! %i2.. - arguments
55:
56: _objc_msgSend:
57: save %sp,-96,%sp ! save register windows
58:
59: ! test for nil argument and locking requirements
60: sethi %hi(__objc_multithread_mask),%l1
61: ld [%l1+%lo(__objc_multithread_mask)],%l1
62: andcc %l1,%i0,%l1 ! if (self & multi)
63: bnz,a L_normalCase ! then normalcase
64: ld [%i0+isa],%o0 ! class = self->isa (class arg)
65:
66: tst %i0 ! if (self)
67: bnz L_sendLocking ! lockingcase
68: nop
69: ! self is NIL, return
70: ld [%i7+8],%g3 // load instruction
71: sethi %hi(CLEARLOW22),%g2 // mask off low 22 bits
72: andcc %g3,%g2,%g0 // if 0, then its an UNIMP inst
73: bz L_struct_returnSend0 // and we will return a structure
74: nop //
75: ret // Get back, JoJo
76: restore // <ds>
77: L_struct_returnSend0:
78: jmp %i7 + 12 // convention for returning structs
79: restore // <ds>
80:
81: ! Init pointers to class and cache
82: L_normalCase:
83: ld [%o0+cache],%l4 ! cache <- class->cache
84: ld [%l4+mask],%l3 ! mask <- cache->mask
85: add %l4,buckets,%l2 ! buckets <- cache->buckets
86: and %i1,%l3,%l1 ! index <- selector & mask
87:
88: ! Try to find a method in the cache
89: L_loop:
90: sll %l1,2,%l6 ! adjust to word index
91: ld [%l2+%l6],%l4 ! method = buckets[index]
92: tst %l4 ! if (method == NULL)
93: bz,a L_cacheMiss ! handle cacheMiss case
94: mov %i1,%o1 ! (DS) selector arg for LoadCache
95:
96: ld [%l4+method_name],%l5! name = method->method_name
97: cmp %l5,%i1 ! if (name == selector)
98: be,a L_cacheHit ! goto hit
99: ld [%l4+method_imp],%o0! load method_imp pointer to call
100:
101: inc %l1 ! index++
102: b L_loop ! check next cache entry
103: and %l1,%l3,%l1 ! index = index & mask
104: L_cacheMiss:
105: call __class_lookupMethodAndLoadCache
106: nop
107: L_cacheHit:
108: jmp %o0 !
109: restore
110:
111: ! Locking version of objc_msgSend
112: ! spins on the mutex lock.
113:
114: L_sendLocking:
115: set (_messageLock),%l7! get the lock addr
116: set 1,%l1 ! lock code (1)
117: L_lockspin:
118: swap [%l7],%l1 ! try to set the lock
119: tst %l1 ! if lock was already set
120: bnz L_lockspin ! try again
121: set 1,%l1 ! lock code (1)
122:
123: ! got the lock, ready to proceed
124:
125: ld [%i0+isa],%o0 ! class = self->isa
126: ld [%o0+cache],%l4 ! cache = class->cache
127: ld [%l4+mask],%l3 ! mask = cache->mask
128: add %l4,buckets,%l2 ! buckets = cache->buckets
129: and %i1,%l3,%l1 ! index = selector & mask
130:
131: L_loop_lk:
132: sll %l1,2,%l6 ! adjust to word index
133: ld [%l2+%l6],%l4 ! method = buckets[index]
134: tst %l4 ! if (method == NULL)
135: bz,a L_cacheMiss_lk ! handle cacheMiss case
136: mov %i1,%o1 ! (DS) selector arg for LoadCache
137:
138: ld [%l4+method_name],%l5! name = method->method_name
139: cmp %l5,%i1 ! if (name == selector)
140: be,a L_cacheHit_lk ! goto hit
141: ld [%l4+method_imp],%o0 ! impl = method->method_imp
142:
143: inc %l1 ! index++
144: b L_loop_lk ! check next cache entry
145: and %l1,%l3,%l1 ! index = index & mask
146:
147: L_cacheMiss_lk:
148: call __class_lookupMethodAndLoadCache
149: nop
150: L_cacheHit_lk:
151: swap [%l7],%g0 ! clear the lock
152: jmp %o0
153: restore
154:
155:
156: .globl _objc_msgSendSuper
157: _objc_msgSendSuper:
158: save %sp,-120,%sp ! save register window
159: ld [%i0+receiver],%l0 ! receiver = caller->receiver
160: tst %l0 ! if (receiver)
161: bnz L_receiver ! work on it
162: st %l0,[%fp+68] ! <delay slot> save a copy
163: L_noreceiver: ! return on NULL receiver
164: ld [%i7+8],%g3 // load instruction
165: sethi %hi(CLEARLOW22),%g2 // mask off low 22 bits
166: andcc %g3,%g2,%g0 // if 0, then its an UNIMP inst
167: bz L_struct_returnSend1 // and we will return a structure
168: nop //
169: ret // Get back, JoJo
170: restore // <ds>
171: L_struct_returnSend1:
172: jmp %i7 + 12 // convention for returning structs
173: restore // <ds>
174:
175: L_receiver:
176: sethi %hi(__objc_multithread_mask),%l1
177: ld [%l1+%lo(__objc_multithread_mask)],%l1
178: tst %l1
179: bz L_superLock
180: ld [%i0+class],%o0 ! class = caller->class
181: ld [%o0+cache],%l4 ! cache = class->cache
182: ld [%l4+mask],%l3 ! mask = cache->mask
183: add %l4,buckets,%l2 ! buckets = cache->buckets
184: and %i1,%l3,%l1 ! index = selector & mask
185:
186: L_super_loop:
187: sll %l1,2,%l6 ! adjust to word index
188: ld [%l2+%l6],%l4 ! method = buckets[index]
189: tst %l4 ! if (method == NULL)
190: bz,a L_super_cacheMiss ! handle cacheMiss case
191: mov %i1,%o1 ! (DS) selector arg for LoadCache
192:
193: ld [%l4+method_name],%l5! name = method->method_name
194: cmp %l5,%i1 ! if (name == selector)
195: be L_super_cacheHit ! goto hit
196: ld [%l4+method_imp],%g1 ! method = buckets[index]
197:
198: inc %l1 ! index++
199: b L_super_loop ! check next cache entry
200: and %l1,%l3,%l1 ! index = index & mask
201:
202: L_super_cacheMiss:
203: call __class_lookupMethodAndLoadCache
204: nop
205: mov %o0,%g1 ! save result from Loadcache
206: restore
207: jmp %g1
208: ld [%sp+68],%o0 ! restore receiver
209:
210:
211: L_super_cacheHit:
212: restore
213: jmp %g1
214: ld [%sp+68],%o0 ! restore receiver
215:
216:
217: ! locking version of objc_msgSendSuper
218: ! spins on the mutex lock
219:
220: L_superLock:
221: sethi %hi(_messageLock),%l1! aquire the lock addr
222: or %l1,%lo(_messageLock),%l7
223: L_super_lockspin:
224: ldstub [%l7],%l1 ! try to set the lock
225: tst %l1 ! if lock was already set
226: bne L_super_lockspin ! try again
227: nop
228:
229: ! got the lock, ready to proceed
230: ! %o0 = class [set above]
231: ld [%o0+cache],%l4 ! cache = class->cache
232: ld [%l4+mask],%l3 ! mask = cache->mask
233: add %l4,buckets,%l2 ! buckets = cache->buckets
234: and %i1,%l3,%l1 ! index = selector & mask
235:
236: L_super_loop_lk:
237: sll %l1,2,%l6 ! adjust to word index
238: ld [%l2+%l6],%l4 ! method = buckets[index]
239: tst %l4 ! if (method == NULL)
240: bz,a L_super_cacheMiss_lk ! handle cacheMiss case
241: mov %i1,%o1 ! (DS) selector arg for LoadCache
242:
243: ld [%l4+method_name],%l5! name = method->method_name
244: cmp %l5,%i1 ! if (name == selector)
245: be L_super_cacheHit_lk ! goto hit
246: ld [%l4+method_imp],%g1 ! impl = method->method_imp
247:
248: inc %l1 ! index++
249: b L_super_loop_lk ! check next cache entry
250: and %l1,%l3,%l1 ! index = index & mask
251:
252: L_super_cacheMiss_lk:
253: call __class_lookupMethodAndLoadCache
254: nop
255: mov %o0,%g1 ! save result from Loadcache
256: st %g0,[%l7] ! clear lock
257: restore
258: jmp %g1
259: ld [%sp+68],%o0 ! restore receiver
260:
261: L_super_cacheHit_lk:
262: st %g0,[%l7] ! clear the lock
263: restore
264: jmp %g1
265: ld [%sp+68],%o0 ! restore receiver
266:
267:
268: .objc_meth_var_names
269: .align 1
270: L30: .ascii "forward::\0"
271:
272: .objc_message_refs
273: .align 2
274: L31: .long L30
275:
276: .cstring
277: .align 1
278: L32: .ascii "Does not recognize selector %s\0"
279:
280: .text
281: .align 2
282:
283: .globl __objc_msgForward
284: __objc_msgForward:
285: save %sp,-96,%sp
286: sethi %hi(L31),%g2
287: ld [%g2+%lo(L31)],%g2
288: cmp %i1,%g2 ! if (selector == @selector(forward::))
289: be L_error
290: nop
291: add %fp,68,%g1 ! ptr to stack area
292: st %i0,[%g1]
293: st %i1,[%g1+4]
294: st %i2,[%g1+8]
295: st %i3,[%g1+12]
296: st %i4,[%g1+16]
297: st %i5,[%g1+20]
298: mov %i1,%o2
299: mov %g2,%o1
300: mov %g1,%o3
301: call _objc_msgSend
302: mov %i0,%o0
303: ret
304: restore %g0,%o0,%o0
305:
306: L_error:
307: mov %i1, %o2
308: set L32,%i1
309: ba __objc_error ! never returns
310: nop
311:
312:
313: ! id objc_msgSendv(id self, SEL sel, unsigned size, marg_list args)
314:
315: .globl _objc_msgSendv
316: _objc_msgSendv:
317: add %g0,-96,%g1 ! Get min stack size + 4 (rounded by 8)
318: subcc %o2,28,%g2 ! Get size of non reg params + 4
319: ble Lsave_stack ! None or 1, so skip making stack larger
320: sub %g1,%g2,%g2 ! Add local size to minimum stack
321: and %g2,-8,%g1 ! Need to round to 8 bit boundary
322: Lsave_stack:
323: save %sp,%g1,%sp ! Save min stack + 4 for 8 byte bound! ...
324: mov %i0,%o0
325: mov %i1,%o1
326: addcc %i2,-8,%i2 ! adjust for first 2 args (self & sel)
327: be L_send_msg
328: nop
329:
330: ld [%i3+8],%o2 ! get 3rd arg
331: addcc %i2,-4,%i2 ! size--
332: be L_send_msg
333: nop
334:
335: ld [%i3+12],%o3 ! arg 4
336: addcc %i2,-4,%i2 ! size--
337: be L_send_msg
338: nop
339:
340: ld [%i3+16],%o4 ! arg 5
341: addcc %i2,-4,%i2 ! size--
342: be L_send_msg
343: nop
344:
345: ld [%i3+20],%o5 ! arg 6
346: addcc %i2,-4,%i2 ! size--
347: be L_send_msg
348: nop
349: add %i3,24,%i1 ! %i1 = args + 24
350: add %sp,92,%i5
351: L_loopv: ! deal with remaining args
352: ld [%i1],%i3
353: addcc %i2,-4,%i2 ! size--
354: st %i3,[%i5]
355: add %i5,4,%i5
356: bnz L_loopv
357: add %i1,4,%i1 ! arg++
358:
359: L_send_msg:
360: ld [%i7+8],%g3 ! load instruction
361: sethi %hi(CLEARLOW22),%g2
362: andcc %g3,%g2,%g0 ! if 0 it is an UNIMP inst
363: be L_struct_returnSendv! return a structure
364: nop
365:
366: ! Case of no struct returned
367:
368: call _objc_msgSend
369: nop
370: mov %o0,%i0 ! Ret int, 1st half
371: ret ! ... of long long
372: restore %o1,0,%o1 ! 2nd half of ll
373:
374: L_struct_returnSendv:
375: ld [%fp+64],%g2
376: st %g2,[%sp+64]
377: call _objc_msgSend
378: nop
379: unimp 0
380: jmp %i7+12
381: restore
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.