]> git.saurik.com Git - apple/libdispatch.git/blob - src/object.m
libdispatch-501.20.1.tar.gz
[apple/libdispatch.git] / src / object.m
1 /*
2 * Copyright (c) 2011-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20
21 #include "internal.h"
22
23 #if USE_OBJC
24
25 #if !__OBJC2__
26 #error "Cannot build with legacy ObjC runtime"
27 #endif
28 #if _OS_OBJECT_OBJC_ARC
29 #error "Cannot build with ARC"
30 #endif
31
32 #include <objc/objc-internal.h>
33 #include <objc/objc-exception.h>
34
35 #pragma mark -
36 #pragma mark _os_object_gc
37
38 #if __OBJC_GC__
39 #include <objc/objc-auto.h>
40 #include <auto_zone.h>
41
42 static bool _os_object_have_gc;
43 static malloc_zone_t *_os_object_gc_zone;
44
45 static void
46 _os_object_gc_init(void)
47 {
48 _os_object_have_gc = objc_collectingEnabled();
49 if (slowpath(_os_object_have_gc)) {
50 _os_object_gc_zone = objc_collectableZone();
51 (void)[OS_OBJECT_CLASS(object) class]; // OS_object class realization
52 }
53 }
54
55 static _os_object_t
56 _os_object_make_uncollectable(_os_object_t obj)
57 {
58 if (slowpath(_os_object_have_gc)) {
59 auto_zone_retain(_os_object_gc_zone, obj);
60 }
61 return obj;
62 }
63
64 static _os_object_t
65 _os_object_make_collectable(_os_object_t obj)
66 {
67 if (slowpath(_os_object_have_gc)) {
68 auto_zone_release(_os_object_gc_zone, obj);
69 }
70 return obj;
71 }
72
73 DISPATCH_NOINLINE
74 static id
75 _os_objc_gc_retain(id obj)
76 {
77 if (fastpath(obj)) {
78 auto_zone_retain(_os_object_gc_zone, obj);
79 }
80 return obj;
81 }
82
83 DISPATCH_NOINLINE
84 static void
85 _os_objc_gc_release(id obj)
86 {
87 if (fastpath(obj)) {
88 (void)auto_zone_release(_os_object_gc_zone, obj);
89 }
90 asm(""); // prevent tailcall
91 }
92
93 DISPATCH_NOINLINE
94 static id
95 _os_object_gc_retain(id obj)
96 {
97 if ([obj isKindOfClass:OS_OBJECT_OBJC_CLASS(object)]) {
98 return _os_object_retain(obj);
99 } else {
100 return _os_objc_gc_retain(obj);
101 }
102 }
103
104 DISPATCH_NOINLINE
105 static void
106 _os_object_gc_release(id obj)
107 {
108 if ([obj isKindOfClass:OS_OBJECT_OBJC_CLASS(object)]) {
109 return _os_object_release(obj);
110 } else {
111 return _os_objc_gc_release(obj);
112 }
113 }
114
115 #else // __OBJC_GC__
116 #define _os_object_gc_init()
117 #define _os_object_make_uncollectable(obj) (obj)
118 #define _os_object_make_collectable(obj) (obj)
119 #define _os_object_have_gc 0
120 #define _os_object_gc_retain(obj) (obj)
121 #define _os_object_gc_release(obj)
122 #endif // __OBJC_GC__
123
124 #pragma mark -
125 #pragma mark _os_object_t
126
127 static inline id
128 _os_objc_alloc(Class cls, size_t size)
129 {
130 id obj;
131 size -= sizeof(((struct _os_object_s *)NULL)->os_obj_isa);
132 while (!fastpath(obj = class_createInstance(cls, size))) {
133 _dispatch_temporary_resource_shortage();
134 }
135 return obj;
136 }
137
138 static void*
139 _os_objc_destructInstance(id obj)
140 {
141 // noop if only Libystem is loaded
142 return obj;
143 }
144
145 #if DISPATCH_COCOA_COMPAT
146 static bool _os_object_debug_missing_pools;
147 #endif
148
149 void
150 _os_object_init(void)
151 {
152 _objc_init();
153 _os_object_gc_init();
154 if (slowpath(_os_object_have_gc)) return;
155 Block_callbacks_RR callbacks = {
156 sizeof(Block_callbacks_RR),
157 (void (*)(const void *))&objc_retain,
158 (void (*)(const void *))&objc_release,
159 (void (*)(const void *))&_os_objc_destructInstance
160 };
161 _Block_use_RR2(&callbacks);
162 #if DISPATCH_COCOA_COMPAT
163 const char *v = getenv("OBJC_DEBUG_MISSING_POOLS");
164 _os_object_debug_missing_pools = v && !strcmp(v, "YES");
165 #endif
166 }
167
168 _os_object_t
169 _os_object_alloc_realized(const void *cls, size_t size)
170 {
171 dispatch_assert(size >= sizeof(struct _os_object_s));
172 return _os_object_make_uncollectable(_os_objc_alloc(cls, size));
173 }
174
175 _os_object_t
176 _os_object_alloc(const void *_cls, size_t size)
177 {
178 dispatch_assert(size >= sizeof(struct _os_object_s));
179 Class cls = _cls ? [(id)_cls class] : [OS_OBJECT_CLASS(object) class];
180 return _os_object_make_uncollectable(_os_objc_alloc(cls, size));
181 }
182
183 void
184 _os_object_dealloc(_os_object_t obj)
185 {
186 [_os_object_make_collectable(obj) dealloc];
187 }
188
189 void
190 _os_object_xref_dispose(_os_object_t obj)
191 {
192 struct _os_object_s *o = (struct _os_object_s *)obj;
193 _os_object_xrefcnt_dispose_barrier(o);
194 [obj _xref_dispose];
195 }
196
197 void
198 _os_object_dispose(_os_object_t obj)
199 {
200 struct _os_object_s *o = (struct _os_object_s *)obj;
201 _os_object_refcnt_dispose_barrier(o);
202 [obj _dispose];
203 }
204
205 #undef os_retain
206 void*
207 os_retain(void *obj)
208 {
209 if (slowpath(_os_object_have_gc)) return _os_object_gc_retain(obj);
210 return objc_retain(obj);
211 }
212
213 #undef os_release
214 void
215 os_release(void *obj)
216 {
217 if (slowpath(_os_object_have_gc)) return _os_object_gc_release(obj);
218 return objc_release(obj);
219 }
220
221 #pragma mark -
222 #pragma mark _os_object
223
224 @implementation OS_OBJECT_CLASS(object)
225
226 -(id)retain {
227 return _os_object_retain(self);
228 }
229
230 -(oneway void)release {
231 return _os_object_release(self);
232 }
233
234 -(NSUInteger)retainCount {
235 return _os_object_retain_count(self);
236 }
237
238 -(BOOL)retainWeakReference {
239 return _os_object_retain_weak(self);
240 }
241
242 -(BOOL)allowsWeakReference {
243 return _os_object_allows_weak_reference(self);
244 }
245
246 - (void)_xref_dispose {
247 return _os_object_release_internal(self);
248 }
249
250 - (void)_dispose {
251 return _os_object_dealloc(self);
252 }
253
254 @end
255
256 #pragma mark -
257 #pragma mark _dispatch_objc
258
259 #include <Foundation/NSString.h>
260
261 id
262 _dispatch_objc_alloc(Class cls, size_t size)
263 {
264 return _os_objc_alloc(cls, size);
265 }
266
267 void
268 _dispatch_objc_retain(dispatch_object_t dou)
269 {
270 return (void)os_retain(dou);
271 }
272
273 void
274 _dispatch_objc_release(dispatch_object_t dou)
275 {
276 return os_release(dou);
277 }
278
279 void
280 _dispatch_objc_set_context(dispatch_object_t dou, void *context)
281 {
282 return [dou _setContext:context];
283 }
284
285 void *
286 _dispatch_objc_get_context(dispatch_object_t dou)
287 {
288 return [dou _getContext];
289 }
290
291 void
292 _dispatch_objc_set_finalizer_f(dispatch_object_t dou,
293 dispatch_function_t finalizer)
294 {
295 return [dou _setFinalizer:finalizer];
296 }
297
298 void
299 _dispatch_objc_set_target_queue(dispatch_object_t dou, dispatch_queue_t queue)
300 {
301 return [dou _setTargetQueue:queue];
302 }
303
304 void
305 _dispatch_objc_suspend(dispatch_object_t dou)
306 {
307 return [dou _suspend];
308 }
309
310 void
311 _dispatch_objc_resume(dispatch_object_t dou)
312 {
313 return [dou _resume];
314 }
315
316 size_t
317 _dispatch_objc_debug(dispatch_object_t dou, char* buf, size_t bufsiz)
318 {
319 NSUInteger offset = 0;
320 NSString *desc = [dou debugDescription];
321 [desc getBytes:buf maxLength:bufsiz-1 usedLength:&offset
322 encoding:NSUTF8StringEncoding options:0
323 range:NSMakeRange(0, [desc length]) remainingRange:NULL];
324 if (offset) buf[offset] = 0;
325 return offset;
326 }
327
328 #pragma mark -
329 #pragma mark _dispatch_object
330
331 // Force non-lazy class realization rdar://10640168
332 #define DISPATCH_OBJC_LOAD() + (void)load {}
333
334 @implementation DISPATCH_CLASS(object)
335
336 - (id)init {
337 self = [super init];
338 [self release];
339 self = nil;
340 return self;
341 }
342
343 - (void)_xref_dispose {
344 _dispatch_xref_dispose(self);
345 [super _xref_dispose];
346 }
347
348 - (void)_dispose {
349 return _dispatch_dispose(self); // calls _os_object_dealloc()
350 }
351
352 - (NSString *)debugDescription {
353 Class nsstring = objc_lookUpClass("NSString");
354 if (!nsstring) return nil;
355 char buf[2048];
356 struct dispatch_object_s *obj = (struct dispatch_object_s *)self;
357 if (obj->do_vtable->do_debug) {
358 dx_debug(obj, buf, sizeof(buf));
359 } else {
360 strlcpy(buf, dx_kind(obj), sizeof(buf));
361 }
362 return [nsstring stringWithFormat:
363 [nsstring stringWithUTF8String:"<%s: %s>"],
364 class_getName([self class]), buf];
365 }
366
367 @end
368
369 @implementation DISPATCH_CLASS(queue)
370 DISPATCH_OBJC_LOAD()
371
372 - (NSString *)description {
373 Class nsstring = objc_lookUpClass("NSString");
374 if (!nsstring) return nil;
375 return [nsstring stringWithFormat:
376 [nsstring stringWithUTF8String:"<%s: %s[%p]>"],
377 class_getName([self class]), dispatch_queue_get_label(self), self];
378 }
379
380 @end
381
382 @implementation DISPATCH_CLASS(source)
383 DISPATCH_OBJC_LOAD()
384
385 - (void)_xref_dispose {
386 _dispatch_source_xref_dispose(self);
387 [super _xref_dispose];
388 }
389
390 @end
391
392 @implementation DISPATCH_CLASS(queue_runloop)
393 DISPATCH_OBJC_LOAD()
394
395 - (void)_xref_dispose {
396 _dispatch_runloop_queue_xref_dispose(self);
397 [super _xref_dispose];
398 }
399
400 @end
401
402 #define DISPATCH_CLASS_IMPL(name) \
403 @implementation DISPATCH_CLASS(name) \
404 DISPATCH_OBJC_LOAD() \
405 @end
406
407 DISPATCH_CLASS_IMPL(semaphore)
408 DISPATCH_CLASS_IMPL(group)
409 DISPATCH_CLASS_IMPL(queue_root)
410 DISPATCH_CLASS_IMPL(queue_mgr)
411 DISPATCH_CLASS_IMPL(queue_specific_queue)
412 DISPATCH_CLASS_IMPL(queue_attr)
413 DISPATCH_CLASS_IMPL(mach)
414 DISPATCH_CLASS_IMPL(mach_msg)
415 DISPATCH_CLASS_IMPL(io)
416 DISPATCH_CLASS_IMPL(operation)
417 DISPATCH_CLASS_IMPL(disk)
418
419 @implementation OS_OBJECT_CLASS(voucher)
420 DISPATCH_OBJC_LOAD()
421
422 - (id)init {
423 self = [super init];
424 [self release];
425 self = nil;
426 return self;
427 }
428
429 - (void)_xref_dispose {
430 return _voucher_xref_dispose(self); // calls _os_object_release_internal()
431 }
432
433 - (void)_dispose {
434 return _voucher_dispose(self); // calls _os_object_dealloc()
435 }
436
437 - (NSString *)debugDescription {
438 Class nsstring = objc_lookUpClass("NSString");
439 if (!nsstring) return nil;
440 char buf[2048];
441 _voucher_debug(self, buf, sizeof(buf));
442 return [nsstring stringWithFormat:
443 [nsstring stringWithUTF8String:"<%s: %s>"],
444 class_getName([self class]), buf];
445 }
446
447 @end
448
449 #if VOUCHER_ENABLE_RECIPE_OBJECTS
450 @implementation OS_OBJECT_CLASS(voucher_recipe)
451 DISPATCH_OBJC_LOAD()
452
453 - (id)init {
454 self = [super init];
455 [self release];
456 self = nil;
457 return self;
458 }
459
460 - (void)_dispose {
461
462 }
463
464 - (NSString *)debugDescription {
465 return nil; // TODO: voucher_recipe debugDescription
466 }
467
468 @end
469 #endif
470
471 #pragma mark -
472 #pragma mark dispatch_autorelease_pool
473
474 #if DISPATCH_COCOA_COMPAT
475
476 void *
477 _dispatch_autorelease_pool_push(void) {
478 if (!slowpath(_os_object_debug_missing_pools)) {
479 return objc_autoreleasePoolPush();
480 }
481 return NULL;
482 }
483
484 void
485 _dispatch_autorelease_pool_pop(void *context) {
486 if (!slowpath(_os_object_debug_missing_pools)) {
487 return objc_autoreleasePoolPop(context);
488 }
489 }
490
491 #endif // DISPATCH_COCOA_COMPAT
492
493 #pragma mark -
494 #pragma mark dispatch_client_callout
495
496 // Abort on uncaught exceptions thrown from client callouts rdar://8577499
497 #if DISPATCH_USE_CLIENT_CALLOUT && !__USING_SJLJ_EXCEPTIONS__
498 // On platforms with zero-cost exceptions, use a compiler-generated catch-all
499 // exception handler.
500
501 DISPATCH_NORETURN extern void objc_terminate(void);
502
503 #undef _dispatch_client_callout
504 void
505 _dispatch_client_callout(void *ctxt, dispatch_function_t f)
506 {
507 @try {
508 return f(ctxt);
509 }
510 @catch (...) {
511 objc_terminate();
512 }
513 }
514
515 #undef _dispatch_client_callout2
516 void
517 _dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t))
518 {
519 @try {
520 return f(ctxt, i);
521 }
522 @catch (...) {
523 objc_terminate();
524 }
525 }
526
527 #undef _dispatch_client_callout4
528 void
529 _dispatch_client_callout4(void *ctxt, dispatch_mach_reason_t reason,
530 dispatch_mach_msg_t dmsg, mach_error_t error,
531 dispatch_mach_handler_function_t f)
532 {
533 @try {
534 return f(ctxt, reason, dmsg, error);
535 }
536 @catch (...) {
537 objc_terminate();
538 }
539 }
540
541 #endif // DISPATCH_USE_CLIENT_CALLOUT
542
543 #endif // USE_OBJC