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
146 _os_object_init(void)
149 _os_object_gc_init();
150 if (slowpath(_os_object_have_gc)) return;
151 Block_callbacks_RR callbacks = {
152 sizeof(Block_callbacks_RR),
153 (void (*)(const void *))&objc_retain,
154 (void (*)(const void *))&objc_release,
155 (void (*)(const void *))&_os_objc_destructInstance
157 _Block_use_RR2(&callbacks);
161 _os_object_alloc_realized(const void *cls, size_t size)
163 dispatch_assert(size >= sizeof(struct _os_object_s));
164 return _os_object_make_uncollectable(_os_objc_alloc(cls, size));
168 _os_object_alloc(const void *_cls, size_t size)
170 dispatch_assert(size >= sizeof(struct _os_object_s));
171 Class cls = _cls ? [(id)_cls class] : [OS_OBJECT_CLASS(object) class];
172 return _os_object_make_uncollectable(_os_objc_alloc(cls, size));
176 _os_object_dealloc(_os_object_t obj)
178 [_os_object_make_collectable(obj) dealloc];
182 _os_object_xref_dispose(_os_object_t obj)
188 _os_object_dispose(_os_object_t obj)
197 if (slowpath(_os_object_have_gc)) return _os_object_gc_retain(obj);
198 return objc_retain(obj);
203 os_release(void *obj)
205 if (slowpath(_os_object_have_gc)) return _os_object_gc_release(obj);
206 return objc_release(obj);
210 #pragma mark _os_object
212 @implementation OS_OBJECT_CLASS(object)
215 return _os_object_retain(self);
218 -(oneway void)release {
219 return _os_object_release(self);
222 -(NSUInteger)retainCount {
223 return _os_object_retain_count(self);
226 -(BOOL)retainWeakReference {
227 return _os_object_retain_weak(self);
230 -(BOOL)allowsWeakReference {
231 return _os_object_allows_weak_reference(self);
234 - (void)_xref_dispose {
235 return _os_object_release_internal(self);
239 return _os_object_dealloc(self);
245 #pragma mark _dispatch_objc
247 #include <Foundation/NSString.h>
250 _dispatch_objc_alloc(Class cls, size_t size)
252 return _os_objc_alloc(cls, size);
256 _dispatch_objc_retain(dispatch_object_t dou)
258 return (void)os_retain(dou);
262 _dispatch_objc_release(dispatch_object_t dou)
264 return os_release(dou);
268 _dispatch_objc_set_context(dispatch_object_t dou, void *context)
270 return [dou _setContext:context];
274 _dispatch_objc_get_context(dispatch_object_t dou)
276 return [dou _getContext];
280 _dispatch_objc_set_finalizer_f(dispatch_object_t dou,
281 dispatch_function_t finalizer)
283 return [dou _setFinalizer:finalizer];
287 _dispatch_objc_set_target_queue(dispatch_object_t dou, dispatch_queue_t queue)
289 return [dou _setTargetQueue:queue];
293 _dispatch_objc_suspend(dispatch_object_t dou)
295 return [dou _suspend];
299 _dispatch_objc_resume(dispatch_object_t dou)
301 return [dou _resume];
305 _dispatch_objc_debug(dispatch_object_t dou, char* buf, size_t bufsiz)
307 NSUInteger offset = 0;
308 NSString *desc = [dou debugDescription];
309 [desc getBytes:buf maxLength:bufsiz-1 usedLength:&offset
310 encoding:NSUTF8StringEncoding options:0
311 range:NSMakeRange(0, [desc length]) remainingRange:NULL];
312 if (offset) buf[offset] = 0;
317 #pragma mark _dispatch_object
319 // Force non-lazy class realization rdar://10640168
320 #define DISPATCH_OBJC_LOAD() + (void)load {}
322 @implementation DISPATCH_CLASS(object)
331 - (void)_xref_dispose {
332 _dispatch_xref_dispose(self);
333 [super _xref_dispose];
337 return _dispatch_dispose(self); // calls _os_object_dealloc()
340 - (NSString *)debugDescription {
341 Class nsstring = objc_lookUpClass("NSString");
342 if (!nsstring) return nil;
344 struct dispatch_object_s *obj = (struct dispatch_object_s *)self;
345 if (obj->do_vtable->do_debug) {
346 dx_debug(obj, buf, sizeof(buf));
348 strlcpy(buf, dx_kind(obj), sizeof(buf));
350 return [nsstring stringWithFormat:
351 [nsstring stringWithUTF8String:"<%s: %s>"],
352 class_getName([self class]), buf];
357 @implementation DISPATCH_CLASS(queue)
360 - (NSString *)description {
361 Class nsstring = objc_lookUpClass("NSString");
362 if (!nsstring) return nil;
363 return [nsstring stringWithFormat:
364 [nsstring stringWithUTF8String:"<%s: %s[%p]>"],
365 class_getName([self class]), dispatch_queue_get_label(self), self];
370 @implementation DISPATCH_CLASS(source)
373 - (void)_xref_dispose {
374 _dispatch_source_xref_dispose(self);
375 [super _xref_dispose];
380 @implementation DISPATCH_CLASS(queue_runloop)
383 - (void)_xref_dispose {
384 _dispatch_runloop_queue_xref_dispose(self);
385 [super _xref_dispose];
390 #define DISPATCH_CLASS_IMPL(name) \
391 @implementation DISPATCH_CLASS(name) \
392 DISPATCH_OBJC_LOAD() \
395 DISPATCH_CLASS_IMPL(semaphore)
396 DISPATCH_CLASS_IMPL(group)
397 DISPATCH_CLASS_IMPL(queue_root)
398 DISPATCH_CLASS_IMPL(queue_mgr)
399 DISPATCH_CLASS_IMPL(queue_specific_queue)
400 DISPATCH_CLASS_IMPL(queue_attr)
401 DISPATCH_CLASS_IMPL(mach)
402 DISPATCH_CLASS_IMPL(mach_msg)
403 DISPATCH_CLASS_IMPL(io)
404 DISPATCH_CLASS_IMPL(operation)
405 DISPATCH_CLASS_IMPL(disk)
407 @implementation OS_OBJECT_CLASS(voucher)
417 - (void)_xref_dispose {
418 return _voucher_xref_dispose(self); // calls _os_object_release_internal()
422 return _voucher_dispose(self); // calls _os_object_dealloc()
425 - (NSString *)debugDescription {
426 Class nsstring = objc_lookUpClass("NSString");
427 if (!nsstring) return nil;
429 _voucher_debug(self, buf, sizeof(buf));
430 return [nsstring stringWithFormat:
431 [nsstring stringWithUTF8String:"<%s: %s>"],
432 class_getName([self class]), buf];
437 #if VOUCHER_ENABLE_RECIPE_OBJECTS
438 @implementation OS_OBJECT_CLASS(voucher_recipe)
452 - (NSString *)debugDescription {
453 return nil; // TODO: voucher_recipe debugDescription
460 #pragma mark dispatch_autorelease_pool
462 #if DISPATCH_COCOA_COMPAT
465 _dispatch_autorelease_pool_push(void) {
466 return objc_autoreleasePoolPush();
470 _dispatch_autorelease_pool_pop(void *context) {
471 return objc_autoreleasePoolPop(context);
474 #endif // DISPATCH_COCOA_COMPAT
477 #pragma mark dispatch_client_callout
479 // Abort on uncaught exceptions thrown from client callouts rdar://8577499
480 #if DISPATCH_USE_CLIENT_CALLOUT && !__USING_SJLJ_EXCEPTIONS__
481 // On platforms with zero-cost exceptions, use a compiler-generated catch-all
482 // exception handler.
484 DISPATCH_NORETURN extern void objc_terminate(void);
486 #undef _dispatch_client_callout
488 _dispatch_client_callout(void *ctxt, dispatch_function_t f)
498 #undef _dispatch_client_callout2
500 _dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t))
510 #undef _dispatch_client_callout3
512 _dispatch_client_callout3(void *ctxt, dispatch_data_t region, size_t offset,
513 const void *buffer, size_t size, dispatch_data_applier_function_t f)
516 return f(ctxt, region, offset, buffer, size);
523 #undef _dispatch_client_callout4
525 _dispatch_client_callout4(void *ctxt, dispatch_mach_reason_t reason,
526 dispatch_mach_msg_t dmsg, mach_error_t error,
527 dispatch_mach_handler_function_t f)
530 return f(ctxt, reason, dmsg, error);
537 #endif // DISPATCH_USE_CLIENT_CALLOUT
540 #pragma mark _dispatch_block_create
542 // The compiler hides the name of the function it generates, and changes it if
543 // we try to reference it directly, but the linker still sees it.
544 extern void DISPATCH_BLOCK_SPECIAL_INVOKE(void *)
545 asm("____dispatch_block_create_block_invoke");
546 void (*_dispatch_block_special_invoke)(void*) = DISPATCH_BLOCK_SPECIAL_INVOKE;
549 _dispatch_block_create(dispatch_block_flags_t flags, voucher_t voucher,
550 pthread_priority_t pri, dispatch_block_t block)
552 dispatch_block_t copy_block = _dispatch_Block_copy(block); // 17094902
553 struct dispatch_block_private_data_s dbpds =
554 DISPATCH_BLOCK_PRIVATE_DATA_INITIALIZER(flags, voucher, pri, copy_block);
555 dispatch_block_t new_block = _dispatch_Block_copy(^{
556 // Capture object references, which retains copy_block and voucher.
557 // All retained objects must be captured by the *block*. We
558 // cannot borrow any references, because the block might be
559 // called zero or several times, so Block_release() is the
560 // only place that can release retained objects.
563 _dispatch_block_invoke(&dbpds);
565 Block_release(copy_block);