mirror of
https://github.com/darlinghq/darling-objc4.git
synced 2024-11-23 04:09:46 +00:00
objc4-781.2
This commit is contained in:
parent
1db0a624c9
commit
4d6225bbe3
1
interposable.txt
Normal file
1
interposable.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
_objc_release
|
@ -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
|
||||||
|
22
markgc.cpp
22
markgc.cpp
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
0
objcrt/objcrt.vcproj
Executable file → Normal file
0
prebuild.bat
Executable file → Normal file
0
prebuild.bat
Executable file → Normal file
86
runtime/DenseMapExtras.h
Normal file
86
runtime/DenseMapExtras.h
Normal 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 */
|
@ -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
382
runtime/Messengers.subproj/objc-msg-arm64.S
Executable file → Normal 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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
437
runtime/Module/ObjectiveC.apinotes
Normal file
437
runtime/Module/ObjectiveC.apinotes
Normal 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]
|
40
runtime/Module/module.modulemap
Normal file
40
runtime/Module/module.modulemap
Normal 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
|
||||||
|
}
|
@ -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
161
runtime/NSObject-internal.h
Normal 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
|
@ -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
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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
182
runtime/PointerUnion.h
Normal 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 */
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
174
runtime/arm64-asm.h
Normal 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
|
@ -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. */
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
@ -1 +0,0 @@
|
|||||||
../../NSObjCRuntime.h
|
|
@ -1 +0,0 @@
|
|||||||
../../NSObject.h
|
|
@ -1 +0,0 @@
|
|||||||
../../Object.h
|
|
@ -1 +0,0 @@
|
|||||||
../../Protocol.h
|
|
@ -1 +0,0 @@
|
|||||||
../../hashtable.h
|
|
@ -1 +0,0 @@
|
|||||||
../../hashtable2.h
|
|
@ -1 +0,0 @@
|
|||||||
../../maptable.h
|
|
@ -1 +0,0 @@
|
|||||||
../../message.h
|
|
@ -1 +0,0 @@
|
|||||||
../../objc-api.h
|
|
@ -1 +0,0 @@
|
|||||||
../../objc-auto.h
|
|
@ -1 +0,0 @@
|
|||||||
../../objc-class.h
|
|
@ -1 +0,0 @@
|
|||||||
../../objc-exception.h
|
|
@ -1 +0,0 @@
|
|||||||
../../objc-internal.h
|
|
@ -1 +0,0 @@
|
|||||||
../../objc-load.h
|
|
@ -1 +0,0 @@
|
|||||||
../../objc-runtime.h
|
|
@ -1 +0,0 @@
|
|||||||
../../objc-sync.h
|
|
@ -1 +0,0 @@
|
|||||||
../../objc.h
|
|
@ -1 +0,0 @@
|
|||||||
../../runtime.h
|
|
134
runtime/isa.h
Normal file
134
runtime/isa.h
Normal 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
@ -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
293
runtime/llvm-DenseSet.h
Normal 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
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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")
|
||||||
|
@ -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
|
||||||
|
71
runtime/objc-block-trampolines.h
Normal file
71
runtime/objc-block-trampolines.h
Normal 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
|
@ -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,
|
|
||||||
¤tProtection, &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,
|
||||||
|
¤tProtection, &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;
|
||||||
}
|
}
|
||||||
|
282
runtime/objc-blocktramps-arm.S
Normal file
282
runtime/objc-blocktramps-arm.S
Normal 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
|
@ -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
|
1102
runtime/objc-blocktramps-i386.S
Normal file
1102
runtime/objc-blocktramps-i386.S
Normal file
File diff suppressed because it is too large
Load Diff
1097
runtime/objc-blocktramps-x86_64.S
Normal file
1097
runtime/objc-blocktramps-x86_64.S
Normal file
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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")
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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 *
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
//
|
//
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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_ */
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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> *) { }
|
|
||||||
|
@ -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
38
runtime/objc-locks-new.h
Normal 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
40
runtime/objc-locks-old.h
Normal 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
68
runtime/objc-locks.h
Normal 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
Loading…
Reference in New Issue
Block a user