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@
25 #if _OS_OBJECT_OBJC_ARC
26 #error "Cannot build with ARC"
28 #if defined(__OBJC_GC__)
29 #error Objective C GC isn't supported anymore
32 #include <objc/objc-internal.h>
33 #include <objc/objc-exception.h>
34 #include <Foundation/NSString.h>
37 #pragma mark _os_object_t
40 _os_objc_alloc(Class cls, size_t size)
43 size -= sizeof(((struct _os_object_s *)NULL)->os_obj_isa);
44 while (!fastpath(obj = class_createInstance(cls, size))) {
45 _dispatch_temporary_resource_shortage();
51 _os_objc_destructInstance(id obj)
53 // noop if only Libystem is loaded
57 #if DISPATCH_COCOA_COMPAT
58 static bool _os_object_debug_missing_pools;
65 Block_callbacks_RR callbacks = {
66 sizeof(Block_callbacks_RR),
67 (void (*)(const void *))&objc_retain,
68 (void (*)(const void *))&objc_release,
69 (void (*)(const void *))&_os_objc_destructInstance
71 _Block_use_RR2(&callbacks);
72 #if DISPATCH_COCOA_COMPAT
73 const char *v = getenv("OBJC_DEBUG_MISSING_POOLS");
74 _os_object_debug_missing_pools = v && !strcmp(v, "YES");
79 _os_object_alloc_realized(const void *cls, size_t size)
81 dispatch_assert(size >= sizeof(struct _os_object_s));
82 return _os_objc_alloc(cls, size);
86 _os_object_alloc(const void *_cls, size_t size)
88 dispatch_assert(size >= sizeof(struct _os_object_s));
89 Class cls = _cls ? [(id)_cls class] : [OS_OBJECT_CLASS(object) class];
90 return _os_objc_alloc(cls, size);
94 _os_object_dealloc(_os_object_t obj)
100 _os_object_xref_dispose(_os_object_t obj)
102 struct _os_object_s *o = (struct _os_object_s *)obj;
103 _os_object_xrefcnt_dispose_barrier(o);
108 _os_object_dispose(_os_object_t obj)
110 struct _os_object_s *o = (struct _os_object_s *)obj;
111 _os_object_refcnt_dispose_barrier(o);
119 return objc_retain(obj);
124 os_release(void *obj)
126 return objc_release(obj);
130 #pragma mark _os_object
132 @implementation OS_OBJECT_CLASS(object)
133 DISPATCH_UNAVAILABLE_INIT()
136 return _os_object_retain(self);
139 -(oneway void)release {
140 return _os_object_release(self);
143 -(NSUInteger)retainCount {
144 return _os_object_retain_count(self);
147 -(BOOL)retainWeakReference {
148 return _os_object_retain_weak(self);
151 -(BOOL)allowsWeakReference {
152 return _os_object_allows_weak_reference(self);
155 - (void)_xref_dispose {
156 return _os_object_release_internal(self);
160 return _os_object_dealloc(self);
166 #pragma mark _dispatch_objc
167 #if OS_OBJECT_HAVE_OBJC2
170 _dispatch_objc_alloc(Class cls, size_t size)
172 return _os_objc_alloc(cls, size);
176 _dispatch_objc_retain(dispatch_object_t dou)
178 return (void)os_retain(dou);
182 _dispatch_objc_release(dispatch_object_t dou)
184 return os_release(dou);
188 _dispatch_objc_set_context(dispatch_object_t dou, void *context)
190 return [dou _setContext:context];
194 _dispatch_objc_get_context(dispatch_object_t dou)
196 return [dou _getContext];
200 _dispatch_objc_set_finalizer_f(dispatch_object_t dou,
201 dispatch_function_t finalizer)
203 return [dou _setFinalizer:finalizer];
207 _dispatch_objc_set_target_queue(dispatch_object_t dou, dispatch_queue_t queue)
209 return [dou _setTargetQueue:queue];
213 _dispatch_objc_suspend(dispatch_object_t dou)
215 return [dou _suspend];
219 _dispatch_objc_resume(dispatch_object_t dou)
221 return [dou _resume];
225 _dispatch_objc_activate(dispatch_object_t dou)
227 return [dou _activate];
231 _dispatch_objc_debug(dispatch_object_t dou, char* buf, size_t bufsiz)
233 NSUInteger offset = 0;
234 NSString *desc = [dou debugDescription];
235 [desc getBytes:buf maxLength:bufsiz-1 usedLength:&offset
236 encoding:NSUTF8StringEncoding options:0
237 range:NSMakeRange(0, [desc length]) remainingRange:NULL];
238 if (offset) buf[offset] = 0;
244 #pragma mark _dispatch_object
246 // Force non-lazy class realization rdar://10640168
247 #define DISPATCH_OBJC_LOAD() + (void)load {}
249 @implementation DISPATCH_CLASS(object)
250 DISPATCH_UNAVAILABLE_INIT()
253 return _dispatch_dispose(self); // calls _os_object_dealloc()
256 - (NSString *)debugDescription {
257 Class nsstring = objc_lookUpClass("NSString");
258 if (!nsstring) return nil;
260 struct dispatch_object_s *obj = (struct dispatch_object_s *)self;
261 if (dx_vtable(obj)->do_debug) {
262 dx_debug(obj, buf, sizeof(buf));
264 strlcpy(buf, dx_kind(obj), sizeof(buf));
266 return [nsstring stringWithFormat:
267 [nsstring stringWithUTF8String:"<%s: %s>"],
268 class_getName([self class]), buf];
273 @implementation DISPATCH_CLASS(queue)
275 DISPATCH_UNAVAILABLE_INIT()
277 - (NSString *)description {
278 Class nsstring = objc_lookUpClass("NSString");
279 if (!nsstring) return nil;
280 return [nsstring stringWithFormat:
281 [nsstring stringWithUTF8String:"<%s: %s[%p]>"],
282 class_getName([self class]), dispatch_queue_get_label(self), self];
285 - (void)_xref_dispose {
286 _dispatch_queue_xref_dispose((struct dispatch_queue_s *)self);
287 [super _xref_dispose];
292 @implementation DISPATCH_CLASS(source)
294 DISPATCH_UNAVAILABLE_INIT()
296 - (void)_xref_dispose {
297 _dispatch_queue_xref_dispose((struct dispatch_queue_s *)self);
298 _dispatch_source_xref_dispose(self);
299 [super _xref_dispose];
304 @implementation DISPATCH_CLASS(mach)
306 DISPATCH_UNAVAILABLE_INIT()
308 - (void)_xref_dispose {
309 _dispatch_queue_xref_dispose((struct dispatch_queue_s *)self);
310 [super _xref_dispose];
315 @implementation DISPATCH_CLASS(queue_runloop)
317 DISPATCH_UNAVAILABLE_INIT()
319 - (void)_xref_dispose {
320 _dispatch_queue_xref_dispose((struct dispatch_queue_s *)self);
321 _dispatch_runloop_queue_xref_dispose(self);
322 [super _xref_dispose];
327 #define DISPATCH_CLASS_IMPL(name) \
328 @implementation DISPATCH_CLASS(name) \
329 DISPATCH_OBJC_LOAD() \
330 DISPATCH_UNAVAILABLE_INIT() \
333 #if !DISPATCH_DATA_IS_BRIDGED_TO_NSDATA
334 DISPATCH_CLASS_IMPL(data)
336 DISPATCH_CLASS_IMPL(semaphore)
337 DISPATCH_CLASS_IMPL(group)
338 DISPATCH_CLASS_IMPL(queue_serial)
339 DISPATCH_CLASS_IMPL(queue_concurrent)
340 DISPATCH_CLASS_IMPL(queue_main)
341 DISPATCH_CLASS_IMPL(queue_root)
342 DISPATCH_CLASS_IMPL(queue_mgr)
343 DISPATCH_CLASS_IMPL(queue_specific_queue)
344 DISPATCH_CLASS_IMPL(queue_attr)
345 DISPATCH_CLASS_IMPL(mach_msg)
346 DISPATCH_CLASS_IMPL(io)
347 DISPATCH_CLASS_IMPL(operation)
348 DISPATCH_CLASS_IMPL(disk)
350 @implementation OS_OBJECT_CLASS(voucher)
351 DISPATCH_UNAVAILABLE_INIT()
354 - (void)_xref_dispose {
355 return _voucher_xref_dispose(self); // calls _os_object_release_internal()
359 return _voucher_dispose(self); // calls _os_object_dealloc()
362 - (NSString *)debugDescription {
363 Class nsstring = objc_lookUpClass("NSString");
364 if (!nsstring) return nil;
366 _voucher_debug(self, buf, sizeof(buf));
367 return [nsstring stringWithFormat:
368 [nsstring stringWithUTF8String:"<%s: %s>"],
369 class_getName([self class]), buf];
374 #if VOUCHER_ENABLE_RECIPE_OBJECTS
375 @implementation OS_OBJECT_CLASS(voucher_recipe)
376 DISPATCH_UNAVAILABLE_INIT()
383 - (NSString *)debugDescription {
384 return nil; // TODO: voucher_recipe debugDescription
392 #pragma mark dispatch_last_resort_autorelease_pool
394 #if DISPATCH_COCOA_COMPAT
397 _dispatch_last_resort_autorelease_pool_push(void)
399 if (!slowpath(_os_object_debug_missing_pools)) {
400 return _dispatch_autorelease_pool_push();
406 _dispatch_last_resort_autorelease_pool_pop(void *context)
408 if (!slowpath(_os_object_debug_missing_pools)) {
409 return _dispatch_autorelease_pool_pop(context);
413 #endif // DISPATCH_COCOA_COMPAT
416 #pragma mark dispatch_client_callout
418 // Abort on uncaught exceptions thrown from client callouts rdar://8577499
419 #if DISPATCH_USE_CLIENT_CALLOUT && !__USING_SJLJ_EXCEPTIONS__ && \
421 // On platforms with zero-cost exceptions, use a compiler-generated catch-all
422 // exception handler.
424 DISPATCH_NORETURN extern void objc_terminate(void);
426 #undef _dispatch_client_callout
428 _dispatch_client_callout(void *ctxt, dispatch_function_t f)
438 #undef _dispatch_client_callout2
440 _dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t))
451 #undef _dispatch_client_callout4
453 _dispatch_client_callout4(void *ctxt, dispatch_mach_reason_t reason,
454 dispatch_mach_msg_t dmsg, mach_error_t error,
455 dispatch_mach_handler_function_t f)
458 return f(ctxt, reason, dmsg, error);
466 #endif // DISPATCH_USE_CLIENT_CALLOUT