-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathobjc-private.h
More file actions
1083 lines (872 loc) · 33.8 KB
/
objc-private.h
File metadata and controls
1083 lines (872 loc) · 33.8 KB
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
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* 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@
*/
/*
* objc-private.h
* Copyright 1988-1996, NeXT Software, Inc.
*/
#ifndef _OBJC_PRIVATE_H_
#define _OBJC_PRIVATE_H_
#include "objc-config.h"
/* Isolate ourselves from the definitions of id and Class in the compiler
* and public headers.
*/
#ifdef _OBJC_OBJC_H_
#error include objc-private.h before other headers
#endif
#define OBJC_TYPES_DEFINED 1
#define OBJC_OLD_DISPATCH_PROTOTYPES 0
#include <cstddef> // for nullptr_t
#include <stdint.h>
#include <assert.h>
struct objc_class;
struct objc_object;
typedef struct objc_class *Class;
typedef struct objc_object *id;
namespace {
struct SideTable;
};
#if (!SUPPORT_NONPOINTER_ISA && !SUPPORT_PACKED_ISA && !SUPPORT_INDEXED_ISA) ||\
( SUPPORT_NONPOINTER_ISA && SUPPORT_PACKED_ISA && !SUPPORT_INDEXED_ISA) ||\
( SUPPORT_NONPOINTER_ISA && !SUPPORT_PACKED_ISA && SUPPORT_INDEXED_ISA)
// good config
#else
# error bad config
#endif
/// WGRunTimeSourceCode 源码阅读
//MARK: isa底层结构->采用了共用体的结构,利用位域技术来存储更多信息
union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits; //存放所有的数据
#if SUPPORT_PACKED_ISA
// extra_rc must be the MSB-most field (so it matches carry/overflow flags)
// nonpointer must be the LSB (fixme or get rid of it)
// shiftcls must occupy the same bits that a real class pointer would
// bits + RC_ONE is equivalent to extra_rc + 1
// RC_HALF is the high bit of extra_rc (i.e. half of its range)
// future expansion:
// uintptr_t fast_rr : 1; // no r/r overrides
// uintptr_t lock : 2; // lock for atomic property, @synch
// uintptr_t extraBytes : 1; // allocated with extra bytes
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
struct { //利用了位域技术,这个结构体纯粹就是为了增加可读性,其它没什么作用
//0:代表普通的isa指针(存储着class、Meta-class对象的内存地址) 1:优化过的isa指针,存储了更多的信息
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1; //是否设置过关联对象,若没有,释放时更快
uintptr_t has_cxx_dtor : 1; //是否有C++的析构函数(.cxx_destruct),若没有,释放时更快
//从二进制位的倒数第三位开始数,共计33位来表示Class、Meta-Class的内存地址
uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
uintptr_t magic : 6; //用于在调试时分辨对象是否未完成初始化
uintptr_t weakly_referenced : 1; //是否有被弱引用指向过,若没有,释放时会更快
uintptr_t deallocating : 1; //对象是否正在释放
//引用计数器是否过大无法存储在isa中,如果是1,那么引用计数器就存储在一个叫SideTable的类的属性中
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 19; //里面存储的值是引用计数值减1(如果引用计数为3,则这里存储的就是2)
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
};
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# define ISA_MAGIC_MASK 0x001f800000000001ULL
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
struct {
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 8;
# define RC_ONE (1ULL<<56)
# define RC_HALF (1ULL<<7)
};
# else
# error unknown architecture for packed isa
# endif
// SUPPORT_PACKED_ISA
#endif
#if SUPPORT_INDEXED_ISA
# if __ARM_ARCH_7K__ >= 2
# define ISA_INDEX_IS_NPI 1
# define ISA_INDEX_MASK 0x0001FFFC
# define ISA_INDEX_SHIFT 2
# define ISA_INDEX_BITS 15
# define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS)
# define ISA_INDEX_MAGIC_MASK 0x001E0001
# define ISA_INDEX_MAGIC_VALUE 0x001C0001
struct {
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t indexcls : 15;
uintptr_t magic : 4;
uintptr_t has_cxx_dtor : 1;
uintptr_t weakly_referenced : 1;
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 7;
# define RC_ONE (1ULL<<25)
# define RC_HALF (1ULL<<6)
};
# else
# error unknown architecture for indexed isa
# endif
// SUPPORT_INDEXED_ISA
#endif
};
/// WGRunTimeSourceCode 源码阅读
/*
OC对象的本质是一个objc_object的结构体,里面存放的是isa_t类型的指针
在arm64架构之前,isa就是一个普通的指针,存储着Class、Meta_Class对象的内存地址,而从arm64位架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来存储更多的信息
如果我们想获取一个OC对象的类对象的地址,得通过 isa & ISA_MASK 才能得到类对象/元类对象的地址
*/
//MARK: OC对象的底层结构
struct objc_object {
private:
isa_t isa;
public:
// ISA() assumes(假设) this is NOT a tagged pointer object
Class ISA();
// getIsa() allows this to be a tagged pointer object
Class getIsa();
// initIsa() should be used to init the isa of new objects only.
// If this object already has an isa, use changeIsa() for correctness.
// initInstanceIsa(): objects with no custom RR/AWZ
// initClassIsa(): class objects
// initProtocolIsa(): protocol objects
// initIsa(): other objects
void initIsa(Class cls /*nonpointer=false*/);
void initClassIsa(Class cls /*nonpointer=maybe*/);
void initProtocolIsa(Class cls /*nonpointer=maybe*/);
void initInstanceIsa(Class cls, bool hasCxxDtor);
// changeIsa() should be used to change the isa of existing objects.
// If this is a new object, use initIsa() for performance.
Class changeIsa(Class newCls);
/*
Tagged Pointer专门用来存储小的对象,例如NSNumber, NSDate, NSString。
Tagged Pointer指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。
所以,它的内存并不存储在堆中,也不需要malloc和free。
在内存读取上有着3倍的效率,创建时比以前快106倍。
*/
bool hasNonpointerIsa();
bool isTaggedPointer();
bool isBasicTaggedPointer();
bool isExtTaggedPointer();
bool isClass();
// object may have associated objects? //关联对象相关
bool hasAssociatedObjects();
void setHasAssociatedObjects();
// object may be weakly referenced? //若引用相关
bool isWeaklyReferenced();
void setWeaklyReferenced_nolock();
// object may have -.cxx_destruct implementation?
bool hasCxxDtor();
// Optimized calls to retain/release methods
id retain();
void release();
id autorelease();
// Implementations of retain/release methods
id rootRetain();
bool rootRelease();
id rootAutorelease();
bool rootTryRetain();
bool rootReleaseShouldDealloc();
uintptr_t rootRetainCount();
// Implementation of dealloc methods
bool rootIsDeallocating();
void clearDeallocating();
void rootDealloc();
private:
void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);
// Slow paths for inline control
id rootAutorelease2();
bool overrelease_error();
#if SUPPORT_NONPOINTER_ISA
// Unified retain count manipulation for nonpointer isa
id rootRetain(bool tryRetain, bool handleOverflow);
bool rootRelease(bool performDealloc, bool handleUnderflow);
id rootRetain_overflow(bool tryRetain);
bool rootRelease_underflow(bool performDealloc);
void clearDeallocating_slow();
// Side table retain count overflow for nonpointer isa
void sidetable_lock();
void sidetable_unlock();
void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
bool sidetable_addExtraRC_nolock(size_t delta_rc);
size_t sidetable_subExtraRC_nolock(size_t delta_rc);
size_t sidetable_getExtraRC_nolock();
#endif
// Side-table-only retain count
bool sidetable_isDeallocating();
void sidetable_clearDeallocating();
bool sidetable_isWeaklyReferenced();
void sidetable_setWeaklyReferenced_nolock();
id sidetable_retain();
id sidetable_retain_slow(SideTable& table);
uintptr_t sidetable_release(bool performDealloc = true);
uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);
bool sidetable_tryRetain();
uintptr_t sidetable_retainCount();
#if DEBUG
bool sidetable_present();
#endif
};
#if __OBJC2__
typedef struct method_t *Method;
typedef struct ivar_t *Ivar;
typedef struct category_t *Category;
typedef struct property_t *objc_property_t;
#else
typedef struct old_method *Method;
typedef struct old_ivar *Ivar;
typedef struct old_category *Category;
typedef struct old_property *objc_property_t;
#endif
// Public headers
#include "objc.h"
#include "runtime.h"
#include "objc-os.h"
#include "objc-abi.h"
#include "objc-api.h"
#include "objc-config.h"
#include "objc-internal.h"
#include "maptable.h"
#include "hashtable2.h"
/* Do not include message.h here. */
/* #include "message.h" */
#define __APPLE_API_PRIVATE
#include "objc-gdb.h"
#undef __APPLE_API_PRIVATE
// Private headers
#if __OBJC2__
#include "objc-runtime-new.h"
#else
#include "objc-runtime-old.h"
#endif
#include "objc-references.h"
#include "objc-initialize.h"
#include "objc-loadmethod.h"
#if SUPPORT_PREOPT && __cplusplus
#include <objc-shared-cache.h>
using objc_selopt_t = const objc_opt::objc_selopt_t;
#else
struct objc_selopt_t;
#endif
#define STRINGIFY(x) #x
#define STRINGIFY2(x) STRINGIFY(x)
__BEGIN_DECLS
struct header_info;
// Split out the rw data from header info. For now put it in a huge array
// that more than exceeds the space needed. In future we'll just allocate
// this in the shared cache builder.
typedef struct header_info_rw {
bool getLoaded() const {
return isLoaded;
}
void setLoaded(bool v) {
isLoaded = v ? 1: 0;
}
bool getAllClassesRealized() const {
return allClassesRealized;
}
void setAllClassesRealized(bool v) {
allClassesRealized = v ? 1: 0;
}
header_info *getNext() const {
return (header_info *)(next << 2);
}
void setNext(header_info *v) {
next = ((uintptr_t)v) >> 2;
}
private:
#ifdef __LP64__
uintptr_t isLoaded : 1;
uintptr_t allClassesRealized : 1;
uintptr_t next : 62;
#else
uintptr_t isLoaded : 1;
uintptr_t allClassesRealized : 1;
uintptr_t next : 30;
#endif
} header_info_rw;
struct header_info_rw* getPreoptimizedHeaderRW(const struct header_info *const hdr);
typedef struct header_info {
private:
// Note, this is no longer a pointer, but instead an offset to a pointer
// from this location.
intptr_t mhdr_offset;
// Note, this is no longer a pointer, but instead an offset to a pointer
// from this location.
intptr_t info_offset;
// Do not add fields without editing ObjCModernAbstraction.hpp
public:
header_info_rw *getHeaderInfoRW() {
header_info_rw *preopt =
isPreoptimized() ? getPreoptimizedHeaderRW(this) : nil;
if (preopt) return preopt;
else return &rw_data[0];
}
const headerType *mhdr() const {
return (const headerType *)(((intptr_t)&mhdr_offset) + mhdr_offset);
}
void setmhdr(const headerType *mhdr) {
mhdr_offset = (intptr_t)mhdr - (intptr_t)&mhdr_offset;
}
const objc_image_info *info() const {
return (const objc_image_info *)(((intptr_t)&info_offset) + info_offset);
}
void setinfo(const objc_image_info *info) {
info_offset = (intptr_t)info - (intptr_t)&info_offset;
}
bool isLoaded() {
return getHeaderInfoRW()->getLoaded();
}
void setLoaded(bool v) {
getHeaderInfoRW()->setLoaded(v);
}
bool areAllClassesRealized() {
return getHeaderInfoRW()->getAllClassesRealized();
}
void setAllClassesRealized(bool v) {
getHeaderInfoRW()->setAllClassesRealized(v);
}
header_info *getNext() {
return getHeaderInfoRW()->getNext();
}
void setNext(header_info *v) {
getHeaderInfoRW()->setNext(v);
}
bool isBundle() {
return mhdr()->filetype == MH_BUNDLE;
}
const char *fname() const {
return dyld_image_path_containing_address(mhdr());
}
bool isPreoptimized() const;
#if !__OBJC2__
struct old_protocol **proto_refs;
struct objc_module *mod_ptr;
size_t mod_count;
# if TARGET_OS_WIN32
struct objc_module **modules;
size_t moduleCount;
struct old_protocol **protocols;
size_t protocolCount;
void *imageinfo;
size_t imageinfoBytes;
SEL *selrefs;
size_t selrefCount;
struct objc_class **clsrefs;
size_t clsrefCount;
TCHAR *moduleName;
# endif
#endif
private:
// Images in the shared cache will have an empty array here while those
// allocated at run time will allocate a single entry.
header_info_rw rw_data[];
} header_info;
extern header_info *FirstHeader;
extern header_info *LastHeader;
extern int HeaderCount;
extern void appendHeader(header_info *hi);
extern void removeHeader(header_info *hi);
extern objc_image_info *_getObjcImageInfo(const headerType *head, size_t *size);
extern bool _hasObjcContents(const header_info *hi);
// Mach-O segment and section names are 16 bytes and may be un-terminated.
static inline bool segnameEquals(const char *lhs, const char *rhs) {
return 0 == strncmp(lhs, rhs, 16);
}
static inline bool segnameStartsWith(const char *segname, const char *prefix) {
return 0 == strncmp(segname, prefix, strlen(prefix));
}
static inline bool sectnameEquals(const char *lhs, const char *rhs) {
return segnameEquals(lhs, rhs);
}
static inline bool sectnameStartsWith(const char *sectname, const char *prefix){
return segnameStartsWith(sectname, prefix);
}
/* selectors */
extern void sel_init(size_t selrefCount);
extern SEL sel_registerNameNoLock(const char *str, bool copy);
extern void sel_lock(void);
extern void sel_unlock(void);
extern SEL SEL_load;
extern SEL SEL_initialize;
extern SEL SEL_resolveClassMethod;
extern SEL SEL_resolveInstanceMethod;
extern SEL SEL_cxx_construct;
extern SEL SEL_cxx_destruct;
extern SEL SEL_retain;
extern SEL SEL_release;
extern SEL SEL_autorelease;
extern SEL SEL_retainCount;
extern SEL SEL_alloc;
extern SEL SEL_allocWithZone;
extern SEL SEL_dealloc;
extern SEL SEL_copy;
extern SEL SEL_new;
extern SEL SEL_forwardInvocation;
extern SEL SEL_tryRetain;
extern SEL SEL_isDeallocating;
extern SEL SEL_retainWeakReference;
extern SEL SEL_allowsWeakReference;
/* preoptimization */
extern void preopt_init(void);
extern void disableSharedCacheOptimizations(void);
extern bool isPreoptimized(void);
extern bool noMissingWeakSuperclasses(void);
extern header_info *preoptimizedHinfoForHeader(const headerType *mhdr);
extern objc_selopt_t *preoptimizedSelectors(void);
extern Protocol *getPreoptimizedProtocol(const char *name);
extern unsigned getPreoptimizedClassUnreasonableCount();
extern Class getPreoptimizedClass(const char *name);
extern Class* copyPreoptimizedClasses(const char *name, int *outCount);
extern Class _calloc_class(size_t size);
/* method lookup */
extern IMP lookUpImpOrNil(Class, SEL, id obj, bool initialize, bool cache, bool resolver);
extern IMP lookUpImpOrForward(Class, SEL, id obj, bool initialize, bool cache, bool resolver);
extern IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel);
extern bool class_respondsToSelector_inst(Class cls, SEL sel, id inst);
extern bool objcMsgLogEnabled;
extern bool logMessageSend(bool isClassMethod,
const char *objectsClass,
const char *implementingClass,
SEL selector);
/* message dispatcher */
extern IMP _class_lookupMethodAndLoadCache3(id, SEL, Class);
#if !OBJC_OLD_DISPATCH_PROTOTYPES
extern void _objc_msgForward_impcache(void);
#else
extern id _objc_msgForward_impcache(id, SEL, ...);
#endif
/* errors */
extern void __objc_error(id, const char *, ...) __attribute__((format (printf, 2, 3), noreturn));
extern void _objc_inform(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
extern void _objc_inform_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
extern void _objc_inform_now_and_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
extern void _objc_inform_deprecated(const char *oldname, const char *newname) __attribute__((noinline));
extern void inform_duplicate(const char *name, Class oldCls, Class cls);
/* magic */
extern Class _objc_getFreedObjectClass (void);
/* map table additions */
extern void *NXMapKeyCopyingInsert(NXMapTable *table, const void *key, const void *value);
extern void *NXMapKeyFreeingRemove(NXMapTable *table, const void *key);
/* hash table additions */
extern unsigned _NXHashCapacity(NXHashTable *table);
extern void _NXHashRehashToCapacity(NXHashTable *table, unsigned newCapacity);
/* property attribute parsing */
extern const char *copyPropertyAttributeString(const objc_property_attribute_t *attrs, unsigned int count);
extern objc_property_attribute_t *copyPropertyAttributeList(const char *attrs, unsigned int *outCount);
extern char *copyPropertyAttributeValue(const char *attrs, const char *name);
/* locking */
extern void lock_init(void);
class monitor_locker_t : nocopy_t {
monitor_t& lock;
public:
monitor_locker_t(monitor_t& newLock) : lock(newLock) { lock.enter(); }
~monitor_locker_t() { lock.leave(); }
};
class recursive_mutex_locker_t : nocopy_t {
recursive_mutex_t& lock;
public:
recursive_mutex_locker_t(recursive_mutex_t& newLock)
: lock(newLock) { lock.lock(); }
~recursive_mutex_locker_t() { lock.unlock(); }
};
class rwlock_reader_t : nocopy_t {
rwlock_t& lock;
public:
rwlock_reader_t(rwlock_t& newLock) : lock(newLock) { lock.read(); }
~rwlock_reader_t() { lock.unlockRead(); }
};
class rwlock_writer_t : nocopy_t {
rwlock_t& lock;
public:
rwlock_writer_t(rwlock_t& newLock) : lock(newLock) { lock.write(); }
~rwlock_writer_t() { lock.unlockWrite(); }
};
/* Exceptions */
struct alt_handler_list;
extern void exception_init(void);
extern void _destroyAltHandlerList(struct alt_handler_list *list);
/* Class change notifications (gdb only for now) */
#define OBJC_CLASS_ADDED (1<<0)
#define OBJC_CLASS_REMOVED (1<<1)
#define OBJC_CLASS_IVARS_CHANGED (1<<2)
#define OBJC_CLASS_METHODS_CHANGED (1<<3)
extern void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)
__attribute__((noinline));
// Settings from environment variables
#define OPTION(var, env, help) extern bool var;
#include "objc-env.h"
#undef OPTION
extern void environ_init(void);
extern void logReplacedMethod(const char *className, SEL s, bool isMeta, const char *catName, IMP oldImp, IMP newImp);
// objc per-thread storage
typedef struct {
struct _objc_initializing_classes *initializingClasses; // for +initialize
struct SyncCache *syncCache; // for @synchronize
struct alt_handler_list *handlerList; // for exception alt handlers
char *printableNames[4]; // temporary demangled names for logging
// If you add new fields here, don't forget to update
// _objc_pthread_destroyspecific()
} _objc_pthread_data;
extern _objc_pthread_data *_objc_fetch_pthread_data(bool create);
extern void tls_init(void);
// encoding.h
extern unsigned int encoding_getNumberOfArguments(const char *typedesc);
extern unsigned int encoding_getSizeOfArguments(const char *typedesc);
extern unsigned int encoding_getArgumentInfo(const char *typedesc, unsigned int arg, const char **type, int *offset);
extern void encoding_getReturnType(const char *t, char *dst, size_t dst_len);
extern char * encoding_copyReturnType(const char *t);
extern void encoding_getArgumentType(const char *t, unsigned int index, char *dst, size_t dst_len);
extern char *encoding_copyArgumentType(const char *t, unsigned int index);
// sync.h
extern void _destroySyncCache(struct SyncCache *cache);
// arr
extern void arr_init(void);
extern id objc_autoreleaseReturnValue(id obj);
// block trampolines
extern IMP _imp_implementationWithBlockNoCopy(id block);
// layout.h
typedef struct {
uint8_t *bits;
size_t bitCount;
size_t bitsAllocated;
bool weak;
} layout_bitmap;
extern layout_bitmap layout_bitmap_create(const unsigned char *layout_string, size_t layoutStringInstanceSize, size_t instanceSize, bool weak);
extern layout_bitmap layout_bitmap_create_empty(size_t instanceSize, bool weak);
extern void layout_bitmap_free(layout_bitmap bits);
extern const unsigned char *layout_string_create(layout_bitmap bits);
extern void layout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset);
extern void layout_bitmap_grow(layout_bitmap *bits, size_t newCount);
extern void layout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos);
extern void layout_bitmap_slide_anywhere(layout_bitmap *bits, size_t oldPos, size_t newPos);
extern bool layout_bitmap_splat(layout_bitmap dst, layout_bitmap src,
size_t oldSrcInstanceSize);
extern bool layout_bitmap_or(layout_bitmap dst, layout_bitmap src, const char *msg);
extern bool layout_bitmap_clear(layout_bitmap dst, layout_bitmap src, const char *msg);
extern void layout_bitmap_print(layout_bitmap bits);
// fixme runtime
extern bool MultithreadedForkChild;
extern id objc_noop_imp(id self, SEL _cmd);
extern Class look_up_class(const char *aClassName, bool includeUnconnected, bool includeClassHandler);
extern "C" void map_images(unsigned count, const char * const paths[],
const struct mach_header * const mhdrs[]);
extern void map_images_nolock(unsigned count, const char * const paths[],
const struct mach_header * const mhdrs[]);
extern void load_images(const char *path, const struct mach_header *mh);
extern void unmap_image(const char *path, const struct mach_header *mh);
extern void unmap_image_nolock(const struct mach_header *mh);
extern void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClass);
extern void _unload_image(header_info *hi);
extern const char ** _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount);
extern const header_info *_headerForClass(Class cls);
extern Class _class_remap(Class cls);
extern Class _class_getNonMetaClass(Class cls, id obj);
extern Ivar _class_getVariable(Class cls, const char *name);
extern unsigned _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone, id *results, unsigned num_requested);
extern id _objc_constructOrFree(id bytes, Class cls);
extern const char *_category_getName(Category cat);
extern const char *_category_getClassName(Category cat);
extern Class _category_getClass(Category cat);
extern IMP _category_getLoadMethod(Category cat);
extern id object_cxxConstructFromClass(id obj, Class cls);
extern void object_cxxDestruct(id obj);
extern void _class_resolveMethod(Class cls, SEL sel, id inst);
extern void fixupCopiedIvars(id newObject, id oldObject);
extern Class _class_getClassForIvar(Class cls, Ivar ivar);
#define OBJC_WARN_DEPRECATED \
do { \
static int warned = 0; \
if (!warned) { \
warned = 1; \
_objc_inform_deprecated(__FUNCTION__, NULL); \
} \
} while (0) \
__END_DECLS
#ifndef STATIC_ASSERT
# define STATIC_ASSERT(x) _STATIC_ASSERT2(x, __LINE__)
# define _STATIC_ASSERT2(x, line) _STATIC_ASSERT3(x, line)
# define _STATIC_ASSERT3(x, line) \
typedef struct { \
int _static_assert[(x) ? 0 : -1]; \
} _static_assert_ ## line __attribute__((unavailable))
#endif
#define countof(arr) (sizeof(arr) / sizeof((arr)[0]))
static __inline uint32_t _objc_strhash(const char *s) {
uint32_t hash = 0;
for (;;) {
int a = *s++;
if (0 == a) break;
hash += (hash << 8) + a;
}
return hash;
}
#if __cplusplus
template <typename T>
static inline T log2u(T x) {
return (x<2) ? 0 : log2u(x>>1)+1;
}
template <typename T>
static inline T exp2u(T x) {
return (1 << x);
}
template <typename T>
static T exp2m1u(T x) {
return (1 << x) - 1;
}
#endif
// Misalignment-safe integer types
__attribute__((aligned(1))) typedef uintptr_t unaligned_uintptr_t;
__attribute__((aligned(1))) typedef intptr_t unaligned_intptr_t;
__attribute__((aligned(1))) typedef uint64_t unaligned_uint64_t;
__attribute__((aligned(1))) typedef int64_t unaligned_int64_t;
__attribute__((aligned(1))) typedef uint32_t unaligned_uint32_t;
__attribute__((aligned(1))) typedef int32_t unaligned_int32_t;
__attribute__((aligned(1))) typedef uint16_t unaligned_uint16_t;
__attribute__((aligned(1))) typedef int16_t unaligned_int16_t;
// Global operator new and delete. We must not use any app overrides.
// This ALSO REQUIRES each of these be in libobjc's unexported symbol list.
#if __cplusplus
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winline-new-delete"
#include <new>
inline void* operator new(std::size_t size) throw (std::bad_alloc) { return malloc(size); }
inline void* operator new[](std::size_t size) throw (std::bad_alloc) { return malloc(size); }
inline void* operator new(std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }
inline void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }
inline void operator delete(void* p) throw() { free(p); }
inline void operator delete[](void* p) throw() { free(p); }
inline void operator delete(void* p, const std::nothrow_t&) throw() { free(p); }
inline void operator delete[](void* p, const std::nothrow_t&) throw() { free(p); }
#pragma clang diagnostic pop
#endif
class TimeLogger {
uint64_t mStart;
bool mRecord;
public:
TimeLogger(bool record = true)
: mStart(nanoseconds())
, mRecord(record)
{ }
void log(const char *msg) {
if (mRecord) {
uint64_t end = nanoseconds();
_objc_inform("%.2f ms: %s", (end - mStart) / 1000000.0, msg);
mStart = nanoseconds();
}
}
};
// StripedMap<T> is a map of void* -> T, sized appropriately //StripedMap<T>是一个以void *为hash key, T为vaule的hash 表
// for cache-friendly lock striping.
// For example, this may be used as StripedMap<spinlock_t>
// or as StripedMap<SomeStruct> where SomeStruct stores a spin lock.
template<typename T>
/// WGRunTimeSourceCode 源码阅读
/*
这里可以看出SideTables的长度为64,说明可以存放64个SideTable
全局的SideTables就是通过这种方式获取的,所以StripedMap中的T就代表SideTable类型了
static StripedMap<SideTable>& SideTables() {
return *reinterpret_cast<StripedMap<SideTable>*>(SideTableBuf);
}
*/
//MARK:SideTables结构实际的类型StripedMap,可以存放64个SideTable
//MARK: StripedMap底层结构
class StripedMap {
enum { CacheLineSize = 64 };
#if TARGET_OS_EMBEDDED
enum { StripeCount = 8 };
#else
enum { StripeCount = 64 }; //ios设备 StripeCount = 64字节
#endif
struct PaddedT { //StripedMap总所有的T类型的数据都被封装到PaddedT结构体中,是为了字节对齐,估计是存取hash值时的效率考虑
T value alignas(CacheLineSize); //64字节对齐
};
PaddedT array[StripeCount]; //PaddedT被放到数组array中,array[64]
//以obj的地址为key,找到SideTables中对应的SideTable
static unsigned int indexForPointer(const void *p) { //以void *作为key,获取对应的value值在StripedMap中的位置
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
return ((addr >> 4) ^ (addr >> 9)) % StripeCount; //取余是为了防止index越界
}
public: //取值,通过对象obj的地址找到对应的SideTable
T& operator[] (const void *p) {
return array[indexForPointer(p)].value;
}
const T& operator[] (const void *p) const {
return const_cast<StripedMap<T>>(this)[p];
}
//由于SideTables是全局的hash数组,所以肯定是需要加锁操作的
//锁操作都是通过array[i].value方式进行的,所以对于模板的抽象数据T类型,必须具备相关的lock操作接口。而T类型对应的就是SideTable类型
// Shortcuts for StripedMaps of locks.
void lockAll() {
for (unsigned int i = 0; i < StripeCount; i++) {
array[i].value.lock();
}
}
void unlockAll() {
for (unsigned int i = 0; i < StripeCount; i++) {
array[i].value.unlock();
}
}
void forceResetAll() {
for (unsigned int i = 0; i < StripeCount; i++) {
array[i].value.forceReset();
}
}
void defineLockOrder() {
for (unsigned int i = 1; i < StripeCount; i++) {
lockdebug_lock_precedes_lock(&array[i-1].value, &array[i].value);
}
}
void precedeLock(const void *newlock) {
// assumes defineLockOrder is also called
lockdebug_lock_precedes_lock(&array[StripeCount-1].value, newlock);
}
void succeedLock(const void *oldlock) {
// assumes defineLockOrder is also called
lockdebug_lock_precedes_lock(oldlock, &array[0].value);
}
const void *getLock(int i) {
if (i < StripeCount) return &array[i].value;
else return nil;
}
#if DEBUG
StripedMap() {
// Verify alignment expectations.
uintptr_t base = (uintptr_t)&array[0].value;
uintptr_t delta = (uintptr_t)&array[1].value - base;
assert(delta % CacheLineSize == 0);
assert(base % CacheLineSize == 0);
}
#endif
};
// DisguisedPtr<T> acts like pointer type T*, except the
// stored value is disguised to hide it from tools like `leaks`.
// nil is disguised as itself so zero-filled memory works as expected,
// which means 0x80..00 is also disguised as itself but we don't care.
// Note that weak_entry_t knows about this encoding.
template <typename T>
class DisguisedPtr {
uintptr_t value;
static uintptr_t disguise(T* ptr) {
return -(uintptr_t)ptr;
}
static T* undisguise(uintptr_t val) {
return (T*)-val;
}
public:
DisguisedPtr() { }
DisguisedPtr(T* ptr)
: value(disguise(ptr)) { }
DisguisedPtr(const DisguisedPtr<T>& ptr)
: value(ptr.value) { }
DisguisedPtr<T>& operator = (T* rhs) {
value = disguise(rhs);
return *this;
}
DisguisedPtr<T>& operator = (const DisguisedPtr<T>& rhs) {
value = rhs.value;
return *this;
}
operator T* () const {
return undisguise(value);