]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-private.h
objc4-781.tar.gz
[apple/objc4.git] / runtime / objc-private.h
1 /*
2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * objc-private.h
25 * Copyright 1988-1996, NeXT Software, Inc.
26 */
27
28 #ifndef _OBJC_PRIVATE_H_
29 #define _OBJC_PRIVATE_H_
30
31 #include "objc-config.h"
32
33 /* Isolate ourselves from the definitions of id and Class in the compiler
34 * and public headers.
35 */
36
37 #ifdef _OBJC_OBJC_H_
38 #error include objc-private.h before other headers
39 #endif
40
41 #define OBJC_TYPES_DEFINED 1
42 #undef OBJC_OLD_DISPATCH_PROTOTYPES
43 #define OBJC_OLD_DISPATCH_PROTOTYPES 0
44
45 #include <cstddef> // for nullptr_t
46 #include <stdint.h>
47 #include <assert.h>
48
49 // An assert that's disabled for release builds but still ensures the expression compiles.
50 #ifdef NDEBUG
51 #define ASSERT(x) (void)sizeof(!(x))
52 #else
53 #define ASSERT(x) assert(x)
54 #endif
55
56 struct objc_class;
57 struct objc_object;
58
59 typedef struct objc_class *Class;
60 typedef struct objc_object *id;
61
62 namespace {
63 struct SideTable;
64 };
65
66 #include "isa.h"
67
68 union isa_t {
69 isa_t() { }
70 isa_t(uintptr_t value) : bits(value) { }
71
72 Class cls;
73 uintptr_t bits;
74 #if defined(ISA_BITFIELD)
75 struct {
76 ISA_BITFIELD; // defined in isa.h
77 };
78 #endif
79 };
80
81
82 struct objc_object {
83 private:
84 isa_t isa;
85
86 public:
87
88 // ISA() assumes this is NOT a tagged pointer object
89 Class ISA();
90
91 // rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
92 Class rawISA();
93
94 // getIsa() allows this to be a tagged pointer object
95 Class getIsa();
96
97 uintptr_t isaBits() const;
98
99 // initIsa() should be used to init the isa of new objects only.
100 // If this object already has an isa, use changeIsa() for correctness.
101 // initInstanceIsa(): objects with no custom RR/AWZ
102 // initClassIsa(): class objects
103 // initProtocolIsa(): protocol objects
104 // initIsa(): other objects
105 void initIsa(Class cls /*nonpointer=false*/);
106 void initClassIsa(Class cls /*nonpointer=maybe*/);
107 void initProtocolIsa(Class cls /*nonpointer=maybe*/);
108 void initInstanceIsa(Class cls, bool hasCxxDtor);
109
110 // changeIsa() should be used to change the isa of existing objects.
111 // If this is a new object, use initIsa() for performance.
112 Class changeIsa(Class newCls);
113
114 bool hasNonpointerIsa();
115 bool isTaggedPointer();
116 bool isBasicTaggedPointer();
117 bool isExtTaggedPointer();
118 bool isClass();
119
120 // object may have associated objects?
121 bool hasAssociatedObjects();
122 void setHasAssociatedObjects();
123
124 // object may be weakly referenced?
125 bool isWeaklyReferenced();
126 void setWeaklyReferenced_nolock();
127
128 // object may have -.cxx_destruct implementation?
129 bool hasCxxDtor();
130
131 // Optimized calls to retain/release methods
132 id retain();
133 void release();
134 id autorelease();
135
136 // Implementations of retain/release methods
137 id rootRetain();
138 bool rootRelease();
139 id rootAutorelease();
140 bool rootTryRetain();
141 bool rootReleaseShouldDealloc();
142 uintptr_t rootRetainCount();
143
144 // Implementation of dealloc methods
145 bool rootIsDeallocating();
146 void clearDeallocating();
147 void rootDealloc();
148
149 private:
150 void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);
151
152 // Slow paths for inline control
153 id rootAutorelease2();
154 uintptr_t overrelease_error();
155
156 #if SUPPORT_NONPOINTER_ISA
157 // Unified retain count manipulation for nonpointer isa
158 id rootRetain(bool tryRetain, bool handleOverflow);
159 bool rootRelease(bool performDealloc, bool handleUnderflow);
160 id rootRetain_overflow(bool tryRetain);
161 uintptr_t rootRelease_underflow(bool performDealloc);
162
163 void clearDeallocating_slow();
164
165 // Side table retain count overflow for nonpointer isa
166 void sidetable_lock();
167 void sidetable_unlock();
168
169 void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
170 bool sidetable_addExtraRC_nolock(size_t delta_rc);
171 size_t sidetable_subExtraRC_nolock(size_t delta_rc);
172 size_t sidetable_getExtraRC_nolock();
173 #endif
174
175 // Side-table-only retain count
176 bool sidetable_isDeallocating();
177 void sidetable_clearDeallocating();
178
179 bool sidetable_isWeaklyReferenced();
180 void sidetable_setWeaklyReferenced_nolock();
181
182 id sidetable_retain();
183 id sidetable_retain_slow(SideTable& table);
184
185 uintptr_t sidetable_release(bool performDealloc = true);
186 uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);
187
188 bool sidetable_tryRetain();
189
190 uintptr_t sidetable_retainCount();
191 #if DEBUG
192 bool sidetable_present();
193 #endif
194 };
195
196
197 #if __OBJC2__
198 typedef struct method_t *Method;
199 typedef struct ivar_t *Ivar;
200 typedef struct category_t *Category;
201 typedef struct property_t *objc_property_t;
202 #else
203 typedef struct old_method *Method;
204 typedef struct old_ivar *Ivar;
205 typedef struct old_category *Category;
206 typedef struct old_property *objc_property_t;
207 #endif
208
209 // Public headers
210
211 #include "objc.h"
212 #include "runtime.h"
213 #include "objc-os.h"
214 #include "objc-abi.h"
215 #include "objc-api.h"
216 #include "objc-config.h"
217 #include "objc-internal.h"
218 #include "maptable.h"
219 #include "hashtable2.h"
220
221 /* Do not include message.h here. */
222 /* #include "message.h" */
223
224 #define __APPLE_API_PRIVATE
225 #include "objc-gdb.h"
226 #undef __APPLE_API_PRIVATE
227
228
229 // Private headers
230
231 #include "objc-ptrauth.h"
232
233 #if __OBJC2__
234 #include "objc-runtime-new.h"
235 #else
236 #include "objc-runtime-old.h"
237 #endif
238
239 #include "objc-references.h"
240 #include "objc-initialize.h"
241 #include "objc-loadmethod.h"
242
243
244 #if SUPPORT_PREOPT && __cplusplus
245 #include <objc-shared-cache.h>
246 using objc_selopt_t = const objc_opt::objc_selopt_t;
247 #else
248 struct objc_selopt_t;
249 #endif
250
251
252 #define STRINGIFY(x) #x
253 #define STRINGIFY2(x) STRINGIFY(x)
254
255 __BEGIN_DECLS
256
257 namespace objc {
258
259 struct SafeRanges {
260 private:
261 struct Range {
262 uintptr_t start;
263 uintptr_t end;
264
265 inline bool contains(uintptr_t ptr) const {
266 uintptr_t m_start, m_end;
267 #if __arm64__
268 // <rdar://problem/48304934> Force the compiler to use ldp
269 // we really don't want 2 loads and 2 jumps.
270 __asm__(
271 # if __LP64__
272 "ldp %x[one], %x[two], [%x[src]]"
273 # else
274 "ldp %w[one], %w[two], [%x[src]]"
275 # endif
276 : [one] "=r" (m_start), [two] "=r" (m_end)
277 : [src] "r" (this)
278 );
279 #else
280 m_start = start;
281 m_end = end;
282 #endif
283 return m_start <= ptr && ptr < m_end;
284 }
285 };
286
287 struct Range *ranges;
288 uint32_t count;
289 uint32_t size : 31;
290 uint32_t sorted : 1;
291
292 public:
293 inline bool contains(uint16_t witness, uintptr_t ptr) const {
294 return witness < count && ranges[witness].contains(ptr);
295 }
296
297 bool find(uintptr_t ptr, uint32_t &pos);
298 void add(uintptr_t start, uintptr_t end);
299 void remove(uintptr_t start, uintptr_t end);
300 };
301
302 extern struct SafeRanges dataSegmentsRanges;
303
304 } // objc
305
306 struct header_info;
307
308 // Split out the rw data from header info. For now put it in a huge array
309 // that more than exceeds the space needed. In future we'll just allocate
310 // this in the shared cache builder.
311 typedef struct header_info_rw {
312
313 bool getLoaded() const {
314 return isLoaded;
315 }
316
317 void setLoaded(bool v) {
318 isLoaded = v ? 1: 0;
319 }
320
321 bool getAllClassesRealized() const {
322 return allClassesRealized;
323 }
324
325 void setAllClassesRealized(bool v) {
326 allClassesRealized = v ? 1: 0;
327 }
328
329 header_info *getNext() const {
330 return (header_info *)(next << 2);
331 }
332
333 void setNext(header_info *v) {
334 next = ((uintptr_t)v) >> 2;
335 }
336
337 private:
338 #ifdef __LP64__
339 uintptr_t isLoaded : 1;
340 uintptr_t allClassesRealized : 1;
341 uintptr_t next : 62;
342 #else
343 uintptr_t isLoaded : 1;
344 uintptr_t allClassesRealized : 1;
345 uintptr_t next : 30;
346 #endif
347 } header_info_rw;
348
349 struct header_info_rw* getPreoptimizedHeaderRW(const struct header_info *const hdr);
350
351 typedef struct header_info {
352 private:
353 // Note, this is no longer a pointer, but instead an offset to a pointer
354 // from this location.
355 intptr_t mhdr_offset;
356
357 // Note, this is no longer a pointer, but instead an offset to a pointer
358 // from this location.
359 intptr_t info_offset;
360
361 // Do not add fields without editing ObjCModernAbstraction.hpp
362 public:
363
364 header_info_rw *getHeaderInfoRW() {
365 header_info_rw *preopt =
366 isPreoptimized() ? getPreoptimizedHeaderRW(this) : nil;
367 if (preopt) return preopt;
368 else return &rw_data[0];
369 }
370
371 const headerType *mhdr() const {
372 return (const headerType *)(((intptr_t)&mhdr_offset) + mhdr_offset);
373 }
374
375 void setmhdr(const headerType *mhdr) {
376 mhdr_offset = (intptr_t)mhdr - (intptr_t)&mhdr_offset;
377 }
378
379 const objc_image_info *info() const {
380 return (const objc_image_info *)(((intptr_t)&info_offset) + info_offset);
381 }
382
383 void setinfo(const objc_image_info *info) {
384 info_offset = (intptr_t)info - (intptr_t)&info_offset;
385 }
386
387 bool isLoaded() {
388 return getHeaderInfoRW()->getLoaded();
389 }
390
391 void setLoaded(bool v) {
392 getHeaderInfoRW()->setLoaded(v);
393 }
394
395 bool areAllClassesRealized() {
396 return getHeaderInfoRW()->getAllClassesRealized();
397 }
398
399 void setAllClassesRealized(bool v) {
400 getHeaderInfoRW()->setAllClassesRealized(v);
401 }
402
403 header_info *getNext() {
404 return getHeaderInfoRW()->getNext();
405 }
406
407 void setNext(header_info *v) {
408 getHeaderInfoRW()->setNext(v);
409 }
410
411 bool isBundle() {
412 return mhdr()->filetype == MH_BUNDLE;
413 }
414
415 const char *fname() const {
416 return dyld_image_path_containing_address(mhdr());
417 }
418
419 bool isPreoptimized() const;
420
421 bool hasPreoptimizedSelectors() const;
422
423 bool hasPreoptimizedClasses() const;
424
425 bool hasPreoptimizedProtocols() const;
426
427 #if !__OBJC2__
428 struct old_protocol **proto_refs;
429 struct objc_module *mod_ptr;
430 size_t mod_count;
431 # if TARGET_OS_WIN32
432 struct objc_module **modules;
433 size_t moduleCount;
434 struct old_protocol **protocols;
435 size_t protocolCount;
436 void *imageinfo;
437 size_t imageinfoBytes;
438 SEL *selrefs;
439 size_t selrefCount;
440 struct objc_class **clsrefs;
441 size_t clsrefCount;
442 TCHAR *moduleName;
443 # endif
444 #endif
445
446 private:
447 // Images in the shared cache will have an empty array here while those
448 // allocated at run time will allocate a single entry.
449 header_info_rw rw_data[];
450 } header_info;
451
452 extern header_info *FirstHeader;
453 extern header_info *LastHeader;
454
455 extern void appendHeader(header_info *hi);
456 extern void removeHeader(header_info *hi);
457
458 extern objc_image_info *_getObjcImageInfo(const headerType *head, size_t *size);
459 extern bool _hasObjcContents(const header_info *hi);
460
461
462 // Mach-O segment and section names are 16 bytes and may be un-terminated.
463
464 static inline bool segnameEquals(const char *lhs, const char *rhs) {
465 return 0 == strncmp(lhs, rhs, 16);
466 }
467
468 static inline bool segnameStartsWith(const char *segname, const char *prefix) {
469 return 0 == strncmp(segname, prefix, strlen(prefix));
470 }
471
472 static inline bool sectnameEquals(const char *lhs, const char *rhs) {
473 return segnameEquals(lhs, rhs);
474 }
475
476 static inline bool sectnameStartsWith(const char *sectname, const char *prefix){
477 return segnameStartsWith(sectname, prefix);
478 }
479
480
481 #if __OBJC2__
482 extern bool didCallDyldNotifyRegister;
483 #endif
484
485
486 /* selectors */
487 extern void sel_init(size_t selrefCount);
488 extern SEL sel_registerNameNoLock(const char *str, bool copy);
489
490 extern SEL SEL_cxx_construct;
491 extern SEL SEL_cxx_destruct;
492
493 /* preoptimization */
494 extern void preopt_init(void);
495 extern void disableSharedCacheOptimizations(void);
496 extern bool isPreoptimized(void);
497 extern bool noMissingWeakSuperclasses(void);
498 extern header_info *preoptimizedHinfoForHeader(const headerType *mhdr);
499
500 extern objc_selopt_t *preoptimizedSelectors(void);
501
502 extern bool sharedCacheSupportsProtocolRoots(void);
503 extern Protocol *getPreoptimizedProtocol(const char *name);
504 extern Protocol *getSharedCachePreoptimizedProtocol(const char *name);
505
506 extern unsigned getPreoptimizedClassUnreasonableCount();
507 extern Class getPreoptimizedClass(const char *name);
508 extern Class* copyPreoptimizedClasses(const char *name, int *outCount);
509
510 extern Class _calloc_class(size_t size);
511
512 /* method lookup */
513 enum {
514 LOOKUP_INITIALIZE = 1,
515 LOOKUP_RESOLVER = 2,
516 LOOKUP_CACHE = 4,
517 LOOKUP_NIL = 8,
518 };
519 extern IMP lookUpImpOrForward(id obj, SEL, Class cls, int behavior);
520
521 static inline IMP
522 lookUpImpOrNil(id obj, SEL sel, Class cls, int behavior = 0)
523 {
524 return lookUpImpOrForward(obj, sel, cls, behavior | LOOKUP_CACHE | LOOKUP_NIL);
525 }
526
527 extern IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel);
528 extern BOOL class_respondsToSelector_inst(id inst, SEL sel, Class cls);
529 extern Class class_initialize(Class cls, id inst);
530
531 extern bool objcMsgLogEnabled;
532 extern bool logMessageSend(bool isClassMethod,
533 const char *objectsClass,
534 const char *implementingClass,
535 SEL selector);
536
537 /* message dispatcher */
538
539 #if !OBJC_OLD_DISPATCH_PROTOTYPES
540 extern void _objc_msgForward_impcache(void);
541 #else
542 extern id _objc_msgForward_impcache(id, SEL, ...);
543 #endif
544
545 /* errors */
546 extern id(*badAllocHandler)(Class);
547 extern id _objc_callBadAllocHandler(Class cls) __attribute__((cold, noinline));
548 extern void __objc_error(id, const char *, ...) __attribute__((cold, format (printf, 2, 3), noreturn));
549 extern void _objc_inform(const char *fmt, ...) __attribute__((cold, format(printf, 1, 2)));
550 extern void _objc_inform_on_crash(const char *fmt, ...) __attribute__((cold, format (printf, 1, 2)));
551 extern void _objc_inform_now_and_on_crash(const char *fmt, ...) __attribute__((cold, format (printf, 1, 2)));
552 extern void _objc_inform_deprecated(const char *oldname, const char *newname) __attribute__((cold, noinline));
553 extern void inform_duplicate(const char *name, Class oldCls, Class cls);
554
555 /* magic */
556 extern Class _objc_getFreedObjectClass (void);
557
558 /* map table additions */
559 extern void *NXMapKeyCopyingInsert(NXMapTable *table, const void *key, const void *value);
560 extern void *NXMapKeyFreeingRemove(NXMapTable *table, const void *key);
561
562 /* hash table additions */
563 extern unsigned _NXHashCapacity(NXHashTable *table);
564 extern void _NXHashRehashToCapacity(NXHashTable *table, unsigned newCapacity);
565
566 /* property attribute parsing */
567 extern const char *copyPropertyAttributeString(const objc_property_attribute_t *attrs, unsigned int count);
568 extern objc_property_attribute_t *copyPropertyAttributeList(const char *attrs, unsigned int *outCount);
569 extern char *copyPropertyAttributeValue(const char *attrs, const char *name);
570
571 /* locking */
572
573 class monitor_locker_t : nocopy_t {
574 monitor_t& lock;
575 public:
576 monitor_locker_t(monitor_t& newLock) : lock(newLock) { lock.enter(); }
577 ~monitor_locker_t() { lock.leave(); }
578 };
579
580 class recursive_mutex_locker_t : nocopy_t {
581 recursive_mutex_t& lock;
582 public:
583 recursive_mutex_locker_t(recursive_mutex_t& newLock)
584 : lock(newLock) { lock.lock(); }
585 ~recursive_mutex_locker_t() { lock.unlock(); }
586 };
587
588
589 /* Exceptions */
590 struct alt_handler_list;
591 extern void exception_init(void);
592 extern void _destroyAltHandlerList(struct alt_handler_list *list);
593
594 /* Class change notifications (gdb only for now) */
595 #define OBJC_CLASS_ADDED (1<<0)
596 #define OBJC_CLASS_REMOVED (1<<1)
597 #define OBJC_CLASS_IVARS_CHANGED (1<<2)
598 #define OBJC_CLASS_METHODS_CHANGED (1<<3)
599 extern void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)
600 __attribute__((noinline));
601
602
603 // Settings from environment variables
604 #define OPTION(var, env, help) extern bool var;
605 #include "objc-env.h"
606 #undef OPTION
607
608 extern void environ_init(void);
609 extern void runtime_init(void);
610
611 extern void logReplacedMethod(const char *className, SEL s, bool isMeta, const char *catName, IMP oldImp, IMP newImp);
612
613
614 // objc per-thread storage
615 typedef struct {
616 struct _objc_initializing_classes *initializingClasses; // for +initialize
617 struct SyncCache *syncCache; // for @synchronize
618 struct alt_handler_list *handlerList; // for exception alt handlers
619 char *printableNames[4]; // temporary demangled names for logging
620 const char **classNameLookups; // for objc_getClass() hooks
621 unsigned classNameLookupsAllocated;
622 unsigned classNameLookupsUsed;
623
624 // If you add new fields here, don't forget to update
625 // _objc_pthread_destroyspecific()
626
627 } _objc_pthread_data;
628
629 extern _objc_pthread_data *_objc_fetch_pthread_data(bool create);
630 extern void tls_init(void);
631
632 // encoding.h
633 extern unsigned int encoding_getNumberOfArguments(const char *typedesc);
634 extern unsigned int encoding_getSizeOfArguments(const char *typedesc);
635 extern unsigned int encoding_getArgumentInfo(const char *typedesc, unsigned int arg, const char **type, int *offset);
636 extern void encoding_getReturnType(const char *t, char *dst, size_t dst_len);
637 extern char * encoding_copyReturnType(const char *t);
638 extern void encoding_getArgumentType(const char *t, unsigned int index, char *dst, size_t dst_len);
639 extern char *encoding_copyArgumentType(const char *t, unsigned int index);
640
641 // sync.h
642 extern void _destroySyncCache(struct SyncCache *cache);
643
644 // arr
645 extern void arr_init(void);
646 extern id objc_autoreleaseReturnValue(id obj);
647
648 // block trampolines
649 extern void _imp_implementationWithBlock_init(void);
650 extern IMP _imp_implementationWithBlockNoCopy(id block);
651
652 // layout.h
653 typedef struct {
654 uint8_t *bits;
655 size_t bitCount;
656 size_t bitsAllocated;
657 bool weak;
658 } layout_bitmap;
659 extern layout_bitmap layout_bitmap_create(const unsigned char *layout_string, size_t layoutStringInstanceSize, size_t instanceSize, bool weak);
660 extern layout_bitmap layout_bitmap_create_empty(size_t instanceSize, bool weak);
661 extern void layout_bitmap_free(layout_bitmap bits);
662 extern const unsigned char *layout_string_create(layout_bitmap bits);
663 extern void layout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset);
664 extern void layout_bitmap_grow(layout_bitmap *bits, size_t newCount);
665 extern void layout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos);
666 extern void layout_bitmap_slide_anywhere(layout_bitmap *bits, size_t oldPos, size_t newPos);
667 extern bool layout_bitmap_splat(layout_bitmap dst, layout_bitmap src,
668 size_t oldSrcInstanceSize);
669 extern bool layout_bitmap_or(layout_bitmap dst, layout_bitmap src, const char *msg);
670 extern bool layout_bitmap_clear(layout_bitmap dst, layout_bitmap src, const char *msg);
671 extern void layout_bitmap_print(layout_bitmap bits);
672
673
674 // fixme runtime
675 extern bool MultithreadedForkChild;
676 extern id objc_noop_imp(id self, SEL _cmd);
677 extern Class look_up_class(const char *aClassName, bool includeUnconnected, bool includeClassHandler);
678 extern "C" void map_images(unsigned count, const char * const paths[],
679 const struct mach_header * const mhdrs[]);
680 extern void map_images_nolock(unsigned count, const char * const paths[],
681 const struct mach_header * const mhdrs[]);
682 extern void load_images(const char *path, const struct mach_header *mh);
683 extern void unmap_image(const char *path, const struct mach_header *mh);
684 extern void unmap_image_nolock(const struct mach_header *mh);
685 extern void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClass);
686 extern void _unload_image(header_info *hi);
687
688 extern const header_info *_headerForClass(Class cls);
689
690 extern Class _class_remap(Class cls);
691 extern Ivar _class_getVariable(Class cls, const char *name);
692
693 extern unsigned _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone, id *results, unsigned num_requested);
694
695 extern const char *_category_getName(Category cat);
696 extern const char *_category_getClassName(Category cat);
697 extern Class _category_getClass(Category cat);
698 extern IMP _category_getLoadMethod(Category cat);
699
700 enum {
701 OBJECT_CONSTRUCT_NONE = 0,
702 OBJECT_CONSTRUCT_FREE_ONFAILURE = 1,
703 OBJECT_CONSTRUCT_CALL_BADALLOC = 2,
704 };
705 extern id object_cxxConstructFromClass(id obj, Class cls, int flags);
706 extern void object_cxxDestruct(id obj);
707
708 extern void fixupCopiedIvars(id newObject, id oldObject);
709 extern Class _class_getClassForIvar(Class cls, Ivar ivar);
710
711
712 #define OBJC_WARN_DEPRECATED \
713 do { \
714 static int warned = 0; \
715 if (!warned) { \
716 warned = 1; \
717 _objc_inform_deprecated(__FUNCTION__, NULL); \
718 } \
719 } while (0) \
720
721 __END_DECLS
722
723
724 #ifndef STATIC_ASSERT
725 # define STATIC_ASSERT(x) _STATIC_ASSERT2(x, __LINE__)
726 # define _STATIC_ASSERT2(x, line) _STATIC_ASSERT3(x, line)
727 # define _STATIC_ASSERT3(x, line) \
728 typedef struct { \
729 int _static_assert[(x) ? 0 : -1]; \
730 } _static_assert_ ## line __attribute__((unavailable))
731 #endif
732
733 #define countof(arr) (sizeof(arr) / sizeof((arr)[0]))
734
735
736 static __inline uint32_t _objc_strhash(const char *s) {
737 uint32_t hash = 0;
738 for (;;) {
739 int a = *s++;
740 if (0 == a) break;
741 hash += (hash << 8) + a;
742 }
743 return hash;
744 }
745
746 #if __cplusplus
747
748 template <typename T>
749 static inline T log2u(T x) {
750 return (x<2) ? 0 : log2u(x>>1)+1;
751 }
752
753 template <typename T>
754 static inline T exp2u(T x) {
755 return (1 << x);
756 }
757
758 template <typename T>
759 static T exp2m1u(T x) {
760 return (1 << x) - 1;
761 }
762
763 #endif
764
765 // Misalignment-safe integer types
766 __attribute__((aligned(1))) typedef uintptr_t unaligned_uintptr_t;
767 __attribute__((aligned(1))) typedef intptr_t unaligned_intptr_t;
768 __attribute__((aligned(1))) typedef uint64_t unaligned_uint64_t;
769 __attribute__((aligned(1))) typedef int64_t unaligned_int64_t;
770 __attribute__((aligned(1))) typedef uint32_t unaligned_uint32_t;
771 __attribute__((aligned(1))) typedef int32_t unaligned_int32_t;
772 __attribute__((aligned(1))) typedef uint16_t unaligned_uint16_t;
773 __attribute__((aligned(1))) typedef int16_t unaligned_int16_t;
774
775
776 // Global operator new and delete. We must not use any app overrides.
777 // This ALSO REQUIRES each of these be in libobjc's unexported symbol list.
778 #if __cplusplus
779 #pragma clang diagnostic push
780 #pragma clang diagnostic ignored "-Winline-new-delete"
781 #include <new>
782 inline void* operator new(std::size_t size) throw (std::bad_alloc) { return malloc(size); }
783 inline void* operator new[](std::size_t size) throw (std::bad_alloc) { return malloc(size); }
784 inline void* operator new(std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }
785 inline void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }
786 inline void operator delete(void* p) throw() { free(p); }
787 inline void operator delete[](void* p) throw() { free(p); }
788 inline void operator delete(void* p, const std::nothrow_t&) throw() { free(p); }
789 inline void operator delete[](void* p, const std::nothrow_t&) throw() { free(p); }
790 #pragma clang diagnostic pop
791 #endif
792
793
794 class TimeLogger {
795 uint64_t mStart;
796 bool mRecord;
797 public:
798 TimeLogger(bool record = true)
799 : mStart(nanoseconds())
800 , mRecord(record)
801 { }
802
803 void log(const char *msg) {
804 if (mRecord) {
805 uint64_t end = nanoseconds();
806 _objc_inform("%.2f ms: %s", (end - mStart) / 1000000.0, msg);
807 mStart = nanoseconds();
808 }
809 }
810 };
811
812 enum { CacheLineSize = 64 };
813
814 // StripedMap<T> is a map of void* -> T, sized appropriately
815 // for cache-friendly lock striping.
816 // For example, this may be used as StripedMap<spinlock_t>
817 // or as StripedMap<SomeStruct> where SomeStruct stores a spin lock.
818 template<typename T>
819 class StripedMap {
820 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
821 enum { StripeCount = 8 };
822 #else
823 enum { StripeCount = 64 };
824 #endif
825
826 struct PaddedT {
827 T value alignas(CacheLineSize);
828 };
829
830 PaddedT array[StripeCount];
831
832 static unsigned int indexForPointer(const void *p) {
833 uintptr_t addr = reinterpret_cast<uintptr_t>(p);
834 return ((addr >> 4) ^ (addr >> 9)) % StripeCount;
835 }
836
837 public:
838 T& operator[] (const void *p) {
839 return array[indexForPointer(p)].value;
840 }
841 const T& operator[] (const void *p) const {
842 return const_cast<StripedMap<T>>(this)[p];
843 }
844
845 // Shortcuts for StripedMaps of locks.
846 void lockAll() {
847 for (unsigned int i = 0; i < StripeCount; i++) {
848 array[i].value.lock();
849 }
850 }
851
852 void unlockAll() {
853 for (unsigned int i = 0; i < StripeCount; i++) {
854 array[i].value.unlock();
855 }
856 }
857
858 void forceResetAll() {
859 for (unsigned int i = 0; i < StripeCount; i++) {
860 array[i].value.forceReset();
861 }
862 }
863
864 void defineLockOrder() {
865 for (unsigned int i = 1; i < StripeCount; i++) {
866 lockdebug_lock_precedes_lock(&array[i-1].value, &array[i].value);
867 }
868 }
869
870 void precedeLock(const void *newlock) {
871 // assumes defineLockOrder is also called
872 lockdebug_lock_precedes_lock(&array[StripeCount-1].value, newlock);
873 }
874
875 void succeedLock(const void *oldlock) {
876 // assumes defineLockOrder is also called
877 lockdebug_lock_precedes_lock(oldlock, &array[0].value);
878 }
879
880 const void *getLock(int i) {
881 if (i < StripeCount) return &array[i].value;
882 else return nil;
883 }
884
885 #if DEBUG
886 StripedMap() {
887 // Verify alignment expectations.
888 uintptr_t base = (uintptr_t)&array[0].value;
889 uintptr_t delta = (uintptr_t)&array[1].value - base;
890 ASSERT(delta % CacheLineSize == 0);
891 ASSERT(base % CacheLineSize == 0);
892 }
893 #else
894 constexpr StripedMap() {}
895 #endif
896 };
897
898
899 // DisguisedPtr<T> acts like pointer type T*, except the
900 // stored value is disguised to hide it from tools like `leaks`.
901 // nil is disguised as itself so zero-filled memory works as expected,
902 // which means 0x80..00 is also disguised as itself but we don't care.
903 // Note that weak_entry_t knows about this encoding.
904 template <typename T>
905 class DisguisedPtr {
906 uintptr_t value;
907
908 static uintptr_t disguise(T* ptr) {
909 return -(uintptr_t)ptr;
910 }
911
912 static T* undisguise(uintptr_t val) {
913 return (T*)-val;
914 }
915
916 public:
917 DisguisedPtr() { }
918 DisguisedPtr(T* ptr)
919 : value(disguise(ptr)) { }
920 DisguisedPtr(const DisguisedPtr<T>& ptr)
921 : value(ptr.value) { }
922
923 DisguisedPtr<T>& operator = (T* rhs) {
924 value = disguise(rhs);
925 return *this;
926 }
927 DisguisedPtr<T>& operator = (const DisguisedPtr<T>& rhs) {
928 value = rhs.value;
929 return *this;
930 }
931
932 operator T* () const {
933 return undisguise(value);
934 }
935 T* operator -> () const {
936 return undisguise(value);
937 }
938 T& operator * () const {
939 return *undisguise(value);
940 }
941 T& operator [] (size_t i) const {
942 return undisguise(value)[i];
943 }
944
945 // pointer arithmetic operators omitted
946 // because we don't currently use them anywhere
947 };
948
949 // fixme type id is weird and not identical to objc_object*
950 static inline bool operator == (DisguisedPtr<objc_object> lhs, id rhs) {
951 return lhs == (objc_object *)rhs;
952 }
953 static inline bool operator != (DisguisedPtr<objc_object> lhs, id rhs) {
954 return lhs != (objc_object *)rhs;
955 }
956
957
958 // Storage for a thread-safe chained hook function.
959 // get() returns the value for calling.
960 // set() installs a new function and returns the old one for chaining.
961 // More precisely, set() writes the old value to a variable supplied by
962 // the caller. get() and set() use appropriate barriers so that the
963 // old value is safely written to the variable before the new value is
964 // called to use it.
965 //
966 // T1: store to old variable; store-release to hook variable
967 // T2: load-acquire from hook variable; call it; called hook loads old variable
968
969 template <typename Fn>
970 class ChainedHookFunction {
971 std::atomic<Fn> hook{nil};
972
973 public:
974 ChainedHookFunction(Fn f) : hook{f} { };
975
976 Fn get() {
977 return hook.load(std::memory_order_acquire);
978 }
979
980 void set(Fn newValue, Fn *oldVariable)
981 {
982 Fn oldValue = hook.load(std::memory_order_relaxed);
983 do {
984 *oldVariable = oldValue;
985 } while (!hook.compare_exchange_weak(oldValue, newValue,
986 std::memory_order_release,
987 std::memory_order_relaxed));
988 }
989 };
990
991
992 // A small vector for use as a global variable. Only supports appending and
993 // iteration. Stores a single element inline, and multiple elements in a heap
994 // allocation. There is no attempt to amortize reallocation cost; this is
995 // intended to be used in situation where zero or one element is common, two
996 // might happen, and three or more is very rare.
997 //
998 // This does not clean up its allocation, and thus cannot be used as a local
999 // variable or member of something with limited lifetime.
1000
1001 template <typename T, unsigned InlineCount>
1002 class GlobalSmallVector {
1003 static_assert(std::is_pod<T>::value, "SmallVector requires POD types");
1004
1005 protected:
1006 unsigned count{0};
1007 union {
1008 T inlineElements[InlineCount];
1009 T *elements;
1010 };
1011
1012 public:
1013 void append(const T &val) {
1014 if (count < InlineCount) {
1015 // We have space. Store the new value inline.
1016 inlineElements[count] = val;
1017 } else if (count == InlineCount) {
1018 // Inline storage is full. Switch to a heap allocation.
1019 T *newElements = (T *)malloc((count + 1) * sizeof(T));
1020 memcpy(newElements, inlineElements, count * sizeof(T));
1021 newElements[count] = val;
1022 elements = newElements;
1023 } else {
1024 // Resize the heap allocation and append.
1025 elements = (T *)realloc(elements, (count + 1) * sizeof(T));
1026 elements[count] = val;
1027 }
1028 count++;
1029 }
1030
1031 const T *begin() const {
1032 return count <= InlineCount ? inlineElements : elements;
1033 }
1034
1035 const T *end() const {
1036 return begin() + count;
1037 }
1038 };
1039
1040 // A small vector that cleans up its internal memory allocation when destroyed.
1041 template <typename T, unsigned InlineCount>
1042 class SmallVector: public GlobalSmallVector<T, InlineCount> {
1043 public:
1044 ~SmallVector() {
1045 if (this->count > InlineCount)
1046 free(this->elements);
1047 }
1048
1049 template <unsigned OtherCount>
1050 void initFrom(const GlobalSmallVector<T, OtherCount> &other) {
1051 ASSERT(this->count == 0);
1052 this->count = (unsigned)(other.end() - other.begin());
1053 if (this->count > InlineCount) {
1054 this->elements = (T *)memdup(other.begin(), this->count * sizeof(T));
1055 } else {
1056 memcpy(this->inlineElements, other.begin(), this->count * sizeof(T));
1057 }
1058 }
1059 };
1060
1061 // Pointer hash function.
1062 // This is not a terrific hash, but it is fast
1063 // and not outrageously flawed for our purposes.
1064
1065 // Based on principles from http://locklessinc.com/articles/fast_hash/
1066 // and evaluation ideas from http://floodyberry.com/noncryptohashzoo/
1067 #if __LP64__
1068 static inline uint32_t ptr_hash(uint64_t key)
1069 {
1070 key ^= key >> 4;
1071 key *= 0x8a970be7488fda55;
1072 key ^= __builtin_bswap64(key);
1073 return (uint32_t)key;
1074 }
1075 #else
1076 static inline uint32_t ptr_hash(uint32_t key)
1077 {
1078 key ^= key >> 4;
1079 key *= 0x5052acdb;
1080 key ^= __builtin_bswap32(key);
1081 return key;
1082 }
1083 #endif
1084
1085 /*
1086 Higher-quality hash function. This is measurably slower in some workloads.
1087 #if __LP64__
1088 uint32_t ptr_hash(uint64_t key)
1089 {
1090 key -= __builtin_bswap64(key);
1091 key *= 0x8a970be7488fda55;
1092 key ^= __builtin_bswap64(key);
1093 key *= 0x8a970be7488fda55;
1094 key ^= __builtin_bswap64(key);
1095 return (uint32_t)key;
1096 }
1097 #else
1098 static uint32_t ptr_hash(uint32_t key)
1099 {
1100 key -= __builtin_bswap32(key);
1101 key *= 0x5052acdb;
1102 key ^= __builtin_bswap32(key);
1103 key *= 0x5052acdb;
1104 key ^= __builtin_bswap32(key);
1105 return key;
1106 }
1107 #endif
1108 */
1109
1110
1111
1112 // Lock declarations
1113 #include "objc-locks.h"
1114
1115 // Inlined parts of objc_object's implementation
1116 #include "objc-object.h"
1117
1118 #endif /* _OBJC_PRIVATE_H_ */
1119