FLEXObjcInternal.mm 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. //
  2. // FLEXObjcInternal.mm
  3. // FLEX
  4. //
  5. // Created by Tanner Bennett on 11/1/18.
  6. //
  7. /*
  8. * Copyright (c) 2005-2007 Apple Inc. All Rights Reserved.
  9. *
  10. * @APPLE_LICENSE_HEADER_START@
  11. *
  12. * This file contains Original Code and/or Modifications of Original Code
  13. * as defined in and that are subject to the Apple Public Source License
  14. * Version 2.0 (the 'License'). You may not use this file except in
  15. * compliance with the License. Please obtain a copy of the License at
  16. * http://www.opensource.apple.com/apsl/ and read it before using this
  17. * file.
  18. *
  19. * The Original Code and all software distributed under the License are
  20. * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  21. * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  22. * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  24. * Please see the License for the specific language governing rights and
  25. * limitations under the License.
  26. *
  27. * @APPLE_LICENSE_HEADER_END@
  28. */
  29. #import "FLEXObjcInternal.h"
  30. #import <objc/runtime.h>
  31. #import <malloc/malloc.h>
  32. #define ALWAYS_INLINE inline __attribute__((always_inline))
  33. #define NEVER_INLINE inline __attribute__((noinline))
  34. // The macros below are copied straight from
  35. // objc-internal.h, objc-private.h, objc-object.h, and objc-config.h with
  36. // as few modifications as possible. Changes are noted in boxed comments.
  37. // https://opensource.apple.com/source/objc4/objc4-723/
  38. // https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-internal.h.auto.html
  39. // https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-private.h.auto.html
  40. // https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-config.h.auto.html
  41. // https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-object.h.auto.html
  42. /////////////////////
  43. // objc-internal.h //
  44. /////////////////////
  45. #if TARGET_OS_OSX && __x86_64__
  46. // 64-bit Mac - tag bit is LSB
  47. # define OBJC_MSB_TAGGED_POINTERS 0
  48. #else
  49. // Everything else - tag bit is MSB
  50. # define OBJC_MSB_TAGGED_POINTERS 1
  51. #endif
  52. #define _OBJC_TAG_INDEX_MASK 0x7
  53. // array slot includes the tag bit itself
  54. #define _OBJC_TAG_SLOT_COUNT 16
  55. #define _OBJC_TAG_SLOT_MASK 0xf
  56. #define _OBJC_TAG_EXT_INDEX_MASK 0xff
  57. // array slot has no extra bits
  58. #define _OBJC_TAG_EXT_SLOT_COUNT 256
  59. #define _OBJC_TAG_EXT_SLOT_MASK 0xff
  60. #if OBJC_MSB_TAGGED_POINTERS
  61. # define _OBJC_TAG_MASK (1UL<<63)
  62. # define _OBJC_TAG_INDEX_SHIFT 60
  63. # define _OBJC_TAG_SLOT_SHIFT 60
  64. # define _OBJC_TAG_PAYLOAD_LSHIFT 4
  65. # define _OBJC_TAG_PAYLOAD_RSHIFT 4
  66. # define _OBJC_TAG_EXT_MASK (0xfUL<<60)
  67. # define _OBJC_TAG_EXT_INDEX_SHIFT 52
  68. # define _OBJC_TAG_EXT_SLOT_SHIFT 52
  69. # define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 12
  70. # define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
  71. #else
  72. # define _OBJC_TAG_MASK 1UL
  73. # define _OBJC_TAG_INDEX_SHIFT 1
  74. # define _OBJC_TAG_SLOT_SHIFT 0
  75. # define _OBJC_TAG_PAYLOAD_LSHIFT 0
  76. # define _OBJC_TAG_PAYLOAD_RSHIFT 4
  77. # define _OBJC_TAG_EXT_MASK 0xfUL
  78. # define _OBJC_TAG_EXT_INDEX_SHIFT 4
  79. # define _OBJC_TAG_EXT_SLOT_SHIFT 4
  80. # define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 0
  81. # define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
  82. #endif
  83. //////////////////////////////////////
  84. // originally _objc_isTaggedPointer //
  85. //////////////////////////////////////
  86. static BOOL flex_isTaggedPointer(const void *ptr)
  87. {
  88. return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
  89. }
  90. ///////////////////
  91. // objc-config.h //
  92. ///////////////////
  93. // Define SUPPORT_INDEXED_ISA=1 on platforms that store the class in the isa
  94. // field as an index into a class table.
  95. #if __ARM_ARCH_7K__ >= 2
  96. # define SUPPORT_INDEXED_ISA 1
  97. #else
  98. # define SUPPORT_INDEXED_ISA 0
  99. #endif
  100. // Define SUPPORT_PACKED_ISA=1 on platforms that store the class in the isa
  101. // field as a maskable pointer with other data around it.
  102. #if (!__LP64__ || TARGET_OS_WIN32 || TARGET_OS_SIMULATOR)
  103. # define SUPPORT_PACKED_ISA 0
  104. #else
  105. # define SUPPORT_PACKED_ISA 1
  106. #endif
  107. // Define SUPPORT_NONPOINTER_ISA=1 on any platform that may store something
  108. // in the isa field that is not a raw pointer.
  109. #if !SUPPORT_INDEXED_ISA && !SUPPORT_PACKED_ISA
  110. # define SUPPORT_NONPOINTER_ISA 0
  111. #else
  112. # define SUPPORT_NONPOINTER_ISA 1
  113. #endif
  114. ////////////////////
  115. // objc-private.h //
  116. ////////////////////
  117. union isa_t
  118. {
  119. isa_t() { }
  120. isa_t(uintptr_t value) : bits(value) { }
  121. Class cls;
  122. uintptr_t bits;
  123. #if SUPPORT_PACKED_ISA
  124. // extra_rc must be the MSB-most field (so it matches carry/overflow flags)
  125. // nonpointer must be the LSB (fixme or get rid of it)
  126. // shiftcls must occupy the same bits that a real class pointer would
  127. // bits + RC_ONE is equivalent to extra_rc + 1
  128. // RC_HALF is the high bit of extra_rc (i.e. half of its range)
  129. // future expansion:
  130. // uintptr_t fast_rr : 1; // no r/r overrides
  131. // uintptr_t lock : 2; // lock for atomic property, @synch
  132. // uintptr_t extraBytes : 1; // allocated with extra bytes
  133. # if __arm64__
  134. # define ISA_MASK 0x0000000ffffffff8ULL
  135. # define ISA_MAGIC_MASK 0x000003f000000001ULL
  136. # define ISA_MAGIC_VALUE 0x000001a000000001ULL
  137. struct {
  138. uintptr_t nonpointer : 1;
  139. uintptr_t has_assoc : 1;
  140. uintptr_t has_cxx_dtor : 1;
  141. uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
  142. uintptr_t magic : 6;
  143. uintptr_t weakly_referenced : 1;
  144. uintptr_t deallocating : 1;
  145. uintptr_t has_sidetable_rc : 1;
  146. uintptr_t extra_rc : 19;
  147. # define RC_ONE (1ULL<<45)
  148. # define RC_HALF (1ULL<<18)
  149. };
  150. # elif __x86_64__
  151. # define ISA_MASK 0x00007ffffffffff8ULL
  152. # define ISA_MAGIC_MASK 0x001f800000000001ULL
  153. # define ISA_MAGIC_VALUE 0x001d800000000001ULL
  154. struct {
  155. uintptr_t nonpointer : 1;
  156. uintptr_t has_assoc : 1;
  157. uintptr_t has_cxx_dtor : 1;
  158. uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
  159. uintptr_t magic : 6;
  160. uintptr_t weakly_referenced : 1;
  161. uintptr_t deallocating : 1;
  162. uintptr_t has_sidetable_rc : 1;
  163. uintptr_t extra_rc : 8;
  164. # define RC_ONE (1ULL<<56)
  165. # define RC_HALF (1ULL<<7)
  166. };
  167. # else
  168. # error unknown architecture for packed isa
  169. # endif
  170. // SUPPORT_PACKED_ISA
  171. #endif
  172. #if SUPPORT_INDEXED_ISA
  173. # if __ARM_ARCH_7K__ >= 2
  174. # define ISA_INDEX_IS_NPI 1
  175. # define ISA_INDEX_MASK 0x0001FFFC
  176. # define ISA_INDEX_SHIFT 2
  177. # define ISA_INDEX_BITS 15
  178. # define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS)
  179. # define ISA_INDEX_MAGIC_MASK 0x001E0001
  180. # define ISA_INDEX_MAGIC_VALUE 0x001C0001
  181. struct {
  182. uintptr_t nonpointer : 1;
  183. uintptr_t has_assoc : 1;
  184. uintptr_t indexcls : 15;
  185. uintptr_t magic : 4;
  186. uintptr_t has_cxx_dtor : 1;
  187. uintptr_t weakly_referenced : 1;
  188. uintptr_t deallocating : 1;
  189. uintptr_t has_sidetable_rc : 1;
  190. uintptr_t extra_rc : 7;
  191. # define RC_ONE (1ULL<<25)
  192. # define RC_HALF (1ULL<<6)
  193. };
  194. # else
  195. # error unknown architecture for indexed isa
  196. # endif
  197. // SUPPORT_INDEXED_ISA
  198. #endif
  199. };
  200. ///////////////////
  201. // objc-object.h //
  202. ///////////////////
  203. ////////////////////////////////////////////////
  204. // originally objc_object::isExtTaggedPointer //
  205. ////////////////////////////////////////////////
  206. static BOOL flex_isExtTaggedPointer(const void *ptr)
  207. {
  208. return ((uintptr_t)ptr & _OBJC_TAG_EXT_MASK) == _OBJC_TAG_EXT_MASK;
  209. }
  210. struct flex_objc_object {
  211. isa_t isa;
  212. };
  213. //////////////////////////////////////////////////////////
  214. // Returns nil on platforms without nonpointer isa. //
  215. // Supporting those platforms would be too complicated //
  216. // for such a niche feature anyway. - @NSExceptional //
  217. // //
  218. // Code modified from objc_object::ISA() on 11/04/18 //
  219. //////////////////////////////////////////////////////////
  220. static id flex_getIsa(const flex_objc_object *object) {
  221. #if SUPPORT_NONPOINTER_ISA
  222. if (object->isa.nonpointer) {
  223. return object_getClass((__bridge id)object);
  224. }
  225. return (__bridge Class)(void *)object->isa.bits;
  226. #else
  227. return nil;
  228. #endif
  229. }
  230. /////////////////////////////////////
  231. // FLEXObjectInternal //
  232. // No Apple code beyond this point //
  233. /////////////////////////////////////
  234. extern "C" {
  235. /// Assumes memory is valid and readable.
  236. /// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/
  237. BOOL FLEXPointerIsValidObjcObject(const void * ptr)
  238. {
  239. uintptr_t pointer = (uintptr_t)ptr;
  240. if (!ptr) {
  241. return NO;
  242. }
  243. // Tagged pointers have 0x1 set, no other valid pointers do
  244. // objc-internal.h -> _objc_isTaggedPointer()
  245. if (flex_isTaggedPointer(ptr) || flex_isExtTaggedPointer(ptr)) {
  246. return YES;
  247. }
  248. // Check pointer alignment
  249. if ((pointer % sizeof(uintptr_t)) != 0) {
  250. return NO;
  251. }
  252. // From LLDB:
  253. // Pointers in a class_t will only have bits 0 through 46 set,
  254. // so if any pointer has bits 47 through 63 high, we know that this is not a valid isa
  255. // http://llvm.org/svn/llvm-project/lldb/trunk/examples/summaries/cocoa/objc_runtime.py
  256. if ((pointer & 0xFFFF800000000000) != 0) {
  257. return NO;
  258. }
  259. // http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html :
  260. if (flex_getIsa((const flex_objc_object *)ptr)) {
  261. return YES;
  262. }
  263. return NO;
  264. }
  265. }