/* * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef _OBJC_RUNTIME_OLD_H #define _OBJC_RUNTIME_OLD_H #include "objc-private.h" #define CLS_CLASS 0x1 #define CLS_META 0x2 #define CLS_INITIALIZED 0x4 #define CLS_POSING 0x8 #define CLS_MAPPED 0x10 #define CLS_FLUSH_CACHE 0x20 #define CLS_GROW_CACHE 0x40 #define CLS_NEED_BIND 0x80 #define CLS_METHOD_ARRAY 0x100 // the JavaBridge constructs classes with these markers #define CLS_JAVA_HYBRID 0x200 #define CLS_JAVA_CLASS 0x400 // thread-safe +initialize #define CLS_INITIALIZING 0x800 // bundle unloading #define CLS_FROM_BUNDLE 0x1000 // C++ ivar support #define CLS_HAS_CXX_STRUCTORS 0x2000 // Lazy method list arrays #define CLS_NO_METHOD_ARRAY 0x4000 // +load implementation #define CLS_HAS_LOAD_METHOD 0x8000 // objc_allocateClassPair API #define CLS_CONSTRUCTING 0x10000 // visibility=hidden #define CLS_HIDDEN 0x20000 // available for use; was CLS_FINALIZE_ON_MAIN_THREAD #define CLS_40000 0x40000 // Lazy property list arrays #define CLS_NO_PROPERTY_ARRAY 0x80000 // +load implementation #define CLS_CONNECTED 0x100000 #define CLS_LOADED 0x200000 // objc_allocateClassPair API #define CLS_CONSTRUCTED 0x400000 // class is leaf for cache flushing #define CLS_LEAF 0x800000 // class instances may have associative references #define CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS 0x1000000 // available for use; was CLS_HAS_INSTANCE_SPECIFIC_LAYOUT #define CLS_2000000 0x2000000 // class compiled with ARC #define CLS_IS_ARC 0x4000000 // class is not ARC but has ARC-style weak ivar layout #define CLS_HAS_WEAK_WITHOUT_ARC 0x8000000 // Terminator for array of method lists #define END_OF_METHODS_LIST ((struct old_method_list*)-1) #define ISCLASS(cls) (((cls)->info & CLS_CLASS) != 0) #define ISMETA(cls) (((cls)->info & CLS_META) != 0) #define GETMETA(cls) (ISMETA(cls) ? (cls) : (cls)->ISA()) struct old_class_ext { uint32_t size; const uint8_t *weak_ivar_layout; struct old_property_list **propertyLists; }; struct old_category { char *category_name; char *class_name; struct old_method_list *instance_methods; struct old_method_list *class_methods; struct old_protocol_list *protocols; // Fields below this point are in version 7 or later only. uint32_t size; struct old_property_list *instance_properties; // Check size for fields below this point. struct old_property_list *class_properties; bool hasClassPropertiesField() const { return size >= offsetof(old_category, class_properties) + sizeof(class_properties); } }; struct old_ivar { char *ivar_name; char *ivar_type; int ivar_offset; #ifdef __LP64__ int space; #endif }; struct old_ivar_list { int ivar_count; #ifdef __LP64__ int space; #endif /* variable length structure */ struct old_ivar ivar_list[1]; }; struct old_method { SEL method_name; char *method_types; IMP method_imp; }; struct old_method_list { void *obsolete; int method_count; #ifdef __LP64__ int space; #endif /* variable length structure */ struct old_method method_list[1]; }; struct old_protocol { Class isa; const char *protocol_name; struct old_protocol_list *protocol_list; struct objc_method_description_list *instance_methods; struct objc_method_description_list *class_methods; }; struct old_protocol_list { struct old_protocol_list *next; long count; struct old_protocol *list[1]; }; struct old_protocol_ext { uint32_t size; struct objc_method_description_list *optional_instance_methods; struct objc_method_description_list *optional_class_methods; struct old_property_list *instance_properties; const char **extendedMethodTypes; struct old_property_list *class_properties; bool hasClassPropertiesField() const { return size >= offsetof(old_protocol_ext, class_properties) + sizeof(class_properties); } }; struct old_property { const char *name; const char *attributes; }; struct old_property_list { uint32_t entsize; uint32_t count; struct old_property first; }; struct objc_class : objc_object { Class superclass; const char *name; uint32_t version; uint32_t info; uint32_t instance_size; struct old_ivar_list *ivars; struct old_method_list **methodLists; Cache cache; struct old_protocol_list *protocols; // CLS_EXT only const uint8_t *ivar_layout; struct old_class_ext *ext; void setInfo(uint32_t set) { OSAtomicOr32Barrier(set, (volatile uint32_t *)&info); } void clearInfo(uint32_t clear) { OSAtomicXor32Barrier(clear, (volatile uint32_t *)&info); } // set and clear must not overlap void changeInfo(uint32_t set, uint32_t clear) { ASSERT((set & clear) == 0); uint32_t oldf, newf; do { oldf = this->info; newf = (oldf | set) & ~clear; } while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&info)); } bool hasCxxCtor() { // set_superclass propagates the flag from the superclass. return info & CLS_HAS_CXX_STRUCTORS; } bool hasCxxDtor() { return hasCxxCtor(); // one bit for both ctor and dtor } // Return YES if the class's ivars are managed by ARC, // or the class is MRC but has ARC-style weak ivars. bool hasAutomaticIvars() { return info & (CLS_IS_ARC | CLS_HAS_WEAK_WITHOUT_ARC); } // Return YES if the class's ivars are managed by ARC. bool isARC() { return info & CLS_IS_ARC; } bool hasCustomRR() { return true; } bool hasCustomAWZ() { return true; } bool forbidsAssociatedObjects() { // Old runtime doesn't support forbidding associated objects. return false; } bool instancesHaveAssociatedObjects() { return info & CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS; } void setInstancesHaveAssociatedObjects() { setInfo(CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS); } bool shouldGrowCache() { return info & CLS_GROW_CACHE; } void setShouldGrowCache(bool grow) { if (grow) setInfo(CLS_GROW_CACHE); else clearInfo(CLS_GROW_CACHE); } // +initialize bits are stored on the metaclass only bool isInitializing() { return getMeta()->info & CLS_INITIALIZING; } // +initialize bits are stored on the metaclass only void setInitializing() { getMeta()->setInfo(CLS_INITIALIZING); } // +initialize bits are stored on the metaclass only bool isInitialized() { return getMeta()->info & CLS_INITIALIZED; } // +initialize bits are stored on the metaclass only void setInitialized() { getMeta()->changeInfo(CLS_INITIALIZED, CLS_INITIALIZING); } bool isLoadable() { // A class registered for +load is ready for +load to be called // if it is connected. return isConnected(); } IMP getLoadMethod(); bool isFuture(); bool isConnected(); const char *mangledName() { return name; } const char *demangledName() { return name; } const char *nameForLogging() { return name; } bool isRootClass() { return superclass == nil; } bool isRootMetaclass() { return ISA() == (Class)this; } bool isMetaClass() { return info & CLS_META; } // NOT identical to this->ISA() when this is a metaclass Class getMeta() { if (isMetaClass()) return (Class)this; else return this->ISA(); } // May be unaligned depending on class's ivars. uint32_t unalignedInstanceStart() { // This is not simply superclass->instance_size. // superclass->instance_size is padded to its sizeof() boundary, // which may envelop one of this class's ivars. // That in turn would break ARC-style ivar layouts. // Instead, we use the address of this class's first ivar when possible. if (!superclass) return 0; if (!ivars || ivars->ivar_count == 0) return superclass->instance_size; return ivars->ivar_list[0].ivar_offset; } // Class's instance start rounded up to a pointer-size boundary. // This is used for ARC layout bitmaps. uint32_t alignedInstanceStart() { return word_align(unalignedInstanceStart()); } // May be unaligned depending on class's ivars. uint32_t unalignedInstanceSize() { return instance_size; } // Class's ivar size rounded up to a pointer-size boundary. uint32_t alignedInstanceSize() { return word_align(unalignedInstanceSize()); } size_t instanceSize(size_t extraBytes) { size_t size = alignedInstanceSize() + extraBytes; // CF requires all objects be at least 16 bytes. if (size < 16) size = 16; return size; } }; #include "hashtable2.h" __BEGIN_DECLS #define oldprotocol(proto) ((struct old_protocol *)proto) #define oldmethod(meth) ((struct old_method *)meth) #define oldcategory(cat) ((struct old_category *)cat) #define oldivar(ivar) ((struct old_ivar *)ivar) #define oldproperty(prop) ((struct old_property *)prop) extern NXHashTable *class_hash; extern void unload_class(Class cls); extern IMP lookupNamedMethodInMethodList(struct old_method_list *mlist, const char *meth_name); extern void _objc_insertMethods(Class cls, struct old_method_list *mlist, struct old_category *cat); extern void _objc_removeMethods(Class cls, struct old_method_list *mlist); extern void _objc_flush_caches (Class cls); extern bool _class_addProperties(Class cls, struct old_property_list *additions); extern bool _class_hasLoadMethod(Class cls); extern void change_class_references(Class imposter, Class original, Class copy, bool changeSuperRefs); extern void flush_marked_caches(void); extern void set_superclass(Class cls, Class supercls, bool cls_is_new); extern void try_free(const void *p); extern struct old_property *property_list_nth(const struct old_property_list *plist, uint32_t i); extern struct old_property **copyPropertyList(struct old_property_list *plist, unsigned int *outCount); extern struct objc_method_description * lookup_protocol_method(struct old_protocol *proto, SEL aSel, bool isRequiredMethod, bool isInstanceMethod, bool recursive); // used by flush_caches outside objc-cache.m extern void _cache_flush(Class cls); #ifdef OBJC_INSTRUMENTED extern unsigned int LinearFlushCachesCount; extern unsigned int LinearFlushCachesVisitedCount; extern unsigned int MaxLinearFlushCachesVisitedCount; extern unsigned int NonlinearFlushCachesCount; extern unsigned int NonlinearFlushCachesClassCount; extern unsigned int NonlinearFlushCachesVisitedCount; extern unsigned int MaxNonlinearFlushCachesVisitedCount; extern unsigned int IdealFlushCachesCount; extern unsigned int MaxIdealFlushCachesCount; #endif __END_DECLS #endif