objc4-781.2

This commit is contained in:
Ariel Abreu 2020-06-09 10:23:25 -04:00
parent 1db0a624c9
commit 4d6225bbe3
No known key found for this signature in database
GPG Key ID: F4D43CC7053EA2B3
373 changed files with 39788 additions and 9791 deletions

1
interposable.txt Normal file
View File

@ -0,0 +1 @@
_objc_release

View File

@ -1,7 +1,7 @@
__objc_init __objc_init
_environ_init _environ_init
_tls_init _tls_init
_lock_init _runtime_init
_recursive_mutex_init _recursive_mutex_init
_exception_init _exception_init
_map_images _map_images
@ -17,12 +17,10 @@ _rtp_init
_gc_fixup_barrier_stubs _gc_fixup_barrier_stubs
__objc_update_stubs_in_mach_header __objc_update_stubs_in_mach_header
_sel_init _sel_init
_sel_lock
___sel_registerName ___sel_registerName
__objc_search_builtins __objc_search_builtins
__ZNK8objc_opt13objc_selopt_t3getEPKc __ZNK8objc_opt13objc_selopt_t3getEPKc
__ZNK8objc_opt13objc_selopt_t4hashEPKc __ZNK8objc_opt13objc_selopt_t4hashEPKc
_sel_unlock
_sel_registerName _sel_registerName
_arr_init _arr_init
__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE4initEj __ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE4initEj
@ -98,6 +96,7 @@ __ZNSt3__122__merge_move_constructIRN8method_t16SortBySELAddressEN13method_list_
__ZNSt3__119__merge_move_assignIRN8method_t16SortBySELAddressEPS1_S4_N13method_list_t15method_iteratorEEEvT0_S7_T1_S8_T2_T_ __ZNSt3__119__merge_move_assignIRN8method_t16SortBySELAddressEPS1_S4_N13method_list_t15method_iteratorEEEvT0_S7_T1_S8_T2_T_
_NXPtrIsEqual _NXPtrIsEqual
__getObjc2CategoryList __getObjc2CategoryList
__getObjc2CategoryList2
__Z29addUnattachedCategoryForClassP10category_tP7class_tP12_header_info __Z29addUnattachedCategoryForClassP10category_tP7class_tP12_header_info
__Z16remethodizeClassP7class_t __Z16remethodizeClassP7class_t
__Z11flushCachesP7class_t __Z11flushCachesP7class_t
@ -145,7 +144,6 @@ __objc_insert_tagged_isa
_objc_msgSend_fixup _objc_msgSend_fixup
__objc_fixupMessageRef __objc_fixupMessageRef
_objc_msgSend _objc_msgSend
__class_lookupMethodAndLoadCache3
_lookUpMethod _lookUpMethod
_prepareForMethodLookup _prepareForMethodLookup
__class_initialize __class_initialize
@ -332,7 +330,6 @@ _objc_atomicCompareAndSwapGlobalBarrier
_sel_getUid _sel_getUid
__ZN12_GLOBAL__N_119AutoreleasePoolPage11tls_deallocEPv __ZN12_GLOBAL__N_119AutoreleasePoolPage11tls_deallocEPv
__ZN12_GLOBAL__N_119AutoreleasePoolPage4killEv __ZN12_GLOBAL__N_119AutoreleasePoolPage4killEv
__objc_constructOrFree
_object_cxxConstruct _object_cxxConstruct
_object_cxxConstructFromClass _object_cxxConstructFromClass
__class_hasCxxStructors __class_hasCxxStructors

View File

@ -31,6 +31,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/errno.h> #include <sys/errno.h>
#include <os/overflow.h>
#include <mach-o/fat.h> #include <mach-o/fat.h>
#include <mach-o/arch.h> #include <mach-o/arch.h>
#include <mach-o/loader.h> #include <mach-o/loader.h>
@ -476,7 +477,15 @@ bool parse_fat(uint8_t *buffer, size_t size)
fat_magic = OSSwapBigToHostInt32(fh->magic); fat_magic = OSSwapBigToHostInt32(fh->magic);
fat_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch); fat_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch);
if (size < (sizeof(struct fat_header) + fat_nfat_arch * sizeof(struct fat_arch))) { size_t fat_arch_size;
// fat_nfat_arch * sizeof(struct fat_arch) + sizeof(struct fat_header)
if (os_mul_and_add_overflow(fat_nfat_arch, sizeof(struct fat_arch),
sizeof(struct fat_header), &fat_arch_size))
{
printf("too many fat archs\n");
return false;
}
if (size < fat_arch_size) {
printf("file is too small\n"); printf("file is too small\n");
return false; return false;
} }
@ -484,7 +493,14 @@ bool parse_fat(uint8_t *buffer, size_t size)
archs = (struct fat_arch *)(buffer + sizeof(struct fat_header)); archs = (struct fat_arch *)(buffer + sizeof(struct fat_header));
/* Special case hidden CPU_TYPE_ARM64 */ /* Special case hidden CPU_TYPE_ARM64 */
if (size >= (sizeof(struct fat_header) + (fat_nfat_arch + 1) * sizeof(struct fat_arch))) { size_t fat_arch_plus_one_size;
if (os_add_overflow(fat_arch_size, sizeof(struct fat_arch),
&fat_arch_plus_one_size))
{
printf("too many fat archs\n");
return false;
}
if (size >= fat_arch_plus_one_size) {
if (fat_nfat_arch > 0 if (fat_nfat_arch > 0
&& OSSwapBigToHostInt32(archs[fat_nfat_arch].cputype) == CPU_TYPE_ARM64) { && OSSwapBigToHostInt32(archs[fat_nfat_arch].cputype) == CPU_TYPE_ARM64) {
fat_nfat_arch++; fat_nfat_arch++;
@ -505,7 +521,7 @@ bool parse_fat(uint8_t *buffer, size_t size)
arch_cputype, arch_cpusubtype); arch_cputype, arch_cpusubtype);
/* Check that slice data is after all fat headers and archs */ /* Check that slice data is after all fat headers and archs */
if (arch_offset < (sizeof(struct fat_header) + fat_nfat_arch * sizeof(struct fat_arch))) { if (arch_offset < fat_arch_size) {
printf("file is badly formed\n"); printf("file is badly formed\n");
return false; return false;
} }

0
objc.sln Executable file → Normal file
View File

BIN
objc.suo

Binary file not shown.

View File

@ -7,6 +7,17 @@
objects = { objects = {
/* Begin PBXAggregateTarget section */ /* Begin PBXAggregateTarget section */
834F9B01212E560100F95A54 /* objc4_tests */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 834F9B04212E560200F95A54 /* Build configuration list for PBXAggregateTarget "objc4_tests" */;
buildPhases = (
834F9B05212E561400F95A54 /* Run Script (build tests) */,
);
dependencies = (
);
name = objc4_tests;
productName = objc4_tests;
};
837F67A81A771F63004D34FA /* objc-simulator */ = { 837F67A81A771F63004D34FA /* objc-simulator */ = {
isa = PBXAggregateTarget; isa = PBXAggregateTarget;
buildConfigurationList = 837F67A91A771F63004D34FA /* Build configuration list for PBXAggregateTarget "objc-simulator" */; buildConfigurationList = 837F67A91A771F63004D34FA /* Build configuration list for PBXAggregateTarget "objc-simulator" */;
@ -25,6 +36,21 @@
393CEAC60DC69E67000B69DE /* objc-references.h in Headers */ = {isa = PBXBuildFile; fileRef = 393CEAC50DC69E67000B69DE /* objc-references.h */; }; 393CEAC60DC69E67000B69DE /* objc-references.h in Headers */ = {isa = PBXBuildFile; fileRef = 393CEAC50DC69E67000B69DE /* objc-references.h */; };
39ABD72312F0B61800D1054C /* objc-weak.h in Headers */ = {isa = PBXBuildFile; fileRef = 39ABD71F12F0B61800D1054C /* objc-weak.h */; }; 39ABD72312F0B61800D1054C /* objc-weak.h in Headers */ = {isa = PBXBuildFile; fileRef = 39ABD71F12F0B61800D1054C /* objc-weak.h */; };
39ABD72412F0B61800D1054C /* objc-weak.mm in Sources */ = {isa = PBXBuildFile; fileRef = 39ABD72012F0B61800D1054C /* objc-weak.mm */; }; 39ABD72412F0B61800D1054C /* objc-weak.mm in Sources */ = {isa = PBXBuildFile; fileRef = 39ABD72012F0B61800D1054C /* objc-weak.mm */; };
6E1475EA21DFDB1B001357EA /* llvm-AlignOf.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E1475E521DFDB1A001357EA /* llvm-AlignOf.h */; };
6E1475EB21DFDB1B001357EA /* llvm-DenseMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E1475E621DFDB1B001357EA /* llvm-DenseMap.h */; };
6E1475EC21DFDB1B001357EA /* llvm-DenseMapInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E1475E721DFDB1B001357EA /* llvm-DenseMapInfo.h */; };
6E1475ED21DFDB1B001357EA /* llvm-type_traits.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E1475E821DFDB1B001357EA /* llvm-type_traits.h */; };
6E1475EE21DFDB1B001357EA /* llvm-MathExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E1475E921DFDB1B001357EA /* llvm-MathExtras.h */; };
6E7B0862232DE7CA00689009 /* PointerUnion.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E7B0861232DE7CA00689009 /* PointerUnion.h */; };
6EACB842232C97A400CE9176 /* objc-zalloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 6EACB841232C97A400CE9176 /* objc-zalloc.h */; };
6EACB844232C97B900CE9176 /* objc-zalloc.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6EACB843232C97B900CE9176 /* objc-zalloc.mm */; };
6ECD0B1F2244999E00910D88 /* llvm-DenseSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ECD0B1E2244999E00910D88 /* llvm-DenseSet.h */; };
7213C36321FA7C730090A271 /* NSObject-internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 7213C36221FA7C730090A271 /* NSObject-internal.h */; settings = {ATTRIBUTES = (Private, ); }; };
7593EC58202248E50046AB96 /* objc-object.h in Headers */ = {isa = PBXBuildFile; fileRef = 7593EC57202248DF0046AB96 /* objc-object.h */; };
75A9504F202BAA0600D7D56F /* objc-locks-new.h in Headers */ = {isa = PBXBuildFile; fileRef = 75A9504E202BAA0300D7D56F /* objc-locks-new.h */; };
75A95051202BAA9A00D7D56F /* objc-locks.h in Headers */ = {isa = PBXBuildFile; fileRef = 75A95050202BAA9A00D7D56F /* objc-locks.h */; };
75A95053202BAC4100D7D56F /* objc-lockdebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 75A95052202BAC4100D7D56F /* objc-lockdebug.h */; };
8306440920D24A5D00E356D2 /* objc-block-trampolines.h in Headers */ = {isa = PBXBuildFile; fileRef = 8306440620D24A3E00E356D2 /* objc-block-trampolines.h */; settings = {ATTRIBUTES = (Private, ); }; };
830F2A740D737FB800392440 /* objc-msg-arm.s in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A690D737FB800392440 /* objc-msg-arm.s */; }; 830F2A740D737FB800392440 /* objc-msg-arm.s in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A690D737FB800392440 /* objc-msg-arm.s */; };
830F2A750D737FB900392440 /* objc-msg-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A6A0D737FB800392440 /* objc-msg-i386.s */; }; 830F2A750D737FB900392440 /* objc-msg-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A6A0D737FB800392440 /* objc-msg-i386.s */; };
830F2A7D0D737FBB00392440 /* objc-msg-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A720D737FB800392440 /* objc-msg-x86_64.s */; }; 830F2A7D0D737FBB00392440 /* objc-msg-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A720D737FB800392440 /* objc-msg-x86_64.s */; };
@ -37,9 +63,6 @@
834DF8B715993EE1002F2BC9 /* objc-sel-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 834DF8B615993EE1002F2BC9 /* objc-sel-old.mm */; }; 834DF8B715993EE1002F2BC9 /* objc-sel-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 834DF8B615993EE1002F2BC9 /* objc-sel-old.mm */; };
834EC0A411614167009B2563 /* objc-abi.h in Headers */ = {isa = PBXBuildFile; fileRef = 834EC0A311614167009B2563 /* objc-abi.h */; settings = {ATTRIBUTES = (Private, ); }; }; 834EC0A411614167009B2563 /* objc-abi.h in Headers */ = {isa = PBXBuildFile; fileRef = 834EC0A311614167009B2563 /* objc-abi.h */; settings = {ATTRIBUTES = (Private, ); }; };
83725F4A14CA5BFA0014370E /* objc-opt.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83725F4914CA5BFA0014370E /* objc-opt.mm */; }; 83725F4A14CA5BFA0014370E /* objc-opt.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83725F4914CA5BFA0014370E /* objc-opt.mm */; };
8379996E13CBAF6F007C2B5F /* a1a2-blocktramps-arm64.s in Sources */ = {isa = PBXBuildFile; fileRef = 8379996D13CBAF6F007C2B5F /* a1a2-blocktramps-arm64.s */; };
8383A3A3122600E9009290B8 /* a1a2-blocktramps-arm.s in Sources */ = {isa = PBXBuildFile; fileRef = 8383A3A1122600E9009290B8 /* a1a2-blocktramps-arm.s */; };
8383A3A4122600E9009290B8 /* a2a3-blocktramps-arm.s in Sources */ = {isa = PBXBuildFile; fileRef = 8383A3A2122600E9009290B8 /* a2a3-blocktramps-arm.s */; };
838485BF0D6D687300CEA253 /* hashtable2.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485B70D6D687300CEA253 /* hashtable2.h */; settings = {ATTRIBUTES = (Public, ); }; }; 838485BF0D6D687300CEA253 /* hashtable2.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485B70D6D687300CEA253 /* hashtable2.h */; settings = {ATTRIBUTES = (Public, ); }; };
838485C00D6D687300CEA253 /* hashtable2.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485B80D6D687300CEA253 /* hashtable2.mm */; }; 838485C00D6D687300CEA253 /* hashtable2.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485B80D6D687300CEA253 /* hashtable2.mm */; };
838485C30D6D687300CEA253 /* maptable.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485BB0D6D687300CEA253 /* maptable.h */; settings = {ATTRIBUTES = (Private, ); }; }; 838485C30D6D687300CEA253 /* maptable.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485BB0D6D687300CEA253 /* maptable.h */; settings = {ATTRIBUTES = (Private, ); }; };
@ -63,7 +86,7 @@
838485FF0D6D68A200CEA253 /* objc-load.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D80D6D68A200CEA253 /* objc-load.mm */; }; 838485FF0D6D68A200CEA253 /* objc-load.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D80D6D68A200CEA253 /* objc-load.mm */; };
838486000D6D68A200CEA253 /* objc-loadmethod.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485D90D6D68A200CEA253 /* objc-loadmethod.h */; }; 838486000D6D68A200CEA253 /* objc-loadmethod.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485D90D6D68A200CEA253 /* objc-loadmethod.h */; };
838486010D6D68A200CEA253 /* objc-loadmethod.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485DA0D6D68A200CEA253 /* objc-loadmethod.mm */; }; 838486010D6D68A200CEA253 /* objc-loadmethod.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485DA0D6D68A200CEA253 /* objc-loadmethod.mm */; };
838486020D6D68A200CEA253 /* objc-lockdebug.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485DB0D6D68A200CEA253 /* objc-lockdebug.mm */; }; 838486020D6D68A200CEA253 /* objc-lockdebug.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485DB0D6D68A200CEA253 /* objc-lockdebug.mm */; settings = {COMPILER_FLAGS = "-Os"; }; };
838486030D6D68A200CEA253 /* objc-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485DC0D6D68A200CEA253 /* objc-private.h */; }; 838486030D6D68A200CEA253 /* objc-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485DC0D6D68A200CEA253 /* objc-private.h */; };
838486070D6D68A200CEA253 /* objc-runtime-new.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485E00D6D68A200CEA253 /* objc-runtime-new.h */; }; 838486070D6D68A200CEA253 /* objc-runtime-new.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485E00D6D68A200CEA253 /* objc-runtime-new.h */; };
838486080D6D68A200CEA253 /* objc-runtime-new.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485E10D6D68A200CEA253 /* objc-runtime-new.mm */; }; 838486080D6D68A200CEA253 /* objc-runtime-new.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485E10D6D68A200CEA253 /* objc-runtime-new.mm */; };
@ -85,6 +108,8 @@
838486250D6D68F000CEA253 /* List.m in Sources */ = {isa = PBXBuildFile; fileRef = 838486230D6D68F000CEA253 /* List.m */; }; 838486250D6D68F000CEA253 /* List.m in Sources */ = {isa = PBXBuildFile; fileRef = 838486230D6D68F000CEA253 /* List.m */; };
838486260D6D68F000CEA253 /* List.h in Headers */ = {isa = PBXBuildFile; fileRef = 838486240D6D68F000CEA253 /* List.h */; settings = {ATTRIBUTES = (Public, ); }; }; 838486260D6D68F000CEA253 /* List.h in Headers */ = {isa = PBXBuildFile; fileRef = 838486240D6D68F000CEA253 /* List.h */; settings = {ATTRIBUTES = (Public, ); }; };
838486280D6D6A2400CEA253 /* message.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485BD0D6D687300CEA253 /* message.h */; settings = {ATTRIBUTES = (Public, ); }; }; 838486280D6D6A2400CEA253 /* message.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485BD0D6D687300CEA253 /* message.h */; settings = {ATTRIBUTES = (Public, ); }; };
83A4AEDC1EA0840800ACADDE /* module.modulemap in Headers */ = {isa = PBXBuildFile; fileRef = 83A4AED71EA06D9D00ACADDE /* module.modulemap */; settings = {ATTRIBUTES = (Public, ); }; };
83A4AEDE1EA08C7200ACADDE /* ObjectiveC.apinotes in Headers */ = {isa = PBXBuildFile; fileRef = 83A4AEDD1EA08C5700ACADDE /* ObjectiveC.apinotes */; settings = {ATTRIBUTES = (Public, ); }; };
83B1A8BE0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = 83B1A8BC0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s */; }; 83B1A8BE0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = 83B1A8BC0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s */; };
83BE02E40FCCB23400661494 /* objc-file-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83BE02E30FCCB23400661494 /* objc-file-old.mm */; }; 83BE02E40FCCB23400661494 /* objc-file-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83BE02E30FCCB23400661494 /* objc-file-old.mm */; };
83BE02E80FCCB24D00661494 /* objc-file-old.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE02E50FCCB24D00661494 /* objc-file-old.h */; }; 83BE02E80FCCB24D00661494 /* objc-file-old.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE02E50FCCB24D00661494 /* objc-file-old.h */; };
@ -92,17 +117,20 @@
83BE02EA0FCCB24D00661494 /* objc-runtime-old.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE02E70FCCB24D00661494 /* objc-runtime-old.h */; }; 83BE02EA0FCCB24D00661494 /* objc-runtime-old.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE02E70FCCB24D00661494 /* objc-runtime-old.h */; };
83C9C3391668B50E00F4E544 /* objc-msg-simulator-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = 83C9C3381668B50E00F4E544 /* objc-msg-simulator-x86_64.s */; }; 83C9C3391668B50E00F4E544 /* objc-msg-simulator-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = 83C9C3381668B50E00F4E544 /* objc-msg-simulator-x86_64.s */; };
83D49E4F13C7C84F0057F1DD /* objc-msg-arm64.s in Sources */ = {isa = PBXBuildFile; fileRef = 83D49E4E13C7C84F0057F1DD /* objc-msg-arm64.s */; }; 83D49E4F13C7C84F0057F1DD /* objc-msg-arm64.s in Sources */ = {isa = PBXBuildFile; fileRef = 83D49E4E13C7C84F0057F1DD /* objc-msg-arm64.s */; };
83D92696212254CF00299F69 /* isa.h in Headers */ = {isa = PBXBuildFile; fileRef = 83D92695212254CF00299F69 /* isa.h */; };
83D9269821225A7400299F69 /* arm64-asm.h in Headers */ = {isa = PBXBuildFile; fileRef = 83D9269721225A7400299F69 /* arm64-asm.h */; };
83EB007B121C9EC200B92C16 /* objc-sel-table.s in Sources */ = {isa = PBXBuildFile; fileRef = 83EB007A121C9EC200B92C16 /* objc-sel-table.s */; }; 83EB007B121C9EC200B92C16 /* objc-sel-table.s in Sources */ = {isa = PBXBuildFile; fileRef = 83EB007A121C9EC200B92C16 /* objc-sel-table.s */; };
83EF5E9820D2298400F486A4 /* objc-blocktramps-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = E8923D9C116AB2820071B552 /* objc-blocktramps-i386.s */; };
83EF5E9920D2298400F486A4 /* objc-blocktramps-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = E8923D9D116AB2820071B552 /* objc-blocktramps-x86_64.s */; };
83EF5E9C20D2299E00F486A4 /* objc-blocktramps-arm.s in Sources */ = {isa = PBXBuildFile; fileRef = 8383A3A1122600E9009290B8 /* objc-blocktramps-arm.s */; };
83F4B52815E843B100E0926F /* NSObjCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F4B52615E843B100E0926F /* NSObjCRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; }; 83F4B52815E843B100E0926F /* NSObjCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F4B52615E843B100E0926F /* NSObjCRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; };
83F4B52915E843B100E0926F /* NSObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F4B52715E843B100E0926F /* NSObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; 83F4B52915E843B100E0926F /* NSObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F4B52715E843B100E0926F /* NSObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
83F550E0155E030800E95D3B /* objc-cache-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83F550DF155E030800E95D3B /* objc-cache-old.mm */; }; 83F550E0155E030800E95D3B /* objc-cache-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83F550DF155E030800E95D3B /* objc-cache-old.mm */; };
87BB4EA70EC39854005D08E1 /* objc-probes.d in Sources */ = {isa = PBXBuildFile; fileRef = 87BB4E900EC39633005D08E1 /* objc-probes.d */; }; 87BB4EA70EC39854005D08E1 /* objc-probes.d in Sources */ = {isa = PBXBuildFile; fileRef = 87BB4E900EC39633005D08E1 /* objc-probes.d */; };
9672F7EE14D5F488007CEC96 /* NSObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9672F7ED14D5F488007CEC96 /* NSObject.mm */; }; 9672F7EE14D5F488007CEC96 /* NSObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9672F7ED14D5F488007CEC96 /* NSObject.mm */; };
E8923DA1116AB2820071B552 /* a1a2-blocktramps-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = E8923D9C116AB2820071B552 /* a1a2-blocktramps-i386.s */; }; C2E6D3FC2225DCF00059DFAA /* DenseMapExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E6D3FB2225DCF00059DFAA /* DenseMapExtras.h */; };
E8923DA2116AB2820071B552 /* a1a2-blocktramps-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = E8923D9D116AB2820071B552 /* a1a2-blocktramps-x86_64.s */; };
E8923DA3116AB2820071B552 /* a2a3-blocktramps-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = E8923D9E116AB2820071B552 /* a2a3-blocktramps-i386.s */; };
E8923DA4116AB2820071B552 /* a2a3-blocktramps-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = E8923D9F116AB2820071B552 /* a2a3-blocktramps-x86_64.s */; };
E8923DA5116AB2820071B552 /* objc-block-trampolines.mm in Sources */ = {isa = PBXBuildFile; fileRef = E8923DA0116AB2820071B552 /* objc-block-trampolines.mm */; }; E8923DA5116AB2820071B552 /* objc-block-trampolines.mm in Sources */ = {isa = PBXBuildFile; fileRef = E8923DA0116AB2820071B552 /* objc-block-trampolines.mm */; };
F9BCC71B205C68E800DD9AFC /* objc-blocktramps-arm64.s in Sources */ = {isa = PBXBuildFile; fileRef = 8379996D13CBAF6F007C2B5F /* objc-blocktramps-arm64.s */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -113,6 +141,13 @@
remoteGlobalIDString = D2AAC0620554660B00DB518D; remoteGlobalIDString = D2AAC0620554660B00DB518D;
remoteInfo = objc; remoteInfo = objc;
}; };
F9BCC728205C6A0900DD9AFC /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = F9BCC6CA205C68E800DD9AFC;
remoteInfo = "objc-trampolines";
};
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@ -120,6 +155,21 @@
393CEAC50DC69E67000B69DE /* objc-references.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-references.h"; path = "runtime/objc-references.h"; sourceTree = "<group>"; }; 393CEAC50DC69E67000B69DE /* objc-references.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-references.h"; path = "runtime/objc-references.h"; sourceTree = "<group>"; };
39ABD71F12F0B61800D1054C /* objc-weak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-weak.h"; path = "runtime/objc-weak.h"; sourceTree = "<group>"; }; 39ABD71F12F0B61800D1054C /* objc-weak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-weak.h"; path = "runtime/objc-weak.h"; sourceTree = "<group>"; };
39ABD72012F0B61800D1054C /* objc-weak.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-weak.mm"; path = "runtime/objc-weak.mm"; sourceTree = "<group>"; }; 39ABD72012F0B61800D1054C /* objc-weak.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-weak.mm"; path = "runtime/objc-weak.mm"; sourceTree = "<group>"; };
6E1475E521DFDB1A001357EA /* llvm-AlignOf.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = "llvm-AlignOf.h"; path = "runtime/llvm-AlignOf.h"; sourceTree = "<group>"; tabWidth = 2; };
6E1475E621DFDB1B001357EA /* llvm-DenseMap.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = "llvm-DenseMap.h"; path = "runtime/llvm-DenseMap.h"; sourceTree = "<group>"; tabWidth = 2; };
6E1475E721DFDB1B001357EA /* llvm-DenseMapInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = "llvm-DenseMapInfo.h"; path = "runtime/llvm-DenseMapInfo.h"; sourceTree = "<group>"; tabWidth = 2; };
6E1475E821DFDB1B001357EA /* llvm-type_traits.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = "llvm-type_traits.h"; path = "runtime/llvm-type_traits.h"; sourceTree = "<group>"; tabWidth = 2; };
6E1475E921DFDB1B001357EA /* llvm-MathExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = "llvm-MathExtras.h"; path = "runtime/llvm-MathExtras.h"; sourceTree = "<group>"; tabWidth = 2; };
6E7B0861232DE7CA00689009 /* PointerUnion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PointerUnion.h; path = runtime/PointerUnion.h; sourceTree = "<group>"; };
6EACB841232C97A400CE9176 /* objc-zalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-zalloc.h"; path = "runtime/objc-zalloc.h"; sourceTree = "<group>"; };
6EACB843232C97B900CE9176 /* objc-zalloc.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-zalloc.mm"; path = "runtime/objc-zalloc.mm"; sourceTree = "<group>"; };
6ECD0B1E2244999E00910D88 /* llvm-DenseSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "llvm-DenseSet.h"; path = "runtime/llvm-DenseSet.h"; sourceTree = "<group>"; };
7213C36221FA7C730090A271 /* NSObject-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSObject-internal.h"; path = "runtime/NSObject-internal.h"; sourceTree = "<group>"; };
7593EC57202248DF0046AB96 /* objc-object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "objc-object.h"; path = "runtime/objc-object.h"; sourceTree = "<group>"; };
75A9504E202BAA0300D7D56F /* objc-locks-new.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "objc-locks-new.h"; path = "runtime/objc-locks-new.h"; sourceTree = "<group>"; };
75A95050202BAA9A00D7D56F /* objc-locks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-locks.h"; path = "runtime/objc-locks.h"; sourceTree = "<group>"; };
75A95052202BAC4100D7D56F /* objc-lockdebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-lockdebug.h"; path = "runtime/objc-lockdebug.h"; sourceTree = "<group>"; };
8306440620D24A3E00E356D2 /* objc-block-trampolines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "objc-block-trampolines.h"; path = "runtime/objc-block-trampolines.h"; sourceTree = "<group>"; };
830F2A690D737FB800392440 /* objc-msg-arm.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-arm.s"; path = "runtime/Messengers.subproj/objc-msg-arm.s"; sourceTree = "<group>"; }; 830F2A690D737FB800392440 /* objc-msg-arm.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-arm.s"; path = "runtime/Messengers.subproj/objc-msg-arm.s"; sourceTree = "<group>"; };
830F2A6A0D737FB800392440 /* objc-msg-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-i386.s"; path = "runtime/Messengers.subproj/objc-msg-i386.s"; sourceTree = "<group>"; }; 830F2A6A0D737FB800392440 /* objc-msg-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-i386.s"; path = "runtime/Messengers.subproj/objc-msg-i386.s"; sourceTree = "<group>"; };
830F2A720D737FB800392440 /* objc-msg-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-x86_64.s"; path = "runtime/Messengers.subproj/objc-msg-x86_64.s"; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; }; 830F2A720D737FB800392440 /* objc-msg-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-x86_64.s"; path = "runtime/Messengers.subproj/objc-msg-x86_64.s"; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
@ -133,9 +183,8 @@
834DF8B615993EE1002F2BC9 /* objc-sel-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-sel-old.mm"; path = "runtime/objc-sel-old.mm"; sourceTree = "<group>"; }; 834DF8B615993EE1002F2BC9 /* objc-sel-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-sel-old.mm"; path = "runtime/objc-sel-old.mm"; sourceTree = "<group>"; };
834EC0A311614167009B2563 /* objc-abi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-abi.h"; path = "runtime/objc-abi.h"; sourceTree = "<group>"; }; 834EC0A311614167009B2563 /* objc-abi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-abi.h"; path = "runtime/objc-abi.h"; sourceTree = "<group>"; };
83725F4914CA5BFA0014370E /* objc-opt.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-opt.mm"; path = "runtime/objc-opt.mm"; sourceTree = "<group>"; }; 83725F4914CA5BFA0014370E /* objc-opt.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-opt.mm"; path = "runtime/objc-opt.mm"; sourceTree = "<group>"; };
8379996D13CBAF6F007C2B5F /* a1a2-blocktramps-arm64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a1a2-blocktramps-arm64.s"; path = "runtime/a1a2-blocktramps-arm64.s"; sourceTree = "<group>"; }; 8379996D13CBAF6F007C2B5F /* objc-blocktramps-arm64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-blocktramps-arm64.s"; path = "runtime/objc-blocktramps-arm64.s"; sourceTree = "<group>"; };
8383A3A1122600E9009290B8 /* a1a2-blocktramps-arm.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a1a2-blocktramps-arm.s"; path = "runtime/a1a2-blocktramps-arm.s"; sourceTree = "<group>"; }; 8383A3A1122600E9009290B8 /* objc-blocktramps-arm.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-blocktramps-arm.s"; path = "runtime/objc-blocktramps-arm.s"; sourceTree = "<group>"; };
8383A3A2122600E9009290B8 /* a2a3-blocktramps-arm.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a2a3-blocktramps-arm.s"; path = "runtime/a2a3-blocktramps-arm.s"; sourceTree = "<group>"; };
838485B30D6D682B00CEA253 /* libobjc.order */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = libobjc.order; sourceTree = "<group>"; }; 838485B30D6D682B00CEA253 /* libobjc.order */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = libobjc.order; sourceTree = "<group>"; };
838485B40D6D683300CEA253 /* APPLE_LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = APPLE_LICENSE; sourceTree = "<group>"; }; 838485B40D6D683300CEA253 /* APPLE_LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = APPLE_LICENSE; sourceTree = "<group>"; };
838485B50D6D683300CEA253 /* ReleaseNotes.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = ReleaseNotes.rtf; sourceTree = "<group>"; }; 838485B50D6D683300CEA253 /* ReleaseNotes.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = ReleaseNotes.rtf; sourceTree = "<group>"; };
@ -184,13 +233,18 @@
8384861A0D6D68A800CEA253 /* runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = runtime.h; path = runtime/runtime.h; sourceTree = "<group>"; }; 8384861A0D6D68A800CEA253 /* runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = runtime.h; path = runtime/runtime.h; sourceTree = "<group>"; };
838486230D6D68F000CEA253 /* List.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = List.m; path = runtime/OldClasses.subproj/List.m; sourceTree = "<group>"; }; 838486230D6D68F000CEA253 /* List.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = List.m; path = runtime/OldClasses.subproj/List.m; sourceTree = "<group>"; };
838486240D6D68F000CEA253 /* List.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = List.h; path = runtime/OldClasses.subproj/List.h; sourceTree = "<group>"; }; 838486240D6D68F000CEA253 /* List.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = List.h; path = runtime/OldClasses.subproj/List.h; sourceTree = "<group>"; };
83A4AED71EA06D9D00ACADDE /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; name = module.modulemap; path = runtime/Module/module.modulemap; sourceTree = "<group>"; };
83A4AEDD1EA08C5700ACADDE /* ObjectiveC.apinotes */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ObjectiveC.apinotes; path = runtime/Module/ObjectiveC.apinotes; sourceTree = "<group>"; };
83B1A8BC0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-simulator-i386.s"; path = "runtime/Messengers.subproj/objc-msg-simulator-i386.s"; sourceTree = "<group>"; }; 83B1A8BC0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-simulator-i386.s"; path = "runtime/Messengers.subproj/objc-msg-simulator-i386.s"; sourceTree = "<group>"; };
83BE02E30FCCB23400661494 /* objc-file-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-file-old.mm"; path = "runtime/objc-file-old.mm"; sourceTree = "<group>"; }; 83BE02E30FCCB23400661494 /* objc-file-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-file-old.mm"; path = "runtime/objc-file-old.mm"; sourceTree = "<group>"; };
83BE02E50FCCB24D00661494 /* objc-file-old.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-file-old.h"; path = "runtime/objc-file-old.h"; sourceTree = "<group>"; }; 83BE02E50FCCB24D00661494 /* objc-file-old.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-file-old.h"; path = "runtime/objc-file-old.h"; sourceTree = "<group>"; };
83BE02E60FCCB24D00661494 /* objc-file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-file.h"; path = "runtime/objc-file.h"; sourceTree = "<group>"; }; 83BE02E60FCCB24D00661494 /* objc-file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-file.h"; path = "runtime/objc-file.h"; sourceTree = "<group>"; };
83BE02E70FCCB24D00661494 /* objc-runtime-old.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-runtime-old.h"; path = "runtime/objc-runtime-old.h"; sourceTree = "<group>"; }; 83BE02E70FCCB24D00661494 /* objc-runtime-old.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-runtime-old.h"; path = "runtime/objc-runtime-old.h"; sourceTree = "<group>"; };
83C9C3381668B50E00F4E544 /* objc-msg-simulator-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-simulator-x86_64.s"; path = "runtime/Messengers.subproj/objc-msg-simulator-x86_64.s"; sourceTree = "<group>"; }; 83C9C3381668B50E00F4E544 /* objc-msg-simulator-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-simulator-x86_64.s"; path = "runtime/Messengers.subproj/objc-msg-simulator-x86_64.s"; sourceTree = "<group>"; };
83CE671D1E6E76B60095A33E /* interposable.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = interposable.txt; sourceTree = "<group>"; };
83D49E4E13C7C84F0057F1DD /* objc-msg-arm64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-arm64.s"; path = "runtime/Messengers.subproj/objc-msg-arm64.s"; sourceTree = "<group>"; }; 83D49E4E13C7C84F0057F1DD /* objc-msg-arm64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-arm64.s"; path = "runtime/Messengers.subproj/objc-msg-arm64.s"; sourceTree = "<group>"; };
83D92695212254CF00299F69 /* isa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = isa.h; path = runtime/isa.h; sourceTree = "<group>"; };
83D9269721225A7400299F69 /* arm64-asm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "arm64-asm.h"; path = "runtime/arm64-asm.h"; sourceTree = "<group>"; };
83EB007A121C9EC200B92C16 /* objc-sel-table.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-sel-table.s"; path = "runtime/objc-sel-table.s"; sourceTree = "<group>"; }; 83EB007A121C9EC200B92C16 /* objc-sel-table.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-sel-table.s"; path = "runtime/objc-sel-table.s"; sourceTree = "<group>"; };
83F4B52615E843B100E0926F /* NSObjCRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSObjCRuntime.h; path = runtime/NSObjCRuntime.h; sourceTree = "<group>"; }; 83F4B52615E843B100E0926F /* NSObjCRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSObjCRuntime.h; path = runtime/NSObjCRuntime.h; sourceTree = "<group>"; };
83F4B52715E843B100E0926F /* NSObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSObject.h; path = runtime/NSObject.h; sourceTree = "<group>"; }; 83F4B52715E843B100E0926F /* NSObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSObject.h; path = runtime/NSObject.h; sourceTree = "<group>"; };
@ -198,12 +252,12 @@
87BB4E900EC39633005D08E1 /* objc-probes.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = "objc-probes.d"; path = "runtime/objc-probes.d"; sourceTree = "<group>"; }; 87BB4E900EC39633005D08E1 /* objc-probes.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = "objc-probes.d"; path = "runtime/objc-probes.d"; sourceTree = "<group>"; };
9672F7ED14D5F488007CEC96 /* NSObject.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NSObject.mm; path = runtime/NSObject.mm; sourceTree = "<group>"; }; 9672F7ED14D5F488007CEC96 /* NSObject.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NSObject.mm; path = runtime/NSObject.mm; sourceTree = "<group>"; };
BC8B5D1212D3D48100C78A5B /* libauto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libauto.dylib; path = /usr/lib/libauto.dylib; sourceTree = "<absolute>"; }; BC8B5D1212D3D48100C78A5B /* libauto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libauto.dylib; path = /usr/lib/libauto.dylib; sourceTree = "<absolute>"; };
C2E6D3FB2225DCF00059DFAA /* DenseMapExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DenseMapExtras.h; path = runtime/DenseMapExtras.h; sourceTree = "<group>"; };
D2AAC0630554660B00DB518D /* libobjc.A.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libobjc.A.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; D2AAC0630554660B00DB518D /* libobjc.A.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libobjc.A.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
E8923D9C116AB2820071B552 /* a1a2-blocktramps-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a1a2-blocktramps-i386.s"; path = "runtime/a1a2-blocktramps-i386.s"; sourceTree = "<group>"; }; E8923D9C116AB2820071B552 /* objc-blocktramps-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-blocktramps-i386.s"; path = "runtime/objc-blocktramps-i386.s"; sourceTree = "<group>"; };
E8923D9D116AB2820071B552 /* a1a2-blocktramps-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a1a2-blocktramps-x86_64.s"; path = "runtime/a1a2-blocktramps-x86_64.s"; sourceTree = "<group>"; }; E8923D9D116AB2820071B552 /* objc-blocktramps-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-blocktramps-x86_64.s"; path = "runtime/objc-blocktramps-x86_64.s"; sourceTree = "<group>"; };
E8923D9E116AB2820071B552 /* a2a3-blocktramps-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a2a3-blocktramps-i386.s"; path = "runtime/a2a3-blocktramps-i386.s"; sourceTree = "<group>"; };
E8923D9F116AB2820071B552 /* a2a3-blocktramps-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a2a3-blocktramps-x86_64.s"; path = "runtime/a2a3-blocktramps-x86_64.s"; sourceTree = "<group>"; };
E8923DA0116AB2820071B552 /* objc-block-trampolines.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-block-trampolines.mm"; path = "runtime/objc-block-trampolines.mm"; sourceTree = "<group>"; }; E8923DA0116AB2820071B552 /* objc-block-trampolines.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-block-trampolines.mm"; path = "runtime/objc-block-trampolines.mm"; sourceTree = "<group>"; };
F9BCC727205C68E800DD9AFC /* libobjc-trampolines.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = "libobjc-trampolines.dylib"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -214,6 +268,13 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
F9BCC721205C68E800DD9AFC /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
@ -229,6 +290,7 @@
08FB7795FE84155DC02AAC07 /* Source */, 08FB7795FE84155DC02AAC07 /* Source */,
838485B20D6D67F900CEA253 /* Other */, 838485B20D6D67F900CEA253 /* Other */,
1AB674ADFE9D54B511CA2CBB /* Products */, 1AB674ADFE9D54B511CA2CBB /* Products */,
F9BCC72A205C6A1600DD9AFC /* Frameworks */,
); );
name = objc; name = objc;
sourceTree = "<group>"; sourceTree = "<group>";
@ -236,8 +298,6 @@
08FB7795FE84155DC02AAC07 /* Source */ = { 08FB7795FE84155DC02AAC07 /* Source */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
8383A3A1122600E9009290B8 /* a1a2-blocktramps-arm.s */,
8383A3A2122600E9009290B8 /* a2a3-blocktramps-arm.s */,
838485B80D6D687300CEA253 /* hashtable2.mm */, 838485B80D6D687300CEA253 /* hashtable2.mm */,
838485BC0D6D687300CEA253 /* maptable.mm */, 838485BC0D6D687300CEA253 /* maptable.mm */,
9672F7ED14D5F488007CEC96 /* NSObject.mm */, 9672F7ED14D5F488007CEC96 /* NSObject.mm */,
@ -245,6 +305,7 @@
830F2A930D73876100392440 /* objc-accessors.mm */, 830F2A930D73876100392440 /* objc-accessors.mm */,
838485CA0D6D68A200CEA253 /* objc-auto.mm */, 838485CA0D6D68A200CEA253 /* objc-auto.mm */,
39ABD72012F0B61800D1054C /* objc-weak.mm */, 39ABD72012F0B61800D1054C /* objc-weak.mm */,
6EACB843232C97B900CE9176 /* objc-zalloc.mm */,
E8923DA0116AB2820071B552 /* objc-block-trampolines.mm */, E8923DA0116AB2820071B552 /* objc-block-trampolines.mm */,
838485CB0D6D68A200CEA253 /* objc-cache.mm */, 838485CB0D6D68A200CEA253 /* objc-cache.mm */,
83F550DF155E030800E95D3B /* objc-cache-old.mm */, 83F550DF155E030800E95D3B /* objc-cache-old.mm */,
@ -271,11 +332,10 @@
834DF8B615993EE1002F2BC9 /* objc-sel-old.mm */, 834DF8B615993EE1002F2BC9 /* objc-sel-old.mm */,
838485EA0D6D68A200CEA253 /* objc-sync.mm */, 838485EA0D6D68A200CEA253 /* objc-sync.mm */,
838485EB0D6D68A200CEA253 /* objc-typeencoding.mm */, 838485EB0D6D68A200CEA253 /* objc-typeencoding.mm */,
8379996D13CBAF6F007C2B5F /* a1a2-blocktramps-arm64.s */, 8383A3A1122600E9009290B8 /* objc-blocktramps-arm.s */,
E8923D9C116AB2820071B552 /* a1a2-blocktramps-i386.s */, 8379996D13CBAF6F007C2B5F /* objc-blocktramps-arm64.s */,
E8923D9D116AB2820071B552 /* a1a2-blocktramps-x86_64.s */, E8923D9C116AB2820071B552 /* objc-blocktramps-i386.s */,
E8923D9E116AB2820071B552 /* a2a3-blocktramps-i386.s */, E8923D9D116AB2820071B552 /* objc-blocktramps-x86_64.s */,
E8923D9F116AB2820071B552 /* a2a3-blocktramps-x86_64.s */,
830F2A690D737FB800392440 /* objc-msg-arm.s */, 830F2A690D737FB800392440 /* objc-msg-arm.s */,
83D49E4E13C7C84F0057F1DD /* objc-msg-arm64.s */, 83D49E4E13C7C84F0057F1DD /* objc-msg-arm64.s */,
830F2A6A0D737FB800392440 /* objc-msg-i386.s */, 830F2A6A0D737FB800392440 /* objc-msg-i386.s */,
@ -291,6 +351,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D2AAC0630554660B00DB518D /* libobjc.A.dylib */, D2AAC0630554660B00DB518D /* libobjc.A.dylib */,
F9BCC727205C68E800DD9AFC /* libobjc-trampolines.dylib */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -301,6 +362,7 @@
830F2AA50D7394C200392440 /* markgc.cpp */, 830F2AA50D7394C200392440 /* markgc.cpp */,
838485B40D6D683300CEA253 /* APPLE_LICENSE */, 838485B40D6D683300CEA253 /* APPLE_LICENSE */,
838485B50D6D683300CEA253 /* ReleaseNotes.rtf */, 838485B50D6D683300CEA253 /* ReleaseNotes.rtf */,
83CE671D1E6E76B60095A33E /* interposable.txt */,
838485B30D6D682B00CEA253 /* libobjc.order */, 838485B30D6D682B00CEA253 /* libobjc.order */,
); );
name = Other; name = Other;
@ -309,6 +371,8 @@
838485C60D6D687700CEA253 /* Public Headers */ = { 838485C60D6D687700CEA253 /* Public Headers */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
83A4AEDD1EA08C5700ACADDE /* ObjectiveC.apinotes */,
83A4AED71EA06D9D00ACADDE /* module.modulemap */,
83F4B52615E843B100E0926F /* NSObjCRuntime.h */, 83F4B52615E843B100E0926F /* NSObjCRuntime.h */,
83F4B52715E843B100E0926F /* NSObject.h */, 83F4B52715E843B100E0926F /* NSObject.h */,
838485BD0D6D687300CEA253 /* message.h */, 838485BD0D6D687300CEA253 /* message.h */,
@ -325,10 +389,12 @@
838485C70D6D688200CEA253 /* Private Headers */ = { 838485C70D6D688200CEA253 /* Private Headers */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
7213C36221FA7C730090A271 /* NSObject-internal.h */,
83112ED30F00599600A5FBAF /* objc-internal.h */, 83112ED30F00599600A5FBAF /* objc-internal.h */,
834EC0A311614167009B2563 /* objc-abi.h */, 834EC0A311614167009B2563 /* objc-abi.h */,
838485BB0D6D687300CEA253 /* maptable.h */, 838485BB0D6D687300CEA253 /* maptable.h */,
834266D70E665A8B002E4DA2 /* objc-gdb.h */, 834266D70E665A8B002E4DA2 /* objc-gdb.h */,
8306440620D24A3E00E356D2 /* objc-block-trampolines.h */,
); );
name = "Private Headers"; name = "Private Headers";
sourceTree = "<group>"; sourceTree = "<group>";
@ -360,11 +426,25 @@
8384862A0D6D6ABC00CEA253 /* Project Headers */ = { 8384862A0D6D6ABC00CEA253 /* Project Headers */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
6E1475E521DFDB1A001357EA /* llvm-AlignOf.h */,
6E1475E621DFDB1B001357EA /* llvm-DenseMap.h */,
6E1475E721DFDB1B001357EA /* llvm-DenseMapInfo.h */,
6ECD0B1E2244999E00910D88 /* llvm-DenseSet.h */,
6E1475E921DFDB1B001357EA /* llvm-MathExtras.h */,
6E1475E821DFDB1B001357EA /* llvm-type_traits.h */,
C2E6D3FB2225DCF00059DFAA /* DenseMapExtras.h */,
6E7B0861232DE7CA00689009 /* PointerUnion.h */,
83D9269721225A7400299F69 /* arm64-asm.h */,
83D92695212254CF00299F69 /* isa.h */,
838485CF0D6D68A200CEA253 /* objc-config.h */, 838485CF0D6D68A200CEA253 /* objc-config.h */,
83BE02E60FCCB24D00661494 /* objc-file.h */,
83BE02E50FCCB24D00661494 /* objc-file-old.h */, 83BE02E50FCCB24D00661494 /* objc-file-old.h */,
83BE02E60FCCB24D00661494 /* objc-file.h */,
838485D40D6D68A200CEA253 /* objc-initialize.h */, 838485D40D6D68A200CEA253 /* objc-initialize.h */,
838485D90D6D68A200CEA253 /* objc-loadmethod.h */, 838485D90D6D68A200CEA253 /* objc-loadmethod.h */,
75A9504E202BAA0300D7D56F /* objc-locks-new.h */,
75A95052202BAC4100D7D56F /* objc-lockdebug.h */,
75A95050202BAA9A00D7D56F /* objc-locks.h */,
7593EC57202248DF0046AB96 /* objc-object.h */,
831C85D30E10CF850066E64C /* objc-os.h */, 831C85D30E10CF850066E64C /* objc-os.h */,
838485DC0D6D68A200CEA253 /* objc-private.h */, 838485DC0D6D68A200CEA253 /* objc-private.h */,
393CEAC50DC69E67000B69DE /* objc-references.h */, 393CEAC50DC69E67000B69DE /* objc-references.h */,
@ -372,19 +452,43 @@
83BE02E70FCCB24D00661494 /* objc-runtime-old.h */, 83BE02E70FCCB24D00661494 /* objc-runtime-old.h */,
838485E50D6D68A200CEA253 /* objc-sel-set.h */, 838485E50D6D68A200CEA253 /* objc-sel-set.h */,
39ABD71F12F0B61800D1054C /* objc-weak.h */, 39ABD71F12F0B61800D1054C /* objc-weak.h */,
6EACB841232C97A400CE9176 /* objc-zalloc.h */,
); );
name = "Project Headers"; name = "Project Headers";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
F9BCC72A205C6A1600DD9AFC /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */ /* Begin PBXHeadersBuildPhase section */
8306440820D24A5300E356D2 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
8306440920D24A5D00E356D2 /* objc-block-trampolines.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D2AAC0600554660B00DB518D /* Headers */ = { D2AAC0600554660B00DB518D /* Headers */ = {
isa = PBXHeadersBuildPhase; isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
83A4AEDE1EA08C7200ACADDE /* ObjectiveC.apinotes in Headers */,
75A95051202BAA9A00D7D56F /* objc-locks.h in Headers */,
6E1475ED21DFDB1B001357EA /* llvm-type_traits.h in Headers */,
83A4AEDC1EA0840800ACADDE /* module.modulemap in Headers */,
830F2A980D738DC200392440 /* hashtable.h in Headers */, 830F2A980D738DC200392440 /* hashtable.h in Headers */,
6EACB842232C97A400CE9176 /* objc-zalloc.h in Headers */,
6E1475EA21DFDB1B001357EA /* llvm-AlignOf.h in Headers */,
838485BF0D6D687300CEA253 /* hashtable2.h in Headers */, 838485BF0D6D687300CEA253 /* hashtable2.h in Headers */,
6E1475EC21DFDB1B001357EA /* llvm-DenseMapInfo.h in Headers */,
C2E6D3FC2225DCF00059DFAA /* DenseMapExtras.h in Headers */,
838486260D6D68F000CEA253 /* List.h in Headers */, 838486260D6D68F000CEA253 /* List.h in Headers */,
838485C30D6D687300CEA253 /* maptable.h in Headers */, 838485C30D6D687300CEA253 /* maptable.h in Headers */,
838486280D6D6A2400CEA253 /* message.h in Headers */, 838486280D6D6A2400CEA253 /* message.h in Headers */,
@ -393,28 +497,38 @@
838485F00D6D68A200CEA253 /* objc-auto.h in Headers */, 838485F00D6D68A200CEA253 /* objc-auto.h in Headers */,
838485F40D6D68A200CEA253 /* objc-class.h in Headers */, 838485F40D6D68A200CEA253 /* objc-class.h in Headers */,
838485F60D6D68A200CEA253 /* objc-config.h in Headers */, 838485F60D6D68A200CEA253 /* objc-config.h in Headers */,
6E1475EE21DFDB1B001357EA /* llvm-MathExtras.h in Headers */,
838485F80D6D68A200CEA253 /* objc-exception.h in Headers */, 838485F80D6D68A200CEA253 /* objc-exception.h in Headers */,
83BE02E80FCCB24D00661494 /* objc-file-old.h in Headers */, 83BE02E80FCCB24D00661494 /* objc-file-old.h in Headers */,
83BE02E90FCCB24D00661494 /* objc-file.h in Headers */, 83BE02E90FCCB24D00661494 /* objc-file.h in Headers */,
75A9504F202BAA0600D7D56F /* objc-locks-new.h in Headers */,
834266D80E665A8B002E4DA2 /* objc-gdb.h in Headers */, 834266D80E665A8B002E4DA2 /* objc-gdb.h in Headers */,
838485FB0D6D68A200CEA253 /* objc-initialize.h in Headers */, 838485FB0D6D68A200CEA253 /* objc-initialize.h in Headers */,
7593EC58202248E50046AB96 /* objc-object.h in Headers */,
83112ED40F00599600A5FBAF /* objc-internal.h in Headers */, 83112ED40F00599600A5FBAF /* objc-internal.h in Headers */,
838485FE0D6D68A200CEA253 /* objc-load.h in Headers */, 838485FE0D6D68A200CEA253 /* objc-load.h in Headers */,
838486000D6D68A200CEA253 /* objc-loadmethod.h in Headers */, 838486000D6D68A200CEA253 /* objc-loadmethod.h in Headers */,
75A95053202BAC4100D7D56F /* objc-lockdebug.h in Headers */,
831C85D50E10CF850066E64C /* objc-os.h in Headers */, 831C85D50E10CF850066E64C /* objc-os.h in Headers */,
838486030D6D68A200CEA253 /* objc-private.h in Headers */, 838486030D6D68A200CEA253 /* objc-private.h in Headers */,
393CEAC60DC69E67000B69DE /* objc-references.h in Headers */, 393CEAC60DC69E67000B69DE /* objc-references.h in Headers */,
6E1475EB21DFDB1B001357EA /* llvm-DenseMap.h in Headers */,
838486070D6D68A200CEA253 /* objc-runtime-new.h in Headers */, 838486070D6D68A200CEA253 /* objc-runtime-new.h in Headers */,
83BE02EA0FCCB24D00661494 /* objc-runtime-old.h in Headers */, 83BE02EA0FCCB24D00661494 /* objc-runtime-old.h in Headers */,
8384860A0D6D68A200CEA253 /* objc-runtime.h in Headers */, 8384860A0D6D68A200CEA253 /* objc-runtime.h in Headers */,
8384860C0D6D68A200CEA253 /* objc-sel-set.h in Headers */, 8384860C0D6D68A200CEA253 /* objc-sel-set.h in Headers */,
6E7B0862232DE7CA00689009 /* PointerUnion.h in Headers */,
7213C36321FA7C730090A271 /* NSObject-internal.h in Headers */,
838486100D6D68A200CEA253 /* objc-sync.h in Headers */, 838486100D6D68A200CEA253 /* objc-sync.h in Headers */,
83D92696212254CF00299F69 /* isa.h in Headers */,
838486130D6D68A200CEA253 /* objc.h in Headers */, 838486130D6D68A200CEA253 /* objc.h in Headers */,
83D9269821225A7400299F69 /* arm64-asm.h in Headers */,
838486140D6D68A200CEA253 /* Object.h in Headers */, 838486140D6D68A200CEA253 /* Object.h in Headers */,
8384861E0D6D68A800CEA253 /* Protocol.h in Headers */, 8384861E0D6D68A800CEA253 /* Protocol.h in Headers */,
838486200D6D68A800CEA253 /* runtime.h in Headers */, 838486200D6D68A800CEA253 /* runtime.h in Headers */,
39ABD72312F0B61800D1054C /* objc-weak.h in Headers */, 39ABD72312F0B61800D1054C /* objc-weak.h in Headers */,
83F4B52815E843B100E0926F /* NSObjCRuntime.h in Headers */, 83F4B52815E843B100E0926F /* NSObjCRuntime.h in Headers */,
6ECD0B1F2244999E00910D88 /* llvm-DenseSet.h in Headers */,
83F4B52915E843B100E0926F /* NSObject.h in Headers */, 83F4B52915E843B100E0926F /* NSObject.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -435,12 +549,30 @@
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
F9BCC729205C6A0900DD9AFC /* PBXTargetDependency */,
); );
name = objc; name = objc;
productName = objc; productName = objc;
productReference = D2AAC0630554660B00DB518D /* libobjc.A.dylib */; productReference = D2AAC0630554660B00DB518D /* libobjc.A.dylib */;
productType = "com.apple.product-type.library.dynamic"; productType = "com.apple.product-type.library.dynamic";
}; };
F9BCC6CA205C68E800DD9AFC /* objc-trampolines */ = {
isa = PBXNativeTarget;
buildConfigurationList = F9BCC724205C68E800DD9AFC /* Build configuration list for PBXNativeTarget "objc-trampolines" */;
buildPhases = (
8306440820D24A5300E356D2 /* Headers */,
F9BCC6EF205C68E800DD9AFC /* Sources */,
F9BCC721205C68E800DD9AFC /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = "objc-trampolines";
productName = objc;
productReference = F9BCC727205C68E800DD9AFC /* libobjc-trampolines.dylib */;
productType = "com.apple.product-type.library.dynamic";
};
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
/* Begin PBXProject section */ /* Begin PBXProject section */
@ -450,6 +582,11 @@
BuildIndependentTargetsInParallel = NO; BuildIndependentTargetsInParallel = NO;
LastUpgradeCheck = 0440; LastUpgradeCheck = 0440;
TargetAttributes = { TargetAttributes = {
834F9B01212E560100F95A54 = {
CreatedOnToolsVersion = 10.0;
DevelopmentTeam = 59GAB85EFG;
ProvisioningStyle = Automatic;
};
837F67A81A771F63004D34FA = { 837F67A81A771F63004D34FA = {
CreatedOnToolsVersion = 6.3; CreatedOnToolsVersion = 6.3;
}; };
@ -471,6 +608,8 @@
targets = ( targets = (
D2AAC0620554660B00DB518D /* objc */, D2AAC0620554660B00DB518D /* objc */,
837F67A81A771F63004D34FA /* objc-simulator */, 837F67A81A771F63004D34FA /* objc-simulator */,
F9BCC6CA205C68E800DD9AFC /* objc-trampolines */,
834F9B01212E560100F95A54 /* objc4_tests */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@ -489,7 +628,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "set -x\n/usr/bin/xcrun -sdk macosx clang++ -Wall -mmacosx-version-min=10.9 -arch x86_64 -std=c++11 \"${SRCROOT}/markgc.cpp\" -o \"${BUILT_PRODUCTS_DIR}/markgc\"\n\"${BUILT_PRODUCTS_DIR}/markgc\" \"${BUILT_PRODUCTS_DIR}/libobjc.A.dylib\""; shellScript = "set -x\n/usr/bin/xcrun -sdk macosx.internal clang++ -Wall -mmacosx-version-min=10.12 -arch x86_64 -std=c++11 \"${SRCROOT}/markgc.cpp\" -o \"${BUILT_PRODUCTS_DIR}/markgc\"\n\"${BUILT_PRODUCTS_DIR}/markgc\" \"${BUILT_PRODUCTS_DIR}/libobjc.A.dylib\"";
}; };
830F2AFA0D73BC5800392440 /* Run Script (symlink) */ = { 830F2AFA0D73BC5800392440 /* Run Script (symlink) */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
@ -503,7 +642,25 @@
); );
runOnlyForDeploymentPostprocessing = 1; runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "cd \"${INSTALL_DIR}\"\n/bin/ln -s libobjc.A.dylib libobjc.dylib\n"; shellScript = "cd \"${INSTALL_DIR}\"\n/bin/ln -s libobjc.A.dylib libobjc.dylib\n\nTBD_UPPER=`echo ${GENERATE_TEXT_BASED_STUBS} | tr a-z A-Z`\n\nif [ ${TBD_UPPER} = \"YES\" ] || [ ${TBD_UPPER} = \"TRUE\" ] || [ ${TBD_UPPER} = \"1\" ]; then\nGENERATE_TBD=1\nfi\n\nif [ ${GENERATE_TBD} ]; then\n /bin/ln -s libobjc.A.tbd libobjc.tbd\nfi\n";
};
834F9B05212E561400F95A54 /* Run Script (build tests) */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Run Script (build tests)";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "set -x\nset -e\n\n# Set this to empty, or a space-separated list of tests to run.\ntestfiles=\"\"\n\n# Location inside DSTROOT of our test files and our BATS config file.\ntestdir=/AppleInternal/CoreOS/tests/objc4\nconfigdir=/AppleInternal/CoreOS/BATS/unit_tests\n\nmkdir -p ${DSTROOT}${testdir}\nmkdir -p ${DSTROOT}${configdir}\n\n# Common test.pl args for building and running.\ntestargs=\"ARCH=`echo ${ARCHS} | tr ' ' ','` OS=${PLATFORM_NAME} MEM=mrc,arc LANGUAGE=c,c++,objc,objc++ RUN=0 VERBOSE=1 BATS=1 ${testfiles}\"\n\n# Build the tests and BATS plist into DSTROOT.\nperl ${SRCROOT}/test/test.pl $testargs BUILD=1 RUN=0\n\n# Move the BATS plist where BATS expects it, and convert it to binary format.\nmv ${DSTROOT}${testdir}/objc4.plist ${DSTROOT}${configdir}\nplutil -convert binary1 ${DSTROOT}${configdir}/objc4.plist\n\n# Copy test sources to DSTROOT; running the test requires reading them again.\ncp -R ${SRCROOT}/test ${DSTROOT}${testdir}/test\n\n# Don't copy gcfiles because XBS chokes on them.\n# Don't copy other cruft because verifiers dislike them. (This doesn't matter for submissions but does affect local buildit builds.)\nrm -rf ${DSTROOT}${testdir}/test/gcfiles\nrm -rf ${DSTROOT}${testdir}/test/*~\nrm -rf ${DSTROOT}${testdir}/test/\\#*\\#\nrm -rf ${DSTROOT}${testdir}/test/.\\#*\n";
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
@ -544,26 +701,31 @@
831C85D60E10CF850066E64C /* objc-os.mm in Sources */, 831C85D60E10CF850066E64C /* objc-os.mm in Sources */,
87BB4EA70EC39854005D08E1 /* objc-probes.d in Sources */, 87BB4EA70EC39854005D08E1 /* objc-probes.d in Sources */,
83BE02E40FCCB23400661494 /* objc-file-old.mm in Sources */, 83BE02E40FCCB23400661494 /* objc-file-old.mm in Sources */,
E8923DA1116AB2820071B552 /* a1a2-blocktramps-i386.s in Sources */,
E8923DA2116AB2820071B552 /* a1a2-blocktramps-x86_64.s in Sources */,
E8923DA3116AB2820071B552 /* a2a3-blocktramps-i386.s in Sources */,
E8923DA4116AB2820071B552 /* a2a3-blocktramps-x86_64.s in Sources */,
E8923DA5116AB2820071B552 /* objc-block-trampolines.mm in Sources */, E8923DA5116AB2820071B552 /* objc-block-trampolines.mm in Sources */,
83B1A8BE0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s in Sources */, 83B1A8BE0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s in Sources */,
83EB007B121C9EC200B92C16 /* objc-sel-table.s in Sources */, 83EB007B121C9EC200B92C16 /* objc-sel-table.s in Sources */,
8383A3A3122600E9009290B8 /* a1a2-blocktramps-arm.s in Sources */,
8383A3A4122600E9009290B8 /* a2a3-blocktramps-arm.s in Sources */,
39ABD72412F0B61800D1054C /* objc-weak.mm in Sources */, 39ABD72412F0B61800D1054C /* objc-weak.mm in Sources */,
83D49E4F13C7C84F0057F1DD /* objc-msg-arm64.s in Sources */, 83D49E4F13C7C84F0057F1DD /* objc-msg-arm64.s in Sources */,
8379996E13CBAF6F007C2B5F /* a1a2-blocktramps-arm64.s in Sources */,
9672F7EE14D5F488007CEC96 /* NSObject.mm in Sources */, 9672F7EE14D5F488007CEC96 /* NSObject.mm in Sources */,
83725F4A14CA5BFA0014370E /* objc-opt.mm in Sources */, 83725F4A14CA5BFA0014370E /* objc-opt.mm in Sources */,
6EACB844232C97B900CE9176 /* objc-zalloc.mm in Sources */,
83F550E0155E030800E95D3B /* objc-cache-old.mm in Sources */, 83F550E0155E030800E95D3B /* objc-cache-old.mm in Sources */,
834DF8B715993EE1002F2BC9 /* objc-sel-old.mm in Sources */, 834DF8B715993EE1002F2BC9 /* objc-sel-old.mm in Sources */,
83C9C3391668B50E00F4E544 /* objc-msg-simulator-x86_64.s in Sources */, 83C9C3391668B50E00F4E544 /* objc-msg-simulator-x86_64.s in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
F9BCC6EF205C68E800DD9AFC /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
83EF5E9C20D2299E00F486A4 /* objc-blocktramps-arm.s in Sources */,
83EF5E9820D2298400F486A4 /* objc-blocktramps-i386.s in Sources */,
83EF5E9920D2298400F486A4 /* objc-blocktramps-x86_64.s in Sources */,
F9BCC71B205C68E800DD9AFC /* objc-blocktramps-arm64.s in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
@ -572,14 +734,22 @@
target = D2AAC0620554660B00DB518D /* objc */; target = D2AAC0620554660B00DB518D /* objc */;
targetProxy = 837F67AC1A771F6E004D34FA /* PBXContainerItemProxy */; targetProxy = 837F67AC1A771F6E004D34FA /* PBXContainerItemProxy */;
}; };
F9BCC729205C6A0900DD9AFC /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F9BCC6CA205C68E800DD9AFC /* objc-trampolines */;
targetProxy = F9BCC728205C6A0900DD9AFC /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
1DEB914B08733D8E0010E9CD /* Debug */ = { 1DEB914B08733D8E0010E9CD /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; COPY_HEADERS_RUN_UNIFDEF = YES;
COPY_HEADERS_UNIFDEF_FLAGS = "-UBUILD_FOR_OSX";
"COPY_HEADERS_UNIFDEF_FLAGS[sdk=macosx*]" = "-DBUILD_FOR_OSX";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEPLOYMENT_LOCATION = YES;
DYLIB_CURRENT_VERSION = 228; DYLIB_CURRENT_VERSION = 228;
EXECUTABLE_PREFIX = lib; EXECUTABLE_PREFIX = lib;
GCC_CW_ASM_SYNTAX = NO; GCC_CW_ASM_SYNTAX = NO;
@ -593,10 +763,13 @@
/System/Library/Frameworks/System.framework/PrivateHeaders, /System/Library/Frameworks/System.framework/PrivateHeaders,
); );
INSTALL_PATH = /usr/lib; INSTALL_PATH = /usr/lib;
IS_ZIPPERED = YES;
LLVM_LTO = NO;
ORDER_FILE = "$(SDKROOT)/AppleInternal/OrderFiles/libobjc.order"; ORDER_FILE = "$(SDKROOT)/AppleInternal/OrderFiles/libobjc.order";
"ORDER_FILE[sdk=iphonesimulator*]" = ""; "ORDER_FILE[sdk=iphonesimulator*]" = "";
OTHER_CFLAGS = ( OTHER_CFLAGS = (
"-fdollars-in-identifiers", "-fdollars-in-identifiers",
"-fno-objc-convert-messages-to-runtime-calls",
"$(OTHER_CFLAGS)", "$(OTHER_CFLAGS)",
); );
"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
@ -610,11 +783,20 @@
__objc_data, __objc_data,
"-Xlinker", "-Xlinker",
0x1000, 0x1000,
"-Xlinker",
"-interposable_list",
"-Xlinker",
interposable.txt,
);
"OTHER_LDFLAGS[sdk=iphonesimulator*][arch=*]" = (
"-lc++abi",
"-Xlinker",
"-interposable_list",
"-Xlinker",
interposable.txt,
); );
"OTHER_LDFLAGS[sdk=iphonesimulator*][arch=*]" = "-lc++abi";
"OTHER_LDFLAGS[sdk=macosx*]" = ( "OTHER_LDFLAGS[sdk=macosx*]" = (
"-lCrashReporterClient", "-lCrashReporterClient",
"-lauto",
"-lc++abi", "-lc++abi",
"-Xlinker", "-Xlinker",
"-sectalign", "-sectalign",
@ -624,10 +806,17 @@
__objc_data, __objc_data,
"-Xlinker", "-Xlinker",
0x1000, 0x1000,
"-Xlinker",
"-interposable_list",
"-Xlinker",
interposable.txt,
); );
OTHER_TAPI_FLAGS = "-exclude-public-header $(DSTROOT)/usr/include/objc/ObjectiveC.apinotes -exclude-public-header $(DSTROOT)/usr/include/objc/module.modulemap -Xparser -Wno-deprecated-declarations -Xparser -Wno-unavailable-declarations -Xparser -D_OBJC_PRIVATE_H_=1 -DOBJC_DECLARE_SYMBOLS=1";
PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/objc; PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/objc;
PRODUCT_NAME = objc.A; PRODUCT_NAME = objc.A;
PUBLIC_HEADERS_FOLDER_PATH = /usr/include/objc; PUBLIC_HEADERS_FOLDER_PATH = /usr/include/objc;
SUPPORTS_TEXT_BASED_API = YES;
TAPI_VERIFY_MODE = Pedantic;
UNEXPORTED_SYMBOLS_FILE = unexported_symbols; UNEXPORTED_SYMBOLS_FILE = unexported_symbols;
}; };
name = Debug; name = Debug;
@ -635,6 +824,10 @@
1DEB914C08733D8E0010E9CD /* Release */ = { 1DEB914C08733D8E0010E9CD /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
COPY_HEADERS_RUN_UNIFDEF = YES;
COPY_HEADERS_UNIFDEF_FLAGS = "-UBUILD_FOR_OSX";
"COPY_HEADERS_UNIFDEF_FLAGS[sdk=macosx*]" = "-DBUILD_FOR_OSX";
DEPLOYMENT_LOCATION = YES;
DYLIB_CURRENT_VERSION = 228; DYLIB_CURRENT_VERSION = 228;
EXECUTABLE_PREFIX = lib; EXECUTABLE_PREFIX = lib;
GCC_CW_ASM_SYNTAX = NO; GCC_CW_ASM_SYNTAX = NO;
@ -647,10 +840,12 @@
/System/Library/Frameworks/System.framework/PrivateHeaders, /System/Library/Frameworks/System.framework/PrivateHeaders,
); );
INSTALL_PATH = /usr/lib; INSTALL_PATH = /usr/lib;
IS_ZIPPERED = YES;
ORDER_FILE = "$(SDKROOT)/AppleInternal/OrderFiles/libobjc.order"; ORDER_FILE = "$(SDKROOT)/AppleInternal/OrderFiles/libobjc.order";
"ORDER_FILE[sdk=iphonesimulator*]" = ""; "ORDER_FILE[sdk=iphonesimulator*]" = "";
OTHER_CFLAGS = ( OTHER_CFLAGS = (
"-fdollars-in-identifiers", "-fdollars-in-identifiers",
"-fno-objc-convert-messages-to-runtime-calls",
"$(OTHER_CFLAGS)", "$(OTHER_CFLAGS)",
); );
"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
@ -664,11 +859,20 @@
__objc_data, __objc_data,
"-Xlinker", "-Xlinker",
0x1000, 0x1000,
"-Xlinker",
"-interposable_list",
"-Xlinker",
interposable.txt,
);
"OTHER_LDFLAGS[sdk=iphonesimulator*][arch=*]" = (
"-lc++abi",
"-Xlinker",
"-interposable_list",
"-Xlinker",
interposable.txt,
); );
"OTHER_LDFLAGS[sdk=iphonesimulator*][arch=*]" = "-lc++abi";
"OTHER_LDFLAGS[sdk=macosx*]" = ( "OTHER_LDFLAGS[sdk=macosx*]" = (
"-lCrashReporterClient", "-lCrashReporterClient",
"-lauto",
"-lc++abi", "-lc++abi",
"-Xlinker", "-Xlinker",
"-sectalign", "-sectalign",
@ -678,28 +882,41 @@
__objc_data, __objc_data,
"-Xlinker", "-Xlinker",
0x1000, 0x1000,
"-Xlinker",
"-interposable_list",
"-Xlinker",
interposable.txt,
); );
OTHER_TAPI_FLAGS = "-exclude-public-header $(DSTROOT)/usr/include/objc/ObjectiveC.apinotes -exclude-public-header $(DSTROOT)/usr/include/objc/module.modulemap -Xparser -Wno-deprecated-declarations -Xparser -Wno-unavailable-declarations -Xparser -D_OBJC_PRIVATE_H_=1 -DOBJC_DECLARE_SYMBOLS=1";
PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/objc; PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/objc;
PRODUCT_NAME = objc.A; PRODUCT_NAME = objc.A;
PUBLIC_HEADERS_FOLDER_PATH = /usr/include/objc; PUBLIC_HEADERS_FOLDER_PATH = /usr/include/objc;
SUPPORTS_TEXT_BASED_API = YES;
TAPI_VERIFY_MODE = Pedantic;
UNEXPORTED_SYMBOLS_FILE = unexported_symbols; UNEXPORTED_SYMBOLS_FILE = unexported_symbols;
WARNING_CFLAGS = (
"$(inherited)",
"-Wglobal-constructors",
);
}; };
name = Release; name = Release;
}; };
1DEB914F08733D8E0010E9CD /* Debug */ = { 1DEB914F08733D8E0010E9CD /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_LINK_OBJC_RUNTIME = NO; CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_OBJC_RUNTIME = NO; CLANG_OBJC_RUNTIME = NO;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
EXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS = "$(inherited) test";
GCC_ENABLE_CPP_EXCEPTIONS = NO; GCC_ENABLE_CPP_EXCEPTIONS = NO;
GCC_ENABLE_CPP_RTTI = NO; GCC_ENABLE_CPP_RTTI = NO;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = "OS_OBJECT_USE_OBJC=0"; GCC_PREPROCESSOR_DEFINITIONS = (
"OS_OBJECT_USE_OBJC=0",
"OBJC_IS_DEBUG_BUILD=1",
);
GCC_STRICT_ALIASING = YES; GCC_STRICT_ALIASING = YES;
GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
@ -709,12 +926,15 @@
GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_SHADOW = YES; GCC_WARN_SHADOW = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
LLVM_LTO = YES;
OTHER_CFLAGS = ""; OTHER_CFLAGS = "";
"OTHER_CFLAGS[arch=x86_64]" = "-fobjc-legacy-dispatch"; "OTHER_CFLAGS[arch=x86_64]" = "-fobjc-legacy-dispatch";
OTHER_CPLUSPLUSFLAGS = ( OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)", "$(OTHER_CFLAGS)",
"-D_LIBCPP_VISIBLE=\"\"", "-D_LIBCPP_VISIBLE=\"\"",
); );
SDKROOT = macosx.internal;
SUPPORTED_PLATFORMS = "macosx iphoneos appletvos watchos";
WARNING_CFLAGS = ( WARNING_CFLAGS = (
"-Wall", "-Wall",
"-Wextra", "-Wextra",
@ -730,12 +950,11 @@
1DEB915008733D8E0010E9CD /* Release */ = { 1DEB915008733D8E0010E9CD /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_LINK_OBJC_RUNTIME = NO; CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_OBJC_RUNTIME = NO; CLANG_OBJC_RUNTIME = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
EXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS = "$(inherited) test";
GCC_ENABLE_CPP_EXCEPTIONS = NO; GCC_ENABLE_CPP_EXCEPTIONS = NO;
GCC_ENABLE_CPP_RTTI = NO; GCC_ENABLE_CPP_RTTI = NO;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
@ -752,7 +971,8 @@
GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_SHADOW = YES; GCC_WARN_SHADOW = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
"OTHER_CFLAGS[arch=i386]" = "-momit-leaf-frame-pointer"; LLVM_LTO = YES;
OTHER_CFLAGS = "-momit-leaf-frame-pointer";
"OTHER_CFLAGS[arch=x86_64]" = ( "OTHER_CFLAGS[arch=x86_64]" = (
"-momit-leaf-frame-pointer", "-momit-leaf-frame-pointer",
"-fobjc-legacy-dispatch", "-fobjc-legacy-dispatch",
@ -761,6 +981,8 @@
"$(OTHER_CFLAGS)", "$(OTHER_CFLAGS)",
"-D_LIBCPP_VISIBLE=\"\"", "-D_LIBCPP_VISIBLE=\"\"",
); );
SDKROOT = macosx.internal;
SUPPORTED_PLATFORMS = "macosx iphoneos appletvos watchos";
WARNING_CFLAGS = ( WARNING_CFLAGS = (
"-Wall", "-Wall",
"-Wextra", "-Wextra",
@ -773,6 +995,24 @@
}; };
name = Release; name = Release;
}; };
834F9B02212E560200F95A54 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 59GAB85EFG;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
834F9B03212E560200F95A54 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 59GAB85EFG;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
837F67AA1A771F63004D34FA /* Debug */ = { 837F67AA1A771F63004D34FA /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
@ -787,6 +1027,78 @@
}; };
name = Release; name = Release;
}; };
F9BCC725205C68E800DD9AFC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_HEADERS_RUN_UNIFDEF = YES;
COPY_HEADERS_UNIFDEF_FLAGS = "-UBUILD_FOR_OSX";
"COPY_HEADERS_UNIFDEF_FLAGS[sdk=macosx*]" = "-DBUILD_FOR_OSX";
COPY_PHASE_STRIP = NO;
DYLIB_CURRENT_VERSION = 228;
EXECUTABLE_PREFIX = lib;
GCC_CW_ASM_SYNTAX = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
HEADER_SEARCH_PATHS = (
"$(DSTROOT)/usr/include/**",
"$(DSTROOT)/usr/local/include/**",
"$(CONFIGURATION_BUILD_DIR)/usr/include/**",
"$(CONFIGURATION_BUILD_DIR)/usr/local/include/**",
/System/Library/Frameworks/System.framework/PrivateHeaders,
);
INSTALL_PATH = /usr/lib;
IS_ZIPPERED = YES;
OTHER_CFLAGS = (
"-fdollars-in-identifiers",
"$(OTHER_CFLAGS)",
);
OTHER_LDFLAGS = (
"-Xlinker",
"-not_for_dyld_shared_cache",
);
PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/objc;
PRODUCT_NAME = "$(TARGET_NAME)";
PUBLIC_HEADERS_FOLDER_PATH = /usr/include/objc;
SUPPORTS_TEXT_BASED_API = YES;
TAPI_VERIFY_MODE = Pedantic;
};
name = Debug;
};
F9BCC726205C68E800DD9AFC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_HEADERS_RUN_UNIFDEF = YES;
COPY_HEADERS_UNIFDEF_FLAGS = "-UBUILD_FOR_OSX";
"COPY_HEADERS_UNIFDEF_FLAGS[sdk=macosx*]" = "-DBUILD_FOR_OSX";
DYLIB_CURRENT_VERSION = 228;
EXECUTABLE_PREFIX = lib;
GCC_CW_ASM_SYNTAX = NO;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
HEADER_SEARCH_PATHS = (
"$(DSTROOT)/usr/include/**",
"$(DSTROOT)/usr/local/include/**",
"$(CONFIGURATION_BUILD_DIR)/usr/include/**",
"$(CONFIGURATION_BUILD_DIR)/usr/local/include/**",
/System/Library/Frameworks/System.framework/PrivateHeaders,
);
INSTALL_PATH = /usr/lib;
IS_ZIPPERED = YES;
OTHER_CFLAGS = (
"-fdollars-in-identifiers",
"$(OTHER_CFLAGS)",
);
OTHER_LDFLAGS = (
"-Xlinker",
"-not_for_dyld_shared_cache",
);
PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/objc;
PRODUCT_NAME = "$(TARGET_NAME)";
PUBLIC_HEADERS_FOLDER_PATH = /usr/include/objc;
SUPPORTS_TEXT_BASED_API = YES;
TAPI_VERIFY_MODE = Pedantic;
};
name = Release;
};
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
@ -808,6 +1120,15 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
834F9B04212E560200F95A54 /* Build configuration list for PBXAggregateTarget "objc4_tests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
834F9B02212E560200F95A54 /* Debug */,
834F9B03212E560200F95A54 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
837F67A91A771F63004D34FA /* Build configuration list for PBXAggregateTarget "objc-simulator" */ = { 837F67A91A771F63004D34FA /* Build configuration list for PBXAggregateTarget "objc-simulator" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
@ -817,6 +1138,15 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
F9BCC724205C68E800DD9AFC /* Build configuration list for PBXNativeTarget "objc-trampolines" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F9BCC725205C68E800DD9AFC /* Debug */,
F9BCC726205C68E800DD9AFC /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */ /* End XCConfigurationList section */
}; };
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;

0
objcrt/objcrt.vcproj Executable file → Normal file
View File

0
prebuild.bat Executable file → Normal file
View File

86
runtime/DenseMapExtras.h Normal file
View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2019 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 DENSEMAPEXTRAS_H
#define DENSEMAPEXTRAS_H
#include "llvm-DenseMap.h"
#include "llvm-DenseSet.h"
namespace objc {
// We cannot use a C++ static initializer to initialize certain globals because
// libc calls us before our C++ initializers run. We also don't want a global
// pointer to some globals because of the extra indirection.
//
// ExplicitInit / LazyInit wrap doing it the hard way.
template <typename Type>
class ExplicitInit {
alignas(Type) uint8_t _storage[sizeof(Type)];
public:
template <typename... Ts>
void init(Ts &&... Args) {
new (_storage) Type(std::forward<Ts>(Args)...);
}
Type &get() {
return *reinterpret_cast<Type *>(_storage);
}
};
template <typename Type>
class LazyInit {
alignas(Type) uint8_t _storage[sizeof(Type)];
bool _didInit;
public:
template <typename... Ts>
Type *get(bool allowCreate, Ts &&... Args) {
if (!_didInit) {
if (!allowCreate) {
return nullptr;
}
new (_storage) Type(std::forward<Ts>(Args)...);
_didInit = true;
}
return reinterpret_cast<Type *>(_storage);
}
};
// Convenience class for Dense Maps & Sets
template <typename Key, typename Value>
class ExplicitInitDenseMap : public ExplicitInit<DenseMap<Key, Value>> { };
template <typename Key, typename Value>
class LazyInitDenseMap : public LazyInit<DenseMap<Key, Value>> { };
template <typename Value>
class ExplicitInitDenseSet : public ExplicitInit<DenseSet<Value>> { };
template <typename Value>
class LazyInitDenseSet : public LazyInit<DenseSet<Value>> { };
} // namespace objc
#endif /* DENSEMAPEXTRAS_H */

View File

@ -29,6 +29,8 @@
#ifdef __arm__ #ifdef __arm__
#include <arm/arch.h> #include <arm/arch.h>
#include "objc-config.h"
#include "isa.h"
#ifndef _ARM_ARCH_7 #ifndef _ARM_ARCH_7
# error requires armv7 # error requires armv7
@ -67,25 +69,6 @@
#endif #endif
// Define SUPPORT_INDEXED_ISA for targets which store the class in the ISA as
// an index in to a class table.
// Note, keep this in sync with objc-config.h.
// FIXME: Remove this duplication. We should get this from objc-config.h.
#if __ARM_ARCH_7K__ >= 2
# define SUPPORT_INDEXED_ISA 1
#else
# define SUPPORT_INDEXED_ISA 0
#endif
// Note, keep these in sync with objc-private.h
#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
.syntax unified .syntax unified
#define MI_EXTERN(var) \ #define MI_EXTERN(var) \
@ -119,98 +102,35 @@ _objc_indexed_classes:
// _objc_entryPoints and _objc_exitPoints are used by method dispatch // _objc_restartableRanges is used by method dispatch
// caching code to figure out whether any threads are actively // caching code to figure out whether any threads are actively
// in the cache for dispatching. The labels surround the asm code // in the cache for dispatching. The labels surround the asm code
// that do cache lookups. The tables are zero-terminated. // that do cache lookups. The tables are zero-terminated.
.align 2 .macro RestartableEntry
.private_extern _objc_entryPoints .long LLookupStart$0
_objc_entryPoints: .long 0
.long _cache_getImp .short LLookupEnd$0 - LLookupStart$0
.long _objc_msgSend .short 0xffff // poor ol' armv7 doesn't support kernel based recovery
.long _objc_msgSend_stret .long 0
.long _objc_msgSendSuper
.long _objc_msgSendSuper_stret
.long _objc_msgSendSuper2
.long _objc_msgSendSuper2_stret
.long _objc_msgLookup
.long _objc_msgLookup_stret
.long _objc_msgLookupSuper2
.long _objc_msgLookupSuper2_stret
.long 0
.private_extern _objc_exitPoints
_objc_exitPoints:
.long LExit_cache_getImp
.long LExit_objc_msgSend
.long LExit_objc_msgSend_stret
.long LExit_objc_msgSendSuper
.long LExit_objc_msgSendSuper_stret
.long LExit_objc_msgSendSuper2
.long LExit_objc_msgSendSuper2_stret
.long LExit_objc_msgLookup
.long LExit_objc_msgLookup_stret
.long LExit_objc_msgLookupSuper2
.long LExit_objc_msgLookupSuper2_stret
.long 0
/********************************************************************
* List every exit insn from every messenger for debugger use.
* Format:
* (
* 1 word instruction's address
* 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
* )
* 1 word zero
*
* ENTER is the start of a dispatcher
* FAST_EXIT is method dispatch
* SLOW_EXIT is uncached method lookup
* NIL_EXIT is returning zero from a message sent to nil
* These must match objc-gdb.h.
********************************************************************/
#define ENTER 1
#define FAST_EXIT 2
#define SLOW_EXIT 3
#define NIL_EXIT 4
.section __DATA,__objc_msg_break
.globl _gdb_objc_messenger_breakpoints
_gdb_objc_messenger_breakpoints:
// contents populated by the macros below
.macro MESSENGER_START
7:
.section __DATA,__objc_msg_break
.long 7b
.long ENTER
.text
.endmacro
.macro MESSENGER_END_FAST
7:
.section __DATA,__objc_msg_break
.long 7b
.long FAST_EXIT
.text
.endmacro
.macro MESSENGER_END_SLOW
7:
.section __DATA,__objc_msg_break
.long 7b
.long SLOW_EXIT
.text
.endmacro
.macro MESSENGER_END_NIL
7:
.section __DATA,__objc_msg_break
.long 7b
.long NIL_EXIT
.text
.endmacro .endmacro
.align 4
.private_extern _objc_restartableRanges
_objc_restartableRanges:
RestartableEntry _cache_getImp
RestartableEntry _objc_msgSend
RestartableEntry _objc_msgSend_stret
RestartableEntry _objc_msgSendSuper
RestartableEntry _objc_msgSendSuper_stret
RestartableEntry _objc_msgSendSuper2
RestartableEntry _objc_msgSendSuper2_stret
RestartableEntry _objc_msgLookup
RestartableEntry _objc_msgLookup_stret
RestartableEntry _objc_msgLookupSuper2
RestartableEntry _objc_msgLookupSuper2_stret
.fill 16, 1, 0
/******************************************************************** /********************************************************************
* Names for relative labels * Names for relative labels
@ -218,7 +138,7 @@ _gdb_objc_messenger_breakpoints:
* Reserved labels: 6: 7: 8: 9: * Reserved labels: 6: 7: 8: 9:
********************************************************************/ ********************************************************************/
// 6: used by CacheLookup // 6: used by CacheLookup
// 7: used by MI_GET_ADDRESS etc and MESSENGER_START etc // 7: used by MI_GET_ADDRESS etc
// 8: used by CacheLookup // 8: used by CacheLookup
#define LNilReceiver 9 #define LNilReceiver 9
#define LNilReceiver_f 9f #define LNilReceiver_f 9f
@ -249,6 +169,10 @@ _gdb_objc_messenger_breakpoints:
#define CACHE 8 #define CACHE 8
#define CACHE_MASK 12 #define CACHE_MASK 12
/* Field offsets in method cache bucket */
#define CACHED_SEL 0
#define CACHED_IMP 4
/* Selected field offsets in method structure */ /* Selected field offsets in method structure */
#define METHOD_NAME 0 #define METHOD_NAME 0
#define METHOD_TYPES 4 #define METHOD_TYPES 4
@ -300,8 +224,8 @@ LExit$0:
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// //
// CacheLookup NORMAL|STRET // CacheLookup NORMAL|STRET <function>
// CacheLookup2 NORMAL|STRET // CacheLookup2 NORMAL|STRET <function>
// //
// Locate the implementation for a selector in a class's method cache. // Locate the implementation for a selector in a class's method cache.
// //
@ -318,6 +242,31 @@ LExit$0:
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
.macro CacheLookup .macro CacheLookup
//
// Restart protocol:
//
// As soon as we're past the LLookupStart$1 label we may have loaded
// an invalid cache pointer or mask.
//
// When task_restartable_ranges_synchronize() is called,
// (or when a signal hits us) before we're past LLookupEnd$1,
// then our PC will be reset to LCacheMiss$1 which forcefully
// jumps to the cache-miss codepath.
//
// It is assumed that the CacheMiss codepath starts right at the end
// of CacheLookup2 and will re-setup the registers to meet the cache-miss
// requirements:
//
// GETIMP:
// The cache-miss is just returning NULL (setting r9 to 0)
//
// NORMAL and STRET:
// - r0 or r1 (STRET) contains the receiver
// - r1 or r2 (STRET) contains the selector
// - r9 contains the isa (reloaded from r0/r1)
// - other registers are set as per calling conventions
//
LLookupStart$1:
ldrh r12, [r9, #CACHE_MASK] // r12 = mask ldrh r12, [r9, #CACHE_MASK] // r12 = mask
ldr r9, [r9, #CACHE] // r9 = buckets ldr r9, [r9, #CACHE] // r9 = buckets
@ -327,7 +276,7 @@ LExit$0:
and r12, r12, r1 // r12 = index = SEL & mask and r12, r12, r1 // r12 = index = SEL & mask
.endif .endif
add r9, r9, r12, LSL #3 // r9 = bucket = buckets+index*8 add r9, r9, r12, LSL #3 // r9 = bucket = buckets+index*8
ldr r12, [r9] // r12 = bucket->sel ldr r12, [r9, #CACHED_SEL] // r12 = bucket->sel
6: 6:
.if $0 == STRET .if $0 == STRET
teq r12, r2 teq r12, r2
@ -335,7 +284,7 @@ LExit$0:
teq r12, r1 teq r12, r1
.endif .endif
bne 8f bne 8f
ldr r12, [r9, #4] // r12 = bucket->imp ldr r12, [r9, #CACHED_IMP] // r12 = bucket->imp
.if $0 == STRET .if $0 == STRET
tst r12, r12 // set ne for stret forwarding tst r12, r12 // set ne for stret forwarding
@ -346,15 +295,19 @@ LExit$0:
.endmacro .endmacro
.macro CacheLookup2 .macro CacheLookup2
#if CACHED_SEL != 0
# error this code requires that SEL be at offset 0
#endif
8: 8:
cmp r12, #1 cmp r12, #1
blo 8f // if (bucket->sel == 0) cache miss blo LCacheMiss$1 // if (bucket->sel == 0) cache miss
it eq // if (bucket->sel == 1) cache wrap it eq // if (bucket->sel == 1) cache wrap
ldreq r9, [r9, #4] // bucket->imp is before first bucket ldreq r9, [r9, #CACHED_IMP] // bucket->imp is before first bucket
ldr r12, [r9, #8]! // r12 = (++bucket)->sel ldr r12, [r9, #8]! // r12 = (++bucket)->sel
b 6b b 6b
8:
LLookupEnd$1:
LCacheMiss$1:
.endmacro .endmacro
@ -377,7 +330,7 @@ LExit$0:
// Note: We are doing a little wasted work here to load values we might not // Note: We are doing a little wasted work here to load values we might not
// need. Branching turns out to be even worse when performance was measured. // need. Branching turns out to be even worse when performance was measured.
MI_GET_ADDRESS(r12, _objc_indexed_classes) MI_GET_ADDRESS(r12, _objc_indexed_classes)
tst.w r9, #ISA_INDEX_IS_NPI tst.w r9, #ISA_INDEX_IS_NPI_MASK
itt ne itt ne
ubfxne r9, r9, #ISA_INDEX_SHIFT, #ISA_INDEX_BITS ubfxne r9, r9, #ISA_INDEX_SHIFT, #ISA_INDEX_BITS
ldrne.w r9, [r12, r9, lsl #2] ldrne.w r9, [r12, r9, lsl #2]
@ -399,12 +352,12 @@ LExit$0:
STATIC_ENTRY _cache_getImp STATIC_ENTRY _cache_getImp
mov r9, r0 mov r9, r0
CacheLookup NORMAL CacheLookup NORMAL, _cache_getImp
// cache hit, IMP in r12 // cache hit, IMP in r12
mov r0, r12 mov r0, r12
bx lr // return imp bx lr // return imp
CacheLookup2 GETIMP CacheLookup2 GETIMP, _cache_getImp
// cache miss, return nil // cache miss, return nil
mov r0, #0 mov r0, #0
bx lr bx lr
@ -425,22 +378,19 @@ LExit$0:
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSend ENTRY _objc_msgSend
MESSENGER_START
cbz r0, LNilReceiver_f cbz r0, LNilReceiver_f
ldr r9, [r0] // r9 = self->isa ldr r9, [r0] // r9 = self->isa
GetClassFromIsa // r9 = class GetClassFromIsa // r9 = class
CacheLookup NORMAL CacheLookup NORMAL, _objc_msgSend
// cache hit, IMP in r12, eq already set for nonstret forwarding // cache hit, IMP in r12, eq already set for nonstret forwarding
MESSENGER_END_FAST
bx r12 // call imp bx r12 // call imp
CacheLookup2 NORMAL CacheLookup2 NORMAL, _objc_msgSend
// cache miss // cache miss
ldr r9, [r0] // r9 = self->isa ldr r9, [r0] // r9 = self->isa
GetClassFromIsa // r9 = class GetClassFromIsa // r9 = class
MESSENGER_END_SLOW
b __objc_msgSend_uncached b __objc_msgSend_uncached
LNilReceiver: LNilReceiver:
@ -449,7 +399,6 @@ LNilReceiver:
mov r2, #0 mov r2, #0
mov r3, #0 mov r3, #0
FP_RETURN_ZERO FP_RETURN_ZERO
MESSENGER_END_NIL
bx lr bx lr
END_ENTRY _objc_msgSend END_ENTRY _objc_msgSend
@ -461,11 +410,11 @@ LNilReceiver:
ldr r9, [r0] // r9 = self->isa ldr r9, [r0] // r9 = self->isa
GetClassFromIsa // r9 = class GetClassFromIsa // r9 = class
CacheLookup NORMAL CacheLookup NORMAL, _objc_msgLookup
// cache hit, IMP in r12, eq already set for nonstret forwarding // cache hit, IMP in r12, eq already set for nonstret forwarding
bx lr bx lr
CacheLookup2 NORMAL CacheLookup2 NORMAL, _objc_msgLookup
// cache miss // cache miss
ldr r9, [r0] // r9 = self->isa ldr r9, [r0] // r9 = self->isa
GetClassFromIsa // r9 = class GetClassFromIsa // r9 = class
@ -504,26 +453,22 @@ LNilReceiver:
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSend_stret ENTRY _objc_msgSend_stret
MESSENGER_START
cbz r1, LNilReceiver_f cbz r1, LNilReceiver_f
ldr r9, [r1] // r9 = self->isa ldr r9, [r1] // r9 = self->isa
GetClassFromIsa // r9 = class GetClassFromIsa // r9 = class
CacheLookup STRET CacheLookup STRET, _objc_msgSend_stret
// cache hit, IMP in r12, ne already set for stret forwarding // cache hit, IMP in r12, ne already set for stret forwarding
MESSENGER_END_FAST
bx r12 bx r12
CacheLookup2 STRET CacheLookup2 STRET, _objc_msgSend_stret
// cache miss // cache miss
ldr r9, [r1] // r9 = self->isa ldr r9, [r1] // r9 = self->isa
GetClassFromIsa // r9 = class GetClassFromIsa // r9 = class
MESSENGER_END_SLOW
b __objc_msgSend_stret_uncached b __objc_msgSend_stret_uncached
LNilReceiver: LNilReceiver:
MESSENGER_END_NIL
bx lr bx lr
END_ENTRY _objc_msgSend_stret END_ENTRY _objc_msgSend_stret
@ -535,11 +480,11 @@ LNilReceiver:
ldr r9, [r1] // r9 = self->isa ldr r9, [r1] // r9 = self->isa
GetClassFromIsa // r9 = class GetClassFromIsa // r9 = class
CacheLookup STRET CacheLookup STRET, _objc_msgLookup_stret
// cache hit, IMP in r12, ne already set for stret forwarding // cache hit, IMP in r12, ne already set for stret forwarding
bx lr bx lr
CacheLookup2 STRET CacheLookup2 STRET, _objc_msgLookup_stret
// cache miss // cache miss
ldr r9, [r1] // r9 = self->isa ldr r9, [r1] // r9 = self->isa
GetClassFromIsa // r9 = class GetClassFromIsa // r9 = class
@ -569,20 +514,17 @@ LNilReceiver:
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSendSuper ENTRY _objc_msgSendSuper
MESSENGER_START
ldr r9, [r0, #CLASS] // r9 = struct super->class ldr r9, [r0, #CLASS] // r9 = struct super->class
CacheLookup NORMAL CacheLookup NORMAL, _objc_msgSendSuper
// cache hit, IMP in r12, eq already set for nonstret forwarding // cache hit, IMP in r12, eq already set for nonstret forwarding
ldr r0, [r0, #RECEIVER] // load real receiver ldr r0, [r0, #RECEIVER] // load real receiver
MESSENGER_END_FAST
bx r12 // call imp bx r12 // call imp
CacheLookup2 NORMAL CacheLookup2 NORMAL, _objc_msgSendSuper
// cache miss // cache miss
ldr r9, [r0, #CLASS] // r9 = struct super->class ldr r9, [r0, #CLASS] // r9 = struct super->class
ldr r0, [r0, #RECEIVER] // load real receiver ldr r0, [r0, #RECEIVER] // load real receiver
MESSENGER_END_SLOW
b __objc_msgSend_uncached b __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper END_ENTRY _objc_msgSendSuper
@ -598,22 +540,19 @@ LNilReceiver:
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSendSuper2 ENTRY _objc_msgSendSuper2
MESSENGER_START
ldr r9, [r0, #CLASS] // class = struct super->class ldr r9, [r0, #CLASS] // class = struct super->class
ldr r9, [r9, #SUPERCLASS] // class = class->superclass ldr r9, [r9, #SUPERCLASS] // class = class->superclass
CacheLookup NORMAL CacheLookup NORMAL, _objc_msgSendSuper2
// cache hit, IMP in r12, eq already set for nonstret forwarding // cache hit, IMP in r12, eq already set for nonstret forwarding
ldr r0, [r0, #RECEIVER] // load real receiver ldr r0, [r0, #RECEIVER] // load real receiver
MESSENGER_END_FAST
bx r12 // call imp bx r12 // call imp
CacheLookup2 NORMAL CacheLookup2 NORMAL, _objc_msgSendSuper2
// cache miss // cache miss
ldr r9, [r0, #CLASS] // class = struct super->class ldr r9, [r0, #CLASS] // class = struct super->class
ldr r9, [r9, #SUPERCLASS] // class = class->superclass ldr r9, [r9, #SUPERCLASS] // class = class->superclass
ldr r0, [r0, #RECEIVER] // load real receiver ldr r0, [r0, #RECEIVER] // load real receiver
MESSENGER_END_SLOW
b __objc_msgSend_uncached b __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper2 END_ENTRY _objc_msgSendSuper2
@ -623,12 +562,12 @@ LNilReceiver:
ldr r9, [r0, #CLASS] // class = struct super->class ldr r9, [r0, #CLASS] // class = struct super->class
ldr r9, [r9, #SUPERCLASS] // class = class->superclass ldr r9, [r9, #SUPERCLASS] // class = class->superclass
CacheLookup NORMAL CacheLookup NORMAL, _objc_msgLookupSuper2
// cache hit, IMP in r12, eq already set for nonstret forwarding // cache hit, IMP in r12, eq already set for nonstret forwarding
ldr r0, [r0, #RECEIVER] // load real receiver ldr r0, [r0, #RECEIVER] // load real receiver
bx lr bx lr
CacheLookup2 NORMAL CacheLookup2 NORMAL, _objc_msgLookupSuper2
// cache miss // cache miss
ldr r9, [r0, #CLASS] ldr r9, [r0, #CLASS]
ldr r9, [r9, #SUPERCLASS] // r9 = class to search ldr r9, [r9, #SUPERCLASS] // r9 = class to search
@ -651,20 +590,17 @@ LNilReceiver:
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSendSuper_stret ENTRY _objc_msgSendSuper_stret
MESSENGER_START
ldr r9, [r1, #CLASS] // r9 = struct super->class ldr r9, [r1, #CLASS] // r9 = struct super->class
CacheLookup STRET CacheLookup STRET, _objc_msgSendSuper_stret
// cache hit, IMP in r12, ne already set for stret forwarding // cache hit, IMP in r12, ne already set for stret forwarding
ldr r1, [r1, #RECEIVER] // load real receiver ldr r1, [r1, #RECEIVER] // load real receiver
MESSENGER_END_FAST
bx r12 // call imp bx r12 // call imp
CacheLookup2 STRET CacheLookup2 STRET, _objc_msgSendSuper_stret
// cache miss // cache miss
ldr r9, [r1, #CLASS] // r9 = struct super->class ldr r9, [r1, #CLASS] // r9 = struct super->class
ldr r1, [r1, #RECEIVER] // load real receiver ldr r1, [r1, #RECEIVER] // load real receiver
MESSENGER_END_SLOW
b __objc_msgSend_stret_uncached b __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSendSuper_stret END_ENTRY _objc_msgSendSuper_stret
@ -675,22 +611,19 @@ LNilReceiver:
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSendSuper2_stret ENTRY _objc_msgSendSuper2_stret
MESSENGER_START
ldr r9, [r1, #CLASS] // class = struct super->class ldr r9, [r1, #CLASS] // class = struct super->class
ldr r9, [r9, #SUPERCLASS] // class = class->superclass ldr r9, [r9, #SUPERCLASS] // class = class->superclass
CacheLookup STRET CacheLookup STRET, _objc_msgSendSuper2_stret
// cache hit, IMP in r12, ne already set for stret forwarding // cache hit, IMP in r12, ne already set for stret forwarding
ldr r1, [r1, #RECEIVER] // load real receiver ldr r1, [r1, #RECEIVER] // load real receiver
MESSENGER_END_FAST
bx r12 // call imp bx r12 // call imp
CacheLookup2 STRET CacheLookup2 STRET, _objc_msgSendSuper2_stret
// cache miss // cache miss
ldr r9, [r1, #CLASS] // class = struct super->class ldr r9, [r1, #CLASS] // class = struct super->class
ldr r9, [r9, #SUPERCLASS] // class = class->superclass ldr r9, [r9, #SUPERCLASS] // class = class->superclass
ldr r1, [r1, #RECEIVER] // load real receiver ldr r1, [r1, #RECEIVER] // load real receiver
MESSENGER_END_SLOW
b __objc_msgSend_stret_uncached b __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSendSuper2_stret END_ENTRY _objc_msgSendSuper2_stret
@ -700,12 +633,12 @@ LNilReceiver:
ldr r9, [r1, #CLASS] // class = struct super->class ldr r9, [r1, #CLASS] // class = struct super->class
ldr r9, [r9, #SUPERCLASS] // class = class->superclass ldr r9, [r9, #SUPERCLASS] // class = class->superclass
CacheLookup STRET CacheLookup STRET, _objc_msgLookupSuper2_stret
// cache hit, IMP in r12, ne already set for stret forwarding // cache hit, IMP in r12, ne already set for stret forwarding
ldr r1, [r1, #RECEIVER] // load real receiver ldr r1, [r1, #RECEIVER] // load real receiver
bx lr bx lr
CacheLookup2 STRET CacheLookup2 STRET, _objc_msgLookupSuper2_stret
// cache miss // cache miss
ldr r9, [r1, #CLASS] ldr r9, [r1, #CLASS]
ldr r9, [r9, #SUPERCLASS] // r9 = class to search ldr r9, [r9, #SUPERCLASS] // r9 = class to search
@ -738,6 +671,7 @@ LNilReceiver:
sub sp, #8 // align stack sub sp, #8 // align stack
FP_SAVE FP_SAVE
// lookUpImpOrForward(obj, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER)
.if $0 == NORMAL .if $0 == NORMAL
// receiver already in r0 // receiver already in r0
// selector already in r1 // selector already in r1
@ -746,8 +680,8 @@ LNilReceiver:
mov r1, r2 // selector mov r1, r2 // selector
.endif .endif
mov r2, r9 // class to search mov r2, r9 // class to search
mov r3, #3 // LOOKUP_INITIALIZE | LOOKUP_INITIALIZE
blx __class_lookupMethodAndLoadCache3 blx _lookUpImpOrForward
mov r12, r0 // r12 = IMP mov r12, r0 // r12 = IMP
.if $0 == NORMAL .if $0 == NORMAL
@ -837,10 +771,6 @@ LNilReceiver:
// THIS IS NOT A CALLABLE C FUNCTION // THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band Z is 0 (EQ) for normal, 1 (NE) for stret // Out-of-band Z is 0 (EQ) for normal, 1 (NE) for stret
MESSENGER_START
nop
MESSENGER_END_SLOW
beq __objc_msgForward beq __objc_msgForward
b __objc_msgForward_stret b __objc_msgForward_stret

382
runtime/Messengers.subproj/objc-msg-arm64.S Executable file → Normal file
View File

@ -29,108 +29,100 @@
#ifdef __arm64__ #ifdef __arm64__
#include <arm/arch.h> #include <arm/arch.h>
#include "isa.h"
#include "arm64-asm.h"
#include "objc-config.h"
.data .data
// _objc_entryPoints and _objc_exitPoints are used by method dispatch // _objc_restartableRanges is used by method dispatch
// caching code to figure out whether any threads are actively // caching code to figure out whether any threads are actively
// in the cache for dispatching. The labels surround the asm code // in the cache for dispatching. The labels surround the asm code
// that do cache lookups. The tables are zero-terminated. // that do cache lookups. The tables are zero-terminated.
.align 4 .macro RestartableEntry
.private_extern _objc_entryPoints #if __LP64__
_objc_entryPoints: .quad LLookupStart$0
.quad _cache_getImp #else
.quad _objc_msgSend .long LLookupStart$0
.quad _objc_msgSendSuper .long 0
.quad _objc_msgSendSuper2 #endif
.quad _objc_msgLookup .short LLookupEnd$0 - LLookupStart$0
.quad _objc_msgLookupSuper2 .short LLookupRecover$0 - LLookupStart$0
.quad 0 .long 0
.private_extern _objc_exitPoints
_objc_exitPoints:
.quad LExit_cache_getImp
.quad LExit_objc_msgSend
.quad LExit_objc_msgSendSuper
.quad LExit_objc_msgSendSuper2
.quad LExit_objc_msgLookup
.quad LExit_objc_msgLookupSuper2
.quad 0
/********************************************************************
* List every exit insn from every messenger for debugger use.
* Format:
* (
* 1 word instruction's address
* 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
* )
* 1 word zero
*
* ENTER is the start of a dispatcher
* FAST_EXIT is method dispatch
* SLOW_EXIT is uncached method lookup
* NIL_EXIT is returning zero from a message sent to nil
* These must match objc-gdb.h.
********************************************************************/
#define ENTER 1
#define FAST_EXIT 2
#define SLOW_EXIT 3
#define NIL_EXIT 4
.section __DATA,__objc_msg_break
.globl _gdb_objc_messenger_breakpoints
_gdb_objc_messenger_breakpoints:
// contents populated by the macros below
.macro MESSENGER_START
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad ENTER
.text
.endmacro
.macro MESSENGER_END_FAST
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad FAST_EXIT
.text
.endmacro
.macro MESSENGER_END_SLOW
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad SLOW_EXIT
.text
.endmacro
.macro MESSENGER_END_NIL
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad NIL_EXIT
.text
.endmacro .endmacro
.align 4
.private_extern _objc_restartableRanges
_objc_restartableRanges:
RestartableEntry _cache_getImp
RestartableEntry _objc_msgSend
RestartableEntry _objc_msgSendSuper
RestartableEntry _objc_msgSendSuper2
RestartableEntry _objc_msgLookup
RestartableEntry _objc_msgLookupSuper2
.fill 16, 1, 0
/* objc_super parameter to sendSuper */ /* objc_super parameter to sendSuper */
#define RECEIVER 0 #define RECEIVER 0
#define CLASS 8 #define CLASS __SIZEOF_POINTER__
/* Selected field offsets in class structure */ /* Selected field offsets in class structure */
#define SUPERCLASS 8 #define SUPERCLASS __SIZEOF_POINTER__
#define CACHE 16 #define CACHE (2 * __SIZEOF_POINTER__)
/* Selected field offsets in isa field */
#define ISA_MASK 0x0000000ffffffff8
/* Selected field offsets in method structure */ /* Selected field offsets in method structure */
#define METHOD_NAME 0 #define METHOD_NAME 0
#define METHOD_TYPES 8 #define METHOD_TYPES __SIZEOF_POINTER__
#define METHOD_IMP 16 #define METHOD_IMP (2 * __SIZEOF_POINTER__)
#define BUCKET_SIZE (2 * __SIZEOF_POINTER__)
/********************************************************************
* GetClassFromIsa_p16 src
* src is a raw isa field. Sets p16 to the corresponding class pointer.
* The raw isa might be an indexed isa to be decoded, or a
* packed isa that needs to be masked.
*
* On exit:
* $0 is unchanged
* p16 is a class pointer
* x10 is clobbered
********************************************************************/
#if SUPPORT_INDEXED_ISA
.align 3
.globl _objc_indexed_classes
_objc_indexed_classes:
.fill ISA_INDEX_COUNT, PTRSIZE, 0
#endif
.macro GetClassFromIsa_p16 /* src */
#if SUPPORT_INDEXED_ISA
// Indexed isa
mov p16, $0 // optimistically set dst = src
tbz p16, #ISA_INDEX_IS_NPI_BIT, 1f // done if not non-pointer isa
// isa in p16 is indexed
adrp x10, _objc_indexed_classes@PAGE
add x10, x10, _objc_indexed_classes@PAGEOFF
ubfx p16, p16, #ISA_INDEX_SHIFT, #ISA_INDEX_BITS // extract index
ldr p16, [x10, p16, UXTP #PTRSHIFT] // load class from array
1:
#elif __LP64__
// 64-bit packed isa
and p16, $0, #ISA_MASK
#else
// 32-bit raw isa
mov p16, $0
#endif
.endmacro
/******************************************************************** /********************************************************************
@ -164,12 +156,12 @@ LExit$0:
********************************************************************/ ********************************************************************/
.macro UNWIND .macro UNWIND
.section __LD,__compact_unwind,regular,debug .section __LD,__compact_unwind,regular,debug
.quad $0 PTR $0
.set LUnwind$0, LExit$0 - $0 .set LUnwind$0, LExit$0 - $0
.long LUnwind$0 .long LUnwind$0
.long $1 .long $1
.quad 0 /* no personality */ PTR 0 /* no personality */
.quad 0 /* no LSDA */ PTR 0 /* no LSDA */
.text .text
.endmacro .endmacro
@ -179,10 +171,15 @@ LExit$0:
/******************************************************************** /********************************************************************
* *
* CacheLookup NORMAL|GETIMP|LOOKUP * CacheLookup NORMAL|GETIMP|LOOKUP <function>
* *
* Locate the implementation for a selector in a class method cache. * Locate the implementation for a selector in a class method cache.
* *
* When this is used in a function that doesn't hold the runtime lock,
* this represents the critical section that may access dead memory.
* If the kernel causes one of these functions to go down the recovery
* path, we pretend the lookup failed by jumping the JumpMiss branch.
*
* Takes: * Takes:
* x1 = selector * x1 = selector
* x16 = class to be searched * x16 = class to be searched
@ -200,14 +197,19 @@ LExit$0:
#define GETIMP 1 #define GETIMP 1
#define LOOKUP 2 #define LOOKUP 2
// CacheHit: x17 = cached IMP, x12 = address of cached IMP, x1 = SEL, x16 = isa
.macro CacheHit .macro CacheHit
.if $0 == NORMAL .if $0 == NORMAL
MESSENGER_END_FAST TailCallCachedImp x17, x12, x1, x16 // authenticate and call imp
br x17 // call imp
.elseif $0 == GETIMP .elseif $0 == GETIMP
mov x0, x17 // return imp mov p0, p17
ret cbz p0, 9f // don't ptrauth a nil imp
AuthAndResignAsIMP x0, x12, x1, x16 // authenticate imp and re-sign as IMP
9: ret // return IMP
.elseif $0 == LOOKUP .elseif $0 == LOOKUP
// No nil check for ptrauth: the caller would crash anyway when they
// jump to a nil IMP. We don't care if that jump also fails ptrauth.
AuthAndResignAsIMP x17, x12, x1, x16 // authenticate imp and re-sign as IMP
ret // return imp via x17 ret // return imp via x17
.else .else
.abort oops .abort oops
@ -217,11 +219,11 @@ LExit$0:
.macro CheckMiss .macro CheckMiss
// miss if bucket->sel == 0 // miss if bucket->sel == 0
.if $0 == GETIMP .if $0 == GETIMP
cbz x9, LGetImpMiss cbz p9, LGetImpMiss
.elseif $0 == NORMAL .elseif $0 == NORMAL
cbz x9, __objc_msgSend_uncached cbz p9, __objc_msgSend_uncached
.elseif $0 == LOOKUP .elseif $0 == LOOKUP
cbz x9, __objc_msgLookup_uncached cbz p9, __objc_msgLookup_uncached
.else .else
.abort oops .abort oops
.endif .endif
@ -240,41 +242,89 @@ LExit$0:
.endmacro .endmacro
.macro CacheLookup .macro CacheLookup
// x1 = SEL, x16 = isa //
ldp x10, x11, [x16, #CACHE] // x10 = buckets, x11 = occupied|mask // Restart protocol:
and w12, w1, w11 // x12 = _cmd & mask //
add x12, x10, x12, LSL #4 // x12 = buckets + ((_cmd & mask)<<4) // As soon as we're past the LLookupStart$1 label we may have loaded
// an invalid cache pointer or mask.
//
// When task_restartable_ranges_synchronize() is called,
// (or when a signal hits us) before we're past LLookupEnd$1,
// then our PC will be reset to LLookupRecover$1 which forcefully
// jumps to the cache-miss codepath which have the following
// requirements:
//
// GETIMP:
// The cache-miss is just returning NULL (setting x0 to 0)
//
// NORMAL and LOOKUP:
// - x0 contains the receiver
// - x1 contains the selector
// - x16 contains the isa
// - other registers are set as per calling conventions
//
LLookupStart$1:
ldp x9, x17, [x12] // {x9, x17} = *bucket // p1 = SEL, p16 = isa
1: cmp x9, x1 // if (bucket->sel != _cmd) ldr p11, [x16, #CACHE] // p11 = mask|buckets
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
and p10, p11, #0x0000ffffffffffff // p10 = buckets
and p12, p1, p11, LSR #48 // x12 = _cmd & mask
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4
and p10, p11, #~0xf // p10 = buckets
and p11, p11, #0xf // p11 = maskShift
mov p12, #0xffff
lsr p11, p12, p11 // p11 = mask = 0xffff >> p11
and p12, p1, p11 // x12 = _cmd & mask
#else
#error Unsupported cache mask storage for ARM64.
#endif
add p12, p10, p12, LSL #(1+PTRSHIFT)
// p12 = buckets + ((_cmd & mask) << (1+PTRSHIFT))
ldp p17, p9, [x12] // {imp, sel} = *bucket
1: cmp p9, p1 // if (bucket->sel != _cmd)
b.ne 2f // scan more b.ne 2f // scan more
CacheHit $0 // call or return imp CacheHit $0 // call or return imp
2: // not hit: x12 = not-hit bucket 2: // not hit: p12 = not-hit bucket
CheckMiss $0 // miss if bucket->sel == 0 CheckMiss $0 // miss if bucket->sel == 0
cmp x12, x10 // wrap if bucket == buckets cmp p12, p10 // wrap if bucket == buckets
b.eq 3f b.eq 3f
ldp x9, x17, [x12, #-16]! // {x9, x17} = *--bucket ldp p17, p9, [x12, #-BUCKET_SIZE]! // {imp, sel} = *--bucket
b 1b // loop b 1b // loop
3: // wrap: x12 = first bucket, w11 = mask 3: // wrap: p12 = first bucket, w11 = mask
add x12, x12, w11, UXTW #4 // x12 = buckets+(mask<<4) #if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
add p12, p12, p11, LSR #(48 - (1+PTRSHIFT))
// p12 = buckets + (mask << 1+PTRSHIFT)
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4
add p12, p12, p11, LSL #(1+PTRSHIFT)
// p12 = buckets + (mask << 1+PTRSHIFT)
#else
#error Unsupported cache mask storage for ARM64.
#endif
// Clone scanning loop to miss instead of hang when cache is corrupt. // Clone scanning loop to miss instead of hang when cache is corrupt.
// The slow path may detect any corruption and halt later. // The slow path may detect any corruption and halt later.
ldp x9, x17, [x12] // {x9, x17} = *bucket ldp p17, p9, [x12] // {imp, sel} = *bucket
1: cmp x9, x1 // if (bucket->sel != _cmd) 1: cmp p9, p1 // if (bucket->sel != _cmd)
b.ne 2f // scan more b.ne 2f // scan more
CacheHit $0 // call or return imp CacheHit $0 // call or return imp
2: // not hit: x12 = not-hit bucket 2: // not hit: p12 = not-hit bucket
CheckMiss $0 // miss if bucket->sel == 0 CheckMiss $0 // miss if bucket->sel == 0
cmp x12, x10 // wrap if bucket == buckets cmp p12, p10 // wrap if bucket == buckets
b.eq 3f b.eq 3f
ldp x9, x17, [x12, #-16]! // {x9, x17} = *--bucket ldp p17, p9, [x12, #-BUCKET_SIZE]! // {imp, sel} = *--bucket
b 1b // loop b 1b // loop
LLookupEnd$1:
LLookupRecover$1:
3: // double wrap 3: // double wrap
JumpMiss $0 JumpMiss $0
@ -292,6 +342,7 @@ LExit$0:
* *
********************************************************************/ ********************************************************************/
#if SUPPORT_TAGGED_POINTERS
.data .data
.align 3 .align 3
.globl _objc_debug_taggedpointer_classes .globl _objc_debug_taggedpointer_classes
@ -300,38 +351,45 @@ _objc_debug_taggedpointer_classes:
.globl _objc_debug_taggedpointer_ext_classes .globl _objc_debug_taggedpointer_ext_classes
_objc_debug_taggedpointer_ext_classes: _objc_debug_taggedpointer_ext_classes:
.fill 256, 8, 0 .fill 256, 8, 0
#endif
ENTRY _objc_msgSend ENTRY _objc_msgSend
UNWIND _objc_msgSend, NoFrame UNWIND _objc_msgSend, NoFrame
MESSENGER_START
cmp x0, #0 // nil check and tagged pointer check cmp p0, #0 // nil check and tagged pointer check
#if SUPPORT_TAGGED_POINTERS
b.le LNilOrTagged // (MSB tagged pointer looks negative) b.le LNilOrTagged // (MSB tagged pointer looks negative)
ldr x13, [x0] // x13 = isa #else
and x16, x13, #ISA_MASK // x16 = class b.eq LReturnZero
#endif
ldr p13, [x0] // p13 = isa
GetClassFromIsa_p16 p13 // p16 = class
LGetIsaDone: LGetIsaDone:
CacheLookup NORMAL // calls imp or objc_msgSend_uncached // calls imp or objc_msgSend_uncached
CacheLookup NORMAL, _objc_msgSend
#if SUPPORT_TAGGED_POINTERS
LNilOrTagged: LNilOrTagged:
b.eq LReturnZero // nil check b.eq LReturnZero // nil check
// tagged // tagged
mov x10, #0xf000000000000000
cmp x0, x10
b.hs LExtTag
adrp x10, _objc_debug_taggedpointer_classes@PAGE adrp x10, _objc_debug_taggedpointer_classes@PAGE
add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
ubfx x11, x0, #60, #4 ubfx x11, x0, #60, #4
ldr x16, [x10, x11, LSL #3] ldr x16, [x10, x11, LSL #3]
b LGetIsaDone adrp x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGE
add x10, x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGEOFF
cmp x10, x16
b.ne LGetIsaDone
LExtTag:
// ext tagged // ext tagged
adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE
add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF
ubfx x11, x0, #52, #8 ubfx x11, x0, #52, #8
ldr x16, [x10, x11, LSL #3] ldr x16, [x10, x11, LSL #3]
b LGetIsaDone b LGetIsaDone
// SUPPORT_TAGGED_POINTERS
#endif
LReturnZero: LReturnZero:
// x0 is already zero // x0 is already zero
@ -340,7 +398,6 @@ LReturnZero:
movi d1, #0 movi d1, #0
movi d2, #0 movi d2, #0
movi d3, #0 movi d3, #0
MESSENGER_END_NIL
ret ret
END_ENTRY _objc_msgSend END_ENTRY _objc_msgSend
@ -348,26 +405,31 @@ LReturnZero:
ENTRY _objc_msgLookup ENTRY _objc_msgLookup
UNWIND _objc_msgLookup, NoFrame UNWIND _objc_msgLookup, NoFrame
cmp p0, #0 // nil check and tagged pointer check
cmp x0, #0 // nil check and tagged pointer check #if SUPPORT_TAGGED_POINTERS
b.le LLookup_NilOrTagged // (MSB tagged pointer looks negative) b.le LLookup_NilOrTagged // (MSB tagged pointer looks negative)
ldr x13, [x0] // x13 = isa #else
and x16, x13, #ISA_MASK // x16 = class b.eq LLookup_Nil
#endif
ldr p13, [x0] // p13 = isa
GetClassFromIsa_p16 p13 // p16 = class
LLookup_GetIsaDone: LLookup_GetIsaDone:
CacheLookup LOOKUP // returns imp // returns imp
CacheLookup LOOKUP, _objc_msgLookup
#if SUPPORT_TAGGED_POINTERS
LLookup_NilOrTagged: LLookup_NilOrTagged:
b.eq LLookup_Nil // nil check b.eq LLookup_Nil // nil check
// tagged // tagged
mov x10, #0xf000000000000000
cmp x0, x10
b.hs LLookup_ExtTag
adrp x10, _objc_debug_taggedpointer_classes@PAGE adrp x10, _objc_debug_taggedpointer_classes@PAGE
add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
ubfx x11, x0, #60, #4 ubfx x11, x0, #60, #4
ldr x16, [x10, x11, LSL #3] ldr x16, [x10, x11, LSL #3]
b LLookup_GetIsaDone adrp x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGE
add x10, x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGEOFF
cmp x10, x16
b.ne LLookup_GetIsaDone
LLookup_ExtTag: LLookup_ExtTag:
adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE
@ -375,6 +437,8 @@ LLookup_ExtTag:
ubfx x11, x0, #52, #8 ubfx x11, x0, #52, #8
ldr x16, [x10, x11, LSL #3] ldr x16, [x10, x11, LSL #3]
b LLookup_GetIsaDone b LLookup_GetIsaDone
// SUPPORT_TAGGED_POINTERS
#endif
LLookup_Nil: LLookup_Nil:
adrp x17, __objc_msgNil@PAGE adrp x17, __objc_msgNil@PAGE
@ -399,10 +463,10 @@ LLookup_Nil:
ENTRY _objc_msgSendSuper ENTRY _objc_msgSendSuper
UNWIND _objc_msgSendSuper, NoFrame UNWIND _objc_msgSendSuper, NoFrame
MESSENGER_START
ldp x0, x16, [x0] // x0 = real receiver, x16 = class ldp p0, p16, [x0] // p0 = real receiver, p16 = class
CacheLookup NORMAL // calls imp or objc_msgSend_uncached // calls imp or objc_msgSend_uncached
CacheLookup NORMAL, _objc_msgSendSuper
END_ENTRY _objc_msgSendSuper END_ENTRY _objc_msgSendSuper
@ -410,11 +474,10 @@ LLookup_Nil:
ENTRY _objc_msgSendSuper2 ENTRY _objc_msgSendSuper2
UNWIND _objc_msgSendSuper2, NoFrame UNWIND _objc_msgSendSuper2, NoFrame
MESSENGER_START
ldp x0, x16, [x0] // x0 = real receiver, x16 = class ldp p0, p16, [x0] // p0 = real receiver, p16 = class
ldr x16, [x16, #SUPERCLASS] // x16 = class->superclass ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass
CacheLookup NORMAL CacheLookup NORMAL, _objc_msgSendSuper2
END_ENTRY _objc_msgSendSuper2 END_ENTRY _objc_msgSendSuper2
@ -422,9 +485,9 @@ LLookup_Nil:
ENTRY _objc_msgLookupSuper2 ENTRY _objc_msgLookupSuper2
UNWIND _objc_msgLookupSuper2, NoFrame UNWIND _objc_msgLookupSuper2, NoFrame
ldp x0, x16, [x0] // x0 = real receiver, x16 = class ldp p0, p16, [x0] // p0 = real receiver, p16 = class
ldr x16, [x16, #SUPERCLASS] // x16 = class->superclass ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass
CacheLookup LOOKUP CacheLookup LOOKUP, _objc_msgLookupSuper2
END_ENTRY _objc_msgLookupSuper2 END_ENTRY _objc_msgLookupSuper2
@ -432,6 +495,7 @@ LLookup_Nil:
.macro MethodTableLookup .macro MethodTableLookup
// push frame // push frame
SignLR
stp fp, lr, [sp, #-16]! stp fp, lr, [sp, #-16]!
mov fp, sp mov fp, sp
@ -447,11 +511,13 @@ LLookup_Nil:
stp x6, x7, [sp, #(8*16+6*8)] stp x6, x7, [sp, #(8*16+6*8)]
str x8, [sp, #(8*16+8*8)] str x8, [sp, #(8*16+8*8)]
// lookUpImpOrForward(obj, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER)
// receiver and selector already in x0 and x1 // receiver and selector already in x0 and x1
mov x2, x16 mov x2, x16
bl __class_lookupMethodAndLoadCache3 mov x3, #3
bl _lookUpImpOrForward
// imp in x0 // IMP in x0
mov x17, x0 mov x17, x0
// restore registers and return // restore registers and return
@ -467,6 +533,7 @@ LLookup_Nil:
mov sp, fp mov sp, fp
ldp fp, lr, [sp], #16 ldp fp, lr, [sp], #16
AuthenticateLR
.endmacro .endmacro
@ -474,10 +541,10 @@ LLookup_Nil:
UNWIND __objc_msgSend_uncached, FrameWithNoSaves UNWIND __objc_msgSend_uncached, FrameWithNoSaves
// THIS IS NOT A CALLABLE C FUNCTION // THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band x16 is the class to search // Out-of-band p16 is the class to search
MethodTableLookup MethodTableLookup
br x17 TailCallFunctionPointer x17
END_ENTRY __objc_msgSend_uncached END_ENTRY __objc_msgSend_uncached
@ -486,7 +553,7 @@ LLookup_Nil:
UNWIND __objc_msgLookup_uncached, FrameWithNoSaves UNWIND __objc_msgLookup_uncached, FrameWithNoSaves
// THIS IS NOT A CALLABLE C FUNCTION // THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band x16 is the class to search // Out-of-band p16 is the class to search
MethodTableLookup MethodTableLookup
ret ret
@ -496,11 +563,11 @@ LLookup_Nil:
STATIC_ENTRY _cache_getImp STATIC_ENTRY _cache_getImp
and x16, x0, #ISA_MASK GetClassFromIsa_p16 p0
CacheLookup GETIMP CacheLookup GETIMP, _cache_getImp
LGetImpMiss: LGetImpMiss:
mov x0, #0 mov p0, #0
ret ret
END_ENTRY _cache_getImp END_ENTRY _cache_getImp
@ -519,10 +586,6 @@ LGetImpMiss:
STATIC_ENTRY __objc_msgForward_impcache STATIC_ENTRY __objc_msgForward_impcache
MESSENGER_START
nop
MESSENGER_END_SLOW
// No stret specialization. // No stret specialization.
b __objc_msgForward b __objc_msgForward
@ -532,8 +595,8 @@ LGetImpMiss:
ENTRY __objc_msgForward ENTRY __objc_msgForward
adrp x17, __objc_forward_handler@PAGE adrp x17, __objc_forward_handler@PAGE
ldr x17, [x17, __objc_forward_handler@PAGEOFF] ldr p17, [x17, __objc_forward_handler@PAGEOFF]
br x17 TailCallFunctionPointer x17
END_ENTRY __objc_msgForward END_ENTRY __objc_msgForward
@ -553,9 +616,10 @@ LGetImpMiss:
ENTRY _method_invoke ENTRY _method_invoke
// x1 is method triplet instead of SEL // x1 is method triplet instead of SEL
ldr x17, [x1, #METHOD_IMP] add p16, p1, #METHOD_IMP
ldr x1, [x1, #METHOD_NAME] ldr p17, [x16]
br x17 ldr p1, [x1, #METHOD_NAME]
TailCallMethodListImp x17, x16
END_ENTRY _method_invoke END_ENTRY _method_invoke
#endif #endif

View File

@ -40,89 +40,30 @@
.data .data
// _objc_entryPoints and _objc_exitPoints are used by objc // _objc_restartableRanges is used by method dispatch
// to get the critical regions for which method caches // to get the critical regions for which method caches
// cannot be garbage collected. // cannot be garbage collected.
.align 2 .macro RestartableEntry
.private_extern _objc_entryPoints .long $0
_objc_entryPoints:
.long __cache_getImp
.long __cache_getMethod
.long _objc_msgSend
.long _objc_msgSend_fpret
.long _objc_msgSend_stret
.long _objc_msgSendSuper
.long _objc_msgSendSuper_stret
.long 0 .long 0
.short $1 - $0
.private_extern _objc_exitPoints .short 0xffff // The old runtime doesn't support kernel based recovery
_objc_exitPoints:
.long LGetImpExit
.long LGetMethodExit
.long LMsgSendExit
.long LMsgSendFpretExit
.long LMsgSendStretExit
.long LMsgSendSuperExit
.long LMsgSendSuperStretExit
.long 0 .long 0
/********************************************************************
* List every exit insn from every messenger for debugger use.
* Format:
* (
* 1 word instruction's address
* 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
* )
* 1 word zero
*
* ENTER is the start of a dispatcher
* FAST_EXIT is method dispatch
* SLOW_EXIT is uncached method lookup
* NIL_EXIT is returning zero from a message sent to nil
* These must match objc-gdb.h.
********************************************************************/
#define ENTER 1
#define FAST_EXIT 2
#define SLOW_EXIT 3
#define NIL_EXIT 4
.section __DATA,__objc_msg_break
.globl _gdb_objc_messenger_breakpoints
_gdb_objc_messenger_breakpoints:
// contents populated by the macros below
.macro MESSENGER_START
4:
.section __DATA,__objc_msg_break
.long 4b
.long ENTER
.text
.endmacro
.macro MESSENGER_END_FAST
4:
.section __DATA,__objc_msg_break
.long 4b
.long FAST_EXIT
.text
.endmacro
.macro MESSENGER_END_SLOW
4:
.section __DATA,__objc_msg_break
.long 4b
.long SLOW_EXIT
.text
.endmacro
.macro MESSENGER_END_NIL
4:
.section __DATA,__objc_msg_break
.long 4b
.long NIL_EXIT
.text
.endmacro .endmacro
.align 4
.private_extern _objc_restartableRanges
_objc_restartableRanges:
RestartableEntry __cache_getImp, LGetImpExit
RestartableEntry __cache_getMethod, LGetMethodExit
RestartableEntry _objc_msgSend, LMsgSendExit
RestartableEntry _objc_msgSend_fpret, LMsgSendFpretExit
RestartableEntry _objc_msgSend_stret, LMsgSendStretExit
RestartableEntry _objc_msgSendSuper, LMsgSendSuperExit
RestartableEntry _objc_msgSendSuper_stret, LMsgSendSuperStretExit
.fill 16, 1, 0
/******************************************************************** /********************************************************************
* *
@ -492,8 +433,6 @@ LMsgSendHitInstrumentDone_$0_$1_$2:
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
.macro MethodTableLookup .macro MethodTableLookup
MESSENGER_END_SLOW
// stack has return address and nothing else // stack has return address and nothing else
subl $$(12+5*16), %esp subl $$(12+5*16), %esp
@ -502,10 +441,12 @@ LMsgSendHitInstrumentDone_$0_$1_$2:
movdqa %xmm1, 2*16(%esp) movdqa %xmm1, 2*16(%esp)
movdqa %xmm0, 1*16(%esp) movdqa %xmm0, 1*16(%esp)
// lookUpImpOrForward(obj, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER)
movl $$3, 12(%esp) // LOOKUP_INITIALIZE | LOOKUP_RESOLVER
movl %eax, 8(%esp) // class movl %eax, 8(%esp) // class
movl %ecx, 4(%esp) // selector movl %ecx, 4(%esp) // selector
movl %edx, 0(%esp) // receiver movl %edx, 0(%esp) // receiver
call __class_lookupMethodAndLoadCache3 call _lookUpImpOrForward
movdqa 4*16(%esp), %xmm3 movdqa 4*16(%esp), %xmm3
movdqa 3*16(%esp), %xmm2 movdqa 3*16(%esp), %xmm2
@ -593,7 +534,6 @@ LGetImpExit:
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSend ENTRY _objc_msgSend
MESSENGER_START
CALL_MCOUNTER CALL_MCOUNTER
// load receiver and selector // load receiver and selector
@ -609,7 +549,6 @@ LMsgSendReceiverOk:
movl isa(%eax), %edx // class = self->isa movl isa(%eax), %edx // class = self->isa
CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss
xor %edx, %edx // set nonstret for msgForward_internal xor %edx, %edx // set nonstret for msgForward_internal
MESSENGER_END_FAST
jmp *%eax jmp *%eax
// cache miss: go search the method lists // cache miss: go search the method lists
@ -624,7 +563,6 @@ LMsgSendNilSelf:
movl $0,%edx movl $0,%edx
xorps %xmm0, %xmm0 xorps %xmm0, %xmm0
LMsgSendDone: LMsgSendDone:
MESSENGER_END_NIL
ret ret
// guaranteed non-nil entry point (disabled for now) // guaranteed non-nil entry point (disabled for now)
@ -647,7 +585,6 @@ LMsgSendExit:
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSendSuper ENTRY _objc_msgSendSuper
MESSENGER_START
CALL_MCOUNTER CALL_MCOUNTER
// load selector and class to search // load selector and class to search
@ -658,7 +595,6 @@ LMsgSendExit:
// search the cache (class in %edx) // search the cache (class in %edx)
CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss
xor %edx, %edx // set nonstret for msgForward_internal xor %edx, %edx // set nonstret for msgForward_internal
MESSENGER_END_FAST
jmp *%eax // goto *imp jmp *%eax // goto *imp
// cache miss: go search the method lists // cache miss: go search the method lists
@ -671,7 +607,6 @@ LMsgSendSuperCacheMiss:
LMsgSendSuperIgnored: LMsgSendSuperIgnored:
movl super(%esp), %eax movl super(%esp), %eax
movl receiver(%eax), %eax movl receiver(%eax), %eax
MESSENGER_END_NIL
ret ret
LMsgSendSuperExit: LMsgSendSuperExit:
@ -736,7 +671,6 @@ LMsgSendvArgsOK:
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSend_fpret ENTRY _objc_msgSend_fpret
MESSENGER_START
CALL_MCOUNTER CALL_MCOUNTER
// load receiver and selector // load receiver and selector
@ -752,7 +686,6 @@ LMsgSendFpretReceiverOk:
movl isa(%eax), %edx // class = self->isa movl isa(%eax), %edx // class = self->isa
CacheLookup WORD_RETURN, MSG_SEND, LMsgSendFpretCacheMiss CacheLookup WORD_RETURN, MSG_SEND, LMsgSendFpretCacheMiss
xor %edx, %edx // set nonstret for msgForward_internal xor %edx, %edx // set nonstret for msgForward_internal
MESSENGER_END_FAST
jmp *%eax // goto *imp jmp *%eax // goto *imp
// cache miss: go search the method lists // cache miss: go search the method lists
@ -766,7 +699,6 @@ LMsgSendFpretNilSelf:
// %eax is already zero // %eax is already zero
fldz fldz
LMsgSendFpretDone: LMsgSendFpretDone:
MESSENGER_END_NIL
ret ret
LMsgSendFpretExit: LMsgSendFpretExit:
@ -839,7 +771,6 @@ LMsgSendvFpretArgsOK:
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSend_stret ENTRY _objc_msgSend_stret
MESSENGER_START
CALL_MCOUNTER CALL_MCOUNTER
// load receiver and selector // load receiver and selector
@ -855,7 +786,6 @@ LMsgSendStretReceiverOk:
movl isa(%eax), %edx // class = self->isa movl isa(%eax), %edx // class = self->isa
CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss
movl $1, %edx // set stret for objc_msgForward movl $1, %edx // set stret for objc_msgForward
MESSENGER_END_FAST
jmp *%eax // goto *imp jmp *%eax // goto *imp
// cache miss: go search the method lists // cache miss: go search the method lists
@ -866,7 +796,6 @@ LMsgSendStretCacheMiss:
// message sent to nil: redirect to nil receiver, if any // message sent to nil: redirect to nil receiver, if any
LMsgSendStretNilSelf: LMsgSendStretNilSelf:
MESSENGER_END_NIL
ret $4 // pop struct return address (#2995932) ret $4 // pop struct return address (#2995932)
// guaranteed non-nil entry point (disabled for now) // guaranteed non-nil entry point (disabled for now)
@ -899,7 +828,6 @@ LMsgSendStretExit:
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSendSuper_stret ENTRY _objc_msgSendSuper_stret
MESSENGER_START
CALL_MCOUNTER CALL_MCOUNTER
// load selector and class to search // load selector and class to search
@ -910,7 +838,6 @@ LMsgSendStretExit:
// search the cache (class in %edx) // search the cache (class in %edx)
CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss
movl $1, %edx // set stret for objc_msgForward movl $1, %edx // set stret for objc_msgForward
MESSENGER_END_FAST
jmp *%eax // goto *imp jmp *%eax // goto *imp
// cache miss: go search the method lists // cache miss: go search the method lists
@ -1013,10 +940,6 @@ L_forward_stret_handler:
// THIS IS NOT A CALLABLE C FUNCTION // THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band register %edx is nonzero for stret, zero otherwise // Out-of-band register %edx is nonzero for stret, zero otherwise
MESSENGER_START
nop
MESSENGER_END_SLOW
// Check return type (stret or not) // Check return type (stret or not)
testl %edx, %edx testl %edx, %edx
jnz __objc_msgForward_stret jnz __objc_msgForward_stret

View File

@ -28,101 +28,36 @@
.data .data
// _objc_entryPoints and _objc_exitPoints are used by objc // _objc_restartableRanges is used by method dispatch
// to get the critical regions for which method caches // to get the critical regions for which method caches
// cannot be garbage collected. // cannot be garbage collected.
.align 2 .macro RestartableEntry
.private_extern _objc_entryPoints .long $0
_objc_entryPoints:
.long _cache_getImp
.long _objc_msgSend
.long _objc_msgSend_fpret
.long _objc_msgSend_stret
.long _objc_msgSendSuper
.long _objc_msgSendSuper2
.long _objc_msgSendSuper_stret
.long _objc_msgSendSuper2_stret
.long _objc_msgLookup
.long _objc_msgLookup_fpret
.long _objc_msgLookup_stret
.long _objc_msgLookupSuper2
.long _objc_msgLookupSuper2_stret
.long 0 .long 0
.short LExit$0 - $0
.private_extern _objc_exitPoints .short 0xffff // The simulator doesn't support kernel based recovery
_objc_exitPoints:
.long LExit_cache_getImp
.long LExit_objc_msgSend
.long LExit_objc_msgSend_fpret
.long LExit_objc_msgSend_stret
.long LExit_objc_msgSendSuper
.long LExit_objc_msgSendSuper2
.long LExit_objc_msgSendSuper_stret
.long LExit_objc_msgSendSuper2_stret
.long LExit_objc_msgLookup
.long LExit_objc_msgLookup_fpret
.long LExit_objc_msgLookup_stret
.long LExit_objc_msgLookupSuper2
.long LExit_objc_msgLookupSuper2_stret
.long 0 .long 0
/********************************************************************
* List every exit insn from every messenger for debugger use.
* Format:
* (
* 1 word instruction's address
* 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
* )
* 1 word zero
*
* ENTER is the start of a dispatcher
* FAST_EXIT is method dispatch
* SLOW_EXIT is uncached method lookup
* NIL_EXIT is returning zero from a message sent to nil
* These must match objc-gdb.h.
********************************************************************/
#define ENTER 1
#define FAST_EXIT 2
#define SLOW_EXIT 3
#define NIL_EXIT 4
.section __DATA,__objc_msg_break
.globl _gdb_objc_messenger_breakpoints
_gdb_objc_messenger_breakpoints:
// contents populated by the macros below
.macro MESSENGER_START
4:
.section __DATA,__objc_msg_break
.long 4b
.long ENTER
.text
.endmacro
.macro MESSENGER_END_FAST
4:
.section __DATA,__objc_msg_break
.long 4b
.long FAST_EXIT
.text
.endmacro
.macro MESSENGER_END_SLOW
4:
.section __DATA,__objc_msg_break
.long 4b
.long SLOW_EXIT
.text
.endmacro
.macro MESSENGER_END_NIL
4:
.section __DATA,__objc_msg_break
.long 4b
.long NIL_EXIT
.text
.endmacro .endmacro
.align 4
.private_extern _objc_restartableRanges
_objc_restartableRanges:
RestartableEntry _cache_getImp
RestartableEntry _objc_msgSend
RestartableEntry _objc_msgSend_fpret
RestartableEntry _objc_msgSend_stret
RestartableEntry _objc_msgSendSuper
RestartableEntry _objc_msgSendSuper2
RestartableEntry _objc_msgSendSuper_stret
RestartableEntry _objc_msgSendSuper2_stret
RestartableEntry _objc_msgLookup
RestartableEntry _objc_msgLookup_fpret
RestartableEntry _objc_msgLookup_stret
RestartableEntry _objc_msgLookupSuper2
RestartableEntry _objc_msgLookupSuper2_stret
.fill 16, 1, 0
/******************************************************************** /********************************************************************
* Names for relative labels * Names for relative labels
@ -188,6 +123,12 @@ _gdb_objc_messenger_breakpoints:
// Selected field offsets in class structure // Selected field offsets in class structure
#define isa 0 #define isa 0
#define superclass 4 #define superclass 4
#define cache_buckets 8
#define cache_mask 12
// Method cache
#define cached_sel 0
#define cached_imp 4
// Method descriptor // Method descriptor
#define method_name 0 #define method_name 0
@ -277,23 +218,26 @@ LExit$0:
// eax = found bucket // eax = found bucket
.if $1 == GETIMP .if $1 == GETIMP
movl 4(%eax), %eax // return imp movl cached_imp(%eax), %eax // return imp
ret cmpl $$0, %eax
jz 9f // don't xor a nil imp
xorl %edx, %eax // xor the isa with the imp
9: ret
.else .else
.if $0 != STRET
// eq already set for forwarding by `jne`
.else
test %eax, %eax // set ne for stret forwarding
.endif
.if $1 == CALL .if $1 == CALL
MESSENGER_END_FAST xorl cached_imp(%eax), %edx // xor imp and isa
jmp *4(%eax) // call imp .if $0 != STRET
// ne already set for forwarding by `xor`
.else
cmp %eax, %eax // set eq for stret forwarding
.endif
jmp *%edx // call imp
.elseif $1 == LOOKUP .elseif $1 == LOOKUP
movl 4(%eax), %eax // return imp movl cached_imp(%eax), %eax // return imp
xorl %edx, %eax // xor isa into imp
ret ret
.else .else
@ -307,23 +251,23 @@ LExit$0:
.macro CacheLookup .macro CacheLookup
movzwl 12(%edx), %eax // eax = mask movzwl cache_mask(%edx), %eax // eax = mask
andl %ecx, %eax // eax = SEL & mask andl %ecx, %eax // eax = SEL & mask
shll $$3, %eax // eax = offset = (SEL & mask) * 8 shll $$3, %eax // eax = offset = (SEL & mask) * 8
addl 8(%edx), %eax // eax = bucket = cache->buckets+offset addl cache_buckets(%edx), %eax // eax = bucket = buckets+offset
cmpl (%eax), %ecx // if (bucket->sel != SEL) cmpl cached_sel(%eax), %ecx // if (bucket->sel != SEL)
jne 1f // scan more jne 1f // scan more
// The `jne` above sets flags for CacheHit // The `jne` above sets flags for CacheHit
CacheHit $0, $1 // call or return imp CacheHit $0, $1 // call or return imp
1: 1:
// loop // loop
cmpl $$1, (%eax) cmpl $$1, cached_sel(%eax)
jbe 3f // if (bucket->sel <= 1) wrap or miss jbe 3f // if (bucket->sel <= 1) wrap or miss
addl $$8, %eax // bucket++ addl $$8, %eax // bucket++
2: 2:
cmpl (%eax), %ecx // if (bucket->sel != sel) cmpl cached_sel(%eax), %ecx // if (bucket->sel != sel)
jne 1b // scan more jne 1b // scan more
// The `jne` above sets flags for CacheHit // The `jne` above sets flags for CacheHit
CacheHit $0, $1 // call or return imp CacheHit $0, $1 // call or return imp
@ -332,7 +276,7 @@ LExit$0:
// wrap or miss // wrap or miss
jb LCacheMiss_f // if (bucket->sel < 1) cache miss jb LCacheMiss_f // if (bucket->sel < 1) cache miss
// wrap // wrap
movl 4(%eax), %eax // bucket->imp is really first bucket movl cached_imp(%eax), %eax // bucket->imp is really first bucket
jmp 2f jmp 2f
// Clone scanning loop to miss instead of hang when cache is corrupt. // Clone scanning loop to miss instead of hang when cache is corrupt.
@ -340,12 +284,12 @@ LExit$0:
1: 1:
// loop // loop
cmpq $$1, (%eax) cmpl $$1, cached_sel(%eax)
jbe 3f // if (bucket->sel <= 1) wrap or miss jbe 3f // if (bucket->sel <= 1) wrap or miss
addl $$8, %eax // bucket++ addl $$8, %eax // bucket++
2: 2:
cmpl (%eax), %ecx // if (bucket->sel != sel) cmpl cached_sel(%eax), %ecx // if (bucket->sel != sel)
jne 1b // scan more jne 1b // scan more
// The `jne` above sets flags for CacheHit // The `jne` above sets flags for CacheHit
CacheHit $0, $1 // call or return imp CacheHit $0, $1 // call or return imp
@ -388,10 +332,12 @@ LExit$0:
movdqa %xmm1, 2*16(%esp) movdqa %xmm1, 2*16(%esp)
movdqa %xmm0, 1*16(%esp) movdqa %xmm0, 1*16(%esp)
// lookUpImpOrForward(obj, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER)
movl $$3, 12(%esp) // LOOKUP_INITIALIZE | LOOKUP_RESOLVER
movl %edx, 8(%esp) // class movl %edx, 8(%esp) // class
movl %ecx, 4(%esp) // selector movl %ecx, 4(%esp) // selector
movl %eax, 0(%esp) // receiver movl %eax, 0(%esp) // receiver
call __class_lookupMethodAndLoadCache3 call _lookUpImpOrForward
// imp in eax // imp in eax
@ -401,9 +347,9 @@ LExit$0:
movdqa 1*16(%esp), %xmm0 movdqa 1*16(%esp), %xmm0
.if $0 == NORMAL .if $0 == NORMAL
cmp %eax, %eax // set eq for nonstret forwarding
.else
test %eax, %eax // set ne for stret forwarding test %eax, %eax // set ne for stret forwarding
.else
cmp %eax, %eax // set eq for nonstret forwarding
.endif .endif
leave leave
@ -482,15 +428,12 @@ LNilTestSlow:
.if $0 == NORMAL .if $0 == NORMAL
ZeroReturn ZeroReturn
MESSENGER_END_NIL
ret ret
.elseif $0 == FPRET .elseif $0 == FPRET
ZeroReturnFPRET ZeroReturnFPRET
MESSENGER_END_NIL
ret ret
.elseif $0 == STRET .elseif $0 == STRET
ZeroReturnSTRET ZeroReturnSTRET
MESSENGER_END_NIL
ret $$4 ret $$4
.else .else
.abort oops .abort oops
@ -553,7 +496,6 @@ LCacheMiss:
ENTRY _objc_msgSend ENTRY _objc_msgSend
UNWIND _objc_msgSend, NoFrame UNWIND _objc_msgSend, NoFrame
MESSENGER_START
movl selector(%esp), %ecx movl selector(%esp), %ecx
movl self(%esp), %eax movl self(%esp), %eax
@ -567,7 +509,6 @@ LCacheMiss:
LCacheMiss: LCacheMiss:
// isa still in edx // isa still in edx
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSend END_ENTRY _objc_msgSend
@ -596,13 +537,11 @@ LCacheMiss:
/******************************************************************** /********************************************************************
* *
* id objc_msgSendSuper(struct objc_super *super, SEL _cmd, ...); * id objc_msgSendSuper(struct objc_super *super, SEL _cmd, ...);
* IMP objc_msgLookupSuper(struct objc_super *super, SEL _cmd, ...);
* *
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSendSuper ENTRY _objc_msgSendSuper
UNWIND _objc_msgSendSuper, NoFrame UNWIND _objc_msgSendSuper, NoFrame
MESSENGER_START
movl selector(%esp), %ecx movl selector(%esp), %ecx
movl super(%esp), %eax // struct objc_super movl super(%esp), %eax // struct objc_super
@ -613,30 +552,11 @@ LCacheMiss:
LCacheMiss: LCacheMiss:
// class still in edx // class still in edx
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper END_ENTRY _objc_msgSendSuper
ENTRY _objc_msgLookupSuper
UNWIND _objc_msgLookupSuper, NoFrame
movl selector(%esp), %ecx
movl super(%esp), %eax // struct objc_super
movl class(%eax), %edx // struct objc_super->class
movl receiver(%eax), %eax // struct objc_super->receiver
movl %eax, super(%esp) // replace super arg with receiver
CacheLookup NORMAL, LOOKUP // returns IMP on success
LCacheMiss:
// class still in edx
jmp __objc_msgLookup_uncached
END_ENTRY _objc_msgLookupSuper
/******************************************************************** /********************************************************************
* *
* id objc_msgSendSuper2(struct objc_super *super, SEL _cmd, ...); * id objc_msgSendSuper2(struct objc_super *super, SEL _cmd, ...);
@ -646,7 +566,6 @@ LCacheMiss:
ENTRY _objc_msgSendSuper2 ENTRY _objc_msgSendSuper2
UNWIND _objc_msgSendSuper2, NoFrame UNWIND _objc_msgSendSuper2, NoFrame
MESSENGER_START
movl selector(%esp), %ecx movl selector(%esp), %ecx
movl super(%esp), %eax // struct objc_super movl super(%esp), %eax // struct objc_super
@ -658,7 +577,6 @@ LCacheMiss:
LCacheMiss: LCacheMiss:
// class still in edx // class still in edx
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper2 END_ENTRY _objc_msgSendSuper2
@ -691,7 +609,6 @@ LCacheMiss:
ENTRY _objc_msgSend_fpret ENTRY _objc_msgSend_fpret
UNWIND _objc_msgSend_fpret, NoFrame UNWIND _objc_msgSend_fpret, NoFrame
MESSENGER_START
movl selector(%esp), %ecx movl selector(%esp), %ecx
movl self(%esp), %eax movl self(%esp), %eax
@ -705,7 +622,6 @@ LCacheMiss:
LCacheMiss: LCacheMiss:
// class still in edx // class still in edx
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSend_fpret END_ENTRY _objc_msgSend_fpret
@ -740,7 +656,6 @@ LCacheMiss:
ENTRY _objc_msgSend_stret ENTRY _objc_msgSend_stret
UNWIND _objc_msgSend_stret, NoFrame UNWIND _objc_msgSend_stret, NoFrame
MESSENGER_START
movl selector_stret(%esp), %ecx movl selector_stret(%esp), %ecx
movl self_stret(%esp), %eax movl self_stret(%esp), %eax
@ -754,7 +669,6 @@ LCacheMiss:
LCacheMiss: LCacheMiss:
// class still in edx // class still in edx
MESSENGER_END_SLOW
jmp __objc_msgSend_stret_uncached jmp __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSend_stret END_ENTRY _objc_msgSend_stret
@ -783,13 +697,11 @@ LCacheMiss:
/******************************************************************** /********************************************************************
* *
* void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...); * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
* IMP objc_msgLookupSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
* *
********************************************************************/ ********************************************************************/
ENTRY _objc_msgSendSuper_stret ENTRY _objc_msgSendSuper_stret
UNWIND _objc_msgSendSuper_stret, NoFrame UNWIND _objc_msgSendSuper_stret, NoFrame
MESSENGER_START
movl selector_stret(%esp), %ecx movl selector_stret(%esp), %ecx
movl super_stret(%esp), %eax // struct objc_super movl super_stret(%esp), %eax // struct objc_super
@ -800,29 +712,11 @@ LCacheMiss:
LCacheMiss: LCacheMiss:
// class still in edx // class still in edx
MESSENGER_END_SLOW
jmp __objc_msgSend_stret_uncached jmp __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSendSuper_stret END_ENTRY _objc_msgSendSuper_stret
ENTRY _objc_msgLookupSuper_stret
UNWIND _objc_msgLookupSuper_stret, NoFrame
movl selector_stret(%esp), %ecx
movl super_stret(%esp), %eax // struct objc_super
movl class(%eax), %edx // struct objc_super->class
movl receiver(%eax), %eax // struct objc_super->receiver
movl %eax, super_stret(%esp) // replace super arg with receiver
CacheLookup STRET, LOOKUP // returns IMP on success
LCacheMiss:
// class still in edx
jmp __objc_msgLookup_stret_uncached
END_ENTRY _objc_msgLookupSuper_stret
/******************************************************************** /********************************************************************
* *
* void objc_msgSendSuper2_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...); * void objc_msgSendSuper2_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
@ -832,7 +726,6 @@ LCacheMiss:
ENTRY _objc_msgSendSuper2_stret ENTRY _objc_msgSendSuper2_stret
UNWIND _objc_msgSendSuper2_stret, NoFrame UNWIND _objc_msgSendSuper2_stret, NoFrame
MESSENGER_START
movl selector_stret(%esp), %ecx movl selector_stret(%esp), %ecx
movl super_stret(%esp), %eax // struct objc_super movl super_stret(%esp), %eax // struct objc_super
@ -845,7 +738,6 @@ LCacheMiss:
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss:
// class still in edx // class still in edx
MESSENGER_END_SLOW
jmp __objc_msgSend_stret_uncached jmp __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSendSuper2_stret END_ENTRY _objc_msgSendSuper2_stret
@ -958,11 +850,7 @@ L_forward_stret_handler:
// THIS IS NOT A CALLABLE C FUNCTION // THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band condition register is NE for stret, EQ otherwise. // Out-of-band condition register is NE for stret, EQ otherwise.
MESSENGER_START je __objc_msgForward_stret
nop
MESSENGER_END_SLOW
jne __objc_msgForward_stret
jmp __objc_msgForward jmp __objc_msgForward
END_ENTRY _objc_msgForward_impcache END_ENTRY _objc_msgForward_impcache

View File

@ -22,7 +22,7 @@
*/ */
#include <TargetConditionals.h> #include <TargetConditionals.h>
#if __x86_64__ && TARGET_OS_SIMULATOR #if __x86_64__ && TARGET_OS_SIMULATOR && !TARGET_OS_IOSMAC
/******************************************************************** /********************************************************************
******************************************************************** ********************************************************************
@ -34,105 +34,37 @@
.data .data
// _objc_entryPoints and _objc_exitPoints are used by objc // _objc_restartableRanges is used by method dispatch
// to get the critical regions for which method caches // to get the critical regions for which method caches
// cannot be garbage collected. // cannot be garbage collected.
.align 4 .macro RestartableEntry
.private_extern _objc_entryPoints .quad $0
_objc_entryPoints: .short LExit$0 - $0
.quad _cache_getImp .short 0xffff // The simulator doesn't support kernel based recovery
.quad _objc_msgSend .long 0
.quad _objc_msgSend_fpret
.quad _objc_msgSend_fp2ret
.quad _objc_msgSend_stret
.quad _objc_msgSendSuper
.quad _objc_msgSendSuper_stret
.quad _objc_msgSendSuper2
.quad _objc_msgSendSuper2_stret
.quad _objc_msgLookup
.quad _objc_msgLookup_fpret
.quad _objc_msgLookup_fp2ret
.quad _objc_msgLookup_stret
.quad _objc_msgLookupSuper2
.quad _objc_msgLookupSuper2_stret
.quad 0
.private_extern _objc_exitPoints
_objc_exitPoints:
.quad LExit_cache_getImp
.quad LExit_objc_msgSend
.quad LExit_objc_msgSend_fpret
.quad LExit_objc_msgSend_fp2ret
.quad LExit_objc_msgSend_stret
.quad LExit_objc_msgSendSuper
.quad LExit_objc_msgSendSuper_stret
.quad LExit_objc_msgSendSuper2
.quad LExit_objc_msgSendSuper2_stret
.quad LExit_objc_msgLookup
.quad LExit_objc_msgLookup_fpret
.quad LExit_objc_msgLookup_fp2ret
.quad LExit_objc_msgLookup_stret
.quad LExit_objc_msgLookupSuper2
.quad LExit_objc_msgLookupSuper2_stret
.quad 0
/********************************************************************
* List every exit insn from every messenger for debugger use.
* Format:
* (
* 1 word instruction's address
* 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
* )
* 1 word zero
*
* ENTER is the start of a dispatcher
* FAST_EXIT is method dispatch
* SLOW_EXIT is uncached method lookup
* NIL_EXIT is returning zero from a message sent to nil
* These must match objc-gdb.h.
********************************************************************/
#define ENTER 1
#define FAST_EXIT 2
#define SLOW_EXIT 3
#define NIL_EXIT 4
.section __DATA,__objc_msg_break
.globl _gdb_objc_messenger_breakpoints
_gdb_objc_messenger_breakpoints:
// contents populated by the macros below
.macro MESSENGER_START
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad ENTER
.text
.endmacro
.macro MESSENGER_END_FAST
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad FAST_EXIT
.text
.endmacro
.macro MESSENGER_END_SLOW
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad SLOW_EXIT
.text
.endmacro
.macro MESSENGER_END_NIL
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad NIL_EXIT
.text
.endmacro .endmacro
.align 4
.private_extern _objc_restartableRanges
_objc_restartableRanges:
RestartableEntry _cache_getImp
RestartableEntry _objc_msgSend
RestartableEntry _objc_msgSend_fpret
RestartableEntry _objc_msgSend_fp2ret
RestartableEntry _objc_msgSend_stret
RestartableEntry _objc_msgSendSuper
RestartableEntry _objc_msgSendSuper_stret
RestartableEntry _objc_msgSendSuper2
RestartableEntry _objc_msgSendSuper2_stret
RestartableEntry _objc_msgLookup
RestartableEntry _objc_msgLookup_fpret
RestartableEntry _objc_msgLookup_fp2ret
RestartableEntry _objc_msgLookup_stret
RestartableEntry _objc_msgLookupSuper2
RestartableEntry _objc_msgLookupSuper2_stret
.fill 16, 1, 0
/******************************************************************** /********************************************************************
* Recommended multi-byte NOP instructions * Recommended multi-byte NOP instructions
@ -218,6 +150,10 @@ _gdb_objc_messenger_breakpoints:
#define method_name 0 #define method_name 0
#define method_imp 16 #define method_imp 16
// Method cache
#define cached_sel 0
#define cached_imp 8
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// //
@ -297,29 +233,30 @@ LExit$0:
.macro CacheHit .macro CacheHit
// CacheHit must always be preceded by a not-taken `jne` instruction
// in order to set the correct flags for _objc_msgForward_impcache.
// r11 = found bucket // r11 = found bucket
.if $1 == GETIMP .if $1 == GETIMP
movq 8(%r11), %rax // return imp movq cached_imp(%r11), %rax // return imp
ret cmpq $$0, %rax
jz 9f // don't xor a nil imp
xorq %r10, %rax // xor the isa with the imp
9: ret
.else .else
.if $0 != STRET
// eq already set for forwarding by `jne`
.else
test %r11, %r11 // set ne for stret forwarding
.endif
.if $1 == CALL .if $1 == CALL
MESSENGER_END_FAST movq cached_imp(%r11), %r11 // load imp
jmp *8(%r11) // call imp xorq %r10, %r11 // xor imp and isa
.if $0 != STRET
// ne already set for forwarding by `xor`
.else
cmp %r11, %r11 // set eq for stret forwarding
.endif
jmp *%r11 // call imp
.elseif $1 == LOOKUP .elseif $1 == LOOKUP
movq 8(%r11), %r11 // return imp movq cached_imp(%r11), %r11
xorq %r10, %r11 // return imp ^ isa
ret ret
.else .else
@ -342,35 +279,33 @@ LExit$0:
addq 16(%r10), %r11 // r11 = class->cache.buckets + offset addq 16(%r10), %r11 // r11 = class->cache.buckets + offset
.if $0 != STRET .if $0 != STRET
cmpq (%r11), %a2 // if (bucket->sel != _cmd) cmpq cached_sel(%r11), %a2 // if (bucket->sel != _cmd)
.else .else
cmpq (%r11), %a3 // if (bucket->sel != _cmd) cmpq cached_sel(%r11), %a3 // if (bucket->sel != _cmd)
.endif .endif
jne 1f // scan more jne 1f // scan more
// CacheHit must always be preceded by a not-taken `jne` instruction
CacheHit $0, $1 // call or return imp CacheHit $0, $1 // call or return imp
1: 1:
// loop // loop
cmpq $$1, (%r11) cmpq $$1, cached_sel(%r11)
jbe 3f // if (bucket->sel <= 1) wrap or miss jbe 3f // if (bucket->sel <= 1) wrap or miss
addq $$16, %r11 // bucket++ addq $$16, %r11 // bucket++
2: 2:
.if $0 != STRET .if $0 != STRET
cmpq (%r11), %a2 // if (bucket->sel != _cmd) cmpq cached_sel(%r11), %a2 // if (bucket->sel != _cmd)
.else .else
cmpq (%r11), %a3 // if (bucket->sel != _cmd) cmpq cached_sel(%r11), %a3 // if (bucket->sel != _cmd)
.endif .endif
jne 1b // scan more jne 1b // scan more
// CacheHit must always be preceded by a not-taken `jne` instruction
CacheHit $0, $1 // call or return imp CacheHit $0, $1 // call or return imp
3: 3:
// wrap or miss // wrap or miss
jb LCacheMiss_f // if (bucket->sel < 1) cache miss jb LCacheMiss_f // if (bucket->sel < 1) cache miss
// wrap // wrap
movq 8(%r11), %r11 // bucket->imp is really first bucket movq cached_imp(%r11), %r11 // bucket->imp is really first bucket
jmp 2f jmp 2f
// Clone scanning loop to miss instead of hang when cache is corrupt. // Clone scanning loop to miss instead of hang when cache is corrupt.
@ -378,18 +313,17 @@ LExit$0:
1: 1:
// loop // loop
cmpq $$1, (%r11) cmpq $$1, cached_sel(%r11)
jbe 3f // if (bucket->sel <= 1) wrap or miss jbe 3f // if (bucket->sel <= 1) wrap or miss
addq $$16, %r11 // bucket++ addq $$16, %r11 // bucket++
2: 2:
.if $0 != STRET .if $0 != STRET
cmpq (%r11), %a2 // if (bucket->sel != _cmd) cmpq cached_sel(%r11), %a2 // if (bucket->sel != _cmd)
.else .else
cmpq (%r11), %a3 // if (bucket->sel != _cmd) cmpq cached_sel(%r11), %a3 // if (bucket->sel != _cmd)
.endif .endif
jne 1b // scan more jne 1b // scan more
// CacheHit must always be preceded by a not-taken `jne` instruction
CacheHit $0, $1 // call or return imp CacheHit $0, $1 // call or return imp
3: 3:
@ -434,8 +368,7 @@ LExit$0:
push %a6 push %a6
movdqa %xmm7, -0x10(%rbp) movdqa %xmm7, -0x10(%rbp)
// _class_lookupMethodAndLoadCache3(receiver, selector, class) // lookUpImpOrForward(obj, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER)
.if $0 == NORMAL .if $0 == NORMAL
// receiver already in a1 // receiver already in a1
// selector already in a2 // selector already in a2
@ -444,7 +377,8 @@ LExit$0:
movq %a3, %a2 movq %a3, %a2
.endif .endif
movq %r10, %a3 movq %r10, %a3
call __class_lookupMethodAndLoadCache3 movl $$3, %a4d
call _lookUpImpOrForward
// IMP is now in %rax // IMP is now in %rax
movq %rax, %r11 movq %rax, %r11
@ -466,9 +400,9 @@ LExit$0:
movdqa -0x10(%rbp), %xmm7 movdqa -0x10(%rbp), %xmm7
.if $0 == NORMAL .if $0 == NORMAL
cmp %r11, %r11 // set eq for nonstret forwarding
.else
test %r11, %r11 // set ne for stret forwarding test %r11, %r11 // set ne for stret forwarding
.else
cmp %r11, %r11 // set eq for nonstret forwarding
.endif .endif
leave leave
@ -567,14 +501,13 @@ LNilOrTagged:
.else .else
movq %a2, %r11 movq %a2, %r11
.endif .endif
shrq $$60, %r11
cmpl $$0xf, %r11d
je 1f
// basic tagged // basic tagged
shrq $$60, %r11
leaq _objc_debug_taggedpointer_classes(%rip), %r10 leaq _objc_debug_taggedpointer_classes(%rip), %r10
movq (%r10, %r11, 8), %r10 // read isa from table movq (%r10, %r11, 8), %r10 // read isa from table
jmp LGetIsaDone_b leaq _OBJC_CLASS_$___NSUnrecognizedTaggedPointer(%rip), %r11
1: cmp %r10, %r11
jne LGetIsaDone_b
// ext tagged // ext tagged
.if $0 != STRET .if $0 != STRET
movq %a1, %r11 movq %a1, %r11
@ -602,7 +535,6 @@ LNil:
.else .else
.abort oops .abort oops
.endif .endif
MESSENGER_END_NIL
ret ret
.endmacro .endmacro
@ -671,7 +603,6 @@ _objc_debug_taggedpointer_ext_classes:
ENTRY _objc_msgSend ENTRY _objc_msgSend
UNWIND _objc_msgSend, NoFrame UNWIND _objc_msgSend, NoFrame
MESSENGER_START
GetIsaCheckNil NORMAL // r10 = self->isa, or return zero GetIsaCheckNil NORMAL // r10 = self->isa, or return zero
CacheLookup NORMAL, CALL // calls IMP on success CacheLookup NORMAL, CALL // calls IMP on success
@ -682,7 +613,6 @@ _objc_debug_taggedpointer_ext_classes:
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss:
// isa still in r10 // isa still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSend END_ENTRY _objc_msgSend
@ -728,7 +658,6 @@ LCacheMiss:
ENTRY _objc_msgSendSuper ENTRY _objc_msgSendSuper
UNWIND _objc_msgSendSuper, NoFrame UNWIND _objc_msgSendSuper, NoFrame
MESSENGER_START
// search the cache (objc_super in %a1) // search the cache (objc_super in %a1)
movq class(%a1), %r10 // class = objc_super->class movq class(%a1), %r10 // class = objc_super->class
@ -738,7 +667,6 @@ LCacheMiss:
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss:
// class still in r10 // class still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper END_ENTRY _objc_msgSendSuper
@ -750,7 +678,6 @@ LCacheMiss:
ENTRY _objc_msgSendSuper2 ENTRY _objc_msgSendSuper2
UNWIND _objc_msgSendSuper2, NoFrame UNWIND _objc_msgSendSuper2, NoFrame
MESSENGER_START
// objc_super->class is superclass of class to search // objc_super->class is superclass of class to search
@ -763,7 +690,6 @@ LCacheMiss:
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss:
// superclass still in r10 // superclass still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper2 END_ENTRY _objc_msgSendSuper2
@ -808,7 +734,6 @@ LCacheMiss:
ENTRY _objc_msgSend_fpret ENTRY _objc_msgSend_fpret
UNWIND _objc_msgSend_fpret, NoFrame UNWIND _objc_msgSend_fpret, NoFrame
MESSENGER_START
GetIsaCheckNil FPRET // r10 = self->isa, or return zero GetIsaCheckNil FPRET // r10 = self->isa, or return zero
CacheLookup FPRET, CALL // calls IMP on success CacheLookup FPRET, CALL // calls IMP on success
@ -819,7 +744,6 @@ LCacheMiss:
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss:
// isa still in r10 // isa still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSend_fpret END_ENTRY _objc_msgSend_fpret
@ -862,7 +786,6 @@ LCacheMiss:
ENTRY _objc_msgSend_fp2ret ENTRY _objc_msgSend_fp2ret
UNWIND _objc_msgSend_fp2ret, NoFrame UNWIND _objc_msgSend_fp2ret, NoFrame
MESSENGER_START
GetIsaCheckNil FP2RET // r10 = self->isa, or return zero GetIsaCheckNil FP2RET // r10 = self->isa, or return zero
CacheLookup FP2RET, CALL // calls IMP on success CacheLookup FP2RET, CALL // calls IMP on success
@ -873,7 +796,6 @@ LCacheMiss:
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss:
// isa still in r10 // isa still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSend_fp2ret END_ENTRY _objc_msgSend_fp2ret
@ -922,7 +844,6 @@ LCacheMiss:
ENTRY _objc_msgSend_stret ENTRY _objc_msgSend_stret
UNWIND _objc_msgSend_stret, NoFrame UNWIND _objc_msgSend_stret, NoFrame
MESSENGER_START
GetIsaCheckNil STRET // r10 = self->isa, or return zero GetIsaCheckNil STRET // r10 = self->isa, or return zero
CacheLookup STRET, CALL // calls IMP on success CacheLookup STRET, CALL // calls IMP on success
@ -933,7 +854,6 @@ LCacheMiss:
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss:
// isa still in r10 // isa still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_stret_uncached jmp __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSend_stret END_ENTRY _objc_msgSend_stret
@ -988,7 +908,6 @@ LCacheMiss:
ENTRY _objc_msgSendSuper_stret ENTRY _objc_msgSendSuper_stret
UNWIND _objc_msgSendSuper_stret, NoFrame UNWIND _objc_msgSendSuper_stret, NoFrame
MESSENGER_START
// search the cache (objc_super in %a2) // search the cache (objc_super in %a2)
movq class(%a2), %r10 // class = objc_super->class movq class(%a2), %r10 // class = objc_super->class
@ -998,7 +917,6 @@ LCacheMiss:
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss:
// class still in r10 // class still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_stret_uncached jmp __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSendSuper_stret END_ENTRY _objc_msgSendSuper_stret
@ -1010,7 +928,6 @@ LCacheMiss:
ENTRY _objc_msgSendSuper2_stret ENTRY _objc_msgSendSuper2_stret
UNWIND _objc_msgSendSuper2_stret, NoFrame UNWIND _objc_msgSendSuper2_stret, NoFrame
MESSENGER_START
// search the cache (objc_super in %a2) // search the cache (objc_super in %a2)
movq class(%a2), %r10 // class = objc_super->class movq class(%a2), %r10 // class = objc_super->class
@ -1021,7 +938,6 @@ LCacheMiss:
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss:
// superclass still in r10 // superclass still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_stret_uncached jmp __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSendSuper2_stret END_ENTRY _objc_msgSendSuper2_stret
@ -1132,11 +1048,7 @@ LCacheMiss:
// THIS IS NOT A CALLABLE C FUNCTION // THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band condition register is NE for stret, EQ otherwise. // Out-of-band condition register is NE for stret, EQ otherwise.
MESSENGER_START je __objc_msgForward_stret
nop
MESSENGER_END_SLOW
jne __objc_msgForward_stret
jmp __objc_msgForward jmp __objc_msgForward
END_ENTRY __objc_msgForward_impcache END_ENTRY __objc_msgForward_impcache

View File

@ -175,10 +175,11 @@ MISS:
mov eax, isa[edx] mov eax, isa[edx]
// MethodTableLookup WORD_RETURN, MSG_SEND // MethodTableLookup WORD_RETURN, MSG_SEND
push $3
push eax push eax
push ecx push ecx
push edx push edx
call _class_lookupMethodAndLoadCache3 call lookUpImpOrFoward
mov edx, kFwdMsgSend mov edx, kFwdMsgSend
leave leave
@ -244,10 +245,11 @@ MISS:
mov eax, isa[edx] mov eax, isa[edx]
// MethodTableLookup WORD_RETURN, MSG_SEND // MethodTableLookup WORD_RETURN, MSG_SEND
push $3
push eax push eax
push ecx push ecx
push edx push edx
call _class_lookupMethodAndLoadCache3 call lookUpImpOrFoward
mov edx, kFwdMsgSend mov edx, kFwdMsgSend
leave leave
@ -313,10 +315,11 @@ MISS:
mov eax, super_class[eax] mov eax, super_class[eax]
// MethodTableLookup WORD_RETURN, MSG_SENDSUPER // MethodTableLookup WORD_RETURN, MSG_SENDSUPER
push $3
push eax push eax
push ecx push ecx
push edx push edx
call _class_lookupMethodAndLoadCache3 call lookUpImpOrFoward
mov edx, kFwdMsgSend mov edx, kFwdMsgSend
leave leave
@ -375,10 +378,11 @@ MISS:
mov eax, isa[edx] mov eax, isa[edx]
// MethodTableLookup WORD_RETURN, MSG_SEND // MethodTableLookup WORD_RETURN, MSG_SEND
push $3
push eax push eax
push ecx push ecx
push edx push edx
call _class_lookupMethodAndLoadCache3 call lookUpImpOrFoward
mov edx, kFwdMsgSendStret mov edx, kFwdMsgSendStret
leave leave
@ -445,10 +449,11 @@ MISS:
mov eax, super_class[eax] mov eax, super_class[eax]
// MethodTableLookup WORD_RETURN, MSG_SENDSUPER // MethodTableLookup WORD_RETURN, MSG_SENDSUPER
push $3
push eax push eax
push ecx push ecx
push edx push edx
call _class_lookupMethodAndLoadCache3 call lookUpImpOrFoward
mov edx, kFwdMsgSendStret mov edx, kFwdMsgSendStret
leave leave

View File

@ -22,7 +22,9 @@
*/ */
#include <TargetConditionals.h> #include <TargetConditionals.h>
#if __x86_64__ && !TARGET_OS_SIMULATOR #if __x86_64__ && !(TARGET_OS_SIMULATOR && !TARGET_OS_IOSMAC)
#include "isa.h"
/******************************************************************** /********************************************************************
******************************************************************** ********************************************************************
@ -34,105 +36,37 @@
.data .data
// _objc_entryPoints and _objc_exitPoints are used by objc // _objc_restartableRanges is used by method dispatch
// to get the critical regions for which method caches // to get the critical regions for which method caches
// cannot be garbage collected. // cannot be garbage collected.
.align 4 .macro RestartableEntry
.private_extern _objc_entryPoints .quad LLookupStart$0
_objc_entryPoints: .short LLookupEnd$0 - LLookupStart$0
.quad _cache_getImp .short LCacheMiss$0 - LLookupStart$0
.quad _objc_msgSend .long 0
.quad _objc_msgSend_fpret
.quad _objc_msgSend_fp2ret
.quad _objc_msgSend_stret
.quad _objc_msgSendSuper
.quad _objc_msgSendSuper_stret
.quad _objc_msgSendSuper2
.quad _objc_msgSendSuper2_stret
.quad _objc_msgLookup
.quad _objc_msgLookup_fpret
.quad _objc_msgLookup_fp2ret
.quad _objc_msgLookup_stret
.quad _objc_msgLookupSuper2
.quad _objc_msgLookupSuper2_stret
.quad 0
.private_extern _objc_exitPoints
_objc_exitPoints:
.quad LExit_cache_getImp
.quad LExit_objc_msgSend
.quad LExit_objc_msgSend_fpret
.quad LExit_objc_msgSend_fp2ret
.quad LExit_objc_msgSend_stret
.quad LExit_objc_msgSendSuper
.quad LExit_objc_msgSendSuper_stret
.quad LExit_objc_msgSendSuper2
.quad LExit_objc_msgSendSuper2_stret
.quad LExit_objc_msgLookup
.quad LExit_objc_msgLookup_fpret
.quad LExit_objc_msgLookup_fp2ret
.quad LExit_objc_msgLookup_stret
.quad LExit_objc_msgLookupSuper2
.quad LExit_objc_msgLookupSuper2_stret
.quad 0
/********************************************************************
* List every exit insn from every messenger for debugger use.
* Format:
* (
* 1 word instruction's address
* 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
* )
* 1 word zero
*
* ENTER is the start of a dispatcher
* FAST_EXIT is method dispatch
* SLOW_EXIT is uncached method lookup
* NIL_EXIT is returning zero from a message sent to nil
* These must match objc-gdb.h.
********************************************************************/
#define ENTER 1
#define FAST_EXIT 2
#define SLOW_EXIT 3
#define NIL_EXIT 4
.section __DATA,__objc_msg_break
.globl _gdb_objc_messenger_breakpoints
_gdb_objc_messenger_breakpoints:
// contents populated by the macros below
.macro MESSENGER_START
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad ENTER
.text
.endmacro
.macro MESSENGER_END_FAST
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad FAST_EXIT
.text
.endmacro
.macro MESSENGER_END_SLOW
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad SLOW_EXIT
.text
.endmacro
.macro MESSENGER_END_NIL
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad NIL_EXIT
.text
.endmacro .endmacro
.align 4
.private_extern _objc_restartableRanges
_objc_restartableRanges:
RestartableEntry _cache_getImp
RestartableEntry _objc_msgSend
RestartableEntry _objc_msgSend_fpret
RestartableEntry _objc_msgSend_fp2ret
RestartableEntry _objc_msgSend_stret
RestartableEntry _objc_msgSendSuper
RestartableEntry _objc_msgSendSuper_stret
RestartableEntry _objc_msgSendSuper2
RestartableEntry _objc_msgSendSuper2_stret
RestartableEntry _objc_msgLookup
RestartableEntry _objc_msgLookup_fpret
RestartableEntry _objc_msgLookup_fp2ret
RestartableEntry _objc_msgLookup_stret
RestartableEntry _objc_msgLookupSuper2
RestartableEntry _objc_msgLookupSuper2_stret
.fill 16, 1, 0
/******************************************************************** /********************************************************************
* Recommended multi-byte NOP instructions * Recommended multi-byte NOP instructions
@ -181,9 +115,6 @@ _gdb_objc_messenger_breakpoints:
* DO NOT USE THESE LABELS ELSEWHERE * DO NOT USE THESE LABELS ELSEWHERE
* Reserved labels: 6: 7: 8: 9: * Reserved labels: 6: 7: 8: 9:
********************************************************************/ ********************************************************************/
#define LCacheMiss 6
#define LCacheMiss_f 6f
#define LCacheMiss_b 6b
#define LNilTestSlow 7 #define LNilTestSlow 7
#define LNilTestSlow_f 7f #define LNilTestSlow_f 7f
#define LNilTestSlow_b 7b #define LNilTestSlow_b 7b
@ -225,6 +156,10 @@ _gdb_objc_messenger_breakpoints:
#define method_name 0 #define method_name 0
#define method_imp 16 #define method_imp 16
// Method cache
#define cached_sel 0
#define cached_imp 8
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// //
@ -285,10 +220,15 @@ LExit$0:
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// //
// CacheLookup return-type, caller // CacheLookup return-type, caller, function
// //
// Locate the implementation for a class in a selector's method cache. // Locate the implementation for a class in a selector's method cache.
// //
// When this is used in a function that doesn't hold the runtime lock,
// this represents the critical section that may access dead memory.
// If the kernel causes one of these functions to go down the recovery
// path, we pretend the lookup failed by jumping the JumpMiss branch.
//
// Takes: // Takes:
// $0 = NORMAL, FPRET, FP2RET, STRET // $0 = NORMAL, FPRET, FP2RET, STRET
// $1 = CALL, LOOKUP, GETIMP // $1 = CALL, LOOKUP, GETIMP
@ -304,29 +244,30 @@ LExit$0:
.macro CacheHit .macro CacheHit
// CacheHit must always be preceded by a not-taken `jne` instruction
// in order to set the correct flags for _objc_msgForward_impcache.
// r11 = found bucket // r11 = found bucket
.if $1 == GETIMP .if $1 == GETIMP
movq 8(%r11), %rax // return imp movq cached_imp(%r11), %rax // return imp
ret cmpq $$0, %rax
jz 9f // don't xor a nil imp
xorq %r10, %rax // xor the isa with the imp
9: ret
.else .else
.if $0 != STRET
// eq already set for forwarding by `jne`
.else
test %r11, %r11 // set ne for stret forwarding
.endif
.if $1 == CALL .if $1 == CALL
MESSENGER_END_FAST movq cached_imp(%r11), %r11 // load imp
jmp *8(%r11) // call imp xorq %r10, %r11 // xor imp and isa
.if $0 != STRET
// ne already set for forwarding by `xor`
.else
cmp %r11, %r11 // set eq for stret forwarding
.endif
jmp *%r11 // call imp
.elseif $1 == LOOKUP .elseif $1 == LOOKUP
movq 8(%r11), %r11 // return imp movq cached_imp(%r11), %r11
xorq %r10, %r11 // return imp ^ isa
ret ret
.else .else
@ -339,6 +280,29 @@ LExit$0:
.macro CacheLookup .macro CacheLookup
//
// Restart protocol:
//
// As soon as we're past the LLookupStart$1 label we may have loaded
// an invalid cache pointer or mask.
//
// When task_restartable_ranges_synchronize() is called,
// (or when a signal hits us) before we're past LLookupEnd$1,
// then our PC will be reset to LCacheMiss$1 which forcefully
// jumps to the cache-miss codepath which have the following
// requirements:
//
// GETIMP:
// The cache-miss is just returning NULL (setting %rax to 0)
//
// NORMAL and STRET:
// - a1 or a2 (STRET) contains the receiver
// - a2 or a3 (STRET) contains the selector
// - r10 contains the isa
// - other registers are set as per calling conventions
//
LLookupStart$2:
.if $0 != STRET .if $0 != STRET
movq %a2, %r11 // r11 = _cmd movq %a2, %r11 // r11 = _cmd
.else .else
@ -349,35 +313,33 @@ LExit$0:
addq 16(%r10), %r11 // r11 = class->cache.buckets + offset addq 16(%r10), %r11 // r11 = class->cache.buckets + offset
.if $0 != STRET .if $0 != STRET
cmpq (%r11), %a2 // if (bucket->sel != _cmd) cmpq cached_sel(%r11), %a2 // if (bucket->sel != _cmd)
.else .else
cmpq (%r11), %a3 // if (bucket->sel != _cmd) cmpq cached_sel(%r11), %a3 // if (bucket->sel != _cmd)
.endif .endif
jne 1f // scan more jne 1f // scan more
// CacheHit must always be preceded by a not-taken `jne` instruction
CacheHit $0, $1 // call or return imp CacheHit $0, $1 // call or return imp
1: 1:
// loop // loop
cmpq $$1, (%r11) cmpq $$1, cached_sel(%r11)
jbe 3f // if (bucket->sel <= 1) wrap or miss jbe 3f // if (bucket->sel <= 1) wrap or miss
addq $$16, %r11 // bucket++ addq $$16, %r11 // bucket++
2: 2:
.if $0 != STRET .if $0 != STRET
cmpq (%r11), %a2 // if (bucket->sel != _cmd) cmpq cached_sel(%r11), %a2 // if (bucket->sel != _cmd)
.else .else
cmpq (%r11), %a3 // if (bucket->sel != _cmd) cmpq cached_sel(%r11), %a3 // if (bucket->sel != _cmd)
.endif .endif
jne 1b // scan more jne 1b // scan more
// CacheHit must always be preceded by a not-taken `jne` instruction
CacheHit $0, $1 // call or return imp CacheHit $0, $1 // call or return imp
3: 3:
// wrap or miss // wrap or miss
jb LCacheMiss_f // if (bucket->sel < 1) cache miss jb LCacheMiss$2 // if (bucket->sel < 1) cache miss
// wrap // wrap
movq 8(%r11), %r11 // bucket->imp is really first bucket movq cached_imp(%r11), %r11 // bucket->imp is really first bucket
jmp 2f jmp 2f
// Clone scanning loop to miss instead of hang when cache is corrupt. // Clone scanning loop to miss instead of hang when cache is corrupt.
@ -385,24 +347,24 @@ LExit$0:
1: 1:
// loop // loop
cmpq $$1, (%r11) cmpq $$1, cached_sel(%r11)
jbe 3f // if (bucket->sel <= 1) wrap or miss jbe 3f // if (bucket->sel <= 1) wrap or miss
addq $$16, %r11 // bucket++ addq $$16, %r11 // bucket++
2: 2:
.if $0 != STRET .if $0 != STRET
cmpq (%r11), %a2 // if (bucket->sel != _cmd) cmpq cached_sel(%r11), %a2 // if (bucket->sel != _cmd)
.else .else
cmpq (%r11), %a3 // if (bucket->sel != _cmd) cmpq cached_sel(%r11), %a3 // if (bucket->sel != _cmd)
.endif .endif
jne 1b // scan more jne 1b // scan more
// CacheHit must always be preceded by a not-taken `jne` instruction
CacheHit $0, $1 // call or return imp CacheHit $0, $1 // call or return imp
3: 3:
// double wrap or miss // double wrap or miss
jmp LCacheMiss_f jmp LCacheMiss$2
LLookupEnd$2:
.endmacro .endmacro
@ -441,8 +403,7 @@ LExit$0:
push %a6 push %a6
movdqa %xmm7, -0x10(%rbp) movdqa %xmm7, -0x10(%rbp)
// _class_lookupMethodAndLoadCache3(receiver, selector, class) // lookUpImpOrForward(obj, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER)
.if $0 == NORMAL .if $0 == NORMAL
// receiver already in a1 // receiver already in a1
// selector already in a2 // selector already in a2
@ -451,7 +412,8 @@ LExit$0:
movq %a3, %a2 movq %a3, %a2
.endif .endif
movq %r10, %a3 movq %r10, %a3
call __class_lookupMethodAndLoadCache3 movl $$3, %a4d
call _lookUpImpOrForward
// IMP is now in %rax // IMP is now in %rax
movq %rax, %r11 movq %rax, %r11
@ -473,9 +435,9 @@ LExit$0:
movdqa -0x10(%rbp), %xmm7 movdqa -0x10(%rbp), %xmm7
.if $0 == NORMAL .if $0 == NORMAL
cmp %r11, %r11 // set eq for nonstret forwarding test %r11, %r11 // set ne for nonstret forwarding
.else .else
test %r11, %r11 // set ne for stret forwarding cmp %r11, %r11 // set eq for stret forwarding
.endif .endif
leave leave
@ -503,13 +465,13 @@ LExit$0:
testb $$1, %a1b testb $$1, %a1b
PN PN
jnz LGetIsaSlow_f jnz LGetIsaSlow_f
movq $$0x00007ffffffffff8, %r10 movq $$ ISA_MASK, %r10
andq (%a1), %r10 andq (%a1), %r10
.else .else
testb $$1, %a2b testb $$1, %a2b
PN PN
jnz LGetIsaSlow_f jnz LGetIsaSlow_f
movq $$0x00007ffffffffff8, %r10 movq $$ ISA_MASK, %r10
andq (%a2), %r10 andq (%a2), %r10
.endif .endif
LGetIsaDone: LGetIsaDone:
@ -523,13 +485,12 @@ LGetIsaSlow:
movl %a2d, %r11d movl %a2d, %r11d
.endif .endif
andl $$0xF, %r11d andl $$0xF, %r11d
cmp $$0xF, %r11d
je 1f
// basic tagged // basic tagged
leaq _objc_debug_taggedpointer_classes(%rip), %r10 leaq _objc_debug_taggedpointer_classes(%rip), %r10
movq (%r10, %r11, 8), %r10 // read isa from table movq (%r10, %r11, 8), %r10 // read isa from table
jmp LGetIsaDone_b leaq _OBJC_CLASS_$___NSUnrecognizedTaggedPointer(%rip), %r11
1: cmp %r10, %r11
jne LGetIsaDone_b
// extended tagged // extended tagged
.if $0 != STRET .if $0 != STRET
movl %a1d, %r11d movl %a1d, %r11d
@ -642,7 +603,6 @@ LNilTestSlow:
.else .else
.abort oops .abort oops
.endif .endif
MESSENGER_END_NIL
ret ret
.endmacro .endmacro
@ -680,9 +640,10 @@ LNilTestSlow:
// do lookup // do lookup
movq %a1, %r10 // move class to r10 for CacheLookup movq %a1, %r10 // move class to r10 for CacheLookup
CacheLookup NORMAL, GETIMP // returns IMP on success // returns IMP on success
CacheLookup NORMAL, GETIMP, _cache_getImp
LCacheMiss: LCacheMiss_cache_getImp:
// cache miss, return nil // cache miss, return nil
xorl %eax, %eax xorl %eax, %eax
ret ret
@ -713,21 +674,20 @@ _objc_debug_taggedpointer_ext_classes:
ENTRY _objc_msgSend ENTRY _objc_msgSend
UNWIND _objc_msgSend, NoFrame UNWIND _objc_msgSend, NoFrame
MESSENGER_START
NilTest NORMAL NilTest NORMAL
GetIsaFast NORMAL // r10 = self->isa GetIsaFast NORMAL // r10 = self->isa
CacheLookup NORMAL, CALL // calls IMP on success // calls IMP on success
CacheLookup NORMAL, CALL, _objc_msgSend
NilTestReturnZero NORMAL NilTestReturnZero NORMAL
GetIsaSupport NORMAL GetIsaSupport NORMAL
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgSend:
// isa still in r10 // isa still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSend END_ENTRY _objc_msgSend
@ -738,14 +698,15 @@ LCacheMiss:
NilTest NORMAL NilTest NORMAL
GetIsaFast NORMAL // r10 = self->isa GetIsaFast NORMAL // r10 = self->isa
CacheLookup NORMAL, LOOKUP // returns IMP on success // returns IMP on success
CacheLookup NORMAL, LOOKUP, _objc_msgLookup
NilTestReturnIMP NORMAL NilTestReturnIMP NORMAL
GetIsaSupport NORMAL GetIsaSupport NORMAL
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgLookup:
// isa still in r10 // isa still in r10
jmp __objc_msgLookup_uncached jmp __objc_msgLookup_uncached
@ -776,17 +737,16 @@ LCacheMiss:
ENTRY _objc_msgSendSuper ENTRY _objc_msgSendSuper
UNWIND _objc_msgSendSuper, NoFrame UNWIND _objc_msgSendSuper, NoFrame
MESSENGER_START
// search the cache (objc_super in %a1) // search the cache (objc_super in %a1)
movq class(%a1), %r10 // class = objc_super->class movq class(%a1), %r10 // class = objc_super->class
movq receiver(%a1), %a1 // load real receiver movq receiver(%a1), %a1 // load real receiver
CacheLookup NORMAL, CALL // calls IMP on success // calls IMP on success
CacheLookup NORMAL, CALL, _objc_msgSendSuper
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgSendSuper:
// class still in r10 // class still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper END_ENTRY _objc_msgSendSuper
@ -798,7 +758,6 @@ LCacheMiss:
ENTRY _objc_msgSendSuper2 ENTRY _objc_msgSendSuper2
UNWIND _objc_msgSendSuper2, NoFrame UNWIND _objc_msgSendSuper2, NoFrame
MESSENGER_START
// objc_super->class is superclass of class to search // objc_super->class is superclass of class to search
@ -806,12 +765,12 @@ LCacheMiss:
movq class(%a1), %r10 // cls = objc_super->class movq class(%a1), %r10 // cls = objc_super->class
movq receiver(%a1), %a1 // load real receiver movq receiver(%a1), %a1 // load real receiver
movq 8(%r10), %r10 // cls = class->superclass movq 8(%r10), %r10 // cls = class->superclass
CacheLookup NORMAL, CALL // calls IMP on success // calls IMP on success
CacheLookup NORMAL, CALL, _objc_msgSendSuper2
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgSendSuper2:
// superclass still in r10 // superclass still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper2 END_ENTRY _objc_msgSendSuper2
@ -825,10 +784,11 @@ LCacheMiss:
movq class(%a1), %r10 // cls = objc_super->class movq class(%a1), %r10 // cls = objc_super->class
movq receiver(%a1), %a1 // load real receiver movq receiver(%a1), %a1 // load real receiver
movq 8(%r10), %r10 // cls = class->superclass movq 8(%r10), %r10 // cls = class->superclass
CacheLookup NORMAL, LOOKUP // returns IMP on success // returns IMP on success
CacheLookup NORMAL, LOOKUP, _objc_msgLookupSuper2
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgLookupSuper2:
// superclass still in r10 // superclass still in r10
jmp __objc_msgLookup_uncached jmp __objc_msgLookup_uncached
@ -856,21 +816,20 @@ LCacheMiss:
ENTRY _objc_msgSend_fpret ENTRY _objc_msgSend_fpret
UNWIND _objc_msgSend_fpret, NoFrame UNWIND _objc_msgSend_fpret, NoFrame
MESSENGER_START
NilTest FPRET NilTest FPRET
GetIsaFast FPRET // r10 = self->isa GetIsaFast FPRET // r10 = self->isa
CacheLookup FPRET, CALL // calls IMP on success // calls IMP on success
CacheLookup FPRET, CALL, _objc_msgSend_fpret
NilTestReturnZero FPRET NilTestReturnZero FPRET
GetIsaSupport FPRET GetIsaSupport FPRET
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgSend_fpret:
// isa still in r10 // isa still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSend_fpret END_ENTRY _objc_msgSend_fpret
@ -881,14 +840,15 @@ LCacheMiss:
NilTest FPRET NilTest FPRET
GetIsaFast FPRET // r10 = self->isa GetIsaFast FPRET // r10 = self->isa
CacheLookup FPRET, LOOKUP // returns IMP on success // returns IMP on success
CacheLookup FPRET, LOOKUP, _objc_msgLookup_fpret
NilTestReturnIMP FPRET NilTestReturnIMP FPRET
GetIsaSupport FPRET GetIsaSupport FPRET
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgLookup_fpret:
// isa still in r10 // isa still in r10
jmp __objc_msgLookup_uncached jmp __objc_msgLookup_uncached
@ -916,21 +876,20 @@ LCacheMiss:
ENTRY _objc_msgSend_fp2ret ENTRY _objc_msgSend_fp2ret
UNWIND _objc_msgSend_fp2ret, NoFrame UNWIND _objc_msgSend_fp2ret, NoFrame
MESSENGER_START
NilTest FP2RET NilTest FP2RET
GetIsaFast FP2RET // r10 = self->isa GetIsaFast FP2RET // r10 = self->isa
CacheLookup FP2RET, CALL // calls IMP on success // calls IMP on success
CacheLookup FP2RET, CALL, _objc_msgSend_fp2ret
NilTestReturnZero FP2RET NilTestReturnZero FP2RET
GetIsaSupport FP2RET GetIsaSupport FP2RET
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgSend_fp2ret:
// isa still in r10 // isa still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_uncached jmp __objc_msgSend_uncached
END_ENTRY _objc_msgSend_fp2ret END_ENTRY _objc_msgSend_fp2ret
@ -941,14 +900,15 @@ LCacheMiss:
NilTest FP2RET NilTest FP2RET
GetIsaFast FP2RET // r10 = self->isa GetIsaFast FP2RET // r10 = self->isa
CacheLookup FP2RET, LOOKUP // returns IMP on success // returns IMP on success
CacheLookup FP2RET, LOOKUP, _objc_msgLookup_fp2ret
NilTestReturnIMP FP2RET NilTestReturnIMP FP2RET
GetIsaSupport FP2RET GetIsaSupport FP2RET
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgLookup_fp2ret:
// isa still in r10 // isa still in r10
jmp __objc_msgLookup_uncached jmp __objc_msgLookup_uncached
@ -982,21 +942,20 @@ LCacheMiss:
ENTRY _objc_msgSend_stret ENTRY _objc_msgSend_stret
UNWIND _objc_msgSend_stret, NoFrame UNWIND _objc_msgSend_stret, NoFrame
MESSENGER_START
NilTest STRET NilTest STRET
GetIsaFast STRET // r10 = self->isa GetIsaFast STRET // r10 = self->isa
CacheLookup STRET, CALL // calls IMP on success // calls IMP on success
CacheLookup STRET, CALL, _objc_msgSend_stret
NilTestReturnZero STRET NilTestReturnZero STRET
GetIsaSupport STRET GetIsaSupport STRET
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgSend_stret:
// isa still in r10 // isa still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_stret_uncached jmp __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSend_stret END_ENTRY _objc_msgSend_stret
@ -1007,14 +966,15 @@ LCacheMiss:
NilTest STRET NilTest STRET
GetIsaFast STRET // r10 = self->isa GetIsaFast STRET // r10 = self->isa
CacheLookup STRET, LOOKUP // returns IMP on success // returns IMP on success
CacheLookup STRET, LOOKUP, _objc_msgLookup_stret
NilTestReturnIMP STRET NilTestReturnIMP STRET
GetIsaSupport STRET GetIsaSupport STRET
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgLookup_stret:
// isa still in r10 // isa still in r10
jmp __objc_msgLookup_stret_uncached jmp __objc_msgLookup_stret_uncached
@ -1054,17 +1014,16 @@ LCacheMiss:
ENTRY _objc_msgSendSuper_stret ENTRY _objc_msgSendSuper_stret
UNWIND _objc_msgSendSuper_stret, NoFrame UNWIND _objc_msgSendSuper_stret, NoFrame
MESSENGER_START
// search the cache (objc_super in %a2) // search the cache (objc_super in %a2)
movq class(%a2), %r10 // class = objc_super->class movq class(%a2), %r10 // class = objc_super->class
movq receiver(%a2), %a2 // load real receiver movq receiver(%a2), %a2 // load real receiver
CacheLookup STRET, CALL // calls IMP on success // calls IMP on success
CacheLookup STRET, CALL, _objc_msgSendSuper_stret
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgSendSuper_stret:
// class still in r10 // class still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_stret_uncached jmp __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSendSuper_stret END_ENTRY _objc_msgSendSuper_stret
@ -1076,18 +1035,17 @@ LCacheMiss:
ENTRY _objc_msgSendSuper2_stret ENTRY _objc_msgSendSuper2_stret
UNWIND _objc_msgSendSuper2_stret, NoFrame UNWIND _objc_msgSendSuper2_stret, NoFrame
MESSENGER_START
// search the cache (objc_super in %a2) // search the cache (objc_super in %a2)
movq class(%a2), %r10 // class = objc_super->class movq class(%a2), %r10 // class = objc_super->class
movq receiver(%a2), %a2 // load real receiver movq receiver(%a2), %a2 // load real receiver
movq 8(%r10), %r10 // class = class->superclass movq 8(%r10), %r10 // class = class->superclass
CacheLookup STRET, CALL // calls IMP on success // calls IMP on success
CacheLookup STRET, CALL, _objc_msgSendSuper2_stret
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgSendSuper2_stret:
// superclass still in r10 // superclass still in r10
MESSENGER_END_SLOW
jmp __objc_msgSend_stret_uncached jmp __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSendSuper2_stret END_ENTRY _objc_msgSendSuper2_stret
@ -1099,10 +1057,11 @@ LCacheMiss:
movq class(%a2), %r10 // class = objc_super->class movq class(%a2), %r10 // class = objc_super->class
movq receiver(%a2), %a2 // load real receiver movq receiver(%a2), %a2 // load real receiver
movq 8(%r10), %r10 // class = class->superclass movq 8(%r10), %r10 // class = class->superclass
CacheLookup STRET, LOOKUP // returns IMP on success // returns IMP on success
CacheLookup STRET, LOOKUP, _objc_msgLookupSuper2_stret
// cache miss: go search the method lists // cache miss: go search the method lists
LCacheMiss: LCacheMiss_objc_msgLookupSuper2_stret:
// superclass still in r10 // superclass still in r10
jmp __objc_msgLookup_stret_uncached jmp __objc_msgLookup_stret_uncached
@ -1201,11 +1160,7 @@ LCacheMiss:
// THIS IS NOT A CALLABLE C FUNCTION // THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band condition register is NE for stret, EQ otherwise. // Out-of-band condition register is NE for stret, EQ otherwise.
MESSENGER_START je __objc_msgForward_stret
nop
MESSENGER_END_SLOW
jne __objc_msgForward_stret
jmp __objc_msgForward jmp __objc_msgForward
END_ENTRY __objc_msgForward_impcache END_ENTRY __objc_msgForward_impcache
@ -1281,49 +1236,4 @@ LCacheMiss:
.quad 0 .quad 0
.quad 0 .quad 0
// Workaround for Skype evil (rdar://19715989)
.text
.align 4
.private_extern _map_images
.private_extern _map_2_images
.private_extern _hax
_hax:
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
_map_images:
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
jmp _map_2_images
#endif #endif

View File

@ -0,0 +1,437 @@
---
Name: ObjectiveC
Classes:
- Name: NSArray
SwiftBridge: 'Swift.Array'
- Name: NSDictionary
SwiftBridge: 'Swift.Dictionary'
- Name: NSSet
SwiftBridge: 'Swift.Set'
- Name: NSString
SwiftBridge: 'Swift.String'
- Name: List
Methods:
- Selector: init
MethodKind: Instance
NullabilityOfRet: N
- Selector: 'isEqual:'
MethodKind: Instance
Nullability:
- O
NullabilityOfRet: S
- Name: NSObject
SwiftName: NSObject
Methods:
- Selector: alloc
MethodKind: Class
NullabilityOfRet: N
- Selector: 'allocWithZone:'
MethodKind: Class
Nullability:
- S
NullabilityOfRet: N
- Selector: class
MethodKind: Class
Availability: nonswift
AvailabilityMsg: use 'self' instead
- Selector: 'conformsToProtocol:'
MethodKind: Class
Nullability:
- N
NullabilityOfRet: S
- Selector: copy
MethodKind: Instance
NullabilityOfRet: N
- Selector: dealloc
MethodKind: Instance
Availability: nonswift
AvailabilityMsg: use 'deinit' to define a de-initializer
- Selector: debugDescription
MethodKind: Class
NullabilityOfRet: N
- Selector: description
MethodKind: Class
NullabilityOfRet: N
- Selector: 'forwardingTargetForSelector:'
MethodKind: Instance
Nullability:
- S
NullabilityOfRet: O
- Selector: 'forwardInvocation:'
MethodKind: Instance
Availability: nonswift
- Selector: init
MethodKind: Instance
NullabilityOfRet: N
DesignatedInit: true
- Selector: 'instanceMethodSignatureForSelector:'
MethodKind: Class
Availability: nonswift
- Selector: 'isSubclassOfClass:'
MethodKind: Class
Nullability:
- N
NullabilityOfRet: S
- Selector: 'methodSignatureForSelector:'
MethodKind: Instance
Availability: nonswift
- Selector: mutableCopy
MethodKind: Instance
NullabilityOfRet: N
- Selector: new
MethodKind: Class
NullabilityOfRet: N
- Selector: superclass
MethodKind: Class
NullabilityOfRet: O
- Name: Object
Methods:
- Selector: init
MethodKind: Instance
NullabilityOfRet: N
- Selector: 'isEqual:'
MethodKind: Instance
Nullability:
- O
NullabilityOfRet: S
Protocols:
- Name: NSObject
SwiftName: NSObjectProtocol
Methods:
- Selector: class
MethodKind: Instance
Availability: nonswift
AvailabilityMsg: use 'type(of:)' instead
- Selector: 'conformsToProtocol:'
MethodKind: Instance
Nullability:
- N
NullabilityOfRet: S
- Selector: 'isEqual:'
MethodKind: Instance
Nullability:
- O
NullabilityOfRet: S
- Selector: 'isKindOfClass:'
MethodKind: Instance
Nullability:
- N
NullabilityOfRet: S
- Selector: 'isMemberOfClass:'
MethodKind: Instance
Nullability:
- N
NullabilityOfRet: S
- Selector: self
MethodKind: Instance
NullabilityOfRet: N
Properties:
- Name: debugDescription
Nullability: N
- Name: description
Nullability: N
- Name: superclass
Nullability: O
Tags:
- Name: _NSZone
SwiftName: _NSZone
# Runtime functions did not yet have nullability in Swift 3.
SwiftVersions:
- Version: 3
Functions:
# objc.h swift3
- Name: object_getClassName
NullabilityOfRet: U
Nullability: [U]
- Name: sel_isMapped
Nullability: [U]
- Name: sel_getUid
NullabilityOfRet: U
Nullability: [U]
# objc-exception.h swift3
- Name: objc_exception_throw
Nullability: [U]
- Name: objc_begin_catch
NullabilityOfRet: U
Nullability: [U]
- Name: objc_setExceptionPreprocessor
NullabilityOfRet: U
Nullability: [U]
- Name: objc_setExceptionMatcher
NullabilityOfRet: U
Nullability: [U]
- Name: objc_setUncaughtExceptionHandler
NullabilityOfRet: U
Nullability: [U]
- Name: objc_addExceptionHandler
Nullability: [U, U]
# objc-sync.h swift3
- Name: objc_sync_enter
Nullability: [U]
- Name: objc_sync_exit
Nullability: [U]
# runtime.h swift3
- Name: object_getClass
NullabilityOfRet: U
Nullability: [U]
- Name: object_setClass
NullabilityOfRet: U
Nullability: [U, U]
- Name: object_isClass
Nullability: [U]
- Name: object_getIvar
NullabilityOfRet: U
Nullability: [U, U]
- Name: object_setIvar
Nullability: [U, U, U]
- Name: object_setIvarWithStrongDefault
Nullability: [U, U, U]
- Name: objc_getClass
NullabilityOfRet: U
Nullability: [U]
- Name: objc_getMetaClass
NullabilityOfRet: U
Nullability: [U]
- Name: objc_lookUpClass
NullabilityOfRet: U
Nullability: [U]
- Name: objc_getRequiredClass
NullabilityOfRet: U
Nullability: [U]
- Name: objc_getClassList
Parameters:
- Position: 0
Type: "Class _Nullable * _Null_unspecified"
- Name: objc_copyClassList
ResultType: "Class _Nullable * _Null_unspecified"
Nullability: [U]
- Name: class_getName
NullabilityOfRet: U
Nullability: [U]
- Name: class_isMetaClass
Nullability: [U]
- Name: class_getSuperclass
NullabilityOfRet: U
Nullability: [U]
- Name: class_getVersion
Nullability: [U]
- Name: class_setVersion
Nullability: [U]
- Name: class_getInstanceSize
Nullability: [U]
- Name: class_getInstanceVariable
NullabilityOfRet: U
Nullability: [U, U]
- Name: class_getClassVariable
NullabilityOfRet: U
Nullability: [U, U]
- Name: class_copyIvarList
ResultType: "Ivar _Nullable * _Null_unspecified"
Nullability: [U, U]
- Name: class_getInstanceMethod
NullabilityOfRet: U
Nullability: [U, U]
- Name: class_getClassMethod
NullabilityOfRet: U
Nullability: [U, U]
- Name: class_getMethodImplementation
NullabilityOfRet: U
Nullability: [U, U]
- Name: class_getMethodImplementation_stret
NullabilityOfRet: U
Nullability: [U, U]
- Name: class_respondsToSelector
Nullability: [U, U]
- Name: class_copyMethodList
Nullability: [U, U]
ResultType: "Method _Nullable * _Null_unspecified"
- Name: class_conformsToProtocol
Nullability: [U, U]
- Name: class_copyProtocolList
# fixme ResultType:
NullabilityOfRet: U
Nullability: [U, U]
- Name: class_getProperty
NullabilityOfRet: U
Nullability: [U, U]
- Name: class_copyPropertyList
ResultType: "objc_property_t _Nullable * _Null_unspecified"
Nullability: [U, U]
- Name: class_getIvarLayout
NullabilityOfRet: U
Nullability: [U]
- Name: class_getWeakIvarLayout
NullabilityOfRet: U
Nullability: [U]
- Name: class_addMethod
Nullability: [U, U, U, U]
- Name: class_replaceMethod
NullabilityOfRet: U
Nullability: [U, U, U, U]
- Name: class_addIvar
Nullability: [U, U, U, U, U]
- Name: class_addProtocol
Nullability: [U, U]
- Name: class_addProperty
Nullability: [U, U, U, U]
- Name: class_replaceProperty
Nullability: [U, U, U, U]
- Name: class_setIvarLayout
Nullability: [U, U]
- Name: class_setWeakIvarLayout
Nullability: [U, U]
- Name: class_createInstance
NullabilityOfRet: U
Nullability: [U, U]
- Name: objc_allocateClassPair
NullabilityOfRet: U
Nullability: [U, U, U]
- Name: objc_registerClassPair
Nullability: [U]
- Name: objc_duplicateClass
NullabilityOfRet: U
Nullability: [U, U, U]
- Name: objc_disposeClassPair
Nullability: [U]
- Name: method_getName
NullabilityOfRet: U
Nullability: [U]
- Name: method_getImplementation
NullabilityOfRet: U
Nullability: [U]
- Name: method_getTypeEncoding
NullabilityOfRet: U
Nullability: [U]
- Name: method_getNumberOfArguments
Nullability: [U]
- Name: method_copyReturnType
NullabilityOfRet: U
Nullability: [U]
- Name: method_copyArgumentType
NullabilityOfRet: U
Nullability: [U, U]
- Name: method_getReturnType
Nullability: [U, U, U]
- Name: method_getArgumentType
Nullability: [U, U, U, U]
- Name: method_getDescription
NullabilityOfRet: U
Nullability: [U]
- Name: method_setImplementation
NullabilityOfRet: U
Nullability: [U, U]
- Name: method_exchangeImplementations
Nullability: [U, U]
- Name: ivar_getName
NullabilityOfRet: U
Nullability: [U]
- Name: ivar_getTypeEncoding
NullabilityOfRet: U
Nullability: [U]
- Name: ivar_getOffset
Nullability: [U]
- Name: property_getName
NullabilityOfRet: U
Nullability: [U]
- Name: property_getAttributes
NullabilityOfRet: U
Nullability: [U]
- Name: property_copyAttributeList
NullabilityOfRet: U
Nullability: [U, U]
- Name: property_copyAttributeValue
NullabilityOfRet: U
Nullability: [U, U]
- Name: objc_getProtocol
NullabilityOfRet: U
Nullability: [U]
- Name: objc_copyProtocolList
# fixme ResultType:
NullabilityOfRet: U
Nullability: [U]
- Name: protocol_conformsToProtocol
Nullability: [U, U]
- Name: protocol_isEqual
Nullability: [U, U]
- Name: protocol_getName
NullabilityOfRet: U
Nullability: [U]
- Name: protocol_getMethodDescription
Nullability: [U, U, U, U]
- Name: protocol_copyMethodDescriptionList
NullabilityOfRet: U
Nullability: [U, U, U, U]
- Name: protocol_getProperty
NullabilityOfRet: U
Nullability: [U, U, U, U]
- Name: protocol_copyPropertyList
ResultType: "objc_property_t _Nullable * _Null_unspecified"
Nullability: [U, U]
- Name: protocol_copyPropertyList2
ResultType: "objc_property_t _Nullable * _Null_unspecified"
Nullability: [U, U, U, U]
- Name: protocol_copyProtocolList
# fixme ResultType:
NullabilityOfRet: U
Nullability: [U, U]
- Name: objc_allocateProtocol
NullabilityOfRet: U
Nullability: [U]
- Name: objc_registerProtocol
Nullability: [U]
- Name: protocol_addMethodDescription
Nullability: [U, U, U, U, U]
- Name: protocol_addProtocol
Nullability: [U, U]
- Name: protocol_addProperty
Nullability: [U, U, U, U, U, U]
- Name: objc_copyImageNames
ResultType: "const char * _Nullable * _Null_unspecified"
Nullability: [U]
- Name: class_getImageName
NullabilityOfRet: U
Nullability: [U]
- Name: objc_copyClassNamesForImage
ResultType: "const char * _Nullable * _Null_unspecified"
Nullability: [U, U]
- Name: sel_getName
NullabilityOfRet: U
Nullability: [U]
- Name: sel_registerName
NullabilityOfRet: U
Nullability: [U]
- Name: sel_isEqual
Nullability: [U, U]
- Name: objc_enumerationMutation
Nullability: [U]
- Name: objc_setEnumerationMutationHandler
Nullability: [U]
- Name: objc_setForwardHandler
Nullability: [U, U]
- Name: imp_implementationWithBlock
NullabilityOfRet: U
Nullability: [U]
- Name: imp_getBlock
NullabilityOfRet: U
Nullability: [U]
- Name: imp_removeBlock
Nullability: [U]
- Name: objc_loadWeak
NullabilityOfRet: U
Nullability: [U]
- Name: objc_storeWeak
NullabilityOfRet: U
Nullability: [U, U]
- Name: objc_setAssociatedObject
Nullability: [U, U, U, U]
- Name: objc_getAssociatedObject
NullabilityOfRet: U
Nullability: [U, U]
- Name: objc_removeAssociatedObjects
Nullability: [U]

View File

@ -0,0 +1,40 @@
module ObjectiveC [system] [extern_c] {
umbrella "."
export *
module * {
export *
}
module NSObject {
requires objc
header "NSObject.h"
export *
}
#if defined(BUILD_FOR_OSX)
module List {
// Uses @defs, which does not work in ObjC++ or non-ARC.
requires objc, !objc_arc, !cplusplus
header "List.h"
export *
}
module Object {
requires objc
header "Object.h"
export *
}
module Protocol {
requires objc
header "Protocol.h"
export *
}
#endif
#if !defined(BUILD_FOR_OSX)
// These file are not available outside macOS.
exclude header "hashtable.h"
exclude header "hashtable2.h"
#endif
}

View File

@ -8,7 +8,7 @@
#include <TargetConditionals.h> #include <TargetConditionals.h>
#include <objc/objc.h> #include <objc/objc.h>
#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 #if __LP64__ || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger; typedef long NSInteger;
typedef unsigned long NSUInteger; typedef unsigned long NSUInteger;
#else #else

161
runtime/NSObject-internal.h Normal file
View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2019 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 _NSOBJECT_INTERNAL_H
#define _NSOBJECT_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.
*/
/*
* NSObject-internal.h: Private SPI for use by other system frameworks.
*/
/***********************************************************************
Autorelease pool implementation
A thread's autorelease pool is a stack of pointers.
Each pointer is either an object to release, or POOL_BOUNDARY which is
an autorelease pool boundary.
A pool token is a pointer to the POOL_BOUNDARY for that pool. When
the pool is popped, every object hotter than the sentinel is released.
The stack is divided into a doubly-linked list of pages. Pages are added
and deleted as necessary.
Thread-local storage points to the hot page, where newly autoreleased
objects are stored.
**********************************************************************/
// structure version number. Only bump if ABI compatability is broken
#define AUTORELEASEPOOL_VERSION 1
// Set this to 1 to mprotect() autorelease pool contents
#define PROTECT_AUTORELEASEPOOL 0
// Set this to 1 to validate the entire autorelease pool header all the time
// (i.e. use check() instead of fastcheck() everywhere)
#define CHECK_AUTORELEASEPOOL (DEBUG)
#ifdef __cplusplus
#include <string.h>
#include <assert.h>
#include <objc/objc.h>
#include <pthread.h>
#ifndef C_ASSERT
#if __has_feature(cxx_static_assert)
#define C_ASSERT(expr) static_assert(expr, "(" #expr ")!")
#elif __has_feature(c_static_assert)
#define C_ASSERT(expr) _Static_assert(expr, "(" #expr ")!")
#else
#define C_ASSERT(expr)
#endif
#endif
// Make ASSERT work when objc-private.h hasn't been included.
#ifndef ASSERT
#define ASSERT(x) assert(x)
#endif
struct magic_t {
static const uint32_t M0 = 0xA1A1A1A1;
# define M1 "AUTORELEASE!"
static const size_t M1_len = 12;
uint32_t m[4];
magic_t() {
ASSERT(M1_len == strlen(M1));
ASSERT(M1_len == 3 * sizeof(m[1]));
m[0] = M0;
strncpy((char *)&m[1], M1, M1_len);
}
~magic_t() {
// Clear magic before deallocation.
// This prevents some false positives in memory debugging tools.
// fixme semantically this should be memset_s(), but the
// compiler doesn't optimize that at all (rdar://44856676).
volatile uint64_t *p = (volatile uint64_t *)m;
p[0] = 0; p[1] = 0;
}
bool check() const {
return (m[0] == M0 && 0 == strncmp((char *)&m[1], M1, M1_len));
}
bool fastcheck() const {
#if CHECK_AUTORELEASEPOOL
return check();
#else
return (m[0] == M0);
#endif
}
# undef M1
};
class AutoreleasePoolPage;
struct AutoreleasePoolPageData
{
magic_t const magic;
__unsafe_unretained id *next;
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
AutoreleasePoolPageData(__unsafe_unretained id* _next, pthread_t _thread, AutoreleasePoolPage* _parent, uint32_t _depth, uint32_t _hiwat)
: magic(), next(_next), thread(_thread),
parent(_parent), child(nil),
depth(_depth), hiwat(_hiwat)
{
}
};
struct thread_data_t
{
#ifdef __LP64__
pthread_t const thread;
uint32_t const hiwat;
uint32_t const depth;
#else
pthread_t const thread;
uint32_t const hiwat;
uint32_t const depth;
uint32_t padding;
#endif
};
C_ASSERT(sizeof(thread_data_t) == 16);
#undef C_ASSERT
#endif
#endif

View File

@ -18,7 +18,7 @@
@property (readonly) NSUInteger hash; @property (readonly) NSUInteger hash;
@property (readonly) Class superclass; @property (readonly) Class superclass;
- (Class)class OBJC_SWIFT_UNAVAILABLE("use 'anObject.dynamicType' instead"); - (Class)class OBJC_SWIFT_UNAVAILABLE("use 'type(of: anObject)' instead");
- (instancetype)self; - (instancetype)self;
- (id)performSelector:(SEL)aSelector; - (id)performSelector:(SEL)aSelector;
@ -47,11 +47,14 @@
@end @end
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
OBJC_ROOT_CLASS OBJC_ROOT_CLASS
OBJC_EXPORT OBJC_EXPORT
@interface NSObject <NSObject> { @interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY; Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
} }
+ (void)load; + (void)load;
@ -82,7 +85,7 @@ OBJC_EXPORT
+ (IMP)instanceMethodForSelector:(SEL)aSelector; + (IMP)instanceMethodForSelector:(SEL)aSelector;
- (void)doesNotRecognizeSelector:(SEL)aSelector; - (void)doesNotRecognizeSelector:(SEL)aSelector;
- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); - (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE(""); - (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE(""); - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");
@ -93,8 +96,8 @@ OBJC_EXPORT
+ (BOOL)isSubclassOfClass:(Class)aClass; + (BOOL)isSubclassOfClass:(Class)aClass;
+ (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); + (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
+ (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); + (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
+ (NSUInteger)hash; + (NSUInteger)hash;
+ (Class)superclass; + (Class)superclass;

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,8 @@
#if __OBJC__ && !__OBJC2__ #if __OBJC__ && !__OBJC2__
__OSX_AVAILABLE(10.0) __OSX_AVAILABLE(10.0)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __IOS_UNAVAILABLE __TVOS_UNAVAILABLE
__WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE
OBJC_ROOT_CLASS OBJC_ROOT_CLASS
@interface Object @interface Object
{ {

View File

@ -35,14 +35,6 @@ typedef struct objc_object *id;
#if __OBJC2__ #if __OBJC2__
__OSX_AVAILABLE(10.0)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE
OBJC_ROOT_CLASS
@interface Object {
Class isa;
}
@end
@implementation Object @implementation Object
+ (id)initialize + (id)initialize

182
runtime/PointerUnion.h Normal file
View File

@ -0,0 +1,182 @@
/*
* Copyright (c) 2019 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 POINTERUNION_H
#define POINTERUNION_H
#include <cstdint>
#include <atomic>
namespace objc {
template <typename T> struct PointerUnionTypeSelectorReturn {
using Return = T;
};
/// Get a type based on whether two types are the same or not.
///
/// For:
///
/// \code
/// using Ret = typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return;
/// \endcode
///
/// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
struct PointerUnionTypeSelector {
using Return = typename PointerUnionTypeSelectorReturn<RET_NE>::Return;
};
template <typename T, typename RET_EQ, typename RET_NE>
struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> {
using Return = typename PointerUnionTypeSelectorReturn<RET_EQ>::Return;
};
template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
struct PointerUnionTypeSelectorReturn<
PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>> {
using Return =
typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return;
};
template <class PT1, class PT2>
class PointerUnion {
uintptr_t _value;
static_assert(alignof(PT1) >= 2, "alignment requirement");
static_assert(alignof(PT2) >= 2, "alignment requirement");
struct IsPT1 {
static const uintptr_t Num = 0;
};
struct IsPT2 {
static const uintptr_t Num = 1;
};
template <typename T> struct UNION_DOESNT_CONTAIN_TYPE {};
uintptr_t getPointer() const {
return _value & ~1;
}
uintptr_t getTag() const {
return _value & 1;
}
public:
explicit PointerUnion(const std::atomic<uintptr_t> &raw)
: _value(raw.load(std::memory_order_relaxed))
{ }
PointerUnion(PT1 t) : _value((uintptr_t)t) { }
PointerUnion(PT2 t) : _value((uintptr_t)t | 1) { }
void storeAt(std::atomic<uintptr_t> &raw, std::memory_order order) const {
raw.store(_value, order);
}
template <typename T>
bool is() const {
using Ty = typename PointerUnionTypeSelector<PT1, T, IsPT1,
PointerUnionTypeSelector<PT2, T, IsPT2,
UNION_DOESNT_CONTAIN_TYPE<T>>>::Return;
return getTag() == Ty::Num;
}
template <typename T> T get() const {
ASSERT(is<T>() && "Invalid accessor called");
return reinterpret_cast<T>(getPointer());
}
template <typename T> T dyn_cast() const {
if (is<T>())
return get<T>();
return T();
}
};
template <class PT1, class PT2, class PT3, class PT4 = void>
class PointerUnion4 {
uintptr_t _value;
static_assert(alignof(PT1) >= 4, "alignment requirement");
static_assert(alignof(PT2) >= 4, "alignment requirement");
static_assert(alignof(PT3) >= 4, "alignment requirement");
static_assert(alignof(PT4) >= 4, "alignment requirement");
struct IsPT1 {
static const uintptr_t Num = 0;
};
struct IsPT2 {
static const uintptr_t Num = 1;
};
struct IsPT3 {
static const uintptr_t Num = 2;
};
struct IsPT4 {
static const uintptr_t Num = 3;
};
template <typename T> struct UNION_DOESNT_CONTAIN_TYPE {};
uintptr_t getPointer() const {
return _value & ~3;
}
uintptr_t getTag() const {
return _value & 3;
}
public:
explicit PointerUnion4(const std::atomic<uintptr_t> &raw)
: _value(raw.load(std::memory_order_relaxed))
{ }
PointerUnion4(PT1 t) : _value((uintptr_t)t) { }
PointerUnion4(PT2 t) : _value((uintptr_t)t | 1) { }
PointerUnion4(PT3 t) : _value((uintptr_t)t | 2) { }
PointerUnion4(PT4 t) : _value((uintptr_t)t | 3) { }
void storeAt(std::atomic<uintptr_t> &raw, std::memory_order order) const {
raw.store(_value, order);
}
template <typename T>
bool is() const {
using Ty = typename PointerUnionTypeSelector<PT1, T, IsPT1,
PointerUnionTypeSelector<PT2, T, IsPT2,
PointerUnionTypeSelector<PT3, T, IsPT3,
PointerUnionTypeSelector<PT4, T, IsPT4,
UNION_DOESNT_CONTAIN_TYPE<T>>>>>::Return;
return getTag() == Ty::Num;
}
template <typename T> T get() const {
ASSERT(is<T>() && "Invalid accessor called");
return reinterpret_cast<T>(getPointer());
}
template <typename T> T dyn_cast() const {
if (is<T>())
return get<T>();
return T();
}
};
} // namespace objc
#endif /* DENSEMAPEXTRAS_H */

View File

@ -41,7 +41,7 @@
// All methods of class Protocol are unavailable. // All methods of class Protocol are unavailable.
// Use the functions in objc/runtime.h instead. // Use the functions in objc/runtime.h instead.
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
@interface Protocol : NSObject @interface Protocol : NSObject
@end @end
@ -50,7 +50,7 @@ OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0)
#include <objc/Object.h> #include <objc/Object.h>
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
@interface Protocol : Object @interface Protocol : Object
{ {
@private @private
@ -74,12 +74,20 @@ OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0)
__OSX_DEPRECATED(10.0, 10.5, "use protocol_getMethodDescription instead") __OSX_DEPRECATED(10.0, 10.5, "use protocol_getMethodDescription instead")
__IOS_DEPRECATED(2.0, 2.0, "use protocol_getMethodDescription instead") __IOS_DEPRECATED(2.0, 2.0, "use protocol_getMethodDescription instead")
__TVOS_DEPRECATED(9.0, 9.0, "use protocol_getMethodDescription instead") __TVOS_DEPRECATED(9.0, 9.0, "use protocol_getMethodDescription instead")
__WATCHOS_DEPRECATED(1.0, 1.0, "use protocol_getMethodDescription instead"); __WATCHOS_DEPRECATED(1.0, 1.0, "use protocol_getMethodDescription instead")
#ifndef __APPLE_BLEACH_SDK__
__BRIDGEOS_DEPRECATED(2.0, 2.0, "use protocol_getMethodDescription instead")
#endif
;
- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel - (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel
__OSX_DEPRECATED(10.0, 10.5, "use protocol_getMethodDescription instead") __OSX_DEPRECATED(10.0, 10.5, "use protocol_getMethodDescription instead")
__IOS_DEPRECATED(2.0, 2.0, "use protocol_getMethodDescription instead") __IOS_DEPRECATED(2.0, 2.0, "use protocol_getMethodDescription instead")
__TVOS_DEPRECATED(9.0, 9.0, "use protocol_getMethodDescription instead") __TVOS_DEPRECATED(9.0, 9.0, "use protocol_getMethodDescription instead")
__WATCHOS_DEPRECATED(1.0, 1.0, "use protocol_getMethodDescription instead"); __WATCHOS_DEPRECATED(1.0, 1.0, "use protocol_getMethodDescription instead")
#ifndef __APPLE_BLEACH_SDK__
__BRIDGEOS_DEPRECATED(2.0, 2.0, "use protocol_getMethodDescription instead")
#endif
;
@end @end

View File

@ -45,22 +45,20 @@
// by CF, so __IncompleteProtocol would be left without an R/R implementation // by CF, so __IncompleteProtocol would be left without an R/R implementation
// otherwise, which would break ARC. // otherwise, which would break ARC.
@interface __IncompleteProtocol : NSObject @end @interface __IncompleteProtocol : NSObject
@implementation __IncompleteProtocol @end
#if __OBJC2__ #if __OBJC2__
// fixme hack - make __IncompleteProtocol a non-lazy class __attribute__((objc_nonlazy_class))
+ (void) load { }
#endif #endif
@implementation __IncompleteProtocol
@end @end
@implementation Protocol
#if __OBJC2__ #if __OBJC2__
// fixme hack - make Protocol a non-lazy class __attribute__((objc_nonlazy_class))
+ (void) load { }
#endif #endif
@implementation Protocol
- (BOOL) conformsTo: (Protocol *)aProtocolObj - (BOOL) conformsTo: (Protocol *)aProtocolObj
{ {

View File

@ -1,148 +0,0 @@
#if __arm__
#include <arm/arch.h>
#include <mach/vm_param.h>
.syntax unified
.text
.private_extern __a1a2_tramphead
.private_extern __a1a2_firsttramp
.private_extern __a1a2_trampend
// Trampoline machinery assumes the trampolines are Thumb function pointers
#if !__thumb2__
# error sorry
#endif
.thumb
.thumb_func __a1a2_tramphead
.thumb_func __a1a2_firsttramp
.thumb_func __a1a2_trampend
.align PAGE_MAX_SHIFT
__a1a2_tramphead:
/*
r0 == self
r12 == pc of trampoline's first instruction + PC bias
lr == original return address
*/
mov r1, r0 // _cmd = self
// Trampoline's data is one page before the trampoline text.
// Also correct PC bias of 4 bytes.
sub r12, #PAGE_MAX_SIZE
ldr r0, [r12, #-4] // self = block object
ldr pc, [r0, #12] // tail call block->invoke
// not reached
// Align trampolines to 8 bytes
.align 3
.macro TrampolineEntry
mov r12, pc
b __a1a2_tramphead
.align 3
.endmacro
.macro TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
.endmacro
.macro TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
.endmacro
.private_extern __a1a2_firsttramp
__a1a2_firsttramp:
// 2048-2 trampolines to fill 16K page
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
.private_extern __a1a2_trampend
__a1a2_trampend:
#endif

View File

@ -1,566 +0,0 @@
/*
* 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@
*/
#ifdef __i386__
#include <mach/vm_param.h>
.text
.private_extern __a1a2_tramphead
.private_extern __a1a2_firsttramp
.private_extern __a1a2_nexttramp
.private_extern __a1a2_trampend
.align PAGE_SHIFT
__a1a2_tramphead:
popl %eax
andl $0xFFFFFFF8, %eax
subl $ PAGE_SIZE, %eax
movl 4(%esp), %ecx // self -> ecx
movl %ecx, 8(%esp) // ecx -> _cmd
movl (%eax), %ecx // blockPtr -> ecx
movl %ecx, 4(%esp) // ecx -> self
jmp *12(%ecx) // tail to block->invoke
.macro TrampolineEntry
call __a1a2_tramphead
nop
nop
nop
.endmacro
.align 5
__a1a2_firsttramp:
TrampolineEntry
__a1a2_nexttramp: // used to calculate size of each trampoline
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
__a1a2_trampend:
#endif

View File

@ -1,564 +0,0 @@
/*
* 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@
*/
#ifdef __x86_64__
#include <mach/vm_param.h>
.text
.private_extern __a1a2_tramphead
.private_extern __a1a2_firsttramp
.private_extern __a1a2_nexttramp
.private_extern __a1a2_trampend
.align PAGE_SHIFT
__a1a2_tramphead:
popq %r10
andq $0xFFFFFFFFFFFFFFF8, %r10
subq $ PAGE_SIZE, %r10
movq %rdi, %rsi // arg1 -> arg2
movq (%r10), %rdi // block -> arg1
jmp *16(%rdi)
.macro TrampolineEntry
callq __a1a2_tramphead
nop
nop
nop
.endmacro
.align 5
__a1a2_firsttramp:
TrampolineEntry
__a1a2_nexttramp:
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
__a1a2_trampend:
#endif

View File

@ -1,148 +0,0 @@
#if __arm__
#include <arm/arch.h>
#include <mach/vm_param.h>
.syntax unified
.text
.private_extern __a2a3_tramphead
.private_extern __a2a3_firsttramp
.private_extern __a2a3_trampend
// Trampoline machinery assumes the trampolines are Thumb function pointers
#if !__thumb2__
# error sorry
#endif
.thumb
.thumb_func __a2a3_tramphead
.thumb_func __a2a3_firsttramp
.thumb_func __a2a3_trampend
.align PAGE_MAX_SHIFT
__a2a3_tramphead:
/*
r1 == self
r12 == pc of trampoline's first instruction + PC bias
lr == original return address
*/
mov r2, r1 // _cmd = self
// Trampoline's data is one page before the trampoline text.
// Also correct PC bias of 4 bytes.
sub r12, #PAGE_MAX_SIZE
ldr r1, [r12, #-4] // self = block object
ldr pc, [r1, #12] // tail call block->invoke
// not reached
// Align trampolines to 8 bytes
.align 3
.macro TrampolineEntry
mov r12, pc
b __a2a3_tramphead
.align 3
.endmacro
.macro TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
.endmacro
.macro TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
.endmacro
.private_extern __a2a3_firsttramp
__a2a3_firsttramp:
// 2048-2 trampolines to fill 16K page
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
.private_extern __a2a3_trampend
__a2a3_trampend:
#endif

View File

@ -1,566 +0,0 @@
/*
* 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@
*/
#ifdef __i386__
#include <mach/vm_param.h>
.text
.private_extern __a2a3_tramphead
.private_extern __a2a3_firsttramp
.private_extern __a2a3_nexttramp
.private_extern __a2a3_trampend
.align PAGE_SHIFT
__a2a3_tramphead:
popl %eax
andl $0xFFFFFFF8, %eax
subl $ PAGE_SIZE, %eax
movl 8(%esp), %ecx // self -> ecx
movl %ecx, 12(%esp) // ecx -> _cmd
movl (%eax), %ecx // blockPtr -> ecx
movl %ecx, 8(%esp) // ecx -> self
jmp *12(%ecx) // tail to block->invoke
.macro TrampolineEntry
call __a2a3_tramphead
nop
nop
nop
.endmacro
.align 5
__a2a3_firsttramp:
TrampolineEntry
__a2a3_nexttramp:
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
__a2a3_trampend:
#endif

View File

@ -1,565 +0,0 @@
/*
* 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@
*/
#ifdef __x86_64__
#include <mach/vm_param.h>
.text
.private_extern __a2a3_tramphead
.private_extern __a2a3_firsttramp
.private_extern __a2a3_nexttramp
.private_extern __a2a3_trampend
.align PAGE_SHIFT
__a2a3_tramphead:
popq %r10
andq $0xFFFFFFFFFFFFFFF8, %r10
subq $ PAGE_SIZE, %r10
// %rdi -- first arg -- is address of return value's space. Don't mess with it.
movq %rsi, %rdx // arg2 -> arg3
movq (%r10), %rsi // block -> arg2
jmp *16(%rsi)
.macro TrampolineEntry
callq __a2a3_tramphead
nop
nop
nop
.endmacro
.align 5
__a2a3_firsttramp:
TrampolineEntry
__a2a3_nexttramp:
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
__a2a3_trampend:
#endif

174
runtime/arm64-asm.h Normal file
View File

@ -0,0 +1,174 @@
/*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 2018 Apple Inc. All Rights Reserved.
*
* 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@
*/
/********************************************************************
*
* arm64-asm.h - asm tools for arm64/arm64_32 and ROP/JOP
*
********************************************************************/
#if __arm64__
#if __LP64__
// true arm64
#define SUPPORT_TAGGED_POINTERS 1
#define PTR .quad
#define PTRSIZE 8
#define PTRSHIFT 3 // 1<<PTRSHIFT == PTRSIZE
// "p" registers are pointer-sized
#define UXTP UXTX
#define p0 x0
#define p1 x1
#define p2 x2
#define p3 x3
#define p4 x4
#define p5 x5
#define p6 x6
#define p7 x7
#define p8 x8
#define p9 x9
#define p10 x10
#define p11 x11
#define p12 x12
#define p13 x13
#define p14 x14
#define p15 x15
#define p16 x16
#define p17 x17
// true arm64
#else
// arm64_32
#define SUPPORT_TAGGED_POINTERS 0
#define PTR .long
#define PTRSIZE 4
#define PTRSHIFT 2 // 1<<PTRSHIFT == PTRSIZE
// "p" registers are pointer-sized
#define UXTP UXTW
#define p0 w0
#define p1 w1
#define p2 w2
#define p3 w3
#define p4 w4
#define p5 w5
#define p6 w6
#define p7 w7
#define p8 w8
#define p9 w9
#define p10 w10
#define p11 w11
#define p12 w12
#define p13 w13
#define p14 w14
#define p15 w15
#define p16 w16
#define p17 w17
// arm64_32
#endif
#if __has_feature(ptrauth_returns)
// ROP
# define SignLR pacibsp
# define AuthenticateLR autibsp
#else
// not ROP
# define SignLR
# define AuthenticateLR
#endif
#if __has_feature(ptrauth_calls)
// JOP
.macro TailCallFunctionPointer
// $0 = function pointer value
braaz $0
.endmacro
.macro TailCallCachedImp
// $0 = cached imp, $1 = address of cached imp, $2 = SEL, $3 = isa
eor $1, $1, $2 // mix SEL into ptrauth modifier
eor $1, $1, $3 // mix isa into ptrauth modifier
brab $0, $1
.endmacro
.macro TailCallMethodListImp
// $0 = method list imp, $1 = address of method list imp
braa $0, $1
.endmacro
.macro TailCallBlockInvoke
// $0 = invoke function, $1 = address of invoke function
braa $0, $1
.endmacro
.macro AuthAndResignAsIMP
// $0 = cached imp, $1 = address of cached imp, $2 = SEL, $3 = isa
// note: assumes the imp is not nil
eor $1, $1, $2 // mix SEL into ptrauth modifier
eor $1, $1, $3 // mix isa into ptrauth modifier
autib $0, $1 // authenticate cached imp
ldr xzr, [$0] // crash if authentication failed
paciza $0 // resign cached imp as IMP
.endmacro
// JOP
#else
// not JOP
.macro TailCallFunctionPointer
// $0 = function pointer value
br $0
.endmacro
.macro TailCallCachedImp
// $0 = cached imp, $1 = address of cached imp, $2 = SEL, $3 = isa
eor $0, $0, $3
br $0
.endmacro
.macro TailCallMethodListImp
// $0 = method list imp, $1 = address of method list imp
br $0
.endmacro
.macro TailCallBlockInvoke
// $0 = invoke function, $1 = address of invoke function
br $0
.endmacro
.macro AuthAndResignAsIMP
// $0 = cached imp, $1 = address of cached imp, $2 = SEL
eor $0, $0, $3
.endmacro
// not JOP
#endif
#define TailCallBlockInvoke TailCallMethodListImp
// __arm64__
#endif

View File

@ -30,9 +30,8 @@
#define _OBJC_LITTLE_HASHTABLE_H_ #define _OBJC_LITTLE_HASHTABLE_H_
#ifndef _OBJC_PRIVATE_H_ #ifndef _OBJC_PRIVATE_H_
# define OBJC_HASH_AVAILABILITY \ # define OBJC_HASH_AVAILABILITY \
__OSX_DEPRECATED(10.0, 10.1, "NXHashTable is deprecated") \ OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.0, 10.1, "NXHashTable is deprecated")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE
#else #else
# define OBJC_HASH_AVAILABILITY # define OBJC_HASH_AVAILABILITY
#endif #endif
@ -52,9 +51,13 @@ The objective C class HashTable is preferred when dealing with (key, values) ass
As well-behaved scalable data structures, hash tables double in size when they start becoming full, thus guaranteeing both average constant time access and linear size. */ As well-behaved scalable data structures, hash tables double in size when they start becoming full, thus guaranteeing both average constant time access and linear size. */
typedef struct { typedef struct {
uintptr_t (*hash)(const void *info, const void *data); uintptr_t (* _Nonnull hash)(const void * _Nullable info,
int (*isEqual)(const void *info, const void *data1, const void *data2); const void * _Nullable data);
void (*free)(const void *info, void *data); int (* _Nonnull isEqual)(const void * _Nullable info,
const void * _Nullable data1,
const void * _Nullable data2);
void (* _Nonnull free)(const void * _Nullable info,
void * _Nullable data);
int style; /* reserved for future expansion; currently 0 */ int style; /* reserved for future expansion; currently 0 */
} NXHashTablePrototype; } NXHashTablePrototype;
@ -67,41 +70,63 @@ typedef struct {
*/ */
typedef struct { typedef struct {
const NXHashTablePrototype *prototype OBJC_HASH_AVAILABILITY; const NXHashTablePrototype * _Nonnull prototype OBJC_HASH_AVAILABILITY;
unsigned count OBJC_HASH_AVAILABILITY; unsigned count OBJC_HASH_AVAILABILITY;
unsigned nbBuckets OBJC_HASH_AVAILABILITY; unsigned nbBuckets OBJC_HASH_AVAILABILITY;
void *buckets OBJC_HASH_AVAILABILITY; void * _Nullable buckets OBJC_HASH_AVAILABILITY;
const void *info OBJC_HASH_AVAILABILITY; const void * _Nullable info OBJC_HASH_AVAILABILITY;
} NXHashTable OBJC_HASH_AVAILABILITY; } NXHashTable OBJC_HASH_AVAILABILITY;
/* private data structure; may change */ /* private data structure; may change */
OBJC_EXPORT NXHashTable *NXCreateHashTableFromZone (NXHashTablePrototype prototype, unsigned capacity, const void *info, void *z) OBJC_HASH_AVAILABILITY; OBJC_EXPORT NXHashTable * _Nonnull
OBJC_EXPORT NXHashTable *NXCreateHashTable (NXHashTablePrototype prototype, unsigned capacity, const void *info) OBJC_HASH_AVAILABILITY; NXCreateHashTableFromZone (NXHashTablePrototype prototype, unsigned capacity,
const void * _Nullable info, void * _Nullable z)
OBJC_HASH_AVAILABILITY;
OBJC_EXPORT NXHashTable * _Nonnull
NXCreateHashTable (NXHashTablePrototype prototype, unsigned capacity,
const void * _Nullable info)
OBJC_HASH_AVAILABILITY;
/* if hash is 0, pointer hash is assumed */ /* if hash is 0, pointer hash is assumed */
/* if isEqual is 0, pointer equality is assumed */ /* if isEqual is 0, pointer equality is assumed */
/* if free is 0, elements are not freed */ /* if free is 0, elements are not freed */
/* capacity is only a hint; 0 creates a small table */ /* capacity is only a hint; 0 creates a small table */
/* info allows call backs to be very general */ /* info allows call backs to be very general */
OBJC_EXPORT void NXFreeHashTable (NXHashTable *table) OBJC_HASH_AVAILABILITY; OBJC_EXPORT void
NXFreeHashTable (NXHashTable * _Nonnull table)
OBJC_HASH_AVAILABILITY;
/* calls free for each data, and recovers table */ /* calls free for each data, and recovers table */
OBJC_EXPORT void NXEmptyHashTable (NXHashTable *table) OBJC_HASH_AVAILABILITY; OBJC_EXPORT void
NXEmptyHashTable (NXHashTable * _Nonnull table)
OBJC_HASH_AVAILABILITY;
/* does not deallocate table nor data; keeps current capacity */ /* does not deallocate table nor data; keeps current capacity */
OBJC_EXPORT void NXResetHashTable (NXHashTable *table) OBJC_HASH_AVAILABILITY; OBJC_EXPORT void
NXResetHashTable (NXHashTable * _Nonnull table)
OBJC_HASH_AVAILABILITY;
/* frees each entry; keeps current capacity */ /* frees each entry; keeps current capacity */
OBJC_EXPORT BOOL NXCompareHashTables (NXHashTable *table1, NXHashTable *table2) OBJC_HASH_AVAILABILITY; OBJC_EXPORT BOOL
NXCompareHashTables (NXHashTable * _Nonnull table1,
NXHashTable * _Nonnull table2)
OBJC_HASH_AVAILABILITY;
/* Returns YES if the two sets are equal (each member of table1 in table2, and table have same size) */ /* Returns YES if the two sets are equal (each member of table1 in table2, and table have same size) */
OBJC_EXPORT NXHashTable *NXCopyHashTable (NXHashTable *table) OBJC_HASH_AVAILABILITY; OBJC_EXPORT NXHashTable * _Nonnull
NXCopyHashTable (NXHashTable * _Nonnull table)
OBJC_HASH_AVAILABILITY;
/* makes a fresh table, copying data pointers, not data itself. */ /* makes a fresh table, copying data pointers, not data itself. */
OBJC_EXPORT unsigned NXCountHashTable (NXHashTable *table) OBJC_HASH_AVAILABILITY; OBJC_EXPORT unsigned
NXCountHashTable (NXHashTable * _Nonnull table)
OBJC_HASH_AVAILABILITY;
/* current number of data in table */ /* current number of data in table */
OBJC_EXPORT int NXHashMember (NXHashTable *table, const void *data) OBJC_HASH_AVAILABILITY; OBJC_EXPORT int
NXHashMember (NXHashTable * _Nonnull table, const void * _Nullable data)
OBJC_HASH_AVAILABILITY;
/* returns non-0 iff data is present in table. /* returns non-0 iff data is present in table.
Example of use when the hashed data is a struct containing the key, Example of use when the hashed data is a struct containing the key,
and when the callee only has a key: and when the callee only has a key:
@ -110,7 +135,9 @@ OBJC_EXPORT int NXHashMember (NXHashTable *table, const void *data) OBJC_HASH_AV
return NXHashMember (myTable, &pseudo) return NXHashMember (myTable, &pseudo)
*/ */
OBJC_EXPORT void *NXHashGet (NXHashTable *table, const void *data) OBJC_HASH_AVAILABILITY; OBJC_EXPORT void * _Nullable
NXHashGet (NXHashTable * _Nonnull table, const void * _Nullable data)
OBJC_HASH_AVAILABILITY;
/* return original table data or NULL. /* return original table data or NULL.
Example of use when the hashed data is a struct containing the key, Example of use when the hashed data is a struct containing the key,
and when the callee only has a key: and when the callee only has a key:
@ -120,14 +147,20 @@ OBJC_EXPORT void *NXHashGet (NXHashTable *table, const void *data) OBJC_HASH_AVA
original = NXHashGet (myTable, &pseudo) original = NXHashGet (myTable, &pseudo)
*/ */
OBJC_EXPORT void *NXHashInsert (NXHashTable *table, const void *data) OBJC_HASH_AVAILABILITY; OBJC_EXPORT void * _Nullable
NXHashInsert (NXHashTable * _Nonnull table, const void * _Nullable data)
OBJC_HASH_AVAILABILITY;
/* previous data or NULL is returned. */ /* previous data or NULL is returned. */
OBJC_EXPORT void *NXHashInsertIfAbsent (NXHashTable *table, const void *data) OBJC_HASH_AVAILABILITY; OBJC_EXPORT void * _Nullable
NXHashInsertIfAbsent (NXHashTable * _Nonnull table, const void * _Nullable data)
OBJC_HASH_AVAILABILITY;
/* If data already in table, returns the one in table /* If data already in table, returns the one in table
else adds argument to table and returns argument. */ else adds argument to table and returns argument. */
OBJC_EXPORT void *NXHashRemove (NXHashTable *table, const void *data) OBJC_HASH_AVAILABILITY; OBJC_EXPORT void * _Nullable
NXHashRemove (NXHashTable * _Nonnull table, const void * _Nullable data)
OBJC_HASH_AVAILABILITY;
/* previous data or NULL is returned */ /* previous data or NULL is returned */
/* Iteration over all elements of a table consists in setting up an iteration state and then to progress until all entries have been visited. An example of use for counting elements in a table is: /* Iteration over all elements of a table consists in setting up an iteration state and then to progress until all entries have been visited. An example of use for counting elements in a table is:
@ -142,9 +175,13 @@ OBJC_EXPORT void *NXHashRemove (NXHashTable *table, const void *data) OBJC_HASH_
typedef struct {int i; int j;} NXHashState OBJC_HASH_AVAILABILITY; typedef struct {int i; int j;} NXHashState OBJC_HASH_AVAILABILITY;
/* callers should not rely on actual contents of the struct */ /* callers should not rely on actual contents of the struct */
OBJC_EXPORT NXHashState NXInitHashState(NXHashTable *table) OBJC_HASH_AVAILABILITY; OBJC_EXPORT NXHashState
NXInitHashState(NXHashTable * _Nonnull table)
OBJC_HASH_AVAILABILITY;
OBJC_EXPORT int NXNextHashState(NXHashTable *table, NXHashState *state, void **data) OBJC_HASH_AVAILABILITY; OBJC_EXPORT int
NXNextHashState(NXHashTable * _Nonnull table, NXHashState * _Nonnull state,
void * _Nullable * _Nonnull data) OBJC_HASH_AVAILABILITY;
/* returns 0 when all elements have been visited */ /* returns 0 when all elements have been visited */
/************************************************************************* /*************************************************************************
@ -152,23 +189,45 @@ OBJC_EXPORT int NXNextHashState(NXHashTable *table, NXHashState *state, void **d
* and common prototypes * and common prototypes
*************************************************************************/ *************************************************************************/
OBJC_EXPORT uintptr_t NXPtrHash(const void *info, const void *data) OBJC_HASH_AVAILABILITY; OBJC_EXPORT uintptr_t
NXPtrHash(const void * _Nullable info, const void * _Nullable data)
OBJC_HASH_AVAILABILITY;
/* scrambles the address bits; info unused */ /* scrambles the address bits; info unused */
OBJC_EXPORT uintptr_t NXStrHash(const void *info, const void *data) OBJC_HASH_AVAILABILITY;
OBJC_EXPORT uintptr_t
NXStrHash(const void * _Nullable info, const void * _Nullable data)
OBJC_HASH_AVAILABILITY;
/* string hashing; info unused */ /* string hashing; info unused */
OBJC_EXPORT int NXPtrIsEqual(const void *info, const void *data1, const void *data2) OBJC_HASH_AVAILABILITY;
OBJC_EXPORT int
NXPtrIsEqual(const void * _Nullable info, const void * _Nullable data1,
const void * _Nullable data2)
OBJC_HASH_AVAILABILITY;
/* pointer comparison; info unused */ /* pointer comparison; info unused */
OBJC_EXPORT int NXStrIsEqual(const void *info, const void *data1, const void *data2) OBJC_HASH_AVAILABILITY;
OBJC_EXPORT int
NXStrIsEqual(const void * _Nullable info, const void * _Nullable data1,
const void * _Nullable data2)
OBJC_HASH_AVAILABILITY;
/* string comparison; NULL ok; info unused */ /* string comparison; NULL ok; info unused */
OBJC_EXPORT void NXNoEffectFree(const void *info, void *data) OBJC_HASH_AVAILABILITY;
OBJC_EXPORT void
NXNoEffectFree(const void * _Nullable info, void * _Nullable data)
OBJC_HASH_AVAILABILITY;
/* no effect; info unused */ /* no effect; info unused */
OBJC_EXPORT void NXReallyFree(const void *info, void *data) OBJC_HASH_AVAILABILITY;
OBJC_EXPORT void
NXReallyFree(const void * _Nullable info, void * _Nullable data)
OBJC_HASH_AVAILABILITY;
/* frees it; info unused */ /* frees it; info unused */
/* The two following prototypes are useful for manipulating set of pointers or set of strings; For them free is defined as NXNoEffectFree */ /* The two following prototypes are useful for manipulating set of pointers or set of strings; For them free is defined as NXNoEffectFree */
OBJC_EXPORT const NXHashTablePrototype NXPtrPrototype OBJC_HASH_AVAILABILITY; OBJC_EXPORT const NXHashTablePrototype NXPtrPrototype
OBJC_HASH_AVAILABILITY;
/* prototype when data is a pointer (void *) */ /* prototype when data is a pointer (void *) */
OBJC_EXPORT const NXHashTablePrototype NXStrPrototype OBJC_HASH_AVAILABILITY;
OBJC_EXPORT const NXHashTablePrototype NXStrPrototype
OBJC_HASH_AVAILABILITY;
/* prototype when data is a string (char *) */ /* prototype when data is a string (char *) */
/* following prototypes help describe mappings where the key is the first element of a struct and is either a pointer or a string. /* following prototypes help describe mappings where the key is the first element of a struct and is either a pointer or a string.
@ -181,8 +240,10 @@ For example NXStrStructKeyPrototype can be used to hash pointers to Example, whe
For the following prototypes, free is defined as NXReallyFree. For the following prototypes, free is defined as NXReallyFree.
*/ */
OBJC_EXPORT const NXHashTablePrototype NXPtrStructKeyPrototype OBJC_HASH_AVAILABILITY; OBJC_EXPORT const NXHashTablePrototype NXPtrStructKeyPrototype
OBJC_EXPORT const NXHashTablePrototype NXStrStructKeyPrototype OBJC_HASH_AVAILABILITY; OBJC_HASH_AVAILABILITY;
OBJC_EXPORT const NXHashTablePrototype NXStrStructKeyPrototype
OBJC_HASH_AVAILABILITY;
#if !__OBJC2__ && !TARGET_OS_WIN32 #if !__OBJC2__ && !TARGET_OS_WIN32
@ -196,29 +257,39 @@ A unique string is a string that is allocated once for all (never de-allocated)
typedef const char *NXAtom OBJC_HASH_AVAILABILITY; typedef const char *NXAtom OBJC_HASH_AVAILABILITY;
OBJC_EXPORT NXAtom NXUniqueString(const char *buffer) OBJC_HASH_AVAILABILITY; OBJC_EXPORT NXAtom _Nullable
NXUniqueString(const char * _Nullable buffer)
OBJC_HASH_AVAILABILITY;
/* assumes that buffer is \0 terminated, and returns /* assumes that buffer is \0 terminated, and returns
a previously created string or a new string that is a copy of buffer. a previously created string or a new string that is a copy of buffer.
If NULL is passed returns NULL. If NULL is passed returns NULL.
Returned string should never be modified. To ensure this invariant, Returned string should never be modified. To ensure this invariant,
allocations are made in a special read only zone. */ allocations are made in a special read only zone. */
OBJC_EXPORT NXAtom NXUniqueStringWithLength(const char *buffer, int length) OBJC_HASH_AVAILABILITY; OBJC_EXPORT NXAtom _Nonnull
NXUniqueStringWithLength(const char * _Nullable buffer, int length)
OBJC_HASH_AVAILABILITY;
/* assumes that buffer is a non NULL buffer of at least /* assumes that buffer is a non NULL buffer of at least
length characters. Returns a previously created string or length characters. Returns a previously created string or
a new string that is a copy of buffer. a new string that is a copy of buffer.
If buffer contains \0, string will be truncated. If buffer contains \0, string will be truncated.
As for NXUniqueString, returned string should never be modified. */ As for NXUniqueString, returned string should never be modified. */
OBJC_EXPORT NXAtom NXUniqueStringNoCopy(const char *string) OBJC_HASH_AVAILABILITY; OBJC_EXPORT NXAtom _Nullable
NXUniqueStringNoCopy(const char * _Nullable string)
OBJC_HASH_AVAILABILITY;
/* If there is already a unique string equal to string, returns the original. /* If there is already a unique string equal to string, returns the original.
Otherwise, string is entered in the table, without making a copy. Argument should then never be modified. */ Otherwise, string is entered in the table, without making a copy. Argument should then never be modified. */
OBJC_EXPORT char *NXCopyStringBuffer(const char *buffer) OBJC_HASH_AVAILABILITY; OBJC_EXPORT char * _Nullable
NXCopyStringBuffer(const char * _Nullable buffer)
OBJC_HASH_AVAILABILITY;
/* given a buffer, allocates a new string copy of buffer. /* given a buffer, allocates a new string copy of buffer.
Buffer should be \0 terminated; returned string is \0 terminated. */ Buffer should be \0 terminated; returned string is \0 terminated. */
OBJC_EXPORT char *NXCopyStringBufferFromZone(const char *buffer, void *z) OBJC_HASH_AVAILABILITY; OBJC_EXPORT char * _Nullable
NXCopyStringBufferFromZone(const char * _Nullable buffer, void * _Nullable z)
OBJC_HASH_AVAILABILITY;
/* given a buffer, allocates a new string copy of buffer. /* given a buffer, allocates a new string copy of buffer.
Buffer should be \0 terminated; returned string is \0 terminated. */ Buffer should be \0 terminated; returned string is \0 terminated. */

View File

@ -562,7 +562,7 @@ static int accessUniqueString = 0;
static char *z = NULL; static char *z = NULL;
static size_t zSize = 0; static size_t zSize = 0;
static mutex_t uniquerLock; mutex_t NXUniqueStringLock;
static const char *CopyIntoReadOnly (const char *str) { static const char *CopyIntoReadOnly (const char *str) {
size_t len = strlen (str) + 1; size_t len = strlen (str) + 1;
@ -574,7 +574,7 @@ static const char *CopyIntoReadOnly (const char *str) {
return result; return result;
} }
mutex_locker_t lock(uniquerLock); mutex_locker_t lock(NXUniqueStringLock);
if (zSize < len) { if (zSize < len) {
zSize = CHUNK_SIZE *((len + CHUNK_SIZE - 1) / CHUNK_SIZE); zSize = CHUNK_SIZE *((len + CHUNK_SIZE - 1) / CHUNK_SIZE);
/* not enough room, we try to allocate. If no room left, too bad */ /* not enough room, we try to allocate. If no room left, too bad */

View File

@ -1 +0,0 @@
../../NSObjCRuntime.h

View File

@ -1 +0,0 @@
../../NSObject.h

View File

@ -1 +0,0 @@
../../Object.h

View File

@ -1 +0,0 @@
../../Protocol.h

View File

@ -1 +0,0 @@
../../hashtable.h

View File

@ -1 +0,0 @@
../../hashtable2.h

View File

@ -1 +0,0 @@
../../maptable.h

View File

@ -1 +0,0 @@
../../message.h

View File

@ -1 +0,0 @@
../../objc-api.h

View File

@ -1 +0,0 @@
../../objc-auto.h

View File

@ -1 +0,0 @@
../../objc-class.h

View File

@ -1 +0,0 @@
../../objc-exception.h

View File

@ -1 +0,0 @@
../../objc-internal.h

View File

@ -1 +0,0 @@
../../objc-load.h

View File

@ -1 +0,0 @@
../../objc-runtime.h

View File

@ -1 +0,0 @@
../../objc-sync.h

View File

@ -1 +0,0 @@
../../objc.h

View File

@ -1 +0,0 @@
../../runtime.h

134
runtime/isa.h Normal file
View File

@ -0,0 +1,134 @@
/*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 2018 Apple Inc. All Rights Reserved.
*
* 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@
*/
/********************************************************************
*
* isa.h - Definitions of isa fields for C and assembly code.
*
********************************************************************/
#ifndef _OBJC_ISA_H_
#define _OBJC_ISA_H_
#include "objc-config.h"
#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
#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
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 19
# 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
# define ISA_BITFIELD \
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 || (__arm64__ && !__LP64__)
// armv7k or arm64_32
# define ISA_INDEX_IS_NPI_BIT 0
# define ISA_INDEX_IS_NPI_MASK 0x00000001
# 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
# define ISA_BITFIELD \
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
// _OBJC_ISA_H_
#endif

File diff suppressed because it is too large Load Diff

View File

@ -75,6 +75,15 @@ template<> struct DenseMapInfo<const char*> {
return _objc_strhash(Val); return _objc_strhash(Val);
} }
static bool isEqual(const char* const &LHS, const char* const &RHS) { static bool isEqual(const char* const &LHS, const char* const &RHS) {
if (LHS == RHS) {
return true;
}
if (LHS == getEmptyKey() || RHS == getEmptyKey()) {
return false;
}
if (LHS == getTombstoneKey() || RHS == getTombstoneKey()) {
return false;
}
return 0 == strcmp(LHS, RHS); return 0 == strcmp(LHS, RHS);
} }
}; };
@ -195,6 +204,13 @@ struct DenseMapInfo<std::pair<T, U> > {
} }
}; };
template<typename T>
struct DenseMapValueInfo {
static inline bool isPurgeable(const T &value) {
return false;
}
};
} // end namespace objc } // end namespace objc
#endif #endif

293
runtime/llvm-DenseSet.h Normal file
View File

@ -0,0 +1,293 @@
//===- llvm/ADT/DenseSet.h - Dense probed hash table ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the DenseSet and SmallDenseSet classes.
//
//===----------------------------------------------------------------------===//
// Taken from clang-1100.247.11.10.9
#ifndef LLVM_ADT_DENSESET_H
#define LLVM_ADT_DENSESET_H
#include "llvm-DenseMap.h"
#include "llvm-DenseMapInfo.h"
#include "llvm-type_traits.h"
#include <algorithm>
#include <cstddef>
#include <initializer_list>
#include <iterator>
#include <utility>
#include <TargetConditionals.h>
#include "objc-private.h"
namespace objc {
namespace detail {
struct DenseSetEmpty {};
// Use the empty base class trick so we can create a DenseMap where the buckets
// contain only a single item.
template <typename KeyT> class DenseSetPair : public DenseSetEmpty {
KeyT key;
public:
KeyT &getFirst() { return key; }
const KeyT &getFirst() const { return key; }
DenseSetEmpty &getSecond() { return *this; }
const DenseSetEmpty &getSecond() const { return *this; }
};
/// Base class for DenseSet and DenseSmallSet.
///
/// MapTy should be either
///
/// DenseMap<ValueT, detail::DenseSetEmpty,
/// DenseMapValueInfo<detail::DenseSetEmpty>,
/// ValueInfoT, detail::DenseSetPair<ValueT>>
///
/// or the equivalent SmallDenseMap type. ValueInfoT must implement the
/// DenseMapInfo "concept".
template <typename ValueT, typename MapTy, typename ValueInfoT>
class DenseSetImpl {
static_assert(sizeof(typename MapTy::value_type) == sizeof(ValueT),
"DenseMap buckets unexpectedly large!");
MapTy TheMap;
template <typename T>
using const_arg_type_t = typename const_pointer_or_const_ref<T>::type;
public:
using key_type = ValueT;
using value_type = ValueT;
using size_type = unsigned;
explicit DenseSetImpl(unsigned InitialReserve = 0) : TheMap(InitialReserve) {}
DenseSetImpl(std::initializer_list<ValueT> Elems)
: DenseSetImpl(PowerOf2Ceil(Elems.size())) {
insert(Elems.begin(), Elems.end());
}
bool empty() const { return TheMap.empty(); }
size_type size() const { return TheMap.size(); }
size_t getMemorySize() const { return TheMap.getMemorySize(); }
/// Grow the DenseSet so that it has at least Size buckets. Will not shrink
/// the Size of the set.
void resize(size_t Size) { TheMap.resize(Size); }
/// Grow the DenseSet so that it can contain at least \p NumEntries items
/// before resizing again.
void reserve(size_t Size) { TheMap.reserve(Size); }
void clear() {
TheMap.clear();
}
/// Return 1 if the specified key is in the set, 0 otherwise.
size_type count(const_arg_type_t<ValueT> V) const {
return TheMap.count(V);
}
bool erase(const ValueT &V) {
return TheMap.erase(V);
}
void swap(DenseSetImpl &RHS) { TheMap.swap(RHS.TheMap); }
// Iterators.
class ConstIterator;
class Iterator {
typename MapTy::iterator I;
friend class DenseSetImpl;
friend class ConstIterator;
public:
using difference_type = typename MapTy::iterator::difference_type;
using value_type = ValueT;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::forward_iterator_tag;
Iterator() = default;
Iterator(const typename MapTy::iterator &i) : I(i) {}
ValueT &operator*() { return I->getFirst(); }
const ValueT &operator*() const { return I->getFirst(); }
ValueT *operator->() { return &I->getFirst(); }
const ValueT *operator->() const { return &I->getFirst(); }
Iterator& operator++() { ++I; return *this; }
Iterator operator++(int) { auto T = *this; ++I; return T; }
bool operator==(const ConstIterator& X) const { return I == X.I; }
bool operator!=(const ConstIterator& X) const { return I != X.I; }
};
class ConstIterator {
typename MapTy::const_iterator I;
friend class DenseSet;
friend class Iterator;
public:
using difference_type = typename MapTy::const_iterator::difference_type;
using value_type = ValueT;
using pointer = const value_type *;
using reference = const value_type &;
using iterator_category = std::forward_iterator_tag;
ConstIterator() = default;
ConstIterator(const Iterator &B) : I(B.I) {}
ConstIterator(const typename MapTy::const_iterator &i) : I(i) {}
const ValueT &operator*() const { return I->getFirst(); }
const ValueT *operator->() const { return &I->getFirst(); }
ConstIterator& operator++() { ++I; return *this; }
ConstIterator operator++(int) { auto T = *this; ++I; return T; }
bool operator==(const ConstIterator& X) const { return I == X.I; }
bool operator!=(const ConstIterator& X) const { return I != X.I; }
};
using iterator = Iterator;
using const_iterator = ConstIterator;
iterator begin() { return Iterator(TheMap.begin()); }
iterator end() { return Iterator(TheMap.end()); }
const_iterator begin() const { return ConstIterator(TheMap.begin()); }
const_iterator end() const { return ConstIterator(TheMap.end()); }
iterator find(const_arg_type_t<ValueT> V) { return Iterator(TheMap.find(V)); }
const_iterator find(const_arg_type_t<ValueT> V) const {
return ConstIterator(TheMap.find(V));
}
/// Alternative version of find() which allows a different, and possibly less
/// expensive, key type.
/// The DenseMapInfo is responsible for supplying methods
/// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key type
/// used.
template <class LookupKeyT>
iterator find_as(const LookupKeyT &Val) {
return Iterator(TheMap.find_as(Val));
}
template <class LookupKeyT>
const_iterator find_as(const LookupKeyT &Val) const {
return ConstIterator(TheMap.find_as(Val));
}
void erase(Iterator I) { return TheMap.erase(I.I); }
void erase(ConstIterator CI) { return TheMap.erase(CI.I); }
std::pair<iterator, bool> insert(const ValueT &V) {
detail::DenseSetEmpty Empty;
return TheMap.try_emplace(V, Empty);
}
std::pair<iterator, bool> insert(ValueT &&V) {
detail::DenseSetEmpty Empty;
return TheMap.try_emplace(std::move(V), Empty);
}
/// Alternative version of insert that uses a different (and possibly less
/// expensive) key type.
template <typename LookupKeyT>
std::pair<iterator, bool> insert_as(const ValueT &V,
const LookupKeyT &LookupKey) {
return TheMap.insert_as({V, detail::DenseSetEmpty()}, LookupKey);
}
template <typename LookupKeyT>
std::pair<iterator, bool> insert_as(ValueT &&V, const LookupKeyT &LookupKey) {
return TheMap.insert_as({std::move(V), detail::DenseSetEmpty()}, LookupKey);
}
// Range insertion of values.
template<typename InputIt>
void insert(InputIt I, InputIt E) {
for (; I != E; ++I)
insert(*I);
}
};
/// Equality comparison for DenseSet.
///
/// Iterates over elements of LHS confirming that each element is also a member
/// of RHS, and that RHS contains no additional values.
/// Equivalent to N calls to RHS.count. Amortized complexity is linear, worst
/// case is O(N^2) (if every hash collides).
template <typename ValueT, typename MapTy, typename ValueInfoT>
bool operator==(const DenseSetImpl<ValueT, MapTy, ValueInfoT> &LHS,
const DenseSetImpl<ValueT, MapTy, ValueInfoT> &RHS) {
if (LHS.size() != RHS.size())
return false;
for (auto &E : LHS)
if (!RHS.count(E))
return false;
return true;
}
/// Inequality comparison for DenseSet.
///
/// Equivalent to !(LHS == RHS). See operator== for performance notes.
template <typename ValueT, typename MapTy, typename ValueInfoT>
bool operator!=(const DenseSetImpl<ValueT, MapTy, ValueInfoT> &LHS,
const DenseSetImpl<ValueT, MapTy, ValueInfoT> &RHS) {
return !(LHS == RHS);
}
} // end namespace detail
/// Implements a dense probed hash-table based set.
template <typename ValueT, typename ValueInfoT = DenseMapInfo<ValueT>>
class DenseSet : public detail::DenseSetImpl<
ValueT, DenseMap<ValueT, detail::DenseSetEmpty,
DenseMapValueInfo<detail::DenseSetEmpty>,
ValueInfoT, detail::DenseSetPair<ValueT>>,
ValueInfoT> {
using BaseT =
detail::DenseSetImpl<ValueT,
DenseMap<ValueT, detail::DenseSetEmpty,
DenseMapValueInfo<detail::DenseSetEmpty>,
ValueInfoT, detail::DenseSetPair<ValueT>>,
ValueInfoT>;
public:
using BaseT::BaseT;
};
/// Implements a dense probed hash-table based set with some number of buckets
/// stored inline.
template <typename ValueT, unsigned InlineBuckets = 4,
typename ValueInfoT = DenseMapInfo<ValueT>>
class SmallDenseSet
: public detail::DenseSetImpl<
ValueT, SmallDenseMap<ValueT, detail::DenseSetEmpty, InlineBuckets,
DenseMapValueInfo<detail::DenseSetEmpty>,
ValueInfoT, detail::DenseSetPair<ValueT>>,
ValueInfoT> {
using BaseT = detail::DenseSetImpl<
ValueT, SmallDenseMap<ValueT, detail::DenseSetEmpty, InlineBuckets,
DenseMapValueInfo<detail::DenseSetEmpty>,
ValueInfoT, detail::DenseSetPair<ValueT>>,
ValueInfoT>;
public:
using BaseT::BaseT;
};
} // end namespace objc
#endif // LLVM_ADT_DENSESET_H

View File

@ -1,24 +1,22 @@
//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===// //===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//
// //
// The LLVM Compiler Infrastructure // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// // See https://llvm.org/LICENSE.txt for license information.
// This file is distributed under the University of Illinois Open Source // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// License. See LICENSE.TXT for details.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// This file provides a template class that determines if a type is a class or // This file provides useful additions to the standard type_traits library.
// not. The basic mechanism, based on using the pointer to member function of
// a zero argument to a function was "boosted" from the boost type_traits
// library. See http://www.boost.org/ for all the gory details.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Taken from llvmCore-3425.0.31. // Taken from clang-1100.247.11.10.9
#ifndef LLVM_SUPPORT_TYPE_TRAITS_H #ifndef LLVM_SUPPORT_TYPE_TRAITS_H
#define LLVM_SUPPORT_TYPE_TRAITS_H #define LLVM_SUPPORT_TYPE_TRAITS_H
#define HAVE_STD_IS_TRIVIALLY_COPYABLE 1
#include <cstddef> #include <cstddef>
#include <utility> #include <utility>
@ -27,195 +25,180 @@
#define __has_feature(x) 0 #define __has_feature(x) 0
#endif #endif
// This is actually the conforming implementation which works with abstract
// classes. However, enough compilers have trouble with it that most will use
// the one in boost/type_traits/object_traits.hpp. This implementation actually
// works with VC7.0, but other interactions seem to fail when we use it.
namespace objc { namespace objc {
namespace dont_use
{
// These two functions should never be used. They are helpers to
// the is_class template below. They cannot be located inside
// is_class because doing so causes at least GCC to think that
// the value of the "value" enumerator is not constant. Placing
// them out here (for some strange reason) allows the sizeof
// operator against them to magically be constant. This is
// important to make the is_class<T>::value idiom zero cost. it
// evaluates to a constant 1 or 0 depending on whether the
// parameter T is a class or not (respectively).
template<typename T> char is_class_helper(void(T::*)());
template<typename T> double is_class_helper(...);
}
template <typename T> /// Metafunction that determines whether the given type is either an
struct is_class /// integral type or an enumeration type, including enum classes.
{ ///
// is_class<> metafunction due to Paul Mensonides (leavings@attbi.com). For /// Note that this accepts potentially more integral types than is_integral
// more details: /// because it is based on being implicitly convertible to an integral type.
// http://groups.google.com/groups?hl=en&selm=000001c1cc83%24e154d5e0%247772e50c%40c161550a&rnum=1 /// Also note that enum classes aren't implicitly convertible to integral types,
/// the value may therefore need to be explicitly converted before being used.
template <typename T> class is_integral_or_enum {
using UnderlyingT = typename std::remove_reference<T>::type;
public: public:
static const bool value = static const bool value =
sizeof(char) == sizeof(dont_use::is_class_helper<T>(0)); !std::is_class<UnderlyingT>::value && // Filter conversion operators.
!std::is_pointer<UnderlyingT>::value &&
!std::is_floating_point<UnderlyingT>::value &&
(std::is_enum<UnderlyingT>::value ||
std::is_convertible<UnderlyingT, unsigned long long>::value);
};
/// If T is a pointer, just return it. If it is not, return T&.
template<typename T, typename Enable = void>
struct add_lvalue_reference_if_not_pointer { using type = T &; };
template <typename T>
struct add_lvalue_reference_if_not_pointer<
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
using type = T;
};
/// If T is a pointer to X, return a pointer to const X. If it is not,
/// return const T.
template<typename T, typename Enable = void>
struct add_const_past_pointer { using type = const T; };
template <typename T>
struct add_const_past_pointer<
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
using type = const typename std::remove_pointer<T>::type *;
};
template <typename T, typename Enable = void>
struct const_pointer_or_const_ref {
using type = const T &;
};
template <typename T>
struct const_pointer_or_const_ref<
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
using type = typename add_const_past_pointer<T>::type;
};
namespace detail {
/// Internal utility to detect trivial copy construction.
template<typename T> union copy_construction_triviality_helper {
T t;
copy_construction_triviality_helper() = default;
copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default;
~copy_construction_triviality_helper() = default;
};
/// Internal utility to detect trivial move construction.
template<typename T> union move_construction_triviality_helper {
T t;
move_construction_triviality_helper() = default;
move_construction_triviality_helper(move_construction_triviality_helper&&) = default;
~move_construction_triviality_helper() = default;
};
template<class T>
union trivial_helper {
T t;
};
} // end namespace detail
/// An implementation of `std::is_trivially_copy_constructible` since we have
/// users with STLs that don't yet include it.
template <typename T>
struct is_trivially_copy_constructible
: std::is_copy_constructible<
::objc::detail::copy_construction_triviality_helper<T>> {};
template <typename T>
struct is_trivially_copy_constructible<T &> : std::true_type {};
template <typename T>
struct is_trivially_copy_constructible<T &&> : std::false_type {};
/// An implementation of `std::is_trivially_move_constructible` since we have
/// users with STLs that don't yet include it.
template <typename T>
struct is_trivially_move_constructible
: std::is_move_constructible<
::objc::detail::move_construction_triviality_helper<T>> {};
template <typename T>
struct is_trivially_move_constructible<T &> : std::true_type {};
template <typename T>
struct is_trivially_move_constructible<T &&> : std::true_type {};
template <typename T>
struct is_copy_assignable {
template<class F>
static auto get(F*) -> decltype(std::declval<F &>() = std::declval<const F &>(), std::true_type{});
static std::false_type get(...);
static constexpr bool value = decltype(get((T*)nullptr))::value;
};
template <typename T>
struct is_move_assignable {
template<class F>
static auto get(F*) -> decltype(std::declval<F &>() = std::declval<F &&>(), std::true_type{});
static std::false_type get(...);
static constexpr bool value = decltype(get((T*)nullptr))::value;
}; };
/// isPodLike - This is a type trait that is used to determine whether a given // An implementation of `std::is_trivially_copyable` since STL version
/// type can be copied around with memcpy instead of running ctors etc. // is not equally supported by all compilers, especially GCC 4.9.
// Uniform implementation of this trait is important for ABI compatibility
// as it has an impact on SmallVector's ABI (among others).
template <typename T> template <typename T>
struct isPodLike { class is_trivially_copyable {
#if __has_feature(is_trivially_copyable)
// If the compiler supports the is_trivially_copyable trait use it, as it // copy constructors
// matches the definition of isPodLike closely. static constexpr bool has_trivial_copy_constructor =
static const bool value = __is_trivially_copyable(T); std::is_copy_constructible<detail::trivial_helper<T>>::value;
#else static constexpr bool has_deleted_copy_constructor =
// If we don't know anything else, we can (at least) assume that all non-class !std::is_copy_constructible<T>::value;
// types are PODs.
static const bool value = !is_class<T>::value; // move constructors
static constexpr bool has_trivial_move_constructor =
std::is_move_constructible<detail::trivial_helper<T>>::value;
static constexpr bool has_deleted_move_constructor =
!std::is_move_constructible<T>::value;
// copy assign
static constexpr bool has_trivial_copy_assign =
is_copy_assignable<detail::trivial_helper<T>>::value;
static constexpr bool has_deleted_copy_assign =
!is_copy_assignable<T>::value;
// move assign
static constexpr bool has_trivial_move_assign =
is_move_assignable<detail::trivial_helper<T>>::value;
static constexpr bool has_deleted_move_assign =
!is_move_assignable<T>::value;
// destructor
static constexpr bool has_trivial_destructor =
std::is_destructible<detail::trivial_helper<T>>::value;
public:
static constexpr bool value =
has_trivial_destructor &&
(has_deleted_move_assign || has_trivial_move_assign) &&
(has_deleted_move_constructor || has_trivial_move_constructor) &&
(has_deleted_copy_assign || has_trivial_copy_assign) &&
(has_deleted_copy_constructor || has_trivial_copy_constructor);
#ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE
static_assert(value == std::is_trivially_copyable<T>::value,
"inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable");
#endif #endif
}; };
// std::pair's are pod-like if their elements are.
template<typename T, typename U>
struct isPodLike<std::pair<T, U> > {
static const bool value = isPodLike<T>::value && isPodLike<U>::value;
};
template <class T, T v>
struct integral_constant {
typedef T value_type;
static const value_type value = v;
typedef integral_constant<T,v> type;
operator value_type() { return value; }
};
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
/// \brief Metafunction that determines whether the two given types are
/// equivalent.
template<typename T, typename U> struct is_same : public false_type {};
template<typename T> struct is_same<T, T> : public true_type {};
/// \brief Metafunction that removes const qualification from a type.
template <typename T> struct remove_const { typedef T type; };
template <typename T> struct remove_const<const T> { typedef T type; };
/// \brief Metafunction that removes volatile qualification from a type.
template <typename T> struct remove_volatile { typedef T type; };
template <typename T> struct remove_volatile<volatile T> { typedef T type; };
/// \brief Metafunction that removes both const and volatile qualification from
/// a type.
template <typename T> struct remove_cv {
typedef typename remove_const<typename remove_volatile<T>::type>::type type;
};
/// \brief Helper to implement is_integral metafunction.
template <typename T> struct is_integral_impl : false_type {};
template <> struct is_integral_impl< bool> : true_type {};
template <> struct is_integral_impl< char> : true_type {};
template <> struct is_integral_impl< signed char> : true_type {};
template <> struct is_integral_impl<unsigned char> : true_type {};
template <> struct is_integral_impl< wchar_t> : true_type {};
template <> struct is_integral_impl< short> : true_type {};
template <> struct is_integral_impl<unsigned short> : true_type {};
template <> struct is_integral_impl< int> : true_type {};
template <> struct is_integral_impl<unsigned int> : true_type {};
template <> struct is_integral_impl< long> : true_type {};
template <> struct is_integral_impl<unsigned long> : true_type {};
template <> struct is_integral_impl< long long> : true_type {};
template <> struct is_integral_impl<unsigned long long> : true_type {};
/// \brief Metafunction that determines whether the given type is an integral
/// type.
template <typename T> template <typename T>
struct is_integral : is_integral_impl<T> {}; class is_trivially_copyable<T*> : public std::true_type {
/// \brief Metafunction to remove reference from a type.
template <typename T> struct remove_reference { typedef T type; };
template <typename T> struct remove_reference<T&> { typedef T type; };
/// \brief Metafunction that determines whether the given type is a pointer
/// type.
template <typename T> struct is_pointer : false_type {};
template <typename T> struct is_pointer<T*> : true_type {};
template <typename T> struct is_pointer<T* const> : true_type {};
template <typename T> struct is_pointer<T* volatile> : true_type {};
template <typename T> struct is_pointer<T* const volatile> : true_type {};
/// \brief Metafunction that determines whether the given type is either an
/// integral type or an enumeration type.
///
/// Note that this accepts potentially more integral types than we whitelist
/// above for is_integral because it is based on merely being convertible
/// implicitly to an integral type.
template <typename T> class is_integral_or_enum {
// Provide an overload which can be called with anything implicitly
// convertible to an unsigned long long. This should catch integer types and
// enumeration types at least. We blacklist classes with conversion operators
// below.
static double check_int_convertible(unsigned long long);
static char check_int_convertible(...);
typedef typename remove_reference<T>::type UnderlyingT;
static UnderlyingT &nonce_instance;
public:
static const bool
value = (!is_class<UnderlyingT>::value && !is_pointer<UnderlyingT>::value &&
!is_same<UnderlyingT, float>::value &&
!is_same<UnderlyingT, double>::value &&
sizeof(char) != sizeof(check_int_convertible(nonce_instance)));
}; };
// enable_if_c - Enable/disable a template based on a metafunction
template<bool Cond, typename T = void>
struct enable_if_c {
typedef T type;
};
template<typename T> struct enable_if_c<false, T> { }; } // end namespace llvm
// enable_if - Enable/disable a template based on a metafunction
template<typename Cond, typename T = void>
struct enable_if : public enable_if_c<Cond::value, T> { };
namespace dont_use {
template<typename Base> char base_of_helper(const volatile Base*);
template<typename Base> double base_of_helper(...);
}
/// is_base_of - Metafunction to determine whether one type is a base class of
/// (or identical to) another type.
template<typename Base, typename Derived>
struct is_base_of {
static const bool value
= is_class<Base>::value && is_class<Derived>::value &&
sizeof(char) == sizeof(dont_use::base_of_helper<Base>((Derived*)0));
};
// remove_pointer - Metafunction to turn Foo* into Foo. Defined in
// C++0x [meta.trans.ptr].
template <typename T> struct remove_pointer { typedef T type; };
template <typename T> struct remove_pointer<T*> { typedef T type; };
template <typename T> struct remove_pointer<T*const> { typedef T type; };
template <typename T> struct remove_pointer<T*volatile> { typedef T type; };
template <typename T> struct remove_pointer<T*const volatile> {
typedef T type; };
template <bool, typename T, typename F>
struct conditional { typedef T type; };
template <typename T, typename F>
struct conditional<false, T, F> { typedef F type; };
}
#ifdef LLVM_DEFINED_HAS_FEATURE #ifdef LLVM_DEFINED_HAS_FEATURE
#undef __has_feature #undef __has_feature
#endif #endif
#endif #endif // LLVM_SUPPORT_TYPE_TRAITS_H

View File

@ -30,9 +30,8 @@
#define _OBJC_MAPTABLE_H_ #define _OBJC_MAPTABLE_H_
#ifndef _OBJC_PRIVATE_H_ #ifndef _OBJC_PRIVATE_H_
# define OBJC_MAP_AVAILABILITY \ # define OBJC_MAP_AVAILABILITY \
__OSX_DEPRECATED(10.0, 10.1, "NXMapTable is deprecated") \ OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.0, 10.1, "NXMapTable is deprecated")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE
#else #else
# define OBJC_MAP_AVAILABILITY # define OBJC_MAP_AVAILABILITY
#endif #endif
@ -49,16 +48,21 @@ __BEGIN_DECLS
typedef struct _NXMapTable { typedef struct _NXMapTable {
/* private data structure; may change */ /* private data structure; may change */
const struct _NXMapTablePrototype *prototype; const struct _NXMapTablePrototype * _Nonnull prototype;
unsigned count; unsigned count;
unsigned nbBucketsMinusOne; unsigned nbBucketsMinusOne;
void *buckets; void * _Nullable buckets;
} NXMapTable OBJC_MAP_AVAILABILITY; } NXMapTable OBJC_MAP_AVAILABILITY;
typedef struct _NXMapTablePrototype { typedef struct _NXMapTablePrototype {
unsigned (*hash)(NXMapTable *, const void *key); unsigned (* _Nonnull hash)(NXMapTable * _Nonnull,
int (*isEqual)(NXMapTable *, const void *key1, const void *key2); const void * _Nullable key);
void (*free)(NXMapTable *, void *key, void *value); int (* _Nonnull isEqual)(NXMapTable * _Nonnull,
const void * _Nullable key1,
const void * _Nullable key2);
void (* _Nonnull free)(NXMapTable * _Nonnull,
void * _Nullable key,
void * _Nullable value);
int style; /* reserved for future expansion; currently 0 */ int style; /* reserved for future expansion; currently 0 */
} NXMapTablePrototype OBJC_MAP_AVAILABILITY; } NXMapTablePrototype OBJC_MAP_AVAILABILITY;
@ -70,36 +74,59 @@ typedef struct _NXMapTablePrototype {
C - isEqual(key1, key2) => key1 == key2 C - isEqual(key1, key2) => key1 == key2
*/ */
#define NX_MAPNOTAKEY ((void *)(-1)) #define NX_MAPNOTAKEY ((void * _Nonnull)(-1))
/*************** Functions ***************/ /*************** Functions ***************/
OBJC_EXPORT NXMapTable *NXCreateMapTableFromZone(NXMapTablePrototype prototype, unsigned capacity, void *z) OBJC_MAP_AVAILABILITY; OBJC_EXPORT NXMapTable * _Nonnull
OBJC_EXPORT NXMapTable *NXCreateMapTable(NXMapTablePrototype prototype, unsigned capacity) OBJC_MAP_AVAILABILITY; NXCreateMapTableFromZone(NXMapTablePrototype prototype,
unsigned capacity, void * _Nullable z)
OBJC_MAP_AVAILABILITY;
OBJC_EXPORT NXMapTable * _Nonnull
NXCreateMapTable(NXMapTablePrototype prototype, unsigned capacity)
OBJC_MAP_AVAILABILITY;
/* capacity is only a hint; 0 creates a small table */ /* capacity is only a hint; 0 creates a small table */
OBJC_EXPORT void NXFreeMapTable(NXMapTable *table) OBJC_MAP_AVAILABILITY; OBJC_EXPORT void
NXFreeMapTable(NXMapTable * _Nonnull table)
OBJC_MAP_AVAILABILITY;
/* call free for each pair, and recovers table */ /* call free for each pair, and recovers table */
OBJC_EXPORT void NXResetMapTable(NXMapTable *table) OBJC_MAP_AVAILABILITY; OBJC_EXPORT void
NXResetMapTable(NXMapTable * _Nonnull table)
OBJC_MAP_AVAILABILITY;
/* free each pair; keep current capacity */ /* free each pair; keep current capacity */
OBJC_EXPORT BOOL NXCompareMapTables(NXMapTable *table1, NXMapTable *table2) OBJC_MAP_AVAILABILITY; OBJC_EXPORT BOOL
NXCompareMapTables(NXMapTable * _Nonnull table1, NXMapTable * _Nonnull table2)
OBJC_MAP_AVAILABILITY;
/* Returns YES if the two sets are equal (each member of table1 in table2, and table have same size) */ /* Returns YES if the two sets are equal (each member of table1 in table2, and table have same size) */
OBJC_EXPORT unsigned NXCountMapTable(NXMapTable *table) OBJC_MAP_AVAILABILITY; OBJC_EXPORT unsigned
NXCountMapTable(NXMapTable * _Nonnull table)
OBJC_MAP_AVAILABILITY;
/* current number of data in table */ /* current number of data in table */
OBJC_EXPORT void *NXMapMember(NXMapTable *table, const void *key, void **value) OBJC_MAP_AVAILABILITY; OBJC_EXPORT void * _Nullable
NXMapMember(NXMapTable * _Nonnull table, const void * _Nullable key,
void * _Nullable * _Nonnull value) OBJC_MAP_AVAILABILITY;
/* return original table key or NX_MAPNOTAKEY. If key is found, value is set */ /* return original table key or NX_MAPNOTAKEY. If key is found, value is set */
OBJC_EXPORT void *NXMapGet(NXMapTable *table, const void *key) OBJC_MAP_AVAILABILITY; OBJC_EXPORT void * _Nullable
NXMapGet(NXMapTable * _Nonnull table, const void * _Nullable key)
OBJC_MAP_AVAILABILITY;
/* return original corresponding value or NULL. When NULL need be stored as value, NXMapMember can be used to test for presence */ /* return original corresponding value or NULL. When NULL need be stored as value, NXMapMember can be used to test for presence */
OBJC_EXPORT void *NXMapInsert(NXMapTable *table, const void *key, const void *value) OBJC_MAP_AVAILABILITY; OBJC_EXPORT void * _Nullable
NXMapInsert(NXMapTable * _Nonnull table, const void * _Nullable key,
const void * _Nullable value)
OBJC_MAP_AVAILABILITY;
/* override preexisting pair; Return previous value or NULL. */ /* override preexisting pair; Return previous value or NULL. */
OBJC_EXPORT void *NXMapRemove(NXMapTable *table, const void *key) OBJC_MAP_AVAILABILITY; OBJC_EXPORT void * _Nullable
NXMapRemove(NXMapTable * _Nonnull table, const void * _Nullable key)
OBJC_MAP_AVAILABILITY;
/* previous value or NULL is returned */ /* previous value or NULL is returned */
/* Iteration over all elements of a table consists in setting up an iteration state and then to progress until all entries have been visited. An example of use for counting elements in a table is: /* Iteration over all elements of a table consists in setting up an iteration state and then to progress until all entries have been visited. An example of use for counting elements in a table is:
@ -115,22 +142,31 @@ OBJC_EXPORT void *NXMapRemove(NXMapTable *table, const void *key) OBJC_MAP_AVAIL
typedef struct {int index;} NXMapState OBJC_MAP_AVAILABILITY; typedef struct {int index;} NXMapState OBJC_MAP_AVAILABILITY;
/* callers should not rely on actual contents of the struct */ /* callers should not rely on actual contents of the struct */
OBJC_EXPORT NXMapState NXInitMapState(NXMapTable *table) OBJC_MAP_AVAILABILITY; OBJC_EXPORT NXMapState
NXInitMapState(NXMapTable * _Nonnull table)
OBJC_MAP_AVAILABILITY;
OBJC_EXPORT int NXNextMapState(NXMapTable *table, NXMapState *state, const void **key, const void **value) OBJC_MAP_AVAILABILITY; OBJC_EXPORT int
NXNextMapState(NXMapTable * _Nonnull table, NXMapState * _Nonnull state,
const void * _Nullable * _Nonnull key,
const void * _Nullable * _Nonnull value)
OBJC_MAP_AVAILABILITY;
/* returns 0 when all elements have been visited */ /* returns 0 when all elements have been visited */
/*************** Conveniences ***************/ /*************** Conveniences ***************/
OBJC_EXPORT const NXMapTablePrototype NXPtrValueMapPrototype OBJC_MAP_AVAILABILITY; OBJC_EXPORT const NXMapTablePrototype NXPtrValueMapPrototype
OBJC_MAP_AVAILABILITY;
/* hashing is pointer/integer hashing; /* hashing is pointer/integer hashing;
isEqual is identity; isEqual is identity;
free is no-op. */ free is no-op. */
OBJC_EXPORT const NXMapTablePrototype NXStrValueMapPrototype OBJC_MAP_AVAILABILITY; OBJC_EXPORT const NXMapTablePrototype NXStrValueMapPrototype
OBJC_MAP_AVAILABILITY;
/* hashing is string hashing; /* hashing is string hashing;
isEqual is strcmp; isEqual is strcmp;
free is no-op. */ free is no-op. */
OBJC_EXPORT const NXMapTablePrototype NXObjectMapPrototype OBJC2_UNAVAILABLE; OBJC_EXPORT const NXMapTablePrototype NXObjectMapPrototype
OBJC2_UNAVAILABLE;
/* for objects; uses methods: hash, isEqual:, free, all for key. */ /* for objects; uses methods: hash, isEqual:, free, all for key. */
__END_DECLS __END_DECLS

View File

@ -161,11 +161,107 @@ BOOL NXCompareMapTables(NXMapTable *table1, NXMapTable *table2) {
unsigned NXCountMapTable(NXMapTable *table) { return table->count; } unsigned NXCountMapTable(NXMapTable *table) { return table->count; }
#if __x86_64__
extern "C" void __NXMAPTABLE_CORRUPTED__
(const void *table, const void *buckets, uint64_t count,
uint64_t nbBucketsMinusOne, uint64_t badkeys, uint64_t index,
uint64_t index2, uint64_t pairIndexes, const void *key1,
const void *value1, const void *key2, const void *value2,
const void *key3, const void *value3);
static int _mapStrIsEqual(NXMapTable *table, const void *key1, const void *key2);
asm("\n .text"
"\n .private_extern ___NXMAPTABLE_CORRUPTED__"
"\n ___NXMAPTABLE_CORRUPTED__:"
// push a frame for the unwinder to see
"\n pushq %rbp"
"\n mov %rsp, %rbp"
// push register parameters to the stack in reverse order
"\n pushq %r9"
"\n pushq %r8"
"\n pushq %rcx"
"\n pushq %rdx"
"\n pushq %rsi"
"\n pushq %rdi"
// pop the pushed register parameters into their destinations
"\n popq %rax" // table
"\n popq %rbx" // buckets
"\n popq %rcx" // count
"\n popq %rdx" // nbBucketsMinusOne
"\n popq %rdi" // badkeys
"\n popq %rsi" // index
// read stack parameters into their destinations
"\n mov 0*8+16(%rbp), %r8" // index2
"\n mov 1*8+16(%rbp), %r9" // pairIndexes
"\n mov 2*8+16(%rbp), %r10" // key1
"\n mov 3*8+16(%rbp), %r11" // value1
"\n mov 4*8+16(%rbp), %r12" // key2
"\n mov 5*8+16(%rbp), %r13" // value2
"\n mov 6*8+16(%rbp), %r14" // key3
"\n mov 7*8+16(%rbp), %r15" // value3
"\n ud2");
#endif
// Look for a particular case of data corruption (rdar://36373000)
// and investigate it further before crashing.
static void validateKey(NXMapTable *table, MapPair *pair,
unsigned index, unsigned index2)
{
#if __x86_64__
# define BADKEY ((void * _Nonnull)(0xfffffffffffffffeULL))
if (pair->key != BADKEY ||
table->prototype->isEqual != _mapStrIsEqual)
{
return;
}
_objc_inform_now_and_on_crash
("NXMapTable %p (%p) has invalid key/value pair %p->%p (%p)",
table, table->buckets, pair->key, pair->value, pair);
_objc_inform_now_and_on_crash
("table %p, buckets %p, count %u, nbNucketsMinusOne %u, "
"prototype %p (hash %p, isEqual %p, free %p)",
table, table->buckets, table->count, table->nbBucketsMinusOne,
table->prototype, table->prototype->hash, table->prototype->isEqual,
table->prototype->free);
// Count the number of bad keys in the table.
MapPair *pairs = (MapPair *)table->buckets;
unsigned badKeys = 0;
for (unsigned i = 0; i < table->nbBucketsMinusOne+1; i++) {
if (pairs[i].key == BADKEY) badKeys++;
}
_objc_inform_now_and_on_crash("%u invalid keys in table", badKeys);
// Record some additional key pairs for posterity.
unsigned pair2Index = nextIndex(table, index);
unsigned pair3Index = nextIndex(table, pair2Index);
MapPair *pair2 = pairs + pair2Index;
MapPair *pair3 = pairs + pair3Index;
uint64_t pairIndexes = ((uint64_t)pair2Index << 32) | pair3Index;
// Save a bunch of values to registers so we can see them in the crash log.
__NXMAPTABLE_CORRUPTED__
(// rax, rbx, rcx, rdx
table, table->buckets, table->count, table->nbBucketsMinusOne,
// rdi, rsi, skip rbp, skip rsp
badKeys, index,
// r8, r9, r10, r11
index2, pairIndexes, pair->key, pair->value,
// r12, r13, r14, r15
pair2->key, pair2->value, pair3->key, pair3->value);
#endif
}
static INLINE void *_NXMapMember(NXMapTable *table, const void *key, void **value) { static INLINE void *_NXMapMember(NXMapTable *table, const void *key, void **value) {
MapPair *pairs = (MapPair *)table->buckets; MapPair *pairs = (MapPair *)table->buckets;
unsigned index = bucketOf(table, key); unsigned index = bucketOf(table, key);
MapPair *pair = pairs + index; MapPair *pair = pairs + index;
if (pair->key == NX_MAPNOTAKEY) return NX_MAPNOTAKEY; if (pair->key == NX_MAPNOTAKEY) return NX_MAPNOTAKEY;
validateKey(table, pair, index, index);
if (isEqual(table, pair->key, key)) { if (isEqual(table, pair->key, key)) {
*value = (void *)pair->value; *value = (void *)pair->value;
return (void *)pair->key; return (void *)pair->key;
@ -174,6 +270,7 @@ static INLINE void *_NXMapMember(NXMapTable *table, const void *key, void **valu
while ((index2 = nextIndex(table, index2)) != index) { while ((index2 = nextIndex(table, index2)) != index) {
pair = pairs + index2; pair = pairs + index2;
if (pair->key == NX_MAPNOTAKEY) return NX_MAPNOTAKEY; if (pair->key == NX_MAPNOTAKEY) return NX_MAPNOTAKEY;
validateKey(table, pair, index, index2);
if (isEqual(table, pair->key, key)) { if (isEqual(table, pair->key, key)) {
*value = (void *)pair->value; *value = (void *)pair->value;
return (void *)pair->key; return (void *)pair->key;
@ -244,7 +341,7 @@ void *NXMapInsert(NXMapTable *table, const void *key, const void *value) {
while ((index2 = nextIndex(table, index2)) != index) { while ((index2 = nextIndex(table, index2)) != index) {
pair = pairs + index2; pair = pairs + index2;
if (pair->key == NX_MAPNOTAKEY) { if (pair->key == NX_MAPNOTAKEY) {
pair->key = key; pair->value = value; pair->key = key; pair->value = value;
table->count++; table->count++;
if (table->count * 4 > numBuckets * 3) _NXMapRehash(table); if (table->count * 4 > numBuckets * 3) _NXMapRehash(table);
return NULL; return NULL;
@ -261,8 +358,6 @@ void *NXMapInsert(NXMapTable *table, const void *key, const void *value) {
} }
} }
static int mapRemove = 0;
void *NXMapRemove(NXMapTable *table, const void *key) { void *NXMapRemove(NXMapTable *table, const void *key) {
MapPair *pairs = (MapPair *)table->buckets; MapPair *pairs = (MapPair *)table->buckets;
unsigned index = bucketOf(table, key); unsigned index = bucketOf(table, key);
@ -271,7 +366,6 @@ void *NXMapRemove(NXMapTable *table, const void *key) {
int found = 0; int found = 0;
const void *old = NULL; const void *old = NULL;
if (pair->key == NX_MAPNOTAKEY) return NULL; if (pair->key == NX_MAPNOTAKEY) return NULL;
mapRemove ++;
/* compute chain */ /* compute chain */
{ {
unsigned index2 = index; unsigned index2 = index;

View File

@ -24,27 +24,23 @@
#ifndef _OBJC_MESSAGE_H #ifndef _OBJC_MESSAGE_H
#define _OBJC_MESSAGE_H #define _OBJC_MESSAGE_H
#pragma GCC system_header
#include <objc/objc.h> #include <objc/objc.h>
#include <objc/runtime.h> #include <objc/runtime.h>
#pragma GCC system_header
#ifndef OBJC_SUPER #ifndef OBJC_SUPER
#define OBJC_SUPER #define OBJC_SUPER
/// Specifies the superclass of an instance. /// Specifies the superclass of an instance.
struct objc_super { struct objc_super {
/// Specifies an instance of a class. /// Specifies an instance of a class.
__unsafe_unretained id receiver; __unsafe_unretained _Nonnull id receiver;
/// Specifies the particular superclass of the instance to message. /// Specifies the particular superclass of the instance to message.
#if !defined(__cplusplus) && !__OBJC2__ #if !defined(__cplusplus) && !__OBJC2__
/* For compatibility with old objc-runtime.h header */ /* For compatibility with old objc-runtime.h header */
__unsafe_unretained Class class; __unsafe_unretained _Nonnull Class class;
#else #else
__unsafe_unretained Class super_class; __unsafe_unretained _Nonnull Class super_class;
#endif #endif
/* super_class is the first class to search */ /* super_class is the first class to search */
}; };
@ -61,10 +57,16 @@ struct objc_super {
* before being called. * before being called.
*/ */
#if !OBJC_OLD_DISPATCH_PROTOTYPES #if !OBJC_OLD_DISPATCH_PROTOTYPES
OBJC_EXPORT void objc_msgSend(void /* id self, SEL op, ... */ ) #pragma clang diagnostic push
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0); #pragma clang diagnostic ignored "-Wincompatible-library-redeclaration"
OBJC_EXPORT void objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ ) OBJC_EXPORT void
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0); objc_msgSend(void /* id self, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
#pragma clang diagnostic pop
#else #else
/** /**
* Sends a message with a simple return value to an instance of a class. * Sends a message with a simple return value to an instance of a class.
@ -82,8 +84,9 @@ OBJC_EXPORT void objc_msgSendSuper(void /* struct objc_super *super, SEL op, ...
* other messages are sent using \c objc_msgSend. Methods that have data structures as return values * other messages are sent using \c objc_msgSend. Methods that have data structures as return values
* are sent using \c objc_msgSendSuper_stret and \c objc_msgSend_stret. * are sent using \c objc_msgSendSuper_stret and \c objc_msgSend_stret.
*/ */
OBJC_EXPORT id objc_msgSend(id self, SEL op, ...) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0); objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
/** /**
* Sends a message with a simple return value to the superclass of an instance of a class. * Sends a message with a simple return value to the superclass of an instance of a class.
* *
@ -98,8 +101,9 @@ OBJC_EXPORT id objc_msgSend(id self, SEL op, ...)
* *
* @see objc_msgSend * @see objc_msgSend
*/ */
OBJC_EXPORT id objc_msgSendSuper(struct objc_super *super, SEL op, ...) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0); objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
#endif #endif
@ -113,20 +117,27 @@ OBJC_EXPORT id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
* before being called. * before being called.
*/ */
#if !OBJC_OLD_DISPATCH_PROTOTYPES #if !OBJC_OLD_DISPATCH_PROTOTYPES
OBJC_EXPORT void objc_msgSend_stret(void /* id self, SEL op, ... */ ) #pragma clang diagnostic push
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0) #pragma clang diagnostic ignored "-Wincompatible-library-redeclaration"
OBJC_EXPORT void
objc_msgSend_stret(void /* id self, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
OBJC_EXPORT void objc_msgSendSuper_stret(void /* struct objc_super *super, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0) OBJC_EXPORT void
objc_msgSendSuper_stret(void /* struct objc_super *super, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
#pragma clang diagnostic pop
#else #else
/** /**
* Sends a message with a data-structure return value to an instance of a class. * Sends a message with a data-structure return value to an instance of a class.
* *
* @see objc_msgSend * @see objc_msgSend
*/ */
OBJC_EXPORT void objc_msgSend_stret(id self, SEL op, ...) OBJC_EXPORT void
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0) objc_msgSend_stret(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
/** /**
@ -134,8 +145,10 @@ OBJC_EXPORT void objc_msgSend_stret(id self, SEL op, ...)
* *
* @see objc_msgSendSuper * @see objc_msgSendSuper
*/ */
OBJC_EXPORT void objc_msgSendSuper_stret(struct objc_super *super, SEL op, ...) OBJC_EXPORT void
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0) objc_msgSendSuper_stret(struct objc_super * _Nonnull super,
SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
#endif #endif
@ -158,19 +171,26 @@ OBJC_EXPORT void objc_msgSendSuper_stret(struct objc_super *super, SEL op, ...)
* before being called. * before being called.
*/ */
#if !OBJC_OLD_DISPATCH_PROTOTYPES #if !OBJC_OLD_DISPATCH_PROTOTYPES
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincompatible-library-redeclaration"
# if defined(__i386__) # if defined(__i386__)
OBJC_EXPORT void objc_msgSend_fpret(void /* id self, SEL op, ... */ ) OBJC_EXPORT void
OBJC_AVAILABLE(10.4, 2.0, 9.0, 1.0); objc_msgSend_fpret(void /* id self, SEL op, ... */ )
OBJC_AVAILABLE(10.4, 2.0, 9.0, 1.0, 2.0);
# elif defined(__x86_64__) # elif defined(__x86_64__)
OBJC_EXPORT void objc_msgSend_fpret(void /* id self, SEL op, ... */ ) OBJC_EXPORT void
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); objc_msgSend_fpret(void /* id self, SEL op, ... */ )
OBJC_EXPORT void objc_msgSend_fp2ret(void /* id self, SEL op, ... */ ) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT void
objc_msgSend_fp2ret(void /* id self, SEL op, ... */ )
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
#pragma clang diagnostic pop
# endif # endif
// !OBJC_OLD_DISPATCH_PROTOTYPES // !OBJC_OLD_DISPATCH_PROTOTYPES
@ -187,8 +207,12 @@ OBJC_EXPORT void objc_msgSend_fp2ret(void /* id self, SEL op, ... */ )
* you must use \c objc_msgSend_fpret for functions returning non-integral type. For \c float or * you must use \c objc_msgSend_fpret for functions returning non-integral type. For \c float or
* \c long \c double return types, cast the function to an appropriate function pointer type first. * \c long \c double return types, cast the function to an appropriate function pointer type first.
*/ */
OBJC_EXPORT double objc_msgSend_fpret(id self, SEL op, ...) #pragma clang diagnostic push
OBJC_AVAILABLE(10.4, 2.0, 9.0, 1.0); #pragma clang diagnostic ignored "-Wincompatible-library-redeclaration"
OBJC_EXPORT double
objc_msgSend_fpret(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.4, 2.0, 9.0, 1.0, 2.0);
#pragma clang diagnostic pop
/* Use objc_msgSendSuper() for fp-returning messages to super. */ /* Use objc_msgSendSuper() for fp-returning messages to super. */
/* See also objc_msgSendv_fpret() below. */ /* See also objc_msgSendv_fpret() below. */
@ -199,15 +223,17 @@ OBJC_EXPORT double objc_msgSend_fpret(id self, SEL op, ...)
* *
* @see objc_msgSend * @see objc_msgSend
*/ */
OBJC_EXPORT long double objc_msgSend_fpret(id self, SEL op, ...) OBJC_EXPORT long double
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); objc_msgSend_fpret(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
# if __STDC_VERSION__ >= 199901L # if __STDC_VERSION__ >= 199901L
OBJC_EXPORT _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...) OBJC_EXPORT _Complex long double
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); objc_msgSend_fp2ret(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
# else # else
OBJC_EXPORT void objc_msgSend_fp2ret(id self, SEL op, ...) OBJC_EXPORT void objc_msgSend_fp2ret(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
# endif # endif
/* Use objc_msgSendSuper() for fp-returning messages to super. */ /* Use objc_msgSendSuper() for fp-returning messages to super. */
@ -229,16 +255,25 @@ OBJC_EXPORT void objc_msgSend_fp2ret(id self, SEL op, ...)
* before being called. * before being called.
*/ */
#if !OBJC_OLD_DISPATCH_PROTOTYPES #if !OBJC_OLD_DISPATCH_PROTOTYPES
OBJC_EXPORT void method_invoke(void /* id receiver, Method m, ... */ ) #pragma clang diagnostic push
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); #pragma clang diagnostic ignored "-Wincompatible-library-redeclaration"
OBJC_EXPORT void method_invoke_stret(void /* id receiver, Method m, ... */ ) OBJC_EXPORT void
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0) method_invoke(void /* id receiver, Method m, ... */ )
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
method_invoke_stret(void /* id receiver, Method m, ... */ )
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
#pragma clang diagnostic pop
#else #else
OBJC_EXPORT id method_invoke(id receiver, Method m, ...) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); method_invoke(id _Nullable receiver, Method _Nonnull m, ...)
OBJC_EXPORT void method_invoke_stret(id receiver, Method m, ...) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0)
OBJC_EXPORT void
method_invoke_stret(id _Nullable receiver, Method _Nonnull m, ...)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
#endif #endif
@ -259,16 +294,25 @@ OBJC_EXPORT void method_invoke_stret(id receiver, Method m, ...)
* but may be compared to other IMP values. * but may be compared to other IMP values.
*/ */
#if !OBJC_OLD_DISPATCH_PROTOTYPES #if !OBJC_OLD_DISPATCH_PROTOTYPES
OBJC_EXPORT void _objc_msgForward(void /* id receiver, SEL sel, ... */ ) #pragma clang diagnostic push
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0); #pragma clang diagnostic ignored "-Wincompatible-library-redeclaration"
OBJC_EXPORT void _objc_msgForward_stret(void /* id receiver, SEL sel, ... */ ) OBJC_EXPORT void
OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0) _objc_msgForward(void /* id receiver, SEL sel, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
_objc_msgForward_stret(void /* id receiver, SEL sel, ... */ )
OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
#pragma clang diagnostic pop
#else #else
OBJC_EXPORT id _objc_msgForward(id receiver, SEL sel, ...) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0); _objc_msgForward(id _Nonnull receiver, SEL _Nonnull sel, ...)
OBJC_EXPORT void _objc_msgForward_stret(id receiver, SEL sel, ...) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0)
OBJC_EXPORT void
_objc_msgForward_stret(id _Nonnull receiver, SEL _Nonnull sel, ...)
OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
#endif #endif
@ -288,14 +332,25 @@ OBJC_EXPORT void _objc_msgForward_stret(id receiver, SEL sel, ...)
typedef void* marg_list; typedef void* marg_list;
OBJC_EXPORT id objc_msgSendv(id self, SEL op, size_t arg_size, marg_list arg_frame) OBJC2_UNAVAILABLE; OBJC_EXPORT id _Nullable
OBJC_EXPORT void objc_msgSendv_stret(void *stretAddr, id self, SEL op, size_t arg_size, marg_list arg_frame) OBJC2_UNAVAILABLE; objc_msgSendv(id _Nullable self, SEL _Nonnull op, size_t arg_size,
marg_list _Nonnull arg_frame)
OBJC2_UNAVAILABLE;
OBJC_EXPORT void
objc_msgSendv_stret(void * _Nonnull stretAddr, id _Nullable self,
SEL _Nonnull op, size_t arg_size,
marg_list _Nullable arg_frame)
OBJC2_UNAVAILABLE;
/* Note that objc_msgSendv_stret() does not return a structure type, /* Note that objc_msgSendv_stret() does not return a structure type,
* and should not be cast to do so. This is unlike objc_msgSend_stret() * and should not be cast to do so. This is unlike objc_msgSend_stret()
* and objc_msgSendSuper_stret(). * and objc_msgSendSuper_stret().
*/ */
#if defined(__i386__) #if defined(__i386__)
OBJC_EXPORT double objc_msgSendv_fpret(id self, SEL op, unsigned arg_size, marg_list arg_frame) OBJC2_UNAVAILABLE; OBJC_EXPORT double
objc_msgSendv_fpret(id _Nullable self, SEL _Nonnull op,
unsigned arg_size, marg_list _Nullable arg_frame)
OBJC2_UNAVAILABLE;
#endif #endif

View File

@ -43,11 +43,51 @@
#include <objc/runtime.h> #include <objc/runtime.h>
#include <objc/message.h> #include <objc/message.h>
/* Linker metadata symbols */
// NSObject was in Foundation/CF on macOS < 10.8.
#if TARGET_OS_OSX
#if __OBJC2__
OBJC_EXPORT const char __objc_nsobject_class_10_5
__asm__("$ld$hide$os10.5$_OBJC_CLASS_$_NSObject");
OBJC_EXPORT const char __objc_nsobject_class_10_6
__asm__("$ld$hide$os10.6$_OBJC_CLASS_$_NSObject");
OBJC_EXPORT const char __objc_nsobject_class_10_7
__asm__("$ld$hide$os10.7$_OBJC_CLASS_$_NSObject");
OBJC_EXPORT const char __objc_nsobject_metaclass_10_5
__asm__("$ld$hide$os10.5$_OBJC_METACLASS_$_NSObject");
OBJC_EXPORT const char __objc_nsobject_metaclass_10_6
__asm__("$ld$hide$os10.6$_OBJC_METACLASS_$_NSObject");
OBJC_EXPORT const char __objc_nsobject_metaclass_10_7
__asm__("$ld$hide$os10.7$_OBJC_METACLASS_$_NSObject");
OBJC_EXPORT const char __objc_nsobject_isa_10_5
__asm__("$ld$hide$os10.5$_OBJC_IVAR_$_NSObject.isa");
OBJC_EXPORT const char __objc_nsobject_isa_10_6
__asm__("$ld$hide$os10.6$_OBJC_IVAR_$_NSObject.isa");
OBJC_EXPORT const char __objc_nsobject_isa_10_7
__asm__("$ld$hide$os10.7$_OBJC_IVAR_$_NSObject.isa");
#else
OBJC_EXPORT const char __objc_nsobject_class_10_5
__asm__("$ld$hide$os10.5$.objc_class_name_NSObject");
OBJC_EXPORT const char __objc_nsobject_class_10_6
__asm__("$ld$hide$os10.6$.objc_class_name_NSObject");
OBJC_EXPORT const char __objc_nsobject_class_10_7
__asm__("$ld$hide$os10.7$.objc_class_name_NSObject");
#endif
#endif
/* Runtime startup. */ /* Runtime startup. */
// Old static initializer. Used by old crt1.o and old bug workarounds. // Old static initializer. Used by old crt1.o and old bug workarounds.
OBJC_EXPORT void _objcInit(void) OBJC_EXPORT void
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0); _objcInit(void)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
/* Images */ /* Images */
@ -60,6 +100,7 @@ typedef struct objc_image_info {
#if __cplusplus >= 201103L #if __cplusplus >= 201103L
private: private:
enum : uint32_t { enum : uint32_t {
// 1 byte assorted flags
IsReplacement = 1<<0, // used for Fix&Continue, now ignored IsReplacement = 1<<0, // used for Fix&Continue, now ignored
SupportsGC = 1<<1, // image supports GC SupportsGC = 1<<1, // image supports GC
RequiresGC = 1<<2, // image requires GC RequiresGC = 1<<2, // image requires GC
@ -67,17 +108,28 @@ typedef struct objc_image_info {
CorrectedSynthesize = 1<<4, // used for an old workaround, now ignored CorrectedSynthesize = 1<<4, // used for an old workaround, now ignored
IsSimulated = 1<<5, // image compiled for a simulator platform IsSimulated = 1<<5, // image compiled for a simulator platform
HasCategoryClassProperties = 1<<6, // class properties in category_t HasCategoryClassProperties = 1<<6, // class properties in category_t
OptimizedByDyldClosure = 1 << 7, // dyld (not the shared cache) optimized this.
SwiftVersionMaskShift = 8, // 1 byte Swift unstable ABI version number
SwiftVersionMask = 0xff << SwiftVersionMaskShift // Swift ABI version SwiftUnstableVersionMaskShift = 8,
SwiftUnstableVersionMask = 0xff << SwiftUnstableVersionMaskShift,
// 2 byte Swift stable ABI version number
SwiftStableVersionMaskShift = 16,
SwiftStableVersionMask = 0xffffUL << SwiftStableVersionMaskShift
}; };
public: public:
enum : uint32_t { enum : uint32_t {
// Values for SwiftUnstableVersion
// All stable ABIs store SwiftVersion5 here.
SwiftVersion1 = 1, SwiftVersion1 = 1,
SwiftVersion1_2 = 2, SwiftVersion1_2 = 2,
SwiftVersion2 = 3, SwiftVersion2 = 3,
SwiftVersion3 = 4 SwiftVersion3 = 4,
SwiftVersion4 = 5,
SwiftVersion4_1 = 6,
SwiftVersion4_2 = 6, // [sic]
SwiftVersion5 = 7
}; };
public: public:
@ -86,8 +138,9 @@ typedef struct objc_image_info {
bool requiresGC() const { return flags & RequiresGC; } bool requiresGC() const { return flags & RequiresGC; }
bool optimizedByDyld() const { return flags & OptimizedByDyld; } bool optimizedByDyld() const { return flags & OptimizedByDyld; }
bool hasCategoryClassProperties() const { return flags & HasCategoryClassProperties; } bool hasCategoryClassProperties() const { return flags & HasCategoryClassProperties; }
bool containsSwift() const { return (flags & SwiftVersionMask) != 0; } bool optimizedByDyldClosure() const { return flags & OptimizedByDyldClosure; }
uint32_t swiftVersion() const { return (flags & SwiftVersionMask) >> SwiftVersionMaskShift; } bool containsSwift() const { return (flags & SwiftUnstableVersionMask) != 0; }
uint32_t swiftUnstableVersion() const { return (flags & SwiftUnstableVersionMask) >> SwiftUnstableVersionMaskShift; }
#endif #endif
} objc_image_info; } objc_image_info;
@ -122,52 +175,78 @@ HasClassProperties:
/* Properties */ /* Properties */
// Read or write an object property. Not all object properties use these. // Read or write an object property. Not all object properties use these.
OBJC_EXPORT id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); objc_getProperty(id _Nullable self, SEL _Nonnull _cmd,
OBJC_EXPORT void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy) ptrdiff_t offset, BOOL atomic)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset) OBJC_EXPORT void
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0); objc_setProperty(id _Nullable self, SEL _Nonnull _cmd, ptrdiff_t offset,
OBJC_EXPORT void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset) id _Nullable newValue, BOOL atomic, signed char shouldCopy)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0); OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0); OBJC_EXPORT void
OBJC_EXPORT void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset) objc_setProperty_atomic(id _Nullable self, SEL _Nonnull _cmd,
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0); id _Nullable newValue, ptrdiff_t offset)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_setProperty_nonatomic(id _Nullable self, SEL _Nonnull _cmd,
id _Nullable newValue, ptrdiff_t offset)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_setProperty_atomic_copy(id _Nullable self, SEL _Nonnull _cmd,
id _Nullable newValue, ptrdiff_t offset)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_setProperty_nonatomic_copy(id _Nullable self, SEL _Nonnull _cmd,
id _Nullable newValue, ptrdiff_t offset)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
// Read or write a non-object property. Not all uses are C structs, // Read or write a non-object property. Not all uses are C structs,
// and not all C struct properties use this. // and not all C struct properties use this.
OBJC_EXPORT void objc_copyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic, BOOL hasStrong) OBJC_EXPORT void
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); objc_copyStruct(void * _Nonnull dest, const void * _Nonnull src,
ptrdiff_t size, BOOL atomic, BOOL hasStrong)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
// Perform a copy of a C++ object using striped locks. Used by non-POD C++ typed atomic properties. // Perform a copy of a C++ object using striped locks. Used by non-POD C++ typed atomic properties.
OBJC_EXPORT void objc_copyCppObjectAtomic(void *dest, const void *src, void (*copyHelper) (void *dest, const void *source)) OBJC_EXPORT void
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0); objc_copyCppObjectAtomic(void * _Nonnull dest, const void * _Nonnull src,
void (* _Nonnull copyHelper)
(void * _Nonnull dest, const void * _Nonnull source))
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
/* Classes. */ /* Classes. */
#if __OBJC2__ #if __OBJC2__
OBJC_EXPORT IMP _objc_empty_vtable OBJC_EXPORT IMP _Nonnull _objc_empty_vtable
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
#endif #endif
OBJC_EXPORT struct objc_cache _objc_empty_cache OBJC_EXPORT struct objc_cache _objc_empty_cache
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0); OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
/* Messages */ /* Messages */
#if __OBJC2__ #if __OBJC2__
// objc_msgSendSuper2() takes the current search class, not its superclass. // objc_msgSendSuper2() takes the current search class, not its superclass.
OBJC_EXPORT id objc_msgSendSuper2(struct objc_super *super, SEL op, ...) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.6, 2.0, 9.0, 1.0); objc_msgSendSuper2(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
OBJC_EXPORT void objc_msgSendSuper2_stret(struct objc_super *super, SEL op,...) OBJC_AVAILABLE(10.6, 2.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.6, 2.0, 9.0, 1.0)
OBJC_EXPORT void
objc_msgSendSuper2_stret(struct objc_super * _Nonnull super,
SEL _Nonnull op,...)
OBJC_AVAILABLE(10.6, 2.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
// objc_msgSend_noarg() may be faster for methods with no additional arguments. // objc_msgSend_noarg() may be faster for methods with no additional arguments.
OBJC_EXPORT id objc_msgSend_noarg(id self, SEL _cmd) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); objc_msgSend_noarg(id _Nullable self, SEL _Nonnull _cmd)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
#endif #endif
#if __OBJC2__ #if __OBJC2__
@ -175,29 +254,42 @@ OBJC_EXPORT id objc_msgSend_noarg(id self, SEL _cmd)
// may perform extra sanity checking. // may perform extra sanity checking.
// Old objc_msgSendSuper() does not have a debug version; this is OBJC2 only. // Old objc_msgSendSuper() does not have a debug version; this is OBJC2 only.
// *_fixup() do not have debug versions; use non-fixup only for debug mode. // *_fixup() do not have debug versions; use non-fixup only for debug mode.
OBJC_EXPORT id objc_msgSend_debug(id self, SEL op, ...) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); objc_msgSend_debug(id _Nullable self, SEL _Nonnull op, ...)
OBJC_EXPORT id objc_msgSendSuper2_debug(struct objc_super *super, SEL op, ...) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT void objc_msgSend_stret_debug(id self, SEL op, ...) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0) objc_msgSendSuper2_debug(struct objc_super * _Nonnull super,
SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_msgSend_stret_debug(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
OBJC_EXPORT void objc_msgSendSuper2_stret_debug(struct objc_super *super, SEL op,...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0) OBJC_EXPORT void
objc_msgSendSuper2_stret_debug(struct objc_super * _Nonnull super,
SEL _Nonnull op,...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
# if defined(__i386__) # if defined(__i386__)
OBJC_EXPORT double objc_msgSend_fpret_debug(id self, SEL op, ...) OBJC_EXPORT double
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); objc_msgSend_fpret_debug(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
# elif defined(__x86_64__) # elif defined(__x86_64__)
OBJC_EXPORT long double objc_msgSend_fpret_debug(id self, SEL op, ...) OBJC_EXPORT long double
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); objc_msgSend_fpret_debug(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
# if __STDC_VERSION__ >= 199901L # if __STDC_VERSION__ >= 199901L
OBJC_EXPORT _Complex long double objc_msgSend_fp2ret_debug(id self, SEL op, ...) OBJC_EXPORT _Complex long double
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); objc_msgSend_fp2ret_debug(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
# else # else
OBJC_EXPORT void objc_msgSend_fp2ret_debug(id self, SEL op, ...) OBJC_EXPORT void
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); objc_msgSend_fp2ret_debug(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
# endif # endif
# endif # endif
@ -219,66 +311,80 @@ OBJC_EXPORT void objc_msgSend_fp2ret_debug(id self, SEL op, ...)
// - Red zone is not preserved. // - Red zone is not preserved.
// See each architecture's implementation for details. // See each architecture's implementation for details.
OBJC_EXPORT void objc_msgLookup(void) OBJC_EXPORT void
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); objc_msgLookup(void)
OBJC_EXPORT void objc_msgLookupSuper2(void) OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT void objc_msgLookup_stret(void) OBJC_EXPORT void
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0) objc_msgLookupSuper2(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
OBJC_EXPORT void
objc_msgLookup_stret(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
OBJC_EXPORT void objc_msgLookupSuper2_stret(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0) OBJC_EXPORT void
objc_msgLookupSuper2_stret(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
# if defined(__i386__) # if defined(__i386__)
OBJC_EXPORT void objc_msgLookup_fpret(void) OBJC_EXPORT void
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); objc_msgLookup_fpret(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
# elif defined(__x86_64__) # elif defined(__x86_64__)
OBJC_EXPORT void objc_msgLookup_fpret(void) OBJC_EXPORT void
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); objc_msgLookup_fpret(void)
OBJC_EXPORT void objc_msgLookup_fp2ret(void) OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT void
objc_msgLookup_fp2ret(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
# endif # endif
#endif #endif
#if TARGET_OS_OSX && defined(__x86_64__) #if (TARGET_OS_OSX || TARGET_OS_SIMULATOR) && defined(__x86_64__)
// objc_msgSend_fixup() is used for vtable-dispatchable call sites. // objc_msgSend_fixup() was used for vtable-dispatchable call sites.
OBJC_EXPORT void objc_msgSend_fixup(void) // The symbols remain exported on macOS for binary compatibility.
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized") // The symbols can probably be removed from iOS simulator but we haven't tried.
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_EXPORT void
OBJC_EXPORT void objc_msgSend_stret_fixup(void) objc_msgSend_fixup(void)
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized") __OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized");
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_msgSendSuper2_fixup(void) OBJC_EXPORT void
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized") objc_msgSend_stret_fixup(void)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; __OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized");
OBJC_EXPORT void objc_msgSendSuper2_stret_fixup(void)
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized") OBJC_EXPORT void
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; objc_msgSendSuper2_fixup(void)
OBJC_EXPORT void objc_msgSend_fpret_fixup(void) __OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized");
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_EXPORT void
OBJC_EXPORT void objc_msgSend_fp2ret_fixup(void) objc_msgSendSuper2_stret_fixup(void)
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized") __OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized");
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void
objc_msgSend_fpret_fixup(void)
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized");
OBJC_EXPORT void
objc_msgSend_fp2ret_fixup(void)
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized");
#endif #endif
/* C++-compatible exception handling. */ /* C++-compatible exception handling. */
#if __OBJC2__ #if __OBJC2__
// fixme these conflict with C++ compiler's internal definitions
#if !defined(__cplusplus)
// Vtable for C++ exception typeinfo for Objective-C types. // Vtable for C++ exception typeinfo for Objective-C types.
OBJC_EXPORT const void *objc_ehtype_vtable[] OBJC_EXPORT const void * _Nullable objc_ehtype_vtable[]
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
// C++ exception typeinfo for type `id`. // C++ exception typeinfo for type `id`.
OBJC_EXPORT struct objc_typeinfo OBJC_EHTYPE_id OBJC_EXPORT struct objc_typeinfo OBJC_EHTYPE_id
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
#endif
// Exception personality function for Objective-C and Objective-C++ code. // Exception personality function for Objective-C and Objective-C++ code.
struct _Unwind_Exception; struct _Unwind_Exception;
@ -287,16 +393,17 @@ OBJC_EXPORT int
__objc_personality_v0(int version, __objc_personality_v0(int version,
int actions, int actions,
uint64_t exceptionClass, uint64_t exceptionClass,
struct _Unwind_Exception *exceptionObject, struct _Unwind_Exception * _Nonnull exceptionObject,
struct _Unwind_Context *context) struct _Unwind_Context * _Nonnull context)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
#endif #endif
/* ARC */ /* ARC */
OBJC_EXPORT id objc_retainBlock(id) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); objc_retainBlock(id _Nullable)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
/* Non-pointer isa */ /* Non-pointer isa */
@ -305,7 +412,7 @@ OBJC_EXPORT id objc_retainBlock(id)
// Extract class pointer from an isa field. // Extract class pointer from an isa field.
#if TARGET_OS_SIMULATOR #if TARGET_OS_SIMULATOR && !TARGET_OS_IOSMAC
// No simulators use nonpointer isa yet. // No simulators use nonpointer isa yet.
#elif __LP64__ #elif __LP64__
@ -315,9 +422,9 @@ OBJC_EXPORT id objc_retainBlock(id)
// Packed-isa version. This one is used directly by Swift code. // Packed-isa version. This one is used directly by Swift code.
// (Class)(isa & (uintptr_t)&objc_absolute_packed_isa_class_mask) == class ptr // (Class)(isa & (uintptr_t)&objc_absolute_packed_isa_class_mask) == class ptr
OBJC_EXPORT const struct { char c; } objc_absolute_packed_isa_class_mask OBJC_EXPORT const struct { char c; } objc_absolute_packed_isa_class_mask
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
#elif __ARM_ARCH_7K__ >= 2 #elif (__ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__))
# define OBJC_HAVE_NONPOINTER_ISA 1 # define OBJC_HAVE_NONPOINTER_ISA 1
# define OBJC_HAVE_INDEXED_NONPOINTER_ISA 1 # define OBJC_HAVE_INDEXED_NONPOINTER_ISA 1
@ -329,18 +436,42 @@ OBJC_EXPORT const struct { char c; } objc_absolute_packed_isa_class_mask
// cls = (Class)isa; // cls = (Class)isa;
// } // }
OBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_magic_mask OBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_magic_mask
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
OBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_magic_value OBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_magic_value
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
OBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_index_mask OBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_index_mask
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
OBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_index_shift OBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_index_shift
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
#endif #endif
// OBJC2
#endif #endif
/* Object class */
// This symbol might be required for binary compatibility, so we
// declare it here where TAPI will see it.
#if __OBJC__ && __OBJC2__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
#if !defined(OBJC_DECLARE_SYMBOLS)
__OSX_AVAILABLE(10.0)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE
__WATCHOS_UNAVAILABLE
# ifndef __APPLE_BLEACH_SDK__
__BRIDGEOS_UNAVAILABLE
# endif
#endif
OBJC_ROOT_CLASS
@interface Object {
Class isa;
}
@end
#pragma clang diagnostic pop
#endif
// _OBJC_ABI_H // _OBJC_ABI_H
#endif #endif

View File

@ -39,10 +39,9 @@
- (id)mutableCopyWithZone:(void *)zone; - (id)mutableCopyWithZone:(void *)zone;
@end @end
// These locks must not be at function scope. StripedMap<spinlock_t> PropertyLocks;
static StripedMap<spinlock_t> PropertyLocks; StripedMap<spinlock_t> StructLocks;
static StripedMap<spinlock_t> StructLocks; StripedMap<spinlock_t> CppObjectLocks;
static StripedMap<spinlock_t> CppObjectLocks;
#define MUTABLE_COPY 2 #define MUTABLE_COPY 2

View File

@ -28,6 +28,7 @@
#include <Availability.h> #include <Availability.h>
#include <AvailabilityMacros.h> #include <AvailabilityMacros.h>
#include <TargetConditionals.h> #include <TargetConditionals.h>
#include <sys/types.h>
#ifndef __has_feature #ifndef __has_feature
# define __has_feature(x) 0 # define __has_feature(x) 0
@ -41,6 +42,41 @@
# define __has_attribute(x) 0 # define __has_attribute(x) 0
#endif #endif
#if !__has_feature(nullability)
# ifndef _Nullable
# define _Nullable
# endif
# ifndef _Nonnull
# define _Nonnull
# endif
# ifndef _Null_unspecified
# define _Null_unspecified
# endif
#endif
#ifndef __APPLE_BLEACH_SDK__
# if __has_feature(attribute_availability_bridgeos)
# ifndef __BRIDGEOS_AVAILABLE
# define __BRIDGEOS_AVAILABLE(_vers) __OS_AVAILABILITY(bridgeos,introduced=_vers)
# endif
# ifndef __BRIDGEOS_DEPRECATED
# define __BRIDGEOS_DEPRECATED(_start, _dep, _msg) __BRIDGEOS_AVAILABLE(_start) __OS_AVAILABILITY_MSG(bridgeos,deprecated=_dep,_msg)
# endif
# ifndef __BRIDGEOS_UNAVAILABLE
# define __BRIDGEOS_UNAVAILABLE __OS_AVAILABILITY(bridgeos,unavailable)
# endif
# else
# ifndef __BRIDGEOS_AVAILABLE
# define __BRIDGEOS_AVAILABLE(_vers)
# endif
# ifndef __BRIDGEOS_DEPRECATED
# define __BRIDGEOS_DEPRECATED(_start, _dep, _msg)
# endif
# ifndef __BRIDGEOS_UNAVAILABLE
# define __BRIDGEOS_UNAVAILABLE
# endif
# endif
#endif
/* /*
* OBJC_API_VERSION 0 or undef: Tiger and earlier API only * OBJC_API_VERSION 0 or undef: Tiger and earlier API only
@ -86,15 +122,67 @@
/* OBJC_OLD_DISPATCH_PROTOTYPES == 0 enforces the rule that the dispatch /* OBJC_OLD_DISPATCH_PROTOTYPES == 0 enforces the rule that the dispatch
* functions must be cast to an appropriate function pointer type. */ * functions must be cast to an appropriate function pointer type. */
#if !defined(OBJC_OLD_DISPATCH_PROTOTYPES) #if !defined(OBJC_OLD_DISPATCH_PROTOTYPES)
# define OBJC_OLD_DISPATCH_PROTOTYPES 1 # if __swift__
// Existing Swift code expects IMP to be Comparable.
// Variadic IMP is comparable via OpaquePointer; non-variadic IMP isn't.
# define OBJC_OLD_DISPATCH_PROTOTYPES 1
# else
# define OBJC_OLD_DISPATCH_PROTOTYPES 0
# endif
#endif #endif
/* OBJC_AVAILABLE: shorthand for all-OS availability */ /* OBJC_AVAILABLE: shorthand for all-OS availability */
#if !defined(OBJC_AVAILABLE) #ifndef __APPLE_BLEACH_SDK__
# define OBJC_AVAILABLE(x, i, t, w) \ # if !defined(OBJC_AVAILABLE)
__OSX_AVAILABLE(x) __IOS_AVAILABLE(i) \ # define OBJC_AVAILABLE(x, i, t, w, b) \
__TVOS_AVAILABLE(t) __WATCHOS_AVAILABLE(w) __OSX_AVAILABLE(x) __IOS_AVAILABLE(i) __TVOS_AVAILABLE(t) \
__WATCHOS_AVAILABLE(w) __BRIDGEOS_AVAILABLE(b)
# endif
#else
# if !defined(OBJC_AVAILABLE)
# define OBJC_AVAILABLE(x, i, t, w, b) \
__OSX_AVAILABLE(x) __IOS_AVAILABLE(i) __TVOS_AVAILABLE(t) \
__WATCHOS_AVAILABLE(w)
# endif
#endif
/* OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE: Deprecated on OS X,
* unavailable everywhere else. */
#ifndef __APPLE_BLEACH_SDK__
# if !defined(OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE)
# define OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(_start, _dep, _msg) \
__OSX_DEPRECATED(_start, _dep, _msg) \
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE \
__WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE
# endif
#else
# if !defined(OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE)
# define OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(_start, _dep, _msg) \
__OSX_DEPRECATED(_start, _dep, _msg) \
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE \
__WATCHOS_UNAVAILABLE
# endif
#endif
/* OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE: Available on OS X,
* unavailable everywhere else. */
#ifndef __APPLE_BLEACH_SDK__
# if !defined(OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE)
# define OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE(vers) \
__OSX_AVAILABLE(vers) \
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE \
__WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE
# endif
#else
# if !defined(OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE)
# define OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE(vers) \
__OSX_AVAILABLE(vers) \
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE \
__WATCHOS_UNAVAILABLE
# endif
#endif #endif
@ -118,7 +206,7 @@
# define OBJC2_UNAVAILABLE \ # define OBJC2_UNAVAILABLE \
__OSX_DEPRECATED(10.5, 10.5, "not available in __OBJC2__") \ __OSX_DEPRECATED(10.5, 10.5, "not available in __OBJC2__") \
__IOS_DEPRECATED(2.0, 2.0, "not available in __OBJC2__") \ __IOS_DEPRECATED(2.0, 2.0, "not available in __OBJC2__") \
__TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE
# endif # endif
#endif #endif
@ -229,4 +317,12 @@
#define OBJC_OPTIONS(_type, _name) _type _name; enum #define OBJC_OPTIONS(_type, _name) _type _name; enum
#endif #endif
#if !defined(OBJC_RETURNS_RETAINED)
# if __OBJC__ && __has_attribute(ns_returns_retained)
# define OBJC_RETURNS_RETAINED __attribute__((ns_returns_retained))
# else
# define OBJC_RETURNS_RETAINED
# endif
#endif
#endif #endif

View File

@ -24,8 +24,6 @@
#ifndef _OBJC_AUTO_H_ #ifndef _OBJC_AUTO_H_
#define _OBJC_AUTO_H_ #define _OBJC_AUTO_H_
#pragma GCC system_header
#include <objc/objc.h> #include <objc/objc.h>
#include <malloc/malloc.h> #include <malloc/malloc.h>
#include <stdint.h> #include <stdint.h>
@ -57,7 +55,7 @@ enum {
OBJC_EXHAUSTIVE_COLLECTION = (3 << 0), OBJC_EXHAUSTIVE_COLLECTION = (3 << 0),
OBJC_COLLECT_IF_NEEDED = (1 << 3), OBJC_COLLECT_IF_NEEDED = (1 << 3),
OBJC_WAIT_UNTIL_DONE = (1 << 4), OBJC_WAIT_UNTIL_DONE = (1 << 4)
}; };
enum { enum {
@ -65,71 +63,72 @@ enum {
}; };
#ifndef OBJC_NO_GC #if !defined(OBJC_NO_GC) || \
(OBJC_DECLARE_SYMBOLS && !defined(OBJC_NO_GC_API))
/* Out-of-line declarations */ /* Out-of-line declarations */
OBJC_EXPORT void objc_collect(unsigned long options) OBJC_EXPORT void objc_collect(unsigned long options)
__OSX_DEPRECATED(10.6, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.6, 10.8, "it does nothing");
OBJC_EXPORT BOOL objc_collectingEnabled(void) OBJC_EXPORT BOOL objc_collectingEnabled(void)
__OSX_DEPRECATED(10.5, 10.8, "it always returns NO") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.5, 10.8, "it always returns NO");
OBJC_EXPORT malloc_zone_t *objc_collectableZone(void) OBJC_EXPORT malloc_zone_t *objc_collectableZone(void)
__OSX_DEPRECATED(10.7, 10.8, "it always returns nil") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.7, 10.8, "it always returns nil");
OBJC_EXPORT void objc_setCollectionThreshold(size_t threshold) OBJC_EXPORT void objc_setCollectionThreshold(size_t threshold)
__OSX_DEPRECATED(10.5, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.5, 10.8, "it does nothing");
OBJC_EXPORT void objc_setCollectionRatio(size_t ratio) OBJC_EXPORT void objc_setCollectionRatio(size_t ratio)
__OSX_DEPRECATED(10.5, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.5, 10.8, "it does nothing");
OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation) OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation)
__OSX_DEPRECATED(10.6, 10.8, "use OSAtomicCompareAndSwapPtr instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.6, 10.8, "use OSAtomicCompareAndSwapPtr instead");
OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation) OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation)
__OSX_DEPRECATED(10.6, 10.8, "use OSAtomicCompareAndSwapPtrBarrier instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.6, 10.8, "use OSAtomicCompareAndSwapPtrBarrier instead");
OBJC_EXPORT BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation) OBJC_EXPORT BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation)
__OSX_DEPRECATED(10.6, 10.8, "use OSAtomicCompareAndSwapPtr instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.6, 10.8, "use OSAtomicCompareAndSwapPtr instead");
OBJC_EXPORT BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation) OBJC_EXPORT BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation)
__OSX_DEPRECATED(10.6, 10.8, "use OSAtomicCompareAndSwapPtrBarrier instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.6, 10.8, "use OSAtomicCompareAndSwapPtrBarrier instead");
OBJC_EXPORT BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation) OBJC_EXPORT BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation)
__OSX_DEPRECATED(10.6, 10.8, "use OSAtomicCompareAndSwapPtr instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.6, 10.8, "use OSAtomicCompareAndSwapPtr instead");
OBJC_EXPORT BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation) OBJC_EXPORT BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation)
__OSX_DEPRECATED(10.6, 10.8, "use OSAtomicCompareAndSwapPtrBarrier instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.6, 10.8, "use OSAtomicCompareAndSwapPtrBarrier instead");
OBJC_EXPORT id objc_assign_strongCast(id val, id *dest) OBJC_EXPORT id objc_assign_strongCast(id val, id *dest)
__OSX_DEPRECATED(10.4, 10.8, "use a simple assignment instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.8, "use a simple assignment instead");
OBJC_EXPORT id objc_assign_global(id val, id *dest) OBJC_EXPORT id objc_assign_global(id val, id *dest)
__OSX_DEPRECATED(10.4, 10.8, "use a simple assignment instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.8, "use a simple assignment instead");
OBJC_EXPORT id objc_assign_threadlocal(id val, id *dest) OBJC_EXPORT id objc_assign_threadlocal(id val, id *dest)
__OSX_DEPRECATED(10.7, 10.8, "use a simple assignment instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.7, 10.8, "use a simple assignment instead");
OBJC_EXPORT id objc_assign_ivar(id value, id dest, ptrdiff_t offset) OBJC_EXPORT id objc_assign_ivar(id value, id dest, ptrdiff_t offset)
__OSX_DEPRECATED(10.4, 10.8, "use a simple assignment instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.8, "use a simple assignment instead");
OBJC_EXPORT void *objc_memmove_collectable(void *dst, const void *src, size_t size) OBJC_EXPORT void *objc_memmove_collectable(void *dst, const void *src, size_t size)
__OSX_DEPRECATED(10.4, 10.8, "use memmove instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.8, "use memmove instead");
OBJC_EXPORT id objc_read_weak(id *location) OBJC_EXPORT id objc_read_weak(id *location)
__OSX_DEPRECATED(10.5, 10.8, "use a simple read instead, or convert to zeroing __weak") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.5, 10.8, "use a simple read instead, or convert to zeroing __weak");
OBJC_EXPORT id objc_assign_weak(id value, id *location) OBJC_EXPORT id objc_assign_weak(id value, id *location)
__OSX_DEPRECATED(10.5, 10.8, "use a simple assignment instead, or convert to zeroing __weak") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.5, 10.8, "use a simple assignment instead, or convert to zeroing __weak");
OBJC_EXPORT void objc_registerThreadWithCollector(void) OBJC_EXPORT void objc_registerThreadWithCollector(void)
__OSX_DEPRECATED(10.6, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.6, 10.8, "it does nothing");
OBJC_EXPORT void objc_unregisterThreadWithCollector(void) OBJC_EXPORT void objc_unregisterThreadWithCollector(void)
__OSX_DEPRECATED(10.6, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.6, 10.8, "it does nothing");
OBJC_EXPORT void objc_assertRegisteredThreadWithCollector(void) OBJC_EXPORT void objc_assertRegisteredThreadWithCollector(void)
__OSX_DEPRECATED(10.6, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.6, 10.8, "it does nothing");
OBJC_EXPORT void objc_clear_stack(unsigned long options) OBJC_EXPORT void objc_clear_stack(unsigned long options)
__OSX_DEPRECATED(10.5, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.5, 10.8, "it does nothing");
OBJC_EXPORT BOOL objc_is_finalized(void *ptr) OBJC_EXPORT BOOL objc_is_finalized(void *ptr)
__OSX_DEPRECATED(10.4, 10.8, "it always returns NO") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.8, "it always returns NO");
OBJC_EXPORT void objc_finalizeOnMainThread(Class cls) OBJC_EXPORT void objc_finalizeOnMainThread(Class cls)
__OSX_DEPRECATED(10.5, 10.5, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.5, 10.5, "it does nothing");
OBJC_EXPORT BOOL objc_collecting_enabled(void) OBJC_EXPORT BOOL objc_collecting_enabled(void)
__OSX_DEPRECATED(10.4, 10.5, "it always returns NO") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.5, "it always returns NO");
OBJC_EXPORT void objc_set_collection_threshold(size_t threshold) OBJC_EXPORT void objc_set_collection_threshold(size_t threshold)
__OSX_DEPRECATED(10.4, 10.5, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.5, "it does nothing");
OBJC_EXPORT void objc_set_collection_ratio(size_t ratio) OBJC_EXPORT void objc_set_collection_ratio(size_t ratio)
__OSX_DEPRECATED(10.4, 10.5, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.5, "it does nothing");
OBJC_EXPORT void objc_start_collector_thread(void) OBJC_EXPORT void objc_start_collector_thread(void)
__OSX_DEPRECATED(10.4, 10.5, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.5, "it does nothing");
OBJC_EXPORT void objc_startCollectorThread(void) OBJC_EXPORT void objc_startCollectorThread(void)
__OSX_DEPRECATED(10.5, 10.7, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.5, 10.7, "it does nothing");
OBJC_EXPORT id objc_allocate_object(Class cls, int extra) OBJC_EXPORT id objc_allocate_object(Class cls, int extra)
__OSX_DEPRECATED(10.4, 10.4, "use class_createInstance instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.4, "use class_createInstance instead");
/* !defined(OBJC_NO_GC) */ /* !defined(OBJC_NO_GC) */
@ -199,7 +198,7 @@ static OBJC_INLINE id objc_assign_threadlocal(id val, id *dest)
OBJC_GC_DEPRECATED("use a simple assignment instead") OBJC_GC_DEPRECATED("use a simple assignment instead")
static OBJC_INLINE id objc_assign_ivar(id val, id dest, ptrdiff_t offset) static OBJC_INLINE id objc_assign_ivar(id val, id dest, ptrdiff_t offset)
{ return (*(id*)((char *)dest+offset) = val); } { return (*(id*)((intptr_t)(char *)dest+offset) = val); }
OBJC_GC_DEPRECATED("use a simple read instead, or convert to zeroing __weak") OBJC_GC_DEPRECATED("use a simple read instead, or convert to zeroing __weak")
static OBJC_INLINE id objc_read_weak(id *location) static OBJC_INLINE id objc_read_weak(id *location)
@ -235,10 +234,10 @@ static OBJC_INLINE void objc_start_collector_thread(void) { }
extern id objc_allocate_object(Class cls, int extra) UNAVAILABLE_ATTRIBUTE; extern id objc_allocate_object(Class cls, int extra) UNAVAILABLE_ATTRIBUTE;
#else #else
OBJC_EXPORT id class_createInstance(Class cls, size_t extraBytes) OBJC_EXPORT id class_createInstance(Class cls, size_t extraBytes)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0); OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_GC_DEPRECATED("use class_createInstance instead") OBJC_GC_DEPRECATED("use class_createInstance instead")
static OBJC_INLINE id objc_allocate_object(Class cls, int extra) static OBJC_INLINE id objc_allocate_object(Class cls, int extra)
{ return class_createInstance(cls, extra); } { return class_createInstance(cls, (size_t)extra); }
#endif #endif
OBJC_GC_DEPRECATED("it does nothing") OBJC_GC_DEPRECATED("it does nothing")

View File

@ -21,7 +21,9 @@
* @APPLE_LICENSE_HEADER_END@ * @APPLE_LICENSE_HEADER_END@
*/ */
#define OBJC_DECLARE_SYMBOLS 1
#include "objc-private.h" #include "objc-private.h"
#include "objc-auto.h"
// GC is no longer supported. // GC is no longer supported.
@ -35,86 +37,85 @@
#else #else
// No GC but we do need to export GC symbols. // No GC but we do need to export GC symbols.
// These are mostly the same as the OBJC_NO_GC inline versions in objc-auto.h.
# if !SUPPORT_GC_COMPAT # if !SUPPORT_GC_COMPAT
# error inconsistent config settings # error inconsistent config settings
# endif # endif
OBJC_EXPORT void objc_collect(unsigned long options __unused) { } void objc_collect(unsigned long options __unused) { }
OBJC_EXPORT BOOL objc_collectingEnabled(void) { return NO; } BOOL objc_collectingEnabled(void) { return NO; }
OBJC_EXPORT void objc_setCollectionThreshold(size_t threshold __unused) { } void objc_setCollectionThreshold(size_t threshold __unused) { }
OBJC_EXPORT void objc_setCollectionRatio(size_t ratio __unused) { } void objc_setCollectionRatio(size_t ratio __unused) { }
OBJC_EXPORT void objc_startCollectorThread(void) { } void objc_startCollectorThread(void) { }
#if TARGET_OS_WIN32 #if TARGET_OS_WIN32
OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation) BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation)
{ void *original = InterlockedCompareExchangePointer((void * volatile *)objectLocation, (void *)replacement, (void *)predicate); return (original == predicate); } { void *original = InterlockedCompareExchangePointer((void * volatile *)objectLocation, (void *)replacement, (void *)predicate); return (original == predicate); }
OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation) BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation)
{ void *original = InterlockedCompareExchangePointer((void * volatile *)objectLocation, (void *)replacement, (void *)predicate); return (original == predicate); } { void *original = InterlockedCompareExchangePointer((void * volatile *)objectLocation, (void *)replacement, (void *)predicate); return (original == predicate); }
#else #else
OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation) BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation)
{ return OSAtomicCompareAndSwapPtr((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); } { return OSAtomicCompareAndSwapPtr((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); }
OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation) BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation)
{ return OSAtomicCompareAndSwapPtrBarrier((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); } { return OSAtomicCompareAndSwapPtrBarrier((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); }
#endif #endif
OBJC_EXPORT BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation) BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation)
{ return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); } { return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); }
OBJC_EXPORT BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation) BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation)
{ return objc_atomicCompareAndSwapPtrBarrier(predicate, replacement, objectLocation); } { return objc_atomicCompareAndSwapPtrBarrier(predicate, replacement, objectLocation); }
OBJC_EXPORT BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation) BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation)
{ return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); } { return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); }
OBJC_EXPORT BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation) BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation)
{ return objc_atomicCompareAndSwapPtrBarrier(predicate, replacement, objectLocation); } { return objc_atomicCompareAndSwapPtrBarrier(predicate, replacement, objectLocation); }
OBJC_EXPORT id objc_assign_strongCast(id val, id *dest) id objc_assign_strongCast(id val, id *dest)
{ return (*dest = val); } { return (*dest = val); }
OBJC_EXPORT id objc_assign_global(id val, id *dest) id objc_assign_global(id val, id *dest)
{ return (*dest = val); } { return (*dest = val); }
OBJC_EXPORT id objc_assign_threadlocal(id val, id *dest) id objc_assign_threadlocal(id val, id *dest)
{ return (*dest = val); } { return (*dest = val); }
OBJC_EXPORT id objc_assign_ivar(id val, id dest, ptrdiff_t offset) id objc_assign_ivar(id val, id dest, ptrdiff_t offset)
{ return (*(id*)((char *)dest+offset) = val); } { return (*(id*)((char *)dest+offset) = val); }
OBJC_EXPORT id objc_read_weak(id *location) id objc_read_weak(id *location)
{ return *location; } { return *location; }
OBJC_EXPORT id objc_assign_weak(id value, id *location) id objc_assign_weak(id value, id *location)
{ return (*location = value); } { return (*location = value); }
OBJC_EXPORT void *objc_memmove_collectable(void *dst, const void *src, size_t size) void *objc_memmove_collectable(void *dst, const void *src, size_t size)
{ return memmove(dst, src, size); } { return memmove(dst, src, size); }
OBJC_EXPORT void objc_finalizeOnMainThread(Class cls __unused) { } void objc_finalizeOnMainThread(Class cls __unused) { }
OBJC_EXPORT BOOL objc_is_finalized(void *ptr __unused) { return NO; } BOOL objc_is_finalized(void *ptr __unused) { return NO; }
OBJC_EXPORT void objc_clear_stack(unsigned long options __unused) { } void objc_clear_stack(unsigned long options __unused) { }
OBJC_EXPORT BOOL objc_collecting_enabled(void) { return NO; } BOOL objc_collecting_enabled(void) { return NO; }
OBJC_EXPORT void objc_set_collection_threshold(size_t threshold __unused) { } void objc_set_collection_threshold(size_t threshold __unused) { }
OBJC_EXPORT void objc_set_collection_ratio(size_t ratio __unused) { } void objc_set_collection_ratio(size_t ratio __unused) { }
OBJC_EXPORT void objc_start_collector_thread(void) { } void objc_start_collector_thread(void) { }
OBJC_EXPORT id objc_allocate_object(Class cls, int extra) id objc_allocate_object(Class cls, int extra)
{ return class_createInstance(cls, extra); } { return class_createInstance(cls, extra); }
OBJC_EXPORT void objc_registerThreadWithCollector() { } void objc_registerThreadWithCollector() { }
OBJC_EXPORT void objc_unregisterThreadWithCollector() { } void objc_unregisterThreadWithCollector() { }
OBJC_EXPORT void objc_assertRegisteredThreadWithCollector() { } void objc_assertRegisteredThreadWithCollector() { }
OBJC_EXPORT malloc_zone_t* objc_collect_init(int(*callback)() __unused) { return nil; } malloc_zone_t* objc_collect_init(int(*callback)() __unused) { return nil; }
OBJC_EXPORT void* objc_collectableZone() { return nil; } malloc_zone_t* objc_collectableZone() { return nil; }
OBJC_EXPORT BOOL objc_isAuto(id object __unused) { return NO; } BOOL objc_isAuto(id object __unused) { return NO; }
OBJC_EXPORT BOOL objc_dumpHeap(char *filename __unused, unsigned long length __unused) BOOL objc_dumpHeap(char *filename __unused, unsigned long length __unused)
{ return NO; } { return NO; }
// not OBJC_NO_GC_API // not OBJC_NO_GC_API

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2018 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_TRAMPOLINES_H
#define _OBJC_TRAMPOLINES_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-block-trampolines.h: Symbols for IMP block trampolines
*/
// WARNING: remapped code and dtrace do not play well together. Dtrace
// will place trap instructions to instrument the code, which then get
// remapped along with everything else. The remapped traps are not
// recognized by dtrace and the process crashes. To avoid this, dtrace
// blacklists this library by name. Do not change the name of this
// library. rdar://problem/42627391
#include <objc/objc-api.h>
OBJC_EXPORT const char _objc_blockTrampolineImpl
OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);
OBJC_EXPORT const char _objc_blockTrampolineStart
OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);
OBJC_EXPORT const char _objc_blockTrampolineLast
OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);
OBJC_EXPORT const char _objc_blockTrampolineImpl_stret
OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0)
OBJC_ARM64_UNAVAILABLE;
OBJC_EXPORT const char _objc_blockTrampolineStart_stret
OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0)
OBJC_ARM64_UNAVAILABLE;
OBJC_EXPORT const char _objc_blockTrampolineLast_stret
OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0)
OBJC_ARM64_UNAVAILABLE;
#endif

View File

@ -35,27 +35,161 @@
#include <Block.h> #include <Block.h>
#include <Block_private.h> #include <Block_private.h>
#include <mach/mach.h> #include <mach/mach.h>
#include <objc/objc-block-trampolines.h>
// symbols defined in assembly files // fixme C++ compilers don't implemement memory_order_consume efficiently.
// Don't use the symbols directly; they're thumb-biased on some ARM archs. // Use memory_order_relaxed and cross our fingers.
#define TRAMP(tramp) \ #define MEMORY_ORDER_CONSUME std::memory_order_relaxed
static inline __unused uintptr_t tramp(void) { \
extern void *_##tramp; \
return ((uintptr_t)&_##tramp) & ~1UL; \
}
// Scalar return
TRAMP(a1a2_tramphead); // trampoline header code
TRAMP(a1a2_firsttramp); // first trampoline
TRAMP(a1a2_trampend); // after the last trampoline
#if SUPPORT_STRET // 8 bytes of text and data per trampoline on all architectures.
// Struct return #define SLOT_SIZE 8
TRAMP(a2a3_tramphead);
TRAMP(a2a3_firsttramp); // The trampolines are defined in assembly files in libobjc-trampolines.dylib.
TRAMP(a2a3_trampend); // We can't link to libobjc-trampolines.dylib directly because
// for security reasons it isn't in the dyld shared cache.
// Trampoline addresses are lazily looked up.
// All of them are hidden behind a single atomic pointer for lock-free init.
#ifdef __PTRAUTH_INTRINSICS__
# define TrampolinePtrauth __ptrauth(ptrauth_key_function_pointer, 1, 0x3af1)
#else
# define TrampolinePtrauth
#endif #endif
class TrampolinePointerWrapper {
struct TrampolinePointers {
class TrampolineAddress {
const void * TrampolinePtrauth storage;
public:
TrampolineAddress(void *dylib, const char *name) {
#define PREFIX "_objc_blockTrampoline"
char symbol[strlen(PREFIX) + strlen(name) + 1];
strcpy(symbol, PREFIX);
strcat(symbol, name);
// dlsym() from a text segment returns a signed pointer
// Authenticate it manually and let the compiler re-sign it.
storage = ptrauth_auth_data(dlsym(dylib, symbol),
ptrauth_key_function_pointer, 0);
if (!storage) {
_objc_fatal("couldn't dlsym %s", symbol);
}
}
uintptr_t address() {
return (uintptr_t)(void*)storage;
}
};
TrampolineAddress impl; // trampoline header code
TrampolineAddress start; // first trampoline
#if DEBUG
// These symbols are only used in assertions.
// fixme might be able to move the assertions to libobjc-trampolines itself
TrampolineAddress last; // start of the last trampoline
// We don't use the address after the last trampoline because that
// address might be in a different section, and then dlsym() would not
// sign it as a function pointer.
# if SUPPORT_STRET
TrampolineAddress impl_stret;
TrampolineAddress start_stret;
TrampolineAddress last_stret;
# endif
#endif
uintptr_t textSegment;
uintptr_t textSegmentSize;
void check() {
#if DEBUG
ASSERT(impl.address() == textSegment + PAGE_MAX_SIZE);
ASSERT(impl.address() % PAGE_SIZE == 0); // not PAGE_MAX_SIZE
assert(impl.address() + PAGE_MAX_SIZE ==
last.address() + SLOT_SIZE);
ASSERT(last.address()+8 < textSegment + textSegmentSize);
ASSERT((last.address() - start.address()) % SLOT_SIZE == 0);
# if SUPPORT_STRET
ASSERT(impl_stret.address() == textSegment + 2*PAGE_MAX_SIZE);
ASSERT(impl_stret.address() % PAGE_SIZE == 0); // not PAGE_MAX_SIZE
assert(impl_stret.address() + PAGE_MAX_SIZE ==
last_stret.address() + SLOT_SIZE);
assert(start.address() - impl.address() ==
start_stret.address() - impl_stret.address());
assert(last_stret.address() + SLOT_SIZE <
textSegment + textSegmentSize);
assert((last_stret.address() - start_stret.address())
% SLOT_SIZE == 0);
# endif
#endif
}
TrampolinePointers(void *dylib)
: impl(dylib, "Impl")
, start(dylib, "Start")
#if DEBUG
, last(dylib, "Last")
# if SUPPORT_STRET
, impl_stret(dylib, "Impl_stret")
, start_stret(dylib, "Start_stret")
, last_stret(dylib, "Last_stret")
# endif
#endif
{
const auto *mh =
dyld_image_header_containing_address((void *)impl.address());
unsigned long size = 0;
textSegment = (uintptr_t)
getsegmentdata((headerType *)mh, "__TEXT", &size);
textSegmentSize = size;
check();
}
};
std::atomic<TrampolinePointers *> trampolines{nil};
TrampolinePointers *get() {
return trampolines.load(MEMORY_ORDER_CONSUME);
}
public:
void Initialize() {
if (get()) return;
// This code may be called concurrently.
// In the worst case we perform extra dyld operations.
void *dylib = dlopen("/usr/lib/libobjc-trampolines.dylib",
RTLD_NOW | RTLD_LOCAL | RTLD_FIRST);
if (!dylib) {
_objc_fatal("couldn't dlopen libobjc-trampolines.dylib: %s",
dlerror());
}
auto t = new TrampolinePointers(dylib);
TrampolinePointers *old = nil;
if (! trampolines.compare_exchange_strong(old, t, memory_order_release))
{
delete t; // Lost an initialization race.
}
}
uintptr_t textSegment() { return get()->textSegment; }
uintptr_t textSegmentSize() { return get()->textSegmentSize; }
// See comments below about PAGE_SIZE and PAGE_MAX_SIZE.
uintptr_t dataSize() { return PAGE_MAX_SIZE; }
uintptr_t impl() { return get()->impl.address(); }
uintptr_t start() { return get()->start.address(); }
};
static TrampolinePointerWrapper Trampolines;
// argument mode identifier // argument mode identifier
// Some calculations assume that these modes are sequential starting from 0.
// This order must match the order of the trampoline's assembly code.
typedef enum { typedef enum {
ReturnValueInRegisterArgumentMode, ReturnValueInRegisterArgumentMode,
#if SUPPORT_STRET #if SUPPORT_STRET
@ -65,34 +199,46 @@ typedef enum {
ArgumentModeCount ArgumentModeCount
} ArgumentMode; } ArgumentMode;
// We must take care with our data layout on architectures that support // We must take care with our data layout on architectures that support
// multiple page sizes. // multiple page sizes.
// //
// The trampoline template in __TEXT is sized and aligned with PAGE_MAX_SIZE. // The trampoline template in __TEXT is sized and aligned with PAGE_MAX_SIZE.
// On some platforms this requires additional linker flags. // On some platforms this requires additional linker flags.
// //
// When we allocate a page pair, we use PAGE_MAX_SIZE size. // When we allocate a page group, we use PAGE_MAX_SIZE size.
// This allows trampoline code to find its data by subtracting PAGE_MAX_SIZE. // This allows trampoline code to find its data by subtracting PAGE_MAX_SIZE.
// //
// When we allocate a page pair, we use the process's page alignment. // When we allocate a page group, we use the process's page alignment.
// This simplifies allocation because we don't need to force greater than // This simplifies allocation because we don't need to force greater than
// default alignment when running with small pages, but it also means // default alignment when running with small pages, but it also means
// the trampoline code MUST NOT look for its data by masking with PAGE_MAX_MASK. // the trampoline code MUST NOT look for its data by masking with PAGE_MAX_MASK.
struct TrampolineBlockPagePair struct TrampolineBlockPageGroup
{ {
TrampolineBlockPagePair *nextPagePair; // linked list of all pages TrampolineBlockPageGroup *nextPageGroup; // linked list of all pages
TrampolineBlockPagePair *nextAvailablePage; // linked list of pages with available slots TrampolineBlockPageGroup *nextAvailablePage; // linked list of pages with available slots
uintptr_t nextAvailable; // index of next available slot, endIndex() if no more available uintptr_t nextAvailable; // index of next available slot, endIndex() if no more available
const void * TrampolinePtrauth const text; // text VM region; stored only for the benefit of the leaks tool
TrampolineBlockPageGroup()
: nextPageGroup(nil)
, nextAvailablePage(nil)
, nextAvailable(startIndex())
, text((const void *)((uintptr_t)this + Trampolines.dataSize()))
{ }
// Payload data: block pointers and free list. // Payload data: block pointers and free list.
// Bytes parallel with trampoline header code are the fields above or unused // Bytes parallel with trampoline header code are the fields above or unused
// uint8_t blocks[ PAGE_MAX_SIZE - sizeof(TrampolineBlockPagePair) ] // uint8_t payloads[PAGE_MAX_SIZE - sizeof(TrampolineBlockPageGroup)]
// Code: trampoline header followed by trampolines. // Code: Mach-O header, then trampoline header followed by trampolines.
// uint8_t trampolines[PAGE_MAX_SIZE]; // On platforms with struct return we have non-stret trampolines and
// stret trampolines. The stret and non-stret trampolines at a given
// index share the same data page.
// uint8_t macho[PAGE_MAX_SIZE];
// uint8_t trampolines[ArgumentModeCount][PAGE_MAX_SIZE];
// Per-trampoline block data format: // Per-trampoline block data format:
// initial value is 0 while page data is filled sequentially // initial value is 0 while page data is filled sequentially
@ -105,11 +251,11 @@ struct TrampolineBlockPagePair
}; };
static uintptr_t headerSize() { static uintptr_t headerSize() {
return (uintptr_t) (a1a2_firsttramp() - a1a2_tramphead()); return (uintptr_t) (Trampolines.start() - Trampolines.impl());
} }
static uintptr_t slotSize() { static uintptr_t slotSize() {
return 8; return SLOT_SIZE;
} }
static uintptr_t startIndex() { static uintptr_t startIndex() {
@ -118,7 +264,7 @@ struct TrampolineBlockPagePair
} }
static uintptr_t endIndex() { static uintptr_t endIndex() {
return (uintptr_t)PAGE_MAX_SIZE / slotSize(); return (uintptr_t)Trampolines.dataSize() / slotSize();
} }
static bool validIndex(uintptr_t index) { static bool validIndex(uintptr_t index) {
@ -126,208 +272,161 @@ struct TrampolineBlockPagePair
} }
Payload *payload(uintptr_t index) { Payload *payload(uintptr_t index) {
assert(validIndex(index)); ASSERT(validIndex(index));
return (Payload *)((char *)this + index*slotSize()); return (Payload *)((char *)this + index*slotSize());
} }
IMP trampoline(uintptr_t index) { uintptr_t trampolinesForMode(int aMode) {
assert(validIndex(index)); // Skip over the data area, one page of Mach-O headers,
char *imp = (char *)this + index*slotSize() + PAGE_MAX_SIZE; // and one text page for each mode before this one.
return (uintptr_t)this + Trampolines.dataSize() +
PAGE_MAX_SIZE * (1 + aMode);
}
IMP trampoline(int aMode, uintptr_t index) {
ASSERT(validIndex(index));
char *base = (char *)trampolinesForMode(aMode);
char *imp = base + index*slotSize();
#if __arm__ #if __arm__
imp++; // trampoline is Thumb instructions imp++; // trampoline is Thumb instructions
#endif
#if __has_feature(ptrauth_calls)
imp = ptrauth_sign_unauthenticated(imp,
ptrauth_key_function_pointer, 0);
#endif #endif
return (IMP)imp; return (IMP)imp;
} }
uintptr_t indexForTrampoline(IMP tramp) { uintptr_t indexForTrampoline(uintptr_t tramp) {
uintptr_t tramp0 = (uintptr_t)this + PAGE_MAX_SIZE; for (int aMode = 0; aMode < ArgumentModeCount; aMode++) {
uintptr_t start = tramp0 + headerSize(); uintptr_t base = trampolinesForMode(aMode);
uintptr_t end = tramp0 + PAGE_MAX_SIZE; uintptr_t start = base + startIndex() * slotSize();
uintptr_t address = (uintptr_t)tramp; uintptr_t end = base + endIndex() * slotSize();
if (address >= start && address < end) { if (tramp >= start && tramp < end) {
return (uintptr_t)(address - tramp0) / slotSize(); return (uintptr_t)(tramp - base) / slotSize();
}
} }
return 0; return 0;
} }
static void check() { static void check() {
assert(TrampolineBlockPagePair::slotSize() == 8); ASSERT(TrampolineBlockPageGroup::headerSize() >= sizeof(TrampolineBlockPageGroup));
assert(TrampolineBlockPagePair::headerSize() >= sizeof(TrampolineBlockPagePair)); ASSERT(TrampolineBlockPageGroup::headerSize() % TrampolineBlockPageGroup::slotSize() == 0);
assert(TrampolineBlockPagePair::headerSize() % TrampolineBlockPagePair::slotSize() == 0);
// _objc_inform("%p %p %p", a1a2_tramphead(), a1a2_firsttramp(),
// a1a2_trampend());
assert(a1a2_tramphead() % PAGE_SIZE == 0); // not PAGE_MAX_SIZE
assert(a1a2_tramphead() + PAGE_MAX_SIZE == a1a2_trampend());
#if SUPPORT_STRET
// _objc_inform("%p %p %p", a2a3_tramphead(), a2a3_firsttramp(),
// a2a3_trampend());
assert(a2a3_tramphead() % PAGE_SIZE == 0); // not PAGE_MAX_SIZE
assert(a2a3_tramphead() + PAGE_MAX_SIZE == a2a3_trampend());
#endif
#if __arm__
// make sure trampolines are Thumb
extern void *_a1a2_firsttramp;
extern void *_a2a3_firsttramp;
assert(((uintptr_t)&_a1a2_firsttramp) % 2 == 1);
assert(((uintptr_t)&_a2a3_firsttramp) % 2 == 1);
#endif
} }
}; };
// two sets of trampoline pages; one for stack returns and one for register returns static TrampolineBlockPageGroup *HeadPageGroup;
static TrampolineBlockPagePair *headPagePairs[ArgumentModeCount];
#pragma mark Utility Functions #pragma mark Utility Functions
static inline void _lock() { #if !__OBJC2__
#if __OBJC2__ #define runtimeLock classLock
runtimeLock.write();
#else
classLock.lock();
#endif #endif
}
static inline void _unlock() {
#if __OBJC2__
runtimeLock.unlockWrite();
#else
classLock.unlock();
#endif
}
static inline void _assert_locked() {
#if __OBJC2__
runtimeLock.assertWriting();
#else
classLock.assertLocked();
#endif
}
#pragma mark Trampoline Management Functions #pragma mark Trampoline Management Functions
static TrampolineBlockPagePair *_allocateTrampolinesAndData(ArgumentMode aMode) static TrampolineBlockPageGroup *_allocateTrampolinesAndData()
{ {
_assert_locked(); runtimeLock.assertLocked();
vm_address_t dataAddress; vm_address_t dataAddress;
TrampolineBlockPagePair::check(); TrampolineBlockPageGroup::check();
TrampolineBlockPagePair *headPagePair = headPagePairs[aMode]; // Our final mapping will look roughly like this:
// r/w data
// r/o text mapped from libobjc-trampolines.dylib
// with fixed offsets from the text to the data embedded in the text.
//
// More precisely it will look like this:
// 1 page r/w data
// 1 page libobjc-trampolines.dylib Mach-O header
// N pages trampoline code, one for each ArgumentMode
// M pages for the rest of libobjc-trampolines' TEXT segment.
// The kernel requires that we remap the entire TEXT segment every time.
// We assume that our code begins on the second TEXT page, but are robust
// against other additions to the end of the TEXT segment.
if (headPagePair) { ASSERT(HeadPageGroup == nil || HeadPageGroup->nextAvailablePage == nil);
assert(headPagePair->nextAvailablePage == nil);
}
auto textSource = Trampolines.textSegment();
auto textSourceSize = Trampolines.textSegmentSize();
auto dataSize = Trampolines.dataSize();
// Allocate a single contiguous region big enough to hold data+text.
kern_return_t result; kern_return_t result;
for (int i = 0; i < 5; i++) { result = vm_allocate(mach_task_self(), &dataAddress,
result = vm_allocate(mach_task_self(), &dataAddress, dataSize + textSourceSize,
PAGE_MAX_SIZE * 2, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_FOUNDATION));
TRUE | VM_MAKE_TAG(VM_MEMORY_FOUNDATION));
if (result != KERN_SUCCESS) {
mach_error("vm_allocate failed", result);
return nil;
}
vm_address_t codeAddress = dataAddress + PAGE_MAX_SIZE;
result = vm_deallocate(mach_task_self(), codeAddress, PAGE_MAX_SIZE);
if (result != KERN_SUCCESS) {
mach_error("vm_deallocate failed", result);
return nil;
}
uintptr_t codePage;
switch(aMode) {
case ReturnValueInRegisterArgumentMode:
codePage = a1a2_tramphead();
break;
#if SUPPORT_STRET
case ReturnValueOnStackArgumentMode:
codePage = a2a3_tramphead();
break;
#endif
default:
_objc_fatal("unknown return mode %d", (int)aMode);
break;
}
vm_prot_t currentProtection, maxProtection;
result = vm_remap(mach_task_self(), &codeAddress, PAGE_MAX_SIZE,
0, FALSE, mach_task_self(), codePage, TRUE,
&currentProtection, &maxProtection, VM_INHERIT_SHARE);
if (result != KERN_SUCCESS) {
result = vm_deallocate(mach_task_self(),
dataAddress, PAGE_MAX_SIZE);
if (result != KERN_SUCCESS) {
mach_error("vm_deallocate for retry failed.", result);
return nil;
}
} else {
break;
}
}
if (result != KERN_SUCCESS) { if (result != KERN_SUCCESS) {
return nil; _objc_fatal("vm_allocate trampolines failed (%d)", result);
} }
TrampolineBlockPagePair *pagePair = (TrampolineBlockPagePair *) dataAddress; // Remap libobjc-trampolines' TEXT segment atop all
pagePair->nextAvailable = pagePair->startIndex(); // but the first of the pages we just allocated:
pagePair->nextPagePair = nil; vm_address_t textDest = dataAddress + dataSize;
pagePair->nextAvailablePage = nil; vm_prot_t currentProtection, maxProtection;
result = vm_remap(mach_task_self(), &textDest,
textSourceSize,
0, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
mach_task_self(), textSource, TRUE,
&currentProtection, &maxProtection, VM_INHERIT_SHARE);
if (result != KERN_SUCCESS) {
_objc_fatal("vm_remap trampolines failed (%d)", result);
}
if (headPagePair) { auto *pageGroup = new ((void*)dataAddress) TrampolineBlockPageGroup;
TrampolineBlockPagePair *lastPagePair = headPagePair;
while(lastPagePair->nextPagePair)
lastPagePair = lastPagePair->nextPagePair;
lastPagePair->nextPagePair = pagePair; if (HeadPageGroup) {
headPagePairs[aMode]->nextAvailablePage = pagePair; TrampolineBlockPageGroup *lastPageGroup = HeadPageGroup;
while(lastPageGroup->nextPageGroup) {
lastPageGroup = lastPageGroup->nextPageGroup;
}
lastPageGroup->nextPageGroup = pageGroup;
HeadPageGroup->nextAvailablePage = pageGroup;
} else { } else {
headPagePairs[aMode] = pagePair; HeadPageGroup = pageGroup;
} }
return pagePair; return pageGroup;
} }
static TrampolineBlockPagePair * static TrampolineBlockPageGroup *
_getOrAllocatePagePairWithNextAvailable(ArgumentMode aMode) getOrAllocatePageGroupWithNextAvailable()
{ {
_assert_locked(); runtimeLock.assertLocked();
TrampolineBlockPagePair *headPagePair = headPagePairs[aMode]; if (!HeadPageGroup)
return _allocateTrampolinesAndData();
if (!headPagePair)
return _allocateTrampolinesAndData(aMode);
// make sure head page is filled first // make sure head page is filled first
if (headPagePair->nextAvailable != headPagePair->endIndex()) if (HeadPageGroup->nextAvailable != HeadPageGroup->endIndex())
return headPagePair; return HeadPageGroup;
if (headPagePair->nextAvailablePage) // check if there is a page w/a hole if (HeadPageGroup->nextAvailablePage) // check if there is a page w/a hole
return headPagePair->nextAvailablePage; return HeadPageGroup->nextAvailablePage;
return _allocateTrampolinesAndData(aMode); // tack on a new one return _allocateTrampolinesAndData(); // tack on a new one
} }
static TrampolineBlockPagePair * static TrampolineBlockPageGroup *
_pageAndIndexContainingIMP(IMP anImp, uintptr_t *outIndex, pageAndIndexContainingIMP(IMP anImp, uintptr_t *outIndex)
TrampolineBlockPagePair **outHeadPagePair)
{ {
_assert_locked(); runtimeLock.assertLocked();
for (int arg = 0; arg < ArgumentModeCount; arg++) { // Authenticate as a function pointer, returning an un-signed address.
for (TrampolineBlockPagePair *pagePair = headPagePairs[arg]; uintptr_t trampAddress =
pagePair; (uintptr_t)ptrauth_auth_data((const char *)anImp,
pagePair = pagePair->nextPagePair) ptrauth_key_function_pointer, 0);
{
uintptr_t index = pagePair->indexForTrampoline(anImp); for (TrampolineBlockPageGroup *pageGroup = HeadPageGroup;
if (index) { pageGroup;
if (outIndex) *outIndex = index; pageGroup = pageGroup->nextPageGroup)
if (outHeadPagePair) *outHeadPagePair = headPagePairs[arg]; {
return pagePair; uintptr_t index = pageGroup->indexForTrampoline(trampAddress);
} if (index) {
if (outIndex) *outIndex = index;
return pageGroup;
} }
} }
@ -336,7 +435,7 @@ _pageAndIndexContainingIMP(IMP anImp, uintptr_t *outIndex,
static ArgumentMode static ArgumentMode
_argumentModeForBlock(id block) argumentModeForBlock(id block)
{ {
ArgumentMode aMode = ReturnValueInRegisterArgumentMode; ArgumentMode aMode = ReturnValueInRegisterArgumentMode;
@ -344,29 +443,50 @@ _argumentModeForBlock(id block)
if (_Block_has_signature(block) && _Block_use_stret(block)) if (_Block_has_signature(block) && _Block_use_stret(block))
aMode = ReturnValueOnStackArgumentMode; aMode = ReturnValueOnStackArgumentMode;
#else #else
assert(! (_Block_has_signature(block) && _Block_use_stret(block))); ASSERT(! (_Block_has_signature(block) && _Block_use_stret(block)));
#endif #endif
return aMode; return aMode;
} }
/// Initialize the trampoline machinery. Normally this does nothing, as
/// everything is initialized lazily, but for certain processes we eagerly load
/// the trampolines dylib.
void
_imp_implementationWithBlock_init(void)
{
#if TARGET_OS_OSX
// Eagerly load libobjc-trampolines.dylib in certain processes. Some
// programs (most notably QtWebEngineProcess used by older versions of
// embedded Chromium) enable a highly restrictive sandbox profile which
// blocks access to that dylib. If anything calls
// imp_implementationWithBlock (as AppKit has started doing) then we'll
// crash trying to load it. Loading it here sets it up before the sandbox
// profile is enabled and blocks it.
//
// This fixes EA Origin (rdar://problem/50813789)
// and Steam (rdar://problem/55286131)
if (__progname &&
(strcmp(__progname, "QtWebEngineProcess") == 0 ||
strcmp(__progname, "Steam Helper") == 0)) {
Trampolines.Initialize();
}
#endif
}
// `block` must already have been copied // `block` must already have been copied
IMP IMP
_imp_implementationWithBlockNoCopy(id block) _imp_implementationWithBlockNoCopy(id block)
{ {
_assert_locked(); runtimeLock.assertLocked();
ArgumentMode aMode = _argumentModeForBlock(block); TrampolineBlockPageGroup *pageGroup =
getOrAllocatePageGroupWithNextAvailable();
TrampolineBlockPagePair *pagePair = uintptr_t index = pageGroup->nextAvailable;
_getOrAllocatePagePairWithNextAvailable(aMode); ASSERT(index >= pageGroup->startIndex() && index < pageGroup->endIndex());
if (!headPagePairs[aMode]) TrampolineBlockPageGroup::Payload *payload = pageGroup->payload(index);
headPagePairs[aMode] = pagePair;
uintptr_t index = pagePair->nextAvailable;
assert(index >= pagePair->startIndex() && index < pagePair->endIndex());
TrampolineBlockPagePair::Payload *payload = pagePair->payload(index);
uintptr_t nextAvailableIndex = payload->nextAvailable; uintptr_t nextAvailableIndex = payload->nextAvailable;
if (nextAvailableIndex == 0) { if (nextAvailableIndex == 0) {
@ -374,104 +494,109 @@ _imp_implementationWithBlockNoCopy(id block)
// If the page is now full this will now be endIndex(), handled below. // If the page is now full this will now be endIndex(), handled below.
nextAvailableIndex = index + 1; nextAvailableIndex = index + 1;
} }
pagePair->nextAvailable = nextAvailableIndex; pageGroup->nextAvailable = nextAvailableIndex;
if (nextAvailableIndex == pagePair->endIndex()) { if (nextAvailableIndex == pageGroup->endIndex()) {
// PagePair is now full (free list or wilderness exhausted) // PageGroup is now full (free list or wilderness exhausted)
// Remove from available page linked list // Remove from available page linked list
TrampolineBlockPagePair *iterator = headPagePairs[aMode]; TrampolineBlockPageGroup *iterator = HeadPageGroup;
while(iterator && (iterator->nextAvailablePage != pagePair)) { while(iterator && (iterator->nextAvailablePage != pageGroup)) {
iterator = iterator->nextAvailablePage; iterator = iterator->nextAvailablePage;
} }
if (iterator) { if (iterator) {
iterator->nextAvailablePage = pagePair->nextAvailablePage; iterator->nextAvailablePage = pageGroup->nextAvailablePage;
pagePair->nextAvailablePage = nil; pageGroup->nextAvailablePage = nil;
} }
} }
payload->block = block; payload->block = block;
return pagePair->trampoline(index); return pageGroup->trampoline(argumentModeForBlock(block), index);
} }
#pragma mark Public API #pragma mark Public API
IMP imp_implementationWithBlock(id block) IMP imp_implementationWithBlock(id block)
{ {
// Block object must be copied outside runtimeLock
// because it performs arbitrary work.
block = Block_copy(block); block = Block_copy(block);
_lock();
IMP returnIMP = _imp_implementationWithBlockNoCopy(block); // Trampolines must be initialized outside runtimeLock
_unlock(); // because it calls dlopen().
return returnIMP; Trampolines.Initialize();
mutex_locker_t lock(runtimeLock);
return _imp_implementationWithBlockNoCopy(block);
} }
id imp_getBlock(IMP anImp) { id imp_getBlock(IMP anImp) {
uintptr_t index; uintptr_t index;
TrampolineBlockPagePair *pagePair; TrampolineBlockPageGroup *pageGroup;
if (!anImp) return nil; if (!anImp) return nil;
_lock(); mutex_locker_t lock(runtimeLock);
pagePair = _pageAndIndexContainingIMP(anImp, &index, nil); pageGroup = pageAndIndexContainingIMP(anImp, &index);
if (!pagePair) { if (!pageGroup) {
_unlock();
return nil; return nil;
} }
TrampolineBlockPagePair::Payload *payload = pagePair->payload(index); TrampolineBlockPageGroup::Payload *payload = pageGroup->payload(index);
if (payload->nextAvailable <= TrampolineBlockPagePair::endIndex()) { if (payload->nextAvailable <= TrampolineBlockPageGroup::endIndex()) {
// unallocated // unallocated
_unlock();
return nil; return nil;
} }
_unlock();
return payload->block; return payload->block;
} }
BOOL imp_removeBlock(IMP anImp) { BOOL imp_removeBlock(IMP anImp) {
TrampolineBlockPagePair *pagePair;
TrampolineBlockPagePair *headPagePair;
uintptr_t index;
if (!anImp) return NO; if (!anImp) return NO;
_lock(); id block;
pagePair = _pageAndIndexContainingIMP(anImp, &index, &headPagePair);
if (!pagePair) {
_unlock();
return NO;
}
TrampolineBlockPagePair::Payload *payload = pagePair->payload(index);
id block = payload->block;
// block is released below
payload->nextAvailable = pagePair->nextAvailable;
pagePair->nextAvailable = index;
// make sure this page is on available linked list
TrampolineBlockPagePair *pagePairIterator = headPagePair;
// see if page is the next available page for any existing pages
while (pagePairIterator->nextAvailablePage &&
pagePairIterator->nextAvailablePage != pagePair)
{ {
pagePairIterator = pagePairIterator->nextAvailablePage; mutex_locker_t lock(runtimeLock);
uintptr_t index;
TrampolineBlockPageGroup *pageGroup =
pageAndIndexContainingIMP(anImp, &index);
if (!pageGroup) {
return NO;
}
TrampolineBlockPageGroup::Payload *payload = pageGroup->payload(index);
block = payload->block;
// block is released below, outside the lock
payload->nextAvailable = pageGroup->nextAvailable;
pageGroup->nextAvailable = index;
// make sure this page is on available linked list
TrampolineBlockPageGroup *pageGroupIterator = HeadPageGroup;
// see if page is the next available page for any existing pages
while (pageGroupIterator->nextAvailablePage &&
pageGroupIterator->nextAvailablePage != pageGroup)
{
pageGroupIterator = pageGroupIterator->nextAvailablePage;
}
if (! pageGroupIterator->nextAvailablePage) {
// if iteration stopped because nextAvail was nil
// add to end of list.
pageGroupIterator->nextAvailablePage = pageGroup;
pageGroup->nextAvailablePage = nil;
}
} }
if (! pagePairIterator->nextAvailablePage) { // do this AFTER dropping the lock
// if iteration stopped because nextAvail was nil
// add to end of list.
pagePairIterator->nextAvailablePage = pagePair;
pagePair->nextAvailablePage = nil;
}
_unlock();
Block_release(block); Block_release(block);
return YES; return YES;
} }

View File

@ -0,0 +1,282 @@
#if __arm__
#include <arm/arch.h>
#include <mach/vm_param.h>
.syntax unified
.text
.globl __objc_blockTrampolineImpl
.globl __objc_blockTrampolineStart
.globl __objc_blockTrampolineLast
// Trampoline machinery assumes the trampolines are Thumb function pointers
#if !__thumb2__
# error sorry
#endif
.thumb
// Exported symbols are not marked as functions.
// The trampoline construction code assumes that the Thumb bit is not set.
.thumb_func L__objc_blockTrampolineImpl_func
.align PAGE_MAX_SHIFT
__objc_blockTrampolineImpl:
L__objc_blockTrampolineImpl_func:
/*
r0 == self
r12 == pc of trampoline's first instruction + PC bias
lr == original return address
*/
mov r1, r0 // _cmd = self
// Trampoline's data is two pages before the trampoline text.
// Also correct PC bias of 4 bytes.
sub r12, # 2*PAGE_MAX_SIZE
ldr r0, [r12, #-4] // self = block object
ldr pc, [r0, #12] // tail call block->invoke
// not reached
.macro TrampolineEntry
mov r12, pc
b L__objc_blockTrampolineImpl_func
.align 3
.endmacro
.macro TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
.endmacro
.macro TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
.endmacro
.align 5
__objc_blockTrampolineStart:
// 2048-4 trampolines to fill 16K page
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
__objc_blockTrampolineLast:
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
.text
.globl __objc_blockTrampolineImpl_stret
.globl __objc_blockTrampolineStart_stret
.globl __objc_blockTrampolineLast_stret
// Trampoline machinery assumes the trampolines are Thumb function pointers
#if !__thumb2__
# error sorry
#endif
.thumb
// Exported symbols are not marked as functions.
// The trampoline construction code assumes that the Thumb bit is not set.
.thumb_func L__objc_blockTrampolineImpl_stret_func
.align PAGE_MAX_SHIFT
__objc_blockTrampolineImpl_stret:
L__objc_blockTrampolineImpl_stret_func:
/*
r1 == self
r12 == pc of trampoline's first instruction + PC bias
lr == original return address
*/
mov r2, r1 // _cmd = self
// Trampoline's data is three pages before the trampoline text.
// Also correct PC bias of 4 bytes.
sub r12, # 3*PAGE_MAX_SIZE
ldr r1, [r12, #-4] // self = block object
ldr pc, [r1, #12] // tail call block->invoke
// not reached
.macro TrampolineEntry_stret
mov r12, pc
b L__objc_blockTrampolineImpl_stret_func
.align 3
.endmacro
.macro TrampolineEntryX16_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
.endmacro
.macro TrampolineEntryX256_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
.endmacro
.align 5
__objc_blockTrampolineStart_stret:
// 2048-4 trampolines to fill 16K page
TrampolineEntryX256_stret
TrampolineEntryX256_stret
TrampolineEntryX256_stret
TrampolineEntryX256_stret
TrampolineEntryX256_stret
TrampolineEntryX256_stret
TrampolineEntryX256_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntryX16_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
TrampolineEntry_stret
__objc_blockTrampolineLast_stret:
TrampolineEntry_stret
// TrampolineEntry_stret
// TrampolineEntry_stret
// TrampolineEntry_stret
// TrampolineEntry_stret
#endif

View File

@ -1,35 +1,46 @@
#if __arm64__ #if __arm64__
#include <mach/vm_param.h> #include <mach/vm_param.h>
#include "arm64-asm.h"
// Offset of block->invoke field.
#if __LP64__
// true arm64
# define BLOCK_INVOKE 16
#else
// arm64_32
# define BLOCK_INVOKE 12
#endif
.text .text
.globl __objc_blockTrampolineImpl
.private_extern __a1a2_tramphead .globl __objc_blockTrampolineStart
.private_extern __a1a2_firsttramp .globl __objc_blockTrampolineLast
.private_extern __a1a2_trampend
.align PAGE_MAX_SHIFT .align PAGE_MAX_SHIFT
__a1a2_tramphead: __objc_blockTrampolineImpl:
L_a1a2_tramphead: L_objc_blockTrampolineImpl:
/* /*
x0 == self x0 == self
x17 == address of called trampoline's data (1 page before its code) x17 == address of called trampoline's data (2 pages before its code)
lr == original return address lr == original return address
*/ */
mov x1, x0 // _cmd = self mov x1, x0 // _cmd = self
ldr x0, [x17] // self = block object ldr p0, [x17] // self = block object
ldr x16, [x0, #16] // tail call block->invoke add p15, p0, #BLOCK_INVOKE // x15 = &block->invoke
br x16 ldr p16, [x15] // x16 = block->invoke
TailCallBlockInvoke x16, x15
// pad up to TrampolineBlockPagePair header size // pad up to TrampolineBlockPagePair header size
nop nop
nop nop
nop
.macro TrampolineEntry .macro TrampolineEntry
// load address of trampoline data (one page before this instruction) // load address of trampoline data (two pages before this instruction)
adr x17, -PAGE_MAX_SIZE adr x17, -2*PAGE_MAX_SIZE
b L_a1a2_tramphead b L_objc_blockTrampolineImpl
.endmacro .endmacro
.macro TrampolineEntryX16 .macro TrampolineEntryX16
@ -77,9 +88,8 @@ L_a1a2_tramphead:
.endmacro .endmacro
.align 3 .align 3
.private_extern __a1a2_firsttramp __objc_blockTrampolineStart:
__a1a2_firsttramp: // 2048-4 trampolines to fill 16K page
// 2048-3 trampolines to fill 16K page
TrampolineEntryX256 TrampolineEntryX256
TrampolineEntryX256 TrampolineEntryX256
TrampolineEntryX256 TrampolineEntryX256
@ -121,14 +131,12 @@ __a1a2_firsttramp:
TrampolineEntry TrampolineEntry
TrampolineEntry TrampolineEntry
TrampolineEntry TrampolineEntry
__objc_blockTrampolineLast:
TrampolineEntry TrampolineEntry
TrampolineEntry
// TrampolineEntry // TrampolineEntry
// TrampolineEntry // TrampolineEntry
// TrampolineEntry // TrampolineEntry
// TrampolineEntry
.private_extern __a1a2_trampend
__a1a2_trampend:
#endif #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,7 @@ __BEGIN_DECLS
extern IMP _cache_getImp(Class cls, SEL sel); extern IMP _cache_getImp(Class cls, SEL sel);
extern Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_internal_imp); extern Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_internal_imp);
extern void cache_init(void);
extern void flush_cache(Class cls); extern void flush_cache(Class cls);
extern bool _cache_fill(Class cls, Method meth, SEL sel); extern bool _cache_fill(Class cls, Method meth, SEL sel);
extern void _cache_addForwardEntry(Class cls, SEL sel); extern void _cache_addForwardEntry(Class cls, SEL sel);

View File

@ -693,8 +693,14 @@ static uintptr_t _get_pc_for_thread(thread_t thread)
* reading function is in progress because it might still be using * reading function is in progress because it might still be using
* the garbage memory. * the garbage memory.
**********************************************************************/ **********************************************************************/
OBJC_EXPORT uintptr_t objc_entryPoints[]; typedef struct {
OBJC_EXPORT uintptr_t objc_exitPoints[]; uint64_t location;
unsigned short length;
unsigned short recovery_offs;
unsigned int flags;
} task_restartable_range_t;
extern "C" task_restartable_range_t objc_restartableRanges[];
static int _collecting_in_critical(void) static int _collecting_in_critical(void)
{ {
@ -707,7 +713,7 @@ static int _collecting_in_critical(void)
kern_return_t ret; kern_return_t ret;
int result; int result;
mach_port_t mythread = pthread_mach_thread_np(pthread_self()); mach_port_t mythread = pthread_mach_thread_np(objc_thread_self());
// Get a list of all the threads in the current task // Get a list of all the threads in the current task
ret = task_threads (mach_task_self (), &threads, &number); ret = task_threads (mach_task_self (), &threads, &number);
@ -738,10 +744,11 @@ static int _collecting_in_critical(void)
} }
// Check whether it is in the cache lookup code // Check whether it is in the cache lookup code
for (region = 0; objc_entryPoints[region] != 0; region++) for (region = 0; objc_restartableRanges[region].location != 0; region++)
{ {
if ((pc >= objc_entryPoints[region]) && uint32_t loc = (uint32_t)objc_restartableRanges[region].location;
(pc <= objc_exitPoints[region])) if ((pc > loc) &&
(pc - loc) < objc_restartableRanges[region].length)
{ {
result = TRUE; result = TRUE;
goto done; goto done;
@ -1788,6 +1795,9 @@ void _class_printMethodCacheStatistics(void)
#endif #endif
void cache_init()
{
}
// !__OBJC2__ // !__OBJC2__
#endif #endif

View File

@ -6,6 +6,8 @@
__BEGIN_DECLS __BEGIN_DECLS
extern void cache_init(void);
extern IMP cache_getImp(Class cls, SEL sel); extern IMP cache_getImp(Class cls, SEL sel);
extern void cache_fill(Class cls, SEL sel, IMP imp, id receiver); extern void cache_fill(Class cls, SEL sel, IMP imp, id receiver);

View File

@ -90,7 +90,9 @@
/* Initial cache bucket count. INIT_CACHE_SIZE must be a power of two. */ /* Initial cache bucket count. INIT_CACHE_SIZE must be a power of two. */
enum { enum {
INIT_CACHE_SIZE_LOG2 = 2, INIT_CACHE_SIZE_LOG2 = 2,
INIT_CACHE_SIZE = (1 << INIT_CACHE_SIZE_LOG2) INIT_CACHE_SIZE = (1 << INIT_CACHE_SIZE_LOG2),
MAX_CACHE_SIZE_LOG2 = 16,
MAX_CACHE_SIZE = (1 << MAX_CACHE_SIZE_LOG2),
}; };
static void cache_collect_free(struct bucket_t *data, mask_t capacity); static void cache_collect_free(struct bucket_t *data, mask_t capacity);
@ -147,8 +149,14 @@ asm("\n .section __TEXT,__const"
"\n .globl __objc_empty_vtable" "\n .globl __objc_empty_vtable"
"\n .set __objc_empty_vtable, 0" "\n .set __objc_empty_vtable, 0"
"\n .globl __objc_empty_cache" "\n .globl __objc_empty_cache"
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4
"\n .align 4"
"\n L__objc_empty_cache: .space " stringize2(EMPTY_BYTES)
"\n .set __objc_empty_cache, L__objc_empty_cache + 0xf"
#else
"\n .align 3" "\n .align 3"
"\n __objc_empty_cache: .space " stringize2(EMPTY_BYTES) "\n __objc_empty_cache: .space " stringize2(EMPTY_BYTES)
#endif
); );
@ -173,111 +181,133 @@ static inline mask_t cache_next(mask_t i, mask_t mask) {
#endif #endif
// copied from dispatch_atomic_maximally_synchronizing_barrier // mega_barrier doesn't really work, but it works enough on ARM that
// fixme verify that this barrier hack does in fact work here // we leave well enough alone and keep using it there.
#if __x86_64__ #if __arm__
#define mega_barrier() \
do { unsigned long _clbr; __asm__ __volatile__( \
"cpuid" \
: "=a" (_clbr) : "0" (0) : "rbx", "rcx", "rdx", "cc", "memory" \
); } while(0)
#elif __i386__
#define mega_barrier() \
do { unsigned long _clbr; __asm__ __volatile__( \
"cpuid" \
: "=a" (_clbr) : "0" (0) : "ebx", "ecx", "edx", "cc", "memory" \
); } while(0)
#elif __arm__ || __arm64__
#define mega_barrier() \ #define mega_barrier() \
__asm__ __volatile__( \ __asm__ __volatile__( \
"dsb ish" \ "dsb ish" \
: : : "memory") : : : "memory")
#else
#error unknown architecture
#endif #endif
#if __arm64__ #if __arm64__
// Pointer-size register prefix for inline asm
# if __LP64__
# define p "x" // true arm64
# else
# define p "w" // arm64_32
# endif
// Use atomic double-word instructions to update cache entries. // Use atomic double-word instructions to update cache entries.
// This requires cache buckets not cross cache line boundaries. // This requires cache buckets not cross cache line boundaries.
#define stp(onep, twop, destp) \ static ALWAYS_INLINE void
__asm__ ("stp %[one], %[two], [%[dest]]" \ stp(uintptr_t onep, uintptr_t twop, void *destp)
: "=m" (((uint64_t *)(destp))[0]), \ {
"=m" (((uint64_t *)(destp))[1]) \ __asm__ ("stp %" p "[one], %" p "[two], [%x[dest]]"
: [one] "r" (onep), \ : "=m" (((uintptr_t *)(destp))[0]),
[two] "r" (twop), \ "=m" (((uintptr_t *)(destp))[1])
[dest] "r" (destp) \ : [one] "r" (onep),
: /* no clobbers */ \ [two] "r" (twop),
) [dest] "r" (destp)
#define ldp(onep, twop, srcp) \ : /* no clobbers */
__asm__ ("ldp %[one], %[two], [%[src]]" \ );
: [one] "=r" (onep), \ }
[two] "=r" (twop) \
: "m" (((uint64_t *)(srcp))[0]), \
"m" (((uint64_t *)(srcp))[1]), \
[src] "r" (srcp) \
: /* no clobbers */ \
)
static ALWAYS_INLINE void __unused
ldp(uintptr_t& onep, uintptr_t& twop, const void *srcp)
{
__asm__ ("ldp %" p "[one], %" p "[two], [%x[src]]"
: [one] "=r" (onep),
[two] "=r" (twop)
: "m" (((const uintptr_t *)(srcp))[0]),
"m" (((const uintptr_t *)(srcp))[1]),
[src] "r" (srcp)
: /* no clobbers */
);
}
#undef p
#endif #endif
// Class points to cache. SEL is key. Cache buckets store SEL+IMP. // Class points to cache. SEL is key. Cache buckets store SEL+IMP.
// Caches are never built in the dyld shared cache. // Caches are never built in the dyld shared cache.
static inline mask_t cache_hash(cache_key_t key, mask_t mask) static inline mask_t cache_hash(SEL sel, mask_t mask)
{ {
return (mask_t)(key & mask); return (mask_t)(uintptr_t)sel & mask;
} }
cache_t *getCache(Class cls) cache_t *getCache(Class cls)
{ {
assert(cls); ASSERT(cls);
return &cls->cache; return &cls->cache;
} }
cache_key_t getKey(SEL sel)
{
assert(sel);
return (cache_key_t)sel;
}
#if __arm64__ #if __arm64__
void bucket_t::set(cache_key_t newKey, IMP newImp) template<Atomicity atomicity, IMPEncoding impEncoding>
void bucket_t::set(SEL newSel, IMP newImp, Class cls)
{ {
assert(_key == 0 || _key == newKey); ASSERT(_sel.load(memory_order::memory_order_relaxed) == 0 ||
_sel.load(memory_order::memory_order_relaxed) == newSel);
static_assert(offsetof(bucket_t,_imp) == 0 &&
offsetof(bucket_t,_sel) == sizeof(void *),
"bucket_t layout doesn't match arm64 bucket_t::set()");
uintptr_t encodedImp = (impEncoding == Encoded
? encodeImp(newImp, newSel, cls)
: (uintptr_t)newImp);
// LDP/STP guarantees that all observers get // LDP/STP guarantees that all observers get
// either key/imp or newKey/newImp // either imp/sel or newImp/newSel
stp(newKey, newImp, this); stp(encodedImp, (uintptr_t)newSel, this);
} }
#else #else
void bucket_t::set(cache_key_t newKey, IMP newImp) template<Atomicity atomicity, IMPEncoding impEncoding>
void bucket_t::set(SEL newSel, IMP newImp, Class cls)
{ {
assert(_key == 0 || _key == newKey); ASSERT(_sel.load(memory_order::memory_order_relaxed) == 0 ||
_sel.load(memory_order::memory_order_relaxed) == newSel);
// objc_msgSend uses key and imp with no locks. // objc_msgSend uses sel and imp with no locks.
// It is safe for objc_msgSend to see new imp but NULL key // It is safe for objc_msgSend to see new imp but NULL sel
// (It will get a cache miss but not dispatch to the wrong place.) // (It will get a cache miss but not dispatch to the wrong place.)
// It is unsafe for objc_msgSend to see old imp and new key. // It is unsafe for objc_msgSend to see old imp and new sel.
// Therefore we write new imp, wait a lot, then write new key. // Therefore we write new imp, wait a lot, then write new sel.
_imp = newImp; uintptr_t newIMP = (impEncoding == Encoded
? encodeImp(newImp, newSel, cls)
: (uintptr_t)newImp);
if (_key != newKey) { if (atomicity == Atomic) {
mega_barrier(); _imp.store(newIMP, memory_order::memory_order_relaxed);
_key = newKey;
if (_sel.load(memory_order::memory_order_relaxed) != newSel) {
#ifdef __arm__
mega_barrier();
_sel.store(newSel, memory_order::memory_order_relaxed);
#elif __x86_64__ || __i386__
_sel.store(newSel, memory_order::memory_order_release);
#else
#error Don't know how to do bucket_t::set on this architecture.
#endif
}
} else {
_imp.store(newIMP, memory_order::memory_order_relaxed);
_sel.store(newSel, memory_order::memory_order_relaxed);
} }
} }
#endif #endif
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
void cache_t::setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask) void cache_t::setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask)
{ {
// objc_msgSend uses mask and buckets with no locks. // objc_msgSend uses mask and buckets with no locks.
@ -287,29 +317,138 @@ void cache_t::setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask)
// Therefore we write new buckets, wait a lot, then write new mask. // Therefore we write new buckets, wait a lot, then write new mask.
// objc_msgSend reads mask first, then buckets. // objc_msgSend reads mask first, then buckets.
#ifdef __arm__
// ensure other threads see buckets contents before buckets pointer // ensure other threads see buckets contents before buckets pointer
mega_barrier(); mega_barrier();
_buckets = newBuckets; _buckets.store(newBuckets, memory_order::memory_order_relaxed);
// ensure other threads see new buckets before new mask // ensure other threads see new buckets before new mask
mega_barrier(); mega_barrier();
_mask = newMask; _mask.store(newMask, memory_order::memory_order_relaxed);
_occupied = 0; _occupied = 0;
#elif __x86_64__ || i386
// ensure other threads see buckets contents before buckets pointer
_buckets.store(newBuckets, memory_order::memory_order_release);
// ensure other threads see new buckets before new mask
_mask.store(newMask, memory_order::memory_order_release);
_occupied = 0;
#else
#error Don't know how to do setBucketsAndMask on this architecture.
#endif
} }
struct bucket_t *cache_t::emptyBuckets()
{
return (bucket_t *)&_objc_empty_cache;
}
struct bucket_t *cache_t::buckets() struct bucket_t *cache_t::buckets()
{ {
return _buckets; return _buckets.load(memory_order::memory_order_relaxed);
} }
mask_t cache_t::mask() mask_t cache_t::mask()
{ {
return _mask; return _mask.load(memory_order::memory_order_relaxed);
} }
void cache_t::initializeToEmpty()
{
bzero(this, sizeof(*this));
_buckets.store((bucket_t *)&_objc_empty_cache, memory_order::memory_order_relaxed);
}
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
void cache_t::setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask)
{
uintptr_t buckets = (uintptr_t)newBuckets;
uintptr_t mask = (uintptr_t)newMask;
ASSERT(buckets <= bucketsMask);
ASSERT(mask <= maxMask);
_maskAndBuckets.store(((uintptr_t)newMask << maskShift) | (uintptr_t)newBuckets, std::memory_order_relaxed);
_occupied = 0;
}
struct bucket_t *cache_t::emptyBuckets()
{
return (bucket_t *)&_objc_empty_cache;
}
struct bucket_t *cache_t::buckets()
{
uintptr_t maskAndBuckets = _maskAndBuckets.load(memory_order::memory_order_relaxed);
return (bucket_t *)(maskAndBuckets & bucketsMask);
}
mask_t cache_t::mask()
{
uintptr_t maskAndBuckets = _maskAndBuckets.load(memory_order::memory_order_relaxed);
return maskAndBuckets >> maskShift;
}
void cache_t::initializeToEmpty()
{
bzero(this, sizeof(*this));
_maskAndBuckets.store((uintptr_t)&_objc_empty_cache, std::memory_order_relaxed);
}
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4
void cache_t::setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask)
{
uintptr_t buckets = (uintptr_t)newBuckets;
unsigned mask = (unsigned)newMask;
ASSERT(buckets == (buckets & bucketsMask));
ASSERT(mask <= 0xffff);
// The shift amount is equal to the number of leading zeroes in
// the last 16 bits of mask. Count all the leading zeroes, then
// subtract to ignore the top half.
uintptr_t maskShift = __builtin_clz(mask) - (sizeof(mask) * CHAR_BIT - 16);
ASSERT(mask == (0xffff >> maskShift));
_maskAndBuckets.store(buckets | maskShift, memory_order::memory_order_relaxed);
_occupied = 0;
ASSERT(this->buckets() == newBuckets);
ASSERT(this->mask() == newMask);
}
struct bucket_t *cache_t::emptyBuckets()
{
return (bucket_t *)((uintptr_t)&_objc_empty_cache & bucketsMask);
}
struct bucket_t *cache_t::buckets()
{
uintptr_t maskAndBuckets = _maskAndBuckets.load(memory_order::memory_order_relaxed);
return (bucket_t *)(maskAndBuckets & bucketsMask);
}
mask_t cache_t::mask()
{
uintptr_t maskAndBuckets = _maskAndBuckets.load(memory_order::memory_order_relaxed);
uintptr_t maskShift = (maskAndBuckets & maskMask);
return 0xffff >> maskShift;
}
void cache_t::initializeToEmpty()
{
bzero(this, sizeof(*this));
_maskAndBuckets.store((uintptr_t)&_objc_empty_cache, std::memory_order_relaxed);
}
#else
#error Unknown cache mask storage type.
#endif
mask_t cache_t::occupied() mask_t cache_t::occupied()
{ {
return _occupied; return _occupied;
@ -320,30 +459,21 @@ void cache_t::incrementOccupied()
_occupied++; _occupied++;
} }
void cache_t::initializeToEmpty() unsigned cache_t::capacity()
{
bzero(this, sizeof(*this));
_buckets = (bucket_t *)&_objc_empty_cache;
}
mask_t cache_t::capacity()
{ {
return mask() ? mask()+1 : 0; return mask() ? mask()+1 : 0;
} }
#if CACHE_END_MARKER
size_t cache_t::bytesForCapacity(uint32_t cap) size_t cache_t::bytesForCapacity(uint32_t cap)
{ {
// fixme put end marker inline when capacity+1 malloc is inefficient return sizeof(bucket_t) * cap;
return sizeof(bucket_t) * (cap + 1);
} }
#if CACHE_END_MARKER
bucket_t *cache_t::endMarker(struct bucket_t *b, uint32_t cap) bucket_t *cache_t::endMarker(struct bucket_t *b, uint32_t cap)
{ {
// bytesForCapacity() chooses whether the end marker is inline or not
return (bucket_t *)((uintptr_t)b + bytesForCapacity(cap)) - 1; return (bucket_t *)((uintptr_t)b + bytesForCapacity(cap)) - 1;
} }
@ -351,21 +481,18 @@ bucket_t *allocateBuckets(mask_t newCapacity)
{ {
// Allocate one extra bucket to mark the end of the list. // Allocate one extra bucket to mark the end of the list.
// This can't overflow mask_t because newCapacity is a power of 2. // This can't overflow mask_t because newCapacity is a power of 2.
// fixme instead put the end mark inline when +1 is malloc-inefficient
bucket_t *newBuckets = (bucket_t *) bucket_t *newBuckets = (bucket_t *)
calloc(cache_t::bytesForCapacity(newCapacity), 1); calloc(cache_t::bytesForCapacity(newCapacity), 1);
bucket_t *end = cache_t::endMarker(newBuckets, newCapacity); bucket_t *end = cache_t::endMarker(newBuckets, newCapacity);
#if __arm__ #if __arm__
// End marker's key is 1 and imp points BEFORE the first bucket. // End marker's sel is 1 and imp points BEFORE the first bucket.
// This saves an instruction in objc_msgSend. // This saves an instruction in objc_msgSend.
end->setKey((cache_key_t)(uintptr_t)1); end->set<NotAtomic, Raw>((SEL)(uintptr_t)1, (IMP)(newBuckets - 1), nil);
end->setImp((IMP)(newBuckets - 1));
#else #else
// End marker's key is 1 and imp points to the first bucket. // End marker's sel is 1 and imp points to the first bucket.
end->setKey((cache_key_t)(uintptr_t)1); end->set<NotAtomic, Raw>((SEL)(uintptr_t)1, (IMP)newBuckets, nil);
end->setImp((IMP)newBuckets);
#endif #endif
if (PrintCaches) recordNewCache(newCapacity); if (PrintCaches) recordNewCache(newCapacity);
@ -375,11 +502,6 @@ bucket_t *allocateBuckets(mask_t newCapacity)
#else #else
size_t cache_t::bytesForCapacity(uint32_t cap)
{
return sizeof(bucket_t) * cap;
}
bucket_t *allocateBuckets(mask_t newCapacity) bucket_t *allocateBuckets(mask_t newCapacity)
{ {
if (PrintCaches) recordNewCache(newCapacity); if (PrintCaches) recordNewCache(newCapacity);
@ -392,13 +514,17 @@ bucket_t *allocateBuckets(mask_t newCapacity)
bucket_t *emptyBucketsForCapacity(mask_t capacity, bool allocate = true) bucket_t *emptyBucketsForCapacity(mask_t capacity, bool allocate = true)
{ {
#if CONFIG_USE_CACHE_LOCK
cacheUpdateLock.assertLocked(); cacheUpdateLock.assertLocked();
#else
runtimeLock.assertLocked();
#endif
size_t bytes = cache_t::bytesForCapacity(capacity); size_t bytes = cache_t::bytesForCapacity(capacity);
// Use _objc_empty_cache if the buckets is small enough. // Use _objc_empty_cache if the buckets is small enough.
if (bytes <= EMPTY_BYTES) { if (bytes <= EMPTY_BYTES) {
return (bucket_t *)&_objc_empty_cache; return cache_t::emptyBuckets();
} }
// Use shared empty buckets allocated on the heap. // Use shared empty buckets allocated on the heap.
@ -443,11 +569,9 @@ bool cache_t::canBeFreed()
return !isConstantEmptyCache(); return !isConstantEmptyCache();
} }
ALWAYS_INLINE
void cache_t::reallocate(mask_t oldCapacity, mask_t newCapacity) void cache_t::reallocate(mask_t oldCapacity, mask_t newCapacity, bool freeOld)
{ {
bool freeOld = canBeFreed();
bucket_t *oldBuckets = buckets(); bucket_t *oldBuckets = buckets();
bucket_t *newBuckets = allocateBuckets(newCapacity); bucket_t *newBuckets = allocateBuckets(newCapacity);
@ -455,14 +579,13 @@ void cache_t::reallocate(mask_t oldCapacity, mask_t newCapacity)
// This is thought to save cache memory at the cost of extra cache fills. // This is thought to save cache memory at the cost of extra cache fills.
// fixme re-measure this // fixme re-measure this
assert(newCapacity > 0); ASSERT(newCapacity > 0);
assert((uintptr_t)(mask_t)(newCapacity-1) == newCapacity-1); ASSERT((uintptr_t)(mask_t)(newCapacity-1) == newCapacity-1);
setBucketsAndMask(newBuckets, newCapacity - 1); setBucketsAndMask(newBuckets, newCapacity - 1);
if (freeOld) { if (freeOld) {
cache_collect_free(oldBuckets, oldCapacity); cache_collect_free(oldBuckets, oldCapacity);
cache_collect(false);
} }
} }
@ -474,16 +597,35 @@ void cache_t::bad_cache(id receiver, SEL sel, Class isa)
("Method cache corrupted. This may be a message to an " ("Method cache corrupted. This may be a message to an "
"invalid object, or a memory error somewhere else."); "invalid object, or a memory error somewhere else.");
cache_t *cache = &isa->cache; cache_t *cache = &isa->cache;
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
bucket_t *buckets = cache->_buckets.load(memory_order::memory_order_relaxed);
_objc_inform_now_and_on_crash _objc_inform_now_and_on_crash
("%s %p, SEL %p, isa %p, cache %p, buckets %p, " ("%s %p, SEL %p, isa %p, cache %p, buckets %p, "
"mask 0x%x, occupied 0x%x", "mask 0x%x, occupied 0x%x",
receiver ? "receiver" : "unused", receiver, receiver ? "receiver" : "unused", receiver,
sel, isa, cache, cache->_buckets, sel, isa, cache, buckets,
cache->_mask, cache->_occupied); cache->_mask.load(memory_order::memory_order_relaxed),
cache->_occupied);
_objc_inform_now_and_on_crash _objc_inform_now_and_on_crash
("%s %zu bytes, buckets %zu bytes", ("%s %zu bytes, buckets %zu bytes",
receiver ? "receiver" : "unused", malloc_size(receiver), receiver ? "receiver" : "unused", malloc_size(receiver),
malloc_size(cache->_buckets)); malloc_size(buckets));
#elif (CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16 || \
CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4)
uintptr_t maskAndBuckets = cache->_maskAndBuckets.load(memory_order::memory_order_relaxed);
_objc_inform_now_and_on_crash
("%s %p, SEL %p, isa %p, cache %p, buckets and mask 0x%lx, "
"occupied 0x%x",
receiver ? "receiver" : "unused", receiver,
sel, isa, cache, maskAndBuckets,
cache->_occupied);
_objc_inform_now_and_on_crash
("%s %zu bytes, buckets %zu bytes",
receiver ? "receiver" : "unused", malloc_size(receiver),
malloc_size(cache->buckets()));
#else
#error Unknown cache mask storage type.
#endif
_objc_inform_now_and_on_crash _objc_inform_now_and_on_crash
("selector '%s'", sel_getName(sel)); ("selector '%s'", sel_getName(sel));
_objc_inform_now_and_on_crash _objc_inform_now_and_on_crash
@ -493,89 +635,75 @@ void cache_t::bad_cache(id receiver, SEL sel, Class isa)
"invalid object, or a memory error somewhere else."); "invalid object, or a memory error somewhere else.");
} }
ALWAYS_INLINE
bucket_t * cache_t::find(cache_key_t k, id receiver) void cache_t::insert(Class cls, SEL sel, IMP imp, id receiver)
{
assert(k != 0);
bucket_t *b = buckets();
mask_t m = mask();
mask_t begin = cache_hash(k, m);
mask_t i = begin;
do {
if (b[i].key() == 0 || b[i].key() == k) {
return &b[i];
}
} while ((i = cache_next(i, m)) != begin);
// hack
Class cls = (Class)((uintptr_t)this - offsetof(objc_class, cache));
cache_t::bad_cache(receiver, (SEL)k, cls);
}
void cache_t::expand()
{ {
#if CONFIG_USE_CACHE_LOCK
cacheUpdateLock.assertLocked(); cacheUpdateLock.assertLocked();
#else
runtimeLock.assertLocked();
#endif
uint32_t oldCapacity = capacity(); ASSERT(sel != 0 && cls->isInitialized());
uint32_t newCapacity = oldCapacity ? oldCapacity*2 : INIT_CACHE_SIZE;
if ((uint32_t)(mask_t)newCapacity != newCapacity) {
// mask overflow - can't grow further
// fixme this wastes one bit of mask
newCapacity = oldCapacity;
}
reallocate(oldCapacity, newCapacity);
}
static void cache_fill_nolock(Class cls, SEL sel, IMP imp, id receiver)
{
cacheUpdateLock.assertLocked();
// Never cache before +initialize is done
if (!cls->isInitialized()) return;
// Make sure the entry wasn't added to the cache by some other thread
// before we grabbed the cacheUpdateLock.
if (cache_getImp(cls, sel)) return;
cache_t *cache = getCache(cls);
cache_key_t key = getKey(sel);
// Use the cache as-is if it is less than 3/4 full // Use the cache as-is if it is less than 3/4 full
mask_t newOccupied = cache->occupied() + 1; mask_t newOccupied = occupied() + 1;
mask_t capacity = cache->capacity(); unsigned oldCapacity = capacity(), capacity = oldCapacity;
if (cache->isConstantEmptyCache()) { if (slowpath(isConstantEmptyCache())) {
// Cache is read-only. Replace it. // Cache is read-only. Replace it.
cache->reallocate(capacity, capacity ?: INIT_CACHE_SIZE); if (!capacity) capacity = INIT_CACHE_SIZE;
reallocate(oldCapacity, capacity, /* freeOld */false);
} }
else if (newOccupied <= capacity / 4 * 3) { else if (fastpath(newOccupied + CACHE_END_MARKER <= capacity / 4 * 3)) {
// Cache is less than 3/4 full. Use it as-is. // Cache is less than 3/4 full. Use it as-is.
} }
else { else {
// Cache is too full. Expand it. capacity = capacity ? capacity * 2 : INIT_CACHE_SIZE;
cache->expand(); if (capacity > MAX_CACHE_SIZE) {
capacity = MAX_CACHE_SIZE;
}
reallocate(oldCapacity, capacity, true);
} }
bucket_t *b = buckets();
mask_t m = capacity - 1;
mask_t begin = cache_hash(sel, m);
mask_t i = begin;
// Scan for the first unused slot and insert there. // Scan for the first unused slot and insert there.
// There is guaranteed to be an empty slot because the // There is guaranteed to be an empty slot because the
// minimum size is 4 and we resized at 3/4 full. // minimum size is 4 and we resized at 3/4 full.
bucket_t *bucket = cache->find(key, receiver); do {
if (bucket->key() == 0) cache->incrementOccupied(); if (fastpath(b[i].sel() == 0)) {
bucket->set(key, imp); incrementOccupied();
b[i].set<Atomic, Encoded>(sel, imp, cls);
return;
}
if (b[i].sel() == sel) {
// The entry was added to the cache by some other thread
// before we grabbed the cacheUpdateLock.
return;
}
} while (fastpath((i = cache_next(i, m)) != begin));
cache_t::bad_cache(receiver, (SEL)sel, cls);
} }
void cache_fill(Class cls, SEL sel, IMP imp, id receiver) void cache_fill(Class cls, SEL sel, IMP imp, id receiver)
{ {
runtimeLock.assertLocked();
#if !DEBUG_TASK_THREADS #if !DEBUG_TASK_THREADS
mutex_locker_t lock(cacheUpdateLock); // Never cache before +initialize is done
cache_fill_nolock(cls, sel, imp, receiver); if (cls->isInitialized()) {
cache_t *cache = getCache(cls);
#if CONFIG_USE_CACHE_LOCK
mutex_locker_t lock(cacheUpdateLock);
#endif
cache->insert(cls, sel, imp, receiver);
}
#else #else
_collecting_in_critical(); _collecting_in_critical();
return;
#endif #endif
} }
@ -584,7 +712,11 @@ void cache_fill(Class cls, SEL sel, IMP imp, id receiver)
// This must not shrink the cache - that breaks the lock-free scheme. // This must not shrink the cache - that breaks the lock-free scheme.
void cache_erase_nolock(Class cls) void cache_erase_nolock(Class cls)
{ {
#if CONFIG_USE_CACHE_LOCK
cacheUpdateLock.assertLocked(); cacheUpdateLock.assertLocked();
#else
runtimeLock.assertLocked();
#endif
cache_t *cache = getCache(cls); cache_t *cache = getCache(cls);
@ -595,14 +727,17 @@ void cache_erase_nolock(Class cls)
cache->setBucketsAndMask(buckets, capacity - 1); // also clears occupied cache->setBucketsAndMask(buckets, capacity - 1); // also clears occupied
cache_collect_free(oldBuckets, capacity); cache_collect_free(oldBuckets, capacity);
cache_collect(false);
} }
} }
void cache_delete(Class cls) void cache_delete(Class cls)
{ {
#if CONFIG_USE_CACHE_LOCK
mutex_locker_t lock(cacheUpdateLock); mutex_locker_t lock(cacheUpdateLock);
#else
runtimeLock.assertLocked();
#endif
if (cls->cache.canBeFreed()) { if (cls->cache.canBeFreed()) {
if (PrintCaches) recordDeadCache(cls->cache.capacity()); if (PrintCaches) recordDeadCache(cls->cache.capacity());
free(cls->cache.buckets()); free(cls->cache.buckets());
@ -648,7 +783,7 @@ static uintptr_t _get_pc_for_thread(thread_t thread)
arm_thread_state64_t state; arm_thread_state64_t state;
unsigned int count = ARM_THREAD_STATE64_COUNT; unsigned int count = ARM_THREAD_STATE64_COUNT;
kern_return_t okay = thread_get_state (thread, ARM_THREAD_STATE64, (thread_state_t)&state, &count); kern_return_t okay = thread_get_state (thread, ARM_THREAD_STATE64, (thread_state_t)&state, &count);
return (okay == KERN_SUCCESS) ? state.__pc : PC_SENTINEL; return (okay == KERN_SUCCESS) ? (uintptr_t)arm_thread_state64_get_pc(state) : PC_SENTINEL;
} }
#else #else
{ {
@ -665,21 +800,64 @@ static uintptr_t _get_pc_for_thread(thread_t thread)
* reading function is in progress because it might still be using * reading function is in progress because it might still be using
* the garbage memory. * the garbage memory.
**********************************************************************/ **********************************************************************/
OBJC_EXPORT uintptr_t objc_entryPoints[]; #if HAVE_TASK_RESTARTABLE_RANGES
OBJC_EXPORT uintptr_t objc_exitPoints[]; #include <kern/restartable.h>
#else
typedef struct {
uint64_t location;
unsigned short length;
unsigned short recovery_offs;
unsigned int flags;
} task_restartable_range_t;
#endif
extern "C" task_restartable_range_t objc_restartableRanges[];
#if HAVE_TASK_RESTARTABLE_RANGES
static bool shouldUseRestartableRanges = true;
#endif
void cache_init()
{
#if HAVE_TASK_RESTARTABLE_RANGES
mach_msg_type_number_t count = 0;
kern_return_t kr;
while (objc_restartableRanges[count].location) {
count++;
}
kr = task_restartable_ranges_register(mach_task_self(),
objc_restartableRanges, count);
if (kr == KERN_SUCCESS) return;
_objc_fatal("task_restartable_ranges_register failed (result 0x%x: %s)",
kr, mach_error_string(kr));
#endif // HAVE_TASK_RESTARTABLE_RANGES
}
static int _collecting_in_critical(void) static int _collecting_in_critical(void)
{ {
#if TARGET_OS_WIN32 #if TARGET_OS_WIN32
return TRUE; return TRUE;
#else #elif HAVE_TASK_RESTARTABLE_RANGES
// Only use restartable ranges if we registered them earlier.
if (shouldUseRestartableRanges) {
kern_return_t kr = task_restartable_ranges_synchronize(mach_task_self());
if (kr == KERN_SUCCESS) return FALSE;
_objc_fatal("task_restartable_ranges_synchronize failed (result 0x%x: %s)",
kr, mach_error_string(kr));
}
#endif // !HAVE_TASK_RESTARTABLE_RANGES
// Fallthrough if we didn't use restartable ranges.
thread_act_port_array_t threads; thread_act_port_array_t threads;
unsigned number; unsigned number;
unsigned count; unsigned count;
kern_return_t ret; kern_return_t ret;
int result; int result;
mach_port_t mythread = pthread_mach_thread_np(pthread_self()); mach_port_t mythread = pthread_mach_thread_np(objc_thread_self());
// Get a list of all the threads in the current task // Get a list of all the threads in the current task
#if !DEBUG_TASK_THREADS #if !DEBUG_TASK_THREADS
@ -715,10 +893,11 @@ static int _collecting_in_critical(void)
} }
// Check whether it is in the cache lookup code // Check whether it is in the cache lookup code
for (region = 0; objc_entryPoints[region] != 0; region++) for (region = 0; objc_restartableRanges[region].location != 0; region++)
{ {
if ((pc >= objc_entryPoints[region]) && uint64_t loc = objc_restartableRanges[region].location;
(pc <= objc_exitPoints[region])) if ((pc > loc) &&
(pc - loc < (uint64_t)objc_restartableRanges[region].length))
{ {
result = TRUE; result = TRUE;
goto done; goto done;
@ -737,7 +916,6 @@ static int _collecting_in_critical(void)
// Return our finding // Return our finding
return result; return result;
#endif
} }
@ -798,13 +976,18 @@ static void _garbage_make_room(void)
**********************************************************************/ **********************************************************************/
static void cache_collect_free(bucket_t *data, mask_t capacity) static void cache_collect_free(bucket_t *data, mask_t capacity)
{ {
#if CONFIG_USE_CACHE_LOCK
cacheUpdateLock.assertLocked(); cacheUpdateLock.assertLocked();
#else
runtimeLock.assertLocked();
#endif
if (PrintCaches) recordDeadCache(capacity); if (PrintCaches) recordDeadCache(capacity);
_garbage_make_room (); _garbage_make_room ();
garbage_byte_size += cache_t::bytesForCapacity(capacity); garbage_byte_size += cache_t::bytesForCapacity(capacity);
garbage_refs[garbage_count++] = data; garbage_refs[garbage_count++] = data;
cache_collect(false);
} }
@ -815,7 +998,11 @@ static void cache_collect_free(bucket_t *data, mask_t capacity)
**********************************************************************/ **********************************************************************/
void cache_collect(bool collectALot) void cache_collect(bool collectALot)
{ {
#if CONFIG_USE_CACHE_LOCK
cacheUpdateLock.assertLocked(); cacheUpdateLock.assertLocked();
#else
runtimeLock.assertLocked();
#endif
// Done if the garbage is not full // Done if the garbage is not full
if (garbage_byte_size < garbage_threshold && !collectALot) { if (garbage_byte_size < garbage_threshold && !collectALot) {

View File

@ -36,6 +36,7 @@
static Method _class_getMethod(Class cls, SEL sel); static Method _class_getMethod(Class cls, SEL sel);
static Method _class_getMethodNoSuper(Class cls, SEL sel); static Method _class_getMethodNoSuper(Class cls, SEL sel);
static Method _class_getMethodNoSuper_nolock(Class cls, SEL sel); static Method _class_getMethodNoSuper_nolock(Class cls, SEL sel);
static Class _class_getNonMetaClass(Class cls, id obj);
static void flush_caches(Class cls, bool flush_meta); static void flush_caches(Class cls, bool flush_meta);
@ -163,13 +164,12 @@ static old_method_list *fixupSelectorsInMethodList(Class cls, old_method_list *m
// Mach-O bundles are fixed up in place. // Mach-O bundles are fixed up in place.
// This prevents leaks when a bundle is unloaded. // This prevents leaks when a bundle is unloaded.
} }
sel_lock(); mutex_locker_t lock(selLock);
for ( i = 0; i < mlist->method_count; i += 1 ) { for ( i = 0; i < mlist->method_count; i += 1 ) {
method = &mlist->method_list[i]; method = &mlist->method_list[i];
method->method_name = method->method_name =
sel_registerNameNoLock((const char *)method->method_name, isBundle); // Always copy selector data from bundles. sel_registerNameNoLock((const char *)method->method_name, isBundle); // Always copy selector data from bundles.
} }
sel_unlock();
mlist->obsolete = fixed_up_method_list; mlist->obsolete = fixed_up_method_list;
} }
return mlist; return mlist;
@ -325,6 +325,112 @@ static void _freedHandler(id obj, SEL sel)
} }
/***********************************************************************
* _class_resolveClassMethod
* Call +resolveClassMethod, looking for a method to be added to class cls.
* cls should be a metaclass.
* Does not check if the method already exists.
**********************************************************************/
static void _class_resolveClassMethod(id inst, SEL sel, Class cls)
{
ASSERT(cls->isMetaClass());
SEL resolve_sel = @selector(resolveClassMethod:);
if (!lookUpImpOrNil(inst, resolve_sel, cls)) {
// Resolver not implemented.
return;
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(_class_getNonMetaClass(cls, inst), resolve_sel, sel);
// Cache the result (good or bad) so the resolver doesn't fire next time.
// +resolveClassMethod adds to self->ISA() a.k.a. cls
IMP imp = lookUpImpOrNil(inst, sel, cls);
if (resolved && PrintResolving) {
if (imp) {
_objc_inform("RESOLVE: method %c[%s %s] "
"dynamically resolved to %p",
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel), imp);
}
else {
// Method resolver didn't add anything?
_objc_inform("RESOLVE: +[%s resolveClassMethod:%s] returned YES"
", but no new implementation of %c[%s %s] was found",
cls->nameForLogging(), sel_getName(sel),
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel));
}
}
}
/***********************************************************************
* _class_resolveInstanceMethod
* Call +resolveInstanceMethod, looking for a method to be added to class cls.
* cls may be a metaclass or a non-meta class.
* Does not check if the method already exists.
**********************************************************************/
static void _class_resolveInstanceMethod(id inst, SEL sel, Class cls)
{
SEL resolve_sel = @selector(resolveInstanceMethod:);
if (! lookUpImpOrNil(cls, resolve_sel, cls->ISA())) {
// Resolver not implemented.
return;
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(cls, resolve_sel, sel);
// Cache the result (good or bad) so the resolver doesn't fire next time.
// +resolveInstanceMethod adds to self a.k.a. cls
IMP imp = lookUpImpOrNil(inst, sel, cls);
if (resolved && PrintResolving) {
if (imp) {
_objc_inform("RESOLVE: method %c[%s %s] "
"dynamically resolved to %p",
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel), imp);
}
else {
// Method resolver didn't add anything?
_objc_inform("RESOLVE: +[%s resolveInstanceMethod:%s] returned YES"
", but no new implementation of %c[%s %s] was found",
cls->nameForLogging(), sel_getName(sel),
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel));
}
}
}
/***********************************************************************
* _class_resolveMethod
* Call +resolveClassMethod or +resolveInstanceMethod.
* Returns nothing; any result would be potentially out-of-date already.
* Does not check if the method already exists.
**********************************************************************/
static void
_class_resolveMethod(id inst, SEL sel, Class cls)
{
if (! cls->isMetaClass()) {
// try [cls resolveInstanceMethod:sel]
_class_resolveInstanceMethod(inst, sel, cls);
}
else {
// try [nonMetaClass resolveClassMethod:sel]
// and [cls resolveInstanceMethod:sel]
_class_resolveClassMethod(inst, sel, cls);
if (!lookUpImpOrNil(inst, sel, cls)) {
_class_resolveInstanceMethod(inst, sel, cls);
}
}
}
/*********************************************************************** /***********************************************************************
* log_and_fill_cache * log_and_fill_cache
* Log this method call. If the logger permits it, fill the method cache. * Log this method call. If the logger permits it, fill the method cache.
@ -347,33 +453,19 @@ log_and_fill_cache(Class cls, Class implementer, Method meth, SEL sel)
} }
/***********************************************************************
* _class_lookupMethodAndLoadCache.
* Method lookup for dispatchers ONLY. OTHER CODE SHOULD USE lookUpImp().
* This lookup avoids optimistic cache scan because the dispatcher
* already tried that.
**********************************************************************/
IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)
{
return lookUpImpOrForward(cls, sel, obj,
YES/*initialize*/, NO/*cache*/, YES/*resolver*/);
}
/*********************************************************************** /***********************************************************************
* lookUpImpOrForward. * lookUpImpOrForward.
* The standard IMP lookup. * The standard IMP lookup.
* initialize==NO tries to avoid +initialize (but sometimes fails) * Without LOOKUP_INITIALIZE: tries to avoid +initialize (but sometimes fails)
* cache==NO skips optimistic unlocked lookup (but uses cache elsewhere) * Without LOOKUP_CACHE: skips optimistic unlocked lookup (but uses cache elsewhere)
* Most callers should use initialize==YES and cache==YES. * Most callers should use LOOKUP_INITIALIZE and LOOKUP_CACHE
* inst is an instance of cls or a subclass thereof, or nil if none is known. * inst is an instance of cls or a subclass thereof, or nil if none is known.
* If cls is an un-initialized metaclass then a non-nil inst is faster. * If cls is an un-initialized metaclass then a non-nil inst is faster.
* May return _objc_msgForward_impcache. IMPs destined for external use * May return _objc_msgForward_impcache. IMPs destined for external use
* must be converted to _objc_msgForward or _objc_msgForward_stret. * must be converted to _objc_msgForward or _objc_msgForward_stret.
* If you don't want forwarding at all, use lookUpImpOrNil() instead. * If you don't want forwarding at all, use LOOKUP_NIL.
**********************************************************************/ **********************************************************************/
IMP lookUpImpOrForward(Class cls, SEL sel, id inst, IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
bool initialize, bool cache, bool resolver)
{ {
Class curClass; Class curClass;
IMP methodPC = nil; IMP methodPC = nil;
@ -383,9 +475,9 @@ IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
methodListLock.assertUnlocked(); methodListLock.assertUnlocked();
// Optimistic cache lookup // Optimistic cache lookup
if (cache) { if (behavior & LOOKUP_CACHE) {
methodPC = _cache_getImp(cls, sel); methodPC = _cache_getImp(cls, sel);
if (methodPC) return methodPC; if (methodPC) goto out_nolock;
} }
// Check for freed class // Check for freed class
@ -393,10 +485,10 @@ IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
return (IMP) _freedHandler; return (IMP) _freedHandler;
// Check for +initialize // Check for +initialize
if (initialize && !cls->isInitialized()) { if ((behavior & LOOKUP_INITIALIZE) && !cls->isInitialized()) {
_class_initialize (_class_getNonMetaClass(cls, inst)); initializeNonMetaClass (_class_getNonMetaClass(cls, inst));
// If sel == initialize, _class_initialize will send +initialize and // If sel == initialize, initializeNonMetaClass will send +initialize
// then the messenger will send +initialize again after this // and then the messenger will send +initialize again after this
// procedure finishes. Of course, if this is not being called // procedure finishes. Of course, if this is not being called
// from the messenger then it won't happen. 2778172 // from the messenger then it won't happen. 2778172
} }
@ -454,7 +546,7 @@ IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
// No implementation found. Try method resolver once. // No implementation found. Try method resolver once.
if (resolver && !triedResolver) { if ((behavior & LOOKUP_RESOLVER) && !triedResolver) {
methodListLock.unlock(); methodListLock.unlock();
_class_resolveMethod(cls, sel, inst); _class_resolveMethod(cls, sel, inst);
triedResolver = YES; triedResolver = YES;
@ -470,23 +562,14 @@ IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
done: done:
methodListLock.unlock(); methodListLock.unlock();
out_nolock:
if ((behavior & LOOKUP_NIL) && methodPC == (IMP)_objc_msgForward_impcache) {
return nil;
}
return methodPC; return methodPC;
} }
/***********************************************************************
* lookUpImpOrNil.
* Like lookUpImpOrForward, but returns nil instead of _objc_msgForward_impcache
**********************************************************************/
IMP lookUpImpOrNil(Class cls, SEL sel, id inst,
bool initialize, bool cache, bool resolver)
{
IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver);
if (imp == _objc_msgForward_impcache) return nil;
else return imp;
}
/*********************************************************************** /***********************************************************************
* lookupMethodInClassAndLoadCache. * lookupMethodInClassAndLoadCache.
* Like _class_lookupMethodAndLoadCache, but does not search superclasses. * Like _class_lookupMethodAndLoadCache, but does not search superclasses.
@ -683,33 +766,6 @@ void class_setIvarLayout(Class cls, const uint8_t *layout)
cls->ivar_layout = ustrdupMaybeNil(layout); cls->ivar_layout = ustrdupMaybeNil(layout);
} }
// SPI: Instance-specific object layout.
void _class_setIvarLayoutAccessor(Class cls, const uint8_t* (*accessor) (id object)) {
if (!cls) return;
if (! (cls->info & CLS_EXT)) {
_objc_inform("class '%s' needs to be recompiled", cls->name);
return;
}
// fixme leak
cls->ivar_layout = (const uint8_t *)accessor;
cls->setInfo(CLS_HAS_INSTANCE_SPECIFIC_LAYOUT);
}
const uint8_t *_object_getIvarLayout(Class cls, id object) {
if (cls && (cls->info & CLS_EXT)) {
const uint8_t* layout = cls->ivar_layout;
if (cls->info & CLS_HAS_INSTANCE_SPECIFIC_LAYOUT) {
const uint8_t* (*accessor) (id object) = (const uint8_t* (*)(id))layout;
layout = accessor(object);
}
return layout;
} else {
return nil;
}
}
/*********************************************************************** /***********************************************************************
* class_setWeakIvarLayout * class_setWeakIvarLayout
@ -762,7 +818,7 @@ const char *class_getName(Class cls)
* Return the ordinary class for this class or metaclass. * Return the ordinary class for this class or metaclass.
* Used by +initialize. * Used by +initialize.
**********************************************************************/ **********************************************************************/
Class _class_getNonMetaClass(Class cls, id obj) static Class _class_getNonMetaClass(Class cls, id obj)
{ {
// fixme ick // fixme ick
if (cls->isMetaClass()) { if (cls->isMetaClass()) {
@ -780,13 +836,21 @@ Class _class_getNonMetaClass(Class cls, id obj)
else { else {
cls = objc_getClass(cls->name); cls = objc_getClass(cls->name);
} }
assert(cls); ASSERT(cls);
} }
return cls; return cls;
} }
Class class_initialize(Class cls, id inst) {
if (!cls->isInitialized()) {
initializeNonMetaClass (_class_getNonMetaClass(cls, inst));
}
return cls;
}
Cache _class_getCache(Class cls) Cache _class_getCache(Class cls)
{ {
return cls->cache; return cls->cache;
@ -837,7 +901,7 @@ IMP _category_getLoadMethod(Category cat)
* If methods are removed between calls to class_nextMethodList(), it may * If methods are removed between calls to class_nextMethodList(), it may
* omit surviving method lists or simply crash. * omit surviving method lists or simply crash.
**********************************************************************/ **********************************************************************/
OBJC_EXPORT struct objc_method_list *class_nextMethodList(Class cls, void **it) struct objc_method_list *class_nextMethodList(Class cls, void **it)
{ {
OBJC_WARN_DEPRECATED; OBJC_WARN_DEPRECATED;
@ -851,7 +915,7 @@ OBJC_EXPORT struct objc_method_list *class_nextMethodList(Class cls, void **it)
* *
* Formerly class_addInstanceMethods () * Formerly class_addInstanceMethods ()
**********************************************************************/ **********************************************************************/
OBJC_EXPORT void class_addMethods(Class cls, struct objc_method_list *meths) void class_addMethods(Class cls, struct objc_method_list *meths)
{ {
OBJC_WARN_DEPRECATED; OBJC_WARN_DEPRECATED;
@ -871,7 +935,7 @@ OBJC_EXPORT void class_addMethods(Class cls, struct objc_method_list *meths)
/*********************************************************************** /***********************************************************************
* class_removeMethods. * class_removeMethods.
**********************************************************************/ **********************************************************************/
OBJC_EXPORT void class_removeMethods(Class cls, struct objc_method_list *meths) void class_removeMethods(Class cls, struct objc_method_list *meths)
{ {
OBJC_WARN_DEPRECATED; OBJC_WARN_DEPRECATED;
@ -942,8 +1006,7 @@ Method class_getInstanceMethod(Class cls, SEL sel)
} }
// Search method lists, try method resolver, etc. // Search method lists, try method resolver, etc.
lookUpImpOrNil(cls, sel, nil, lookUpImpOrForward(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);
NO/*initialize*/, NO/*cache*/, YES/*resolver*/);
meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache); meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache);
if (meth == (Method)1) { if (meth == (Method)1) {
@ -1494,6 +1557,9 @@ unsigned int method_getSizeOfArguments(Method m)
return encoding_getSizeOfArguments(method_getTypeEncoding(m)); return encoding_getSizeOfArguments(method_getTypeEncoding(m));
} }
// This function was accidentally un-exported beginning in macOS 10.9.
// As of macOS 10.13 nobody had complained.
/*
unsigned int method_getArgumentInfo(Method m, int arg, unsigned int method_getArgumentInfo(Method m, int arg,
const char **type, int *offset) const char **type, int *offset)
{ {
@ -1502,9 +1568,10 @@ unsigned int method_getArgumentInfo(Method m, int arg,
return encoding_getArgumentInfo(method_getTypeEncoding(m), return encoding_getArgumentInfo(method_getTypeEncoding(m),
arg, type, offset); arg, type, offset);
} }
*/
static spinlock_t impLock; spinlock_t impLock;
IMP method_setImplementation(Method m_gen, IMP imp) IMP method_setImplementation(Method m_gen, IMP imp)
{ {
@ -2289,7 +2356,7 @@ objc_constructInstance(Class cls, void *bytes)
obj->initIsa(cls); obj->initIsa(cls);
if (cls->hasCxxCtor()) { if (cls->hasCxxCtor()) {
return object_cxxConstructFromClass(obj, cls); return object_cxxConstructFromClass(obj, cls, OBJECT_CONSTRUCT_NONE);
} else { } else {
return obj; return obj;
} }
@ -2464,6 +2531,21 @@ id class_createInstanceFromZone(Class cls, size_t extraBytes, void *z)
return (*_zoneAlloc)(cls, extraBytes, z); return (*_zoneAlloc)(cls, extraBytes, z);
} }
id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
{
id obj;
if (fastpath(!zone)) {
obj = class_createInstance(cls, 0);
} else {
obj = class_createInstanceFromZone(cls, 0, zone);
}
if (slowpath(!obj)) obj = _objc_callBadAllocHandler(cls);
return obj;
}
unsigned class_createInstances(Class cls, size_t extraBytes, unsigned class_createInstances(Class cls, size_t extraBytes,
id *results, unsigned num_requested) id *results, unsigned num_requested)
{ {

View File

@ -160,18 +160,6 @@
#include "objc-abi.h" #include "objc-abi.h"
#include <objc/message.h> #include <objc/message.h>
/* overriding the default object allocation and error handling routines */
OBJC_EXPORT id (*_alloc)(Class, size_t);
OBJC_EXPORT id (*_copy)(id, size_t);
OBJC_EXPORT id (*_realloc)(id, size_t);
OBJC_EXPORT id (*_dealloc)(id);
OBJC_EXPORT id (*_zoneAlloc)(Class, size_t, void *);
OBJC_EXPORT id (*_zoneRealloc)(id, size_t, void *);
OBJC_EXPORT id (*_zoneCopy)(id, size_t, void *);
/*********************************************************************** /***********************************************************************
* Information about multi-thread support: * Information about multi-thread support:
* *
@ -207,7 +195,9 @@ Class object_setClass(id obj, Class cls)
// weakly-referenced object has an un-+initialized isa. // weakly-referenced object has an un-+initialized isa.
// Unresolved future classes are not so protected. // Unresolved future classes are not so protected.
if (!cls->isFuture() && !cls->isInitialized()) { if (!cls->isFuture() && !cls->isInitialized()) {
_class_initialize(_class_getNonMetaClass(cls, nil)); // use lookUpImpOrNil to indirectly provoke +initialize
// to avoid duplicating the code to actually send +initialize
lookUpImpOrNil(nil, @selector(initialize), cls, LOOKUP_INITIALIZE);
} }
return obj->changeIsa(cls); return obj->changeIsa(cls);
@ -494,9 +484,9 @@ void object_cxxDestruct(id obj)
* return nil: construction failed because a C++ constructor threw an exception * return nil: construction failed because a C++ constructor threw an exception
**********************************************************************/ **********************************************************************/
id id
object_cxxConstructFromClass(id obj, Class cls) object_cxxConstructFromClass(id obj, Class cls, int flags)
{ {
assert(cls->hasCxxCtor()); // required for performance, not correctness ASSERT(cls->hasCxxCtor()); // required for performance, not correctness
id (*ctor)(id); id (*ctor)(id);
Class supercls; Class supercls;
@ -505,8 +495,8 @@ object_cxxConstructFromClass(id obj, Class cls)
// Call superclasses' ctors first, if any. // Call superclasses' ctors first, if any.
if (supercls && supercls->hasCxxCtor()) { if (supercls && supercls->hasCxxCtor()) {
bool ok = object_cxxConstructFromClass(obj, supercls); bool ok = object_cxxConstructFromClass(obj, supercls, flags);
if (!ok) return nil; // some superclass's ctor failed - give up if (slowpath(!ok)) return nil; // some superclass's ctor failed - give up
} }
// Find this class's ctor, if any. // Find this class's ctor, if any.
@ -518,11 +508,17 @@ object_cxxConstructFromClass(id obj, Class cls)
_objc_inform("CXX: calling C++ constructors for class %s", _objc_inform("CXX: calling C++ constructors for class %s",
cls->nameForLogging()); cls->nameForLogging());
} }
if ((*ctor)(obj)) return obj; // ctor called and succeeded - ok if (fastpath((*ctor)(obj))) return obj; // ctor called and succeeded - ok
supercls = cls->superclass; // this reload avoids a spill on the stack
// This class's ctor was called and failed. // This class's ctor was called and failed.
// Call superclasses's dtors to clean up. // Call superclasses's dtors to clean up.
if (supercls) object_cxxDestructFromClass(obj, supercls); if (supercls) object_cxxDestructFromClass(obj, supercls);
if (flags & OBJECT_CONSTRUCT_FREE_ONFAILURE) free(obj);
if (flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
return _objc_callBadAllocHandler(cls);
}
return nil; return nil;
} }
@ -576,117 +572,6 @@ void fixupCopiedIvars(id newObject, id oldObject)
} }
/***********************************************************************
* _class_resolveClassMethod
* Call +resolveClassMethod, looking for a method to be added to class cls.
* cls should be a metaclass.
* Does not check if the method already exists.
**********************************************************************/
static void _class_resolveClassMethod(Class cls, SEL sel, id inst)
{
assert(cls->isMetaClass());
if (! lookUpImpOrNil(cls, SEL_resolveClassMethod, inst,
NO/*initialize*/, YES/*cache*/, NO/*resolver*/))
{
// Resolver not implemented.
return;
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(_class_getNonMetaClass(cls, inst),
SEL_resolveClassMethod, sel);
// Cache the result (good or bad) so the resolver doesn't fire next time.
// +resolveClassMethod adds to self->ISA() a.k.a. cls
IMP imp = lookUpImpOrNil(cls, sel, inst,
NO/*initialize*/, YES/*cache*/, NO/*resolver*/);
if (resolved && PrintResolving) {
if (imp) {
_objc_inform("RESOLVE: method %c[%s %s] "
"dynamically resolved to %p",
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel), imp);
}
else {
// Method resolver didn't add anything?
_objc_inform("RESOLVE: +[%s resolveClassMethod:%s] returned YES"
", but no new implementation of %c[%s %s] was found",
cls->nameForLogging(), sel_getName(sel),
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel));
}
}
}
/***********************************************************************
* _class_resolveInstanceMethod
* Call +resolveInstanceMethod, looking for a method to be added to class cls.
* cls may be a metaclass or a non-meta class.
* Does not check if the method already exists.
**********************************************************************/
static void _class_resolveInstanceMethod(Class cls, SEL sel, id inst)
{
if (! lookUpImpOrNil(cls->ISA(), SEL_resolveInstanceMethod, cls,
NO/*initialize*/, YES/*cache*/, NO/*resolver*/))
{
// Resolver not implemented.
return;
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(cls, SEL_resolveInstanceMethod, sel);
// Cache the result (good or bad) so the resolver doesn't fire next time.
// +resolveInstanceMethod adds to self a.k.a. cls
IMP imp = lookUpImpOrNil(cls, sel, inst,
NO/*initialize*/, YES/*cache*/, NO/*resolver*/);
if (resolved && PrintResolving) {
if (imp) {
_objc_inform("RESOLVE: method %c[%s %s] "
"dynamically resolved to %p",
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel), imp);
}
else {
// Method resolver didn't add anything?
_objc_inform("RESOLVE: +[%s resolveInstanceMethod:%s] returned YES"
", but no new implementation of %c[%s %s] was found",
cls->nameForLogging(), sel_getName(sel),
cls->isMetaClass() ? '+' : '-',
cls->nameForLogging(), sel_getName(sel));
}
}
}
/***********************************************************************
* _class_resolveMethod
* Call +resolveClassMethod or +resolveInstanceMethod.
* Returns nothing; any result would be potentially out-of-date already.
* Does not check if the method already exists.
**********************************************************************/
void _class_resolveMethod(Class cls, SEL sel, id inst)
{
if (! cls->isMetaClass()) {
// try [cls resolveInstanceMethod:sel]
_class_resolveInstanceMethod(cls, sel, inst);
}
else {
// try [nonMetaClass resolveClassMethod:sel]
// and [cls resolveInstanceMethod:sel]
_class_resolveClassMethod(cls, sel, inst);
if (!lookUpImpOrNil(cls, sel, inst,
NO/*initialize*/, YES/*cache*/, NO/*resolver*/))
{
_class_resolveInstanceMethod(cls, sel, inst);
}
}
}
/*********************************************************************** /***********************************************************************
* class_getClassMethod. Return the class method for the specified * class_getClassMethod. Return the class method for the specified
@ -745,23 +630,18 @@ BOOL class_respondsToMethod(Class cls, SEL sel)
BOOL class_respondsToSelector(Class cls, SEL sel) BOOL class_respondsToSelector(Class cls, SEL sel)
{ {
return class_respondsToSelector_inst(cls, sel, nil); return class_respondsToSelector_inst(nil, sel, cls);
} }
// inst is an instance of cls or a subclass thereof, or nil if none is known. // inst is an instance of cls or a subclass thereof, or nil if none is known.
// Non-nil inst is faster in some cases. See lookUpImpOrForward() for details. // Non-nil inst is faster in some cases. See lookUpImpOrForward() for details.
bool class_respondsToSelector_inst(Class cls, SEL sel, id inst) NEVER_INLINE BOOL
class_respondsToSelector_inst(id inst, SEL sel, Class cls)
{ {
IMP imp;
if (!sel || !cls) return NO;
// Avoids +initialize because it historically did so. // Avoids +initialize because it historically did so.
// We're not returning a callable IMP anyway. // We're not returning a callable IMP anyway.
imp = lookUpImpOrNil(cls, sel, inst, return sel && cls && lookUpImpOrNil(inst, sel, cls, LOOKUP_RESOLVER);
NO/*initialize*/, YES/*cache*/, YES/*resolver*/);
return bool(imp);
} }
@ -788,8 +668,7 @@ IMP class_getMethodImplementation(Class cls, SEL sel)
if (!cls || !sel) return nil; if (!cls || !sel) return nil;
imp = lookUpImpOrNil(cls, sel, nil, imp = lookUpImpOrNil(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);
YES/*initialize*/, YES/*cache*/, YES/*resolver*/);
// Translate forwarding function to C-callable external version // Translate forwarding function to C-callable external version
if (!imp) { if (!imp) {
@ -816,6 +695,9 @@ IMP class_getMethodImplementation_stret(Class cls, SEL sel)
/*********************************************************************** /***********************************************************************
* instrumentObjcMessageSends * instrumentObjcMessageSends
**********************************************************************/ **********************************************************************/
// Define this everywhere even if it isn't used to simplify fork() safety code.
spinlock_t objcMsgLogLock;
#if !SUPPORT_MESSAGE_LOGGING #if !SUPPORT_MESSAGE_LOGGING
void instrumentObjcMessageSends(BOOL flag) void instrumentObjcMessageSends(BOOL flag)
@ -826,7 +708,6 @@ void instrumentObjcMessageSends(BOOL flag)
bool objcMsgLogEnabled = false; bool objcMsgLogEnabled = false;
static int objcMsgLogFD = -1; static int objcMsgLogFD = -1;
static spinlock_t objcMsgLogLock;
bool logMessageSend(bool isClassMethod, bool logMessageSend(bool isClassMethod,
const char *objectsClass, const char *objectsClass,
@ -946,26 +827,6 @@ char * method_copyArgumentType(Method m, unsigned int index)
return encoding_copyArgumentType(method_getTypeEncoding(m), index); return encoding_copyArgumentType(method_getTypeEncoding(m), index);
} }
/***********************************************************************
* _objc_constructOrFree
* Call C++ constructors, and free() if they fail.
* bytes->isa must already be set.
* cls must have cxx constructors.
* Returns the object, or nil.
**********************************************************************/
id
_objc_constructOrFree(id bytes, Class cls)
{
assert(cls->hasCxxCtor()); // for performance, not correctness
id obj = object_cxxConstructFromClass(bytes, cls);
if (!obj) free(bytes);
return obj;
}
/*********************************************************************** /***********************************************************************
* _class_createInstancesFromZone * _class_createInstancesFromZone
* Batch-allocating version of _class_createInstanceFromZone. * Batch-allocating version of _class_createInstanceFromZone.
@ -996,8 +857,10 @@ _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone,
for (unsigned i = 0; i < num_allocated; i++) { for (unsigned i = 0; i < num_allocated; i++) {
id obj = results[i]; id obj = results[i];
obj->initIsa(cls); // fixme allow nonpointer obj->initIsa(cls); // fixme allow nonpointer
if (ctor) obj = _objc_constructOrFree(obj, cls); if (ctor) {
obj = object_cxxConstructFromClass(obj, cls,
OBJECT_CONSTRUCT_FREE_ONFAILURE);
}
if (obj) { if (obj) {
results[i-shift] = obj; results[i-shift] = obj;
} else { } else {
@ -1043,11 +906,11 @@ copyPropertyAttributeString(const objc_property_attribute_t *attrs,
#if DEBUG #if DEBUG
// debug build: sanitize input // debug build: sanitize input
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
assert(attrs[i].name); ASSERT(attrs[i].name);
assert(strlen(attrs[i].name) > 0); ASSERT(strlen(attrs[i].name) > 0);
assert(! strchr(attrs[i].name, ',')); ASSERT(! strchr(attrs[i].name, ','));
assert(! strchr(attrs[i].name, '"')); ASSERT(! strchr(attrs[i].name, '"'));
if (attrs[i].value) assert(! strchr(attrs[i].value, ',')); if (attrs[i].value) ASSERT(! strchr(attrs[i].value, ','));
} }
#endif #endif
@ -1133,8 +996,8 @@ iteratePropertyAttributes(const char *attrs,
const char *nameStart; const char *nameStart;
const char *nameEnd; const char *nameEnd;
assert(start < end); ASSERT(start < end);
assert(*start); ASSERT(*start);
if (*start != '\"') { if (*start != '\"') {
// single-char short name // single-char short name
nameStart = start; nameStart = start;
@ -1154,7 +1017,7 @@ iteratePropertyAttributes(const char *attrs,
const char *valueStart; const char *valueStart;
const char *valueEnd; const char *valueEnd;
assert(start <= end); ASSERT(start <= end);
valueStart = start; valueStart = start;
valueEnd = end; valueEnd = end;
@ -1231,8 +1094,8 @@ copyPropertyAttributeList(const char *attrs, unsigned int *outCount)
attrcount = iteratePropertyAttributes(attrs, copyOneAttribute, &ra, &rs); attrcount = iteratePropertyAttributes(attrs, copyOneAttribute, &ra, &rs);
assert((uint8_t *)(ra+1) <= (uint8_t *)result+size); ASSERT((uint8_t *)(ra+1) <= (uint8_t *)result+size);
assert((uint8_t *)rs <= (uint8_t *)result+size); ASSERT((uint8_t *)rs <= (uint8_t *)result+size);
if (attrcount == 0) { if (attrcount == 0) {
free(result); free(result);

View File

@ -26,6 +26,15 @@
#include <TargetConditionals.h> #include <TargetConditionals.h>
// Define __OBJC2__ for the benefit of our asm files.
#ifndef __OBJC2__
# if TARGET_OS_OSX && !TARGET_OS_IOSMAC && __i386__
// old ABI
# else
# define __OBJC2__ 1
# endif
#endif
// Avoid the !NDEBUG double negative. // Avoid the !NDEBUG double negative.
#if !NDEBUG #if !NDEBUG
# define DEBUG 1 # define DEBUG 1
@ -42,7 +51,7 @@
#endif #endif
// Define SUPPORT_ZONES=1 to enable malloc zone support in NXHashTable. // Define SUPPORT_ZONES=1 to enable malloc zone support in NXHashTable.
#if !TARGET_OS_OSX #if !(TARGET_OS_OSX || TARGET_OS_IOSMAC)
# define SUPPORT_ZONES 0 # define SUPPORT_ZONES 0
#else #else
# define SUPPORT_ZONES 1 # define SUPPORT_ZONES 1
@ -56,7 +65,7 @@
#endif #endif
// Define SUPPORT_PREOPT=1 to enable dyld shared cache optimizations // Define SUPPORT_PREOPT=1 to enable dyld shared cache optimizations
#if TARGET_OS_WIN32 || TARGET_OS_SIMULATOR #if TARGET_OS_WIN32
# define SUPPORT_PREOPT 0 # define SUPPORT_PREOPT 0
#else #else
# define SUPPORT_PREOPT 1 # define SUPPORT_PREOPT 1
@ -73,7 +82,7 @@
// Define SUPPORT_MSB_TAGGED_POINTERS to use the MSB // Define SUPPORT_MSB_TAGGED_POINTERS to use the MSB
// as the tagged pointer marker instead of the LSB. // as the tagged pointer marker instead of the LSB.
// Be sure to edit tagged pointer SPI in objc-internal.h as well. // Be sure to edit tagged pointer SPI in objc-internal.h as well.
#if !SUPPORT_TAGGED_POINTERS || !TARGET_OS_IPHONE #if !SUPPORT_TAGGED_POINTERS || (TARGET_OS_OSX || TARGET_OS_IOSMAC)
# define SUPPORT_MSB_TAGGED_POINTERS 0 # define SUPPORT_MSB_TAGGED_POINTERS 0
#else #else
# define SUPPORT_MSB_TAGGED_POINTERS 1 # define SUPPORT_MSB_TAGGED_POINTERS 1
@ -83,7 +92,7 @@
// field as an index into a class table. // field as an index into a class table.
// Note, keep this in sync with any .s files which also define it. // Note, keep this in sync with any .s files which also define it.
// Be sure to edit objc-abi.h as well. // Be sure to edit objc-abi.h as well.
#if __ARM_ARCH_7K__ >= 2 #if __ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__)
# define SUPPORT_INDEXED_ISA 1 # define SUPPORT_INDEXED_ISA 1
#else #else
# define SUPPORT_INDEXED_ISA 0 # define SUPPORT_INDEXED_ISA 0
@ -91,7 +100,8 @@
// Define SUPPORT_PACKED_ISA=1 on platforms that store the class in the isa // Define SUPPORT_PACKED_ISA=1 on platforms that store the class in the isa
// field as a maskable pointer with other data around it. // field as a maskable pointer with other data around it.
#if (!__LP64__ || TARGET_OS_WIN32 || TARGET_OS_SIMULATOR) #if (!__LP64__ || TARGET_OS_WIN32 || \
(TARGET_OS_SIMULATOR && !TARGET_OS_IOSMAC))
# define SUPPORT_PACKED_ISA 0 # define SUPPORT_PACKED_ISA 0
#else #else
# define SUPPORT_PACKED_ISA 1 # define SUPPORT_PACKED_ISA 1
@ -125,7 +135,7 @@
// Define SUPPORT_ALT_HANDLERS if you're using zero-cost exceptions // Define SUPPORT_ALT_HANDLERS if you're using zero-cost exceptions
// but also need to support AppKit's alt-handler scheme // but also need to support AppKit's alt-handler scheme
// Be sure to edit objc-exception.h as well (objc_add/removeExceptionHandler) // Be sure to edit objc-exception.h as well (objc_add/removeExceptionHandler)
#if !SUPPORT_ZEROCOST_EXCEPTIONS || TARGET_OS_IPHONE || TARGET_OS_EMBEDDED #if !SUPPORT_ZEROCOST_EXCEPTIONS || !TARGET_OS_OSX
# define SUPPORT_ALT_HANDLERS 0 # define SUPPORT_ALT_HANDLERS 0
#else #else
# define SUPPORT_ALT_HANDLERS 1 # define SUPPORT_ALT_HANDLERS 1
@ -146,17 +156,18 @@
#endif #endif
// Define SUPPORT_MESSAGE_LOGGING to enable NSObjCMessageLoggingEnabled // Define SUPPORT_MESSAGE_LOGGING to enable NSObjCMessageLoggingEnabled
#if TARGET_OS_WIN32 || TARGET_OS_EMBEDDED #if !TARGET_OS_OSX
# define SUPPORT_MESSAGE_LOGGING 0 # define SUPPORT_MESSAGE_LOGGING 0
#else #else
# define SUPPORT_MESSAGE_LOGGING 1 # define SUPPORT_MESSAGE_LOGGING 1
#endif #endif
// Define SUPPORT_QOS_HACK to work around deadlocks due to QoS bugs. // Define HAVE_TASK_RESTARTABLE_RANGES to enable usage of
#if !__OBJC2__ || TARGET_OS_WIN32 || DARLING // task_restartable_ranges_synchronize()
# define SUPPORT_QOS_HACK 0 #if TARGET_OS_SIMULATOR || defined(__i386__) || defined(__arm__) || !TARGET_OS_MAC
# define HAVE_TASK_RESTARTABLE_RANGES 0
#else #else
# define SUPPORT_QOS_HACK 1 # define HAVE_TASK_RESTARTABLE_RANGES 1
#endif #endif
// OBJC_INSTRUMENTED controls whether message dispatching is dynamically // OBJC_INSTRUMENTED controls whether message dispatching is dynamically
@ -167,4 +178,43 @@
// because objc-class.h is public and objc-config.h is not. // because objc-class.h is public and objc-config.h is not.
//#define OBJC_INSTRUMENTED //#define OBJC_INSTRUMENTED
// In __OBJC2__, the runtimeLock is a mutex always held
// hence the cache lock is redundant and can be elided.
//
// If the runtime lock ever becomes a rwlock again,
// the cache lock would need to be used again
#if __OBJC2__
#define CONFIG_USE_CACHE_LOCK 0
#else
#define CONFIG_USE_CACHE_LOCK 1
#endif
// Determine how the method cache stores IMPs.
#define CACHE_IMP_ENCODING_NONE 1 // Method cache contains raw IMP.
#define CACHE_IMP_ENCODING_ISA_XOR 2 // Method cache contains ISA ^ IMP.
#define CACHE_IMP_ENCODING_PTRAUTH 3 // Method cache contains ptrauth'd IMP.
#if __PTRAUTH_INTRINSICS__
// Always use ptrauth when it's supported.
#define CACHE_IMP_ENCODING CACHE_IMP_ENCODING_PTRAUTH
#elif defined(__arm__)
// 32-bit ARM uses no encoding.
#define CACHE_IMP_ENCODING CACHE_IMP_ENCODING_NONE
#else
// Everything else uses ISA ^ IMP.
#define CACHE_IMP_ENCODING CACHE_IMP_ENCODING_ISA_XOR
#endif
#define CACHE_MASK_STORAGE_OUTLINED 1
#define CACHE_MASK_STORAGE_HIGH_16 2
#define CACHE_MASK_STORAGE_LOW_4 3
#if defined(__arm64__) && __LP64__
#define CACHE_MASK_STORAGE CACHE_MASK_STORAGE_HIGH_16
#elif defined(__arm64__) && !__LP64__
#define CACHE_MASK_STORAGE CACHE_MASK_STORAGE_LOW_4
#else
#define CACHE_MASK_STORAGE CACHE_MASK_STORAGE_OUTLINED
#endif
#endif #endif

View File

@ -22,8 +22,9 @@ OPTION( PrintAltHandlers, OBJC_PRINT_ALT_HANDLERS, "log processi
OPTION( PrintReplacedMethods, OBJC_PRINT_REPLACED_METHODS, "log methods replaced by category implementations") OPTION( PrintReplacedMethods, OBJC_PRINT_REPLACED_METHODS, "log methods replaced by category implementations")
OPTION( PrintDeprecation, OBJC_PRINT_DEPRECATION_WARNINGS, "warn about calls to deprecated runtime functions") OPTION( PrintDeprecation, OBJC_PRINT_DEPRECATION_WARNINGS, "warn about calls to deprecated runtime functions")
OPTION( PrintPoolHiwat, OBJC_PRINT_POOL_HIGHWATER, "log high-water marks for autorelease pools") OPTION( PrintPoolHiwat, OBJC_PRINT_POOL_HIGHWATER, "log high-water marks for autorelease pools")
OPTION( PrintCustomRR, OBJC_PRINT_CUSTOM_RR, "log classes with un-optimized custom retain/release methods") OPTION( PrintCustomCore, OBJC_PRINT_CUSTOM_CORE, "log classes with custom core methods")
OPTION( PrintCustomAWZ, OBJC_PRINT_CUSTOM_AWZ, "log classes with un-optimized custom allocWithZone methods") OPTION( PrintCustomRR, OBJC_PRINT_CUSTOM_RR, "log classes with custom retain/release methods")
OPTION( PrintCustomAWZ, OBJC_PRINT_CUSTOM_AWZ, "log classes with custom allocWithZone methods")
OPTION( PrintRawIsa, OBJC_PRINT_RAW_ISA, "log classes that require raw pointer isa fields") OPTION( PrintRawIsa, OBJC_PRINT_RAW_ISA, "log classes that require raw pointer isa fields")
OPTION( DebugUnload, OBJC_DEBUG_UNLOAD, "warn about poorly-behaving bundles when unloaded") OPTION( DebugUnload, OBJC_DEBUG_UNLOAD, "warn about poorly-behaving bundles when unloaded")
@ -39,4 +40,6 @@ OPTION( DebugDontCrash, OBJC_DEBUG_DONT_CRASH, "halt the pro
OPTION( DisableVtables, OBJC_DISABLE_VTABLES, "disable vtable dispatch") OPTION( DisableVtables, OBJC_DISABLE_VTABLES, "disable vtable dispatch")
OPTION( DisablePreopt, OBJC_DISABLE_PREOPTIMIZATION, "disable preoptimization courtesy of dyld shared cache") OPTION( DisablePreopt, OBJC_DISABLE_PREOPTIMIZATION, "disable preoptimization courtesy of dyld shared cache")
OPTION( DisableTaggedPointers, OBJC_DISABLE_TAGGED_POINTERS, "disable tagged pointer optimization of NSNumber et al.") OPTION( DisableTaggedPointers, OBJC_DISABLE_TAGGED_POINTERS, "disable tagged pointer optimization of NSNumber et al.")
OPTION( DisableTaggedPointerObfuscation, OBJC_DISABLE_TAG_OBFUSCATION, "disable obfuscation of tagged pointers")
OPTION( DisableNonpointerIsa, OBJC_DISABLE_NONPOINTER_ISA, "disable non-pointer isa fields") OPTION( DisableNonpointerIsa, OBJC_DISABLE_NONPOINTER_ISA, "disable non-pointer isa fields")
OPTION( DisableInitializeForkSafety, OBJC_DISABLE_INITIALIZE_FORK_SAFETY, "disable safety checks for +initialize after fork")

View File

@ -76,8 +76,6 @@ void _objc_error(id rcv, const char *fmt, va_list args)
#include <_simple.h> #include <_simple.h>
OBJC_EXPORT void (*_error)(id, const char *, va_list);
// Return true if c is a UTF8 continuation byte // Return true if c is a UTF8 continuation byte
static bool isUTF8Continuation(char c) static bool isUTF8Continuation(char c)
{ {
@ -85,7 +83,7 @@ static bool isUTF8Continuation(char c)
} }
// Add "message" to any forthcoming crash log. // Add "message" to any forthcoming crash log.
static mutex_t crashlog_lock; mutex_t crashlog_lock;
static void _objc_crashlog(const char *message) static void _objc_crashlog(const char *message)
{ {
char *newmsg; char *newmsg;
@ -160,7 +158,7 @@ static void _objc_syslog(const char *message)
#if !__OBJC2__ #if !__OBJC2__
// used by ExceptionHandling.framework // used by ExceptionHandling.framework
#endif #endif
__attribute__((noreturn)) __attribute__((noreturn, cold))
void _objc_error(id self, const char *fmt, va_list ap) void _objc_error(id self, const char *fmt, va_list ap)
{ {
char *buf; char *buf;
@ -183,7 +181,7 @@ void __objc_error(id rcv, const char *fmt, ...)
va_end(vp); va_end(vp);
} }
static __attribute__((noreturn)) static __attribute__((noreturn, cold))
void _objc_fatalv(uint64_t reason, uint64_t flags, const char *fmt, va_list ap) void _objc_fatalv(uint64_t reason, uint64_t flags, const char *fmt, va_list ap)
{ {
char *buf1; char *buf1;
@ -200,8 +198,8 @@ void _objc_fatalv(uint64_t reason, uint64_t flags, const char *fmt, va_list ap)
_Exit(1); _Exit(1);
} }
else { else {
// abort_with_reason(OS_REASON_OBJC, reason, buf1, flags); _objc_crashlog(buf1);
abort(); abort_with_reason(OS_REASON_OBJC, reason, buf1, flags);
} }
} }
@ -218,7 +216,7 @@ void _objc_fatal(const char *fmt, ...)
va_list ap; va_list ap;
va_start(ap,fmt); va_start(ap,fmt);
_objc_fatalv(OBJC_EXIT_REASON_UNSPECIFIED, _objc_fatalv(OBJC_EXIT_REASON_UNSPECIFIED,
/*OS_REASON_FLAG_ONE_TIME_FAILURE*/ 0, OS_REASON_FLAG_ONE_TIME_FAILURE,
fmt, ap); fmt, ap);
} }

View File

@ -31,51 +31,57 @@
// compiler reserves a setjmp buffer + 4 words as localExceptionData // compiler reserves a setjmp buffer + 4 words as localExceptionData
OBJC_EXPORT void objc_exception_throw(id exception) OBJC_EXPORT void
__OSX_AVAILABLE(10.3) objc_exception_throw(id _Nonnull exception)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE(10.3);
OBJC_EXPORT void objc_exception_try_enter(void *localExceptionData)
__OSX_AVAILABLE(10.3) OBJC_EXPORT void
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; objc_exception_try_enter(void * _Nonnull localExceptionData)
OBJC_EXPORT void objc_exception_try_exit(void *localExceptionData) OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE(10.3);
__OSX_AVAILABLE(10.3)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_EXPORT void
OBJC_EXPORT id objc_exception_extract(void *localExceptionData) objc_exception_try_exit(void * _Nonnull localExceptionData)
__OSX_AVAILABLE(10.3) OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE(10.3);
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT int objc_exception_match(Class exceptionClass, id exception) OBJC_EXPORT id _Nonnull
__OSX_AVAILABLE(10.3) objc_exception_extract(void * _Nonnull localExceptionData)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE(10.3);
OBJC_EXPORT int objc_exception_match(Class _Nonnull exceptionClass,
id _Nonnull exception)
OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE(10.3);
typedef struct { typedef struct {
int version; int version;
void (*throw_exc)(id); // version 0 void (* _Nonnull throw_exc)(id _Nonnull); // version 0
void (*try_enter)(void *); // version 0 void (* _Nonnull try_enter)(void * _Nonnull); // version 0
void (*try_exit)(void *); // version 0 void (* _Nonnull try_exit)(void * _Nonnull); // version 0
id (*extract)(void *); // version 0 id _Nonnull (* _Nonnull extract)(void * _Nonnull); // version 0
int (*match)(Class, id); // version 0 int (* _Nonnull match)(Class _Nonnull, id _Nonnull); // version 0
} objc_exception_functions_t; } objc_exception_functions_t;
// get table; version tells how many // get table; version tells how many
OBJC_EXPORT void objc_exception_get_functions(objc_exception_functions_t *table) OBJC_EXPORT void
__OSX_AVAILABLE(10.3) objc_exception_get_functions(objc_exception_functions_t * _Nullable table)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE(10.3);
// set table // set table
OBJC_EXPORT void objc_exception_set_functions(objc_exception_functions_t *table) OBJC_EXPORT void
__OSX_AVAILABLE(10.3) objc_exception_set_functions(objc_exception_functions_t * _Nullable table)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE(10.3);
// !__OBJC2__ // !__OBJC2__
#else #else
// __OBJC2__ // __OBJC2__
typedef id (*objc_exception_preprocessor)(id exception); typedef id _Nonnull (*objc_exception_preprocessor)(id _Nonnull exception);
typedef int (*objc_exception_matcher)(Class catch_type, id exception); typedef int (*objc_exception_matcher)(Class _Nonnull catch_type,
typedef void (*objc_uncaught_exception_handler)(id exception); id _Nonnull exception);
typedef void (*objc_exception_handler)(id unused, void *context); typedef void (*objc_uncaught_exception_handler)(id _Null_unspecified /* _Nonnull */ exception);
typedef void (*objc_exception_handler)(id _Nullable unused,
void * _Nullable context);
/** /**
* Throw a runtime exception. This function is inserted by the compiler * Throw a runtime exception. This function is inserted by the compiler
@ -83,31 +89,47 @@ typedef void (*objc_exception_handler)(id unused, void *context);
* *
* @param exception The exception to be thrown. * @param exception The exception to be thrown.
*/ */
OBJC_EXPORT void objc_exception_throw(id exception) OBJC_EXPORT void
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); objc_exception_throw(id _Nonnull exception)
OBJC_EXPORT void objc_exception_rethrow(void) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT id objc_begin_catch(void *exc_buf)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT void objc_end_catch(void)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT void objc_terminate(void)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
OBJC_EXPORT objc_exception_preprocessor objc_setExceptionPreprocessor(objc_exception_preprocessor fn) OBJC_EXPORT void
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); objc_exception_rethrow(void)
OBJC_EXPORT objc_exception_matcher objc_setExceptionMatcher(objc_exception_matcher fn) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT objc_uncaught_exception_handler objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler fn) OBJC_EXPORT id _Nonnull
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0); objc_begin_catch(void * _Nonnull exc_buf)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_end_catch(void)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void
objc_terminate(void)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
OBJC_EXPORT objc_exception_preprocessor _Nonnull
objc_setExceptionPreprocessor(objc_exception_preprocessor _Nonnull fn)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT objc_exception_matcher _Nonnull
objc_setExceptionMatcher(objc_exception_matcher _Nonnull fn)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT objc_uncaught_exception_handler _Nonnull
objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler _Nonnull fn)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
// Not for iOS. // Not for iOS.
OBJC_EXPORT uintptr_t objc_addExceptionHandler(objc_exception_handler fn, void *context) OBJC_EXPORT uintptr_t
__OSX_AVAILABLE(10.5) objc_addExceptionHandler(objc_exception_handler _Nonnull fn,
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; void * _Nullable context)
OBJC_EXPORT void objc_removeExceptionHandler(uintptr_t token) OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE(10.5);
__OSX_AVAILABLE(10.5)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_EXPORT void
objc_removeExceptionHandler(uintptr_t token)
OBJC_OSX_AVAILABLE_OTHERS_UNAVAILABLE(10.5);
// __OBJC2__ // __OBJC2__
#endif #endif

View File

@ -133,8 +133,8 @@ typedef struct _threadChain {
static ThreadChainLink_t ThreadChainLink; static ThreadChainLink_t ThreadChainLink;
static ThreadChainLink_t *getChainLink() { static ThreadChainLink_t *getChainLink() {
// follow links until thread_self() found (someday) XXX // follow links until objc_thread_self() found (someday) XXX
objc_thread_t self = thread_self(); objc_thread_t self = objc_thread_self();
ThreadChainLink_t *walker = &ThreadChainLink; ThreadChainLink_t *walker = &ThreadChainLink;
while (walker->perThreadID != self) { while (walker->perThreadID != self) {
if (walker->next != nil) { if (walker->next != nil) {
@ -238,6 +238,7 @@ void _destroyAltHandlerList(struct alt_handler_list *list)
**********************************************************************/ **********************************************************************/
#include "objc-private.h" #include "objc-private.h"
#include <objc/objc-abi.h>
#include <objc/objc-exception.h> #include <objc/objc-exception.h>
#include <objc/NSObject.h> #include <objc/NSObject.h>
#include <execinfo.h> #include <execinfo.h>
@ -310,7 +311,7 @@ CXX_PERSONALITY(int version,
struct objc_typeinfo { struct objc_typeinfo {
// Position of vtable and name fields must match C++ typeinfo object // Position of vtable and name fields must match C++ typeinfo object
const void **vtable; // always objc_ehtype_vtable+2 const void ** __ptrauth_cxx_vtable_pointer vtable; // objc_ehtype_vtable+2
const char *name; // c++ typeinfo string const char *name; // c++ typeinfo string
Class cls_unremapped; Class cls_unremapped;
@ -321,54 +322,97 @@ struct objc_exception {
struct objc_typeinfo tinfo; struct objc_typeinfo tinfo;
}; };
extern "C" {
static void _objc_exception_noop(void) { } __attribute__((used))
static bool _objc_exception_false(void) { return 0; } void _objc_exception_noop(void) { }
// static bool _objc_exception_true(void) { return 1; } __attribute__((used))
static void _objc_exception_abort1(void) { bool _objc_exception_false(void) { return 0; }
// bool _objc_exception_true(void) { return 1; }
__attribute__((used))
void _objc_exception_abort1(void) {
_objc_fatal("unexpected call into objc exception typeinfo vtable %d", 1); _objc_fatal("unexpected call into objc exception typeinfo vtable %d", 1);
} }
static void _objc_exception_abort2(void) { __attribute__((used))
void _objc_exception_abort2(void) {
_objc_fatal("unexpected call into objc exception typeinfo vtable %d", 2); _objc_fatal("unexpected call into objc exception typeinfo vtable %d", 2);
} }
static void _objc_exception_abort3(void) { __attribute__((used))
void _objc_exception_abort3(void) {
_objc_fatal("unexpected call into objc exception typeinfo vtable %d", 3); _objc_fatal("unexpected call into objc exception typeinfo vtable %d", 3);
} }
static void _objc_exception_abort4(void) { __attribute__((used))
void _objc_exception_abort4(void) {
_objc_fatal("unexpected call into objc exception typeinfo vtable %d", 4); _objc_fatal("unexpected call into objc exception typeinfo vtable %d", 4);
} }
__attribute__((used))
bool _objc_exception_do_catch(struct objc_typeinfo *catch_tinfo,
struct objc_typeinfo *throw_tinfo,
void **throw_obj_p,
unsigned outer);
}
static bool _objc_exception_do_catch(struct objc_typeinfo *catch_tinfo, // C++ pointers to vtables are signed with no extra data.
struct objc_typeinfo *throw_tinfo, // C++ vtable entries are signed with a number derived from the function name.
void **throw_obj_p, // For this fake vtable, we hardcode number as deciphered from the
unsigned outer); // assembly output during libc++abi's build.
#if __has_feature(ptrauth_calls)
# define VTABLE_PTR_AUTH "@AUTH(da, 0)"
# define VTABLE_ENTRY_AUTH(x) "@AUTH(ia," #x ",addr)"
#else
# define VTABLE_PTR_AUTH ""
# define VTABLE_ENTRY_AUTH(x) ""
#endif
// forward declaration #if __LP64__
OBJC_EXPORT struct objc_typeinfo OBJC_EHTYPE_id; # define PTR ".quad "
# define TWOPTRSIZE "16"
#else
# define PTR ".long "
# define TWOPTRSIZE "8"
#endif
OBJC_EXPORT // Hand-built vtable for objc exception typeinfo.
const void *objc_ehtype_vtable[] = { // "OLD" is GNU libcpp, "NEW" is libc++abi.
nil, // typeinfo's vtable? - fixme
(void*)&OBJC_EHTYPE_id, // typeinfo's typeinfo - hack
(void*)_objc_exception_noop, // in-place destructor?
(void*)_objc_exception_noop, // destructor?
(void*)_objc_exception_false, // OLD __is_pointer_p
(void*)_objc_exception_false, // OLD __is_function_p
(void*)_objc_exception_do_catch, // OLD __do_catch, NEW can_catch
(void*)_objc_exception_false, // OLD __do_upcast, NEW search_above_dst
(void*)_objc_exception_false, // NEW search_below_dst
(void*)_objc_exception_abort1, // paranoia: blow up if libc++abi
(void*)_objc_exception_abort2, // adds something new
(void*)_objc_exception_abort3,
(void*)_objc_exception_abort4,
};
OBJC_EXPORT asm(
struct objc_typeinfo OBJC_EHTYPE_id = { "\n .cstring"
objc_ehtype_vtable+2, "\n l_.id_str: .asciz \"id\""
"id",
nil "\n .section __DATA,__const"
}; "\n .globl _OBJC_EHTYPE_id"
"\n .globl _objc_ehtype_vtable"
"\n .p2align 4"
"\n _OBJC_EHTYPE_id:"
"\n " PTR "(_objc_ehtype_vtable+" TWOPTRSIZE ") " VTABLE_PTR_AUTH
"\n " PTR "l_.id_str"
"\n " PTR "0"
"\n _objc_ehtype_vtable:"
"\n " PTR "0"
// typeinfo's typeinfo - fixme hack
"\n " PTR "_OBJC_EHTYPE_id"
// destructor and in-place destructor
"\n " PTR "__objc_exception_noop" VTABLE_ENTRY_AUTH(52634)
"\n " PTR "__objc_exception_noop" VTABLE_ENTRY_AUTH(10344)
// OLD __is_pointer_p
"\n " PTR "__objc_exception_noop" VTABLE_ENTRY_AUTH(6889)
// OLD __is_function_p
"\n " PTR "__objc_exception_noop" VTABLE_ENTRY_AUTH(23080)
// OLD __do_catch, NEW can_catch
"\n " PTR "__objc_exception_do_catch" VTABLE_ENTRY_AUTH(27434)
// OLD __do_upcast, NEW search_above_dst
"\n " PTR "__objc_exception_false" VTABLE_ENTRY_AUTH(48481)
// NEW search_below_dst
"\n " PTR "__objc_exception_false" VTABLE_ENTRY_AUTH(41165)
// NEW has_unambiguous_public_base (fixme need this?)
"\n " PTR "__objc_exception_abort1" VTABLE_ENTRY_AUTH(14357)
// paranoia: die if libcxxabi adds anything else
"\n " PTR "__objc_exception_abort2"
"\n " PTR "__objc_exception_abort3"
"\n " PTR "__objc_exception_abort4"
);
@ -583,10 +627,10 @@ void objc_end_catch(void)
// `outer` is not passed by the new libcxxabi // `outer` is not passed by the new libcxxabi
static bool _objc_exception_do_catch(struct objc_typeinfo *catch_tinfo, bool _objc_exception_do_catch(struct objc_typeinfo *catch_tinfo,
struct objc_typeinfo *throw_tinfo, struct objc_typeinfo *throw_tinfo,
void **throw_obj_p, void **throw_obj_p,
unsigned outer UNAVAILABLE_ATTRIBUTE) unsigned outer UNAVAILABLE_ATTRIBUTE)
{ {
id exception; id exception;
@ -1059,7 +1103,6 @@ struct alt_handler_list {
struct alt_handler_list *next_DEBUGONLY; struct alt_handler_list *next_DEBUGONLY;
}; };
static mutex_t DebugLock;
static struct alt_handler_list *DebugLists; static struct alt_handler_list *DebugLists;
static uintptr_t DebugCounter; static uintptr_t DebugCounter;
@ -1080,7 +1123,7 @@ fetch_handler_list(bool create)
if (DebugAltHandlers) { if (DebugAltHandlers) {
// Save this list so the debug code can find it from other threads // Save this list so the debug code can find it from other threads
mutex_locker_t lock(DebugLock); mutex_locker_t lock(AltHandlerDebugLock);
list->next_DEBUGONLY = DebugLists; list->next_DEBUGONLY = DebugLists;
DebugLists = list; DebugLists = list;
} }
@ -1095,7 +1138,7 @@ void _destroyAltHandlerList(struct alt_handler_list *list)
if (list) { if (list) {
if (DebugAltHandlers) { if (DebugAltHandlers) {
// Detach from the list-of-lists. // Detach from the list-of-lists.
mutex_locker_t lock(DebugLock); mutex_locker_t lock(AltHandlerDebugLock);
struct alt_handler_list **listp = &DebugLists; struct alt_handler_list **listp = &DebugLists;
while (*listp && *listp != list) listp = &(*listp)->next_DEBUGONLY; while (*listp && *listp != list) listp = &(*listp)->next_DEBUGONLY;
if (*listp) *listp = (*listp)->next_DEBUGONLY; if (*listp) *listp = (*listp)->next_DEBUGONLY;
@ -1160,7 +1203,7 @@ uintptr_t objc_addExceptionHandler(objc_exception_handler fn, void *context)
if (DebugAltHandlers) { if (DebugAltHandlers) {
// Record backtrace in case this handler is misused later. // Record backtrace in case this handler is misused later.
mutex_locker_t lock(DebugLock); mutex_locker_t lock(AltHandlerDebugLock);
token = DebugCounter++; token = DebugCounter++;
if (token == 0) token = DebugCounter++; if (token == 0) token = DebugCounter++;
@ -1172,9 +1215,9 @@ uintptr_t objc_addExceptionHandler(objc_exception_handler fn, void *context)
bzero(data->debug, sizeof(*data->debug)); bzero(data->debug, sizeof(*data->debug));
} }
pthread_getname_np(pthread_self(), data->debug->thread, THREADNAME_COUNT); pthread_getname_np(objc_thread_self(), data->debug->thread, THREADNAME_COUNT);
strlcpy(data->debug->queue, strlcpy(data->debug->queue,
dispatch_queue_get_label(dispatch_get_current_queue()), dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL),
THREADNAME_COUNT); THREADNAME_COUNT);
data->debug->backtraceSize = data->debug->backtraceSize =
backtrace(data->debug->backtrace, BACKTRACE_COUNT); backtrace(data->debug->backtrace, BACKTRACE_COUNT);
@ -1274,7 +1317,7 @@ void alt_handler_error(uintptr_t token)
"or break in objc_alt_handler_error() to debug."); "or break in objc_alt_handler_error() to debug.");
if (DebugAltHandlers) { if (DebugAltHandlers) {
DebugLock.lock(); AltHandlerDebugLock.lock();
// Search other threads' alt handler lists for this handler. // Search other threads' alt handler lists for this handler.
struct alt_handler_list *list; struct alt_handler_list *list;
@ -1314,7 +1357,7 @@ void alt_handler_error(uintptr_t token)
} }
} }
done: done:
DebugLock.unlock(); AltHandlerDebugLock.unlock();
} }
@ -1394,3 +1437,6 @@ void exception_init(void)
// __OBJC2__ // __OBJC2__
#endif #endif
// Define this everywhere even if it isn't used, to simplify fork() safety code
mutex_t AltHandlerDebugLock;

View File

@ -40,8 +40,8 @@ extern struct old_protocol **_getObjcProtocols(const header_info *hi, size_t *np
extern Class *_getObjcClassRefs(const header_info *hi, size_t *nclasses); extern Class *_getObjcClassRefs(const header_info *hi, size_t *nclasses);
extern const char *_getObjcClassNames(const header_info *hi, size_t *size); extern const char *_getObjcClassNames(const header_info *hi, size_t *size);
using Initializer = void(*)(void); using UnsignedInitializer = void(*)(void);
extern Initializer* getLibobjcInitializers(const headerType *mhdr, size_t *count); extern UnsignedInitializer* getLibobjcInitializers(const headerType *mhdr, size_t *count);
__END_DECLS __END_DECLS

View File

@ -88,7 +88,7 @@ GETSECT(_getObjcSelectorRefs, SEL, "__OBJC", "__message_refs");
GETSECT(_getObjcClassRefs, Class, "__OBJC", "__cls_refs"); GETSECT(_getObjcClassRefs, Class, "__OBJC", "__cls_refs");
GETSECT(_getObjcClassNames, const char, "__OBJC", "__class_names"); GETSECT(_getObjcClassNames, const char, "__OBJC", "__class_names");
// __OBJC,__class_names section only emitted by CodeWarrior rdar://4951638 // __OBJC,__class_names section only emitted by CodeWarrior rdar://4951638
GETSECT(getLibobjcInitializers, Initializer, "__DATA", "__objc_init_func"); GETSECT(getLibobjcInitializers, UnsignedInitializer, "__DATA", "__objc_init_func");
objc_image_info * objc_image_info *

View File

@ -30,22 +30,70 @@
// classref_t is not fixed up at launch; use remapClass() to convert // classref_t is not fixed up at launch; use remapClass() to convert
// classlist and catlist and protolist sections are marked const here
// because those sections may be in read-only __DATA_CONST segments.
extern SEL *_getObjc2SelectorRefs(const header_info *hi, size_t *count); extern SEL *_getObjc2SelectorRefs(const header_info *hi, size_t *count);
extern message_ref_t *_getObjc2MessageRefs(const header_info *hi, size_t *count); extern message_ref_t *_getObjc2MessageRefs(const header_info *hi, size_t *count);
extern Class*_getObjc2ClassRefs(const header_info *hi, size_t *count); extern Class*_getObjc2ClassRefs(const header_info *hi, size_t *count);
extern Class*_getObjc2SuperRefs(const header_info *hi, size_t *count); extern Class*_getObjc2SuperRefs(const header_info *hi, size_t *count);
extern classref_t *_getObjc2ClassList(const header_info *hi, size_t *count); extern classref_t const *_getObjc2ClassList(const header_info *hi, size_t *count);
extern classref_t *_getObjc2NonlazyClassList(const header_info *hi, size_t *count); extern classref_t const *_getObjc2NonlazyClassList(const header_info *hi, size_t *count);
extern category_t **_getObjc2CategoryList(const header_info *hi, size_t *count); extern category_t * const *_getObjc2CategoryList(const header_info *hi, size_t *count);
extern category_t **_getObjc2NonlazyCategoryList(const header_info *hi, size_t *count); extern category_t * const *_getObjc2CategoryList2(const header_info *hi, size_t *count);
extern protocol_t **_getObjc2ProtocolList(const header_info *hi, size_t *count); extern category_t * const *_getObjc2NonlazyCategoryList(const header_info *hi, size_t *count);
extern protocol_t * const *_getObjc2ProtocolList(const header_info *hi, size_t *count);
extern protocol_t **_getObjc2ProtocolRefs(const header_info *hi, size_t *count); extern protocol_t **_getObjc2ProtocolRefs(const header_info *hi, size_t *count);
using Initializer = void(*)(void);
extern Initializer* getLibobjcInitializers(const header_info *hi, size_t *count);
extern classref_t *_getObjc2NonlazyClassList(const headerType *mhdr, size_t *count); // FIXME: rdar://29241917&33734254 clang doesn't sign static initializers.
extern category_t **_getObjc2NonlazyCategoryList(const headerType *mhdr, size_t *count); struct UnsignedInitializer {
extern Initializer* getLibobjcInitializers(const headerType *mhdr, size_t *count); private:
uintptr_t storage;
public:
void operator () () const {
using Initializer = void(*)();
Initializer init =
ptrauth_sign_unauthenticated((Initializer)storage,
ptrauth_key_function_pointer, 0);
init();
}
};
extern UnsignedInitializer *getLibobjcInitializers(const header_info *hi, size_t *count);
extern classref_t const *_getObjc2NonlazyClassList(const headerType *mhdr, size_t *count);
extern category_t * const *_getObjc2NonlazyCategoryList(const headerType *mhdr, size_t *count);
extern UnsignedInitializer *getLibobjcInitializers(const headerType *mhdr, size_t *count);
static inline void
foreach_data_segment(const headerType *mhdr,
std::function<void(const segmentType *, intptr_t slide)> code)
{
intptr_t slide = 0;
// compute VM slide
const segmentType *seg = (const segmentType *) (mhdr + 1);
for (unsigned long i = 0; i < mhdr->ncmds; i++) {
if (seg->cmd == SEGMENT_CMD &&
segnameEquals(seg->segname, "__TEXT"))
{
slide = (char *)mhdr - (char *)seg->vmaddr;
break;
}
seg = (const segmentType *)((char *)seg + seg->cmdsize);
}
// enumerate __DATA* segments
seg = (const segmentType *) (mhdr + 1);
for (unsigned long i = 0; i < mhdr->ncmds; i++) {
if (seg->cmd == SEGMENT_CMD &&
segnameStartsWith(seg->segname, "__DATA"))
{
code(seg, slide);
}
seg = (const segmentType *)((char *)seg + seg->cmdsize);
}
}
#endif #endif

View File

@ -59,13 +59,14 @@ GETSECT(_getObjc2SelectorRefs, SEL, "__objc_selrefs");
GETSECT(_getObjc2MessageRefs, message_ref_t, "__objc_msgrefs"); GETSECT(_getObjc2MessageRefs, message_ref_t, "__objc_msgrefs");
GETSECT(_getObjc2ClassRefs, Class, "__objc_classrefs"); GETSECT(_getObjc2ClassRefs, Class, "__objc_classrefs");
GETSECT(_getObjc2SuperRefs, Class, "__objc_superrefs"); GETSECT(_getObjc2SuperRefs, Class, "__objc_superrefs");
GETSECT(_getObjc2ClassList, classref_t, "__objc_classlist"); GETSECT(_getObjc2ClassList, classref_t const, "__objc_classlist");
GETSECT(_getObjc2NonlazyClassList, classref_t, "__objc_nlclslist"); GETSECT(_getObjc2NonlazyClassList, classref_t const, "__objc_nlclslist");
GETSECT(_getObjc2CategoryList, category_t *, "__objc_catlist"); GETSECT(_getObjc2CategoryList, category_t * const, "__objc_catlist");
GETSECT(_getObjc2NonlazyCategoryList, category_t *, "__objc_nlcatlist"); GETSECT(_getObjc2CategoryList2, category_t * const, "__objc_catlist2");
GETSECT(_getObjc2ProtocolList, protocol_t *, "__objc_protolist"); GETSECT(_getObjc2NonlazyCategoryList, category_t * const, "__objc_nlcatlist");
GETSECT(_getObjc2ProtocolList, protocol_t * const, "__objc_protolist");
GETSECT(_getObjc2ProtocolRefs, protocol_t *, "__objc_protorefs"); GETSECT(_getObjc2ProtocolRefs, protocol_t *, "__objc_protorefs");
GETSECT(getLibobjcInitializers, Initializer, "__objc_init_func"); GETSECT(getLibobjcInitializers, UnsignedInitializer, "__objc_init_func");
objc_image_info * objc_image_info *
@ -75,31 +76,15 @@ _getObjcImageInfo(const headerType *mhdr, size_t *outBytes)
outBytes, nil); outBytes, nil);
} }
static const segmentType *
getsegbynamefromheader(const headerType *mhdr, const char *segname)
{
const segmentType *seg = (const segmentType *) (mhdr + 1);
for (unsigned long i = 0; i < mhdr->ncmds; i++){
if (seg->cmd == SEGMENT_CMD && segnameEquals(seg->segname, segname)) {
return seg;
}
seg = (const segmentType *)((char *)seg + seg->cmdsize);
}
return nil;
}
// Look for an __objc* section other than __objc_imageinfo // Look for an __objc* section other than __objc_imageinfo
static bool segmentHasObjcContents(const segmentType *seg) static bool segmentHasObjcContents(const segmentType *seg)
{ {
if (seg) { for (uint32_t i = 0; i < seg->nsects; i++) {
for (uint32_t i = 0; i < seg->nsects; i++) { const sectionType *sect = ((const sectionType *)(seg+1))+i;
const sectionType *sect = ((const sectionType *)(seg+1))+i; if (sectnameStartsWith(sect->sectname, "__objc_") &&
if (sectnameStartsWith(sect->sectname, "__objc_") && !sectnameEquals(sect->sectname, "__objc_imageinfo"))
!sectnameEquals(sect->sectname, "__objc_imageinfo")) {
{ return true;
return true;
}
} }
} }
@ -110,16 +95,15 @@ static bool segmentHasObjcContents(const segmentType *seg)
bool bool
_hasObjcContents(const header_info *hi) _hasObjcContents(const header_info *hi)
{ {
const segmentType *data = bool foundObjC = false;
getsegbynamefromheader(hi->mhdr(), "__DATA");
const segmentType *data_const = foreach_data_segment(hi->mhdr(), [&](const segmentType *seg, intptr_t slide)
getsegbynamefromheader(hi->mhdr(), "__DATA_CONST"); {
const segmentType *data_dirty = if (segmentHasObjcContents(seg)) foundObjC = true;
getsegbynamefromheader(hi->mhdr(), "__DATA_DIRTY"); });
return foundObjC;
return segmentHasObjcContents(data)
|| segmentHasObjcContents(data_const)
|| segmentHasObjcContents(data_dirty);
} }

View File

@ -34,7 +34,9 @@
#ifdef __APPLE_API_PRIVATE #ifdef __APPLE_API_PRIVATE
#define _OBJC_PRIVATE_H_ #ifndef _OBJC_PRIVATE_H_
# define _OBJC_PRIVATE_H_
#endif
#include <stdint.h> #include <stdint.h>
#include <objc/hashtable.h> #include <objc/hashtable.h>
#include <objc/maptable.h> #include <objc/maptable.h>
@ -47,17 +49,30 @@ __BEGIN_DECLS
**********************************************************************/ **********************************************************************/
// Return cls if it's a valid class, or crash. // Return cls if it's a valid class, or crash.
OBJC_EXPORT Class gdb_class_getClass(Class cls) OBJC_EXPORT Class _Nonnull
gdb_class_getClass(Class _Nonnull cls)
#if __OBJC2__ #if __OBJC2__
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0); OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
#else #else
OBJC_AVAILABLE(10.7, 3.1, 9.0, 1.0); OBJC_AVAILABLE(10.7, 3.1, 9.0, 1.0, 2.0);
#endif #endif
// Same as gdb_class_getClass(object_getClass(cls)). // Same as gdb_class_getClass(object_getClass(cls)).
OBJC_EXPORT Class gdb_object_getClass(id obj) OBJC_EXPORT Class _Nonnull gdb_object_getClass(id _Nullable obj)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0); OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
/***********************************************************************
* Class inspection
**********************************************************************/
#if __OBJC2__
// Return the raw, mangled name of cls.
OBJC_EXPORT const char * _Nonnull
objc_debug_class_getNameRaw(Class _Nullable cls)
OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
#endif
/*********************************************************************** /***********************************************************************
* Class lists for heap. * Class lists for heap.
@ -66,15 +81,25 @@ OBJC_EXPORT Class gdb_object_getClass(id obj)
#if __OBJC2__ #if __OBJC2__
// Maps class name to Class, for in-use classes only. NXStrValueMapPrototype. // Maps class name to Class, for in-use classes only. NXStrValueMapPrototype.
OBJC_EXPORT NXMapTable *gdb_objc_realized_classes OBJC_EXPORT NXMapTable * _Nullable gdb_objc_realized_classes
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0); OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
// A generation count of realized classes. Increments when new classes
// are realized. This is NOT an exact count of the number of classes.
// It's not guaranteed by how much it increases when classes are
// realized, only that it increases by something. When classes are
// removed (unloading bundles or destroying dynamically allocated
// classes) the number will also increase to signal that there has
// been a change.
OBJC_EXPORT uintptr_t objc_debug_realized_class_generation_count;
#else #else
// Hashes Classes, for all known classes. Custom prototype. // Hashes Classes, for all known classes. Custom prototype.
OBJC_EXPORT NXHashTable *_objc_debug_class_hash OBJC_EXPORT NXHashTable * _Nullable _objc_debug_class_hash
__OSX_AVAILABLE(10.2) __OSX_AVAILABLE(10.2)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; __IOS_UNAVAILABLE __TVOS_UNAVAILABLE
__WATCHOS_UNAVAILABLE __BRIDGEOS_UNAVAILABLE;
#endif #endif
@ -88,14 +113,14 @@ OBJC_EXPORT NXHashTable *_objc_debug_class_hash
// Extract isa pointer from an isa field. // Extract isa pointer from an isa field.
// (Class)(isa & mask) == class pointer // (Class)(isa & mask) == class pointer
OBJC_EXPORT const uintptr_t objc_debug_isa_class_mask OBJC_EXPORT const uintptr_t objc_debug_isa_class_mask
OBJC_AVAILABLE(10.10, 7.0, 9.0, 1.0); OBJC_AVAILABLE(10.10, 7.0, 9.0, 1.0, 2.0);
// Extract magic cookie from an isa field. // Extract magic cookie from an isa field.
// (isa & magic_mask) == magic_value // (isa & magic_mask) == magic_value
OBJC_EXPORT const uintptr_t objc_debug_isa_magic_mask OBJC_EXPORT const uintptr_t objc_debug_isa_magic_mask
OBJC_AVAILABLE(10.10, 7.0, 9.0, 1.0); OBJC_AVAILABLE(10.10, 7.0, 9.0, 1.0, 2.0);
OBJC_EXPORT const uintptr_t objc_debug_isa_magic_value OBJC_EXPORT const uintptr_t objc_debug_isa_magic_value
OBJC_AVAILABLE(10.10, 7.0, 9.0, 1.0); OBJC_AVAILABLE(10.10, 7.0, 9.0, 1.0, 2.0);
// Use indexed ISAs for targets which store index of the class in the ISA. // Use indexed ISAs for targets which store index of the class in the ISA.
// This index can be used to index the array of classes. // This index can be used to index the array of classes.
@ -109,7 +134,7 @@ OBJC_EXPORT const uintptr_t objc_debug_indexed_isa_index_shift;
// And then we can use that index to get the class from this array. Note // And then we can use that index to get the class from this array. Note
// the size is provided so that clients can ensure the index they get is in // the size is provided so that clients can ensure the index they get is in
// bounds and not read off the end of the array. // bounds and not read off the end of the array.
OBJC_EXPORT Class objc_indexed_classes[]; OBJC_EXPORT Class _Nullable objc_indexed_classes[];
// When we don't have enough bits to store a class*, we can instead store an // When we don't have enough bits to store a class*, we can instead store an
// index in to this array. Classes are added here when they are realized. // index in to this array. Classes are added here when they are realized.
@ -121,6 +146,63 @@ OBJC_EXPORT uintptr_t objc_indexed_classes_count;
#endif #endif
/***********************************************************************
* Class structure decoding
**********************************************************************/
#if __OBJC2__
// Mask for the pointer from class struct to class rw data.
// Other bits may be used for flags.
// Use 0x00007ffffffffff8UL or 0xfffffffcUL when this variable is unavailable.
OBJC_EXPORT const uintptr_t objc_debug_class_rw_data_mask
OBJC_AVAILABLE(10.13, 11.0, 11.0, 4.0, 2.0);
// The ABI version for the internal runtime representations
// lldb, CoreSymbolication and debugging tools need to know
OBJC_EXTERN const uint32_t objc_class_abi_version
OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
// the maximum ABI version in existence for now
#define OBJC_CLASS_ABI_VERSION_MAX 1
// Used when objc_class_abi_version is absent or 0
struct class_rw_v0_t {
uint32_t flags;
uint32_t version;
uintptr_t ro; // class_ro_t
uintptr_t methods; // method_array_t
uintptr_t properties; // property_array_t
uintptr_t protocols; // protocol_array_t
Class _Nullable firstSubclass;
Class _Nullable nextSiblingClass;
char *_Nullable demangledName;
// uint32_t index; // only when indexed-isa is used
};
// Used when objc_class_abi_version is 1
struct class_rw_v1_t {
uint32_t flags;
uint16_t witness;
uint16_t index; // only when indexed-isa is used
uintptr_t ro_or_rw_ext; // tagged union based on the low bit:
// 0: class_ro_t 1: class_rw_ext_t
Class _Nullable firstSubclass;
Class _Nullable nextSiblingClass;
};
struct class_rw_ext_v1_t {
uintptr_t ro; // class_ro_t
uintptr_t methods; // method_array_t
uintptr_t properties; // property_array_t
uintptr_t protocols; // protocol_array_t
char *_Nullable demangledName;
uint32_t version;
};
#endif
/*********************************************************************** /***********************************************************************
* Tagged pointer decoding * Tagged pointer decoding
**********************************************************************/ **********************************************************************/
@ -130,24 +212,30 @@ OBJC_EXPORT uintptr_t objc_indexed_classes_count;
// if (obj & mask) obj is a tagged pointer object // if (obj & mask) obj is a tagged pointer object
OBJC_EXPORT uintptr_t objc_debug_taggedpointer_mask OBJC_EXPORT uintptr_t objc_debug_taggedpointer_mask
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0); OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
// tagged pointers are obfuscated by XORing with a random value
// decoded_obj = (obj ^ obfuscator)
OBJC_EXPORT uintptr_t objc_debug_taggedpointer_obfuscator
OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);
// tag_slot = (obj >> slot_shift) & slot_mask // tag_slot = (obj >> slot_shift) & slot_mask
OBJC_EXPORT unsigned int objc_debug_taggedpointer_slot_shift OBJC_EXPORT unsigned int objc_debug_taggedpointer_slot_shift
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0); OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
OBJC_EXPORT uintptr_t objc_debug_taggedpointer_slot_mask OBJC_EXPORT uintptr_t objc_debug_taggedpointer_slot_mask
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0); OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
// class = classes[tag_slot] // class = classes[tag_slot]
OBJC_EXPORT Class objc_debug_taggedpointer_classes[] OBJC_EXPORT Class _Nullable objc_debug_taggedpointer_classes[]
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0); OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
// payload = (obj << payload_lshift) >> payload_rshift // payload = (decoded_obj << payload_lshift) >> payload_rshift
// Payload signedness is determined by the signedness of the right-shift. // Payload signedness is determined by the signedness of the right-shift.
OBJC_EXPORT unsigned int objc_debug_taggedpointer_payload_lshift OBJC_EXPORT unsigned int objc_debug_taggedpointer_payload_lshift
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0); OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
OBJC_EXPORT unsigned int objc_debug_taggedpointer_payload_rshift OBJC_EXPORT unsigned int objc_debug_taggedpointer_payload_rshift
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0); OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
// Extended tagged pointers (255 classes, 52-bit payload). // Extended tagged pointers (255 classes, 52-bit payload).
@ -156,68 +244,56 @@ OBJC_EXPORT unsigned int objc_debug_taggedpointer_payload_rshift
// tagged pointer scheme alone, it will appear to have an isa // tagged pointer scheme alone, it will appear to have an isa
// that is either nil or class __NSUnrecognizedTaggedPointer. // that is either nil or class __NSUnrecognizedTaggedPointer.
// if (ext_mask != 0 && (obj & ext_mask) == ext_mask) // if (ext_mask != 0 && (decoded_obj & ext_mask) == ext_mask)
// obj is a ext tagged pointer object // obj is a ext tagged pointer object
OBJC_EXPORT uintptr_t objc_debug_taggedpointer_ext_mask OBJC_EXPORT uintptr_t objc_debug_taggedpointer_ext_mask
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
// ext_tag_slot = (obj >> ext_slot_shift) & ext_slot_mask // ext_tag_slot = (obj >> ext_slot_shift) & ext_slot_mask
OBJC_EXPORT unsigned int objc_debug_taggedpointer_ext_slot_shift OBJC_EXPORT unsigned int objc_debug_taggedpointer_ext_slot_shift
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
OBJC_EXPORT uintptr_t objc_debug_taggedpointer_ext_slot_mask OBJC_EXPORT uintptr_t objc_debug_taggedpointer_ext_slot_mask
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
// class = ext_classes[ext_tag_slot] // class = ext_classes[ext_tag_slot]
OBJC_EXPORT Class objc_debug_taggedpointer_ext_classes[] OBJC_EXPORT Class _Nullable objc_debug_taggedpointer_ext_classes[]
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
// payload = (obj << ext_payload_lshift) >> ext_payload_rshift // payload = (decoded_obj << ext_payload_lshift) >> ext_payload_rshift
// Payload signedness is determined by the signedness of the right-shift. // Payload signedness is determined by the signedness of the right-shift.
OBJC_EXPORT unsigned int objc_debug_taggedpointer_ext_payload_lshift OBJC_EXPORT unsigned int objc_debug_taggedpointer_ext_payload_lshift
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
OBJC_EXPORT unsigned int objc_debug_taggedpointer_ext_payload_rshift OBJC_EXPORT unsigned int objc_debug_taggedpointer_ext_payload_rshift
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
#endif #endif
/*********************************************************************** /***********************************************************************
* Breakpoints in objc_msgSend for debugger stepping. * Swift marker bits
* The array is a {0,0} terminated list of addresses.
* Each address is one of the following:
* OBJC_MESSENGER_START: Address is the start of a messenger function.
* OBJC_MESSENGER_END_FAST: Address is a jump insn that calls an IMP.
* OBJC_MESSENGER_END_SLOW: Address is some insn in the slow lookup path.
* OBJC_MESSENGER_END_NIL: Address is a return insn for messages to nil.
*
* Every path from OBJC_MESSENGER_START should reach some OBJC_MESSENGER_END.
* At all ENDs, the stack and parameter register state is the same as START.
*
* In some cases, the END_FAST case jumps to something other than the
* method's implementation. In those cases the jump's destination will
* be another function that is marked OBJC_MESSENGER_START.
**********************************************************************/ **********************************************************************/
#if __OBJC2__ #if __OBJC2__
OBJC_EXPORT const uintptr_t objc_debug_swift_stable_abi_bit
#define OBJC_MESSENGER_START 1 OBJC_AVAILABLE(10.14.4, 12.2, 12.2, 5.2, 3.2);
#define OBJC_MESSENGER_END_FAST 2
#define OBJC_MESSENGER_END_SLOW 3
#define OBJC_MESSENGER_END_NIL 4
struct objc_messenger_breakpoint {
uintptr_t address;
uintptr_t kind;
};
OBJC_EXPORT struct objc_messenger_breakpoint
gdb_objc_messenger_breakpoints[]
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
#endif #endif
/***********************************************************************
* AutoreleasePoolPage
**********************************************************************/
OBJC_EXTERN const uint32_t objc_debug_autoreleasepoolpage_magic_offset OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
OBJC_EXTERN const uint32_t objc_debug_autoreleasepoolpage_next_offset OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
OBJC_EXTERN const uint32_t objc_debug_autoreleasepoolpage_thread_offset OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
OBJC_EXTERN const uint32_t objc_debug_autoreleasepoolpage_parent_offset OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
OBJC_EXTERN const uint32_t objc_debug_autoreleasepoolpage_child_offset OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
OBJC_EXTERN const uint32_t objc_debug_autoreleasepoolpage_depth_offset OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
OBJC_EXTERN const uint32_t objc_debug_autoreleasepoolpage_hiwat_offset OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
__END_DECLS __END_DECLS
// APPLE_API_PRIVATE
#endif #endif
// _OBJC_GDB_H
#endif #endif

View File

@ -30,7 +30,7 @@ __BEGIN_DECLS
struct _objc_initializing_classes; struct _objc_initializing_classes;
extern void _class_initialize(Class cls); extern void initializeNonMetaClass(Class cls);
extern void _destroyInitializingClassList(struct _objc_initializing_classes *list); extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);

View File

@ -95,11 +95,19 @@
#include "objc-private.h" #include "objc-private.h"
#include "message.h" #include "message.h"
#include "objc-initialize.h" #include "objc-initialize.h"
#include "DenseMapExtras.h"
/* classInitLock protects CLS_INITIALIZED and CLS_INITIALIZING, and /* classInitLock protects CLS_INITIALIZED and CLS_INITIALIZING, and
* is signalled when any class is done initializing. * is signalled when any class is done initializing.
* Threads that are waiting for a class to finish initializing wait on this. */ * Threads that are waiting for a class to finish initializing wait on this. */
static monitor_t classInitLock; monitor_t classInitLock;
struct _objc_willInitializeClassCallback {
_objc_func_willInitializeClass f;
void *context;
};
static GlobalSmallVector<_objc_willInitializeClassCallback, 1> willInitializeFuncs;
/*********************************************************************** /***********************************************************************
@ -262,9 +270,12 @@ static void _setThisThreadIsNotInitializingClass(Class cls)
typedef struct PendingInitialize { typedef struct PendingInitialize {
Class subclass; Class subclass;
struct PendingInitialize *next; struct PendingInitialize *next;
PendingInitialize(Class cls) : subclass(cls), next(nullptr) { }
} PendingInitialize; } PendingInitialize;
static NXMapTable *pendingInitializeMap; typedef objc::DenseMap<Class, PendingInitialize *> PendingInitializeMap;
static PendingInitializeMap *pendingInitializeMap;
/*********************************************************************** /***********************************************************************
* _finishInitializing * _finishInitializing
@ -277,11 +288,11 @@ static void _finishInitializing(Class cls, Class supercls)
PendingInitialize *pending; PendingInitialize *pending;
classInitLock.assertLocked(); classInitLock.assertLocked();
assert(!supercls || supercls->isInitialized()); ASSERT(!supercls || supercls->isInitialized());
if (PrintInitializing) { if (PrintInitializing) {
_objc_inform("INITIALIZE: %s is fully +initialized", _objc_inform("INITIALIZE: thread %p: %s is fully +initialized",
cls->nameForLogging()); objc_thread_self(), cls->nameForLogging());
} }
// mark this class as fully +initialized // mark this class as fully +initialized
@ -291,21 +302,23 @@ static void _finishInitializing(Class cls, Class supercls)
// mark any subclasses that were merely waiting for this class // mark any subclasses that were merely waiting for this class
if (!pendingInitializeMap) return; if (!pendingInitializeMap) return;
pending = (PendingInitialize *)NXMapGet(pendingInitializeMap, cls);
if (!pending) return;
NXMapRemove(pendingInitializeMap, cls); auto it = pendingInitializeMap->find(cls);
if (it == pendingInitializeMap->end()) return;
pending = it->second;
pendingInitializeMap->erase(it);
// Destroy the pending table if it's now empty, to save memory. // Destroy the pending table if it's now empty, to save memory.
if (NXCountMapTable(pendingInitializeMap) == 0) { if (pendingInitializeMap->size() == 0) {
NXFreeMapTable(pendingInitializeMap); delete pendingInitializeMap;
pendingInitializeMap = nil; pendingInitializeMap = nil;
} }
while (pending) { while (pending) {
PendingInitialize *next = pending->next; PendingInitialize *next = pending->next;
if (pending->subclass) _finishInitializing(pending->subclass, cls); if (pending->subclass) _finishInitializing(pending->subclass, cls);
free(pending); delete pending;
pending = next; pending = next;
} }
} }
@ -318,26 +331,27 @@ static void _finishInitializing(Class cls, Class supercls)
**********************************************************************/ **********************************************************************/
static void _finishInitializingAfter(Class cls, Class supercls) static void _finishInitializingAfter(Class cls, Class supercls)
{ {
PendingInitialize *pending;
classInitLock.assertLocked(); classInitLock.assertLocked();
if (PrintInitializing) { if (PrintInitializing) {
_objc_inform("INITIALIZE: %s waiting for superclass +[%s initialize]", _objc_inform("INITIALIZE: thread %p: class %s will be marked as fully "
cls->nameForLogging(), supercls->nameForLogging()); "+initialized after superclass +[%s initialize] completes",
objc_thread_self(), cls->nameForLogging(),
supercls->nameForLogging());
} }
if (!pendingInitializeMap) { if (!pendingInitializeMap) {
pendingInitializeMap = pendingInitializeMap = new PendingInitializeMap{10};
NXCreateMapTable(NXPtrValueMapPrototype, 10);
// fixme pre-size this table for CF/NSObject +initialize // fixme pre-size this table for CF/NSObject +initialize
} }
pending = (PendingInitialize *)malloc(sizeof(*pending)); PendingInitialize *pending = new PendingInitialize{cls};
pending->subclass = cls; auto result = pendingInitializeMap->try_emplace(supercls, pending);
pending->next = (PendingInitialize *) if (!result.second) {
NXMapGet(pendingInitializeMap, supercls); pending->next = result.first->second;
NXMapInsert(pendingInitializeMap, supercls, pending); result.first->second = pending;
}
} }
@ -352,6 +366,11 @@ void callInitialize(Class cls)
void waitForInitializeToComplete(Class cls) void waitForInitializeToComplete(Class cls)
{ {
if (PrintInitializing) {
_objc_inform("INITIALIZE: thread %p: blocking until +[%s initialize] "
"completes", objc_thread_self(), cls->nameForLogging());
}
monitor_locker_t lock(classInitLock); monitor_locker_t lock(classInitLock);
while (!cls->isInitialized()) { while (!cls->isInitialized()) {
classInitLock.wait(); classInitLock.wait();
@ -362,18 +381,119 @@ void waitForInitializeToComplete(Class cls)
void callInitialize(Class cls) void callInitialize(Class cls)
{ {
((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize); ((void(*)(Class, SEL))objc_msgSend)(cls, @selector(initialize));
asm(""); asm("");
} }
/***********************************************************************
* classHasTrivialInitialize
* Returns true if the class has no +initialize implementation or
* has a +initialize implementation that looks empty.
* Any root class +initialize implemetation is assumed to be trivial.
**********************************************************************/
static bool classHasTrivialInitialize(Class cls)
{
if (cls->isRootClass() || cls->isRootMetaclass()) return true;
Class rootCls = cls->ISA()->ISA()->superclass;
IMP rootImp = lookUpImpOrNil(rootCls, @selector(initialize), rootCls->ISA());
IMP imp = lookUpImpOrNil(cls, @selector(initialize), cls->ISA());
return (imp == nil || imp == (IMP)&objc_noop_imp || imp == rootImp);
}
/***********************************************************************
* lockAndFinishInitializing
* Mark a class as finished initializing and notify waiters, or queue for later.
* If the superclass is also done initializing, then update
* the info bits and notify waiting threads.
* If not, update them later. (This can happen if this +initialize
* was itself triggered from inside a superclass +initialize.)
**********************************************************************/
static void lockAndFinishInitializing(Class cls, Class supercls)
{
monitor_locker_t lock(classInitLock);
if (!supercls || supercls->isInitialized()) {
_finishInitializing(cls, supercls);
} else {
_finishInitializingAfter(cls, supercls);
}
}
/***********************************************************************
* performForkChildInitialize
* +initialize after fork() is problematic. It's possible for the
* fork child process to call some +initialize that would deadlock waiting
* for another +initialize in the parent process.
* We wouldn't know how much progress it made therein, so we can't
* act as if +initialize completed nor can we restart +initialize
* from scratch.
*
* Instead we proceed introspectively. If the class has some
* +initialize implementation, we halt. If the class has no
* +initialize implementation of its own, we continue. Root
* class +initialize is assumed to be empty if it exists.
*
* We apply this rule even if the child's +initialize does not appear
* to be blocked by anything. This prevents races wherein the +initialize
* deadlock only rarely hits. Instead we disallow it even when we "won"
* the race.
*
* Exception: processes that are single-threaded when fork() is called
* have no restrictions on +initialize in the child. Examples: sshd and httpd.
*
* Classes that wish to implement +initialize and be callable after
* fork() must use an atfork() handler to provoke +initialize in fork prepare.
**********************************************************************/
// Called before halting when some +initialize
// method can't be called after fork().
BREAKPOINT_FUNCTION(
void objc_initializeAfterForkError(Class cls)
);
void performForkChildInitialize(Class cls, Class supercls)
{
if (classHasTrivialInitialize(cls)) {
if (PrintInitializing) {
_objc_inform("INITIALIZE: thread %p: skipping trivial +[%s "
"initialize] in fork() child process",
objc_thread_self(), cls->nameForLogging());
}
lockAndFinishInitializing(cls, supercls);
}
else {
if (PrintInitializing) {
_objc_inform("INITIALIZE: thread %p: refusing to call +[%s "
"initialize] in fork() child process because "
"it may have been in progress when fork() was called",
objc_thread_self(), cls->nameForLogging());
}
_objc_inform_now_and_on_crash
("+[%s initialize] may have been in progress in another thread "
"when fork() was called.",
cls->nameForLogging());
objc_initializeAfterForkError(cls);
_objc_fatal
("+[%s initialize] may have been in progress in another thread "
"when fork() was called. We cannot safely call it or "
"ignore it in the fork() child process. Crashing instead. "
"Set a breakpoint on objc_initializeAfterForkError to debug.",
cls->nameForLogging());
}
}
/*********************************************************************** /***********************************************************************
* class_initialize. Send the '+initialize' message on demand to any * class_initialize. Send the '+initialize' message on demand to any
* uninitialized class. Force initialization of superclasses first. * uninitialized class. Force initialization of superclasses first.
**********************************************************************/ **********************************************************************/
void _class_initialize(Class cls) void initializeNonMetaClass(Class cls)
{ {
assert(!cls->isMetaClass()); ASSERT(!cls->isMetaClass());
Class supercls; Class supercls;
bool reallyInitialize = NO; bool reallyInitialize = NO;
@ -382,15 +502,19 @@ void _class_initialize(Class cls)
// See note about deadlock above. // See note about deadlock above.
supercls = cls->superclass; supercls = cls->superclass;
if (supercls && !supercls->isInitialized()) { if (supercls && !supercls->isInitialized()) {
_class_initialize(supercls); initializeNonMetaClass(supercls);
} }
// Try to atomically set CLS_INITIALIZING. // Try to atomically set CLS_INITIALIZING.
SmallVector<_objc_willInitializeClassCallback, 1> localWillInitializeFuncs;
{ {
monitor_locker_t lock(classInitLock); monitor_locker_t lock(classInitLock);
if (!cls->isInitialized() && !cls->isInitializing()) { if (!cls->isInitialized() && !cls->isInitializing()) {
cls->setInitializing(); cls->setInitializing();
reallyInitialize = YES; reallyInitialize = YES;
// Grab a copy of the will-initialize funcs with the lock held.
localWillInitializeFuncs.initFrom(willInitializeFuncs);
} }
} }
@ -400,43 +524,54 @@ void _class_initialize(Class cls)
// Record that we're initializing this class so we can message it. // Record that we're initializing this class so we can message it.
_setThisThreadIsInitializingClass(cls); _setThisThreadIsInitializingClass(cls);
if (MultithreadedForkChild) {
// LOL JK we don't really call +initialize methods after fork().
performForkChildInitialize(cls, supercls);
return;
}
for (auto callback : localWillInitializeFuncs)
callback.f(callback.context, cls);
// Send the +initialize message. // Send the +initialize message.
// Note that +initialize is sent to the superclass (again) if // Note that +initialize is sent to the superclass (again) if
// this class doesn't implement +initialize. 2157218 // this class doesn't implement +initialize. 2157218
if (PrintInitializing) { if (PrintInitializing) {
_objc_inform("INITIALIZE: calling +[%s initialize]", _objc_inform("INITIALIZE: thread %p: calling +[%s initialize]",
cls->nameForLogging()); objc_thread_self(), cls->nameForLogging());
} }
// Exceptions: A +initialize call that throws an exception // Exceptions: A +initialize call that throws an exception
// is deemed to be a complete and successful +initialize. // is deemed to be a complete and successful +initialize.
@try { //
// Only __OBJC2__ adds these handlers. !__OBJC2__ has a
// bootstrapping problem of this versus CF's call to
// objc_exception_set_functions().
#if __OBJC2__
@try
#endif
{
callInitialize(cls); callInitialize(cls);
if (PrintInitializing) { if (PrintInitializing) {
_objc_inform("INITIALIZE: finished +[%s initialize]", _objc_inform("INITIALIZE: thread %p: finished +[%s initialize]",
cls->nameForLogging()); objc_thread_self(), cls->nameForLogging());
} }
} }
#if __OBJC2__
@catch (...) { @catch (...) {
if (PrintInitializing) { if (PrintInitializing) {
_objc_inform("INITIALIZE: +[%s initialize] threw an exception", _objc_inform("INITIALIZE: thread %p: +[%s initialize] "
cls->nameForLogging()); "threw an exception",
objc_thread_self(), cls->nameForLogging());
} }
@throw; @throw;
} }
@finally { @finally
#endif
{
// Done initializing. // Done initializing.
// If the superclass is also done initializing, then update lockAndFinishInitializing(cls, supercls);
// the info bits and notify waiting threads.
// If not, update them later. (This can happen if this +initialize
// was itself triggered from inside a superclass +initialize.)
monitor_locker_t lock(classInitLock);
if (!supercls || supercls->isInitialized()) {
_finishInitializing(cls, supercls);
} else {
_finishInitializingAfter(cls, supercls);
}
} }
return; return;
} }
@ -450,9 +585,14 @@ void _class_initialize(Class cls)
// before blocking. // before blocking.
if (_thisThreadIsInitializingClass(cls)) { if (_thisThreadIsInitializingClass(cls)) {
return; return;
} else { } else if (!MultithreadedForkChild) {
waitForInitializeToComplete(cls); waitForInitializeToComplete(cls);
return; return;
} else {
// We're on the child side of fork(), facing a class that
// was initializing by some other thread when fork() was called.
_setThisThreadIsInitializingClass(cls);
performForkChildInitialize(cls, supercls);
} }
} }
@ -472,3 +612,33 @@ void _class_initialize(Class cls)
_objc_fatal("thread-safe class init in objc runtime is buggy!"); _objc_fatal("thread-safe class init in objc runtime is buggy!");
} }
} }
void _objc_addWillInitializeClassFunc(_objc_func_willInitializeClass _Nonnull func, void * _Nullable context) {
#if __OBJC2__
unsigned count;
Class *realizedClasses;
// Fetch all currently initialized classes. Do this with classInitLock held
// so we don't race with setting those flags.
{
monitor_locker_t initLock(classInitLock);
realizedClasses = objc_copyRealizedClassList(&count);
for (unsigned i = 0; i < count; i++) {
// Remove uninitialized classes from the array.
if (!realizedClasses[i]->isInitializing() && !realizedClasses[i]->isInitialized())
realizedClasses[i] = Nil;
}
willInitializeFuncs.append({func, context});
}
// Invoke the callback for all realized classes that weren't cleared out.
for (unsigned i = 0; i < count; i++) {
if (Class cls = realizedClasses[i]) {
func(context, cls);
}
}
free(realizedClasses);
#endif
}

View File

@ -41,9 +41,9 @@
#include <objc/runtime.h> #include <objc/runtime.h>
#include <Availability.h> #include <Availability.h>
#include <malloc/malloc.h> #include <malloc/malloc.h>
#include <mach-o/loader.h>
#include <dispatch/dispatch.h> #include <dispatch/dispatch.h>
__BEGIN_DECLS
// Termination reasons in the OS_REASON_OBJC namespace. // Termination reasons in the OS_REASON_OBJC namespace.
#define OBJC_EXIT_REASON_UNSPECIFIED 1 #define OBJC_EXIT_REASON_UNSPECIFIED 1
@ -54,13 +54,23 @@ __BEGIN_DECLS
// The runtime's class structure will never grow beyond this. // The runtime's class structure will never grow beyond this.
#define OBJC_MAX_CLASS_SIZE (32*sizeof(void*)) #define OBJC_MAX_CLASS_SIZE (32*sizeof(void*))
__BEGIN_DECLS
// This symbol is exported only from debug builds of libobjc itself.
#if defined(OBJC_IS_DEBUG_BUILD)
OBJC_EXPORT void _objc_isDebugBuild(void);
#endif
// In-place construction of an Objective-C class. // In-place construction of an Objective-C class.
// cls and metacls must each be OBJC_MAX_CLASS_SIZE bytes. // 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 a class with the same name already exists.
// Returns nil if the superclass is under construction. // Returns nil if the superclass is under construction.
// Call objc_registerClassPair() when you are done. // Call objc_registerClassPair() when you are done.
OBJC_EXPORT Class objc_initializeClassPair(Class superclass, const char *name, Class cls, Class metacls) OBJC_EXPORT Class _Nullable
OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0); 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. // Class and metaclass construction from a compiler-generated memory image.
// cls and cls->isa must each be OBJC_MAX_CLASS_SIZE bytes. // cls and cls->isa must each be OBJC_MAX_CLASS_SIZE bytes.
@ -72,86 +82,164 @@ OBJC_EXPORT Class objc_initializeClassPair(Class superclass, const char *name, C
// Do not call objc_registerClassPair(). // Do not call objc_registerClassPair().
#if __OBJC2__ #if __OBJC2__
struct objc_image_info; struct objc_image_info;
OBJC_EXPORT Class objc_readClassPair(Class cls, OBJC_EXPORT Class _Nullable
const struct objc_image_info *info) objc_readClassPair(Class _Nonnull cls,
OBJC_AVAILABLE(10.10, 8.0, 9.0, 1.0); const struct objc_image_info * _Nonnull info)
OBJC_AVAILABLE(10.10, 8.0, 9.0, 1.0, 2.0);
#endif #endif
// Batch object allocation using malloc_zone_batch_malloc(). // Batch object allocation using malloc_zone_batch_malloc().
OBJC_EXPORT unsigned class_createInstances(Class cls, size_t extraBytes, OBJC_EXPORT unsigned
id *results, unsigned num_requested) class_createInstances(Class _Nullable cls, size_t extraBytes,
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0) id _Nonnull * _Nonnull results, unsigned num_requested)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0)
OBJC_ARC_UNAVAILABLE; OBJC_ARC_UNAVAILABLE;
// Get the isa pointer written into objects just before being freed. // Get the isa pointer written into objects just before being freed.
OBJC_EXPORT Class _objc_getFreedObjectClass(void) OBJC_EXPORT Class _Nonnull
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0); _objc_getFreedObjectClass(void)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
// env NSObjCMessageLoggingEnabled // env NSObjCMessageLoggingEnabled
OBJC_EXPORT void instrumentObjcMessageSends(BOOL flag) OBJC_EXPORT void
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0); instrumentObjcMessageSends(BOOL flag)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
// Initializer called by libSystem // Initializer called by libSystem
OBJC_EXPORT void _objc_init(void) OBJC_EXPORT void
_objc_init(void)
#if __OBJC2__ #if __OBJC2__
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0); OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
#else #else
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
#endif #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. // Return YES if GC is on and `object` is a GC allocation.
OBJC_EXPORT BOOL objc_isAuto(id object) OBJC_EXPORT BOOL
__OSX_DEPRECATED(10.4, 10.8, "it always returns NO") objc_isAuto(id _Nullable object)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.8, "it always returns NO");
// GC debugging
OBJC_EXPORT BOOL
objc_dumpHeap(char * _Nonnull filename, unsigned long length)
OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.8, "it always returns NO");
// GC startup callback from Foundation // GC startup callback from Foundation
OBJC_EXPORT malloc_zone_t *objc_collect_init(int (*callback)(void)) OBJC_EXPORT malloc_zone_t * _Nullable
__OSX_DEPRECATED(10.4, 10.8, "it does nothing") objc_collect_init(int (* _Nonnull callback)(void))
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.8, "it does nothing");
#if __OBJC2__
// Copies the list of currently realized classes
// intended for introspection only
// most users will want objc_copyClassList instead.
OBJC_EXPORT
Class _Nonnull * _Nullable
objc_copyRealizedClassList(unsigned int *_Nullable outCount)
OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
typedef struct objc_imp_cache_entry {
SEL _Nonnull sel;
IMP _Nonnull imp;
} objc_imp_cache_entry;
OBJC_EXPORT
objc_imp_cache_entry *_Nullable
class_copyImpCache(Class _Nonnull cls, int * _Nullable outCount)
OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
#endif
// Plainly-implemented GC barriers. Rosetta used to use these. // Plainly-implemented GC barriers. Rosetta used to use these.
OBJC_EXPORT id objc_assign_strongCast_generic(id value, id *dest) OBJC_EXPORT id _Nullable
objc_assign_strongCast_generic(id _Nullable value, id _Nullable * _Nonnull dest)
UNAVAILABLE_ATTRIBUTE; UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT id objc_assign_global_generic(id value, id *dest)
OBJC_EXPORT id _Nullable
objc_assign_global_generic(id _Nullable value, id _Nullable * _Nonnull dest)
UNAVAILABLE_ATTRIBUTE; UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT id objc_assign_threadlocal_generic(id value, id *dest)
OBJC_EXPORT id _Nullable
objc_assign_threadlocal_generic(id _Nullable value,
id _Nullable * _Nonnull dest)
UNAVAILABLE_ATTRIBUTE; UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT id objc_assign_ivar_generic(id value, id dest, ptrdiff_t offset)
OBJC_EXPORT id _Nullable
objc_assign_ivar_generic(id _Nullable value, id _Nonnull dest, ptrdiff_t offset)
UNAVAILABLE_ATTRIBUTE; UNAVAILABLE_ATTRIBUTE;
// GC preflight for an app executable. // GC preflight for an app executable.
// 1: some slice requires GC // 1: some slice requires GC
// 0: no slice requires GC // 0: no slice requires GC
// -1: I/O or file format error // -1: I/O or file format error
OBJC_EXPORT int objc_appRequiresGC(int fd) OBJC_EXPORT int
objc_appRequiresGC(int fd)
__OSX_AVAILABLE(10.11) __OSX_AVAILABLE(10.11)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; __IOS_UNAVAILABLE __TVOS_UNAVAILABLE
__WATCHOS_UNAVAILABLE
#ifndef __APPLE_BLEACH_SDK__
__BRIDGEOS_UNAVAILABLE
#endif
;
// Install missing-class callback. Used by the late unlamented ZeroLink. // Install missing-class callback. Used by the late unlamented ZeroLink.
OBJC_EXPORT void _objc_setClassLoader(BOOL (*newClassLoader)(const char *)) OBJC2_UNAVAILABLE; OBJC_EXPORT void
_objc_setClassLoader(BOOL (* _Nonnull newClassLoader)(const char * _Nonnull))
OBJC2_UNAVAILABLE;
#if !(TARGET_OS_OSX && !TARGET_OS_IOSMAC && __i386__)
// Add a class copy fixup handler. The name is a misnomer, as
// multiple calls will install multiple handlers. Older versions
// of the Swift runtime call it by name, and it's only used by Swift
// so it's not worth deprecating this name in favor of a better one.
OBJC_EXPORT void
_objc_setClassCopyFixupHandler(void (* _Nonnull newFixupHandler)
(Class _Nonnull oldClass, Class _Nonnull newClass))
OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);
#endif
// Install handler for allocation failures. // Install handler for allocation failures.
// Handler may abort, or throw, or provide an object to return. // Handler may abort, or throw, or provide an object to return.
OBJC_EXPORT void _objc_setBadAllocHandler(id (*newHandler)(Class isa)) OBJC_EXPORT void
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0); _objc_setBadAllocHandler(id _Nullable (* _Nonnull newHandler)
(Class _Nullable isa))
// This can go away when AppKit stops calling it (rdar://7811851) OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
#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 // Used by ExceptionHandling.framework
#if !__OBJC2__ #if !__OBJC2__
OBJC_EXPORT void _objc_error(id rcv, const char *fmt, va_list args) OBJC_EXPORT void
__attribute__((noreturn)) _objc_error(id _Nullable rcv, const char * _Nonnull fmt, va_list args)
__OSX_DEPRECATED(10.0, 10.5, "use other logging facilities instead") __attribute__((noreturn, cold))
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE; OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.0, 10.5, "use other logging facilities instead");
#endif #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. // Tagged pointer objects.
#if __LP64__ #if __LP64__
@ -174,6 +262,7 @@ typedef uint16_t objc_tag_index_t;
enum enum
#endif #endif
{ {
// 60-bit payloads
OBJC_TAG_NSAtom = 0, OBJC_TAG_NSAtom = 0,
OBJC_TAG_1 = 1, OBJC_TAG_1 = 1,
OBJC_TAG_NSString = 2, OBJC_TAG_NSString = 2,
@ -181,8 +270,24 @@ enum
OBJC_TAG_NSIndexPath = 4, OBJC_TAG_NSIndexPath = 4,
OBJC_TAG_NSManagedObjectID = 5, OBJC_TAG_NSManagedObjectID = 5,
OBJC_TAG_NSDate = 6, OBJC_TAG_NSDate = 6,
// 60-bit reserved
OBJC_TAG_RESERVED_7 = 7, 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_NSColor = 16,
OBJC_TAG_UIColor = 17,
OBJC_TAG_CGColor = 18,
OBJC_TAG_NSIndexSet = 19,
OBJC_TAG_First60BitPayload = 0, OBJC_TAG_First60BitPayload = 0,
OBJC_TAG_Last60BitPayload = 6, OBJC_TAG_Last60BitPayload = 6,
OBJC_TAG_First52BitPayload = 8, OBJC_TAG_First52BitPayload = 8,
@ -202,48 +307,50 @@ _objc_taggedPointersEnabled(void);
// Register a class for a tagged pointer tag. // Register a class for a tagged pointer tag.
// Aborts if the tag is invalid or already in use. // Aborts if the tag is invalid or already in use.
OBJC_EXPORT void _objc_registerTaggedPointerClass(objc_tag_index_t tag, Class cls) OBJC_EXPORT void
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0); _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 the registered class for the given tag.
// Returns nil if the tag is valid but has no registered class. // Returns nil if the tag is valid but has no registered class.
// Aborts if the tag is invalid. // Aborts if the tag is invalid.
OBJC_EXPORT Class _objc_getClassForTag(objc_tag_index_t tag) OBJC_EXPORT Class _Nullable
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0); _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. // Create a tagged pointer object with the given tag and payload.
// Assumes the tag is valid. // Assumes the tag is valid.
// Assumes tagged pointers are enabled. // Assumes tagged pointers are enabled.
// The payload will be silently truncated to fit. // The payload will be silently truncated to fit.
static inline void * static inline void * _Nonnull
_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t payload); _objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t payload);
// Return true if ptr is a tagged pointer object. // Return true if ptr is a tagged pointer object.
// Does not check the validity of ptr's class. // Does not check the validity of ptr's class.
static inline bool static inline bool
_objc_isTaggedPointer(const void *ptr); _objc_isTaggedPointer(const void * _Nullable ptr);
// Extract the tag value from the given tagged pointer object. // Extract the tag value from the given tagged pointer object.
// Assumes ptr is a valid tagged pointer object. // Assumes ptr is a valid tagged pointer object.
// Does not check the validity of ptr's tag. // Does not check the validity of ptr's tag.
static inline objc_tag_index_t static inline objc_tag_index_t
_objc_getTaggedPointerTag(const void *ptr); _objc_getTaggedPointerTag(const void * _Nullable ptr);
// Extract the payload from the given tagged pointer object. // Extract the payload from the given tagged pointer object.
// Assumes ptr is a valid tagged pointer object. // Assumes ptr is a valid tagged pointer object.
// The payload value is zero-extended. // The payload value is zero-extended.
static inline uintptr_t static inline uintptr_t
_objc_getTaggedPointerValue(const void *ptr); _objc_getTaggedPointerValue(const void * _Nullable ptr);
// Extract the payload from the given tagged pointer object. // Extract the payload from the given tagged pointer object.
// Assumes ptr is a valid tagged pointer object. // Assumes ptr is a valid tagged pointer object.
// The payload value is sign-extended. // The payload value is sign-extended.
static inline intptr_t static inline intptr_t
_objc_getTaggedPointerSignedValue(const void *ptr); _objc_getTaggedPointerSignedValue(const void * _Nullable ptr);
// Don't use the values below. Use the declarations above. // Don't use the values below. Use the declarations above.
#if TARGET_OS_OSX && __x86_64__ #if (TARGET_OS_OSX || TARGET_OS_IOSMAC) && __x86_64__
// 64-bit Mac - tag bit is LSB // 64-bit Mac - tag bit is LSB
# define OBJC_MSB_TAGGED_POINTERS 0 # define OBJC_MSB_TAGGED_POINTERS 0
#else #else
@ -262,29 +369,43 @@ _objc_getTaggedPointerSignedValue(const void *ptr);
#define _OBJC_TAG_EXT_SLOT_MASK 0xff #define _OBJC_TAG_EXT_SLOT_MASK 0xff
#if OBJC_MSB_TAGGED_POINTERS #if OBJC_MSB_TAGGED_POINTERS
# define _OBJC_TAG_MASK (1ULL<<63) # define _OBJC_TAG_MASK (1UL<<63)
# define _OBJC_TAG_INDEX_SHIFT 60 # define _OBJC_TAG_INDEX_SHIFT 60
# define _OBJC_TAG_SLOT_SHIFT 60 # define _OBJC_TAG_SLOT_SHIFT 60
# define _OBJC_TAG_PAYLOAD_LSHIFT 4 # define _OBJC_TAG_PAYLOAD_LSHIFT 4
# define _OBJC_TAG_PAYLOAD_RSHIFT 4 # define _OBJC_TAG_PAYLOAD_RSHIFT 4
# define _OBJC_TAG_EXT_MASK (0xfULL<<60) # define _OBJC_TAG_EXT_MASK (0xfUL<<60)
# define _OBJC_TAG_EXT_INDEX_SHIFT 52 # define _OBJC_TAG_EXT_INDEX_SHIFT 52
# define _OBJC_TAG_EXT_SLOT_SHIFT 52 # define _OBJC_TAG_EXT_SLOT_SHIFT 52
# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 12 # define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 12
# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12 # define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
#else #else
# define _OBJC_TAG_MASK 1 # define _OBJC_TAG_MASK 1UL
# define _OBJC_TAG_INDEX_SHIFT 1 # define _OBJC_TAG_INDEX_SHIFT 1
# define _OBJC_TAG_SLOT_SHIFT 0 # define _OBJC_TAG_SLOT_SHIFT 0
# define _OBJC_TAG_PAYLOAD_LSHIFT 0 # define _OBJC_TAG_PAYLOAD_LSHIFT 0
# define _OBJC_TAG_PAYLOAD_RSHIFT 4 # define _OBJC_TAG_PAYLOAD_RSHIFT 4
# define _OBJC_TAG_EXT_MASK 0xfULL # define _OBJC_TAG_EXT_MASK 0xfUL
# define _OBJC_TAG_EXT_INDEX_SHIFT 4 # define _OBJC_TAG_EXT_INDEX_SHIFT 4
# define _OBJC_TAG_EXT_SLOT_SHIFT 4 # define _OBJC_TAG_EXT_SLOT_SHIFT 4
# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 0 # define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 0
# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12 # define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
#endif #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 static inline bool
_objc_taggedPointersEnabled(void) _objc_taggedPointersEnabled(void)
{ {
@ -292,42 +413,45 @@ _objc_taggedPointersEnabled(void)
return (objc_debug_taggedpointer_mask != 0); return (objc_debug_taggedpointer_mask != 0);
} }
static inline void * static inline void * _Nonnull
_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t value) _objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t value)
{ {
// PAYLOAD_LSHIFT and PAYLOAD_RSHIFT are the payload extraction shifts. // PAYLOAD_LSHIFT and PAYLOAD_RSHIFT are the payload extraction shifts.
// They are reversed here for payload insertion. // They are reversed here for payload insertion.
// assert(_objc_taggedPointersEnabled()); // ASSERT(_objc_taggedPointersEnabled());
if (tag <= OBJC_TAG_Last60BitPayload) { if (tag <= OBJC_TAG_Last60BitPayload) {
// assert(((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT) == value); // ASSERT(((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT) == value);
return (void*) uintptr_t result =
(_OBJC_TAG_MASK | (_OBJC_TAG_MASK |
((uintptr_t)tag << _OBJC_TAG_INDEX_SHIFT) | ((uintptr_t)tag << _OBJC_TAG_INDEX_SHIFT) |
((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT)); ((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT));
return _objc_encodeTaggedPointer(result);
} else { } else {
// assert(tag >= OBJC_TAG_First52BitPayload); // ASSERT(tag >= OBJC_TAG_First52BitPayload);
// assert(tag <= OBJC_TAG_Last52BitPayload); // ASSERT(tag <= OBJC_TAG_Last52BitPayload);
// assert(((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT) == value); // ASSERT(((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT) == value);
return (void*) uintptr_t result =
(_OBJC_TAG_EXT_MASK | (_OBJC_TAG_EXT_MASK |
((uintptr_t)(tag - OBJC_TAG_First52BitPayload) << _OBJC_TAG_EXT_INDEX_SHIFT) | ((uintptr_t)(tag - OBJC_TAG_First52BitPayload) << _OBJC_TAG_EXT_INDEX_SHIFT) |
((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT)); ((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT));
return _objc_encodeTaggedPointer(result);
} }
} }
static inline bool static inline bool
_objc_isTaggedPointer(const void *ptr) _objc_isTaggedPointer(const void * _Nullable ptr)
{ {
return ((intptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK; return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
} }
static inline objc_tag_index_t static inline objc_tag_index_t
_objc_getTaggedPointerTag(const void *ptr) _objc_getTaggedPointerTag(const void * _Nullable ptr)
{ {
// assert(_objc_isTaggedPointer(ptr)); // ASSERT(_objc_isTaggedPointer(ptr));
uintptr_t basicTag = ((uintptr_t)ptr >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK; uintptr_t value = _objc_decodeTaggedPointer(ptr);
uintptr_t extTag = ((uintptr_t)ptr >> _OBJC_TAG_EXT_INDEX_SHIFT) & _OBJC_TAG_EXT_INDEX_MASK; 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) { if (basicTag == _OBJC_TAG_INDEX_MASK) {
return (objc_tag_index_t)(extTag + OBJC_TAG_First52BitPayload); return (objc_tag_index_t)(extTag + OBJC_TAG_First52BitPayload);
} else { } else {
@ -336,26 +460,28 @@ _objc_getTaggedPointerTag(const void *ptr)
} }
static inline uintptr_t static inline uintptr_t
_objc_getTaggedPointerValue(const void *ptr) _objc_getTaggedPointerValue(const void * _Nullable ptr)
{ {
// assert(_objc_isTaggedPointer(ptr)); // ASSERT(_objc_isTaggedPointer(ptr));
uintptr_t basicTag = ((uintptr_t)ptr >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK; uintptr_t value = _objc_decodeTaggedPointer(ptr);
uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
if (basicTag == _OBJC_TAG_INDEX_MASK) { if (basicTag == _OBJC_TAG_INDEX_MASK) {
return ((uintptr_t)ptr << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT; return (value << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
} else { } else {
return ((uintptr_t)ptr << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT; return (value << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;
} }
} }
static inline intptr_t static inline intptr_t
_objc_getTaggedPointerSignedValue(const void *ptr) _objc_getTaggedPointerSignedValue(const void * _Nullable ptr)
{ {
// assert(_objc_isTaggedPointer(ptr)); // ASSERT(_objc_isTaggedPointer(ptr));
uintptr_t basicTag = ((uintptr_t)ptr >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK; uintptr_t value = _objc_decodeTaggedPointer(ptr);
uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
if (basicTag == _OBJC_TAG_INDEX_MASK) { if (basicTag == _OBJC_TAG_INDEX_MASK) {
return ((intptr_t)ptr << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT; return ((intptr_t)value << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
} else { } else {
return ((intptr_t)ptr << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT; return ((intptr_t)value << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;
} }
} }
@ -376,22 +502,78 @@ _objc_getTaggedPointerSignedValue(const void *ptr)
* *
* class_getMethodImplementation(object_getClass(obj), name); * class_getMethodImplementation(object_getClass(obj), name);
*/ */
OBJC_EXPORT IMP object_getMethodImplementation(id obj, SEL name) OBJC_EXPORT IMP _Nonnull
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0); object_getMethodImplementation(id _Nullable obj, SEL _Nonnull name)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
OBJC_EXPORT IMP object_getMethodImplementation_stret(id obj, SEL name) OBJC_EXPORT IMP _Nonnull
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0) object_getMethodImplementation_stret(id _Nullable obj, SEL _Nonnull name)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0)
OBJC_ARM64_UNAVAILABLE; OBJC_ARM64_UNAVAILABLE;
// Instance-specific instance variable layout. /**
* 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;
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 "Unknown" includes non-object ivars and non-ARC non-__weak ivars
@ -406,230 +588,299 @@ typedef enum {
objc_ivar_memoryUnretained // direct access / direct access objc_ivar_memoryUnretained // direct access / direct access
} objc_ivar_memory_management_t; } objc_ivar_memory_management_t;
OBJC_EXPORT objc_ivar_memory_management_t _class_getIvarMemoryManagement(Class cls, Ivar ivar) OBJC_EXPORT objc_ivar_memory_management_t
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0); _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 cls) OBJC_EXPORT BOOL _class_isFutureClass(Class _Nullable cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0); OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
// API to only be called by root classes like NSObject or NSProxy // API to only be called by root classes like NSObject or NSProxy
OBJC_EXPORT OBJC_EXPORT
id id _Nonnull
_objc_rootRetain(id obj) _objc_rootRetain(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
void void
_objc_rootRelease(id obj) _objc_rootRelease(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
bool bool
_objc_rootReleaseWasZero(id obj) _objc_rootReleaseWasZero(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
bool bool
_objc_rootTryRetain(id obj) _objc_rootTryRetain(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
bool bool
_objc_rootIsDeallocating(id obj) _objc_rootIsDeallocating(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
id id _Nonnull
_objc_rootAutorelease(id obj) _objc_rootAutorelease(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
uintptr_t uintptr_t
_objc_rootRetainCount(id obj) _objc_rootRetainCount(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
id id _Nonnull
_objc_rootInit(id obj) _objc_rootInit(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
id id _Nullable
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone) _objc_rootAllocWithZone(Class _Nonnull cls, malloc_zone_t * _Nullable zone)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
id id _Nullable
_objc_rootAlloc(Class cls) _objc_rootAlloc(Class _Nonnull cls)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
void void
_objc_rootDealloc(id obj) _objc_rootDealloc(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
void void
_objc_rootFinalize(id obj) _objc_rootFinalize(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
malloc_zone_t * malloc_zone_t * _Nonnull
_objc_rootZone(id obj) _objc_rootZone(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
uintptr_t uintptr_t
_objc_rootHash(id obj) _objc_rootHash(id _Nonnull obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
void * void * _Nonnull
objc_autoreleasePoolPush(void) objc_autoreleasePoolPush(void)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT
void void
objc_autoreleasePoolPop(void *context) objc_autoreleasePoolPop(void * _Nonnull context)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT id objc_alloc(Class cls) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0); objc_alloc(Class _Nullable cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
OBJC_EXPORT id objc_allocWithZone(Class cls) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0); objc_allocWithZone(Class _Nullable cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
OBJC_EXPORT id objc_retain(id obj) OBJC_EXPORT id _Nullable
objc_alloc_init(Class _Nullable cls)
OBJC_AVAILABLE(10.14.4, 12.2, 12.2, 5.2, 3.2);
OBJC_EXPORT id _Nullable
objc_opt_new(Class _Nullable cls)
OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
OBJC_EXPORT id _Nullable
objc_opt_self(id _Nullable obj)
OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
OBJC_EXPORT Class _Nullable
objc_opt_class(id _Nullable obj)
OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
OBJC_EXPORT BOOL
objc_opt_respondsToSelector(id _Nullable obj, SEL _Nullable sel)
OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
OBJC_EXPORT BOOL
objc_opt_isKindOfClass(id _Nullable obj, Class _Nullable cls)
OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
OBJC_EXPORT BOOL
objc_sync_try_enter(id _Nonnull obj)
OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
OBJC_EXPORT id _Nullable
objc_retain(id _Nullable obj)
__asm__("_objc_retain") __asm__("_objc_retain")
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void objc_release(id obj) OBJC_EXPORT void
objc_release(id _Nullable obj)
__asm__("_objc_release") __asm__("_objc_release")
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT id objc_autorelease(id obj) OBJC_EXPORT id _Nullable
objc_autorelease(id _Nullable obj)
__asm__("_objc_autorelease") __asm__("_objc_autorelease")
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
// Prepare a value at +1 for return through a +0 autoreleasing convention. // Prepare a value at +1 for return through a +0 autoreleasing convention.
OBJC_EXPORT OBJC_EXPORT id _Nullable
id objc_autoreleaseReturnValue(id _Nullable obj)
objc_autoreleaseReturnValue(id obj) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Prepare a value at +0 for return through a +0 autoreleasing convention. // Prepare a value at +0 for return through a +0 autoreleasing convention.
OBJC_EXPORT OBJC_EXPORT id _Nullable
id objc_retainAutoreleaseReturnValue(id _Nullable obj)
objc_retainAutoreleaseReturnValue(id obj) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Accept a value returned through a +0 autoreleasing convention for use at +1. // Accept a value returned through a +0 autoreleasing convention for use at +1.
OBJC_EXPORT OBJC_EXPORT id _Nullable
id objc_retainAutoreleasedReturnValue(id _Nullable obj)
objc_retainAutoreleasedReturnValue(id obj) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Accept a value returned through a +0 autoreleasing convention for use at +0. // Accept a value returned through a +0 autoreleasing convention for use at +0.
OBJC_EXPORT OBJC_EXPORT id _Nullable
id objc_unsafeClaimAutoreleasedReturnValue(id _Nullable obj)
objc_unsafeClaimAutoreleasedReturnValue(id obj) OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0);
OBJC_EXPORT OBJC_EXPORT void
void objc_storeStrong(id _Nullable * _Nonnull location, id _Nullable obj)
objc_storeStrong(id *location, id obj) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT OBJC_EXPORT id _Nullable
id objc_retainAutorelease(id _Nullable obj)
objc_retainAutorelease(id obj) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// obsolete. // obsolete.
OBJC_EXPORT id objc_retain_autorelease(id obj) OBJC_EXPORT id _Nullable
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); objc_retain_autorelease(id _Nullable obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT id _Nullable
id objc_loadWeakRetained(id _Nullable * _Nonnull location)
objc_loadWeakRetained(id *location) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT OBJC_EXPORT id _Nullable
id objc_initWeak(id _Nullable * _Nonnull location, id _Nullable val)
objc_initWeak(id *location, id val) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Like objc_storeWeak, but stores nil if the new object is deallocating // Like objc_storeWeak, but stores nil if the new object is deallocating
// or the new object's class does not support weak references. // or the new object's class does not support weak references.
// Returns the value stored (either the new object or nil). // Returns the value stored (either the new object or nil).
OBJC_EXPORT OBJC_EXPORT id _Nullable
id objc_storeWeakOrNil(id _Nullable * _Nonnull location, id _Nullable obj)
objc_storeWeakOrNil(id *location, id obj) OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0);
// Like objc_initWeak, but stores nil if the new object is deallocating // Like objc_initWeak, but stores nil if the new object is deallocating
// or the new object's class does not support weak references. // or the new object's class does not support weak references.
// Returns the value stored (either the new object or nil). // Returns the value stored (either the new object or nil).
OBJC_EXPORT OBJC_EXPORT id _Nullable
id objc_initWeakOrNil(id _Nullable * _Nonnull location, id _Nullable val)
objc_initWeakOrNil(id *location, id val) OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0);
OBJC_EXPORT OBJC_EXPORT void
void objc_destroyWeak(id _Nullable * _Nonnull location)
objc_destroyWeak(id *location) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT OBJC_EXPORT void
void objc_copyWeak(id _Nullable * _Nonnull to, id _Nullable * _Nonnull from)
objc_copyWeak(id *to, id *from) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT OBJC_EXPORT void
void objc_moveWeak(id _Nullable * _Nonnull to, id _Nullable * _Nonnull from)
objc_moveWeak(id *to, id *from) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT OBJC_EXPORT void
void
_objc_autoreleasePoolPrint(void) _objc_autoreleasePoolPrint(void)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT BOOL objc_should_deallocate(id object) OBJC_EXPORT BOOL
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); 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 object) OBJC_EXPORT void
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); objc_clear_deallocating(id _Nonnull object)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
// to make CF link for now // to make CF link for now
OBJC_EXPORT OBJC_EXPORT void * _Nonnull
void *
_objc_autoreleasePoolPush(void) _objc_autoreleasePoolPush(void)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0); OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT OBJC_EXPORT void
void _objc_autoreleasePoolPop(void * _Nonnull context)
_objc_autoreleasePoolPop(void *context) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
/**
* Load a classref, which is a chunk of data containing a class
* pointer. May perform initialization and rewrite the classref to
* point to a new object, if needed. Returns the loaded Class.
*
* In particular, if the classref points to a stub class (indicated
* by setting the bottom bit of the class pointer to 1), then this
* will call the stub's initializer and then replace the classref
* value with the value returned by the initializer.
*
* @param clsref The classref to load.
* @return The loaded Class pointer.
*/
#if __OBJC2__
OBJC_EXPORT _Nullable Class
objc_loadClassref(_Nullable Class * _Nonnull clsref)
OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
#endif
// Extra @encode data for XPC, or NULL // Extra @encode data for XPC, or NULL
OBJC_EXPORT const char *_protocol_getMethodTypeEncoding(Protocol *p, SEL sel, BOOL isRequiredMethod, BOOL isInstanceMethod) OBJC_EXPORT const char * _Nullable
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0); _protocol_getMethodTypeEncoding(Protocol * _Nonnull proto, SEL _Nonnull sel,
BOOL isRequiredMethod, BOOL isInstanceMethod)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
/**
* Function type for a function that is called when a realized class
* is about to be initialized.
*
* @param context The context pointer the function was registered with.
* @param cls The class that's about to be initialized.
*/
struct mach_header;
typedef void (*_objc_func_willInitializeClass)(void * _Nullable context, Class _Nonnull cls);
/**
* Add a function to be called when a realized class is about to be
* initialized. The class can be queried and manipulated using runtime
* functions. Don't message it.
*
* When adding a new function, that function is immediately called with all
* realized classes that are already initialized or are in the process
* of initialization.
*
* @param func The function to add.
* @param context A context pointer that will be passed to the function when called.
*/
#define OBJC_WILLINITIALIZECLASSFUNC_DEFINED 1
OBJC_EXPORT void _objc_addWillInitializeClassFunc(_objc_func_willInitializeClass _Nonnull func, void * _Nullable context)
OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 4.0);
// API to only be called by classes that provide their own reference count storage // API to only be called by classes that provide their own reference count storage
OBJC_EXPORT OBJC_EXPORT void
void _objc_deallocOnMainThreadHelper(void * _Nullable context)
_objc_deallocOnMainThreadHelper(void *context) OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// On async versus sync deallocation and the _dealloc2main flag // On async versus sync deallocation and the _dealloc2main flag
// //

View File

@ -338,8 +338,8 @@ layout_bitmap_grow(layout_bitmap *bits, size_t newCount)
realloc(bits->bits, (newAllocated+7) / 8); realloc(bits->bits, (newAllocated+7) / 8);
bits->bitsAllocated = newAllocated; bits->bitsAllocated = newAllocated;
} }
assert(bits->bitsAllocated >= bits->bitCount); ASSERT(bits->bitsAllocated >= bits->bitCount);
assert(bits->bitsAllocated >= newCount); ASSERT(bits->bitsAllocated >= newCount);
} }

View File

@ -35,20 +35,21 @@
/* dynamically loading Mach-O object files that contain Objective-C code */ /* dynamically loading Mach-O object files that contain Objective-C code */
OBJC_EXPORT long objc_loadModules ( OBJC_EXPORT long objc_loadModules (
char *modlist[], char * _Nullable modlist[_Nullable],
void *errStream, void * _Nullable errStream,
void (*class_callback) (Class, Category), void (* _Nullable class_callback) (Class _Nullable, Category _Nullable),
/*headerType*/ struct mach_header **hdr_addr, /*headerType*/ struct mach_header * _Nullable * _Nullable hdr_addr,
char *debug_file char * _Nullable debug_file
) OBJC2_UNAVAILABLE; ) OBJC2_UNAVAILABLE;
OBJC_EXPORT int objc_loadModule ( OBJC_EXPORT int objc_loadModule (
char * moduleName, char * _Nullable moduleName,
void (*class_callback) (Class, Category), void (* _Nullable class_callback) (Class _Nullable, Category _Nullable),
int * errorCode int * _Nullable errorCode
) OBJC2_UNAVAILABLE; ) OBJC2_UNAVAILABLE;
OBJC_EXPORT long objc_unloadModules( OBJC_EXPORT long objc_unloadModules(
void *errorStream, /* input (optional) */ void * _Nullable errorStream, /* input (optional) */
void (*unloadCallback)(Class, Category) /* input (optional) */ void (* _Nullable unloadCallback)(Class _Nullable, Category _Nullable) /* input (optional) */
) OBJC2_UNAVAILABLE; ) OBJC2_UNAVAILABLE;
#endif /* _OBJC_LOAD_H_ */ #endif /* _OBJC_LOAD_H_ */

View File

@ -201,7 +201,7 @@ static void call_class_loads(void)
if (PrintLoading) { if (PrintLoading) {
_objc_inform("LOAD: +[%s load]\n", cls->nameForLogging()); _objc_inform("LOAD: +[%s load]\n", cls->nameForLogging());
} }
(*load_method)(cls, SEL_load); (*load_method)(cls, @selector(load));
} }
// Destroy the detached list. // Destroy the detached list.
@ -248,7 +248,7 @@ static bool call_category_loads(void)
cls->nameForLogging(), cls->nameForLogging(),
_category_getName(cat)); _category_getName(cat));
} }
(*load_method)(cls, SEL_load); (*load_method)(cls, @selector(load));
cats[i].cat = nil; cats[i].cat = nil;
} }
} }

View File

@ -21,32 +21,50 @@
* @APPLE_LICENSE_HEADER_END@ * @APPLE_LICENSE_HEADER_END@
*/ */
#if LOCKDEBUG
extern void lockdebug_assert_all_locks_locked();
extern void lockdebug_assert_no_locks_locked();
extern void lockdebug_setInForkPrepare(bool);
extern void lockdebug_lock_precedes_lock(const void *oldlock, const void *newlock);
#else
static constexpr inline void lockdebug_assert_all_locks_locked() { }
static constexpr inline void lockdebug_assert_no_locks_locked() { }
static constexpr inline void lockdebug_setInForkPrepare(bool) { }
static constexpr inline void lockdebug_lock_precedes_lock(const void *, const void *) { }
#endif
extern void lockdebug_remember_mutex(mutex_tt<true> *lock);
extern void lockdebug_mutex_lock(mutex_tt<true> *lock); extern void lockdebug_mutex_lock(mutex_tt<true> *lock);
extern void lockdebug_mutex_try_lock(mutex_tt<true> *lock); extern void lockdebug_mutex_try_lock(mutex_tt<true> *lock);
extern void lockdebug_mutex_unlock(mutex_tt<true> *lock); extern void lockdebug_mutex_unlock(mutex_tt<true> *lock);
extern void lockdebug_mutex_assert_locked(mutex_tt<true> *lock); extern void lockdebug_mutex_assert_locked(mutex_tt<true> *lock);
extern void lockdebug_mutex_assert_unlocked(mutex_tt<true> *lock); extern void lockdebug_mutex_assert_unlocked(mutex_tt<true> *lock);
static inline void lockdebug_mutex_lock(mutex_tt<false> *lock) { } static constexpr inline void lockdebug_remember_mutex(mutex_tt<false> *lock) { }
static inline void lockdebug_mutex_try_lock(mutex_tt<false> *lock) { } static constexpr inline void lockdebug_mutex_lock(mutex_tt<false> *lock) { }
static inline void lockdebug_mutex_unlock(mutex_tt<false> *lock) { } static constexpr inline void lockdebug_mutex_try_lock(mutex_tt<false> *lock) { }
static inline void lockdebug_mutex_assert_locked(mutex_tt<false> *lock) { } static constexpr inline void lockdebug_mutex_unlock(mutex_tt<false> *lock) { }
static inline void lockdebug_mutex_assert_unlocked(mutex_tt<false> *lock) { } static constexpr inline void lockdebug_mutex_assert_locked(mutex_tt<false> *lock) { }
static constexpr inline void lockdebug_mutex_assert_unlocked(mutex_tt<false> *lock) { }
extern void lockdebug_remember_monitor(monitor_tt<true> *lock);
extern void lockdebug_monitor_enter(monitor_tt<true> *lock); extern void lockdebug_monitor_enter(monitor_tt<true> *lock);
extern void lockdebug_monitor_leave(monitor_tt<true> *lock); extern void lockdebug_monitor_leave(monitor_tt<true> *lock);
extern void lockdebug_monitor_wait(monitor_tt<true> *lock); extern void lockdebug_monitor_wait(monitor_tt<true> *lock);
extern void lockdebug_monitor_assert_locked(monitor_tt<true> *lock); extern void lockdebug_monitor_assert_locked(monitor_tt<true> *lock);
extern void lockdebug_monitor_assert_unlocked(monitor_tt<true> *lock); extern void lockdebug_monitor_assert_unlocked(monitor_tt<true> *lock);
static inline void lockdebug_monitor_enter(monitor_tt<false> *lock) { } static constexpr inline void lockdebug_remember_monitor(monitor_tt<false> *lock) { }
static inline void lockdebug_monitor_leave(monitor_tt<false> *lock) { } static constexpr inline void lockdebug_monitor_enter(monitor_tt<false> *lock) { }
static inline void lockdebug_monitor_wait(monitor_tt<false> *lock) { } static constexpr inline void lockdebug_monitor_leave(monitor_tt<false> *lock) { }
static inline void lockdebug_monitor_assert_locked(monitor_tt<false> *lock) { } static constexpr inline void lockdebug_monitor_wait(monitor_tt<false> *lock) { }
static inline void lockdebug_monitor_assert_unlocked(monitor_tt<false> *lock) {} static constexpr inline void lockdebug_monitor_assert_locked(monitor_tt<false> *lock) { }
static constexpr inline void lockdebug_monitor_assert_unlocked(monitor_tt<false> *lock) {}
extern void
lockdebug_remember_recursive_mutex(recursive_mutex_tt<true> *lock);
extern void extern void
lockdebug_recursive_mutex_lock(recursive_mutex_tt<true> *lock); lockdebug_recursive_mutex_lock(recursive_mutex_tt<true> *lock);
extern void extern void
@ -56,34 +74,13 @@ lockdebug_recursive_mutex_assert_locked(recursive_mutex_tt<true> *lock);
extern void extern void
lockdebug_recursive_mutex_assert_unlocked(recursive_mutex_tt<true> *lock); lockdebug_recursive_mutex_assert_unlocked(recursive_mutex_tt<true> *lock);
static inline void static constexpr inline void
lockdebug_remember_recursive_mutex(recursive_mutex_tt<false> *lock) { }
static constexpr inline void
lockdebug_recursive_mutex_lock(recursive_mutex_tt<false> *lock) { } lockdebug_recursive_mutex_lock(recursive_mutex_tt<false> *lock) { }
static inline void static constexpr inline void
lockdebug_recursive_mutex_unlock(recursive_mutex_tt<false> *lock) { } lockdebug_recursive_mutex_unlock(recursive_mutex_tt<false> *lock) { }
static inline void static constexpr inline void
lockdebug_recursive_mutex_assert_locked(recursive_mutex_tt<false> *lock) { } lockdebug_recursive_mutex_assert_locked(recursive_mutex_tt<false> *lock) { }
static inline void static constexpr inline void
lockdebug_recursive_mutex_assert_unlocked(recursive_mutex_tt<false> *lock) { } lockdebug_recursive_mutex_assert_unlocked(recursive_mutex_tt<false> *lock) { }
extern void lockdebug_rwlock_read(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_try_read_success(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_unlock_read(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_write(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_try_write_success(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_unlock_write(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_assert_reading(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_assert_writing(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_assert_locked(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_assert_unlocked(rwlock_tt<true> *lock);
static inline void lockdebug_rwlock_read(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_try_read_success(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_unlock_read(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_write(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_try_write_success(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_unlock_write(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_assert_reading(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_assert_writing(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_assert_locked(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_assert_unlocked(rwlock_tt<false> *) { }

View File

@ -28,117 +28,253 @@
#include "objc-private.h" #include "objc-private.h"
#if DEBUG && !TARGET_OS_WIN32 #if LOCKDEBUG && !TARGET_OS_WIN32
#include <unordered_map>
/***********************************************************************
* Thread-local bool set during _objc_atfork_prepare().
* That function is allowed to break some lock ordering rules.
**********************************************************************/
static tls_key_t fork_prepare_tls;
void
lockdebug_setInForkPrepare(bool inForkPrepare)
{
INIT_ONCE_PTR(fork_prepare_tls, tls_create(nil), (void)0);
tls_set(fork_prepare_tls, (void*)inForkPrepare);
}
static bool
inForkPrepare()
{
INIT_ONCE_PTR(fork_prepare_tls, tls_create(nil), (void)0);
return (bool)tls_get(fork_prepare_tls);
}
/***********************************************************************
* Lock order graph.
* "lock X precedes lock Y" means that X must be acquired first.
* This property is transitive.
**********************************************************************/
struct lockorder {
const void *l;
std::vector<const lockorder *> predecessors;
mutable std::unordered_map<const lockorder *, bool> memo;
lockorder(const void *newl) : l(newl) { }
};
static std::unordered_map<const void*, lockorder *> lockOrderList;
// not mutex_t because we don't want lock debugging on this lock
static mutex_tt<false> lockOrderLock;
static bool
lockPrecedesLock(const lockorder *oldlock, const lockorder *newlock)
{
auto memoed = newlock->memo.find(oldlock);
if (memoed != newlock->memo.end()) {
return memoed->second;
}
bool result = false;
for (const auto *pre : newlock->predecessors) {
if (oldlock == pre || lockPrecedesLock(oldlock, pre)) {
result = true;
break;
}
}
newlock->memo[oldlock] = result;
return result;
}
static bool
lockPrecedesLock(const void *oldlock, const void *newlock)
{
mutex_tt<false>::locker lock(lockOrderLock);
auto oldorder = lockOrderList.find(oldlock);
auto neworder = lockOrderList.find(newlock);
if (neworder == lockOrderList.end() || oldorder == lockOrderList.end()) {
return false;
}
return lockPrecedesLock(oldorder->second, neworder->second);
}
static bool
lockUnorderedWithLock(const void *oldlock, const void *newlock)
{
mutex_tt<false>::locker lock(lockOrderLock);
auto oldorder = lockOrderList.find(oldlock);
auto neworder = lockOrderList.find(newlock);
if (neworder == lockOrderList.end() || oldorder == lockOrderList.end()) {
return true;
}
if (lockPrecedesLock(oldorder->second, neworder->second) ||
lockPrecedesLock(neworder->second, oldorder->second))
{
return false;
}
return true;
}
void lockdebug_lock_precedes_lock(const void *oldlock, const void *newlock)
{
if (lockPrecedesLock(newlock, oldlock)) {
_objc_fatal("contradiction in lock order declaration");
}
mutex_tt<false>::locker lock(lockOrderLock);
auto oldorder = lockOrderList.find(oldlock);
auto neworder = lockOrderList.find(newlock);
if (oldorder == lockOrderList.end()) {
lockOrderList[oldlock] = new lockorder(oldlock);
oldorder = lockOrderList.find(oldlock);
}
if (neworder == lockOrderList.end()) {
lockOrderList[newlock] = new lockorder(newlock);
neworder = lockOrderList.find(newlock);
}
neworder->second->predecessors.push_back(oldorder->second);
}
/*********************************************************************** /***********************************************************************
* Recording - per-thread list of mutexes and monitors held * Recording - per-thread list of mutexes and monitors held
**********************************************************************/ **********************************************************************/
typedef struct { enum class lockkind {
void *l; // the lock itself MUTEX = 1, MONITOR = 2, RDLOCK = 3, WRLOCK = 4, RECURSIVE = 5
int k; // the kind of lock it is (MUTEX, MONITOR, etc) };
int i; // the lock's nest count
} lockcount;
#define MUTEX 1 #define MUTEX lockkind::MUTEX
#define MONITOR 2 #define MONITOR lockkind::MONITOR
#define RDLOCK 3 #define RDLOCK lockkind::RDLOCK
#define WRLOCK 4 #define WRLOCK lockkind::WRLOCK
#define RECURSIVE 5 #define RECURSIVE lockkind::RECURSIVE
typedef struct _objc_lock_list { struct lockcount {
int allocated; lockkind k; // the kind of lock it is (MUTEX, MONITOR, etc)
int used; int i; // the lock's nest count
lockcount list[0]; };
} _objc_lock_list;
using objc_lock_list = std::unordered_map<const void *, lockcount>;
// Thread-local list of locks owned by a thread.
// Used by lock ownership checks.
static tls_key_t lock_tls; static tls_key_t lock_tls;
// Global list of all locks.
// Used by fork() safety check.
// This can't be a static struct because of C++ initialization order problems.
static objc_lock_list& AllLocks() {
static objc_lock_list *locks;
INIT_ONCE_PTR(locks, new objc_lock_list, (void)0);
return *locks;
}
static void static void
destroyLocks(void *value) destroyLocks(void *value)
{ {
_objc_lock_list *locks = (_objc_lock_list *)value; auto locks = (objc_lock_list *)value;
// fixme complain about any still-held locks? // fixme complain about any still-held locks?
if (locks) free(locks); if (locks) delete locks;
} }
static struct _objc_lock_list * static objc_lock_list&
getLocks(BOOL create) ownedLocks()
{ {
_objc_lock_list *locks;
// Use a dedicated tls key to prevent differences vs non-debug in // Use a dedicated tls key to prevent differences vs non-debug in
// usage of objc's other tls keys (required for some unit tests). // usage of objc's other tls keys (required for some unit tests).
INIT_ONCE_PTR(lock_tls, tls_create(&destroyLocks), (void)0); INIT_ONCE_PTR(lock_tls, tls_create(&destroyLocks), (void)0);
locks = (_objc_lock_list *)tls_get(lock_tls); auto locks = (objc_lock_list *)tls_get(lock_tls);
if (!locks) { if (!locks) {
if (!create) { locks = new objc_lock_list;
return NULL; tls_set(lock_tls, locks);
} else {
locks = (_objc_lock_list *)calloc(1, sizeof(_objc_lock_list) + sizeof(lockcount) * 16);
locks->allocated = 16;
locks->used = 0;
tls_set(lock_tls, locks);
}
} }
if (locks->allocated == locks->used) { return *locks;
if (!create) {
return locks;
} else {
_objc_lock_list *oldlocks = locks;
locks = (_objc_lock_list *)calloc(1, sizeof(_objc_lock_list) + 2 * oldlocks->used * sizeof(lockcount));
locks->used = oldlocks->used;
locks->allocated = oldlocks->used * 2;
memcpy(locks->list, oldlocks->list, locks->used * sizeof(lockcount));
tls_set(lock_tls, locks);
free(oldlocks);
}
}
return locks;
} }
static BOOL static bool
hasLock(_objc_lock_list *locks, void *lock, int kind) hasLock(objc_lock_list& locks, const void *lock, lockkind kind)
{ {
int i; auto iter = locks.find(lock);
if (!locks) return NO; if (iter != locks.end() && iter->second.k == kind) return true;
return false;
for (i = 0; i < locks->used; i++) {
if (locks->list[i].l == lock && locks->list[i].k == kind) return YES;
}
return NO;
} }
static void static const char *sym(const void *lock)
setLock(_objc_lock_list *locks, void *lock, int kind)
{ {
int i; Dl_info info;
for (i = 0; i < locks->used; i++) { int ok = dladdr(lock, &info);
if (locks->list[i].l == lock && locks->list[i].k == kind) { if (ok && info.dli_sname && info.dli_sname[0]) return info.dli_sname;
locks->list[i].i++; else return "??";
return;
}
}
locks->list[locks->used].l = lock;
locks->list[locks->used].i = 1;
locks->list[locks->used].k = kind;
locks->used++;
} }
static void static void
clearLock(_objc_lock_list *locks, void *lock, int kind) setLock(objc_lock_list& locks, const void *lock, lockkind kind)
{ {
int i; // Check if we already own this lock.
for (i = 0; i < locks->used; i++) { auto iter = locks.find(lock);
if (locks->list[i].l == lock && locks->list[i].k == kind) { if (iter != locks.end() && iter->second.k == kind) {
if (--locks->list[i].i == 0) { iter->second.i++;
locks->list[i].l = NULL; return;
locks->list[i] = locks->list[--locks->used]; }
// Newly-acquired lock. Verify lock ordering.
// Locks not in AllLocks are exempt (i.e. @synchronize locks)
if (&locks != &AllLocks() && AllLocks().find(lock) != AllLocks().end()) {
for (auto& oldlock : locks) {
if (AllLocks().find(oldlock.first) == AllLocks().end()) {
// oldlock is exempt
continue;
}
if (lockPrecedesLock(lock, oldlock.first)) {
_objc_fatal("lock %p (%s) incorrectly acquired before %p (%s)",
oldlock.first, sym(oldlock.first), lock, sym(lock));
}
if (!inForkPrepare() &&
lockUnorderedWithLock(lock, oldlock.first))
{
// _objc_atfork_prepare is allowed to acquire
// otherwise-unordered locks, but nothing else may.
_objc_fatal("lock %p (%s) acquired before %p (%s) "
"with no defined lock order",
oldlock.first, sym(oldlock.first), lock, sym(lock));
}
}
}
locks[lock] = lockcount{kind, 1};
}
static void
clearLock(objc_lock_list& locks, const void *lock, lockkind kind)
{
auto iter = locks.find(lock);
if (iter != locks.end()) {
auto& l = iter->second;
if (l.k == kind) {
if (--l.i == 0) {
locks.erase(iter);
} }
return; return;
} }
@ -148,50 +284,62 @@ clearLock(_objc_lock_list *locks, void *lock, int kind)
} }
/***********************************************************************
* fork() safety checking
**********************************************************************/
void
lockdebug_remember_mutex(mutex_t *lock)
{
setLock(AllLocks(), lock, MUTEX);
}
void
lockdebug_remember_recursive_mutex(recursive_mutex_t *lock)
{
setLock(AllLocks(), lock, RECURSIVE);
}
void
lockdebug_remember_monitor(monitor_t *lock)
{
setLock(AllLocks(), lock, MONITOR);
}
void
lockdebug_assert_all_locks_locked()
{
auto& owned = ownedLocks();
for (const auto& l : AllLocks()) {
if (!hasLock(owned, l.first, l.second.k)) {
_objc_fatal("lock %p:%d is incorrectly not owned",
l.first, l.second.k);
}
}
}
void
lockdebug_assert_no_locks_locked()
{
auto& owned = ownedLocks();
for (const auto& l : AllLocks()) {
if (hasLock(owned, l.first, l.second.k)) {
_objc_fatal("lock %p:%d is incorrectly owned", l.first, l.second.k);
}
}
}
/*********************************************************************** /***********************************************************************
* Mutex checking * Mutex checking
**********************************************************************/ **********************************************************************/
#if !TARGET_OS_SIMULATOR
// Non-simulator platforms have lock debugging built into os_unfair_lock.
void void
lockdebug_mutex_lock(mutex_t *lock) lockdebug_mutex_lock(mutex_t *lock)
{ {
// empty auto& locks = ownedLocks();
}
void
lockdebug_mutex_unlock(mutex_t *lock)
{
// empty
}
void
lockdebug_mutex_assert_locked(mutex_t *lock)
{
os_unfair_lock_assert_owner((os_unfair_lock *)lock);
}
void
lockdebug_mutex_assert_unlocked(mutex_t *lock)
{
os_unfair_lock_assert_not_owner((os_unfair_lock *)lock);
}
// !TARGET_OS_SIMULATOR
#else
// TARGET_OS_SIMULATOR
// Simulator platforms have no built-in lock debugging in os_unfair_lock.
void
lockdebug_mutex_lock(mutex_t *lock)
{
_objc_lock_list *locks = getLocks(YES);
if (hasLock(locks, lock, MUTEX)) { if (hasLock(locks, lock, MUTEX)) {
_objc_fatal("deadlock: relocking mutex"); _objc_fatal("deadlock: relocking mutex");
@ -205,14 +353,14 @@ lockdebug_mutex_lock(mutex_t *lock)
void void
lockdebug_mutex_try_lock_success(mutex_t *lock) lockdebug_mutex_try_lock_success(mutex_t *lock)
{ {
_objc_lock_list *locks = getLocks(YES); auto& locks = ownedLocks();
setLock(locks, lock, MUTEX); setLock(locks, lock, MUTEX);
} }
void void
lockdebug_mutex_unlock(mutex_t *lock) lockdebug_mutex_unlock(mutex_t *lock)
{ {
_objc_lock_list *locks = getLocks(NO); auto& locks = ownedLocks();
if (!hasLock(locks, lock, MUTEX)) { if (!hasLock(locks, lock, MUTEX)) {
_objc_fatal("unlocking unowned mutex"); _objc_fatal("unlocking unowned mutex");
@ -224,7 +372,7 @@ lockdebug_mutex_unlock(mutex_t *lock)
void void
lockdebug_mutex_assert_locked(mutex_t *lock) lockdebug_mutex_assert_locked(mutex_t *lock)
{ {
_objc_lock_list *locks = getLocks(NO); auto& locks = ownedLocks();
if (!hasLock(locks, lock, MUTEX)) { if (!hasLock(locks, lock, MUTEX)) {
_objc_fatal("mutex incorrectly not locked"); _objc_fatal("mutex incorrectly not locked");
@ -234,7 +382,7 @@ lockdebug_mutex_assert_locked(mutex_t *lock)
void void
lockdebug_mutex_assert_unlocked(mutex_t *lock) lockdebug_mutex_assert_unlocked(mutex_t *lock)
{ {
_objc_lock_list *locks = getLocks(NO); auto& locks = ownedLocks();
if (hasLock(locks, lock, MUTEX)) { if (hasLock(locks, lock, MUTEX)) {
_objc_fatal("mutex incorrectly locked"); _objc_fatal("mutex incorrectly locked");
@ -242,24 +390,21 @@ lockdebug_mutex_assert_unlocked(mutex_t *lock)
} }
// TARGET_OS_SIMULATOR
#endif
/*********************************************************************** /***********************************************************************
* Recursive mutex checking * Recursive mutex checking
**********************************************************************/ **********************************************************************/
void void
lockdebug_recursive_mutex_lock(recursive_mutex_tt<true> *lock) lockdebug_recursive_mutex_lock(recursive_mutex_t *lock)
{ {
_objc_lock_list *locks = getLocks(YES); auto& locks = ownedLocks();
setLock(locks, lock, RECURSIVE); setLock(locks, lock, RECURSIVE);
} }
void void
lockdebug_recursive_mutex_unlock(recursive_mutex_tt<true> *lock) lockdebug_recursive_mutex_unlock(recursive_mutex_t *lock)
{ {
_objc_lock_list *locks = getLocks(NO); auto& locks = ownedLocks();
if (!hasLock(locks, lock, RECURSIVE)) { if (!hasLock(locks, lock, RECURSIVE)) {
_objc_fatal("unlocking unowned recursive mutex"); _objc_fatal("unlocking unowned recursive mutex");
@ -269,9 +414,9 @@ lockdebug_recursive_mutex_unlock(recursive_mutex_tt<true> *lock)
void void
lockdebug_recursive_mutex_assert_locked(recursive_mutex_tt<true> *lock) lockdebug_recursive_mutex_assert_locked(recursive_mutex_t *lock)
{ {
_objc_lock_list *locks = getLocks(NO); auto& locks = ownedLocks();
if (!hasLock(locks, lock, RECURSIVE)) { if (!hasLock(locks, lock, RECURSIVE)) {
_objc_fatal("recursive mutex incorrectly not locked"); _objc_fatal("recursive mutex incorrectly not locked");
@ -279,9 +424,9 @@ lockdebug_recursive_mutex_assert_locked(recursive_mutex_tt<true> *lock)
} }
void void
lockdebug_recursive_mutex_assert_unlocked(recursive_mutex_tt<true> *lock) lockdebug_recursive_mutex_assert_unlocked(recursive_mutex_t *lock)
{ {
_objc_lock_list *locks = getLocks(NO); auto& locks = ownedLocks();
if (hasLock(locks, lock, RECURSIVE)) { if (hasLock(locks, lock, RECURSIVE)) {
_objc_fatal("recursive mutex incorrectly locked"); _objc_fatal("recursive mutex incorrectly locked");
@ -296,7 +441,7 @@ lockdebug_recursive_mutex_assert_unlocked(recursive_mutex_tt<true> *lock)
void void
lockdebug_monitor_enter(monitor_t *lock) lockdebug_monitor_enter(monitor_t *lock)
{ {
_objc_lock_list *locks = getLocks(YES); auto& locks = ownedLocks();
if (hasLock(locks, lock, MONITOR)) { if (hasLock(locks, lock, MONITOR)) {
_objc_fatal("deadlock: relocking monitor"); _objc_fatal("deadlock: relocking monitor");
@ -307,7 +452,7 @@ lockdebug_monitor_enter(monitor_t *lock)
void void
lockdebug_monitor_leave(monitor_t *lock) lockdebug_monitor_leave(monitor_t *lock)
{ {
_objc_lock_list *locks = getLocks(NO); auto& locks = ownedLocks();
if (!hasLock(locks, lock, MONITOR)) { if (!hasLock(locks, lock, MONITOR)) {
_objc_fatal("unlocking unowned monitor"); _objc_fatal("unlocking unowned monitor");
@ -318,7 +463,7 @@ lockdebug_monitor_leave(monitor_t *lock)
void void
lockdebug_monitor_wait(monitor_t *lock) lockdebug_monitor_wait(monitor_t *lock)
{ {
_objc_lock_list *locks = getLocks(NO); auto& locks = ownedLocks();
if (!hasLock(locks, lock, MONITOR)) { if (!hasLock(locks, lock, MONITOR)) {
_objc_fatal("waiting in unowned monitor"); _objc_fatal("waiting in unowned monitor");
@ -329,7 +474,7 @@ lockdebug_monitor_wait(monitor_t *lock)
void void
lockdebug_monitor_assert_locked(monitor_t *lock) lockdebug_monitor_assert_locked(monitor_t *lock)
{ {
_objc_lock_list *locks = getLocks(NO); auto& locks = ownedLocks();
if (!hasLock(locks, lock, MONITOR)) { if (!hasLock(locks, lock, MONITOR)) {
_objc_fatal("monitor incorrectly not locked"); _objc_fatal("monitor incorrectly not locked");
@ -339,133 +484,11 @@ lockdebug_monitor_assert_locked(monitor_t *lock)
void void
lockdebug_monitor_assert_unlocked(monitor_t *lock) lockdebug_monitor_assert_unlocked(monitor_t *lock)
{ {
_objc_lock_list *locks = getLocks(NO); auto& locks = ownedLocks();
if (hasLock(locks, lock, MONITOR)) { if (hasLock(locks, lock, MONITOR)) {
_objc_fatal("monitor incorrectly held"); _objc_fatal("monitor incorrectly held");
} }
} }
/***********************************************************************
* rwlock checking
**********************************************************************/
void
lockdebug_rwlock_read(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(YES);
if (hasLock(locks, lock, RDLOCK)) {
// Recursive rwlock read is bad (may deadlock vs pending writer)
_objc_fatal("recursive rwlock read");
}
if (hasLock(locks, lock, WRLOCK)) {
_objc_fatal("deadlock: read after write for rwlock");
}
setLock(locks, lock, RDLOCK);
}
// try-read success is the only case with lockdebug effects.
// try-read when already reading is OK (won't deadlock)
// try-read when already writing is OK (will fail)
// try-read failure does nothing.
void
lockdebug_rwlock_try_read_success(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(YES);
setLock(locks, lock, RDLOCK);
}
void
lockdebug_rwlock_unlock_read(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, RDLOCK)) {
_objc_fatal("un-reading unowned rwlock");
}
clearLock(locks, lock, RDLOCK);
}
void
lockdebug_rwlock_write(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(YES);
if (hasLock(locks, lock, RDLOCK)) {
// Lock promotion not allowed (may deadlock)
_objc_fatal("deadlock: write after read for rwlock");
}
if (hasLock(locks, lock, WRLOCK)) {
_objc_fatal("recursive rwlock write");
}
setLock(locks, lock, WRLOCK);
}
// try-write success is the only case with lockdebug effects.
// try-write when already reading is OK (will fail)
// try-write when already writing is OK (will fail)
// try-write failure does nothing.
void
lockdebug_rwlock_try_write_success(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(YES);
setLock(locks, lock, WRLOCK);
}
void
lockdebug_rwlock_unlock_write(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, WRLOCK)) {
_objc_fatal("un-writing unowned rwlock");
}
clearLock(locks, lock, WRLOCK);
}
void
lockdebug_rwlock_assert_reading(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, RDLOCK)) {
_objc_fatal("rwlock incorrectly not reading");
}
}
void
lockdebug_rwlock_assert_writing(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, WRLOCK)) {
_objc_fatal("rwlock incorrectly not writing");
}
}
void
lockdebug_rwlock_assert_locked(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, RDLOCK) && !hasLock(locks, lock, WRLOCK)) {
_objc_fatal("rwlock incorrectly neither reading nor writing");
}
}
void
lockdebug_rwlock_assert_unlocked(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (hasLock(locks, lock, RDLOCK) || hasLock(locks, lock, WRLOCK)) {
_objc_fatal("rwlock incorrectly not unlocked");
}
}
#endif #endif

38
runtime/objc-locks-new.h Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2017 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-locks-new.h
* Declarations of all locks used in the runtime.
**********************************************************************/
#ifndef _OBJC_LOCKS_NEW_H
#define _OBJC_LOCKS_NEW_H
// fork() safety requires careful tracking of all locks used in the runtime.
// Thou shalt not declare any locks outside this file.
extern mutex_t runtimeLock;
extern mutex_t DemangleCacheLock;
#endif

40
runtime/objc-locks-old.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2017 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-locks-old.h
* Declarations of all locks used in the runtime.
**********************************************************************/
#ifndef _OBJC_LOCKS_OLD_H
#define _OBJC_LOCKS_OLD_H
// fork() safety requires careful tracking of all locks used in the runtime.
// Thou shalt not declare any locks outside this file.
extern mutex_t classLock;
extern mutex_t methodListLock;
extern mutex_t NXUniqueStringLock;
extern spinlock_t impLock;
#endif

68
runtime/objc-locks.h Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2017 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-locks.h
* Declarations of all locks used in the runtime.
**********************************************************************/
#ifndef _OBJC_LOCKS_H
#define _OBJC_LOCKS_H
// fork() safety requires careful tracking of all locks used in the runtime.
// Thou shalt not declare any locks outside this file.
// Lock ordering is declared in _objc_fork_prepare()
// and is enforced by lockdebug.
extern monitor_t classInitLock;
extern mutex_t selLock;
#if CONFIG_USE_CACHE_LOCK
extern mutex_t cacheUpdateLock;
#endif
extern recursive_mutex_t loadMethodLock;
extern mutex_t crashlog_lock;
extern spinlock_t objcMsgLogLock;
extern mutex_t AltHandlerDebugLock;
extern mutex_t AssociationsManagerLock;
extern StripedMap<spinlock_t> PropertyLocks;
extern StripedMap<spinlock_t> StructLocks;
extern StripedMap<spinlock_t> CppObjectLocks;
// SideTable lock is buried awkwardly. Call a function to manipulate it.
extern void SideTableLockAll();
extern void SideTableUnlockAll();
extern void SideTableForceResetAll();
extern void SideTableDefineLockOrder();
extern void SideTableLocksPrecedeLock(const void *newlock);
extern void SideTableLocksSucceedLock(const void *oldlock);
extern void SideTableLocksPrecedeLocks(StripedMap<spinlock_t>& newlocks);
extern void SideTableLocksSucceedLocks(StripedMap<spinlock_t>& oldlocks);
#if __OBJC2__
#include "objc-locks-new.h"
#else
#include "objc-locks-old.h"
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More