-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathobjc-internal.h
885 lines (743 loc) · 31.9 KB
/
objc-internal.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
/*
* Copyright (c) 2009 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_INTERNAL_H
#define _OBJC_INTERNAL_H
/*
* WARNING DANGER HAZARD BEWARE EEK
*
* Everything in this file is for Apple Internal use only.
* These will change in arbitrary OS updates and in unpredictable ways.
* When your program breaks, you get to keep both pieces.
*/
/*
* objc-internal.h: Private SPI for use by other system frameworks.
*/
#include <objc/objc.h>
#include <objc/runtime.h>
#include <Availability.h>
#include <malloc/malloc.h>
#include <mach-o/loader.h>
#include <dispatch/dispatch.h>
// Termination reasons in the OS_REASON_OBJC namespace.
#define OBJC_EXIT_REASON_UNSPECIFIED 1
#define OBJC_EXIT_REASON_GC_NOT_SUPPORTED 2
// This is the allocation size required for each of the class and the metaclass
// with objc_initializeClassPair() and objc_readClassPair().
// The runtime's class structure will never grow beyond this.
#define OBJC_MAX_CLASS_SIZE (32*sizeof(void*))
__BEGIN_DECLS
// In-place construction of an Objective-C class.
// cls and metacls must each be OBJC_MAX_CLASS_SIZE bytes.
// Returns nil if a class with the same name already exists.
// Returns nil if the superclass is under construction.
// Call objc_registerClassPair() when you are done.
OBJC_EXPORT Class _Nullable
objc_initializeClassPair(Class _Nullable superclass, const char * _Nonnull name,
Class _Nonnull cls, Class _Nonnull metacls)
OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0, 2.0);
// Class and metaclass construction from a compiler-generated memory image.
// cls and cls->isa must each be OBJC_MAX_CLASS_SIZE bytes.
// Extra bytes not used the the metadata must be zero.
// info is the same objc_image_info that would be emitted by a static compiler.
// Returns nil if a class with the same name already exists.
// Returns nil if the superclass is nil and the class is not marked as a root.
// Returns nil if the superclass is under construction.
// Do not call objc_registerClassPair().
#if __OBJC2__
struct objc_image_info;
OBJC_EXPORT Class _Nullable
objc_readClassPair(Class _Nonnull cls,
const struct objc_image_info * _Nonnull info)
OBJC_AVAILABLE(10.10, 8.0, 9.0, 1.0, 2.0);
#endif
// Batch object allocation using malloc_zone_batch_malloc().
OBJC_EXPORT unsigned
class_createInstances(Class _Nullable cls, size_t extraBytes,
id _Nonnull * _Nonnull results, unsigned num_requested)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0)
OBJC_ARC_UNAVAILABLE;
// Get the isa pointer written into objects just before being freed.
OBJC_EXPORT Class _Nonnull
_objc_getFreedObjectClass(void)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
// env NSObjCMessageLoggingEnabled
OBJC_EXPORT void
instrumentObjcMessageSends(BOOL flag)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
// Initializer called by libSystem
OBJC_EXPORT void
_objc_init(void)
#if __OBJC2__
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
#else
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
#endif
// fork() safety called by libSystem
OBJC_EXPORT void
_objc_atfork_prepare(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
OBJC_EXPORT void
_objc_atfork_parent(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
OBJC_EXPORT void
_objc_atfork_child(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
// Return YES if GC is on and `object` is a GC allocation.
OBJC_EXPORT BOOL
objc_isAuto(id _Nullable object)
__OSX_DEPRECATED(10.4, 10.8, "it always returns NO")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE
__WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;
// GC debugging
OBJC_EXPORT BOOL
objc_dumpHeap(char * _Nonnull filename, unsigned long length)
__OSX_DEPRECATED(10.4, 10.8, "it always returns NO")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE
__WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;
// GC startup callback from Foundation
OBJC_EXPORT malloc_zone_t * _Nullable
objc_collect_init(int (* _Nonnull callback)(void))
__OSX_DEPRECATED(10.4, 10.8, "it does nothing")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE
__WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;
// Plainly-implemented GC barriers. Rosetta used to use these.
OBJC_EXPORT id _Nullable
objc_assign_strongCast_generic(id _Nullable value, id _Nullable * _Nonnull dest)
UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT id _Nullable
objc_assign_global_generic(id _Nullable value, id _Nullable * _Nonnull dest)
UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT id _Nullable
objc_assign_threadlocal_generic(id _Nullable value,
id _Nullable * _Nonnull dest)
UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT id _Nullable
objc_assign_ivar_generic(id _Nullable value, id _Nonnull dest, ptrdiff_t offset)
UNAVAILABLE_ATTRIBUTE;
// GC preflight for an app executable.
// 1: some slice requires GC
// 0: no slice requires GC
// -1: I/O or file format error
OBJC_EXPORT int
objc_appRequiresGC(int fd)
__OSX_AVAILABLE(10.11)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE
__WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;
// Install missing-class callback. Used by the late unlamented ZeroLink.
OBJC_EXPORT void
_objc_setClassLoader(BOOL (* _Nonnull newClassLoader)(const char * _Nonnull))
OBJC2_UNAVAILABLE;
#if !(TARGET_OS_OSX && !TARGET_OS_IOSMAC && __i386__)
OBJC_EXPORT void
_objc_setClassCopyFixupHandler(void (* _Nonnull newFixupHandler)
(Class _Nonnull oldClass, Class _Nonnull newClass));
// fixme work around bug in Swift
// OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0)
#endif
// Install handler for allocation failures.
// Handler may abort, or throw, or provide an object to return.
OBJC_EXPORT void
_objc_setBadAllocHandler(id _Nullable (* _Nonnull newHandler)
(Class _Nullable isa))
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
// Used by ExceptionHandling.framework
#if !__OBJC2__
OBJC_EXPORT void
_objc_error(id _Nullable rcv, const char * _Nonnull fmt, va_list args)
__attribute__((noreturn))
__OSX_DEPRECATED(10.0, 10.5, "use other logging facilities instead")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE
__WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;
#endif
/**
* Returns the names of all the classes within a library.
*
* @param image The mach header for library or framework you are inquiring about.
* @param outCount The number of class names returned.
*
* @return An array of C strings representing the class names.
*/
OBJC_EXPORT const char * _Nonnull * _Nullable
objc_copyClassNamesForImageHeader(const struct mach_header * _Nonnull mh,
unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);
// Tagged pointer objects.
#if __LP64__
#define OBJC_HAVE_TAGGED_POINTERS 1
#endif
#if OBJC_HAVE_TAGGED_POINTERS
// Tagged pointer layout and usage is subject to change on different OS versions.
// Tag indexes 0..<7 have a 60-bit payload.
// Tag index 7 is reserved.
// Tag indexes 8..<264 have a 52-bit payload.
// Tag index 264 is reserved.
#if __has_feature(objc_fixed_enum) || __cplusplus >= 201103L
enum objc_tag_index_t : uint16_t
#else
typedef uint16_t objc_tag_index_t;
enum
#endif
{
// 60-bit payloads
OBJC_TAG_NSAtom = 0,
OBJC_TAG_1 = 1,
OBJC_TAG_NSString = 2,
OBJC_TAG_NSNumber = 3,
OBJC_TAG_NSIndexPath = 4,
OBJC_TAG_NSManagedObjectID = 5,
OBJC_TAG_NSDate = 6,
// 60-bit reserved
OBJC_TAG_RESERVED_7 = 7,
// 52-bit payloads
OBJC_TAG_Photos_1 = 8,
OBJC_TAG_Photos_2 = 9,
OBJC_TAG_Photos_3 = 10,
OBJC_TAG_Photos_4 = 11,
OBJC_TAG_XPC_1 = 12,
OBJC_TAG_XPC_2 = 13,
OBJC_TAG_XPC_3 = 14,
OBJC_TAG_XPC_4 = 15,
OBJC_TAG_First60BitPayload = 0,
OBJC_TAG_Last60BitPayload = 6,
OBJC_TAG_First52BitPayload = 8,
OBJC_TAG_Last52BitPayload = 263,
OBJC_TAG_RESERVED_264 = 264
};
#if __has_feature(objc_fixed_enum) && !defined(__cplusplus)
typedef enum objc_tag_index_t objc_tag_index_t;
#endif
// Returns true if tagged pointers are enabled.
// The other functions below must not be called if tagged pointers are disabled.
static inline bool
_objc_taggedPointersEnabled(void);
// Register a class for a tagged pointer tag.
// Aborts if the tag is invalid or already in use.
OBJC_EXPORT void
_objc_registerTaggedPointerClass(objc_tag_index_t tag, Class _Nonnull cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
// Returns the registered class for the given tag.
// Returns nil if the tag is valid but has no registered class.
// Aborts if the tag is invalid.
OBJC_EXPORT Class _Nullable
_objc_getClassForTag(objc_tag_index_t tag)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
// Create a tagged pointer object with the given tag and payload.
// Assumes the tag is valid.
// Assumes tagged pointers are enabled.
// The payload will be silently truncated to fit.
static inline void * _Nonnull
_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t payload);
// Return true if ptr is a tagged pointer object.
// Does not check the validity of ptr's class.
static inline bool
_objc_isTaggedPointer(const void * _Nullable ptr);
// Extract the tag value from the given tagged pointer object.
// Assumes ptr is a valid tagged pointer object.
// Does not check the validity of ptr's tag.
static inline objc_tag_index_t
_objc_getTaggedPointerTag(const void * _Nullable ptr);
// Extract the payload from the given tagged pointer object.
// Assumes ptr is a valid tagged pointer object.
// The payload value is zero-extended.
static inline uintptr_t
_objc_getTaggedPointerValue(const void * _Nullable ptr);
// Extract the payload from the given tagged pointer object.
// Assumes ptr is a valid tagged pointer object.
// The payload value is sign-extended.
static inline intptr_t
_objc_getTaggedPointerSignedValue(const void * _Nullable ptr);
// Don't use the values below. Use the declarations above.
#if (TARGET_OS_OSX || TARGET_OS_IOSMAC) && __x86_64__
// 64-bit Mac - tag bit is LSB
# define OBJC_MSB_TAGGED_POINTERS 0
#else
// Everything else - tag bit is MSB
# define OBJC_MSB_TAGGED_POINTERS 1
#endif
#define _OBJC_TAG_INDEX_MASK 0x7
// array slot includes the tag bit itself
#define _OBJC_TAG_SLOT_COUNT 16
#define _OBJC_TAG_SLOT_MASK 0xf
#define _OBJC_TAG_EXT_INDEX_MASK 0xff
// array slot has no extra bits
#define _OBJC_TAG_EXT_SLOT_COUNT 256
#define _OBJC_TAG_EXT_SLOT_MASK 0xff
#if OBJC_MSB_TAGGED_POINTERS
# define _OBJC_TAG_MASK (1UL<<63)
# define _OBJC_TAG_INDEX_SHIFT 60
# define _OBJC_TAG_SLOT_SHIFT 60
# define _OBJC_TAG_PAYLOAD_LSHIFT 4
# define _OBJC_TAG_PAYLOAD_RSHIFT 4
# define _OBJC_TAG_EXT_MASK (0xfUL<<60)
# define _OBJC_TAG_EXT_INDEX_SHIFT 52
# define _OBJC_TAG_EXT_SLOT_SHIFT 52
# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 12
# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
#else
# define _OBJC_TAG_MASK 1UL
# define _OBJC_TAG_INDEX_SHIFT 1
# define _OBJC_TAG_SLOT_SHIFT 0
# define _OBJC_TAG_PAYLOAD_LSHIFT 0
# define _OBJC_TAG_PAYLOAD_RSHIFT 4
# define _OBJC_TAG_EXT_MASK 0xfUL
# define _OBJC_TAG_EXT_INDEX_SHIFT 4
# define _OBJC_TAG_EXT_SLOT_SHIFT 4
# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 0
# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
#endif
extern uintptr_t objc_debug_taggedpointer_obfuscator;
static inline void * _Nonnull
_objc_encodeTaggedPointer(uintptr_t ptr)
{
return (void *)(objc_debug_taggedpointer_obfuscator ^ ptr);
}
static inline uintptr_t
_objc_decodeTaggedPointer(const void * _Nullable ptr)
{
return (uintptr_t)ptr ^ objc_debug_taggedpointer_obfuscator;
}
static inline bool
_objc_taggedPointersEnabled(void)
{
extern uintptr_t objc_debug_taggedpointer_mask;
return (objc_debug_taggedpointer_mask != 0);
}
static inline void * _Nonnull
_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t value)
{
// PAYLOAD_LSHIFT and PAYLOAD_RSHIFT are the payload extraction shifts.
// They are reversed here for payload insertion.
// assert(_objc_taggedPointersEnabled());
if (tag <= OBJC_TAG_Last60BitPayload) {
// assert(((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT) == value);
uintptr_t result =
(_OBJC_TAG_MASK |
((uintptr_t)tag << _OBJC_TAG_INDEX_SHIFT) |
((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT));
return _objc_encodeTaggedPointer(result);
} else {
// assert(tag >= OBJC_TAG_First52BitPayload);
// assert(tag <= OBJC_TAG_Last52BitPayload);
// assert(((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT) == value);
uintptr_t result =
(_OBJC_TAG_EXT_MASK |
((uintptr_t)(tag - OBJC_TAG_First52BitPayload) << _OBJC_TAG_EXT_INDEX_SHIFT) |
((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT));
return _objc_encodeTaggedPointer(result);
}
}
static inline bool
_objc_isTaggedPointer(const void * _Nullable ptr)
{
return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}
static inline objc_tag_index_t
_objc_getTaggedPointerTag(const void * _Nullable ptr)
{
// assert(_objc_isTaggedPointer(ptr));
uintptr_t value = _objc_decodeTaggedPointer(ptr);
uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
uintptr_t extTag = (value >> _OBJC_TAG_EXT_INDEX_SHIFT) & _OBJC_TAG_EXT_INDEX_MASK;
if (basicTag == _OBJC_TAG_INDEX_MASK) {
return (objc_tag_index_t)(extTag + OBJC_TAG_First52BitPayload);
} else {
return (objc_tag_index_t)basicTag;
}
}
static inline uintptr_t
_objc_getTaggedPointerValue(const void * _Nullable ptr)
{
// assert(_objc_isTaggedPointer(ptr));
uintptr_t value = _objc_decodeTaggedPointer(ptr);
uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
if (basicTag == _OBJC_TAG_INDEX_MASK) {
return (value << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
} else {
return (value << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;
}
}
static inline intptr_t
_objc_getTaggedPointerSignedValue(const void * _Nullable ptr)
{
// assert(_objc_isTaggedPointer(ptr));
uintptr_t value = _objc_decodeTaggedPointer(ptr);
uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
if (basicTag == _OBJC_TAG_INDEX_MASK) {
return ((intptr_t)value << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
} else {
return ((intptr_t)value << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;
}
}
// OBJC_HAVE_TAGGED_POINTERS
#endif
/**
* Returns the method implementation of an object.
*
* @param obj An Objective-C object.
* @param name An Objective-C selector.
*
* @return The IMP corresponding to the instance method implemented by
* the class of \e obj.
*
* @note Equivalent to:
*
* class_getMethodImplementation(object_getClass(obj), name);
*/
OBJC_EXPORT IMP _Nonnull
object_getMethodImplementation(id _Nullable obj, SEL _Nonnull name)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
OBJC_EXPORT IMP _Nonnull
object_getMethodImplementation_stret(id _Nullable obj, SEL _Nonnull name)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE;
/**
* Adds multiple methods to a class in bulk. This amortizes overhead that can be
* expensive when adding methods one by one with class_addMethod.
*
* @param cls The class to which to add the methods.
* @param names An array of selectors for the methods to add.
* @param imps An array of functions which implement the new methods.
* @param types An array of strings that describe the types of each method's
* arguments.
* @param count The number of items in the names, imps, and types arrays.
* @param outFiledCount Upon return, contains the number of failed selectors in
* the returned array.
*
* @return A NULL-terminated C array of selectors which could not be added. A
* method cannot be added when a method of that name already exists on that
* class. When no failures occur, the return value is \c NULL. When a non-NULL
* value is returned, the caller must free the array with \c free().
*
*/
#if __OBJC2__
OBJC_EXPORT _Nullable SEL * _Nullable
class_addMethodsBulk(_Nullable Class cls, _Nonnull const SEL * _Nonnull names,
_Nonnull const IMP * _Nonnull imps,
const char * _Nonnull * _Nonnull types, uint32_t count,
uint32_t * _Nullable outFailedCount)
OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);
#endif
/**
* Replaces multiple methods in a class in bulk. This amortizes overhead that
* can be expensive when adding methods one by one with class_replaceMethod.
*
* @param cls The class to modify.
* @param names An array of selectors for the methods to replace.
* @param imps An array of functions will be the new method implementantations.
* @param types An array of strings that describe the types of each method's
* arguments.
* @param count The number of items in the names, imps, and types arrays.
*/
#if __OBJC2__
OBJC_EXPORT void
class_replaceMethodsBulk(_Nullable Class cls,
_Nonnull const SEL * _Nonnull names,
_Nonnull const IMP * _Nonnull imps,
const char * _Nonnull * _Nonnull types,
uint32_t count)
OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);
#endif
// Instance-specific instance variable layout. This is no longer implemented.
OBJC_EXPORT void
_class_setIvarLayoutAccessor(Class _Nullable cls,
const uint8_t* _Nullable (* _Nonnull accessor)
(id _Nullable object))
UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT const uint8_t * _Nullable
_object_getIvarLayout(Class _Nullable cls, id _Nullable object)
UNAVAILABLE_ATTRIBUTE;
/*
"Unknown" includes non-object ivars and non-ARC non-__weak ivars
"Strong" includes ARC __strong ivars
"Weak" includes ARC and new MRC __weak ivars
"Unretained" includes ARC __unsafe_unretained and old GC+MRC __weak ivars
成员变量的内存管理方式,包括:未知/strong/weak/assign。
*/
typedef enum {
objc_ivar_memoryUnknown, // unknown / unknown
objc_ivar_memoryStrong, // direct access / objc_storeStrong
objc_ivar_memoryWeak, // objc_loadWeak[Retained] / objc_storeWeak
objc_ivar_memoryUnretained // direct access / direct access
} objc_ivar_memory_management_t;
OBJC_EXPORT objc_ivar_memory_management_t
_class_getIvarMemoryManagement(Class _Nullable cls, Ivar _Nonnull ivar)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
OBJC_EXPORT BOOL _class_isFutureClass(Class _Nullable cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
// API to only be called by root classes like NSObject or NSProxy
OBJC_EXPORT
id _Nonnull
_objc_rootRetain(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
void
_objc_rootRelease(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
bool
_objc_rootReleaseWasZero(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
bool
_objc_rootTryRetain(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
bool
_objc_rootIsDeallocating(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
id _Nonnull
_objc_rootAutorelease(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
uintptr_t
_objc_rootRetainCount(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
id _Nonnull
_objc_rootInit(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
id _Nullable
_objc_rootAllocWithZone(Class _Nonnull cls, malloc_zone_t * _Nullable zone)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
id _Nullable
_objc_rootAlloc(Class _Nonnull cls)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
void
_objc_rootDealloc(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
void
_objc_rootFinalize(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
malloc_zone_t * _Nonnull
_objc_rootZone(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
uintptr_t
_objc_rootHash(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
void * _Nonnull
objc_autoreleasePoolPush(void)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
void
objc_autoreleasePoolPop(void * _Nonnull context)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT id _Nullable
objc_alloc(Class _Nullable cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
OBJC_EXPORT id _Nullable
objc_allocWithZone(Class _Nullable cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
OBJC_EXPORT id _Nullable
objc_retain(id _Nullable obj)
__asm__("_objc_retain")
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_release(id _Nullable obj)
__asm__("_objc_release")
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT id _Nullable
objc_autorelease(id _Nullable obj)
__asm__("_objc_autorelease")
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
// Prepare a value at +1 for return through a +0 autoreleasing convention.
OBJC_EXPORT id _Nullable
objc_autoreleaseReturnValue(id _Nullable obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
// Prepare a value at +0 for return through a +0 autoreleasing convention.
OBJC_EXPORT id _Nullable
objc_retainAutoreleaseReturnValue(id _Nullable obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
// Accept a value returned through a +0 autoreleasing convention for use at +1.
OBJC_EXPORT id _Nullable
objc_retainAutoreleasedReturnValue(id _Nullable obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
// Accept a value returned through a +0 autoreleasing convention for use at +0.
OBJC_EXPORT id _Nullable
objc_unsafeClaimAutoreleasedReturnValue(id _Nullable obj)
OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_storeStrong(id _Nullable * _Nonnull location, id _Nullable obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT id _Nullable
objc_retainAutorelease(id _Nullable obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
// obsolete.
OBJC_EXPORT id _Nullable
objc_retain_autorelease(id _Nullable obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT id _Nullable
objc_loadWeakRetained(id _Nullable * _Nonnull location)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT id _Nullable
objc_initWeak(id _Nullable * _Nonnull location, id _Nullable val)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
// Like objc_storeWeak, but stores nil if the new object is deallocating
// or the new object's class does not support weak references.
// Returns the value stored (either the new object or nil).
OBJC_EXPORT id _Nullable
objc_storeWeakOrNil(id _Nullable * _Nonnull location, id _Nullable obj)
OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0, 2.0);
// Like objc_initWeak, but stores nil if the new object is deallocating
// or the new object's class does not support weak references.
// Returns the value stored (either the new object or nil).
OBJC_EXPORT id _Nullable
objc_initWeakOrNil(id _Nullable * _Nonnull location, id _Nullable val)
OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_destroyWeak(id _Nullable * _Nonnull location)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_copyWeak(id _Nullable * _Nonnull to, id _Nullable * _Nonnull from)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_moveWeak(id _Nullable * _Nonnull to, id _Nullable * _Nonnull from)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
_objc_autoreleasePoolPrint(void)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT BOOL
objc_should_deallocate(id _Nonnull object)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_clear_deallocating(id _Nonnull object)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
// to make CF link for now
OBJC_EXPORT void * _Nonnull
_objc_autoreleasePoolPush(void)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
_objc_autoreleasePoolPop(void * _Nonnull context)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
// Extra @encode data for XPC, or NULL
OBJC_EXPORT const char * _Nullable
_protocol_getMethodTypeEncoding(Protocol * _Nonnull proto, SEL _Nonnull sel,
BOOL isRequiredMethod, BOOL isInstanceMethod)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
// API to only be called by classes that provide their own reference count storage
OBJC_EXPORT void
_objc_deallocOnMainThreadHelper(void * _Nullable context)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
// On async versus sync deallocation and the _dealloc2main flag
//
// Theory:
//
// If order matters, then code must always: [self dealloc].
// If order doesn't matter, then always async should be safe.
//
// Practice:
//
// The _dealloc2main bit is set for GUI objects that may be retained by other
// threads. Once deallocation begins on the main thread, doing more async
// deallocation will at best cause extra UI latency and at worst cause
// use-after-free bugs in unretained delegate style patterns. Yes, this is
// extremely fragile. Yes, in the long run, developers should switch to weak
// references.
//
// Note is NOT safe to do any equality check against the result of
// dispatch_get_current_queue(). The main thread can and does drain more than
// one dispatch queue. That is why we call pthread_main_np().
//
typedef enum {
_OBJC_RESURRECT_OBJECT = -1, /* _logicBlock has called -retain, and scheduled a -release for later. */
_OBJC_DEALLOC_OBJECT_NOW = 1, /* call [self dealloc] immediately. */
_OBJC_DEALLOC_OBJECT_LATER = 2 /* call [self dealloc] on the main queue. */
} _objc_object_disposition_t;
#define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC_BLOCK(_rc_ivar, _logicBlock) \
-(id)retain { \
/* this will fail to compile if _rc_ivar is an unsigned type */ \
int _retain_count_ivar_must_not_be_unsigned[0L - (__typeof__(_rc_ivar))-1] __attribute__((unused)); \
__typeof__(_rc_ivar) _prev = __sync_fetch_and_add(&_rc_ivar, 2); \
if (_prev < -2) { /* specifically allow resurrection from logical 0. */ \
__builtin_trap(); /* BUG: retain of over-released ref */ \
} \
return self; \
} \
-(oneway void)release { \
__typeof__(_rc_ivar) _prev = __sync_fetch_and_sub(&_rc_ivar, 2); \
if (_prev > 0) { \
return; \
} else if (_prev < 0) { \
__builtin_trap(); /* BUG: over-release */ \
} \
_objc_object_disposition_t fate = _logicBlock(self); \
if (fate == _OBJC_RESURRECT_OBJECT) { \
return; \
} \
/* mark the object as deallocating. */ \
if (!__sync_bool_compare_and_swap(&_rc_ivar, -2, 1)) { \
__builtin_trap(); /* BUG: dangling ref did a retain */ \
} \
if (fate == _OBJC_DEALLOC_OBJECT_NOW) { \
[self dealloc]; \
} else if (fate == _OBJC_DEALLOC_OBJECT_LATER) { \
dispatch_barrier_async_f(dispatch_get_main_queue(), self, \
_objc_deallocOnMainThreadHelper); \
} else { \
__builtin_trap(); /* BUG: bogus fate value */ \
} \
} \
-(NSUInteger)retainCount { \
return (_rc_ivar + 2) >> 1; \
} \
-(BOOL)_tryRetain { \
__typeof__(_rc_ivar) _prev; \
do { \
_prev = _rc_ivar; \
if (_prev & 1) { \
return 0; \
} else if (_prev == -2) { \
return 0; \
} else if (_prev < -2) { \
__builtin_trap(); /* BUG: over-release elsewhere */ \
} \
} while ( ! __sync_bool_compare_and_swap(&_rc_ivar, _prev, _prev + 2)); \
return 1; \
} \
-(BOOL)_isDeallocating { \
if (_rc_ivar == -2) { \
return 1; \
} else if (_rc_ivar < -2) { \
__builtin_trap(); /* BUG: over-release elsewhere */ \
} \
return _rc_ivar & 1; \
}
#define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, _dealloc2main) \
_OBJC_SUPPORTED_INLINE_REFCNT_LOGIC_BLOCK(_rc_ivar, (^(id _self_ __attribute__((unused))) { \
if (_dealloc2main && !pthread_main_np()) { \
return _OBJC_DEALLOC_OBJECT_LATER; \
} else { \
return _OBJC_DEALLOC_OBJECT_NOW; \
} \
}))
#define _OBJC_SUPPORTED_INLINE_REFCNT(_rc_ivar) _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, 0)
#define _OBJC_SUPPORTED_INLINE_REFCNT_WITH_DEALLOC2MAIN(_rc_ivar) _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, 1)
__END_DECLS
#endif