zend_jit_arm64.dasc 471 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588
  1. /*
  2. * +----------------------------------------------------------------------+
  3. * | Zend JIT |
  4. * +----------------------------------------------------------------------+
  5. * | Copyright (c) The PHP Group |
  6. * +----------------------------------------------------------------------+
  7. * | This source file is subject to version 3.01 of the PHP license, |
  8. * | that is bundled with this package in the file LICENSE, and is |
  9. * | available through the world-wide-web at the following url: |
  10. * | https://www.php.net/license/3_01.txt |
  11. * | If you did not receive a copy of the PHP license and are unable to |
  12. * | obtain it through the world-wide-web, please send a note to |
  13. * | license@php.net so we can mail you a copy immediately. |
  14. * +----------------------------------------------------------------------+
  15. * | Authors: Dmitry Stogov <dmitry@php.net> |
  16. * | Xinchen Hui <laruence@php.net> |
  17. * | Hao Sun <hao.sun@arm.com> |
  18. * +----------------------------------------------------------------------+
  19. */
  20. |.arch arm64
  21. |.define FP, x27
  22. |.define IP, x28
  23. |.define IPl, w28
  24. |.define RX, x28 // the same as VM IP reused as a general purpose reg
  25. |.define LR, x30
  26. |.define CARG1, x0
  27. |.define CARG2, x1
  28. |.define CARG3, x2
  29. |.define CARG4, x3
  30. |.define CARG5, x4
  31. |.define CARG6, x5
  32. |.define CARG1w, w0
  33. |.define CARG2w, w1
  34. |.define CARG3w, w2
  35. |.define CARG4w, w3
  36. |.define CARG5w, w4
  37. |.define CARG6w, w5
  38. |.define RETVALx, x0
  39. |.define RETVALw, w0
  40. |.define FCARG1x, x0
  41. |.define FCARG1w, w0
  42. |.define FCARG2x, x1
  43. |.define FCARG2w, w1
  44. |.define SPAD, 0x20 // padding for CPU stack alignment
  45. |.define NR_SPAD, 0x30 // padding for CPU stack alignment
  46. |.define T3, [sp, #0x28] // Used to store old value of IP (CALL VM only)
  47. |.define T2, [sp, #0x20] // Used to store old value of FP (CALL VM only)
  48. |.define T1, [sp, #0x10]
  49. // We use REG0/1/2 and FPR0/1 to replace r0/1/2 and xmm0/1 in the x86 implementation.
  50. // Scratch registers
  51. |.define REG0, x8
  52. |.define REG0w, w8
  53. |.define REG1, x9
  54. |.define REG1w, w9
  55. |.define REG2, x10
  56. |.define REG2w, w10
  57. |.define FPR0, d0
  58. |.define FPR1, d1
  59. |.define ZREG_REG0, ZREG_X8
  60. |.define ZREG_REG1, ZREG_X9
  61. |.define ZREG_REG2, ZREG_X10
  62. |.define ZREG_FPR0, ZREG_V0
  63. |.define ZREG_FPR1, ZREG_V1
  64. // Temporaries, not preserved across calls
  65. |.define TMP1, x15
  66. |.define TMP1w, w15
  67. |.define TMP2, x16
  68. |.define TMP2w, w16
  69. |.define TMP3, x17 // TODO: remember about hard-coded: mrs TMP3, tpidr_el0
  70. |.define TMP3w, w17
  71. |.define FPTMP, d16
  72. |.define ZREG_TMP1, ZREG_X15
  73. |.define ZREG_TMP2, ZREG_X16
  74. |.define ZREG_TMP3, ZREG_X17
  75. |.define ZREG_FPTMP, ZREG_V16
  76. |.define HYBRID_SPAD, 32 // padding for stack alignment
  77. #define TMP_ZVAL_OFFSET 16
  78. #define DASM_ALIGNMENT 16
  79. const char* zend_reg_name[] = {
  80. "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
  81. "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
  82. "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
  83. "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp",
  84. "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
  85. "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
  86. "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
  87. "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"
  88. };
  89. #define ZREG_FCARG1 ZREG_X0
  90. #define ZREG_FCARG2 ZREG_X1
  91. |.type EX, zend_execute_data, FP
  92. |.type OP, zend_op
  93. |.type ZVAL, zval
  94. |.actionlist dasm_actions
  95. |.globals zend_lb
  96. |.section code, cold_code, jmp_table
  97. static void* dasm_labels[zend_lb_MAX];
  98. #if ZTS
  99. static size_t tsrm_ls_cache_tcb_offset = 0;
  100. # ifdef __APPLE__
  101. struct TLVDescriptor {
  102. void* (*thunk)(struct TLVDescriptor*);
  103. uint64_t key;
  104. uint64_t offset;
  105. };
  106. typedef struct TLVDescriptor TLVDescriptor;
  107. # endif
  108. #endif
  109. #define IS_SIGNED_32BIT(val) ((((intptr_t)(val)) <= 0x7fffffff) && (((intptr_t)(val)) >= (-2147483647 - 1)))
  110. /* Encoding of immediate. */
  111. #define MAX_IMM12 0xfff // maximum value for imm12
  112. #define MAX_IMM16 0xffff // maximum value for imm16
  113. #define MOVZ_IMM MAX_IMM16 // movz insn
  114. #define LDR_STR_PIMM64 (MAX_IMM12*8) // ldr/str insn for 64-bit register: pimm is imm12 * 8
  115. #define LDR_STR_PIMM32 (MAX_IMM12*4) // ldr/str insn for 32-bit register: pimm is imm12 * 4
  116. #define LDRB_STRB_PIMM MAX_IMM12 // ldrb/strb insn
  117. #define B_IMM (1<<27) // signed imm26 * 4
  118. #define ADR_IMM (1<<20) // signed imm21
  119. #define ADRP_IMM (1LL<<32) // signed imm21 * 4096
  120. static bool arm64_may_use_b(const void *addr)
  121. {
  122. if (addr >= dasm_buf && addr < dasm_end) {
  123. return (((char*)dasm_end - (char*)dasm_buf) < B_IMM);
  124. } else if (addr >= dasm_end) {
  125. return (((char*)addr - (char*)dasm_buf) < B_IMM);
  126. } else if (addr < dasm_buf) {
  127. return (((char*)dasm_end - (char*)addr) < B_IMM);
  128. }
  129. return 0;
  130. }
  131. static bool arm64_may_use_adr(const void *addr)
  132. {
  133. if (addr >= dasm_buf && addr < dasm_end) {
  134. return (((char*)dasm_end - (char*)dasm_buf) < ADR_IMM);
  135. } else if (addr >= dasm_end) {
  136. return (((char*)addr - (char*)dasm_buf) < ADR_IMM);
  137. } else if (addr < dasm_buf) {
  138. return (((char*)dasm_end - (char*)addr) < ADR_IMM);
  139. }
  140. return 0;
  141. }
  142. static bool arm64_may_use_adrp(const void *addr)
  143. {
  144. if (addr >= dasm_buf && addr < dasm_end) {
  145. return (((char*)dasm_end - (char*)dasm_buf) < ADRP_IMM);
  146. } else if (addr >= dasm_end) {
  147. return (((char*)addr - (char*)dasm_buf) < ADRP_IMM);
  148. } else if (addr < dasm_buf) {
  149. return (((char*)dasm_end - (char*)addr) < ADRP_IMM);
  150. }
  151. return 0;
  152. }
  153. /* Determine whether "val" falls into two allowed ranges:
  154. * Range 1: [0, 0xfff]
  155. * Range 2: LSL #12 to Range 1
  156. * Used to guard the immediate encoding for add/adds/sub/subs/cmp/cmn instructions. */
  157. static bool arm64_may_encode_imm12(const int64_t val)
  158. {
  159. return (val >= 0 && (val <= MAX_IMM12 || !(val & 0xffffffffff000fff)));
  160. }
  161. /* Determine whether an immediate value can be encoded as the immediate operand of logical instructions. */
  162. static bool logical_immediate_p(uint64_t value, uint32_t reg_size)
  163. {
  164. /* fast path: power of two */
  165. if (value > 0 && !(value & (value - 1))) {
  166. return true;
  167. }
  168. if (reg_size == 32) {
  169. if (dasm_imm13((uint32_t)value, (uint32_t)value) != -1) {
  170. return true;
  171. }
  172. } else if (reg_size == 64) {
  173. if (dasm_imm13((uint32_t)value, (uint32_t)(value >> 32)) != -1) {
  174. return true;
  175. }
  176. } else {
  177. ZEND_UNREACHABLE();
  178. }
  179. return false;
  180. }
  181. /* Not Implemented Yet */
  182. |.macro NIY
  183. || //ZEND_ASSERT(0);
  184. | brk #0
  185. |.endmacro
  186. |.macro NIY_STUB
  187. || //ZEND_ASSERT(0);
  188. | brk #0
  189. |.endmacro
  190. |.macro ADD_HYBRID_SPAD
  191. ||#ifndef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
  192. | add sp, sp, # HYBRID_SPAD
  193. ||#endif
  194. |.endmacro
  195. |.macro SUB_HYBRID_SPAD
  196. ||#ifndef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
  197. | sub sp, sp, # HYBRID_SPAD
  198. ||#endif
  199. |.endmacro
  200. /* Move address into register. TODO: Support 52-bit address */
  201. |.macro LOAD_ADDR, reg, addr
  202. | // 48-bit virtual address
  203. || if (((uintptr_t)(addr)) == 0) {
  204. | mov reg, xzr
  205. || } else if (((uintptr_t)(addr)) <= MOVZ_IMM) {
  206. | movz reg, #((uint64_t)(addr))
  207. || } else if (arm64_may_use_adr((void*)(addr))) {
  208. | adr reg, &addr
  209. || } else if (arm64_may_use_adrp((void*)(addr))) {
  210. | adrp reg, &(((uintptr_t)(addr)))
  211. || if (((uintptr_t)(addr)) & 0xfff) {
  212. | add reg, reg, #(((uintptr_t)(addr)) & 0xfff)
  213. || }
  214. || } else if ((uintptr_t)(addr) & 0xffff) {
  215. | movz reg, #((uintptr_t)(addr) & 0xffff)
  216. || if (((uintptr_t)(addr) >> 16) & 0xffff) {
  217. | movk reg, #(((uintptr_t)(addr) >> 16) & 0xffff), lsl #16
  218. || }
  219. || if (((uintptr_t)(addr) >> 32) & 0xffff) {
  220. | movk reg, #(((uintptr_t)(addr) >> 32) & 0xffff), lsl #32
  221. || }
  222. || } else if (((uintptr_t)(addr) >> 16) & 0xffff) {
  223. | movz reg, #(((uintptr_t)(addr) >> 16) & 0xffff), lsl #16
  224. || if (((uintptr_t)(addr) >> 32) & 0xffff) {
  225. | movk reg, #(((uintptr_t)(addr) >> 32) & 0xffff), lsl #32
  226. || }
  227. || } else {
  228. | movz reg, #(((uintptr_t)(addr) >> 32) & 0xffff), lsl #32
  229. || }
  230. |.endmacro
  231. /* Move 32-bit immediate value into register. */
  232. |.macro LOAD_32BIT_VAL, reg, val
  233. || if (((uint32_t)(val)) <= MOVZ_IMM) {
  234. | movz reg, #((uint32_t)(val))
  235. || } else if (((uint32_t)(val) & 0xffff)) {
  236. | movz reg, #((uint32_t)(val) & 0xffff)
  237. || if ((((uint32_t)(val) >> 16) & 0xffff)) {
  238. | movk reg, #(((uint32_t)(val) >> 16) & 0xffff), lsl #16
  239. || }
  240. || } else {
  241. | movz reg, #(((uint32_t)(val) >> 16) & 0xffff), lsl #16
  242. || }
  243. |.endmacro
  244. /* Move 64-bit immediate value into register. */
  245. |.macro LOAD_64BIT_VAL, reg, val
  246. || if (((uint64_t)(val)) == 0) {
  247. | mov reg, xzr
  248. || } else if (((uint64_t)(val)) <= MOVZ_IMM) {
  249. | movz reg, #((uint64_t)(val))
  250. || } else if (~((uint64_t)(val)) <= MOVZ_IMM) {
  251. | movn reg, #(~((uint64_t)(val)))
  252. || } else if ((uint64_t)(val) & 0xffff) {
  253. | movz reg, #((uint64_t)(val) & 0xffff)
  254. || if (((uint64_t)(val) >> 16) & 0xffff) {
  255. | movk reg, #(((uint64_t)(val) >> 16) & 0xffff), lsl #16
  256. || }
  257. || if (((uint64_t)(val) >> 32) & 0xffff) {
  258. | movk reg, #(((uint64_t)(val) >> 32) & 0xffff), lsl #32
  259. || }
  260. || if ((((uint64_t)(val) >> 48) & 0xffff)) {
  261. | movk reg, #(((uint64_t)(val) >> 48) & 0xffff), lsl #48
  262. || }
  263. || } else if (((uint64_t)(val) >> 16) & 0xffff) {
  264. | movz reg, #(((uint64_t)(val) >> 16) & 0xffff), lsl #16
  265. || if (((uint64_t)(val) >> 32) & 0xffff) {
  266. | movk reg, #(((uint64_t)(val) >> 32) & 0xffff), lsl #32
  267. || }
  268. || if ((((uint64_t)(val) >> 48) & 0xffff)) {
  269. | movk reg, #(((uint64_t)(val) >> 48) & 0xffff), lsl #48
  270. || }
  271. || } else if (((uint64_t)(val) >> 32) & 0xffff) {
  272. | movz reg, #(((uint64_t)(val) >> 32) & 0xffff), lsl #32
  273. || if ((((uint64_t)(val) >> 48) & 0xffff)) {
  274. | movk reg, #(((uint64_t)(val) >> 48) & 0xffff), lsl #48
  275. || }
  276. || } else {
  277. | movz reg, #(((uint64_t)(val) >> 48) & 0xffff), lsl #48
  278. || }
  279. |.endmacro
  280. /* Extract the low 8 bits from 'src_reg' into 'dst_reg'.
  281. * Note: 0xff can be encoded as imm for 'and' instruction. */
  282. |.macro GET_LOW_8BITS, dst_reg, src_reg
  283. | and dst_reg, src_reg, #0xff
  284. |.endmacro
  285. /* Bitwise operation with immediate. 'bw_ins' can be and/orr/eor/ands.
  286. * 32-bit and 64-bit registers are distinguished. */
  287. |.macro BW_OP_32_WITH_CONST, bw_ins, dst_reg, src_reg1, val, tmp_reg
  288. || if (val == 0) {
  289. | bw_ins dst_reg, src_reg1, wzr
  290. || } else if (logical_immediate_p((uint32_t)val, 32)) {
  291. | bw_ins dst_reg, src_reg1, #val
  292. || } else {
  293. | LOAD_32BIT_VAL tmp_reg, val
  294. | bw_ins dst_reg, src_reg1, tmp_reg
  295. || }
  296. |.endmacro
  297. |.macro BW_OP_64_WITH_CONST, bw_ins, dst_reg, src_reg1, val, tmp_reg
  298. || if (val == 0) {
  299. | bw_ins dst_reg, src_reg1, xzr
  300. || } else if (logical_immediate_p(val, 64)) {
  301. | bw_ins dst_reg, src_reg1, #val
  302. || } else {
  303. | LOAD_64BIT_VAL tmp_reg, val
  304. | bw_ins dst_reg, src_reg1, tmp_reg
  305. || }
  306. |.endmacro
  307. /* Test bits 'tst' with immediate. 32-bit and 64-bit registers are distinguished. */
  308. |.macro TST_32_WITH_CONST, reg, val, tmp_reg
  309. || if (val == 0) {
  310. | tst reg, wzr
  311. || } else if (logical_immediate_p((uint32_t)val, 32)) {
  312. | tst reg, #val
  313. || } else {
  314. | LOAD_32BIT_VAL tmp_reg, val
  315. | tst reg, tmp_reg
  316. || }
  317. |.endmacro
  318. |.macro TST_64_WITH_CONST, reg, val, tmp_reg
  319. || if (val == 0) {
  320. | tst reg, xzr
  321. || } else if (logical_immediate_p(val, 64)) {
  322. | tst reg, #val
  323. || } else {
  324. | LOAD_64BIT_VAL tmp_reg, val
  325. | tst reg, tmp_reg
  326. || }
  327. |.endmacro
  328. /* Test bits between 64-bit register with constant 1. */
  329. |.macro TST_64_WITH_ONE, reg
  330. | tst reg, #1
  331. |.endmacro
  332. /* Compare a register value with immediate. 32-bit and 64-bit registers are distinguished.
  333. * Note: Comparing 64-bit register with 32-bit immediate is handled in CMP_64_WITH_CONST_32. */
  334. |.macro CMP_32_WITH_CONST, reg, val, tmp_reg
  335. || if (val == 0) {
  336. | cmp reg, wzr
  337. || } else if (arm64_may_encode_imm12((int64_t)(val))) {
  338. | cmp reg, #val
  339. || } else if (arm64_may_encode_imm12((int64_t)(-val))) {
  340. | cmn reg, #-val
  341. || } else {
  342. | LOAD_32BIT_VAL tmp_reg, val
  343. | cmp reg, tmp_reg
  344. || }
  345. |.endmacro
  346. |.macro CMP_64_WITH_CONST_32, reg, val, tmp_reg
  347. || if (val == 0) {
  348. | cmp reg, xzr
  349. || } else if (arm64_may_encode_imm12((int64_t)(val))) {
  350. | cmp reg, #val
  351. || } else if (arm64_may_encode_imm12((int64_t)(-val))) {
  352. | cmn reg, #-val
  353. || } else {
  354. | LOAD_32BIT_VAL tmp_reg, val
  355. | cmp reg, tmp_reg
  356. || }
  357. |.endmacro
  358. |.macro CMP_64_WITH_CONST, reg, val, tmp_reg
  359. || if (val == 0) {
  360. | cmp reg, xzr
  361. || } else if (arm64_may_encode_imm12((int64_t)(val))) {
  362. | cmp reg, #val
  363. || } else if (arm64_may_encode_imm12((int64_t)(-val))) {
  364. | cmn reg, #-val
  365. || } else {
  366. | LOAD_64BIT_VAL tmp_reg, val
  367. | cmp reg, tmp_reg
  368. || }
  369. |.endmacro
  370. /* Add/sub a register value with immediate. 'add_sub_ins' can be add/sub/adds/subs.
  371. * 32-bit and 64-bit registers are distinguished.
  372. * Note: Case of 64-bit register with 32-bit immediate is handled in ADD_SUB_64_WITH_CONST_32. */
  373. |.macro ADD_SUB_32_WITH_CONST, add_sub_ins, dst_reg, src_reg1, val, tmp_reg
  374. || if (val == 0) {
  375. | add_sub_ins dst_reg, src_reg1, wzr
  376. || } else if (arm64_may_encode_imm12((int64_t)(val))) {
  377. | add_sub_ins dst_reg, src_reg1, #val
  378. || } else {
  379. | LOAD_32BIT_VAL tmp_reg, val
  380. | add_sub_ins dst_reg, src_reg1, tmp_reg
  381. || }
  382. |.endmacro
  383. |.macro ADD_SUB_64_WITH_CONST_32, add_sub_ins, dst_reg, src_reg1, val, tmp_reg
  384. || if (val == 0) {
  385. | add_sub_ins dst_reg, src_reg1, xzr
  386. || } else if (arm64_may_encode_imm12((int64_t)(val))) {
  387. | add_sub_ins dst_reg, src_reg1, #val
  388. || } else {
  389. | LOAD_32BIT_VAL tmp_reg, val
  390. | add_sub_ins dst_reg, src_reg1, tmp_reg
  391. || }
  392. |.endmacro
  393. |.macro ADD_SUB_64_WITH_CONST, add_sub_ins, dst_reg, src_reg1, val, tmp_reg
  394. || if (val == 0) {
  395. | add_sub_ins dst_reg, src_reg1, xzr
  396. || } else if (arm64_may_encode_imm12((int64_t)(val))) {
  397. | add_sub_ins dst_reg, src_reg1, #val
  398. || } else {
  399. | LOAD_64BIT_VAL tmp_reg, val
  400. | add_sub_ins dst_reg, src_reg1, tmp_reg
  401. || }
  402. |.endmacro
  403. /* Memory access(load/store) with 32-bit 'offset'.
  404. * Use "unsigned offset" variant if 'offset' can be encoded, otherwise move 'offset' into temp register.
  405. * 8-bit, 32-bit and 64-bit registers to be transferred are distinguished.
  406. * Note: 'reg' can be used as 'tmp_reg' if 1) 'reg' is one GPR, AND 2) 'reg' != 'base_reg', AND 3) ins is 'ldr'. */
  407. |.macro MEM_ACCESS_64_WITH_UOFFSET, ldr_str_ins, reg, base_reg, offset, tmp_reg
  408. || if (((uintptr_t)(offset)) > LDR_STR_PIMM64) {
  409. | LOAD_32BIT_VAL tmp_reg, offset
  410. | ldr_str_ins reg, [base_reg, tmp_reg]
  411. || } else {
  412. | ldr_str_ins reg, [base_reg, #(offset)]
  413. || }
  414. |.endmacro
  415. |.macro MEM_ACCESS_32_WITH_UOFFSET, ldr_str_ins, reg, base_reg, offset, tmp_reg
  416. || if (((uintptr_t)(offset)) > LDR_STR_PIMM32) {
  417. | LOAD_32BIT_VAL tmp_reg, offset
  418. | ldr_str_ins reg, [base_reg, tmp_reg]
  419. || } else {
  420. | ldr_str_ins reg, [base_reg, #(offset)]
  421. || }
  422. |.endmacro
  423. |.macro MEM_ACCESS_8_WITH_UOFFSET, ldrb_strb_ins, reg, base_reg, offset, tmp_reg
  424. || if (((uintptr_t)(offset)) > LDRB_STRB_PIMM) {
  425. | LOAD_32BIT_VAL tmp_reg, offset
  426. | ldrb_strb_ins reg, [base_reg, tmp_reg]
  427. || } else {
  428. | ldrb_strb_ins reg, [base_reg, #(offset)]
  429. || }
  430. |.endmacro
  431. /* Memory access(load/store) with 64-bit 'offset'.
  432. * Use "unsigned offset" variant if 'offset' can be encoded, otherwise move 'offset' into temp register. */
  433. |.macro MEM_ACCESS_64_WITH_UOFFSET_64, ldr_str_ins, reg, base_reg, offset, tmp_reg
  434. || if (((uintptr_t)(offset)) > LDR_STR_PIMM64) {
  435. | LOAD_64BIT_VAL tmp_reg, offset
  436. | ldr_str_ins reg, [base_reg, tmp_reg]
  437. || } else {
  438. | ldr_str_ins reg, [base_reg, #(offset)]
  439. || }
  440. |.endmacro
  441. /* ZTS: get thread local variable "_tsrm_ls_cache" */
  442. |.macro LOAD_TSRM_CACHE, reg
  443. ||#ifdef __APPLE__
  444. | .long 0xd53bd071 // TODO: hard-coded: mrs TMP3, tpidrro_el0
  445. | and TMP3, TMP3, #0xfffffffffffffff8
  446. | MEM_ACCESS_64_WITH_UOFFSET_64 ldr, TMP3, TMP3, (((TLVDescriptor*)tsrm_ls_cache_tcb_offset)->key << 3), TMP1
  447. | MEM_ACCESS_64_WITH_UOFFSET_64 ldr, reg, TMP3, (((TLVDescriptor*)tsrm_ls_cache_tcb_offset)->offset), TMP1
  448. ||#else
  449. | .long 0xd53bd051 // TODO: hard-coded: mrs TMP3, tpidr_el0
  450. || ZEND_ASSERT(tsrm_ls_cache_tcb_offset <= LDR_STR_PIMM64);
  451. | ldr reg, [TMP3, #tsrm_ls_cache_tcb_offset]
  452. ||#endif
  453. |.endmacro
  454. |.macro LOAD_ADDR_ZTS, reg, struct, field
  455. | .if ZTS
  456. | LOAD_TSRM_CACHE TMP3
  457. | ADD_SUB_64_WITH_CONST_32 add, reg, TMP3, (struct.._offset + offsetof(zend_..struct, field)), reg
  458. | .else
  459. | LOAD_ADDR reg, &struct.field
  460. | .endif
  461. |.endmacro
  462. /* Store address 'addr' into memory 'mem'. */
  463. |.macro ADDR_STORE, mem, addr, tmp_reg
  464. | LOAD_ADDR tmp_reg, addr
  465. | str tmp_reg, mem
  466. |.endmacro
  467. /* Store a register value 'reg' into memory 'addr'.
  468. * For ZTS mode, base register with unsigned offset variant is used,
  469. * and 8-bit/32-bit/64-bit registers to be transferred are distinguished. */
  470. |.macro MEM_STORE, str_ins, reg, addr, tmp_reg
  471. || if (((uintptr_t)(addr)) > MOVZ_IMM && arm64_may_use_adr((void*)(addr))) {
  472. | adr tmp_reg, &addr
  473. | str_ins reg, [tmp_reg]
  474. || } else if (((uintptr_t)(addr)) > MOVZ_IMM && arm64_may_use_adrp((void*)(addr))) {
  475. | adrp tmp_reg, &(((uintptr_t)(addr)))
  476. | str_ins reg, [tmp_reg, #(((uintptr_t)(addr)) & 0xfff)]
  477. || } else {
  478. | LOAD_ADDR tmp_reg, addr
  479. | str_ins reg, [tmp_reg]
  480. || }
  481. |.endmacro
  482. |.macro MEM_STORE_64_ZTS, str_ins, reg, struct, field, tmp_reg
  483. | .if ZTS
  484. | LOAD_TSRM_CACHE TMP3
  485. | MEM_ACCESS_64_WITH_UOFFSET str_ins, reg, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg
  486. | .else
  487. | MEM_STORE str_ins, reg, &struct.field, tmp_reg
  488. | .endif
  489. |.endmacro
  490. |.macro MEM_STORE_32_ZTS, str_ins, reg, struct, field, tmp_reg
  491. | .if ZTS
  492. | LOAD_TSRM_CACHE TMP3
  493. | MEM_ACCESS_32_WITH_UOFFSET str_ins, reg, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg
  494. | .else
  495. | MEM_STORE str_ins, reg, &struct.field, tmp_reg
  496. | .endif
  497. |.endmacro
  498. |.macro MEM_STORE_8_ZTS, strb_ins, reg, struct, field, tmp_reg
  499. | .if ZTS
  500. | LOAD_TSRM_CACHE TMP3
  501. | MEM_ACCESS_8_WITH_UOFFSET strb_ins, reg, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg
  502. | .else
  503. | MEM_STORE strb_ins, reg, &struct.field, tmp_reg
  504. | .endif
  505. |.endmacro
  506. /* Load value from memory 'addr' and write it into register 'reg'.
  507. * For ZTS mode, base register with unsigned offset variant is used,
  508. * and 8-bit/32-bit/64-bit registers to be transferred are distinguished. */
  509. |.macro MEM_LOAD, ldr_ins, reg, addr, tmp_reg
  510. || if (((uintptr_t)(addr)) > MOVZ_IMM && arm64_may_use_adr((void*)(addr))) {
  511. | adr tmp_reg, &addr
  512. | ldr_ins reg, [tmp_reg]
  513. || } else if (((uintptr_t)(addr)) > MOVZ_IMM && arm64_may_use_adrp((void*)(addr))) {
  514. | adrp tmp_reg, &(((uintptr_t)(addr)))
  515. | ldr_ins reg, [tmp_reg, #(((uintptr_t)(addr)) & 0xfff)]
  516. || } else {
  517. | LOAD_ADDR tmp_reg, addr
  518. | ldr_ins reg, [tmp_reg]
  519. || }
  520. |.endmacro
  521. |.macro MEM_LOAD_64_ZTS, ldr_ins, reg, struct, field, tmp_reg
  522. | .if ZTS
  523. | LOAD_TSRM_CACHE TMP3
  524. | MEM_ACCESS_64_WITH_UOFFSET ldr_ins, reg, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg
  525. | .else
  526. | MEM_LOAD ldr_ins, reg, &struct.field, tmp_reg
  527. | .endif
  528. |.endmacro
  529. |.macro MEM_LOAD_32_ZTS, ldr_ins, reg, struct, field, tmp_reg
  530. | .if ZTS
  531. | LOAD_TSRM_CACHE TMP3
  532. | MEM_ACCESS_32_WITH_UOFFSET ldr_ins, reg, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg
  533. | .else
  534. | MEM_LOAD ldr_ins, reg, &struct.field, tmp_reg
  535. | .endif
  536. |.endmacro
  537. |.macro MEM_LOAD_8_ZTS, ldrb_ins, reg, struct, field, tmp_reg
  538. | .if ZTS
  539. | LOAD_TSRM_CACHE TMP3
  540. | MEM_ACCESS_8_WITH_UOFFSET ldrb_ins, reg, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg
  541. | .else
  542. | MEM_LOAD ldrb_ins, reg, &struct.field, tmp_reg
  543. | .endif
  544. |.endmacro
  545. /* Conduct arithmetic operation between the value in memory 'addr' and register value in 'reg',
  546. * and the computation result is stored back in 'reg'. 'op_ins' can be add/sub. */
  547. |.macro MEM_LOAD_OP, op_ins, ldr_ins, reg, addr, tmp_reg1, tmp_reg2
  548. | MEM_LOAD ldr_ins, tmp_reg1, addr, tmp_reg2
  549. | op_ins reg, reg, tmp_reg1
  550. |.endmacro
  551. |.macro MEM_LOAD_OP_ZTS, op_ins, ldr_ins, reg, struct, field, tmp_reg1, tmp_reg2
  552. | .if ZTS
  553. | LOAD_TSRM_CACHE TMP3
  554. | MEM_ACCESS_64_WITH_UOFFSET ldr_ins, tmp_reg2, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg1
  555. | op_ins reg, reg, tmp_reg2
  556. | .else
  557. | MEM_LOAD_OP op_ins, ldr_ins, reg, &struct.field, tmp_reg1, tmp_reg2
  558. | .endif
  559. |.endmacro
  560. /* Conduct arithmetic operation between the value in memory 'addr' and operand 'op', and the computation
  561. * result is stored back to memory 'addr'. Operand 'op' can be either a register value or an immediate value.
  562. * Currently, only add instruction is used as 'op_ins'.
  563. * Note: It should be guaranteed that the immediate value can be encoded for 'op_ins'. */
  564. |.macro MEM_UPDATE, op_ins, ldr_ins, str_ins, op, addr, tmp_reg1, tmp_reg2
  565. | LOAD_ADDR tmp_reg2, addr
  566. | ldr_ins, tmp_reg1, [tmp_reg2]
  567. | op_ins tmp_reg1, tmp_reg1, op
  568. | str_ins tmp_reg1, [tmp_reg2]
  569. |.endmacro
  570. |.macro MEM_UPDATE_ZTS, op_ins, ldr_ins, str_ins, op, struct, field, tmp_reg1, tmp_reg2
  571. | .if ZTS
  572. | LOAD_TSRM_CACHE TMP3
  573. || if (((uintptr_t)(struct.._offset+offsetof(zend_..struct, field))) > LDR_STR_PIMM64) {
  574. | LOAD_32BIT_VAL tmp_reg1, (struct.._offset+offsetof(zend_..struct, field))
  575. | ldr_ins tmp_reg2, [TMP3, tmp_reg1]
  576. | op_ins tmp_reg2, tmp_reg2, op
  577. | str_ins tmp_reg2, [TMP3, tmp_reg1]
  578. || } else {
  579. | ldr_ins tmp_reg2, [TMP3, #(struct.._offset+offsetof(zend_..struct, field))]
  580. | op_ins tmp_reg2, tmp_reg2, op
  581. | str_ins tmp_reg2, [TMP3, #(struct.._offset+offsetof(zend_..struct, field))]
  582. || }
  583. | .else
  584. | MEM_UPDATE op_ins, ldr_ins, str_ins, op, &struct.field, tmp_reg1, tmp_reg2
  585. | .endif
  586. |.endmacro
  587. |.macro EXT_CALL, func, tmp_reg
  588. || if (arm64_may_use_b(func)) {
  589. | bl &func
  590. || } else {
  591. | LOAD_ADDR tmp_reg, func
  592. | blr tmp_reg
  593. || }
  594. |.endmacro
  595. |.macro EXT_JMP, func, tmp_reg
  596. || if (arm64_may_use_b(func)) {
  597. | b &func
  598. || } else {
  599. | LOAD_ADDR tmp_reg, func
  600. | br tmp_reg
  601. || }
  602. |.endmacro
  603. |.macro SAVE_IP
  604. || if (GCC_GLOBAL_REGS) {
  605. | str IP, EX->opline
  606. || }
  607. |.endmacro
  608. |.macro LOAD_IP
  609. || if (GCC_GLOBAL_REGS) {
  610. | ldr IP, EX->opline
  611. || }
  612. |.endmacro
  613. |.macro LOAD_IP_ADDR, addr
  614. || if (GCC_GLOBAL_REGS) {
  615. | LOAD_ADDR IP, addr
  616. || } else {
  617. | ADDR_STORE EX->opline, addr, RX
  618. || }
  619. |.endmacro
  620. |.macro LOAD_IP_ADDR_ZTS, struct, field, tmp_reg
  621. | .if ZTS
  622. || if (GCC_GLOBAL_REGS) {
  623. | LOAD_TSRM_CACHE IP
  624. | MEM_ACCESS_64_WITH_UOFFSET ldr, IP, IP, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg
  625. || } else {
  626. | LOAD_TSRM_CACHE RX
  627. | ADD_SUB_64_WITH_CONST_32 add, RX, RX, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg
  628. | str RX, EX->opline
  629. || }
  630. | .else
  631. | LOAD_IP_ADDR &struct.field
  632. | .endif
  633. |.endmacro
  634. |.macro GET_IP, reg
  635. || if (GCC_GLOBAL_REGS) {
  636. | mov reg, IP
  637. || } else {
  638. | ldr reg, EX->opline
  639. || }
  640. |.endmacro
  641. /* Update IP with register 'reg'. Note: shift variant is handled by ADD_IP_SHIFT. */
  642. |.macro ADD_IP, reg, tmp_reg
  643. || if (GCC_GLOBAL_REGS) {
  644. | add IP, IP, reg
  645. || } else {
  646. | ldr tmp_reg, EX->opline
  647. | add tmp_reg, tmp_reg, reg
  648. | str tmp_reg, EX->opline
  649. || }
  650. |.endmacro
  651. |.macro ADD_IP_SHIFT, reg, shift, tmp_reg
  652. || if (GCC_GLOBAL_REGS) {
  653. | add IP, IP, reg, shift
  654. || } else {
  655. | ldr tmp_reg, EX->opline
  656. | add tmp_reg, tmp_reg, reg, shift
  657. | str tmp_reg, EX->opline
  658. || }
  659. |.endmacro
  660. /* Update IP with 32-bit immediate 'val'. */
  661. |.macro ADD_IP_WITH_CONST, val, tmp_reg
  662. || ZEND_ASSERT(arm64_may_encode_imm12((int64_t)(val)));
  663. || if (GCC_GLOBAL_REGS) {
  664. | add IP, IP, #val
  665. || } else {
  666. | ldr tmp_reg, EX->opline
  667. | add tmp_reg, tmp_reg, #val
  668. | str tmp_reg, EX->opline
  669. || }
  670. |.endmacro
  671. |.macro JMP_IP, tmp_reg
  672. || if (GCC_GLOBAL_REGS) {
  673. | ldr tmp_reg, [IP]
  674. | br tmp_reg
  675. || } else {
  676. | ldr tmp_reg, EX:CARG1->opline
  677. | br tmp_reg
  678. || }
  679. |.endmacro
  680. |.macro CMP_IP, addr, tmp_reg1, tmp_reg2
  681. | LOAD_ADDR tmp_reg1, addr
  682. || if (GCC_GLOBAL_REGS) {
  683. | cmp IP, tmp_reg1
  684. || } else {
  685. | ldr tmp_reg2, EX->opline
  686. | cmp tmp_reg2, tmp_reg1
  687. || }
  688. |.endmacro
  689. |.macro LOAD_ZVAL_ADDR, reg, addr
  690. || if (Z_MODE(addr) == IS_CONST_ZVAL) {
  691. | LOAD_ADDR reg, Z_ZV(addr)
  692. || } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
  693. || if (Z_OFFSET(addr)) {
  694. | ADD_SUB_64_WITH_CONST_32 add, reg, Rx(Z_REG(addr)), Z_OFFSET(addr), reg
  695. || } else {
  696. || if (Z_REG(addr) == ZREG_RSP) {
  697. | mov reg, sp
  698. || } else {
  699. | mov reg, Rx(Z_REG(addr))
  700. || }
  701. || }
  702. || } else {
  703. || ZEND_UNREACHABLE();
  704. || }
  705. |.endmacro
  706. |.macro GET_Z_TYPE_INFO, reg, zv
  707. | ldr reg, [zv, #offsetof(zval,u1.type_info)]
  708. |.endmacro
  709. |.macro SET_Z_TYPE_INFO, zv, type, tmp_reg
  710. | LOAD_32BIT_VAL tmp_reg, type
  711. | str tmp_reg, [zv, #offsetof(zval,u1.type_info)]
  712. |.endmacro
  713. |.macro GET_ZVAL_TYPE, reg, addr, tmp_reg
  714. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  715. | MEM_ACCESS_8_WITH_UOFFSET ldrb, reg, Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval,u1.v.type), tmp_reg
  716. |.endmacro
  717. |.macro GET_ZVAL_TYPE_INFO, reg, addr, tmp_reg
  718. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  719. | MEM_ACCESS_32_WITH_UOFFSET ldr, reg, Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval,u1.type_info), tmp_reg
  720. |.endmacro
  721. |.macro SET_ZVAL_TYPE_INFO, addr, type, tmp_reg1, tmp_reg2
  722. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  723. | LOAD_32BIT_VAL tmp_reg1, type
  724. | MEM_ACCESS_32_WITH_UOFFSET str, tmp_reg1, Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval,u1.type_info), tmp_reg2
  725. |.endmacro
  726. |.macro SET_ZVAL_TYPE_INFO_FROM_REG, addr, reg, tmp_reg
  727. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  728. | MEM_ACCESS_32_WITH_UOFFSET str, reg, Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval,u1.type_info), tmp_reg
  729. |.endmacro
  730. |.macro GET_Z_PTR, reg, zv
  731. | ldr reg, [zv]
  732. |.endmacro
  733. |.macro GET_ZVAL_PTR, reg, addr, tmp_reg
  734. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  735. | MEM_ACCESS_64_WITH_UOFFSET ldr, reg, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg
  736. |.endmacro
  737. |.macro SET_ZVAL_PTR, addr, reg, tmp_reg
  738. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  739. | MEM_ACCESS_64_WITH_UOFFSET str, reg, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg
  740. |.endmacro
  741. |.macro UNDEF_OPLINE_RESULT, tmp_reg
  742. | ldr REG0, EX->opline
  743. | ldr REG0w, OP:REG0->result.var
  744. | add REG0, FP, REG0
  745. | SET_Z_TYPE_INFO REG0, IS_UNDEF, tmp_reg
  746. |.endmacro
  747. |.macro UNDEF_OPLINE_RESULT_IF_USED, tmp_reg1, tmp_reg2
  748. | ldrb tmp_reg1, OP:RX->result_type
  749. | TST_32_WITH_CONST tmp_reg1, (IS_TMP_VAR|IS_VAR), tmp_reg2
  750. | beq >1
  751. | ldr REG0w, OP:RX->result.var
  752. | add REG0, FP, REG0
  753. | SET_Z_TYPE_INFO REG0, IS_UNDEF, tmp_reg1
  754. |1:
  755. |.endmacro
  756. /* Floating-point comparison between register 'reg' and value from memory 'addr'.
  757. * Note: the equivalent macros in JIT/x86 are SSE_AVX_OP and SSE_OP. */
  758. |.macro DOUBLE_CMP, reg, addr, tmp_reg, fp_tmp_reg
  759. || if (Z_MODE(addr) == IS_CONST_ZVAL) {
  760. | MEM_LOAD ldr, Rd(fp_tmp_reg-ZREG_V0), Z_ZV(addr), Rx(tmp_reg)
  761. | fcmp Rd(reg-ZREG_V0), Rd(fp_tmp_reg-ZREG_V0)
  762. || } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
  763. | MEM_ACCESS_64_WITH_UOFFSET ldr, Rd(fp_tmp_reg-ZREG_V0), Rx(Z_REG(addr)), Z_OFFSET(addr), Rx(tmp_reg)
  764. | fcmp Rd(reg-ZREG_V0), Rd(fp_tmp_reg-ZREG_V0)
  765. || } else if (Z_MODE(addr) == IS_REG) {
  766. | fcmp Rd(reg-ZREG_V0), Rd(Z_REG(addr)-ZREG_V0)
  767. || } else {
  768. || ZEND_UNREACHABLE();
  769. || }
  770. |.endmacro
  771. /* Convert LONG value 'val' into DOUBLE type, and move it into FP register 'reg'.
  772. * Note: the equivalent macro in JIT/x86 is SSE_GET_LONG. */
  773. |.macro DOUBLE_GET_LONG, reg, val, tmp_reg
  774. || if (val == 0) {
  775. | fmov Rd(reg-ZREG_V0), xzr // TODO: "movi d0, #0" is not recognized by DynASM/arm64
  776. || } else {
  777. | LOAD_64BIT_VAL Rx(tmp_reg), val
  778. | scvtf Rd(reg-ZREG_V0), Rx(tmp_reg)
  779. || }
  780. |.endmacro
  781. /* Convert LONG value from memory 'addr' into DOUBLE type, and move it into FP register 'reg'.
  782. * Note: the equivalent macro in JIT/x86 is SSE_GET_ZVAL_LVAL. */
  783. |.macro DOUBLE_GET_ZVAL_LVAL, reg, addr, tmp_reg1, tmp_reg2
  784. || if (Z_MODE(addr) == IS_CONST_ZVAL) {
  785. | DOUBLE_GET_LONG reg, Z_LVAL_P(Z_ZV(addr)), tmp_reg1
  786. || } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
  787. | MEM_ACCESS_64_WITH_UOFFSET ldr, Rx(tmp_reg1), Rx(Z_REG(addr)), Z_OFFSET(addr), Rx(tmp_reg2)
  788. | scvtf Rd(reg-ZREG_V0), Rx(tmp_reg1)
  789. || } else if (Z_MODE(addr) == IS_REG) {
  790. | scvtf Rd(reg-ZREG_V0), Rx(Z_REG(addr))
  791. || } else {
  792. || ZEND_UNREACHABLE();
  793. || }
  794. |.endmacro
  795. /* Floating-point arithmetic operation between two FP registers.
  796. * Note: the equivalent macro in JIT/x86 is AVX_MATH_REG. */
  797. |.macro DOUBLE_MATH_REG, opcode, dst_reg, op1_reg, op2_reg
  798. || switch (opcode) {
  799. || case ZEND_ADD:
  800. | fadd Rd(dst_reg-ZREG_V0), Rd(op1_reg-ZREG_V0), Rd(op2_reg-ZREG_V0)
  801. || break;
  802. || case ZEND_SUB:
  803. | fsub Rd(dst_reg-ZREG_V0), Rd(op1_reg-ZREG_V0), Rd(op2_reg-ZREG_V0)
  804. || break;
  805. || case ZEND_MUL:
  806. | fmul Rd(dst_reg-ZREG_V0), Rd(op1_reg-ZREG_V0), Rd(op2_reg-ZREG_V0)
  807. || break;
  808. || case ZEND_DIV:
  809. | fdiv Rd(dst_reg-ZREG_V0), Rd(op1_reg-ZREG_V0), Rd(op2_reg-ZREG_V0)
  810. || break;
  811. || }
  812. |.endmacro
  813. /* Conduct binary operation between register 'reg' and value from memory 'addr',
  814. * and the computation result is stored in 'reg'.
  815. * For LONG_ADD_SUB, 'add_sub_ins' can be adds/subs. For LONG_BW_OP, 'bw_ins' can be and/orr/eor.
  816. * For LONG_CMP, 'cmp' instruction is used by default and only flag registers are affected.
  817. * Note: the equivalent macro in JIT/x86 is LONG_OP. */
  818. |.macro LONG_ADD_SUB, add_sub_ins, reg, addr, tmp_reg
  819. || if (Z_MODE(addr) == IS_CONST_ZVAL) {
  820. | ADD_SUB_64_WITH_CONST add_sub_ins, Rx(reg), Rx(reg), Z_LVAL_P(Z_ZV(addr)), tmp_reg
  821. || } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
  822. | MEM_ACCESS_64_WITH_UOFFSET ldr, tmp_reg, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg
  823. | add_sub_ins Rx(reg), Rx(reg), tmp_reg
  824. || } else if (Z_MODE(addr) == IS_REG) {
  825. | add_sub_ins Rx(reg), Rx(reg), Rx(Z_REG(addr))
  826. || } else {
  827. || ZEND_UNREACHABLE();
  828. || }
  829. |.endmacro
  830. |.macro LONG_BW_OP, bw_ins, reg, addr, tmp_reg
  831. || if (Z_MODE(addr) == IS_CONST_ZVAL) {
  832. | BW_OP_64_WITH_CONST bw_ins, Rx(reg), Rx(reg), Z_LVAL_P(Z_ZV(addr)), tmp_reg
  833. || } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
  834. | MEM_ACCESS_64_WITH_UOFFSET ldr, tmp_reg, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg
  835. | bw_ins Rx(reg), Rx(reg), tmp_reg
  836. || } else if (Z_MODE(addr) == IS_REG) {
  837. | bw_ins Rx(reg), Rx(reg), Rx(Z_REG(addr))
  838. || } else {
  839. || ZEND_UNREACHABLE();
  840. || }
  841. |.endmacro
  842. |.macro LONG_CMP, reg, addr, tmp_reg
  843. || if (Z_MODE(addr) == IS_CONST_ZVAL) {
  844. | CMP_64_WITH_CONST Rx(reg), Z_LVAL_P(Z_ZV(addr)), tmp_reg
  845. || } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
  846. | MEM_ACCESS_64_WITH_UOFFSET ldr, tmp_reg, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg
  847. | cmp Rx(reg), tmp_reg
  848. || } else if (Z_MODE(addr) == IS_REG) {
  849. | cmp Rx(reg), Rx(Z_REG(addr))
  850. || } else {
  851. || ZEND_UNREACHABLE();
  852. || }
  853. |.endmacro
  854. /* Conduct add/sub between value from memory 'addr' and an immediate value 'val', and
  855. * the computation result is stored back into 'addr'.
  856. * Note: it should be guaranteed that 'val' can be encoded into add/sub instruction. */
  857. |.macro LONG_ADD_SUB_WITH_IMM, add_sub_ins, addr, val, tmp_reg1, tmp_reg2
  858. || ZEND_ASSERT(arm64_may_encode_imm12((int64_t)(val)));
  859. || if (Z_MODE(addr) == IS_MEM_ZVAL) {
  860. || if (((uint32_t)(Z_OFFSET(addr))) > LDR_STR_PIMM64) {
  861. | LOAD_32BIT_VAL tmp_reg2, Z_OFFSET(addr)
  862. | ldr tmp_reg1, [Rx(Z_REG(addr)), tmp_reg2]
  863. | add_sub_ins tmp_reg1, tmp_reg1, #val
  864. | str tmp_reg1, [Rx(Z_REG(addr)), tmp_reg2]
  865. || } else {
  866. | ldr tmp_reg1, [Rx(Z_REG(addr)), #Z_OFFSET(addr)]
  867. | add_sub_ins tmp_reg1, tmp_reg1, #val
  868. | str tmp_reg1, [Rx(Z_REG(addr)), #Z_OFFSET(addr)]
  869. || }
  870. || } else if (Z_MODE(addr) == IS_REG) {
  871. | add_sub_ins Rx(Z_REG(addr)), Rx(Z_REG(addr)), #val
  872. || } else {
  873. || ZEND_UNREACHABLE();
  874. || }
  875. |.endmacro
  876. /* Compare value from memory 'addr' with immediate value 'val'.
  877. * Note: the equivalent macro in JIT/x86 is LONG_OP_WITH_CONST. */
  878. |.macro LONG_CMP_WITH_CONST, addr, val, tmp_reg1, tmp_reg2
  879. || if (Z_MODE(addr) == IS_MEM_ZVAL) {
  880. | MEM_ACCESS_64_WITH_UOFFSET ldr, tmp_reg1, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg2
  881. | CMP_64_WITH_CONST tmp_reg1, val, tmp_reg2
  882. || } else if (Z_MODE(addr) == IS_REG) {
  883. | CMP_64_WITH_CONST Rx(Z_REG(addr)), val, tmp_reg1
  884. || } else {
  885. || ZEND_UNREACHABLE();
  886. || }
  887. |.endmacro
  888. |.macro GET_ZVAL_LVAL, reg, addr, tmp_reg
  889. || if (Z_MODE(addr) == IS_CONST_ZVAL) {
  890. || if (Z_LVAL_P(Z_ZV(addr)) == 0) {
  891. | mov Rx(reg), xzr
  892. || } else {
  893. | LOAD_64BIT_VAL Rx(reg), Z_LVAL_P(Z_ZV(addr))
  894. || }
  895. || } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
  896. | MEM_ACCESS_64_WITH_UOFFSET ldr, Rx(reg), Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg
  897. || } else if (Z_MODE(addr) == IS_REG) {
  898. || if (reg != Z_REG(addr)) {
  899. | mov Rx(reg), Rx(Z_REG(addr))
  900. || }
  901. || } else {
  902. || ZEND_UNREACHABLE();
  903. || }
  904. |.endmacro
  905. |.macro LONG_MATH, opcode, reg, addr, tmp_reg1
  906. || switch (opcode) {
  907. || case ZEND_ADD:
  908. | LONG_ADD_SUB adds, reg, addr, tmp_reg1
  909. || break;
  910. || case ZEND_SUB:
  911. | LONG_ADD_SUB subs, reg, addr, tmp_reg1
  912. || break;
  913. || case ZEND_BW_OR:
  914. | LONG_BW_OP orr, reg, addr, tmp_reg1
  915. || break;
  916. || case ZEND_BW_AND:
  917. | LONG_BW_OP and, reg, addr, tmp_reg1
  918. || break;
  919. || case ZEND_BW_XOR:
  920. | LONG_BW_OP eor, reg, addr, tmp_reg1
  921. || break;
  922. || default:
  923. || ZEND_UNREACHABLE();
  924. || }
  925. |.endmacro
  926. |.macro LONG_MATH_REG, opcode, dst_reg, src_reg1, src_reg2
  927. || switch (opcode) {
  928. || case ZEND_ADD:
  929. | adds dst_reg, src_reg1, src_reg2
  930. || break;
  931. || case ZEND_SUB:
  932. | subs dst_reg, src_reg1, src_reg2
  933. || break;
  934. || case ZEND_BW_OR:
  935. | orr dst_reg, src_reg1, src_reg2
  936. || break;
  937. || case ZEND_BW_AND:
  938. | and dst_reg, src_reg1, src_reg2
  939. || break;
  940. || case ZEND_BW_XOR:
  941. | eor dst_reg, src_reg1, src_reg2
  942. || break;
  943. || default:
  944. || ZEND_UNREACHABLE();
  945. || }
  946. |.endmacro
  947. /* Store LONG value into memory 'addr'.
  948. * This LONG value can be an immediate value i.e. 'val' in macro SET_ZVAL_LVAL, or
  949. * a register value i.e. 'reg' in macro SET_ZVAL_LVAL_FROM_REG. */
  950. |.macro SET_ZVAL_LVAL_FROM_REG, addr, reg, tmp_reg
  951. || if (Z_MODE(addr) == IS_REG) {
  952. | mov Rx(Z_REG(addr)), reg
  953. || } else {
  954. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  955. | MEM_ACCESS_64_WITH_UOFFSET str, reg, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg
  956. || }
  957. |.endmacro
  958. |.macro SET_ZVAL_LVAL, addr, val, tmp_reg1, tmp_reg2
  959. || if (val == 0) {
  960. | SET_ZVAL_LVAL_FROM_REG addr, xzr, tmp_reg2
  961. || } else {
  962. | LOAD_64BIT_VAL tmp_reg1, val
  963. | SET_ZVAL_LVAL_FROM_REG addr, tmp_reg1, tmp_reg2
  964. || }
  965. |.endmacro
  966. /* Store DOUBLE value from FP register 'reg' into memory 'addr'.
  967. * Note: the equivalent macro in JIT/x86 is SSE_SET_ZVAL_DVAL. */
  968. |.macro SET_ZVAL_DVAL, addr, reg, tmp_reg
  969. || if (Z_MODE(addr) == IS_REG) {
  970. || if (reg != Z_REG(addr)) {
  971. | fmov Rd(Z_REG(addr)-ZREG_V0), Rd(reg-ZREG_V0)
  972. || }
  973. || } else {
  974. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  975. | MEM_ACCESS_64_WITH_UOFFSET str, Rd(reg-ZREG_V0), Rx(Z_REG(addr)), Z_OFFSET(addr), Rx(tmp_reg)
  976. || }
  977. |.endmacro
  978. /* Load DOUBLE value from memory 'addr' into FP register 'reg'.
  979. * Note: the equivalent macro in JIT/x86 is SSE_GET_ZVAL_DVAL. */
  980. |.macro GET_ZVAL_DVAL, reg, addr, tmp_reg
  981. || if (Z_MODE(addr) != IS_REG || reg != Z_REG(addr)) {
  982. || if (Z_MODE(addr) == IS_CONST_ZVAL) {
  983. | MEM_LOAD ldr, Rd(reg-ZREG_V0), Z_ZV(addr), Rx(tmp_reg)
  984. || } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
  985. | MEM_ACCESS_64_WITH_UOFFSET ldr, Rd(reg-ZREG_V0), Rx(Z_REG(addr)), Z_OFFSET(addr), Rx(tmp_reg)
  986. || } else if (Z_MODE(addr) == IS_REG) {
  987. | fmov Rd(reg-ZREG_V0), Rd(Z_REG(addr)-ZREG_V0)
  988. || } else {
  989. || ZEND_UNREACHABLE();
  990. || }
  991. || }
  992. |.endmacro
  993. |.macro ZVAL_COPY_CONST, dst_addr, dst_info, dst_def_info, zv, tmp_reg1, tmp_reg2, fp_tmp_reg
  994. || if (Z_TYPE_P(zv) > IS_TRUE) {
  995. || if (Z_TYPE_P(zv) == IS_DOUBLE) {
  996. || zend_reg dst_reg = (Z_MODE(dst_addr) == IS_REG) ? Z_REG(dst_addr) : fp_tmp_reg;
  997. | MEM_LOAD ldr, Rd(dst_reg-ZREG_V0), zv, Rx(tmp_reg1)
  998. | SET_ZVAL_DVAL dst_addr, dst_reg, tmp_reg2
  999. || } else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) {
  1000. || zend_reg dst_reg = (Z_MODE(dst_addr) == IS_REG) ? Z_REG(dst_addr) : fp_tmp_reg;
  1001. | DOUBLE_GET_LONG dst_reg, Z_LVAL_P(zv), tmp_reg1
  1002. | SET_ZVAL_DVAL dst_addr, dst_reg, tmp_reg2
  1003. || } else {
  1004. | // In x64, if the range of this LONG value can be represented via INT type, only move the low 32 bits into dst_addr.
  1005. | // Note that imm32 is signed extended to 64 bits during mov.
  1006. | // In aarch64, we choose to handle both cases in the same way. Even though 4 mov's are used for 64-bit value and 2 mov's are
  1007. | // needed for 32-bit value, an extra ext insn is needed for 32-bit vlaue.
  1008. | SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv), Rx(tmp_reg1), Rx(tmp_reg2)
  1009. || }
  1010. || }
  1011. || if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
  1012. || if (dst_def_info == MAY_BE_DOUBLE) {
  1013. || if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
  1014. | SET_ZVAL_TYPE_INFO dst_addr, IS_DOUBLE, Rw(tmp_reg1), Rx(tmp_reg2)
  1015. || }
  1016. || } else if (((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (1<<Z_TYPE_P(zv))) || (dst_info & (MAY_BE_STRING|MAY_BE_ARRAY)) != 0) {
  1017. | SET_ZVAL_TYPE_INFO dst_addr, Z_TYPE_INFO_P(zv), Rw(tmp_reg1), Rx(tmp_reg2)
  1018. || }
  1019. || }
  1020. |.endmacro
  1021. |.macro ZVAL_COPY_CONST_2, dst_addr, res_addr, dst_info, dst_def_info, zv, tmp_reg1, tmp_reg2, fp_tmp_reg
  1022. || if (Z_TYPE_P(zv) > IS_TRUE) {
  1023. || if (Z_TYPE_P(zv) == IS_DOUBLE) {
  1024. || zend_reg dst_reg = (Z_MODE(dst_addr) == IS_REG) ?
  1025. || Z_REG(dst_addr) : ((Z_MODE(res_addr) == IS_REG) ? Z_REG(res_addr) : fp_tmp_reg);
  1026. | MEM_LOAD ldr, Rd(dst_reg-ZREG_V0), zv, Rx(tmp_reg1)
  1027. | SET_ZVAL_DVAL dst_addr, dst_reg, tmp_reg2
  1028. | SET_ZVAL_DVAL res_addr, dst_reg, tmp_reg2
  1029. || } else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) {
  1030. || if (Z_MODE(dst_addr) == IS_REG) {
  1031. | DOUBLE_GET_LONG Z_REG(dst_addr), Z_LVAL_P(zv), tmp_reg1
  1032. | SET_ZVAL_DVAL res_addr, Z_REG(dst_addr), tmp_reg2
  1033. || } else if (Z_MODE(res_addr) == IS_REG) {
  1034. | DOUBLE_GET_LONG Z_REG(res_addr), Z_LVAL_P(zv), tmp_reg1
  1035. | SET_ZVAL_DVAL dst_addr, Z_REG(res_addr), tmp_reg2
  1036. || } else {
  1037. | DOUBLE_GET_LONG fp_tmp_reg, Z_LVAL_P(zv), tmp_reg1
  1038. | SET_ZVAL_DVAL dst_addr, fp_tmp_reg, tmp_reg2
  1039. | SET_ZVAL_DVAL res_addr, fp_tmp_reg, tmp_reg2
  1040. || }
  1041. || } else {
  1042. || if (Z_MODE(dst_addr) == IS_REG) {
  1043. | SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv), Rx(tmp_reg1), Rx(tmp_reg2)
  1044. | SET_ZVAL_LVAL_FROM_REG res_addr, Rx(Z_REG(dst_addr)), Rx(tmp_reg1)
  1045. || } else if (Z_MODE(res_addr) == IS_REG) {
  1046. | SET_ZVAL_LVAL res_addr, Z_LVAL_P(zv), Rx(tmp_reg1), Rx(tmp_reg2)
  1047. | SET_ZVAL_LVAL_FROM_REG dst_addr, Rx(Z_REG(res_addr)), Rx(tmp_reg1)
  1048. || } else {
  1049. | SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv), Rx(tmp_reg1), Rx(tmp_reg2)
  1050. | SET_ZVAL_LVAL res_addr, Z_LVAL_P(zv), Rx(tmp_reg1), Rx(tmp_reg2)
  1051. || }
  1052. || }
  1053. || }
  1054. || if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
  1055. || if (dst_def_info == MAY_BE_DOUBLE) {
  1056. || if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
  1057. | SET_ZVAL_TYPE_INFO dst_addr, IS_DOUBLE, Rw(tmp_reg1), Rx(tmp_reg2)
  1058. || }
  1059. || } else if (((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (1<<Z_TYPE_P(zv))) || (dst_info & (MAY_BE_STRING|MAY_BE_ARRAY)) != 0) {
  1060. | SET_ZVAL_TYPE_INFO dst_addr, Z_TYPE_INFO_P(zv), Rw(tmp_reg1), Rx(tmp_reg2)
  1061. || }
  1062. || }
  1063. || if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
  1064. || if (dst_def_info == MAY_BE_DOUBLE) {
  1065. | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, Rw(tmp_reg1), Rx(tmp_reg2)
  1066. || } else {
  1067. | SET_ZVAL_TYPE_INFO res_addr, Z_TYPE_INFO_P(zv), Rw(tmp_reg1), Rx(tmp_reg2)
  1068. || }
  1069. || }
  1070. |.endmacro
  1071. // the same as above, but "src" may overlap with "reg1"
  1072. // Useful info would be stored into reg1 and reg2, and they might be used afterward.
  1073. |.macro ZVAL_COPY_VALUE, dst_addr, dst_info, src_addr, src_info, reg1, reg2, tmp_reg1, tmp_reg2, fp_tmp_reg
  1074. | ZVAL_COPY_VALUE_V dst_addr, dst_info, src_addr, src_info, reg1, reg2, tmp_reg1, fp_tmp_reg
  1075. || if ((src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)) &&
  1076. || !(src_info & MAY_BE_GUARD) &&
  1077. || has_concrete_type(src_info & MAY_BE_ANY)) {
  1078. || if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
  1079. || if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
  1080. || uint32_t type = concrete_type(src_info);
  1081. | SET_ZVAL_TYPE_INFO dst_addr, type, Rw(tmp_reg1), Rx(tmp_reg2)
  1082. || }
  1083. || }
  1084. || } else {
  1085. | GET_ZVAL_TYPE_INFO Rw(reg1), src_addr, Rx(tmp_reg1)
  1086. | SET_ZVAL_TYPE_INFO_FROM_REG dst_addr, Rw(reg1), Rx(tmp_reg1)
  1087. || }
  1088. |.endmacro
  1089. |.macro ZVAL_COPY_VALUE_V, dst_addr, dst_info, src_addr, src_info, reg1, reg2, tmp_reg, fp_tmp_reg
  1090. || if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
  1091. || if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
  1092. || if (Z_MODE(src_addr) == IS_REG) {
  1093. || if (Z_MODE(dst_addr) != IS_REG || Z_REG(dst_addr) != Z_REG(src_addr)) {
  1094. | SET_ZVAL_LVAL_FROM_REG dst_addr, Rx(Z_REG(src_addr)), Rx(tmp_reg)
  1095. || }
  1096. || } else if (Z_MODE(dst_addr) == IS_REG) {
  1097. | GET_ZVAL_LVAL Z_REG(dst_addr), src_addr, Rx(tmp_reg)
  1098. || } else {
  1099. | GET_ZVAL_LVAL reg2, src_addr, Rx(tmp_reg)
  1100. | SET_ZVAL_LVAL_FROM_REG dst_addr, Rx(reg2), Rx(tmp_reg)
  1101. || }
  1102. || } else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
  1103. || if (Z_MODE(src_addr) == IS_REG) {
  1104. | SET_ZVAL_DVAL dst_addr, Z_REG(src_addr), tmp_reg
  1105. || } else if (Z_MODE(dst_addr) == IS_REG) {
  1106. | GET_ZVAL_DVAL Z_REG(dst_addr), src_addr, tmp_reg
  1107. || } else {
  1108. | GET_ZVAL_DVAL fp_tmp_reg, src_addr, tmp_reg
  1109. | SET_ZVAL_DVAL dst_addr, fp_tmp_reg, tmp_reg
  1110. || }
  1111. || // Combine the following two branches.
  1112. || // } else if (!(src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD))) {
  1113. || } else {
  1114. | GET_ZVAL_PTR Rx(reg2), src_addr, Rx(tmp_reg)
  1115. | SET_ZVAL_PTR dst_addr, Rx(reg2), Rx(tmp_reg)
  1116. || }
  1117. || }
  1118. |.endmacro
  1119. |.macro ZVAL_COPY_VALUE_2, dst_addr, dst_info, res_addr, src_addr, src_info, reg1, reg2, tmp_reg, tmp_reg2, fp_tmp_reg
  1120. || if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
  1121. || if ((src_info & MAY_BE_ANY) == MAY_BE_LONG) {
  1122. || if (Z_MODE(src_addr) == IS_REG) {
  1123. || if (Z_MODE(dst_addr) != IS_REG || Z_REG(dst_addr) != Z_REG(src_addr)) {
  1124. | SET_ZVAL_LVAL_FROM_REG dst_addr, Rx(Z_REG(src_addr)), Rx(tmp_reg)
  1125. || }
  1126. || if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != Z_REG(src_addr)) {
  1127. | SET_ZVAL_LVAL_FROM_REG res_addr, Rx(Z_REG(src_addr)), Rx(tmp_reg)
  1128. || }
  1129. || } else if (Z_MODE(dst_addr) == IS_REG) {
  1130. | GET_ZVAL_LVAL Z_REG(dst_addr), src_addr, Rx(tmp_reg)
  1131. || if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != Z_REG(dst_addr)) {
  1132. | SET_ZVAL_LVAL_FROM_REG res_addr, Rx(Z_REG(dst_addr)), Rx(tmp_reg)
  1133. || }
  1134. || } else if (Z_MODE(res_addr) == IS_REG) {
  1135. | GET_ZVAL_LVAL Z_REG(res_addr), src_addr, Rx(tmp_reg)
  1136. | SET_ZVAL_LVAL_FROM_REG dst_addr, Rx(Z_REG(res_addr)), Rx(tmp_reg)
  1137. || } else {
  1138. | GET_ZVAL_LVAL reg2, src_addr, Rx(tmp_reg)
  1139. | SET_ZVAL_LVAL_FROM_REG dst_addr, Rx(reg2), Rx(tmp_reg)
  1140. | SET_ZVAL_LVAL_FROM_REG res_addr, Rx(reg2), Rx(tmp_reg)
  1141. || }
  1142. || } else if ((src_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
  1143. || if (Z_MODE(src_addr) == IS_REG) {
  1144. | SET_ZVAL_DVAL dst_addr, Z_REG(src_addr), tmp_reg
  1145. | SET_ZVAL_DVAL res_addr, Z_REG(src_addr), tmp_reg
  1146. || } else if (Z_MODE(dst_addr) == IS_REG) {
  1147. | GET_ZVAL_DVAL Z_REG(dst_addr), src_addr, tmp_reg
  1148. | SET_ZVAL_DVAL res_addr, Z_REG(dst_addr), tmp_reg
  1149. || } else if (Z_MODE(res_addr) == IS_REG) {
  1150. | GET_ZVAL_DVAL Z_REG(res_addr), src_addr, tmp_reg
  1151. | SET_ZVAL_DVAL dst_addr, Z_REG(res_addr), tmp_reg
  1152. || } else {
  1153. | GET_ZVAL_DVAL fp_tmp_reg, src_addr, tmp_reg
  1154. | SET_ZVAL_DVAL dst_addr, fp_tmp_reg, tmp_reg
  1155. | SET_ZVAL_DVAL res_addr, fp_tmp_reg, tmp_reg
  1156. || }
  1157. || } else {
  1158. | GET_ZVAL_PTR Rx(reg2), src_addr, Rx(tmp_reg)
  1159. | SET_ZVAL_PTR dst_addr, Rx(reg2), Rx(tmp_reg)
  1160. | SET_ZVAL_PTR res_addr, Rx(reg2), Rx(tmp_reg)
  1161. || }
  1162. || }
  1163. || if ((src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)) &&
  1164. || has_concrete_type(src_info & MAY_BE_ANY)) {
  1165. || uint32_t type = concrete_type(src_info);
  1166. || if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
  1167. || if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
  1168. | SET_ZVAL_TYPE_INFO dst_addr, type, Rw(tmp_reg), Rx(tmp_reg2)
  1169. || }
  1170. || }
  1171. || if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
  1172. | SET_ZVAL_TYPE_INFO res_addr, type, Rw(tmp_reg), Rx(tmp_reg2)
  1173. || }
  1174. || } else {
  1175. | GET_ZVAL_TYPE_INFO Rw(reg1), src_addr, Rx(tmp_reg)
  1176. | SET_ZVAL_TYPE_INFO_FROM_REG dst_addr, Rw(reg1), Rx(tmp_reg)
  1177. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, Rw(reg1), Rx(tmp_reg)
  1178. || }
  1179. |.endmacro
  1180. |.macro IF_UNDEF, type_reg, label
  1181. | cbz type_reg, label
  1182. |.endmacro
  1183. |.macro IF_TYPE, type, val, label
  1184. || if (val == 0) {
  1185. | cbz type, label
  1186. || } else {
  1187. | cmp type, #val
  1188. | beq label
  1189. || }
  1190. |.endmacro
  1191. |.macro IF_NOT_TYPE, type, val, label
  1192. || if (val == 0) {
  1193. | cbnz type, label
  1194. || } else {
  1195. | cmp type, #val
  1196. | bne label
  1197. || }
  1198. |.endmacro
  1199. |.macro IF_Z_TYPE, zv, val, label, tmp_reg
  1200. | ldrb tmp_reg, [zv, #offsetof(zval, u1.v.type)]
  1201. | IF_TYPE tmp_reg, val, label
  1202. |.endmacro
  1203. |.macro IF_NOT_Z_TYPE, zv, val, label, tmp_reg
  1204. | ldrb tmp_reg, [zv, #offsetof(zval, u1.v.type)]
  1205. | IF_NOT_TYPE tmp_reg, val, label
  1206. |.endmacro
  1207. |.macro CMP_ZVAL_TYPE, addr, val, tmp_reg
  1208. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  1209. | MEM_ACCESS_8_WITH_UOFFSET ldrb, Rw(tmp_reg), Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval, u1.v.type), Rx(tmp_reg)
  1210. | cmp Rw(tmp_reg), #val
  1211. |.endmacro
  1212. |.macro IF_ZVAL_TYPE, addr, val, label, tmp_reg
  1213. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  1214. | MEM_ACCESS_8_WITH_UOFFSET ldrb, Rw(tmp_reg), Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval, u1.v.type), Rx(tmp_reg)
  1215. | IF_TYPE Rw(tmp_reg), val, label
  1216. |.endmacro
  1217. |.macro IF_NOT_ZVAL_TYPE, addr, val, label, tmp_reg
  1218. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  1219. | MEM_ACCESS_8_WITH_UOFFSET ldrb, Rw(tmp_reg), Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval, u1.v.type), Rx(tmp_reg)
  1220. | IF_NOT_TYPE Rw(tmp_reg), val, label
  1221. |.endmacro
  1222. |.macro IF_FLAGS, type_flags, mask, label, tmp_reg
  1223. | TST_32_WITH_CONST type_flags, mask, tmp_reg
  1224. | bne label
  1225. |.endmacro
  1226. |.macro IF_NOT_FLAGS, type_flags, mask, label, tmp_reg
  1227. | TST_32_WITH_CONST type_flags, mask, tmp_reg
  1228. | beq label
  1229. |.endmacro
  1230. |.macro IF_REFCOUNTED, type_flags, label, tmp_reg
  1231. | TST_32_WITH_CONST type_flags, (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT), tmp_reg
  1232. | bne label
  1233. |.endmacro
  1234. |.macro IF_NOT_REFCOUNTED, type_flags, label, tmp_reg
  1235. | TST_32_WITH_CONST type_flags, (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT), tmp_reg
  1236. | beq label
  1237. |.endmacro
  1238. |.macro IF_ZVAL_FLAGS, addr, mask, label, tmp_reg1, tmp_reg2
  1239. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  1240. | MEM_ACCESS_8_WITH_UOFFSET ldrb, Rw(tmp_reg1), Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval, u1.v.type_flags), Rx(tmp_reg2)
  1241. | IF_FLAGS Rw(tmp_reg1), mask, label, Rw(tmp_reg2)
  1242. |.endmacro
  1243. |.macro IF_NOT_ZVAL_FLAGS, addr, mask, label, tmp_reg1, tmp_reg2
  1244. || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
  1245. | MEM_ACCESS_8_WITH_UOFFSET ldrb, Rw(tmp_reg1), Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval, u1.v.type_flags), Rx(tmp_reg2)
  1246. | IF_NOT_FLAGS Rw(tmp_reg1), mask, label, Rw(tmp_reg2)
  1247. |.endmacro
  1248. |.macro IF_ZVAL_REFCOUNTED, addr, label, tmp_reg1, tmp_reg2
  1249. | IF_ZVAL_FLAGS addr, IS_TYPE_REFCOUNTED, label, tmp_reg1, tmp_reg2
  1250. |.endmacro
  1251. |.macro IF_NOT_ZVAL_REFCOUNTED, addr, label, tmp_reg1, tmp_reg2
  1252. | IF_NOT_ZVAL_FLAGS addr, IS_TYPE_REFCOUNTED, label, tmp_reg1, tmp_reg2
  1253. |.endmacro
  1254. |.macro IF_NOT_ZVAL_COLLECTABLE, addr, label, tmp_reg1, tmp_reg2
  1255. | IF_NOT_ZVAL_FLAGS addr, IS_TYPE_COLLECTABLE, label, tmp_reg1, tmp_reg2
  1256. |.endmacro
  1257. |.macro GC_ADDREF, zv, tmp_reg
  1258. | ldr tmp_reg, [zv]
  1259. | add tmp_reg, tmp_reg, #1
  1260. | str tmp_reg, [zv]
  1261. |.endmacro
  1262. |.macro GC_ADDREF_2, zv, tmp_reg
  1263. | ldr tmp_reg, [zv]
  1264. | add tmp_reg, tmp_reg, #2
  1265. | str tmp_reg, [zv]
  1266. |.endmacro
  1267. |.macro GC_DELREF, zv, tmp_reg
  1268. | ldr tmp_reg, [zv]
  1269. | subs tmp_reg, tmp_reg, #1
  1270. | str tmp_reg, [zv]
  1271. |.endmacro
  1272. |.macro IF_GC_MAY_NOT_LEAK, ptr, label, tmp_reg1, tmp_reg2
  1273. | ldr tmp_reg1, [ptr, #4]
  1274. | TST_32_WITH_CONST tmp_reg1, (GC_INFO_MASK | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)), tmp_reg2
  1275. | bne label
  1276. |.endmacro
  1277. |.macro ADDREF_CONST, zv, tmp_reg1, tmp_reg2
  1278. | LOAD_ADDR tmp_reg1, Z_PTR_P(zv)
  1279. | ldr tmp_reg2, [tmp_reg1]
  1280. | add tmp_reg2, tmp_reg2, #1
  1281. | str tmp_reg2, [tmp_reg1]
  1282. |.endmacro
  1283. |.macro ADDREF_CONST_2, zv, tmp_reg1, tmp_reg2
  1284. | LOAD_ADDR tmp_reg1, Z_PTR_P(zv)
  1285. | ldr tmp_reg2, [tmp_reg1]
  1286. | add tmp_reg2, tmp_reg2, #2
  1287. | str tmp_reg2, [tmp_reg1]
  1288. |.endmacro
  1289. |.macro TRY_ADDREF, val_info, type_flags_reg, value_ptr_reg, tmp_reg
  1290. || if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
  1291. || if (val_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  1292. | IF_NOT_REFCOUNTED type_flags_reg, >1, tmp_reg
  1293. || }
  1294. | GC_ADDREF value_ptr_reg, tmp_reg
  1295. |1:
  1296. || }
  1297. |.endmacro
  1298. |.macro TRY_ADDREF_2, val_info, type_flags_reg, value_ptr_reg, tmp_reg
  1299. || if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
  1300. || if (val_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  1301. | IF_NOT_REFCOUNTED type_flags_reg, >1, tmp_reg
  1302. || }
  1303. | ldr tmp_reg, [value_ptr_reg]
  1304. | add tmp_reg, tmp_reg, #2
  1305. | str tmp_reg, [value_ptr_reg]
  1306. |1:
  1307. || }
  1308. |.endmacro
  1309. |.macro ZVAL_DEREF, reg, info, tmp_reg
  1310. || if (info & MAY_BE_REF) {
  1311. | IF_NOT_Z_TYPE, reg, IS_REFERENCE, >1, tmp_reg
  1312. | GET_Z_PTR reg, reg
  1313. | add reg, reg, #offsetof(zend_reference, val)
  1314. |1:
  1315. || }
  1316. |.endmacro
  1317. |.macro SET_EX_OPLINE, op, tmp_reg
  1318. || if (op == last_valid_opline) {
  1319. || zend_jit_use_last_valid_opline();
  1320. | SAVE_IP
  1321. || } else {
  1322. | ADDR_STORE EX->opline, op, tmp_reg
  1323. || if (!GCC_GLOBAL_REGS) {
  1324. || zend_jit_reset_last_valid_opline();
  1325. || }
  1326. || }
  1327. |.endmacro
  1328. // arg1 "zval" should be in FCARG1x
  1329. |.macro ZVAL_DTOR_FUNC, var_info, opline, tmp_reg
  1330. || do {
  1331. || if (!((var_info) & MAY_BE_GUARD)
  1332. || && has_concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  1333. || zend_uchar type = concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
  1334. || if (type == IS_STRING && !ZEND_DEBUG) {
  1335. | EXT_CALL _efree, tmp_reg
  1336. || break;
  1337. || } else if (type == IS_ARRAY) {
  1338. || if ((var_info) & (MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF)) {
  1339. || if (opline && ((var_info) & (MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF))) {
  1340. | SET_EX_OPLINE opline, tmp_reg
  1341. || }
  1342. | EXT_CALL zend_array_destroy, tmp_reg
  1343. || } else {
  1344. | EXT_CALL zend_jit_array_free, tmp_reg
  1345. || }
  1346. || break;
  1347. || } else if (type == IS_OBJECT) {
  1348. || if (opline) {
  1349. | SET_EX_OPLINE opline, REG0
  1350. || }
  1351. | EXT_CALL zend_objects_store_del, tmp_reg
  1352. || break;
  1353. || }
  1354. || }
  1355. || if (opline) {
  1356. | SET_EX_OPLINE opline, tmp_reg
  1357. || }
  1358. | EXT_CALL rc_dtor_func, tmp_reg
  1359. || } while(0);
  1360. |.endmacro
  1361. |.macro ZVAL_PTR_DTOR, addr, op_info, gc, cold, opline, tmp_reg1, tmp_reg2
  1362. || if ((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF|MAY_BE_GUARD)) {
  1363. || if ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_INDIRECT|MAY_BE_GUARD)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  1364. | // if (Z_REFCOUNTED_P(cv)) {
  1365. || if (cold) {
  1366. | IF_ZVAL_REFCOUNTED addr, >1, tmp_reg1, tmp_reg2
  1367. |.cold_code
  1368. |1:
  1369. || } else {
  1370. | IF_NOT_ZVAL_REFCOUNTED addr, >4, tmp_reg1, tmp_reg2
  1371. || }
  1372. || }
  1373. | // if (!Z_DELREF_P(cv)) {
  1374. | GET_ZVAL_PTR FCARG1x, addr, Rx(tmp_reg2)
  1375. | GC_DELREF FCARG1x, Rw(tmp_reg1)
  1376. || if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_1(op_info)) {
  1377. || if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_N(op_info)) {
  1378. || if (gc && (((op_info) & MAY_BE_GUARD) || (RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0))) {
  1379. | bne >3
  1380. || } else {
  1381. | bne >4
  1382. || }
  1383. || }
  1384. | // zval_dtor_func(r);
  1385. | ZVAL_DTOR_FUNC op_info, opline, Rx(tmp_reg1)
  1386. || if (gc && (((op_info) & MAY_BE_GUARD) || (RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0))) {
  1387. | b >4
  1388. || }
  1389. |3:
  1390. || }
  1391. || if (gc && (((op_info) & MAY_BE_GUARD) || (RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0))) {
  1392. || if ((op_info) & (MAY_BE_REF|MAY_BE_GUARD)) {
  1393. || zend_jit_addr ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, offsetof(zend_reference, val));
  1394. | IF_NOT_ZVAL_TYPE addr, IS_REFERENCE, >1, tmp_reg1
  1395. | IF_NOT_ZVAL_COLLECTABLE ref_addr, >4, tmp_reg1, tmp_reg2
  1396. | GET_ZVAL_PTR FCARG1x, ref_addr, Rx(tmp_reg2)
  1397. |1:
  1398. || }
  1399. | IF_GC_MAY_NOT_LEAK FCARG1x, >4, Rw(tmp_reg1), Rw(tmp_reg2)
  1400. | // gc_possible_root(Z_COUNTED_P(z))
  1401. | EXT_CALL gc_possible_root, Rx(tmp_reg1)
  1402. || }
  1403. || if (cold && ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_INDIRECT|MAY_BE_GUARD)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) != 0) {
  1404. | b >4
  1405. |.code
  1406. || }
  1407. |4:
  1408. || }
  1409. |.endmacro
  1410. |.macro FREE_OP, op_type, op, op_info, cold, opline, tmp_reg1, tmp_reg2
  1411. || if (op_type & (IS_VAR|IS_TMP_VAR)) {
  1412. || zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
  1413. | ZVAL_PTR_DTOR addr, op_info, 0, cold, opline, tmp_reg1, tmp_reg2
  1414. || }
  1415. |.endmacro
  1416. |.macro SEPARATE_ARRAY, addr, op_info, cold, tmp_reg1, tmp_reg2
  1417. || if (RC_MAY_BE_N(op_info)) {
  1418. || if (Z_REG(addr) != ZREG_FP) {
  1419. | GET_ZVAL_LVAL ZREG_REG0, addr, Rx(tmp_reg1)
  1420. || if (RC_MAY_BE_1(op_info)) {
  1421. | // if (GC_REFCOUNT() > 1)
  1422. | ldr Rw(tmp_reg1), [REG0]
  1423. | cmp Rw(tmp_reg1), #1
  1424. | bls >2
  1425. || }
  1426. || if (Z_REG(addr) != ZREG_FCARG1 || Z_OFFSET(addr) != 0) {
  1427. | LOAD_ZVAL_ADDR FCARG1x, addr
  1428. || }
  1429. | EXT_CALL zend_jit_zval_array_dup, REG0
  1430. | mov REG0, RETVALx
  1431. |2:
  1432. | mov FCARG1x, REG0
  1433. || } else {
  1434. | GET_ZVAL_LVAL ZREG_FCARG1, addr, Rx(tmp_reg1)
  1435. || if (RC_MAY_BE_1(op_info)) {
  1436. | // if (GC_REFCOUNT() > 1)
  1437. | ldr Rw(tmp_reg1), [FCARG1x]
  1438. | cmp Rw(tmp_reg1), #1
  1439. || if (cold) {
  1440. | bhi >1
  1441. |.cold_code
  1442. |1:
  1443. || } else {
  1444. | bls >2
  1445. || }
  1446. || }
  1447. | IF_NOT_ZVAL_REFCOUNTED addr, >1, tmp_reg1, tmp_reg2
  1448. | GC_DELREF FCARG1x, Rw(tmp_reg1)
  1449. |1:
  1450. | EXT_CALL zend_array_dup, REG0
  1451. | mov REG0, RETVALx
  1452. | SET_ZVAL_PTR addr, REG0, Rx(tmp_reg1)
  1453. | SET_ZVAL_TYPE_INFO addr, IS_ARRAY_EX, Rw(tmp_reg1), Rx(tmp_reg2)
  1454. | mov FCARG1x, REG0
  1455. || if (RC_MAY_BE_1(op_info)) {
  1456. || if (cold) {
  1457. | b >2
  1458. |.code
  1459. || }
  1460. || }
  1461. |2:
  1462. || }
  1463. || } else {
  1464. | GET_ZVAL_LVAL ZREG_FCARG1, addr, Rx(tmp_reg1)
  1465. || }
  1466. |.endmacro
  1467. /* argument is passed in FCARG1x */
  1468. |.macro EFREE_REFERENCE
  1469. ||#if ZEND_DEBUG
  1470. | mov FCARG2x, xzr // filename
  1471. | mov CARG3w, wzr // lineno
  1472. | mov CARG4, xzr
  1473. | mov CARG5, xzr
  1474. | EXT_CALL _efree, REG0
  1475. ||#else
  1476. ||#ifdef HAVE_BUILTIN_CONSTANT_P
  1477. | EXT_CALL _efree_32, REG0
  1478. ||#else
  1479. | EXT_CALL _efree, REG0
  1480. ||#endif
  1481. ||#endif
  1482. |.endmacro
  1483. |.macro EMALLOC, size, op_array, opline
  1484. ||#if ZEND_DEBUG
  1485. || const char *filename = op_array->filename ? op_array->filename->val : NULL;
  1486. | mov FCARG1x, #size
  1487. | LOAD_ADDR FCARG2x, filename
  1488. | LOAD_32BIT_VAL CARG3w, opline->lineno
  1489. | mov CARG4, xzr
  1490. | mov CARG5, xzr
  1491. | EXT_CALL _emalloc, REG0
  1492. | mov REG0, RETVALx
  1493. ||#else
  1494. ||#ifdef HAVE_BUILTIN_CONSTANT_P
  1495. || if (size > 24 && size <= 32) {
  1496. | EXT_CALL _emalloc_32, REG0
  1497. | mov REG0, RETVALx
  1498. || } else {
  1499. | mov FCARG1x, #size
  1500. | EXT_CALL _emalloc, REG0
  1501. | mov REG0, RETVALx
  1502. || }
  1503. ||#else
  1504. | mov FCARG1x, #size
  1505. | EXT_CALL _emalloc, REG0
  1506. | mov REG0, RETVALx
  1507. ||#endif
  1508. ||#endif
  1509. |.endmacro
  1510. |.macro OBJ_RELEASE, reg, exit_label, tmp_reg1, tmp_reg2
  1511. | GC_DELREF Rx(reg), Rw(tmp_reg1)
  1512. | bne >1
  1513. | // zend_objects_store_del(obj);
  1514. || if (reg != ZREG_FCARG1) {
  1515. | mov FCARG1x, Rx(reg)
  1516. || }
  1517. | EXT_CALL zend_objects_store_del, Rx(tmp_reg1)
  1518. | b exit_label
  1519. |1:
  1520. | IF_GC_MAY_NOT_LEAK Rx(reg), >1, Rw(tmp_reg1), Rw(tmp_reg2)
  1521. | // gc_possible_root(obj)
  1522. || if (reg != ZREG_FCARG1) {
  1523. | mov FCARG1x, Rx(reg)
  1524. || }
  1525. | EXT_CALL gc_possible_root, Rx(tmp_reg1)
  1526. |1:
  1527. |.endmacro
  1528. |.macro UNDEFINED_OFFSET, opline
  1529. || if (opline == last_valid_opline) {
  1530. || zend_jit_use_last_valid_opline();
  1531. | bl ->undefined_offset_ex
  1532. || } else {
  1533. | SET_EX_OPLINE opline, REG0
  1534. | bl ->undefined_offset
  1535. || }
  1536. |.endmacro
  1537. |.macro UNDEFINED_INDEX, opline
  1538. || if (opline == last_valid_opline) {
  1539. || zend_jit_use_last_valid_opline();
  1540. | bl ->undefined_index_ex
  1541. || } else {
  1542. | SET_EX_OPLINE opline, REG0
  1543. | bl ->undefined_index
  1544. || }
  1545. |.endmacro
  1546. |.macro CANNOT_ADD_ELEMENT, opline
  1547. || if (opline == last_valid_opline) {
  1548. || zend_jit_use_last_valid_opline();
  1549. | bl ->cannot_add_element_ex
  1550. || } else {
  1551. | SET_EX_OPLINE opline, REG0
  1552. | bl ->cannot_add_element
  1553. || }
  1554. |.endmacro
  1555. static bool reuse_ip = 0;
  1556. static bool delayed_call_chain = 0;
  1557. static uint32_t delayed_call_level = 0;
  1558. static const zend_op *last_valid_opline = NULL;
  1559. static bool use_last_vald_opline = 0;
  1560. static bool track_last_valid_opline = 0;
  1561. static int jit_return_label = -1;
  1562. static uint32_t current_trace_num = 0;
  1563. static uint32_t allowed_opt_flags = 0;
  1564. static void zend_jit_track_last_valid_opline(void)
  1565. {
  1566. use_last_vald_opline = 0;
  1567. track_last_valid_opline = 1;
  1568. }
  1569. static void zend_jit_use_last_valid_opline(void)
  1570. {
  1571. if (track_last_valid_opline) {
  1572. use_last_vald_opline = 1;
  1573. track_last_valid_opline = 0;
  1574. }
  1575. }
  1576. static bool zend_jit_trace_uses_initial_ip(void)
  1577. {
  1578. return use_last_vald_opline;
  1579. }
  1580. static void zend_jit_set_last_valid_opline(const zend_op *target_opline)
  1581. {
  1582. if (!reuse_ip) {
  1583. track_last_valid_opline = 0;
  1584. last_valid_opline = target_opline;
  1585. }
  1586. }
  1587. static void zend_jit_reset_last_valid_opline(void)
  1588. {
  1589. track_last_valid_opline = 0;
  1590. last_valid_opline = NULL;
  1591. }
  1592. static void zend_jit_start_reuse_ip(void)
  1593. {
  1594. zend_jit_reset_last_valid_opline();
  1595. reuse_ip = 1;
  1596. }
  1597. static int zend_jit_reuse_ip(dasm_State **Dst)
  1598. {
  1599. if (!reuse_ip) {
  1600. zend_jit_start_reuse_ip();
  1601. | // call = EX(call);
  1602. | ldr RX, EX->call
  1603. }
  1604. return 1;
  1605. }
  1606. static void zend_jit_stop_reuse_ip(void)
  1607. {
  1608. reuse_ip = 0;
  1609. }
  1610. static int zend_jit_interrupt_handler_stub(dasm_State **Dst)
  1611. {
  1612. |->interrupt_handler:
  1613. | SAVE_IP
  1614. | //EG(vm_interrupt) = 0;
  1615. | MEM_STORE_8_ZTS strb, wzr, executor_globals, vm_interrupt, TMP1
  1616. | //if (EG(timed_out)) {
  1617. | MEM_LOAD_8_ZTS ldrb, TMP1w, executor_globals, timed_out, TMP1
  1618. | cbz TMP1w, >1
  1619. | //zend_timeout();
  1620. | EXT_CALL zend_timeout, TMP1
  1621. |1:
  1622. | //} else if (zend_interrupt_function) {
  1623. if (zend_interrupt_function) {
  1624. | //zend_interrupt_function(execute_data);
  1625. | mov CARG1, FP
  1626. | EXT_CALL zend_interrupt_function, TMP1
  1627. | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1
  1628. | cbz REG0, >1
  1629. | EXT_CALL zend_jit_exception_in_interrupt_handler_helper, TMP1
  1630. |1:
  1631. | //ZEND_VM_ENTER();
  1632. | //execute_data = EG(current_execute_data);
  1633. | MEM_LOAD_64_ZTS ldr, FP, executor_globals, current_execute_data, TMP1
  1634. | LOAD_IP
  1635. }
  1636. | //ZEND_VM_CONTINUE()
  1637. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  1638. | ADD_HYBRID_SPAD
  1639. | JMP_IP TMP1
  1640. } else if (GCC_GLOBAL_REGS) {
  1641. | ldp x29, x30, [sp], # SPAD // stack alignment
  1642. | JMP_IP TMP1
  1643. } else {
  1644. | ldp FP, RX, T2 // retore FP and IP
  1645. | ldp x29, x30, [sp], # NR_SPAD // stack alignment
  1646. | mov RETVALx, #1 // ZEND_VM_ENTER
  1647. | ret
  1648. }
  1649. return 1;
  1650. }
  1651. static int zend_jit_exception_handler_stub(dasm_State **Dst)
  1652. {
  1653. |->exception_handler:
  1654. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  1655. const void *handler = zend_get_opcode_handler_func(EG(exception_op));
  1656. | ADD_HYBRID_SPAD
  1657. | EXT_CALL handler, REG0
  1658. | JMP_IP TMP1
  1659. } else {
  1660. const void *handler = EG(exception_op)->handler;
  1661. if (GCC_GLOBAL_REGS) {
  1662. | ldp x29, x30, [sp], # SPAD // stack alignment
  1663. | EXT_JMP handler, REG0
  1664. } else {
  1665. | mov FCARG1x, FP
  1666. | EXT_CALL handler, REG0
  1667. | ldp FP, RX, T2 // retore FP and IP
  1668. | ldp x29, x30, [sp], # NR_SPAD // stack alignment
  1669. | tbnz RETVALw, #31, >1
  1670. | mov RETVALw, #1 // ZEND_VM_ENTER
  1671. |1:
  1672. | ret
  1673. }
  1674. }
  1675. return 1;
  1676. }
  1677. static int zend_jit_exception_handler_undef_stub(dasm_State **Dst)
  1678. {
  1679. |->exception_handler_undef:
  1680. | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, opline_before_exception, REG0
  1681. | ldrb TMP1w, OP:REG0->result_type
  1682. | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w
  1683. | beq >1
  1684. | ldr REG0w, OP:REG0->result.var
  1685. | add REG0, REG0, FP
  1686. | SET_Z_TYPE_INFO REG0, IS_UNDEF, TMP1w
  1687. |1:
  1688. | b ->exception_handler
  1689. return 1;
  1690. }
  1691. static int zend_jit_exception_handler_free_op1_op2_stub(dasm_State **Dst)
  1692. {
  1693. zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  1694. |->exception_handler_free_op1_op2:
  1695. | UNDEF_OPLINE_RESULT_IF_USED TMP1w, TMP2w
  1696. | ldrb TMP1w, OP:RX->op1_type
  1697. | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w
  1698. | beq >9
  1699. | ldr REG0w, OP:RX->op1.var
  1700. | add REG0, REG0, FP
  1701. | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2
  1702. |9:
  1703. | ldrb TMP1w, OP:RX->op2_type
  1704. | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w
  1705. | beq >9
  1706. | ldr REG0w, OP:RX->op2.var
  1707. | add REG0, REG0, FP
  1708. | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2
  1709. |9:
  1710. | b ->exception_handler
  1711. return 1;
  1712. }
  1713. static int zend_jit_exception_handler_free_op2_stub(dasm_State **Dst)
  1714. {
  1715. zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  1716. |->exception_handler_free_op2:
  1717. | MEM_LOAD_64_ZTS ldr, RX, executor_globals, opline_before_exception, REG0
  1718. | UNDEF_OPLINE_RESULT_IF_USED TMP1w, TMP2w
  1719. | ldrb TMP1w, OP:RX->op2_type
  1720. | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w
  1721. | beq >9
  1722. | ldr REG0w, OP:RX->op2.var
  1723. | add REG0, REG0, FP
  1724. | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2
  1725. |9:
  1726. | b ->exception_handler
  1727. return 1;
  1728. }
  1729. static int zend_jit_leave_function_stub(dasm_State **Dst)
  1730. {
  1731. |->leave_function_handler:
  1732. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  1733. | TST_32_WITH_CONST FCARG1w, ZEND_CALL_TOP, TMP1w
  1734. | bne >1
  1735. | EXT_CALL zend_jit_leave_nested_func_helper, REG0
  1736. | ADD_HYBRID_SPAD
  1737. | JMP_IP TMP1
  1738. |1:
  1739. | EXT_CALL zend_jit_leave_top_func_helper, REG0
  1740. | ADD_HYBRID_SPAD
  1741. | JMP_IP TMP1
  1742. } else {
  1743. if (GCC_GLOBAL_REGS) {
  1744. | ldp x29, x30, [sp], # SPAD // stack alignment
  1745. } else {
  1746. | mov FCARG2x, FP
  1747. | ldp FP, RX, T2 // retore FP and IP
  1748. | ldp x29, x30, [sp], # NR_SPAD // stack alignment
  1749. }
  1750. | TST_32_WITH_CONST FCARG1w, ZEND_CALL_TOP, TMP1w
  1751. | bne >1
  1752. | EXT_JMP zend_jit_leave_nested_func_helper, REG0
  1753. |1:
  1754. | EXT_JMP zend_jit_leave_top_func_helper, REG0
  1755. }
  1756. return 1;
  1757. }
  1758. static int zend_jit_leave_throw_stub(dasm_State **Dst)
  1759. {
  1760. |->leave_throw_handler:
  1761. | // if (opline->opcode != ZEND_HANDLE_EXCEPTION) {
  1762. if (GCC_GLOBAL_REGS) {
  1763. | ldrb TMP1w, OP:IP->opcode
  1764. | cmp TMP1w, #ZEND_HANDLE_EXCEPTION
  1765. | beq >5
  1766. | // EG(opline_before_exception) = opline;
  1767. | MEM_STORE_64_ZTS str, IP, executor_globals, opline_before_exception, TMP2
  1768. |5:
  1769. | // opline = EG(exception_op);
  1770. | LOAD_IP_ADDR_ZTS executor_globals, exception_op, TMP2
  1771. | // HANDLE_EXCEPTION()
  1772. | b ->exception_handler
  1773. } else {
  1774. | GET_IP TMP1
  1775. | ldrb TMP2w, OP:TMP1->opcode
  1776. | cmp TMP2w, #ZEND_HANDLE_EXCEPTION
  1777. | beq >5
  1778. | // EG(opline_before_exception) = opline;
  1779. | MEM_STORE_64_ZTS str, TMP1, executor_globals, opline_before_exception, TMP2
  1780. |5:
  1781. | // opline = EG(exception_op);
  1782. | LOAD_IP_ADDR_ZTS executor_globals, exception_op, TMP2
  1783. | ldp FP, RX, T2 // retore FP and IP
  1784. | ldp x29, x30, [sp], # NR_SPAD // stack alignment
  1785. | mov RETVALx, #2 // ZEND_VM_LEAVE
  1786. | ret
  1787. }
  1788. return 1;
  1789. }
  1790. static int zend_jit_icall_throw_stub(dasm_State **Dst)
  1791. {
  1792. |->icall_throw_handler:
  1793. | // zend_rethrow_exception(zend_execute_data *execute_data)
  1794. | ldr IP, EX->opline
  1795. | // if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) {
  1796. | ldrb TMP1w, OP:IP->opcode
  1797. | cmp TMP1w, #ZEND_HANDLE_EXCEPTION
  1798. | beq >1
  1799. | // EG(opline_before_exception) = opline;
  1800. | MEM_STORE_64_ZTS str, IP, executor_globals, opline_before_exception, TMP2
  1801. |1:
  1802. | // opline = EG(exception_op);
  1803. | LOAD_IP_ADDR_ZTS executor_globals, exception_op, TMP2
  1804. || if (GCC_GLOBAL_REGS) {
  1805. | str IP, EX->opline
  1806. || }
  1807. | // HANDLE_EXCEPTION()
  1808. | b ->exception_handler
  1809. return 1;
  1810. }
  1811. static int zend_jit_throw_cannot_pass_by_ref_stub(dasm_State **Dst)
  1812. {
  1813. zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  1814. |->throw_cannot_pass_by_ref:
  1815. | ldr REG0, EX->opline
  1816. | ldr REG1w, OP:REG0->result.var
  1817. | add REG1, REG1, RX
  1818. | SET_Z_TYPE_INFO REG1, IS_UNDEF, TMP1w
  1819. | // last EX(call) frame may be delayed
  1820. | ldr TMP1, EX->call
  1821. | cmp RX, TMP1
  1822. | beq >1
  1823. | ldr REG1, EX->call
  1824. | str REG1, EX:RX->prev_execute_data
  1825. | str RX, EX->call
  1826. |1:
  1827. | mov RX, REG0
  1828. | ldr FCARG1w, OP:REG0->op2.num
  1829. | EXT_CALL zend_cannot_pass_by_reference, REG0
  1830. | ldrb TMP1w, OP:RX->op1_type
  1831. | cmp TMP1w, #IS_TMP_VAR
  1832. | bne >9
  1833. | ldr REG0w, OP:RX->op1.var
  1834. | add REG0, REG0, FP
  1835. | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2
  1836. |9:
  1837. | b ->exception_handler
  1838. return 1;
  1839. }
  1840. static int zend_jit_undefined_offset_ex_stub(dasm_State **Dst)
  1841. {
  1842. |->undefined_offset_ex:
  1843. | SAVE_IP
  1844. | b ->undefined_offset
  1845. return 1;
  1846. }
  1847. static int zend_jit_undefined_offset_stub(dasm_State **Dst)
  1848. {
  1849. |->undefined_offset:
  1850. #ifdef __APPLE__
  1851. | stp x29, x30, [sp, # -16]!
  1852. | mov x29, sp
  1853. #endif
  1854. | //sub r4, 8
  1855. | ldr REG0, EX->opline
  1856. | ldr REG1w, OP:REG0->result.var
  1857. | add REG1, REG1, FP
  1858. | SET_Z_TYPE_INFO REG1, IS_NULL, TMP1w
  1859. | ldrb REG1w, OP:REG0->op2_type
  1860. | cmp REG1w, #IS_CONST
  1861. | bne >2
  1862. | ldrsw REG1, OP:REG0->op2.constant
  1863. | add REG0, REG0, REG1
  1864. | b >3
  1865. |2:
  1866. | ldr REG0w, OP:REG0->op2.var
  1867. | add REG0, REG0, FP
  1868. |3:
  1869. | mov CARG1, #E_WARNING
  1870. | LOAD_ADDR CARG2, "Undefined array key " ZEND_LONG_FMT
  1871. | ldr CARG3, [REG0]
  1872. #ifdef __APPLE__
  1873. | str CARG3, [sp, #-16]!
  1874. | EXT_CALL zend_error, REG0
  1875. | add sp, sp, #16
  1876. | ldp x29, x30, [sp], #16
  1877. | ret
  1878. #else
  1879. | EXT_JMP zend_error, REG0 // tail call
  1880. | //add r4, 8 // stack alignment
  1881. | //ret
  1882. #endif
  1883. return 1;
  1884. }
  1885. static int zend_jit_undefined_index_ex_stub(dasm_State **Dst)
  1886. {
  1887. |->undefined_index_ex:
  1888. | SAVE_IP
  1889. | b ->undefined_index
  1890. return 1;
  1891. }
  1892. static int zend_jit_undefined_index_stub(dasm_State **Dst)
  1893. {
  1894. |->undefined_index:
  1895. #ifdef __APPLE__
  1896. | stp x29, x30, [sp, # -16]!
  1897. | mov x29, sp
  1898. #endif
  1899. | //sub r4, 8
  1900. | ldr REG0, EX->opline
  1901. | ldr REG1w, OP:REG0->result.var
  1902. | add REG1, REG1, FP
  1903. | SET_Z_TYPE_INFO REG1, IS_NULL, TMP1w
  1904. | ldrb REG1w, OP:REG0->op2_type
  1905. | cmp REG1w, #IS_CONST
  1906. | bne >2
  1907. | ldrsw REG1, OP:REG0->op2.constant
  1908. | add REG0, REG0, REG1
  1909. | b >3
  1910. |2:
  1911. | ldr REG0w, OP:REG0->op2.var
  1912. | add REG0, REG0, FP
  1913. |3:
  1914. | mov CARG1, #E_WARNING
  1915. | LOAD_ADDR CARG2, "Undefined array key \"%s\""
  1916. | ldr CARG3, [REG0]
  1917. | add CARG3, CARG3, #offsetof(zend_string, val)
  1918. #ifdef __APPLE__
  1919. | str CARG3, [sp, #-16]!
  1920. | EXT_CALL zend_error, REG0
  1921. | add sp, sp, #16
  1922. | ldp x29, x30, [sp], #16
  1923. | ret
  1924. #else
  1925. | EXT_JMP zend_error, REG0 // tail call
  1926. | //add r4, 8
  1927. | //ret
  1928. #endif
  1929. return 1;
  1930. }
  1931. static int zend_jit_cannot_add_element_ex_stub(dasm_State **Dst)
  1932. {
  1933. |->cannot_add_element_ex:
  1934. | SAVE_IP
  1935. | b ->cannot_add_element
  1936. return 1;
  1937. }
  1938. static int zend_jit_cannot_add_element_stub(dasm_State **Dst)
  1939. {
  1940. |->cannot_add_element:
  1941. | // sub r4, 8
  1942. | ldr REG0, EX->opline
  1943. | ldrb TMP1w, OP:REG0->result_type
  1944. | cmp TMP1w, #IS_UNUSED
  1945. | beq >1
  1946. | ldr REG0w, OP:REG0->result.var
  1947. | add REG0, REG0, FP
  1948. | SET_Z_TYPE_INFO REG0, IS_NULL, TMP1w
  1949. |1:
  1950. | mov CARG1, xzr
  1951. | LOAD_ADDR CARG2, "Cannot add element to the array as the next element is already occupied"
  1952. | EXT_JMP zend_throw_error, REG0 // tail call
  1953. | // add r4, 8
  1954. | //ret
  1955. return 1;
  1956. }
  1957. static int zend_jit_undefined_function_stub(dasm_State **Dst)
  1958. {
  1959. |->undefined_function:
  1960. | ldr REG0, EX->opline
  1961. | mov CARG1, xzr
  1962. | LOAD_ADDR CARG2, "Call to undefined function %s()"
  1963. | ldrsw CARG3, [REG0, #offsetof(zend_op, op2.constant)]
  1964. | ldr CARG3, [REG0, CARG3]
  1965. | add CARG3, CARG3, #offsetof(zend_string, val)
  1966. #ifdef __APPLE__
  1967. | str CARG3, [sp, #-16]!
  1968. #endif
  1969. | EXT_CALL zend_throw_error, REG0
  1970. #ifdef __APPLE__
  1971. | add sp, sp, #16
  1972. #endif
  1973. | b ->exception_handler
  1974. return 1;
  1975. }
  1976. static int zend_jit_negative_shift_stub(dasm_State **Dst)
  1977. {
  1978. |->negative_shift:
  1979. | ldr RX, EX->opline
  1980. | LOAD_ADDR CARG1, zend_ce_arithmetic_error
  1981. | LOAD_ADDR CARG2, "Bit shift by negative number"
  1982. | EXT_CALL zend_throw_error, REG0
  1983. | b ->exception_handler_free_op1_op2
  1984. return 1;
  1985. }
  1986. static int zend_jit_mod_by_zero_stub(dasm_State **Dst)
  1987. {
  1988. |->mod_by_zero:
  1989. | ldr RX, EX->opline
  1990. | LOAD_ADDR CARG1, zend_ce_division_by_zero_error
  1991. | LOAD_ADDR CARG2, "Modulo by zero"
  1992. | EXT_CALL zend_throw_error, REG0
  1993. | b ->exception_handler_free_op1_op2
  1994. return 1;
  1995. }
  1996. static int zend_jit_invalid_this_stub(dasm_State **Dst)
  1997. {
  1998. |->invalid_this:
  1999. | UNDEF_OPLINE_RESULT TMP1w
  2000. | mov CARG1, xzr
  2001. | LOAD_ADDR CARG2, "Using $this when not in object context"
  2002. | EXT_CALL zend_throw_error, REG0
  2003. | b ->exception_handler
  2004. return 1;
  2005. }
  2006. static int zend_jit_hybrid_runtime_jit_stub(dasm_State **Dst)
  2007. {
  2008. if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
  2009. return 1;
  2010. }
  2011. |->hybrid_runtime_jit:
  2012. | EXT_CALL zend_runtime_jit, REG0
  2013. | JMP_IP TMP1
  2014. return 1;
  2015. }
  2016. static int zend_jit_hybrid_profile_jit_stub(dasm_State **Dst)
  2017. {
  2018. if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
  2019. return 1;
  2020. }
  2021. |->hybrid_profile_jit:
  2022. | // ++zend_jit_profile_counter;
  2023. | LOAD_ADDR REG0, &zend_jit_profile_counter
  2024. | ldr TMP1, [REG0]
  2025. | add TMP1, TMP1, #1
  2026. | str TMP1, [REG0]
  2027. | // op_array = (zend_op_array*)EX(func);
  2028. | ldr REG0, EX->func
  2029. | // run_time_cache = EX(run_time_cache);
  2030. | ldr REG2, EX->run_time_cache
  2031. | // jit_extension = (const void*)ZEND_FUNC_INFO(op_array);
  2032. | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])]
  2033. | // ++ZEND_COUNTER_INFO(op_array)
  2034. || if ((zend_jit_profile_counter_rid * sizeof(void*)) > LDR_STR_PIMM64) {
  2035. | LOAD_32BIT_VAL TMP1, (zend_jit_profile_counter_rid * sizeof(void*))
  2036. | ldr TMP2, [REG2, TMP1]
  2037. | add TMP2, TMP2, #1
  2038. | str TMP2, [REG2, TMP1]
  2039. || } else {
  2040. | ldr TMP2, [REG2, #(zend_jit_profile_counter_rid * sizeof(void*))]
  2041. | add TMP2, TMP2, #1
  2042. | str TMP2, [REG2, #(zend_jit_profile_counter_rid * sizeof(void*))]
  2043. || }
  2044. | // return ((zend_vm_opcode_handler_t)jit_extension->orig_handler)()
  2045. | ldr TMP1, [REG0, #offsetof(zend_jit_op_array_extension, orig_handler)]
  2046. | br TMP1
  2047. return 1;
  2048. }
  2049. static int zend_jit_hybrid_hot_code_stub(dasm_State **Dst)
  2050. {
  2051. if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
  2052. return 1;
  2053. }
  2054. |->hybrid_hot_code:
  2055. || ZEND_ASSERT(ZEND_JIT_COUNTER_INIT <= MOVZ_IMM);
  2056. | movz TMP1w, #ZEND_JIT_COUNTER_INIT
  2057. | strh TMP1w, [REG2]
  2058. | mov FCARG1x, FP
  2059. | GET_IP FCARG2x
  2060. | EXT_CALL zend_jit_hot_func, REG0
  2061. | JMP_IP TMP1
  2062. return 1;
  2063. }
  2064. /*
  2065. * This code is based Mike Pall's "Hashed profile counters" idea, implemented
  2066. * in LuaJIT. The full description may be found in "LuaJIT 2.0 intellectual
  2067. * property disclosure and research opportunities" email
  2068. * at http://lua-users.org/lists/lua-l/2009-11/msg00089.html
  2069. *
  2070. * In addition we use a variation of Knuth's multiplicative hash function
  2071. * described at https://code.i-harness.com/en/q/a21ce
  2072. *
  2073. * uint64_t hash(uint64_t x) {
  2074. * x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
  2075. * x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
  2076. * x = x ^ (x >> 31);
  2077. * return x;
  2078. * }
  2079. *
  2080. * uint_32_t hash(uint32_t x) {
  2081. * x = ((x >> 16) ^ x) * 0x45d9f3b;
  2082. * x = ((x >> 16) ^ x) * 0x45d9f3b;
  2083. * x = (x >> 16) ^ x;
  2084. * return x;
  2085. * }
  2086. *
  2087. */
  2088. static int zend_jit_hybrid_hot_counter_stub(dasm_State **Dst, uint32_t cost)
  2089. {
  2090. | ldr REG0, EX->func
  2091. | ldr REG1, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])]
  2092. | ldr REG2, [REG1, #offsetof(zend_jit_op_array_hot_extension, counter)]
  2093. | ldrh TMP2w, [REG2]
  2094. | ADD_SUB_32_WITH_CONST subs, TMP2w, TMP2w, cost, TMP1w
  2095. | strh TMP2w, [REG2]
  2096. | ble ->hybrid_hot_code
  2097. | GET_IP REG2
  2098. | ldr TMP1, [REG0, #offsetof(zend_op_array, opcodes)]
  2099. | sub REG2, REG2, TMP1
  2100. | // divide by sizeof(zend_op)
  2101. || ZEND_ASSERT(sizeof(zend_op) == 32);
  2102. | add TMP1, REG1, REG2, asr #2
  2103. | ldr TMP1, [TMP1, #offsetof(zend_jit_op_array_hot_extension, orig_handlers)]
  2104. | br TMP1
  2105. return 1;
  2106. }
  2107. static int zend_jit_hybrid_func_hot_counter_stub(dasm_State **Dst)
  2108. {
  2109. if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
  2110. return 1;
  2111. }
  2112. |->hybrid_func_hot_counter:
  2113. return zend_jit_hybrid_hot_counter_stub(Dst,
  2114. ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
  2115. }
  2116. static int zend_jit_hybrid_loop_hot_counter_stub(dasm_State **Dst)
  2117. {
  2118. if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
  2119. return 1;
  2120. }
  2121. |->hybrid_loop_hot_counter:
  2122. return zend_jit_hybrid_hot_counter_stub(Dst,
  2123. ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
  2124. }
  2125. static int zend_jit_hybrid_hot_trace_stub(dasm_State **Dst)
  2126. {
  2127. if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
  2128. return 1;
  2129. }
  2130. // On entry from counter stub:
  2131. // REG2 -> zend_op_trace_info.counter
  2132. |->hybrid_hot_trace:
  2133. | mov TMP1w, #ZEND_JIT_COUNTER_INIT
  2134. | strh TMP1w, [REG2]
  2135. | mov FCARG1x, FP
  2136. | GET_IP FCARG2x
  2137. | EXT_CALL zend_jit_trace_hot_root, REG0
  2138. | tbnz RETVALw, #31, >1 // Result is < 0 on failure.
  2139. | MEM_LOAD_64_ZTS ldr, FP, executor_globals, current_execute_data, REG0
  2140. | LOAD_IP
  2141. | JMP_IP TMP1
  2142. |1:
  2143. | EXT_JMP zend_jit_halt_op->handler, REG0
  2144. return 1;
  2145. }
  2146. static int zend_jit_hybrid_trace_counter_stub(dasm_State **Dst, uint32_t cost)
  2147. {
  2148. | ldr REG0, EX->func
  2149. | ldr REG1, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])]
  2150. | ldr REG1, [REG1, #offsetof(zend_jit_op_array_trace_extension, offset)]
  2151. | add TMP1, REG1, IP
  2152. | ldr REG2, [TMP1, #offsetof(zend_op_trace_info, counter)]
  2153. | ldrh TMP2w, [REG2]
  2154. | ADD_SUB_32_WITH_CONST subs, TMP2w, TMP2w, cost, TMP1w
  2155. | strh TMP2w, [REG2]
  2156. | ble ->hybrid_hot_trace
  2157. // Note: "REG1 + IP" is re-calculated as TMP1 is used as temporary register by the prior
  2158. // ADD_SUB_32_WITH_CONST. Will optimize in the future if more temporary registers are available.
  2159. | add TMP1, REG1, IP
  2160. | ldr TMP2, [TMP1, #offsetof(zend_op_trace_info, orig_handler)]
  2161. | br TMP2
  2162. return 1;
  2163. }
  2164. static int zend_jit_hybrid_func_trace_counter_stub(dasm_State **Dst)
  2165. {
  2166. if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
  2167. return 1;
  2168. }
  2169. |->hybrid_func_trace_counter:
  2170. return zend_jit_hybrid_trace_counter_stub(Dst,
  2171. ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
  2172. }
  2173. static int zend_jit_hybrid_ret_trace_counter_stub(dasm_State **Dst)
  2174. {
  2175. if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_return)) {
  2176. return 1;
  2177. }
  2178. |->hybrid_ret_trace_counter:
  2179. return zend_jit_hybrid_trace_counter_stub(Dst,
  2180. ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_return) - 1) / JIT_G(hot_return)));
  2181. }
  2182. static int zend_jit_hybrid_loop_trace_counter_stub(dasm_State **Dst)
  2183. {
  2184. if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
  2185. return 1;
  2186. }
  2187. |->hybrid_loop_trace_counter:
  2188. return zend_jit_hybrid_trace_counter_stub(Dst,
  2189. ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
  2190. }
  2191. static int zend_jit_trace_halt_stub(dasm_State **Dst)
  2192. {
  2193. |->trace_halt:
  2194. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  2195. | ADD_HYBRID_SPAD
  2196. | EXT_JMP zend_jit_halt_op->handler, REG0
  2197. } else if (GCC_GLOBAL_REGS) {
  2198. | ldp x29, x30, [sp], # SPAD // stack alignment
  2199. | mov IP, xzr // PC must be zero
  2200. | ret
  2201. } else {
  2202. | ldp FP, RX, T2 // retore FP and IP
  2203. | ldp x29, x30, [sp], # NR_SPAD // stack alignment
  2204. | movn RETVALx, #0 // ZEND_VM_RETURN (-1)
  2205. | ret
  2206. }
  2207. return 1;
  2208. }
  2209. static int zend_jit_trace_exit_stub(dasm_State **Dst)
  2210. {
  2211. |->trace_exit:
  2212. |
  2213. | // Save CPU registers(32 GP regs + 32 FP regs) on stack in the order of d31 to x0
  2214. |
  2215. | stp d30, d31, [sp, #-16]!
  2216. | stp d28, d29, [sp, #-16]!
  2217. | stp d26, d27, [sp, #-16]!
  2218. | stp d24, d25, [sp, #-16]!
  2219. | stp d22, d23, [sp, #-16]!
  2220. | stp d20, d21, [sp, #-16]!
  2221. | stp d18, d19, [sp, #-16]!
  2222. | stp d16, d17, [sp, #-16]!
  2223. | //stp d14, d15, [sp, #-16]! // we don't use preserved registers yet
  2224. | //stp d12, d13, [sp, #-16]!
  2225. | //stp d10, d11, [sp, #-16]!
  2226. | //stp d8, d9, [sp, #-16]!
  2227. | stp d6, d7, [sp, #(-16*5)]!
  2228. | stp d4, d5, [sp, #-16]!
  2229. | stp d2, d3, [sp, #-16]!
  2230. | stp d0, d1, [sp, #-16]!
  2231. |
  2232. | //str x30, [sp, #-16]! // we don't use callee-saved registers yet (x31 can be omitted)
  2233. | stp x28, x29, [sp, #(-16*2)]! // we have to store RX (x28)
  2234. | //stp x26, x27, [sp, #-16]! // we don't use callee-saved registers yet
  2235. | //stp x24, x25, [sp, #-16]!
  2236. | //stp x22, x23, [sp, #-16]!
  2237. | //stp x20, x21, [sp, #-16]!
  2238. | //stp x18, x19, [sp, #-16]!
  2239. | //stp x16, x17, [sp, #-16]! // we don't need temporary registers
  2240. | stp x14, x15, [sp, #-(16*7)]!
  2241. | stp x12, x13, [sp, #-16]!
  2242. | stp x10, x11, [sp, #-16]!
  2243. | stp x8, x9, [sp, #-16]!
  2244. | stp x6, x7, [sp, #-16]!
  2245. | stp x4, x5, [sp, #-16]!
  2246. | stp x2, x3, [sp, #-16]!
  2247. | stp x0, x1, [sp, #-16]!
  2248. |
  2249. | mov FCARG1w, TMP1w // exit_num
  2250. | mov FCARG2x, sp
  2251. |
  2252. | // EX(opline) = opline
  2253. | SAVE_IP
  2254. | // zend_jit_trace_exit(trace_num, exit_num)
  2255. | EXT_CALL zend_jit_trace_exit, REG0
  2256. |
  2257. | add sp, sp, #(32 * 16) // restore sp
  2258. |
  2259. | tst RETVALw, RETVALw
  2260. | bne >1 // not zero
  2261. | // execute_data = EG(current_execute_data)
  2262. | MEM_LOAD_64_ZTS ldr, FP, executor_globals, current_execute_data, REG0
  2263. | // opline = EX(opline)
  2264. | LOAD_IP
  2265. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  2266. | ADD_HYBRID_SPAD
  2267. | JMP_IP TMP1
  2268. } else if (GCC_GLOBAL_REGS) {
  2269. | ldp x29, x30, [sp], # SPAD // stack alignment
  2270. | JMP_IP TMP1
  2271. } else {
  2272. | ldp FP, RX, T2 // retore FP and IP
  2273. | ldp x29, x30, [sp], # NR_SPAD // stack alignment
  2274. | mov RETVALx, #1 // ZEND_VM_ENTER
  2275. | ret
  2276. }
  2277. |1:
  2278. | blt ->trace_halt
  2279. | // execute_data = EG(current_execute_data)
  2280. | MEM_LOAD_64_ZTS ldr, FP, executor_globals, current_execute_data, REG0
  2281. | // opline = EX(opline)
  2282. | LOAD_IP
  2283. | // check for interrupt (try to avoid this ???)
  2284. | MEM_LOAD_8_ZTS ldrb, TMP1w, executor_globals, vm_interrupt, TMP1
  2285. | cbnz TMP1w, ->interrupt_handler
  2286. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  2287. | ADD_HYBRID_SPAD
  2288. | ldr REG0, EX->func
  2289. | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])]
  2290. | ldr REG0, [REG0, #offsetof(zend_jit_op_array_trace_extension, offset)]
  2291. | ldr REG0, [IP, REG0]
  2292. | br REG0
  2293. } else if (GCC_GLOBAL_REGS) {
  2294. | ldp x29, x30, [sp], # SPAD // stack alignment
  2295. | ldr REG0, EX->func
  2296. | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])]
  2297. | ldr REG0, [REG0, #offsetof(zend_jit_op_array_trace_extension, offset)]
  2298. | ldr REG0, [IP, REG0]
  2299. | br REG0
  2300. } else {
  2301. | ldr IP, EX->opline
  2302. | mov FCARG1x, FP
  2303. | ldr REG0, EX->func
  2304. | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])]
  2305. | ldr REG0, [REG0, #offsetof(zend_jit_op_array_trace_extension, offset)]
  2306. | ldr REG0, [IP, REG0]
  2307. | blr REG0
  2308. |
  2309. | tst RETVALw, RETVALw
  2310. | blt ->trace_halt
  2311. |
  2312. | ldp FP, RX, T2 // retore FP and IP
  2313. | ldp x29, x30, [sp], # NR_SPAD // stack alignment
  2314. | mov RETVALx, #1 // ZEND_VM_ENTER
  2315. | ret
  2316. }
  2317. return 1;
  2318. }
  2319. static int zend_jit_trace_escape_stub(dasm_State **Dst)
  2320. {
  2321. |->trace_escape:
  2322. |
  2323. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  2324. | ADD_HYBRID_SPAD
  2325. | JMP_IP, TMP1
  2326. } else if (GCC_GLOBAL_REGS) {
  2327. | ldp x29, x30, [sp], # SPAD // stack alignment
  2328. | JMP_IP, TMP1
  2329. } else {
  2330. | ldp FP, RX, T2 // retore FP and IP
  2331. | ldp x29, x30, [sp], # NR_SPAD // stack alignment
  2332. | mov RETVALx, #1 // ZEND_VM_ENTER
  2333. | ret
  2334. }
  2335. return 1;
  2336. }
  2337. /* Keep 32 exit points in a single code block */
  2338. #define ZEND_JIT_EXIT_POINTS_SPACING 4 // bl = bytes
  2339. #define ZEND_JIT_EXIT_POINTS_PER_GROUP 32 // number of continuous exit points
  2340. static int zend_jit_trace_exit_group_stub(dasm_State **Dst, uint32_t n)
  2341. {
  2342. uint32_t i;
  2343. | bl >2
  2344. |1:
  2345. for (i = 1; i < ZEND_JIT_EXIT_POINTS_PER_GROUP; i++) {
  2346. | bl >2
  2347. }
  2348. |2:
  2349. | adr TMP1, <1
  2350. | sub TMP1, lr, TMP1
  2351. | lsr TMP1, TMP1, #2
  2352. if (n) {
  2353. | ADD_SUB_32_WITH_CONST add, TMP1w, TMP1w, n, TMP2w
  2354. }
  2355. | b ->trace_exit // pass exit_num in TMP1w
  2356. return 1;
  2357. }
  2358. #ifdef CONTEXT_THREADED_JIT
  2359. static int zend_jit_context_threaded_call_stub(dasm_State **Dst)
  2360. {
  2361. |->context_threaded_call:
  2362. | NIY_STUB // TODO
  2363. return 1;
  2364. }
  2365. #endif
  2366. static int zend_jit_assign_const_stub(dasm_State **Dst)
  2367. {
  2368. zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  2369. zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0);
  2370. uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
  2371. |->assign_const:
  2372. | stp x29, x30, [sp, #-32]!
  2373. | mov x29, sp
  2374. if (!zend_jit_assign_to_variable(
  2375. Dst, NULL,
  2376. var_addr, var_addr, -1, -1,
  2377. IS_CONST, val_addr, val_info,
  2378. 0, 0)) {
  2379. return 0;
  2380. }
  2381. | ldp x29, x30, [sp], #32
  2382. | ret
  2383. return 1;
  2384. }
  2385. static int zend_jit_assign_tmp_stub(dasm_State **Dst)
  2386. {
  2387. zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  2388. zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0);
  2389. uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
  2390. |->assign_tmp:
  2391. | stp x29, x30, [sp, #-32]!
  2392. | mov x29, sp
  2393. if (!zend_jit_assign_to_variable(
  2394. Dst, NULL,
  2395. var_addr, var_addr, -1, -1,
  2396. IS_TMP_VAR, val_addr, val_info,
  2397. 0, 0)) {
  2398. return 0;
  2399. }
  2400. | ldp x29, x30, [sp], #32
  2401. | ret
  2402. return 1;
  2403. }
  2404. static int zend_jit_assign_var_stub(dasm_State **Dst)
  2405. {
  2406. zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  2407. zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0);
  2408. uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF;
  2409. |->assign_var:
  2410. | stp x29, x30, [sp, #-32]!
  2411. | mov x29, sp
  2412. if (!zend_jit_assign_to_variable(
  2413. Dst, NULL,
  2414. var_addr, var_addr, -1, -1,
  2415. IS_VAR, val_addr, val_info,
  2416. 0, 0)) {
  2417. return 0;
  2418. }
  2419. | ldp x29, x30, [sp], #32
  2420. | ret
  2421. return 1;
  2422. }
  2423. static int zend_jit_assign_cv_noref_stub(dasm_State **Dst)
  2424. {
  2425. zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  2426. zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0);
  2427. uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN/*|MAY_BE_UNDEF*/;
  2428. |->assign_cv_noref:
  2429. | stp x29, x30, [sp, #-32]!
  2430. | mov x29, sp
  2431. if (!zend_jit_assign_to_variable(
  2432. Dst, NULL,
  2433. var_addr, var_addr, -1, -1,
  2434. IS_CV, val_addr, val_info,
  2435. 0, 0)) {
  2436. return 0;
  2437. }
  2438. | ldp x29, x30, [sp], #32
  2439. | ret
  2440. return 1;
  2441. }
  2442. static int zend_jit_assign_cv_stub(dasm_State **Dst)
  2443. {
  2444. zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  2445. zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0);
  2446. uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF/*|MAY_BE_UNDEF*/;
  2447. |->assign_cv:
  2448. | stp x29, x30, [sp, #-32]!
  2449. | mov x29, sp
  2450. if (!zend_jit_assign_to_variable(
  2451. Dst, NULL,
  2452. var_addr, var_addr, -1, -1,
  2453. IS_CV, val_addr, val_info,
  2454. 0, 0)) {
  2455. return 0;
  2456. }
  2457. | ldp x29, x30, [sp], #32
  2458. | ret
  2459. return 1;
  2460. }
  2461. static const zend_jit_stub zend_jit_stubs[] = {
  2462. JIT_STUB(interrupt_handler, SP_ADJ_JIT, SP_ADJ_VM),
  2463. JIT_STUB(exception_handler, SP_ADJ_JIT, SP_ADJ_VM),
  2464. JIT_STUB(exception_handler_undef, SP_ADJ_JIT, SP_ADJ_VM),
  2465. JIT_STUB(exception_handler_free_op1_op2, SP_ADJ_JIT, SP_ADJ_VM),
  2466. JIT_STUB(exception_handler_free_op2, SP_ADJ_JIT, SP_ADJ_VM),
  2467. JIT_STUB(leave_function, SP_ADJ_JIT, SP_ADJ_VM),
  2468. JIT_STUB(leave_throw, SP_ADJ_JIT, SP_ADJ_VM),
  2469. JIT_STUB(icall_throw, SP_ADJ_JIT, SP_ADJ_VM),
  2470. JIT_STUB(throw_cannot_pass_by_ref, SP_ADJ_JIT, SP_ADJ_VM),
  2471. JIT_STUB(undefined_offset, SP_ADJ_JIT, SP_ADJ_VM),
  2472. JIT_STUB(undefined_index, SP_ADJ_JIT, SP_ADJ_VM),
  2473. JIT_STUB(cannot_add_element, SP_ADJ_JIT, SP_ADJ_VM),
  2474. JIT_STUB(undefined_offset_ex, SP_ADJ_JIT, SP_ADJ_VM),
  2475. JIT_STUB(undefined_index_ex, SP_ADJ_JIT, SP_ADJ_VM),
  2476. JIT_STUB(cannot_add_element_ex, SP_ADJ_JIT, SP_ADJ_VM),
  2477. JIT_STUB(undefined_function, SP_ADJ_JIT, SP_ADJ_VM),
  2478. JIT_STUB(negative_shift, SP_ADJ_JIT, SP_ADJ_VM),
  2479. JIT_STUB(mod_by_zero, SP_ADJ_JIT, SP_ADJ_VM),
  2480. JIT_STUB(invalid_this, SP_ADJ_JIT, SP_ADJ_VM),
  2481. JIT_STUB(trace_halt, SP_ADJ_JIT, SP_ADJ_VM),
  2482. JIT_STUB(trace_exit, SP_ADJ_JIT, SP_ADJ_VM),
  2483. JIT_STUB(trace_escape, SP_ADJ_JIT, SP_ADJ_VM),
  2484. JIT_STUB(hybrid_runtime_jit, SP_ADJ_VM, SP_ADJ_NONE),
  2485. JIT_STUB(hybrid_profile_jit, SP_ADJ_VM, SP_ADJ_NONE),
  2486. JIT_STUB(hybrid_hot_code, SP_ADJ_VM, SP_ADJ_NONE),
  2487. JIT_STUB(hybrid_func_hot_counter, SP_ADJ_VM, SP_ADJ_NONE),
  2488. JIT_STUB(hybrid_loop_hot_counter, SP_ADJ_VM, SP_ADJ_NONE),
  2489. JIT_STUB(hybrid_hot_trace, SP_ADJ_VM, SP_ADJ_NONE),
  2490. JIT_STUB(hybrid_func_trace_counter, SP_ADJ_VM, SP_ADJ_NONE),
  2491. JIT_STUB(hybrid_ret_trace_counter, SP_ADJ_VM, SP_ADJ_NONE),
  2492. JIT_STUB(hybrid_loop_trace_counter, SP_ADJ_VM, SP_ADJ_NONE),
  2493. JIT_STUB(assign_const, SP_ADJ_RET, SP_ADJ_ASSIGN),
  2494. JIT_STUB(assign_tmp, SP_ADJ_RET, SP_ADJ_ASSIGN),
  2495. JIT_STUB(assign_var, SP_ADJ_RET, SP_ADJ_ASSIGN),
  2496. JIT_STUB(assign_cv_noref, SP_ADJ_RET, SP_ADJ_ASSIGN),
  2497. JIT_STUB(assign_cv, SP_ADJ_RET, SP_ADJ_ASSIGN),
  2498. #ifdef CONTEXT_THREADED_JIT
  2499. JIT_STUB(context_threaded_call, SP_ADJ_NONE, SP_ADJ_NONE),
  2500. #endif
  2501. };
  2502. #ifdef HAVE_GDB
  2503. # if 0
  2504. typedef struct _Unwind_Context _Unwind_Context;
  2505. typedef int (*_Unwind_Trace_Fn)(_Unwind_Context *, void *);
  2506. extern int _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
  2507. extern uintptr_t _Unwind_GetCFA(_Unwind_Context *);
  2508. typedef struct _zend_jit_unwind_arg {
  2509. int cnt;
  2510. uintptr_t cfa[3];
  2511. } zend_jit_unwind_arg;
  2512. static int zend_jit_unwind_cb(_Unwind_Context *ctx, void *a)
  2513. {
  2514. zend_jit_unwind_arg *arg = (zend_jit_unwind_arg*)a;
  2515. arg->cfa[arg->cnt] = _Unwind_GetCFA(ctx);
  2516. arg->cnt++;
  2517. if (arg->cnt == 3) {
  2518. return 5; // _URC_END_OF_STACK
  2519. }
  2520. return 0; // _URC_NO_REASON;
  2521. }
  2522. static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data)
  2523. {
  2524. zend_jit_unwind_arg arg;
  2525. memset(&arg, 0, sizeof(arg));
  2526. _Unwind_Backtrace(zend_jit_unwind_cb, &arg);
  2527. if (arg.cnt == 3) {
  2528. sp_adj[SP_ADJ_VM] = arg.cfa[2] - arg.cfa[1];
  2529. }
  2530. }
  2531. # else
  2532. static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data)
  2533. {
  2534. uintptr_t ret;
  2535. __asm__ (
  2536. "ldr %0, [x29]\n\t"
  2537. "sub %0 ,%0, x29"
  2538. : "=r"(ret));
  2539. sp_adj[SP_ADJ_VM] = ret;
  2540. }
  2541. # endif
  2542. extern void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data);
  2543. static zend_never_inline void zend_jit_set_sp_adj_vm(void)
  2544. {
  2545. void (ZEND_FASTCALL *orig_zend_touch_vm_stack_data)(void *);
  2546. orig_zend_touch_vm_stack_data = zend_touch_vm_stack_data;
  2547. zend_touch_vm_stack_data = zend_jit_touch_vm_stack_data;
  2548. execute_ex(NULL); // set sp_adj[SP_ADJ_VM]
  2549. zend_touch_vm_stack_data = orig_zend_touch_vm_stack_data;
  2550. }
  2551. #endif
  2552. static int zend_jit_setup(void)
  2553. {
  2554. allowed_opt_flags = 0;
  2555. #if ZTS
  2556. tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
  2557. ZEND_ASSERT(tsrm_ls_cache_tcb_offset != 0);
  2558. #endif
  2559. memset(sp_adj, 0, sizeof(sp_adj));
  2560. #ifdef HAVE_GDB
  2561. sp_adj[SP_ADJ_RET] = 0;
  2562. sp_adj[SP_ADJ_ASSIGN] = 32;
  2563. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  2564. zend_jit_set_sp_adj_vm(); // set sp_adj[SP_ADJ_VM]
  2565. #ifndef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
  2566. || sp_adj[SP_ADJ_JIT] = sp_adj[SP_ADJ_VM] + HYBRID_SPAD; // sub r4, HYBRID_SPAD
  2567. #else
  2568. || sp_adj[SP_ADJ_JIT] = sp_adj[SP_ADJ_VM];
  2569. #endif
  2570. } else if (GCC_GLOBAL_REGS) {
  2571. || sp_adj[SP_ADJ_JIT] = sp_adj[SP_ADJ_RET] + SPAD; // sub r4, SPAD
  2572. } else {
  2573. || sp_adj[SP_ADJ_JIT] = sp_adj[SP_ADJ_RET] + NR_SPAD; // sub r4, NR_SPAD
  2574. }
  2575. #endif
  2576. return SUCCESS;
  2577. }
  2578. static ZEND_ATTRIBUTE_UNUSED int zend_jit_trap(dasm_State **Dst)
  2579. {
  2580. | brk #0
  2581. return 1;
  2582. }
  2583. static int zend_jit_align_func(dasm_State **Dst)
  2584. {
  2585. reuse_ip = 0;
  2586. delayed_call_chain = 0;
  2587. last_valid_opline = NULL;
  2588. use_last_vald_opline = 0;
  2589. track_last_valid_opline = 0;
  2590. jit_return_label = -1;
  2591. |.align 16
  2592. return 1;
  2593. }
  2594. static int zend_jit_prologue(dasm_State **Dst)
  2595. {
  2596. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  2597. | SUB_HYBRID_SPAD
  2598. } else if (GCC_GLOBAL_REGS) {
  2599. | stp x29, x30, [sp, # -SPAD]! // stack alignment
  2600. |// mov x29, sp
  2601. } else {
  2602. | stp x29, x30, [sp, # -NR_SPAD]! // stack alignment
  2603. |// mov x29, sp
  2604. | stp FP, RX, T2 // save FP and IP
  2605. | mov FP, FCARG1x
  2606. }
  2607. return 1;
  2608. }
  2609. static int zend_jit_label(dasm_State **Dst, unsigned int label)
  2610. {
  2611. |=>label:
  2612. return 1;
  2613. }
  2614. static int zend_jit_save_call_chain(dasm_State **Dst, uint32_t call_level)
  2615. {
  2616. | // call->prev_execute_data = EX(call);
  2617. if (call_level == 1) {
  2618. | str xzr, EX:RX->prev_execute_data
  2619. } else {
  2620. | ldr REG0, EX->call
  2621. | str REG0, EX:RX->prev_execute_data
  2622. }
  2623. | // EX(call) = call;
  2624. | str RX, EX->call
  2625. delayed_call_chain = 0;
  2626. return 1;
  2627. }
  2628. static int zend_jit_set_ip(dasm_State **Dst, const zend_op *opline)
  2629. {
  2630. if (last_valid_opline == opline) {
  2631. zend_jit_use_last_valid_opline();
  2632. } else if (GCC_GLOBAL_REGS && last_valid_opline) {
  2633. zend_jit_use_last_valid_opline();
  2634. | LOAD_64BIT_VAL TMP1, (opline - last_valid_opline) * sizeof(zend_op)
  2635. | ADD_IP TMP1, TMP2
  2636. } else {
  2637. | LOAD_IP_ADDR opline
  2638. }
  2639. zend_jit_set_last_valid_opline(opline);
  2640. return 1;
  2641. }
  2642. static int zend_jit_set_ip_ex(dasm_State **Dst, const zend_op *opline, bool set_ip_reg)
  2643. {
  2644. return zend_jit_set_ip(Dst, opline);
  2645. }
  2646. static int zend_jit_set_valid_ip(dasm_State **Dst, const zend_op *opline)
  2647. {
  2648. if (delayed_call_chain) {
  2649. if (!zend_jit_save_call_chain(Dst, delayed_call_level)) {
  2650. return 0;
  2651. }
  2652. }
  2653. if (!zend_jit_set_ip(Dst, opline)) {
  2654. return 0;
  2655. }
  2656. reuse_ip = 0;
  2657. return 1;
  2658. }
  2659. static int zend_jit_check_timeout(dasm_State **Dst, const zend_op *opline, const void *exit_addr)
  2660. {
  2661. | MEM_LOAD_8_ZTS ldrb, TMP1w, executor_globals, vm_interrupt, TMP1
  2662. if (exit_addr) {
  2663. | cbnz TMP1w, &exit_addr
  2664. } else if (last_valid_opline == opline) {
  2665. || zend_jit_use_last_valid_opline();
  2666. | cbnz TMP1w, ->interrupt_handler
  2667. } else {
  2668. | cbnz TMP1w, >1
  2669. |.cold_code
  2670. |1:
  2671. | LOAD_IP_ADDR opline
  2672. | b ->interrupt_handler
  2673. |.code
  2674. }
  2675. return 1;
  2676. }
  2677. static int zend_jit_trace_end_loop(dasm_State **Dst, int loop_label, const void *timeout_exit_addr)
  2678. {
  2679. if (timeout_exit_addr) {
  2680. | MEM_LOAD_8_ZTS ldrb, TMP1w, executor_globals, vm_interrupt, TMP1
  2681. | cbz TMP1w, =>loop_label
  2682. | b &timeout_exit_addr
  2683. } else {
  2684. | b =>loop_label
  2685. }
  2686. return 1;
  2687. }
  2688. static int zend_jit_check_exception(dasm_State **Dst)
  2689. {
  2690. | MEM_LOAD_64_ZTS ldr, TMP2, executor_globals, exception, TMP1
  2691. | cbnz TMP2, ->exception_handler
  2692. return 1;
  2693. }
  2694. static int zend_jit_check_exception_undef_result(dasm_State **Dst, const zend_op *opline)
  2695. {
  2696. if (opline->result_type & (IS_TMP_VAR|IS_VAR)) {
  2697. | MEM_LOAD_64_ZTS ldr, TMP2, executor_globals, exception, TMP1
  2698. | cbnz TMP2, ->exception_handler_undef
  2699. return 1;
  2700. }
  2701. return zend_jit_check_exception(Dst);
  2702. }
  2703. static int zend_jit_trace_begin(dasm_State **Dst, uint32_t trace_num, zend_jit_trace_info *parent, uint32_t exit_num)
  2704. {
  2705. current_trace_num = trace_num;
  2706. | // EG(jit_trace_num) = trace_num;
  2707. | LOAD_32BIT_VAL TMP1w, trace_num
  2708. | MEM_STORE_32_ZTS str, TMP1w, executor_globals, jit_trace_num, TMP2
  2709. return 1;
  2710. }
  2711. static int zend_jit_trace_end(dasm_State **Dst, zend_jit_trace_info *t)
  2712. {
  2713. uint32_t i;
  2714. const void *exit_addr;
  2715. /* Emit veneers table for exit points (B instruction for each exit number) */
  2716. |.cold_code
  2717. for (i = 0; i < t->exit_count; i++) {
  2718. exit_addr = zend_jit_trace_get_exit_addr(i);
  2719. if (!exit_addr) {
  2720. return 0;
  2721. }
  2722. | b &exit_addr
  2723. }
  2724. |=>1: // end of the code
  2725. |.code
  2726. return 1;
  2727. }
  2728. static int zend_jit_patch(const void *code, size_t size, uint32_t jmp_table_size, const void *from_addr, const void *to_addr)
  2729. {
  2730. int ret = 0;
  2731. uint8_t *p, *end;
  2732. const void *veneer = NULL;
  2733. ptrdiff_t delta;
  2734. if (jmp_table_size) {
  2735. const void **jmp_slot = (const void **)((char*)code + ZEND_MM_ALIGNED_SIZE_EX(size, sizeof(void*)));
  2736. do {
  2737. if (*jmp_slot == from_addr) {
  2738. *jmp_slot = to_addr;
  2739. ret++;
  2740. }
  2741. jmp_slot++;
  2742. } while (--jmp_table_size);
  2743. }
  2744. end = (uint8_t*)code;
  2745. p = end + size;
  2746. while (p > end) {
  2747. uint32_t *ins_ptr;
  2748. uint32_t ins;
  2749. p -= 4;
  2750. ins_ptr = (uint32_t*)p;
  2751. ins = *ins_ptr;
  2752. if ((ins & 0xfc000000u) == 0x14000000u) {
  2753. // B (imm26:0..25)
  2754. delta = (uint32_t*)from_addr - ins_ptr;
  2755. if (((ins ^ (uint32_t)delta) & 0x01ffffffu) == 0) {
  2756. delta = (uint32_t*)to_addr - ins_ptr;
  2757. if (((delta + 0x02000000) >> 26) != 0) {
  2758. abort(); // brnach target out of range
  2759. }
  2760. *ins_ptr = (ins & 0xfc000000u) | ((uint32_t)delta & 0x03ffffffu);
  2761. ret++;
  2762. if (!veneer) {
  2763. veneer = p;
  2764. }
  2765. }
  2766. } else if ((ins & 0xff000000u) == 0x54000000u ||
  2767. (ins & 0x7e000000u) == 0x34000000u) {
  2768. // B.cond, CBZ, CBNZ (imm19:5..23)
  2769. delta = (uint32_t*)from_addr - ins_ptr;
  2770. if (((ins ^ ((uint32_t)delta << 5)) & 0x00ffffe0u) == 0) {
  2771. delta = (uint32_t*)to_addr - ins_ptr;
  2772. if (((delta + 0x40000) >> 19) != 0) {
  2773. if (veneer) {
  2774. delta = (uint32_t*)veneer - ins_ptr;
  2775. if (((delta + 0x40000) >> 19) != 0) {
  2776. abort(); // brnach target out of range
  2777. }
  2778. } else {
  2779. abort(); // brnach target out of range
  2780. }
  2781. }
  2782. *ins_ptr = (ins & 0xff00001fu) | (((uint32_t)delta & 0x7ffffu) << 5);
  2783. ret++;
  2784. }
  2785. } else if ((ins & 0x7e000000u) == 0x36000000u) {
  2786. // TBZ, TBNZ (imm14:5..18)
  2787. delta = (uint32_t*)from_addr - ins_ptr;
  2788. if (((ins ^ ((uint32_t)delta << 5)) & 0x0007ffe0u) == 0) {
  2789. delta = (uint32_t*)to_addr - ins_ptr;
  2790. if (((delta + 0x2000) >> 14) != 0) {
  2791. if (veneer) {
  2792. delta = (uint32_t*)veneer - ins_ptr;
  2793. if (((delta + 0x2000) >> 14) != 0) {
  2794. abort(); // brnach target out of range
  2795. }
  2796. } else {
  2797. abort(); // brnach target out of range
  2798. }
  2799. }
  2800. *ins_ptr = (ins & 0xfff8001fu) | (((uint32_t)delta & 0x3fffu) << 5);
  2801. ret++;
  2802. }
  2803. }
  2804. }
  2805. JIT_CACHE_FLUSH(code, (char*)code + size);
  2806. #ifdef HAVE_VALGRIND
  2807. VALGRIND_DISCARD_TRANSLATIONS(code, size);
  2808. #endif
  2809. return ret;
  2810. }
  2811. static int zend_jit_link_side_trace(const void *code, size_t size, uint32_t jmp_table_size, uint32_t exit_num, const void *addr)
  2812. {
  2813. return zend_jit_patch(code, size, jmp_table_size, zend_jit_trace_get_exit_addr(exit_num), addr);
  2814. }
  2815. static int zend_jit_trace_link_to_root(dasm_State **Dst, zend_jit_trace_info *t, const void *timeout_exit_addr)
  2816. {
  2817. const void *link_addr;
  2818. size_t prologue_size;
  2819. /* Skip prologue. */
  2820. // TODO: don't hardcode this ???
  2821. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  2822. #ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
  2823. prologue_size = 0;
  2824. #else
  2825. // sub sp, sp, #0x20
  2826. prologue_size = 4;
  2827. #endif
  2828. } else if (GCC_GLOBAL_REGS) {
  2829. // stp x29, x30, [sp, # -SPAD]!
  2830. prologue_size = 4;
  2831. } else {
  2832. // stp x29, x30, [sp, # -NR_SPAD]! // stack alignment
  2833. // stp FP, RX, T2
  2834. // mov FP, FCARG1x
  2835. prologue_size = 12;
  2836. }
  2837. link_addr = (const void*)((const char*)t->code_start + prologue_size);
  2838. if (timeout_exit_addr) {
  2839. /* Check timeout for links to LOOP */
  2840. | MEM_LOAD_8_ZTS ldrb, TMP1w, executor_globals, vm_interrupt, TMP1
  2841. | cbz TMP1w, &link_addr
  2842. | b &timeout_exit_addr
  2843. } else {
  2844. | b &link_addr
  2845. }
  2846. return 1;
  2847. }
  2848. static int zend_jit_trace_return(dasm_State **Dst, bool original_handler, const zend_op *opline)
  2849. {
  2850. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  2851. | ADD_HYBRID_SPAD
  2852. if (!original_handler) {
  2853. | JMP_IP TMP1
  2854. } else {
  2855. | ldr REG0, EX->func
  2856. | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])]
  2857. | ldr REG0, [REG0, #offsetof(zend_jit_op_array_trace_extension, offset)]
  2858. | ldr REG0, [IP, REG0]
  2859. | br REG0
  2860. }
  2861. } else if (GCC_GLOBAL_REGS) {
  2862. | ldp x29, x30, [sp], # SPAD // stack alignment
  2863. if (!original_handler) {
  2864. | JMP_IP TMP1
  2865. } else {
  2866. | ldr REG0, EX->func
  2867. | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])]
  2868. | ldr REG0, [REG0, #offsetof(zend_jit_op_array_trace_extension, offset)]
  2869. | ldr REG0, [IP, REG0]
  2870. | br REG0
  2871. }
  2872. } else {
  2873. if (original_handler) {
  2874. | mov FCARG1x, FP
  2875. | ldr REG0, EX->func
  2876. | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])]
  2877. | ldr REG0, [REG0, #offsetof(zend_jit_op_array_trace_extension, offset)]
  2878. | ldr REG0, [IP, REG0]
  2879. | blr REG0
  2880. }
  2881. | ldp FP, RX, T2 // retore FP and IP
  2882. | ldp x29, x30, [sp], # NR_SPAD // stack alignment
  2883. if (!original_handler || !opline ||
  2884. (opline->opcode != ZEND_RETURN
  2885. && opline->opcode != ZEND_RETURN_BY_REF
  2886. && opline->opcode != ZEND_GENERATOR_RETURN
  2887. && opline->opcode != ZEND_GENERATOR_CREATE
  2888. && opline->opcode != ZEND_YIELD
  2889. && opline->opcode != ZEND_YIELD_FROM)) {
  2890. | mov RETVALx, #2 // ZEND_VM_LEAVE
  2891. }
  2892. | ret
  2893. }
  2894. return 1;
  2895. }
  2896. static int zend_jit_type_guard(dasm_State **Dst, const zend_op *opline, uint32_t var, uint8_t type)
  2897. {
  2898. int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
  2899. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  2900. zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
  2901. if (!exit_addr) {
  2902. return 0;
  2903. }
  2904. | IF_NOT_ZVAL_TYPE var_addr, type, &exit_addr, ZREG_TMP1
  2905. return 1;
  2906. }
  2907. static int zend_jit_scalar_type_guard(dasm_State **Dst, const zend_op *opline, uint32_t var)
  2908. {
  2909. int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
  2910. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  2911. if (!exit_addr) {
  2912. return 0;
  2913. }
  2914. | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP1w, FP, var+offsetof(zval, u1.v.type), TMP1
  2915. | cmp TMP1w, #IS_STRING
  2916. | bhs &exit_addr
  2917. return 1;
  2918. }
  2919. static int zend_jit_packed_guard(dasm_State **Dst, const zend_op *opline, uint32_t var, uint32_t op_info)
  2920. {
  2921. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
  2922. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  2923. zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
  2924. if (!exit_addr) {
  2925. return 0;
  2926. }
  2927. | GET_ZVAL_LVAL ZREG_FCARG1, var_addr, TMP1
  2928. if (op_info & MAY_BE_ARRAY_PACKED) {
  2929. | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)]
  2930. | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w
  2931. | beq &exit_addr
  2932. } else {
  2933. | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)]
  2934. | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w
  2935. | bne &exit_addr
  2936. }
  2937. return 1;
  2938. }
  2939. static int zend_jit_trace_handler(dasm_State **Dst, const zend_op_array *op_array, const zend_op *opline, int may_throw, zend_jit_trace_rec *trace)
  2940. {
  2941. zend_jit_op_array_trace_extension *jit_extension =
  2942. (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
  2943. size_t offset = jit_extension->offset;
  2944. const void *handler =
  2945. (zend_vm_opcode_handler_t)ZEND_OP_TRACE_INFO(opline, offset)->call_handler;
  2946. if (!zend_jit_set_valid_ip(Dst, opline)) {
  2947. return 0;
  2948. }
  2949. if (!GCC_GLOBAL_REGS) {
  2950. | mov FCARG1x, FP
  2951. }
  2952. | EXT_CALL handler, REG0
  2953. if (may_throw
  2954. && opline->opcode != ZEND_RETURN
  2955. && opline->opcode != ZEND_RETURN_BY_REF) {
  2956. | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1
  2957. | cbnz REG0, ->exception_handler
  2958. }
  2959. while (trace->op != ZEND_JIT_TRACE_VM && trace->op != ZEND_JIT_TRACE_END) {
  2960. trace++;
  2961. }
  2962. if (!GCC_GLOBAL_REGS
  2963. && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_RETURN)) {
  2964. if (opline->opcode == ZEND_RETURN ||
  2965. opline->opcode == ZEND_RETURN_BY_REF ||
  2966. opline->opcode == ZEND_DO_UCALL ||
  2967. opline->opcode == ZEND_DO_FCALL_BY_NAME ||
  2968. opline->opcode == ZEND_DO_FCALL ||
  2969. opline->opcode == ZEND_GENERATOR_CREATE) {
  2970. | MEM_LOAD_64_ZTS ldr, FP, executor_globals, current_execute_data, TMP1
  2971. }
  2972. }
  2973. if (zend_jit_trace_may_exit(op_array, opline)) {
  2974. if (opline->opcode == ZEND_RETURN ||
  2975. opline->opcode == ZEND_RETURN_BY_REF ||
  2976. opline->opcode == ZEND_GENERATOR_CREATE) {
  2977. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  2978. #if 0
  2979. /* this check should be handled by the following OPLINE guard or jmp [IP] */
  2980. | LOAD_ADDR TMP1, zend_jit_halt_op
  2981. | cmp IP, TMP1
  2982. | beq ->trace_halt
  2983. #endif
  2984. } else if (GCC_GLOBAL_REGS) {
  2985. | cbz IP, ->trace_halt
  2986. } else {
  2987. | tst RETVALw, RETVALw
  2988. | blt ->trace_halt
  2989. }
  2990. } else if (opline->opcode == ZEND_EXIT ||
  2991. opline->opcode == ZEND_GENERATOR_RETURN ||
  2992. opline->opcode == ZEND_YIELD ||
  2993. opline->opcode == ZEND_YIELD_FROM) {
  2994. | b ->trace_halt
  2995. }
  2996. if (trace->op != ZEND_JIT_TRACE_END ||
  2997. (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
  2998. trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
  2999. const zend_op *next_opline = trace->opline;
  3000. const zend_op *exit_opline = NULL;
  3001. uint32_t exit_point;
  3002. const void *exit_addr;
  3003. uint32_t old_info = 0;
  3004. uint32_t old_res_info = 0;
  3005. zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
  3006. if (zend_is_smart_branch(opline)) {
  3007. bool exit_if_true = 0;
  3008. exit_opline = zend_jit_trace_get_exit_opline(trace, opline + 1, &exit_if_true);
  3009. } else {
  3010. switch (opline->opcode) {
  3011. case ZEND_JMPZ:
  3012. case ZEND_JMPNZ:
  3013. case ZEND_JMPZ_EX:
  3014. case ZEND_JMPNZ_EX:
  3015. case ZEND_JMP_SET:
  3016. case ZEND_COALESCE:
  3017. case ZEND_JMP_NULL:
  3018. case ZEND_FE_RESET_R:
  3019. case ZEND_FE_RESET_RW:
  3020. exit_opline = (trace->opline == opline + 1) ?
  3021. OP_JMP_ADDR(opline, opline->op2) :
  3022. opline + 1;
  3023. break;
  3024. case ZEND_JMPZNZ:
  3025. exit_opline = (trace->opline == OP_JMP_ADDR(opline, opline->op2)) ?
  3026. ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) :
  3027. OP_JMP_ADDR(opline, opline->op2);
  3028. break;
  3029. case ZEND_FE_FETCH_R:
  3030. case ZEND_FE_FETCH_RW:
  3031. exit_opline = (trace->opline == opline + 1) ?
  3032. ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) :
  3033. opline + 1;
  3034. break;
  3035. }
  3036. }
  3037. switch (opline->opcode) {
  3038. case ZEND_FE_FETCH_R:
  3039. case ZEND_FE_FETCH_RW:
  3040. if (opline->op2_type != IS_UNUSED) {
  3041. old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var));
  3042. SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
  3043. }
  3044. break;
  3045. }
  3046. if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
  3047. old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
  3048. SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
  3049. }
  3050. exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
  3051. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  3052. if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
  3053. SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
  3054. }
  3055. switch (opline->opcode) {
  3056. case ZEND_FE_FETCH_R:
  3057. case ZEND_FE_FETCH_RW:
  3058. if (opline->op2_type != IS_UNUSED) {
  3059. SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var), old_info);
  3060. }
  3061. break;
  3062. }
  3063. if (!exit_addr) {
  3064. return 0;
  3065. }
  3066. | CMP_IP next_opline, TMP1, TMP2
  3067. | bne &exit_addr
  3068. }
  3069. }
  3070. zend_jit_set_last_valid_opline(trace->opline);
  3071. return 1;
  3072. }
  3073. static int zend_jit_handler(dasm_State **Dst, const zend_op *opline, int may_throw)
  3074. {
  3075. const void *handler;
  3076. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  3077. handler = zend_get_opcode_handler_func(opline);
  3078. } else {
  3079. handler = opline->handler;
  3080. }
  3081. if (!zend_jit_set_valid_ip(Dst, opline)) {
  3082. return 0;
  3083. }
  3084. if (!GCC_GLOBAL_REGS) {
  3085. | mov FCARG1x, FP
  3086. }
  3087. | EXT_CALL handler, REG0
  3088. if (may_throw) {
  3089. zend_jit_check_exception(Dst);
  3090. }
  3091. /* Skip the following OP_DATA */
  3092. switch (opline->opcode) {
  3093. case ZEND_ASSIGN_DIM:
  3094. case ZEND_ASSIGN_OBJ:
  3095. case ZEND_ASSIGN_STATIC_PROP:
  3096. case ZEND_ASSIGN_DIM_OP:
  3097. case ZEND_ASSIGN_OBJ_OP:
  3098. case ZEND_ASSIGN_STATIC_PROP_OP:
  3099. case ZEND_ASSIGN_STATIC_PROP_REF:
  3100. case ZEND_ASSIGN_OBJ_REF:
  3101. zend_jit_set_last_valid_opline(opline + 2);
  3102. break;
  3103. default:
  3104. zend_jit_set_last_valid_opline(opline + 1);
  3105. break;
  3106. }
  3107. return 1;
  3108. }
  3109. static int zend_jit_tail_handler(dasm_State **Dst, const zend_op *opline)
  3110. {
  3111. if (!zend_jit_set_valid_ip(Dst, opline)) {
  3112. return 0;
  3113. }
  3114. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  3115. if (opline->opcode == ZEND_DO_UCALL ||
  3116. opline->opcode == ZEND_DO_FCALL_BY_NAME ||
  3117. opline->opcode == ZEND_DO_FCALL ||
  3118. opline->opcode == ZEND_RETURN) {
  3119. /* Use inlined HYBRID VM handler */
  3120. const void *handler = opline->handler;
  3121. | ADD_HYBRID_SPAD
  3122. | EXT_JMP handler, REG0
  3123. } else {
  3124. const void *handler = zend_get_opcode_handler_func(opline);
  3125. | EXT_CALL handler, REG0
  3126. | ADD_HYBRID_SPAD
  3127. | JMP_IP TMP1
  3128. }
  3129. } else {
  3130. const void *handler = opline->handler;
  3131. if (GCC_GLOBAL_REGS) {
  3132. | ldp x29, x30, [sp], # SPAD // stack alignment
  3133. } else {
  3134. | mov FCARG1x, FP
  3135. | ldp FP, RX, T2 // retore FP and IP
  3136. | ldp x29, x30, [sp], # NR_SPAD // stack alignment
  3137. }
  3138. | EXT_JMP handler, REG0
  3139. }
  3140. zend_jit_reset_last_valid_opline();
  3141. return 1;
  3142. }
  3143. static int zend_jit_trace_opline_guard(dasm_State **Dst, const zend_op *opline)
  3144. {
  3145. uint32_t exit_point = zend_jit_trace_get_exit_point(NULL, 0);
  3146. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  3147. if (!exit_addr) {
  3148. return 0;
  3149. }
  3150. | CMP_IP opline, TMP1, TMP2
  3151. | bne &exit_addr
  3152. zend_jit_set_last_valid_opline(opline);
  3153. return 1;
  3154. }
  3155. static int zend_jit_jmp(dasm_State **Dst, unsigned int target_label)
  3156. {
  3157. | b =>target_label
  3158. return 1;
  3159. }
  3160. static int zend_jit_cond_jmp(dasm_State **Dst, const zend_op *next_opline, unsigned int target_label)
  3161. {
  3162. | CMP_IP next_opline, TMP1, TMP2
  3163. | bne =>target_label
  3164. zend_jit_set_last_valid_opline(next_opline);
  3165. return 1;
  3166. }
  3167. #ifdef CONTEXT_THREADED_JIT
  3168. static int zend_jit_context_threaded_call(dasm_State **Dst, const zend_op *opline, unsigned int next_block)
  3169. {
  3170. | NIY // TODO
  3171. return 1;
  3172. }
  3173. #endif
  3174. static int zend_jit_call(dasm_State **Dst, const zend_op *opline, unsigned int next_block)
  3175. {
  3176. #ifdef CONTEXT_THREADED_JIT
  3177. return zend_jit_context_threaded_call(Dst, opline, next_block);
  3178. #else
  3179. return zend_jit_tail_handler(Dst, opline);
  3180. #endif
  3181. }
  3182. static int zend_jit_spill_store(dasm_State **Dst, zend_jit_addr src, zend_jit_addr dst, uint32_t info, bool set_type)
  3183. {
  3184. ZEND_ASSERT(Z_MODE(src) == IS_REG);
  3185. ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
  3186. if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
  3187. | SET_ZVAL_LVAL_FROM_REG dst, Rx(Z_REG(src)), TMP1
  3188. if (set_type &&
  3189. (Z_REG(dst) != ZREG_FP ||
  3190. !JIT_G(current_frame) ||
  3191. STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
  3192. | SET_ZVAL_TYPE_INFO dst, IS_LONG, TMP1w, TMP2
  3193. }
  3194. } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
  3195. | SET_ZVAL_DVAL dst, Z_REG(src), ZREG_TMP1
  3196. if (set_type &&
  3197. (Z_REG(dst) != ZREG_FP ||
  3198. !JIT_G(current_frame) ||
  3199. STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
  3200. | SET_ZVAL_TYPE_INFO dst, IS_DOUBLE, TMP1w, TMP2
  3201. }
  3202. } else {
  3203. ZEND_UNREACHABLE();
  3204. }
  3205. return 1;
  3206. }
  3207. static int zend_jit_load_reg(dasm_State **Dst, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
  3208. {
  3209. ZEND_ASSERT(Z_MODE(src) == IS_MEM_ZVAL);
  3210. ZEND_ASSERT(Z_MODE(dst) == IS_REG);
  3211. if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
  3212. | GET_ZVAL_LVAL Z_REG(dst), src, TMP1
  3213. } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
  3214. | GET_ZVAL_DVAL Z_REG(dst), src, ZREG_TMP1
  3215. } else {
  3216. ZEND_UNREACHABLE();
  3217. }
  3218. return 1;
  3219. }
  3220. static int zend_jit_store_var(dasm_State **Dst, uint32_t info, int var, zend_reg reg, bool set_type)
  3221. {
  3222. zend_jit_addr src = ZEND_ADDR_REG(reg);
  3223. zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
  3224. return zend_jit_spill_store(Dst, src, dst, info, set_type);
  3225. }
  3226. static int zend_jit_store_var_type(dasm_State **Dst, int var, uint32_t type)
  3227. {
  3228. zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
  3229. | SET_ZVAL_TYPE_INFO dst, type, TMP1w, TMP2
  3230. return 1;
  3231. }
  3232. static int zend_jit_store_var_if_necessary(dasm_State **Dst, int var, zend_jit_addr src, uint32_t info)
  3233. {
  3234. if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
  3235. zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
  3236. return zend_jit_spill_store(Dst, src, dst, info, 1);
  3237. }
  3238. return 1;
  3239. }
  3240. static int zend_jit_store_var_if_necessary_ex(dasm_State **Dst, int var, zend_jit_addr src, uint32_t info, zend_jit_addr old, uint32_t old_info)
  3241. {
  3242. if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
  3243. zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
  3244. bool set_type = 1;
  3245. if ((info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) ==
  3246. (old_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF))) {
  3247. if (Z_MODE(old) != IS_REG || Z_LOAD(old) || Z_STORE(old)) {
  3248. set_type = 0;
  3249. }
  3250. }
  3251. return zend_jit_spill_store(Dst, src, dst, info, set_type);
  3252. }
  3253. return 1;
  3254. }
  3255. static int zend_jit_load_var(dasm_State **Dst, uint32_t info, int var, zend_reg reg)
  3256. {
  3257. zend_jit_addr src = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
  3258. zend_jit_addr dst = ZEND_ADDR_REG(reg);
  3259. return zend_jit_load_reg(Dst, src, dst, info);
  3260. }
  3261. static int zend_jit_invalidate_var_if_necessary(dasm_State **Dst, zend_uchar op_type, zend_jit_addr addr, znode_op op)
  3262. {
  3263. if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) {
  3264. zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
  3265. | SET_ZVAL_TYPE_INFO dst, IS_UNDEF, TMP1w, TMP2
  3266. }
  3267. return 1;
  3268. }
  3269. static int zend_jit_update_regs(dasm_State **Dst, uint32_t var, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
  3270. {
  3271. if (!zend_jit_same_addr(src, dst)) {
  3272. if (Z_MODE(src) == IS_REG) {
  3273. if (Z_MODE(dst) == IS_REG) {
  3274. if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
  3275. | mov Rx(Z_REG(dst)), Rx(Z_REG(src))
  3276. } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
  3277. | fmov Rd(Z_REG(dst)-ZREG_V0), Rd(Z_REG(src)-ZREG_V0)
  3278. } else {
  3279. ZEND_UNREACHABLE();
  3280. }
  3281. if (!Z_LOAD(src) && !Z_STORE(src) && Z_STORE(dst)) {
  3282. zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
  3283. if (!zend_jit_spill_store(Dst, dst, var_addr, info,
  3284. JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
  3285. JIT_G(current_frame) == NULL ||
  3286. STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
  3287. (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
  3288. )) {
  3289. return 0;
  3290. }
  3291. }
  3292. } else if (Z_MODE(dst) == IS_MEM_ZVAL) {
  3293. if (!Z_LOAD(src) && !Z_STORE(src)) {
  3294. if (!zend_jit_spill_store(Dst, src, dst, info,
  3295. JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
  3296. JIT_G(current_frame) == NULL ||
  3297. STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
  3298. (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
  3299. )) {
  3300. return 0;
  3301. }
  3302. }
  3303. } else {
  3304. ZEND_UNREACHABLE();
  3305. }
  3306. } else if (Z_MODE(src) == IS_MEM_ZVAL) {
  3307. if (Z_MODE(dst) == IS_REG) {
  3308. if (!zend_jit_load_reg(Dst, src, dst, info)) {
  3309. return 0;
  3310. }
  3311. } else {
  3312. ZEND_UNREACHABLE();
  3313. }
  3314. } else {
  3315. ZEND_UNREACHABLE();
  3316. }
  3317. } else if (Z_MODE(dst) == IS_REG && Z_STORE(dst)) {
  3318. dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
  3319. if (!zend_jit_spill_store(Dst, src, dst, info,
  3320. JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
  3321. JIT_G(current_frame) == NULL ||
  3322. STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
  3323. (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
  3324. )) {
  3325. return 0;
  3326. }
  3327. }
  3328. return 1;
  3329. }
  3330. static int zend_jit_escape_if_undef_r0(dasm_State **Dst, int var, uint32_t flags, const zend_op *opline)
  3331. {
  3332. zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  3333. | IF_NOT_ZVAL_TYPE val_addr, IS_UNDEF, >1, ZREG_TMP1
  3334. if (flags & ZEND_JIT_EXIT_RESTORE_CALL) {
  3335. if (!zend_jit_save_call_chain(Dst, -1)) {
  3336. return 0;
  3337. }
  3338. }
  3339. ZEND_ASSERT(opline);
  3340. if ((opline-1)->opcode != ZEND_FETCH_CONSTANT
  3341. && (opline-1)->opcode != ZEND_FETCH_LIST_R
  3342. && ((opline-1)->op1_type & (IS_VAR|IS_TMP_VAR))
  3343. && !(flags & ZEND_JIT_EXIT_FREE_OP1)) {
  3344. val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline-1)->op1.var);
  3345. | IF_NOT_ZVAL_REFCOUNTED val_addr, >2, ZREG_TMP1, ZREG_TMP2
  3346. | GET_ZVAL_PTR TMP1, val_addr, TMP2
  3347. | GC_ADDREF TMP1, TMP2w
  3348. |2:
  3349. }
  3350. | LOAD_IP_ADDR (opline - 1)
  3351. | b ->trace_escape
  3352. |1:
  3353. return 1;
  3354. }
  3355. static int zend_jit_store_const(dasm_State **Dst, int var, zend_reg reg)
  3356. {
  3357. zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
  3358. if (reg == ZREG_LONG_MIN_MINUS_1) {
  3359. uint64_t val = 0xc3e0000000000000;
  3360. | SET_ZVAL_LVAL dst, val, TMP1, TMP2
  3361. | SET_ZVAL_TYPE_INFO dst, IS_DOUBLE, TMP1w, TMP2
  3362. } else if (reg == ZREG_LONG_MIN) {
  3363. uint64_t val = 0x8000000000000000;
  3364. | SET_ZVAL_LVAL dst, val, TMP1, TMP2
  3365. | SET_ZVAL_TYPE_INFO dst, IS_LONG, TMP1w, TMP2
  3366. } else if (reg == ZREG_LONG_MAX) {
  3367. uint64_t val = 0x7fffffffffffffff;
  3368. | SET_ZVAL_LVAL dst, val, TMP1, TMP2
  3369. | SET_ZVAL_TYPE_INFO dst, IS_LONG, TMP1w, TMP2
  3370. } else if (reg == ZREG_LONG_MAX_PLUS_1) {
  3371. uint64_t val = 0x43e0000000000000;
  3372. | SET_ZVAL_LVAL dst, val, TMP1, TMP2
  3373. | SET_ZVAL_TYPE_INFO dst, IS_DOUBLE, TMP1w, TMP2
  3374. } else if (reg == ZREG_NULL) {
  3375. | SET_ZVAL_TYPE_INFO dst, IS_NULL, TMP1w, TMP2
  3376. } else if (reg == ZREG_ZVAL_TRY_ADDREF) {
  3377. | IF_NOT_ZVAL_REFCOUNTED dst, >1, ZREG_TMP1, ZREG_TMP2
  3378. | GET_ZVAL_PTR TMP1, dst, TMP2
  3379. | GC_ADDREF TMP1, TMP2w
  3380. |1:
  3381. } else if (reg == ZREG_ZVAL_COPY_GPR0) {
  3382. zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  3383. | ZVAL_COPY_VALUE dst, -1, val_addr, -1, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  3384. | TRY_ADDREF -1, REG1w, REG2, TMP1w
  3385. } else {
  3386. ZEND_UNREACHABLE();
  3387. }
  3388. return 1;
  3389. }
  3390. static int zend_jit_free_trampoline(dasm_State **Dst)
  3391. {
  3392. | // if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
  3393. | ldr TMP1w, [REG0, #offsetof(zend_function, common.fn_flags)]
  3394. | TST_32_WITH_CONST TMP1w, ZEND_ACC_CALL_VIA_TRAMPOLINE, TMP2w
  3395. | beq >1
  3396. | mov FCARG1x, REG0
  3397. | EXT_CALL zend_jit_free_trampoline_helper, REG0
  3398. |1:
  3399. return 1;
  3400. }
  3401. static int zend_jit_inc_dec(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op1_def_info, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw)
  3402. {
  3403. if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_LONG)) {
  3404. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >2, ZREG_TMP1
  3405. }
  3406. if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
  3407. | ZVAL_COPY_VALUE res_addr, res_use_info, op1_addr, MAY_BE_LONG, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  3408. }
  3409. if (!zend_jit_update_regs(Dst, opline->op1.var, op1_addr, op1_def_addr, MAY_BE_LONG)) {
  3410. return 0;
  3411. }
  3412. if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
  3413. | LONG_ADD_SUB_WITH_IMM adds, op1_def_addr, Z_L(1), TMP1, TMP2
  3414. } else {
  3415. | LONG_ADD_SUB_WITH_IMM subs, op1_def_addr, Z_L(1), TMP1, TMP2
  3416. }
  3417. if (may_overflow &&
  3418. (((op1_def_info & MAY_BE_GUARD) && (op1_def_info & MAY_BE_LONG)) ||
  3419. ((opline->result_type != IS_UNUSED && (res_info & MAY_BE_GUARD) && (res_info & MAY_BE_LONG))))) {
  3420. int32_t exit_point;
  3421. const void *exit_addr;
  3422. zend_jit_trace_stack *stack;
  3423. uint32_t old_op1_info, old_res_info = 0;
  3424. stack = JIT_G(current_frame)->stack;
  3425. old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
  3426. SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_DOUBLE, 0);
  3427. if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
  3428. SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_LONG_MAX_PLUS_1);
  3429. } else {
  3430. SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_LONG_MIN_MINUS_1);
  3431. }
  3432. if (opline->result_type != IS_UNUSED) {
  3433. old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
  3434. if (opline->opcode == ZEND_PRE_INC) {
  3435. SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
  3436. SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_LONG_MAX_PLUS_1);
  3437. } else if (opline->opcode == ZEND_PRE_DEC) {
  3438. SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
  3439. SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_LONG_MIN_MINUS_1);
  3440. } else if (opline->opcode == ZEND_POST_INC) {
  3441. SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
  3442. SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_LONG_MAX);
  3443. } else if (opline->opcode == ZEND_POST_DEC) {
  3444. SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
  3445. SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_LONG_MIN);
  3446. }
  3447. }
  3448. exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
  3449. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  3450. if (!exit_addr) {
  3451. return 0;
  3452. }
  3453. | bvs &exit_addr
  3454. if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
  3455. opline->result_type != IS_UNUSED) {
  3456. | ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_LONG, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  3457. }
  3458. SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
  3459. if (opline->result_type != IS_UNUSED) {
  3460. SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
  3461. }
  3462. } else if (may_overflow) {
  3463. | bvs >1
  3464. if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
  3465. opline->result_type != IS_UNUSED) {
  3466. | ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_LONG, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  3467. }
  3468. |.cold_code
  3469. |1:
  3470. if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
  3471. uint64_t val = 0x43e0000000000000;
  3472. if (Z_MODE(op1_def_addr) == IS_REG) {
  3473. | LOAD_64BIT_VAL TMP1, val
  3474. | fmov Rd(Z_REG(op1_def_addr)-ZREG_V0), TMP1
  3475. } else {
  3476. | SET_ZVAL_LVAL op1_def_addr, val, TMP2, TMP1
  3477. }
  3478. } else {
  3479. uint64_t val = 0xc3e0000000000000;
  3480. if (Z_MODE(op1_def_addr) == IS_REG) {
  3481. | LOAD_64BIT_VAL TMP1, val
  3482. | fmov Rd(Z_REG(op1_def_addr)-ZREG_V0), TMP1
  3483. } else {
  3484. | SET_ZVAL_LVAL op1_def_addr, val, TMP2, TMP1
  3485. }
  3486. }
  3487. if (Z_MODE(op1_def_addr) == IS_MEM_ZVAL) {
  3488. | SET_ZVAL_TYPE_INFO op1_def_addr, IS_DOUBLE, TMP1w, TMP2
  3489. }
  3490. if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
  3491. opline->result_type != IS_UNUSED) {
  3492. | ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_DOUBLE, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  3493. }
  3494. | b >3
  3495. |.code
  3496. } else {
  3497. if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
  3498. opline->result_type != IS_UNUSED) {
  3499. | ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_LONG, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  3500. }
  3501. }
  3502. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
  3503. |.cold_code
  3504. |2:
  3505. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
  3506. | SET_EX_OPLINE opline, REG0
  3507. if (op1_info & MAY_BE_UNDEF) {
  3508. | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >2, ZREG_TMP1
  3509. | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
  3510. | LOAD_32BIT_VAL FCARG1w, opline->op1.var
  3511. | EXT_CALL zend_jit_undefined_op_helper, REG0
  3512. | SET_ZVAL_TYPE_INFO op1_addr, IS_NULL, TMP1w, TMP2
  3513. op1_info |= MAY_BE_NULL;
  3514. }
  3515. |2:
  3516. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  3517. | // ZVAL_DEREF(var_ptr);
  3518. if (op1_info & MAY_BE_REF) {
  3519. | IF_NOT_Z_TYPE, FCARG1x, IS_REFERENCE, >2, TMP1w
  3520. | GET_Z_PTR FCARG1x, FCARG1x
  3521. | ldr TMP1, [FCARG1x, #offsetof(zend_reference, sources.ptr)]
  3522. | cbz TMP1, >1
  3523. if (RETURN_VALUE_USED(opline)) {
  3524. | LOAD_ZVAL_ADDR FCARG2x, res_addr
  3525. } else {
  3526. | mov FCARG2x, xzr
  3527. }
  3528. if (opline->opcode == ZEND_PRE_INC) {
  3529. | EXT_CALL zend_jit_pre_inc_typed_ref, REG0
  3530. } else if (opline->opcode == ZEND_PRE_DEC) {
  3531. | EXT_CALL zend_jit_pre_dec_typed_ref, REG0
  3532. } else if (opline->opcode == ZEND_POST_INC) {
  3533. | EXT_CALL zend_jit_post_inc_typed_ref, REG0
  3534. } else if (opline->opcode == ZEND_POST_DEC) {
  3535. | EXT_CALL zend_jit_post_dec_typed_ref, REG0
  3536. } else {
  3537. ZEND_UNREACHABLE();
  3538. }
  3539. zend_jit_check_exception(Dst);
  3540. | b >3
  3541. |1:
  3542. | add FCARG1x, FCARG1x, #offsetof(zend_reference, val)
  3543. |2:
  3544. }
  3545. if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
  3546. zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  3547. | ZVAL_COPY_VALUE res_addr, res_use_info, val_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  3548. | TRY_ADDREF op1_info, REG0w, REG2, TMP1w
  3549. }
  3550. if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
  3551. if (opline->opcode == ZEND_PRE_INC && opline->result_type != IS_UNUSED) {
  3552. | LOAD_ZVAL_ADDR FCARG2x, res_addr
  3553. | EXT_CALL zend_jit_pre_inc, REG0
  3554. } else {
  3555. | EXT_CALL increment_function, REG0
  3556. }
  3557. } else {
  3558. if (opline->opcode == ZEND_PRE_DEC && opline->result_type != IS_UNUSED) {
  3559. | LOAD_ZVAL_ADDR FCARG2x, res_addr
  3560. | EXT_CALL zend_jit_pre_dec, REG0
  3561. } else {
  3562. | EXT_CALL decrement_function, REG0
  3563. }
  3564. }
  3565. if (may_throw) {
  3566. zend_jit_check_exception(Dst);
  3567. }
  3568. } else {
  3569. zend_reg tmp_reg;
  3570. if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
  3571. | ZVAL_COPY_VALUE res_addr, res_use_info, op1_addr, MAY_BE_DOUBLE, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  3572. }
  3573. if (Z_MODE(op1_def_addr) == IS_REG) {
  3574. tmp_reg = Z_REG(op1_def_addr);
  3575. } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
  3576. tmp_reg = Z_REG(op1_addr);
  3577. } else {
  3578. tmp_reg = ZREG_FPR0;
  3579. }
  3580. | GET_ZVAL_DVAL tmp_reg, op1_addr, ZREG_TMP1
  3581. if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
  3582. uint64_t val = 0x3ff0000000000000; // 1.0
  3583. | LOAD_64BIT_VAL TMP1, val
  3584. | fmov FPTMP, TMP1
  3585. | fadd Rd(tmp_reg-ZREG_V0), Rd(tmp_reg-ZREG_V0), FPTMP
  3586. } else {
  3587. uint64_t val = 0x3ff0000000000000; // 1.0
  3588. | LOAD_64BIT_VAL TMP1, val
  3589. | fmov FPTMP, TMP1
  3590. | fsub Rd(tmp_reg-ZREG_V0), Rd(tmp_reg-ZREG_V0), FPTMP
  3591. }
  3592. | SET_ZVAL_DVAL op1_def_addr, tmp_reg, ZREG_TMP1
  3593. if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
  3594. opline->result_type != IS_UNUSED) {
  3595. | ZVAL_COPY_VALUE res_addr, res_use_info, op1_addr, op1_def_info, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  3596. | TRY_ADDREF op1_def_info, REG0w, REG1, TMP1w
  3597. }
  3598. }
  3599. | b >3
  3600. |.code
  3601. }
  3602. |3:
  3603. if (!zend_jit_store_var_if_necessary_ex(Dst, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
  3604. return 0;
  3605. }
  3606. if (opline->result_type != IS_UNUSED) {
  3607. if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
  3608. return 0;
  3609. }
  3610. }
  3611. return 1;
  3612. }
  3613. static int zend_jit_opline_uses_reg(const zend_op *opline, int8_t reg)
  3614. {
  3615. if ((opline+1)->opcode == ZEND_OP_DATA
  3616. && ((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV))
  3617. && JIT_G(current_frame)->stack[EX_VAR_TO_NUM((opline+1)->op1.var)].reg == reg) {
  3618. return 1;
  3619. }
  3620. return
  3621. ((opline->result_type & (IS_VAR|IS_TMP_VAR|IS_CV)) &&
  3622. JIT_G(current_frame)->stack[EX_VAR_TO_NUM(opline->result.var)].reg == reg) ||
  3623. ((opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) &&
  3624. JIT_G(current_frame)->stack[EX_VAR_TO_NUM(opline->op1.var)].reg == reg) ||
  3625. ((opline->op2_type & (IS_VAR|IS_TMP_VAR|IS_CV)) &&
  3626. JIT_G(current_frame)->stack[EX_VAR_TO_NUM(opline->op2.var)].reg == reg);
  3627. }
  3628. static int zend_jit_math_long_long(dasm_State **Dst,
  3629. const zend_op *opline,
  3630. zend_uchar opcode,
  3631. zend_jit_addr op1_addr,
  3632. zend_jit_addr op2_addr,
  3633. zend_jit_addr res_addr,
  3634. uint32_t res_info,
  3635. uint32_t res_use_info,
  3636. int may_overflow)
  3637. {
  3638. bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
  3639. zend_reg result_reg;
  3640. zend_reg tmp_reg = ZREG_REG0;
  3641. bool use_ovf_flag = 1;
  3642. if (Z_MODE(res_addr) == IS_REG && (res_info & MAY_BE_LONG)) {
  3643. if (may_overflow && (res_info & MAY_BE_GUARD)
  3644. && JIT_G(current_frame)
  3645. && zend_jit_opline_uses_reg(opline, Z_REG(res_addr))) {
  3646. result_reg = ZREG_REG0;
  3647. } else {
  3648. result_reg = Z_REG(res_addr);
  3649. }
  3650. } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr) && !may_overflow) {
  3651. result_reg = Z_REG(op1_addr);
  3652. } else if (Z_REG(res_addr) != ZREG_REG0) {
  3653. result_reg = ZREG_REG0;
  3654. } else {
  3655. /* ASSIGN_DIM_OP */
  3656. result_reg = ZREG_FCARG1;
  3657. tmp_reg = ZREG_FCARG1;
  3658. }
  3659. if (opcode == ZEND_MUL &&
  3660. Z_MODE(op2_addr) == IS_CONST_ZVAL &&
  3661. Z_LVAL_P(Z_ZV(op2_addr)) == 2) {
  3662. if (Z_MODE(op1_addr) == IS_REG) {
  3663. | adds Rx(result_reg), Rx(Z_REG(op1_addr)), Rx(Z_REG(op1_addr))
  3664. } else {
  3665. | GET_ZVAL_LVAL result_reg, op1_addr, TMP1
  3666. | adds Rx(result_reg), Rx(result_reg), Rx(result_reg)
  3667. }
  3668. } else if (opcode == ZEND_MUL &&
  3669. Z_MODE(op2_addr) == IS_CONST_ZVAL &&
  3670. !may_overflow &&
  3671. zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr)))) {
  3672. | GET_ZVAL_LVAL result_reg, op1_addr, TMP1
  3673. | mov TMP1, #zend_long_floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
  3674. | lsl Rx(result_reg), Rx(result_reg), TMP1
  3675. } else if (opcode == ZEND_MUL &&
  3676. Z_MODE(op1_addr) == IS_CONST_ZVAL &&
  3677. Z_LVAL_P(Z_ZV(op1_addr)) == 2) {
  3678. if (Z_MODE(op2_addr) == IS_REG) {
  3679. | adds Rx(result_reg), Rx(Z_REG(op2_addr)), Rx(Z_REG(op2_addr))
  3680. } else {
  3681. | GET_ZVAL_LVAL result_reg, op2_addr, TMP1
  3682. | adds Rx(result_reg), Rx(result_reg), Rx(result_reg)
  3683. }
  3684. } else if (opcode == ZEND_MUL &&
  3685. Z_MODE(op1_addr) == IS_CONST_ZVAL &&
  3686. !may_overflow &&
  3687. zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op1_addr)))) {
  3688. | GET_ZVAL_LVAL result_reg, op2_addr, TMP1
  3689. | mov TMP1, #zend_long_floor_log2(Z_LVAL_P(Z_ZV(op1_addr)))
  3690. | lsl Rx(result_reg), Rx(result_reg), TMP1
  3691. } else if (opcode == ZEND_DIV &&
  3692. (Z_MODE(op2_addr) == IS_CONST_ZVAL &&
  3693. zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr))))) {
  3694. | GET_ZVAL_LVAL result_reg, op1_addr, TMP1
  3695. | asr Rx(result_reg), Rx(result_reg), #zend_long_floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
  3696. #if 0
  3697. /* x86 specific optimizations through LEA instraction are not supported on ARM */
  3698. } else if (opcode == ZEND_ADD &&
  3699. !may_overflow &&
  3700. Z_MODE(op1_addr) == IS_REG &&
  3701. Z_MODE(op2_addr) == IS_CONST_ZVAL) {
  3702. | NIY // TODO: test
  3703. } else if (opcode == ZEND_ADD &&
  3704. !may_overflow &&
  3705. Z_MODE(op2_addr) == IS_REG &&
  3706. Z_MODE(op1_addr) == IS_CONST_ZVAL) {
  3707. | NIY // TODO: test
  3708. } else if (opcode == ZEND_SUB &&
  3709. !may_overflow &&
  3710. Z_MODE(op1_addr) == IS_REG &&
  3711. Z_MODE(op2_addr) == IS_CONST_ZVAL) {
  3712. | NIY // TODO: test
  3713. #endif
  3714. } else if (opcode == ZEND_MUL) {
  3715. | GET_ZVAL_LVAL ZREG_TMP1, op1_addr, TMP1
  3716. | GET_ZVAL_LVAL ZREG_TMP2, op2_addr, TMP2
  3717. | mul Rx(result_reg), TMP1, TMP2
  3718. if(may_overflow) {
  3719. /* Use 'smulh' to get the upper 64 bits fo the 128-bit result.
  3720. * For signed multiplication, the top 65 bits of the result will contain
  3721. * either all zeros or all ones if no overflow occurred.
  3722. * Flag: bne -> overflow. beq -> no overflow.
  3723. */
  3724. use_ovf_flag = 0;
  3725. | smulh TMP1, TMP1, TMP2
  3726. | cmp TMP1, Rx(result_reg), asr #63
  3727. }
  3728. } else {
  3729. | GET_ZVAL_LVAL result_reg, op1_addr, TMP1
  3730. if ((opcode == ZEND_ADD || opcode == ZEND_SUB)
  3731. && Z_MODE(op2_addr) == IS_CONST_ZVAL
  3732. && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
  3733. /* +/- 0 */
  3734. may_overflow = 0;
  3735. } else if (same_ops && opcode != ZEND_DIV) {
  3736. | LONG_MATH_REG opcode, Rx(result_reg), Rx(result_reg), Rx(result_reg)
  3737. } else {
  3738. | LONG_MATH opcode, result_reg, op2_addr, TMP1
  3739. }
  3740. }
  3741. if (may_overflow) {
  3742. if (res_info & MAY_BE_GUARD) {
  3743. int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
  3744. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  3745. if (!exit_addr) {
  3746. return 0;
  3747. }
  3748. if ((res_info & MAY_BE_ANY) == MAY_BE_LONG) {
  3749. if (use_ovf_flag) {
  3750. | bvs &exit_addr
  3751. } else {
  3752. | bne &exit_addr
  3753. }
  3754. if (Z_MODE(res_addr) == IS_REG && result_reg != Z_REG(res_addr)) {
  3755. | mov Rx(Z_REG(res_addr)), Rx(result_reg)
  3756. }
  3757. } else if ((res_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
  3758. if (use_ovf_flag) {
  3759. | bvc &exit_addr
  3760. } else {
  3761. | beq &exit_addr
  3762. }
  3763. } else {
  3764. ZEND_UNREACHABLE();
  3765. }
  3766. } else {
  3767. if (res_info & MAY_BE_LONG) {
  3768. if (use_ovf_flag) {
  3769. | bvs >1
  3770. } else {
  3771. | bne >1
  3772. }
  3773. } else {
  3774. if (use_ovf_flag) {
  3775. | bvc >1
  3776. } else {
  3777. | beq >1
  3778. }
  3779. }
  3780. }
  3781. }
  3782. if (Z_MODE(res_addr) == IS_MEM_ZVAL && (res_info & MAY_BE_LONG)) {
  3783. | SET_ZVAL_LVAL_FROM_REG res_addr, Rx(result_reg), TMP1
  3784. if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
  3785. if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
  3786. | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
  3787. }
  3788. }
  3789. }
  3790. if (may_overflow && (!(res_info & MAY_BE_GUARD) || (res_info & MAY_BE_ANY) == MAY_BE_DOUBLE)) {
  3791. zend_reg tmp_reg1 = ZREG_FPR0;
  3792. zend_reg tmp_reg2 = ZREG_FPR1;
  3793. if (res_info & MAY_BE_LONG) {
  3794. |.cold_code
  3795. |1:
  3796. }
  3797. do {
  3798. if ((Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 1) ||
  3799. (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1)) {
  3800. if (opcode == ZEND_ADD) {
  3801. uint64_t val = 0x43e0000000000000;
  3802. if (Z_MODE(res_addr) == IS_REG) {
  3803. | LOAD_64BIT_VAL TMP1, val
  3804. | fmov Rd(Z_REG(res_addr)-ZREG_V0), TMP1
  3805. } else {
  3806. | SET_ZVAL_LVAL res_addr, val, TMP2, TMP1
  3807. }
  3808. break;
  3809. } else if (opcode == ZEND_SUB) {
  3810. uint64_t val = 0xc3e0000000000000;
  3811. if (Z_MODE(res_addr) == IS_REG) {
  3812. | LOAD_64BIT_VAL TMP1, val
  3813. | fmov Rd(Z_REG(res_addr)-ZREG_V0), TMP1
  3814. } else {
  3815. | SET_ZVAL_LVAL res_addr, val, TMP2, TMP1
  3816. }
  3817. break;
  3818. }
  3819. }
  3820. | DOUBLE_GET_ZVAL_LVAL tmp_reg1, op1_addr, tmp_reg, ZREG_TMP1
  3821. | DOUBLE_GET_ZVAL_LVAL tmp_reg2, op2_addr, tmp_reg, ZREG_TMP1
  3822. | DOUBLE_MATH_REG opcode, tmp_reg1, tmp_reg1, tmp_reg2
  3823. | SET_ZVAL_DVAL res_addr, tmp_reg1, ZREG_TMP1
  3824. } while (0);
  3825. if (Z_MODE(res_addr) == IS_MEM_ZVAL
  3826. && (res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
  3827. | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, TMP1w, TMP2
  3828. }
  3829. if (res_info & MAY_BE_LONG) {
  3830. | b >2
  3831. |.code
  3832. }
  3833. |2:
  3834. }
  3835. return 1;
  3836. }
  3837. static int zend_jit_math_long_double(dasm_State **Dst,
  3838. zend_uchar opcode,
  3839. zend_jit_addr op1_addr,
  3840. zend_jit_addr op2_addr,
  3841. zend_jit_addr res_addr,
  3842. uint32_t res_use_info)
  3843. {
  3844. zend_reg result_reg =
  3845. (Z_MODE(res_addr) == IS_REG) ? Z_REG(res_addr) : ZREG_FPR0;
  3846. zend_reg op2_reg;
  3847. | DOUBLE_GET_ZVAL_LVAL result_reg, op1_addr, ZREG_TMP1, ZREG_TMP2
  3848. if (Z_MODE(op2_addr) == IS_REG) {
  3849. op2_reg = Z_REG(op2_addr);
  3850. } else {
  3851. op2_reg = ZREG_FPTMP;
  3852. | GET_ZVAL_DVAL op2_reg, op2_addr, ZREG_TMP1
  3853. }
  3854. | DOUBLE_MATH_REG opcode, result_reg, result_reg, op2_reg
  3855. | SET_ZVAL_DVAL res_addr, result_reg, ZREG_TMP1
  3856. if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
  3857. if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
  3858. | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, TMP1w, TMP2
  3859. }
  3860. }
  3861. return 1;
  3862. }
  3863. static int zend_jit_math_double_long(dasm_State **Dst,
  3864. zend_uchar opcode,
  3865. zend_jit_addr op1_addr,
  3866. zend_jit_addr op2_addr,
  3867. zend_jit_addr res_addr,
  3868. uint32_t res_use_info)
  3869. {
  3870. zend_reg result_reg, op1_reg, op2_reg;
  3871. if (zend_is_commutative(opcode)
  3872. && (Z_MODE(res_addr) != IS_REG || Z_MODE(op1_addr) != IS_REG || Z_REG(res_addr) != Z_REG(op1_addr))) {
  3873. if (Z_MODE(res_addr) == IS_REG) {
  3874. result_reg = Z_REG(res_addr);
  3875. } else {
  3876. result_reg = ZREG_FPR0;
  3877. }
  3878. | DOUBLE_GET_ZVAL_LVAL result_reg, op2_addr, ZREG_TMP1, ZREG_TMP2
  3879. if (Z_MODE(op1_addr) == IS_REG) {
  3880. op1_reg = Z_REG(op1_addr);
  3881. } else {
  3882. op1_reg = ZREG_FPTMP;
  3883. | GET_ZVAL_DVAL op1_reg, op1_addr, ZREG_TMP1
  3884. }
  3885. | DOUBLE_MATH_REG opcode, result_reg, result_reg, op1_reg
  3886. } else {
  3887. if (Z_MODE(res_addr) == IS_REG) {
  3888. result_reg = Z_REG(res_addr);
  3889. } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
  3890. result_reg = Z_REG(op1_addr);
  3891. } else {
  3892. result_reg = ZREG_FPR0;
  3893. }
  3894. if (Z_MODE(op1_addr) == IS_REG) {
  3895. op1_reg = Z_REG(op1_addr);
  3896. } else {
  3897. | GET_ZVAL_DVAL result_reg, op1_addr, ZREG_TMP1
  3898. op1_reg = result_reg;
  3899. }
  3900. if ((opcode == ZEND_ADD || opcode == ZEND_SUB)
  3901. && Z_MODE(op2_addr) == IS_CONST_ZVAL
  3902. && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
  3903. /* +/- 0 */
  3904. } else {
  3905. op2_reg = ZREG_FPTMP;
  3906. | DOUBLE_GET_ZVAL_LVAL op2_reg, op2_addr, ZREG_TMP1, ZREG_TMP2
  3907. | DOUBLE_MATH_REG opcode, result_reg, op1_reg, op2_reg
  3908. }
  3909. }
  3910. | SET_ZVAL_DVAL res_addr, result_reg, ZREG_TMP1
  3911. if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
  3912. if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
  3913. if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
  3914. | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, TMP1w, TMP2
  3915. }
  3916. }
  3917. }
  3918. return 1;
  3919. }
  3920. static int zend_jit_math_double_double(dasm_State **Dst,
  3921. zend_uchar opcode,
  3922. zend_jit_addr op1_addr,
  3923. zend_jit_addr op2_addr,
  3924. zend_jit_addr res_addr,
  3925. uint32_t res_use_info)
  3926. {
  3927. bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
  3928. zend_reg result_reg, op1_reg, op2_reg;
  3929. zend_jit_addr val_addr;
  3930. if (Z_MODE(res_addr) == IS_REG) {
  3931. result_reg = Z_REG(res_addr);
  3932. } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
  3933. result_reg = Z_REG(op1_addr);
  3934. } else if (zend_is_commutative(opcode) && Z_MODE(op2_addr) == IS_REG && Z_LAST_USE(op2_addr)) {
  3935. result_reg = Z_REG(op2_addr);
  3936. } else {
  3937. result_reg = ZREG_FPR0;
  3938. }
  3939. if (Z_MODE(op1_addr) == IS_REG) {
  3940. op1_reg = Z_REG(op1_addr);
  3941. val_addr = op2_addr;
  3942. } else if (Z_MODE(op2_addr) == IS_REG && zend_is_commutative(opcode)) {
  3943. op1_reg = Z_REG(op2_addr);
  3944. val_addr = op1_addr;
  3945. } else {
  3946. | GET_ZVAL_DVAL result_reg, op1_addr, ZREG_TMP1
  3947. op1_reg = result_reg;
  3948. val_addr = op2_addr;
  3949. }
  3950. if ((opcode == ZEND_MUL) &&
  3951. Z_MODE(val_addr) == IS_CONST_ZVAL && Z_DVAL_P(Z_ZV(val_addr)) == 2.0) {
  3952. | DOUBLE_MATH_REG ZEND_ADD, result_reg, op1_reg, op1_reg
  3953. } else {
  3954. if (same_ops) {
  3955. op2_reg = op1_reg;
  3956. } else if (Z_MODE(val_addr) == IS_REG) {
  3957. op2_reg = Z_REG(val_addr);
  3958. } else {
  3959. op2_reg = ZREG_FPTMP;
  3960. | GET_ZVAL_DVAL op2_reg, val_addr, ZREG_TMP1
  3961. }
  3962. | DOUBLE_MATH_REG opcode, result_reg, op1_reg, op2_reg
  3963. }
  3964. | SET_ZVAL_DVAL res_addr, result_reg, ZREG_TMP1
  3965. if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
  3966. if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
  3967. if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
  3968. | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, TMP1w, TMP2
  3969. }
  3970. }
  3971. }
  3972. return 1;
  3973. }
  3974. static int zend_jit_math_helper(dasm_State **Dst,
  3975. const zend_op *opline,
  3976. zend_uchar opcode,
  3977. zend_uchar op1_type,
  3978. znode_op op1,
  3979. zend_jit_addr op1_addr,
  3980. uint32_t op1_info,
  3981. zend_uchar op2_type,
  3982. znode_op op2,
  3983. zend_jit_addr op2_addr,
  3984. uint32_t op2_info,
  3985. uint32_t res_var,
  3986. zend_jit_addr res_addr,
  3987. uint32_t res_info,
  3988. uint32_t res_use_info,
  3989. int may_overflow,
  3990. int may_throw)
  3991. /* Labels: 1,2,3,4,5,6 */
  3992. {
  3993. bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
  3994. if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
  3995. if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
  3996. if (op1_info & MAY_BE_DOUBLE) {
  3997. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3, ZREG_TMP1
  3998. } else {
  3999. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6, ZREG_TMP1
  4000. }
  4001. }
  4002. if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
  4003. if (op2_info & MAY_BE_DOUBLE) {
  4004. | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >1, ZREG_TMP1
  4005. |.cold_code
  4006. |1:
  4007. if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
  4008. | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >6, ZREG_TMP1
  4009. }
  4010. if (!zend_jit_math_long_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
  4011. return 0;
  4012. }
  4013. | b >5
  4014. |.code
  4015. } else {
  4016. | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6, ZREG_TMP1
  4017. }
  4018. }
  4019. if (!zend_jit_math_long_long(Dst, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
  4020. return 0;
  4021. }
  4022. if (op1_info & MAY_BE_DOUBLE) {
  4023. |.cold_code
  4024. |3:
  4025. if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
  4026. | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >6, ZREG_TMP1
  4027. }
  4028. if (op2_info & MAY_BE_DOUBLE) {
  4029. if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
  4030. if (!same_ops) {
  4031. | IF_NOT_ZVAL_TYPE, op2_addr, IS_DOUBLE, >1, ZREG_TMP1
  4032. } else {
  4033. | IF_NOT_ZVAL_TYPE, op2_addr, IS_DOUBLE, >6, ZREG_TMP1
  4034. }
  4035. }
  4036. if (!zend_jit_math_double_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
  4037. return 0;
  4038. }
  4039. | b >5
  4040. }
  4041. if (!same_ops) {
  4042. |1:
  4043. if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
  4044. | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6, ZREG_TMP1
  4045. }
  4046. if (!zend_jit_math_double_long(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
  4047. return 0;
  4048. }
  4049. | b >5
  4050. }
  4051. |.code
  4052. }
  4053. } else if ((op1_info & MAY_BE_DOUBLE) &&
  4054. !(op1_info & MAY_BE_LONG) &&
  4055. (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
  4056. (res_info & MAY_BE_DOUBLE)) {
  4057. if (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
  4058. | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >6, ZREG_TMP1
  4059. }
  4060. if (op2_info & MAY_BE_DOUBLE) {
  4061. if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
  4062. if (!same_ops && (op2_info & MAY_BE_LONG)) {
  4063. | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >1, ZREG_TMP1
  4064. } else {
  4065. | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >6, ZREG_TMP1
  4066. }
  4067. }
  4068. if (!zend_jit_math_double_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
  4069. return 0;
  4070. }
  4071. }
  4072. if (!same_ops && (op2_info & MAY_BE_LONG)) {
  4073. if (op2_info & MAY_BE_DOUBLE) {
  4074. |.cold_code
  4075. }
  4076. |1:
  4077. if (op2_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
  4078. | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6, ZREG_TMP1
  4079. }
  4080. if (!zend_jit_math_double_long(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
  4081. return 0;
  4082. }
  4083. if (op2_info & MAY_BE_DOUBLE) {
  4084. | b >5
  4085. |.code
  4086. }
  4087. }
  4088. } else if ((op2_info & MAY_BE_DOUBLE) &&
  4089. !(op2_info & MAY_BE_LONG) &&
  4090. (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
  4091. (res_info & MAY_BE_DOUBLE)) {
  4092. if (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
  4093. | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >6, ZREG_TMP1
  4094. }
  4095. if (op1_info & MAY_BE_DOUBLE) {
  4096. if (!same_ops && (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
  4097. if (!same_ops && (op1_info & MAY_BE_LONG)) {
  4098. | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >1, ZREG_TMP1
  4099. } else {
  4100. | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >6, ZREG_TMP1
  4101. }
  4102. }
  4103. if (!zend_jit_math_double_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
  4104. return 0;
  4105. }
  4106. }
  4107. if (!same_ops && (op1_info & MAY_BE_LONG)) {
  4108. if (op1_info & MAY_BE_DOUBLE) {
  4109. |.cold_code
  4110. }
  4111. |1:
  4112. if (op1_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
  4113. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6, ZREG_TMP1
  4114. }
  4115. if (!zend_jit_math_long_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
  4116. return 0;
  4117. }
  4118. if (op1_info & MAY_BE_DOUBLE) {
  4119. | b >5
  4120. |.code
  4121. }
  4122. }
  4123. }
  4124. |5:
  4125. if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
  4126. (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
  4127. if ((op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
  4128. (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
  4129. (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
  4130. |.cold_code
  4131. }
  4132. |6:
  4133. if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1) {
  4134. if (Z_MODE(res_addr) == IS_REG) {
  4135. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
  4136. | LOAD_ZVAL_ADDR FCARG1x, real_addr
  4137. } else if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) {
  4138. | LOAD_ZVAL_ADDR FCARG1x, res_addr
  4139. }
  4140. if (Z_MODE(op1_addr) == IS_REG) {
  4141. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
  4142. if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
  4143. return 0;
  4144. }
  4145. op1_addr = real_addr;
  4146. }
  4147. | LOAD_ZVAL_ADDR FCARG2x, op1_addr
  4148. } else {
  4149. if (Z_MODE(op1_addr) == IS_REG) {
  4150. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
  4151. if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
  4152. return 0;
  4153. }
  4154. op1_addr = real_addr;
  4155. }
  4156. | LOAD_ZVAL_ADDR FCARG2x, op1_addr
  4157. if (Z_MODE(res_addr) == IS_REG) {
  4158. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
  4159. | LOAD_ZVAL_ADDR FCARG1x, real_addr
  4160. } else if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) {
  4161. | LOAD_ZVAL_ADDR FCARG1x, res_addr
  4162. }
  4163. }
  4164. if (Z_MODE(op2_addr) == IS_REG) {
  4165. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
  4166. if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) {
  4167. return 0;
  4168. }
  4169. op2_addr = real_addr;
  4170. }
  4171. | LOAD_ZVAL_ADDR CARG3, op2_addr
  4172. | SET_EX_OPLINE opline, REG0
  4173. if (opcode == ZEND_ADD) {
  4174. | EXT_CALL add_function, REG0
  4175. } else if (opcode == ZEND_SUB) {
  4176. | EXT_CALL sub_function, REG0
  4177. } else if (opcode == ZEND_MUL) {
  4178. | EXT_CALL mul_function, REG0
  4179. } else if (opcode == ZEND_DIV) {
  4180. | EXT_CALL div_function, REG0
  4181. } else {
  4182. ZEND_UNREACHABLE();
  4183. }
  4184. | FREE_OP op1_type, op1, op1_info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  4185. | FREE_OP op2_type, op2, op2_info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  4186. if (may_throw) {
  4187. if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
  4188. | MEM_LOAD_64_ZTS ldr, TMP2, executor_globals, exception, TMP1
  4189. | cbnz TMP2, ->exception_handler_free_op2
  4190. } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
  4191. zend_jit_check_exception_undef_result(Dst, opline);
  4192. } else {
  4193. zend_jit_check_exception(Dst);
  4194. }
  4195. }
  4196. if (Z_MODE(res_addr) == IS_REG) {
  4197. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
  4198. if (!zend_jit_load_reg(Dst, real_addr, res_addr, res_info)) {
  4199. return 0;
  4200. }
  4201. }
  4202. if ((op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
  4203. (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
  4204. (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
  4205. | b <5
  4206. |.code
  4207. }
  4208. }
  4209. return 1;
  4210. }
  4211. static int zend_jit_math(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw)
  4212. {
  4213. ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
  4214. ZEND_ASSERT((op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
  4215. (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)));
  4216. if (!zend_jit_math_helper(Dst, opline, opline->opcode, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->result.var, res_addr, res_info, res_use_info, may_overflow, may_throw)) {
  4217. return 0;
  4218. }
  4219. if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
  4220. return 0;
  4221. }
  4222. return 1;
  4223. }
  4224. static int zend_jit_add_arrays(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr res_addr)
  4225. {
  4226. if (Z_MODE(op2_addr) != IS_MEM_ZVAL || Z_REG(op2_addr) != ZREG_FCARG1) {
  4227. | GET_ZVAL_LVAL ZREG_FCARG1, op1_addr, TMP1
  4228. | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1
  4229. } else if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1) {
  4230. | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1
  4231. | GET_ZVAL_LVAL ZREG_FCARG1, op1_addr, TMP1
  4232. } else {
  4233. | GET_ZVAL_LVAL ZREG_REG0, op2_addr, TMP1
  4234. | GET_ZVAL_LVAL ZREG_FCARG1, op1_addr, TMP1
  4235. | mov FCARG2x, REG0
  4236. }
  4237. | EXT_CALL zend_jit_add_arrays_helper, REG0
  4238. | SET_ZVAL_PTR res_addr, RETVALx, TMP1
  4239. | SET_ZVAL_TYPE_INFO res_addr, IS_ARRAY_EX, TMP1w, TMP2
  4240. | FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  4241. | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  4242. return 1;
  4243. }
  4244. static int zend_jit_long_math_helper(dasm_State **Dst,
  4245. const zend_op *opline,
  4246. zend_uchar opcode,
  4247. zend_uchar op1_type,
  4248. znode_op op1,
  4249. zend_jit_addr op1_addr,
  4250. uint32_t op1_info,
  4251. zend_ssa_range *op1_range,
  4252. zend_uchar op2_type,
  4253. znode_op op2,
  4254. zend_jit_addr op2_addr,
  4255. uint32_t op2_info,
  4256. zend_ssa_range *op2_range,
  4257. uint32_t res_var,
  4258. zend_jit_addr res_addr,
  4259. uint32_t res_info,
  4260. uint32_t res_use_info,
  4261. int may_throw)
  4262. /* Labels: 6 */
  4263. {
  4264. bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
  4265. zend_reg result_reg;
  4266. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
  4267. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6, ZREG_TMP1
  4268. }
  4269. if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
  4270. | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6, ZREG_TMP1
  4271. }
  4272. if (Z_MODE(res_addr) == IS_REG) {
  4273. if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR)
  4274. && opline->op2_type != IS_CONST) {
  4275. result_reg = ZREG_REG0;
  4276. } else {
  4277. result_reg = Z_REG(res_addr);
  4278. }
  4279. } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
  4280. result_reg = Z_REG(op1_addr);
  4281. } else if (Z_REG(res_addr) != ZREG_REG0) {
  4282. result_reg = ZREG_REG0;
  4283. } else {
  4284. /* ASSIGN_DIM_OP */
  4285. result_reg = ZREG_FCARG1;
  4286. }
  4287. if (opcode == ZEND_SL) {
  4288. if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
  4289. zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
  4290. if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
  4291. if (EXPECTED(op2_lval > 0)) {
  4292. | mov Rx(result_reg), xzr
  4293. } else {
  4294. zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
  4295. zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
  4296. | SET_EX_OPLINE opline, REG0
  4297. | b ->negative_shift
  4298. }
  4299. } else if (Z_MODE(op1_addr) == IS_REG && op2_lval == 1) {
  4300. | add Rx(result_reg), Rx(Z_REG(op1_addr)), Rx(Z_REG(op1_addr))
  4301. } else {
  4302. | GET_ZVAL_LVAL result_reg, op1_addr, TMP1
  4303. | lsl Rx(result_reg), Rx(result_reg), #op2_lval
  4304. }
  4305. } else {
  4306. zend_reg op2_reg;
  4307. if (Z_MODE(op2_addr) == IS_REG) {
  4308. op2_reg = Z_REG(op2_addr);
  4309. } else {
  4310. op2_reg = ZREG_TMP2;
  4311. | GET_ZVAL_LVAL ZREG_TMP2, op2_addr, TMP2
  4312. }
  4313. if (!op2_range ||
  4314. op2_range->min < 0 ||
  4315. op2_range->max >= SIZEOF_ZEND_LONG * 8) {
  4316. | cmp Rx(op2_reg), #(SIZEOF_ZEND_LONG*8)
  4317. | bhs >1
  4318. |.cold_code
  4319. |1:
  4320. | mov Rx(result_reg), xzr
  4321. | cmp Rx(op2_reg), xzr
  4322. | bgt >1
  4323. zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
  4324. zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
  4325. | SET_EX_OPLINE opline, REG0
  4326. | b ->negative_shift
  4327. |.code
  4328. }
  4329. | GET_ZVAL_LVAL result_reg, op1_addr, TMP1
  4330. | lsl Rx(result_reg), Rx(result_reg), Rx(op2_reg)
  4331. |1:
  4332. }
  4333. } else if (opcode == ZEND_SR) {
  4334. | GET_ZVAL_LVAL result_reg, op1_addr, TMP1
  4335. if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
  4336. zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
  4337. if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
  4338. if (EXPECTED(op2_lval > 0)) {
  4339. | asr Rx(result_reg), Rx(result_reg), #((SIZEOF_ZEND_LONG * 8) - 1)
  4340. } else {
  4341. zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
  4342. zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
  4343. | SET_EX_OPLINE opline, REG0
  4344. | b ->negative_shift
  4345. }
  4346. } else {
  4347. | asr Rx(result_reg), Rx(result_reg), #op2_lval
  4348. }
  4349. } else {
  4350. zend_reg op2_reg;
  4351. if (Z_MODE(op2_addr) == IS_REG) {
  4352. op2_reg = Z_REG(op2_addr);
  4353. } else {
  4354. op2_reg = ZREG_TMP2;
  4355. | GET_ZVAL_LVAL ZREG_TMP2, op2_addr, TMP2
  4356. }
  4357. if (!op2_range ||
  4358. op2_range->min < 0 ||
  4359. op2_range->max >= SIZEOF_ZEND_LONG * 8) {
  4360. | cmp Rx(op2_reg), #(SIZEOF_ZEND_LONG*8)
  4361. | bhs >1
  4362. |.cold_code
  4363. |1:
  4364. | cmp Rx(op2_reg), xzr
  4365. | mov Rx(op2_reg), #((SIZEOF_ZEND_LONG * 8) - 1)
  4366. | bgt >1
  4367. zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
  4368. zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
  4369. | SET_EX_OPLINE opline, REG0
  4370. | b ->negative_shift
  4371. |.code
  4372. }
  4373. |1:
  4374. | asr Rx(result_reg), Rx(result_reg), Rx(op2_reg)
  4375. }
  4376. } else if (opcode == ZEND_MOD) {
  4377. if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
  4378. zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
  4379. if (op2_lval == 0) {
  4380. zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
  4381. zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
  4382. | SET_EX_OPLINE opline, REG0
  4383. | b ->mod_by_zero
  4384. } else if (op2_lval == -1) {
  4385. | mov Rx(result_reg), xzr
  4386. } else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) {
  4387. zval tmp;
  4388. zend_jit_addr tmp_addr;
  4389. /* Optimisation for mod of power of 2 */
  4390. ZVAL_LONG(&tmp, op2_lval - 1);
  4391. tmp_addr = ZEND_ADDR_CONST_ZVAL(&tmp);
  4392. | GET_ZVAL_LVAL result_reg, op1_addr, TMP1
  4393. | LONG_MATH ZEND_BW_AND, result_reg, tmp_addr, TMP1
  4394. } else {
  4395. | GET_ZVAL_LVAL ZREG_TMP1, op1_addr, TMP1
  4396. | GET_ZVAL_LVAL ZREG_TMP2, op2_addr, TMP2
  4397. | sdiv Rx(result_reg), TMP1, TMP2
  4398. | msub Rx(result_reg), Rx(result_reg), TMP2, TMP1
  4399. }
  4400. } else {
  4401. zend_reg op2_reg;
  4402. if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
  4403. | MEM_ACCESS_64_WITH_UOFFSET ldr, TMP2, Rx(Z_REG(op2_addr)), Z_OFFSET(op2_addr), TMP2
  4404. op2_reg = ZREG_TMP2;
  4405. } else {
  4406. ZEND_ASSERT(Z_MODE(op2_addr) == IS_REG);
  4407. op2_reg = Z_REG(op2_addr);
  4408. }
  4409. if (!op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
  4410. | cbz Rx(op2_reg), >1
  4411. |.cold_code
  4412. |1:
  4413. zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
  4414. zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
  4415. | SET_EX_OPLINE opline, REG0
  4416. | b ->mod_by_zero
  4417. |.code
  4418. }
  4419. /* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */
  4420. if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) {
  4421. | cmn Rx(op2_reg), #1
  4422. | beq >1
  4423. |.cold_code
  4424. |1:
  4425. | SET_ZVAL_LVAL_FROM_REG res_addr, xzr, TMP1
  4426. if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
  4427. if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
  4428. if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
  4429. | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
  4430. }
  4431. }
  4432. }
  4433. | b >5
  4434. |.code
  4435. }
  4436. | GET_ZVAL_LVAL ZREG_TMP1, op1_addr, TMP1
  4437. | sdiv Rx(result_reg), TMP1, Rx(op2_reg)
  4438. | msub Rx(result_reg), Rx(result_reg), Rx(op2_reg), TMP1
  4439. }
  4440. } else if (same_ops) {
  4441. | GET_ZVAL_LVAL result_reg, op1_addr, TMP1
  4442. | LONG_MATH_REG opcode, Rx(result_reg), Rx(result_reg), Rx(result_reg)
  4443. } else {
  4444. | GET_ZVAL_LVAL result_reg, op1_addr, TMP1
  4445. | LONG_MATH opcode, result_reg, op2_addr, TMP1
  4446. }
  4447. if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != result_reg) {
  4448. | SET_ZVAL_LVAL_FROM_REG res_addr, Rx(result_reg), TMP1
  4449. }
  4450. if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
  4451. if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
  4452. if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
  4453. | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
  4454. }
  4455. }
  4456. }
  4457. if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) ||
  4458. (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
  4459. if ((op1_info & MAY_BE_LONG) &&
  4460. (op2_info & MAY_BE_LONG)) {
  4461. |.cold_code
  4462. }
  4463. |6:
  4464. if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1) {
  4465. if (Z_MODE(res_addr) == IS_REG) {
  4466. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
  4467. | LOAD_ZVAL_ADDR FCARG1x, real_addr
  4468. } else if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) {
  4469. | LOAD_ZVAL_ADDR FCARG1x, res_addr
  4470. }
  4471. if (Z_MODE(op1_addr) == IS_REG) {
  4472. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
  4473. if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
  4474. return 0;
  4475. }
  4476. op1_addr = real_addr;
  4477. }
  4478. | LOAD_ZVAL_ADDR FCARG2x, op1_addr
  4479. } else {
  4480. if (Z_MODE(op1_addr) == IS_REG) {
  4481. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
  4482. if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
  4483. return 0;
  4484. }
  4485. op1_addr = real_addr;
  4486. }
  4487. | LOAD_ZVAL_ADDR FCARG2x, op1_addr
  4488. if (Z_MODE(res_addr) == IS_REG) {
  4489. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
  4490. | LOAD_ZVAL_ADDR FCARG1x, real_addr
  4491. } else if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) {
  4492. | LOAD_ZVAL_ADDR FCARG1x, res_addr
  4493. }
  4494. }
  4495. if (Z_MODE(op2_addr) == IS_REG) {
  4496. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
  4497. if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) {
  4498. return 0;
  4499. }
  4500. op2_addr = real_addr;
  4501. }
  4502. | LOAD_ZVAL_ADDR CARG3, op2_addr
  4503. | SET_EX_OPLINE opline, REG0
  4504. if (opcode == ZEND_BW_OR) {
  4505. | EXT_CALL bitwise_or_function, REG0
  4506. } else if (opcode == ZEND_BW_AND) {
  4507. | EXT_CALL bitwise_and_function, REG0
  4508. } else if (opcode == ZEND_BW_XOR) {
  4509. | EXT_CALL bitwise_xor_function, REG0
  4510. } else if (opcode == ZEND_SL) {
  4511. | EXT_CALL shift_left_function, REG0
  4512. } else if (opcode == ZEND_SR) {
  4513. | EXT_CALL shift_right_function, REG0
  4514. } else if (opcode == ZEND_MOD) {
  4515. | EXT_CALL mod_function, REG0
  4516. } else {
  4517. ZEND_UNREACHABLE();
  4518. }
  4519. if (op1_addr == res_addr && (op2_info & MAY_BE_RCN)) {
  4520. /* compound assignment may decrement "op2" refcount */
  4521. op2_info |= MAY_BE_RC1;
  4522. }
  4523. | FREE_OP op1_type, op1, op1_info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  4524. | FREE_OP op2_type, op2, op2_info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  4525. if (may_throw) {
  4526. if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
  4527. | MEM_LOAD_64_ZTS ldr, TMP2, executor_globals, exception, TMP1
  4528. | cbnz TMP2, ->exception_handler_free_op2
  4529. } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
  4530. zend_jit_check_exception_undef_result(Dst, opline);
  4531. } else {
  4532. zend_jit_check_exception(Dst);
  4533. }
  4534. }
  4535. if (Z_MODE(res_addr) == IS_REG) {
  4536. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
  4537. if (!zend_jit_load_reg(Dst, real_addr, res_addr, res_info)) {
  4538. return 0;
  4539. }
  4540. }
  4541. if ((op1_info & MAY_BE_LONG) &&
  4542. (op2_info & MAY_BE_LONG)) {
  4543. | b >5
  4544. |.code
  4545. }
  4546. }
  4547. |5:
  4548. return 1;
  4549. }
  4550. static int zend_jit_long_math(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_ssa_range *op1_range, zend_jit_addr op1_addr, uint32_t op2_info, zend_ssa_range *op2_range, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_throw)
  4551. {
  4552. ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
  4553. ZEND_ASSERT((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG));
  4554. if (!zend_jit_long_math_helper(Dst, opline, opline->opcode,
  4555. opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
  4556. opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
  4557. opline->result.var, res_addr, res_info, res_use_info, may_throw)) {
  4558. return 0;
  4559. }
  4560. if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
  4561. return 0;
  4562. }
  4563. return 1;
  4564. }
  4565. static int zend_jit_concat_helper(dasm_State **Dst,
  4566. const zend_op *opline,
  4567. zend_uchar op1_type,
  4568. znode_op op1,
  4569. zend_jit_addr op1_addr,
  4570. uint32_t op1_info,
  4571. zend_uchar op2_type,
  4572. znode_op op2,
  4573. zend_jit_addr op2_addr,
  4574. uint32_t op2_info,
  4575. zend_jit_addr res_addr,
  4576. int may_throw)
  4577. {
  4578. if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
  4579. if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
  4580. | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >6, ZREG_TMP1
  4581. }
  4582. if (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
  4583. | IF_NOT_ZVAL_TYPE op2_addr, IS_STRING, >6, ZREG_TMP1
  4584. }
  4585. if (Z_MODE(op1_addr) == IS_MEM_ZVAL && Z_REG(op1_addr) == Z_REG(res_addr) && Z_OFFSET(op1_addr) == Z_OFFSET(res_addr)) {
  4586. if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) {
  4587. | LOAD_ZVAL_ADDR FCARG1x, res_addr
  4588. }
  4589. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  4590. | EXT_CALL zend_jit_fast_assign_concat_helper, REG0
  4591. /* concatination with itself may reduce refcount */
  4592. op2_info |= MAY_BE_RC1;
  4593. } else {
  4594. if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) {
  4595. | LOAD_ZVAL_ADDR FCARG1x, res_addr
  4596. }
  4597. | LOAD_ZVAL_ADDR FCARG2x, op1_addr
  4598. | LOAD_ZVAL_ADDR CARG3, op2_addr
  4599. if (op1_type == IS_CV || op1_type == IS_CONST) {
  4600. | EXT_CALL zend_jit_fast_concat_helper, REG0
  4601. } else {
  4602. | EXT_CALL zend_jit_fast_concat_tmp_helper, REG0
  4603. }
  4604. }
  4605. /* concatination with empty string may increase refcount */
  4606. op2_info |= MAY_BE_RCN;
  4607. | FREE_OP op2_type, op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  4608. |5:
  4609. }
  4610. if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) ||
  4611. (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING))) {
  4612. if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
  4613. |.cold_code
  4614. |6:
  4615. }
  4616. if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1) {
  4617. if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) {
  4618. | LOAD_ZVAL_ADDR FCARG1x, res_addr
  4619. }
  4620. | LOAD_ZVAL_ADDR FCARG2x, op1_addr
  4621. } else {
  4622. | LOAD_ZVAL_ADDR FCARG2x, op1_addr
  4623. if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) {
  4624. | LOAD_ZVAL_ADDR FCARG1x, res_addr
  4625. }
  4626. }
  4627. | LOAD_ZVAL_ADDR CARG3, op2_addr
  4628. | SET_EX_OPLINE opline, REG0
  4629. | EXT_CALL concat_function, REG0
  4630. /* concatination with empty string may increase refcount */
  4631. op1_info |= MAY_BE_RCN;
  4632. op2_info |= MAY_BE_RCN;
  4633. | FREE_OP op1_type, op1, op1_info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  4634. | FREE_OP op2_type, op2, op2_info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  4635. if (may_throw) {
  4636. if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
  4637. zend_jit_check_exception_undef_result(Dst, opline);
  4638. } else {
  4639. zend_jit_check_exception(Dst);
  4640. }
  4641. }
  4642. if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
  4643. | b <5
  4644. |.code
  4645. }
  4646. }
  4647. return 1;
  4648. }
  4649. static int zend_jit_concat(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, zend_jit_addr res_addr, int may_throw)
  4650. {
  4651. zend_jit_addr op1_addr, op2_addr;
  4652. ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
  4653. ZEND_ASSERT((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING));
  4654. op1_addr = OP1_ADDR();
  4655. op2_addr = OP2_ADDR();
  4656. return zend_jit_concat_helper(Dst, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, res_addr, may_throw);
  4657. }
  4658. static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_op *opline, uint32_t type, uint32_t op1_info, uint32_t op2_info, uint8_t dim_type, const void *found_exit_addr, const void *not_found_exit_addr, const void *exit_addr)
  4659. /* Labels: 1,2,3,4,5 */
  4660. {
  4661. zend_jit_addr op2_addr = OP2_ADDR();
  4662. zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  4663. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
  4664. && type == BP_VAR_R
  4665. && !exit_addr) {
  4666. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  4667. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  4668. if (!exit_addr) {
  4669. return 0;
  4670. }
  4671. }
  4672. if (op2_info & MAY_BE_LONG) {
  4673. bool op2_loaded = 0;
  4674. bool packed_loaded = 0;
  4675. bool bad_packed_key = 0;
  4676. if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) {
  4677. | // if (EXPECTED(Z_TYPE_P(dim) == IS_LONG))
  4678. | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >3, ZREG_TMP1
  4679. }
  4680. if (op1_info & MAY_BE_PACKED_GUARD) {
  4681. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
  4682. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  4683. if (!exit_addr) {
  4684. return 0;
  4685. }
  4686. if (op1_info & MAY_BE_ARRAY_PACKED) {
  4687. | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)]
  4688. | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w
  4689. | beq &exit_addr
  4690. } else {
  4691. | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)]
  4692. | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w
  4693. | bne &exit_addr
  4694. }
  4695. }
  4696. if (type == BP_VAR_W) {
  4697. | // hval = Z_LVAL_P(dim);
  4698. | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1
  4699. op2_loaded = 1;
  4700. }
  4701. if (op1_info & MAY_BE_ARRAY_PACKED) {
  4702. zend_long val = -1;
  4703. if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
  4704. val = Z_LVAL_P(Z_ZV(op2_addr));
  4705. if (val >= 0 && val < HT_MAX_SIZE) {
  4706. packed_loaded = 1;
  4707. } else {
  4708. bad_packed_key = 1;
  4709. }
  4710. } else {
  4711. if (!op2_loaded) {
  4712. | // hval = Z_LVAL_P(dim);
  4713. | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1
  4714. op2_loaded = 1;
  4715. }
  4716. packed_loaded = 1;
  4717. }
  4718. if (dim_type == IS_UNDEF && type == BP_VAR_W) {
  4719. /* don't generate "fast" code for packed array */
  4720. packed_loaded = 0;
  4721. }
  4722. if (packed_loaded) {
  4723. | // ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
  4724. if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
  4725. | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)]
  4726. | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w
  4727. | beq >4 // HASH_FIND
  4728. }
  4729. | // if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
  4730. | ldr REG0w, [FCARG1x, #offsetof(zend_array, nNumUsed)]
  4731. if (val == 0) {
  4732. | cmp REG0, xzr
  4733. } else if (val > 0 && !op2_loaded) {
  4734. | CMP_64_WITH_CONST REG0, val, TMP1
  4735. } else {
  4736. | cmp REG0, FCARG2x
  4737. }
  4738. if (type == BP_JIT_IS) {
  4739. if (not_found_exit_addr) {
  4740. | bls &not_found_exit_addr
  4741. } else {
  4742. | bls >9 // NOT_FOUND
  4743. }
  4744. } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
  4745. | bls &exit_addr
  4746. } else if (type == BP_VAR_IS && not_found_exit_addr) {
  4747. | bls &not_found_exit_addr
  4748. } else if (type == BP_VAR_RW && not_found_exit_addr) {
  4749. | bls &not_found_exit_addr
  4750. } else if (type == BP_VAR_IS && found_exit_addr) {
  4751. | bls >7 // NOT_FOUND
  4752. } else {
  4753. | bls >2 // NOT_FOUND
  4754. }
  4755. | // _ret = &_ht->arData[_h].val;
  4756. if (val >= 0) {
  4757. | ldr REG0, [FCARG1x, #offsetof(zend_array, arData)]
  4758. if (val != 0) {
  4759. | ADD_SUB_64_WITH_CONST add, REG0, REG0, (val * sizeof(Bucket)), TMP1
  4760. }
  4761. } else {
  4762. | ldr TMP1, [FCARG1x, #offsetof(zend_array, arData)]
  4763. | add REG0, TMP1, FCARG2x, lsl #5
  4764. }
  4765. }
  4766. }
  4767. switch (type) {
  4768. case BP_JIT_IS:
  4769. if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
  4770. if (packed_loaded) {
  4771. | b >5
  4772. }
  4773. |4:
  4774. if (!op2_loaded) {
  4775. | // hval = Z_LVAL_P(dim);
  4776. | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1
  4777. }
  4778. if (packed_loaded) {
  4779. | EXT_CALL _zend_hash_index_find, REG0
  4780. } else {
  4781. | EXT_CALL zend_hash_index_find, REG0
  4782. }
  4783. | mov REG0, RETVALx
  4784. if (not_found_exit_addr) {
  4785. | cbz REG0, &not_found_exit_addr
  4786. } else {
  4787. | cbz REG0, >9 // NOT_FOUND
  4788. }
  4789. if (op2_info & MAY_BE_STRING) {
  4790. | b >5
  4791. }
  4792. } else if (packed_loaded) {
  4793. if (op2_info & MAY_BE_STRING) {
  4794. | b >5
  4795. }
  4796. } else if (not_found_exit_addr) {
  4797. | b &not_found_exit_addr
  4798. } else {
  4799. | b >9 // NOT_FOUND
  4800. }
  4801. break;
  4802. case BP_VAR_R:
  4803. case BP_VAR_IS:
  4804. case BP_VAR_UNSET:
  4805. if (packed_loaded) {
  4806. if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
  4807. | IF_NOT_Z_TYPE REG0, IS_UNDEF, >8, TMP1w
  4808. } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
  4809. /* perform IS_UNDEF check only after result type guard (during deoptimization) */
  4810. if (!found_exit_addr || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) {
  4811. | IF_Z_TYPE REG0, IS_UNDEF, &exit_addr, TMP1w
  4812. }
  4813. } else if (type == BP_VAR_IS && not_found_exit_addr) {
  4814. | IF_Z_TYPE REG0, IS_UNDEF, &not_found_exit_addr, TMP1w
  4815. } else if (type == BP_VAR_IS && found_exit_addr) {
  4816. | IF_Z_TYPE REG0, IS_UNDEF, >7, TMP1w // NOT_FOUND
  4817. } else {
  4818. | IF_Z_TYPE REG0, IS_UNDEF, >2, TMP1w // NOT_FOUND
  4819. }
  4820. }
  4821. if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (packed_loaded && (op1_info & MAY_BE_ARRAY_NUMERIC_HASH))) {
  4822. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
  4823. | b &exit_addr
  4824. } else if (type == BP_VAR_IS && not_found_exit_addr) {
  4825. | b &not_found_exit_addr
  4826. } else if (type == BP_VAR_IS && found_exit_addr) {
  4827. | b >7 // NOT_FOUND
  4828. } else {
  4829. | b >2 // NOT_FOUND
  4830. }
  4831. }
  4832. if (!packed_loaded || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) {
  4833. |4:
  4834. if (!op2_loaded) {
  4835. | // hval = Z_LVAL_P(dim);
  4836. | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1
  4837. }
  4838. if (packed_loaded) {
  4839. | EXT_CALL _zend_hash_index_find, REG0
  4840. } else {
  4841. | EXT_CALL zend_hash_index_find, REG0
  4842. }
  4843. | mov REG0, RETVALx
  4844. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
  4845. | cbz REG0, &exit_addr
  4846. } else if (type == BP_VAR_IS && not_found_exit_addr) {
  4847. | cbz REG0, &not_found_exit_addr
  4848. } else if (type == BP_VAR_IS && found_exit_addr) {
  4849. | cbz REG0, >7 // NOT_FOUND
  4850. } else {
  4851. | cbz REG0, >2 // NOT_FOUND
  4852. }
  4853. }
  4854. |.cold_code
  4855. |2:
  4856. switch (type) {
  4857. case BP_VAR_R:
  4858. if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
  4859. | // zend_error(E_WARNING,"Undefined array key " ZEND_LONG_FMT, hval);
  4860. | // retval = &EG(uninitialized_zval);
  4861. | UNDEFINED_OFFSET opline
  4862. | b >9
  4863. }
  4864. break;
  4865. case BP_VAR_IS:
  4866. case BP_VAR_UNSET:
  4867. if (!not_found_exit_addr && !found_exit_addr) {
  4868. | // retval = &EG(uninitialized_zval);
  4869. | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2
  4870. | b >9
  4871. }
  4872. break;
  4873. default:
  4874. ZEND_UNREACHABLE();
  4875. }
  4876. |.code
  4877. break;
  4878. case BP_VAR_RW:
  4879. if (packed_loaded && !not_found_exit_addr) {
  4880. | IF_NOT_Z_TYPE REG0, IS_UNDEF, >8, TMP1w
  4881. }
  4882. if (!packed_loaded ||
  4883. !not_found_exit_addr ||
  4884. (op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) {
  4885. if (packed_loaded && not_found_exit_addr) {
  4886. |.cold_code
  4887. }
  4888. |2:
  4889. |4:
  4890. if (!op2_loaded) {
  4891. | // hval = Z_LVAL_P(dim);
  4892. | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1
  4893. }
  4894. | SET_EX_OPLINE opline, REG0
  4895. if (packed_loaded) {
  4896. | EXT_CALL zend_jit_hash_index_lookup_rw_no_packed, REG0
  4897. } else {
  4898. | EXT_CALL zend_jit_hash_index_lookup_rw, REG0
  4899. }
  4900. | mov REG0, RETVALx
  4901. if (not_found_exit_addr) {
  4902. if (packed_loaded) {
  4903. | cbnz REG0, >8
  4904. | b &not_found_exit_addr
  4905. |.code
  4906. } else {
  4907. | cbz REG0, &not_found_exit_addr
  4908. }
  4909. } else {
  4910. | cbz REG0, >9
  4911. }
  4912. }
  4913. break;
  4914. case BP_VAR_W:
  4915. if (packed_loaded) {
  4916. | IF_NOT_Z_TYPE REG0, IS_UNDEF, >8, TMP1w
  4917. }
  4918. if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) || packed_loaded || bad_packed_key || dim_type == IS_UNDEF) {
  4919. |2:
  4920. |4:
  4921. if (!op2_loaded) {
  4922. | // hval = Z_LVAL_P(dim);
  4923. | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1
  4924. }
  4925. | EXT_CALL zend_hash_index_lookup, REG0
  4926. | mov REG0, RETVALx
  4927. }
  4928. break;
  4929. default:
  4930. ZEND_UNREACHABLE();
  4931. }
  4932. if (type != BP_JIT_IS && (op2_info & MAY_BE_STRING)) {
  4933. | b >8
  4934. }
  4935. }
  4936. if (op2_info & MAY_BE_STRING) {
  4937. |3:
  4938. if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
  4939. | // if (EXPECTED(Z_TYPE_P(dim) == IS_STRING))
  4940. | IF_NOT_ZVAL_TYPE op2_addr, IS_STRING, >3, ZREG_TMP1
  4941. }
  4942. | // offset_key = Z_STR_P(dim);
  4943. | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1
  4944. | // retval = zend_hash_find(ht, offset_key);
  4945. switch (type) {
  4946. case BP_JIT_IS:
  4947. if (opline->op2_type != IS_CONST) {
  4948. | ldrb TMP1w, [FCARG2x, #offsetof(zend_string, val)]
  4949. | cmp TMP1w, #((uint8_t) ('9'))
  4950. | ble >1
  4951. |.cold_code
  4952. |1:
  4953. | EXT_CALL zend_jit_symtable_find, REG0
  4954. | b >1
  4955. |.code
  4956. | EXT_CALL zend_hash_find, REG0
  4957. |1:
  4958. } else {
  4959. | EXT_CALL zend_hash_find_known_hash, REG0
  4960. }
  4961. | mov REG0, RETVALx
  4962. if (not_found_exit_addr) {
  4963. | cbz REG0, &not_found_exit_addr
  4964. } else {
  4965. | cbz REG0, >9 // NOT_FOUND
  4966. }
  4967. break;
  4968. case BP_VAR_R:
  4969. case BP_VAR_IS:
  4970. case BP_VAR_UNSET:
  4971. if (opline->op2_type != IS_CONST) {
  4972. | ldrb TMP1w, [FCARG2x, #offsetof(zend_string, val)]
  4973. | cmp TMP1w, #((uint8_t) ('9'))
  4974. | ble >1
  4975. |.cold_code
  4976. |1:
  4977. | EXT_CALL zend_jit_symtable_find, REG0
  4978. | b >1
  4979. |.code
  4980. | EXT_CALL zend_hash_find, REG0
  4981. |1:
  4982. } else {
  4983. | EXT_CALL zend_hash_find_known_hash, REG0
  4984. }
  4985. | mov REG0, RETVALx
  4986. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
  4987. | cbz REG0, &exit_addr
  4988. } else if (type == BP_VAR_IS && not_found_exit_addr) {
  4989. | cbz REG0, &not_found_exit_addr
  4990. } else if (type == BP_VAR_IS && found_exit_addr) {
  4991. | cbz REG0, >7
  4992. } else {
  4993. | cbz REG0, >2 // NOT_FOUND
  4994. |.cold_code
  4995. |2:
  4996. switch (type) {
  4997. case BP_VAR_R:
  4998. // zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key));
  4999. | UNDEFINED_INDEX opline
  5000. | b >9
  5001. break;
  5002. case BP_VAR_IS:
  5003. case BP_VAR_UNSET:
  5004. | // retval = &EG(uninitialized_zval);
  5005. | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2
  5006. | b >9
  5007. break;
  5008. default:
  5009. ZEND_UNREACHABLE();
  5010. }
  5011. |.code
  5012. }
  5013. break;
  5014. case BP_VAR_RW:
  5015. | SET_EX_OPLINE opline, REG0
  5016. if (opline->op2_type != IS_CONST) {
  5017. | EXT_CALL zend_jit_symtable_lookup_rw, REG0
  5018. } else {
  5019. | EXT_CALL zend_jit_hash_lookup_rw, REG0
  5020. }
  5021. | mov REG0, RETVALx
  5022. if (not_found_exit_addr) {
  5023. | cbz REG0, &not_found_exit_addr
  5024. } else {
  5025. | cbz REG0, >9
  5026. }
  5027. break;
  5028. case BP_VAR_W:
  5029. if (opline->op2_type != IS_CONST) {
  5030. | EXT_CALL zend_jit_symtable_lookup_w, REG0
  5031. } else {
  5032. | EXT_CALL zend_hash_lookup, REG0
  5033. }
  5034. | mov REG0, RETVALx
  5035. break;
  5036. default:
  5037. ZEND_UNREACHABLE();
  5038. }
  5039. }
  5040. if (type == BP_JIT_IS && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))) {
  5041. |5:
  5042. if (op1_info & MAY_BE_ARRAY_OF_REF) {
  5043. | ZVAL_DEREF REG0, MAY_BE_REF, TMP1w
  5044. }
  5045. | ldrb TMP1w, [REG0,#offsetof(zval, u1.v.type)]
  5046. | cmp TMP1w, #IS_NULL
  5047. if (not_found_exit_addr) {
  5048. | ble &not_found_exit_addr
  5049. } else if (found_exit_addr) {
  5050. | bgt &found_exit_addr
  5051. } else {
  5052. | ble >9 // NOT FOUND
  5053. }
  5054. }
  5055. if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
  5056. if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) {
  5057. |.cold_code
  5058. |3:
  5059. }
  5060. | SET_EX_OPLINE opline, REG0
  5061. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  5062. switch (type) {
  5063. case BP_VAR_R:
  5064. | LOAD_ZVAL_ADDR CARG3, res_addr
  5065. | EXT_CALL zend_jit_fetch_dim_r_helper, REG0
  5066. | mov REG0, RETVALx
  5067. | b >9
  5068. break;
  5069. case BP_JIT_IS:
  5070. | EXT_CALL zend_jit_fetch_dim_isset_helper, REG0
  5071. | mov REG0, RETVALx
  5072. if (not_found_exit_addr) {
  5073. | cbz REG0, &not_found_exit_addr
  5074. if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) {
  5075. | b >8
  5076. }
  5077. } else if (found_exit_addr) {
  5078. | cbnz REG0, &found_exit_addr
  5079. if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) {
  5080. | b >9
  5081. }
  5082. } else {
  5083. | cbnz REG0, >8
  5084. | b >9
  5085. }
  5086. break;
  5087. case BP_VAR_IS:
  5088. case BP_VAR_UNSET:
  5089. | LOAD_ZVAL_ADDR CARG3, res_addr
  5090. | EXT_CALL zend_jit_fetch_dim_is_helper, REG0
  5091. | mov REG0, RETVALx
  5092. | b >9
  5093. break;
  5094. case BP_VAR_RW:
  5095. | EXT_CALL zend_jit_fetch_dim_rw_helper, REG0
  5096. | mov REG0, RETVALx
  5097. | cbnz REG0, >8
  5098. | b >9
  5099. break;
  5100. case BP_VAR_W:
  5101. | EXT_CALL zend_jit_fetch_dim_w_helper, REG0
  5102. | mov REG0, RETVALx
  5103. | cbnz REG0, >8
  5104. | b >9
  5105. break;
  5106. default:
  5107. ZEND_UNREACHABLE();
  5108. }
  5109. if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) {
  5110. |.code
  5111. }
  5112. }
  5113. return 1;
  5114. }
  5115. static int zend_jit_simple_assign(dasm_State **Dst,
  5116. const zend_op *opline,
  5117. zend_jit_addr var_addr,
  5118. uint32_t var_info,
  5119. uint32_t var_def_info,
  5120. zend_uchar val_type,
  5121. zend_jit_addr val_addr,
  5122. uint32_t val_info,
  5123. zend_jit_addr res_addr,
  5124. int in_cold,
  5125. int save_r1)
  5126. /* Labels: 1,2,3 */
  5127. {
  5128. zend_reg tmp_reg;
  5129. if (Z_MODE(var_addr) == IS_REG || Z_REG(var_addr) != ZREG_REG0) {
  5130. tmp_reg = ZREG_REG0;
  5131. } else {
  5132. /* ASSIGN_DIM */
  5133. tmp_reg = ZREG_FCARG1;
  5134. }
  5135. if (Z_MODE(val_addr) == IS_CONST_ZVAL) {
  5136. zval *zv = Z_ZV(val_addr);
  5137. if (!res_addr) {
  5138. | ZVAL_COPY_CONST var_addr, var_info, var_def_info, zv, tmp_reg, ZREG_TMP1, ZREG_FPR0
  5139. } else {
  5140. | ZVAL_COPY_CONST_2 var_addr, res_addr, var_info, var_def_info, zv, tmp_reg, ZREG_TMP1, ZREG_FPR0
  5141. }
  5142. if (Z_REFCOUNTED_P(zv)) {
  5143. if (!res_addr) {
  5144. | ADDREF_CONST zv, TMP1, TMP2
  5145. } else {
  5146. | ADDREF_CONST_2 zv, TMP1, TMP2
  5147. }
  5148. }
  5149. } else {
  5150. if (val_info & MAY_BE_UNDEF) {
  5151. if (in_cold) {
  5152. | IF_NOT_ZVAL_TYPE val_addr, IS_UNDEF, >2, ZREG_TMP1
  5153. } else {
  5154. | IF_ZVAL_TYPE val_addr, IS_UNDEF, >1, ZREG_TMP1
  5155. |.cold_code
  5156. |1:
  5157. }
  5158. | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
  5159. if (save_r1) {
  5160. | str FCARG1x, T1 // save
  5161. }
  5162. | SET_ZVAL_TYPE_INFO var_addr, IS_NULL, TMP1w, TMP2
  5163. if (res_addr) {
  5164. | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2
  5165. }
  5166. if (opline) {
  5167. | SET_EX_OPLINE opline, Rx(tmp_reg)
  5168. }
  5169. ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL && Z_REG(val_addr) == ZREG_FP);
  5170. | LOAD_32BIT_VAL FCARG1w, Z_OFFSET(val_addr)
  5171. | EXT_CALL zend_jit_undefined_op_helper, REG0
  5172. | cbz RETVALx, ->exception_handler_undef
  5173. if (save_r1) {
  5174. | ldr FCARG1x, T1 // restore
  5175. }
  5176. | b >3
  5177. if (in_cold) {
  5178. |2:
  5179. } else {
  5180. |.code
  5181. }
  5182. }
  5183. if (val_info & MAY_BE_REF) {
  5184. if (val_type == IS_CV) {
  5185. ZEND_ASSERT(Z_REG(var_addr) != ZREG_REG2);
  5186. if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_REG2 || Z_OFFSET(val_addr) != 0) {
  5187. | LOAD_ZVAL_ADDR REG2, val_addr
  5188. }
  5189. | ZVAL_DEREF REG2, val_info, TMP1w
  5190. val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG2, 0);
  5191. } else {
  5192. zend_jit_addr ref_addr;
  5193. if (in_cold) {
  5194. | IF_NOT_ZVAL_TYPE val_addr, IS_REFERENCE, >1, ZREG_TMP1
  5195. } else {
  5196. | IF_ZVAL_TYPE val_addr, IS_REFERENCE, >1, ZREG_TMP1
  5197. |.cold_code
  5198. |1:
  5199. }
  5200. if (Z_REG(val_addr) == ZREG_REG2) {
  5201. | str REG2, T1 // save
  5202. }
  5203. | // zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
  5204. | GET_ZVAL_PTR REG2, val_addr, TMP1
  5205. | GC_DELREF REG2, TMP1w
  5206. | // ZVAL_COPY_VALUE(return_value, &ref->val);
  5207. ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG2, offsetof(zend_reference, val));
  5208. if (!res_addr) {
  5209. | ZVAL_COPY_VALUE var_addr, var_info, ref_addr, val_info, ZREG_REG2, tmp_reg, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  5210. } else {
  5211. | ZVAL_COPY_VALUE_2 var_addr, var_info, res_addr, ref_addr, val_info, ZREG_REG2, tmp_reg, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  5212. }
  5213. | beq >2 // GC_DELREF() reached zero
  5214. | IF_NOT_REFCOUNTED REG2w, >3, TMP1w
  5215. if (!res_addr) {
  5216. | GC_ADDREF Rx(tmp_reg), TMP1w
  5217. } else {
  5218. | GC_ADDREF_2 Rx(tmp_reg), TMP1w
  5219. }
  5220. | b >3
  5221. |2:
  5222. if (res_addr) {
  5223. | IF_NOT_REFCOUNTED REG2w, >2, TMP1w
  5224. | GC_ADDREF Rx(tmp_reg), TMP1w
  5225. |2:
  5226. }
  5227. if (Z_REG(val_addr) == ZREG_REG2) {
  5228. | ldr REG2, T1 // restore
  5229. }
  5230. if (save_r1) {
  5231. | str FCARG1x, T1 // save
  5232. }
  5233. | GET_ZVAL_PTR FCARG1x, val_addr, TMP1
  5234. | EFREE_REFERENCE
  5235. if (save_r1) {
  5236. | ldr FCARG1x, T1 // restore
  5237. }
  5238. | b >3
  5239. if (in_cold) {
  5240. |1:
  5241. } else {
  5242. |.code
  5243. }
  5244. }
  5245. }
  5246. if (!res_addr) {
  5247. | ZVAL_COPY_VALUE var_addr, var_info, val_addr, val_info, ZREG_REG2, tmp_reg, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  5248. } else {
  5249. | ZVAL_COPY_VALUE_2 var_addr, var_info, res_addr, val_addr, val_info, ZREG_REG2, tmp_reg, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  5250. }
  5251. if (val_type == IS_CV) {
  5252. if (!res_addr) {
  5253. | TRY_ADDREF val_info, REG2w, Rx(tmp_reg), TMP1w
  5254. } else {
  5255. | TRY_ADDREF_2 val_info, REG2w, Rx(tmp_reg), TMP1w
  5256. }
  5257. } else {
  5258. if (res_addr) {
  5259. | TRY_ADDREF val_info, REG2w, Rx(tmp_reg), TMP1w
  5260. }
  5261. }
  5262. |3:
  5263. }
  5264. return 1;
  5265. }
  5266. static int zend_jit_assign_to_typed_ref(dasm_State **Dst,
  5267. const zend_op *opline,
  5268. zend_uchar val_type,
  5269. zend_jit_addr val_addr,
  5270. zend_jit_addr res_addr,
  5271. bool check_exception)
  5272. {
  5273. | // if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(variable_ptr)))) {
  5274. | ldr TMP1, [FCARG1x, #offsetof(zend_reference, sources.ptr)]
  5275. | cbnz TMP1, >2
  5276. |.cold_code
  5277. |2:
  5278. if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2 || Z_OFFSET(val_addr) != 0) {
  5279. | LOAD_ZVAL_ADDR FCARG2x, val_addr
  5280. }
  5281. if (opline) {
  5282. | SET_EX_OPLINE opline, REG0
  5283. }
  5284. if (val_type == IS_CONST) {
  5285. | EXT_CALL zend_jit_assign_const_to_typed_ref, REG0
  5286. } else if (val_type == IS_TMP_VAR) {
  5287. | EXT_CALL zend_jit_assign_tmp_to_typed_ref, REG0
  5288. } else if (val_type == IS_VAR) {
  5289. | EXT_CALL zend_jit_assign_var_to_typed_ref, REG0
  5290. } else if (val_type == IS_CV) {
  5291. | EXT_CALL zend_jit_assign_cv_to_typed_ref, REG0
  5292. } else {
  5293. ZEND_UNREACHABLE();
  5294. }
  5295. if (res_addr) {
  5296. zend_jit_addr ret_addr = ZEND_ADDR_MEM_ZVAL(ZREG_X0, 0); // RETVAL
  5297. | ZVAL_COPY_VALUE res_addr, -1, ret_addr, -1, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  5298. | TRY_ADDREF -1, REG1w, REG2, TMP1w
  5299. }
  5300. if (check_exception) {
  5301. | // if (UNEXPECTED(EG(exception) != NULL)) {
  5302. | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1
  5303. | cbz REG0, >8 // END OF zend_jit_assign_to_variable()
  5304. | b ->exception_handler
  5305. } else {
  5306. | b >8
  5307. }
  5308. |.code
  5309. return 1;
  5310. }
  5311. static int zend_jit_assign_to_variable_call(dasm_State **Dst,
  5312. const zend_op *opline,
  5313. zend_jit_addr __var_use_addr,
  5314. zend_jit_addr var_addr,
  5315. uint32_t __var_info,
  5316. uint32_t __var_def_info,
  5317. zend_uchar val_type,
  5318. zend_jit_addr val_addr,
  5319. uint32_t val_info,
  5320. zend_jit_addr __res_addr,
  5321. bool __check_exception)
  5322. {
  5323. if (val_info & MAY_BE_UNDEF) {
  5324. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  5325. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  5326. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  5327. if (!exit_addr) {
  5328. return 0;
  5329. }
  5330. | IF_ZVAL_TYPE val_addr, IS_UNDEF, &exit_addr, ZREG_TMP1
  5331. } else {
  5332. | IF_ZVAL_TYPE val_addr, IS_UNDEF, >1, ZREG_TMP1
  5333. |.cold_code
  5334. |1:
  5335. ZEND_ASSERT(Z_REG(val_addr) == ZREG_FP);
  5336. if (Z_REG(var_addr) != ZREG_FP) {
  5337. | str Rx(Z_REG(var_addr)), T1 // save
  5338. }
  5339. | SET_EX_OPLINE opline, REG0
  5340. | LOAD_32BIT_VAL FCARG1w, Z_OFFSET(val_addr)
  5341. | EXT_CALL zend_jit_undefined_op_helper, REG0
  5342. if (Z_REG(var_addr) != ZREG_FP) {
  5343. | ldr Rx(Z_REG(var_addr)), T1 // restore
  5344. }
  5345. if (Z_MODE(var_addr) != IS_MEM_ZVAL || Z_REG(var_addr) != ZREG_FCARG1 || Z_OFFSET(var_addr) != 0) {
  5346. | LOAD_ZVAL_ADDR FCARG1x, var_addr
  5347. }
  5348. | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval
  5349. | bl ->assign_const
  5350. | b >9
  5351. |.code
  5352. |1:
  5353. }
  5354. }
  5355. if (Z_MODE(var_addr) != IS_MEM_ZVAL || Z_REG(var_addr) != ZREG_FCARG1 || Z_OFFSET(var_addr) != 0) {
  5356. | LOAD_ZVAL_ADDR FCARG1x, var_addr
  5357. }
  5358. if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2 || Z_OFFSET(val_addr) != 0) {
  5359. | LOAD_ZVAL_ADDR FCARG2x, val_addr
  5360. }
  5361. if (opline) {
  5362. | SET_EX_OPLINE opline, REG0
  5363. }
  5364. if (!(val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
  5365. | bl ->assign_tmp
  5366. } else if (val_type == IS_CONST) {
  5367. | bl ->assign_const
  5368. } else if (val_type == IS_TMP_VAR) {
  5369. | bl ->assign_tmp
  5370. } else if (val_type == IS_VAR) {
  5371. if (!(val_info & MAY_BE_REF)) {
  5372. | bl ->assign_tmp
  5373. } else {
  5374. | bl ->assign_var
  5375. }
  5376. } else if (val_type == IS_CV) {
  5377. if (!(val_info & MAY_BE_REF)) {
  5378. | bl ->assign_cv_noref
  5379. } else {
  5380. | bl ->assign_cv
  5381. }
  5382. if ((val_info & MAY_BE_UNDEF) && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
  5383. |9:
  5384. }
  5385. } else {
  5386. ZEND_UNREACHABLE();
  5387. }
  5388. return 1;
  5389. }
  5390. static int zend_jit_assign_to_variable(dasm_State **Dst,
  5391. const zend_op *opline,
  5392. zend_jit_addr var_use_addr,
  5393. zend_jit_addr var_addr,
  5394. uint32_t var_info,
  5395. uint32_t var_def_info,
  5396. zend_uchar val_type,
  5397. zend_jit_addr val_addr,
  5398. uint32_t val_info,
  5399. zend_jit_addr res_addr,
  5400. bool check_exception)
  5401. /* Labels: 1,2,3,4,5,8 */
  5402. {
  5403. int done = 0;
  5404. zend_reg ref_reg, tmp_reg;
  5405. if (Z_MODE(var_addr) == IS_REG || Z_REG(var_use_addr) != ZREG_REG0) {
  5406. ref_reg = ZREG_FCARG1;
  5407. tmp_reg = ZREG_REG0;
  5408. } else {
  5409. /* ASSIGN_DIM */
  5410. ref_reg = ZREG_REG0;
  5411. tmp_reg = ZREG_FCARG1;
  5412. }
  5413. if (var_info & MAY_BE_REF) {
  5414. if (Z_MODE(var_use_addr) != IS_MEM_ZVAL || Z_REG(var_use_addr) != ref_reg || Z_OFFSET(var_use_addr) != 0) {
  5415. | LOAD_ZVAL_ADDR Rx(ref_reg), var_use_addr
  5416. var_addr = var_use_addr = ZEND_ADDR_MEM_ZVAL(ref_reg, 0);
  5417. }
  5418. | // if (Z_ISREF_P(variable_ptr)) {
  5419. | IF_NOT_Z_TYPE Rx(ref_reg), IS_REFERENCE, >3, TMP1w
  5420. | // if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(variable_ptr)))) {
  5421. | GET_Z_PTR FCARG1x, Rx(ref_reg)
  5422. if (!zend_jit_assign_to_typed_ref(Dst, opline, val_type, val_addr, res_addr, check_exception)) {
  5423. return 0;
  5424. }
  5425. | add Rx(ref_reg), FCARG1x, #offsetof(zend_reference, val)
  5426. |3:
  5427. }
  5428. if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
  5429. if (RC_MAY_BE_1(var_info)) {
  5430. int in_cold = 0;
  5431. if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  5432. | IF_ZVAL_REFCOUNTED var_use_addr, >1, ZREG_TMP1, ZREG_TMP2
  5433. |.cold_code
  5434. |1:
  5435. in_cold = 1;
  5436. }
  5437. if (Z_REG(var_use_addr) == ZREG_FCARG1 || Z_REG(var_use_addr) == ZREG_REG0) {
  5438. bool keep_gc = 0;
  5439. | GET_ZVAL_PTR Rx(tmp_reg), var_use_addr, TMP1
  5440. #if 0
  5441. // TODO: This optiization doesn't work on ARM
  5442. if (tmp_reg == ZREG_FCARG1) {
  5443. if (Z_MODE(val_addr) == IS_REG) {
  5444. keep_gc = 1;
  5445. } else if ((val_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_GUARD)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) == 0) {
  5446. keep_gc = 1;
  5447. } else if (Z_MODE(val_addr) == IS_CONST_ZVAL) {
  5448. zval *zv = Z_ZV(val_addr);
  5449. if (Z_TYPE_P(zv) == IS_DOUBLE) {
  5450. if (Z_DVAL_P(zv) == 0) {
  5451. keep_gc = 1;
  5452. }
  5453. } else if (IS_SIGNED_32BIT(Z_LVAL_P(zv))) {
  5454. keep_gc = 1;
  5455. }
  5456. } else if (Z_MODE(val_addr) == IS_MEM_ZVAL) {
  5457. if ((val_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
  5458. keep_gc = 1;
  5459. }
  5460. }
  5461. }
  5462. #endif
  5463. if (!keep_gc) {
  5464. | str Rx(tmp_reg), T1 // save
  5465. }
  5466. if (!zend_jit_simple_assign(Dst, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, in_cold, 0)) {
  5467. return 0;
  5468. }
  5469. if (!keep_gc) {
  5470. | ldr FCARG1x, T1 // restore
  5471. }
  5472. } else {
  5473. | GET_ZVAL_PTR FCARG1x, var_use_addr, TMP1
  5474. if (!zend_jit_simple_assign(Dst, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, in_cold, 1)) {
  5475. return 0;
  5476. }
  5477. }
  5478. | GC_DELREF FCARG1x, TMP1w
  5479. if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
  5480. | bne >4
  5481. } else {
  5482. | bne >8
  5483. }
  5484. | ZVAL_DTOR_FUNC var_info, opline, TMP1
  5485. if (in_cold || (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0)) {
  5486. if (check_exception) {
  5487. | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1
  5488. | cbz REG0, >8
  5489. | b ->exception_handler
  5490. } else {
  5491. | b >8
  5492. }
  5493. }
  5494. if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
  5495. |4:
  5496. | IF_GC_MAY_NOT_LEAK FCARG1x, >8, TMP1w, TMP2w
  5497. | EXT_CALL gc_possible_root, REG0
  5498. if (in_cold) {
  5499. | b >8
  5500. }
  5501. }
  5502. if (in_cold) {
  5503. |.code
  5504. } else {
  5505. done = 1;
  5506. }
  5507. } else /* if (RC_MAY_BE_N(var_info)) */ {
  5508. if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  5509. | IF_NOT_ZVAL_REFCOUNTED var_use_addr, >5, ZREG_TMP1, ZREG_TMP2
  5510. }
  5511. if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
  5512. if (Z_REG(var_use_addr) != ZREG_FP) {
  5513. | str Rx(Z_REG(var_use_addr)), T1 // save
  5514. }
  5515. | GET_ZVAL_PTR FCARG1x, var_use_addr, TMP1
  5516. | GC_DELREF FCARG1x, TMP1w
  5517. | IF_GC_MAY_NOT_LEAK FCARG1x, >5, TMP1w, TMP2w
  5518. | EXT_CALL gc_possible_root, TMP1
  5519. if (Z_REG(var_use_addr) != ZREG_FP) {
  5520. | ldr Rx(Z_REG(var_use_addr)), T1 // restore
  5521. }
  5522. } else {
  5523. | GET_ZVAL_PTR Rx(tmp_reg), var_use_addr, TMP1
  5524. | GC_DELREF Rx(tmp_reg), TMP1w
  5525. }
  5526. |5:
  5527. }
  5528. }
  5529. if (!done && !zend_jit_simple_assign(Dst, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, 0, 0)) {
  5530. return 0;
  5531. }
  5532. |8:
  5533. return 1;
  5534. }
  5535. static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, uint32_t val_info, uint8_t dim_type, int may_throw)
  5536. {
  5537. zend_jit_addr op2_addr, op3_addr, res_addr;
  5538. op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0;
  5539. op3_addr = OP1_DATA_ADDR();
  5540. if (opline->result_type == IS_UNUSED) {
  5541. res_addr = 0;
  5542. } else {
  5543. res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  5544. }
  5545. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (val_info & MAY_BE_UNDEF)) {
  5546. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  5547. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  5548. if (!exit_addr) {
  5549. return 0;
  5550. }
  5551. | IF_ZVAL_TYPE op3_addr, IS_UNDEF, &exit_addr, ZREG_TMP1
  5552. val_info &= ~MAY_BE_UNDEF;
  5553. }
  5554. if (op1_info & MAY_BE_REF) {
  5555. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  5556. | IF_NOT_Z_TYPE FCARG1x, IS_REFERENCE, >1, TMP1w
  5557. | GET_Z_PTR FCARG2x, FCARG1x
  5558. | ldrb TMP1w, [FCARG2x, #(offsetof(zend_reference, val) + offsetof(zval, u1.v.type))]
  5559. | cmp TMP1w, #IS_ARRAY
  5560. | bne >2
  5561. | add FCARG1x, FCARG2x, #offsetof(zend_reference, val)
  5562. | b >3
  5563. |.cold_code
  5564. |2:
  5565. | SET_EX_OPLINE opline, REG0
  5566. | EXT_CALL zend_jit_prepare_assign_dim_ref, REG0
  5567. | mov FCARG1x, RETVALx
  5568. | cbnz FCARG1x, >1
  5569. | b ->exception_handler_undef
  5570. |.code
  5571. |1:
  5572. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  5573. }
  5574. if (op1_info & MAY_BE_ARRAY) {
  5575. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
  5576. | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7, ZREG_TMP1
  5577. }
  5578. |3:
  5579. | SEPARATE_ARRAY op1_addr, op1_info, 1, ZREG_TMP1, ZREG_TMP2
  5580. } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) {
  5581. if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
  5582. | CMP_ZVAL_TYPE op1_addr, IS_NULL, ZREG_TMP1
  5583. | bgt >7
  5584. }
  5585. | // ZVAL_ARR(container, zend_new_array(8));
  5586. if (Z_REG(op1_addr) != ZREG_FP) {
  5587. | str Rx(Z_REG(op1_addr)), T1 // save
  5588. }
  5589. | EXT_CALL _zend_new_array_0, REG0
  5590. | mov REG0, RETVALx
  5591. if (Z_REG(op1_addr) != ZREG_FP) {
  5592. | ldr Rx(Z_REG(op1_addr)), T1 // restore
  5593. }
  5594. | SET_ZVAL_LVAL_FROM_REG op1_addr, REG0, TMP1
  5595. | SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX, TMP1w, TMP2
  5596. | mov FCARG1x, REG0
  5597. }
  5598. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
  5599. |6:
  5600. if (opline->op2_type == IS_UNUSED) {
  5601. uint32_t var_info = MAY_BE_NULL;
  5602. zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  5603. | // var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
  5604. | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval
  5605. | EXT_CALL zend_hash_next_index_insert, REG0
  5606. | // if (UNEXPECTED(!var_ptr)) {
  5607. | mov REG0, RETVALx
  5608. | cbz REG0, >1
  5609. |.cold_code
  5610. |1:
  5611. | // zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
  5612. | CANNOT_ADD_ELEMENT opline
  5613. | //ZEND_VM_C_GOTO(assign_dim_op_ret_null);
  5614. | b >9
  5615. |.code
  5616. if (!zend_jit_simple_assign(Dst, opline, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0, 0)) {
  5617. return 0;
  5618. }
  5619. } else {
  5620. uint32_t var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
  5621. zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  5622. if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_W, op1_info, op2_info, dim_type, NULL, NULL, NULL)) {
  5623. return 0;
  5624. }
  5625. if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
  5626. var_info |= MAY_BE_REF;
  5627. }
  5628. if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
  5629. var_info |= MAY_BE_RC1;
  5630. }
  5631. |8:
  5632. | // value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
  5633. if (opline->op1_type == IS_VAR) {
  5634. ZEND_ASSERT(opline->result_type == IS_UNUSED);
  5635. if (!zend_jit_assign_to_variable_call(Dst, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
  5636. return 0;
  5637. }
  5638. } else {
  5639. if (!zend_jit_assign_to_variable(Dst, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
  5640. return 0;
  5641. }
  5642. }
  5643. }
  5644. }
  5645. if (((op1_info & MAY_BE_ARRAY) &&
  5646. (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) ||
  5647. (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY)))) {
  5648. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
  5649. |.cold_code
  5650. |7:
  5651. }
  5652. if ((op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) &&
  5653. (op1_info & MAY_BE_ARRAY)) {
  5654. if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
  5655. | CMP_ZVAL_TYPE op1_addr, IS_NULL, ZREG_TMP1
  5656. | bgt >2
  5657. }
  5658. | // ZVAL_ARR(container, zend_new_array(8));
  5659. if (Z_REG(op1_addr) != ZREG_FP) {
  5660. | str Rx(Z_REG(op1_addr)), T1 // save
  5661. }
  5662. | EXT_CALL _zend_new_array_0, REG0
  5663. | mov REG0, RETVALx
  5664. if (Z_REG(op1_addr) != ZREG_FP) {
  5665. | ldr Rx(Z_REG(op1_addr)), T1 // restore
  5666. }
  5667. | SET_ZVAL_LVAL_FROM_REG op1_addr, REG0, TMP1
  5668. | SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX, TMP1w, TMP2
  5669. | mov FCARG1x, REG0
  5670. | // ZEND_VM_C_GOTO(assign_dim_op_new_array);
  5671. | b <6
  5672. |2:
  5673. }
  5674. if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
  5675. | SET_EX_OPLINE opline, REG0
  5676. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  5677. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  5678. }
  5679. if (opline->op2_type == IS_UNUSED) {
  5680. | mov FCARG2x, xzr
  5681. } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
  5682. ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
  5683. | LOAD_ADDR FCARG2x, (Z_ZV(op2_addr) + 1)
  5684. } else {
  5685. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  5686. }
  5687. if (opline->result_type == IS_UNUSED) {
  5688. | mov CARG4, xzr
  5689. } else {
  5690. | LOAD_ZVAL_ADDR CARG4, res_addr
  5691. }
  5692. | LOAD_ZVAL_ADDR CARG3, op3_addr
  5693. | EXT_CALL zend_jit_assign_dim_helper, REG0
  5694. #ifdef ZEND_JIT_USE_RC_INFERENCE
  5695. if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) && (val_info & MAY_BE_RC1)) {
  5696. /* ASSIGN_DIM may increase refcount of the value */
  5697. val_info |= MAY_BE_RCN;
  5698. }
  5699. #endif
  5700. | FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  5701. }
  5702. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
  5703. if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
  5704. | b >9 // END
  5705. }
  5706. |.code
  5707. }
  5708. }
  5709. #ifdef ZEND_JIT_USE_RC_INFERENCE
  5710. if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
  5711. /* ASSIGN_DIM may increase refcount of the key */
  5712. op2_info |= MAY_BE_RCN;
  5713. }
  5714. #endif
  5715. |9:
  5716. | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  5717. if (may_throw) {
  5718. zend_jit_check_exception(Dst);
  5719. }
  5720. return 1;
  5721. }
  5722. static int zend_jit_assign_dim_op(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op1_def_info, zend_jit_addr op1_addr, uint32_t op2_info, uint32_t op1_data_info, zend_ssa_range *op1_data_range, uint8_t dim_type, int may_throw)
  5723. {
  5724. zend_jit_addr op2_addr, op3_addr, var_addr;
  5725. const void *not_found_exit_addr = NULL;
  5726. uint32_t var_info = MAY_BE_NULL;
  5727. ZEND_ASSERT(opline->result_type == IS_UNUSED);
  5728. op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0;
  5729. op3_addr = OP1_DATA_ADDR();
  5730. if (op1_info & MAY_BE_REF) {
  5731. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  5732. | IF_NOT_Z_TYPE FCARG1x, IS_REFERENCE, >1, TMP1w
  5733. | GET_Z_PTR FCARG2x, FCARG1x
  5734. | ldrb TMP1w, [FCARG2x, #(offsetof(zend_reference, val) + offsetof(zval, u1.v.type))]
  5735. | cmp TMP1w, #IS_ARRAY
  5736. | bne >2
  5737. | add FCARG1x, FCARG2x, #offsetof(zend_reference, val)
  5738. | b >3
  5739. |.cold_code
  5740. |2:
  5741. | SET_EX_OPLINE opline, REG0
  5742. | EXT_CALL zend_jit_prepare_assign_dim_ref, REG0
  5743. | mov FCARG1x, RETVALx
  5744. | cbnz RETVALx, >1
  5745. | b ->exception_handler_undef
  5746. |.code
  5747. |1:
  5748. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  5749. }
  5750. if (op1_info & MAY_BE_ARRAY) {
  5751. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
  5752. | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7, ZREG_TMP1
  5753. }
  5754. |3:
  5755. | SEPARATE_ARRAY op1_addr, op1_info, 1, ZREG_TMP1, ZREG_TMP2
  5756. }
  5757. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) {
  5758. if (op1_info & MAY_BE_ARRAY) {
  5759. |.cold_code
  5760. |7:
  5761. }
  5762. if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
  5763. | CMP_ZVAL_TYPE op1_addr, IS_NULL, ZREG_TMP1
  5764. | bgt >7
  5765. }
  5766. if (Z_REG(op1_addr) != ZREG_FP) {
  5767. | str Rx(Z_REG(op1_addr)), T1 // save
  5768. }
  5769. if (op1_info & MAY_BE_UNDEF) {
  5770. if (op1_info & MAY_BE_NULL) {
  5771. | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1
  5772. }
  5773. | SET_EX_OPLINE opline, REG0
  5774. | LOAD_32BIT_VAL FCARG1x, opline->op1.var
  5775. | EXT_CALL zend_jit_undefined_op_helper, REG0
  5776. |1:
  5777. }
  5778. | // ZVAL_ARR(container, zend_new_array(8));
  5779. | EXT_CALL _zend_new_array_0, REG0
  5780. | mov REG0, RETVALx
  5781. if (Z_REG(op1_addr) != ZREG_FP) {
  5782. | ldr Rx(Z_REG(op1_addr)), T1 // restore
  5783. }
  5784. | SET_ZVAL_LVAL_FROM_REG op1_addr, REG0, TMP1
  5785. | SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX, TMP1w, TMP2
  5786. | mov FCARG1x, REG0
  5787. if (op1_info & MAY_BE_ARRAY) {
  5788. | b >1
  5789. |.code
  5790. |1:
  5791. }
  5792. }
  5793. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
  5794. uint32_t var_def_info = zend_array_element_type(op1_def_info, opline->op1_type, 1, 0);
  5795. |6:
  5796. if (opline->op2_type == IS_UNUSED) {
  5797. var_info = MAY_BE_NULL;
  5798. | // var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
  5799. | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval
  5800. | EXT_CALL zend_hash_next_index_insert, REG0
  5801. | mov REG0, RETVALx
  5802. | // if (UNEXPECTED(!var_ptr)) {
  5803. | cbz REG0, >1
  5804. |.cold_code
  5805. |1:
  5806. | // zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
  5807. | CANNOT_ADD_ELEMENT opline
  5808. | //ZEND_VM_C_GOTO(assign_dim_op_ret_null);
  5809. | b >9
  5810. |.code
  5811. } else {
  5812. var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
  5813. if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
  5814. var_info |= MAY_BE_REF;
  5815. }
  5816. if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
  5817. var_info |= MAY_BE_RC1;
  5818. }
  5819. if (dim_type != IS_UNKNOWN
  5820. && dim_type != IS_UNDEF
  5821. && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
  5822. && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
  5823. && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
  5824. int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
  5825. not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  5826. if (!not_found_exit_addr) {
  5827. return 0;
  5828. }
  5829. }
  5830. if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_RW, op1_info, op2_info, dim_type, NULL, not_found_exit_addr, NULL)) {
  5831. return 0;
  5832. }
  5833. |8:
  5834. if (not_found_exit_addr && dim_type != IS_REFERENCE) {
  5835. | IF_NOT_Z_TYPE, REG0, dim_type, &not_found_exit_addr, TMP1w
  5836. var_info = (1 << dim_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
  5837. }
  5838. if (var_info & MAY_BE_REF) {
  5839. binary_op_type binary_op = get_binary_op(opline->extended_value);
  5840. | IF_NOT_Z_TYPE, REG0, IS_REFERENCE, >1, TMP1w
  5841. | GET_Z_PTR FCARG1x, REG0
  5842. | ldr TMP1, [FCARG1x, #offsetof(zend_reference, sources.ptr)]
  5843. | cbnz TMP1, >2
  5844. | add REG0, FCARG1x, #offsetof(zend_reference, val)
  5845. |.cold_code
  5846. |2:
  5847. | LOAD_ZVAL_ADDR FCARG2x, op3_addr
  5848. | LOAD_ADDR CARG3, binary_op
  5849. | SET_EX_OPLINE opline, REG0
  5850. if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR))
  5851. && (op1_data_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  5852. | EXT_CALL zend_jit_assign_op_to_typed_ref_tmp, REG0
  5853. } else {
  5854. | EXT_CALL zend_jit_assign_op_to_typed_ref, REG0
  5855. }
  5856. | b >9
  5857. |.code
  5858. |1:
  5859. }
  5860. }
  5861. var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  5862. switch (opline->extended_value) {
  5863. case ZEND_ADD:
  5864. case ZEND_SUB:
  5865. case ZEND_MUL:
  5866. case ZEND_DIV:
  5867. if (!zend_jit_math_helper(Dst, opline, opline->extended_value, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, op3_addr, op1_data_info, 0, var_addr, var_def_info, var_info,
  5868. 1 /* may overflow */, may_throw)) {
  5869. return 0;
  5870. }
  5871. break;
  5872. case ZEND_BW_OR:
  5873. case ZEND_BW_AND:
  5874. case ZEND_BW_XOR:
  5875. case ZEND_SL:
  5876. case ZEND_SR:
  5877. case ZEND_MOD:
  5878. if (!zend_jit_long_math_helper(Dst, opline, opline->extended_value,
  5879. IS_CV, opline->op1, var_addr, var_info, NULL,
  5880. (opline+1)->op1_type, (opline+1)->op1, op3_addr, op1_data_info,
  5881. op1_data_range,
  5882. 0, var_addr, var_def_info, var_info, may_throw)) {
  5883. return 0;
  5884. }
  5885. break;
  5886. case ZEND_CONCAT:
  5887. if (!zend_jit_concat_helper(Dst, opline, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, op3_addr, op1_data_info, var_addr,
  5888. may_throw)) {
  5889. return 0;
  5890. }
  5891. break;
  5892. default:
  5893. ZEND_UNREACHABLE();
  5894. }
  5895. | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  5896. }
  5897. if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
  5898. binary_op_type binary_op;
  5899. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
  5900. |.cold_code
  5901. |7:
  5902. }
  5903. | SET_EX_OPLINE opline, REG0
  5904. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  5905. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  5906. }
  5907. if (opline->op2_type == IS_UNUSED) {
  5908. | mov FCARG2x, xzr
  5909. } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
  5910. ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
  5911. | LOAD_ADDR FCARG2x, (Z_ZV(op2_addr) + 1)
  5912. } else {
  5913. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  5914. }
  5915. binary_op = get_binary_op(opline->extended_value);
  5916. | LOAD_ZVAL_ADDR CARG3, op3_addr
  5917. | LOAD_ADDR CARG4, binary_op
  5918. | EXT_CALL zend_jit_assign_dim_op_helper, REG0
  5919. |9:
  5920. | FREE_OP (opline+1)->op1_type, (opline+1)->op1, op1_data_info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  5921. | FREE_OP opline->op2_type, opline->op2, op2_info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  5922. if (may_throw) {
  5923. zend_jit_check_exception(Dst);
  5924. }
  5925. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
  5926. | b >9 // END
  5927. |.code
  5928. |9:
  5929. }
  5930. } else if ((op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY))
  5931. && (!not_found_exit_addr || (var_info & MAY_BE_REF))) {
  5932. |.cold_code
  5933. |9:
  5934. | FREE_OP (opline+1)->op1_type, (opline+1)->op1, op1_data_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  5935. | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  5936. if (may_throw) {
  5937. zend_jit_check_exception(Dst);
  5938. }
  5939. | b >9
  5940. |.code
  5941. |9:
  5942. }
  5943. return 1;
  5944. }
  5945. static int zend_jit_assign_op(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op1_def_info, zend_ssa_range *op1_range, uint32_t op2_info, zend_ssa_range *op2_range, int may_overflow, int may_throw)
  5946. {
  5947. zend_jit_addr op1_addr, op2_addr;
  5948. ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
  5949. ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
  5950. op1_addr = OP1_ADDR();
  5951. op2_addr = OP2_ADDR();
  5952. if (op1_info & MAY_BE_REF) {
  5953. binary_op_type binary_op = get_binary_op(opline->extended_value);
  5954. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  5955. | IF_NOT_Z_TYPE, FCARG1x, IS_REFERENCE, >1, TMP1w
  5956. | GET_Z_PTR FCARG1x, FCARG1x
  5957. | ldr TMP1, [FCARG1x, #offsetof(zend_reference, sources.ptr)]
  5958. | cbnz TMP1, >2
  5959. | add FCARG1x, FCARG1x, #offsetof(zend_reference, val)
  5960. |.cold_code
  5961. |2:
  5962. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  5963. | LOAD_ADDR CARG3, binary_op
  5964. | SET_EX_OPLINE opline, REG0
  5965. if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
  5966. && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  5967. | EXT_CALL zend_jit_assign_op_to_typed_ref_tmp, REG0
  5968. } else {
  5969. | EXT_CALL zend_jit_assign_op_to_typed_ref, REG0
  5970. }
  5971. zend_jit_check_exception(Dst);
  5972. | b >9
  5973. |.code
  5974. |1:
  5975. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  5976. }
  5977. int result;
  5978. switch (opline->extended_value) {
  5979. case ZEND_ADD:
  5980. case ZEND_SUB:
  5981. case ZEND_MUL:
  5982. case ZEND_DIV:
  5983. result = zend_jit_math_helper(Dst, opline, opline->extended_value, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->op1.var, op1_addr, op1_def_info, op1_info, may_overflow, may_throw);
  5984. break;
  5985. case ZEND_BW_OR:
  5986. case ZEND_BW_AND:
  5987. case ZEND_BW_XOR:
  5988. case ZEND_SL:
  5989. case ZEND_SR:
  5990. case ZEND_MOD:
  5991. result = zend_jit_long_math_helper(Dst, opline, opline->extended_value,
  5992. opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
  5993. opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
  5994. opline->op1.var, op1_addr, op1_def_info, op1_info, may_throw);
  5995. break;
  5996. case ZEND_CONCAT:
  5997. result = zend_jit_concat_helper(Dst, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, op1_addr, may_throw);
  5998. break;
  5999. default:
  6000. ZEND_UNREACHABLE();
  6001. }
  6002. |9:
  6003. return result;
  6004. }
  6005. static int zend_jit_cmp_long_long(dasm_State **Dst,
  6006. const zend_op *opline,
  6007. zend_ssa_range *op1_range,
  6008. zend_jit_addr op1_addr,
  6009. zend_ssa_range *op2_range,
  6010. zend_jit_addr op2_addr,
  6011. zend_jit_addr res_addr,
  6012. zend_uchar smart_branch_opcode,
  6013. uint32_t target_label,
  6014. uint32_t target_label2,
  6015. const void *exit_addr,
  6016. bool skip_comparison)
  6017. {
  6018. bool swap = 0;
  6019. bool result;
  6020. if (zend_jit_is_constant_cmp_long_long(opline, op1_range, op1_addr, op2_range, op2_addr, &result)) {
  6021. if (!smart_branch_opcode ||
  6022. smart_branch_opcode == ZEND_JMPZ_EX ||
  6023. smart_branch_opcode == ZEND_JMPNZ_EX) {
  6024. | SET_ZVAL_TYPE_INFO res_addr, (result ? IS_TRUE : IS_FALSE), TMP1w, TMP2
  6025. }
  6026. if (smart_branch_opcode && !exit_addr) {
  6027. if (smart_branch_opcode == ZEND_JMPZ ||
  6028. smart_branch_opcode == ZEND_JMPZ_EX) {
  6029. if (!result) {
  6030. | b => target_label
  6031. }
  6032. } else if (smart_branch_opcode == ZEND_JMPNZ ||
  6033. smart_branch_opcode == ZEND_JMPNZ_EX) {
  6034. if (result) {
  6035. | b => target_label
  6036. }
  6037. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  6038. if (!result) {
  6039. | b => target_label
  6040. } else {
  6041. | b => target_label2
  6042. }
  6043. } else {
  6044. ZEND_UNREACHABLE();
  6045. }
  6046. }
  6047. return 1;
  6048. }
  6049. if (skip_comparison) {
  6050. if (Z_MODE(op1_addr) != IS_REG &&
  6051. (Z_MODE(op2_addr) == IS_REG ||
  6052. (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL))) {
  6053. swap = 1;
  6054. }
  6055. } else if (Z_MODE(op1_addr) == IS_REG) {
  6056. if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
  6057. | cmp Rx(Z_REG(op1_addr)), xzr
  6058. } else {
  6059. | LONG_CMP Z_REG(op1_addr), op2_addr, TMP1
  6060. }
  6061. } else if (Z_MODE(op2_addr) == IS_REG) {
  6062. if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 0) {
  6063. | cmp Rx(Z_REG(op2_addr)), xzr
  6064. } else {
  6065. | LONG_CMP Z_REG(op2_addr), op1_addr, TMP1
  6066. }
  6067. swap = 1;
  6068. } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL) {
  6069. | LONG_CMP_WITH_CONST op2_addr, Z_LVAL_P(Z_ZV(op1_addr)), TMP1, TMP2
  6070. swap = 1;
  6071. } else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_MODE(op1_addr) != IS_CONST_ZVAL) {
  6072. | LONG_CMP_WITH_CONST op1_addr, Z_LVAL_P(Z_ZV(op2_addr)), TMP1, TMP2
  6073. } else {
  6074. | GET_ZVAL_LVAL ZREG_REG0, op1_addr, TMP1
  6075. if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
  6076. | cmp Rx(ZREG_REG0), xzr
  6077. } else {
  6078. | LONG_CMP ZREG_REG0, op2_addr, TMP1
  6079. }
  6080. }
  6081. if (smart_branch_opcode) {
  6082. if (smart_branch_opcode == ZEND_JMPZ_EX ||
  6083. smart_branch_opcode == ZEND_JMPNZ_EX) {
  6084. switch (opline->opcode) {
  6085. case ZEND_IS_EQUAL:
  6086. case ZEND_IS_IDENTICAL:
  6087. case ZEND_CASE:
  6088. case ZEND_CASE_STRICT:
  6089. | cset REG0w, eq
  6090. break;
  6091. case ZEND_IS_NOT_EQUAL:
  6092. case ZEND_IS_NOT_IDENTICAL:
  6093. | cset REG0w, ne
  6094. break;
  6095. case ZEND_IS_SMALLER:
  6096. if (swap) {
  6097. | cset REG0w, gt
  6098. } else {
  6099. | cset REG0w, lt
  6100. }
  6101. break;
  6102. case ZEND_IS_SMALLER_OR_EQUAL:
  6103. if (swap) {
  6104. | cset REG0w, ge
  6105. } else {
  6106. | cset REG0w, le
  6107. }
  6108. break;
  6109. default:
  6110. ZEND_UNREACHABLE();
  6111. }
  6112. | add REG0w, REG0w, #2
  6113. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  6114. }
  6115. if (smart_branch_opcode == ZEND_JMPZ ||
  6116. smart_branch_opcode == ZEND_JMPZ_EX) {
  6117. switch (opline->opcode) {
  6118. case ZEND_IS_EQUAL:
  6119. case ZEND_IS_IDENTICAL:
  6120. case ZEND_CASE:
  6121. case ZEND_CASE_STRICT:
  6122. if (exit_addr) {
  6123. | bne &exit_addr
  6124. } else {
  6125. | bne => target_label
  6126. }
  6127. break;
  6128. case ZEND_IS_NOT_EQUAL:
  6129. if (exit_addr) {
  6130. | beq &exit_addr
  6131. } else {
  6132. | beq => target_label
  6133. }
  6134. break;
  6135. case ZEND_IS_NOT_IDENTICAL:
  6136. if (exit_addr) {
  6137. | bne &exit_addr
  6138. } else {
  6139. | beq => target_label
  6140. }
  6141. break;
  6142. case ZEND_IS_SMALLER:
  6143. if (swap) {
  6144. if (exit_addr) {
  6145. | ble &exit_addr
  6146. } else {
  6147. | ble => target_label
  6148. }
  6149. } else {
  6150. if (exit_addr) {
  6151. | bge &exit_addr
  6152. } else {
  6153. | bge => target_label
  6154. }
  6155. }
  6156. break;
  6157. case ZEND_IS_SMALLER_OR_EQUAL:
  6158. if (swap) {
  6159. if (exit_addr) {
  6160. | blt &exit_addr
  6161. } else {
  6162. | blt => target_label
  6163. }
  6164. } else {
  6165. if (exit_addr) {
  6166. | bgt &exit_addr
  6167. } else {
  6168. | bgt => target_label
  6169. }
  6170. }
  6171. break;
  6172. default:
  6173. ZEND_UNREACHABLE();
  6174. }
  6175. } else if (smart_branch_opcode == ZEND_JMPNZ ||
  6176. smart_branch_opcode == ZEND_JMPNZ_EX) {
  6177. switch (opline->opcode) {
  6178. case ZEND_IS_EQUAL:
  6179. case ZEND_IS_IDENTICAL:
  6180. case ZEND_CASE:
  6181. case ZEND_CASE_STRICT:
  6182. if (exit_addr) {
  6183. | beq &exit_addr
  6184. } else {
  6185. | beq => target_label
  6186. }
  6187. break;
  6188. case ZEND_IS_NOT_EQUAL:
  6189. if (exit_addr) {
  6190. | bne &exit_addr
  6191. } else {
  6192. | bne => target_label
  6193. }
  6194. break;
  6195. case ZEND_IS_NOT_IDENTICAL:
  6196. if (exit_addr) {
  6197. | beq &exit_addr
  6198. } else {
  6199. | bne => target_label
  6200. }
  6201. break;
  6202. case ZEND_IS_SMALLER:
  6203. if (swap) {
  6204. if (exit_addr) {
  6205. | bgt &exit_addr
  6206. } else {
  6207. | bgt => target_label
  6208. }
  6209. } else {
  6210. if (exit_addr) {
  6211. | blt &exit_addr
  6212. } else {
  6213. | blt => target_label
  6214. }
  6215. }
  6216. break;
  6217. case ZEND_IS_SMALLER_OR_EQUAL:
  6218. if (swap) {
  6219. if (exit_addr) {
  6220. | bge &exit_addr
  6221. } else {
  6222. | bge => target_label
  6223. }
  6224. } else {
  6225. if (exit_addr) {
  6226. | ble &exit_addr
  6227. } else {
  6228. | ble => target_label
  6229. }
  6230. }
  6231. break;
  6232. default:
  6233. ZEND_UNREACHABLE();
  6234. }
  6235. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  6236. switch (opline->opcode) {
  6237. case ZEND_IS_EQUAL:
  6238. case ZEND_IS_IDENTICAL:
  6239. case ZEND_CASE:
  6240. case ZEND_CASE_STRICT:
  6241. | bne => target_label
  6242. break;
  6243. case ZEND_IS_NOT_EQUAL:
  6244. case ZEND_IS_NOT_IDENTICAL:
  6245. | beq => target_label
  6246. break;
  6247. case ZEND_IS_SMALLER:
  6248. if (swap) {
  6249. | ble => target_label
  6250. } else {
  6251. | bge => target_label
  6252. }
  6253. break;
  6254. case ZEND_IS_SMALLER_OR_EQUAL:
  6255. if (swap) {
  6256. | blt => target_label
  6257. } else {
  6258. | bgt => target_label
  6259. }
  6260. break;
  6261. default:
  6262. ZEND_UNREACHABLE();
  6263. }
  6264. | b => target_label2
  6265. } else {
  6266. ZEND_UNREACHABLE();
  6267. }
  6268. } else {
  6269. switch (opline->opcode) {
  6270. case ZEND_IS_EQUAL:
  6271. case ZEND_IS_IDENTICAL:
  6272. case ZEND_CASE:
  6273. case ZEND_CASE_STRICT:
  6274. | cset REG0w, eq
  6275. break;
  6276. case ZEND_IS_NOT_EQUAL:
  6277. case ZEND_IS_NOT_IDENTICAL:
  6278. | cset REG0w, ne
  6279. break;
  6280. case ZEND_IS_SMALLER:
  6281. if (swap) {
  6282. | cset REG0w, gt
  6283. } else {
  6284. | cset REG0w, lt
  6285. }
  6286. break;
  6287. case ZEND_IS_SMALLER_OR_EQUAL:
  6288. if (swap) {
  6289. | cset REG0w, ge
  6290. } else {
  6291. | cset REG0w, le
  6292. }
  6293. break;
  6294. default:
  6295. ZEND_UNREACHABLE();
  6296. }
  6297. | add REG0w, REG0w, #2
  6298. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  6299. }
  6300. return 1;
  6301. }
  6302. static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, bool swap, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
  6303. {
  6304. if (smart_branch_opcode) {
  6305. if (smart_branch_opcode == ZEND_JMPZ) {
  6306. switch (opline->opcode) {
  6307. case ZEND_IS_EQUAL:
  6308. case ZEND_IS_IDENTICAL:
  6309. case ZEND_CASE:
  6310. case ZEND_CASE_STRICT:
  6311. if (exit_addr) {
  6312. | bne &exit_addr
  6313. } else {
  6314. | bne => target_label
  6315. }
  6316. break;
  6317. case ZEND_IS_NOT_EQUAL:
  6318. | bvs >1
  6319. if (exit_addr) {
  6320. | beq &exit_addr
  6321. } else {
  6322. | beq => target_label
  6323. }
  6324. |1:
  6325. break;
  6326. case ZEND_IS_NOT_IDENTICAL:
  6327. if (exit_addr) {
  6328. | bvs &exit_addr
  6329. | bne &exit_addr
  6330. } else {
  6331. | bvs >1
  6332. | beq => target_label
  6333. |1:
  6334. }
  6335. break;
  6336. case ZEND_IS_SMALLER:
  6337. if (swap) {
  6338. if (exit_addr) {
  6339. | bvs &exit_addr
  6340. | bls &exit_addr
  6341. } else {
  6342. | bvs => target_label
  6343. | bls => target_label
  6344. }
  6345. } else {
  6346. if (exit_addr) {
  6347. | bhs &exit_addr
  6348. } else {
  6349. | bhs => target_label
  6350. }
  6351. }
  6352. break;
  6353. case ZEND_IS_SMALLER_OR_EQUAL:
  6354. if (swap) {
  6355. if (exit_addr) {
  6356. | bvs &exit_addr
  6357. | blo &exit_addr
  6358. } else {
  6359. | bvs => target_label
  6360. | blo => target_label
  6361. }
  6362. } else {
  6363. if (exit_addr) {
  6364. | bhi &exit_addr
  6365. } else {
  6366. | bhi => target_label
  6367. }
  6368. }
  6369. break;
  6370. default:
  6371. ZEND_UNREACHABLE();
  6372. }
  6373. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  6374. switch (opline->opcode) {
  6375. case ZEND_IS_EQUAL:
  6376. case ZEND_IS_IDENTICAL:
  6377. case ZEND_CASE:
  6378. case ZEND_CASE_STRICT:
  6379. | bvs >1
  6380. if (exit_addr) {
  6381. | beq &exit_addr
  6382. } else {
  6383. | beq => target_label
  6384. }
  6385. |1:
  6386. break;
  6387. case ZEND_IS_NOT_EQUAL:
  6388. if (exit_addr) {
  6389. | bne &exit_addr
  6390. } else {
  6391. | bne => target_label
  6392. }
  6393. break;
  6394. case ZEND_IS_NOT_IDENTICAL:
  6395. if (exit_addr) {
  6396. | bvs >1
  6397. | beq &exit_addr
  6398. |1:
  6399. } else {
  6400. | bne => target_label
  6401. }
  6402. break;
  6403. case ZEND_IS_SMALLER:
  6404. if (swap) {
  6405. | bvs >1 // Always False if involving NaN
  6406. if (exit_addr) {
  6407. | bhi &exit_addr
  6408. } else {
  6409. | bhi => target_label
  6410. }
  6411. |1:
  6412. } else {
  6413. | bvs >1
  6414. if (exit_addr) {
  6415. | blo &exit_addr
  6416. } else {
  6417. | blo => target_label
  6418. }
  6419. |1:
  6420. }
  6421. break;
  6422. case ZEND_IS_SMALLER_OR_EQUAL:
  6423. if (swap) {
  6424. | bvs >1 // Always False if involving NaN
  6425. if (exit_addr) {
  6426. | bhs &exit_addr
  6427. } else {
  6428. | bhs => target_label
  6429. }
  6430. |1:
  6431. } else {
  6432. | bvs >1
  6433. if (exit_addr) {
  6434. | bls &exit_addr
  6435. } else {
  6436. | bls => target_label
  6437. }
  6438. |1:
  6439. }
  6440. break;
  6441. default:
  6442. ZEND_UNREACHABLE();
  6443. }
  6444. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  6445. switch (opline->opcode) {
  6446. case ZEND_IS_EQUAL:
  6447. case ZEND_IS_IDENTICAL:
  6448. case ZEND_CASE:
  6449. case ZEND_CASE_STRICT:
  6450. | bne => target_label
  6451. break;
  6452. case ZEND_IS_NOT_EQUAL:
  6453. case ZEND_IS_NOT_IDENTICAL:
  6454. | bvs => target_label2
  6455. | beq => target_label
  6456. break;
  6457. case ZEND_IS_SMALLER:
  6458. if (swap) {
  6459. | bvs => target_label
  6460. | bls => target_label
  6461. } else {
  6462. | bhs => target_label
  6463. }
  6464. break;
  6465. case ZEND_IS_SMALLER_OR_EQUAL:
  6466. if (swap) {
  6467. | bvs => target_label
  6468. | blo => target_label
  6469. } else {
  6470. | bhi => target_label
  6471. }
  6472. break;
  6473. default:
  6474. ZEND_UNREACHABLE();
  6475. }
  6476. | b => target_label2
  6477. } else if (smart_branch_opcode == ZEND_JMPZ_EX) {
  6478. switch (opline->opcode) {
  6479. case ZEND_IS_EQUAL:
  6480. case ZEND_IS_IDENTICAL:
  6481. case ZEND_CASE:
  6482. case ZEND_CASE_STRICT:
  6483. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  6484. | bne => target_label
  6485. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  6486. break;
  6487. case ZEND_IS_NOT_EQUAL:
  6488. case ZEND_IS_NOT_IDENTICAL:
  6489. | bvs >1
  6490. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  6491. | beq => target_label
  6492. |1:
  6493. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  6494. break;
  6495. case ZEND_IS_SMALLER:
  6496. if (swap) {
  6497. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  6498. | bvs => target_label
  6499. | bls => target_label
  6500. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  6501. } else {
  6502. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  6503. | bhs => target_label
  6504. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  6505. }
  6506. break;
  6507. case ZEND_IS_SMALLER_OR_EQUAL:
  6508. if (swap) {
  6509. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  6510. | bvs => target_label
  6511. | blo => target_label
  6512. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  6513. } else {
  6514. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  6515. | bhi => target_label
  6516. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  6517. }
  6518. break;
  6519. default:
  6520. ZEND_UNREACHABLE();
  6521. }
  6522. } else if (smart_branch_opcode == ZEND_JMPNZ_EX) {
  6523. switch (opline->opcode) {
  6524. case ZEND_IS_EQUAL:
  6525. case ZEND_IS_IDENTICAL:
  6526. case ZEND_CASE:
  6527. case ZEND_CASE_STRICT:
  6528. | bvs >1
  6529. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  6530. | beq => target_label
  6531. |1:
  6532. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  6533. break;
  6534. case ZEND_IS_NOT_EQUAL:
  6535. case ZEND_IS_NOT_IDENTICAL:
  6536. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  6537. | bvs => target_label
  6538. | bne => target_label
  6539. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  6540. break;
  6541. case ZEND_IS_SMALLER:
  6542. if (swap) {
  6543. | cset REG0w, hi
  6544. | add REG0w, REG0w, #2
  6545. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  6546. | bvs >1 // Always False if involving NaN
  6547. | bhi => target_label
  6548. |1:
  6549. } else {
  6550. | bvs >1
  6551. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  6552. | blo => target_label
  6553. |1:
  6554. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  6555. }
  6556. break;
  6557. case ZEND_IS_SMALLER_OR_EQUAL:
  6558. if (swap) {
  6559. | cset REG0w, hs
  6560. | add REG0w, REG0w, #2
  6561. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  6562. | bvs >1 // Always False if involving NaN
  6563. | bhs => target_label
  6564. |1:
  6565. } else {
  6566. | bvs >1
  6567. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  6568. | bls => target_label
  6569. |1:
  6570. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  6571. }
  6572. break;
  6573. default:
  6574. ZEND_UNREACHABLE();
  6575. }
  6576. } else {
  6577. ZEND_UNREACHABLE();
  6578. }
  6579. } else {
  6580. switch (opline->opcode) {
  6581. case ZEND_IS_EQUAL:
  6582. case ZEND_IS_IDENTICAL:
  6583. case ZEND_CASE:
  6584. case ZEND_CASE_STRICT:
  6585. | bvs >1
  6586. | mov REG0, #IS_TRUE
  6587. | beq >2
  6588. |1:
  6589. | mov REG0, #IS_FALSE
  6590. |2:
  6591. break;
  6592. case ZEND_IS_NOT_EQUAL:
  6593. case ZEND_IS_NOT_IDENTICAL:
  6594. | bvs >1
  6595. | mov REG0, #IS_FALSE
  6596. | beq >2
  6597. |1:
  6598. | mov REG0, #IS_TRUE
  6599. |2:
  6600. break;
  6601. case ZEND_IS_SMALLER:
  6602. | bvs >1
  6603. | mov REG0, #IS_TRUE
  6604. || if (swap) {
  6605. | bhi >2
  6606. || } else {
  6607. | blo >2
  6608. || }
  6609. |1:
  6610. | mov REG0, #IS_FALSE
  6611. |2:
  6612. break;
  6613. case ZEND_IS_SMALLER_OR_EQUAL:
  6614. | bvs >1
  6615. | mov REG0, #IS_TRUE
  6616. || if (swap) {
  6617. | bhs >2
  6618. || } else {
  6619. | bls >2
  6620. || }
  6621. |1:
  6622. | mov REG0, #IS_FALSE
  6623. |2:
  6624. break;
  6625. default:
  6626. ZEND_UNREACHABLE();
  6627. }
  6628. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  6629. }
  6630. return 1;
  6631. }
  6632. static int zend_jit_cmp_long_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
  6633. {
  6634. zend_reg tmp_reg = ZREG_FPR0;
  6635. | DOUBLE_GET_ZVAL_LVAL tmp_reg, op1_addr, ZREG_REG0, ZREG_TMP1
  6636. | DOUBLE_CMP tmp_reg, op2_addr, ZREG_TMP1, ZREG_FPTMP
  6637. return zend_jit_cmp_double_common(Dst, opline, res_addr, 0, smart_branch_opcode, target_label, target_label2, exit_addr);
  6638. }
  6639. static int zend_jit_cmp_double_long(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
  6640. {
  6641. zend_reg tmp_reg = ZREG_FPR0;
  6642. | DOUBLE_GET_ZVAL_LVAL tmp_reg, op2_addr, ZREG_REG0, ZREG_TMP1
  6643. | DOUBLE_CMP tmp_reg, op1_addr, ZREG_TMP1, ZREG_FPTMP
  6644. return zend_jit_cmp_double_common(Dst, opline, res_addr, /* swap */ 1, smart_branch_opcode, target_label, target_label2, exit_addr);
  6645. }
  6646. static int zend_jit_cmp_double_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
  6647. {
  6648. bool swap = 0;
  6649. if (Z_MODE(op1_addr) == IS_REG) {
  6650. | DOUBLE_CMP Z_REG(op1_addr), op2_addr, ZREG_TMP1, ZREG_FPTMP
  6651. } else if (Z_MODE(op2_addr) == IS_REG) {
  6652. | DOUBLE_CMP Z_REG(op2_addr), op1_addr, ZREG_TMP1, ZREG_FPTMP
  6653. swap = 1;
  6654. } else {
  6655. zend_reg tmp_reg = ZREG_FPR0;
  6656. | GET_ZVAL_DVAL tmp_reg, op1_addr, ZREG_TMP1
  6657. | DOUBLE_CMP tmp_reg, op2_addr, ZREG_TMP1, ZREG_FPTMP
  6658. }
  6659. return zend_jit_cmp_double_common(Dst, opline, res_addr, swap, smart_branch_opcode, target_label, target_label2, exit_addr);
  6660. }
  6661. static int zend_jit_cmp_slow(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
  6662. {
  6663. | tst RETVALw, RETVALw
  6664. if (smart_branch_opcode) {
  6665. if (smart_branch_opcode == ZEND_JMPZ_EX ||
  6666. smart_branch_opcode == ZEND_JMPNZ_EX) {
  6667. switch (opline->opcode) {
  6668. case ZEND_IS_EQUAL:
  6669. case ZEND_CASE:
  6670. | cset REG0w, eq
  6671. break;
  6672. case ZEND_IS_NOT_EQUAL:
  6673. | cset REG0w, ne
  6674. break;
  6675. case ZEND_IS_SMALLER:
  6676. | cset REG0w, lt
  6677. break;
  6678. case ZEND_IS_SMALLER_OR_EQUAL:
  6679. | cset REG0w, le
  6680. break;
  6681. default:
  6682. ZEND_UNREACHABLE();
  6683. }
  6684. | add REG0w, REG0w, #2
  6685. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  6686. }
  6687. if (smart_branch_opcode == ZEND_JMPZ ||
  6688. smart_branch_opcode == ZEND_JMPZ_EX) {
  6689. switch (opline->opcode) {
  6690. case ZEND_IS_EQUAL:
  6691. case ZEND_CASE:
  6692. if (exit_addr) {
  6693. | bne &exit_addr
  6694. } else {
  6695. | bne => target_label
  6696. }
  6697. break;
  6698. case ZEND_IS_NOT_EQUAL:
  6699. if (exit_addr) {
  6700. | beq &exit_addr
  6701. } else {
  6702. | beq => target_label
  6703. }
  6704. break;
  6705. case ZEND_IS_SMALLER:
  6706. if (exit_addr) {
  6707. | bge &exit_addr
  6708. } else {
  6709. | bge => target_label
  6710. }
  6711. break;
  6712. case ZEND_IS_SMALLER_OR_EQUAL:
  6713. if (exit_addr) {
  6714. | bgt &exit_addr
  6715. } else {
  6716. | bgt => target_label
  6717. }
  6718. break;
  6719. default:
  6720. ZEND_UNREACHABLE();
  6721. }
  6722. } else if (smart_branch_opcode == ZEND_JMPNZ ||
  6723. smart_branch_opcode == ZEND_JMPNZ_EX) {
  6724. switch (opline->opcode) {
  6725. case ZEND_IS_EQUAL:
  6726. case ZEND_CASE:
  6727. if (exit_addr) {
  6728. | beq &exit_addr
  6729. } else {
  6730. | beq => target_label
  6731. }
  6732. break;
  6733. case ZEND_IS_NOT_EQUAL:
  6734. if (exit_addr) {
  6735. | bne &exit_addr
  6736. } else {
  6737. | bne => target_label
  6738. }
  6739. break;
  6740. case ZEND_IS_SMALLER:
  6741. if (exit_addr) {
  6742. | blt &exit_addr
  6743. } else {
  6744. | blt => target_label
  6745. }
  6746. break;
  6747. case ZEND_IS_SMALLER_OR_EQUAL:
  6748. if (exit_addr) {
  6749. | ble &exit_addr
  6750. } else {
  6751. | ble => target_label
  6752. }
  6753. break;
  6754. default:
  6755. ZEND_UNREACHABLE();
  6756. }
  6757. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  6758. switch (opline->opcode) {
  6759. case ZEND_IS_EQUAL:
  6760. case ZEND_CASE:
  6761. | bne => target_label
  6762. break;
  6763. case ZEND_IS_NOT_EQUAL:
  6764. | beq => target_label
  6765. break;
  6766. case ZEND_IS_SMALLER:
  6767. | bge => target_label
  6768. break;
  6769. case ZEND_IS_SMALLER_OR_EQUAL:
  6770. | bgt => target_label
  6771. break;
  6772. default:
  6773. ZEND_UNREACHABLE();
  6774. }
  6775. | b => target_label2
  6776. } else {
  6777. ZEND_UNREACHABLE();
  6778. }
  6779. } else {
  6780. switch (opline->opcode) {
  6781. case ZEND_IS_EQUAL:
  6782. case ZEND_CASE:
  6783. | cset REG0w, eq
  6784. break;
  6785. case ZEND_IS_NOT_EQUAL:
  6786. | cset REG0w, ne
  6787. break;
  6788. case ZEND_IS_SMALLER:
  6789. | cset REG0w, lt
  6790. break;
  6791. case ZEND_IS_SMALLER_OR_EQUAL:
  6792. | cset REG0w, le
  6793. break;
  6794. default:
  6795. ZEND_UNREACHABLE();
  6796. }
  6797. | add REG0w, REG0w, #2
  6798. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  6799. }
  6800. return 1;
  6801. }
  6802. static int zend_jit_cmp(dasm_State **Dst,
  6803. const zend_op *opline,
  6804. uint32_t op1_info,
  6805. zend_ssa_range *op1_range,
  6806. zend_jit_addr op1_addr,
  6807. uint32_t op2_info,
  6808. zend_ssa_range *op2_range,
  6809. zend_jit_addr op2_addr,
  6810. zend_jit_addr res_addr,
  6811. int may_throw,
  6812. zend_uchar smart_branch_opcode,
  6813. uint32_t target_label,
  6814. uint32_t target_label2,
  6815. const void *exit_addr,
  6816. bool skip_comparison)
  6817. {
  6818. bool same_ops = (opline->op1_type == opline->op2_type) && (opline->op1.var == opline->op2.var);
  6819. bool has_slow;
  6820. has_slow =
  6821. (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
  6822. (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
  6823. ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
  6824. (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))));
  6825. if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
  6826. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
  6827. if (op1_info & MAY_BE_DOUBLE) {
  6828. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >4, ZREG_TMP1
  6829. } else {
  6830. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >9, ZREG_TMP1
  6831. }
  6832. }
  6833. if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
  6834. if (op2_info & MAY_BE_DOUBLE) {
  6835. | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >3, ZREG_TMP1
  6836. |.cold_code
  6837. |3:
  6838. if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
  6839. | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9, ZREG_TMP1
  6840. }
  6841. if (!zend_jit_cmp_long_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
  6842. return 0;
  6843. }
  6844. | b >6
  6845. |.code
  6846. } else {
  6847. | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9, ZREG_TMP1
  6848. }
  6849. }
  6850. if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison)) {
  6851. return 0;
  6852. }
  6853. if (op1_info & MAY_BE_DOUBLE) {
  6854. |.cold_code
  6855. |4:
  6856. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
  6857. | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >9, ZREG_TMP1
  6858. }
  6859. if (op2_info & MAY_BE_DOUBLE) {
  6860. if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
  6861. if (!same_ops) {
  6862. | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >5, ZREG_TMP1
  6863. } else {
  6864. | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9, ZREG_TMP1
  6865. }
  6866. }
  6867. if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
  6868. return 0;
  6869. }
  6870. | b >6
  6871. }
  6872. if (!same_ops) {
  6873. |5:
  6874. if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
  6875. | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9, ZREG_TMP1
  6876. }
  6877. if (!zend_jit_cmp_double_long(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
  6878. return 0;
  6879. }
  6880. | b >6
  6881. }
  6882. |.code
  6883. }
  6884. } else if ((op1_info & MAY_BE_DOUBLE) &&
  6885. !(op1_info & MAY_BE_LONG) &&
  6886. (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
  6887. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
  6888. | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >9, ZREG_TMP1
  6889. }
  6890. if (op2_info & MAY_BE_DOUBLE) {
  6891. if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
  6892. if (!same_ops && (op2_info & MAY_BE_LONG)) {
  6893. | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >3, ZREG_TMP1
  6894. } else {
  6895. | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9, ZREG_TMP1
  6896. }
  6897. }
  6898. if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
  6899. return 0;
  6900. }
  6901. }
  6902. if (!same_ops && (op2_info & MAY_BE_LONG)) {
  6903. if (op2_info & MAY_BE_DOUBLE) {
  6904. |.cold_code
  6905. }
  6906. |3:
  6907. if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
  6908. | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9, ZREG_TMP1
  6909. }
  6910. if (!zend_jit_cmp_double_long(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
  6911. return 0;
  6912. }
  6913. if (op2_info & MAY_BE_DOUBLE) {
  6914. | b >6
  6915. |.code
  6916. }
  6917. }
  6918. } else if ((op2_info & MAY_BE_DOUBLE) &&
  6919. !(op2_info & MAY_BE_LONG) &&
  6920. (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
  6921. if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
  6922. | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9, ZREG_TMP1
  6923. }
  6924. if (op1_info & MAY_BE_DOUBLE) {
  6925. if (!same_ops && (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
  6926. if (!same_ops && (op1_info & MAY_BE_LONG)) {
  6927. | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >3, ZREG_TMP1
  6928. } else {
  6929. | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >9, ZREG_TMP1
  6930. }
  6931. }
  6932. if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
  6933. return 0;
  6934. }
  6935. }
  6936. if (!same_ops && (op1_info & MAY_BE_LONG)) {
  6937. if (op1_info & MAY_BE_DOUBLE) {
  6938. |.cold_code
  6939. }
  6940. |3:
  6941. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
  6942. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >9, ZREG_TMP1
  6943. }
  6944. if (!zend_jit_cmp_long_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
  6945. return 0;
  6946. }
  6947. if (op1_info & MAY_BE_DOUBLE) {
  6948. | b >6
  6949. |.code
  6950. }
  6951. }
  6952. }
  6953. if (has_slow ||
  6954. (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
  6955. (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
  6956. if (has_slow) {
  6957. |.cold_code
  6958. |9:
  6959. }
  6960. | SET_EX_OPLINE opline, REG0
  6961. if (Z_MODE(op1_addr) == IS_REG) {
  6962. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
  6963. if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
  6964. return 0;
  6965. }
  6966. op1_addr = real_addr;
  6967. }
  6968. if (Z_MODE(op2_addr) == IS_REG) {
  6969. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
  6970. if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) {
  6971. return 0;
  6972. }
  6973. op2_addr = real_addr;
  6974. }
  6975. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  6976. if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
  6977. | IF_NOT_Z_TYPE FCARG1x, IS_UNDEF, >1, TMP1w
  6978. | LOAD_32BIT_VAL FCARG1x, opline->op1.var
  6979. | EXT_CALL zend_jit_undefined_op_helper, REG0
  6980. | LOAD_ADDR_ZTS FCARG1x, executor_globals, uninitialized_zval
  6981. |1:
  6982. }
  6983. if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
  6984. | IF_NOT_ZVAL_TYPE op2_addr, IS_UNDEF, >1, ZREG_TMP1
  6985. | str FCARG1x, T1 // save
  6986. | LOAD_32BIT_VAL FCARG1x, opline->op2.var
  6987. | EXT_CALL zend_jit_undefined_op_helper, REG0
  6988. | ldr FCARG1x, T1 // restore
  6989. | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval
  6990. | b >2
  6991. |1:
  6992. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  6993. |2:
  6994. } else {
  6995. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  6996. }
  6997. | EXT_CALL zend_compare, REG0
  6998. if ((opline->opcode != ZEND_CASE &&
  6999. (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
  7000. (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) ||
  7001. ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) &&
  7002. (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) {
  7003. | str RETVALw, T1 // save
  7004. if (opline->opcode != ZEND_CASE) {
  7005. | FREE_OP opline->op1_type, opline->op1, op1_info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  7006. }
  7007. | FREE_OP opline->op2_type, opline->op2, op2_info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  7008. | ldr RETVALw, T1 // restore
  7009. }
  7010. if (may_throw) {
  7011. zend_jit_check_exception_undef_result(Dst, opline);
  7012. }
  7013. if (!zend_jit_cmp_slow(Dst, opline, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
  7014. return 0;
  7015. }
  7016. if (has_slow) {
  7017. | b >6
  7018. |.code
  7019. }
  7020. }
  7021. |6:
  7022. return 1;
  7023. }
  7024. static int zend_jit_identical(dasm_State **Dst,
  7025. const zend_op *opline,
  7026. uint32_t op1_info,
  7027. zend_ssa_range *op1_range,
  7028. zend_jit_addr op1_addr,
  7029. uint32_t op2_info,
  7030. zend_ssa_range *op2_range,
  7031. zend_jit_addr op2_addr,
  7032. zend_jit_addr res_addr,
  7033. int may_throw,
  7034. zend_uchar smart_branch_opcode,
  7035. uint32_t target_label,
  7036. uint32_t target_label2,
  7037. const void *exit_addr,
  7038. bool skip_comparison)
  7039. {
  7040. uint32_t identical_label = (uint32_t)-1;
  7041. uint32_t not_identical_label = (uint32_t)-1;
  7042. if (smart_branch_opcode && !exit_addr) {
  7043. if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
  7044. if (smart_branch_opcode == ZEND_JMPZ) {
  7045. not_identical_label = target_label;
  7046. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  7047. identical_label = target_label;
  7048. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  7049. not_identical_label = target_label;
  7050. identical_label = target_label2;
  7051. } else {
  7052. ZEND_UNREACHABLE();
  7053. }
  7054. } else {
  7055. if (smart_branch_opcode == ZEND_JMPZ) {
  7056. identical_label = target_label;
  7057. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  7058. not_identical_label = target_label;
  7059. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  7060. identical_label = target_label;
  7061. not_identical_label = target_label2;
  7062. } else {
  7063. ZEND_UNREACHABLE();
  7064. }
  7065. }
  7066. }
  7067. if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
  7068. (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
  7069. if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison)) {
  7070. return 0;
  7071. }
  7072. return 1;
  7073. } else if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE &&
  7074. (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE) {
  7075. if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
  7076. return 0;
  7077. }
  7078. return 1;
  7079. }
  7080. if ((op1_info & MAY_BE_UNDEF) && (op2_info & MAY_BE_UNDEF)) {
  7081. op1_info |= MAY_BE_NULL;
  7082. op2_info |= MAY_BE_NULL;
  7083. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  7084. | IF_Z_TYPE FCARG1x, IS_UNDEF, >1, TMP1w
  7085. |.cold_code
  7086. |1:
  7087. | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
  7088. | SET_EX_OPLINE opline, REG0
  7089. | LOAD_32BIT_VAL FCARG1w, opline->op1.var
  7090. | EXT_CALL zend_jit_undefined_op_helper, REG0
  7091. if (may_throw) {
  7092. zend_jit_check_exception_undef_result(Dst, opline);
  7093. }
  7094. | LOAD_ADDR_ZTS FCARG1x, executor_globals, uninitialized_zval
  7095. | b >1
  7096. |.code
  7097. |1:
  7098. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  7099. | IF_Z_TYPE FCARG2x, IS_UNDEF, >1, TMP1w
  7100. |.cold_code
  7101. |1:
  7102. | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
  7103. | SET_EX_OPLINE opline, REG0
  7104. | str FCARG1x, T1 // save
  7105. | LOAD_32BIT_VAL FCARG1w, opline->op2.var
  7106. | EXT_CALL zend_jit_undefined_op_helper, REG0
  7107. if (may_throw) {
  7108. zend_jit_check_exception_undef_result(Dst, opline);
  7109. }
  7110. | ldr FCARG1x, T1 // restore
  7111. | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval
  7112. | b >1
  7113. |.code
  7114. |1:
  7115. } else if (op1_info & MAY_BE_UNDEF) {
  7116. op1_info |= MAY_BE_NULL;
  7117. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  7118. | IF_Z_TYPE FCARG1x, IS_UNDEF, >1, TMP1w
  7119. |.cold_code
  7120. |1:
  7121. | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
  7122. | SET_EX_OPLINE opline, REG0
  7123. | LOAD_32BIT_VAL FCARG1w, opline->op1.var
  7124. | EXT_CALL zend_jit_undefined_op_helper, REG0
  7125. if (may_throw) {
  7126. zend_jit_check_exception_undef_result(Dst, opline);
  7127. }
  7128. | LOAD_ADDR_ZTS FCARG1x, executor_globals, uninitialized_zval
  7129. | b >1
  7130. |.code
  7131. |1:
  7132. if (opline->op2_type != IS_CONST) {
  7133. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  7134. }
  7135. } else if (op2_info & MAY_BE_UNDEF) {
  7136. op2_info |= MAY_BE_NULL;
  7137. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  7138. | IF_Z_TYPE FCARG2x, IS_UNDEF, >1, TMP1w
  7139. |.cold_code
  7140. |1:
  7141. | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
  7142. | SET_EX_OPLINE opline, REG0
  7143. | LOAD_32BIT_VAL FCARG1w, opline->op2.var
  7144. | EXT_CALL zend_jit_undefined_op_helper, REG0
  7145. if (may_throw) {
  7146. zend_jit_check_exception_undef_result(Dst, opline);
  7147. }
  7148. | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval
  7149. | b >1
  7150. |.code
  7151. |1:
  7152. if (opline->op1_type != IS_CONST) {
  7153. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  7154. }
  7155. } else if ((op1_info & op2_info & MAY_BE_ANY) != 0) {
  7156. if (opline->op1_type != IS_CONST) {
  7157. if (Z_MODE(op1_addr) == IS_REG) {
  7158. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
  7159. if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
  7160. return 0;
  7161. }
  7162. op1_addr = real_addr;
  7163. }
  7164. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  7165. }
  7166. if (opline->op2_type != IS_CONST) {
  7167. if (Z_MODE(op2_addr) == IS_REG) {
  7168. zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
  7169. if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) {
  7170. return 0;
  7171. }
  7172. op2_addr = real_addr;
  7173. }
  7174. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  7175. }
  7176. }
  7177. if ((op1_info & op2_info & MAY_BE_ANY) == 0) {
  7178. if ((opline->opcode != ZEND_CASE_STRICT &&
  7179. (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
  7180. (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) ||
  7181. ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) &&
  7182. (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) {
  7183. if (opline->opcode != ZEND_CASE_STRICT) {
  7184. | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  7185. }
  7186. | FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  7187. }
  7188. if (smart_branch_opcode) {
  7189. if (may_throw) {
  7190. zend_jit_check_exception_undef_result(Dst, opline);
  7191. }
  7192. if (exit_addr) {
  7193. if (smart_branch_opcode == ZEND_JMPZ) {
  7194. | b &exit_addr
  7195. }
  7196. } else if (not_identical_label != (uint32_t)-1) {
  7197. | b =>not_identical_label
  7198. }
  7199. } else {
  7200. | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE), TMP1w, TMP2
  7201. if (may_throw) {
  7202. zend_jit_check_exception(Dst);
  7203. }
  7204. }
  7205. return 1;
  7206. }
  7207. if (opline->op1_type & (IS_CV|IS_VAR)) {
  7208. | ZVAL_DEREF FCARG1x, op1_info, TMP1w
  7209. }
  7210. if (opline->op2_type & (IS_CV|IS_VAR)) {
  7211. | ZVAL_DEREF FCARG2x, op2_info, TMP1w
  7212. }
  7213. if (has_concrete_type(op1_info)
  7214. && has_concrete_type(op2_info)
  7215. && concrete_type(op1_info) == concrete_type(op2_info)
  7216. && concrete_type(op1_info) <= IS_TRUE) {
  7217. if (smart_branch_opcode) {
  7218. if (exit_addr) {
  7219. if (smart_branch_opcode == ZEND_JMPNZ) {
  7220. | b &exit_addr
  7221. }
  7222. } else if (identical_label != (uint32_t)-1) {
  7223. | b =>identical_label
  7224. }
  7225. } else {
  7226. | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE), TMP1w, TMP2
  7227. }
  7228. } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) == IS_CONST_ZVAL) {
  7229. if (zend_is_identical(Z_ZV(op1_addr), Z_ZV(op2_addr))) {
  7230. if (smart_branch_opcode) {
  7231. if (exit_addr) {
  7232. if (smart_branch_opcode == ZEND_JMPNZ) {
  7233. | b &exit_addr
  7234. }
  7235. } else if (identical_label != (uint32_t)-1) {
  7236. | b =>identical_label
  7237. }
  7238. } else {
  7239. | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE), TMP1w, TMP2
  7240. }
  7241. } else {
  7242. if (smart_branch_opcode) {
  7243. if (exit_addr) {
  7244. if (smart_branch_opcode == ZEND_JMPZ) {
  7245. | b &exit_addr
  7246. }
  7247. } else if (not_identical_label != (uint32_t)-1) {
  7248. | b =>not_identical_label
  7249. }
  7250. } else {
  7251. | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE), TMP1w, TMP2
  7252. }
  7253. }
  7254. } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op1_addr)) <= IS_TRUE) {
  7255. zval *val = Z_ZV(op1_addr);
  7256. | ldrb TMP1w, [FCARG2x, #offsetof(zval, u1.v.type)]
  7257. | cmp TMP1w, #Z_TYPE_P(val)
  7258. if (smart_branch_opcode) {
  7259. if (opline->op2_type == IS_VAR && (op2_info & MAY_BE_REF)) {
  7260. | bne >8
  7261. | FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  7262. if (may_throw) {
  7263. zend_jit_check_exception_undef_result(Dst, opline);
  7264. }
  7265. if (exit_addr && smart_branch_opcode == ZEND_JMPNZ) {
  7266. | b &exit_addr
  7267. } else if (identical_label != (uint32_t)-1) {
  7268. | b =>identical_label
  7269. } else {
  7270. | b >9
  7271. }
  7272. |8:
  7273. } else if (exit_addr && smart_branch_opcode == ZEND_JMPNZ) {
  7274. | beq &exit_addr
  7275. } else if (identical_label != (uint32_t)-1) {
  7276. | beq =>identical_label
  7277. } else {
  7278. | beq >9
  7279. }
  7280. } else {
  7281. if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
  7282. | cset REG0w, eq
  7283. } else {
  7284. | cset REG0w, ne
  7285. }
  7286. | add REG0w, REG0w, #2
  7287. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  7288. }
  7289. if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) &&
  7290. (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
  7291. | FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  7292. if (may_throw) {
  7293. zend_jit_check_exception_undef_result(Dst, opline);
  7294. }
  7295. }
  7296. if (exit_addr) {
  7297. if (smart_branch_opcode == ZEND_JMPZ) {
  7298. | b &exit_addr
  7299. }
  7300. } else if (smart_branch_opcode && not_identical_label != (uint32_t)-1) {
  7301. | b =>not_identical_label
  7302. }
  7303. } else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op2_addr)) <= IS_TRUE) {
  7304. zval *val = Z_ZV(op2_addr);
  7305. | ldrb TMP1w, [FCARG1x, #offsetof(zval, u1.v.type)]
  7306. | cmp TMP1w, #Z_TYPE_P(val)
  7307. if (smart_branch_opcode) {
  7308. if (opline->opcode != ZEND_CASE_STRICT
  7309. && opline->op1_type == IS_VAR && (op1_info & MAY_BE_REF)) {
  7310. | bne >8
  7311. | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  7312. if (may_throw) {
  7313. zend_jit_check_exception_undef_result(Dst, opline);
  7314. }
  7315. if (exit_addr && smart_branch_opcode == ZEND_JMPNZ) {
  7316. | b &exit_addr
  7317. } else if (identical_label != (uint32_t)-1) {
  7318. | b =>identical_label
  7319. } else {
  7320. | b >9
  7321. }
  7322. |8:
  7323. } else if (exit_addr && smart_branch_opcode == ZEND_JMPNZ) {
  7324. | beq &exit_addr
  7325. } else if (identical_label != (uint32_t)-1) {
  7326. | beq =>identical_label
  7327. } else {
  7328. | beq >9
  7329. }
  7330. } else {
  7331. if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
  7332. | cset REG0w, eq
  7333. } else {
  7334. | cset REG0w, ne
  7335. }
  7336. | add REG0w, REG0w, #2
  7337. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  7338. }
  7339. if (opline->opcode != ZEND_CASE_STRICT
  7340. && (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
  7341. (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
  7342. | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  7343. if (may_throw) {
  7344. zend_jit_check_exception_undef_result(Dst, opline);
  7345. }
  7346. }
  7347. if (smart_branch_opcode) {
  7348. if (exit_addr) {
  7349. if (smart_branch_opcode == ZEND_JMPZ) {
  7350. | b &exit_addr
  7351. }
  7352. } else if (not_identical_label != (uint32_t)-1) {
  7353. | b =>not_identical_label
  7354. }
  7355. }
  7356. } else {
  7357. if (opline->op1_type == IS_CONST) {
  7358. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  7359. }
  7360. if (opline->op2_type == IS_CONST) {
  7361. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  7362. }
  7363. | EXT_CALL zend_is_identical, REG0
  7364. if ((opline->opcode != ZEND_CASE_STRICT &&
  7365. (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
  7366. (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) ||
  7367. ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) &&
  7368. (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) {
  7369. | str RETVALw, T1 // save
  7370. if (opline->opcode != ZEND_CASE_STRICT) {
  7371. | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  7372. }
  7373. | FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  7374. if (may_throw) {
  7375. zend_jit_check_exception_undef_result(Dst, opline);
  7376. }
  7377. | ldr RETVALw, T1 // restore
  7378. }
  7379. if (smart_branch_opcode) {
  7380. if (exit_addr) {
  7381. if (smart_branch_opcode == ZEND_JMPNZ) {
  7382. | cbnz RETVALw, &exit_addr
  7383. } else {
  7384. | cbz RETVALw, &exit_addr
  7385. }
  7386. } else if (not_identical_label != (uint32_t)-1) {
  7387. | cbz RETVALw, =>not_identical_label
  7388. if (identical_label != (uint32_t)-1) {
  7389. | b =>identical_label
  7390. }
  7391. } else if (identical_label != (uint32_t)-1) {
  7392. | cbnz RETVALw, =>identical_label
  7393. }
  7394. } else {
  7395. if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
  7396. | add RETVALw, RETVALw, #2
  7397. } else {
  7398. | neg RETVALw, RETVALw
  7399. | add RETVALw, RETVALw, #3
  7400. }
  7401. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, RETVALw, TMP1
  7402. }
  7403. }
  7404. |9:
  7405. if (may_throw) {
  7406. zend_jit_check_exception(Dst);
  7407. }
  7408. return 1;
  7409. }
  7410. static int zend_jit_bool_jmpznz(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, uint32_t target_label, uint32_t target_label2, int may_throw, zend_uchar branch_opcode, const void *exit_addr)
  7411. {
  7412. uint32_t true_label = -1;
  7413. uint32_t false_label = -1;
  7414. bool set_bool = 0;
  7415. bool set_bool_not = 0;
  7416. bool set_delayed = 0;
  7417. bool jmp_done = 0;
  7418. if (branch_opcode == ZEND_BOOL) {
  7419. set_bool = 1;
  7420. } else if (branch_opcode == ZEND_BOOL_NOT) {
  7421. set_bool = 1;
  7422. set_bool_not = 1;
  7423. } else if (branch_opcode == ZEND_JMPZ) {
  7424. false_label = target_label;
  7425. } else if (branch_opcode == ZEND_JMPNZ) {
  7426. true_label = target_label;
  7427. } else if (branch_opcode == ZEND_JMPZNZ) {
  7428. true_label = target_label2;
  7429. false_label = target_label;
  7430. } else if (branch_opcode == ZEND_JMPZ_EX) {
  7431. set_bool = 1;
  7432. false_label = target_label;
  7433. } else if (branch_opcode == ZEND_JMPNZ_EX) {
  7434. set_bool = 1;
  7435. true_label = target_label;
  7436. } else {
  7437. ZEND_UNREACHABLE();
  7438. }
  7439. if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
  7440. if (zend_is_true(Z_ZV(op1_addr))) {
  7441. /* Always TRUE */
  7442. if (set_bool) {
  7443. if (set_bool_not) {
  7444. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  7445. } else {
  7446. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  7447. }
  7448. }
  7449. if (true_label != (uint32_t)-1) {
  7450. | b =>true_label
  7451. }
  7452. } else {
  7453. /* Always FALSE */
  7454. if (set_bool) {
  7455. if (set_bool_not) {
  7456. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  7457. } else {
  7458. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  7459. }
  7460. }
  7461. if (false_label != (uint32_t)-1) {
  7462. | b =>false_label
  7463. }
  7464. }
  7465. return 1;
  7466. }
  7467. if (opline->op1_type == IS_CV && (op1_info & MAY_BE_REF)) {
  7468. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  7469. | ZVAL_DEREF FCARG1x, op1_info, TMP1w
  7470. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  7471. }
  7472. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
  7473. if (!(op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_TRUE))) {
  7474. /* Always TRUE */
  7475. if (set_bool) {
  7476. if (set_bool_not) {
  7477. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  7478. } else {
  7479. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  7480. }
  7481. }
  7482. if (true_label != (uint32_t)-1) {
  7483. | b =>true_label
  7484. }
  7485. } else {
  7486. if (!(op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE)))) {
  7487. /* Always FALSE */
  7488. if (set_bool) {
  7489. if (set_bool_not) {
  7490. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  7491. } else {
  7492. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  7493. }
  7494. }
  7495. } else {
  7496. | CMP_ZVAL_TYPE op1_addr, IS_TRUE, ZREG_TMP1
  7497. if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
  7498. if ((op1_info & MAY_BE_LONG) &&
  7499. !(op1_info & MAY_BE_UNDEF) &&
  7500. !set_bool) {
  7501. if (exit_addr) {
  7502. if (branch_opcode == ZEND_JMPNZ) {
  7503. | blt >9
  7504. } else {
  7505. | blt &exit_addr
  7506. }
  7507. } else if (false_label != (uint32_t)-1) {
  7508. | blt =>false_label
  7509. } else {
  7510. | blt >9
  7511. }
  7512. jmp_done = 1;
  7513. } else {
  7514. | bgt >2
  7515. }
  7516. }
  7517. if (!(op1_info & MAY_BE_TRUE)) {
  7518. /* It's FALSE */
  7519. if (set_bool) {
  7520. if (set_bool_not) {
  7521. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  7522. } else {
  7523. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  7524. }
  7525. }
  7526. } else {
  7527. if (exit_addr) {
  7528. if (set_bool) {
  7529. | bne >1
  7530. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  7531. if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
  7532. | b &exit_addr
  7533. } else {
  7534. | b >9
  7535. }
  7536. |1:
  7537. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  7538. if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
  7539. if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_LONG))) {
  7540. | bne &exit_addr
  7541. }
  7542. }
  7543. } else {
  7544. if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
  7545. | beq &exit_addr
  7546. } else if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_LONG))) {
  7547. | bne &exit_addr
  7548. } else {
  7549. | beq >9
  7550. }
  7551. }
  7552. } else if (true_label != (uint32_t)-1 || false_label != (uint32_t)-1) {
  7553. if (set_bool) {
  7554. | bne >1
  7555. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  7556. if (true_label != (uint32_t)-1) {
  7557. | b =>true_label
  7558. } else {
  7559. | b >9
  7560. }
  7561. |1:
  7562. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  7563. } else {
  7564. if (true_label != (uint32_t)-1) {
  7565. | beq =>true_label
  7566. } else if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_LONG))) {
  7567. | bne =>false_label
  7568. jmp_done = 1;
  7569. } else {
  7570. | beq >9
  7571. }
  7572. }
  7573. } else if (set_bool) {
  7574. | cset REG0w, eq
  7575. if (set_bool_not) {
  7576. | neg REG0w, REG0w
  7577. | add REG0w, REG0w, #3
  7578. } else {
  7579. | add REG0w, REG0w, #2
  7580. }
  7581. if ((op1_info & MAY_BE_UNDEF) && (op1_info & MAY_BE_ANY)) {
  7582. set_delayed = 1;
  7583. } else {
  7584. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  7585. }
  7586. }
  7587. }
  7588. }
  7589. /* It's FALSE, but may be UNDEF */
  7590. if (op1_info & MAY_BE_UNDEF) {
  7591. if (op1_info & MAY_BE_ANY) {
  7592. if (set_delayed) {
  7593. | CMP_ZVAL_TYPE op1_addr, IS_UNDEF, ZREG_TMP1
  7594. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  7595. | beq >1
  7596. } else {
  7597. | IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1
  7598. }
  7599. |.cold_code
  7600. |1:
  7601. }
  7602. | LOAD_32BIT_VAL FCARG1w, opline->op1.var
  7603. | SET_EX_OPLINE opline, REG0
  7604. | EXT_CALL zend_jit_undefined_op_helper, REG0
  7605. if (may_throw) {
  7606. if (!zend_jit_check_exception_undef_result(Dst, opline)) {
  7607. return 0;
  7608. }
  7609. }
  7610. if (exit_addr) {
  7611. if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
  7612. | b &exit_addr
  7613. }
  7614. } else if (false_label != (uint32_t)-1) {
  7615. | b =>false_label
  7616. }
  7617. if (op1_info & MAY_BE_ANY) {
  7618. if (exit_addr) {
  7619. if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
  7620. | b >9
  7621. }
  7622. } else if (false_label == (uint32_t)-1) {
  7623. | b >9
  7624. }
  7625. |.code
  7626. }
  7627. }
  7628. if (!jmp_done) {
  7629. if (exit_addr) {
  7630. if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
  7631. if (op1_info & MAY_BE_LONG) {
  7632. | b >9
  7633. }
  7634. } else if (op1_info & MAY_BE_LONG) {
  7635. | b &exit_addr
  7636. }
  7637. } else if (false_label != (uint32_t)-1) {
  7638. | b =>false_label
  7639. } else if ((op1_info & MAY_BE_LONG) || (op1_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
  7640. | b >9
  7641. }
  7642. }
  7643. }
  7644. }
  7645. if (op1_info & MAY_BE_LONG) {
  7646. |2:
  7647. if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) {
  7648. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >2, ZREG_TMP1
  7649. }
  7650. if (Z_MODE(op1_addr) == IS_REG) {
  7651. | tst Rx(Z_REG(op1_addr)), Rx(Z_REG(op1_addr))
  7652. } else {
  7653. | LONG_CMP_WITH_CONST op1_addr, Z_L(0), TMP1, TMP2
  7654. }
  7655. if (set_bool) {
  7656. | cset REG0w, ne
  7657. if (set_bool_not) {
  7658. | neg REG0w, REG0w
  7659. | add REG0w, REG0w, #3
  7660. } else {
  7661. | add REG0w, REG0w, #2
  7662. }
  7663. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  7664. }
  7665. if (exit_addr) {
  7666. if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
  7667. | bne &exit_addr
  7668. } else {
  7669. | beq &exit_addr
  7670. }
  7671. } else if (true_label != (uint32_t)-1 || false_label != (uint32_t)-1) {
  7672. if (true_label != (uint32_t)-1) {
  7673. | bne =>true_label
  7674. if (false_label != (uint32_t)-1) {
  7675. | b =>false_label
  7676. }
  7677. } else {
  7678. | beq =>false_label
  7679. }
  7680. }
  7681. }
  7682. if ((op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) == MAY_BE_DOUBLE) {
  7683. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7684. |.cold_code
  7685. }
  7686. |2:
  7687. | fmov FPR0, xzr // TODO: "movi d0, #0" is not recognized by DynASM/arm64
  7688. | DOUBLE_CMP ZREG_FPR0, op1_addr, ZREG_TMP1, ZREG_FPTMP
  7689. if (set_bool) {
  7690. if (exit_addr) {
  7691. if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
  7692. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  7693. | bvs &exit_addr
  7694. | bne &exit_addr
  7695. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  7696. } else {
  7697. | bvs >1
  7698. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  7699. | beq &exit_addr
  7700. |1:
  7701. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  7702. }
  7703. } else if (false_label != (uint32_t)-1) { // JMPZ_EX
  7704. | bvs >1
  7705. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  7706. | beq => false_label
  7707. |1:
  7708. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  7709. } else if (true_label != (uint32_t)-1) { // JMPNZ_EX
  7710. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  7711. | bvs => true_label
  7712. | bne => true_label
  7713. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  7714. } else if (set_bool_not) { // BOOL_NOT
  7715. | mov REG0w, #IS_FALSE
  7716. | bvs >1
  7717. | bne >1
  7718. | mov REG0w, #IS_TRUE
  7719. |1:
  7720. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  7721. } else { // BOOL
  7722. | mov REG0w, #IS_TRUE
  7723. | bvs >1
  7724. | bne >1
  7725. | mov REG0w, #IS_FALSE
  7726. |1:
  7727. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  7728. }
  7729. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7730. | b >9
  7731. |.code
  7732. }
  7733. } else {
  7734. if (exit_addr) {
  7735. if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
  7736. | bvs &exit_addr
  7737. | bne &exit_addr
  7738. |1:
  7739. } else {
  7740. | bvs >1
  7741. | beq &exit_addr
  7742. |1:
  7743. }
  7744. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7745. | b >9
  7746. }
  7747. } else {
  7748. ZEND_ASSERT(true_label != (uint32_t)-1 || false_label != (uint32_t)-1);
  7749. if (false_label != (uint32_t)-1 ) {
  7750. | bvs >1
  7751. | beq => false_label
  7752. |1:
  7753. if (true_label != (uint32_t)-1) {
  7754. | b =>true_label
  7755. } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7756. | b >9
  7757. }
  7758. } else {
  7759. | bvs => true_label
  7760. | bne => true_label
  7761. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7762. | b >9
  7763. }
  7764. }
  7765. }
  7766. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7767. |.code
  7768. }
  7769. }
  7770. } else if (op1_info & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) {
  7771. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7772. |.cold_code
  7773. |2:
  7774. }
  7775. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  7776. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  7777. }
  7778. | SET_EX_OPLINE opline, REG0
  7779. | EXT_CALL zend_is_true, REG0
  7780. | mov REG0, RETVALx
  7781. if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
  7782. (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  7783. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
  7784. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  7785. | IF_NOT_ZVAL_REFCOUNTED op1_addr, >3, ZREG_TMP1, ZREG_TMP2
  7786. }
  7787. | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
  7788. | GC_DELREF FCARG1x, TMP1w
  7789. | bne >3
  7790. // In x86, r0 is used in macro ZVAL_DTOR_FUNC as temporary register, hence, r0 should be saved/restored
  7791. // before/after this macro. In AArch64, TMP1 is used, but we still have to store REG0,
  7792. // because it's clobbered by function call.
  7793. | str REG0, T1 // save
  7794. | ZVAL_DTOR_FUNC op1_info, opline, TMP1
  7795. | ldr REG0, T1 // restore
  7796. |3:
  7797. }
  7798. if (may_throw) {
  7799. | MEM_LOAD_64_ZTS ldr, REG1, executor_globals, exception, TMP1
  7800. | cbnz REG1, ->exception_handler_undef
  7801. }
  7802. if (set_bool) {
  7803. if (set_bool_not) {
  7804. | neg REG0w, REG0w
  7805. | add REG0w, REG0w, #3
  7806. } else {
  7807. | add REG0w, REG0w, #2
  7808. }
  7809. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  7810. if (exit_addr) {
  7811. | CMP_ZVAL_TYPE res_addr, IS_FALSE, ZREG_TMP1
  7812. if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
  7813. | bne &exit_addr
  7814. } else {
  7815. | beq &exit_addr
  7816. }
  7817. } else if (true_label != (uint32_t)-1 || false_label != (uint32_t)-1) {
  7818. | CMP_ZVAL_TYPE res_addr, IS_FALSE, ZREG_TMP1
  7819. if (true_label != (uint32_t)-1) {
  7820. | bne =>true_label
  7821. if (false_label != (uint32_t)-1) {
  7822. | b =>false_label
  7823. } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7824. | b >9
  7825. }
  7826. } else {
  7827. | beq =>false_label
  7828. }
  7829. }
  7830. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7831. | b >9
  7832. |.code
  7833. }
  7834. } else {
  7835. if (exit_addr) {
  7836. if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
  7837. | cbnz REG0w, &exit_addr
  7838. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7839. | b >9
  7840. }
  7841. } else {
  7842. | cbz REG0w, &exit_addr
  7843. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7844. | b >9
  7845. }
  7846. }
  7847. } else if (true_label != (uint32_t)-1) {
  7848. | cbnz REG0w, =>true_label
  7849. if (false_label != (uint32_t)-1) {
  7850. | b =>false_label
  7851. } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7852. | b >9
  7853. }
  7854. } else {
  7855. | cbz REG0w, =>false_label
  7856. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7857. | b >9
  7858. }
  7859. }
  7860. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
  7861. |.code
  7862. }
  7863. }
  7864. }
  7865. |9:
  7866. return 1;
  7867. }
  7868. static int zend_jit_qm_assign(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr)
  7869. {
  7870. if (op1_addr != op1_def_addr) {
  7871. if (!zend_jit_update_regs(Dst, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
  7872. return 0;
  7873. }
  7874. if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
  7875. op1_addr = op1_def_addr;
  7876. }
  7877. }
  7878. if (!zend_jit_simple_assign(Dst, opline, res_addr, res_use_info, res_info, opline->op1_type, op1_addr, op1_info, 0, 0, 0)) {
  7879. return 0;
  7880. }
  7881. if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
  7882. return 0;
  7883. }
  7884. if (op1_info & MAY_BE_UNDEF) {
  7885. zend_jit_check_exception(Dst);
  7886. }
  7887. return 1;
  7888. }
  7889. static int zend_jit_assign(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_use_addr, uint32_t op1_def_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr op2_def_addr, uint32_t res_info, zend_jit_addr res_addr, int may_throw)
  7890. {
  7891. ZEND_ASSERT(opline->op1_type == IS_CV);
  7892. if (op2_addr != op2_def_addr) {
  7893. if (!zend_jit_update_regs(Dst, opline->op2.var, op2_addr, op2_def_addr, op2_info)) {
  7894. return 0;
  7895. }
  7896. if (Z_MODE(op2_def_addr) == IS_REG && Z_MODE(op2_addr) != IS_REG) {
  7897. op2_addr = op2_def_addr;
  7898. }
  7899. }
  7900. if (Z_MODE(op1_addr) != IS_REG
  7901. && Z_MODE(op1_use_addr) == IS_REG
  7902. && !Z_LOAD(op1_use_addr)
  7903. && !Z_STORE(op1_use_addr)) {
  7904. /* Force type update */
  7905. op1_info |= MAY_BE_UNDEF;
  7906. }
  7907. if (!zend_jit_assign_to_variable(Dst, opline, op1_use_addr, op1_addr, op1_info, op1_def_info, opline->op2_type, op2_addr, op2_info, res_addr,
  7908. may_throw)) {
  7909. return 0;
  7910. }
  7911. if (!zend_jit_store_var_if_necessary_ex(Dst, opline->op1.var, op1_addr, op1_def_info, op1_use_addr, op1_info)) {
  7912. return 0;
  7913. }
  7914. if (opline->result_type != IS_UNUSED) {
  7915. if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
  7916. return 0;
  7917. }
  7918. }
  7919. return 1;
  7920. }
  7921. /* copy of hidden zend_closure */
  7922. typedef struct _zend_closure {
  7923. zend_object std;
  7924. zend_function func;
  7925. zval this_ptr;
  7926. zend_class_entry *called_scope;
  7927. zif_handler orig_internal_handler;
  7928. } zend_closure;
  7929. static int zend_jit_stack_check(dasm_State **Dst, const zend_op *opline, uint32_t used_stack)
  7930. {
  7931. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  7932. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  7933. if (!exit_addr) {
  7934. return 0;
  7935. }
  7936. | // Check Stack Overflow
  7937. | MEM_LOAD_64_ZTS ldr, REG1, executor_globals, vm_stack_end, TMP1
  7938. | MEM_LOAD_OP_ZTS sub, ldr, REG1, executor_globals, vm_stack_top, TMP1, TMP2
  7939. | CMP_64_WITH_CONST_32 REG1, used_stack, TMP1
  7940. | blo &exit_addr
  7941. return 1;
  7942. }
  7943. static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_function *func, bool is_closure, bool delayed_fetch_this, int checked_stack)
  7944. {
  7945. uint32_t used_stack;
  7946. bool stack_check = 1;
  7947. // REG0 -> zend_function
  7948. // FCARG1 -> used_stack
  7949. if (func) {
  7950. used_stack = zend_vm_calc_used_stack(opline->extended_value, func);
  7951. if ((int)used_stack <= checked_stack) {
  7952. stack_check = 0;
  7953. }
  7954. } else {
  7955. used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value) * sizeof(zval);
  7956. | // if (EXPECTED(ZEND_USER_CODE(func->type))) {
  7957. if (!is_closure) {
  7958. | LOAD_32BIT_VAL FCARG1w, used_stack
  7959. | // Check whether REG0 is an internal function.
  7960. | ldrb TMP1w, [REG0, #offsetof(zend_function, type)]
  7961. | TST_32_WITH_CONST TMP1w, 1, TMP2w
  7962. | bne >1
  7963. } else {
  7964. | LOAD_32BIT_VAL FCARG1w, used_stack
  7965. }
  7966. | // used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval);
  7967. | LOAD_32BIT_VAL REG2w, opline->extended_value
  7968. if (!is_closure) {
  7969. | ldr TMP1w, [REG0, #offsetof(zend_function, op_array.num_args)]
  7970. | cmp REG2w, TMP1w
  7971. | csel REG2w, REG2w, TMP1w, le
  7972. | ldr TMP1w, [REG0, #offsetof(zend_function, op_array.last_var)]
  7973. | sub REG2w, REG2w, TMP1w
  7974. | ldr TMP1w, [REG0, #offsetof(zend_function, op_array.T)]
  7975. | sub REG2w, REG2w, TMP1w
  7976. } else {
  7977. | ldr TMP1w, [REG0, #offsetof(zend_closure, func.op_array.num_args)]
  7978. | cmp REG2w, TMP1w
  7979. | csel REG2w, REG2w, TMP1w, le
  7980. | ldr TMP1w, [REG0, #offsetof(zend_closure, func.op_array.last_var)]
  7981. | sub REG2w, REG2w, TMP1w
  7982. | ldr TMP1w, [REG0, #offsetof(zend_closure, func.op_array.T)]
  7983. | sub REG2w, REG2w, TMP1w
  7984. }
  7985. | sxtw REG2, REG2w
  7986. | sub FCARG1x, FCARG1x, REG2, lsl #4
  7987. |1:
  7988. }
  7989. zend_jit_start_reuse_ip();
  7990. | // if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
  7991. | MEM_LOAD_64_ZTS ldr, RX, executor_globals, vm_stack_top, TMP1
  7992. if (stack_check) {
  7993. | // Check Stack Overflow
  7994. | MEM_LOAD_64_ZTS ldr, REG2, executor_globals, vm_stack_end, TMP1
  7995. | sub REG2, REG2, RX
  7996. if (func) {
  7997. | CMP_64_WITH_CONST_32 REG2, used_stack, TMP1
  7998. } else {
  7999. | cmp REG2, FCARG1x
  8000. }
  8001. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  8002. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  8003. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  8004. if (!exit_addr) {
  8005. return 0;
  8006. }
  8007. | blo &exit_addr
  8008. } else {
  8009. | blo >1
  8010. | // EG(vm_stack_top) = (zval*)((char*)call + used_stack);
  8011. |.cold_code
  8012. |1:
  8013. if (func) {
  8014. | LOAD_32BIT_VAL FCARG1w, used_stack
  8015. }
  8016. if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
  8017. | SET_EX_OPLINE opline, REG0
  8018. | EXT_CALL zend_jit_int_extend_stack_helper, REG0
  8019. } else {
  8020. if (!is_closure) {
  8021. | mov FCARG2x, REG0
  8022. } else {
  8023. | add FCARG2x, REG0, #offsetof(zend_closure, func)
  8024. }
  8025. | SET_EX_OPLINE opline, REG0
  8026. | EXT_CALL zend_jit_extend_stack_helper, REG0
  8027. }
  8028. | mov RX, RETVALx
  8029. | b >1
  8030. |.code
  8031. }
  8032. }
  8033. if (func) {
  8034. || if (arm64_may_encode_imm12((int64_t)used_stack)) {
  8035. | MEM_UPDATE_ZTS add, ldr, str, #used_stack, executor_globals, vm_stack_top, REG2, TMP1
  8036. || } else {
  8037. | LOAD_32BIT_VAL TMP1w, used_stack
  8038. | MEM_UPDATE_ZTS add, ldr, str, TMP1, executor_globals, vm_stack_top, REG2, TMP2
  8039. || }
  8040. } else {
  8041. | MEM_UPDATE_ZTS add, ldr, str, FCARG1x, executor_globals, vm_stack_top, REG2, TMP1
  8042. }
  8043. | // zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
  8044. if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || opline->opcode != ZEND_INIT_METHOD_CALL) {
  8045. | // ZEND_SET_CALL_INFO(call, 0, call_info);
  8046. | LOAD_32BIT_VAL TMP1w, (IS_UNDEF | ZEND_CALL_NESTED_FUNCTION)
  8047. | str TMP1w, EX:RX->This.u1.type_info
  8048. }
  8049. if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
  8050. | // call->func = func;
  8051. |1:
  8052. | ADDR_STORE EX:RX->func, func, REG1
  8053. } else {
  8054. if (!is_closure) {
  8055. | // call->func = func;
  8056. | str REG0, EX:RX->func
  8057. } else {
  8058. | // call->func = &closure->func;
  8059. | add REG1, REG0, #offsetof(zend_closure, func)
  8060. | str REG1, EX:RX->func
  8061. }
  8062. |1:
  8063. }
  8064. if (opline->opcode == ZEND_INIT_METHOD_CALL) {
  8065. | // Z_PTR(call->This) = obj;
  8066. | ldr REG1, T1
  8067. | str REG1, EX:RX->This.value.ptr
  8068. if (opline->op1_type == IS_UNUSED || delayed_fetch_this) {
  8069. | // call->call_info |= ZEND_CALL_HAS_THIS;
  8070. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  8071. | LOAD_32BIT_VAL TMP1w, ZEND_CALL_HAS_THIS
  8072. | str TMP1w, EX:RX->This.u1.type_info
  8073. } else {
  8074. | ldr TMP1w, EX:RX->This.u1.type_info
  8075. | BW_OP_32_WITH_CONST orr, TMP1w, TMP1w, ZEND_CALL_HAS_THIS, TMP2w
  8076. | str TMP1w, EX:RX->This.u1.type_info
  8077. }
  8078. } else {
  8079. if (opline->op1_type == IS_CV) {
  8080. | // GC_ADDREF(obj);
  8081. | GC_ADDREF REG1, TMP1w
  8082. }
  8083. | // call->call_info |= ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS;
  8084. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  8085. | LOAD_32BIT_VAL TMP1w, (ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS)
  8086. | str TMP1w, EX:RX->This.u1.type_info
  8087. } else {
  8088. | ldr TMP1w, EX:RX->This.u1.type_info
  8089. | BW_OP_32_WITH_CONST orr, TMP1w, TMP1w, (ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS), TMP2w
  8090. | str TMP1w, EX:RX->This.u1.type_info
  8091. }
  8092. }
  8093. } else if (!is_closure) {
  8094. | // Z_CE(call->This) = called_scope;
  8095. | str xzr, EX:RX->This.value.ptr
  8096. } else {
  8097. if (opline->op2_type == IS_CV) {
  8098. | // GC_ADDREF(closure);
  8099. | GC_ADDREF REG0, TMP1w
  8100. }
  8101. | // object_or_called_scope = closure->called_scope;
  8102. | ldr REG1, [REG0, #offsetof(zend_closure, called_scope)]
  8103. | str REG1, EX:RX->This.value.ptr
  8104. | // call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE |
  8105. | // (closure->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE);
  8106. | ldr REG2w, [REG0, #offsetof(zend_closure, func.common.fn_flags)]
  8107. | BW_OP_32_WITH_CONST and, REG2w, REG2w, ZEND_ACC_FAKE_CLOSURE, TMP1w
  8108. | BW_OP_32_WITH_CONST orr, REG2w, REG2w, (ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE), TMP1w
  8109. | // if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
  8110. | ldrb TMP1w, [REG0, #offsetof(zend_closure, this_ptr.u1.v.type)]
  8111. | cmp TMP1w, #IS_UNDEF
  8112. | beq >1
  8113. | // call_info |= ZEND_CALL_HAS_THIS;
  8114. | BW_OP_32_WITH_CONST orr, REG2w, REG2w, ZEND_CALL_HAS_THIS, TMP1w
  8115. | // object_or_called_scope = Z_OBJ(closure->this_ptr);
  8116. | ldr REG1, [REG0, #offsetof(zend_closure, this_ptr.value.ptr)]
  8117. |1:
  8118. | // ZEND_SET_CALL_INFO(call, 0, call_info);
  8119. | ldr TMP1w, EX:RX->This.u1.type_info
  8120. | orr TMP1w, TMP1w, REG2w
  8121. | str TMP1w, EX:RX->This.u1.type_info
  8122. | // Z_PTR(call->This) = object_or_called_scope;
  8123. | str REG1, EX:RX->This.value.ptr
  8124. | ldr TMP1, [REG0, #offsetof(zend_closure, func.op_array.run_time_cache__ptr)]
  8125. | cbnz TMP1, >1
  8126. | add FCARG1x, REG0, #offsetof(zend_closure, func)
  8127. | EXT_CALL zend_jit_init_func_run_time_cache_helper, REG0
  8128. |1:
  8129. }
  8130. | // ZEND_CALL_NUM_ARGS(call) = num_args;
  8131. | LOAD_32BIT_VAL TMP1w, opline->extended_value
  8132. | str TMP1w, EX:RX->This.u2.num_args
  8133. return 1;
  8134. }
  8135. static int zend_jit_init_fcall_guard(dasm_State **Dst, uint32_t level, const zend_function *func, const zend_op *to_opline)
  8136. {
  8137. int32_t exit_point;
  8138. const void *exit_addr;
  8139. if (func->type == ZEND_INTERNAL_FUNCTION) {
  8140. #ifdef ZEND_WIN32
  8141. // TODO: ASLR may cause different addresses in different workers ???
  8142. return 0;
  8143. #endif
  8144. } else if (func->type == ZEND_USER_FUNCTION) {
  8145. if (!zend_accel_in_shm(func->op_array.opcodes)) {
  8146. /* op_array and op_array->opcodes are not persistent. We can't link. */
  8147. return 0;
  8148. }
  8149. } else {
  8150. ZEND_UNREACHABLE();
  8151. return 0;
  8152. }
  8153. exit_point = zend_jit_trace_get_exit_point(to_opline, ZEND_JIT_EXIT_POLYMORPHISM);
  8154. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  8155. if (!exit_addr) {
  8156. return 0;
  8157. }
  8158. | // call = EX(call);
  8159. | ldr REG1, EX->call
  8160. while (level > 0) {
  8161. | ldr REG1, EX:REG1->prev_execute_data
  8162. level--;
  8163. }
  8164. if (func->type == ZEND_USER_FUNCTION &&
  8165. (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
  8166. (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
  8167. !func->common.function_name)) {
  8168. const zend_op *opcodes = func->op_array.opcodes;
  8169. | ldr REG1, EX:REG1->func
  8170. | LOAD_ADDR REG2, ((ptrdiff_t)opcodes)
  8171. | ldr TMP1, [REG1, #offsetof(zend_op_array, opcodes)]
  8172. | cmp TMP1, REG2
  8173. | bne &exit_addr
  8174. } else {
  8175. | LOAD_ADDR REG2, ((ptrdiff_t)func)
  8176. | ldr TMP1, EX:REG1->func
  8177. | cmp TMP1, REG2
  8178. | bne &exit_addr
  8179. }
  8180. return 1;
  8181. }
  8182. static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, int checked_stack)
  8183. {
  8184. zend_func_info *info = ZEND_FUNC_INFO(op_array);
  8185. zend_call_info *call_info = NULL;
  8186. zend_function *func = NULL;
  8187. if (delayed_call_chain) {
  8188. if (!zend_jit_save_call_chain(Dst, delayed_call_level)) {
  8189. return 0;
  8190. }
  8191. }
  8192. if (info) {
  8193. call_info = info->callee_info;
  8194. while (call_info && call_info->caller_init_opline != opline) {
  8195. call_info = call_info->next_callee;
  8196. }
  8197. if (call_info && call_info->callee_func && !call_info->is_prototype) {
  8198. func = call_info->callee_func;
  8199. }
  8200. }
  8201. if (!func
  8202. && trace
  8203. && trace->op == ZEND_JIT_TRACE_INIT_CALL) {
  8204. func = (zend_function*)trace->func;
  8205. }
  8206. if (opline->opcode == ZEND_INIT_FCALL
  8207. && func
  8208. && func->type == ZEND_INTERNAL_FUNCTION) {
  8209. /* load constant address later */
  8210. } else if (func && op_array == &func->op_array) {
  8211. /* recursive call */
  8212. | ldr REG0, EX->func
  8213. } else {
  8214. | // if (CACHED_PTR(opline->result.num))
  8215. | ldr REG2, EX->run_time_cache
  8216. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG2, opline->result.num, TMP1
  8217. | cbz REG0, >1
  8218. |.cold_code
  8219. |1:
  8220. if (opline->opcode == ZEND_INIT_FCALL
  8221. && func
  8222. && func->type == ZEND_USER_FUNCTION
  8223. && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) {
  8224. | LOAD_ADDR FCARG1x, func
  8225. | MEM_ACCESS_64_WITH_UOFFSET str, FCARG1x, REG2, opline->result.num, TMP1
  8226. | EXT_CALL zend_jit_init_func_run_time_cache_helper, REG0
  8227. | mov REG0, RETVALx
  8228. | b >3
  8229. } else {
  8230. zval *zv = RT_CONSTANT(opline, opline->op2);
  8231. if (opline->opcode == ZEND_INIT_FCALL) {
  8232. | LOAD_ADDR FCARG1x, Z_STR_P(zv);
  8233. | ADD_SUB_64_WITH_CONST_32 add, FCARG2x, REG2, opline->result.num, TMP1
  8234. | EXT_CALL zend_jit_find_func_helper, REG0
  8235. } else if (opline->opcode == ZEND_INIT_FCALL_BY_NAME) {
  8236. | LOAD_ADDR FCARG1x, Z_STR_P(zv + 1);
  8237. | ADD_SUB_64_WITH_CONST_32 add, FCARG2x, REG2, opline->result.num, TMP1
  8238. | EXT_CALL zend_jit_find_func_helper, REG0
  8239. } else if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
  8240. | LOAD_ADDR FCARG1x, zv;
  8241. | ADD_SUB_64_WITH_CONST_32 add, FCARG2x, REG2, opline->result.num, TMP1
  8242. | EXT_CALL zend_jit_find_ns_func_helper, REG0
  8243. } else {
  8244. ZEND_UNREACHABLE();
  8245. }
  8246. | // Get the return value of function zend_jit_find_func_helper/zend_jit_find_ns_func_helper
  8247. | mov REG0, RETVALx
  8248. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  8249. int32_t exit_point = zend_jit_trace_get_exit_point(opline,
  8250. func && (func->common.fn_flags & ZEND_ACC_IMMUTABLE) ? ZEND_JIT_EXIT_INVALIDATE : 0);
  8251. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  8252. if (!exit_addr) {
  8253. return 0;
  8254. }
  8255. if (!func || opline->opcode == ZEND_INIT_FCALL) {
  8256. | cbnz REG0, >3
  8257. } else if (func->type == ZEND_USER_FUNCTION
  8258. && !(func->common.fn_flags & ZEND_ACC_IMMUTABLE)) {
  8259. const zend_op *opcodes = func->op_array.opcodes;
  8260. | LOAD_ADDR REG1, ((ptrdiff_t)opcodes)
  8261. | ldr TMP1, [REG0, #offsetof(zend_op_array, opcodes)]
  8262. | cmp TMP1, REG1
  8263. | beq >3
  8264. } else {
  8265. | LOAD_ADDR REG1, ((ptrdiff_t)func)
  8266. | cmp REG0, REG1
  8267. | beq >3
  8268. }
  8269. | b &exit_addr
  8270. } else {
  8271. | cbnz REG0, >3
  8272. | // SAVE_OPLINE();
  8273. | SET_EX_OPLINE opline, REG0
  8274. | b ->undefined_function
  8275. }
  8276. }
  8277. |.code
  8278. |3:
  8279. }
  8280. if (!zend_jit_push_call_frame(Dst, opline, op_array, func, 0, 0, checked_stack)) {
  8281. return 0;
  8282. }
  8283. if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
  8284. if (!zend_jit_save_call_chain(Dst, call_level)) {
  8285. return 0;
  8286. }
  8287. } else {
  8288. delayed_call_chain = 1;
  8289. delayed_call_level = call_level;
  8290. }
  8291. return 1;
  8292. }
  8293. static int zend_jit_init_method_call(dasm_State **Dst,
  8294. const zend_op *opline,
  8295. uint32_t b,
  8296. const zend_op_array *op_array,
  8297. zend_ssa *ssa,
  8298. const zend_ssa_op *ssa_op,
  8299. int call_level,
  8300. uint32_t op1_info,
  8301. zend_jit_addr op1_addr,
  8302. zend_class_entry *ce,
  8303. bool ce_is_instanceof,
  8304. bool on_this,
  8305. bool delayed_fetch_this,
  8306. zend_class_entry *trace_ce,
  8307. zend_jit_trace_rec *trace,
  8308. int checked_stack,
  8309. bool polymorphic_side_trace)
  8310. {
  8311. zend_func_info *info = ZEND_FUNC_INFO(op_array);
  8312. zend_call_info *call_info = NULL;
  8313. zend_function *func = NULL;
  8314. zval *function_name;
  8315. ZEND_ASSERT(opline->op2_type == IS_CONST);
  8316. ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
  8317. function_name = RT_CONSTANT(opline, opline->op2);
  8318. if (info) {
  8319. call_info = info->callee_info;
  8320. while (call_info && call_info->caller_init_opline != opline) {
  8321. call_info = call_info->next_callee;
  8322. }
  8323. if (call_info && call_info->callee_func && !call_info->is_prototype) {
  8324. func = call_info->callee_func;
  8325. }
  8326. }
  8327. if (polymorphic_side_trace) {
  8328. /* function is passed in r0 from parent_trace */
  8329. } else {
  8330. if (on_this) {
  8331. zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
  8332. | GET_ZVAL_PTR FCARG1x, this_addr, TMP1
  8333. } else {
  8334. if (op1_info & MAY_BE_REF) {
  8335. if (opline->op1_type == IS_CV) {
  8336. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  8337. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  8338. }
  8339. | ZVAL_DEREF FCARG1x, op1_info, TMP1w
  8340. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  8341. } else {
  8342. /* Hack: Convert reference to regular value to simplify JIT code */
  8343. ZEND_ASSERT(Z_REG(op1_addr) == ZREG_FP);
  8344. | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >1, ZREG_TMP1
  8345. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  8346. | EXT_CALL zend_jit_unref_helper, REG0
  8347. |1:
  8348. }
  8349. }
  8350. if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
  8351. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  8352. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  8353. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  8354. if (!exit_addr) {
  8355. return 0;
  8356. }
  8357. | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr, ZREG_TMP1
  8358. } else {
  8359. | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1, ZREG_TMP1
  8360. |.cold_code
  8361. |1:
  8362. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  8363. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  8364. }
  8365. | SET_EX_OPLINE opline, REG0
  8366. if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
  8367. | EXT_CALL zend_jit_invalid_method_call_tmp, REG0
  8368. } else {
  8369. | EXT_CALL zend_jit_invalid_method_call, REG0
  8370. }
  8371. | b ->exception_handler
  8372. |.code
  8373. }
  8374. }
  8375. | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
  8376. }
  8377. if (delayed_call_chain) {
  8378. if (!zend_jit_save_call_chain(Dst, delayed_call_level)) {
  8379. return 0;
  8380. }
  8381. }
  8382. | str FCARG1x, T1 // save
  8383. if (func) {
  8384. | // fbc = CACHED_PTR(opline->result.num + sizeof(void*));
  8385. | ldr REG0, EX->run_time_cache
  8386. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, (opline->result.num + sizeof(void*)), TMP1
  8387. | cbz REG0, >1
  8388. } else {
  8389. | // if (CACHED_PTR(opline->result.num) == obj->ce)) {
  8390. | ldr REG0, EX->run_time_cache
  8391. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG2, REG0, opline->result.num, TMP1
  8392. | ldr TMP1, [FCARG1x, #offsetof(zend_object, ce)]
  8393. | cmp REG2, TMP1
  8394. | bne >1
  8395. | // fbc = CACHED_PTR(opline->result.num + sizeof(void*));
  8396. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, (opline->result.num + sizeof(void*)), TMP1
  8397. }
  8398. |.cold_code
  8399. |1:
  8400. | LOAD_ADDR FCARG2x, function_name
  8401. if (TMP_ZVAL_OFFSET == 0) {
  8402. | mov CARG3, sp
  8403. } else {
  8404. | add CARG3, sp, #TMP_ZVAL_OFFSET
  8405. }
  8406. | SET_EX_OPLINE opline, REG0
  8407. if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
  8408. | EXT_CALL zend_jit_find_method_tmp_helper, REG0
  8409. } else {
  8410. | EXT_CALL zend_jit_find_method_helper, REG0
  8411. }
  8412. | mov REG0, RETVALx
  8413. | cbnz REG0, >2
  8414. | b ->exception_handler
  8415. |.code
  8416. |2:
  8417. }
  8418. if ((!func || zend_jit_may_be_modified(func, op_array))
  8419. && trace
  8420. && trace->op == ZEND_JIT_TRACE_INIT_CALL
  8421. && trace->func
  8422. ) {
  8423. int32_t exit_point;
  8424. const void *exit_addr;
  8425. exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : ZEND_JIT_EXIT_METHOD_CALL);
  8426. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  8427. if (!exit_addr) {
  8428. return 0;
  8429. }
  8430. func = (zend_function*)trace->func;
  8431. if (func->type == ZEND_USER_FUNCTION &&
  8432. (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
  8433. (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
  8434. !func->common.function_name)) {
  8435. const zend_op *opcodes = func->op_array.opcodes;
  8436. | LOAD_ADDR TMP1, opcodes
  8437. | ldr TMP2, [REG0, #offsetof(zend_op_array, opcodes)]
  8438. | cmp TMP2, TMP1
  8439. | bne &exit_addr
  8440. } else {
  8441. | LOAD_ADDR TMP1, func
  8442. | cmp REG0, TMP1
  8443. | bne &exit_addr
  8444. }
  8445. }
  8446. if (!func) {
  8447. | // if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
  8448. | ldr TMP1w, [REG0, #offsetof(zend_function, common.fn_flags)]
  8449. | TST_32_WITH_CONST TMP1w, ZEND_ACC_STATIC, TMP2w
  8450. | bne >1
  8451. |.cold_code
  8452. |1:
  8453. }
  8454. if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) != 0) {
  8455. | ldr FCARG1x, T1 // restore
  8456. | mov FCARG2x, REG0
  8457. | LOAD_32BIT_VAL CARG3w, opline->extended_value
  8458. if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
  8459. | EXT_CALL zend_jit_push_static_metod_call_frame_tmp, REG0
  8460. } else {
  8461. | EXT_CALL zend_jit_push_static_metod_call_frame, REG0
  8462. }
  8463. if ((opline->op1_type & (IS_VAR|IS_TMP_VAR) && !delayed_fetch_this)) {
  8464. | cbz RETVALx, ->exception_handler
  8465. }
  8466. | mov RX, RETVALx
  8467. }
  8468. if (!func) {
  8469. | b >9
  8470. |.code
  8471. }
  8472. if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) {
  8473. if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 0, delayed_fetch_this, checked_stack)) {
  8474. return 0;
  8475. }
  8476. }
  8477. if (!func) {
  8478. |9:
  8479. }
  8480. zend_jit_start_reuse_ip();
  8481. if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
  8482. if (!zend_jit_save_call_chain(Dst, call_level)) {
  8483. return 0;
  8484. }
  8485. } else {
  8486. delayed_call_chain = 1;
  8487. delayed_call_level = call_level;
  8488. }
  8489. return 1;
  8490. }
  8491. static int zend_jit_init_closure_call(dasm_State **Dst,
  8492. const zend_op *opline,
  8493. uint32_t b,
  8494. const zend_op_array *op_array,
  8495. zend_ssa *ssa,
  8496. const zend_ssa_op *ssa_op,
  8497. int call_level,
  8498. zend_jit_trace_rec *trace,
  8499. int checked_stack)
  8500. {
  8501. zend_function *func = NULL;
  8502. zend_jit_addr op2_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
  8503. | GET_ZVAL_PTR REG0, op2_addr, TMP1
  8504. if (ssa->var_info[ssa_op->op2_use].ce != zend_ce_closure
  8505. && !(ssa->var_info[ssa_op->op2_use].type & MAY_BE_CLASS_GUARD)) {
  8506. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  8507. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  8508. if (!exit_addr) {
  8509. return 0;
  8510. }
  8511. | LOAD_ADDR FCARG1x, ((ptrdiff_t)zend_ce_closure)
  8512. | ldr, TMP1, [REG0, #offsetof(zend_object, ce)]
  8513. | cmp TMP1, FCARG1x
  8514. | bne &exit_addr
  8515. if (ssa->var_info && ssa_op->op2_use >= 0) {
  8516. ssa->var_info[ssa_op->op2_use].type |= MAY_BE_CLASS_GUARD;
  8517. ssa->var_info[ssa_op->op2_use].ce = zend_ce_closure;
  8518. ssa->var_info[ssa_op->op2_use].is_instanceof = 0;
  8519. }
  8520. }
  8521. if (trace
  8522. && trace->op == ZEND_JIT_TRACE_INIT_CALL
  8523. && trace->func
  8524. && trace->func->type == ZEND_USER_FUNCTION) {
  8525. const zend_op *opcodes;
  8526. int32_t exit_point;
  8527. const void *exit_addr;
  8528. func = (zend_function*)trace->func;
  8529. opcodes = func->op_array.opcodes;
  8530. exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_CLOSURE_CALL);
  8531. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  8532. if (!exit_addr) {
  8533. return 0;
  8534. }
  8535. | LOAD_ADDR FCARG1x, ((ptrdiff_t)opcodes)
  8536. | ldr TMP1, [REG0, #offsetof(zend_closure, func.op_array.opcodes)]
  8537. | cmp TMP1, FCARG1x
  8538. | bne &exit_addr
  8539. }
  8540. if (delayed_call_chain) {
  8541. if (!zend_jit_save_call_chain(Dst, delayed_call_level)) {
  8542. return 0;
  8543. }
  8544. }
  8545. if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 1, 0, checked_stack)) {
  8546. return 0;
  8547. }
  8548. if (zend_jit_needs_call_chain(NULL, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
  8549. if (!zend_jit_save_call_chain(Dst, call_level)) {
  8550. return 0;
  8551. }
  8552. } else {
  8553. delayed_call_chain = 1;
  8554. delayed_call_level = call_level;
  8555. }
  8556. if (trace
  8557. && trace->op == ZEND_JIT_TRACE_END
  8558. && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
  8559. if (!zend_jit_set_valid_ip(Dst, opline + 1)) {
  8560. return 0;
  8561. }
  8562. }
  8563. return 1;
  8564. }
  8565. static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, int call_level, unsigned int next_block, zend_jit_trace_rec *trace)
  8566. {
  8567. zend_func_info *info = ZEND_FUNC_INFO(op_array);
  8568. zend_call_info *call_info = NULL;
  8569. const zend_function *func = NULL;
  8570. uint32_t i;
  8571. zend_jit_addr res_addr;
  8572. uint32_t call_num_args = 0;
  8573. bool unknown_num_args = 0;
  8574. const void *exit_addr = NULL;
  8575. const zend_op *prev_opline;
  8576. if (RETURN_VALUE_USED(opline)) {
  8577. res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  8578. } else {
  8579. /* CPU stack allocated temporary zval */
  8580. res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RSP, TMP_ZVAL_OFFSET);
  8581. }
  8582. prev_opline = opline - 1;
  8583. while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) {
  8584. prev_opline--;
  8585. }
  8586. if (prev_opline->opcode == ZEND_SEND_UNPACK || prev_opline->opcode == ZEND_SEND_ARRAY ||
  8587. prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
  8588. unknown_num_args = 1;
  8589. }
  8590. if (info) {
  8591. call_info = info->callee_info;
  8592. while (call_info && call_info->caller_call_opline != opline) {
  8593. call_info = call_info->next_callee;
  8594. }
  8595. if (call_info && call_info->callee_func && !call_info->is_prototype) {
  8596. func = call_info->callee_func;
  8597. }
  8598. if ((op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)
  8599. && JIT_G(current_frame)
  8600. && JIT_G(current_frame)->call
  8601. && !JIT_G(current_frame)->call->func) {
  8602. call_info = NULL; func = NULL; /* megamorphic call from trait */
  8603. }
  8604. }
  8605. if (!func) {
  8606. /* resolve function at run time */
  8607. } else if (func->type == ZEND_USER_FUNCTION) {
  8608. ZEND_ASSERT(opline->opcode != ZEND_DO_ICALL);
  8609. call_num_args = call_info->num_args;
  8610. } else if (func->type == ZEND_INTERNAL_FUNCTION) {
  8611. ZEND_ASSERT(opline->opcode != ZEND_DO_UCALL);
  8612. call_num_args = call_info->num_args;
  8613. } else {
  8614. ZEND_UNREACHABLE();
  8615. }
  8616. if (trace && !func) {
  8617. if (trace->op == ZEND_JIT_TRACE_DO_ICALL) {
  8618. ZEND_ASSERT(trace->func->type == ZEND_INTERNAL_FUNCTION);
  8619. #ifndef ZEND_WIN32
  8620. // TODO: ASLR may cause different addresses in different workers ???
  8621. func = trace->func;
  8622. if (JIT_G(current_frame) &&
  8623. JIT_G(current_frame)->call &&
  8624. TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
  8625. call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
  8626. } else {
  8627. unknown_num_args = 1;
  8628. }
  8629. #endif
  8630. } else if (trace->op == ZEND_JIT_TRACE_ENTER) {
  8631. ZEND_ASSERT(trace->func->type == ZEND_USER_FUNCTION);
  8632. if (zend_accel_in_shm(trace->func->op_array.opcodes)) {
  8633. func = trace->func;
  8634. if (JIT_G(current_frame) &&
  8635. JIT_G(current_frame)->call &&
  8636. TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
  8637. call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
  8638. } else {
  8639. unknown_num_args = 1;
  8640. }
  8641. }
  8642. }
  8643. }
  8644. bool may_have_extra_named_params =
  8645. opline->extended_value == ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS &&
  8646. (!func || func->common.fn_flags & ZEND_ACC_VARIADIC);
  8647. if (!reuse_ip) {
  8648. zend_jit_start_reuse_ip();
  8649. | // call = EX(call);
  8650. | ldr RX, EX->call
  8651. }
  8652. zend_jit_stop_reuse_ip();
  8653. | // fbc = call->func;
  8654. | // mov r2, EX:RX->func ???
  8655. | // SAVE_OPLINE();
  8656. | SET_EX_OPLINE opline, REG0
  8657. if (opline->opcode == ZEND_DO_FCALL) {
  8658. if (!func) {
  8659. if (trace) {
  8660. uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  8661. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  8662. if (!exit_addr) {
  8663. return 0;
  8664. }
  8665. | ldr REG0, EX:RX->func
  8666. | ldr TMP1w, [REG0, #offsetof(zend_op_array, fn_flags)]
  8667. | TST_32_WITH_CONST TMP1w, ZEND_ACC_DEPRECATED, TMP2w
  8668. | bne &exit_addr
  8669. }
  8670. }
  8671. }
  8672. if (!delayed_call_chain) {
  8673. if (call_level == 1) {
  8674. | str xzr, EX->call
  8675. } else {
  8676. | //EX(call) = call->prev_execute_data;
  8677. | ldr REG0, EX:RX->prev_execute_data
  8678. | str REG0, EX->call
  8679. }
  8680. }
  8681. delayed_call_chain = 0;
  8682. | //call->prev_execute_data = execute_data;
  8683. | str EX, EX:RX->prev_execute_data
  8684. if (!func) {
  8685. | ldr REG0, EX:RX->func
  8686. }
  8687. if (opline->opcode == ZEND_DO_FCALL) {
  8688. if (!func) {
  8689. if (!trace) {
  8690. | ldr TMP1w, [REG0, #offsetof(zend_op_array, fn_flags)]
  8691. | TST_32_WITH_CONST TMP1w, ZEND_ACC_DEPRECATED, TMP2w
  8692. | bne >1
  8693. |.cold_code
  8694. |1:
  8695. if (!GCC_GLOBAL_REGS) {
  8696. | mov FCARG1x, RX
  8697. }
  8698. | EXT_CALL zend_jit_deprecated_helper, REG0
  8699. | GET_LOW_8BITS RETVALw, RETVALw
  8700. | ldr REG0, EX:RX->func // reload
  8701. | cbnz RETVALw, >1 // Result is 0 on exception
  8702. | b ->exception_handler
  8703. |.code
  8704. |1:
  8705. }
  8706. } else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
  8707. if (!GCC_GLOBAL_REGS) {
  8708. | mov FCARG1x, RX
  8709. }
  8710. | EXT_CALL zend_jit_deprecated_helper, REG0
  8711. | cbz RETVALw, ->exception_handler
  8712. }
  8713. }
  8714. if (!func
  8715. && opline->opcode != ZEND_DO_UCALL
  8716. && opline->opcode != ZEND_DO_ICALL) {
  8717. | ldrb TMP1w, [REG0, #offsetof(zend_function, type)]
  8718. | cmp TMP1w, #ZEND_USER_FUNCTION
  8719. | bne >8
  8720. }
  8721. if ((!func || func->type == ZEND_USER_FUNCTION)
  8722. && opline->opcode != ZEND_DO_ICALL) {
  8723. | // EX(call) = NULL;
  8724. | str xzr, EX:RX->call
  8725. if (RETURN_VALUE_USED(opline)) {
  8726. | // EX(return_value) = EX_VAR(opline->result.var);
  8727. | LOAD_ZVAL_ADDR REG2, res_addr
  8728. | str REG2, EX:RX->return_value
  8729. } else {
  8730. | // EX(return_value) = 0;
  8731. | str xzr, EX:RX->return_value
  8732. }
  8733. //EX_LOAD_RUN_TIME_CACHE(op_array);
  8734. if (!func || func->op_array.cache_size) {
  8735. if (func && op_array == &func->op_array) {
  8736. /* recursive call */
  8737. if (trace || func->op_array.cache_size > sizeof(void*)) {
  8738. | ldr REG2, EX->run_time_cache
  8739. | str REG2, EX:RX->run_time_cache
  8740. }
  8741. } else {
  8742. // Always defined as ZEND_MAP_PTR_KIND_PTR_OR_OFFSET. See Zend/zend_map_ptr.h.
  8743. #if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR
  8744. if (func) {
  8745. | ldr REG0, EX:RX->func
  8746. }
  8747. | ldr REG2, [REG0, #offsetof(zend_op_array, run_time_cache__ptr)]
  8748. | ldr REG2, [REG2]
  8749. #elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET
  8750. if (func && !(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
  8751. if (ZEND_MAP_PTR_IS_OFFSET(func->op_array.run_time_cache)) {
  8752. | MEM_LOAD_64_ZTS ldr, REG2, compiler_globals, map_ptr_base, TMP1
  8753. | ADD_SUB_64_WITH_CONST add, REG2, REG2, (uintptr_t)ZEND_MAP_PTR(func->op_array.run_time_cache), TMP1
  8754. | ldr REG2, [REG2]
  8755. } else if ((func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
  8756. && (!func->op_array.scope || (func->op_array.scope->ce_flags & ZEND_ACC_LINKED))) {
  8757. if (func) {
  8758. | ldr REG0, EX:RX->func
  8759. }
  8760. | ldr REG2, [REG0, #offsetof(zend_op_array, run_time_cache__ptr)]
  8761. | MEM_LOAD_OP_ZTS add, ldr, REG2, compiler_globals, map_ptr_base, REG1, TMP1
  8762. | ldr REG2, [REG2]
  8763. } else {
  8764. /* the called op_array may be not persisted yet */
  8765. if (func) {
  8766. | ldr REG0, EX:RX->func
  8767. }
  8768. | ldr REG2, [REG0, #offsetof(zend_op_array, run_time_cache__ptr)]
  8769. | TST_64_WITH_ONE REG2
  8770. | beq >1
  8771. | MEM_LOAD_OP_ZTS add, ldr, REG2, compiler_globals, map_ptr_base, REG1, TMP1
  8772. |1:
  8773. | ldr REG2, [REG2]
  8774. }
  8775. } else {
  8776. if (func) {
  8777. | ldr REG0, EX:RX->func
  8778. }
  8779. | ldr REG2, [REG0, #offsetof(zend_op_array, run_time_cache__ptr)]
  8780. | TST_64_WITH_ONE REG2
  8781. | beq >1
  8782. | MEM_LOAD_OP_ZTS add, ldr, REG2, compiler_globals, map_ptr_base, REG1, TMP1
  8783. |1:
  8784. | ldr REG2, [REG2]
  8785. }
  8786. #else
  8787. # error "Unknown ZEND_MAP_PTR_KIND"
  8788. #endif
  8789. | str REG2, EX:RX->run_time_cache
  8790. }
  8791. }
  8792. | // EG(current_execute_data) = execute_data;
  8793. | MEM_STORE_64_ZTS str, RX, executor_globals, current_execute_data, REG1
  8794. | mov FP, RX
  8795. | // opline = op_array->opcodes;
  8796. if (func && !unknown_num_args) {
  8797. | ADD_SUB_64_WITH_CONST_32 add, TMP1, RX, (EX_NUM_TO_VAR(call_num_args) + offsetof(zval, u1.type_info)), TMP1 // induction variable
  8798. for (i = call_num_args; i < func->op_array.last_var; i++) {
  8799. | // ZVAL_UNDEF(EX_VAR(n))
  8800. | str wzr, [TMP1], #16
  8801. }
  8802. if (call_num_args <= func->op_array.num_args) {
  8803. if (!trace || (trace->op == ZEND_JIT_TRACE_END
  8804. && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
  8805. uint32_t num_args;
  8806. if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
  8807. if (trace) {
  8808. num_args = 0;
  8809. } else if (call_info) {
  8810. num_args = skip_valid_arguments(op_array, ssa, call_info);
  8811. } else {
  8812. num_args = call_num_args;
  8813. }
  8814. } else {
  8815. num_args = call_num_args;
  8816. }
  8817. if (zend_accel_in_shm(func->op_array.opcodes)) {
  8818. | LOAD_IP_ADDR (func->op_array.opcodes + num_args)
  8819. } else {
  8820. | ldr REG0, EX->func
  8821. || ZEND_ASSERT(arm64_may_encode_imm12((int64_t)(num_args * sizeof(zend_op))));
  8822. if (GCC_GLOBAL_REGS) {
  8823. | ldr IP, [REG0, #offsetof(zend_op_array, opcodes)]
  8824. if (num_args) {
  8825. | add IP, IP, #(num_args * sizeof(zend_op))
  8826. }
  8827. } else {
  8828. | ldr FCARG1x, [REG0, #offsetof(zend_op_array, opcodes)]
  8829. if (num_args) {
  8830. | add FCARG1x, FCARG1x, #(num_args * sizeof(zend_op))
  8831. }
  8832. | str FCARG1x, EX->opline
  8833. }
  8834. }
  8835. if (GCC_GLOBAL_REGS && !trace && op_array == &func->op_array
  8836. && num_args >= op_array->required_num_args) {
  8837. /* recursive call */
  8838. if (ZEND_OBSERVER_ENABLED) {
  8839. | SAVE_IP
  8840. | mov FCARG1x, FP
  8841. | EXT_CALL zend_observer_fcall_begin, REG0
  8842. }
  8843. #ifdef CONTEXT_THREADED_JIT
  8844. | NIY // TODO
  8845. #else
  8846. | b =>num_args
  8847. #endif
  8848. return 1;
  8849. }
  8850. }
  8851. } else {
  8852. if (!trace || (trace->op == ZEND_JIT_TRACE_END
  8853. && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
  8854. if (func && zend_accel_in_shm(func->op_array.opcodes)) {
  8855. | LOAD_IP_ADDR (func->op_array.opcodes)
  8856. } else if (GCC_GLOBAL_REGS) {
  8857. | ldr IP, [REG0, #offsetof(zend_op_array, opcodes)]
  8858. } else {
  8859. | ldr FCARG1x, [REG0, #offsetof(zend_op_array, opcodes)]
  8860. | str FCARG1x, EX->opline
  8861. }
  8862. }
  8863. if (!GCC_GLOBAL_REGS) {
  8864. | mov FCARG1x, FP
  8865. }
  8866. | EXT_CALL zend_jit_copy_extra_args_helper, REG0
  8867. }
  8868. } else {
  8869. | // opline = op_array->opcodes
  8870. if (func && zend_accel_in_shm(func->op_array.opcodes)) {
  8871. | LOAD_IP_ADDR (func->op_array.opcodes)
  8872. } else if (GCC_GLOBAL_REGS) {
  8873. | ldr IP, [REG0, #offsetof(zend_op_array, opcodes)]
  8874. } else {
  8875. | ldr FCARG1x, [REG0, #offsetof(zend_op_array, opcodes)]
  8876. | str FCARG1x, EX->opline
  8877. }
  8878. if (func) {
  8879. | // num_args = EX_NUM_ARGS();
  8880. | ldr REG1w, [FP, #offsetof(zend_execute_data, This.u2.num_args)]
  8881. | // if (UNEXPECTED(num_args > first_extra_arg))
  8882. | CMP_32_WITH_CONST REG1w, (func->op_array.num_args), TMP1w
  8883. } else {
  8884. | // first_extra_arg = op_array->num_args;
  8885. | ldr REG2w, [REG0, #offsetof(zend_op_array, num_args)]
  8886. | // num_args = EX_NUM_ARGS();
  8887. | ldr REG1w, [FP, #offsetof(zend_execute_data, This.u2.num_args)]
  8888. | // if (UNEXPECTED(num_args > first_extra_arg))
  8889. | cmp REG1w, REG2w
  8890. }
  8891. | bgt >1
  8892. |.cold_code
  8893. |1:
  8894. if (!GCC_GLOBAL_REGS) {
  8895. | mov FCARG1x, FP
  8896. }
  8897. | EXT_CALL zend_jit_copy_extra_args_helper, REG0
  8898. if (!func) {
  8899. | ldr REG0, EX->func // reload
  8900. }
  8901. | ldr REG1w, [FP, #offsetof(zend_execute_data, This.u2.num_args)] // reload
  8902. | b >1
  8903. |.code
  8904. if (!func || (func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0) {
  8905. if (!func) {
  8906. | // if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0))
  8907. | ldr TMP1w, [REG0, #offsetof(zend_op_array, fn_flags)]
  8908. | TST_32_WITH_CONST TMP1w, ZEND_ACC_HAS_TYPE_HINTS, TMP2w
  8909. | bne >1
  8910. }
  8911. | // opline += num_args;
  8912. || ZEND_ASSERT(sizeof(zend_op) == 32);
  8913. | mov REG2w, REG1w
  8914. | ADD_IP_SHIFT REG2, lsl #5, TMP1
  8915. }
  8916. |1:
  8917. | // if (EXPECTED((int)num_args < op_array->last_var)) {
  8918. if (func) {
  8919. | LOAD_32BIT_VAL REG2w, func->op_array.last_var
  8920. } else {
  8921. | ldr REG2w, [REG0, #offsetof(zend_op_array, last_var)]
  8922. }
  8923. | subs REG2w, REG2w, REG1w
  8924. | ble >3
  8925. | // zval *var = EX_VAR_NUM(num_args);
  8926. | add REG1, FP, REG1, lsl #4
  8927. || ZEND_ASSERT(arm64_may_encode_imm12((int64_t)(ZEND_CALL_FRAME_SLOT * sizeof(zval))));
  8928. | add REG1, REG1, #(ZEND_CALL_FRAME_SLOT * sizeof(zval))
  8929. |2:
  8930. | SET_Z_TYPE_INFO REG1, IS_UNDEF, TMP1w
  8931. | add REG1, REG1, #16
  8932. | subs REG2w, REG2w, #1
  8933. | bne <2
  8934. |3:
  8935. }
  8936. if (ZEND_OBSERVER_ENABLED) {
  8937. | SAVE_IP
  8938. | mov FCARG1x, FP
  8939. | EXT_CALL zend_observer_fcall_begin, REG0
  8940. }
  8941. if (trace) {
  8942. if (!func && (opline->opcode != ZEND_DO_UCALL)) {
  8943. | b >9
  8944. }
  8945. } else {
  8946. #ifdef CONTEXT_THREADED_JIT
  8947. | NIY // TODO: CONTEXT_THREADED_JIT is always undefined.
  8948. #else
  8949. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  8950. | ADD_HYBRID_SPAD
  8951. | JMP_IP TMP1
  8952. } else if (GCC_GLOBAL_REGS) {
  8953. | ldp x29, x30, [sp], # SPAD // stack alignment
  8954. | JMP_IP TMP1
  8955. } else {
  8956. | ldp FP, RX, T2 // retore FP and IP
  8957. | ldp x29, x30, [sp], # NR_SPAD // stack alignment
  8958. | mov RETVALx, #1 // ZEND_VM_ENTER
  8959. | ret
  8960. }
  8961. }
  8962. #endif
  8963. }
  8964. if ((!func || func->type == ZEND_INTERNAL_FUNCTION)
  8965. && (opline->opcode != ZEND_DO_UCALL)) {
  8966. if (!func && (opline->opcode != ZEND_DO_ICALL)) {
  8967. |8:
  8968. }
  8969. if (opline->opcode == ZEND_DO_FCALL_BY_NAME) {
  8970. if (!func) {
  8971. if (trace) {
  8972. uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  8973. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  8974. if (!exit_addr) {
  8975. return 0;
  8976. }
  8977. | ldr TMP1w, [REG0, #offsetof(zend_op_array, fn_flags)]
  8978. | TST_32_WITH_CONST TMP1w, ZEND_ACC_DEPRECATED, TMP2w
  8979. | bne &exit_addr
  8980. } else {
  8981. | ldr TMP1w, [REG0, #offsetof(zend_op_array, fn_flags)]
  8982. | TST_32_WITH_CONST TMP1w, ZEND_ACC_DEPRECATED, TMP2w
  8983. | bne >1
  8984. |.cold_code
  8985. |1:
  8986. if (!GCC_GLOBAL_REGS) {
  8987. | mov FCARG1x, RX
  8988. }
  8989. | EXT_CALL zend_jit_deprecated_helper, REG0
  8990. | GET_LOW_8BITS RETVALw, RETVALw
  8991. | ldr REG0, EX:RX->func // reload
  8992. | cbnz RETVALw, >1 // Result is 0 on exception
  8993. | b ->exception_handler
  8994. |.code
  8995. |1:
  8996. }
  8997. } else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
  8998. if (!GCC_GLOBAL_REGS) {
  8999. | mov FCARG1x, RX
  9000. }
  9001. | EXT_CALL zend_jit_deprecated_helper, REG0
  9002. | cbz RETVALw, ->exception_handler
  9003. | ldr REG0, EX:RX->func // reload
  9004. }
  9005. }
  9006. | // ZVAL_NULL(EX_VAR(opline->result.var));
  9007. | LOAD_ZVAL_ADDR FCARG2x, res_addr
  9008. | SET_Z_TYPE_INFO FCARG2x, IS_NULL, TMP1w
  9009. | // EG(current_execute_data) = execute_data;
  9010. | MEM_STORE_64_ZTS str, RX, executor_globals, current_execute_data, REG1
  9011. zend_jit_reset_last_valid_opline();
  9012. | // fbc->internal_function.handler(call, ret);
  9013. | mov FCARG1x, RX
  9014. if (func) {
  9015. | EXT_CALL func->internal_function.handler, REG0
  9016. } else {
  9017. | ldr TMP1, [REG0, #offsetof(zend_internal_function, handler)]
  9018. | blr TMP1
  9019. }
  9020. | // EG(current_execute_data) = execute_data;
  9021. | MEM_STORE_64_ZTS str, FP, executor_globals, current_execute_data, REG0
  9022. | // zend_vm_stack_free_args(call);
  9023. if (func && !unknown_num_args) {
  9024. for (i = 0; i < call_num_args; i++ ) {
  9025. if (zend_jit_needs_arg_dtor(func, i, call_info)) {
  9026. uint32_t offset = EX_NUM_TO_VAR(i);
  9027. zend_jit_addr arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset);
  9028. | ZVAL_PTR_DTOR arg_addr, (MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN), 0, 1, opline, ZREG_TMP1, ZREG_TMP2
  9029. }
  9030. }
  9031. } else {
  9032. | mov FCARG1x, RX
  9033. | EXT_CALL zend_jit_vm_stack_free_args_helper, REG0
  9034. }
  9035. if (may_have_extra_named_params) {
  9036. | ldrb TMP1w, [RX, #(offsetof(zend_execute_data, This.u1.type_info) + 3)]
  9037. | TST_32_WITH_CONST TMP1w, (ZEND_CALL_HAS_EXTRA_NAMED_PARAMS >> 24), TMP2w
  9038. | bne >1
  9039. |.cold_code
  9040. |1:
  9041. | ldr FCARG1x, [RX, #offsetof(zend_execute_data, extra_named_params)]
  9042. | EXT_CALL zend_free_extra_named_params, REG0
  9043. | b >2
  9044. |.code
  9045. |2:
  9046. }
  9047. |8:
  9048. if (opline->opcode == ZEND_DO_FCALL) {
  9049. // TODO: optimize ???
  9050. | // if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS))
  9051. | ldrb TMP1w, [RX, #(offsetof(zend_execute_data, This.u1.type_info) + 2)]
  9052. | TST_32_WITH_CONST TMP1w, (ZEND_CALL_RELEASE_THIS >> 16), TMP2w
  9053. | bne >1
  9054. |.cold_code
  9055. |1:
  9056. | add TMP1, RX, #offsetof(zend_execute_data, This)
  9057. | GET_Z_PTR FCARG1x, TMP1
  9058. | // OBJ_RELEASE(object);
  9059. | OBJ_RELEASE ZREG_FCARG1, >2, ZREG_TMP1, ZREG_TMP2
  9060. | b >2
  9061. |.code
  9062. |2:
  9063. }
  9064. if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
  9065. !JIT_G(current_frame) ||
  9066. !JIT_G(current_frame)->call ||
  9067. !TRACE_FRAME_IS_NESTED(JIT_G(current_frame)->call) ||
  9068. prev_opline->opcode == ZEND_SEND_UNPACK ||
  9069. prev_opline->opcode == ZEND_SEND_ARRAY ||
  9070. prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
  9071. | // zend_vm_stack_free_call_frame(call);
  9072. | ldrb TMP1w, [RX, #(offsetof(zend_execute_data, This.u1.type_info) + 2)]
  9073. | TST_32_WITH_CONST TMP1w, ((ZEND_CALL_ALLOCATED >> 16) & 0xff), TMP2w
  9074. | bne >1
  9075. |.cold_code
  9076. |1:
  9077. | mov FCARG1x, RX
  9078. | EXT_CALL zend_jit_free_call_frame, REG0
  9079. | b >1
  9080. |.code
  9081. }
  9082. | MEM_STORE_64_ZTS str, RX, executor_globals, vm_stack_top, REG0
  9083. |1:
  9084. if (!RETURN_VALUE_USED(opline)) {
  9085. zend_class_entry *ce;
  9086. bool ce_is_instanceof;
  9087. uint32_t func_info = call_info ?
  9088. zend_get_func_info(call_info, ssa, &ce, &ce_is_instanceof) :
  9089. (MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN);
  9090. /* If an exception is thrown, the return_value may stay at the
  9091. * original value of null. */
  9092. func_info |= MAY_BE_NULL;
  9093. if (func_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
  9094. | ZVAL_PTR_DTOR res_addr, func_info, 1, 1, opline, ZREG_TMP1, ZREG_TMP2
  9095. }
  9096. }
  9097. | // if (UNEXPECTED(EG(exception) != NULL)) {
  9098. | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1
  9099. | cbnz REG0, ->icall_throw_handler
  9100. // TODO: Can we avoid checking for interrupts after each call ???
  9101. if (trace && last_valid_opline != opline) {
  9102. int32_t exit_point = zend_jit_trace_get_exit_point(opline + 1, ZEND_JIT_EXIT_TO_VM);
  9103. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  9104. if (!exit_addr) {
  9105. return 0;
  9106. }
  9107. } else {
  9108. exit_addr = NULL;
  9109. }
  9110. if (!zend_jit_check_timeout(Dst, opline + 1, exit_addr)) {
  9111. return 0;
  9112. }
  9113. if ((!trace || !func) && opline->opcode != ZEND_DO_ICALL) {
  9114. | LOAD_IP_ADDR (opline + 1)
  9115. } else if (trace
  9116. && trace->op == ZEND_JIT_TRACE_END
  9117. && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
  9118. | LOAD_IP_ADDR (opline + 1)
  9119. }
  9120. }
  9121. if (!func) {
  9122. |9:
  9123. }
  9124. return 1;
  9125. }
  9126. static int zend_jit_send_val(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
  9127. {
  9128. uint32_t arg_num = opline->op2.num;
  9129. zend_jit_addr arg_addr;
  9130. ZEND_ASSERT(opline->opcode == ZEND_SEND_VAL || arg_num <= MAX_ARG_FLAG_NUM);
  9131. if (!zend_jit_reuse_ip(Dst)) {
  9132. return 0;
  9133. }
  9134. if (opline->opcode == ZEND_SEND_VAL_EX) {
  9135. uint32_t mask = ZEND_SEND_BY_REF << ((arg_num + 3) * 2);
  9136. ZEND_ASSERT(arg_num <= MAX_ARG_FLAG_NUM);
  9137. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
  9138. && JIT_G(current_frame)
  9139. && JIT_G(current_frame)->call
  9140. && JIT_G(current_frame)->call->func) {
  9141. if (ARG_MUST_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
  9142. /* Don't generate code that always throws exception */
  9143. return 0;
  9144. }
  9145. } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  9146. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  9147. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  9148. if (!exit_addr) {
  9149. return 0;
  9150. }
  9151. | ldr REG0, EX:RX->func
  9152. | ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)]
  9153. | TST_32_WITH_CONST TMP1w, mask, TMP2w
  9154. | bne &exit_addr
  9155. } else {
  9156. | ldr REG0, EX:RX->func
  9157. | ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)]
  9158. | TST_32_WITH_CONST TMP1w, mask, TMP2w
  9159. | bne >1
  9160. |.cold_code
  9161. |1:
  9162. if (Z_MODE(op1_addr) == IS_REG) {
  9163. /* set type to avoid zval_ptr_dtor() on uninitialized value */
  9164. zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
  9165. | SET_ZVAL_TYPE_INFO addr, IS_UNDEF, TMP1w, TMP2
  9166. }
  9167. | SET_EX_OPLINE opline, REG0
  9168. | b ->throw_cannot_pass_by_ref
  9169. |.code
  9170. }
  9171. }
  9172. arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
  9173. if (opline->op1_type == IS_CONST) {
  9174. zval *zv = RT_CONSTANT(opline, opline->op1);
  9175. | ZVAL_COPY_CONST arg_addr, MAY_BE_ANY, MAY_BE_ANY, zv, ZREG_REG0, ZREG_TMP1, ZREG_FPR0
  9176. if (Z_REFCOUNTED_P(zv)) {
  9177. | ADDREF_CONST zv, REG0, TMP1
  9178. }
  9179. } else {
  9180. | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  9181. }
  9182. return 1;
  9183. }
  9184. static int zend_jit_check_undef_args(dasm_State **Dst, const zend_op *opline)
  9185. {
  9186. | ldr FCARG1x, EX->call
  9187. | ldrb TMP1w, [FCARG1x, #(offsetof(zend_execute_data, This.u1.type_info) + 3)]
  9188. | TST_32_WITH_CONST TMP1w, (ZEND_CALL_MAY_HAVE_UNDEF >> 24), TMP2w
  9189. | bne >1
  9190. |.cold_code
  9191. |1:
  9192. | SET_EX_OPLINE opline, REG0
  9193. | EXT_CALL zend_handle_undef_args, REG0
  9194. | cbz RETVALw, >2
  9195. | b ->exception_handler
  9196. |.code
  9197. |2:
  9198. return 1;
  9199. }
  9200. static int zend_jit_send_ref(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, int cold)
  9201. {
  9202. zend_jit_addr op1_addr, arg_addr, ref_addr;
  9203. op1_addr = OP1_ADDR();
  9204. arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
  9205. if (!zend_jit_reuse_ip(Dst)) {
  9206. return 0;
  9207. }
  9208. if (opline->op1_type == IS_VAR) {
  9209. if (op1_info & MAY_BE_INDIRECT) {
  9210. | LOAD_ZVAL_ADDR REG0, op1_addr
  9211. | // if (EXPECTED(Z_TYPE_P(ret) == IS_INDIRECT)) {
  9212. | IF_NOT_Z_TYPE REG0, IS_INDIRECT, >1, TMP1w
  9213. | // ret = Z_INDIRECT_P(ret);
  9214. | GET_Z_PTR REG0, REG0
  9215. |1:
  9216. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  9217. }
  9218. } else if (opline->op1_type == IS_CV) {
  9219. if (op1_info & MAY_BE_UNDEF) {
  9220. if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
  9221. | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1
  9222. | SET_ZVAL_TYPE_INFO op1_addr, IS_NULL, TMP1w, TMP2
  9223. | b >2
  9224. |1:
  9225. }
  9226. op1_info &= ~MAY_BE_UNDEF;
  9227. op1_info |= MAY_BE_NULL;
  9228. }
  9229. } else {
  9230. ZEND_UNREACHABLE();
  9231. }
  9232. if (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) {
  9233. if (op1_info & MAY_BE_REF) {
  9234. | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >2, ZREG_TMP1
  9235. | GET_ZVAL_PTR REG1, op1_addr, TMP1
  9236. | GC_ADDREF REG1, TMP1w
  9237. | SET_ZVAL_PTR arg_addr, REG1, TMP1
  9238. | SET_ZVAL_TYPE_INFO arg_addr, IS_REFERENCE_EX, TMP1w, TMP2
  9239. | b >6
  9240. }
  9241. |2:
  9242. | // ZVAL_NEW_REF(arg, varptr);
  9243. if (opline->op1_type == IS_VAR) {
  9244. if (Z_REG(op1_addr) != ZREG_REG0 || Z_OFFSET(op1_addr) != 0) {
  9245. | LOAD_ZVAL_ADDR REG0, op1_addr
  9246. }
  9247. | str REG0, T1 // save
  9248. }
  9249. | EMALLOC sizeof(zend_reference), op_array, opline // Allocate space in REG0
  9250. | mov TMP1w, #2
  9251. | str TMP1w, [REG0]
  9252. || ZEND_ASSERT(GC_REFERENCE <= MOVZ_IMM);
  9253. | movz TMP1w, #GC_REFERENCE
  9254. | str TMP1w, [REG0, #offsetof(zend_reference, gc.u.type_info)]
  9255. | str xzr, [REG0, #offsetof(zend_reference, sources.ptr)]
  9256. ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, offsetof(zend_reference, val));
  9257. if (opline->op1_type == IS_VAR) {
  9258. zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG1, 0);
  9259. | ldr REG1, T1 // restore
  9260. | ZVAL_COPY_VALUE ref_addr, MAY_BE_ANY, val_addr, op1_info, ZREG_REG2, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  9261. | SET_ZVAL_PTR val_addr, REG0, TMP1
  9262. | SET_ZVAL_TYPE_INFO val_addr, IS_REFERENCE_EX, TMP1w, TMP2
  9263. } else {
  9264. | ZVAL_COPY_VALUE ref_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  9265. | SET_ZVAL_PTR op1_addr, REG0, TMP1
  9266. | SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX, TMP1w, TMP2
  9267. }
  9268. | SET_ZVAL_PTR arg_addr, REG0, TMP1
  9269. | SET_ZVAL_TYPE_INFO arg_addr, IS_REFERENCE_EX, TMP1w, TMP2
  9270. }
  9271. |6:
  9272. | FREE_OP opline->op1_type, opline->op1, op1_info, !cold, opline, ZREG_TMP1, ZREG_TMP2
  9273. |7:
  9274. return 1;
  9275. }
  9276. static int zend_jit_send_var(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr)
  9277. {
  9278. uint32_t arg_num = opline->op2.num;
  9279. zend_jit_addr arg_addr;
  9280. ZEND_ASSERT((opline->opcode != ZEND_SEND_VAR_EX &&
  9281. opline->opcode != ZEND_SEND_VAR_NO_REF_EX) ||
  9282. arg_num <= MAX_ARG_FLAG_NUM);
  9283. arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
  9284. if (!zend_jit_reuse_ip(Dst)) {
  9285. return 0;
  9286. }
  9287. if (opline->opcode == ZEND_SEND_VAR_EX) {
  9288. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
  9289. && JIT_G(current_frame)
  9290. && JIT_G(current_frame)->call
  9291. && JIT_G(current_frame)->call->func) {
  9292. if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
  9293. if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 0)) {
  9294. return 0;
  9295. }
  9296. return 1;
  9297. }
  9298. } else {
  9299. uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
  9300. | ldr REG0, EX:RX->func
  9301. | ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)]
  9302. | TST_32_WITH_CONST TMP1w, mask, TMP2w
  9303. | bne >1
  9304. |.cold_code
  9305. |1:
  9306. if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 1)) {
  9307. return 0;
  9308. }
  9309. | b >7
  9310. |.code
  9311. }
  9312. } else if (opline->opcode == ZEND_SEND_VAR_NO_REF_EX) {
  9313. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
  9314. && JIT_G(current_frame)
  9315. && JIT_G(current_frame)->call
  9316. && JIT_G(current_frame)->call->func) {
  9317. if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
  9318. | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  9319. if (!ARG_MAY_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
  9320. if (!(op1_info & MAY_BE_REF)) {
  9321. /* Don't generate code that always throws exception */
  9322. return 0;
  9323. } else {
  9324. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  9325. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  9326. if (!exit_addr) {
  9327. return 0;
  9328. }
  9329. | GET_LOW_8BITS TMP1w, REG1w
  9330. | cmp TMP1w, #IS_REFERENCE
  9331. | bne &exit_addr
  9332. }
  9333. }
  9334. return 1;
  9335. }
  9336. } else {
  9337. uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
  9338. | ldr REG0, EX:RX->func
  9339. | ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)]
  9340. | TST_32_WITH_CONST TMP1w, mask, TMP2w
  9341. | bne >1
  9342. |.cold_code
  9343. |1:
  9344. mask = ZEND_SEND_PREFER_REF << ((arg_num + 3) * 2);
  9345. | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  9346. if (op1_info & MAY_BE_REF) {
  9347. | GET_LOW_8BITS TMP1w, REG1w
  9348. | cmp TMP1w, #IS_REFERENCE
  9349. | beq >7
  9350. }
  9351. | ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)]
  9352. | TST_32_WITH_CONST TMP1w, mask, TMP2w
  9353. | bne >7
  9354. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  9355. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  9356. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  9357. if (!exit_addr) {
  9358. return 0;
  9359. }
  9360. | b &exit_addr
  9361. } else {
  9362. | SET_EX_OPLINE opline, REG0
  9363. | LOAD_ZVAL_ADDR FCARG1x, arg_addr
  9364. | EXT_CALL zend_jit_only_vars_by_reference, REG0
  9365. if (!zend_jit_check_exception(Dst)) {
  9366. return 0;
  9367. }
  9368. | b >7
  9369. }
  9370. |.code
  9371. }
  9372. } else if (opline->opcode == ZEND_SEND_FUNC_ARG) {
  9373. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
  9374. && JIT_G(current_frame)
  9375. && JIT_G(current_frame)->call
  9376. && JIT_G(current_frame)->call->func) {
  9377. if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
  9378. if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 0)) {
  9379. return 0;
  9380. }
  9381. return 1;
  9382. }
  9383. } else {
  9384. | ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
  9385. | TST_32_WITH_CONST TMP1w, ZEND_CALL_SEND_ARG_BY_REF, TMP2w
  9386. | bne >1
  9387. |.cold_code
  9388. |1:
  9389. if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 1)) {
  9390. return 0;
  9391. }
  9392. | b >7
  9393. |.code
  9394. }
  9395. }
  9396. if (op1_info & MAY_BE_UNDEF) {
  9397. if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
  9398. | IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1
  9399. |.cold_code
  9400. |1:
  9401. }
  9402. | SET_EX_OPLINE opline, REG0
  9403. | LOAD_32BIT_VAL FCARG1w, opline->op1.var
  9404. | EXT_CALL zend_jit_undefined_op_helper, REG0
  9405. | SET_ZVAL_TYPE_INFO arg_addr, IS_NULL, TMP1w, TMP2
  9406. | cbz RETVALx, ->exception_handler
  9407. if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
  9408. | b >7
  9409. |.code
  9410. } else {
  9411. |7:
  9412. return 1;
  9413. }
  9414. }
  9415. if (opline->opcode == ZEND_SEND_VAR_NO_REF) {
  9416. | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  9417. if (op1_info & MAY_BE_REF) {
  9418. | GET_LOW_8BITS TMP1w, REG1w
  9419. | cmp TMP1w, #IS_REFERENCE
  9420. | beq >7
  9421. }
  9422. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  9423. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  9424. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  9425. if (!exit_addr) {
  9426. return 0;
  9427. }
  9428. | b &exit_addr
  9429. } else {
  9430. | SET_EX_OPLINE opline, REG0
  9431. | LOAD_ZVAL_ADDR FCARG1x, arg_addr
  9432. | EXT_CALL zend_jit_only_vars_by_reference, REG0
  9433. if (!zend_jit_check_exception(Dst)) {
  9434. return 0;
  9435. }
  9436. }
  9437. } else {
  9438. if (op1_info & MAY_BE_REF) {
  9439. if (opline->op1_type == IS_CV) {
  9440. zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  9441. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  9442. | ZVAL_DEREF FCARG1x, op1_info, TMP1w
  9443. | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, val_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  9444. | TRY_ADDREF op1_info, REG0w, REG2, TMP1w
  9445. } else {
  9446. zend_jit_addr ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 8);
  9447. | IF_ZVAL_TYPE op1_addr, IS_REFERENCE, >1, ZREG_TMP1
  9448. |.cold_code
  9449. |1:
  9450. | // zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
  9451. | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
  9452. | // ZVAL_COPY_VALUE(return_value, &ref->value);
  9453. | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, ref_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  9454. | GC_DELREF FCARG1x, TMP1w
  9455. | beq >1
  9456. | IF_NOT_REFCOUNTED REG0w, >2, TMP1w
  9457. | GC_ADDREF REG2, TMP1w
  9458. | b >2
  9459. |1:
  9460. | EFREE_REFERENCE
  9461. | b >2
  9462. |.code
  9463. | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  9464. |2:
  9465. }
  9466. } else {
  9467. if (op1_addr != op1_def_addr) {
  9468. if (!zend_jit_update_regs(Dst, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
  9469. return 0;
  9470. }
  9471. if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
  9472. op1_addr= op1_def_addr;
  9473. }
  9474. }
  9475. | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  9476. if (opline->op1_type == IS_CV) {
  9477. | TRY_ADDREF op1_info, REG0w, REG2, TMP1w
  9478. }
  9479. }
  9480. }
  9481. |7:
  9482. return 1;
  9483. }
  9484. static int zend_jit_check_func_arg(dasm_State **Dst, const zend_op *opline)
  9485. {
  9486. uint32_t arg_num = opline->op2.num;
  9487. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
  9488. && JIT_G(current_frame)
  9489. && JIT_G(current_frame)->call
  9490. && JIT_G(current_frame)->call->func) {
  9491. if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
  9492. if (!TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) {
  9493. TRACE_FRAME_SET_LAST_SEND_BY_REF(JIT_G(current_frame)->call);
  9494. | // ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
  9495. || if (reuse_ip) {
  9496. | ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
  9497. | BW_OP_32_WITH_CONST orr, TMP1w, TMP1w, ZEND_CALL_SEND_ARG_BY_REF, TMP2w
  9498. | str TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
  9499. || } else {
  9500. | ldr REG0, EX->call
  9501. | ldr TMP1w, [REG0, #offsetof(zend_execute_data, This.u1.type_info)]
  9502. | BW_OP_32_WITH_CONST orr, TMP1w, TMP1w, ZEND_CALL_SEND_ARG_BY_REF, TMP2w
  9503. | str TMP1w, [REG0, #offsetof(zend_execute_data, This.u1.type_info)]
  9504. || }
  9505. }
  9506. } else {
  9507. if (!TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
  9508. TRACE_FRAME_SET_LAST_SEND_BY_VAL(JIT_G(current_frame)->call);
  9509. | // ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
  9510. || if (reuse_ip) {
  9511. | ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
  9512. | BW_OP_32_WITH_CONST and, TMP1w, TMP1w, (~ZEND_CALL_SEND_ARG_BY_REF), TMP2w
  9513. | str TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
  9514. || } else {
  9515. | ldr REG0, EX->call
  9516. | ldr TMP1w, [REG0, #offsetof(zend_execute_data, This.u1.type_info)]
  9517. | BW_OP_32_WITH_CONST and, TMP1w, TMP1w, (~ZEND_CALL_SEND_ARG_BY_REF), TMP2w
  9518. | str TMP1w, [REG0, #offsetof(zend_execute_data, This.u1.type_info)]
  9519. || }
  9520. }
  9521. }
  9522. } else {
  9523. // if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
  9524. uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
  9525. if (!zend_jit_reuse_ip(Dst)) {
  9526. return 0;
  9527. }
  9528. | ldr REG0, EX:RX->func
  9529. | ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)]
  9530. | TST_32_WITH_CONST TMP1w, mask, TMP2w
  9531. | bne >1
  9532. |.cold_code
  9533. |1:
  9534. | // ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
  9535. | ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
  9536. | BW_OP_32_WITH_CONST orr, TMP1w, TMP1w, ZEND_CALL_SEND_ARG_BY_REF, TMP2w
  9537. | str TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
  9538. | b >1
  9539. |.code
  9540. | // ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
  9541. | ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
  9542. | BW_OP_32_WITH_CONST and, TMP1w, TMP1w, (~(ZEND_CALL_SEND_ARG_BY_REF)), TMP2w
  9543. | str TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)]
  9544. |1:
  9545. }
  9546. return 1;
  9547. }
  9548. static int zend_jit_smart_true(dasm_State **Dst, const zend_op *opline, int jmp, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
  9549. {
  9550. if (smart_branch_opcode) {
  9551. if (smart_branch_opcode == ZEND_JMPZ) {
  9552. if (jmp) {
  9553. | b >7
  9554. }
  9555. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  9556. | b =>target_label
  9557. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  9558. | b =>target_label2
  9559. } else {
  9560. ZEND_UNREACHABLE();
  9561. }
  9562. } else {
  9563. zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  9564. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  9565. if (jmp) {
  9566. | b >7
  9567. }
  9568. }
  9569. return 1;
  9570. }
  9571. static int zend_jit_smart_false(dasm_State **Dst, const zend_op *opline, int jmp, zend_uchar smart_branch_opcode, uint32_t target_label)
  9572. {
  9573. if (smart_branch_opcode) {
  9574. if (smart_branch_opcode == ZEND_JMPZ) {
  9575. | b =>target_label
  9576. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  9577. if (jmp) {
  9578. | b >7
  9579. }
  9580. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  9581. | b =>target_label
  9582. } else {
  9583. ZEND_UNREACHABLE();
  9584. }
  9585. } else {
  9586. zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  9587. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  9588. if (jmp) {
  9589. | b >7
  9590. }
  9591. }
  9592. return 1;
  9593. }
  9594. static int zend_jit_defined(dasm_State **Dst, const zend_op *opline, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
  9595. {
  9596. uint32_t defined_label = (uint32_t)-1;
  9597. uint32_t undefined_label = (uint32_t)-1;
  9598. zval *zv = RT_CONSTANT(opline, opline->op1);
  9599. zend_jit_addr res_addr = 0;
  9600. if (smart_branch_opcode && !exit_addr) {
  9601. if (smart_branch_opcode == ZEND_JMPZ) {
  9602. undefined_label = target_label;
  9603. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  9604. defined_label = target_label;
  9605. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  9606. undefined_label = target_label;
  9607. defined_label = target_label2;
  9608. } else {
  9609. ZEND_UNREACHABLE();
  9610. }
  9611. }
  9612. | // if (CACHED_PTR(opline->extended_value)) {
  9613. | ldr REG0, EX->run_time_cache
  9614. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, opline->extended_value, TMP1
  9615. | cbz REG0, >1
  9616. | TST_64_WITH_ONE REG0
  9617. | bne >4
  9618. |.cold_code
  9619. |4:
  9620. | MEM_LOAD_64_ZTS ldr, FCARG1x, executor_globals, zend_constants, FCARG1x
  9621. | ldr TMP1w, [FCARG1x, #offsetof(HashTable, nNumOfElements)]
  9622. | cmp TMP1, REG0, lsr #1
  9623. if (smart_branch_opcode) {
  9624. if (exit_addr) {
  9625. if (smart_branch_opcode == ZEND_JMPZ) {
  9626. | beq &exit_addr
  9627. } else {
  9628. | beq >3
  9629. }
  9630. } else if (undefined_label != (uint32_t)-1) {
  9631. | beq =>undefined_label
  9632. } else {
  9633. | beq >3
  9634. }
  9635. } else {
  9636. | beq >2
  9637. }
  9638. |1:
  9639. | SET_EX_OPLINE opline, REG0
  9640. | LOAD_ADDR FCARG1x, zv
  9641. | EXT_CALL zend_jit_check_constant, REG0
  9642. if (exit_addr) {
  9643. if (smart_branch_opcode == ZEND_JMPNZ) {
  9644. | cbz RETVALx, >3
  9645. } else {
  9646. | cbnz RETVALx, >3
  9647. }
  9648. | b &exit_addr
  9649. } else if (smart_branch_opcode) {
  9650. if (undefined_label != (uint32_t)-1) {
  9651. | cbz RETVALx, =>undefined_label
  9652. } else {
  9653. | cbz RETVALx, >3
  9654. }
  9655. if (defined_label != (uint32_t)-1) {
  9656. | b =>defined_label
  9657. } else {
  9658. | b >3
  9659. }
  9660. } else {
  9661. res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  9662. | cbnz RETVALx, >1
  9663. |2:
  9664. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  9665. | b >3
  9666. }
  9667. |.code
  9668. if (smart_branch_opcode) {
  9669. if (exit_addr) {
  9670. if (smart_branch_opcode == ZEND_JMPNZ) {
  9671. | b &exit_addr
  9672. }
  9673. } else if (defined_label != (uint32_t)-1) {
  9674. | b =>defined_label
  9675. }
  9676. } else {
  9677. |1:
  9678. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  9679. }
  9680. |3:
  9681. return 1;
  9682. }
  9683. static int zend_jit_type_check(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
  9684. {
  9685. uint32_t mask;
  9686. zend_jit_addr op1_addr = OP1_ADDR();
  9687. // TODO: support for is_resource() ???
  9688. ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
  9689. if (op1_info & MAY_BE_UNDEF) {
  9690. if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
  9691. | IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1
  9692. |.cold_code
  9693. |1:
  9694. }
  9695. | SET_EX_OPLINE opline, REG0
  9696. | LOAD_32BIT_VAL FCARG1w, opline->op1.var
  9697. | EXT_CALL zend_jit_undefined_op_helper, REG0
  9698. zend_jit_check_exception_undef_result(Dst, opline);
  9699. if (opline->extended_value & MAY_BE_NULL) {
  9700. if (exit_addr) {
  9701. if (smart_branch_opcode == ZEND_JMPNZ) {
  9702. | b &exit_addr
  9703. } else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0) {
  9704. | b >7
  9705. }
  9706. } else if (!zend_jit_smart_true(Dst, opline, (op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0, smart_branch_opcode, target_label, target_label2)) {
  9707. return 0;
  9708. }
  9709. } else {
  9710. if (exit_addr) {
  9711. if (smart_branch_opcode == ZEND_JMPZ) {
  9712. | b &exit_addr
  9713. } else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0) {
  9714. | b >7
  9715. }
  9716. } else if (!zend_jit_smart_false(Dst, opline, (op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0, smart_branch_opcode, target_label)) {
  9717. return 0;
  9718. }
  9719. }
  9720. if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
  9721. |.code
  9722. }
  9723. }
  9724. if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
  9725. mask = opline->extended_value;
  9726. if (!(op1_info & MAY_BE_GUARD) && !(op1_info & (MAY_BE_ANY - mask))) {
  9727. | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  9728. if (exit_addr) {
  9729. if (smart_branch_opcode == ZEND_JMPNZ) {
  9730. | b &exit_addr
  9731. }
  9732. } else if (!zend_jit_smart_true(Dst, opline, 0, smart_branch_opcode, target_label, target_label2)) {
  9733. return 0;
  9734. }
  9735. } else if (!(op1_info & MAY_BE_GUARD) && !(op1_info & mask)) {
  9736. | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  9737. if (exit_addr) {
  9738. if (smart_branch_opcode == ZEND_JMPZ) {
  9739. | b &exit_addr
  9740. }
  9741. } else if (!zend_jit_smart_false(Dst, opline, 0, smart_branch_opcode, target_label)) {
  9742. return 0;
  9743. }
  9744. } else {
  9745. bool invert = 0;
  9746. zend_uchar type;
  9747. switch (mask) {
  9748. case MAY_BE_NULL: type = IS_NULL; break;
  9749. case MAY_BE_FALSE: type = IS_FALSE; break;
  9750. case MAY_BE_TRUE: type = IS_TRUE; break;
  9751. case MAY_BE_LONG: type = IS_LONG; break;
  9752. case MAY_BE_DOUBLE: type = IS_DOUBLE; break;
  9753. case MAY_BE_STRING: type = IS_STRING; break;
  9754. case MAY_BE_ARRAY: type = IS_ARRAY; break;
  9755. case MAY_BE_OBJECT: type = IS_OBJECT; break;
  9756. case MAY_BE_ANY - MAY_BE_NULL: type = IS_NULL; invert = 1; break;
  9757. case MAY_BE_ANY - MAY_BE_FALSE: type = IS_FALSE; invert = 1; break;
  9758. case MAY_BE_ANY - MAY_BE_TRUE: type = IS_TRUE; invert = 1; break;
  9759. case MAY_BE_ANY - MAY_BE_LONG: type = IS_LONG; invert = 1; break;
  9760. case MAY_BE_ANY - MAY_BE_DOUBLE: type = IS_DOUBLE; invert = 1; break;
  9761. case MAY_BE_ANY - MAY_BE_STRING: type = IS_STRING; invert = 1; break;
  9762. case MAY_BE_ANY - MAY_BE_ARRAY: type = IS_ARRAY; invert = 1; break;
  9763. case MAY_BE_ANY - MAY_BE_OBJECT: type = IS_OBJECT; invert = 1; break;
  9764. case MAY_BE_ANY - MAY_BE_RESOURCE: type = IS_OBJECT; invert = 1; break;
  9765. default:
  9766. type = 0;
  9767. }
  9768. if (op1_info & MAY_BE_REF) {
  9769. | LOAD_ZVAL_ADDR REG0, op1_addr
  9770. | ZVAL_DEREF REG0, op1_info, TMP1w
  9771. }
  9772. if (type == 0) {
  9773. if (smart_branch_opcode &&
  9774. (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
  9775. (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  9776. if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  9777. | // if (Z_REFCOUNTED_P(cv)) {
  9778. | IF_ZVAL_REFCOUNTED op1_addr, >1, ZREG_TMP1, ZREG_TMP2
  9779. |.cold_code
  9780. |1:
  9781. }
  9782. | // if (!Z_DELREF_P(cv)) {
  9783. | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
  9784. | GC_DELREF FCARG1x, TMP1w
  9785. if (RC_MAY_BE_1(op1_info)) {
  9786. if (RC_MAY_BE_N(op1_info)) {
  9787. | bne >3
  9788. }
  9789. if (op1_info & MAY_BE_REF) {
  9790. | ldrb REG0w, [REG0, #offsetof(zval,u1.v.type)]
  9791. } else {
  9792. | MEM_ACCESS_8_WITH_UOFFSET ldrb, REG0w, FP, (opline->op1.var + offsetof(zval,u1.v.type)), TMP1
  9793. }
  9794. | str REG0w, T1 // save
  9795. | // zval_dtor_func(r);
  9796. | ZVAL_DTOR_FUNC op1_info, opline, TMP1
  9797. | ldr REG1w, T1 // restore
  9798. | b >2
  9799. }
  9800. if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  9801. if (!RC_MAY_BE_1(op1_info)) {
  9802. | b >3
  9803. }
  9804. |.code
  9805. }
  9806. |3:
  9807. if (op1_info & MAY_BE_REF) {
  9808. | ldrb REG1w, [REG0, #offsetof(zval,u1.v.type)]
  9809. } else {
  9810. | MEM_ACCESS_8_WITH_UOFFSET ldrb, REG1w, FP, (opline->op1.var + offsetof(zval,u1.v.type)), TMP1
  9811. }
  9812. |2:
  9813. } else {
  9814. if (op1_info & MAY_BE_REF) {
  9815. | ldrb REG1w, [REG0, #offsetof(zval,u1.v.type)]
  9816. } else {
  9817. | MEM_ACCESS_8_WITH_UOFFSET ldrb, REG1w, FP, (opline->op1.var + offsetof(zval,u1.v.type)), TMP1
  9818. }
  9819. }
  9820. | mov REG0w, #1
  9821. | lsl REG0w, REG0w, REG1w
  9822. | TST_32_WITH_CONST REG0w, mask, TMP1w
  9823. if (exit_addr) {
  9824. if (smart_branch_opcode == ZEND_JMPNZ) {
  9825. | bne &exit_addr
  9826. } else {
  9827. | beq &exit_addr
  9828. }
  9829. } else if (smart_branch_opcode) {
  9830. if (smart_branch_opcode == ZEND_JMPZ) {
  9831. | beq =>target_label
  9832. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  9833. | bne =>target_label
  9834. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  9835. | beq =>target_label
  9836. | b =>target_label2
  9837. } else {
  9838. ZEND_UNREACHABLE();
  9839. }
  9840. } else {
  9841. zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  9842. | cset REG0w, ne
  9843. | add REG0w, REG0w, #2
  9844. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  9845. | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  9846. }
  9847. } else {
  9848. if (smart_branch_opcode &&
  9849. (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
  9850. (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  9851. if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  9852. | // if (Z_REFCOUNTED_P(cv)) {
  9853. | IF_ZVAL_REFCOUNTED op1_addr, >1, ZREG_TMP1, ZREG_TMP2
  9854. |.cold_code
  9855. |1:
  9856. }
  9857. | // if (!Z_DELREF_P(cv)) {
  9858. | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
  9859. | GC_DELREF FCARG1x, TMP1w
  9860. if (RC_MAY_BE_1(op1_info)) {
  9861. if (RC_MAY_BE_N(op1_info)) {
  9862. | bne >3
  9863. }
  9864. if (op1_info & MAY_BE_REF) {
  9865. | ldrb REG0w, [REG0, #offsetof(zval,u1.v.type)]
  9866. } else {
  9867. | MEM_ACCESS_8_WITH_UOFFSET ldrb, REG0w, FP, (opline->op1.var + offsetof(zval,u1.v.type)), TMP1
  9868. }
  9869. | str REG0w, T1 // save
  9870. | // zval_dtor_func(r);
  9871. | ZVAL_DTOR_FUNC op1_info, opline, TMP1
  9872. | ldr REG1w, T1 // restore
  9873. | b >2
  9874. }
  9875. if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  9876. if (!RC_MAY_BE_1(op1_info)) {
  9877. | b >3
  9878. }
  9879. |.code
  9880. }
  9881. |3:
  9882. if (op1_info & MAY_BE_REF) {
  9883. | ldrb REG1w, [REG0, #offsetof(zval,u1.v.type)]
  9884. } else {
  9885. | MEM_ACCESS_8_WITH_UOFFSET ldrb, REG1w, FP, (opline->op1.var + offsetof(zval,u1.v.type)), TMP1
  9886. }
  9887. |2:
  9888. // Note: 'type' is of uchar type and holds a positive value,
  9889. // hence it's safe to directly encode it as the imm field of 'cmp' instruction.
  9890. | cmp REG1w, #type
  9891. } else {
  9892. if (op1_info & MAY_BE_REF) {
  9893. | ldrb TMP1w, [REG0, #offsetof(zval,u1.v.type)]
  9894. | cmp TMP1w, #type
  9895. } else {
  9896. | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP1w, FP, (opline->op1.var + offsetof(zval,u1.v.type)), TMP1
  9897. | cmp TMP1w, #type
  9898. }
  9899. }
  9900. if (exit_addr) {
  9901. if (invert) {
  9902. if (smart_branch_opcode == ZEND_JMPNZ) {
  9903. | bne &exit_addr
  9904. } else {
  9905. | beq &exit_addr
  9906. }
  9907. } else {
  9908. if (smart_branch_opcode == ZEND_JMPNZ) {
  9909. | beq &exit_addr
  9910. } else {
  9911. | bne &exit_addr
  9912. }
  9913. }
  9914. } else if (smart_branch_opcode) {
  9915. if (invert) {
  9916. if (smart_branch_opcode == ZEND_JMPZ) {
  9917. | beq =>target_label
  9918. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  9919. | bne =>target_label
  9920. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  9921. | beq =>target_label
  9922. | b =>target_label2
  9923. } else {
  9924. ZEND_UNREACHABLE();
  9925. }
  9926. } else {
  9927. if (smart_branch_opcode == ZEND_JMPZ) {
  9928. | bne =>target_label
  9929. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  9930. | beq =>target_label
  9931. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  9932. | bne =>target_label
  9933. | b =>target_label2
  9934. } else {
  9935. ZEND_UNREACHABLE();
  9936. }
  9937. }
  9938. } else {
  9939. zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  9940. if (invert) {
  9941. | cset REG0w, ne
  9942. } else {
  9943. | cset REG0w, eq
  9944. }
  9945. | add REG0w, REG0w, #2
  9946. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  9947. | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  9948. }
  9949. }
  9950. }
  9951. }
  9952. |7:
  9953. return 1;
  9954. }
  9955. static int zend_jit_leave_frame(dasm_State **Dst)
  9956. {
  9957. | // EG(current_execute_data) = EX(prev_execute_data);
  9958. | ldr REG0, EX->prev_execute_data
  9959. | MEM_STORE_64_ZTS str, REG0, executor_globals, current_execute_data, REG2
  9960. return 1;
  9961. }
  9962. static int zend_jit_free_cvs(dasm_State **Dst)
  9963. {
  9964. | // EG(current_execute_data) = EX(prev_execute_data);
  9965. | ldr FCARG1x, EX->prev_execute_data
  9966. | MEM_STORE_64_ZTS str, FCARG1x, executor_globals, current_execute_data, REG0
  9967. | // zend_free_compiled_variables(execute_data);
  9968. | mov FCARG1x, FP
  9969. | EXT_CALL zend_free_compiled_variables, REG0
  9970. return 1;
  9971. }
  9972. static int zend_jit_free_cv(dasm_State **Dst, uint32_t info, uint32_t var)
  9973. {
  9974. if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
  9975. uint32_t offset = EX_NUM_TO_VAR(var);
  9976. zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offset);
  9977. | ZVAL_PTR_DTOR addr, info, 1, 1, NULL, ZREG_TMP1, ZREG_TMP2
  9978. }
  9979. return 1;
  9980. }
  9981. static int zend_jit_free_op(dasm_State **Dst, const zend_op *opline, uint32_t info, uint32_t var_offset)
  9982. {
  9983. if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
  9984. zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var_offset);
  9985. | ZVAL_PTR_DTOR addr, info, 0, 1, opline, ZREG_TMP1, ZREG_TMP2
  9986. }
  9987. return 1;
  9988. }
  9989. static int zend_jit_leave_func(dasm_State **Dst,
  9990. const zend_op_array *op_array,
  9991. const zend_op *opline,
  9992. uint32_t op1_info,
  9993. bool left_frame,
  9994. zend_jit_trace_rec *trace,
  9995. zend_jit_trace_info *trace_info,
  9996. int indirect_var_access,
  9997. int may_throw)
  9998. {
  9999. bool may_be_top_frame =
  10000. JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
  10001. !JIT_G(current_frame) ||
  10002. !TRACE_FRAME_IS_NESTED(JIT_G(current_frame));
  10003. bool may_need_call_helper =
  10004. indirect_var_access || /* may have symbol table */
  10005. !op_array->function_name || /* may have symbol table */
  10006. may_be_top_frame ||
  10007. (op_array->fn_flags & ZEND_ACC_VARIADIC) || /* may have extra named args */
  10008. JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
  10009. !JIT_G(current_frame) ||
  10010. TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) == -1 || /* unknown number of args */
  10011. (uint32_t)TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) > op_array->num_args; /* extra args */
  10012. bool may_need_release_this =
  10013. !(op_array->fn_flags & ZEND_ACC_CLOSURE) &&
  10014. op_array->scope &&
  10015. !(op_array->fn_flags & ZEND_ACC_STATIC) &&
  10016. (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
  10017. !JIT_G(current_frame) ||
  10018. !TRACE_FRAME_NO_NEED_RELEASE_THIS(JIT_G(current_frame)));
  10019. if (may_need_call_helper || may_need_release_this) {
  10020. | ldr FCARG1w, [FP, #offsetof(zend_execute_data, This.u1.type_info)]
  10021. }
  10022. if (may_need_call_helper) {
  10023. if (!left_frame) {
  10024. left_frame = 1;
  10025. if (!zend_jit_leave_frame(Dst)) {
  10026. return 0;
  10027. }
  10028. }
  10029. /* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */
  10030. | TST_32_WITH_CONST FCARG1w, (ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS|ZEND_CALL_FAKE_CLOSURE), TMP1w
  10031. if (trace && trace->op != ZEND_JIT_TRACE_END) {
  10032. | bne >1
  10033. |.cold_code
  10034. |1:
  10035. if (!GCC_GLOBAL_REGS) {
  10036. | mov FCARG1x, FP
  10037. }
  10038. | EXT_CALL zend_jit_leave_func_helper, REG0
  10039. if (may_be_top_frame) {
  10040. // TODO: try to avoid this check ???
  10041. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  10042. #if 0
  10043. /* this check should be handled by the following OPLINE guard */
  10044. | LOAD_ADDR TMP1, zend_jit_halt_op
  10045. | cmp IP, TMP1
  10046. | beq ->trace_halt
  10047. #endif
  10048. } else if (GCC_GLOBAL_REGS) {
  10049. | cbz IP, ->trace_halt
  10050. } else {
  10051. | tst RETVALw, RETVALw
  10052. | blt ->trace_halt
  10053. }
  10054. }
  10055. if (!GCC_GLOBAL_REGS) {
  10056. | // execute_data = EG(current_execute_data)
  10057. | MEM_LOAD_64_ZTS ldr, FP, executor_globals, current_execute_data, TMP1
  10058. }
  10059. | b >8
  10060. |.code
  10061. } else {
  10062. | bne ->leave_function_handler
  10063. }
  10064. }
  10065. if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
  10066. if (!left_frame) {
  10067. left_frame = 1;
  10068. if (!zend_jit_leave_frame(Dst)) {
  10069. return 0;
  10070. }
  10071. }
  10072. | // OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
  10073. | ldr FCARG1x, EX->func
  10074. | sub FCARG1x, FCARG1x, #sizeof(zend_object)
  10075. | OBJ_RELEASE ZREG_FCARG1, >4, ZREG_TMP1, ZREG_TMP2
  10076. |4:
  10077. } else if (may_need_release_this) {
  10078. if (!left_frame) {
  10079. left_frame = 1;
  10080. if (!zend_jit_leave_frame(Dst)) {
  10081. return 0;
  10082. }
  10083. }
  10084. | // if (call_info & ZEND_CALL_RELEASE_THIS)
  10085. | TST_32_WITH_CONST FCARG1w, ZEND_CALL_RELEASE_THIS, TMP1w
  10086. | beq >4
  10087. | // zend_object *object = Z_OBJ(execute_data->This);
  10088. | ldr FCARG1x, EX->This.value.obj
  10089. | // OBJ_RELEASE(object);
  10090. | OBJ_RELEASE ZREG_FCARG1, >4, ZREG_TMP1, ZREG_TMP2
  10091. |4:
  10092. // TODO: avoid EG(excption) check for $this->foo() calls
  10093. may_throw = 1;
  10094. }
  10095. | // EG(vm_stack_top) = (zval*)execute_data;
  10096. | MEM_STORE_64_ZTS str, FP, executor_globals, vm_stack_top, REG0
  10097. | // execute_data = EX(prev_execute_data);
  10098. | ldr FP, EX->prev_execute_data
  10099. if (!left_frame) {
  10100. | // EG(current_execute_data) = execute_data;
  10101. | MEM_STORE_64_ZTS str, FP, executor_globals, current_execute_data, REG0
  10102. }
  10103. |9:
  10104. if (trace) {
  10105. if (trace->op != ZEND_JIT_TRACE_END
  10106. && (JIT_G(current_frame) && !TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
  10107. zend_jit_reset_last_valid_opline();
  10108. } else {
  10109. | LOAD_IP
  10110. | ADD_IP_WITH_CONST sizeof(zend_op), TMP1
  10111. }
  10112. |8:
  10113. if (trace->op == ZEND_JIT_TRACE_BACK
  10114. && (!JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
  10115. const zend_op *next_opline = trace->opline;
  10116. if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
  10117. && (op1_info & MAY_BE_RC1)
  10118. && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
  10119. /* exception might be thrown during destruction of unused return value */
  10120. | // if (EG(exception))
  10121. | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1
  10122. | cbnz REG0, ->leave_throw_handler
  10123. }
  10124. do {
  10125. trace++;
  10126. } while (trace->op == ZEND_JIT_TRACE_INIT_CALL);
  10127. ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
  10128. next_opline = trace->opline;
  10129. ZEND_ASSERT(next_opline != NULL);
  10130. if (trace->op == ZEND_JIT_TRACE_END
  10131. && trace->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
  10132. trace_info->flags |= ZEND_JIT_TRACE_LOOP;
  10133. | CMP_IP next_opline, TMP1, TMP2
  10134. | beq =>0 // LOOP
  10135. #ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
  10136. | JMP_IP TMP1
  10137. #else
  10138. | b ->trace_escape
  10139. #endif
  10140. } else {
  10141. | CMP_IP next_opline, TMP1, TMP2
  10142. | bne ->trace_escape
  10143. }
  10144. zend_jit_set_last_valid_opline(trace->opline);
  10145. return 1;
  10146. } else if (may_throw ||
  10147. (((opline->op1_type & (IS_VAR|IS_TMP_VAR))
  10148. && (op1_info & MAY_BE_RC1)
  10149. && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)))
  10150. && (!JIT_G(current_frame) || TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))))) {
  10151. | // if (EG(exception))
  10152. | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1
  10153. | cbnz REG0, ->leave_throw_handler
  10154. }
  10155. return 1;
  10156. } else {
  10157. | // if (EG(exception))
  10158. | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1
  10159. | LOAD_IP
  10160. | cbnz REG0, ->leave_throw_handler
  10161. | // opline = EX(opline) + 1
  10162. | ADD_IP_WITH_CONST sizeof(zend_op), TMP1
  10163. }
  10164. if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
  10165. | ADD_HYBRID_SPAD
  10166. #ifdef CONTEXT_THREADED_JIT
  10167. | NIY // TODO: CONTEXT_THREADED_JIT is always undefined
  10168. #else
  10169. | JMP_IP TMP1
  10170. #endif
  10171. } else if (GCC_GLOBAL_REGS) {
  10172. | ldp x29, x30, [sp], # SPAD // stack alignment
  10173. #ifdef CONTEXT_THREADED_JIT
  10174. | NIY // TODO
  10175. #else
  10176. | JMP_IP TMP1
  10177. #endif
  10178. } else {
  10179. #ifdef CONTEXT_THREADED_JIT
  10180. ZEND_UNREACHABLE();
  10181. // TODO: context threading can't work without GLOBAL REGS because we have to change
  10182. // the value of execute_data in execute_ex()
  10183. | NIY // TODO
  10184. #else
  10185. | ldp FP, RX, T2 // retore FP and IP
  10186. | ldp x29, x30, [sp], # NR_SPAD // stack alignment
  10187. | mov RETVALx, #2 // ZEND_VM_LEAVE ????
  10188. | ret
  10189. #endif
  10190. }
  10191. return 1;
  10192. }
  10193. static int zend_jit_return(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr)
  10194. {
  10195. zend_jit_addr ret_addr;
  10196. int8_t return_value_used;
  10197. ZEND_ASSERT(op_array->type != ZEND_EVAL_CODE && op_array->function_name);
  10198. ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF));
  10199. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && JIT_G(current_frame)) {
  10200. if (TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
  10201. return_value_used = 1;
  10202. } else if (TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))) {
  10203. return_value_used = 0;
  10204. } else {
  10205. return_value_used = -1;
  10206. }
  10207. } else {
  10208. return_value_used = -1;
  10209. }
  10210. if (ZEND_OBSERVER_ENABLED) {
  10211. if (Z_MODE(op1_addr) == IS_REG) {
  10212. zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
  10213. if (!zend_jit_spill_store(Dst, op1_addr, dst, op1_info, 1)) {
  10214. return 0;
  10215. }
  10216. op1_addr = dst;
  10217. }
  10218. | LOAD_ZVAL_ADDR FCARG2x, op1_addr
  10219. | mov FCARG1x, FP
  10220. | SET_EX_OPLINE opline, REG0
  10221. | EXT_CALL zend_observer_fcall_end, REG0
  10222. }
  10223. // if (!EX(return_value))
  10224. if (Z_MODE(op1_addr) == IS_REG && Z_REG(op1_addr) == ZREG_REG1) {
  10225. if (return_value_used != 0) {
  10226. | ldr REG2, EX->return_value
  10227. }
  10228. ret_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG2, 0);
  10229. } else {
  10230. if (return_value_used != 0) {
  10231. | ldr REG1, EX->return_value
  10232. }
  10233. ret_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG1, 0);
  10234. }
  10235. if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
  10236. (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  10237. if (return_value_used == -1) {
  10238. | cbz Rx(Z_REG(ret_addr)), >1
  10239. |.cold_code
  10240. |1:
  10241. }
  10242. if (return_value_used != 1) {
  10243. if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  10244. if (jit_return_label >= 0) {
  10245. | IF_NOT_ZVAL_REFCOUNTED op1_addr, =>jit_return_label, ZREG_TMP1, ZREG_TMP2
  10246. } else {
  10247. | IF_NOT_ZVAL_REFCOUNTED op1_addr, >9, ZREG_TMP1, ZREG_TMP2
  10248. }
  10249. }
  10250. | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
  10251. | GC_DELREF FCARG1x, TMP1w
  10252. if (RC_MAY_BE_1(op1_info)) {
  10253. if (RC_MAY_BE_N(op1_info)) {
  10254. if (jit_return_label >= 0) {
  10255. | bne =>jit_return_label
  10256. } else {
  10257. | bne >9
  10258. }
  10259. }
  10260. | //SAVE_OPLINE()
  10261. | ZVAL_DTOR_FUNC op1_info, opline, TMP1
  10262. | //????ldr REG1, EX->return_value // reload ???
  10263. }
  10264. if (return_value_used == -1) {
  10265. if (jit_return_label >= 0) {
  10266. | b =>jit_return_label
  10267. } else {
  10268. | b >9
  10269. }
  10270. |.code
  10271. }
  10272. }
  10273. } else if (return_value_used == -1) {
  10274. if (jit_return_label >= 0) {
  10275. | cbz Rx(Z_REG(ret_addr)), =>jit_return_label
  10276. } else {
  10277. | cbz Rx(Z_REG(ret_addr)), >9
  10278. }
  10279. }
  10280. if (return_value_used == 0) {
  10281. |9:
  10282. return 1;
  10283. }
  10284. if (opline->op1_type == IS_CONST) {
  10285. zval *zv = RT_CONSTANT(opline, opline->op1);
  10286. | ZVAL_COPY_CONST ret_addr, MAY_BE_ANY, MAY_BE_ANY, zv, ZREG_REG0, ZREG_TMP1, ZREG_FPR0
  10287. if (Z_REFCOUNTED_P(zv)) {
  10288. | ADDREF_CONST zv, REG0, TMP1
  10289. }
  10290. } else if (opline->op1_type == IS_TMP_VAR) {
  10291. | ZVAL_COPY_VALUE ret_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  10292. } else if (opline->op1_type == IS_CV) {
  10293. if (op1_info & MAY_BE_REF) {
  10294. | LOAD_ZVAL_ADDR REG0, op1_addr
  10295. | ZVAL_DEREF REG0, op1_info, TMP1w
  10296. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  10297. }
  10298. | ZVAL_COPY_VALUE ret_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  10299. if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
  10300. if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
  10301. (op1_info & (MAY_BE_REF|MAY_BE_OBJECT)) ||
  10302. !op_array->function_name) {
  10303. | TRY_ADDREF op1_info, REG0w, REG2, TMP1w
  10304. } else if (return_value_used != 1) {
  10305. | // if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) ZVAL_NULL(retval_ptr);
  10306. | SET_ZVAL_TYPE_INFO op1_addr, IS_NULL, TMP1w, TMP2
  10307. }
  10308. }
  10309. } else {
  10310. if (op1_info & MAY_BE_REF) {
  10311. zend_jit_addr ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, offsetof(zend_reference, val));
  10312. | IF_ZVAL_TYPE op1_addr, IS_REFERENCE, >1, ZREG_TMP1
  10313. |.cold_code
  10314. |1:
  10315. | // zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
  10316. | GET_ZVAL_PTR REG0, op1_addr, TMP1
  10317. | // ZVAL_COPY_VALUE(return_value, &ref->value);
  10318. | ZVAL_COPY_VALUE ret_addr, MAY_BE_ANY, ref_addr, op1_info, ZREG_REG2, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  10319. | GC_DELREF REG0, TMP1w
  10320. | beq >2
  10321. | // if (IS_REFCOUNTED())
  10322. if (jit_return_label >= 0) {
  10323. | IF_NOT_REFCOUNTED REG2w, =>jit_return_label, TMP1w
  10324. } else {
  10325. | IF_NOT_REFCOUNTED REG2w, >9, TMP1w
  10326. }
  10327. | // ADDREF
  10328. | GET_ZVAL_PTR REG2, ret_addr, TMP1 // reload
  10329. | GC_ADDREF REG2, TMP1w
  10330. if (jit_return_label >= 0) {
  10331. | b =>jit_return_label
  10332. } else {
  10333. | b >9
  10334. }
  10335. |2:
  10336. | mov FCARG1x, REG0
  10337. | EFREE_REFERENCE
  10338. if (jit_return_label >= 0) {
  10339. | b =>jit_return_label
  10340. } else {
  10341. | b >9
  10342. }
  10343. |.code
  10344. }
  10345. | ZVAL_COPY_VALUE ret_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  10346. }
  10347. |9:
  10348. return 1;
  10349. }
  10350. static int zend_jit_zval_copy_deref(dasm_State **Dst, zend_jit_addr res_addr, zend_jit_addr val_addr, zend_reg type_reg)
  10351. {
  10352. ZEND_ASSERT(type_reg == ZREG_REG2);
  10353. | GET_ZVAL_PTR REG1, val_addr, TMP1
  10354. | IF_NOT_REFCOUNTED REG2w, >2, TMP1w
  10355. | GET_LOW_8BITS TMP2w, REG2w
  10356. | IF_NOT_TYPE TMP2w, IS_REFERENCE, >1
  10357. | add REG1, REG1, #offsetof(zend_reference, val)
  10358. | GET_Z_TYPE_INFO REG2w, REG1
  10359. | GET_Z_PTR REG1, REG1
  10360. | IF_NOT_REFCOUNTED REG2w, >2, TMP1w
  10361. |1:
  10362. | GC_ADDREF REG1, TMP2w
  10363. |2:
  10364. | SET_ZVAL_PTR res_addr, REG1, TMP1
  10365. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG2w, TMP1
  10366. return 1;
  10367. }
  10368. static int zend_jit_fetch_dim_read(dasm_State **Dst,
  10369. const zend_op *opline,
  10370. zend_ssa *ssa,
  10371. const zend_ssa_op *ssa_op,
  10372. uint32_t op1_info,
  10373. zend_jit_addr op1_addr,
  10374. bool op1_avoid_refcounting,
  10375. uint32_t op2_info,
  10376. uint32_t res_info,
  10377. zend_jit_addr res_addr,
  10378. uint8_t dim_type)
  10379. {
  10380. zend_jit_addr orig_op1_addr, op2_addr;
  10381. const void *exit_addr = NULL;
  10382. const void *not_found_exit_addr = NULL;
  10383. const void *res_exit_addr = NULL;
  10384. bool result_avoid_refcounting = 0;
  10385. uint32_t may_be_string = (opline->opcode != ZEND_FETCH_LIST_R) ? MAY_BE_STRING : 0;
  10386. int may_throw = 0;
  10387. orig_op1_addr = OP1_ADDR();
  10388. op2_addr = OP2_ADDR();
  10389. if (opline->opcode != ZEND_FETCH_DIM_IS
  10390. && JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  10391. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  10392. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  10393. if (!exit_addr) {
  10394. return 0;
  10395. }
  10396. }
  10397. if ((res_info & MAY_BE_GUARD)
  10398. && JIT_G(current_frame)
  10399. && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
  10400. uint32_t flags = 0;
  10401. uint32_t old_op1_info = 0;
  10402. uint32_t old_info;
  10403. zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
  10404. int32_t exit_point;
  10405. if (opline->opcode != ZEND_FETCH_LIST_R
  10406. && (opline->op1_type & (IS_VAR|IS_TMP_VAR))
  10407. && !op1_avoid_refcounting) {
  10408. flags |= ZEND_JIT_EXIT_FREE_OP1;
  10409. }
  10410. if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
  10411. && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  10412. flags |= ZEND_JIT_EXIT_FREE_OP2;
  10413. }
  10414. if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
  10415. && !(flags & ZEND_JIT_EXIT_FREE_OP1)
  10416. && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
  10417. && (ssa_op+1)->op1_use == ssa_op->result_def
  10418. && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))
  10419. && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
  10420. result_avoid_refcounting = 1;
  10421. ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
  10422. }
  10423. if (op1_avoid_refcounting) {
  10424. old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
  10425. SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
  10426. }
  10427. if (!(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))) {
  10428. old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
  10429. SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
  10430. SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_GPR0);
  10431. exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
  10432. SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
  10433. res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  10434. if (!res_exit_addr) {
  10435. return 0;
  10436. }
  10437. res_info &= ~MAY_BE_GUARD;
  10438. ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
  10439. }
  10440. if (opline->opcode == ZEND_FETCH_DIM_IS
  10441. && !(res_info & MAY_BE_NULL)) {
  10442. old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
  10443. SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_NULL, 0);
  10444. SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NULL);
  10445. exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
  10446. SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
  10447. not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  10448. if (!not_found_exit_addr) {
  10449. return 0;
  10450. }
  10451. }
  10452. if (op1_avoid_refcounting) {
  10453. SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
  10454. }
  10455. }
  10456. if (op1_info & MAY_BE_REF) {
  10457. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  10458. | ZVAL_DEREF FCARG1x, op1_info, TMP1w
  10459. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  10460. }
  10461. if (op1_info & MAY_BE_ARRAY) {
  10462. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
  10463. if (exit_addr && !(op1_info & (MAY_BE_OBJECT|may_be_string))) {
  10464. | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, &exit_addr, ZREG_TMP1
  10465. } else {
  10466. | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7, ZREG_TMP1
  10467. }
  10468. }
  10469. | GET_ZVAL_LVAL ZREG_FCARG1, op1_addr, TMP1
  10470. if ((op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) ||
  10471. (opline->opcode != ZEND_FETCH_DIM_IS && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE)) {
  10472. may_throw = 1;
  10473. }
  10474. if (!zend_jit_fetch_dimension_address_inner(Dst, opline, (opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS, op1_info, op2_info, dim_type, res_exit_addr, not_found_exit_addr, exit_addr)) {
  10475. return 0;
  10476. }
  10477. }
  10478. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
  10479. if (op1_info & MAY_BE_ARRAY) {
  10480. |.cold_code
  10481. |7:
  10482. }
  10483. if (opline->opcode != ZEND_FETCH_LIST_R && (op1_info & MAY_BE_STRING)) {
  10484. may_throw = 1;
  10485. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING))) {
  10486. if (exit_addr && !(op1_info & MAY_BE_OBJECT)) {
  10487. | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, &exit_addr, ZREG_TMP1
  10488. } else {
  10489. | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >6, ZREG_TMP1
  10490. }
  10491. }
  10492. | SET_EX_OPLINE opline, REG0
  10493. | GET_ZVAL_LVAL ZREG_FCARG1, op1_addr, TMP1
  10494. if (opline->opcode != ZEND_FETCH_DIM_IS) {
  10495. if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
  10496. | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1
  10497. | EXT_CALL zend_jit_fetch_dim_str_offset_r_helper, REG0
  10498. } else {
  10499. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  10500. | EXT_CALL zend_jit_fetch_dim_str_r_helper, REG0
  10501. }
  10502. | SET_ZVAL_PTR res_addr, RETVALx, TMP1
  10503. | SET_ZVAL_TYPE_INFO res_addr, IS_STRING, TMP1w, TMP2
  10504. } else {
  10505. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  10506. | LOAD_ZVAL_ADDR CARG3, res_addr
  10507. | EXT_CALL zend_jit_fetch_dim_str_is_helper, REG0
  10508. }
  10509. if ((op1_info & MAY_BE_ARRAY) ||
  10510. (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING)))) {
  10511. | b >9 // END
  10512. }
  10513. |6:
  10514. }
  10515. if (op1_info & MAY_BE_OBJECT) {
  10516. may_throw = 1;
  10517. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string))) {
  10518. if (exit_addr) {
  10519. | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr, ZREG_TMP1
  10520. } else {
  10521. | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >6, ZREG_TMP1
  10522. }
  10523. }
  10524. | SET_EX_OPLINE opline, REG0
  10525. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  10526. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  10527. }
  10528. if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
  10529. ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
  10530. | LOAD_ADDR FCARG2x, (Z_ZV(op2_addr) + 1)
  10531. } else {
  10532. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  10533. }
  10534. | LOAD_ZVAL_ADDR CARG3, res_addr
  10535. if (opline->opcode != ZEND_FETCH_DIM_IS) {
  10536. | EXT_CALL zend_jit_fetch_dim_obj_r_helper, REG0
  10537. } else {
  10538. | EXT_CALL zend_jit_fetch_dim_obj_is_helper, REG0
  10539. }
  10540. if ((op1_info & MAY_BE_ARRAY) ||
  10541. (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) {
  10542. | b >9 // END
  10543. }
  10544. |6:
  10545. }
  10546. if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))
  10547. && (!exit_addr || !(op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) {
  10548. if ((opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) || (op2_info & MAY_BE_UNDEF)) {
  10549. | SET_EX_OPLINE opline, REG0
  10550. if (opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) {
  10551. may_throw = 1;
  10552. | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1
  10553. | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
  10554. | LOAD_32BIT_VAL FCARG1w, opline->op1.var
  10555. | EXT_CALL zend_jit_undefined_op_helper, REG0
  10556. |1:
  10557. }
  10558. if (op2_info & MAY_BE_UNDEF) {
  10559. may_throw = 1;
  10560. | IF_NOT_ZVAL_TYPE op2_addr, IS_UNDEF, >1, ZREG_TMP1
  10561. | LOAD_32BIT_VAL FCARG1w, opline->op2.var
  10562. | EXT_CALL zend_jit_undefined_op_helper, REG0
  10563. |1:
  10564. }
  10565. }
  10566. if (opline->opcode != ZEND_FETCH_DIM_IS && opline->opcode != ZEND_FETCH_LIST_R) {
  10567. may_throw = 1;
  10568. if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
  10569. | LOAD_ZVAL_ADDR FCARG1x, orig_op1_addr
  10570. } else {
  10571. | SET_EX_OPLINE opline, REG0
  10572. if (Z_MODE(op1_addr) != IS_MEM_ZVAL ||
  10573. Z_REG(op1_addr) != ZREG_FCARG1 ||
  10574. Z_OFFSET(op1_addr) != 0) {
  10575. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  10576. }
  10577. }
  10578. | EXT_CALL zend_jit_invalid_array_access, REG0
  10579. }
  10580. | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2
  10581. if (op1_info & MAY_BE_ARRAY) {
  10582. | b >9 // END
  10583. }
  10584. }
  10585. if (op1_info & MAY_BE_ARRAY) {
  10586. |.code
  10587. }
  10588. }
  10589. if (op1_info & MAY_BE_ARRAY) {
  10590. zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  10591. |8:
  10592. if (res_exit_addr) {
  10593. uint32_t type = concrete_type(res_info);
  10594. if ((op1_info & MAY_BE_ARRAY_OF_REF)
  10595. && dim_type != IS_UNKNOWN
  10596. && dim_type != IS_REFERENCE) {
  10597. if (type < IS_STRING) {
  10598. | IF_NOT_ZVAL_TYPE val_addr, type, >1, ZREG_TMP1
  10599. |.cold_code
  10600. |1:
  10601. | IF_NOT_ZVAL_TYPE val_addr, IS_REFERENCE, &res_exit_addr, ZREG_TMP1
  10602. | GET_Z_PTR REG0, REG0
  10603. | add REG0, REG0, #offsetof(zend_reference, val)
  10604. | IF_ZVAL_TYPE val_addr, type, >1, ZREG_TMP1
  10605. | b &res_exit_addr
  10606. |.code
  10607. |1:
  10608. } else {
  10609. | GET_ZVAL_TYPE_INFO REG2w, val_addr, TMP1
  10610. | GET_LOW_8BITS TMP1w, REG2w
  10611. | IF_NOT_TYPE TMP1w, type, >1
  10612. |.cold_code
  10613. |1:
  10614. | IF_NOT_TYPE TMP1w, IS_REFERENCE, &res_exit_addr
  10615. | GET_Z_PTR REG0, REG0
  10616. | add REG0, REG0, #offsetof(zend_reference, val)
  10617. | GET_ZVAL_TYPE_INFO REG2w, val_addr, TMP1
  10618. | GET_LOW_8BITS TMP1w, REG2w
  10619. | IF_TYPE TMP1w, type, >1
  10620. | b &res_exit_addr
  10621. |.code
  10622. |1:
  10623. }
  10624. } else {
  10625. if (op1_info & MAY_BE_ARRAY_OF_REF) {
  10626. | ZVAL_DEREF REG0, MAY_BE_REF, TMP1w
  10627. }
  10628. if (type < IS_STRING) {
  10629. | IF_NOT_ZVAL_TYPE val_addr, type, &res_exit_addr, ZREG_TMP1
  10630. } else {
  10631. | GET_ZVAL_TYPE_INFO REG2w, val_addr, TMP1
  10632. | GET_LOW_8BITS TMP1w, REG2w
  10633. | IF_NOT_TYPE TMP1w, type, &res_exit_addr
  10634. }
  10635. }
  10636. | // ZVAL_COPY
  10637. |7:
  10638. | ZVAL_COPY_VALUE_V res_addr, -1, val_addr, res_info, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_FPR0
  10639. if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
  10640. if (type < IS_STRING) {
  10641. if (Z_REG(res_addr) != ZREG_FP ||
  10642. JIT_G(current_frame) == NULL ||
  10643. STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(res_addr))) != type) {
  10644. | SET_ZVAL_TYPE_INFO res_addr, type, TMP1w, TMP2
  10645. }
  10646. } else {
  10647. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG2w, TMP1
  10648. if (!result_avoid_refcounting) {
  10649. | TRY_ADDREF res_info, REG2w, REG1, TMP1w
  10650. }
  10651. }
  10652. } else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
  10653. return 0;
  10654. }
  10655. } else if (op1_info & MAY_BE_ARRAY_OF_REF) {
  10656. | // ZVAL_COPY_DEREF
  10657. | GET_ZVAL_TYPE_INFO Rw(ZREG_REG2), val_addr, TMP1
  10658. if (!zend_jit_zval_copy_deref(Dst, res_addr, val_addr, ZREG_REG2)) {
  10659. return 0;
  10660. }
  10661. } else {
  10662. | // ZVAL_COPY
  10663. | ZVAL_COPY_VALUE res_addr, -1, val_addr, res_info, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  10664. | TRY_ADDREF res_info, REG1w, REG2, TMP1w
  10665. }
  10666. }
  10667. |9: // END
  10668. #ifdef ZEND_JIT_USE_RC_INFERENCE
  10669. if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
  10670. /* Magic offsetGet() may increase refcount of the key */
  10671. op2_info |= MAY_BE_RCN;
  10672. }
  10673. #endif
  10674. if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
  10675. if ((op2_info & MAY_HAVE_DTOR) && (op2_info & MAY_BE_RC1)) {
  10676. may_throw = 1;
  10677. }
  10678. | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  10679. }
  10680. if (opline->opcode != ZEND_FETCH_LIST_R && !op1_avoid_refcounting) {
  10681. if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
  10682. if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
  10683. may_throw = 1;
  10684. }
  10685. | FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  10686. }
  10687. }
  10688. if (may_throw) {
  10689. if (!zend_jit_check_exception(Dst)) {
  10690. return 0;
  10691. }
  10692. }
  10693. return 1;
  10694. }
  10695. static int zend_jit_fetch_dim(dasm_State **Dst,
  10696. const zend_op *opline,
  10697. uint32_t op1_info,
  10698. zend_jit_addr op1_addr,
  10699. uint32_t op2_info,
  10700. zend_jit_addr res_addr,
  10701. uint8_t dim_type)
  10702. {
  10703. zend_jit_addr op2_addr;
  10704. int may_throw = 0;
  10705. op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0;
  10706. if (op1_info & MAY_BE_REF) {
  10707. may_throw = 1;
  10708. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  10709. | IF_NOT_Z_TYPE FCARG1x, IS_REFERENCE, >1, TMP1w
  10710. | GET_Z_PTR FCARG2x, FCARG1x
  10711. | ldrb TMP1w, [FCARG2x, #(offsetof(zend_reference, val) + offsetof(zval, u1.v.type))]
  10712. | cmp TMP1w, #IS_ARRAY
  10713. | bne >2
  10714. | add FCARG1x, FCARG2x, #offsetof(zend_reference, val)
  10715. | b >3
  10716. |.cold_code
  10717. |2:
  10718. | SET_EX_OPLINE opline, REG0
  10719. | EXT_CALL zend_jit_prepare_assign_dim_ref, REG0
  10720. | mov FCARG1x, RETVALx
  10721. | cbnz FCARG1x, >1
  10722. | b ->exception_handler_undef
  10723. |.code
  10724. |1:
  10725. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  10726. }
  10727. if (op1_info & MAY_BE_ARRAY) {
  10728. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
  10729. | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7, ZREG_TMP1
  10730. }
  10731. |3:
  10732. | SEPARATE_ARRAY op1_addr, op1_info, 1, ZREG_TMP1, ZREG_TMP2
  10733. }
  10734. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) {
  10735. if (op1_info & MAY_BE_ARRAY) {
  10736. |.cold_code
  10737. |7:
  10738. }
  10739. if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
  10740. | CMP_ZVAL_TYPE op1_addr, IS_NULL, ZREG_TMP1
  10741. | bgt >7
  10742. }
  10743. if (Z_REG(op1_addr) != ZREG_FP) {
  10744. | str Rx(Z_REG(op1_addr)), T1 // save
  10745. }
  10746. if ((op1_info & MAY_BE_UNDEF)
  10747. && opline->opcode == ZEND_FETCH_DIM_RW) {
  10748. may_throw = 1;
  10749. if (op1_info & MAY_BE_NULL) {
  10750. | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1
  10751. }
  10752. | SET_EX_OPLINE opline, REG0
  10753. | LOAD_32BIT_VAL FCARG1w, opline->op1.var
  10754. | EXT_CALL zend_jit_undefined_op_helper, REG0
  10755. |1:
  10756. }
  10757. | // ZVAL_ARR(container, zend_new_array(8));
  10758. | EXT_CALL _zend_new_array_0, REG0
  10759. | mov REG0, RETVALx
  10760. if (Z_REG(op1_addr) != ZREG_FP) {
  10761. | ldr Rx(Z_REG(op1_addr)), T1 // restore
  10762. }
  10763. | SET_ZVAL_LVAL_FROM_REG op1_addr, REG0, TMP1
  10764. | SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX, TMP1w, TMP2
  10765. | mov FCARG1x, REG0
  10766. if (op1_info & MAY_BE_ARRAY) {
  10767. | b >1
  10768. |.code
  10769. |1:
  10770. }
  10771. }
  10772. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
  10773. |6:
  10774. if (opline->op2_type == IS_UNUSED) {
  10775. may_throw = 1;
  10776. | // var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
  10777. | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval
  10778. | EXT_CALL zend_hash_next_index_insert, REG0
  10779. | // if (UNEXPECTED(!var_ptr)) {
  10780. | cbz RETVALx, >1
  10781. |.cold_code
  10782. |1:
  10783. | // zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
  10784. | CANNOT_ADD_ELEMENT opline
  10785. | SET_ZVAL_TYPE_INFO res_addr, IS_UNDEF, TMP1w, TMP2
  10786. | //ZEND_VM_C_GOTO(assign_dim_op_ret_null);
  10787. | b >8
  10788. |.code
  10789. | SET_ZVAL_PTR res_addr, RETVALx, TMP1
  10790. | SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT, TMP1w, TMP2
  10791. } else {
  10792. uint32_t type;
  10793. switch (opline->opcode) {
  10794. case ZEND_FETCH_DIM_W:
  10795. case ZEND_FETCH_LIST_W:
  10796. type = BP_VAR_W;
  10797. break;
  10798. case ZEND_FETCH_DIM_RW:
  10799. may_throw = 1;
  10800. type = BP_VAR_RW;
  10801. break;
  10802. case ZEND_FETCH_DIM_UNSET:
  10803. type = BP_VAR_UNSET;
  10804. break;
  10805. default:
  10806. ZEND_UNREACHABLE();
  10807. }
  10808. if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
  10809. may_throw = 1;
  10810. }
  10811. if (!zend_jit_fetch_dimension_address_inner(Dst, opline, type, op1_info, op2_info, dim_type, NULL, NULL, NULL)) {
  10812. return 0;
  10813. }
  10814. |8:
  10815. | SET_ZVAL_PTR res_addr, REG0, TMP1
  10816. | SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT, TMP1w, TMP2
  10817. if (type == BP_VAR_RW || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
  10818. |.cold_code
  10819. |9:
  10820. | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2
  10821. | b >8
  10822. |.code
  10823. }
  10824. }
  10825. }
  10826. if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
  10827. may_throw = 1;
  10828. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
  10829. |.cold_code
  10830. |7:
  10831. }
  10832. | SET_EX_OPLINE opline, REG0
  10833. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  10834. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  10835. }
  10836. if (opline->op2_type == IS_UNUSED) {
  10837. | mov FCARG2x, xzr
  10838. } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
  10839. ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
  10840. | LOAD_ADDR FCARG2x, (Z_ZV(op2_addr) + 1)
  10841. } else {
  10842. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  10843. }
  10844. | LOAD_ZVAL_ADDR CARG3, res_addr
  10845. switch (opline->opcode) {
  10846. case ZEND_FETCH_DIM_W:
  10847. case ZEND_FETCH_LIST_W:
  10848. | EXT_CALL zend_jit_fetch_dim_obj_w_helper, REG0
  10849. break;
  10850. case ZEND_FETCH_DIM_RW:
  10851. | EXT_CALL zend_jit_fetch_dim_obj_rw_helper, REG0
  10852. break;
  10853. // case ZEND_FETCH_DIM_UNSET:
  10854. // | EXT_CALL zend_jit_fetch_dim_obj_unset_helper, REG0
  10855. // break;
  10856. default:
  10857. ZEND_UNREACHABLE();
  10858. }
  10859. if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
  10860. | b >8 // END
  10861. |.code
  10862. }
  10863. }
  10864. #ifdef ZEND_JIT_USE_RC_INFERENCE
  10865. if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
  10866. /* ASSIGN_DIM may increase refcount of the key */
  10867. op2_info |= MAY_BE_RCN;
  10868. }
  10869. #endif
  10870. if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
  10871. && (op2_info & MAY_HAVE_DTOR)
  10872. && (op2_info & MAY_BE_RC1)) {
  10873. may_throw = 1;
  10874. }
  10875. |8:
  10876. | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  10877. if (may_throw) {
  10878. if (!zend_jit_check_exception(Dst)) {
  10879. return 0;
  10880. }
  10881. }
  10882. return 1;
  10883. }
  10884. static int zend_jit_isset_isempty_dim(dasm_State **Dst,
  10885. const zend_op *opline,
  10886. uint32_t op1_info,
  10887. zend_jit_addr op1_addr,
  10888. bool op1_avoid_refcounting,
  10889. uint32_t op2_info,
  10890. uint8_t dim_type,
  10891. int may_throw,
  10892. zend_uchar smart_branch_opcode,
  10893. uint32_t target_label,
  10894. uint32_t target_label2,
  10895. const void *exit_addr)
  10896. {
  10897. zend_jit_addr op2_addr, res_addr;
  10898. // TODO: support for empty() ???
  10899. ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
  10900. op2_addr = OP2_ADDR();
  10901. res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  10902. if (op1_info & MAY_BE_REF) {
  10903. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  10904. | ZVAL_DEREF FCARG1x, op1_info, TMP1w
  10905. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  10906. }
  10907. if (op1_info & MAY_BE_ARRAY) {
  10908. const void *found_exit_addr = NULL;
  10909. const void *not_found_exit_addr = NULL;
  10910. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
  10911. | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7, ZREG_TMP1
  10912. }
  10913. | GET_ZVAL_LVAL ZREG_FCARG1, op1_addr, TMP1
  10914. if (exit_addr
  10915. && !(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY))
  10916. && !may_throw
  10917. && (!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || op1_avoid_refcounting)
  10918. && (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
  10919. if (smart_branch_opcode == ZEND_JMPNZ) {
  10920. found_exit_addr = exit_addr;
  10921. } else {
  10922. not_found_exit_addr = exit_addr;
  10923. }
  10924. }
  10925. if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_JIT_IS, op1_info, op2_info, dim_type, found_exit_addr, not_found_exit_addr, NULL)) {
  10926. return 0;
  10927. }
  10928. if (found_exit_addr) {
  10929. |9:
  10930. return 1;
  10931. } else if (not_found_exit_addr) {
  10932. |8:
  10933. return 1;
  10934. }
  10935. }
  10936. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
  10937. if (op1_info & MAY_BE_ARRAY) {
  10938. |.cold_code
  10939. |7:
  10940. }
  10941. if (op1_info & (MAY_BE_STRING|MAY_BE_OBJECT)) {
  10942. | SET_EX_OPLINE opline, REG0
  10943. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  10944. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  10945. }
  10946. if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
  10947. ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
  10948. | LOAD_ADDR FCARG2x, (Z_ZV(op2_addr) + 1)
  10949. } else {
  10950. | LOAD_ZVAL_ADDR FCARG2x, op2_addr
  10951. }
  10952. | EXT_CALL zend_jit_isset_dim_helper, REG0
  10953. | cbz RETVALw, >9
  10954. if (op1_info & MAY_BE_ARRAY) {
  10955. | b >8
  10956. |.code
  10957. }
  10958. } else {
  10959. if (op2_info & MAY_BE_UNDEF) {
  10960. if (op2_info & MAY_BE_ANY) {
  10961. | IF_NOT_ZVAL_TYPE op2_addr, IS_UNDEF, >1, ZREG_TMP1
  10962. }
  10963. | SET_EX_OPLINE opline, REG0
  10964. | LOAD_32BIT_VAL FCARG1w, opline->op2.var
  10965. | EXT_CALL zend_jit_undefined_op_helper, REG0
  10966. |1:
  10967. }
  10968. if (op1_info & MAY_BE_ARRAY) {
  10969. | b >9
  10970. |.code
  10971. }
  10972. }
  10973. }
  10974. #ifdef ZEND_JIT_USE_RC_INFERENCE
  10975. if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
  10976. /* Magic offsetExists() may increase refcount of the key */
  10977. op2_info |= MAY_BE_RCN;
  10978. }
  10979. #endif
  10980. if (op1_info & (MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_OBJECT)) {
  10981. |8:
  10982. | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  10983. if (!op1_avoid_refcounting) {
  10984. | FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  10985. }
  10986. if (may_throw) {
  10987. if (!zend_jit_check_exception_undef_result(Dst, opline)) {
  10988. return 0;
  10989. }
  10990. }
  10991. if (!(opline->extended_value & ZEND_ISEMPTY)) {
  10992. if (exit_addr) {
  10993. if (smart_branch_opcode == ZEND_JMPNZ) {
  10994. | b &exit_addr
  10995. } else {
  10996. | b >8
  10997. }
  10998. } else if (smart_branch_opcode) {
  10999. if (smart_branch_opcode == ZEND_JMPZ) {
  11000. | b =>target_label2
  11001. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  11002. | b =>target_label
  11003. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  11004. | b =>target_label2
  11005. } else {
  11006. ZEND_UNREACHABLE();
  11007. }
  11008. } else {
  11009. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  11010. | b >8
  11011. }
  11012. } else {
  11013. | NIY // TODO: support for empty()
  11014. }
  11015. }
  11016. |9: // not found
  11017. | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  11018. if (!op1_avoid_refcounting) {
  11019. | FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  11020. }
  11021. if (may_throw) {
  11022. if (!zend_jit_check_exception_undef_result(Dst, opline)) {
  11023. return 0;
  11024. }
  11025. }
  11026. if (!(opline->extended_value & ZEND_ISEMPTY)) {
  11027. if (exit_addr) {
  11028. if (smart_branch_opcode == ZEND_JMPZ) {
  11029. | b &exit_addr
  11030. }
  11031. } else if (smart_branch_opcode) {
  11032. if (smart_branch_opcode == ZEND_JMPZ) {
  11033. | b =>target_label
  11034. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  11035. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  11036. | b =>target_label
  11037. } else {
  11038. ZEND_UNREACHABLE();
  11039. }
  11040. } else {
  11041. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  11042. }
  11043. } else {
  11044. | NIY // TODO: support for empty()
  11045. }
  11046. |8:
  11047. return 1;
  11048. }
  11049. static int zend_jit_bind_global(dasm_State **Dst, const zend_op *opline, uint32_t op1_info)
  11050. {
  11051. zend_jit_addr op1_addr = OP1_ADDR();
  11052. zend_string *varname = Z_STR_P(RT_CONSTANT(opline, opline->op2));
  11053. | // idx = (uint32_t)(uintptr_t)CACHED_PTR(opline->extended_value) - 1;
  11054. | ldr FCARG2x, EX->run_time_cache
  11055. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, FCARG2x, opline->extended_value, TMP1
  11056. | sub REG0, REG0, #1
  11057. | // if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket)))
  11058. | MEM_LOAD_32_ZTS ldr, REG1w, executor_globals, symbol_table.nNumUsed, REG1
  11059. | cmp REG0, REG1, lsl #5
  11060. | bhs >9
  11061. | // Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
  11062. | MEM_LOAD_64_ZTS ldr, TMP1, executor_globals, symbol_table.arData, REG1
  11063. | add REG0, REG0, TMP1
  11064. | IF_NOT_Z_TYPE REG0, IS_REFERENCE, >9, TMP1w
  11065. | // (EXPECTED(p->key == varname))
  11066. | ldr TMP1, [REG0, #offsetof(Bucket, key)]
  11067. | LOAD_ADDR TMP2, varname
  11068. | cmp TMP1, TMP2
  11069. | bne >9
  11070. | GET_Z_PTR REG0, REG0
  11071. | GC_ADDREF REG0, TMP1w
  11072. |1:
  11073. if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
  11074. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  11075. | // if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr)))
  11076. | IF_ZVAL_REFCOUNTED op1_addr, >2, ZREG_TMP1, ZREG_TMP2
  11077. |.cold_code
  11078. |2:
  11079. }
  11080. | // zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
  11081. | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
  11082. | // ZVAL_REF(variable_ptr, ref)
  11083. | SET_ZVAL_PTR op1_addr, REG0, TMP1
  11084. | SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX, TMP1w, TMP2
  11085. | // if (GC_DELREF(garbage) == 0)
  11086. | GC_DELREF FCARG1x, TMP1w
  11087. if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
  11088. | bne >3
  11089. } else {
  11090. | bne >5
  11091. }
  11092. | ZVAL_DTOR_FUNC op1_info, opline, TMP1
  11093. | b >5
  11094. if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
  11095. |3:
  11096. | // GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr)
  11097. | IF_GC_MAY_NOT_LEAK FCARG1x, >5, TMP1w, TMP2w
  11098. | EXT_CALL gc_possible_root, REG0
  11099. | b >5
  11100. }
  11101. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  11102. |.code
  11103. }
  11104. }
  11105. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  11106. | // ZVAL_REF(variable_ptr, ref)
  11107. | SET_ZVAL_PTR op1_addr, REG0, TMP1
  11108. | SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX, TMP1w, TMP2
  11109. }
  11110. |5:
  11111. //END of handler
  11112. |.cold_code
  11113. |9:
  11114. | LOAD_ADDR FCARG1x, (ptrdiff_t)varname
  11115. if (opline->extended_value) {
  11116. | ADD_SUB_64_WITH_CONST_32 add, FCARG2x, FCARG2x, opline->extended_value, TMP1
  11117. }
  11118. | EXT_CALL zend_jit_fetch_global_helper, REG0
  11119. | mov REG0, RETVALx
  11120. | b <1
  11121. |.code
  11122. return 1;
  11123. }
  11124. static int zend_jit_verify_arg_type(dasm_State **Dst, const zend_op *opline, zend_arg_info *arg_info, bool check_exception)
  11125. {
  11126. zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  11127. bool in_cold = 0;
  11128. uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
  11129. zend_reg tmp_reg = (type_mask == 0 || is_power_of_two(type_mask)) ? ZREG_FCARG1 : ZREG_REG0;
  11130. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
  11131. && JIT_G(current_frame)
  11132. && JIT_G(current_frame)->prev) {
  11133. zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
  11134. uint8_t type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
  11135. if (type != IS_UNKNOWN && (type_mask & (1u << type))) {
  11136. return 1;
  11137. }
  11138. }
  11139. if (ZEND_ARG_SEND_MODE(arg_info)) {
  11140. if (opline->opcode == ZEND_RECV_INIT) {
  11141. | LOAD_ZVAL_ADDR Rx(tmp_reg), res_addr
  11142. | ZVAL_DEREF Rx(tmp_reg), MAY_BE_REF, TMP1w
  11143. res_addr = ZEND_ADDR_MEM_ZVAL(tmp_reg, 0);
  11144. } else {
  11145. | GET_ZVAL_PTR Rx(tmp_reg), res_addr, TMP1
  11146. res_addr = ZEND_ADDR_MEM_ZVAL(tmp_reg, offsetof(zend_reference, val));
  11147. }
  11148. }
  11149. if (type_mask != 0) {
  11150. if (is_power_of_two(type_mask)) {
  11151. uint32_t type_code = concrete_type(type_mask);
  11152. | IF_NOT_ZVAL_TYPE res_addr, type_code, >1, ZREG_TMP1
  11153. } else {
  11154. | mov REG2w, #1
  11155. | MEM_ACCESS_8_WITH_UOFFSET ldrb, REG1w, Rx(Z_REG(res_addr)), Z_OFFSET(res_addr)+offsetof(zval, u1.v.type), TMP1
  11156. | lsl REG2w, REG2w, REG1w
  11157. | TST_32_WITH_CONST REG2w, type_mask, TMP1w
  11158. | beq >1
  11159. }
  11160. |.cold_code
  11161. |1:
  11162. in_cold = 1;
  11163. }
  11164. if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) {
  11165. | LOAD_ZVAL_ADDR FCARG1x, res_addr
  11166. }
  11167. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  11168. | SET_EX_OPLINE opline, REG0
  11169. } else {
  11170. | ADDR_STORE EX->opline, opline, REG0
  11171. }
  11172. | LOAD_ADDR FCARG2x, (ptrdiff_t)arg_info
  11173. | EXT_CALL zend_jit_verify_arg_slow, REG0
  11174. if (check_exception) {
  11175. | GET_LOW_8BITS REG0w, RETVALw
  11176. if (in_cold) {
  11177. | cbnz REG0w, >1
  11178. | b ->exception_handler
  11179. |.code
  11180. |1:
  11181. } else {
  11182. | cbz REG0w, ->exception_handler
  11183. }
  11184. } else if (in_cold) {
  11185. | b >1
  11186. |.code
  11187. |1:
  11188. }
  11189. return 1;
  11190. }
  11191. static int zend_jit_recv(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array)
  11192. {
  11193. uint32_t arg_num = opline->op1.num;
  11194. zend_arg_info *arg_info = NULL;
  11195. if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
  11196. if (EXPECTED(arg_num <= op_array->num_args)) {
  11197. arg_info = &op_array->arg_info[arg_num-1];
  11198. } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
  11199. arg_info = &op_array->arg_info[op_array->num_args];
  11200. }
  11201. if (arg_info && !ZEND_TYPE_IS_SET(arg_info->type)) {
  11202. arg_info = NULL;
  11203. }
  11204. }
  11205. if (arg_info || (opline+1)->opcode != ZEND_RECV) {
  11206. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  11207. if (!JIT_G(current_frame) ||
  11208. TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) < 0 ||
  11209. arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
  11210. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  11211. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  11212. if (!exit_addr) {
  11213. return 0;
  11214. }
  11215. | ldr TMP1w, EX->This.u2.num_args
  11216. | CMP_32_WITH_CONST TMP1w, arg_num, TMP2w
  11217. | blo &exit_addr
  11218. }
  11219. } else {
  11220. | ldr TMP1w, EX->This.u2.num_args
  11221. | CMP_32_WITH_CONST TMP1w, arg_num, TMP2w
  11222. | blo >1
  11223. |.cold_code
  11224. |1:
  11225. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  11226. | SET_EX_OPLINE opline, REG0
  11227. } else {
  11228. | ADDR_STORE EX->opline, opline, REG0
  11229. }
  11230. | mov FCARG1x, FP
  11231. | EXT_CALL zend_missing_arg_error, REG0
  11232. | b ->exception_handler
  11233. |.code
  11234. }
  11235. }
  11236. if (arg_info) {
  11237. if (!zend_jit_verify_arg_type(Dst, opline, arg_info, 1)) {
  11238. return 0;
  11239. }
  11240. }
  11241. if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
  11242. if ((opline+1)->opcode != ZEND_RECV && (opline+1)->opcode != ZEND_RECV_INIT) {
  11243. | LOAD_IP_ADDR (opline + 1)
  11244. zend_jit_set_last_valid_opline(opline + 1);
  11245. }
  11246. }
  11247. return 1;
  11248. }
  11249. static int zend_jit_recv_init(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, bool is_last, int may_throw)
  11250. {
  11251. uint32_t arg_num = opline->op1.num;
  11252. zval *zv = RT_CONSTANT(opline, opline->op2);
  11253. zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  11254. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
  11255. && JIT_G(current_frame)
  11256. && TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) >= 0) {
  11257. if (arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
  11258. | ZVAL_COPY_CONST res_addr, -1, -1, zv, ZREG_REG0, ZREG_TMP1, ZREG_FPR0
  11259. if (Z_REFCOUNTED_P(zv)) {
  11260. | ADDREF_CONST zv, REG0, TMP1
  11261. }
  11262. }
  11263. } else {
  11264. if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
  11265. (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
  11266. | ldr TMP1w, EX->This.u2.num_args
  11267. | CMP_32_WITH_CONST TMP1w, arg_num, TMP2w
  11268. | bhs >5
  11269. }
  11270. | ZVAL_COPY_CONST res_addr, -1, -1, zv, ZREG_REG0, ZREG_TMP1, ZREG_FPR0
  11271. if (Z_REFCOUNTED_P(zv)) {
  11272. | ADDREF_CONST zv, REG0, TMP1
  11273. }
  11274. }
  11275. if (Z_CONSTANT_P(zv)) {
  11276. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  11277. | SET_EX_OPLINE opline, REG0
  11278. } else {
  11279. | ADDR_STORE EX->opline, opline, REG0
  11280. }
  11281. | LOAD_ZVAL_ADDR FCARG1x, res_addr
  11282. | ldr REG0, EX->func
  11283. | ldr FCARG2x, [REG0, #offsetof(zend_op_array, scope)]
  11284. | EXT_CALL zval_update_constant_ex, REG0
  11285. | cbnz RETVALw, >1
  11286. |.cold_code
  11287. |1:
  11288. | ZVAL_PTR_DTOR res_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 1, 0, opline, ZREG_TMP1, ZREG_TMP2
  11289. | SET_ZVAL_TYPE_INFO res_addr, IS_UNDEF, TMP1w, TMP2
  11290. | b ->exception_handler
  11291. |.code
  11292. }
  11293. |5:
  11294. if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
  11295. do {
  11296. zend_arg_info *arg_info;
  11297. if (arg_num <= op_array->num_args) {
  11298. arg_info = &op_array->arg_info[arg_num-1];
  11299. } else if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
  11300. arg_info = &op_array->arg_info[op_array->num_args];
  11301. } else {
  11302. break;
  11303. }
  11304. if (!ZEND_TYPE_IS_SET(arg_info->type)) {
  11305. break;
  11306. }
  11307. if (!zend_jit_verify_arg_type(Dst, opline, arg_info, may_throw)) {
  11308. return 0;
  11309. }
  11310. } while (0);
  11311. }
  11312. if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
  11313. if (is_last) {
  11314. | LOAD_IP_ADDR (opline + 1)
  11315. zend_jit_set_last_valid_opline(opline + 1);
  11316. }
  11317. }
  11318. return 1;
  11319. }
  11320. static int zend_jit_class_guard(dasm_State **Dst, const zend_op *opline, zend_class_entry *ce)
  11321. {
  11322. int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
  11323. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  11324. if (!exit_addr) {
  11325. return 0;
  11326. }
  11327. | LOAD_ADDR TMP1, ((ptrdiff_t)ce)
  11328. | ldr TMP2, [FCARG1x, #offsetof(zend_object, ce)]
  11329. | cmp TMP2, TMP1
  11330. | bne &exit_addr
  11331. return 1;
  11332. }
  11333. static int zend_jit_fetch_obj(dasm_State **Dst,
  11334. const zend_op *opline,
  11335. const zend_op_array *op_array,
  11336. zend_ssa *ssa,
  11337. const zend_ssa_op *ssa_op,
  11338. uint32_t op1_info,
  11339. zend_jit_addr op1_addr,
  11340. bool op1_indirect,
  11341. zend_class_entry *ce,
  11342. bool ce_is_instanceof,
  11343. bool on_this,
  11344. bool delayed_fetch_this,
  11345. bool op1_avoid_refcounting,
  11346. zend_class_entry *trace_ce,
  11347. uint8_t prop_type,
  11348. int may_throw)
  11349. {
  11350. zval *member;
  11351. zend_property_info *prop_info;
  11352. bool may_be_dynamic = 1;
  11353. zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  11354. zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
  11355. zend_jit_addr prop_addr;
  11356. uint32_t res_info = RES_INFO();
  11357. bool type_loaded = 0;
  11358. ZEND_ASSERT(opline->op2_type == IS_CONST);
  11359. ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
  11360. member = RT_CONSTANT(opline, opline->op2);
  11361. ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
  11362. prop_info = zend_get_known_property_info(op_array, ce, Z_STR_P(member), on_this, op_array->filename);
  11363. if (on_this) {
  11364. | GET_ZVAL_PTR FCARG1x, this_addr, TMP1
  11365. } else {
  11366. if (opline->op1_type == IS_VAR
  11367. && opline->opcode == ZEND_FETCH_OBJ_W
  11368. && (op1_info & MAY_BE_INDIRECT)
  11369. && Z_REG(op1_addr) == ZREG_FP) {
  11370. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  11371. | IF_NOT_Z_TYPE FCARG1x, IS_INDIRECT, >1, TMP1w
  11372. | GET_Z_PTR FCARG1x, FCARG1x
  11373. |1:
  11374. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  11375. }
  11376. if (op1_info & MAY_BE_REF) {
  11377. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  11378. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  11379. }
  11380. | ZVAL_DEREF FCARG1x, op1_info, TMP1w
  11381. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  11382. }
  11383. if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
  11384. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  11385. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  11386. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  11387. if (!exit_addr) {
  11388. return 0;
  11389. }
  11390. | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr, ZREG_TMP1
  11391. } else {
  11392. | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >7, ZREG_TMP1
  11393. }
  11394. }
  11395. | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
  11396. }
  11397. if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
  11398. prop_info = zend_get_known_property_info(op_array, trace_ce, Z_STR_P(member), on_this, op_array->filename);
  11399. if (prop_info) {
  11400. ce = trace_ce;
  11401. ce_is_instanceof = 0;
  11402. if (!(op1_info & MAY_BE_CLASS_GUARD)) {
  11403. if (on_this && JIT_G(current_frame)
  11404. && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
  11405. ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
  11406. } else if (zend_jit_class_guard(Dst, opline, ce)) {
  11407. if (on_this && JIT_G(current_frame)) {
  11408. JIT_G(current_frame)->ce = ce;
  11409. TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
  11410. }
  11411. } else {
  11412. return 0;
  11413. }
  11414. if (ssa->var_info && ssa_op->op1_use >= 0) {
  11415. ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
  11416. ssa->var_info[ssa_op->op1_use].ce = ce;
  11417. ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
  11418. }
  11419. }
  11420. }
  11421. }
  11422. if (!prop_info) {
  11423. | ldr REG0, EX->run_time_cache
  11424. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG2, REG0, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS), TMP1
  11425. | ldr TMP1, [FCARG1x, #offsetof(zend_object, ce)]
  11426. | cmp REG2, TMP1
  11427. | bne >5
  11428. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, ((opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)), TMP1
  11429. may_be_dynamic = zend_may_be_dynamic_property(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename);
  11430. if (may_be_dynamic) {
  11431. | tst REG0, REG0
  11432. if (opline->opcode == ZEND_FETCH_OBJ_W) {
  11433. | blt >5
  11434. } else {
  11435. | blt >8 // dynamic property
  11436. }
  11437. }
  11438. | add TMP1, FCARG1x, REG0
  11439. | ldr REG2w, [TMP1, #offsetof(zval,u1.type_info)]
  11440. | IF_UNDEF REG2w, >5
  11441. | mov FCARG1x, TMP1
  11442. type_loaded = 1;
  11443. prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  11444. if (opline->opcode == ZEND_FETCH_OBJ_W
  11445. && (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS))) {
  11446. uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
  11447. | ldr REG0, EX->run_time_cache
  11448. | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, ((opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2), TMP1
  11449. | cbnz FCARG2x, >1
  11450. |.cold_code
  11451. |1:
  11452. | ldr TMP1w, [FCARG2x, #offsetof(zend_property_info, flags)]
  11453. | tst TMP1w, #ZEND_ACC_READONLY
  11454. if (flags) {
  11455. | beq >3
  11456. } else {
  11457. | beq >4
  11458. }
  11459. | IF_NOT_TYPE REG2w, IS_OBJECT_EX, >2
  11460. | GET_Z_PTR REG2, FCARG1x
  11461. | GC_ADDREF REG2, TMP1w
  11462. | SET_ZVAL_PTR res_addr, REG2, TMP1
  11463. | SET_ZVAL_TYPE_INFO res_addr, IS_OBJECT_EX, TMP1w, TMP2
  11464. | b >9
  11465. |2:
  11466. | mov FCARG1x, FCARG2x
  11467. | SET_EX_OPLINE opline, REG0
  11468. | EXT_CALL zend_readonly_property_modification_error, REG0
  11469. | SET_ZVAL_TYPE_INFO res_addr, _IS_ERROR, TMP1w, TMP2
  11470. | b >9
  11471. |3:
  11472. if (flags == ZEND_FETCH_DIM_WRITE) {
  11473. | SET_EX_OPLINE opline, REG0
  11474. | EXT_CALL zend_jit_check_array_promotion, REG0
  11475. | b >9
  11476. } else if (flags == ZEND_FETCH_REF) {
  11477. | LOAD_ZVAL_ADDR CARG3, res_addr
  11478. | EXT_CALL zend_jit_create_typed_ref, REG0
  11479. | b >9
  11480. } else {
  11481. ZEND_ASSERT(flags == 0);
  11482. }
  11483. |.code
  11484. |4:
  11485. }
  11486. } else {
  11487. prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, prop_info->offset);
  11488. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  11489. if (opline->opcode == ZEND_FETCH_OBJ_W || !(res_info & MAY_BE_GUARD) || !JIT_G(current_frame)) {
  11490. /* perform IS_UNDEF check only after result type guard (during deoptimization) */
  11491. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  11492. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  11493. if (!exit_addr) {
  11494. return 0;
  11495. }
  11496. type_loaded = 1;
  11497. | MEM_ACCESS_32_WITH_UOFFSET ldr, REG2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.type_info)), TMP1
  11498. | IF_UNDEF REG2w, &exit_addr
  11499. }
  11500. } else {
  11501. type_loaded = 1;
  11502. | MEM_ACCESS_32_WITH_UOFFSET ldr, REG2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.type_info)), TMP1
  11503. | IF_UNDEF REG2w, >5
  11504. }
  11505. if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_READONLY)) {
  11506. if (!type_loaded) {
  11507. type_loaded = 1;
  11508. | MEM_ACCESS_32_WITH_UOFFSET ldr, REG2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.type_info)), TMP1
  11509. }
  11510. | IF_NOT_TYPE REG2w, IS_OBJECT_EX, >4
  11511. | GET_ZVAL_PTR REG2, prop_addr, TMP1
  11512. | GC_ADDREF REG2, TMP1w
  11513. | SET_ZVAL_PTR res_addr, REG2, TMP1
  11514. | SET_ZVAL_TYPE_INFO res_addr, IS_OBJECT_EX, TMP1w, TMP2
  11515. | b >9
  11516. |.cold_code
  11517. |4:
  11518. | LOAD_ADDR FCARG1x, prop_info
  11519. | SET_EX_OPLINE opline, REG0
  11520. | EXT_CALL zend_readonly_property_modification_error, REG0
  11521. | SET_ZVAL_TYPE_INFO res_addr, _IS_ERROR, TMP1w, TMP2
  11522. | b >9
  11523. |.code
  11524. }
  11525. if (opline->opcode == ZEND_FETCH_OBJ_W
  11526. && (opline->extended_value & ZEND_FETCH_OBJ_FLAGS)
  11527. && ZEND_TYPE_IS_SET(prop_info->type)) {
  11528. uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
  11529. if (flags == ZEND_FETCH_DIM_WRITE) {
  11530. if ((ZEND_TYPE_FULL_MASK(prop_info->type) & (MAY_BE_ITERABLE|MAY_BE_ARRAY)) == 0) {
  11531. if (!type_loaded) {
  11532. type_loaded = 1;
  11533. | MEM_ACCESS_32_WITH_UOFFSET ldr, REG2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.type_info)), TMP1
  11534. }
  11535. | cmp REG2w, #IS_FALSE
  11536. | ble >1
  11537. |.cold_code
  11538. |1:
  11539. if (Z_REG(prop_addr) != ZREG_FCARG1 || Z_OFFSET(prop_addr) != 0) {
  11540. | LOAD_ZVAL_ADDR FCARG1x, prop_addr
  11541. }
  11542. | LOAD_ADDR FCARG2x, prop_info
  11543. | SET_EX_OPLINE opline, REG0
  11544. | EXT_CALL zend_jit_check_array_promotion, REG0
  11545. | b >9
  11546. |.code
  11547. }
  11548. } else if (flags == ZEND_FETCH_REF) {
  11549. if (!type_loaded) {
  11550. type_loaded = 1;
  11551. | MEM_ACCESS_32_WITH_UOFFSET ldr, REG2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.type_info)), TMP1
  11552. }
  11553. | GET_LOW_8BITS TMP1w, REG2w
  11554. | IF_TYPE TMP1w, IS_REFERENCE, >1
  11555. if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
  11556. | LOAD_ADDR FCARG2x, prop_info
  11557. } else {
  11558. int prop_info_offset =
  11559. (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
  11560. | ldr REG0, [FCARG1x, #offsetof(zend_object, ce)]
  11561. | ldr REG0, [REG0, #offsetof(zend_class_entry, properties_info_table)]
  11562. | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, prop_info_offset, TMP1
  11563. }
  11564. if (Z_REG(prop_addr) != ZREG_FCARG1 || Z_OFFSET(prop_addr) != 0) {
  11565. | LOAD_ZVAL_ADDR FCARG1x, prop_addr
  11566. }
  11567. | LOAD_ZVAL_ADDR CARG3, res_addr
  11568. | EXT_CALL zend_jit_create_typed_ref, REG0
  11569. | b >9
  11570. |1:
  11571. } else {
  11572. ZEND_UNREACHABLE();
  11573. }
  11574. }
  11575. }
  11576. if (opline->opcode == ZEND_FETCH_OBJ_W) {
  11577. if (Z_REG(prop_addr) != ZREG_FCARG1 || Z_OFFSET(prop_addr) != 0) {
  11578. | LOAD_ZVAL_ADDR FCARG1x, prop_addr
  11579. }
  11580. | SET_ZVAL_PTR res_addr, FCARG1x, TMP1
  11581. | SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT, TMP1w, TMP2
  11582. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_info) {
  11583. ssa->var_info[ssa_op->result_def].indirect_reference = 1;
  11584. }
  11585. } else {
  11586. bool result_avoid_refcounting = 0;
  11587. if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) {
  11588. uint32_t flags = 0;
  11589. uint32_t old_info;
  11590. zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
  11591. int32_t exit_point;
  11592. const void *exit_addr;
  11593. uint32_t type;
  11594. zend_jit_addr val_addr = prop_addr;
  11595. if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
  11596. && !delayed_fetch_this
  11597. && !op1_avoid_refcounting) {
  11598. flags = ZEND_JIT_EXIT_FREE_OP1;
  11599. }
  11600. if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
  11601. && !(flags & ZEND_JIT_EXIT_FREE_OP1)
  11602. && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
  11603. && (ssa_op+1)->op1_use == ssa_op->result_def
  11604. && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
  11605. result_avoid_refcounting = 1;
  11606. ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
  11607. }
  11608. type = concrete_type(res_info);
  11609. if (prop_type != IS_UNKNOWN
  11610. && prop_type != IS_UNDEF
  11611. && prop_type != IS_REFERENCE
  11612. && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT) {
  11613. exit_point = zend_jit_trace_get_exit_point(opline, 0);
  11614. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  11615. if (!exit_addr) {
  11616. return 0;
  11617. }
  11618. } else {
  11619. val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  11620. | LOAD_ZVAL_ADDR REG0, prop_addr
  11621. if (op1_avoid_refcounting) {
  11622. SET_STACK_REG(JIT_G(current_frame)->stack,
  11623. EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
  11624. }
  11625. old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
  11626. SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
  11627. SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_GPR0);
  11628. exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
  11629. SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
  11630. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  11631. if (!exit_addr) {
  11632. return 0;
  11633. }
  11634. if (!type_loaded) {
  11635. type_loaded = 1;
  11636. | MEM_ACCESS_32_WITH_UOFFSET ldr, REG2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.type_info)), TMP1
  11637. }
  11638. | // ZVAL_DEREF()
  11639. | GET_LOW_8BITS TMP1w, REG2w
  11640. | IF_NOT_TYPE TMP1w, IS_REFERENCE, >1
  11641. | GET_Z_PTR REG0, REG0
  11642. | add REG0, REG0, #offsetof(zend_reference, val)
  11643. | GET_ZVAL_TYPE_INFO REG2w, val_addr, TMP1
  11644. }
  11645. res_info &= ~MAY_BE_GUARD;
  11646. ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
  11647. if (type < IS_STRING) {
  11648. |1:
  11649. if (type_loaded) {
  11650. | IF_NOT_TYPE REG2w, type, &exit_addr
  11651. } else {
  11652. | IF_NOT_ZVAL_TYPE val_addr, type, &exit_addr, ZREG_TMP1
  11653. }
  11654. } else {
  11655. if (!type_loaded) {
  11656. type_loaded = 1;
  11657. | GET_ZVAL_TYPE_INFO REG2w, val_addr, TMP1
  11658. }
  11659. |1:
  11660. | GET_LOW_8BITS TMP1w, REG2w
  11661. | IF_NOT_TYPE TMP1w, type, &exit_addr
  11662. }
  11663. | // ZVAL_COPY
  11664. | ZVAL_COPY_VALUE_V res_addr, -1, val_addr, res_info, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_FPR0
  11665. if (type < IS_STRING) {
  11666. if (Z_REG(res_addr) != ZREG_FP ||
  11667. JIT_G(current_frame) == NULL ||
  11668. STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(res_addr))) != type) {
  11669. | SET_ZVAL_TYPE_INFO res_addr, type, TMP1w, TMP2
  11670. }
  11671. } else {
  11672. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG2w, TMP1
  11673. if (!result_avoid_refcounting) {
  11674. | TRY_ADDREF res_info, REG2w, REG1, TMP1w
  11675. }
  11676. }
  11677. } else {
  11678. if (!zend_jit_zval_copy_deref(Dst, res_addr, prop_addr, ZREG_REG2)) {
  11679. return 0;
  11680. }
  11681. }
  11682. }
  11683. if (op1_avoid_refcounting) {
  11684. SET_STACK_REG(JIT_G(current_frame)->stack,
  11685. EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
  11686. }
  11687. |.cold_code
  11688. if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
  11689. |5:
  11690. | SET_EX_OPLINE opline, REG0
  11691. if (opline->opcode == ZEND_FETCH_OBJ_W) {
  11692. | EXT_CALL zend_jit_fetch_obj_w_slow, REG0
  11693. } else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
  11694. | EXT_CALL zend_jit_fetch_obj_r_slow, REG0
  11695. } else {
  11696. | EXT_CALL zend_jit_fetch_obj_is_slow, REG0
  11697. }
  11698. | b >9
  11699. }
  11700. if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)- MAY_BE_OBJECT)) && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
  11701. |7:
  11702. if (opline->opcode != ZEND_FETCH_OBJ_IS) {
  11703. | SET_EX_OPLINE opline, REG0
  11704. if (opline->opcode != ZEND_FETCH_OBJ_W
  11705. && (op1_info & MAY_BE_UNDEF)) {
  11706. zend_jit_addr orig_op1_addr = OP1_ADDR();
  11707. if (op1_info & MAY_BE_ANY) {
  11708. | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1
  11709. }
  11710. | LOAD_32BIT_VAL FCARG1w, opline->op1.var
  11711. | EXT_CALL zend_jit_undefined_op_helper, REG0
  11712. |1:
  11713. | LOAD_ZVAL_ADDR FCARG1x, orig_op1_addr
  11714. } else if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  11715. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  11716. }
  11717. | LOAD_ADDR FCARG2x, Z_STRVAL_P(member)
  11718. if (opline->opcode == ZEND_FETCH_OBJ_W) {
  11719. | EXT_CALL zend_jit_invalid_property_write, REG0
  11720. | SET_ZVAL_TYPE_INFO res_addr, _IS_ERROR, TMP1w, TMP2
  11721. } else {
  11722. | EXT_CALL zend_jit_invalid_property_read, REG0
  11723. | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2
  11724. }
  11725. | b >9
  11726. } else {
  11727. | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2
  11728. | b >9
  11729. }
  11730. }
  11731. if (!prop_info
  11732. && may_be_dynamic
  11733. && opline->opcode != ZEND_FETCH_OBJ_W) {
  11734. |8:
  11735. | mov FCARG2x, REG0
  11736. | SET_EX_OPLINE opline, REG0
  11737. if (opline->opcode != ZEND_FETCH_OBJ_IS) {
  11738. | EXT_CALL zend_jit_fetch_obj_r_dynamic, REG0
  11739. } else {
  11740. | EXT_CALL zend_jit_fetch_obj_is_dynamic, REG0
  11741. }
  11742. | b >9
  11743. }
  11744. |.code;
  11745. |9: // END
  11746. if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
  11747. if (opline->op1_type == IS_VAR
  11748. && opline->opcode == ZEND_FETCH_OBJ_W
  11749. && (op1_info & MAY_BE_RC1)) {
  11750. zend_jit_addr orig_op1_addr = OP1_ADDR();
  11751. | IF_NOT_ZVAL_REFCOUNTED orig_op1_addr, >1, ZREG_TMP1, ZREG_TMP2
  11752. | GET_ZVAL_PTR FCARG1x, orig_op1_addr, TMP1
  11753. | GC_DELREF FCARG1x, TMP1w
  11754. | bne >1
  11755. | SET_EX_OPLINE opline, REG0
  11756. | EXT_CALL zend_jit_extract_helper, REG0
  11757. |1:
  11758. } else if (!op1_avoid_refcounting) {
  11759. if (on_this) {
  11760. op1_info &= ~MAY_BE_RC1;
  11761. }
  11762. | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  11763. }
  11764. }
  11765. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
  11766. && prop_info
  11767. && (opline->opcode != ZEND_FETCH_OBJ_W ||
  11768. !(opline->extended_value & ZEND_FETCH_OBJ_FLAGS) ||
  11769. !ZEND_TYPE_IS_SET(prop_info->type))
  11770. && (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || on_this || op1_indirect)) {
  11771. may_throw = 0;
  11772. }
  11773. if (may_throw) {
  11774. if (!zend_jit_check_exception(Dst)) {
  11775. return 0;
  11776. }
  11777. }
  11778. return 1;
  11779. }
  11780. static int zend_jit_incdec_obj(dasm_State **Dst,
  11781. const zend_op *opline,
  11782. const zend_op_array *op_array,
  11783. zend_ssa *ssa,
  11784. const zend_ssa_op *ssa_op,
  11785. uint32_t op1_info,
  11786. zend_jit_addr op1_addr,
  11787. bool op1_indirect,
  11788. zend_class_entry *ce,
  11789. bool ce_is_instanceof,
  11790. bool on_this,
  11791. bool delayed_fetch_this,
  11792. zend_class_entry *trace_ce,
  11793. uint8_t prop_type)
  11794. {
  11795. zval *member;
  11796. zend_string *name;
  11797. zend_property_info *prop_info;
  11798. zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
  11799. zend_jit_addr res_addr = 0;
  11800. zend_jit_addr prop_addr;
  11801. bool needs_slow_path = 0;
  11802. bool use_prop_guard = 0;
  11803. bool may_throw = 0;
  11804. uint32_t res_info = (opline->result_type != IS_UNDEF) ? RES_INFO() : 0;
  11805. ZEND_ASSERT(opline->op2_type == IS_CONST);
  11806. ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
  11807. if (opline->result_type != IS_UNUSED) {
  11808. res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  11809. }
  11810. member = RT_CONSTANT(opline, opline->op2);
  11811. ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
  11812. name = Z_STR_P(member);
  11813. prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
  11814. if (on_this) {
  11815. | GET_ZVAL_PTR FCARG1x, this_addr, TMP1
  11816. } else {
  11817. if (opline->op1_type == IS_VAR
  11818. && (op1_info & MAY_BE_INDIRECT)
  11819. && Z_REG(op1_addr) == ZREG_FP) {
  11820. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  11821. | IF_NOT_Z_TYPE FCARG1x, IS_INDIRECT, >1, TMP1w
  11822. | GET_Z_PTR FCARG1x, FCARG1x
  11823. |1:
  11824. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  11825. }
  11826. if (op1_info & MAY_BE_REF) {
  11827. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  11828. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  11829. }
  11830. | ZVAL_DEREF FCARG1x, op1_info, TMP1w
  11831. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  11832. }
  11833. if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
  11834. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  11835. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  11836. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  11837. if (!exit_addr) {
  11838. return 0;
  11839. }
  11840. | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr, ZREG_TMP1
  11841. } else {
  11842. | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1, ZREG_TMP1
  11843. |.cold_code
  11844. |1:
  11845. | SET_EX_OPLINE opline, REG0
  11846. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  11847. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  11848. }
  11849. | LOAD_ADDR FCARG2x, ZSTR_VAL(name)
  11850. | EXT_CALL zend_jit_invalid_property_incdec, REG0
  11851. | b ->exception_handler
  11852. |.code
  11853. }
  11854. }
  11855. | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
  11856. }
  11857. if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
  11858. prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
  11859. if (prop_info) {
  11860. ce = trace_ce;
  11861. ce_is_instanceof = 0;
  11862. if (!(op1_info & MAY_BE_CLASS_GUARD)) {
  11863. if (on_this && JIT_G(current_frame)
  11864. && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
  11865. ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
  11866. } else if (zend_jit_class_guard(Dst, opline, ce)) {
  11867. if (on_this && JIT_G(current_frame)) {
  11868. JIT_G(current_frame)->ce = ce;
  11869. TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
  11870. }
  11871. } else {
  11872. return 0;
  11873. }
  11874. if (ssa->var_info && ssa_op->op1_use >= 0) {
  11875. ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
  11876. ssa->var_info[ssa_op->op1_use].ce = ce;
  11877. ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
  11878. }
  11879. if (ssa->var_info && ssa_op->op1_def >= 0) {
  11880. ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
  11881. ssa->var_info[ssa_op->op1_def].ce = ce;
  11882. ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
  11883. }
  11884. }
  11885. }
  11886. }
  11887. use_prop_guard = (prop_type != IS_UNKNOWN
  11888. && prop_type != IS_UNDEF
  11889. && prop_type != IS_REFERENCE
  11890. && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
  11891. if (!prop_info) {
  11892. needs_slow_path = 1;
  11893. | ldr REG0, EX->run_time_cache
  11894. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG2, REG0, opline->extended_value, TMP1
  11895. | ldr TMP1, [FCARG1x, #offsetof(zend_object, ce)]
  11896. | cmp REG2, TMP1
  11897. | bne >7
  11898. if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
  11899. | MEM_ACCESS_64_WITH_UOFFSET ldr, TMP1, REG0, (opline->extended_value + sizeof(void*) * 2), TMP1
  11900. | cbnz TMP1, >7
  11901. }
  11902. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, (opline->extended_value + sizeof(void*)), TMP1
  11903. | tst REG0, REG0
  11904. | blt >7
  11905. | add TMP1, FCARG1x, REG0
  11906. if (!use_prop_guard) {
  11907. | ldrb TMP2w, [TMP1, #offsetof(zval,u1.v.type)]
  11908. | IF_TYPE TMP2w , IS_UNDEF, >7
  11909. }
  11910. | mov FCARG1x, TMP1
  11911. prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  11912. } else {
  11913. prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, prop_info->offset);
  11914. if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
  11915. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  11916. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  11917. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  11918. if (!exit_addr) {
  11919. return 0;
  11920. }
  11921. | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.v.type)), TMP1
  11922. | IF_TYPE TMP2w, IS_UNDEF, &exit_addr
  11923. } else {
  11924. | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.v.type)), TMP1
  11925. | IF_TYPE TMP2w, IS_UNDEF, >7
  11926. needs_slow_path = 1;
  11927. }
  11928. }
  11929. if (ZEND_TYPE_IS_SET(prop_info->type)) {
  11930. may_throw = 1;
  11931. | SET_EX_OPLINE opline, REG0
  11932. if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
  11933. | LOAD_ADDR FCARG2x, prop_info
  11934. } else {
  11935. int prop_info_offset =
  11936. (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
  11937. | ldr REG0, [FCARG1x, #offsetof(zend_object, ce)]
  11938. | ldr REG0, [REG0, #offsetof(zend_class_entry, properties_info_table)]
  11939. | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, prop_info_offset, TMP1
  11940. }
  11941. | LOAD_ZVAL_ADDR FCARG1x, prop_addr
  11942. if (opline->result_type == IS_UNUSED) {
  11943. switch (opline->opcode) {
  11944. case ZEND_PRE_INC_OBJ:
  11945. case ZEND_POST_INC_OBJ:
  11946. | EXT_CALL zend_jit_inc_typed_prop, REG0
  11947. break;
  11948. case ZEND_PRE_DEC_OBJ:
  11949. case ZEND_POST_DEC_OBJ:
  11950. | EXT_CALL zend_jit_dec_typed_prop, REG0
  11951. break;
  11952. default:
  11953. ZEND_UNREACHABLE();
  11954. }
  11955. } else {
  11956. | LOAD_ZVAL_ADDR CARG3, res_addr
  11957. switch (opline->opcode) {
  11958. case ZEND_PRE_INC_OBJ:
  11959. | EXT_CALL zend_jit_pre_inc_typed_prop, REG0
  11960. break;
  11961. case ZEND_PRE_DEC_OBJ:
  11962. | EXT_CALL zend_jit_pre_dec_typed_prop, REG0
  11963. break;
  11964. case ZEND_POST_INC_OBJ:
  11965. | EXT_CALL zend_jit_post_inc_typed_prop, REG0
  11966. break;
  11967. case ZEND_POST_DEC_OBJ:
  11968. | EXT_CALL zend_jit_post_dec_typed_prop, REG0
  11969. break;
  11970. default:
  11971. ZEND_UNREACHABLE();
  11972. }
  11973. }
  11974. }
  11975. }
  11976. if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
  11977. uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
  11978. zend_jit_addr var_addr = prop_addr;
  11979. if (use_prop_guard) {
  11980. int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
  11981. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  11982. if (!exit_addr) {
  11983. return 0;
  11984. }
  11985. | IF_NOT_ZVAL_TYPE var_addr, prop_type, &exit_addr, ZREG_TMP1
  11986. var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
  11987. }
  11988. if (var_info & MAY_BE_REF) {
  11989. may_throw = 1;
  11990. var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  11991. if (Z_REG(prop_addr) != ZREG_FCARG1 || Z_OFFSET(prop_addr) != 0) {
  11992. | LOAD_ZVAL_ADDR FCARG1x, prop_addr
  11993. }
  11994. | IF_NOT_ZVAL_TYPE var_addr, IS_REFERENCE, >2, ZREG_TMP1
  11995. | GET_ZVAL_PTR FCARG1x, var_addr, TMP1
  11996. | ldr TMP1, [FCARG1x, #offsetof(zend_reference, sources.ptr)]
  11997. | cbnz TMP1, >1
  11998. | add FCARG1x, FCARG1x, #offsetof(zend_reference, val)
  11999. |.cold_code
  12000. |1:
  12001. if (opline) {
  12002. | SET_EX_OPLINE opline, REG0
  12003. }
  12004. if (opline->result_type == IS_UNUSED) {
  12005. | mov FCARG2x, xzr
  12006. } else {
  12007. | LOAD_ZVAL_ADDR FCARG2x, res_addr
  12008. }
  12009. switch (opline->opcode) {
  12010. case ZEND_PRE_INC_OBJ:
  12011. | EXT_CALL zend_jit_pre_inc_typed_ref, REG0
  12012. break;
  12013. case ZEND_PRE_DEC_OBJ:
  12014. | EXT_CALL zend_jit_pre_dec_typed_ref, REG0
  12015. break;
  12016. case ZEND_POST_INC_OBJ:
  12017. | EXT_CALL zend_jit_post_inc_typed_ref, REG0
  12018. break;
  12019. case ZEND_POST_DEC_OBJ:
  12020. | EXT_CALL zend_jit_post_dec_typed_ref, REG0
  12021. break;
  12022. default:
  12023. ZEND_UNREACHABLE();
  12024. }
  12025. | b >9
  12026. |.code
  12027. |2:
  12028. }
  12029. if (var_info & MAY_BE_LONG) {
  12030. if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
  12031. | IF_NOT_ZVAL_TYPE var_addr, IS_LONG, >2, ZREG_TMP1
  12032. }
  12033. if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
  12034. if (opline->result_type != IS_UNUSED) {
  12035. | ZVAL_COPY_VALUE res_addr, -1, var_addr, MAY_BE_LONG, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  12036. }
  12037. }
  12038. if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
  12039. | LONG_ADD_SUB_WITH_IMM adds, var_addr, Z_L(1), TMP1, TMP2
  12040. } else {
  12041. | LONG_ADD_SUB_WITH_IMM subs, var_addr, Z_L(1), TMP1, TMP2
  12042. }
  12043. | bvs >3
  12044. if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
  12045. if (opline->result_type != IS_UNUSED) {
  12046. | ZVAL_COPY_VALUE res_addr, -1, var_addr, MAY_BE_LONG, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  12047. }
  12048. }
  12049. |.cold_code
  12050. }
  12051. if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
  12052. if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
  12053. may_throw = 1;
  12054. }
  12055. if (var_info & MAY_BE_LONG) {
  12056. |2:
  12057. }
  12058. if (Z_REG(var_addr) != ZREG_FCARG1 || Z_OFFSET(var_addr) != 0) {
  12059. var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  12060. | LOAD_ZVAL_ADDR FCARG1x, prop_addr
  12061. }
  12062. if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
  12063. | ZVAL_COPY_VALUE res_addr, -1, var_addr, MAY_BE_ANY, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  12064. | TRY_ADDREF MAY_BE_ANY, REG0w, REG2, TMP1w
  12065. }
  12066. if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
  12067. if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
  12068. | LOAD_ZVAL_ADDR FCARG2x, res_addr
  12069. | EXT_CALL zend_jit_pre_inc, REG0
  12070. } else {
  12071. | EXT_CALL increment_function, REG0
  12072. }
  12073. } else {
  12074. if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
  12075. | LOAD_ZVAL_ADDR FCARG2x, res_addr
  12076. | EXT_CALL zend_jit_pre_dec, REG0
  12077. } else {
  12078. | EXT_CALL decrement_function, REG0
  12079. }
  12080. }
  12081. if (var_info & MAY_BE_LONG) {
  12082. | b >4
  12083. }
  12084. }
  12085. if (var_info & MAY_BE_LONG) {
  12086. |3:
  12087. if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
  12088. uint64_t val = 0x43e0000000000000;
  12089. | LOAD_64BIT_VAL TMP2, val
  12090. | SET_ZVAL_LVAL_FROM_REG var_addr, TMP2, TMP1
  12091. | SET_ZVAL_TYPE_INFO var_addr, IS_DOUBLE, TMP1w, TMP2
  12092. if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
  12093. | SET_ZVAL_LVAL_FROM_REG res_addr, TMP2, TMP1
  12094. | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, TMP1w, TMP2
  12095. }
  12096. } else {
  12097. uint64_t val = 0xc3e0000000000000;
  12098. | LOAD_64BIT_VAL TMP2, val
  12099. | SET_ZVAL_LVAL_FROM_REG var_addr, TMP2, TMP1
  12100. | SET_ZVAL_TYPE_INFO var_addr, IS_DOUBLE, TMP1w, TMP2
  12101. if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
  12102. | SET_ZVAL_LVAL_FROM_REG res_addr, TMP2, TMP1
  12103. | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, TMP1w, TMP2
  12104. }
  12105. }
  12106. if (opline->result_type != IS_UNUSED
  12107. && (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ)
  12108. && prop_info
  12109. && !ZEND_TYPE_IS_SET(prop_info->type)
  12110. && (res_info & MAY_BE_GUARD)
  12111. && (res_info & MAY_BE_LONG)) {
  12112. zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
  12113. uint32_t old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
  12114. int32_t exit_point;
  12115. const void *exit_addr;
  12116. SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
  12117. exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
  12118. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  12119. if (!exit_addr) {
  12120. return 0;
  12121. }
  12122. SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
  12123. ssa->var_info[ssa_op->result_def].type = res_info & ~MAY_BE_GUARD;
  12124. | b &exit_addr
  12125. |.code
  12126. } else {
  12127. | b >4
  12128. |.code
  12129. |4:
  12130. }
  12131. }
  12132. }
  12133. if (needs_slow_path) {
  12134. may_throw = 1;
  12135. |.cold_code
  12136. |7:
  12137. | SET_EX_OPLINE opline, REG0
  12138. | // value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
  12139. | LOAD_ADDR FCARG2x, name
  12140. | ldr CARG3, EX->run_time_cache
  12141. | ADD_SUB_64_WITH_CONST_32 add, CARG3, CARG3, opline->extended_value, TMP1
  12142. if (opline->result_type == IS_UNUSED) {
  12143. | mov CARG4, xzr
  12144. } else {
  12145. | LOAD_ZVAL_ADDR CARG4, res_addr
  12146. }
  12147. switch (opline->opcode) {
  12148. case ZEND_PRE_INC_OBJ:
  12149. | EXT_CALL zend_jit_pre_inc_obj_helper, REG0
  12150. break;
  12151. case ZEND_PRE_DEC_OBJ:
  12152. | EXT_CALL zend_jit_pre_dec_obj_helper, REG0
  12153. break;
  12154. case ZEND_POST_INC_OBJ:
  12155. | EXT_CALL zend_jit_post_inc_obj_helper, REG0
  12156. break;
  12157. case ZEND_POST_DEC_OBJ:
  12158. | EXT_CALL zend_jit_post_dec_obj_helper, REG0
  12159. break;
  12160. default:
  12161. ZEND_UNREACHABLE();
  12162. }
  12163. | b >9
  12164. |.code
  12165. }
  12166. |9:
  12167. if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
  12168. if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
  12169. may_throw = 1;
  12170. }
  12171. | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  12172. }
  12173. if (may_throw) {
  12174. if (!zend_jit_check_exception(Dst)) {
  12175. return 0;
  12176. }
  12177. }
  12178. return 1;
  12179. }
  12180. static int zend_jit_assign_obj_op(dasm_State **Dst,
  12181. const zend_op *opline,
  12182. const zend_op_array *op_array,
  12183. zend_ssa *ssa,
  12184. const zend_ssa_op *ssa_op,
  12185. uint32_t op1_info,
  12186. zend_jit_addr op1_addr,
  12187. uint32_t val_info,
  12188. zend_ssa_range *val_range,
  12189. bool op1_indirect,
  12190. zend_class_entry *ce,
  12191. bool ce_is_instanceof,
  12192. bool on_this,
  12193. bool delayed_fetch_this,
  12194. zend_class_entry *trace_ce,
  12195. uint8_t prop_type)
  12196. {
  12197. zval *member;
  12198. zend_string *name;
  12199. zend_property_info *prop_info;
  12200. zend_jit_addr val_addr = OP1_DATA_ADDR();
  12201. zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
  12202. zend_jit_addr prop_addr;
  12203. bool needs_slow_path = 0;
  12204. bool use_prop_guard = 0;
  12205. bool may_throw = 0;
  12206. binary_op_type binary_op = get_binary_op(opline->extended_value);
  12207. ZEND_ASSERT(opline->op2_type == IS_CONST);
  12208. ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
  12209. ZEND_ASSERT(opline->result_type == IS_UNUSED);
  12210. member = RT_CONSTANT(opline, opline->op2);
  12211. ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
  12212. name = Z_STR_P(member);
  12213. prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
  12214. if (on_this) {
  12215. | GET_ZVAL_PTR FCARG1x, this_addr, TMP1
  12216. } else {
  12217. if (opline->op1_type == IS_VAR
  12218. && (op1_info & MAY_BE_INDIRECT)
  12219. && Z_REG(op1_addr) == ZREG_FP) {
  12220. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  12221. | IF_NOT_Z_TYPE FCARG1x, IS_INDIRECT, >1, TMP1w
  12222. | GET_Z_PTR FCARG1x, FCARG1x
  12223. |1:
  12224. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  12225. }
  12226. if (op1_info & MAY_BE_REF) {
  12227. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  12228. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  12229. }
  12230. | ZVAL_DEREF FCARG1x, op1_info, TMP1w
  12231. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  12232. }
  12233. if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
  12234. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  12235. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  12236. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  12237. if (!exit_addr) {
  12238. return 0;
  12239. }
  12240. | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr, ZREG_TMP1
  12241. } else {
  12242. | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1, ZREG_TMP1
  12243. |.cold_code
  12244. |1:
  12245. | SET_EX_OPLINE opline, REG0
  12246. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  12247. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  12248. }
  12249. | LOAD_ADDR FCARG2x, ZSTR_VAL(name)
  12250. if (op1_info & MAY_BE_UNDEF) {
  12251. | EXT_CALL zend_jit_invalid_property_assign_op, REG0
  12252. } else {
  12253. | EXT_CALL zend_jit_invalid_property_assign, REG0
  12254. }
  12255. may_throw = 1;
  12256. if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
  12257. && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  12258. | b >8
  12259. } else {
  12260. | b >9
  12261. }
  12262. |.code
  12263. }
  12264. }
  12265. | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
  12266. }
  12267. if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
  12268. prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
  12269. if (prop_info) {
  12270. ce = trace_ce;
  12271. ce_is_instanceof = 0;
  12272. if (!(op1_info & MAY_BE_CLASS_GUARD)) {
  12273. if (on_this && JIT_G(current_frame)
  12274. && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
  12275. ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
  12276. } else if (zend_jit_class_guard(Dst, opline, ce)) {
  12277. if (on_this && JIT_G(current_frame)) {
  12278. JIT_G(current_frame)->ce = ce;
  12279. TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
  12280. }
  12281. } else {
  12282. return 0;
  12283. }
  12284. if (ssa->var_info && ssa_op->op1_use >= 0) {
  12285. ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
  12286. ssa->var_info[ssa_op->op1_use].ce = ce;
  12287. ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
  12288. }
  12289. if (ssa->var_info && ssa_op->op1_def >= 0) {
  12290. ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
  12291. ssa->var_info[ssa_op->op1_def].ce = ce;
  12292. ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
  12293. }
  12294. }
  12295. }
  12296. }
  12297. use_prop_guard = (prop_type != IS_UNKNOWN
  12298. && prop_type != IS_UNDEF
  12299. && prop_type != IS_REFERENCE
  12300. && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
  12301. if (!prop_info) {
  12302. needs_slow_path = 1;
  12303. | ldr REG0, EX->run_time_cache
  12304. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG2, REG0, ((opline+1)->extended_value), TMP1
  12305. | ldr TMP2, [FCARG1x, #offsetof(zend_object, ce)]
  12306. | cmp REG2, TMP2
  12307. | bne >7
  12308. if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
  12309. | MEM_ACCESS_64_WITH_UOFFSET ldr, TMP1, REG0, ((opline+1)->extended_value + sizeof(void*) * 2), TMP1
  12310. | cbnz TMP1, >7
  12311. }
  12312. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, ((opline+1)->extended_value + sizeof(void*)), TMP1
  12313. | tst REG0, REG0
  12314. | blt >7
  12315. | add TMP1, FCARG1x, REG0
  12316. if (!use_prop_guard) {
  12317. | ldrb TMP2w, [TMP1, #offsetof(zval,u1.v.type)]
  12318. | IF_TYPE TMP2w, IS_UNDEF, >7
  12319. }
  12320. | mov FCARG1x, TMP1
  12321. prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  12322. } else {
  12323. prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, prop_info->offset);
  12324. if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
  12325. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  12326. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  12327. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  12328. if (!exit_addr) {
  12329. return 0;
  12330. }
  12331. | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.v.type)), TMP1
  12332. | IF_TYPE TMP2w, IS_UNDEF, &exit_addr
  12333. } else {
  12334. | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.v.type)), TMP1
  12335. | IF_TYPE TMP2w, IS_UNDEF, >7
  12336. needs_slow_path = 1;
  12337. }
  12338. }
  12339. if (ZEND_TYPE_IS_SET(prop_info->type)) {
  12340. uint32_t info = val_info;
  12341. may_throw = 1;
  12342. if (opline) {
  12343. | SET_EX_OPLINE opline, REG0
  12344. }
  12345. | IF_ZVAL_TYPE prop_addr, IS_REFERENCE, >1, ZREG_TMP1
  12346. |.cold_code
  12347. |1:
  12348. | GET_ZVAL_PTR FCARG1x, prop_addr, TMP1
  12349. if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2 || Z_OFFSET(val_addr) != 0) {
  12350. | LOAD_ZVAL_ADDR FCARG2x, val_addr
  12351. }
  12352. | LOAD_ADDR CARG3, binary_op
  12353. if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
  12354. && (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  12355. | EXT_CALL zend_jit_assign_op_to_typed_ref_tmp, REG0
  12356. } else {
  12357. | EXT_CALL zend_jit_assign_op_to_typed_ref, REG0
  12358. }
  12359. | b >9
  12360. |.code
  12361. | // value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
  12362. if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
  12363. | LOAD_ADDR FCARG2x, prop_info
  12364. } else {
  12365. int prop_info_offset =
  12366. (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
  12367. | ldr REG0, [FCARG1x, #offsetof(zend_object, ce)]
  12368. | ldr REG0, [REG0, #offsetof(zend_class_entry, properties_info_table)]
  12369. | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, prop_info_offset, TMP1
  12370. }
  12371. | LOAD_ZVAL_ADDR FCARG1x, prop_addr
  12372. | LOAD_ZVAL_ADDR CARG3, val_addr
  12373. | LOAD_ADDR CARG4, binary_op
  12374. | EXT_CALL zend_jit_assign_op_to_typed_prop, REG0
  12375. if (info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
  12376. info |= MAY_BE_RC1|MAY_BE_RCN;
  12377. }
  12378. | FREE_OP (opline+1)->op1_type, (opline+1)->op1, info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  12379. }
  12380. }
  12381. if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
  12382. zend_jit_addr var_addr = prop_addr;
  12383. uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
  12384. uint32_t var_def_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
  12385. if (use_prop_guard) {
  12386. int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
  12387. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  12388. if (!exit_addr) {
  12389. return 0;
  12390. }
  12391. | IF_NOT_ZVAL_TYPE var_addr, prop_type, &exit_addr, ZREG_TMP1
  12392. var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
  12393. }
  12394. if (var_info & MAY_BE_REF) {
  12395. may_throw = 1;
  12396. var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  12397. | LOAD_ZVAL_ADDR REG0, prop_addr
  12398. | IF_NOT_ZVAL_TYPE var_addr, IS_REFERENCE, >2, ZREG_TMP1
  12399. | GET_ZVAL_PTR FCARG1x, var_addr, TMP1
  12400. | ldr TMP1, [FCARG1x, #offsetof(zend_reference, sources.ptr)]
  12401. | cbnz TMP1, >1
  12402. | add REG0, FCARG1x, #offsetof(zend_reference, val)
  12403. |.cold_code
  12404. |1:
  12405. if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2 || Z_OFFSET(val_addr) != 0) {
  12406. | LOAD_ZVAL_ADDR FCARG2x, val_addr
  12407. }
  12408. if (opline) {
  12409. | SET_EX_OPLINE opline, REG0
  12410. }
  12411. | LOAD_ADDR CARG3, binary_op
  12412. if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR))
  12413. && (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  12414. | EXT_CALL zend_jit_assign_op_to_typed_ref_tmp, REG0
  12415. } else {
  12416. | EXT_CALL zend_jit_assign_op_to_typed_ref, REG0
  12417. }
  12418. | b >9
  12419. |.code
  12420. |2:
  12421. }
  12422. switch (opline->extended_value) {
  12423. case ZEND_ADD:
  12424. case ZEND_SUB:
  12425. case ZEND_MUL:
  12426. if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
  12427. (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  12428. if (opline->extended_value != ZEND_ADD ||
  12429. (var_info & MAY_BE_ANY) != MAY_BE_ARRAY ||
  12430. (val_info & MAY_BE_ANY) == MAY_BE_ARRAY) {
  12431. may_throw = 1;
  12432. }
  12433. }
  12434. if (!zend_jit_math_helper(Dst, opline, opline->extended_value, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, val_addr, val_info, 0, var_addr, var_def_info, var_info,
  12435. 1 /* may overflow */, 0)) {
  12436. return 0;
  12437. }
  12438. break;
  12439. case ZEND_BW_OR:
  12440. case ZEND_BW_AND:
  12441. case ZEND_BW_XOR:
  12442. may_throw = 1;
  12443. if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
  12444. (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  12445. if ((var_info & MAY_BE_ANY) != MAY_BE_STRING ||
  12446. (val_info & MAY_BE_ANY) != MAY_BE_STRING) {
  12447. may_throw = 1;
  12448. }
  12449. }
  12450. goto long_math;
  12451. case ZEND_SL:
  12452. case ZEND_SR:
  12453. if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
  12454. (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  12455. may_throw = 1;
  12456. }
  12457. if ((opline+1)->op1_type != IS_CONST ||
  12458. Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
  12459. Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) < 0) {
  12460. may_throw = 1;
  12461. }
  12462. goto long_math;
  12463. case ZEND_MOD:
  12464. if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
  12465. (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  12466. if (opline->extended_value != ZEND_ADD ||
  12467. (var_info & MAY_BE_ANY) != MAY_BE_ARRAY ||
  12468. (val_info & MAY_BE_ANY) == MAY_BE_ARRAY) {
  12469. may_throw = 1;
  12470. }
  12471. }
  12472. if ((opline+1)->op1_type != IS_CONST ||
  12473. Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
  12474. Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) == 0) {
  12475. may_throw = 1;
  12476. }
  12477. long_math:
  12478. if (!zend_jit_long_math_helper(Dst, opline, opline->extended_value,
  12479. IS_CV, opline->op1, var_addr, var_info, NULL,
  12480. (opline+1)->op1_type, (opline+1)->op1, val_addr, val_info,
  12481. val_range,
  12482. 0, var_addr, var_def_info, var_info, 0)) {
  12483. return 0;
  12484. }
  12485. break;
  12486. case ZEND_CONCAT:
  12487. may_throw = 1;
  12488. if (!zend_jit_concat_helper(Dst, opline, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, val_addr, val_info, var_addr,
  12489. 0)) {
  12490. return 0;
  12491. }
  12492. break;
  12493. default:
  12494. ZEND_UNREACHABLE();
  12495. }
  12496. }
  12497. if (needs_slow_path) {
  12498. may_throw = 1;
  12499. |.cold_code
  12500. |7:
  12501. | SET_EX_OPLINE opline, REG0
  12502. | // value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
  12503. | LOAD_ADDR FCARG2x, name
  12504. | LOAD_ZVAL_ADDR CARG3, val_addr
  12505. | ldr CARG4, EX->run_time_cache
  12506. | ADD_SUB_64_WITH_CONST_32 add, CARG4, CARG4, (opline+1)->extended_value, TMP1
  12507. | LOAD_ADDR CARG5, binary_op
  12508. | EXT_CALL zend_jit_assign_obj_op_helper, REG0
  12509. if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
  12510. val_info |= MAY_BE_RC1|MAY_BE_RCN;
  12511. }
  12512. |8:
  12513. | // FREE_OP_DATA();
  12514. | FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  12515. | b >9
  12516. |.code
  12517. }
  12518. |9:
  12519. if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
  12520. if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
  12521. may_throw = 1;
  12522. }
  12523. | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  12524. }
  12525. if (may_throw) {
  12526. if (!zend_jit_check_exception(Dst)) {
  12527. return 0;
  12528. }
  12529. }
  12530. return 1;
  12531. }
  12532. static int zend_jit_assign_obj(dasm_State **Dst,
  12533. const zend_op *opline,
  12534. const zend_op_array *op_array,
  12535. zend_ssa *ssa,
  12536. const zend_ssa_op *ssa_op,
  12537. uint32_t op1_info,
  12538. zend_jit_addr op1_addr,
  12539. uint32_t val_info,
  12540. bool op1_indirect,
  12541. zend_class_entry *ce,
  12542. bool ce_is_instanceof,
  12543. bool on_this,
  12544. bool delayed_fetch_this,
  12545. zend_class_entry *trace_ce,
  12546. uint8_t prop_type,
  12547. int may_throw)
  12548. {
  12549. zval *member;
  12550. zend_string *name;
  12551. zend_property_info *prop_info;
  12552. zend_jit_addr val_addr = OP1_DATA_ADDR();
  12553. zend_jit_addr res_addr = 0;
  12554. zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
  12555. zend_jit_addr prop_addr;
  12556. bool needs_slow_path = 0;
  12557. bool needs_val_dtor = 0;
  12558. if (RETURN_VALUE_USED(opline)) {
  12559. res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  12560. }
  12561. ZEND_ASSERT(opline->op2_type == IS_CONST);
  12562. ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
  12563. member = RT_CONSTANT(opline, opline->op2);
  12564. ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
  12565. name = Z_STR_P(member);
  12566. prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
  12567. if (on_this) {
  12568. | GET_ZVAL_PTR FCARG1x, this_addr, TMP1
  12569. } else {
  12570. if (opline->op1_type == IS_VAR
  12571. && (op1_info & MAY_BE_INDIRECT)
  12572. && Z_REG(op1_addr) == ZREG_FP) {
  12573. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  12574. | IF_NOT_Z_TYPE FCARG1x, IS_INDIRECT, >1, TMP1w
  12575. | GET_Z_PTR FCARG1x, FCARG1x
  12576. |1:
  12577. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  12578. }
  12579. if (op1_info & MAY_BE_REF) {
  12580. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  12581. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  12582. }
  12583. | ZVAL_DEREF FCARG1x, op1_info, TMP1w
  12584. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  12585. }
  12586. if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
  12587. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  12588. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  12589. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  12590. if (!exit_addr) {
  12591. return 0;
  12592. }
  12593. | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr, ZREG_TMP1
  12594. } else {
  12595. | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1, ZREG_TMP1
  12596. |.cold_code
  12597. |1:
  12598. | SET_EX_OPLINE opline, REG0
  12599. if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  12600. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  12601. }
  12602. | LOAD_ADDR FCARG2x, ZSTR_VAL(name)
  12603. | EXT_CALL zend_jit_invalid_property_assign, REG0
  12604. if (RETURN_VALUE_USED(opline)) {
  12605. | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2
  12606. }
  12607. if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
  12608. && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  12609. needs_val_dtor = 1;
  12610. | b >7
  12611. } else {
  12612. | b >9
  12613. }
  12614. |.code
  12615. }
  12616. }
  12617. | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
  12618. }
  12619. if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
  12620. prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
  12621. if (prop_info) {
  12622. ce = trace_ce;
  12623. ce_is_instanceof = 0;
  12624. if (!(op1_info & MAY_BE_CLASS_GUARD)) {
  12625. if (on_this && JIT_G(current_frame)
  12626. && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
  12627. ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
  12628. } else if (zend_jit_class_guard(Dst, opline, ce)) {
  12629. if (on_this && JIT_G(current_frame)) {
  12630. JIT_G(current_frame)->ce = ce;
  12631. TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
  12632. }
  12633. } else {
  12634. return 0;
  12635. }
  12636. if (ssa->var_info && ssa_op->op1_use >= 0) {
  12637. ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
  12638. ssa->var_info[ssa_op->op1_use].ce = ce;
  12639. ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
  12640. }
  12641. if (ssa->var_info && ssa_op->op1_def >= 0) {
  12642. ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
  12643. ssa->var_info[ssa_op->op1_def].ce = ce;
  12644. ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
  12645. }
  12646. }
  12647. }
  12648. }
  12649. if (!prop_info) {
  12650. needs_slow_path = 1;
  12651. | ldr REG0, EX->run_time_cache
  12652. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG2, REG0, opline->extended_value, TMP1
  12653. | ldr TMP1, [FCARG1x, #offsetof(zend_object, ce)]
  12654. | cmp REG2, TMP1
  12655. | bne >5
  12656. if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
  12657. | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, (opline->extended_value + sizeof(void*) * 2), TMP1
  12658. }
  12659. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, (opline->extended_value + sizeof(void*)), TMP1
  12660. | tst REG0, REG0
  12661. | blt >5
  12662. | add TMP2, FCARG1x, REG0
  12663. | ldrb TMP1w, [TMP2, #offsetof(zval,u1.v.type)]
  12664. | IF_TYPE TMP1w, IS_UNDEF, >5
  12665. | mov FCARG1x, TMP2
  12666. prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  12667. if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
  12668. | cbnz FCARG2x, >1
  12669. |.cold_code
  12670. |1:
  12671. | // value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
  12672. | SET_EX_OPLINE opline, REG0
  12673. | LOAD_ZVAL_ADDR CARG3, val_addr
  12674. if (RETURN_VALUE_USED(opline)) {
  12675. | LOAD_ZVAL_ADDR CARG4, res_addr
  12676. } else {
  12677. | mov CARG4, xzr
  12678. }
  12679. | EXT_CALL zend_jit_assign_to_typed_prop, REG0
  12680. if ((opline+1)->op1_type == IS_CONST) {
  12681. | // TODO: ???
  12682. | // if (Z_TYPE_P(value) == orig_type) {
  12683. | // CACHE_PTR_EX(cache_slot + 2, NULL);
  12684. }
  12685. if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
  12686. && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
  12687. | b >7
  12688. } else {
  12689. | b >9
  12690. }
  12691. |.code
  12692. }
  12693. } else {
  12694. prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, prop_info->offset);
  12695. if (!ce || ce_is_instanceof || !(ce->ce_flags & ZEND_ACC_IMMUTABLE) || ce->__get || ce->__set || (prop_info->flags & ZEND_ACC_READONLY)) {
  12696. // Undefined property with magic __get()/__set()
  12697. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  12698. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  12699. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  12700. if (!exit_addr) {
  12701. return 0;
  12702. }
  12703. | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.v.type)), TMP1
  12704. | IF_TYPE TMP2w, IS_UNDEF, &exit_addr
  12705. } else {
  12706. | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.v.type)), TMP1
  12707. | IF_TYPE TMP2w, IS_UNDEF, >5
  12708. needs_slow_path = 1;
  12709. }
  12710. }
  12711. if (ZEND_TYPE_IS_SET(prop_info->type)) {
  12712. uint32_t info = val_info;
  12713. | // value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
  12714. | SET_EX_OPLINE opline, REG0
  12715. if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
  12716. | LOAD_ADDR FCARG2x, prop_info
  12717. } else {
  12718. int prop_info_offset =
  12719. (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
  12720. | ldr REG0, [FCARG1x, #offsetof(zend_object, ce)]
  12721. | ldr REG0, [REG0, #offsetof(zend_class_entry, properties_info_table)]
  12722. | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, prop_info_offset, TMP1
  12723. }
  12724. | LOAD_ZVAL_ADDR FCARG1x, prop_addr
  12725. | LOAD_ZVAL_ADDR CARG3, val_addr
  12726. if (RETURN_VALUE_USED(opline)) {
  12727. | LOAD_ZVAL_ADDR CARG4, res_addr
  12728. } else {
  12729. | mov CARG4, xzr
  12730. }
  12731. | EXT_CALL zend_jit_assign_to_typed_prop, REG0
  12732. if (info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
  12733. info |= MAY_BE_RC1|MAY_BE_RCN;
  12734. }
  12735. | FREE_OP (opline+1)->op1_type, (opline+1)->op1, info, 0, NULL, ZREG_TMP1, ZREG_TMP2
  12736. }
  12737. }
  12738. if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
  12739. // value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES());
  12740. if (opline->result_type == IS_UNUSED) {
  12741. if (!zend_jit_assign_to_variable_call(Dst, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0)) {
  12742. return 0;
  12743. }
  12744. } else {
  12745. if (!zend_jit_assign_to_variable(Dst, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0)) {
  12746. return 0;
  12747. }
  12748. }
  12749. }
  12750. if (needs_slow_path) {
  12751. |.cold_code
  12752. |5:
  12753. | SET_EX_OPLINE opline, REG0
  12754. | // value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
  12755. | LOAD_ADDR FCARG2x, name
  12756. | LOAD_ZVAL_ADDR CARG3, val_addr
  12757. | ldr CARG4, EX->run_time_cache
  12758. | ADD_SUB_64_WITH_CONST_32 add, CARG4, CARG4, opline->extended_value, TMP1
  12759. if (RETURN_VALUE_USED(opline)) {
  12760. | LOAD_ZVAL_ADDR CARG5, res_addr
  12761. } else {
  12762. | mov CARG5, xzr
  12763. }
  12764. | EXT_CALL zend_jit_assign_obj_helper, REG0
  12765. if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
  12766. val_info |= MAY_BE_RC1|MAY_BE_RCN;
  12767. }
  12768. |7:
  12769. | // FREE_OP_DATA();
  12770. | FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  12771. | b >9
  12772. |.code
  12773. } else if (needs_val_dtor) {
  12774. |.cold_code
  12775. |7:
  12776. | // FREE_OP_DATA();
  12777. | FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  12778. | b >9
  12779. |.code
  12780. }
  12781. |9:
  12782. if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
  12783. | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2
  12784. }
  12785. if (may_throw) {
  12786. if (!zend_jit_check_exception(Dst)) {
  12787. return 0;
  12788. }
  12789. }
  12790. return 1;
  12791. }
  12792. static int zend_jit_free(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, int may_throw)
  12793. {
  12794. zend_jit_addr op1_addr = OP1_ADDR();
  12795. if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
  12796. if (may_throw) {
  12797. | SET_EX_OPLINE opline, REG0
  12798. }
  12799. if (opline->opcode == ZEND_FE_FREE && (op1_info & (MAY_BE_OBJECT|MAY_BE_REF))) {
  12800. if (op1_info & MAY_BE_ARRAY) {
  12801. | IF_ZVAL_TYPE op1_addr, IS_ARRAY, >7, ZREG_TMP1
  12802. }
  12803. | MEM_ACCESS_32_WITH_UOFFSET ldr, FCARG1w, FP, (opline->op1.var + offsetof(zval, u2.fe_iter_idx)), TMP1
  12804. | mvn TMP1w, wzr // TODO: DynAsm fails loading #-1
  12805. | cmp FCARG1w, TMP1w
  12806. | beq >7
  12807. | EXT_CALL zend_hash_iterator_del, REG0
  12808. |7:
  12809. }
  12810. | ZVAL_PTR_DTOR op1_addr, op1_info, 0, 0, opline, ZREG_TMP1, ZREG_TMP2
  12811. if (may_throw) {
  12812. if (!zend_jit_check_exception(Dst)) {
  12813. return 0;
  12814. }
  12815. }
  12816. }
  12817. return 1;
  12818. }
  12819. static int zend_jit_echo(dasm_State **Dst, const zend_op *opline, uint32_t op1_info)
  12820. {
  12821. if (opline->op1_type == IS_CONST) {
  12822. zval *zv;
  12823. size_t len;
  12824. zv = RT_CONSTANT(opline, opline->op1);
  12825. ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
  12826. len = Z_STRLEN_P(zv);
  12827. if (len > 0) {
  12828. const char *str = Z_STRVAL_P(zv);
  12829. | SET_EX_OPLINE opline, REG0
  12830. | LOAD_ADDR CARG1, str
  12831. | LOAD_64BIT_VAL CARG2, len
  12832. | EXT_CALL zend_write, REG0
  12833. if (!zend_jit_check_exception(Dst)) {
  12834. return 0;
  12835. }
  12836. }
  12837. } else {
  12838. zend_jit_addr op1_addr = OP1_ADDR();
  12839. ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
  12840. | SET_EX_OPLINE opline, REG0
  12841. | GET_ZVAL_PTR REG0, op1_addr, TMP1
  12842. | add CARG1, REG0, #offsetof(zend_string, val)
  12843. | ldr CARG2, [REG0, #offsetof(zend_string, len)]
  12844. | EXT_CALL zend_write, REG0
  12845. if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
  12846. | ZVAL_PTR_DTOR op1_addr, op1_info, 0, 0, opline, ZREG_TMP1, ZREG_TMP2
  12847. }
  12848. if (!zend_jit_check_exception(Dst)) {
  12849. return 0;
  12850. }
  12851. }
  12852. return 1;
  12853. }
  12854. static int zend_jit_strlen(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr)
  12855. {
  12856. if (opline->op1_type == IS_CONST) {
  12857. zval *zv;
  12858. size_t len;
  12859. zv = RT_CONSTANT(opline, opline->op1);
  12860. ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
  12861. len = Z_STRLEN_P(zv);
  12862. | SET_ZVAL_LVAL res_addr, len, TMP1, TMP2
  12863. if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
  12864. | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
  12865. } else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) {
  12866. return 0;
  12867. }
  12868. } else {
  12869. ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
  12870. if (Z_MODE(res_addr) == IS_REG) {
  12871. | GET_ZVAL_PTR Rx(Z_REG(res_addr)), op1_addr, TMP1
  12872. | ldr Rx(Z_REG(res_addr)), [Rx(Z_REG(res_addr)), #offsetof(zend_string, len)]
  12873. if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) {
  12874. return 0;
  12875. }
  12876. } else {
  12877. | GET_ZVAL_PTR REG0, op1_addr, TMP1
  12878. | ldr REG0, [REG0, #offsetof(zend_string, len)]
  12879. | SET_ZVAL_LVAL_FROM_REG res_addr, REG0, TMP1
  12880. | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
  12881. }
  12882. | FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  12883. }
  12884. return 1;
  12885. }
  12886. static int zend_jit_count(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, int may_throw)
  12887. {
  12888. if (opline->op1_type == IS_CONST) {
  12889. zval *zv;
  12890. zend_long count;
  12891. zv = RT_CONSTANT(opline, opline->op1);
  12892. ZEND_ASSERT(Z_TYPE_P(zv) == IS_ARRAY);
  12893. count = zend_hash_num_elements(Z_ARRVAL_P(zv));
  12894. | SET_ZVAL_LVAL res_addr, count, TMP1, TMP2
  12895. if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
  12896. | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
  12897. } else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) {
  12898. return 0;
  12899. }
  12900. } else {
  12901. ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY);
  12902. // Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+.
  12903. if (Z_MODE(res_addr) == IS_REG) {
  12904. | GET_ZVAL_PTR Rx(Z_REG(res_addr)), op1_addr, TMP1
  12905. // Sign-extend the 32-bit value to a potentially 64-bit zend_long
  12906. | ldr Rw(Z_REG(res_addr)), [Rx(Z_REG(res_addr)), #offsetof(HashTable, nNumOfElements)]
  12907. if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) {
  12908. return 0;
  12909. }
  12910. } else {
  12911. | GET_ZVAL_PTR REG0, op1_addr, TMP1
  12912. // Sign-extend the 32-bit value to a potentially 64-bit zend_long
  12913. | ldr REG0w, [REG0, #offsetof(HashTable, nNumOfElements)]
  12914. | SET_ZVAL_LVAL_FROM_REG res_addr, REG0, TMP1
  12915. | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
  12916. }
  12917. | FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2
  12918. }
  12919. if (may_throw) {
  12920. return zend_jit_check_exception(Dst);
  12921. }
  12922. return 1;
  12923. }
  12924. static int zend_jit_load_this(dasm_State **Dst, uint32_t var)
  12925. {
  12926. zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
  12927. | ldr FCARG1x, EX->This.value.ptr
  12928. | SET_ZVAL_PTR var_addr, FCARG1x, TMP1
  12929. | SET_ZVAL_TYPE_INFO var_addr, IS_OBJECT_EX, TMP1w, TMP2
  12930. | GC_ADDREF FCARG1x, TMP1w
  12931. return 1;
  12932. }
  12933. static int zend_jit_fetch_this(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, bool check_only)
  12934. {
  12935. if (!op_array->scope || (op_array->fn_flags & ZEND_ACC_STATIC)) {
  12936. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  12937. if (!JIT_G(current_frame) ||
  12938. !TRACE_FRAME_IS_THIS_CHECKED(JIT_G(current_frame))) {
  12939. int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
  12940. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  12941. if (!exit_addr) {
  12942. return 0;
  12943. }
  12944. | ldrb TMP1w, EX->This.u1.v.type
  12945. | cmp TMP1w, #IS_OBJECT
  12946. | bne &exit_addr
  12947. if (JIT_G(current_frame)) {
  12948. TRACE_FRAME_SET_THIS_CHECKED(JIT_G(current_frame));
  12949. }
  12950. }
  12951. } else {
  12952. | ldrb TMP1w, EX->This.u1.v.type
  12953. | cmp TMP1w, #IS_OBJECT
  12954. | bne >1
  12955. |.cold_code
  12956. |1:
  12957. | SET_EX_OPLINE opline, REG0
  12958. | b ->invalid_this
  12959. |.code
  12960. }
  12961. }
  12962. if (!check_only) {
  12963. if (!zend_jit_load_this(Dst, opline->result.var)) {
  12964. return 0;
  12965. }
  12966. }
  12967. return 1;
  12968. }
  12969. static int zend_jit_hash_jmp(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, HashTable *jumptable, int default_b, const void *default_label, const zend_op *next_opline, zend_jit_trace_info *trace_info)
  12970. {
  12971. uint32_t count;
  12972. Bucket *p;
  12973. const zend_op *target;
  12974. int b;
  12975. int32_t exit_point;
  12976. const void *exit_addr;
  12977. if (default_label) {
  12978. | cbz REG0, &default_label
  12979. } else if (next_opline) {
  12980. | cbz REG0, >3
  12981. } else {
  12982. | cbz REG0, =>default_b
  12983. }
  12984. | LOAD_ADDR FCARG1x, jumptable
  12985. | ldr TMP1, [FCARG1x, #offsetof(HashTable, arData)]
  12986. | sub REG0, REG0, TMP1
  12987. | mov FCARG1x, #(sizeof(Bucket) / sizeof(void*))
  12988. | sdiv REG0, REG0, FCARG1x
  12989. | adr FCARG1x, >4
  12990. | ldr TMP1, [FCARG1x, REG0]
  12991. | br TMP1
  12992. |.jmp_table
  12993. |.align 8
  12994. |4:
  12995. if (trace_info) {
  12996. trace_info->jmp_table_size += zend_hash_num_elements(jumptable);
  12997. }
  12998. count = jumptable->nNumUsed;
  12999. p = jumptable->arData;
  13000. do {
  13001. if (Z_TYPE(p->val) == IS_UNDEF) {
  13002. if (default_label) {
  13003. | .addr &default_label
  13004. } else if (next_opline) {
  13005. | .addr >3
  13006. } else {
  13007. | .addr =>default_b
  13008. }
  13009. } else {
  13010. target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL(p->val));
  13011. if (!next_opline) {
  13012. b = ssa->cfg.map[target - op_array->opcodes];
  13013. | .addr =>b
  13014. } else if (next_opline == target) {
  13015. | .addr >3
  13016. } else {
  13017. exit_point = zend_jit_trace_get_exit_point(target, 0);
  13018. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  13019. if (!exit_addr) {
  13020. return 0;
  13021. }
  13022. | .addr &exit_addr
  13023. }
  13024. }
  13025. p++;
  13026. count--;
  13027. } while (count);
  13028. |.code
  13029. return 1;
  13030. }
  13031. static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, zend_jit_trace_rec *trace, zend_jit_trace_info *trace_info)
  13032. {
  13033. HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
  13034. const zend_op *next_opline = NULL;
  13035. if (trace) {
  13036. ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
  13037. ZEND_ASSERT(trace->opline != NULL);
  13038. next_opline = trace->opline;
  13039. }
  13040. if (opline->op1_type == IS_CONST) {
  13041. zval *zv = RT_CONSTANT(opline, opline->op1);
  13042. zval *jump_zv = NULL;
  13043. int b;
  13044. if (opline->opcode == ZEND_SWITCH_LONG) {
  13045. if (Z_TYPE_P(zv) == IS_LONG) {
  13046. jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
  13047. }
  13048. } else if (opline->opcode == ZEND_SWITCH_STRING) {
  13049. if (Z_TYPE_P(zv) == IS_STRING) {
  13050. jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
  13051. }
  13052. } else if (opline->opcode == ZEND_MATCH) {
  13053. if (Z_TYPE_P(zv) == IS_LONG) {
  13054. jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
  13055. } else if (Z_TYPE_P(zv) == IS_STRING) {
  13056. jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
  13057. }
  13058. } else {
  13059. ZEND_UNREACHABLE();
  13060. }
  13061. if (next_opline) {
  13062. const zend_op *target;
  13063. if (jump_zv != NULL) {
  13064. target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv));
  13065. } else {
  13066. target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
  13067. }
  13068. ZEND_ASSERT(target == next_opline);
  13069. } else {
  13070. if (jump_zv != NULL) {
  13071. b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
  13072. } else {
  13073. b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
  13074. }
  13075. | b =>b
  13076. }
  13077. } else {
  13078. zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
  13079. uint32_t op1_info = OP1_INFO();
  13080. zend_jit_addr op1_addr = OP1_ADDR();
  13081. const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
  13082. const zend_op *target;
  13083. int default_b = next_opline ? -1 : ssa->cfg.map[default_opline - op_array->opcodes];
  13084. int b;
  13085. int32_t exit_point;
  13086. const void *fallback_label = NULL;
  13087. const void *default_label = NULL;
  13088. const void *exit_addr;
  13089. if (next_opline) {
  13090. if (next_opline != opline + 1) {
  13091. exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
  13092. fallback_label = zend_jit_trace_get_exit_addr(exit_point);
  13093. if (!fallback_label) {
  13094. return 0;
  13095. }
  13096. }
  13097. if (next_opline != default_opline) {
  13098. exit_point = zend_jit_trace_get_exit_point(default_opline, 0);
  13099. default_label = zend_jit_trace_get_exit_addr(exit_point);
  13100. if (!default_label) {
  13101. return 0;
  13102. }
  13103. }
  13104. }
  13105. if (opline->opcode == ZEND_SWITCH_LONG) {
  13106. if (op1_info & MAY_BE_LONG) {
  13107. if (op1_info & MAY_BE_REF) {
  13108. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >1, ZREG_TMP1
  13109. | GET_ZVAL_LVAL ZREG_FCARG2, op1_addr, TMP1
  13110. |.cold_code
  13111. |1:
  13112. | // ZVAL_DEREF(op)
  13113. if (fallback_label) {
  13114. | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, &fallback_label, ZREG_TMP1
  13115. } else {
  13116. | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >3, ZREG_TMP1
  13117. }
  13118. | GET_ZVAL_PTR FCARG2x, op1_addr, TMP1
  13119. if (fallback_label) {
  13120. | add TMP1, FCARG2x, #offsetof(zend_reference, val)
  13121. | IF_NOT_Z_TYPE TMP1, IS_LONG, &fallback_label, TMP2w
  13122. } else {
  13123. | add TMP1, FCARG2x, #offsetof(zend_reference, val)
  13124. | IF_NOT_Z_TYPE TMP1, IS_LONG, >3, TMP2w
  13125. }
  13126. | ldr FCARG2x, [FCARG2x, #offsetof(zend_reference, val.value.lval)]
  13127. | b >2
  13128. |.code
  13129. |2:
  13130. } else {
  13131. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
  13132. if (fallback_label) {
  13133. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, &fallback_label, ZREG_TMP1
  13134. } else {
  13135. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3, ZREG_TMP1
  13136. }
  13137. }
  13138. | GET_ZVAL_LVAL ZREG_FCARG2, op1_addr, TMP1
  13139. }
  13140. if (HT_IS_PACKED(jumptable)) {
  13141. uint32_t count = jumptable->nNumUsed;
  13142. Bucket *p = jumptable->arData;
  13143. | CMP_64_WITH_CONST_32 FCARG2x, jumptable->nNumUsed, TMP1
  13144. if (default_label) {
  13145. | bhs &default_label
  13146. } else if (next_opline) {
  13147. | bhs >3
  13148. } else {
  13149. | bhs =>default_b
  13150. }
  13151. | adr REG0, >4
  13152. | ldr TMP1, [REG0, FCARG2x, lsl #3]
  13153. | br TMP1
  13154. |.jmp_table
  13155. |.align 8
  13156. |4:
  13157. if (trace_info) {
  13158. trace_info->jmp_table_size += count;
  13159. }
  13160. p = jumptable->arData;
  13161. do {
  13162. if (Z_TYPE(p->val) == IS_UNDEF) {
  13163. if (default_label) {
  13164. | .addr &default_label
  13165. } else if (next_opline) {
  13166. | .addr >3
  13167. } else {
  13168. | .addr =>default_b
  13169. }
  13170. } else {
  13171. target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL(p->val));
  13172. if (!next_opline) {
  13173. b = ssa->cfg.map[target - op_array->opcodes];
  13174. | .addr =>b
  13175. } else if (next_opline == target) {
  13176. | .addr >3
  13177. } else {
  13178. exit_point = zend_jit_trace_get_exit_point(target, 0);
  13179. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  13180. if (!exit_addr) {
  13181. return 0;
  13182. }
  13183. | .addr &exit_addr
  13184. }
  13185. }
  13186. p++;
  13187. count--;
  13188. } while (count);
  13189. |.code
  13190. |3:
  13191. } else {
  13192. | LOAD_ADDR FCARG1x, jumptable
  13193. | EXT_CALL zend_hash_index_find, REG0
  13194. | mov REG0, RETVALx
  13195. if (!zend_jit_hash_jmp(Dst, opline, op_array, ssa, jumptable, default_b, default_label, next_opline, trace_info)) {
  13196. return 0;
  13197. }
  13198. |3:
  13199. }
  13200. }
  13201. } else if (opline->opcode == ZEND_SWITCH_STRING) {
  13202. if (op1_info & MAY_BE_STRING) {
  13203. if (op1_info & MAY_BE_REF) {
  13204. | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >1, ZREG_TMP1
  13205. | GET_ZVAL_PTR FCARG2x, op1_addr, TMP1
  13206. |.cold_code
  13207. |1:
  13208. | // ZVAL_DEREF(op)
  13209. if (fallback_label) {
  13210. | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, &fallback_label, ZREG_TMP1
  13211. } else {
  13212. | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >3, ZREG_TMP1
  13213. }
  13214. | GET_ZVAL_PTR FCARG2x, op1_addr, TMP1
  13215. if (fallback_label) {
  13216. | add TMP1, FCARG2x, #offsetof(zend_reference, val)
  13217. | IF_NOT_Z_TYPE TMP1, IS_STRING, &fallback_label, TMP2w
  13218. } else {
  13219. | add TMP1, FCARG2x, #offsetof(zend_reference, val)
  13220. | IF_NOT_Z_TYPE TMP1, IS_STRING, >3, TMP2w
  13221. }
  13222. | ldr FCARG2x, [FCARG2x, #offsetof(zend_reference, val.value.ptr)]
  13223. | b >2
  13224. |.code
  13225. |2:
  13226. } else {
  13227. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_STRING)) {
  13228. if (fallback_label) {
  13229. | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, &fallback_label, ZREG_TMP1
  13230. } else {
  13231. | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >3, ZREG_TMP1
  13232. }
  13233. }
  13234. | GET_ZVAL_PTR FCARG2x, op1_addr, TMP1
  13235. }
  13236. | LOAD_ADDR FCARG1x, jumptable
  13237. | EXT_CALL zend_hash_find, REG0
  13238. | mov REG0, RETVALx
  13239. if (!zend_jit_hash_jmp(Dst, opline, op_array, ssa, jumptable, default_b, default_label, next_opline, trace_info)) {
  13240. return 0;
  13241. }
  13242. |3:
  13243. }
  13244. } else if (opline->opcode == ZEND_MATCH) {
  13245. if (op1_info & (MAY_BE_LONG|MAY_BE_STRING)) {
  13246. if (op1_info & MAY_BE_REF) {
  13247. | LOAD_ZVAL_ADDR FCARG2x, op1_addr
  13248. | ZVAL_DEREF FCARG2x, op1_info, TMP1w
  13249. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0);
  13250. }
  13251. | LOAD_ADDR FCARG1x, jumptable
  13252. if (op1_info & MAY_BE_LONG) {
  13253. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
  13254. if (op1_info & MAY_BE_STRING) {
  13255. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >5, ZREG_TMP1
  13256. } else if (op1_info & MAY_BE_UNDEF) {
  13257. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6, ZREG_TMP1
  13258. } else if (default_label) {
  13259. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, &default_label, ZREG_TMP1
  13260. } else if (next_opline) {
  13261. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3, ZREG_TMP1
  13262. } else {
  13263. | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, =>default_b, ZREG_TMP1
  13264. }
  13265. }
  13266. | GET_ZVAL_LVAL ZREG_FCARG2, op1_addr, TMP1
  13267. | EXT_CALL zend_hash_index_find, REG0
  13268. | mov REG0, RETVALx
  13269. if (op1_info & MAY_BE_STRING) {
  13270. | b >2
  13271. }
  13272. }
  13273. if (op1_info & MAY_BE_STRING) {
  13274. |5:
  13275. if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_STRING))) {
  13276. if (op1_info & MAY_BE_UNDEF) {
  13277. | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >6, ZREG_TMP1
  13278. } else if (default_label) {
  13279. | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, &default_label, ZREG_TMP1
  13280. } else if (next_opline) {
  13281. | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >3, ZREG_TMP1
  13282. } else {
  13283. | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, =>default_b, ZREG_TMP1
  13284. }
  13285. }
  13286. | GET_ZVAL_PTR FCARG2x, op1_addr, TMP1
  13287. | EXT_CALL zend_hash_find, REG0
  13288. | mov REG0, RETVALx
  13289. }
  13290. |2:
  13291. if (!zend_jit_hash_jmp(Dst, opline, op_array, ssa, jumptable, default_b, default_label, next_opline, trace_info)) {
  13292. return 0;
  13293. }
  13294. }
  13295. if (op1_info & MAY_BE_UNDEF) {
  13296. |6:
  13297. if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_STRING))) {
  13298. if (default_label) {
  13299. | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, &default_label, ZREG_TMP1
  13300. } else if (next_opline) {
  13301. | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >3, ZREG_TMP1
  13302. } else {
  13303. | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, =>default_b, ZREG_TMP1
  13304. }
  13305. }
  13306. | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
  13307. | SET_EX_OPLINE opline, REG0
  13308. | LOAD_32BIT_VAL FCARG1w, opline->op1.var
  13309. | EXT_CALL zend_jit_undefined_op_helper, REG0
  13310. if (!zend_jit_check_exception_undef_result(Dst, opline)) {
  13311. return 0;
  13312. }
  13313. }
  13314. if (default_label) {
  13315. | b &default_label
  13316. } else if (next_opline) {
  13317. | b >3
  13318. } else {
  13319. | b =>default_b
  13320. }
  13321. |3:
  13322. } else {
  13323. ZEND_UNREACHABLE();
  13324. }
  13325. }
  13326. return 1;
  13327. }
  13328. static bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info)
  13329. {
  13330. zend_arg_info *arg_info = &op_array->arg_info[-1];
  13331. ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
  13332. zend_jit_addr op1_addr = OP1_ADDR();
  13333. bool needs_slow_check = 1;
  13334. bool slow_check_in_cold = 1;
  13335. uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
  13336. if (type_mask == 0) {
  13337. slow_check_in_cold = 0;
  13338. } else {
  13339. if (((op1_info & MAY_BE_ANY) & type_mask) == 0) {
  13340. slow_check_in_cold = 0;
  13341. } else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) {
  13342. needs_slow_check = 0;
  13343. } else if (is_power_of_two(type_mask)) {
  13344. uint32_t type_code = concrete_type(type_mask);
  13345. | IF_NOT_ZVAL_TYPE op1_addr, type_code, >6, ZREG_TMP1
  13346. } else {
  13347. | mov REG2w, #1
  13348. | GET_ZVAL_TYPE REG1w, op1_addr, TMP1
  13349. | lsl REG2w, REG2w, REG1w
  13350. | TST_32_WITH_CONST REG2w, type_mask, TMP1w
  13351. | beq >6
  13352. }
  13353. }
  13354. if (needs_slow_check) {
  13355. if (slow_check_in_cold) {
  13356. |.cold_code
  13357. |6:
  13358. }
  13359. | SET_EX_OPLINE opline, REG1
  13360. if (op1_info & MAY_BE_UNDEF) {
  13361. | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >7, ZREG_TMP1
  13362. | LOAD_32BIT_VAL FCARG1x, opline->op1.var
  13363. | EXT_CALL zend_jit_undefined_op_helper, REG0
  13364. | cbz RETVALx, ->exception_handler
  13365. | LOAD_ADDR_ZTS FCARG1x, executor_globals, uninitialized_zval
  13366. | b >8
  13367. }
  13368. |7:
  13369. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  13370. |8:
  13371. | ldr FCARG2x, EX->func
  13372. | LOAD_ADDR CARG3, (ptrdiff_t)arg_info
  13373. | ldr REG0, EX->run_time_cache
  13374. | ADD_SUB_64_WITH_CONST_32 add, CARG4, REG0, opline->op2.num, TMP1
  13375. | EXT_CALL zend_jit_verify_return_slow, REG0
  13376. if (!zend_jit_check_exception(Dst)) {
  13377. return 0;
  13378. }
  13379. if (slow_check_in_cold) {
  13380. | b >9
  13381. |.code
  13382. }
  13383. }
  13384. |9:
  13385. return 1;
  13386. }
  13387. static int zend_jit_isset_isempty_cv(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
  13388. {
  13389. zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  13390. // TODO: support for empty() ???
  13391. ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
  13392. if (op1_info & MAY_BE_REF) {
  13393. if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) {
  13394. | LOAD_ZVAL_ADDR FCARG1x, op1_addr
  13395. op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  13396. }
  13397. | ZVAL_DEREF FCARG1x, op1_info, TMP1w
  13398. |1:
  13399. }
  13400. if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
  13401. if (exit_addr) {
  13402. ZEND_ASSERT(smart_branch_opcode == ZEND_JMPZ);
  13403. } else if (smart_branch_opcode) {
  13404. if (smart_branch_opcode == ZEND_JMPNZ) {
  13405. | b =>target_label
  13406. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  13407. | b =>target_label2
  13408. }
  13409. } else {
  13410. | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
  13411. }
  13412. } else if (!(op1_info & (MAY_BE_ANY - MAY_BE_NULL))) {
  13413. if (exit_addr) {
  13414. ZEND_ASSERT(smart_branch_opcode == ZEND_JMPNZ);
  13415. } else if (smart_branch_opcode) {
  13416. if (smart_branch_opcode != ZEND_JMPNZ) {
  13417. | b =>target_label
  13418. }
  13419. } else {
  13420. | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
  13421. }
  13422. } else {
  13423. ZEND_ASSERT(Z_MODE(op1_addr) == IS_MEM_ZVAL);
  13424. | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP1w, Rx(Z_REG(op1_addr)), (Z_OFFSET(op1_addr)+offsetof(zval, u1.v.type)), TMP1
  13425. | cmp TMP1w, #IS_NULL
  13426. if (exit_addr) {
  13427. if (smart_branch_opcode == ZEND_JMPNZ) {
  13428. | bgt &exit_addr
  13429. } else {
  13430. | ble &exit_addr
  13431. }
  13432. } else if (smart_branch_opcode) {
  13433. if (smart_branch_opcode == ZEND_JMPZ) {
  13434. | ble =>target_label
  13435. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  13436. | bgt =>target_label
  13437. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  13438. | ble =>target_label
  13439. | b =>target_label2
  13440. } else {
  13441. ZEND_UNREACHABLE();
  13442. }
  13443. } else {
  13444. | cset REG0w, gt
  13445. | add REG0w, REG0w, #IS_FALSE
  13446. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  13447. }
  13448. }
  13449. return 1;
  13450. }
  13451. static int zend_jit_fe_reset(dasm_State **Dst, const zend_op *opline, uint32_t op1_info)
  13452. {
  13453. zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  13454. if (opline->op1_type == IS_CONST) {
  13455. zval *zv = RT_CONSTANT(opline, opline->op1);
  13456. | ZVAL_COPY_CONST res_addr, MAY_BE_ANY, MAY_BE_ANY, zv, ZREG_REG0, ZREG_TMP1, ZREG_FPR0
  13457. if (Z_REFCOUNTED_P(zv)) {
  13458. | ADDREF_CONST zv, REG0, TMP1
  13459. }
  13460. } else {
  13461. zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
  13462. | // ZVAL_COPY(res, value);
  13463. | ZVAL_COPY_VALUE res_addr, -1, op1_addr, op1_info, ZREG_REG0, ZREG_FCARG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  13464. if (opline->op1_type == IS_CV) {
  13465. | TRY_ADDREF op1_info, REG0w, FCARG1x, TMP1w
  13466. }
  13467. }
  13468. | // Z_FE_POS_P(res) = 0;
  13469. | MEM_ACCESS_32_WITH_UOFFSET str, wzr, FP, (opline->result.var + offsetof(zval, u2.fe_pos)), TMP1
  13470. return 1;
  13471. }
  13472. static int zend_jit_fe_fetch(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, unsigned int target_label, zend_uchar exit_opcode, const void *exit_addr)
  13473. {
  13474. zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
  13475. | // array = EX_VAR(opline->op1.var);
  13476. | // fe_ht = Z_ARRVAL_P(array);
  13477. | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1
  13478. | // pos = Z_FE_POS_P(array);
  13479. | MEM_ACCESS_32_WITH_UOFFSET ldr, REG0w, FP, (opline->op1.var + offsetof(zval, u2.fe_pos)), TMP1
  13480. | // p = fe_ht->arData + pos;
  13481. || ZEND_ASSERT(sizeof(Bucket) == 32);
  13482. | mov FCARG2w, REG0w
  13483. | ldr TMP1, [FCARG1x, #offsetof(zend_array, arData)]
  13484. | add FCARG2x, TMP1, FCARG2x, lsl #5
  13485. |1:
  13486. | // if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
  13487. | ldr TMP1w, [FCARG1x, #offsetof(zend_array, nNumUsed)]
  13488. | cmp TMP1w, REG0w
  13489. | // ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
  13490. | // ZEND_VM_CONTINUE();
  13491. if (exit_addr) {
  13492. if (exit_opcode == ZEND_JMP) {
  13493. | bls &exit_addr
  13494. } else {
  13495. | bls >3
  13496. }
  13497. } else {
  13498. | bls =>target_label
  13499. }
  13500. | // pos++;
  13501. | add REG0w, REG0w, #1
  13502. | // value_type = Z_TYPE_INFO_P(value);
  13503. | // if (EXPECTED(value_type != IS_UNDEF)) {
  13504. if (!exit_addr || exit_opcode == ZEND_JMP) {
  13505. | IF_NOT_Z_TYPE FCARG2x, IS_UNDEF, >3, TMP1w
  13506. } else {
  13507. | IF_NOT_Z_TYPE FCARG2x, IS_UNDEF, &exit_addr, TMP1w
  13508. }
  13509. | // p++;
  13510. | add FCARG2x, FCARG2x, #sizeof(Bucket)
  13511. | b <1
  13512. |3:
  13513. if (!exit_addr || exit_opcode == ZEND_JMP) {
  13514. zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0);
  13515. zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
  13516. uint32_t val_info;
  13517. | // Z_FE_POS_P(array) = pos + 1;
  13518. | MEM_ACCESS_32_WITH_UOFFSET str, REG0w, FP, (opline->op1.var + offsetof(zval, u2.fe_pos)), TMP1
  13519. if (RETURN_VALUE_USED(opline)) {
  13520. zend_jit_addr res_addr = RES_ADDR();
  13521. if ((op1_info & MAY_BE_ARRAY_KEY_LONG)
  13522. && (op1_info & MAY_BE_ARRAY_KEY_STRING)) {
  13523. | // if (!p->key) {
  13524. | ldr REG0, [FCARG2x, #offsetof(Bucket, key)]
  13525. | cbz REG0, >2
  13526. }
  13527. if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
  13528. | // ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
  13529. | ldr REG0, [FCARG2x, #offsetof(Bucket, key)]
  13530. | SET_ZVAL_PTR res_addr, REG0, TMP1
  13531. | ldr TMP1w, [REG0, #offsetof(zend_refcounted, gc.u.type_info)]
  13532. | TST_32_WITH_CONST TMP1w, IS_STR_INTERNED, TMP2w
  13533. | beq >1
  13534. | SET_ZVAL_TYPE_INFO res_addr, IS_STRING, TMP1w, TMP2
  13535. | b >3
  13536. |1:
  13537. | GC_ADDREF REG0, TMP1w
  13538. | SET_ZVAL_TYPE_INFO res_addr, IS_STRING_EX, TMP1w, TMP2
  13539. if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
  13540. | b >3
  13541. |2:
  13542. }
  13543. }
  13544. if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
  13545. | // ZVAL_LONG(EX_VAR(opline->result.var), p->h);
  13546. | ldr REG0, [FCARG2x, #offsetof(Bucket, h)]
  13547. | SET_ZVAL_LVAL_FROM_REG res_addr, REG0, TMP1
  13548. | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
  13549. }
  13550. |3:
  13551. }
  13552. val_info = ((op1_info & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
  13553. if (val_info & MAY_BE_ARRAY) {
  13554. val_info |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
  13555. }
  13556. if (op1_info & MAY_BE_ARRAY_OF_REF) {
  13557. val_info |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY |
  13558. MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
  13559. } else if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
  13560. val_info |= MAY_BE_RC1 | MAY_BE_RCN;
  13561. }
  13562. if (opline->op2_type == IS_CV) {
  13563. | // zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES());
  13564. if (!zend_jit_assign_to_variable(Dst, opline, var_addr, var_addr, op2_info, -1, IS_CV, val_addr, val_info, 0, 1)) {
  13565. return 0;
  13566. }
  13567. } else {
  13568. | // ZVAL_COPY(res, value);
  13569. | ZVAL_COPY_VALUE var_addr, -1, val_addr, val_info, ZREG_REG0, ZREG_FCARG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  13570. | TRY_ADDREF val_info, REG0w, FCARG1x, TMP1w
  13571. }
  13572. }
  13573. return 1;
  13574. }
  13575. static int zend_jit_fetch_constant(dasm_State **Dst,
  13576. const zend_op *opline,
  13577. const zend_op_array *op_array,
  13578. zend_ssa *ssa,
  13579. const zend_ssa_op *ssa_op,
  13580. zend_jit_addr res_addr)
  13581. {
  13582. zval *zv = RT_CONSTANT(opline, opline->op2) + 1;
  13583. zend_jit_addr const_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0);
  13584. uint32_t res_info = RES_INFO();
  13585. | // c = CACHED_PTR(opline->extended_value);
  13586. | ldr FCARG1x, EX->run_time_cache
  13587. | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, FCARG1x, opline->extended_value, TMP1
  13588. | // if (c != NULL)
  13589. | cbz REG0, >9
  13590. if (!zend_jit_is_persistent_constant(zv, opline->op1.num)) {
  13591. | // if (!IS_SPECIAL_CACHE_VAL(c))
  13592. || ZEND_ASSERT(CACHE_SPECIAL == 1);
  13593. | TST_64_WITH_ONE REG0
  13594. | bne >9
  13595. }
  13596. |8:
  13597. if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
  13598. zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
  13599. uint32_t old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
  13600. int32_t exit_point;
  13601. const void *exit_addr = NULL;
  13602. SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
  13603. SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_GPR0);
  13604. exit_point = zend_jit_trace_get_exit_point(opline+1, 0);
  13605. SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
  13606. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  13607. if (!exit_addr) {
  13608. return 0;
  13609. }
  13610. res_info &= ~MAY_BE_GUARD;
  13611. ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
  13612. uint32_t type = concrete_type(res_info);
  13613. if (type < IS_STRING) {
  13614. | IF_NOT_ZVAL_TYPE const_addr, type, &exit_addr, ZREG_TMP1
  13615. } else {
  13616. | GET_ZVAL_TYPE_INFO REG2w, const_addr, TMP1
  13617. | IF_NOT_TYPE REG2w, type, &exit_addr
  13618. }
  13619. | ZVAL_COPY_VALUE_V res_addr, -1, const_addr, res_info, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_FPR0
  13620. if (type < IS_STRING) {
  13621. if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
  13622. | SET_ZVAL_TYPE_INFO res_addr, type, TMP1w, TMP2
  13623. } else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
  13624. return 0;
  13625. }
  13626. } else {
  13627. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG2w, TMP1
  13628. | TRY_ADDREF res_info, REG2w, REG1, TMP1w
  13629. }
  13630. } else {
  13631. | ZVAL_COPY_VALUE res_addr, MAY_BE_ANY, const_addr, MAY_BE_ANY, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0
  13632. | TRY_ADDREF MAY_BE_ANY, REG0w, REG1, TMP1w
  13633. }
  13634. |.cold_code
  13635. |9:
  13636. | // SAVE_OPLINE();
  13637. | SET_EX_OPLINE opline, REG0
  13638. | // zend_quick_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num OPLINE_CC EXECUTE_DATA_CC);
  13639. | LOAD_ADDR FCARG1x, zv
  13640. | LOAD_32BIT_VAL FCARG2w, opline->op1.num
  13641. | EXT_CALL zend_jit_get_constant, REG0
  13642. | mov REG0, RETVALx
  13643. | // ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
  13644. | cbnz REG0, <8
  13645. | b ->exception_handler
  13646. |.code
  13647. return 1;
  13648. }
  13649. static int zend_jit_in_array(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
  13650. {
  13651. HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
  13652. zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
  13653. ZEND_ASSERT(opline->op1_type != IS_VAR && opline->op1_type != IS_TMP_VAR);
  13654. ZEND_ASSERT((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_STRING);
  13655. | // result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST);
  13656. | LOAD_ADDR FCARG1x, ht
  13657. if (opline->op1_type != IS_CONST) {
  13658. | GET_ZVAL_PTR FCARG2x, op1_addr, TMP1
  13659. | EXT_CALL zend_hash_find, REG0
  13660. } else {
  13661. zend_string *str = Z_STR_P(RT_CONSTANT(opline, opline->op1));
  13662. | LOAD_ADDR FCARG2x, str
  13663. | EXT_CALL zend_hash_find_known_hash, REG0
  13664. }
  13665. if (exit_addr) {
  13666. if (smart_branch_opcode == ZEND_JMPZ) {
  13667. | cbz RETVALx, &exit_addr
  13668. } else {
  13669. | cbnz RETVALx, &exit_addr
  13670. }
  13671. } else if (smart_branch_opcode) {
  13672. if (smart_branch_opcode == ZEND_JMPZ) {
  13673. | cbz RETVALx, =>target_label
  13674. } else if (smart_branch_opcode == ZEND_JMPNZ) {
  13675. | cbnz RETVALx, =>target_label
  13676. } else if (smart_branch_opcode == ZEND_JMPZNZ) {
  13677. | cbz RETVALx, =>target_label
  13678. | b =>target_label2
  13679. } else {
  13680. ZEND_UNREACHABLE();
  13681. }
  13682. } else {
  13683. | tst RETVALx, RETVALx
  13684. | cset REG0w, ne
  13685. | add REG0w, REG0w, #IS_FALSE
  13686. | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
  13687. }
  13688. return 1;
  13689. }
  13690. static int zend_jit_rope(dasm_State **Dst, const zend_op *opline, uint32_t op2_info)
  13691. {
  13692. uint32_t offset;
  13693. offset = (opline->opcode == ZEND_ROPE_INIT) ?
  13694. opline->result.var :
  13695. opline->op1.var + opline->extended_value * sizeof(zend_string*);
  13696. if (opline->op2_type == IS_CONST) {
  13697. zval *zv = RT_CONSTANT(opline, opline->op2);
  13698. zend_string *str;
  13699. ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
  13700. str = Z_STR_P(zv);
  13701. | LOAD_ADDR REG0, str
  13702. | MEM_ACCESS_64_WITH_UOFFSET str, REG0, FP, offset, TMP1
  13703. } else {
  13704. zend_jit_addr op2_addr = OP2_ADDR();
  13705. ZEND_ASSERT((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
  13706. | GET_ZVAL_PTR REG1, op2_addr, TMP1
  13707. | MEM_ACCESS_64_WITH_UOFFSET str, REG1, FP, offset, TMP1
  13708. if (opline->op2_type == IS_CV) {
  13709. | GET_ZVAL_TYPE_INFO REG0w, op2_addr, TMP1
  13710. | TRY_ADDREF op2_info, REG0w, REG1, TMP1w
  13711. }
  13712. }
  13713. if (opline->opcode == ZEND_ROPE_END) {
  13714. zend_jit_addr res_addr = RES_ADDR();
  13715. | ADD_SUB_64_WITH_CONST add, FCARG1x, FP, opline->op1.var, TMP1
  13716. | LOAD_32BIT_VAL FCARG2w, opline->extended_value
  13717. | EXT_CALL zend_jit_rope_end, TMP1
  13718. | SET_ZVAL_PTR res_addr, RETVALx, TMP1
  13719. | SET_ZVAL_TYPE_INFO res_addr, IS_STRING_EX, TMP1w, TMP2
  13720. }
  13721. return 1;
  13722. }
  13723. static bool zend_jit_noref_guard(dasm_State **Dst, const zend_op *opline, zend_jit_addr var_addr)
  13724. {
  13725. int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
  13726. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  13727. if (!exit_addr) {
  13728. return 0;
  13729. }
  13730. | IF_ZVAL_TYPE var_addr, IS_REFERENCE, &exit_addr, ZREG_TMP1
  13731. return 1;
  13732. }
  13733. static bool zend_jit_fetch_reference(dasm_State **Dst, const zend_op *opline, uint8_t var_type, uint32_t *var_info_ptr, zend_jit_addr *var_addr_ptr, bool add_ref_guard, bool add_type_guard)
  13734. {
  13735. zend_jit_addr var_addr = *var_addr_ptr;
  13736. uint32_t var_info = *var_info_ptr;
  13737. const void *exit_addr = NULL;
  13738. if (add_ref_guard || add_type_guard) {
  13739. int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
  13740. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  13741. if (!exit_addr) {
  13742. return 0;
  13743. }
  13744. }
  13745. if (add_ref_guard) {
  13746. | IF_NOT_ZVAL_TYPE var_addr, IS_REFERENCE, &exit_addr, ZREG_TMP1
  13747. }
  13748. if (opline->opcode == ZEND_INIT_METHOD_CALL && opline->op1_type == IS_VAR) {
  13749. /* Hack: Convert reference to regular value to simplify JIT code for INIT_METHOD_CALL */
  13750. if (Z_REG(var_addr) != ZREG_FCARG1 || Z_OFFSET(var_addr) != 0) {
  13751. | LOAD_ZVAL_ADDR FCARG1x, var_addr
  13752. }
  13753. | EXT_CALL zend_jit_unref_helper, REG0
  13754. } else {
  13755. | GET_ZVAL_PTR FCARG1x, var_addr, TMP1
  13756. var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, offsetof(zend_reference, val));
  13757. *var_addr_ptr = var_addr;
  13758. }
  13759. if (var_type != IS_UNKNOWN) {
  13760. var_type &= ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED);
  13761. }
  13762. if (add_type_guard
  13763. && var_type != IS_UNKNOWN
  13764. && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
  13765. | IF_NOT_ZVAL_TYPE var_addr, var_type, &exit_addr, ZREG_TMP1
  13766. ZEND_ASSERT(var_info & (1 << var_type));
  13767. if (var_type < IS_STRING) {
  13768. var_info = (1 << var_type);
  13769. } else if (var_type != IS_ARRAY) {
  13770. var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
  13771. } else {
  13772. var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
  13773. }
  13774. *var_info_ptr = var_info;
  13775. } else {
  13776. var_info &= ~MAY_BE_REF;
  13777. *var_info_ptr = var_info;
  13778. }
  13779. *var_info_ptr |= MAY_BE_GUARD; /* prevent generation of specialized zval dtor */
  13780. return 1;
  13781. }
  13782. static bool zend_jit_fetch_indirect_var(dasm_State **Dst, const zend_op *opline, uint8_t var_type, uint32_t *var_info_ptr, zend_jit_addr *var_addr_ptr, bool add_indirect_guard)
  13783. {
  13784. zend_jit_addr var_addr = *var_addr_ptr;
  13785. uint32_t var_info = *var_info_ptr;
  13786. int32_t exit_point;
  13787. const void *exit_addr;
  13788. if (add_indirect_guard) {
  13789. int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
  13790. const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  13791. if (!exit_addr) {
  13792. return 0;
  13793. }
  13794. | IF_NOT_ZVAL_TYPE var_addr, IS_INDIRECT, &exit_addr, ZREG_TMP1
  13795. | GET_ZVAL_PTR FCARG1x, var_addr, TMP1
  13796. } else {
  13797. /* May be already loaded into FCARG1a or RAX by previus FETCH_OBJ_W/DIM_W */
  13798. if (opline->op1_type != IS_VAR ||
  13799. (opline-1)->result_type != IS_VAR ||
  13800. (opline-1)->result.var != opline->op1.var ||
  13801. (opline-1)->op2_type == IS_VAR ||
  13802. (opline-1)->op2_type == IS_TMP_VAR) {
  13803. | GET_ZVAL_PTR FCARG1x, var_addr, TMP1
  13804. } else if ((opline-1)->opcode == ZEND_FETCH_DIM_W || (opline-1)->opcode == ZEND_FETCH_DIM_RW) {
  13805. | mov FCARG1x, REG0
  13806. }
  13807. }
  13808. *var_info_ptr &= ~MAY_BE_INDIRECT;
  13809. var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0);
  13810. *var_addr_ptr = var_addr;
  13811. if (var_type != IS_UNKNOWN) {
  13812. var_type &= ~(IS_TRACE_INDIRECT|IS_TRACE_PACKED);
  13813. }
  13814. if (!(var_type & IS_TRACE_REFERENCE)
  13815. && var_type != IS_UNKNOWN
  13816. && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
  13817. exit_point = zend_jit_trace_get_exit_point(opline, 0);
  13818. exit_addr = zend_jit_trace_get_exit_addr(exit_point);
  13819. if (!exit_addr) {
  13820. return 0;
  13821. }
  13822. | IF_NOT_Z_TYPE FCARG1x, var_type, &exit_addr, TMP1w
  13823. //var_info = zend_jit_trace_type_to_info_ex(var_type, var_info);
  13824. ZEND_ASSERT(var_info & (1 << var_type));
  13825. if (var_type < IS_STRING) {
  13826. var_info = (1 << var_type);
  13827. } else if (var_type != IS_ARRAY) {
  13828. var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
  13829. } else {
  13830. var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
  13831. }
  13832. *var_info_ptr = var_info;
  13833. }
  13834. return 1;
  13835. }
  13836. static bool zend_jit_may_reuse_reg(const zend_op *opline, const zend_ssa_op *ssa_op, zend_ssa *ssa, int def_var, int use_var)
  13837. {
  13838. if ((ssa->var_info[def_var].type & ~MAY_BE_GUARD) != (ssa->var_info[use_var].type & ~MAY_BE_GUARD)) {
  13839. return 0;
  13840. }
  13841. switch (opline->opcode) {
  13842. case ZEND_QM_ASSIGN:
  13843. case ZEND_SEND_VAR:
  13844. case ZEND_ASSIGN:
  13845. case ZEND_PRE_INC:
  13846. case ZEND_PRE_DEC:
  13847. case ZEND_POST_INC:
  13848. case ZEND_POST_DEC:
  13849. return 1;
  13850. case ZEND_ADD:
  13851. case ZEND_SUB:
  13852. case ZEND_MUL:
  13853. case ZEND_BW_OR:
  13854. case ZEND_BW_AND:
  13855. case ZEND_BW_XOR:
  13856. case ZEND_SL:
  13857. case ZEND_SR:
  13858. if (def_var == ssa_op->result_def &&
  13859. use_var == ssa_op->op1_use) {
  13860. return 1;
  13861. }
  13862. break;
  13863. default:
  13864. break;
  13865. }
  13866. return 0;
  13867. }
  13868. static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op, zend_jit_trace_rec *trace)
  13869. {
  13870. uint32_t op1_info, op2_info;
  13871. switch (opline->opcode) {
  13872. case ZEND_SEND_VAR:
  13873. case ZEND_SEND_VAL:
  13874. case ZEND_SEND_VAL_EX:
  13875. return (opline->op2_type != IS_CONST);
  13876. case ZEND_QM_ASSIGN:
  13877. case ZEND_IS_SMALLER:
  13878. case ZEND_IS_SMALLER_OR_EQUAL:
  13879. case ZEND_IS_EQUAL:
  13880. case ZEND_IS_NOT_EQUAL:
  13881. case ZEND_IS_IDENTICAL:
  13882. case ZEND_IS_NOT_IDENTICAL:
  13883. case ZEND_CASE:
  13884. return 1;
  13885. case ZEND_RETURN:
  13886. return (op_array->type != ZEND_EVAL_CODE && op_array->function_name);
  13887. case ZEND_ASSIGN:
  13888. op1_info = OP1_INFO();
  13889. op2_info = OP2_INFO();
  13890. return
  13891. opline->op1_type == IS_CV &&
  13892. !(op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_RESOURCE|MAY_BE_OBJECT|MAY_BE_REF)) &&
  13893. !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)));
  13894. case ZEND_ADD:
  13895. case ZEND_SUB:
  13896. case ZEND_MUL:
  13897. op1_info = OP1_INFO();
  13898. op2_info = OP2_INFO();
  13899. return !((op1_info | op2_info) & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_DOUBLE)));
  13900. case ZEND_BW_OR:
  13901. case ZEND_BW_AND:
  13902. case ZEND_BW_XOR:
  13903. case ZEND_SL:
  13904. case ZEND_SR:
  13905. case ZEND_MOD:
  13906. op1_info = OP1_INFO();
  13907. op2_info = OP2_INFO();
  13908. return !((op1_info | op2_info) & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - MAY_BE_LONG));
  13909. case ZEND_PRE_INC:
  13910. case ZEND_PRE_DEC:
  13911. case ZEND_POST_INC:
  13912. case ZEND_POST_DEC:
  13913. op1_info = OP1_INFO();
  13914. op2_info = OP1_DEF_INFO();
  13915. return opline->op1_type == IS_CV
  13916. && !(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - MAY_BE_LONG))
  13917. && (op2_info & MAY_BE_LONG);
  13918. case ZEND_STRLEN:
  13919. op1_info = OP1_INFO();
  13920. return (opline->op1_type & (IS_CV|IS_CONST))
  13921. && (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_STRING;
  13922. case ZEND_COUNT:
  13923. op1_info = OP1_INFO();
  13924. return (opline->op1_type & (IS_CV|IS_CONST))
  13925. && (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_ARRAY;
  13926. case ZEND_JMPZ:
  13927. case ZEND_JMPNZ:
  13928. if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
  13929. if (!ssa->cfg.map) {
  13930. return 0;
  13931. }
  13932. if (opline > op_array->opcodes + ssa->cfg.blocks[ssa->cfg.map[opline-op_array->opcodes]].start &&
  13933. ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
  13934. return 0;
  13935. }
  13936. }
  13937. ZEND_FALLTHROUGH;
  13938. case ZEND_BOOL:
  13939. case ZEND_BOOL_NOT:
  13940. case ZEND_JMPZNZ:
  13941. case ZEND_JMPZ_EX:
  13942. case ZEND_JMPNZ_EX:
  13943. return 1;
  13944. case ZEND_FETCH_CONSTANT:
  13945. return 1;
  13946. case ZEND_FETCH_DIM_R:
  13947. op1_info = OP1_INFO();
  13948. op2_info = OP2_INFO();
  13949. if (trace
  13950. && trace->op1_type != IS_UNKNOWN
  13951. && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
  13952. op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
  13953. }
  13954. return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
  13955. (!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || !(op1_info & MAY_BE_RC1)) &&
  13956. (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
  13957. (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING) &&
  13958. (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & MAY_BE_RC1))));
  13959. }
  13960. return 0;
  13961. }
  13962. static bool zend_jit_var_supports_reg(zend_ssa *ssa, int var)
  13963. {
  13964. if (ssa->vars[var].no_val) {
  13965. /* we don't need the value */
  13966. return 0;
  13967. }
  13968. if (!(JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL)) {
  13969. /* Disable global register allocation,
  13970. * register allocation for SSA variables connected through Phi functions
  13971. */
  13972. if (ssa->vars[var].definition_phi) {
  13973. return 0;
  13974. }
  13975. if (ssa->vars[var].phi_use_chain) {
  13976. zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
  13977. do {
  13978. if (!ssa->vars[phi->ssa_var].no_val) {
  13979. return 0;
  13980. }
  13981. phi = zend_ssa_next_use_phi(ssa, var, phi);
  13982. } while (phi);
  13983. }
  13984. }
  13985. if (((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) &&
  13986. ((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_LONG)) {
  13987. /* bad type */
  13988. return 0;
  13989. }
  13990. return 1;
  13991. }
  13992. static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa, int var)
  13993. {
  13994. if (!zend_jit_var_supports_reg(ssa, var)) {
  13995. return 0;
  13996. }
  13997. if (ssa->vars[var].definition >= 0) {
  13998. uint32_t def = ssa->vars[var].definition;
  13999. if (!zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + def, ssa->ops + def, NULL)) {
  14000. return 0;
  14001. }
  14002. }
  14003. if (ssa->vars[var].use_chain >= 0) {
  14004. int use = ssa->vars[var].use_chain;
  14005. do {
  14006. if (!zend_ssa_is_no_val_use(op_array->opcodes + use, ssa->ops + use, var) &&
  14007. !zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + use, ssa->ops + use, NULL)) {
  14008. return 0;
  14009. }
  14010. use = zend_ssa_next_use(ssa->ops, var, use);
  14011. } while (use >= 0);
  14012. }
  14013. return 1;
  14014. }
  14015. static zend_regset zend_jit_get_def_scratch_regset(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, int current_var, bool last_use)
  14016. {
  14017. uint32_t op1_info, op2_info;
  14018. switch (opline->opcode) {
  14019. case ZEND_FETCH_DIM_R:
  14020. op1_info = OP1_INFO();
  14021. op2_info = OP2_INFO();
  14022. if (((opline->op1_type & (IS_TMP_VAR|IS_VAR)) &&
  14023. (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) ||
  14024. ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) &&
  14025. (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)))) {
  14026. return ZEND_REGSET(ZREG_FCARG1);
  14027. }
  14028. break;
  14029. default:
  14030. break;
  14031. }
  14032. return ZEND_REGSET_EMPTY;
  14033. }
  14034. static zend_regset zend_jit_get_scratch_regset(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, int current_var, bool last_use)
  14035. {
  14036. uint32_t op1_info, op2_info, res_info;
  14037. zend_regset regset = ZEND_REGSET_SCRATCH;
  14038. switch (opline->opcode) {
  14039. case ZEND_NOP:
  14040. case ZEND_OP_DATA:
  14041. case ZEND_JMP:
  14042. case ZEND_RETURN:
  14043. regset = ZEND_REGSET_EMPTY;
  14044. break;
  14045. case ZEND_QM_ASSIGN:
  14046. if (ssa_op->op1_def == current_var ||
  14047. ssa_op->result_def == current_var) {
  14048. regset = ZEND_REGSET_EMPTY;
  14049. break;
  14050. }
  14051. /* break missing intentionally */
  14052. case ZEND_SEND_VAL:
  14053. case ZEND_SEND_VAL_EX:
  14054. if (opline->op2_type == IS_CONST) {
  14055. break;
  14056. }
  14057. if (ssa_op->op1_use == current_var) {
  14058. regset = ZEND_REGSET(ZREG_REG0);
  14059. break;
  14060. }
  14061. op1_info = OP1_INFO();
  14062. if (!(op1_info & MAY_BE_UNDEF)) {
  14063. if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_DOUBLE) {
  14064. regset = ZEND_REGSET(ZREG_FPR0);
  14065. } else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_LONG) {
  14066. regset = ZEND_REGSET(ZREG_REG0);
  14067. } else {
  14068. regset = ZEND_REGSET_UNION(ZEND_REGSET(ZREG_REG0), ZEND_REGSET(ZREG_REG2));
  14069. }
  14070. }
  14071. break;
  14072. case ZEND_SEND_VAR:
  14073. if (opline->op2_type == IS_CONST) {
  14074. break;
  14075. }
  14076. if (ssa_op->op1_use == current_var ||
  14077. ssa_op->op1_def == current_var) {
  14078. regset = ZEND_REGSET_EMPTY;
  14079. break;
  14080. }
  14081. op1_info = OP1_INFO();
  14082. if (!(op1_info & MAY_BE_UNDEF)) {
  14083. if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_DOUBLE) {
  14084. regset = ZEND_REGSET(ZREG_FPR0);
  14085. } else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_LONG) {
  14086. } else {
  14087. regset = ZEND_REGSET_UNION(ZEND_REGSET(ZREG_REG0), ZEND_REGSET(ZREG_REG2));
  14088. if (op1_info & MAY_BE_REF) {
  14089. ZEND_REGSET_INCL(regset, ZREG_REG1);
  14090. }
  14091. }
  14092. }
  14093. break;
  14094. case ZEND_ASSIGN:
  14095. if (ssa_op->op2_use == current_var ||
  14096. ssa_op->op2_def == current_var ||
  14097. ssa_op->op1_def == current_var ||
  14098. ssa_op->result_def == current_var) {
  14099. regset = ZEND_REGSET_EMPTY;
  14100. break;
  14101. }
  14102. op1_info = OP1_INFO();
  14103. op2_info = OP2_INFO();
  14104. if (opline->op1_type == IS_CV
  14105. && !(op2_info & MAY_BE_UNDEF)
  14106. && !(op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
  14107. if ((op2_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_DOUBLE) {
  14108. regset = ZEND_REGSET(ZREG_FPR0);
  14109. } else if ((op2_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_LONG) {
  14110. regset = ZEND_REGSET(ZREG_REG0);
  14111. } else {
  14112. regset = ZEND_REGSET_UNION(ZEND_REGSET(ZREG_REG0), ZEND_REGSET(ZREG_REG2));
  14113. }
  14114. }
  14115. break;
  14116. case ZEND_PRE_INC:
  14117. case ZEND_PRE_DEC:
  14118. case ZEND_POST_INC:
  14119. case ZEND_POST_DEC:
  14120. if (ssa_op->op1_use == current_var ||
  14121. ssa_op->op1_def == current_var ||
  14122. ssa_op->result_def == current_var) {
  14123. regset = ZEND_REGSET_EMPTY;
  14124. break;
  14125. }
  14126. op1_info = OP1_INFO();
  14127. if (opline->op1_type == IS_CV
  14128. && (op1_info & MAY_BE_LONG)
  14129. && !(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
  14130. regset = ZEND_REGSET_EMPTY;
  14131. if (op1_info & MAY_BE_DOUBLE) {
  14132. regset = ZEND_REGSET(ZREG_FPR0);
  14133. }
  14134. if (opline->result_type != IS_UNUSED && (op1_info & MAY_BE_LONG)) {
  14135. ZEND_REGSET_INCL(regset, ZREG_REG1);
  14136. }
  14137. }
  14138. break;
  14139. case ZEND_ADD:
  14140. case ZEND_SUB:
  14141. case ZEND_MUL:
  14142. op1_info = OP1_INFO();
  14143. op2_info = OP2_INFO();
  14144. if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) &&
  14145. !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
  14146. regset = ZEND_REGSET_EMPTY;
  14147. if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
  14148. if (ssa_op->result_def != current_var &&
  14149. (ssa_op->op1_use != current_var || !last_use)) {
  14150. ZEND_REGSET_INCL(regset, ZREG_REG0);
  14151. }
  14152. res_info = RES_INFO();
  14153. if (res_info & MAY_BE_DOUBLE) {
  14154. ZEND_REGSET_INCL(regset, ZREG_REG0);
  14155. ZEND_REGSET_INCL(regset, ZREG_FPR0);
  14156. ZEND_REGSET_INCL(regset, ZREG_FPR1);
  14157. } else if (res_info & MAY_BE_GUARD) {
  14158. ZEND_REGSET_INCL(regset, ZREG_REG0);
  14159. }
  14160. }
  14161. if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_DOUBLE)) {
  14162. if (ssa_op->result_def != current_var) {
  14163. ZEND_REGSET_INCL(regset, ZREG_FPR0);
  14164. }
  14165. }
  14166. if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_LONG)) {
  14167. if (zend_is_commutative(opline->opcode)) {
  14168. if (ssa_op->result_def != current_var) {
  14169. ZEND_REGSET_INCL(regset, ZREG_FPR0);
  14170. }
  14171. } else {
  14172. ZEND_REGSET_INCL(regset, ZREG_FPR0);
  14173. if (ssa_op->result_def != current_var &&
  14174. (ssa_op->op1_use != current_var || !last_use)) {
  14175. ZEND_REGSET_INCL(regset, ZREG_FPR1);
  14176. }
  14177. }
  14178. }
  14179. if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_DOUBLE)) {
  14180. if (ssa_op->result_def != current_var &&
  14181. (ssa_op->op1_use != current_var || !last_use) &&
  14182. (!zend_is_commutative(opline->opcode) || ssa_op->op2_use != current_var || !last_use)) {
  14183. ZEND_REGSET_INCL(regset, ZREG_FPR0);
  14184. }
  14185. }
  14186. }
  14187. break;
  14188. case ZEND_BW_OR:
  14189. case ZEND_BW_AND:
  14190. case ZEND_BW_XOR:
  14191. case ZEND_SL:
  14192. case ZEND_SR:
  14193. case ZEND_MOD:
  14194. op1_info = OP1_INFO();
  14195. op2_info = OP2_INFO();
  14196. if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG)) &&
  14197. !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG))) {
  14198. regset = ZEND_REGSET_EMPTY;
  14199. if (ssa_op->result_def != current_var &&
  14200. (ssa_op->op1_use != current_var || !last_use)) {
  14201. ZEND_REGSET_INCL(regset, ZREG_REG0);
  14202. }
  14203. }
  14204. break;
  14205. case ZEND_IS_SMALLER:
  14206. case ZEND_IS_SMALLER_OR_EQUAL:
  14207. case ZEND_IS_EQUAL:
  14208. case ZEND_IS_NOT_EQUAL:
  14209. case ZEND_IS_IDENTICAL:
  14210. case ZEND_IS_NOT_IDENTICAL:
  14211. case ZEND_CASE:
  14212. op1_info = OP1_INFO();
  14213. op2_info = OP2_INFO();
  14214. if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) &&
  14215. !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
  14216. regset = ZEND_REGSET_EMPTY;
  14217. if (!(opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ))) {
  14218. ZEND_REGSET_INCL(regset, ZREG_REG0);
  14219. }
  14220. if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) &&
  14221. opline->op1_type != IS_CONST && opline->op2_type != IS_CONST) {
  14222. if (ssa_op->op1_use != current_var &&
  14223. ssa_op->op2_use != current_var) {
  14224. ZEND_REGSET_INCL(regset, ZREG_REG0);
  14225. }
  14226. }
  14227. if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_DOUBLE)) {
  14228. ZEND_REGSET_INCL(regset, ZREG_FPR0);
  14229. }
  14230. if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_LONG)) {
  14231. ZEND_REGSET_INCL(regset, ZREG_FPR0);
  14232. }
  14233. if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_DOUBLE)) {
  14234. if (ssa_op->op1_use != current_var &&
  14235. ssa_op->op2_use != current_var) {
  14236. ZEND_REGSET_INCL(regset, ZREG_FPR0);
  14237. }
  14238. }
  14239. }
  14240. break;
  14241. case ZEND_BOOL:
  14242. case ZEND_BOOL_NOT:
  14243. case ZEND_JMPZ:
  14244. case ZEND_JMPNZ:
  14245. case ZEND_JMPZNZ:
  14246. case ZEND_JMPZ_EX:
  14247. case ZEND_JMPNZ_EX:
  14248. op1_info = OP1_INFO();
  14249. if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)))) {
  14250. regset = ZEND_REGSET_EMPTY;
  14251. if (op1_info & MAY_BE_DOUBLE) {
  14252. ZEND_REGSET_INCL(regset, ZREG_FPR0);
  14253. }
  14254. if (opline->opcode == ZEND_BOOL ||
  14255. opline->opcode == ZEND_BOOL_NOT ||
  14256. opline->opcode == ZEND_JMPZ_EX ||
  14257. opline->opcode == ZEND_JMPNZ_EX) {
  14258. ZEND_REGSET_INCL(regset, ZREG_REG0);
  14259. }
  14260. }
  14261. break;
  14262. case ZEND_DO_UCALL:
  14263. case ZEND_DO_FCALL:
  14264. case ZEND_DO_FCALL_BY_NAME:
  14265. case ZEND_INCLUDE_OR_EVAL:
  14266. case ZEND_GENERATOR_CREATE:
  14267. case ZEND_YIELD:
  14268. case ZEND_YIELD_FROM:
  14269. regset = ZEND_REGSET_UNION(ZEND_REGSET_GP, ZEND_REGSET_FP);
  14270. break;
  14271. default:
  14272. break;
  14273. }
  14274. if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
  14275. if (ssa_op == ssa->ops
  14276. && JIT_G(current_trace)[ZEND_JIT_TRACE_START_REC_SIZE].op == ZEND_JIT_TRACE_INIT_CALL
  14277. && (JIT_G(current_trace)[ZEND_JIT_TRACE_START_REC_SIZE].info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
  14278. ZEND_REGSET_INCL(regset, ZREG_REG0);
  14279. ZEND_REGSET_INCL(regset, ZREG_REG1);
  14280. }
  14281. }
  14282. return regset;
  14283. }
  14284. static size_t dasm_venners_size = 0;
  14285. void **dasm_labels_veneers = NULL;
  14286. static int zend_jit_add_veneer(dasm_State *Dst, void *buffer, uint32_t ins, int *b, uint32_t *cp, ptrdiff_t offset)
  14287. {
  14288. void *veneer;
  14289. ptrdiff_t na;
  14290. int n, m;
  14291. /* try to reuse veneers for global labels */
  14292. if ((ins >> 16) == DASM_REL_LG
  14293. && *(b-1) < 0
  14294. && dasm_labels_veneers[-*(b-1)]) {
  14295. veneer = dasm_labels_veneers[-*(b-1)];
  14296. na = (ptrdiff_t)veneer - (ptrdiff_t)cp + 4;
  14297. n = (int)na;
  14298. /* check if we can jump to veneer */
  14299. if ((ptrdiff_t)n != na) {
  14300. /* pass */
  14301. } else if (!(ins & 0xf800)) { /* B, BL */
  14302. if ((n & 3) == 0 && ((n+0x08000000) >> 28) == 0) {
  14303. return n;
  14304. }
  14305. } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */
  14306. if ((n & 3) == 0 && ((n+0x00100000) >> 21) == 0) {
  14307. return n;
  14308. }
  14309. } else if ((ins & 0x3000) == 0x2000) { /* ADR */
  14310. /* pass */
  14311. } else if ((ins & 0x3000) == 0x3000) { /* ADRP */
  14312. /* pass */
  14313. } else if ((ins & 0x1000)) { /* TBZ, TBNZ */
  14314. if ((n & 3) == 0 && ((n+0x00008000) >> 16) == 0) {
  14315. return n;
  14316. }
  14317. }
  14318. } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
  14319. && (ins >> 16) == DASM_REL_A) {
  14320. ptrdiff_t addr = (((ptrdiff_t)(*(b-1))) << 32) | (unsigned int)(*(b-2));
  14321. if ((void*)addr >= dasm_buf && (void*)addr < dasm_end) {
  14322. uint32_t exit_point = zend_jit_trace_find_exit_point((void*)addr);
  14323. zend_jit_trace_info *t = zend_jit_get_current_trace_info();
  14324. if (exit_point != (uint32_t)-1) {
  14325. /* Use exit points table */
  14326. ZEND_ASSERT(exit_point < t->exit_count);
  14327. veneer = (char*)buffer + dasm_getpclabel(&Dst, 1) - (t->exit_count - exit_point) * 4;
  14328. na = (ptrdiff_t)veneer - (ptrdiff_t)cp + 4;
  14329. n = (int)na;
  14330. /* check if we can jump to veneer */
  14331. if ((ptrdiff_t)n != na) {
  14332. ZEND_ASSERT(0);
  14333. return 0;
  14334. } else if (!(ins & 0xf800)) { /* B, BL */
  14335. if ((n & 3) != 0 || ((n+0x08000000) >> 28) != 0) {
  14336. ZEND_ASSERT(0);
  14337. return 0;
  14338. }
  14339. } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */
  14340. if ((n & 3) != 0 || ((n+0x00100000) >> 21) != 0) {
  14341. ZEND_ASSERT(0);
  14342. return 0;
  14343. }
  14344. } else if ((ins & 0x3000) == 0x2000) { /* ADR */
  14345. ZEND_ASSERT(0);
  14346. return 0;
  14347. } else if ((ins & 0x3000) == 0x3000) { /* ADRP */
  14348. ZEND_ASSERT(0);
  14349. return 0;
  14350. } else if ((ins & 0x1000)) { /* TBZ, TBNZ */
  14351. if ((n & 3) != 0 || ((n+0x00008000) >> 16) != 0) {
  14352. ZEND_ASSERT(0);
  14353. return 0;
  14354. }
  14355. } else {
  14356. ZEND_ASSERT(0);
  14357. return 0;
  14358. }
  14359. return n;
  14360. }
  14361. }
  14362. }
  14363. veneer = (char*)buffer + (Dst->codesize + dasm_venners_size);
  14364. if (veneer > dasm_end) {
  14365. return 0; /* jit_buffer_size overflow */
  14366. }
  14367. na = (ptrdiff_t)veneer - (ptrdiff_t)cp + 4;
  14368. n = (int)na;
  14369. /* check if we can jump to veneer */
  14370. if ((ptrdiff_t)n != na) {
  14371. ZEND_ASSERT(0);
  14372. return 0;
  14373. } else if (!(ins & 0xf800)) { /* B, BL */
  14374. if ((n & 3) != 0 || ((n+0x08000000) >> 28) != 0) {
  14375. ZEND_ASSERT(0);
  14376. return 0;
  14377. }
  14378. } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */
  14379. if ((n & 3) != 0 || ((n+0x00100000) >> 21) != 0) {
  14380. ZEND_ASSERT(0);
  14381. return 0;
  14382. }
  14383. } else if ((ins & 0x3000) == 0x2000) { /* ADR */
  14384. ZEND_ASSERT(0);
  14385. return 0;
  14386. } else if ((ins & 0x3000) == 0x3000) { /* ADRP */
  14387. ZEND_ASSERT(0);
  14388. return 0;
  14389. } else if ((ins & 0x1000)) { /* TBZ, TBNZ */
  14390. if ((n & 3) != 0 || ((n+0x00008000) >> 16) != 0) {
  14391. ZEND_ASSERT(0);
  14392. return 0;
  14393. }
  14394. } else if ((ins & 0x8000)) { /* absolute */
  14395. ZEND_ASSERT(0);
  14396. return 0;
  14397. } else {
  14398. ZEND_ASSERT(0);
  14399. return 0;
  14400. }
  14401. // TODO: support for long veneers (above 128MB) ???
  14402. /* check if we can use B to jump from veneer */
  14403. na = (ptrdiff_t)cp + offset - (ptrdiff_t)veneer - 4;
  14404. m = (int)na;
  14405. if ((ptrdiff_t)m != na) {
  14406. ZEND_ASSERT(0);
  14407. return 0;
  14408. } else if ((m & 3) != 0 || ((m+0x08000000) >> 28) != 0) {
  14409. ZEND_ASSERT(0);
  14410. return 0;
  14411. }
  14412. /* generate B instruction */
  14413. *(uint32_t*)veneer = 0x14000000 | ((m >> 2) & 0x03ffffff);
  14414. dasm_venners_size += 4;
  14415. if ((ins >> 16) == DASM_REL_LG
  14416. && *(b-1) < 0) {
  14417. /* reuse this veneer for the future jumps to global label */
  14418. dasm_labels_veneers[-*(b-1)] = veneer;
  14419. /* Dst->globals[*(b-1)] = veneer; */
  14420. #ifdef HAVE_DISASM
  14421. if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
  14422. const char *name = zend_jit_disasm_find_symbol((ptrdiff_t)cp + offset - 4, (int64_t *)(&offset));
  14423. if (name && !offset) {
  14424. if (strstr(name, "@veneer") == NULL) {
  14425. char *new_name;
  14426. zend_spprintf(&new_name, 0, "%s@veneer", name);
  14427. zend_jit_disasm_add_symbol(new_name, (uint64_t)(uintptr_t)veneer, 4);
  14428. efree(new_name);
  14429. } else {
  14430. zend_jit_disasm_add_symbol(name, (uint64_t)(uintptr_t)veneer, 4);
  14431. }
  14432. }
  14433. }
  14434. #endif
  14435. }
  14436. return n;
  14437. }
  14438. /*
  14439. * Local variables:
  14440. * tab-width: 4
  14441. * c-basic-offset: 4
  14442. * indent-tabs-mode: t
  14443. * End:
  14444. */