/*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2008 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#import <libkern/OSAtomic.h>
+#import "objc-private.h"
+#import "objc-auto.h"
+#import "runtime.h"
#import "objc-accessors.h"
-#import <objc/objc-auto.h>
-#import <objc/runtime.h>
-#import "../objc-private.h"
-
-#import "/usr/local/include/auto_zone.h"
-
-#import "objc-accessors-table.h"
// stub interface declarations to make compiler happy.
- (id)copyWithZone:(void *)zone;
@end
+@interface __NSMutableCopyable
+- (id)mutableCopyWithZone:(void *)zone;
+@end
+
@interface __NSRetained
- (id)retain;
- (oneway void)release;
- (id)autorelease;
@end
-static /*inline*/ IMP optimized_getter_for_gc(id self, SEL name, ptrdiff_t offset) {
- // replace this method with a faster version that does no message sends, and fewer tests.
- IMP getter = GETPROPERTY_IMP(offset);
- if (getter != NULL) {
- // HACK ALERT: replaces the IMP in the cache!
- Class cls = self->isa;
- Method method = class_getInstanceMethod(cls, name);
- if (method_getImplementation(method) != getter)
- method_setImplementation(method, getter);
- }
- return getter;
-}
-
-static /*inline*/ IMP optimized_setter_for_gc(id self, SEL name, ptrdiff_t offset) {
- // replace this method with a faster version that does no message sends.
- IMP setter = SETPROPERTY_IMP(offset);
- if (setter != NULL) {
- // HACK ALERT: replaces the IMP in the cache!
- Class cls = self->isa;
- Method method = class_getInstanceMethod(cls, name);
- if (method_getImplementation(method) != setter)
- method_setImplementation(method, setter);
- }
- return setter;
-}
-
-// ATOMIC entry points
typedef uintptr_t spin_lock_t;
extern void _spin_lock(spin_lock_t *lockp);
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
if (UseGC) {
- // FIXME: we could optimize getters when a class is first initialized, then KVO won't get confused.
- if (false) {
- IMP getter = optimized_getter_for_gc(self, _cmd, offset);
- if (getter) return getter(self, _cmd);
- }
return *(id*) ((char*)self + offset);
}
return [value autorelease];
}
+enum { OBJC_PROPERTY_RETAIN = 0, OBJC_PROPERTY_COPY = 1, OBJC_PROPERTY_MUTABLECOPY = 2 };
void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, BOOL shouldCopy) {
if (UseGC) {
if (shouldCopy) {
- newValue = [newValue copyWithZone:NULL];
- }
- else if (false) {
- IMP setter = optimized_setter_for_gc(self, _cmd, offset);
- if (setter) {
- setter(self, _cmd, newValue);
- return;
- }
+ newValue = (shouldCopy == OBJC_PROPERTY_MUTABLECOPY ? [newValue mutableCopyWithZone:NULL] : [newValue copyWithZone:NULL]);
}
objc_assign_ivar_internal(newValue, self, offset);
return;
// atomic or not, if slot would be unchanged, do nothing.
if (!shouldCopy && *slot == newValue) return;
- newValue = (shouldCopy ? [newValue copyWithZone:NULL] : [newValue retain]);
+ if (shouldCopy) {
+ newValue = (shouldCopy == OBJC_PROPERTY_MUTABLECOPY ? [newValue mutableCopyWithZone:NULL] : [newValue copyWithZone:NULL]);
+ } else {
+ newValue = [newValue retain];
+ }
if (!atomic) {
oldValue = *slot;
}
-__private_extern__ auto_zone_t *gc_zone;
-
// This entry point was designed wrong. When used as a getter, src needs to be locked so that
// if simultaneously used for a setter then there would be contention on src.
// So we need two locks - one of which will be contended.
}
}
-// PRE-ATOMIC entry points
-
-id <NSCopying> object_getProperty_bycopy(id self, SEL _cmd, ptrdiff_t offset) {
- if (UseGC) {
- IMP getter = optimized_getter_for_gc(self, _cmd, offset);
- if (getter) return getter(self, _cmd);
- }
- id *slot = (id*) ((char*)self + offset);
- return *slot;
-}
-
-void object_setProperty_bycopy(id self, SEL _cmd, id <NSCopying> value, ptrdiff_t offset) {
- id *slot = (id*) ((char*)self + offset);
- id oldValue = *slot;
- objc_assign_ivar_internal([value copyWithZone:NULL], self, offset);
- [oldValue release];
-}
-
-id object_getProperty_byref(id self, SEL _cmd, ptrdiff_t offset) {
- if (UseGC) {
- IMP getter = optimized_getter_for_gc(self, _cmd, offset);
- if (getter) return getter(self, _cmd);
- }
- id *slot = (id*) ((char*)self + offset);
- return *slot;
-}
-
-void object_setProperty_byref(id self, SEL _cmd, id value, ptrdiff_t offset) {
- if (UseGC) {
- IMP setter = optimized_setter_for_gc(self, _cmd, offset);
- if (setter) {
- setter(self, _cmd, value);
- return;
- }
- }
- id *slot = (id*) ((char*)self + offset);
- id oldValue = *slot;
- if (oldValue != value) {
- objc_assign_ivar_internal([value retain], self, offset);
- [oldValue release];
- }
-}