addMethods.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. // TEST_CONFIG
  2. #include "test.h"
  3. #include "testroot.i"
  4. #include <objc/runtime.h>
  5. #include <objc/objc-internal.h>
  6. // Macros for array construction.
  7. // ten IMPs
  8. #define IMPS10 (IMP)fn0, (IMP)fn1, (IMP)fn2, (IMP)fn3, (IMP)fn4, \
  9. (IMP)fn5, (IMP)fn6, (IMP)fn7, (IMP)fn8, (IMP)fn9
  10. // ten method types
  11. #define TYPES10 "", "", "", "", "", "", "", "", "", ""
  12. // ten selectors of the form name0..name9
  13. #define SELS10(name) \
  14. @selector(name##0), @selector(name##1), @selector(name##2), \
  15. @selector(name##3), @selector(name##4), @selector(name##5), \
  16. @selector(name##6), @selector(name##7), @selector(name##8), \
  17. @selector(name##9)
  18. @interface Super : TestRoot @end
  19. @implementation Super
  20. -(int)superMethod0 { return 0; }
  21. -(int)superMethod1 { return 0; }
  22. -(int)superMethod2 { return 0; }
  23. -(int)superMethod3 { return 0; }
  24. -(int)superMethod4 { return 0; }
  25. -(int)superMethod5 { return 0; }
  26. -(int)superMethod6 { return 0; }
  27. -(int)superMethod7 { return 0; }
  28. -(int)superMethod8 { return 0; }
  29. -(int)superMethod9 { return 0; }
  30. -(int)bothMethod0 { return 0; }
  31. -(int)bothMethod1 { return 0; }
  32. -(int)bothMethod2 { return 0; }
  33. -(int)bothMethod3 { return 0; }
  34. -(int)bothMethod4 { return 0; }
  35. -(int)bothMethod5 { return 0; }
  36. -(int)bothMethod6 { return 0; }
  37. -(int)bothMethod7 { return 0; }
  38. -(int)bothMethod8 { return 0; }
  39. -(int)bothMethod9 { return 0; }
  40. @end
  41. @interface Sub : Super @end
  42. @implementation Sub
  43. -(int)subMethod0 { return 0; }
  44. -(int)subMethod1 { return 0; }
  45. -(int)subMethod2 { return 0; }
  46. -(int)subMethod3 { return 0; }
  47. -(int)subMethod4 { return 0; }
  48. -(int)subMethod5 { return 0; }
  49. -(int)subMethod6 { return 0; }
  50. -(int)subMethod7 { return 0; }
  51. -(int)subMethod8 { return 0; }
  52. -(int)subMethod9 { return 0; }
  53. -(int)bothMethod0 { return 0; }
  54. -(int)bothMethod1 { return 0; }
  55. -(int)bothMethod2 { return 0; }
  56. -(int)bothMethod3 { return 0; }
  57. -(int)bothMethod4 { return 0; }
  58. -(int)bothMethod5 { return 0; }
  59. -(int)bothMethod6 { return 0; }
  60. -(int)bothMethod7 { return 0; }
  61. -(int)bothMethod8 { return 0; }
  62. -(int)bothMethod9 { return 0; }
  63. @end
  64. @interface Sub2 : Super @end
  65. @implementation Sub2
  66. -(int)subMethod0 { return 0; }
  67. -(int)subMethod1 { return 0; }
  68. -(int)subMethod2 { return 0; }
  69. -(int)subMethod3 { return 0; }
  70. -(int)subMethod4 { return 0; }
  71. -(int)subMethod5 { return 0; }
  72. -(int)subMethod6 { return 0; }
  73. -(int)subMethod7 { return 0; }
  74. -(int)subMethod8 { return 0; }
  75. -(int)subMethod9 { return 0; }
  76. -(int)bothMethod0 { return 0; }
  77. -(int)bothMethod1 { return 0; }
  78. -(int)bothMethod2 { return 0; }
  79. -(int)bothMethod3 { return 0; }
  80. -(int)bothMethod4 { return 0; }
  81. -(int)bothMethod5 { return 0; }
  82. -(int)bothMethod6 { return 0; }
  83. -(int)bothMethod7 { return 0; }
  84. -(int)bothMethod8 { return 0; }
  85. -(int)bothMethod9 { return 0; }
  86. @end
  87. id fn0(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
  88. return nil;
  89. }
  90. id fn1(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
  91. return nil;
  92. }
  93. id fn2(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
  94. return nil;
  95. }
  96. id fn3(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
  97. return nil;
  98. }
  99. id fn4(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
  100. return nil;
  101. }
  102. id fn5(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
  103. return nil;
  104. }
  105. id fn6(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
  106. return nil;
  107. }
  108. id fn7(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
  109. return nil;
  110. }
  111. id fn8(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
  112. return nil;
  113. }
  114. id fn9(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
  115. return nil;
  116. }
  117. void testBulkMemoryOnce(void)
  118. {
  119. Class c = objc_allocateClassPair([TestRoot class], "c", 0);
  120. objc_registerClassPair(c);
  121. SEL sels[10] = {
  122. SELS10(method)
  123. };
  124. IMP imps[10] = {
  125. IMPS10
  126. };
  127. const char *types[10] = {
  128. TYPES10
  129. };
  130. uint32_t failureCount = 0;
  131. SEL *failed;
  132. // Test all successes.
  133. failed = class_addMethodsBulk(c, sels, imps, types, 4, &failureCount);
  134. testassert(failed == NULL);
  135. testassert(failureCount == 0);
  136. // Test mixed success and failure (this overlaps the previous one, so there
  137. // will be one of each).
  138. failed = class_addMethodsBulk(c, sels + 3, imps + 3, types + 3, 2,
  139. &failureCount);
  140. testassert(failed != NULL);
  141. testassert(failureCount == 1);
  142. testassert(failed[0] == sels[3]);
  143. free(failed);
  144. // Test total failure.
  145. failed = class_addMethodsBulk(c, sels, imps, types, 5, &failureCount);
  146. testassert(failed != NULL);
  147. testassert(failureCount == 5);
  148. for(int i = 0; i < 5; i++) {
  149. testassert(failed[i] == sels[i]);
  150. }
  151. free(failed);
  152. class_replaceMethodsBulk(c, sels, imps, types, 10);
  153. for(int i = 0; i < 10; i++) {
  154. testassert(class_getMethodImplementation(c, sels[i]) == imps[i]);
  155. }
  156. objc_disposeClassPair(c);
  157. }
  158. int main()
  159. {
  160. IMP dummyIMPs[130] = {
  161. IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
  162. IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
  163. IMPS10, IMPS10, IMPS10,
  164. };
  165. // similar to dummyIMPs but with different values in each slot
  166. IMP dummyIMPs2[130] = {
  167. (IMP)fn5, (IMP)fn6, (IMP)fn7, (IMP)fn8, (IMP)fn9,
  168. IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
  169. IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
  170. IMPS10, IMPS10,
  171. (IMP)fn0, (IMP)fn1, (IMP)fn2, (IMP)fn3, (IMP)fn4,
  172. };
  173. const char *dummyTypes[130] = {
  174. TYPES10, TYPES10, TYPES10, TYPES10, TYPES10,
  175. TYPES10, TYPES10, TYPES10, TYPES10, TYPES10,
  176. TYPES10, TYPES10, TYPES10,
  177. };
  178. SEL addSELs[20] = {
  179. SELS10(superMethod),
  180. SELS10(superMethodAddNew)
  181. };
  182. uint32_t failedCount = 0;
  183. SEL *failed;
  184. failed = class_addMethodsBulk([Super class], addSELs, dummyIMPs, dummyTypes,
  185. 20, &failedCount);
  186. // class_addMethodsBulk reports failures for all methods that already exist
  187. testassert(failed != NULL);
  188. testassert(failedCount == 10);
  189. // class_addMethodsBulk failed for existing implementations
  190. for(int i = 0; i < 10; i++) {
  191. testassert(failed[i] == addSELs[i]);
  192. testassert(class_getMethodImplementation([Super class], addSELs[i])
  193. != dummyIMPs[i]);
  194. }
  195. free(failed);
  196. // class_addMethodsBulk does add root implementations
  197. for(int i = 10; i < 20; i++) {
  198. testassert(class_getMethodImplementation([Super class], addSELs[i])
  199. == dummyIMPs[i]);
  200. }
  201. // class_addMethod does override superclass implementations
  202. failed = class_addMethodsBulk([Sub class], addSELs, dummyIMPs, dummyTypes,
  203. 10, &failedCount);
  204. testassert(failedCount == 0);
  205. testassert(failed == NULL);
  206. for(int i = 0; i < 10; i++) {
  207. testassert(class_getMethodImplementation([Sub class], addSELs[i])
  208. == dummyIMPs[i]);
  209. }
  210. SEL subReplaceSELs[40] = {
  211. SELS10(superMethod),
  212. SELS10(subMethodNew),
  213. SELS10(subMethod),
  214. SELS10(bothMethod),
  215. };
  216. // class_replaceMethodsBulk adds new implementations or replaces existing
  217. // ones for methods that exist on the superclass, the subclass, both, or
  218. // neither
  219. class_replaceMethodsBulk([Sub2 class], subReplaceSELs, dummyIMPs,
  220. dummyTypes, 40);
  221. for(int i = 0; i < 40; i++) {
  222. IMP newIMP = class_getMethodImplementation([Sub2 class],
  223. subReplaceSELs[i]);
  224. testassert(newIMP == dummyIMPs[i]);
  225. }
  226. SEL superReplaceSELs[20] = {
  227. SELS10(superMethod),
  228. SELS10(superMethodNew),
  229. };
  230. // class_replaceMethodsBulk adds new implementations or replaces existing
  231. // ones in the superclass
  232. class_replaceMethodsBulk([Super class], superReplaceSELs, dummyIMPs,
  233. dummyTypes, 20);
  234. for(int i = 0; i < 20; i++) {
  235. IMP newIMP = class_getMethodImplementation([Super class],
  236. superReplaceSELs[i]);
  237. testassert(newIMP == dummyIMPs[i]);
  238. }
  239. // class_addMethodsBulk, where almost all of the requested additions
  240. // already exist and thus can't be added. (They were already added
  241. // above by class_replaceMethodsBulk([Sub2 class], subReplaceSELs, ...).)
  242. // This list is large in the hope of provoking any realloc() of the
  243. // new method list inside addMethods().
  244. // The runtime doesn't care that the list contains lots of duplicates.
  245. SEL subAddMostlyExistingSELs[130] = {
  246. SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
  247. SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
  248. SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
  249. SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
  250. SELS10(bothMethod),
  251. };
  252. subAddMostlyExistingSELs[16] = @selector(INDEX_16_IS_DIFFERENT);
  253. failed = class_addMethodsBulk([Sub2 class], subAddMostlyExistingSELs,
  254. dummyIMPs2, dummyTypes, 130, &failedCount);
  255. testassert(failedCount == 129);
  256. testassert(failed != NULL);
  257. for(int i = 0; i < 130; i++) {
  258. IMP newIMP = class_getMethodImplementation([Sub2 class],
  259. subAddMostlyExistingSELs[i]);
  260. if (i == 16) {
  261. // the only one that was actually added
  262. testassert(newIMP != dummyIMPs[i]);
  263. testassert(newIMP == dummyIMPs2[i]);
  264. } else {
  265. // the others should all have failed
  266. testassert(newIMP == dummyIMPs[i]);
  267. testassert(newIMP != dummyIMPs2[i]);
  268. }
  269. }
  270. for (uint32_t i = 0; i < failedCount; i++) {
  271. testassert(failed[i] != NULL);
  272. testassert(failed[i] != subAddMostlyExistingSELs[16]);
  273. }
  274. // fixme actually try calling them
  275. // make sure the Bulk functions aren't leaking
  276. testBulkMemoryOnce();
  277. leak_mark();
  278. for(int i = 0; i < 10; i++) {
  279. testBulkMemoryOnce();
  280. }
  281. leak_check(0);
  282. succeed(__FILE__);
  283. }