2 * Copyright (c) 2011-2014 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
26 #error "Cannot build with legacy ObjC runtime"
28 #if _OS_OBJECT_OBJC_ARC
29 #error "Cannot build with ARC"
32 #include <objc/objc-internal.h>
33 #include <objc/objc-exception.h>
36 #pragma mark _os_object_gc
39 #include <objc/objc-auto.h>
40 #include <auto_zone.h>
42 static bool _os_object_have_gc;
43 static malloc_zone_t *_os_object_gc_zone;
46 _os_object_gc_init(void)
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
56 _os_object_make_uncollectable(_os_object_t obj)
58 if (slowpath(_os_object_have_gc)) {
59 auto_zone_retain(_os_object_gc_zone, obj);
65 _os_object_make_collectable(_os_object_t obj)
67 if (slowpath(_os_object_have_gc)) {
68 auto_zone_release(_os_object_gc_zone, obj);
75 _os_objc_gc_retain(id obj)
78 auto_zone_retain(_os_object_gc_zone, obj);
85 _os_objc_gc_release(id obj)
88 (void)auto_zone_release(_os_object_gc_zone, obj);
90 asm(""); // prevent tailcall
95 _os_object_gc_retain(id obj)
97 if ([obj isKindOfClass:OS_OBJECT_OBJC_CLASS(object)]) {
98 return _os_object_retain(obj);
100 return _os_objc_gc_retain(obj);
106 _os_object_gc_release(id obj)
108 if ([obj isKindOfClass:OS_OBJECT_OBJC_CLASS(object)]) {
109 return _os_object_release(obj);
111 return _os_objc_gc_release(obj);
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__
125 #pragma mark _os_object_t
128 _os_objc_alloc(Class cls, size_t size)
131 size -= sizeof(((struct _os_object_s *)NULL)->os_obj_isa);
132 while (!fastpath(obj = class_createInstance(cls, size))) {
133 _dispatch_temporary_resource_shortage();
139 _os_objc_destructInstance(id obj)
141 // noop if only Libystem is loaded
145 #if DISPATCH_COCOA_COMPAT
146 static bool _os_object_debug_missing_pools;
150 _os_object_init(void)
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
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");
169 _os_object_alloc_realized(const void *cls, size_t size)
171 dispatch_assert(size >= sizeof(struct _os_object_s));
172 return _os_object_make_uncollectable(_os_objc_alloc(cls, size));
176 _os_object_alloc(const void *_cls, size_t size)
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));
184 _os_object_dealloc(_os_object_t obj)
186 [_os_object_make_collectable(obj) dealloc];
190 _os_object_xref_dispose(_os_object_t obj)
192 struct _os_object_s *o = (struct _os_object_s *)obj;
193 _os_object_xrefcnt_dispose_barrier(o);
198 _os_object_dispose(_os_object_t obj)
200 struct _os_object_s *o = (struct _os_object_s *)obj;
201 _os_object_refcnt_dispose_barrier(o);
209 if (slowpath(_os_object_have_gc)) return _os_object_gc_retain(obj);
210 return objc_retain(obj);
215 os_release(void *obj)
217 if (slowpath(_os_object_have_gc)) return _os_object_gc_release(obj);
218 return objc_release(obj);
222 #pragma mark _os_object
224 @implementation OS_OBJECT_CLASS(object)
227 return _os_object_retain(self);
230 -(oneway void)release {
231 return _os_object_release(self);
234 -(NSUInteger)retainCount {
235 return _os_object_retain_count(self);
238 -(BOOL)retainWeakReference {
239 return _os_object_retain_weak(self);
242 -(BOOL)allowsWeakReference {
243 return _os_object_allows_weak_reference(self);
246 - (void)_xref_dispose {
247 return _os_object_release_internal(self);
251 return _os_object_dealloc(self);
257 #pragma mark _dispatch_objc
259 #include <Foundation/NSString.h>
262 _dispatch_objc_alloc(Class cls, size_t size)
264 return _os_objc_alloc(cls, size);
268 _dispatch_objc_retain(dispatch_object_t dou)
270 return (void)os_retain(dou);
274 _dispatch_objc_release(dispatch_object_t dou)
276 return os_release(dou);
280 _dispatch_objc_set_context(dispatch_object_t dou, void *context)
282 return [dou _setContext:context];
286 _dispatch_objc_get_context(dispatch_object_t dou)
288 return [dou _getContext];
292 _dispatch_objc_set_finalizer_f(dispatch_object_t dou,
293 dispatch_function_t finalizer)
295 return [dou _setFinalizer:finalizer];
299 _dispatch_objc_set_target_queue(dispatch_object_t dou, dispatch_queue_t queue)
301 return [dou _setTargetQueue:queue];
305 _dispatch_objc_suspend(dispatch_object_t dou)
307 return [dou _suspend];
311 _dispatch_objc_resume(dispatch_object_t dou)
313 return [dou _resume];
317 _dispatch_objc_debug(dispatch_object_t dou, char* buf, size_t bufsiz)
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;
329 #pragma mark _dispatch_object
331 // Force non-lazy class realization rdar://10640168
332 #define DISPATCH_OBJC_LOAD() + (void)load {}
334 @implementation DISPATCH_CLASS(object)
343 - (void)_xref_dispose {
344 _dispatch_xref_dispose(self);
345 [super _xref_dispose];
349 return _dispatch_dispose(self); // calls _os_object_dealloc()
352 - (NSString *)debugDescription {
353 Class nsstring = objc_lookUpClass("NSString");
354 if (!nsstring) return nil;
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));
360 strlcpy(buf, dx_kind(obj), sizeof(buf));
362 return [nsstring stringWithFormat:
363 [nsstring stringWithUTF8String:"<%s: %s>"],
364 class_getName([self class]), buf];
369 @implementation DISPATCH_CLASS(queue)
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];
382 @implementation DISPATCH_CLASS(source)
385 - (void)_xref_dispose {
386 _dispatch_source_xref_dispose(self);
387 [super _xref_dispose];
392 @implementation DISPATCH_CLASS(queue_runloop)
395 - (void)_xref_dispose {
396 _dispatch_runloop_queue_xref_dispose(self);
397 [super _xref_dispose];
402 #define DISPATCH_CLASS_IMPL(name) \
403 @implementation DISPATCH_CLASS(name) \
404 DISPATCH_OBJC_LOAD() \
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)
419 @implementation OS_OBJECT_CLASS(voucher)
429 - (void)_xref_dispose {
430 return _voucher_xref_dispose(self); // calls _os_object_release_internal()
434 return _voucher_dispose(self); // calls _os_object_dealloc()
437 - (NSString *)debugDescription {
438 Class nsstring = objc_lookUpClass("NSString");
439 if (!nsstring) return nil;
441 _voucher_debug(self, buf, sizeof(buf));
442 return [nsstring stringWithFormat:
443 [nsstring stringWithUTF8String:"<%s: %s>"],
444 class_getName([self class]), buf];
449 #if VOUCHER_ENABLE_RECIPE_OBJECTS
450 @implementation OS_OBJECT_CLASS(voucher_recipe)
464 - (NSString *)debugDescription {
465 return nil; // TODO: voucher_recipe debugDescription
472 #pragma mark dispatch_autorelease_pool
474 #if DISPATCH_COCOA_COMPAT
477 _dispatch_autorelease_pool_push(void) {
478 if (!slowpath(_os_object_debug_missing_pools)) {
479 return objc_autoreleasePoolPush();
485 _dispatch_autorelease_pool_pop(void *context) {
486 if (!slowpath(_os_object_debug_missing_pools)) {
487 return objc_autoreleasePoolPop(context);
491 #endif // DISPATCH_COCOA_COMPAT
494 #pragma mark dispatch_client_callout
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.
501 DISPATCH_NORETURN extern void objc_terminate(void);
503 #undef _dispatch_client_callout
505 _dispatch_client_callout(void *ctxt, dispatch_function_t f)
515 #undef _dispatch_client_callout2
517 _dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t))
527 #undef _dispatch_client_callout4
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)
534 return f(ctxt, reason, dmsg, error);
541 #endif // DISPATCH_USE_CLIENT_CALLOUT