classpair.mm 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. // TEST_CONFIG
  2. #include "test.h"
  3. #include "testroot.i"
  4. #include <objc/runtime.h>
  5. #include <string.h>
  6. @protocol Proto
  7. -(void) instanceMethod;
  8. +(void) classMethod;
  9. @optional
  10. -(void) instanceMethod2;
  11. +(void) classMethod2;
  12. @end
  13. @protocol Proto2
  14. -(void) instanceMethod;
  15. +(void) classMethod;
  16. @optional
  17. -(void) instanceMethod2;
  18. +(void) classMethod_that_does_not_exist;
  19. @end
  20. @protocol Proto3
  21. -(void) instanceMethod;
  22. +(void) classMethod_that_does_not_exist;
  23. @optional
  24. -(void) instanceMethod2;
  25. +(void) classMethod2;
  26. @end
  27. static int super_initialize;
  28. static int super_cxxctor;
  29. static int super_cxxdtor;
  30. struct super_cxx {
  31. int foo;
  32. super_cxx() : foo(0) {
  33. super_cxxctor++;
  34. }
  35. ~super_cxx() {
  36. super_cxxdtor++;
  37. }
  38. };
  39. @interface Super : TestRoot
  40. @property int superProp;
  41. @end
  42. @implementation Super {
  43. super_cxx _foo;
  44. }
  45. @dynamic superProp;
  46. +(void)initialize { super_initialize++; }
  47. +(void) classMethod { fail("+[Super classMethod] called"); }
  48. +(void) classMethod2 { fail("+[Super classMethod2] called"); }
  49. -(void) instanceMethod { fail("-[Super instanceMethod] called"); }
  50. -(void) instanceMethod2 { fail("-[Super instanceMethod2] called"); }
  51. @end
  52. static int state;
  53. static void instance_fn(id self, SEL _cmd __attribute__((unused)))
  54. {
  55. testassert(!class_isMetaClass(object_getClass(self)));
  56. state++;
  57. }
  58. static void class_fn(id self, SEL _cmd __attribute__((unused)))
  59. {
  60. testassert(class_isMetaClass(object_getClass(self)));
  61. state++;
  62. }
  63. static void fail_fn(id self __attribute__((unused)), SEL _cmd)
  64. {
  65. fail("fail_fn '%s' called", sel_getName(_cmd));
  66. }
  67. static void cycle(void)
  68. {
  69. Class cls;
  70. BOOL ok;
  71. objc_property_t prop;
  72. char namebuf[256];
  73. testassert(!objc_getClass("Sub"));
  74. testassert([Super class]);
  75. // Test subclass with bells and whistles
  76. cls = objc_allocateClassPair([Super class], "Sub", 0);
  77. testassert(cls);
  78. class_addMethod(cls, @selector(instanceMethod),
  79. (IMP)&instance_fn, "v@:");
  80. class_addMethod(object_getClass(cls), @selector(classMethod),
  81. (IMP)&class_fn, "v@:");
  82. class_addMethod(object_getClass(cls), @selector(initialize),
  83. (IMP)&class_fn, "v@:");
  84. class_addMethod(object_getClass(cls), @selector(load),
  85. (IMP)&fail_fn, "v@:");
  86. ok = class_addProtocol(cls, @protocol(Proto));
  87. testassert(ok);
  88. ok = class_addProtocol(cls, @protocol(Proto));
  89. testassert(!ok);
  90. char attrname[2];
  91. char attrvalue[2];
  92. objc_property_attribute_t attrs[1];
  93. unsigned int attrcount = sizeof(attrs) / sizeof(attrs[0]);
  94. attrs[0].name = attrname;
  95. attrs[0].value = attrvalue;
  96. strcpy(attrname, "T");
  97. strcpy(attrvalue, "x");
  98. strcpy(namebuf, "subProp");
  99. ok = class_addProperty(cls, namebuf, attrs, attrcount);
  100. testassert(ok);
  101. strcpy(namebuf, "subProp");
  102. ok = class_addProperty(cls, namebuf, attrs, attrcount);
  103. testassert(!ok);
  104. strcpy(attrvalue, "i");
  105. class_replaceProperty(cls, namebuf, attrs, attrcount);
  106. strcpy(namebuf, "superProp");
  107. ok = class_addProperty(cls, namebuf, attrs, attrcount);
  108. testassert(!ok);
  109. bzero(namebuf, sizeof(namebuf));
  110. bzero(attrs, sizeof(attrs));
  111. bzero(attrname, sizeof(attrname));
  112. bzero(attrvalue, sizeof(attrvalue));
  113. #ifndef __LP64__
  114. # define size 4
  115. # define align 2
  116. #else
  117. #define size 8
  118. # define align 3
  119. #endif
  120. /*
  121. {
  122. int ivar;
  123. id ivarid;
  124. id* ivaridstar;
  125. Block_t ivarblock;
  126. }
  127. */
  128. ok = class_addIvar(cls, "ivar", 4, 2, "i");
  129. testassert(ok);
  130. ok = class_addIvar(cls, "ivarid", size, align, "@");
  131. testassert(ok);
  132. ok = class_addIvar(cls, "ivaridstar", size, align, "^@");
  133. testassert(ok);
  134. ok = class_addIvar(cls, "ivarblock", size, align, "@?");
  135. testassert(ok);
  136. ok = class_addIvar(cls, "ivar", 4, 2, "i");
  137. testassert(!ok);
  138. ok = class_addIvar(object_getClass(cls), "classvar", 4, 2, "i");
  139. testassert(!ok);
  140. objc_registerClassPair(cls);
  141. // should call cls's +initialize, not super's
  142. // Provoke +initialize using class_getMethodImplementation(class method)
  143. // in order to test getNonMetaClass's slow case
  144. super_initialize = 0;
  145. state = 0;
  146. class_getMethodImplementation(object_getClass(cls), @selector(class));
  147. testassert(super_initialize == 0);
  148. testassert(state == 1);
  149. testassert(cls == [cls class]);
  150. testassert(cls == objc_getClass("Sub"));
  151. testassert(!class_isMetaClass(cls));
  152. testassert(class_isMetaClass(object_getClass(cls)));
  153. testassert(class_getSuperclass(cls) == [Super class]);
  154. testassert(class_getSuperclass(object_getClass(cls)) == object_getClass([Super class]));
  155. testassert(class_getInstanceSize(cls) >= sizeof(Class) + 4 + 3*size);
  156. testassert(class_conformsToProtocol(cls, @protocol(Proto)));
  157. class_addMethod(cls, @selector(instanceMethod2),
  158. (IMP)&instance_fn, "v@:");
  159. class_addMethod(object_getClass(cls), @selector(classMethod2),
  160. (IMP)&class_fn, "v@:");
  161. ok = class_addIvar(cls, "ivar2", 4, 4, "i");
  162. testassert(!ok);
  163. ok = class_addIvar(object_getClass(cls), "classvar2", 4, 4, "i");
  164. testassert(!ok);
  165. ok = class_addProtocol(cls, @protocol(Proto2));
  166. testassert(ok);
  167. ok = class_addProtocol(cls, @protocol(Proto2));
  168. testassert(!ok);
  169. ok = class_addProtocol(cls, @protocol(Proto));
  170. testassert(!ok);
  171. attrs[0].name = attrname;
  172. attrs[0].value = attrvalue;
  173. strcpy(attrname, "T");
  174. strcpy(attrvalue, "i");
  175. strcpy(namebuf, "subProp2");
  176. ok = class_addProperty(cls, namebuf, attrs, attrcount);
  177. testassert(ok);
  178. strcpy(namebuf, "subProp");
  179. ok = class_addProperty(cls, namebuf, attrs, attrcount);
  180. testassert(!ok);
  181. strcpy(namebuf, "superProp");
  182. ok = class_addProperty(cls, namebuf, attrs, attrcount);
  183. testassert(!ok);
  184. bzero(namebuf, sizeof(namebuf));
  185. bzero(attrs, sizeof(attrs));
  186. bzero(attrname, sizeof(attrname));
  187. bzero(attrvalue, sizeof(attrvalue));
  188. prop = class_getProperty(cls, "subProp");
  189. testassert(prop);
  190. testassert(0 == strcmp(property_getName(prop), "subProp"));
  191. testassert(0 == strcmp(property_getAttributes(prop), "Ti"));
  192. prop = class_getProperty(cls, "subProp2");
  193. testassert(prop);
  194. testassert(0 == strcmp(property_getName(prop), "subProp2"));
  195. testassert(0 == strcmp(property_getAttributes(prop), "Ti"));
  196. // note: adding more methods here causes a false leak check failure
  197. state = 0;
  198. [cls classMethod];
  199. [cls classMethod2];
  200. testassert(state == 2);
  201. // put instance tests on a separate thread so they
  202. // are reliably deallocated before class destruction
  203. testonthread(^{
  204. super_cxxctor = 0;
  205. super_cxxdtor = 0;
  206. id obj = [cls new];
  207. testassert(super_cxxctor == 1);
  208. testassert(super_cxxdtor == 0);
  209. state = 0;
  210. [obj instanceMethod];
  211. [obj instanceMethod2];
  212. testassert(state == 2);
  213. RELEASE_VAR(obj);
  214. testassert(super_cxxctor == 1);
  215. testassert(super_cxxdtor == 1);
  216. });
  217. // Test ivar layouts of sub-subclass
  218. Class cls2 = objc_allocateClassPair(cls, "SubSub", 0);
  219. testassert(cls2);
  220. /*
  221. {
  222. id ivarid2;
  223. id idarray[16];
  224. void* ptrarray[16];
  225. char a;
  226. char b;
  227. char c;
  228. }
  229. */
  230. ok = class_addIvar(cls2, "ivarid2", size, align, "@");
  231. testassert(ok);
  232. ok = class_addIvar(cls2, "idarray", 16*sizeof(id), align, "[16@]");
  233. testassert(ok);
  234. ok = class_addIvar(cls2, "ptrarray", 16*sizeof(void*), align, "[16^]");
  235. testassert(ok);
  236. ok = class_addIvar(cls2, "a", 1, 0, "c");
  237. testassert(ok);
  238. ok = class_addIvar(cls2, "b", 1, 0, "c");
  239. testassert(ok);
  240. ok = class_addIvar(cls2, "c", 1, 0, "c");
  241. testassert(ok);
  242. objc_registerClassPair(cls2);
  243. // 1-byte ivars should be well packed
  244. testassert(ivar_getOffset(class_getInstanceVariable(cls2, "b")) ==
  245. ivar_getOffset(class_getInstanceVariable(cls2, "a")) + 1);
  246. testassert(ivar_getOffset(class_getInstanceVariable(cls2, "c")) ==
  247. ivar_getOffset(class_getInstanceVariable(cls2, "b")) + 1);
  248. objc_disposeClassPair(cls2);
  249. objc_disposeClassPair(cls);
  250. testassert(!objc_getClass("Sub"));
  251. // fixme test layout setters
  252. }
  253. int main()
  254. {
  255. int count = 5000;
  256. // fixme even with this long warmup we still
  257. // suffer false 4096-byte leaks occasionally.
  258. for (int i = 0; i < 500; i++) {
  259. testonthread(^{ cycle(); });
  260. }
  261. leak_mark();
  262. while (count--) {
  263. testonthread(^{ cycle(); });
  264. }
  265. leak_check(4096);
  266. succeed(__FILE__);
  267. }