forked from cocoa-chen/objc-709
-
Notifications
You must be signed in to change notification settings - Fork 0
/
objc-internal.h
743 lines (621 loc) · 26.1 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
/*
* 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 <dispatch/dispatch.h>
__BEGIN_DECLS
// 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*))
// 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 objc_initializeClassPair(Class superclass, const char *name, Class cls, Class metacls)
OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.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 objc_readClassPair(Class cls,
const struct objc_image_info *info)
OBJC_AVAILABLE(10.10, 8.0, 9.0, 1.0);
#endif
// Batch object allocation using malloc_zone_batch_malloc().
OBJC_EXPORT unsigned class_createInstances(Class cls, size_t extraBytes,
id *results, unsigned num_requested)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0)
OBJC_ARC_UNAVAILABLE;
// Get the isa pointer written into objects just before being freed.
OBJC_EXPORT Class _objc_getFreedObjectClass(void)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
// env NSObjCMessageLoggingEnabled
OBJC_EXPORT void instrumentObjcMessageSends(BOOL flag)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
// Initializer called by libSystem
OBJC_EXPORT void _objc_init(void)
#if __OBJC2__
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
#else
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
#endif
// fork() safety called by libSystem
OBJC_EXPORT void _objc_atfork_prepare(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT void _objc_atfork_parent(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT void _objc_atfork_child(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
// Return YES if GC is on and `object` is a GC allocation.
OBJC_EXPORT BOOL objc_isAuto(id object)
__OSX_DEPRECATED(10.4, 10.8, "it always returns NO")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
// GC startup callback from Foundation
OBJC_EXPORT malloc_zone_t *objc_collect_init(int (*callback)(void))
__OSX_DEPRECATED(10.4, 10.8, "it does nothing")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
// Plainly-implemented GC barriers. Rosetta used to use these.
OBJC_EXPORT id objc_assign_strongCast_generic(id value, id *dest)
UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT id objc_assign_global_generic(id value, id *dest)
UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT id objc_assign_threadlocal_generic(id value, id *dest)
UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT id objc_assign_ivar_generic(id value, id 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;
// Install missing-class callback. Used by the late unlamented ZeroLink.
OBJC_EXPORT void _objc_setClassLoader(BOOL (*newClassLoader)(const char *)) OBJC2_UNAVAILABLE;
// Install handler for allocation failures.
// Handler may abort, or throw, or provide an object to return.
OBJC_EXPORT void _objc_setBadAllocHandler(id (*newHandler)(Class isa))
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
// This can go away when AppKit stops calling it (rdar://7811851)
#if __OBJC2__
OBJC_EXPORT void objc_setMultithreaded (BOOL flag)
__OSX_DEPRECATED(10.0, 10.5, "multithreading is always available")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
#endif
// Used by ExceptionHandling.framework
#if !__OBJC2__
OBJC_EXPORT void _objc_error(id rcv, const char *fmt, va_list args)
__attribute__((noreturn))
__OSX_DEPRECATED(10.0, 10.5, "use other logging facilities instead")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
#endif
// 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
{
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,
OBJC_TAG_RESERVED_7 = 7,
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 cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.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 _objc_getClassForTag(objc_tag_index_t tag)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.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 *
_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 *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 *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 *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 *ptr);
// Don't use the values below. Use the declarations above.
#if TARGET_OS_OSX && __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 (1ULL<<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 (0xfULL<<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 1
# 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 0xfULL
# 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
static inline bool
_objc_taggedPointersEnabled(void)
{
extern uintptr_t objc_debug_taggedpointer_mask;
return (objc_debug_taggedpointer_mask != 0);
}
static inline void *
_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);
return (void*)
(_OBJC_TAG_MASK |
((uintptr_t)tag << _OBJC_TAG_INDEX_SHIFT) |
((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT));
} else {
// assert(tag >= OBJC_TAG_First52BitPayload);
// assert(tag <= OBJC_TAG_Last52BitPayload);
// assert(((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT) == value);
return (void*)
(_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));
}
}
static inline bool
_objc_isTaggedPointer(const void *ptr)
{
return ((intptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}
static inline objc_tag_index_t
_objc_getTaggedPointerTag(const void *ptr)
{
// assert(_objc_isTaggedPointer(ptr));
uintptr_t basicTag = ((uintptr_t)ptr >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
uintptr_t extTag = ((uintptr_t)ptr >> _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 *ptr)
{
// assert(_objc_isTaggedPointer(ptr));
uintptr_t basicTag = ((uintptr_t)ptr >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
if (basicTag == _OBJC_TAG_INDEX_MASK) {
return ((uintptr_t)ptr << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
} else {
return ((uintptr_t)ptr << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;
}
}
static inline intptr_t
_objc_getTaggedPointerSignedValue(const void *ptr)
{
// assert(_objc_isTaggedPointer(ptr));
uintptr_t basicTag = ((uintptr_t)ptr >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
if (basicTag == _OBJC_TAG_INDEX_MASK) {
return ((intptr_t)ptr << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
} else {
return ((intptr_t)ptr << _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 object_getMethodImplementation(id obj, SEL name)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
OBJC_EXPORT IMP object_getMethodImplementation_stret(id obj, SEL name)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
// Instance-specific instance variable layout.
OBJC_EXPORT void _class_setIvarLayoutAccessor(Class cls_gen, const uint8_t* (*accessor) (id object))
__OSX_AVAILABLE(10.7)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT const uint8_t *_object_getIvarLayout(Class cls_gen, id object)
__OSX_AVAILABLE(10.7)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
/*
"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
*/
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 cls, Ivar ivar)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT BOOL _class_isFutureClass(Class cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
// API to only be called by root classes like NSObject or NSProxy
OBJC_EXPORT
id
_objc_rootRetain(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
_objc_rootRelease(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
bool
_objc_rootReleaseWasZero(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
bool
_objc_rootTryRetain(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
bool
_objc_rootIsDeallocating(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
_objc_rootAutorelease(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
uintptr_t
_objc_rootRetainCount(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
_objc_rootInit(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
_objc_rootAlloc(Class cls)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
_objc_rootDealloc(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
_objc_rootFinalize(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
malloc_zone_t *
_objc_rootZone(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
uintptr_t
_objc_rootHash(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void *
objc_autoreleasePoolPush(void)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
objc_autoreleasePoolPop(void *context)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT id objc_alloc(Class cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
OBJC_EXPORT id objc_allocWithZone(Class cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
OBJC_EXPORT id objc_retain(id obj)
__asm__("_objc_retain")
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT void objc_release(id obj)
__asm__("_objc_release")
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT id objc_autorelease(id obj)
__asm__("_objc_autorelease")
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Prepare a value at +1 for return through a +0 autoreleasing convention.
OBJC_EXPORT
id
objc_autoreleaseReturnValue(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Prepare a value at +0 for return through a +0 autoreleasing convention.
OBJC_EXPORT
id
objc_retainAutoreleaseReturnValue(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Accept a value returned through a +0 autoreleasing convention for use at +1.
OBJC_EXPORT
id
objc_retainAutoreleasedReturnValue(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Accept a value returned through a +0 autoreleasing convention for use at +0.
OBJC_EXPORT
id
objc_unsafeClaimAutoreleasedReturnValue(id obj)
OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0);
OBJC_EXPORT
void
objc_storeStrong(id *location, id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
objc_retainAutorelease(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// obsolete.
OBJC_EXPORT id objc_retain_autorelease(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
objc_loadWeakRetained(id *location)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
objc_initWeak(id *location, id val)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.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
objc_storeWeakOrNil(id *location, id obj)
OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.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
objc_initWeakOrNil(id *location, id val)
OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0);
OBJC_EXPORT
void
objc_destroyWeak(id *location)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
objc_copyWeak(id *to, id *from)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
objc_moveWeak(id *to, id *from)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
_objc_autoreleasePoolPrint(void)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT BOOL objc_should_deallocate(id object)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT void objc_clear_deallocating(id object)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// to make CF link for now
OBJC_EXPORT
void *
_objc_autoreleasePoolPush(void)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
_objc_autoreleasePoolPop(void *context)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Extra @encode data for XPC, or NULL
OBJC_EXPORT const char *_protocol_getMethodTypeEncoding(Protocol *p, SEL sel, BOOL isRequiredMethod, BOOL isInstanceMethod)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
// API to only be called by classes that provide their own reference count storage
OBJC_EXPORT
void
_objc_deallocOnMainThreadHelper(void *context)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.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