1/* 2 * Copyright (c) 2011-2013 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 42static bool _os_object_have_gc; 43static malloc_zone_t *_os_object_gc_zone; 44 45static 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 } 52} 53 54static _os_object_t 55_os_object_make_uncollectable(_os_object_t obj) 56{ 57 if (slowpath(_os_object_have_gc)) { 58 auto_zone_retain(_os_object_gc_zone, obj); 59 } 60 return obj; 61} 62 63static _os_object_t 64_os_object_make_collectable(_os_object_t obj) 65{ 66 if (slowpath(_os_object_have_gc)) { 67 auto_zone_release(_os_object_gc_zone, obj); 68 } 69 return obj; 70} 71 72#define _os_objc_gc_retain(obj) \ 73 if (slowpath(_os_object_have_gc)) { \ 74 return auto_zone_retain(_os_object_gc_zone, obj); \ 75 } 76 77#define _os_objc_gc_release(obj) \ 78 if (slowpath(_os_object_have_gc)) { \ 79 return (void)auto_zone_release(_os_object_gc_zone, obj); \ 80 } 81 82#else // __OBJC_GC__ 83#define _os_object_gc_init() 84#define _os_object_make_uncollectable(obj) (obj) 85#define _os_object_make_collectable(obj) (obj) 86#define _os_objc_gc_retain(obj) 87#define _os_objc_gc_release(obj) 88#endif // __OBJC_GC__ 89 90#pragma mark - 91#pragma mark _os_object_t 92 93static inline id 94_os_objc_alloc(Class cls, size_t size) 95{ 96 id obj; 97 size -= sizeof(((struct _os_object_s *)NULL)->os_obj_isa); 98 while (!fastpath(obj = class_createInstance(cls, size))) { 99 _dispatch_temporary_resource_shortage(); 100 } 101 return obj; 102} 103 104void 105_os_object_init(void) 106{ 107 _objc_init(); 108 _os_object_gc_init(); 109} 110 111_os_object_t 112_os_object_alloc_realized(const void *cls, size_t size) 113{ 114 dispatch_assert(size >= sizeof(struct _os_object_s)); 115 return _os_object_make_uncollectable(_os_objc_alloc(cls, size)); 116} 117 118_os_object_t 119_os_object_alloc(const void *_cls, size_t size) 120{ 121 dispatch_assert(size >= sizeof(struct _os_object_s)); 122 Class cls = _cls ? [(id)_cls class] : [OS_OBJECT_CLASS(object) class]; 123 return _os_object_make_uncollectable(_os_objc_alloc(cls, size)); 124} 125 126void 127_os_object_dealloc(_os_object_t obj) 128{ 129 [_os_object_make_collectable(obj) dealloc]; 130} 131 132void 133_os_object_xref_dispose(_os_object_t obj) 134{ 135 [obj _xref_dispose]; 136} 137 138void 139_os_object_dispose(_os_object_t obj) 140{ 141 [obj _dispose]; 142} 143 144#pragma mark - 145#pragma mark _os_object 146 147@implementation OS_OBJECT_CLASS(object) 148 149-(id)retain { 150 return _os_object_retain(self); 151} 152 153-(oneway void)release { 154 return _os_object_release(self); 155} 156 157-(NSUInteger)retainCount { 158 return _os_object_retain_count(self); 159} 160 161-(BOOL)retainWeakReference { 162 return _os_object_retain_weak(self); 163} 164 165-(BOOL)allowsWeakReference { 166 return _os_object_allows_weak_reference(self); 167} 168 169- (void)_xref_dispose { 170 return _os_object_release_internal(self); 171} 172 173- (void)_dispose { 174 return _os_object_dealloc(self); 175} 176 177@end 178 179#pragma mark - 180#pragma mark _dispatch_objc 181 182#include <Foundation/NSString.h> 183 184id 185_dispatch_objc_alloc(Class cls, size_t size) 186{ 187 return _os_objc_alloc(cls, size); 188} 189 190void 191_dispatch_objc_retain(dispatch_object_t dou) 192{ 193 _os_objc_gc_retain(dou); 194 return (void)[dou retain]; 195} 196 197void 198_dispatch_objc_release(dispatch_object_t dou) 199{ 200 _os_objc_gc_release(dou); 201 return [dou release]; 202} 203 204void 205_dispatch_objc_set_context(dispatch_object_t dou, void *context) 206{ 207 return [dou _setContext:context]; 208} 209 210void * 211_dispatch_objc_get_context(dispatch_object_t dou) 212{ 213 return [dou _getContext]; 214} 215 216void 217_dispatch_objc_set_finalizer_f(dispatch_object_t dou, 218 dispatch_function_t finalizer) 219{ 220 return [dou _setFinalizer:finalizer]; 221} 222 223void 224_dispatch_objc_set_target_queue(dispatch_object_t dou, dispatch_queue_t queue) 225{ 226 return [dou _setTargetQueue:queue]; 227} 228 229void 230_dispatch_objc_suspend(dispatch_object_t dou) 231{ 232 return [dou _suspend]; 233} 234 235void 236_dispatch_objc_resume(dispatch_object_t dou) 237{ 238 return [dou _resume]; 239} 240 241size_t 242_dispatch_objc_debug(dispatch_object_t dou, char* buf, size_t bufsiz) 243{ 244 NSUInteger offset = 0; 245 NSString *desc = [dou debugDescription]; 246 [desc getBytes:buf maxLength:bufsiz-1 usedLength:&offset 247 encoding:NSUTF8StringEncoding options:0 248 range:NSMakeRange(0, [desc length]) remainingRange:NULL]; 249 if (offset) buf[offset] = 0; 250 return offset; 251} 252 253#pragma mark - 254#pragma mark _dispatch_object 255 256// Force non-lazy class realization rdar://10640168 257#define DISPATCH_OBJC_LOAD() + (void)load {} 258 259@implementation DISPATCH_CLASS(object) 260 261- (id)init { 262 self = [super init]; 263 [self release]; 264 self = nil; 265 return self; 266} 267 268- (void)_xref_dispose { 269 _dispatch_xref_dispose(self); 270 [super _xref_dispose]; 271} 272 273- (void)_dispose { 274 return _dispatch_dispose(self); // calls _os_object_dealloc() 275} 276 277- (NSString *)debugDescription { 278 Class nsstring = objc_lookUpClass("NSString"); 279 if (!nsstring) return nil; 280 char buf[2048]; 281 struct dispatch_object_s *obj = (struct dispatch_object_s *)self; 282 if (obj->do_vtable->do_debug) { 283 dx_debug(obj, buf, sizeof(buf)); 284 } else { 285 strlcpy(buf, dx_kind(obj), sizeof(buf)); 286 } 287 return [nsstring stringWithFormat: 288 [nsstring stringWithUTF8String:"<%s: %s>"], 289 class_getName([self class]), buf]; 290} 291 292@end 293 294@implementation DISPATCH_CLASS(queue) 295DISPATCH_OBJC_LOAD() 296 297- (NSString *)description { 298 Class nsstring = objc_lookUpClass("NSString"); 299 if (!nsstring) return nil; 300 return [nsstring stringWithFormat: 301 [nsstring stringWithUTF8String:"<%s: %s[%p]>"], 302 class_getName([self class]), dispatch_queue_get_label(self), self]; 303} 304 305@end 306 307@implementation DISPATCH_CLASS(source) 308DISPATCH_OBJC_LOAD() 309 310- (void)_xref_dispose { 311 _dispatch_source_xref_dispose(self); 312 [super _xref_dispose]; 313} 314 315@end 316 317@implementation DISPATCH_CLASS(queue_runloop) 318DISPATCH_OBJC_LOAD() 319 320- (void)_xref_dispose { 321 _dispatch_runloop_queue_xref_dispose(self); 322 [super _xref_dispose]; 323} 324 325@end 326 327#define DISPATCH_CLASS_IMPL(name) \ 328 @implementation DISPATCH_CLASS(name) \ 329 DISPATCH_OBJC_LOAD() \ 330 @end 331 332DISPATCH_CLASS_IMPL(semaphore) 333DISPATCH_CLASS_IMPL(group) 334DISPATCH_CLASS_IMPL(queue_root) 335DISPATCH_CLASS_IMPL(queue_mgr) 336DISPATCH_CLASS_IMPL(queue_specific_queue) 337DISPATCH_CLASS_IMPL(queue_attr) 338DISPATCH_CLASS_IMPL(mach) 339DISPATCH_CLASS_IMPL(mach_msg) 340DISPATCH_CLASS_IMPL(io) 341DISPATCH_CLASS_IMPL(operation) 342DISPATCH_CLASS_IMPL(disk) 343 344#pragma mark - 345#pragma mark dispatch_autorelease_pool 346 347#if DISPATCH_COCOA_COMPAT 348 349void * 350_dispatch_autorelease_pool_push(void) { 351 return objc_autoreleasePoolPush(); 352} 353 354void 355_dispatch_autorelease_pool_pop(void *context) { 356 return objc_autoreleasePoolPop(context); 357} 358 359#endif // DISPATCH_COCOA_COMPAT 360 361#pragma mark - 362#pragma mark dispatch_client_callout 363 364// Abort on uncaught exceptions thrown from client callouts rdar://8577499 365#if DISPATCH_USE_CLIENT_CALLOUT && !__arm__ 366// On platforms with zero-cost exceptions, use a compiler-generated catch-all 367// exception handler. 368 369DISPATCH_NORETURN extern void objc_terminate(void); 370 371#undef _dispatch_client_callout 372void 373_dispatch_client_callout(void *ctxt, dispatch_function_t f) 374{ 375 @try { 376 return f(ctxt); 377 } 378 @catch (...) { 379 objc_terminate(); 380 } 381} 382 383#undef _dispatch_client_callout2 384void 385_dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t)) 386{ 387 @try { 388 return f(ctxt, i); 389 } 390 @catch (...) { 391 objc_terminate(); 392 } 393} 394 395#undef _dispatch_client_callout3 396bool 397_dispatch_client_callout3(void *ctxt, dispatch_data_t region, size_t offset, 398 const void *buffer, size_t size, dispatch_data_applier_function_t f) 399{ 400 @try { 401 return f(ctxt, region, offset, buffer, size); 402 } 403 @catch (...) { 404 objc_terminate(); 405 } 406} 407 408#undef _dispatch_client_callout4 409void 410_dispatch_client_callout4(void *ctxt, dispatch_mach_reason_t reason, 411 dispatch_mach_msg_t dmsg, mach_error_t error, 412 dispatch_mach_handler_function_t f) 413{ 414 @try { 415 return f(ctxt, reason, dmsg, error); 416 } 417 @catch (...) { 418 objc_terminate(); 419 } 420} 421 422#endif // DISPATCH_USE_CLIENT_CALLOUT 423 424#endif // USE_OBJC 425