]> git.saurik.com Git - apple/objc4.git/blob - test/customrr.m
objc4-532.2.tar.gz
[apple/objc4.git] / test / customrr.m
1 // These options must match customrr2.m
2 // TEST_CONFIG MEM=mrc
3 /*
4 TEST_BUILD
5 $C{COMPILE} $DIR/customrr.m '-Wl,-exported_symbol,.objc_class_name_InheritingSubCat' -o customrr.out
6 $C{COMPILE} -undefined dynamic_lookup -dynamiclib $DIR/customrr-cat1.m -o customrr-cat1.dylib
7 $C{COMPILE} -undefined dynamic_lookup -dynamiclib $DIR/customrr-cat2.m -o customrr-cat2.dylib
8 END
9 */
10
11
12 #include "test.h"
13 #include <dlfcn.h>
14 #include <Foundation/NSObject.h>
15
16 #if !__OBJC2__
17
18 // pacify exported symbols list
19 @interface InheritingSubCat @end
20 @implementation InheritingSubCat @end
21
22 int main(int argc __unused, char **argv)
23 {
24 succeed(basename(argv[0]));
25 }
26
27 #else
28
29 static int Retains;
30 static int Releases;
31 static int Autoreleases;
32 static int RetainCounts;
33 static int PlusRetains;
34 static int PlusReleases;
35 static int PlusAutoreleases;
36 static int PlusRetainCounts;
37
38 static int SubRetains;
39 static int SubReleases;
40 static int SubAutoreleases;
41 static int SubRetainCounts;
42 static int SubPlusRetains;
43 static int SubPlusReleases;
44 static int SubPlusAutoreleases;
45 static int SubPlusRetainCounts;
46
47 static int Imps;
48
49 static id imp_fn(id self, SEL _cmd __unused, ...)
50 {
51 Imps++;
52 return self;
53 }
54
55 static void zero(void) {
56 Retains = 0;
57 Releases = 0;
58 Autoreleases = 0;
59 RetainCounts = 0;
60 PlusRetains = 0;
61 PlusReleases = 0;
62 PlusAutoreleases = 0;
63 PlusRetainCounts = 0;
64
65 SubRetains = 0;
66 SubReleases = 0;
67 SubAutoreleases = 0;
68 SubRetainCounts = 0;
69 SubPlusRetains = 0;
70 SubPlusReleases = 0;
71 SubPlusAutoreleases = 0;
72 SubPlusRetainCounts = 0;
73
74 Imps = 0;
75 }
76
77
78 id HackRetain(id self, SEL _cmd __unused) { Retains++; return self; }
79 void HackRelease(id self __unused, SEL _cmd __unused) { Releases++; }
80 id HackAutorelease(id self, SEL _cmd __unused) { Autoreleases++; return self; }
81 NSUInteger HackRetainCount(id self __unused, SEL _cmd __unused) { RetainCounts++; return 1; }
82 id HackPlusRetain(id self, SEL _cmd __unused) { PlusRetains++; return self; }
83 void HackPlusRelease(id self __unused, SEL _cmd __unused) { PlusReleases++; }
84 id HackPlusAutorelease(id self, SEL _cmd __unused) { PlusAutoreleases++; return self; }
85 NSUInteger HackPlusRetainCount(id self __unused, SEL _cmd __unused) { PlusRetainCounts++; return 1; }
86
87
88 @interface OverridingSub : NSObject @end
89 @implementation OverridingSub
90
91 -(id) retain { SubRetains++; return self; }
92 +(id) retain { SubPlusRetains++; return self; }
93 -(oneway void) release { SubReleases++; }
94 +(oneway void) release { SubPlusReleases++; }
95 -(id) autorelease { SubAutoreleases++; return self; }
96 +(id) autorelease { SubPlusAutoreleases++; return self; }
97 -(NSUInteger) retainCount { SubRetainCounts++; return 1; }
98 +(NSUInteger) retainCount { SubPlusRetainCounts++; return 1; }
99
100 @end
101
102 @interface InheritingSub : NSObject @end
103 @implementation InheritingSub @end
104
105 @interface InheritingSub2 : NSObject @end
106 @implementation InheritingSub2 @end
107 @interface InheritingSub2_2 : InheritingSub2 @end
108 @implementation InheritingSub2_2 @end
109
110 @interface InheritingSub3 : NSObject @end
111 @implementation InheritingSub3 @end
112 @interface InheritingSub3_2 : InheritingSub3 @end
113 @implementation InheritingSub3_2 @end
114
115 @interface InheritingSub4 : NSObject @end
116 @implementation InheritingSub4 @end
117 @interface InheritingSub4_2 : InheritingSub4 @end
118 @implementation InheritingSub4_2 @end
119
120 @interface InheritingSub5 : NSObject @end
121 @implementation InheritingSub5 @end
122 @interface InheritingSub5_2 : InheritingSub5 @end
123 @implementation InheritingSub5_2 @end
124
125 @interface InheritingSub6 : NSObject @end
126 @implementation InheritingSub6 @end
127 @interface InheritingSub6_2 : InheritingSub6 @end
128 @implementation InheritingSub6_2 @end
129
130 @interface InheritingSub7 : NSObject @end
131 @implementation InheritingSub7 @end
132 @interface InheritingSub7_2 : InheritingSub7 @end
133 @implementation InheritingSub7_2 @end
134
135 @interface InheritingSubCat : NSObject @end
136 @implementation InheritingSubCat @end
137 @interface InheritingSubCat_2 : InheritingSubCat @end
138 @implementation InheritingSubCat_2 @end
139
140
141 int main(int argc __unused, char **argv)
142 {
143 objc_autoreleasePoolPush();
144
145 // Hack NSObject's RR methods.
146 // Don't use runtime functions to do this -
147 // we want the runtime to think that these are NSObject's real code
148 {
149 Class cls = [NSObject class];
150 IMP *m;
151 IMP imp;
152 imp = class_getMethodImplementation(cls, @selector(retain));
153 m = (IMP *)class_getInstanceMethod(cls, @selector(retain));
154 testassert(m[2] == imp); // verify Method struct is as we expect
155
156 m = (IMP *)class_getInstanceMethod(cls, @selector(retain));
157 m[2] = (IMP)HackRetain;
158 m = (IMP *)class_getInstanceMethod(cls, @selector(release));
159 m[2] = (IMP)HackRelease;
160 m = (IMP *)class_getInstanceMethod(cls, @selector(autorelease));
161 m[2] = (IMP)HackAutorelease;
162 m = (IMP *)class_getInstanceMethod(cls, @selector(retainCount));
163 m[2] = (IMP)HackRetainCount;
164 m = (IMP *)class_getClassMethod(cls, @selector(retain));
165 m[2] = (IMP)HackPlusRetain;
166 m = (IMP *)class_getClassMethod(cls, @selector(release));
167 m[2] = (IMP)HackPlusRelease;
168 m = (IMP *)class_getClassMethod(cls, @selector(autorelease));
169 m[2] = (IMP)HackPlusAutorelease;
170 m = (IMP *)class_getClassMethod(cls, @selector(retainCount));
171 m[2] = (IMP)HackPlusRetainCount;
172
173 _objc_flush_caches(cls);
174
175 imp = class_getMethodImplementation(cls, @selector(retain));
176 testassert(imp == (IMP)HackRetain); // verify hack worked
177 }
178
179 Class cls = [NSObject class];
180 Class icl = [InheritingSub class];
181 Class ocl = [OverridingSub class];
182 NSObject *obj = [NSObject new];
183 InheritingSub *inh = [InheritingSub new];
184 OverridingSub *ovr = [OverridingSub new];
185
186 Class ccc;
187 id ooo;
188 Class cc2;
189 id oo2;
190
191 void *dlh;
192
193
194 testprintf("method dispatch does not bypass\n");
195 zero();
196
197 [obj retain];
198 testassert(Retains == 1);
199 [obj release];
200 testassert(Releases == 1);
201 [obj autorelease];
202 testassert(Autoreleases == 1);
203
204 [cls retain];
205 testassert(PlusRetains == 1);
206 [cls release];
207 testassert(PlusReleases == 1);
208 [cls autorelease];
209 testassert(PlusAutoreleases == 1);
210
211 [inh retain];
212 testassert(Retains == 2);
213 [inh release];
214 testassert(Releases == 2);
215 [inh autorelease];
216 testassert(Autoreleases == 2);
217
218 [icl retain];
219 testassert(PlusRetains == 2);
220 [icl release];
221 testassert(PlusReleases == 2);
222 [icl autorelease];
223 testassert(PlusAutoreleases == 2);
224
225 [ovr retain];
226 testassert(SubRetains == 1);
227 [ovr release];
228 testassert(SubReleases == 1);
229 [ovr autorelease];
230 testassert(SubAutoreleases == 1);
231
232 [ocl retain];
233 testassert(SubPlusRetains == 1);
234 [ocl release];
235 testassert(SubPlusReleases == 1);
236 [ocl autorelease];
237 testassert(SubPlusAutoreleases == 1);
238
239
240 testprintf("arc function bypasses instance but not class or override\n");
241 zero();
242
243 objc_retain(obj);
244 testassert(Retains == 0);
245 objc_release(obj);
246 testassert(Releases == 0);
247 objc_autorelease(obj);
248 testassert(Autoreleases == 0);
249
250 objc_retain(cls);
251 testassert(PlusRetains == 1);
252 objc_release(cls);
253 testassert(PlusReleases == 1);
254 objc_autorelease(cls);
255 testassert(PlusAutoreleases == 1);
256
257 objc_retain(inh);
258 testassert(Retains == 0);
259 objc_release(inh);
260 testassert(Releases == 0);
261 objc_autorelease(inh);
262 testassert(Autoreleases == 0);
263
264 objc_retain(icl);
265 testassert(PlusRetains == 2);
266 objc_release(icl);
267 testassert(PlusReleases == 2);
268 objc_autorelease(icl);
269 testassert(PlusAutoreleases == 2);
270
271 objc_retain(ovr);
272 testassert(SubRetains == 1);
273 objc_release(ovr);
274 testassert(SubReleases == 1);
275 objc_autorelease(ovr);
276 testassert(SubAutoreleases == 1);
277
278 objc_retain(ocl);
279 testassert(SubPlusRetains == 1);
280 objc_release(ocl);
281 testassert(SubPlusReleases == 1);
282 objc_autorelease(ocl);
283 testassert(SubPlusAutoreleases == 1);
284
285
286 testprintf("unrelated addMethod does not clobber\n");
287 zero();
288
289 class_addMethod(cls, @selector(unrelatedMethod), (IMP)imp_fn, "");
290
291 objc_retain(obj);
292 testassert(Retains == 0);
293 objc_release(obj);
294 testassert(Releases == 0);
295 objc_autorelease(obj);
296 testassert(Autoreleases == 0);
297
298
299 testprintf("add class method does not clobber\n");
300 zero();
301
302 objc_retain(obj);
303 testassert(Retains == 0);
304 objc_release(obj);
305 testassert(Releases == 0);
306 objc_autorelease(obj);
307 testassert(Autoreleases == 0);
308
309 class_addMethod(cls->isa, @selector(retain), (IMP)imp_fn, "");
310
311 objc_retain(obj);
312 testassert(Retains == 0);
313 objc_release(obj);
314 testassert(Releases == 0);
315 objc_autorelease(obj);
316 testassert(Autoreleases == 0);
317
318
319 testprintf("addMethod clobbers (InheritingSub2, retain)\n");
320 zero();
321
322 ccc = [InheritingSub2 class];
323 ooo = [ccc new];
324 cc2 = [InheritingSub2_2 class];
325 oo2 = [cc2 new];
326
327 objc_retain(ooo);
328 testassert(Retains == 0);
329 objc_release(ooo);
330 testassert(Releases == 0);
331 objc_autorelease(ooo);
332 testassert(Autoreleases == 0);
333
334 objc_retain(oo2);
335 testassert(Retains == 0);
336 objc_release(oo2);
337 testassert(Releases == 0);
338 objc_autorelease(oo2);
339 testassert(Autoreleases == 0);
340
341 class_addMethod(ccc, @selector(retain), (IMP)imp_fn, "");
342
343 objc_retain(ooo);
344 testassert(Retains == 0);
345 testassert(Imps == 1);
346 objc_release(ooo);
347 testassert(Releases == 1);
348 objc_autorelease(ooo);
349 testassert(Autoreleases == 1);
350
351 objc_retain(oo2);
352 testassert(Retains == 0);
353 testassert(Imps == 2);
354 objc_release(oo2);
355 testassert(Releases == 2);
356 objc_autorelease(oo2);
357 testassert(Autoreleases == 2);
358
359
360 testprintf("addMethod clobbers (InheritingSub3, release)\n");
361 zero();
362
363 ccc = [InheritingSub3 class];
364 ooo = [ccc new];
365 cc2 = [InheritingSub3_2 class];
366 oo2 = [cc2 new];
367
368 objc_retain(ooo);
369 testassert(Retains == 0);
370 objc_release(ooo);
371 testassert(Releases == 0);
372 objc_autorelease(ooo);
373 testassert(Autoreleases == 0);
374
375 objc_retain(oo2);
376 testassert(Retains == 0);
377 objc_release(oo2);
378 testassert(Releases == 0);
379 objc_autorelease(oo2);
380 testassert(Autoreleases == 0);
381
382 class_addMethod(ccc, @selector(release), (IMP)imp_fn, "");
383
384 objc_retain(ooo);
385 testassert(Retains == 1);
386 objc_release(ooo);
387 testassert(Releases == 0);
388 testassert(Imps == 1);
389 objc_autorelease(ooo);
390 testassert(Autoreleases == 1);
391
392 objc_retain(oo2);
393 testassert(Retains == 2);
394 objc_release(oo2);
395 testassert(Releases == 0);
396 testassert(Imps == 2);
397 objc_autorelease(oo2);
398 testassert(Autoreleases == 2);
399
400
401 testprintf("addMethod clobbers (InheritingSub4, autorelease)\n");
402 zero();
403
404 ccc = [InheritingSub4 class];
405 ooo = [ccc new];
406 cc2 = [InheritingSub4_2 class];
407 oo2 = [cc2 new];
408
409 objc_retain(ooo);
410 testassert(Retains == 0);
411 objc_release(ooo);
412 testassert(Releases == 0);
413 objc_autorelease(ooo);
414 testassert(Autoreleases == 0);
415
416 objc_retain(oo2);
417 testassert(Retains == 0);
418 objc_release(oo2);
419 testassert(Releases == 0);
420 objc_autorelease(oo2);
421 testassert(Autoreleases == 0);
422
423 class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
424
425 objc_retain(ooo);
426 testassert(Retains == 1);
427 objc_release(ooo);
428 testassert(Releases == 1);
429 objc_autorelease(ooo);
430 testassert(Autoreleases == 0);
431 testassert(Imps == 1);
432
433 objc_retain(oo2);
434 testassert(Retains == 2);
435 objc_release(oo2);
436 testassert(Releases == 2);
437 objc_autorelease(oo2);
438 testassert(Autoreleases == 0);
439 testassert(Imps == 2);
440
441
442 testprintf("addMethod clobbers (InheritingSub5, retainCount)\n");
443 zero();
444
445 ccc = [InheritingSub5 class];
446 ooo = [ccc new];
447 cc2 = [InheritingSub5_2 class];
448 oo2 = [cc2 new];
449
450 objc_retain(ooo);
451 testassert(Retains == 0);
452 objc_release(ooo);
453 testassert(Releases == 0);
454 objc_autorelease(ooo);
455 testassert(Autoreleases == 0);
456
457 objc_retain(oo2);
458 testassert(Retains == 0);
459 objc_release(oo2);
460 testassert(Releases == 0);
461 objc_autorelease(oo2);
462 testassert(Autoreleases == 0);
463
464 class_addMethod(ccc, @selector(retainCount), (IMP)imp_fn, "");
465
466 objc_retain(ooo);
467 testassert(Retains == 1);
468 objc_release(ooo);
469 testassert(Releases == 1);
470 objc_autorelease(ooo);
471 testassert(Autoreleases == 1);
472 // no bypassing call for -retainCount
473
474 objc_retain(oo2);
475 testassert(Retains == 2);
476 objc_release(oo2);
477 testassert(Releases == 2);
478 objc_autorelease(oo2);
479 testassert(Autoreleases == 2);
480 // no bypassing call for -retainCount
481
482
483 testprintf("setSuperclass to clean super does not clobber (InheritingSub6)\n");
484 zero();
485
486 ccc = [InheritingSub6 class];
487 ooo = [ccc new];
488 cc2 = [InheritingSub6_2 class];
489 oo2 = [cc2 new];
490
491 objc_retain(ooo);
492 testassert(Retains == 0);
493 objc_release(ooo);
494 testassert(Releases == 0);
495 objc_autorelease(ooo);
496 testassert(Autoreleases == 0);
497
498 objc_retain(oo2);
499 testassert(Retains == 0);
500 objc_release(oo2);
501 testassert(Releases == 0);
502 objc_autorelease(oo2);
503 testassert(Autoreleases == 0);
504
505 class_setSuperclass(ccc, [InheritingSub class]);
506
507 objc_retain(ooo);
508 testassert(Retains == 0);
509 objc_release(ooo);
510 testassert(Releases == 0);
511 objc_autorelease(ooo);
512 testassert(Autoreleases == 0);
513
514 objc_retain(oo2);
515 testassert(Retains == 0);
516 objc_release(oo2);
517 testassert(Releases == 0);
518 objc_autorelease(oo2);
519 testassert(Autoreleases == 0);
520
521
522 testprintf("setSuperclass to dirty super clobbers (InheritingSub7)\n");
523 zero();
524
525 ccc = [InheritingSub7 class];
526 ooo = [ccc new];
527 cc2 = [InheritingSub7_2 class];
528 oo2 = [cc2 new];
529
530 objc_retain(ooo);
531 testassert(Retains == 0);
532 objc_release(ooo);
533 testassert(Releases == 0);
534 objc_autorelease(ooo);
535 testassert(Autoreleases == 0);
536
537 objc_retain(oo2);
538 testassert(Retains == 0);
539 objc_release(oo2);
540 testassert(Releases == 0);
541 objc_autorelease(oo2);
542 testassert(Autoreleases == 0);
543
544 class_setSuperclass(ccc, [OverridingSub class]);
545
546 objc_retain(ooo);
547 testassert(SubRetains == 1);
548 objc_release(ooo);
549 testassert(SubReleases == 1);
550 objc_autorelease(ooo);
551 testassert(SubAutoreleases == 1);
552
553 objc_retain(oo2);
554 testassert(SubRetains == 2);
555 objc_release(oo2);
556 testassert(SubReleases == 2);
557 objc_autorelease(oo2);
558 testassert(SubAutoreleases == 2);
559
560
561 testprintf("category replacement of unrelated method does not clobber (InheritingSubCat)\n");
562 zero();
563
564 ccc = [InheritingSubCat class];
565 ooo = [ccc new];
566 cc2 = [InheritingSubCat_2 class];
567 oo2 = [cc2 new];
568
569 objc_retain(ooo);
570 testassert(Retains == 0);
571 objc_release(ooo);
572 testassert(Releases == 0);
573 objc_autorelease(ooo);
574 testassert(Autoreleases == 0);
575
576 objc_retain(oo2);
577 testassert(Retains == 0);
578 objc_release(oo2);
579 testassert(Releases == 0);
580 objc_autorelease(oo2);
581 testassert(Autoreleases == 0);
582
583 dlh = dlopen("customrr-cat1.dylib", RTLD_LAZY);
584 testassert(dlh);
585
586 objc_retain(ooo);
587 testassert(Retains == 0);
588 objc_release(ooo);
589 testassert(Releases == 0);
590 objc_autorelease(ooo);
591 testassert(Autoreleases == 0);
592
593 objc_retain(oo2);
594 testassert(Retains == 0);
595 objc_release(oo2);
596 testassert(Releases == 0);
597 objc_autorelease(oo2);
598 testassert(Autoreleases == 0);
599
600
601 testprintf("category replacement clobbers (InheritingSubCat)\n");
602 zero();
603
604 ccc = [InheritingSubCat class];
605 ooo = [ccc new];
606 cc2 = [InheritingSubCat_2 class];
607 oo2 = [cc2 new];
608
609 objc_retain(ooo);
610 testassert(Retains == 0);
611 objc_release(ooo);
612 testassert(Releases == 0);
613 objc_autorelease(ooo);
614 testassert(Autoreleases == 0);
615
616 objc_retain(oo2);
617 testassert(Retains == 0);
618 objc_release(oo2);
619 testassert(Releases == 0);
620 objc_autorelease(oo2);
621 testassert(Autoreleases == 0);
622
623 dlh = dlopen("customrr-cat2.dylib", RTLD_LAZY);
624 testassert(dlh);
625
626 objc_retain(ooo);
627 testassert(Retains == 1);
628 objc_release(ooo);
629 testassert(Releases == 1);
630 objc_autorelease(ooo);
631 testassert(Autoreleases == 1);
632
633 objc_retain(oo2);
634 testassert(Retains == 2);
635 objc_release(oo2);
636 testassert(Releases == 2);
637 objc_autorelease(oo2);
638 testassert(Autoreleases == 2);
639
640
641 testprintf("allocateClassPair with clean super does not clobber\n");
642 zero();
643
644 objc_retain(inh);
645 testassert(Retains == 0);
646 objc_release(inh);
647 testassert(Releases == 0);
648 objc_autorelease(inh);
649 testassert(Autoreleases == 0);
650
651 ccc = objc_allocateClassPair([InheritingSub class], "CleanClassPair", 0);
652 objc_registerClassPair(ccc);
653 ooo = [ccc new];
654
655 objc_retain(inh);
656 testassert(Retains == 0);
657 objc_release(inh);
658 testassert(Releases == 0);
659 objc_autorelease(inh);
660 testassert(Autoreleases == 0);
661
662 objc_retain(ooo);
663 testassert(Retains == 0);
664 objc_release(ooo);
665 testassert(Releases == 0);
666 objc_autorelease(ooo);
667 testassert(Autoreleases == 0);
668
669
670 testprintf("allocateClassPair with clobbered super clobbers\n");
671 zero();
672
673 ccc = objc_allocateClassPair([OverridingSub class], "DirtyClassPair", 0);
674 objc_registerClassPair(ccc);
675 ooo = [ccc new];
676
677 objc_retain(ooo);
678 testassert(SubRetains == 1);
679 objc_release(ooo);
680 testassert(SubReleases == 1);
681 objc_autorelease(ooo);
682 testassert(SubAutoreleases == 1);
683
684
685 testprintf("allocateClassPair with clean super and override clobbers\n");
686 zero();
687
688 ccc = objc_allocateClassPair([InheritingSub class], "Dirty2ClassPair", 0);
689 class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
690 objc_registerClassPair(ccc);
691 ooo = [ccc new];
692
693 objc_retain(ooo);
694 testassert(Retains == 1);
695 objc_release(ooo);
696 testassert(Releases == 1);
697 objc_autorelease(ooo);
698 testassert(Autoreleases == 0);
699 testassert(Imps == 1);
700
701
702 // method_setImplementation and method_exchangeImplementations only
703 // clobber when manipulating NSObject. We can only test one at a time.
704 // To test both, we need two tests: customrr and customrr2.
705
706 // These tests also check recursive clobber.
707
708 #if TEST_EXCHANGEIMPLEMENTATIONS
709 testprintf("exchangeImplementations clobbers (recursive)\n");
710 #else
711 testprintf("setImplementation clobbers (recursive)\n");
712 #endif
713 zero();
714
715 objc_retain(obj);
716 testassert(Retains == 0);
717 objc_release(obj);
718 testassert(Releases == 0);
719 objc_autorelease(obj);
720 testassert(Autoreleases == 0);
721
722 objc_retain(inh);
723 testassert(Retains == 0);
724 objc_release(inh);
725 testassert(Releases == 0);
726 objc_autorelease(inh);
727 testassert(Autoreleases == 0);
728
729 Method meth = class_getInstanceMethod(cls, @selector(retainCount));
730 testassert(meth);
731 #if TEST_EXCHANGEIMPLEMENTATIONS
732 method_exchangeImplementations(meth, meth);
733 #else
734 method_setImplementation(meth, (IMP)imp_fn);
735 #endif
736
737 objc_retain(obj);
738 testassert(Retains == 1);
739 objc_release(obj);
740 testassert(Releases == 1);
741 objc_autorelease(obj);
742 testassert(Autoreleases == 1);
743
744 objc_retain(inh);
745 testassert(Retains == 2);
746 objc_release(inh);
747 testassert(Releases == 2);
748 objc_autorelease(inh);
749 testassert(Autoreleases == 2);
750
751
752 // do not add more tests here - the recursive test must be LAST
753
754 succeed(basename(argv[0]));
755 }
756
757 #endif