nonpointerisa.m 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // TEST_CFLAGS -framework Foundation
  2. // TEST_CONFIG MEM=mrc
  3. #include "test.h"
  4. #include <dlfcn.h>
  5. #include <objc/objc-gdb.h>
  6. #include <Foundation/Foundation.h>
  7. #define ISA(x) (*((uintptr_t *)(x)))
  8. #define NONPOINTER(x) (ISA(x) & 1)
  9. #if SUPPORT_NONPOINTER_ISA
  10. # if __x86_64__
  11. # define RC_ONE (1ULL<<56)
  12. # elif __arm64__ && __LP64__
  13. # define RC_ONE (1ULL<<45)
  14. # elif __ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__)
  15. # define RC_ONE (1ULL<<25)
  16. # else
  17. # error unknown architecture
  18. # endif
  19. #endif
  20. void check_raw_pointer(id obj, Class cls)
  21. {
  22. testassert(object_getClass(obj) == cls);
  23. testassert(!NONPOINTER(obj));
  24. uintptr_t isa = ISA(obj);
  25. testassert((Class)isa == cls);
  26. testassert((Class)(isa & objc_debug_isa_class_mask) == cls);
  27. testassert((Class)(isa & ~objc_debug_isa_class_mask) == 0);
  28. CFRetain(obj);
  29. testassert(ISA(obj) == isa);
  30. testassert([obj retainCount] == 2);
  31. [obj retain];
  32. testassert(ISA(obj) == isa);
  33. testassert([obj retainCount] == 3);
  34. CFRelease(obj);
  35. testassert(ISA(obj) == isa);
  36. testassert([obj retainCount] == 2);
  37. [obj release];
  38. testassert(ISA(obj) == isa);
  39. testassert([obj retainCount] == 1);
  40. }
  41. #if ! SUPPORT_NONPOINTER_ISA
  42. int main()
  43. {
  44. #if OBJC_HAVE_NONPOINTER_ISA || OBJC_HAVE_PACKED_NONPOINTER_ISA || OBJC_HAVE_INDEXED_NONPOINTER_ISA
  45. # error wrong
  46. #endif
  47. testprintf("Isa with index\n");
  48. id index_o = [NSObject new];
  49. check_raw_pointer(index_o, [NSObject class]);
  50. // These variables DO NOT exist without non-pointer isa support.
  51. testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_packed_isa_class_mask"));
  52. testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_mask"));
  53. testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_value"));
  54. testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_mask"));
  55. testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_shift"));
  56. // These variables DO exist even without non-pointer isa support.
  57. testassert(dlsym(RTLD_DEFAULT, "objc_debug_isa_class_mask"));
  58. testassert(dlsym(RTLD_DEFAULT, "objc_debug_isa_magic_mask"));
  59. testassert(dlsym(RTLD_DEFAULT, "objc_debug_isa_magic_value"));
  60. succeed(__FILE__);
  61. }
  62. #else
  63. // SUPPORT_NONPOINTER_ISA
  64. void check_nonpointer(id obj, Class cls)
  65. {
  66. testassert(object_getClass(obj) == cls);
  67. testassert(NONPOINTER(obj));
  68. uintptr_t isa = ISA(obj);
  69. if (objc_debug_indexed_isa_magic_mask != 0) {
  70. // Indexed isa.
  71. testassert((isa & objc_debug_indexed_isa_magic_mask) == objc_debug_indexed_isa_magic_value);
  72. testassert((isa & ~objc_debug_indexed_isa_index_mask) != 0);
  73. uintptr_t index = (isa & objc_debug_indexed_isa_index_mask) >> objc_debug_indexed_isa_index_shift;
  74. testassert(index < objc_indexed_classes_count);
  75. testassert(objc_indexed_classes[index] == cls);
  76. } else {
  77. // Packed isa.
  78. testassert((Class)(isa & objc_debug_isa_class_mask) == cls);
  79. testassert((Class)(isa & ~objc_debug_isa_class_mask) != 0);
  80. testassert((isa & objc_debug_isa_magic_mask) == objc_debug_isa_magic_value);
  81. }
  82. CFRetain(obj);
  83. testassert(ISA(obj) == isa + RC_ONE);
  84. testassert([obj retainCount] == 2);
  85. [obj retain];
  86. testassert(ISA(obj) == isa + RC_ONE*2);
  87. testassert([obj retainCount] == 3);
  88. CFRelease(obj);
  89. testassert(ISA(obj) == isa + RC_ONE);
  90. testassert([obj retainCount] == 2);
  91. [obj release];
  92. testassert(ISA(obj) == isa);
  93. testassert([obj retainCount] == 1);
  94. }
  95. @interface OS_object <NSObject>
  96. +(id)alloc;
  97. @end
  98. @interface Fake_OS_object : NSObject {
  99. int refcnt;
  100. int xref_cnt;
  101. }
  102. @end
  103. @implementation Fake_OS_object
  104. +(void)initialize {
  105. static bool initialized;
  106. if (!initialized) {
  107. initialized = true;
  108. testprintf("Nonpointer during +initialize\n");
  109. testassert(!NONPOINTER(self));
  110. id o = [Fake_OS_object new];
  111. check_nonpointer(o, self);
  112. [o release];
  113. }
  114. }
  115. @end
  116. @interface Sub_OS_object : OS_object @end
  117. @implementation Sub_OS_object
  118. @end
  119. int main()
  120. {
  121. uintptr_t isa;
  122. #if SUPPORT_PACKED_ISA
  123. # if !OBJC_HAVE_NONPOINTER_ISA || !OBJC_HAVE_PACKED_NONPOINTER_ISA || OBJC_HAVE_INDEXED_NONPOINTER_ISA
  124. # error wrong
  125. # endif
  126. testassert(objc_debug_isa_class_mask == (uintptr_t)&objc_absolute_packed_isa_class_mask);
  127. // Indexed isa variables DO NOT exist on packed-isa platforms
  128. testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_mask"));
  129. testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_magic_value"));
  130. testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_mask"));
  131. testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_indexed_isa_index_shift"));
  132. #elif SUPPORT_INDEXED_ISA
  133. # if !OBJC_HAVE_NONPOINTER_ISA || OBJC_HAVE_PACKED_NONPOINTER_ISA || !OBJC_HAVE_INDEXED_NONPOINTER_ISA
  134. # error wrong
  135. # endif
  136. testassert(objc_debug_indexed_isa_magic_mask == (uintptr_t)&objc_absolute_indexed_isa_magic_mask);
  137. testassert(objc_debug_indexed_isa_magic_value == (uintptr_t)&objc_absolute_indexed_isa_magic_value);
  138. testassert(objc_debug_indexed_isa_index_mask == (uintptr_t)&objc_absolute_indexed_isa_index_mask);
  139. testassert(objc_debug_indexed_isa_index_shift == (uintptr_t)&objc_absolute_indexed_isa_index_shift);
  140. // Packed isa variable DOES NOT exist on indexed-isa platforms.
  141. testassert(!dlsym(RTLD_DEFAULT, "objc_absolute_packed_isa_class_mask"));
  142. #else
  143. # error unknown nonpointer isa format
  144. #endif
  145. testprintf("Isa with index\n");
  146. id index_o = [Fake_OS_object new];
  147. check_nonpointer(index_o, [Fake_OS_object class]);
  148. testprintf("Weakly referenced\n");
  149. isa = ISA(index_o);
  150. id weak;
  151. objc_storeWeak(&weak, index_o);
  152. testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
  153. testprintf("Has associated references\n");
  154. id assoc = @"thing";
  155. isa = ISA(index_o);
  156. objc_setAssociatedObject(index_o, assoc, assoc, OBJC_ASSOCIATION_ASSIGN);
  157. testassert(__builtin_popcountl(isa ^ ISA(index_o)) == 1);
  158. testprintf("Isa without index\n");
  159. id raw_o = [OS_object alloc];
  160. check_raw_pointer(raw_o, [OS_object class]);
  161. id buf[4];
  162. id bufo = (id)buf;
  163. testprintf("Change isa 0 -> raw pointer\n");
  164. bzero(buf, sizeof(buf));
  165. object_setClass(bufo, [OS_object class]);
  166. check_raw_pointer(bufo, [OS_object class]);
  167. testprintf("Change isa 0 -> nonpointer\n");
  168. bzero(buf, sizeof(buf));
  169. object_setClass(bufo, [NSObject class]);
  170. check_nonpointer(bufo, [NSObject class]);
  171. testprintf("Change isa nonpointer -> nonpointer\n");
  172. testassert(NONPOINTER(bufo));
  173. _objc_rootRetain(bufo);
  174. testassert(_objc_rootRetainCount(bufo) == 2);
  175. object_setClass(bufo, [Fake_OS_object class]);
  176. testassert(_objc_rootRetainCount(bufo) == 2);
  177. _objc_rootRelease(bufo);
  178. testassert(_objc_rootRetainCount(bufo) == 1);
  179. check_nonpointer(bufo, [Fake_OS_object class]);
  180. testprintf("Change isa nonpointer -> raw pointer\n");
  181. // Retain count must be preserved.
  182. // Use root* to avoid OS_object's overrides.
  183. testassert(NONPOINTER(bufo));
  184. _objc_rootRetain(bufo);
  185. testassert(_objc_rootRetainCount(bufo) == 2);
  186. object_setClass(bufo, [OS_object class]);
  187. testassert(_objc_rootRetainCount(bufo) == 2);
  188. _objc_rootRelease(bufo);
  189. testassert(_objc_rootRetainCount(bufo) == 1);
  190. check_raw_pointer(bufo, [OS_object class]);
  191. testprintf("Change isa raw pointer -> nonpointer (doesn't happen)\n");
  192. testassert(!NONPOINTER(bufo));
  193. _objc_rootRetain(bufo);
  194. testassert(_objc_rootRetainCount(bufo) == 2);
  195. object_setClass(bufo, [Fake_OS_object class]);
  196. testassert(_objc_rootRetainCount(bufo) == 2);
  197. _objc_rootRelease(bufo);
  198. testassert(_objc_rootRetainCount(bufo) == 1);
  199. check_raw_pointer(bufo, [Fake_OS_object class]);
  200. testprintf("Change isa raw pointer -> raw pointer\n");
  201. testassert(!NONPOINTER(bufo));
  202. _objc_rootRetain(bufo);
  203. testassert(_objc_rootRetainCount(bufo) == 2);
  204. object_setClass(bufo, [Sub_OS_object class]);
  205. testassert(_objc_rootRetainCount(bufo) == 2);
  206. _objc_rootRelease(bufo);
  207. testassert(_objc_rootRetainCount(bufo) == 1);
  208. check_raw_pointer(bufo, [Sub_OS_object class]);
  209. succeed(__FILE__);
  210. }
  211. // SUPPORT_NONPOINTER_ISA
  212. #endif