5 #include <objc/runtime.h>
6 #include <objc/objc-internal.h>
8 // Macros for array construction.
10 #define IMPS10 (IMP)fn0, (IMP)fn1, (IMP)fn2, (IMP)fn3, (IMP)fn4, \
11 (IMP)fn5, (IMP)fn6, (IMP)fn7, (IMP)fn8, (IMP)fn9
13 #define TYPES10 "", "", "", "", "", "", "", "", "", ""
14 // ten selectors of the form name0..name9
15 #define SELS10(name) \
16 @selector(name##0), @selector(name##1), @selector(name##2), \
17 @selector(name##3), @selector(name##4), @selector(name##5), \
18 @selector(name##6), @selector(name##7), @selector(name##8), \
22 @interface Super : TestRoot @end
24 -(int)superMethod0 { return 0; }
25 -(int)superMethod1 { return 0; }
26 -(int)superMethod2 { return 0; }
27 -(int)superMethod3 { return 0; }
28 -(int)superMethod4 { return 0; }
29 -(int)superMethod5 { return 0; }
30 -(int)superMethod6 { return 0; }
31 -(int)superMethod7 { return 0; }
32 -(int)superMethod8 { return 0; }
33 -(int)superMethod9 { return 0; }
34 -(int)bothMethod0 { return 0; }
35 -(int)bothMethod1 { return 0; }
36 -(int)bothMethod2 { return 0; }
37 -(int)bothMethod3 { return 0; }
38 -(int)bothMethod4 { return 0; }
39 -(int)bothMethod5 { return 0; }
40 -(int)bothMethod6 { return 0; }
41 -(int)bothMethod7 { return 0; }
42 -(int)bothMethod8 { return 0; }
43 -(int)bothMethod9 { return 0; }
46 @interface Sub : Super @end
48 -(int)subMethod0 { return 0; }
49 -(int)subMethod1 { return 0; }
50 -(int)subMethod2 { return 0; }
51 -(int)subMethod3 { return 0; }
52 -(int)subMethod4 { return 0; }
53 -(int)subMethod5 { return 0; }
54 -(int)subMethod6 { return 0; }
55 -(int)subMethod7 { return 0; }
56 -(int)subMethod8 { return 0; }
57 -(int)subMethod9 { return 0; }
58 -(int)bothMethod0 { return 0; }
59 -(int)bothMethod1 { return 0; }
60 -(int)bothMethod2 { return 0; }
61 -(int)bothMethod3 { return 0; }
62 -(int)bothMethod4 { return 0; }
63 -(int)bothMethod5 { return 0; }
64 -(int)bothMethod6 { return 0; }
65 -(int)bothMethod7 { return 0; }
66 -(int)bothMethod8 { return 0; }
67 -(int)bothMethod9 { return 0; }
70 @interface Sub2 : Super @end
72 -(int)subMethod0 { return 0; }
73 -(int)subMethod1 { return 0; }
74 -(int)subMethod2 { return 0; }
75 -(int)subMethod3 { return 0; }
76 -(int)subMethod4 { return 0; }
77 -(int)subMethod5 { return 0; }
78 -(int)subMethod6 { return 0; }
79 -(int)subMethod7 { return 0; }
80 -(int)subMethod8 { return 0; }
81 -(int)subMethod9 { return 0; }
82 -(int)bothMethod0 { return 0; }
83 -(int)bothMethod1 { return 0; }
84 -(int)bothMethod2 { return 0; }
85 -(int)bothMethod3 { return 0; }
86 -(int)bothMethod4 { return 0; }
87 -(int)bothMethod5 { return 0; }
88 -(int)bothMethod6 { return 0; }
89 -(int)bothMethod7 { return 0; }
90 -(int)bothMethod8 { return 0; }
91 -(int)bothMethod9 { return 0; }
95 id fn0(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
98 id fn1(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
101 id fn2(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
104 id fn3(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
107 id fn4(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
110 id fn5(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
113 id fn6(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
116 id fn7(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
119 id fn8(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
122 id fn9(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
126 void testBulkMemoryOnce(void)
128 Class c = objc_allocateClassPair([TestRoot class], "c", 0);
129 objc_registerClassPair(c);
137 const char *types[10] = {
141 uint32_t failureCount = 0;
144 // Test all successes.
145 failed = class_addMethodsBulk(c, sels, imps, types, 4, &failureCount);
146 testassert(failed == NULL);
147 testassert(failureCount == 0);
149 // Test mixed success and failure (this overlaps the previous one, so there
150 // will be one of each).
151 failed = class_addMethodsBulk(c, sels + 3, imps + 3, types + 3, 2,
153 testassert(failed != NULL);
154 testassert(failureCount == 1);
155 testassert(failed[0] == sels[3]);
158 // Test total failure.
159 failed = class_addMethodsBulk(c, sels, imps, types, 5, &failureCount);
160 testassert(failed != NULL);
161 testassert(failureCount == 5);
162 for(int i = 0; i < 5; i++) {
163 testassert(failed[i] == sels[i]);
167 class_replaceMethodsBulk(c, sels, imps, types, 10);
169 for(int i = 0; i < 10; i++) {
170 testassert(class_getMethodImplementation(c, sels[i]) == imps[i]);
173 objc_disposeClassPair(c);
178 IMP dummyIMPs[130] = {
179 IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
180 IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
181 IMPS10, IMPS10, IMPS10,
184 // similar to dummyIMPs but with different values in each slot
185 IMP dummyIMPs2[130] = {
186 (IMP)fn5, (IMP)fn6, (IMP)fn7, (IMP)fn8, (IMP)fn9,
187 IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
188 IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
190 (IMP)fn0, (IMP)fn1, (IMP)fn2, (IMP)fn3, (IMP)fn4,
193 const char *dummyTypes[130] = {
194 TYPES10, TYPES10, TYPES10, TYPES10, TYPES10,
195 TYPES10, TYPES10, TYPES10, TYPES10, TYPES10,
196 TYPES10, TYPES10, TYPES10,
201 SELS10(superMethodAddNew)
204 uint32_t failedCount = 0;
207 failed = class_addMethodsBulk([Super class], addSELs, dummyIMPs, dummyTypes,
210 // class_addMethodsBulk reports failures for all methods that already exist
211 testassert(failed != NULL);
212 testassert(failedCount == 10);
214 // class_addMethodsBulk failed for existing implementations
215 for(int i = 0; i < 10; i++) {
216 testassert(failed[i] == addSELs[i]);
217 testassert(class_getMethodImplementation([Super class], addSELs[i])
223 // class_addMethodsBulk does add root implementations
224 for(int i = 10; i < 20; i++) {
225 testassert(class_getMethodImplementation([Super class], addSELs[i])
229 // class_addMethod does override superclass implementations
230 failed = class_addMethodsBulk([Sub class], addSELs, dummyIMPs, dummyTypes,
232 testassert(failedCount == 0);
233 testassert(failed == NULL);
234 for(int i = 0; i < 10; i++) {
235 testassert(class_getMethodImplementation([Sub class], addSELs[i])
239 SEL subReplaceSELs[40] = {
241 SELS10(subMethodNew),
246 // class_replaceMethodsBulk adds new implementations or replaces existing
247 // ones for methods that exist on the superclass, the subclass, both, or
249 class_replaceMethodsBulk([Sub2 class], subReplaceSELs, dummyIMPs,
251 for(int i = 0; i < 40; i++) {
252 IMP newIMP = class_getMethodImplementation([Sub2 class],
254 testassert(newIMP == dummyIMPs[i]);
257 SEL superReplaceSELs[20] = {
259 SELS10(superMethodNew),
262 // class_replaceMethodsBulk adds new implementations or replaces existing
263 // ones in the superclass
264 class_replaceMethodsBulk([Super class], superReplaceSELs, dummyIMPs,
266 for(int i = 0; i < 20; i++) {
267 IMP newIMP = class_getMethodImplementation([Super class],
268 superReplaceSELs[i]);
269 testassert(newIMP == dummyIMPs[i]);
273 // class_addMethodsBulk, where almost all of the requested additions
274 // already exist and thus can't be added. (They were already added
275 // above by class_replaceMethodsBulk([Sub2 class], subReplaceSELs, ...).)
277 // This list is large in the hope of provoking any realloc() of the
278 // new method list inside addMethods().
279 // The runtime doesn't care that the list contains lots of duplicates.
280 SEL subAddMostlyExistingSELs[130] = {
281 SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
282 SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
283 SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
284 SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
287 subAddMostlyExistingSELs[16] = @selector(INDEX_16_IS_DIFFERENT);
289 failed = class_addMethodsBulk([Sub2 class], subAddMostlyExistingSELs,
290 dummyIMPs2, dummyTypes, 130, &failedCount);
291 testassert(failedCount == 129);
292 testassert(failed != NULL);
294 for(int i = 0; i < 130; i++) {
295 IMP newIMP = class_getMethodImplementation([Sub2 class],
296 subAddMostlyExistingSELs[i]);
298 // the only one that was actually added
299 testassert(newIMP != dummyIMPs[i]);
300 testassert(newIMP == dummyIMPs2[i]);
302 // the others should all have failed
303 testassert(newIMP == dummyIMPs[i]);
304 testassert(newIMP != dummyIMPs2[i]);
307 for (uint32_t i = 0; i < failedCount; i++) {
308 testassert(failed[i] != NULL);
309 testassert(failed[i] != subAddMostlyExistingSELs[16]);
313 // fixme actually try calling them
315 // make sure the Bulk functions aren't leaking
316 testBulkMemoryOnce();
318 for(int i = 0; i < 10; i++) {
319 testBulkMemoryOnce();