1// TEST_CFLAGS -Wno-unused-parameter 2 3#include "test.h" 4#include "testroot.i" 5 6#if __cplusplus && !__clang__ 7 8int main() 9{ 10 // llvm-g++ is confused by @selector(foo::) and will never be fixed 11 succeed(__FILE__); 12} 13 14#else 15 16#include <objc/objc.h> 17#include <objc/runtime.h> 18#include <objc/objc-internal.h> 19#include <objc/objc-abi.h> 20 21#if defined(__arm__) 22// rdar://8331406 23# define ALIGN_() 24#else 25# define ALIGN_() asm(".align 4"); 26#endif 27 28@interface Super : TestRoot @end 29 30@interface Sub : Super @end 31 32static int state = 0; 33 34static id SELF; 35 36// for typeof() shorthand only 37id (*idmsg0)(id, SEL) __attribute__((unused)); 38long long (*llmsg0)(id, SEL) __attribute__((unused)); 39// struct stret (*stretmsg0)(id, SEL) __attribute__((unused)); 40double (*fpmsg0)(id, SEL) __attribute__((unused)); 41long double (*lfpmsg0)(id, SEL) __attribute__((unused)); 42 43 44#define CHECK_ARGS(sel) \ 45do { \ 46 testassert(self == SELF); \ 47 testassert(_cmd == sel_registerName(#sel "::::::::::::::::::::::::::::"));\ 48 testassert(i1 == 1); \ 49 testassert(i2 == 2); \ 50 testassert(i3 == 3); \ 51 testassert(i4 == 4); \ 52 testassert(i5 == 5); \ 53 testassert(i6 == 6); \ 54 testassert(i7 == 7); \ 55 testassert(i8 == 8); \ 56 testassert(i9 == 9); \ 57 testassert(i10 == 10); \ 58 testassert(i11 == 11); \ 59 testassert(i12 == 12); \ 60 testassert(i13 == 13); \ 61 testassert(f1 == 1.0); \ 62 testassert(f2 == 2.0); \ 63 testassert(f3 == 3.0); \ 64 testassert(f4 == 4.0); \ 65 testassert(f5 == 5.0); \ 66 testassert(f6 == 6.0); \ 67 testassert(f7 == 7.0); \ 68 testassert(f8 == 8.0); \ 69 testassert(f9 == 9.0); \ 70 testassert(f10 == 10.0); \ 71 testassert(f11 == 11.0); \ 72 testassert(f12 == 12.0); \ 73 testassert(f13 == 13.0); \ 74 testassert(f14 == 14.0); \ 75 testassert(f15 == 15.0); \ 76} while (0) 77 78#define CHECK_ARGS_NOARG(sel) \ 79do { \ 80 testassert(self == SELF); \ 81 testassert(_cmd == sel_registerName(#sel "_noarg"));\ 82} while (0) 83 84id NIL_RECEIVER; 85id ID_RESULT; 86long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__; 87double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__; 88long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__; 89// STRET_RESULT in test.h 90 91static struct stret zero; 92 93 94@implementation Super 95-(struct stret)stret { return STRET_RESULT; } 96 97-(id)idret: 98 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 99{ 100 CHECK_ARGS(idret); 101 state = 1; 102 return ID_RESULT; 103} 104 105-(long long)llret: 106 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 107{ 108 CHECK_ARGS(llret); 109 state = 2; 110 return LL_RESULT; 111} 112 113-(struct stret)stret: 114 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 115{ 116 CHECK_ARGS(stret); 117 state = 3; 118 return STRET_RESULT; 119} 120 121-(double)fpret: 122 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 123{ 124 CHECK_ARGS(fpret); 125 state = 4; 126 return FP_RESULT; 127} 128 129-(long double)lfpret: 130 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 131{ 132 CHECK_ARGS(lfpret); 133 state = 5; 134 return LFP_RESULT; 135} 136 137 138-(id)idret_noarg 139{ 140 CHECK_ARGS_NOARG(idret); 141 state = 11; 142 return ID_RESULT; 143} 144 145-(long long)llret_noarg 146{ 147 CHECK_ARGS_NOARG(llret); 148 state = 12; 149 return LL_RESULT; 150} 151 152-(struct stret)stret_noarg 153{ 154 CHECK_ARGS_NOARG(stret); 155 state = 13; 156 return STRET_RESULT; 157} 158 159-(double)fpret_noarg 160{ 161 CHECK_ARGS_NOARG(fpret); 162 state = 14; 163 return FP_RESULT; 164} 165 166-(long double)lfpret_noarg 167{ 168 CHECK_ARGS_NOARG(lfpret); 169 state = 15; 170 return LFP_RESULT; 171} 172 173 174-(void)voidret_nop 175{ 176 return; 177} 178 179-(id)idret_nop 180{ 181 return ID_RESULT; 182} 183 184-(long long)llret_nop 185{ 186 return LL_RESULT; 187} 188 189-(struct stret)stret_nop 190{ 191 return STRET_RESULT; 192} 193 194-(double)fpret_nop 195{ 196 return FP_RESULT; 197} 198 199-(long double)lfpret_nop 200{ 201 return LFP_RESULT; 202} 203 204 205 206+(id)idret: 207 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 208{ 209 fail("+idret called instead of -idret"); 210 CHECK_ARGS(idret); 211} 212 213+(long long)llret: 214 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 215{ 216 fail("+llret called instead of -llret"); 217 CHECK_ARGS(llret); 218} 219 220+(struct stret)stret: 221 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 222{ 223 fail("+stret called instead of -stret"); 224 CHECK_ARGS(stret); 225} 226 227+(double)fpret: 228 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 229{ 230 fail("+fpret called instead of -fpret"); 231 CHECK_ARGS(fpret); 232} 233 234+(long double)lfpret: 235 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 236{ 237 fail("+lfpret called instead of -lfpret"); 238 CHECK_ARGS(lfpret); 239} 240 241+(id)idret_noarg 242{ 243 fail("+idret_noarg called instead of -idret_noarg"); 244 CHECK_ARGS_NOARG(idret); 245} 246 247+(long long)llret_noarg 248{ 249 fail("+llret_noarg called instead of -llret_noarg"); 250 CHECK_ARGS_NOARG(llret); 251} 252 253+(struct stret)stret_noarg 254{ 255 fail("+stret_noarg called instead of -stret_noarg"); 256 CHECK_ARGS_NOARG(stret); 257} 258 259+(double)fpret_noarg 260{ 261 fail("+fpret_noarg called instead of -fpret_noarg"); 262 CHECK_ARGS_NOARG(fpret); 263} 264 265+(long double)lfpret_noarg 266{ 267 fail("+lfpret_noarg called instead of -lfpret_noarg"); 268 CHECK_ARGS_NOARG(lfpret); 269} 270 271@end 272 273 274@implementation Sub 275 276-(id)idret: 277 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 278{ 279 id result; 280 CHECK_ARGS(idret); 281 state = 100; 282 result = [super idret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15]; 283 testassert(state == 1); 284 testassert(result == ID_RESULT); 285 state = 101; 286 return result; 287} 288 289-(long long)llret: 290 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 291{ 292 long long result; 293 CHECK_ARGS(llret); 294 state = 100; 295 result = [super llret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15]; 296 testassert(state == 2); 297 testassert(result == LL_RESULT); 298 state = 102; 299 return result; 300} 301 302-(struct stret)stret: 303 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 304{ 305 struct stret result; 306 CHECK_ARGS(stret); 307 state = 100; 308 result = [super stret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15]; 309 testassert(state == 3); 310 testassert(stret_equal(result, STRET_RESULT)); 311 state = 103; 312 return result; 313} 314 315-(double)fpret: 316 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 317{ 318 double result; 319 CHECK_ARGS(fpret); 320 state = 100; 321 result = [super fpret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15]; 322 testassert(state == 4); 323 testassert(result == FP_RESULT); 324 state = 104; 325 return result; 326} 327 328-(long double)lfpret: 329 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15 330{ 331 long double result; 332 CHECK_ARGS(lfpret); 333 state = 100; 334 result = [super lfpret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15]; 335 testassert(state == 5); 336 testassert(result == LFP_RESULT); 337 state = 105; 338 return result; 339} 340 341 342-(id)idret_noarg 343{ 344 id result; 345 CHECK_ARGS_NOARG(idret); 346 state = 100; 347 result = [super idret_noarg]; 348 testassert(state == 11); 349 testassert(result == ID_RESULT); 350 state = 111; 351 return result; 352} 353 354-(long long)llret_noarg 355{ 356 long long result; 357 CHECK_ARGS_NOARG(llret); 358 state = 100; 359 result = [super llret_noarg]; 360 testassert(state == 12); 361 testassert(result == LL_RESULT); 362 state = 112; 363 return result; 364} 365 366-(struct stret)stret_noarg 367{ 368 struct stret result; 369 CHECK_ARGS_NOARG(stret); 370 state = 100; 371 result = [super stret_noarg]; 372 testassert(state == 13); 373 testassert(stret_equal(result, STRET_RESULT)); 374 state = 113; 375 return result; 376} 377 378-(double)fpret_noarg 379{ 380 double result; 381 CHECK_ARGS_NOARG(fpret); 382 state = 100; 383 result = [super fpret_noarg]; 384 testassert(state == 14); 385 testassert(result == FP_RESULT); 386 state = 114; 387 return result; 388} 389 390-(long double)lfpret_noarg 391{ 392 long double result; 393 CHECK_ARGS_NOARG(lfpret); 394 state = 100; 395 result = [super lfpret_noarg]; 396 testassert(state == 15); 397 testassert(result == LFP_RESULT); 398 state = 115; 399 return result; 400} 401 402@end 403 404 405#if OBJC_HAVE_TAGGED_POINTERS 406 407@interface TaggedSub : Sub @end 408 409@implementation TaggedSub : Sub 410 411+(void)initialize 412{ 413 _objc_registerTaggedPointerClass(OBJC_TAG_7, self); 414} 415 416@end 417 418// DWARF checking machinery 419 420#include <dlfcn.h> 421#include <signal.h> 422#include <sys/mman.h> 423#include <libunwind.h> 424 425#define UNW_STEP_SUCCESS 1 426#define UNW_STEP_END 0 427 428bool caught = false; 429uintptr_t clobbered; 430 431uintptr_t r12 = 0; 432uintptr_t r13 = 0; 433uintptr_t r14 = 0; 434uintptr_t r15 = 0; 435uintptr_t rbx = 0; 436uintptr_t rbp = 0; 437uintptr_t rsp = 0; 438uintptr_t rip = 0; 439 440void handle_exception(x86_thread_state64_t *state) 441{ 442 unw_cursor_t curs; 443 unw_word_t reg; 444 int err; 445 int step; 446 447 err = unw_init_local(&curs, (unw_context_t *)state); 448 testassert(!err); 449 450 step = unw_step(&curs); 451 testassert(step == UNW_STEP_SUCCESS); 452 453 err = unw_get_reg(&curs, UNW_X86_64_R12, ®); 454 testassert(!err); 455 testassert(reg == r12); 456 457 err = unw_get_reg(&curs, UNW_X86_64_R13, ®); 458 testassert(!err); 459 testassert(reg == r13); 460 461 err = unw_get_reg(&curs, UNW_X86_64_R14, ®); 462 testassert(!err); 463 testassert(reg == r14); 464 465 err = unw_get_reg(&curs, UNW_X86_64_R15, ®); 466 testassert(!err); 467 testassert(reg == r15); 468 469 err = unw_get_reg(&curs, UNW_X86_64_RBX, ®); 470 testassert(!err); 471 testassert(reg == rbx); 472 473 err = unw_get_reg(&curs, UNW_X86_64_RBP, ®); 474 testassert(!err); 475 testassert(reg == rbp); 476 477 err = unw_get_reg(&curs, UNW_X86_64_RSP, ®); 478 testassert(!err); 479 testassert(reg == rsp); 480 481 err = unw_get_reg(&curs, UNW_REG_IP, ®); 482 testassert(!err); 483 testassert(reg == rip); 484 485 486 // set thread state to unwound state 487 state->__r12 = r12; 488 state->__r13 = r13; 489 state->__r14 = r14; 490 state->__r15 = r15; 491 state->__rbx = rbx; 492 state->__rbp = rbp; 493 state->__rsp = rsp; 494 state->__rip = rip; 495 496 caught = true; 497} 498 499 500void sigtrap(int sig, siginfo_t *info, void *cc) 501{ 502 ucontext_t *uc = (ucontext_t *)cc; 503 mcontext_t mc = (mcontext_t)uc->uc_mcontext; 504 505 testprintf(" handled\n"); 506 507 testassert(sig == SIGTRAP); 508 testassert((uintptr_t)info->si_addr-1 == clobbered); 509 510 handle_exception(&mc->__ss); 511 // handle_exception changed register state for continuation 512} 513 514 515uint8_t set(uintptr_t dst, uint8_t newvalue) 516{ 517 uintptr_t start = dst & ~(PAGE_SIZE-1); 518 mprotect((void*)start, PAGE_SIZE, PROT_READ|PROT_WRITE); 519 // int3 520 uint8_t oldvalue = *(uint8_t *)dst; 521 *(uint8_t *)dst = newvalue; 522 mprotect((void*)start, PAGE_SIZE, PROT_READ|PROT_EXEC); 523 return oldvalue; 524} 525 526uint8_t clobber(void *fn, uintptr_t offset) 527{ 528 clobbered = (uintptr_t)fn + offset; 529 return set((uintptr_t)fn + offset, 0xcc /*int3*/); 530} 531 532void unclobber(void *fn, uintptr_t offset, uint8_t oldvalue) 533{ 534 set((uintptr_t)fn + offset, oldvalue); 535} 536 537__BEGIN_DECLS 538extern void callit(void *obj, void *sel, void *fn); 539extern struct stret callit_stret(void *obj, void *sel, void *fn); 540__END_DECLS 541 542__asm__( 543"\n .text" 544"\n .globl _callit" 545"\n _callit:" 546// save rsp and rip registers to variables 547"\n movq (%rsp), %r10" 548"\n movq %r10, _rip(%rip)" 549"\n movq %rsp, _rsp(%rip)" 550"\n addq $8, _rsp(%rip)" // rewind to pre-call value 551// save other non-volatile registers to variables 552"\n movq %rbx, _rbx(%rip)" 553"\n movq %rbp, _rbp(%rip)" 554"\n movq %r12, _r12(%rip)" 555"\n movq %r13, _r13(%rip)" 556"\n movq %r14, _r14(%rip)" 557"\n movq %r15, _r15(%rip)" 558"\n jmpq *%rdx" 559 ); 560 561__asm__( 562"\n .text" 563"\n .globl _callit_stret" 564"\n _callit_stret:" 565// save rsp and rip registers to variables 566"\n movq (%rsp), %r10" 567"\n movq %r10, _rip(%rip)" 568"\n movq %rsp, _rsp(%rip)" 569"\n addq $8, _rsp(%rip)" // rewind to pre-call value 570// save other non-volatile registers to variables 571"\n movq %rbx, _rbx(%rip)" 572"\n movq %rbp, _rbp(%rip)" 573"\n movq %r12, _r12(%rip)" 574"\n movq %r13, _r13(%rip)" 575"\n movq %r14, _r14(%rip)" 576"\n movq %r15, _r15(%rip)" 577"\n jmpq *%rcx" 578 ); 579 580uintptr_t *getOffsets(void *symbol, const char *symname) 581{ 582 uintptr_t *result = (uintptr_t *)malloc(PAGE_SIZE * sizeof(uintptr_t)); 583 uintptr_t *end = result + PAGE_SIZE; 584 uintptr_t *p = result; 585 586 // find library 587 Dl_info dl; 588 dladdr(symbol, &dl); 589 590 // call `otool` on library 591 unsetenv("DYLD_LIBRARY_PATH"); 592 unsetenv("DYLD_ROOT_PATH"); 593 unsetenv("DYLD_INSERT_LIBRARIES"); 594 char *cmd; 595 asprintf(&cmd, "/usr/bin/xcrun otool -arch x86_64 -tv -p _%s %s", 596 symname, dl.dli_fname); 597 testprintf("%s\n", cmd); 598 FILE *disa = popen(cmd, "r"); 599 free(cmd); 600 testassert(disa); 601 602 // read past "_symname:" line 603 char *line; 604 size_t len; 605 while ((line = fgetln(disa, &len))) { 606 if (0 == strncmp(1+line, symname, MIN(len-1, strlen(symname)))) break; 607 } 608 609 // read instructions and save offsets 610 char op[128]; 611 long base = 0; 612 long addr; 613 while (2 == fscanf(disa, "%lx%s%*[^\n]\n", &addr, op)) { 614 if (base == 0) base = addr; 615 if (0 != strncmp(op, "nop", 3)) { 616 testassert(p < end); 617 *p++ = addr - base; 618 } else { 619 // assume nops are unreached (e.g. alignment padding) 620 } 621 } 622 pclose(disa); 623 624 testassert(p > result); 625 testassert(p < end); 626 *p = ~0UL; 627 // hack: skip last instruction because libunwind blows up if it's 628 // one byte long and followed by the next function with no NOPs first 629 if (p > result) p[-1] = ~0UL; 630 return result; 631} 632 633void CALLIT(void *o, void *sel_arg, SEL s, void *f) __attribute__((noinline)); 634void CALLIT(void *o, void *sel_arg, SEL s, void *f) 635{ 636 uintptr_t message_ref[2]; 637 if (sel_arg != s) { 638 // fixup dispatch 639 // copy to a local buffer to keep sel_arg un-fixed-up 640 memcpy(message_ref, sel_arg, sizeof(message_ref)); 641 sel_arg = message_ref; 642 } 643 if (s == @selector(idret_nop)) callit(o, sel_arg, f); 644 else if (s == @selector(fpret_nop)) callit(o, sel_arg, f); 645 else if (s == @selector(stret_nop)) callit_stret(o, sel_arg, f); 646 else fail("test_dw selector"); 647} 648 649// sub = ordinary receiver object 650// tagged = tagged receiver object 651// SEL = selector to send 652// sub_arg = arg to pass in receiver register (may be objc_super struct) 653// tagged_arg = arg to pass in receiver register (may be objc_super struct) 654// sel_arg = arg to pass in sel register (may be message_ref) 655void test_dw(const char *name, id sub, id tagged, SEL sel) 656{ 657 testprintf("DWARF FOR %s\n", name); 658 659 void *fn = dlsym(RTLD_DEFAULT, name); 660 testassert(fn); 661 662 // argument substitutions 663 664 void *sub_arg = (void*)objc_unretainedPointer(sub); 665 void *tagged_arg = (void*)objc_unretainedPointer(tagged); 666 void *sel_arg = (void*)sel; 667 668 struct objc_super sup_st = { sub, object_getClass(sub) }; 669 struct objc_super tagged_sup_st = { tagged, object_getClass(tagged) }; 670 struct { void *imp; SEL sel; } message_ref = { fn, sel }; 671 672 if (strstr(name, "Super")) { 673 // super version - replace receiver with objc_super 674 sub_arg = &sup_st; 675 tagged_arg = &tagged_sup_st; 676 } 677 678 if (strstr(name, "_fixup")) { 679 // fixup version - replace sel with message_ref 680 sel_arg = &message_ref; 681 } 682 683 684 uintptr_t *insnOffsets = getOffsets(fn, name); 685 uintptr_t *offsetp = insnOffsets; 686 uintptr_t offset; 687 while ((offset = *offsetp++) != ~0UL) { 688 testprintf("OFFSET %lu\n", offset); 689 690 uint8_t insn_byte = clobber(fn, offset); 691 caught = false; 692 693 // nil 694 if ((void*)objc_unretainedPointer(sub) == sub_arg) { 695 SELF = nil; 696 testprintf(" nil\n"); 697 CALLIT(nil, sel_arg, sel, fn); 698 CALLIT(nil, sel_arg, sel, fn); 699 } 700 701 // uncached 702 SELF = sub; 703 testprintf(" uncached\n"); 704 _objc_flush_caches(object_getClass(sub)); 705 CALLIT(sub_arg, sel_arg, sel, fn); 706 _objc_flush_caches(object_getClass(sub)); 707 CALLIT(sub_arg, sel_arg, sel, fn); 708 709 // cached 710 SELF = sub; 711 testprintf(" cached\n"); 712 CALLIT(sub_arg, sel_arg, sel, fn); 713 CALLIT(sub_arg, sel_arg, sel, fn); 714 715 // uncached,tagged 716 SELF = tagged; 717 testprintf(" uncached,tagged\n"); 718 _objc_flush_caches(object_getClass(tagged)); 719 CALLIT(tagged_arg, sel_arg, sel, fn); 720 _objc_flush_caches(object_getClass(tagged)); 721 CALLIT(tagged_arg, sel_arg, sel, fn); 722 723 // cached,tagged 724 SELF = tagged; 725 testprintf(" cached,tagged\n"); 726 CALLIT(tagged_arg, sel_arg, sel, fn); 727 CALLIT(tagged_arg, sel_arg, sel, fn); 728 729 unclobber(fn, offset, insn_byte); 730 731 // require at least one path above to trip this offset 732 if (!caught) fprintf(stderr, "OFFSET %s+%lu NOT CAUGHT\n", name, offset); 733 } 734 free(insnOffsets); 735} 736 737// x86_64 738#endif 739 740 741void test_basic(id receiver) 742{ 743 id idval; 744 long long llval; 745 struct stret stretval; 746 double fpval; 747 long double lfpval; 748 749 // message uncached 750 // message uncached long long 751 // message uncached stret 752 // message uncached fpret 753 // message uncached fpret long double 754 // message uncached noarg (as above) 755 // message cached 756 // message cached long long 757 // message cached stret 758 // message cached fpret 759 // message cached fpret long double 760 // message cached noarg (as above) 761 // fixme verify that uncached lookup didn't happen the 2nd time? 762 SELF = receiver; 763 for (int i = 0; i < 5; i++) { 764 state = 0; 765 idval = nil; 766 idval = [receiver idret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0]; 767 testassert(state == 101); 768 testassert(idval == ID_RESULT); 769 770 llval = 0; 771 llval = [receiver llret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0]; 772 testassert(state == 102); 773 testassert(llval == LL_RESULT); 774 775 stretval = zero; 776 stretval = [receiver stret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0]; 777 testassert(state == 103); 778 testassert(stret_equal(stretval, STRET_RESULT)); 779 780 fpval = 0; 781 fpval = [receiver fpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0]; 782 testassert(state == 104); 783 testassert(fpval == FP_RESULT); 784 785 lfpval = 0; 786 lfpval = [receiver lfpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0]; 787 testassert(state == 105); 788 testassert(lfpval == LFP_RESULT); 789 790#if __OBJC2__ 791 // explicitly call noarg messenger, even if compiler doesn't emit it 792 state = 0; 793 idval = nil; 794 idval = ((typeof(idmsg0))objc_msgSend_noarg)(receiver, @selector(idret_noarg)); 795 testassert(state == 111); 796 testassert(idval == ID_RESULT); 797 798 llval = 0; 799 llval = ((typeof(llmsg0))objc_msgSend_noarg)(receiver, @selector(llret_noarg)); 800 testassert(state == 112); 801 testassert(llval == LL_RESULT); 802 /* 803 no objc_msgSend_stret_noarg 804 stretval = zero; 805 stretval = ((typeof(stretmsg0))objc_msgSend_stret_noarg)(receiver, @selector(stret_noarg)); 806 stretval = [receiver stret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0]; 807 testassert(state == 113); 808 testassert(stret_equal(stretval, STRET_RESULT)); 809 */ 810# if !__i386__ 811 fpval = 0; 812 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(receiver, @selector(fpret_noarg)); 813 testassert(state == 114); 814 testassert(fpval == FP_RESULT); 815# endif 816# if !__i386__ && !__x86_64__ 817 lfpval = 0; 818 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(receiver, @selector(lfpret_noarg)); 819 testassert(state == 115); 820 testassert(lfpval == LFP_RESULT); 821# endif 822#endif 823 } 824} 825 826int main() 827{ 828 PUSH_POOL { 829 int i; 830 831 id idval; 832 long long llval; 833 struct stret stretval; 834 double fpval; 835 long double lfpval; 836 837#if __x86_64__ 838 struct stret *stretptr; 839#endif 840 841 uint64_t startTime; 842 uint64_t totalTime; 843 uint64_t targetTime; 844 845 Method idmethod; 846 Method llmethod; 847 Method stretmethod; 848 Method fpmethod; 849 Method lfpmethod; 850 851 id (*idfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double); 852 long long (*llfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double); 853 struct stret (*stretfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double); 854 double (*fpfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double); 855 long double (*lfpfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double); 856 857 id (*idmsg)(id, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused)); 858 id (*idmsgsuper)(struct objc_super *, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused)); 859 long long (*llmsg)(id, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused)); 860 struct stret (*stretmsg)(id, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused)); 861 struct stret (*stretmsgsuper)(struct objc_super *, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused)); 862 double (*fpmsg)(id, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused)); 863 long double (*lfpmsg)(id, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused)); 864 865 // get +initialize out of the way 866 [Sub class]; 867#if OBJC_HAVE_TAGGED_POINTERS 868 [TaggedSub class]; 869#endif 870 871 ID_RESULT = [Super new]; 872 873 Sub *sub = [Sub new]; 874 Super *sup = [Super new]; 875#if OBJC_HAVE_TAGGED_POINTERS 876 TaggedSub *tagged = objc_unretainedObject(_objc_makeTaggedPointer(OBJC_TAG_7, 999)); 877#endif 878 879 // Basic cached and uncached dispatch. 880 // Do this first before anything below caches stuff. 881 testprintf("basic\n"); 882 test_basic(sub); 883#if OBJC_HAVE_TAGGED_POINTERS 884 testprintf("basic tagged\n"); 885 test_basic(tagged); 886#endif 887 888 idmethod = class_getInstanceMethod([Super class], @selector(idret::::::::::::::::::::::::::::)); 889 testassert(idmethod); 890 llmethod = class_getInstanceMethod([Super class], @selector(llret::::::::::::::::::::::::::::)); 891 testassert(llmethod); 892 stretmethod = class_getInstanceMethod([Super class], @selector(stret::::::::::::::::::::::::::::)); 893 testassert(stretmethod); 894 fpmethod = class_getInstanceMethod([Super class], @selector(fpret::::::::::::::::::::::::::::)); 895 testassert(fpmethod); 896 lfpmethod = class_getInstanceMethod([Super class], @selector(lfpret::::::::::::::::::::::::::::)); 897 testassert(lfpmethod); 898 899 idfn = (id (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke; 900 llfn = (long long (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke; 901 stretfn = (struct stret (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke_stret; 902 fpfn = (double (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke; 903 lfpfn = (long double (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke; 904 905 // cached message performance 906 // catches failure to cache or (abi=2) failure to fixup (#5584187) 907 // fixme unless they all fail 908 // `.align 4` matches loop alignment to make -O0 work 909 // fill cache first 910 testprintf("time checks\n"); 911 912 SELF = sub; 913 [sub voidret_nop]; 914 [sub llret_nop]; 915 [sub stret_nop]; 916 [sub fpret_nop]; 917 [sub lfpret_nop]; 918 [sub voidret_nop]; 919 [sub llret_nop]; 920 [sub stret_nop]; 921 [sub fpret_nop]; 922 [sub lfpret_nop]; 923 [sub voidret_nop]; 924 [sub llret_nop]; 925 [sub stret_nop]; 926 [sub fpret_nop]; 927 [sub lfpret_nop]; 928 929 // Some of these times have high variance on some compilers. 930 // The errors we're trying to catch should be catastrophically slow, 931 // so the margins here are generous to avoid false failures. 932 933#define COUNT 1000000 934 startTime = mach_absolute_time(); 935 ALIGN_(); 936 for (i = 0; i < COUNT; i++) { 937 [sub voidret_nop]; // id return is too slow for perf test with ARC 938 } 939 totalTime = mach_absolute_time() - startTime; 940 testprintf("time: idret %llu\n", totalTime); 941 targetTime = totalTime; 942 943 startTime = mach_absolute_time(); 944 ALIGN_(); 945 for (i = 0; i < COUNT; i++) { 946 [sub voidret_nop]; // id return is too slow for perf test with ARC 947 } 948 totalTime = mach_absolute_time() - startTime; 949 testprintf("time: idret %llu\n", totalTime); 950 targetTime = totalTime; 951 952 startTime = mach_absolute_time(); 953 ALIGN_(); 954 for (i = 0; i < COUNT; i++) { 955 [sub llret_nop]; 956 } 957 totalTime = mach_absolute_time() - startTime; 958 timecheck("llret ", totalTime, targetTime * 0.7, targetTime * 2.0); 959 960 startTime = mach_absolute_time(); 961 ALIGN_(); 962 for (i = 0; i < COUNT; i++) { 963 [sub stret_nop]; 964 } 965 totalTime = mach_absolute_time() - startTime; 966 timecheck("stret ", totalTime, targetTime * 0.7, targetTime * 5.0); 967 968 startTime = mach_absolute_time(); 969 ALIGN_(); 970 for (i = 0; i < COUNT; i++) { 971 [sub fpret_nop]; 972 } 973 totalTime = mach_absolute_time() - startTime; 974 timecheck("fpret ", totalTime, targetTime * 0.7, targetTime * 4.0); 975 976 startTime = mach_absolute_time(); 977 ALIGN_(); 978 for (i = 0; i < COUNT; i++) { 979 [sub lfpret_nop]; 980 } 981 totalTime = mach_absolute_time() - startTime; 982 timecheck("lfpret", totalTime, targetTime * 0.7, targetTime * 4.0); 983#undef COUNT 984 985 // method_invoke 986 // method_invoke long long 987 // method_invoke_stret stret 988 // method_invoke_stret fpret 989 // method_invoke fpret long double 990 testprintf("method_invoke\n"); 991 992 SELF = sup; 993 994 state = 0; 995 idval = nil; 996 idval = (*idfn)(sup, idmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0); 997 testassert(state == 1); 998 testassert(idval == ID_RESULT); 999 1000 llval = 0; 1001 llval = (*llfn)(sup, llmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0); 1002 testassert(state == 2); 1003 testassert(llval == LL_RESULT); 1004 1005 stretval = zero; 1006 stretval = (*stretfn)(sup, stretmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0); 1007 testassert(state == 3); 1008 testassert(stret_equal(stretval, STRET_RESULT)); 1009 1010 fpval = 0; 1011 fpval = (*fpfn)(sup, fpmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0); 1012 testassert(state == 4); 1013 testassert(fpval == FP_RESULT); 1014 1015 lfpval = 0; 1016 lfpval = (*lfpfn)(sup, lfpmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0); 1017 testassert(state == 5); 1018 testassert(lfpval == LFP_RESULT); 1019 1020 1021 // message to nil 1022 // message to nil long long 1023 // message to nil stret 1024 // message to nil fpret 1025 // message to nil fpret long double 1026 // Use NIL_RECEIVER to avoid compiler optimizations. 1027 testprintf("message to nil\n"); 1028 1029 state = 0; 1030 idval = ID_RESULT; 1031 idval = [(id)NIL_RECEIVER idret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0]; 1032 testassert(state == 0); 1033 testassert(idval == nil); 1034 1035 state = 0; 1036 llval = LL_RESULT; 1037 llval = [(id)NIL_RECEIVER llret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0]; 1038 testassert(state == 0); 1039 testassert(llval == 0LL); 1040 1041 state = 0; 1042 stretval = zero; 1043 stretval = [(id)NIL_RECEIVER stret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0]; 1044 testassert(state == 0); 1045#if __clang__ 1046 testassert(0 == memcmp(&stretval, &zero, sizeof(stretval))); 1047#else 1048 // no stret result guarantee 1049#endif 1050 1051#if __x86_64__ 1052 // check stret return register 1053 state = 0; 1054 stretval = zero; 1055 stretptr = ((struct stret *(*)(struct stret *, id, SEL))objc_msgSend_stret) 1056 (&stretval, nil, @selector(stret_nop)); 1057 testassert(stretptr == &stretval); 1058 testassert(state == 0); 1059 // no stret result guarantee for hand-written calls, even with clang 1060#endif 1061 1062 state = 0; 1063 fpval = FP_RESULT; 1064 fpval = [(id)NIL_RECEIVER fpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0]; 1065 testassert(state == 0); 1066 testassert(fpval == 0.0); 1067 1068 state = 0; 1069 lfpval = LFP_RESULT; 1070 lfpval = [(id)NIL_RECEIVER lfpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0]; 1071 testassert(state == 0); 1072 testassert(lfpval == 0.0); 1073 1074#if __OBJC2__ 1075 // message to nil noarg 1076 // explicitly call noarg messenger, even if compiler doesn't emit it 1077 state = 0; 1078 idval = ID_RESULT; 1079 idval = ((typeof(idmsg0))objc_msgSend_noarg)(nil, @selector(idret_noarg)); 1080 testassert(state == 0); 1081 testassert(idval == nil); 1082 1083 state = 0; 1084 llval = LL_RESULT; 1085 llval = ((typeof(llmsg0))objc_msgSend_noarg)(nil, @selector(llret_noarg)); 1086 testassert(state == 0); 1087 testassert(llval == 0LL); 1088 1089 // no stret_noarg messenger 1090 1091# if !__i386__ 1092 state = 0; 1093 fpval = FP_RESULT; 1094 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(nil, @selector(fpret_noarg)); 1095 testassert(state == 0); 1096 testassert(fpval == 0.0); 1097# endif 1098# if !__i386__ && !__x86_64__ 1099 state = 0; 1100 lfpval = LFP_RESULT; 1101 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(nil, @selector(lfpret_noarg)); 1102 testassert(state == 0); 1103 testassert(lfpval == 0.0); 1104# endif 1105#endif 1106 1107 1108#if __OBJC2__ 1109 // rdar://8271364 objc_msgSendSuper2 must not change objc_super 1110 testprintf("super struct\n"); 1111 struct objc_super sup_st = { 1112 sub, 1113 object_getClass(sub), 1114 }; 1115 1116 SELF = sub; 1117 1118 state = 100; 1119 idval = nil; 1120 idval = ((id(*)(struct objc_super *, SEL, int,int,int,int,int,int,int,int,int,int,int,int,int, double,double,double,double,double,double,double,double,double,double,double,double,double,double,double))objc_msgSendSuper2) (&sup_st, @selector(idret::::::::::::::::::::::::::::), 1,2,3,4,5,6,7,8,9,10,11,12,13, 1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0); 1121 testassert(state == 1); 1122 testassert(idval == ID_RESULT); 1123 testassert(sup_st.receiver == sub); 1124 testassert(sup_st.super_class == object_getClass(sub)); 1125 1126 state = 100; 1127 stretval = zero; 1128 stretval = ((struct stret(*)(struct objc_super *, SEL, int,int,int,int,int,int,int,int,int,int,int,int,int, double,double,double,double,double,double,double,double,double,double,double,double,double,double,double))objc_msgSendSuper2_stret) (&sup_st, @selector(stret::::::::::::::::::::::::::::), 1,2,3,4,5,6,7,8,9,10,11,12,13, 1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0); 1129 testassert(state == 3); 1130 testassert(stret_equal(stretval, STRET_RESULT)); 1131 testassert(sup_st.receiver == sub); 1132 testassert(sup_st.super_class == object_getClass(sub)); 1133#endif 1134 1135#if __OBJC2__ 1136 // Debug messengers. 1137 testprintf("debug messengers\n"); 1138 1139 state = 0; 1140 idmsg = (typeof(idmsg))objc_msgSend_debug; 1141 idval = nil; 1142 idval = (*idmsg)(sub, @selector(idret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0); 1143 testassert(state == 101); 1144 testassert(idval == ID_RESULT); 1145 1146 state = 0; 1147 llmsg = (typeof(llmsg))objc_msgSend_debug; 1148 llval = 0; 1149 llval = (*llmsg)(sub, @selector(llret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0); 1150 testassert(state == 102); 1151 testassert(llval == LL_RESULT); 1152 1153 state = 0; 1154 stretmsg = (typeof(stretmsg))objc_msgSend_stret_debug; 1155 stretval = zero; 1156 stretval = (*stretmsg)(sub, @selector(stret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0); 1157 testassert(state == 103); 1158 testassert(stret_equal(stretval, STRET_RESULT)); 1159 1160 state = 100; 1161 sup_st.receiver = sub; 1162 sup_st.super_class = object_getClass(sub); 1163 idmsgsuper = (typeof(idmsgsuper))objc_msgSendSuper2_debug; 1164 idval = nil; 1165 idval = (*idmsgsuper)(&sup_st, @selector(idret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0); 1166 testassert(state == 1); 1167 testassert(idval == ID_RESULT); 1168 1169 state = 100; 1170 sup_st.receiver = sub; 1171 sup_st.super_class = object_getClass(sub); 1172 stretmsgsuper = (typeof(stretmsgsuper))objc_msgSendSuper2_stret_debug; 1173 stretval = zero; 1174 stretval = (*stretmsgsuper)(&sup_st, @selector(stret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0); 1175 testassert(state == 3); 1176 testassert(stret_equal(stretval, STRET_RESULT)); 1177 1178#if __i386__ 1179 state = 0; 1180 fpmsg = (typeof(fpmsg))objc_msgSend_fpret_debug; 1181 fpval = 0; 1182 fpval = (*fpmsg)(sub, @selector(fpret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0); 1183 testassert(state == 104); 1184 testassert(fpval == FP_RESULT); 1185#endif 1186#if __x86_64__ 1187 state = 0; 1188 lfpmsg = (typeof(lfpmsg))objc_msgSend_fpret_debug; 1189 lfpval = 0; 1190 lfpval = (*lfpmsg)(sub, @selector(lfpret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0); 1191 testassert(state == 105); 1192 testassert(lfpval == LFP_RESULT); 1193 1194 // fixme fp2ret 1195#endif 1196 1197// debug messengers 1198#endif 1199 1200 1201#if __x86_64__ && !__has_feature(objc_arc) 1202 // DWARF unwind tables 1203 // Not for ARC because the extra RR calls hit the traps at the wrong times 1204 testprintf("unwind tables\n"); 1205 1206 // install exception handler 1207 struct sigaction act; 1208 act.sa_sigaction = sigtrap; 1209 act.sa_mask = 0; 1210 act.sa_flags = SA_SIGINFO; 1211 sigaction(SIGTRAP, &act, NULL); 1212 1213 // use _nop methods because other methods make more calls 1214 // which can die in the trapped messenger 1215 1216 test_dw("objc_msgSend", sub,tagged,@selector(idret_nop)); 1217 test_dw("objc_msgSend_stret", sub,tagged,@selector(stret_nop)); 1218 test_dw("objc_msgSend_fpret", sub,tagged,@selector(fpret_nop)); 1219 // fixme fp2ret 1220 test_dw("objc_msgSendSuper", sub,tagged,@selector(idret_nop)); 1221 test_dw("objc_msgSendSuper2", sub,tagged,@selector(idret_nop)); 1222 test_dw("objc_msgSendSuper_stret", sub,tagged,@selector(stret_nop)); 1223 test_dw("objc_msgSendSuper2_stret", sub,tagged,@selector(stret_nop)); 1224 1225 // DWARF unwind tables 1226#endif 1227 } POP_POOL; 1228 succeed(__FILE__); 1229} 1230 1231#endif 1232