123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- // TEST_CONFIG
- #include "test.h"
- #include "testroot.i"
- #include <objc/runtime.h>
- #include <objc/objc-internal.h>
- // Macros for array construction.
- // ten IMPs
- #define IMPS10 (IMP)fn0, (IMP)fn1, (IMP)fn2, (IMP)fn3, (IMP)fn4, \
- (IMP)fn5, (IMP)fn6, (IMP)fn7, (IMP)fn8, (IMP)fn9
- // ten method types
- #define TYPES10 "", "", "", "", "", "", "", "", "", ""
- // ten selectors of the form name0..name9
- #define SELS10(name) \
- @selector(name##0), @selector(name##1), @selector(name##2), \
- @selector(name##3), @selector(name##4), @selector(name##5), \
- @selector(name##6), @selector(name##7), @selector(name##8), \
- @selector(name##9)
- @interface Super : TestRoot @end
- @implementation Super
- -(int)superMethod0 { return 0; }
- -(int)superMethod1 { return 0; }
- -(int)superMethod2 { return 0; }
- -(int)superMethod3 { return 0; }
- -(int)superMethod4 { return 0; }
- -(int)superMethod5 { return 0; }
- -(int)superMethod6 { return 0; }
- -(int)superMethod7 { return 0; }
- -(int)superMethod8 { return 0; }
- -(int)superMethod9 { return 0; }
- -(int)bothMethod0 { return 0; }
- -(int)bothMethod1 { return 0; }
- -(int)bothMethod2 { return 0; }
- -(int)bothMethod3 { return 0; }
- -(int)bothMethod4 { return 0; }
- -(int)bothMethod5 { return 0; }
- -(int)bothMethod6 { return 0; }
- -(int)bothMethod7 { return 0; }
- -(int)bothMethod8 { return 0; }
- -(int)bothMethod9 { return 0; }
- @end
- @interface Sub : Super @end
- @implementation Sub
- -(int)subMethod0 { return 0; }
- -(int)subMethod1 { return 0; }
- -(int)subMethod2 { return 0; }
- -(int)subMethod3 { return 0; }
- -(int)subMethod4 { return 0; }
- -(int)subMethod5 { return 0; }
- -(int)subMethod6 { return 0; }
- -(int)subMethod7 { return 0; }
- -(int)subMethod8 { return 0; }
- -(int)subMethod9 { return 0; }
- -(int)bothMethod0 { return 0; }
- -(int)bothMethod1 { return 0; }
- -(int)bothMethod2 { return 0; }
- -(int)bothMethod3 { return 0; }
- -(int)bothMethod4 { return 0; }
- -(int)bothMethod5 { return 0; }
- -(int)bothMethod6 { return 0; }
- -(int)bothMethod7 { return 0; }
- -(int)bothMethod8 { return 0; }
- -(int)bothMethod9 { return 0; }
- @end
- @interface Sub2 : Super @end
- @implementation Sub2
- -(int)subMethod0 { return 0; }
- -(int)subMethod1 { return 0; }
- -(int)subMethod2 { return 0; }
- -(int)subMethod3 { return 0; }
- -(int)subMethod4 { return 0; }
- -(int)subMethod5 { return 0; }
- -(int)subMethod6 { return 0; }
- -(int)subMethod7 { return 0; }
- -(int)subMethod8 { return 0; }
- -(int)subMethod9 { return 0; }
- -(int)bothMethod0 { return 0; }
- -(int)bothMethod1 { return 0; }
- -(int)bothMethod2 { return 0; }
- -(int)bothMethod3 { return 0; }
- -(int)bothMethod4 { return 0; }
- -(int)bothMethod5 { return 0; }
- -(int)bothMethod6 { return 0; }
- -(int)bothMethod7 { return 0; }
- -(int)bothMethod8 { return 0; }
- -(int)bothMethod9 { return 0; }
- @end
- id fn0(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
- return nil;
- }
- id fn1(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
- return nil;
- }
- id fn2(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
- return nil;
- }
- id fn3(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
- return nil;
- }
- id fn4(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
- return nil;
- }
- id fn5(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
- return nil;
- }
- id fn6(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
- return nil;
- }
- id fn7(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
- return nil;
- }
- id fn8(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
- return nil;
- }
- id fn9(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
- return nil;
- }
- void testBulkMemoryOnce(void)
- {
- Class c = objc_allocateClassPair([TestRoot class], "c", 0);
- objc_registerClassPair(c);
-
- SEL sels[10] = {
- SELS10(method)
- };
- IMP imps[10] = {
- IMPS10
- };
- const char *types[10] = {
- TYPES10
- };
-
- uint32_t failureCount = 0;
- SEL *failed;
-
- // Test all successes.
- failed = class_addMethodsBulk(c, sels, imps, types, 4, &failureCount);
- testassert(failed == NULL);
- testassert(failureCount == 0);
-
- // Test mixed success and failure (this overlaps the previous one, so there
- // will be one of each).
- failed = class_addMethodsBulk(c, sels + 3, imps + 3, types + 3, 2,
- &failureCount);
- testassert(failed != NULL);
- testassert(failureCount == 1);
- testassert(failed[0] == sels[3]);
- free(failed);
-
- // Test total failure.
- failed = class_addMethodsBulk(c, sels, imps, types, 5, &failureCount);
- testassert(failed != NULL);
- testassert(failureCount == 5);
- for(int i = 0; i < 5; i++) {
- testassert(failed[i] == sels[i]);
- }
- free(failed);
-
- class_replaceMethodsBulk(c, sels, imps, types, 10);
-
- for(int i = 0; i < 10; i++) {
- testassert(class_getMethodImplementation(c, sels[i]) == imps[i]);
- }
-
- objc_disposeClassPair(c);
- }
- int main()
- {
- IMP dummyIMPs[130] = {
- IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
- IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
- IMPS10, IMPS10, IMPS10,
- };
-
- // similar to dummyIMPs but with different values in each slot
- IMP dummyIMPs2[130] = {
- (IMP)fn5, (IMP)fn6, (IMP)fn7, (IMP)fn8, (IMP)fn9,
- IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
- IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
- IMPS10, IMPS10,
- (IMP)fn0, (IMP)fn1, (IMP)fn2, (IMP)fn3, (IMP)fn4,
- };
-
- const char *dummyTypes[130] = {
- TYPES10, TYPES10, TYPES10, TYPES10, TYPES10,
- TYPES10, TYPES10, TYPES10, TYPES10, TYPES10,
- TYPES10, TYPES10, TYPES10,
- };
-
- SEL addSELs[20] = {
- SELS10(superMethod),
- SELS10(superMethodAddNew)
- };
-
- uint32_t failedCount = 0;
- SEL *failed;
-
- failed = class_addMethodsBulk([Super class], addSELs, dummyIMPs, dummyTypes,
- 20, &failedCount);
-
- // class_addMethodsBulk reports failures for all methods that already exist
- testassert(failed != NULL);
- testassert(failedCount == 10);
-
- // class_addMethodsBulk failed for existing implementations
- for(int i = 0; i < 10; i++) {
- testassert(failed[i] == addSELs[i]);
- testassert(class_getMethodImplementation([Super class], addSELs[i])
- != dummyIMPs[i]);
- }
-
- free(failed);
- // class_addMethodsBulk does add root implementations
- for(int i = 10; i < 20; i++) {
- testassert(class_getMethodImplementation([Super class], addSELs[i])
- == dummyIMPs[i]);
- }
-
- // class_addMethod does override superclass implementations
- failed = class_addMethodsBulk([Sub class], addSELs, dummyIMPs, dummyTypes,
- 10, &failedCount);
- testassert(failedCount == 0);
- testassert(failed == NULL);
- for(int i = 0; i < 10; i++) {
- testassert(class_getMethodImplementation([Sub class], addSELs[i])
- == dummyIMPs[i]);
- }
-
- SEL subReplaceSELs[40] = {
- SELS10(superMethod),
- SELS10(subMethodNew),
- SELS10(subMethod),
- SELS10(bothMethod),
- };
-
- // class_replaceMethodsBulk adds new implementations or replaces existing
- // ones for methods that exist on the superclass, the subclass, both, or
- // neither
- class_replaceMethodsBulk([Sub2 class], subReplaceSELs, dummyIMPs,
- dummyTypes, 40);
- for(int i = 0; i < 40; i++) {
- IMP newIMP = class_getMethodImplementation([Sub2 class],
- subReplaceSELs[i]);
- testassert(newIMP == dummyIMPs[i]);
- }
-
- SEL superReplaceSELs[20] = {
- SELS10(superMethod),
- SELS10(superMethodNew),
- };
-
- // class_replaceMethodsBulk adds new implementations or replaces existing
- // ones in the superclass
- class_replaceMethodsBulk([Super class], superReplaceSELs, dummyIMPs,
- dummyTypes, 20);
- for(int i = 0; i < 20; i++) {
- IMP newIMP = class_getMethodImplementation([Super class],
- superReplaceSELs[i]);
- testassert(newIMP == dummyIMPs[i]);
- }
- // class_addMethodsBulk, where almost all of the requested additions
- // already exist and thus can't be added. (They were already added
- // above by class_replaceMethodsBulk([Sub2 class], subReplaceSELs, ...).)
- // This list is large in the hope of provoking any realloc() of the
- // new method list inside addMethods().
- // The runtime doesn't care that the list contains lots of duplicates.
- SEL subAddMostlyExistingSELs[130] = {
- SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
- SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
- SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
- SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
- SELS10(bothMethod),
- };
- subAddMostlyExistingSELs[16] = @selector(INDEX_16_IS_DIFFERENT);
- failed = class_addMethodsBulk([Sub2 class], subAddMostlyExistingSELs,
- dummyIMPs2, dummyTypes, 130, &failedCount);
- testassert(failedCount == 129);
- testassert(failed != NULL);
- for(int i = 0; i < 130; i++) {
- IMP newIMP = class_getMethodImplementation([Sub2 class],
- subAddMostlyExistingSELs[i]);
- if (i == 16) {
- // the only one that was actually added
- testassert(newIMP != dummyIMPs[i]);
- testassert(newIMP == dummyIMPs2[i]);
- } else {
- // the others should all have failed
- testassert(newIMP == dummyIMPs[i]);
- testassert(newIMP != dummyIMPs2[i]);
- }
- }
- for (uint32_t i = 0; i < failedCount; i++) {
- testassert(failed[i] != NULL);
- testassert(failed[i] != subAddMostlyExistingSELs[16]);
- }
-
- // fixme actually try calling them
-
- // make sure the Bulk functions aren't leaking
- testBulkMemoryOnce();
- leak_mark();
- for(int i = 0; i < 10; i++) {
- testBulkMemoryOnce();
- }
- leak_check(0);
-
- succeed(__FILE__);
- }
|