/*
* Copyright (c) 2011 Apple Inc. All rights reserved.
*
* @APPLE_APACHE_LICENSE_HEADER_START@
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
#include "internal.h"
#if USE_OBJC
#if !__OBJC2__
#error "Cannot build with legacy ObjC runtime"
#endif
#if _OS_OBJECT_OBJC_ARC
#error "Cannot build with ARC"
#endif
#include <objc/runtime.h>
#include <objc/objc-internal.h>
#include <objc/objc-exception.h>
#pragma mark -
#pragma mark _os_object_gc
#if __OBJC_GC__
#include <objc/objc-auto.h>
#include <auto_zone.h>
static dispatch_once_t _os_object_gc_pred;
static bool _os_object_have_gc;
static malloc_zone_t *_os_object_gc_zone;
static void
_os_object_gc_init(void *ctxt DISPATCH_UNUSED)
{
_os_object_have_gc = objc_collectingEnabled();
if (slowpath(_os_object_have_gc)) {
_os_object_gc_zone = objc_collectableZone();
}
}
static _os_object_t
_os_object_make_uncollectable(_os_object_t obj)
{
dispatch_once_f(&_os_object_gc_pred, NULL, _os_object_gc_init);
if (slowpath(_os_object_have_gc)) {
auto_zone_retain(_os_object_gc_zone, obj);
}
return obj;
}
static _os_object_t
_os_object_make_collectable(_os_object_t obj)
{
dispatch_once_f(&_os_object_gc_pred, NULL, _os_object_gc_init);
if (slowpath(_os_object_have_gc)) {
auto_zone_release(_os_object_gc_zone, obj);
}
return obj;
}
#else
#define _os_object_make_uncollectable(obj) (obj)
#define _os_object_make_collectable(obj) (obj)
#endif // __OBJC_GC__
#pragma mark -
#pragma mark _os_object_t
void
_os_object_init(void)
{
return _objc_init();
}
_os_object_t
_os_object_alloc(const void *_cls, size_t size)
{
Class cls = _cls;
_os_object_t obj;
dispatch_assert(size >= sizeof(struct _os_object_s));
size -= sizeof(((struct _os_object_s *)NULL)->os_obj_isa);
if (!cls) cls = [OS_OBJECT_CLASS(object) class];
while (!fastpath(obj = class_createInstance(cls, size))) {
sleep(1); // Temporary resource shortage
}
return _os_object_make_uncollectable(obj);
}
void
_os_object_dealloc(_os_object_t obj)
{
[_os_object_make_collectable(obj) dealloc];
}
void
_os_object_xref_dispose(_os_object_t obj)
{
[obj _xref_dispose];
}
void
_os_object_dispose(_os_object_t obj)
{
[obj _dispose];
}
#pragma mark -
#pragma mark _os_object
@implementation OS_OBJECT_CLASS(object)
-(id)retain {
return _os_object_retain(self);
}
-(oneway void)release {
return _os_object_release(self);
}
-(NSUInteger)retainCount {
return _os_object_retain_count(self);
}
-(BOOL)retainWeakReference {
return _os_object_retain_weak(self);
}
-(BOOL)allowsWeakReference {
return _os_object_allows_weak_reference(self);
}
- (void)_xref_dispose {
return _os_object_release_internal(self);
}
- (void)_dispose {
return _os_object_dealloc(self);
}
@end
#pragma mark -
#pragma mark _dispatch_object
#include <Foundation/NSString.h>
// Force non-lazy class realization rdar://10640168
#define DISPATCH_OBJC_LOAD() + (void)load {}
@implementation DISPATCH_CLASS(object)
- (id)init {
self = [super init];
[self release];
self = nil;
return self;
}
- (void)_xref_dispose {
_dispatch_xref_dispose(self);
[super _xref_dispose];
}
- (void)_dispose {
return _dispatch_dispose(self); // calls _os_object_dealloc()
}
- (NSString *)debugDescription {
Class nsstring = objc_lookUpClass("NSString");
if (!nsstring) return nil;
char buf[4096];
dx_debug((struct dispatch_object_s *)self, buf, sizeof(buf));
return [nsstring stringWithFormat:
[nsstring stringWithUTF8String:"< class_getName([self class]), buf];
}
@end
@implementation DISPATCH_CLASS(queue)
DISPATCH_OBJC_LOAD()
- (NSString *)description {
Class nsstring = objc_lookUpClass("NSString");
if (!nsstring) return nil;
return [nsstring stringWithFormat:
[nsstring stringWithUTF8String:"< class_getName([self class]), dispatch_queue_get_label(self), self];
}
@end
@implementation DISPATCH_CLASS(source)
DISPATCH_OBJC_LOAD()
- (void)_xref_dispose {
_dispatch_source_xref_dispose(self);
[super _xref_dispose];
}
@end
#define DISPATCH_CLASS_IMPL(name) \
@implementation DISPATCH_CLASS(name) \
DISPATCH_OBJC_LOAD() \
@end
DISPATCH_CLASS_IMPL(semaphore)
DISPATCH_CLASS_IMPL(group)
DISPATCH_CLASS_IMPL(queue_root)
DISPATCH_CLASS_IMPL(queue_mgr)
DISPATCH_CLASS_IMPL(queue_specific_queue)
DISPATCH_CLASS_IMPL(queue_attr)
DISPATCH_CLASS_IMPL(io)
DISPATCH_CLASS_IMPL(operation)
DISPATCH_CLASS_IMPL(disk)
DISPATCH_CLASS_IMPL(data)
#pragma mark -
#pragma mark dispatch_autorelease_pool
#if DISPATCH_COCOA_COMPAT
void *
_dispatch_autorelease_pool_push(void) {
return objc_autoreleasePoolPush();
}
void
_dispatch_autorelease_pool_pop(void *context) {
return objc_autoreleasePoolPop(context);
}
#endif // DISPATCH_COCOA_COMPAT
#pragma mark -
#pragma mark dispatch_client_callout
// Abort on uncaught exceptions thrown from client callouts rdar://8577499
#if DISPATCH_USE_CLIENT_CALLOUT && !__arm__
// On platforms with zero-cost exceptions, use a compiler-generated catch-all
// exception handler.
DISPATCH_NORETURN extern void objc_terminate(void);
#undef _dispatch_client_callout
void
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
@try {
return f(ctxt);
}
@catch (...) {
objc_terminate();
}
}
#undef _dispatch_client_callout2
void
_dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t))
{
@try {
return f(ctxt, i);
}
@catch (...) {
objc_terminate();
}
}
#endif // DISPATCH_USE_CLIENT_CALLOUT
#endif // USE_OBJC