1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680 |
- /*
- asm-placeholder.exe is used below to disassemble objc_msgSend
- TEST_BUILD
- $C{COMPILE} -x assembler $DIR/asm-placeholder.s -o asm-placeholder.exe
- $C{COMPILE} $DIR/msgSend.m -o msgSend.exe -Wno-unused-parameter -Wundeclared-selector -D__DARWIN_OPAQUE_ARM_THREAD_STATE64=1
- END
- */
- #include "test.h"
- #include "testroot.i"
- #include <libkern/OSCacheControl.h>
- #include <sys/stat.h>
- #include <objc/objc.h>
- #include <objc/runtime.h>
- #include <objc/objc-internal.h>
- #include <objc/objc-abi.h>
- #include <simd/simd.h>
- #include <mach-o/loader.h>
- // rdar://21694990 simd.h should have a vector_equal(a, b) function
- static bool vector_equal(vector_ulong2 lhs, vector_ulong2 rhs) {
- return vector_all(lhs == rhs);
- }
- #if __arm64__
- // no stret dispatchers
- # define SUPPORT_STRET 0
- # define objc_msgSend_stret objc_msgSend
- # define objc_msgSendSuper2_stret objc_msgSendSuper2
- # define objc_msgSend_stret_debug objc_msgSend_debug
- # define objc_msgSendSuper2_stret_debug objc_msgSendSuper2_debug
- # define objc_msgLookup_stret objc_msgLookup
- # define objc_msgLookupSuper2_stret objc_msgLookupSuper2
- # define method_invoke_stret method_invoke
- #else
- # define SUPPORT_STRET 1
- #endif
-
-
- #if defined(__arm__)
- // rdar://8331406
- # define ALIGN_()
- #else
- # define ALIGN_() asm(".align 4");
- #endif
- @interface Super : TestRoot @end
- @interface Sub : Super @end
- static int state = 0;
- static id SELF;
- // for typeof() shorthand only
- id (*idmsg0)(id, SEL) __attribute__((unused));
- long long (*llmsg0)(id, SEL) __attribute__((unused));
- // struct stret (*stretmsg0)(id, SEL) __attribute__((unused));
- double (*fpmsg0)(id, SEL) __attribute__((unused));
- long double (*lfpmsg0)(id, SEL) __attribute__((unused));
- vector_ulong2 (*vecmsg0)(id, SEL) __attribute__((unused));
- #define VEC1 ((vector_ulong2){1, 1})
- #define VEC2 ((vector_ulong2){2, 2})
- #define VEC3 ((vector_ulong2){3, 3})
- #define VEC4 ((vector_ulong2){4, 4})
- #define VEC5 ((vector_ulong2){5, 5})
- #define VEC6 ((vector_ulong2){6, 6})
- #define VEC7 ((vector_ulong2){7, 7})
- #define VEC8 ((vector_ulong2){8, 8})
- #define CHECK_ARGS(sel) \
- do { \
- testassert(self == SELF); \
- testassert(_cmd == sel_registerName(#sel "::::::::::::::::::::::::::::::::::::"));\
- testassert(i1 == 1); \
- testassert(i2 == 2); \
- testassert(i3 == 3); \
- testassert(i4 == 4); \
- testassert(i5 == 5); \
- testassert(i6 == 6); \
- testassert(i7 == 7); \
- testassert(i8 == 8); \
- testassert(i9 == 9); \
- testassert(i10 == 10); \
- testassert(i11 == 11); \
- testassert(i12 == 12); \
- testassert(i13 == 13); \
- testassert(f1 == 1.0); \
- testassert(f2 == 2.0); \
- testassert(f3 == 3.0); \
- testassert(f4 == 4.0); \
- testassert(f5 == 5.0); \
- testassert(f6 == 6.0); \
- testassert(f7 == 7.0); \
- testassert(f8 == 8.0); \
- testassert(f9 == 9.0); \
- testassert(f10 == 10.0); \
- testassert(f11 == 11.0); \
- testassert(f12 == 12.0); \
- testassert(f13 == 13.0); \
- testassert(f14 == 14.0); \
- testassert(f15 == 15.0); \
- testassert(vector_all(v1 == 1)); \
- testassert(vector_all(v2 == 2)); \
- testassert(vector_all(v3 == 3)); \
- testassert(vector_all(v4 == 4)); \
- testassert(vector_all(v5 == 5)); \
- testassert(vector_all(v6 == 6)); \
- testassert(vector_all(v7 == 7)); \
- testassert(vector_all(v8 == 8)); \
- } while (0)
- #define CHECK_ARGS_NOARG(sel) \
- do { \
- testassert(self == SELF); \
- testassert(_cmd == sel_registerName(#sel "_noarg"));\
- } while (0)
- id NIL_RECEIVER;
- id ID_RESULT;
- long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__;
- double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__;
- long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__;
- vector_ulong2 VEC_RESULT = { 0x1234567890abcdefULL, 0xfedcba0987654321ULL };
- // STRET_RESULT in test.h
- static struct stret zero;
- struct stret_i1 {
- uintptr_t i1;
- };
- struct stret_i2 {
- uintptr_t i1;
- uintptr_t i2;
- };
- struct stret_i3 {
- uintptr_t i1;
- uintptr_t i2;
- uintptr_t i3;
- };
- struct stret_i4 {
- uintptr_t i1;
- uintptr_t i2;
- uintptr_t i3;
- };
- struct stret_i5 {
- uintptr_t i1;
- uintptr_t i2;
- uintptr_t i3;
- uintptr_t i4;
- uintptr_t i5;
- };
- struct stret_i6 {
- uintptr_t i1;
- uintptr_t i2;
- uintptr_t i3;
- uintptr_t i4;
- uintptr_t i5;
- uintptr_t i6;
- };
- struct stret_i7 {
- uintptr_t i1;
- uintptr_t i2;
- uintptr_t i3;
- uintptr_t i4;
- uintptr_t i5;
- uintptr_t i6;
- uintptr_t i7;
- };
- struct stret_i8 {
- uintptr_t i1;
- uintptr_t i2;
- uintptr_t i3;
- uintptr_t i4;
- uintptr_t i5;
- uintptr_t i8;
- uintptr_t i9;
- };
- struct stret_i9 {
- uintptr_t i1;
- uintptr_t i2;
- uintptr_t i3;
- uintptr_t i4;
- uintptr_t i5;
- uintptr_t i6;
- uintptr_t i7;
- uintptr_t i8;
- uintptr_t i9;
- };
- struct stret_d1 {
- double d1;
- };
- struct stret_d2 {
- double d1;
- double d2;
- };
- struct stret_d3 {
- double d1;
- double d2;
- double d3;
- };
- struct stret_d4 {
- double d1;
- double d2;
- double d3;
- };
- struct stret_d5 {
- double d1;
- double d2;
- double d3;
- double d4;
- double d5;
- };
- struct stret_d6 {
- double d1;
- double d2;
- double d3;
- double d4;
- double d5;
- double d6;
- };
- struct stret_d7 {
- double d1;
- double d2;
- double d3;
- double d4;
- double d5;
- double d6;
- double d7;
- };
- struct stret_d8 {
- double d1;
- double d2;
- double d3;
- double d4;
- double d5;
- double d8;
- double d9;
- };
- struct stret_d9 {
- double d1;
- double d2;
- double d3;
- double d4;
- double d5;
- double d6;
- double d7;
- double d8;
- double d9;
- };
- @interface Super (Prototypes)
- // Method prototypes to pacify -Wundeclared-selector.
- -(id)idret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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;
- -(long long)llret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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;
- -(struct stret)stret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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;
- -(double)fpret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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;
- -(long double)lfpret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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;
- -(vector_ulong2)vecret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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;
- @end
- // Zero all volatile registers.
- #if __cplusplus
- extern "C"
- #endif
- void stomp(void);
- #if __x86_64__
- asm("\n .text"
- "\n .globl _stomp"
- "\n _stomp:"
- "\n mov $0, %rax"
- "\n mov $0, %rcx"
- "\n mov $0, %rdx"
- "\n mov $0, %rsi"
- "\n mov $0, %rdi"
- "\n mov $0, %r8"
- "\n mov $0, %r9"
- "\n mov $0, %r10"
- "\n mov $0, %r11"
- "\n xorps %xmm0, %xmm0"
- "\n xorps %xmm1, %xmm1"
- "\n xorps %xmm2, %xmm2"
- "\n xorps %xmm3, %xmm3"
- "\n xorps %xmm4, %xmm4"
- "\n xorps %xmm5, %xmm5"
- "\n xorps %xmm6, %xmm6"
- "\n xorps %xmm7, %xmm7"
- "\n xorps %xmm8, %xmm8"
- "\n xorps %xmm9, %xmm9"
- "\n xorps %xmm10, %xmm10"
- "\n xorps %xmm11, %xmm11"
- "\n xorps %xmm12, %xmm12"
- "\n xorps %xmm13, %xmm13"
- "\n xorps %xmm14, %xmm14"
- "\n xorps %xmm15, %xmm15"
- "\n ret");
- #elif __i386__
- asm("\n .text"
- "\n .globl _stomp"
- "\n _stomp:"
- "\n mov $0, %eax"
- "\n mov $0, %ecx"
- "\n mov $0, %edx"
- "\n xorps %xmm0, %xmm0"
- "\n xorps %xmm1, %xmm1"
- "\n xorps %xmm2, %xmm2"
- "\n xorps %xmm3, %xmm3"
- "\n xorps %xmm4, %xmm4"
- "\n xorps %xmm5, %xmm5"
- "\n xorps %xmm6, %xmm6"
- "\n xorps %xmm7, %xmm7"
- "\n ret");
- #elif __arm64__
- asm("\n .text"
- "\n .globl _stomp"
- "\n _stomp:"
- "\n mov x0, #0"
- "\n mov x1, #0"
- "\n mov x2, #0"
- "\n mov x3, #0"
- "\n mov x4, #0"
- "\n mov x5, #0"
- "\n mov x6, #0"
- "\n mov x7, #0"
- "\n mov x8, #0"
- "\n mov x9, #0"
- "\n mov x10, #0"
- "\n mov x11, #0"
- "\n mov x12, #0"
- "\n mov x13, #0"
- "\n mov x14, #0"
- "\n mov x15, #0"
- "\n mov x16, #0"
- "\n mov x17, #0"
- "\n movi d0, #0"
- "\n movi d1, #0"
- "\n movi d2, #0"
- "\n movi d3, #0"
- "\n movi d4, #0"
- "\n movi d5, #0"
- "\n movi d6, #0"
- "\n movi d7, #0"
- "\n ret"
- );
- #elif __arm__
- asm("\n .text"
- "\n .globl _stomp"
- "\n .thumb_func _stomp"
- "\n _stomp:"
- "\n mov r0, #0"
- "\n mov r1, #0"
- "\n mov r2, #0"
- "\n mov r3, #0"
- "\n mov r9, #0"
- "\n mov r12, #0"
- "\n vmov.i32 q0, #0"
- "\n vmov.i32 q1, #0"
- "\n vmov.i32 q2, #0"
- "\n vmov.i32 q3, #0"
- "\n vmov.i32 q8, #0"
- "\n vmov.i32 q9, #0"
- "\n vmov.i32 q10, #0"
- "\n vmov.i32 q11, #0"
- "\n vmov.i32 q12, #0"
- "\n vmov.i32 q13, #0"
- "\n vmov.i32 q14, #0"
- "\n vmov.i32 q15, #0"
- "\n bx lr"
- );
- #else
- # error unknown architecture
- #endif
- @implementation Super
- -(struct stret)stret { return STRET_RESULT; }
- // The IMPL_ methods are not called directly. Instead the non IMPL_ name is
- // called. The resolver function installs the real method. This allows
- // the resolver function to stomp on registers to help test register
- // preservation in the uncached path.
- +(BOOL) resolveInstanceMethod:(SEL)sel
- {
- const char *name = sel_getName(sel);
- if (! strstr(name, "::::::::")) return false;
- testprintf("resolving %s\n", name);
- stomp();
- char *realName;
- asprintf(&realName, "IMPL_%s", name);
- SEL realSel = sel_registerName(realName);
- free(realName);
- IMP imp = class_getMethodImplementation(self, realSel);
- if (imp == &_objc_msgForward) return false;
- return class_addMethod(self, sel, imp, "");
- }
- -(id)IMPL_idret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- CHECK_ARGS(idret);
- state = 1;
- return ID_RESULT;
- }
- -(long long)IMPL_llret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- CHECK_ARGS(llret);
- state = 2;
- return LL_RESULT;
- }
- -(struct stret)IMPL_stret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- CHECK_ARGS(stret);
- state = 3;
- return STRET_RESULT;
- }
- -(double)IMPL_fpret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- CHECK_ARGS(fpret);
- state = 4;
- return FP_RESULT;
- }
- -(long double)IMPL_lfpret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- CHECK_ARGS(lfpret);
- state = 5;
- return LFP_RESULT;
- }
- -(vector_ulong2)IMPL_vecret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- CHECK_ARGS(vecret);
- state = 6;
- return VEC_RESULT;
- }
- -(id)idret_noarg
- {
- CHECK_ARGS_NOARG(idret);
- state = 11;
- return ID_RESULT;
- }
- -(long long)llret_noarg
- {
- CHECK_ARGS_NOARG(llret);
- state = 12;
- return LL_RESULT;
- }
- -(struct stret)stret_noarg
- {
- CHECK_ARGS_NOARG(stret);
- state = 13;
- return STRET_RESULT;
- }
- -(double)fpret_noarg
- {
- CHECK_ARGS_NOARG(fpret);
- state = 14;
- return FP_RESULT;
- }
- -(long double)lfpret_noarg
- {
- CHECK_ARGS_NOARG(lfpret);
- state = 15;
- return LFP_RESULT;
- }
- -(vector_ulong2)vecret_noarg
- {
- CHECK_ARGS_NOARG(vecret);
- state = 16;
- return VEC_RESULT;
- }
- -(struct stret)stret_nop
- {
- return STRET_RESULT;
- }
- #define STRET_IMP(n) \
- +(struct stret_##n)stret_##n##_zero \
- { \
- struct stret_##n ret; \
- bzero(&ret, sizeof(ret)); \
- return ret; \
- } \
- +(struct stret_##n)stret_##n##_nonzero \
- { \
- struct stret_##n ret; \
- memset(&ret, 0xff, sizeof(ret)); \
- return ret; \
- }
- STRET_IMP(i1)
- STRET_IMP(i2)
- STRET_IMP(i3)
- STRET_IMP(i4)
- STRET_IMP(i5)
- STRET_IMP(i6)
- STRET_IMP(i7)
- STRET_IMP(i8)
- STRET_IMP(i9)
- STRET_IMP(d1)
- STRET_IMP(d2)
- STRET_IMP(d3)
- STRET_IMP(d4)
- STRET_IMP(d5)
- STRET_IMP(d6)
- STRET_IMP(d7)
- STRET_IMP(d8)
- STRET_IMP(d9)
- +(id)idret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- fail("+idret called instead of -idret");
- CHECK_ARGS(idret);
- }
- +(long long)llret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- fail("+llret called instead of -llret");
- CHECK_ARGS(llret);
- }
- +(struct stret)stret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- fail("+stret called instead of -stret");
- CHECK_ARGS(stret);
- }
- +(double)fpret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- fail("+fpret called instead of -fpret");
- CHECK_ARGS(fpret);
- }
- +(long double)lfpret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- fail("+lfpret called instead of -lfpret");
- CHECK_ARGS(lfpret);
- }
- +(id)idret_noarg
- {
- fail("+idret_noarg called instead of -idret_noarg");
- CHECK_ARGS_NOARG(idret);
- }
- +(long long)llret_noarg
- {
- fail("+llret_noarg called instead of -llret_noarg");
- CHECK_ARGS_NOARG(llret);
- }
- +(struct stret)stret_noarg
- {
- fail("+stret_noarg called instead of -stret_noarg");
- CHECK_ARGS_NOARG(stret);
- }
- +(double)fpret_noarg
- {
- fail("+fpret_noarg called instead of -fpret_noarg");
- CHECK_ARGS_NOARG(fpret);
- }
- +(long double)lfpret_noarg
- {
- fail("+lfpret_noarg called instead of -lfpret_noarg");
- CHECK_ARGS_NOARG(lfpret);
- }
- +(vector_ulong2)vecret_noarg
- {
- fail("+vecret_noarg called instead of -vecret_noarg");
- CHECK_ARGS_NOARG(vecret);
- }
- @end
- @implementation Sub
- -(id)IMPL_idret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- id result;
- CHECK_ARGS(idret);
- state = 100;
- result = [super idret:v1:v2:v3:v4:v5:v6:v7:v8: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];
- testassert(state == 1);
- testassert(result == ID_RESULT);
- state = 101;
- return result;
- }
- -(long long)IMPL_llret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- long long result;
- CHECK_ARGS(llret);
- state = 100;
- result = [super llret:v1:v2:v3:v4:v5:v6:v7:v8: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];
- testassert(state == 2);
- testassert(result == LL_RESULT);
- state = 102;
- return result;
- }
- -(struct stret)IMPL_stret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- struct stret result;
- CHECK_ARGS(stret);
- state = 100;
- result = [super stret:v1:v2:v3:v4:v5:v6:v7:v8: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];
- testassert(state == 3);
- testassert(stret_equal(result, STRET_RESULT));
- state = 103;
- return result;
- }
- -(double)IMPL_fpret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- double result;
- CHECK_ARGS(fpret);
- state = 100;
- result = [super fpret:v1:v2:v3:v4:v5:v6:v7:v8: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];
- testassert(state == 4);
- testassert(result == FP_RESULT);
- state = 104;
- return result;
- }
- -(long double)IMPL_lfpret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- long double result;
- CHECK_ARGS(lfpret);
- state = 100;
- result = [super lfpret:v1:v2:v3:v4:v5:v6:v7:v8: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];
- testassert(state == 5);
- testassert(result == LFP_RESULT);
- state = 105;
- return result;
- }
- -(vector_ulong2)IMPL_vecret:
- (vector_ulong2)v1 :(vector_ulong2)v2 :(vector_ulong2)v3 :(vector_ulong2)v4 :(vector_ulong2)v5 :(vector_ulong2)v6 :(vector_ulong2)v7 :(vector_ulong2)v8 :(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
- {
- vector_ulong2 result;
- CHECK_ARGS(vecret);
- state = 100;
- result = [super vecret:v1:v2:v3:v4:v5:v6:v7:v8: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];
- testassert(state == 6);
- testassert(vector_equal(result, VEC_RESULT));
- state = 106;
- return result;
- }
- -(id)idret_noarg
- {
- id result;
- CHECK_ARGS_NOARG(idret);
- state = 100;
- result = [super idret_noarg];
- testassert(state == 11);
- testassert(result == ID_RESULT);
- state = 111;
- return result;
- }
- -(long long)llret_noarg
- {
- long long result;
- CHECK_ARGS_NOARG(llret);
- state = 100;
- result = [super llret_noarg];
- testassert(state == 12);
- testassert(result == LL_RESULT);
- state = 112;
- return result;
- }
- -(struct stret)stret_noarg
- {
- struct stret result;
- CHECK_ARGS_NOARG(stret);
- state = 100;
- result = [super stret_noarg];
- testassert(state == 13);
- testassert(stret_equal(result, STRET_RESULT));
- state = 113;
- return result;
- }
- -(double)fpret_noarg
- {
- double result;
- CHECK_ARGS_NOARG(fpret);
- state = 100;
- result = [super fpret_noarg];
- testassert(state == 14);
- testassert(result == FP_RESULT);
- state = 114;
- return result;
- }
- -(long double)lfpret_noarg
- {
- long double result;
- CHECK_ARGS_NOARG(lfpret);
- state = 100;
- result = [super lfpret_noarg];
- testassert(state == 15);
- testassert(result == LFP_RESULT);
- state = 115;
- return result;
- }
- -(vector_ulong2)vecret_noarg
- {
- vector_ulong2 result;
- CHECK_ARGS_NOARG(vecret);
- state = 100;
- result = [super vecret_noarg];
- testassert(state == 16);
- testassert(vector_equal(result, VEC_RESULT));
- state = 116;
- return result;
- }
- @end
- #if OBJC_HAVE_TAGGED_POINTERS
- @interface TaggedSub : Sub @end
- @implementation TaggedSub : Sub
- +(void)initialize
- {
- _objc_registerTaggedPointerClass(OBJC_TAG_1, self);
- }
- @end
- @interface ExtTaggedSub : Sub @end
- @implementation ExtTaggedSub : Sub
- +(void)initialize
- {
- _objc_registerTaggedPointerClass(OBJC_TAG_First52BitPayload, self);
- }
- @end
- #endif
- // DWARF checking machinery
- #if TARGET_OS_WIN32
- // unimplemented on this platform
- #define NO_DWARF_REASON "(windows)"
- #elif TARGET_OS_WATCH
- // fixme unimplemented - ucontext not passed to signal handlers
- #define NO_DWARF_REASON "(watchOS)"
- #elif __has_feature(objc_arc)
- // ARC's extra RR calls hit the traps at the wrong times
- #define NO_DWARF_REASON "(ARC)"
- #else
- #define TEST_DWARF 1
- // Classes with no implementations and no cache contents from elsewhere.
- @interface SuperDW : TestRoot @end
- @implementation SuperDW @end
- @interface Sub0DW : SuperDW @end
- @implementation Sub0DW @end
- @interface SubDW : Sub0DW @end
- @implementation SubDW @end
- #include <dlfcn.h>
- #include <signal.h>
- #include <sys/mman.h>
- #include <libunwind.h>
- bool caught = false;
- uintptr_t clobbered;
- __BEGIN_DECLS
- extern void callit(void *obj, void *sel, void *fn);
- extern struct stret callit_stret(void *obj, void *sel, void *fn);
- __END_DECLS
- #if __x86_64__
- typedef uint8_t insn_t;
- typedef insn_t clobbered_insn_t;
- #define BREAK_INSN ((insn_t)0x06) // undefined
- #define BREAK_SIGNAL SIGILL
- uintptr_t r12 = 0;
- uintptr_t r13 = 0;
- uintptr_t r14 = 0;
- uintptr_t r15 = 0;
- uintptr_t rbx = 0;
- uintptr_t rbp = 0;
- uintptr_t rsp = 0;
- uintptr_t rip = 0;
- void handle_exception(x86_thread_state64_t *state)
- {
- unw_cursor_t curs;
- unw_word_t reg;
- int err;
- int step;
- err = unw_init_local(&curs, (unw_context_t *)state);
- testassert(!err);
- step = unw_step(&curs);
- testassert(step > 0);
- err = unw_get_reg(&curs, UNW_X86_64_R12, ®);
- testassert(!err);
- testassert(reg == r12);
- err = unw_get_reg(&curs, UNW_X86_64_R13, ®);
- testassert(!err);
- testassert(reg == r13);
- err = unw_get_reg(&curs, UNW_X86_64_R14, ®);
- testassert(!err);
- testassert(reg == r14);
- err = unw_get_reg(&curs, UNW_X86_64_R15, ®);
- testassert(!err);
- testassert(reg == r15);
- err = unw_get_reg(&curs, UNW_X86_64_RBX, ®);
- testassert(!err);
- testassert(reg == rbx);
- err = unw_get_reg(&curs, UNW_X86_64_RBP, ®);
- testassert(!err);
- testassert(reg == rbp);
- err = unw_get_reg(&curs, UNW_X86_64_RSP, ®);
- testassert(!err);
- testassert(reg == rsp);
- err = unw_get_reg(&curs, UNW_REG_IP, ®);
- testassert(!err);
- testassert(reg == rip);
- // set thread state to unwound state
- state->__r12 = r12;
- state->__r13 = r13;
- state->__r14 = r14;
- state->__r15 = r15;
- state->__rbx = rbx;
- state->__rbp = rbp;
- state->__rsp = rsp;
- state->__rip = rip;
- caught = true;
- }
- void break_handler(int sig, siginfo_t *info, void *cc)
- {
- ucontext_t *uc = (ucontext_t *)cc;
- mcontext_t mc = (mcontext_t)uc->uc_mcontext;
- testprintf(" handled\n");
- testassert(sig == BREAK_SIGNAL);
- testassert((uintptr_t)info->si_addr == clobbered);
- handle_exception(&mc->__ss);
- // handle_exception changed register state for continuation
- }
- __asm__(
- "\n .text"
- "\n .globl _callit"
- "\n _callit:"
- // save sp and return address to variables
- "\n movq (%rsp), %r10"
- "\n movq %r10, _rip(%rip)"
- "\n movq %rsp, _rsp(%rip)"
- "\n addq $8, _rsp(%rip)" // rewind to pre-call value
- // save other non-volatile registers to variables
- "\n movq %rbx, _rbx(%rip)"
- "\n movq %rbp, _rbp(%rip)"
- "\n movq %r12, _r12(%rip)"
- "\n movq %r13, _r13(%rip)"
- "\n movq %r14, _r14(%rip)"
- "\n movq %r15, _r15(%rip)"
- "\n jmpq *%rdx"
- );
- __asm__(
- "\n .text"
- "\n .globl _callit_stret"
- "\n _callit_stret:"
- // save sp and return address to variables
- "\n movq (%rsp), %r10"
- "\n movq %r10, _rip(%rip)"
- "\n movq %rsp, _rsp(%rip)"
- "\n addq $8, _rsp(%rip)" // rewind to pre-call value
- // save other non-volatile registers to variables
- "\n movq %rbx, _rbx(%rip)"
- "\n movq %rbp, _rbp(%rip)"
- "\n movq %r12, _r12(%rip)"
- "\n movq %r13, _r13(%rip)"
- "\n movq %r14, _r14(%rip)"
- "\n movq %r15, _r15(%rip)"
- "\n jmpq *%rcx"
- );
- // x86_64
- #elif __i386__
- typedef uint8_t insn_t;
- typedef insn_t clobbered_insn_t;
- #define BREAK_INSN ((insn_t)0xcc) // int3
- #define BREAK_SIGNAL SIGTRAP
- uintptr_t eip = 0;
- uintptr_t esp = 0;
- uintptr_t ebx = 0;
- uintptr_t ebp = 0;
- uintptr_t edi = 0;
- uintptr_t esi = 0;
- uintptr_t espfix = 0;
- void handle_exception(i386_thread_state_t *state)
- {
- unw_cursor_t curs;
- unw_word_t reg;
- int err;
- int step;
- err = unw_init_local(&curs, (unw_context_t *)state);
- testassert(!err);
- step = unw_step(&curs);
- testassert(step > 0);
- err = unw_get_reg(&curs, UNW_REG_IP, ®);
- testassert(!err);
- testassert(reg == eip);
- err = unw_get_reg(&curs, UNW_X86_ESP, ®);
- testassert(!err);
- testassert(reg == esp);
- err = unw_get_reg(&curs, UNW_X86_EBX, ®);
- testassert(!err);
- testassert(reg == ebx);
- err = unw_get_reg(&curs, UNW_X86_EBP, ®);
- testassert(!err);
- testassert(reg == ebp);
- err = unw_get_reg(&curs, UNW_X86_EDI, ®);
- testassert(!err);
- testassert(reg == edi);
- err = unw_get_reg(&curs, UNW_X86_ESI, ®);
- testassert(!err);
- testassert(reg == esi);
- // set thread state to unwound state
- state->__eip = eip;
- state->__esp = esp + espfix;
- state->__ebx = ebx;
- state->__ebp = ebp;
- state->__edi = edi;
- state->__esi = esi;
- caught = true;
- }
- void break_handler(int sig, siginfo_t *info, void *cc)
- {
- ucontext_t *uc = (ucontext_t *)cc;
- mcontext_t mc = (mcontext_t)uc->uc_mcontext;
- testprintf(" handled\n");
- testassert(sig == BREAK_SIGNAL);
- testassert((uintptr_t)info->si_addr-1 == clobbered);
- handle_exception(&mc->__ss);
- // handle_exception changed register state for continuation
- }
- __asm__(
- "\n .text"
- "\n .globl _callit"
- "\n _callit:"
- // save sp and return address to variables
- "\n call 1f"
- "\n 1: popl %edx"
- "\n movl (%esp), %eax"
- "\n movl %eax, _eip-1b(%edx)"
- "\n movl %esp, _esp-1b(%edx)"
- "\n addl $4, _esp-1b(%edx)" // rewind to pre-call value
- "\n movl $0, _espfix-1b(%edx)"
- // save other non-volatile registers to variables
- "\n movl %ebx, _ebx-1b(%edx)"
- "\n movl %ebp, _ebp-1b(%edx)"
- "\n movl %edi, _edi-1b(%edx)"
- "\n movl %esi, _esi-1b(%edx)"
- "\n jmpl *12(%esp)"
- );
- __asm__(
- "\n .text"
- "\n .globl _callit_stret"
- "\n _callit_stret:"
- // save sp and return address to variables
- "\n call 1f"
- "\n 1: popl %edx"
- "\n movl (%esp), %eax"
- "\n movl %eax, _eip-1b(%edx)"
- "\n movl %esp, _esp-1b(%edx)"
- "\n addl $4, _esp-1b(%edx)" // rewind to pre-call value
- "\n movl $4, _espfix-1b(%edx)"
- // save other non-volatile registers to variables
- "\n movl %ebx, _ebx-1b(%edx)"
- "\n movl %ebp, _ebp-1b(%edx)"
- "\n movl %edi, _edi-1b(%edx)"
- "\n movl %esi, _esi-1b(%edx)"
- "\n jmpl *16(%esp)"
- );
- // i386
- #elif __arm64__
- #include <sys/ucontext.h>
- typedef uint32_t insn_t;
- typedef insn_t clobbered_insn_t;
- #define BREAK_INSN ((insn_t)0xd4200020) // brk #1
- #define BREAK_SIGNAL SIGTRAP
- uintptr_t x19 = 0;
- uintptr_t x20 = 0;
- uintptr_t x21 = 0;
- uintptr_t x22 = 0;
- uintptr_t x23 = 0;
- uintptr_t x24 = 0;
- uintptr_t x25 = 0;
- uintptr_t x26 = 0;
- uintptr_t x27 = 0;
- uintptr_t x28 = 0;
- uintptr_t fp = 0;
- uintptr_t sp = 0;
- uintptr_t pc = 0;
- void handle_exception(arm_thread_state64_t *state)
- {
- unw_cursor_t curs;
- unw_word_t reg;
- int err;
- int step;
- // libunwind layout differs from mcontext layout
- // GPRs are the same but vector registers are not
- unw_context_t unwstate;
- unw_getcontext(&unwstate);
- memcpy(&unwstate, state, sizeof(*state));
- // libunwind and xnu sign some pointers differently
- // xnu: not signed (fixme this may change?)
- // libunwind: PC and LR both signed with return address key and SP
- void **pcp = &((arm_thread_state64_t *)&unwstate)->__opaque_pc;
- *pcp = ptrauth_sign_unauthenticated((void*)__darwin_arm_thread_state64_get_pc(*state),
- ptrauth_key_return_address,
- (ptrauth_extra_data_t)__darwin_arm_thread_state64_get_sp(*state));
- void **lrp = &((arm_thread_state64_t *)&unwstate)->__opaque_lr;
- *lrp = ptrauth_sign_unauthenticated((void*)__darwin_arm_thread_state64_get_lr(*state),
- ptrauth_key_return_address,
- (ptrauth_extra_data_t)__darwin_arm_thread_state64_get_sp(*state));
- err = unw_init_local(&curs, &unwstate);
- testassert(!err);
- step = unw_step(&curs);
- testassert(step > 0);
- err = unw_get_reg(&curs, UNW_ARM64_X19, ®);
- testassert(!err);
- testassert(reg == x19);
- err = unw_get_reg(&curs, UNW_ARM64_X20, ®);
- testassert(!err);
- testassert(reg == x20);
- err = unw_get_reg(&curs, UNW_ARM64_X21, ®);
- testassert(!err);
- testassert(reg == x21);
- err = unw_get_reg(&curs, UNW_ARM64_X22, ®);
- testassert(!err);
- testassert(reg == x22);
- err = unw_get_reg(&curs, UNW_ARM64_X23, ®);
- testassert(!err);
- testassert(reg == x23);
- err = unw_get_reg(&curs, UNW_ARM64_X24, ®);
- testassert(!err);
- testassert(reg == x24);
- err = unw_get_reg(&curs, UNW_ARM64_X25, ®);
- testassert(!err);
- testassert(reg == x25);
- err = unw_get_reg(&curs, UNW_ARM64_X26, ®);
- testassert(!err);
- testassert(reg == x26);
- err = unw_get_reg(&curs, UNW_ARM64_X27, ®);
- testassert(!err);
- testassert(reg == x27);
- err = unw_get_reg(&curs, UNW_ARM64_X28, ®);
- testassert(!err);
- testassert(reg == x28);
- err = unw_get_reg(&curs, UNW_ARM64_FP, ®);
- testassert(!err);
- testassert(reg == fp);
- err = unw_get_reg(&curs, UNW_ARM64_SP, ®);
- testassert(!err);
- testassert(reg == sp);
- err = unw_get_reg(&curs, UNW_REG_IP, ®);
- testassert(!err);
- // libunwind's return is signed but our value is not
- reg = (uintptr_t)ptrauth_strip((void *)reg, ptrauth_key_return_address);
- testassert(reg == pc);
- // libunwind restores PC into LR and doesn't track LR
- // err = unw_get_reg(&curs, UNW_ARM64_LR, ®);
- // testassert(!err);
- // testassert(reg == lr);
- // set signal handler's thread state to unwound state
- state->__x[19] = x19;
- state->__x[20] = x20;
- state->__x[21] = x21;
- state->__x[22] = x22;
- state->__x[23] = x23;
- state->__x[24] = x24;
- state->__x[25] = x25;
- state->__x[26] = x26;
- state->__x[27] = x27;
- state->__x[28] = x28;
- state->__opaque_fp = (void *)fp;
- state->__opaque_lr = (void *)pc; // libunwind restores PC into LR
- state->__opaque_sp = (void *)sp;
- state->__opaque_pc = (void *)pc;
- caught = true;
- }
- void break_handler(int sig, siginfo_t *info, void *cc)
- {
- ucontext_t *uc = (ucontext_t *)cc;
- struct __darwin_mcontext64 *mc = (struct __darwin_mcontext64 *)uc->uc_mcontext;
- testprintf(" handled\n");
- testassert(sig == BREAK_SIGNAL);
- testassert((uintptr_t)info->si_addr == clobbered);
- handle_exception(&mc->__ss);
- // handle_exception changed register state for continuation
- }
- __asm__(
- "\n .text"
- "\n .globl _callit"
- "\n _callit:"
- // save sp and return address to variables
- "\n mov x16, sp"
- "\n adrp x17, _sp@PAGE"
- "\n str x16, [x17, _sp@PAGEOFF]"
- "\n adrp x17, _pc@PAGE"
- "\n str lr, [x17, _pc@PAGEOFF]"
- // save other non-volatile registers to variables
- "\n adrp x17, _x19@PAGE"
- "\n str x19, [x17, _x19@PAGEOFF]"
- "\n adrp x17, _x19@PAGE"
- "\n str x20, [x17, _x20@PAGEOFF]"
- "\n adrp x17, _x19@PAGE"
- "\n str x21, [x17, _x21@PAGEOFF]"
- "\n adrp x17, _x19@PAGE"
- "\n str x22, [x17, _x22@PAGEOFF]"
- "\n adrp x17, _x19@PAGE"
- "\n str x23, [x17, _x23@PAGEOFF]"
- "\n adrp x17, _x19@PAGE"
- "\n str x24, [x17, _x24@PAGEOFF]"
- "\n adrp x17, _x19@PAGE"
- "\n str x25, [x17, _x25@PAGEOFF]"
- "\n adrp x17, _x19@PAGE"
- "\n str x26, [x17, _x26@PAGEOFF]"
- "\n adrp x17, _x19@PAGE"
- "\n str x27, [x17, _x27@PAGEOFF]"
- "\n adrp x17, _x19@PAGE"
- "\n str x28, [x17, _x28@PAGEOFF]"
- "\n adrp x17, _x19@PAGE"
- "\n str fp, [x17, _fp@PAGEOFF]"
- "\n br x2"
- );
- // arm64
- #elif __arm__
- #include <sys/ucontext.h>
- typedef uint16_t insn_t;
- typedef struct {
- insn_t first;
- insn_t second;
- bool thirty_two;
- } clobbered_insn_t;
- #define BREAK_INSN ((insn_t)0xdefe) // trap
- #define BREAK_SIGNAL SIGILL
- #define BREAK_SIGNAL2 SIGTRAP
- uintptr_t r4 = 0;
- uintptr_t r5 = 0;
- uintptr_t r6 = 0;
- uintptr_t r7 = 0;
- uintptr_t r8 = 0;
- uintptr_t r10 = 0;
- uintptr_t r11 = 0;
- uintptr_t sp = 0;
- uintptr_t pc = 0;
- void handle_exception(arm_thread_state_t *state)
- {
- // No unwind tables on this architecture so no libunwind checks.
- // We run the test anyway to verify instruction-level coverage.
- // set thread state to unwound state
- state->__r[4] = r4;
- state->__r[5] = r5;
- state->__r[6] = r6;
- state->__r[7] = r7;
- state->__r[8] = r8;
- state->__r[10] = r10;
- state->__r[11] = r11;
- state->__sp = sp;
- state->__pc = pc;
- // clear IT... bits so caller doesn't act on them
- state->__cpsr &= ~0x0600fc00;
- caught = true;
- }
- void break_handler(int sig, siginfo_t *info, void *cc)
- {
- ucontext_t *uc = (ucontext_t *)cc;
- struct __darwin_mcontext32 *mc = (struct __darwin_mcontext32 *)uc->uc_mcontext;
- testprintf(" handled\n");
- testassert(sig == BREAK_SIGNAL || sig == BREAK_SIGNAL2);
- testassert((uintptr_t)info->si_addr == clobbered);
- handle_exception(&mc->__ss);
- // handle_exception changed register state for continuation
- }
- __asm__(
- "\n .text"
- "\n .syntax unified"
- "\n .code 16"
- "\n .align 5"
- "\n .globl _callit"
- "\n .thumb_func"
- "\n _callit:"
- // save sp and return address to variables
- "\n movw r12, :lower16:(_sp-1f-4)"
- "\n movt r12, :upper16:(_sp-1f-4)"
- "\n 1: add r12, pc"
- "\n str sp, [r12]"
- "\n movw r12, :lower16:(_pc-1f-4)"
- "\n movt r12, :upper16:(_pc-1f-4)"
- "\n 1: add r12, pc"
- "\n str lr, [r12]"
- // save other non-volatile registers to variables
- "\n movw r12, :lower16:(_r4-1f-4)"
- "\n movt r12, :upper16:(_r4-1f-4)"
- "\n 1: add r12, pc"
- "\n str r4, [r12]"
- "\n movw r12, :lower16:(_r5-1f-4)"
- "\n movt r12, :upper16:(_r5-1f-4)"
- "\n 1: add r12, pc"
- "\n str r5, [r12]"
- "\n movw r12, :lower16:(_r6-1f-4)"
- "\n movt r12, :upper16:(_r6-1f-4)"
- "\n 1: add r12, pc"
- "\n str r6, [r12]"
- "\n movw r12, :lower16:(_r7-1f-4)"
- "\n movt r12, :upper16:(_r7-1f-4)"
- "\n 1: add r12, pc"
- "\n str r7, [r12]"
- "\n movw r12, :lower16:(_r8-1f-4)"
- "\n movt r12, :upper16:(_r8-1f-4)"
- "\n 1: add r12, pc"
- "\n str r8, [r12]"
- "\n movw r12, :lower16:(_r10-1f-4)"
- "\n movt r12, :upper16:(_r10-1f-4)"
- "\n 1: add r12, pc"
- "\n str r10, [r12]"
- "\n movw r12, :lower16:(_r11-1f-4)"
- "\n movt r12, :upper16:(_r11-1f-4)"
- "\n 1: add r12, pc"
- "\n str r11, [r12]"
- "\n bx r2"
- );
- __asm__(
- "\n .text"
- "\n .syntax unified"
- "\n .code 16"
- "\n .align 5"
- "\n .globl _callit_stret"
- "\n .thumb_func"
- "\n _callit_stret:"
- // save sp and return address to variables
- "\n movw r12, :lower16:(_sp-1f-4)"
- "\n movt r12, :upper16:(_sp-1f-4)"
- "\n 1: add r12, pc"
- "\n str sp, [r12]"
- "\n movw r12, :lower16:(_pc-1f-4)"
- "\n movt r12, :upper16:(_pc-1f-4)"
- "\n 1: add r12, pc"
- "\n str lr, [r12]"
- // save other non-volatile registers to variables
- "\n movw r12, :lower16:(_r4-1f-4)"
- "\n movt r12, :upper16:(_r4-1f-4)"
- "\n 1: add r12, pc"
- "\n str r4, [r12]"
- "\n movw r12, :lower16:(_r5-1f-4)"
- "\n movt r12, :upper16:(_r5-1f-4)"
- "\n 1: add r12, pc"
- "\n str r5, [r12]"
- "\n movw r12, :lower16:(_r6-1f-4)"
- "\n movt r12, :upper16:(_r6-1f-4)"
- "\n 1: add r12, pc"
- "\n str r6, [r12]"
- "\n movw r12, :lower16:(_r7-1f-4)"
- "\n movt r12, :upper16:(_r7-1f-4)"
- "\n 1: add r12, pc"
- "\n str r7, [r12]"
- "\n movw r12, :lower16:(_r8-1f-4)"
- "\n movt r12, :upper16:(_r8-1f-4)"
- "\n 1: add r12, pc"
- "\n str r8, [r12]"
- "\n movw r12, :lower16:(_r10-1f-4)"
- "\n movt r12, :upper16:(_r10-1f-4)"
- "\n 1: add r12, pc"
- "\n str r10, [r12]"
- "\n movw r12, :lower16:(_r11-1f-4)"
- "\n movt r12, :upper16:(_r11-1f-4)"
- "\n 1: add r12, pc"
- "\n str r11, [r12]"
- "\n bx r3"
- );
- // arm
- #else
- #error unknown architecture
- #endif
- #if __arm__
- uintptr_t fnaddr(void *fn) { return (uintptr_t)fn & ~(uintptr_t)1; }
- #else
- uintptr_t fnaddr(void *fn) { return (uintptr_t)fn; }
- #endif
- void flushICache(uintptr_t addr) {
- sys_icache_invalidate((void *)addr, sizeof(insn_t));
- }
- insn_t set(uintptr_t dst, insn_t newvalue)
- {
- uintptr_t start = dst & ~(PAGE_MAX_SIZE-1);
- int err = mprotect((void*)start, PAGE_MAX_SIZE, PROT_READ|PROT_WRITE);
- if (err) fail("mprotect(%p, RW-) failed (%d)", start, errno);
- insn_t oldvalue = *(insn_t *)dst;
- *(insn_t *)dst = newvalue;
- err = mprotect((void*)start, PAGE_MAX_SIZE, PROT_READ|PROT_EXEC);
- if (err) fail("mprotect(%p, R-X) failed (%d)", start, errno);
- flushICache(dst);
- return oldvalue;
- }
- clobbered_insn_t clobber(void *fn, uintptr_t offset)
- {
- clobbered = fnaddr(fn) + offset;
- insn_t oldInsn = set(fnaddr(fn) + offset, BREAK_INSN);
- #if __arm__
- // Need to clobber 32-bit Thumb instructions with another 32-bit instruction
- // to preserve the behavior of IT... blocks.
- clobbered_insn_t result = {oldInsn, 0, false};
- if (((oldInsn & 0xf000) == 0xf000) ||
- ((oldInsn & 0xf800) == 0xe800))
- {
- testprintf("clobbering thumb-32 at offset %zu\n", offset);
- // Old insn was 32-bit. Clobber all of it.
- // First unclobber.
- set(fnaddr(fn) + offset, oldInsn);
- // f7f0 a0f0 is a "permanently undefined" Thumb-2 instruction.
- // Clobber the first half last so `clobbered` gets the right value.
- result.second = set(fnaddr(fn) + offset + 2, 0xa0f0);
- result.first = set(fnaddr(fn) + offset, 0xf7f0);
- result.thirty_two = true;
- }
- return result;
- #else
- return oldInsn;
- #endif
- }
- void unclobber(void *fn, uintptr_t offset, clobbered_insn_t oldvalue)
- {
- #if __arm__
- if (oldvalue.thirty_two) {
- set(fnaddr(fn) + offset + 2, oldvalue.second);
- }
- set(fnaddr(fn) + offset, oldvalue.first);
- #else
- set(fnaddr(fn) + offset, oldvalue);
- #endif
- }
- // terminator for the list of instruction offsets
- #define END_OFFSETS ~0UL
- // Disassemble instructions symbol..<symbolEnd.
- // Write the offset of each non-NOP instruction start to *offsets..<end.
- // Return the incremented offsets pointer.
- uintptr_t *disassemble(uintptr_t symbol, uintptr_t symbolEnd,
- uintptr_t *offsets, uintptr_t *end)
- {
- // To disassemble:
- // 1. Copy asm-placeholder.exe into a temporary file.
- // 2. Write the instructions into the temp file.
- // 3. Run llvm-objdump on the temp file.
- // 4. Parse the llvm-objdump output.
- // copy asm-placeholder.exe into a new temporary file and open it.
- int placeholder = open("asm-placeholder.exe", O_RDONLY);
- if (placeholder < 0) {
- fail("couldn't open asm-placeholder.exe (%d)", errno);
- }
- size_t tempdirlen = confstr(_CS_DARWIN_USER_TEMP_DIR, nil, 0);
- char tempsuffix[] = "objc-test-msgSend-asm-XXXXXX";
- char *tempname = (char *)malloc(tempdirlen + strlen(tempsuffix));
- confstr(_CS_DARWIN_USER_TEMP_DIR, tempname, tempdirlen);
- strcat(tempname, tempsuffix);
- int fd = mkstemp(tempname);
- if (fd < 0) {
- fail("couldn't create asm temp file %s (%d)", tempname, errno);
- }
- struct stat st;
- if (fstat(placeholder, &st) < 0) {
- fail("couldn't stat asm-placeholder.exe (%d)", errno);
- }
- ssize_t sz = (ssize_t)st.st_size;
- char *buf = (char *)malloc(sz);
- if (pread(placeholder, buf, sz, 0) != sz) {
- fail("couldn't read asm-placeholder.exe (%d)", errno);
- }
- if (pwrite(fd, buf, sz, 0) != sz) {
- fail("couldn't write asm temp file %s (%d)", tempname, errno);
- }
- free(buf);
- close(placeholder);
- // write code into asm-placeholder.exe
- // asm-placeholder.exe may have as little as 1024 bytes of space reserved
- testassert(symbolEnd - symbol < 1024);
- // text section should be 16KB into asm-placeholder.exe
- if (pwrite(fd, (void*)symbol, symbolEnd - symbol, 16384) < 0) {
- fail("couldn't write code into asm temp file %s (%d)", tempname, errno);
- }
- close(fd);
- // run `llvm-objdump -disassemble`
- const char *objdump;
- if (0 == access("/usr/local/bin/llvm-objdump", F_OK)) {
- objdump = "/usr/local/bin/llvm-objdump";
- } else if (0 == access("/usr/bin/llvm-objdump", F_OK)) {
- objdump = "/usr/bin/llvm-objdump";
- } else {
- fail("couldn't find llvm-objdump");
- }
- char *cmd;
- asprintf(&cmd, "%s -disassemble %s", objdump, tempname);
- FILE *disa = popen(cmd, "r");
- if (!disa) {
- fail("couldn't popen %s", cmd);
- }
- free(cmd);
- free(tempname);
- // read past "_main:" line
- char *line;
- size_t len;
- while ((line = fgetln(disa, &len))) {
- testprintf("ASM: %.*s", (int)len, line);
- if (0 == strncmp(line, "_main:", strlen("_main:"))) break;
- }
- // read instructions and save offsets
- char op[128];
- long base = 0;
- long addr;
- uintptr_t *p = offsets;
- // disassembly format:
- // ADDR:\t ...instruction bytes... \tOPCODE ...etc...\n
- while (2 == fscanf(disa, "%lx:\t%*[a-fA-F0-9 ]\t%s%*[^\n]\n", &addr, op)) {
- if (base == 0) base = addr;
- testprintf("ASM: %lx (+%d) ... %s ...\n", addr, addr - base, op);
- // allow longer nops like Intel nopw and nopl
- if (0 != strncmp(op, "nop", 3)) {
- testassert(offsets < end);
- *p++ = addr - base;
- } else {
- // assume nops are unreached (e.g. alignment padding)
- }
- }
- pclose(disa);
- #if __x86_64__
- // hack: skip last instruction because libunwind blows up if it's
- // one byte long and followed by the next function with no NOPs first
- if (p > offsets) *p-- = END_OFFSETS;
- #endif
- return p;
- }
- uintptr_t *getOffsets(const char *symname, uintptr_t *outBase)
- {
- // Find the start of our function.
- uintptr_t symbol = (uintptr_t)dlsym(RTLD_NEXT, symname);
- if (!symbol) return nil;
- #if __has_feature(ptrauth_calls)
- symbol = (uintptr_t)
- ptrauth_strip((void*)symbol, ptrauth_key_function_pointer);
- #endif
- if (outBase) *outBase = symbol;
- // Find the end of our function by finding the start
- // of the next symbol after our target symbol.
- const int insnIncrement =
- #if __arm64__
- 4;
- #elif __arm__
- 2; // in case of thumb or thumb-2
- #elif __i386__ || __x86_64__
- 1;
- #else
- #error unknown architecture
- #endif
- uintptr_t symbolEnd;
- Dl_info dli;
- int ok;
- for (symbolEnd = symbol + insnIncrement;
- ((ok = dladdr((void*)symbolEnd, &dli))) && dli.dli_saddr == (void*)symbol;
- symbolEnd += insnIncrement)
- ;
- testprintf("found %s at %p..<%p %d %p %s\n",
- symname, (void*)symbol, (void*)symbolEnd, ok, dli.dli_saddr, dli.dli_sname);
- // Record the offset to each non-NOP instruction.
- uintptr_t *result = (uintptr_t *)malloc(1000 * sizeof(uintptr_t));
- uintptr_t *end = result + 1000;
- uintptr_t *p = result;
- p = disassemble(symbol, symbolEnd, p, end);
- // Also record the offsets in _objc_msgSend_uncached when present
- // (which is the slow path and has a frame to unwind)
- if (!strstr(symname, "_uncached")) {
- const char *uncached_symname = strstr(symname, "stret")
- ? "_objc_msgSend_stret_uncached" : "_objc_msgSend_uncached";
- uintptr_t uncached_symbol;
- uintptr_t *uncached_offsets =
- getOffsets(uncached_symname, &uncached_symbol);
- if (uncached_offsets) {
- uintptr_t *q = uncached_offsets;
- // Skip prologue and epilogue of objc_msgSend_uncached
- // because it's imprecisely modeled in compact unwind
- int prologueInstructions, epilogueInstructions;
- #if __arm64e__
- prologueInstructions = 3;
- epilogueInstructions = 2;
- #elif __arm64__ || __x86_64__ || __i386__ || __arm__
- prologueInstructions = 2;
- epilogueInstructions = 1;
- #else
- #error unknown architecture
- #endif
- // skip past prologue
- for (int i = 0; i < prologueInstructions; i++) {
- testassert(*q != END_OFFSETS);
- q++;
- }
- // copy instructions
- while (*q != END_OFFSETS) *p++ = *q++ + uncached_symbol - symbol;
- // rewind past epilogue
- for (int i = 0; i < epilogueInstructions; i++) {
- testassert(p > result);
- p--;
- }
- free(uncached_offsets);
- }
- }
- // Terminate the list of offsets and return.
- testassert(p > result);
- testassert(p < end);
- *p = END_OFFSETS;
- return result;
- }
- void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret) __attribute__((noinline));
- void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret)
- {
- uintptr_t message_ref[2];
- if (sel_arg != s) {
- // fixup dispatch
- // copy to a local buffer to keep sel_arg un-fixed-up
- memcpy(message_ref, sel_arg, sizeof(message_ref));
- sel_arg = message_ref;
- }
- if (!stret) callit(o, sel_arg, f);
- #if SUPPORT_STRET
- else callit_stret(o, sel_arg, f);
- #else
- else fail("stret?");
- #endif
- }
- void test_dw_forward(void)
- {
- return;
- }
- struct stret test_dw_forward_stret(void)
- {
- return zero;
- }
- // sub = ordinary receiver object
- // tagged = tagged receiver object
- // SEL = selector to send
- // sub_arg = arg to pass in receiver register (may be objc_super struct)
- // tagged_arg = arg to pass in receiver register (may be objc_super struct)
- // sel_arg = arg to pass in sel register (may be message_ref)
- // uncaughtAllowed is the number of acceptable unreachable instructions
- // (for example, the ones that handle the corrupt-cache-error case)
- void test_dw(const char *name, id sub, id tagged, id exttagged, bool stret,
- int uncaughtAllowed)
- {
- testprintf("DWARF FOR %s%s\n", name, stret ? " (stret)" : "");
- // We need 2 SELs of each alignment so we can generate hash collisions.
- // sel_registerName() never returns those alignments because they
- // differ from malloc's alignment. So we create lots of compiled-in
- // SELs here and hope something fits.
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wundeclared-selector"
- SEL sel = @selector(a);
- SEL lotsOfSels[] = {
- @selector(a1), @selector(a2), @selector(a3), @selector(a4),
- @selector(a5), @selector(a6), @selector(a7), @selector(a8),
- @selector(aa), @selector(ab), @selector(ac), @selector(ad),
- @selector(ae), @selector(af), @selector(ag), @selector(ah),
- @selector(A1), @selector(A2), @selector(A3), @selector(A4),
- @selector(A5), @selector(A6), @selector(A7), @selector(A8),
- @selector(AA), @selector(Ab), @selector(Ac), @selector(Ad),
- @selector(Ae), @selector(Af), @selector(Ag), @selector(Ah),
- @selector(bb1), @selector(bb2), @selector(bb3), @selector(bb4),
- @selector(bb5), @selector(bb6), @selector(bb7), @selector(bb8),
- @selector(bba), @selector(bbb), @selector(bbc), @selector(bbd),
- @selector(bbe), @selector(bbf), @selector(bbg), @selector(bbh),
- @selector(BB1), @selector(BB2), @selector(BB3), @selector(BB4),
- @selector(BB5), @selector(BB6), @selector(BB7), @selector(BB8),
- @selector(BBa), @selector(BBb), @selector(BBc), @selector(BBd),
- @selector(BBe), @selector(BBf), @selector(BBg), @selector(BBh),
- @selector(ccc1), @selector(ccc2), @selector(ccc3), @selector(ccc4),
- @selector(ccc5), @selector(ccc6), @selector(ccc7), @selector(ccc8),
- @selector(ccca), @selector(cccb), @selector(cccc), @selector(cccd),
- @selector(ccce), @selector(cccf), @selector(cccg), @selector(ccch),
- @selector(CCC1), @selector(CCC2), @selector(CCC3), @selector(CCC4),
- @selector(CCC5), @selector(CCC6), @selector(CCC7), @selector(CCC8),
- @selector(CCCa), @selector(CCCb), @selector(CCCc), @selector(CCCd),
- @selector(CCCe), @selector(CCCf), @selector(CCCg), @selector(CCCh),
- };
- #pragma clang diagnostic pop
-
- {
- IMP imp = stret ? (IMP)test_dw_forward_stret : (IMP)test_dw_forward;
- Class cls = object_getClass(sub);
- Class tagcls = object_getClass(tagged);
- Class exttagcls = object_getClass(exttagged);
- class_replaceMethod(cls, sel, imp, "");
- class_replaceMethod(tagcls, sel, imp, "");
- class_replaceMethod(exttagcls, sel, imp, "");
- for (size_t i = 0; i < sizeof(lotsOfSels)/sizeof(lotsOfSels[0]); i++) {
- class_replaceMethod(cls, lotsOfSels[i], imp, "");
- class_replaceMethod(tagcls, lotsOfSels[i], imp, "");
- class_replaceMethod(exttagcls, lotsOfSels[i], imp, "");
- }
- }
-
- #define ALIGNCOUNT 16
- SEL sels[ALIGNCOUNT][2] = {{0}};
- for (int align = 0; align < ALIGNCOUNT; align++) {
- for (size_t i = 0; i < sizeof(lotsOfSels)/sizeof(lotsOfSels[0]); i++) {
- if ((uintptr_t)(void*)lotsOfSels[i] % ALIGNCOUNT == align) {
- if (sels[align][0]) {
- sels[align][1] = lotsOfSels[i];
- } else {
- sels[align][0] = lotsOfSels[i];
- }
- }
- }
- if (!sels[align][0]) fail("no SEL with alignment %d", align);
- if (!sels[align][1]) fail("only one SEL with alignment %d", align);
- }
- void *fn = dlsym(RTLD_DEFAULT, name);
- #if __has_feature(ptrauth_calls)
- fn = ptrauth_strip(fn, ptrauth_key_function_pointer);
- #endif
- testassert(fn);
- // argument substitutions
- void *sub_arg = (__bridge void*)sub;
- void *tagged_arg = (__bridge void*)tagged;
- void *exttagged_arg = (__bridge void*)exttagged;
- void *sel_arg = (void*)sel;
- struct objc_super sup_st = { sub, object_getClass(sub) };
- struct objc_super tagged_sup_st = { tagged, object_getClass(tagged) };
- struct objc_super exttagged_sup_st = { exttagged, object_getClass(exttagged) };
- struct { void *imp; SEL sel; } message_ref = { fn, sel };
- Class cache_cls = object_getClass(sub);
- Class tagged_cache_cls = object_getClass(tagged);
- Class exttagged_cache_cls = object_getClass(exttagged);
- if (strstr(name, "Super")) {
- // super version - replace receiver with objc_super
- // clear caches of superclass
- cache_cls = class_getSuperclass(cache_cls);
- tagged_cache_cls = class_getSuperclass(tagged_cache_cls);
- exttagged_cache_cls = class_getSuperclass(exttagged_cache_cls);
- sub_arg = &sup_st;
- tagged_arg = &tagged_sup_st;
- exttagged_arg = &exttagged_sup_st;
- }
- if (strstr(name, "_fixup")) {
- // fixup version - replace sel with message_ref
- sel_arg = &message_ref;
- }
- uintptr_t *insnOffsets = getOffsets(name, nil);
- testassert(insnOffsets);
- uintptr_t offset;
- int uncaughtCount = 0;
- for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
- offset = insnOffsets[oo];
- testprintf("OFFSET %lu\n", offset);
- clobbered_insn_t saved_insn = clobber(fn, offset);
- caught = false;
- // nil
- if ((__bridge void*)sub == sub_arg) {
- SELF = nil;
- testprintf(" nil\n");
- CALLIT(nil, sel_arg, sel, fn, stret);
- CALLIT(nil, sel_arg, sel, fn, stret);
- }
- // uncached
- SELF = sub;
- testprintf(" uncached\n");
- _objc_flush_caches(cache_cls);
- CALLIT(sub_arg, sel_arg, sel, fn, stret);
- _objc_flush_caches(cache_cls);
- CALLIT(sub_arg, sel_arg, sel, fn, stret);
- // cached
- SELF = sub;
- testprintf(" cached\n");
- CALLIT(sub_arg, sel_arg, sel, fn, stret);
- CALLIT(sub_arg, sel_arg, sel, fn, stret);
-
- // uncached,tagged
- SELF = tagged;
- testprintf(" uncached,tagged\n");
- _objc_flush_caches(tagged_cache_cls);
- CALLIT(tagged_arg, sel_arg, sel, fn, stret);
- _objc_flush_caches(tagged_cache_cls);
- CALLIT(tagged_arg, sel_arg, sel, fn, stret);
- _objc_flush_caches(exttagged_cache_cls);
- CALLIT(exttagged_arg, sel_arg, sel, fn, stret);
- _objc_flush_caches(exttagged_cache_cls);
- CALLIT(exttagged_arg, sel_arg, sel, fn, stret);
- // cached,tagged
- SELF = tagged;
- testprintf(" cached,tagged\n");
- CALLIT(tagged_arg, sel_arg, sel, fn, stret);
- CALLIT(tagged_arg, sel_arg, sel, fn, stret);
- CALLIT(exttagged_arg, sel_arg, sel, fn, stret);
- CALLIT(exttagged_arg, sel_arg, sel, fn, stret);
- // multiple SEL alignments, collisions, wraps
- SELF = sub;
- for (int a = 0; a < ALIGNCOUNT; a++) {
- testprintf(" cached and uncached, SEL alignment %d\n", a);
- // Count both up and down to be independent of
- // implementation's cache scan direction
- _objc_flush_caches(cache_cls);
- for (int x2 = 0; x2 < 8; x2++) {
- for (int s = 0; s < 4; s++) {
- int align = (a+s) % ALIGNCOUNT;
- CALLIT(sub_arg, sels[align][0], sels[align][0], fn, stret);
- CALLIT(sub_arg, sels[align][1], sels[align][1], fn, stret);
- }
- }
- _objc_flush_caches(cache_cls);
- for (int x2 = 0; x2 < 8; x2++) {
- for (int s = 0; s < 4; s++) {
- int align = abs(a-s) % ALIGNCOUNT;
- CALLIT(sub_arg, sels[align][0], sels[align][0], fn, stret);
- CALLIT(sub_arg, sels[align][1], sels[align][1], fn, stret);
- }
- }
- }
-
- unclobber(fn, offset, saved_insn);
- // remember offsets that were caught by none of the above
- if (caught) {
- insnOffsets[oo] = 0;
- } else {
- uncaughtCount++;
- testprintf("offset %s+%lu not caught (%d/%d)\n",
- name, offset, uncaughtCount, uncaughtAllowed);
- }
- }
- // Complain if too many offsets went uncaught.
- // Acceptably-uncaught offsets include the corrupt-cache-error handler.
- if (uncaughtCount != uncaughtAllowed) {
- for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
- if (insnOffsets[oo]) {
- fprintf(stderr, "BAD: offset %s+%lu not caught\n",
- name, insnOffsets[oo]);
- }
- }
- fail("wrong instructions not reached for %s (missed %d, expected %d)",
- name, uncaughtCount, uncaughtAllowed);
- }
- free(insnOffsets);
- }
- // TEST_DWARF
- #endif
- void test_basic(id receiver)
- {
- id idval;
- long long llval;
- struct stret stretval;
- double fpval;
- long double lfpval;
- vector_ulong2 vecval;
- // message uncached
- // message uncached long long
- // message uncached stret
- // message uncached fpret
- // message uncached fpret long double
- // message uncached noarg (as above)
- // message cached
- // message cached long long
- // message cached stret
- // message cached fpret
- // message cached fpret long double
- // message cached noarg (as above)
- // fixme verify that uncached lookup didn't happen the 2nd time?
- SELF = receiver;
- _objc_flush_caches(object_getClass(receiver));
- for (int i = 0; i < 5; i++) {
- testprintf("idret\n");
- state = 0;
- idval = nil;
- idval = [receiver idret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 101);
- testassert(idval == ID_RESULT);
-
- testprintf("llret\n");
- llval = 0;
- llval = [receiver llret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 102);
- testassert(llval == LL_RESULT);
-
- testprintf("stret\n");
- stretval = zero;
- stretval = [receiver stret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 103);
- testassert(stret_equal(stretval, STRET_RESULT));
-
- testprintf("fpret\n");
- fpval = 0;
- fpval = [receiver fpret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 104);
- testassert(fpval == FP_RESULT);
-
- testprintf("lfpret\n");
- lfpval = 0;
- lfpval = [receiver lfpret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 105);
- testassert(lfpval == LFP_RESULT);
-
- testprintf("vecret\n");
- vecval = 0;
- vecval = [receiver vecret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 106);
- testassert(vector_equal(vecval, VEC_RESULT));
- // explicitly call noarg messenger, even if compiler doesn't emit it
- state = 0;
- testprintf("idret noarg\n");
- idval = nil;
- idval = ((typeof(idmsg0))objc_msgSend_noarg)(receiver, @selector(idret_noarg));
- testassert(state == 111);
- testassert(idval == ID_RESULT);
-
- testprintf("llret noarg\n");
- llval = 0;
- llval = ((typeof(llmsg0))objc_msgSend_noarg)(receiver, @selector(llret_noarg));
- testassert(state == 112);
- testassert(llval == LL_RESULT);
- /*
- no objc_msgSend_stret_noarg
- stretval = zero;
- stretval = ((typeof(stretmsg0))objc_msgSend_stret_noarg)(receiver, @selector(stret_noarg));
- stretval = [receiver stret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 113);
- testassert(stret_equal(stretval, STRET_RESULT));
- */
- #if !__i386__
- testprintf("fpret noarg\n");
- fpval = 0;
- fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(receiver, @selector(fpret_noarg));
- testassert(state == 114);
- testassert(fpval == FP_RESULT);
- testprintf("vecret noarg\n");
- vecval = 0;
- vecval = ((typeof(vecmsg0))objc_msgSend_noarg)(receiver, @selector(vecret_noarg));
- testassert(state == 116);
- testassert(vector_equal(vecval, VEC_RESULT));
- #endif
- #if !__i386__ && !__x86_64__
- testprintf("lfpret noarg\n");
- lfpval = 0;
- lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(receiver, @selector(lfpret_noarg));
- testassert(state == 115);
- testassert(lfpval == LFP_RESULT);
- #endif
- }
- testprintf("basic done\n");
- }
- int main()
- {
- PUSH_POOL {
- id idval;
- long long llval;
- struct stret stretval;
- double fpval;
- long double lfpval;
- vector_ulong2 vecval;
- #if __x86_64__
- struct stret *stretptr;
- #endif
- Method idmethod;
- Method llmethod;
- Method stretmethod;
- Method fpmethod;
- Method lfpmethod;
- Method vecmethod;
- id (*idfn)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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);
- long long (*llfn)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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);
- struct stret (*stretfn)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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);
- double (*fpfn)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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);
- long double (*lfpfn)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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);
- vector_ulong2 (*vecfn)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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);
- id (*idmsg)(id, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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));
- id (*idmsgsuper)(struct objc_super *, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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));
- long long (*llmsg)(id, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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));
- struct stret (*stretmsg)(id, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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));
- struct stret (*stretmsgsuper)(struct objc_super *, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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));
- double (*fpmsg)(id, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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));
- long double (*lfpmsg)(id, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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));
- vector_ulong2 (*vecmsg)(id, SEL, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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));
- // get +initialize out of the way
- [Sub class];
- #if OBJC_HAVE_TAGGED_POINTERS
- [TaggedSub class];
- [ExtTaggedSub class];
- #endif
- ID_RESULT = [Super new];
- Sub *sub = [Sub new];
- Super *sup = [Super new];
- #if OBJC_HAVE_TAGGED_POINTERS
- TaggedSub *tagged = (__bridge id)_objc_makeTaggedPointer(OBJC_TAG_1, 999);
- ExtTaggedSub *exttagged = (__bridge id)_objc_makeTaggedPointer(OBJC_TAG_First52BitPayload, 999);
- #endif
- // Basic cached and uncached dispatch.
- // Do this first before anything below caches stuff.
- testprintf("basic\n");
- test_basic(sub);
- #if OBJC_HAVE_TAGGED_POINTERS
- testprintf("basic tagged\n");
- test_basic(tagged);
- testprintf("basic ext tagged\n");
- test_basic(exttagged);
- #endif
- idmethod = class_getInstanceMethod([Super class], @selector(idret::::::::::::::::::::::::::::::::::::));
- testassert(idmethod);
- llmethod = class_getInstanceMethod([Super class], @selector(llret::::::::::::::::::::::::::::::::::::));
- testassert(llmethod);
- stretmethod = class_getInstanceMethod([Super class], @selector(stret::::::::::::::::::::::::::::::::::::));
- testassert(stretmethod);
- fpmethod = class_getInstanceMethod([Super class], @selector(fpret::::::::::::::::::::::::::::::::::::));
- testassert(fpmethod);
- lfpmethod = class_getInstanceMethod([Super class], @selector(lfpret::::::::::::::::::::::::::::::::::::));
- testassert(lfpmethod);
- vecmethod = class_getInstanceMethod([Super class], @selector(vecret::::::::::::::::::::::::::::::::::::));
- testassert(vecmethod);
- idfn = (id (*)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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;
- llfn = (long long (*)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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;
- stretfn = (struct stret (*)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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;
- fpfn = (double (*)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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;
- lfpfn = (long double (*)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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;
- vecfn = (vector_ulong2 (*)(id, Method, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, vector_ulong2, 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;
- // method_invoke
- // method_invoke long long
- // method_invoke_stret stret
- // method_invoke_stret fpret
- // method_invoke fpret long double
- testprintf("method_invoke\n");
- SELF = sup;
- state = 0;
- idval = nil;
- idval = (*idfn)(sup, idmethod, VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 1);
- testassert(idval == ID_RESULT);
- llval = 0;
- llval = (*llfn)(sup, llmethod, VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 2);
- testassert(llval == LL_RESULT);
- stretval = zero;
- stretval = (*stretfn)(sup, stretmethod, VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 3);
- testassert(stret_equal(stretval, STRET_RESULT));
- fpval = 0;
- fpval = (*fpfn)(sup, fpmethod, VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 4);
- testassert(fpval == FP_RESULT);
- lfpval = 0;
- lfpval = (*lfpfn)(sup, lfpmethod, VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 5);
- testassert(lfpval == LFP_RESULT);
- vecval = 0;
- vecval = (*vecfn)(sup, vecmethod, VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 6);
- testassert(vector_equal(vecval, VEC_RESULT));
- // message to nil
- // message to nil long long
- // message to nil stret
- // message to nil fpret
- // message to nil fpret long double
- // Use NIL_RECEIVER to avoid compiler optimizations.
- testprintf("message to nil\n");
- state = 0;
- idval = ID_RESULT;
- idval = [(id)NIL_RECEIVER idret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 0);
- testassert(idval == nil);
-
- state = 0;
- llval = LL_RESULT;
- llval = [(id)NIL_RECEIVER llret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 0);
- testassert(llval == 0LL);
-
- state = 0;
- stretval = zero;
- stretval = [(id)NIL_RECEIVER stret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 0);
- testassert(0 == memcmp(&stretval, &zero, sizeof(stretval)));
- #if __x86_64__
- // check stret return register
- state = 0;
- stretval = zero;
- stretptr = ((struct stret *(*)(struct stret *, id, SEL))objc_msgSend_stret)
- (&stretval, nil, @selector(stret_nop));
- testassert(stretptr == &stretval);
- testassert(state == 0);
- // no stret result guarantee for hand-written calls
- #endif
- #if __i386__
- // check struct-return address stack pop
- for (int i = 0; i < 10000000; i++) {
- state = 0;
- ((struct stret (*)(id, SEL))objc_msgSend_stret)
- (nil, @selector(stret_nop));
- }
- #endif
- state = 0;
- fpval = FP_RESULT;
- fpval = [(id)NIL_RECEIVER fpret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 0);
- testassert(fpval == 0.0);
-
- state = 0;
- lfpval = LFP_RESULT;
- lfpval = [(id)NIL_RECEIVER lfpret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 0);
- testassert(lfpval == 0.0);
-
- state = 0;
- vecval = VEC_RESULT;
- vecval = [(id)NIL_RECEIVER vecret :VEC1:VEC2:VEC3:VEC4:VEC5:VEC6:VEC7:VEC8: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];
- testassert(state == 0);
- testassert(vector_all(vecval == 0));
- // message to nil, different struct types
- // This verifies that ordinary objc_msgSend() erases enough registers
- // for structs that return in registers.
- #define TEST_NIL_STRUCT(i,n) \
- do { \
- struct stret_##i##n z; \
- bzero(&z, sizeof(z)); \
- [Super stret_i##n##_nonzero]; \
- [Super stret_d##n##_nonzero]; \
- struct stret_##i##n val = [(id)NIL_RECEIVER stret_##i##n##_zero]; \
- testassert(0 == memcmp(&z, &val, sizeof(val))); \
- } while (0)
- TEST_NIL_STRUCT(i,1);
- TEST_NIL_STRUCT(i,2);
- TEST_NIL_STRUCT(i,3);
- TEST_NIL_STRUCT(i,4);
- TEST_NIL_STRUCT(i,5);
- TEST_NIL_STRUCT(i,6);
- TEST_NIL_STRUCT(i,7);
- TEST_NIL_STRUCT(i,8);
- TEST_NIL_STRUCT(i,9);
- #if __i386__
- testwarn("rdar://16267205 i386 struct{float} and struct{double}");
- #else
- TEST_NIL_STRUCT(d,1);
- #endif
- TEST_NIL_STRUCT(d,2);
- TEST_NIL_STRUCT(d,3);
- TEST_NIL_STRUCT(d,4);
- TEST_NIL_STRUCT(d,5);
- TEST_NIL_STRUCT(d,6);
- TEST_NIL_STRUCT(d,7);
- TEST_NIL_STRUCT(d,8);
- TEST_NIL_STRUCT(d,9);
- // message to nil noarg
- // explicitly call noarg messenger, even if compiler doesn't emit it
- state = 0;
- idval = ID_RESULT;
- idval = ((typeof(idmsg0))objc_msgSend_noarg)(nil, @selector(idret_noarg));
- testassert(state == 0);
- testassert(idval == nil);
-
- state = 0;
- llval = LL_RESULT;
- llval = ((typeof(llmsg0))objc_msgSend_noarg)(nil, @selector(llret_noarg));
- testassert(state == 0);
- testassert(llval == 0LL);
- // no stret_noarg messenger
- #if !__i386__
- state = 0;
- fpval = FP_RESULT;
- fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(nil, @selector(fpret_noarg));
- testassert(state == 0);
- testassert(fpval == 0.0);
- state = 0;
- vecval = VEC_RESULT;
- vecval = ((typeof(vecmsg0))objc_msgSend_noarg)(nil, @selector(vecret_noarg));
- testassert(state == 0);
- testassert(vector_all(vecval == 0));
- #endif
- #if !__i386__ && !__x86_64__
- state = 0;
- lfpval = LFP_RESULT;
- lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(nil, @selector(lfpret_noarg));
- testassert(state == 0);
- testassert(lfpval == 0.0);
- #endif
- // rdar://8271364 objc_msgSendSuper2 must not change objc_super
- testprintf("super struct\n");
- struct objc_super sup_st = {
- sub,
- object_getClass(sub),
- };
- SELF = sub;
- state = 100;
- idval = nil;
- idval = ((id(*)(struct objc_super *, SEL, vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2, 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::::::::::::::::::::::::::::::::::::), VEC1,VEC2,VEC3,VEC4,VEC5,VEC6,VEC7,VEC8, 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);
- testassert(state == 1);
- testassert(idval == ID_RESULT);
- testassert(sup_st.receiver == sub);
- testassert(sup_st.super_class == object_getClass(sub));
- state = 100;
- stretval = zero;
- stretval = ((struct stret(*)(struct objc_super *, SEL, vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2,vector_ulong2, 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::::::::::::::::::::::::::::::::::::), VEC1,VEC2,VEC3,VEC4,VEC5,VEC6,VEC7,VEC8, 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);
- testassert(state == 3);
- testassert(stret_equal(stretval, STRET_RESULT));
- testassert(sup_st.receiver == sub);
- testassert(sup_st.super_class == object_getClass(sub));
- #if !__arm64__
- // Debug messengers.
- testprintf("debug messengers\n");
- state = 0;
- idmsg = (typeof(idmsg))objc_msgSend_debug;
- idval = nil;
- idval = (*idmsg)(sub, @selector(idret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 101);
- testassert(idval == ID_RESULT);
-
- state = 0;
- llmsg = (typeof(llmsg))objc_msgSend_debug;
- llval = 0;
- llval = (*llmsg)(sub, @selector(llret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 102);
- testassert(llval == LL_RESULT);
-
- state = 0;
- stretmsg = (typeof(stretmsg))objc_msgSend_stret_debug;
- stretval = zero;
- stretval = (*stretmsg)(sub, @selector(stret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 103);
- testassert(stret_equal(stretval, STRET_RESULT));
-
- state = 100;
- sup_st.receiver = sub;
- sup_st.super_class = object_getClass(sub);
- idmsgsuper = (typeof(idmsgsuper))objc_msgSendSuper2_debug;
- idval = nil;
- idval = (*idmsgsuper)(&sup_st, @selector(idret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 1);
- testassert(idval == ID_RESULT);
-
- state = 100;
- sup_st.receiver = sub;
- sup_st.super_class = object_getClass(sub);
- stretmsgsuper = (typeof(stretmsgsuper))objc_msgSendSuper2_stret_debug;
- stretval = zero;
- stretval = (*stretmsgsuper)(&sup_st, @selector(stret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 3);
- testassert(stret_equal(stretval, STRET_RESULT));
- #if __i386__
- state = 0;
- fpmsg = (typeof(fpmsg))objc_msgSend_fpret_debug;
- fpval = 0;
- fpval = (*fpmsg)(sub, @selector(fpret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 104);
- testassert(fpval == FP_RESULT);
- #endif
- #if __x86_64__
- state = 0;
- lfpmsg = (typeof(lfpmsg))objc_msgSend_fpret_debug;
- lfpval = 0;
- lfpval = (*lfpmsg)(sub, @selector(lfpret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- testassert(state == 105);
- testassert(lfpval == LFP_RESULT);
- // fixme fp2ret
- #endif
- // debug messengers
- #endif
- // objc_msgLookup
- #if 1
- // fixme objc_msgLookup test hack stopped working after a compiler update
- #elif __has_feature(objc_arc)
- // ARC interferes with objc_msgLookup test hacks
- #elif __i386__ && TARGET_OS_SIMULATOR
- testwarn("fixme msgLookup hack doesn't work");
- #else
- // fixme hack: call the looked-up method
- # if __arm64__
- # define CALL_LOOKUP(ret) \
- asm volatile ("blr x17 \n mov %x0, x0" : "=r" (ret))
- # define CALL_LOOKUP_STRET(ret) \
- asm volatile ("mov x8, %x1 \n blr x17 \n" : "=m" (ret) : "r" (&ret))
- # elif __arm__
- # define CALL_LOOKUP(ret) \
- asm volatile ("blx r12 \n mov %0, r0" : "=r" (ret))
- # define CALL_LOOKUP_STRET(ret) \
- asm volatile ("mov r0, %1 \n blx r12 \n" : "=m" (ret) : "r" (&ret))
- # elif __x86_64__
- # define CALL_LOOKUP(ret) \
- asm volatile ("call *%%r11 \n mov %%rax, %0" : "=r" (ret))
- # define CALL_LOOKUP_STRET(ret) \
- asm volatile ("mov %1, %%rdi \n call *%%r11 \n" : "=m" (ret) : "r" (&ret))
- # elif __i386__
- # define CALL_LOOKUP(ret) \
- asm volatile ("call *%%eax \n mov %%eax, %0" : "=r" (ret))
- # define CALL_LOOKUP_STRET(ret) \
- asm volatile ("add $4, %%esp \n mov %1, (%%esp) \n call *%%eax \n sub $4, %%esp \n" : "=m" (ret) : "d" (&ret))
- # else
- # error unknown architecture
- # endif
- // msgLookup uncached
- // msgLookup uncached super
- // msgLookup uncached stret
- // msgLookup uncached super stret
- // msgLookup uncached fpret
- // msgLookup uncached fpret long double
- // msgLookup cached
- // msgLookup cached stret
- // msgLookup cached super
- // msgLookup cached super stret
- // msgLookup cached fpret
- // msgLookup cached fpret long double
- // fixme verify that uncached lookup didn't happen the 2nd time?
- SELF = sub;
- _objc_flush_caches(object_getClass(sub));
- for (int i = 0; i < 5; i++) {
- testprintf("objc_msgLookup\n");
- state = 0;
- idmsg = (typeof(idmsg))objc_msgLookup;
- idval = nil;
- (*idmsg)(sub, @selector(idret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- CALL_LOOKUP(idval);
- testassert(state == 101);
- testassert(idval == ID_RESULT);
-
- testprintf("objc_msgLookup_stret\n");
- state = 0;
- stretmsg = (typeof(stretmsg))objc_msgLookup_stret;
- stretval = zero;
- (*stretmsg)(sub, @selector(stret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- CALL_LOOKUP_STRET(stretval);
- testassert(state == 103);
- testassert(stret_equal(stretval, STRET_RESULT));
-
- testprintf("objc_msgLookupSuper2\n");
- state = 100;
- sup_st.receiver = sub;
- sup_st.super_class = object_getClass(sub);
- idmsgsuper = (typeof(idmsgsuper))objc_msgLookupSuper2;
- idval = nil;
- idval = (*idmsgsuper)(&sup_st, @selector(idret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- CALL_LOOKUP(idval);
- testassert(state == 1);
- testassert(idval == ID_RESULT);
-
- testprintf("objc_msgLookupSuper2_stret\n");
- state = 100;
- sup_st.receiver = sub;
- sup_st.super_class = object_getClass(sub);
- stretmsgsuper = (typeof(stretmsgsuper))objc_msgLookupSuper2_stret;
- stretval = zero;
- (*stretmsgsuper)(&sup_st, @selector(stret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- CALL_LOOKUP_STRET(stretval);
- testassert(state == 3);
- testassert(stret_equal(stretval, STRET_RESULT));
-
- #if __i386__
- // fixme fpret, can't test FP stack properly
- #endif
- #if __x86_64__
- // fixme fpret, can't test FP stack properly
- // fixme fp2ret, can't test FP stack properly
- #endif
- }
- // msgLookup to nil
- // msgLookup to nil stret
- // fixme msgLookup to nil long long
- // fixme msgLookup to nil fpret
- // fixme msgLookup to nil fp2ret
- testprintf("objc_msgLookup to nil\n");
- state = 0;
- idmsg = (typeof(idmsg))objc_msgLookup;
- idval = nil;
- (*idmsg)(NIL_RECEIVER, @selector(idret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- CALL_LOOKUP(idval);
- testassert(state == 0);
- testassert(idval == nil);
-
- testprintf("objc_msgLookup_stret to nil\n");
- state = 0;
- stretmsg = (typeof(stretmsg))objc_msgLookup_stret;
- stretval = zero;
- (*stretmsg)(NIL_RECEIVER, @selector(stret::::::::::::::::::::::::::::::::::::), VEC1, VEC2, VEC3, VEC4, VEC5, VEC6, VEC7, VEC8, 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);
- CALL_LOOKUP_STRET(stretval);
- testassert(state == 0);
- // no stret result guarantee
-
- #if __i386__
- // fixme fpret, can't test FP stack properly
- #endif
- #if __x86_64__
- // fixme fpret, can't test FP stack properly
- // fixme fp2ret, can't test FP stack properly
- #endif
- // objc_msgLookup
- #endif
- #if !TEST_DWARF
- testwarn("no unwind tables in this configuration " NO_DWARF_REASON);
- #else
- // DWARF unwind tables
- testprintf("unwind tables\n");
- // Clear simulator-related environment variables.
- // Disassembly will run llvm-objdump which is not a simulator executable.
- unsetenv("DYLD_ROOT_PATH");
- unsetenv("DYLD_FALLBACK_LIBRARY_PATH");
- unsetenv("DYLD_FALLBACK_FRAMEWORK_PATH");
- // Check mprotect() of objc_msgSend.
- // It doesn't work when running on a device with no libobjc root.
- // In that case we skip this part of the test without failing.
- // fixme make this work
- // fixme now it doesn't work even with a libobjc root in place?
- int err1 = mprotect((void *)((uintptr_t)&objc_msgSend & ~(PAGE_MAX_SIZE-1)),
- PAGE_MAX_SIZE, PROT_READ | PROT_WRITE);
- int errno1 = errno;
- int err2 = mprotect((void *)((uintptr_t)&objc_msgSend & ~(PAGE_MAX_SIZE-1)),
- PAGE_MAX_SIZE, PROT_READ | PROT_EXEC);
- int errno2 = errno;
- if (err1 || err2) {
- testwarn("can't mprotect() objc_msgSend (%d, %d). "
- "Skipping unwind table test.",
- err1, errno1, err2, errno2);
- }
- else {
- // install exception handler
- struct sigaction act;
- act.sa_sigaction = break_handler;
- act.sa_mask = 0;
- act.sa_flags = SA_SIGINFO;
- sigaction(BREAK_SIGNAL, &act, nil);
- #if defined(BREAK_SIGNAL2)
- sigaction(BREAK_SIGNAL2, &act, nil);
- #endif
- SubDW *dw = [[SubDW alloc] init];
- objc_setForwardHandler((void*)test_dw_forward, (void*)test_dw_forward_stret);
- # if __x86_64__
- test_dw("objc_msgSend", dw, tagged, exttagged, false, 0);
- test_dw("objc_msgSend_stret", dw, tagged, exttagged, true, 0);
- test_dw("objc_msgSend_fpret", dw, tagged, exttagged, false, 0);
- test_dw("objc_msgSend_fp2ret", dw, tagged, exttagged, false, 0);
- test_dw("objc_msgSendSuper", dw, tagged, exttagged, false, 0);
- test_dw("objc_msgSendSuper2", dw, tagged, exttagged, false, 0);
- test_dw("objc_msgSendSuper_stret", dw, tagged, exttagged, true, 0);
- test_dw("objc_msgSendSuper2_stret", dw, tagged, exttagged, true, 0);
- # elif __i386__
- test_dw("objc_msgSend", dw, dw, dw, false, 0);
- test_dw("objc_msgSend_stret", dw, dw, dw, true, 0);
- test_dw("objc_msgSend_fpret", dw, dw, dw, false, 0);
- test_dw("objc_msgSendSuper", dw, dw, dw, false, 0);
- test_dw("objc_msgSendSuper2", dw, dw, dw, false, 0);
- test_dw("objc_msgSendSuper_stret", dw, dw, dw, true, 0);
- test_dw("objc_msgSendSuper2_stret", dw, dw, dw, true, 0);
- # elif __arm64__
- test_dw("objc_msgSend", dw, tagged, exttagged, false, 1);
- test_dw("objc_msgSendSuper", dw, tagged, exttagged, false, 1);
- test_dw("objc_msgSendSuper2", dw, tagged, exttagged, false, 1);
- # elif __arm__
- test_dw("objc_msgSend", dw, dw, dw, false, 0);
- test_dw("objc_msgSend_stret", dw, dw, dw, true, 0);
- test_dw("objc_msgSendSuper", dw, dw, dw, false, 0);
- test_dw("objc_msgSendSuper2", dw, dw, dw, false, 0);
- test_dw("objc_msgSendSuper_stret", dw, dw, dw, true, 0);
- test_dw("objc_msgSendSuper2_stret", dw, dw, dw, true, 0);
- # else
- # error unknown architecture
- # endif
- }
- // end DWARF unwind test
- #endif
- } POP_POOL;
- succeed(__FILE__);
- }
|