| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "RuntimeLanguagePch.h"
- #include "EHBailoutData.h"
- #include "Library/JavascriptRegularExpression.h"
- #if DBG_DUMP
- #include "ByteCode/OpCodeUtilAsmJs.h"
- #endif
- #include "Language/InterpreterStackFrame.h"
- #include "Library/JavascriptGeneratorFunction.h"
- #include "Library/ForInObjectEnumerator.h"
- ///----------------------------------------------------------------------------
- ///
- /// macros PROCESS_INtoOUT
- ///
- /// This set of macros defines standard patterns for processing OpCodes in
- /// RcInterpreter::Run(). Each macro is named for "in" - "out":
- /// - A: Var
- /// - I: Integer
- /// - R: Double
- /// - X: Nothing
- ///
- /// Examples:
- /// - "A2toA1" reads two registers, each storing an Var, and writes a single
- /// register with a new Var.
- /// - "A1I1toA2" reads two registers, first an Var and second an Int32, then
- /// writes two Var registers.
- ///
- /// Although these could use lookup tables to standard OpLayout types, this
- /// additional indirection would slow the main interpreter loop further by
- /// preventing the main 'switch' statement from using the OpCode to become a
- /// direct local-function jump.
- ///----------------------------------------------------------------------------
- #define PROCESS_FALLTHROUGH(name, func) \
- case OpCode::name:
- #define PROCESS_FALLTHROUGH_COMMON(name, func, suffix) \
- case OpCode::name:
- #define PROCESS_READ_LAYOUT(name, layout, suffix) \
- CompileAssert(OpCodeInfo<OpCode::name>::Layout == OpLayoutType::layout); \
- const unaligned OpLayout##layout##suffix * playout = m_reader.layout##suffix(ip); \
- Assert((playout != nullptr) == (Js::OpLayoutType::##layout != Js::OpLayoutType::Empty)); // Make sure playout is used
- #define PROCESS_NOP_COMMON(name, layout, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, layout, suffix); \
- break; \
- }
- #define PROCESS_NOP(name, layout) PROCESS_NOP_COMMON(name, layout,)
- #define PROCESS_CUSTOM_COMMON(name, func, layout, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, layout, suffix); \
- func(playout); \
- break; \
- }
- #define PROCESS_CUSTOM(name, func, layout) PROCESS_CUSTOM_COMMON(name, func, layout,)
- #define PROCESS_CUSTOM_L_COMMON(name, func, layout, regslot, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, layout, suffix); \
- func(playout); \
- break; \
- }
- #define PROCESS_CUSTOM_L(name, func, layout, regslot) PROCESS_CUSTOM_L_COMMON(name, func, layout, regslot,)
- #define PROCESS_CUSTOM_L_Arg_COMMON(name, func, suffix) PROCESS_CUSTOM_L_COMMON(name, func, Arg, Arg, suffix)
- #define PROCESS_CUSTOM_L_Arg2_COMMON(name, func, layout, suffix) PROCESS_CUSTOM_L_COMMON(name, func, layout, Arg, suffix)
- #define PROCESS_CUSTOM_L_Arg(name, func) PROCESS_CUSTOM_L_COMMON(name, func, Arg, Arg,)
- #define PROCESS_CUSTOM_ArgNoSrc_COMMON(name, func, suffix) PROCESS_CUSTOM_COMMON(name, func, ArgNoSrc, suffix)
- #define PROCESS_CUSTOM_ArgNoSrc(name, func) PROCESS_CUSTOM_COMMON(name, func, ArgNoSrc,)
- #define PROCESS_CUSTOM_L_R0_COMMON(name, func, layout, suffix) PROCESS_CUSTOM_L_COMMON(name, func, layout, R0, suffix)
- #define PROCESS_CUSTOM_L_R0(name, func, layout) PROCESS_CUSTOM_L_COMMON(name, func, layout, R0,)
- #define PROCESS_CUSTOM_L_Value_COMMON(name, func, layout, suffix) PROCESS_CUSTOM_L_COMMON(name, func, layout, Value, suffix)
- #define PROCESS_CUSTOM_L_Value(name, func, layout) PROCESS_CUSTOM_L_COMMON(name, func, layout, Value,)
- #define PROCESS_TRY(name, func) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Br,); \
- func(playout); \
- ip = m_reader.GetIP(); \
- break; \
- }
- #define PROCESS_EMPTY(name, func) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Empty, ); \
- func(); \
- ip = m_reader.GetIP(); \
- break; \
- }
- #define PROCESS_TRYBR2_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, BrReg2, suffix); \
- func((const byte*)(playout + 1), playout->RelativeJumpOffset, playout->R1, playout->R2); \
- ip = m_reader.GetIP(); \
- break; \
- }
- #define PROCESS_CALL_COMMON(name, func, layout, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, layout, suffix); \
- func(playout); \
- break; \
- }
- #define PROCESS_CALL(name, func, layout) PROCESS_CALL_COMMON(name, func, layout,)
- #define PROCESS_CALL_FLAGS_COMMON(name, func, layout, flags, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, layout, suffix); \
- func(playout, flags); \
- break; \
- }
- #define PROCESS_CALL_FLAGS(name, func, layout, regslot) PROCESS_CALL_FLAGS_COMMON(name, func, layout, regslot,)
- #define PROCESS_CALL_FLAGS_None_COMMON(name, func, layout, suffix) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_None, suffix)
- #define PROCESS_CALL_FLAGS_None(name, func, layout) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_None,)
- #define PROCESS_CALL_FLAGS_Value_COMMON(name, func, layout, suffix) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_Value, suffix)
- #define PROCESS_CALL_FLAGS_Value(name, func, layout) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_Value,)
- #define PROCESS_CALL_FLAGS_CallEval_COMMON(name, func, layout, suffix) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_ExtraArg, suffix)
- #define PROCESS_CALL_FLAGS_CallEval(name, func, layout) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_ExtraArg,)
- #define PROCESS_A1toXX_ALLOW_STACK_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1, suffix); \
- func(GetRegAllowStackVar(playout->R0)); \
- break; \
- }
- #define PROCESS_A1toXX_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1, suffix); \
- func(GetReg(playout->R0)); \
- break; \
- }
- #define PROCESS_A1toXX(name, func) PROCESS_A1toXX_COMMON(name, func,)
- #define PROCESS_A1toXXMem_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1, suffix); \
- func(GetReg(playout->R0), GetScriptContext()); \
- break; \
- }
- #define PROCESS_A1toXXMem(name, func) PROCESS_A1toXXMem_COMMON(name, func,)
- #define PROCESS_A1toXXMemNonVar_COMMON(name, func, type, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1, suffix); \
- func((type)GetNonVarReg(playout->R0), GetScriptContext()); \
- break; \
- }
- #define PROCESS_A1toXXMemNonVar(name, func, type) PROCESS_A1toXXMemNonVar_COMMON(name, func, type,)
- #define PROCESS_XXtoA1_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1, suffix); \
- SetReg(playout->R0, \
- func()); \
- break; \
- }
- #define PROCESS_XXtoA1(name, func) PROCESS_XXtoA1_COMMON(name, func,)
- #define PROCESS_XXtoA1NonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1, suffix); \
- SetNonVarReg(playout->R0, \
- func()); \
- break; \
- }
- #define PROCESS_XXtoA1NonVar(name, func) PROCESS_XXtoA1NonVar_COMMON(name, func,)
- #define PROCESS_XXtoA1Mem_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1, suffix); \
- SetReg(playout->R0, \
- func(GetScriptContext())); \
- break; \
- }
- #define PROCESS_XXtoA1Mem(name, func) PROCESS_XXtoA1Mem_COMMON(name, func,)
- #define PROCESS_A1toA1_ALLOW_STACK_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg2, suffix); \
- SetRegAllowStackVar(playout->R0, \
- func(GetRegAllowStackVar(playout->R1))); \
- break; \
- }
- #define PROCESS_A1toA1_ALLOW_STACK(name, func) PROCESS_A1toA1_ALLOW_STACK_COMMON(name, func,)
- #define PROCESS_A1toA1_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg2, suffix); \
- SetReg(playout->R0, \
- func(GetReg(playout->R1))); \
- break; \
- }
- #define PROCESS_A1toA1(name, func) PROCESS_A1toA1_COMMON(name, func,)
- #define PROCESS_A1toA1Profiled_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ProfiledReg2, suffix); \
- SetReg(playout->R0, \
- func(GetReg(playout->R1), playout->profileId)); \
- break; \
- }
- #define PROCESS_A1toA1Profiled(name, func) PROCESS_A1toA1Profiled_COMMON(name, func,)
- #define PROCESS_A1toA1CallNoArg_COMMON(name, func, layout, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, layout, suffix); \
- SetReg(playout->R0, \
- func(playout)); \
- break; \
- }
- #define PROCESS_A1toA1CallNoArg(name, func, layout) PROCESS_A1toA1CallNoArg_COMMON(name, func, layout,)
- #define PROCESS_A1toA1Mem_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg2, suffix); \
- SetReg(playout->R0, \
- func(GetReg(playout->R1),GetScriptContext())); \
- break; \
- }
- #define PROCESS_A1toA1Mem(name, func) PROCESS_A1toA1Mem_COMMON(name, func,)
- #define PROCESS_A1toA1NonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg2, suffix); \
- SetNonVarReg(playout->R0, \
- func(GetNonVarReg(playout->R1))); \
- break; \
- }
- #define PROCESS_A1toA1NonVar(name, func) PROCESS_A1toA1NonVar_COMMON(name, func,)
- #define PROCESS_A1toA1MemNonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg2, suffix); \
- SetNonVarReg(playout->R0, \
- func(GetNonVarReg(playout->R1),GetScriptContext())); \
- break; \
- }
- #define PROCESS_A1toA1MemNonVar(name, func) PROCESS_A1toA1MemNonVar_COMMON(name, func,)
- #define PROCESS_INNERtoA1_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
- SetReg(playout->R0, InnerScopeFromIndex(playout->C1)); \
- break; \
- }
- #define PROCESS_INNERtoA1(name, fun) PROCESS_INNERtoA1_COMMON(name, func,)
- #define PROCESS_U1toINNERMemNonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Unsigned1, suffix); \
- SetInnerScopeFromIndex(playout->C1, func(GetScriptContext())); \
- break; \
- }
- #define PROCESS_U1toINNERMemNonVar(name, func) PROCESS_U1toINNERMemNonVar_COMMON(name, func,)
- #define PROCESS_XXINNERtoA1MemNonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
- SetNonVarReg(playout->R0, \
- func(InnerScopeFromIndex(playout->C1), GetScriptContext())); \
- break; \
- }
- #define PROCESS_XXINNERtoA1MemNonVar(name, func) PROCESS_XXINNERtoA1MemNonVar_COMMON(name, func,)
- #define PROCESS_A1INNERtoA1MemNonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg2Int1, suffix); \
- SetNonVarReg(playout->R0, \
- func(InnerScopeFromIndex(playout->C1), GetNonVarReg(playout->R1), GetScriptContext())); \
- break; \
- }
- #define PROCESS_A1LOCALtoA1MemNonVar(name, func) PROCESS_A1LOCALtoA1MemNonVar_COMMON(name, func,)
- #define PROCESS_LOCALI1toA1_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
- SetReg(playout->R0, \
- func(this->localClosure, playout->C1)); \
- break; \
- }
- #define PROCESS_LOCALI1toA1(name, func) PROCESS_LOCALI1toA1_COMMON(name, func,)
- #define PROCESS_A1I1toA1_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg2Int1, suffix); \
- SetReg(playout->R0, \
- func(GetReg(playout->R1), playout->C1)); \
- break; \
- }
- #define PROCESS_A1I1toA1(name, func) PROCESS_A1I1toA1_COMMON(name, func,)
- #define PROCESS_A1I1toA1Mem_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg2Int1, suffix); \
- SetReg(playout->R0, \
- func(GetReg(playout->R1), playout->C1, GetScriptContext())); \
- break; \
- }
- #define PROCESS_A1I1toA1Mem(name, func) PROCESS_A1I1toA1Mem_COMMON(name, func,)
- #define PROCESS_RegextoA1_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
- SetReg(playout->R0, \
- func(this->m_functionBody->GetLiteralRegex(playout->C1), GetScriptContext())); \
- break; \
- }
- #define PROCESS_RegextoA1(name, func) PROCESS_RegextoA1_COMMON(name, func,)
- #define PROCESS_A2toXX_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg2, suffix); \
- func(GetReg(playout->R0), GetReg(playout->R1)); \
- break; \
- }
- #define PROCESS_A2toXX(name, func) PROCESS_A2toXX_COMMON(name, func,)
- #define PROCESS_A2toXXMemNonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg2, suffix); \
- func(GetNonVarReg(playout->R0), GetNonVarReg(playout->R1), GetScriptContext()); \
- break; \
- }
- #define PROCESS_A2toXXMemNonVar(name, func) PROCESS_A2toXXMemNonVar_COMMON(name, func,)
- #define PROCESS_A1NonVarToA1_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg2, suffix); \
- SetReg(playout->R0, \
- func(GetNonVarReg(playout->R1))); \
- break; \
- }
- #define PROCESS_A2NonVarToA1Reg_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg3, suffix); \
- SetReg(playout->R0, \
- func(GetNonVarReg(playout->R1), playout->R2)); \
- break; \
- }
- #define PROCESS_A2toA1Mem_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg3, suffix); \
- SetReg(playout->R0, \
- func(GetReg(playout->R1), GetReg(playout->R2),GetScriptContext())); \
- break; \
- }
- #define PROCESS_A2toA1Mem(name, func) PROCESS_A2toA1Mem_COMMON(name, func,)
- #define PROCESS_A2toA1MemProfiled_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ProfiledReg3, suffix); \
- SetReg(playout->R0, \
- func(GetReg(playout->R1), GetReg(playout->R2),GetScriptContext(), playout->profileId)); \
- break; \
- }
- #define PROCESS_A2toA1MemProfiled(name, func) PROCESS_A2toA1MemProfiled_COMMON(name, func,)
- #define PROCESS_A2toA1NonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg3, suffix); \
- SetNonVarReg(playout->R0, \
- func(GetNonVarReg(playout->R1), GetNonVarReg(playout->R2))); \
- break; \
- }
- #define PROCESS_A2toA1NonVar(name, func) PROCESS_A2toA1NonVar_COMMON(name, func,)
- #define PROCESS_A2toA1MemNonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg3, suffix); \
- SetNonVarReg(playout->R0, \
- func(GetNonVarReg(playout->R1), GetNonVarReg(playout->R2),GetScriptContext())); \
- break; \
- }
- #define PROCESS_A2toA1MemNonVar(name, func) PROCESS_A2toA1MemNonVar_COMMON(name, func,)
- #define PROCESS_CMMem_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg3, suffix); \
- SetReg(playout->R0, \
- func(GetReg(playout->R1), GetReg(playout->R2), GetScriptContext()) ? JavascriptBoolean::OP_LdTrue(GetScriptContext()) : \
- JavascriptBoolean::OP_LdFalse(GetScriptContext())); \
- break; \
- }
- #define PROCESS_CMMem(name, func) PROCESS_CMMem_COMMON(name, func,)
- #define PROCESS_ELEM_RtU_to_XX_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ElementRootU, suffix); \
- func(playout->PropertyIdIndex); \
- break; \
- }
- #define PROCESS_ELEM_RtU_to_XX(name, func) PROCESS_ELEM_RtU_to_XX_COMMON(name, func,)
- #define PROCESS_ELEM_C2_to_XX_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ElementScopedC, suffix); \
- func(GetEnvForEvalCode(), playout->PropertyIdIndex, GetReg(playout->Value)); \
- break; \
- }
- #define PROCESS_ELEM_C2_to_XX(name, func) PROCESS_ELEM_C2_to_XX_COMMON(name, func,)
- #define PROCESS_GET_ELEM_SLOT_FB_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ElementSlot, suffix); \
- SetReg(playout->Value, \
- func((FrameDisplay*)GetNonVarReg(playout->Instance), this->m_functionBody->GetNestedFuncReference(playout->SlotIndex))); \
- break; \
- }
- #define PROCESS_GET_ELEM_SLOT_FB(name, func) PROCESS_GET_ELEM_SLOT_FB_COMMON(name, func,)
- #define PROCESS_GET_SLOT_FB_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ElementSlotI1, suffix); \
- SetReg(playout->Value, \
- func(this->GetFrameDisplayForNestedFunc(), this->m_functionBody->GetNestedFuncReference(playout->SlotIndex))); \
- break; \
- }
- #define PROCESS_GET_SLOT_FB(name, func) PROCESS_GET_SLOT_FB_COMMON(name, func,)
- #define PROCESS_GET_ELEM_IMem_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ElementI, suffix); \
- SetReg(playout->Value, \
- func(GetReg(playout->Instance), GetReg(playout->Element), GetScriptContext())); \
- break; \
- }
- #define PROCESS_GET_ELEM_IMem(name, func) PROCESS_GET_ELEM_IMem_COMMON(name, func,)
- #define PROCESS_GET_ELEM_IMem_Strict_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ElementI, suffix); \
- SetReg(playout->Value, \
- func(GetReg(playout->Instance), GetReg(playout->Element), GetScriptContext(), PropertyOperation_StrictMode)); \
- break; \
- }
- #define PROCESS_GET_ELEM_IMem_Strict(name, func) PROCESS_GET_ELEM_IMem_Strict_COMMON(name, func,)
- #define PROCESS_BR(name, func) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Br,); \
- ip = func(playout); \
- break; \
- }
- #ifdef BYTECODE_BRANCH_ISLAND
- #define PROCESS_BRLONG(name, func) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, BrLong,); \
- ip = func(playout); \
- break; \
- }
- #endif
- #define PROCESS_BRS(name,func) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, BrS,); \
- if (func(playout->val,GetScriptContext())) \
- { \
- ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
- } \
- break; \
- }
- #define PROCESS_BRB_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, BrReg1, suffix); \
- if (func(GetReg(playout->R1))) \
- { \
- ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
- } \
- break; \
- }
- #define PROCESS_BRB(name, func) PROCESS_BRB_COMMON(name, func,)
- #define PROCESS_BRB_ALLOW_STACK_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, BrReg1, suffix); \
- if (func(GetRegAllowStackVar(playout->R1))) \
- { \
- ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
- } \
- break; \
- }
- #define PROCESS_BRB_ALLOW_STACK(name, func) PROCESS_BRB_ALLOW_STACK_COMMON(name, func,)
- #define PROCESS_BRBS_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, BrReg1, suffix); \
- if (func(GetReg(playout->R1), GetScriptContext())) \
- { \
- ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
- } \
- break; \
- }
- #define PROCESS_BRBS(name, func) PROCESS_BRBS_COMMON(name, func,)
- #define PROCESS_BRBReturnP1toA1_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, BrReg1Unsigned1, suffix); \
- SetReg(playout->R1, func(GetForInEnumerator(playout->C2))); \
- if (!GetReg(playout->R1)) \
- { \
- ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
- } \
- break; \
- }
- #define PROCESS_BRBReturnP1toA1(name, func) PROCESS_BRBReturnP1toA1_COMMON(name, func,)
- #define PROCESS_BRBMem_ALLOW_STACK_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, BrReg1, suffix); \
- if (func(GetRegAllowStackVar(playout->R1),GetScriptContext())) \
- { \
- ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
- } \
- break; \
- }
- #define PROCESS_BRBMem_ALLOW_STACK(name, func) PROCESS_BRBMem_ALLOW_STACK_COMMON(name, func,)
- #define PROCESS_BRCMem_COMMON(name, func,suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, BrReg2, suffix); \
- if (func(GetReg(playout->R1), GetReg(playout->R2),GetScriptContext())) \
- { \
- ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
- } \
- break; \
- }
- #define PROCESS_BRCMem(name, func) PROCESS_BRCMem_COMMON(name, func,)
- #define PROCESS_BRPROP(name, func) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, BrProperty,); \
- if (func(GetReg(playout->Instance), playout->PropertyIdIndex, GetScriptContext())) \
- { \
- ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
- } \
- break; \
- }
- #define PROCESS_BRLOCALPROP(name, func) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, BrLocalProperty,); \
- if (func(this->localClosure, playout->PropertyIdIndex, GetScriptContext())) \
- { \
- ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
- } \
- break; \
- }
- #define PROCESS_BRENVPROP(name, func) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, BrEnvProperty,); \
- if (func(LdEnv(), playout->SlotIndex, playout->PropertyIdIndex, GetScriptContext())) \
- { \
- ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
- } \
- break; \
- }
- #define PROCESS_W1(name, func) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, W1,); \
- func(playout->C1, GetScriptContext()); \
- break; \
- }
- #define PROCESS_U1toA1_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
- SetReg(playout->R0, \
- func(playout->C1,GetScriptContext())); \
- break; \
- }
- #define PROCESS_U1toA1(name, func) PROCESS_U1toA1_COMMON(name, func,)
- #define PROCESS_U1toA1NonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
- SetNonVarReg(playout->R0, \
- func(playout->C1)); \
- break; \
- }
- #define PROCESS_U1toA1NonVar(name, func) PROCESS_U1toA1NonVar_COMMON(name, func,)
- #define PROCESS_U1toA1NonVar_FuncBody_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
- SetNonVarReg(playout->R0, \
- func(playout->C1,GetScriptContext(), this->m_functionBody)); \
- break; \
- }
- #define PROCESS_U1toA1NonVar_FuncBody(name, func) PROCESS_U1toA1NonVar_FuncBody_COMMON(name, func,)
- #define PROCESS_A1I2toXXNonVar_FuncBody(name, func) PROCESS_A1I2toXXNonVar_FuncBody_COMMON(name, func,)
- #define PROCESS_A1I2toXXNonVar_FuncBody_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg3, suffix); \
- func(playout->R0, playout->R1, playout->R2, GetScriptContext(), this->m_functionBody); \
- break; \
- }
- #define PROCESS_A1U1toXX_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
- func(GetReg(playout->R0), playout->C1); \
- break; \
- }
- #define PROCESS_A1U1toXX(name, func) PROCESS_A1U1toXX_COMMON(name, func,)
- #define PROCESS_A1U1toXXWithCache_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ProfiledReg1Unsigned1, suffix); \
- func(GetReg(playout->R0), playout->C1, playout->profileId); \
- break; \
- }
- #define PROCESS_A1U1toXXWithCache(name, func) PROCESS_A1U1toXXWithCache_COMMON(name, func,)
- #define PROCESS_EnvU1toXX_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Unsigned1, suffix); \
- func(LdEnv(), playout->C1); \
- break; \
- }
- #define PROCESS_EnvU1toXX(name, func) PROCESS_EnvU1toXX_COMMON(name, func,)
- #define PROCESS_GET_ELEM_SLOTNonVar_COMMON(name, func, layout, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, layout, suffix); \
- SetNonVarReg(playout->Value, func(GetNonVarReg(playout->Instance), playout)); \
- break; \
- }
- #define PROCESS_GET_ELEM_SLOTNonVar(name, func, layout) PROCESS_GET_ELEM_SLOTNonVar_COMMON(name, func, layout,)
- #define PROCESS_GET_ELEM_LOCALSLOTNonVar_COMMON(name, func, layout, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, layout, suffix); \
- SetNonVarReg(playout->Value, func((Var*)GetLocalClosure(), playout)); \
- break; \
- }
- #define PROCESS_GET_ELEM_LOCALSLOTNonVar(name, func, layout) PROCESS_GET_ELEM_LOCALSLOTNonVar_COMMON(name, func, layout,)
- #define PROCESS_GET_ELEM_PARAMSLOTNonVar_COMMON(name, func, layout, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, layout, suffix); \
- SetNonVarReg(playout->Value, func((Var*)GetParamClosure(), playout)); \
- break; \
- }
- #define PROCESS_GET_ELEM_PARAMSLOTNonVar(name, func, layout) PROCESS_GET_ELEM_PARAMSLOTNonVar_COMMON(name, func, layout,)
- #define PROCESS_GET_ELEM_INNERSLOTNonVar_COMMON(name, func, layout, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, layout, suffix); \
- SetNonVarReg(playout->Value, func(InnerScopeFromIndex(playout->SlotIndex1), playout)); \
- break; \
- }
- #define PROCESS_GET_ELEM_INNERSLOTNonVar(name, func, layout) PROCESS_GET_ELEM_INNERSLOTNonVar_COMMON(name, func, layout,)
- #define PROCESS_GET_ELEM_ENVSLOTNonVar_COMMON(name, func, layout, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, layout, suffix); \
- SetNonVarReg(playout->Value, func(LdEnv(), playout)); \
- break; \
- }
- #define PROCESS_GET_ELEM_ENVSLOTNonVar(name, func, layout) PROCESS_GET_ELEM_ENVSLOTNonVar_COMMON(name, func, layout,)
- #define PROCESS_SET_ELEM_SLOTNonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ElementSlot, suffix); \
- func(GetNonVarReg(playout->Instance), playout->SlotIndex, GetRegAllowStackVarEnableOnly(playout->Value)); \
- break; \
- }
- #define PROCESS_SET_ELEM_SLOTNonVar(name, func) PROCESS_SET_ELEM_SLOTNonVar_COMMON(name, func,)
- #define PROCESS_SET_ELEM_LOCALSLOTNonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ElementSlotI1, suffix); \
- func((Var*)GetLocalClosure(), playout->SlotIndex, GetRegAllowStackVarEnableOnly(playout->Value)); \
- break; \
- }
- #define PROCESS_SET_ELEM_LOCALSLOTNonVar(name, func) PROCESS_SET_ELEM_LOCALSLOTNonVar_COMMON(name, func,)
- #define PROCESS_SET_ELEM_INNERSLOTNonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ElementSlotI2, suffix); \
- func(InnerScopeFromIndex(playout->SlotIndex1), playout->SlotIndex2, GetRegAllowStackVarEnableOnly(playout->Value)); \
- break; \
- }
- #define PROCESS_SET_ELEM_INNERSLOTNonVar(name, func) PROCESS_SET_ELEM_INNERSLOTNonVar_COMMON(name, func,)
- #define PROCESS_SET_ELEM_ENVSLOTNonVar_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, ElementSlotI2, suffix); \
- func(LdEnv(), playout->SlotIndex1, playout->SlotIndex2, GetRegAllowStackVarEnableOnly(playout->Value)); \
- break; \
- }
- #define PROCESS_SET_ELEM_ENVSLOTNonVar(name, func) PROCESS_SET_ELEM_ENVSLOTNonVar_COMMON(name, func,)
- /*---------------------------------------------------------------------------------------------- */
- #define PROCESS_A3toA1Mem_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg4, suffix); \
- SetReg(playout->R0, \
- func(GetReg(playout->R1), GetReg(playout->R2), GetReg(playout->R3), GetScriptContext())); \
- break; \
- }
- #define PROCESS_A3toA1Mem(name, func) PROCESS_A3toA1Mem_COMMON(name, func,)
- /*---------------------------------------------------------------------------------------------- */
- #define PROCESS_A2I1toA1Mem_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg3B1, suffix); \
- SetReg(playout->R0, \
- func(GetReg(playout->R1), GetReg(playout->R2), playout->B3, GetScriptContext())); \
- break; \
- }
- #define PROCESS_A2I1toA1Mem(name, func) PROCESS_A2I1toA1Mem_COMMON(name, func,)
- /*---------------------------------------------------------------------------------------------- */
- #define PROCESS_A2I1toXXMem_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg2B1, suffix); \
- func(GetReg(playout->R0), GetReg(playout->R1), playout->B2, scriptContext); \
- break; \
- }
- #define PROCESS_A2I1toXXMem(name, func) PROCESS_A2I1toXXMem_COMMON(name, func,)
- /*---------------------------------------------------------------------------------------------- */
- #define PROCESS_A3I1toXXMem_COMMON(name, func, suffix) \
- case OpCode::name: \
- { \
- PROCESS_READ_LAYOUT(name, Reg3B1, suffix); \
- func(GetReg(playout->R0), GetReg(playout->R1), GetReg(playout->R2), playout->B3, scriptContext); \
- break; \
- }
- #define PROCESS_A3I1toXXMem(name, func) PROCESS_A3I1toXXMem_COMMON(name, func,)
- #if ENABLE_PROFILE_INFO
- #define PROCESS_IP_TARG_IMPL(name, func, layoutSize) \
- case OpCode::name: \
- { \
- Assert(!switchProfileMode); \
- ip = func<layoutSize, INTERPRETERPROFILE>(ip); \
- if(switchProfileMode) \
- { \
- m_reader.SetIP(ip); \
- return nullptr; \
- } \
- break; \
- }
- #else
- #define PROCESS_IP_TARG_IMPL(name, func, layoutSize) \
- case OpCode::name: \
- { \
- ip = func<layoutSize, INTERPRETERPROFILE>(ip); \
- break; \
- }
- #endif
- #define PROCESS_IP_TARG_COMMON(name, func, suffix) PROCESS_IP_TARG##suffix(name, func)
- #define PROCESS_IP_TARG_Large(name, func) PROCESS_IP_TARG_IMPL(name, func, Js::LargeLayout)
- #define PROCESS_IP_TARG_Medium(name, func) PROCESS_IP_TARG_IMPL(name, func, Js::MediumLayout)
- #define PROCESS_IP_TARG_Small(name, func) PROCESS_IP_TARG_IMPL(name, func, Js::SmallLayout)
- #if ENABLE_TTD
- #if ENABLE_TTD_DIAGNOSTICS_TRACING
- #define SHOULD_DO_TTD_STACK_STMT_OP(CTX) ((CTX)->ShouldPerformRecordOrReplayAction())
- #else
- #define SHOULD_DO_TTD_STACK_STMT_OP(CTX) ((CTX)->ShouldPerformDebuggerAction())
- #endif
- #endif
- namespace Js
- {
- #ifdef ASMJS_PLAT
- typedef void(InterpreterStackFrame::*ArrFunc)(uint32, RegSlot);
- CompileAssert(Js::ArrayBufferView::TYPE_INT8 == 0);
- CompileAssert(Js::ArrayBufferView::TYPE_UINT8 == 1);
- CompileAssert(Js::ArrayBufferView::TYPE_INT16 == 2);
- CompileAssert(Js::ArrayBufferView::TYPE_UINT16 == 3);
- CompileAssert(Js::ArrayBufferView::TYPE_INT32 == 4);
- CompileAssert(Js::ArrayBufferView::TYPE_UINT32 == 5);
- CompileAssert(Js::ArrayBufferView::TYPE_FLOAT32 == 6);
- CompileAssert(Js::ArrayBufferView::TYPE_FLOAT64 == 7);
- CompileAssert(Js::ArrayBufferView::TYPE_INT64 == 8);
- CompileAssert(Js::ArrayBufferView::TYPE_INT8_TO_INT64 == 9);
- CompileAssert(Js::ArrayBufferView::TYPE_UINT8_TO_INT64 == 10);
- CompileAssert(Js::ArrayBufferView::TYPE_INT16_TO_INT64 == 11);
- CompileAssert(Js::ArrayBufferView::TYPE_UINT16_TO_INT64 == 12);
- CompileAssert(Js::ArrayBufferView::TYPE_INT32_TO_INT64 == 13);
- CompileAssert(Js::ArrayBufferView::TYPE_UINT32_TO_INT64 == 14);
- const InterpreterStackFrame::ArrFunc InterpreterStackFrame::StArrFunc[] =
- {
- &InterpreterStackFrame::OP_StArr<int8, int32>,
- &InterpreterStackFrame::OP_StArr<uint8, int32>,
- &InterpreterStackFrame::OP_StArr<int16, int32>,
- &InterpreterStackFrame::OP_StArr<uint16, int32>,
- &InterpreterStackFrame::OP_StArr<int32>,
- &InterpreterStackFrame::OP_StArr<uint32, int32>,
- &InterpreterStackFrame::OP_StArr<float>,
- &InterpreterStackFrame::OP_StArr<double>,
- &InterpreterStackFrame::OP_StArr<int64>,
- &InterpreterStackFrame::OP_StArr<int8, int64>,
- &InterpreterStackFrame::OP_StArr<uint8, int64>,
- &InterpreterStackFrame::OP_StArr<int16, int64>,
- &InterpreterStackFrame::OP_StArr<uint16, int64>,
- &InterpreterStackFrame::OP_StArr<int32, int64>,
- &InterpreterStackFrame::OP_StArr<uint32, int64>,
- };
- const InterpreterStackFrame::ArrFunc InterpreterStackFrame::LdArrFunc[] =
- {
- &InterpreterStackFrame::OP_LdArr<int8, int32>,
- &InterpreterStackFrame::OP_LdArr<uint8, int32>,
- &InterpreterStackFrame::OP_LdArr<int16, int32>,
- &InterpreterStackFrame::OP_LdArr<uint16, int32>,
- &InterpreterStackFrame::OP_LdArr<int32>,
- &InterpreterStackFrame::OP_LdArr<uint32, int32>,
- &InterpreterStackFrame::OP_LdArr<float>,
- &InterpreterStackFrame::OP_LdArr<double>,
- &InterpreterStackFrame::OP_LdArr<int64>,
- &InterpreterStackFrame::OP_LdArr<int8, int64>,
- &InterpreterStackFrame::OP_LdArr<uint8, int64>,
- &InterpreterStackFrame::OP_LdArr<int16, int64>,
- &InterpreterStackFrame::OP_LdArr<uint16, int64>,
- &InterpreterStackFrame::OP_LdArr<int32, int64>,
- &InterpreterStackFrame::OP_LdArr<uint32, int64>,
- };
- const int InterpreterStackFrame::TypeToSizeMap[] =
- {
- /*int8*/ 1,
- /*uint8*/ 1,
- /*int16*/ 2,
- /*uint16*/ 2,
- /*int32*/ 4,
- /*uint32*/ 4,
- /*float*/ 4,
- /*double*/ 8,
- /*int64*/ 8,
- /*int8*/ 1,
- /*uint8*/ 1,
- /*int16*/ 2,
- /*uint16*/ 2,
- /*int32*/ 4,
- /*uint32*/ 4,
- };
- #endif
- Var InterpreterStackFrame::InnerScopeFromRegSlot(RegSlot reg) const
- {
- return InnerScopeFromIndex(reg - m_functionBody->GetFirstInnerScopeRegister());
- }
- Var InterpreterStackFrame::InnerScopeFromIndex(uint32 index) const
- {
- if (index >= m_functionBody->GetInnerScopeCount())
- {
- AssertMsg(false, "Illegal byte code: bad inner scope index");
- Js::Throw::FatalInternalError();
- }
- Assert(this->innerScopeArray != nullptr);
- return this->innerScopeArray[index];
- }
- void InterpreterStackFrame::SetInnerScopeFromIndex(uint32 index, Var scope)
- {
- if (index >= m_functionBody->GetInnerScopeCount())
- {
- AssertMsg(false, "Illegal byte code: bad inner scope index");
- Js::Throw::FatalInternalError();
- }
- Assert(this->innerScopeArray != nullptr);
- this->innerScopeArray[index] = scope;
- }
- const int k_stackFrameVarCount = (sizeof(InterpreterStackFrame) + sizeof(Var) - 1) / sizeof(Var);
- InterpreterStackFrame::Setup::Setup(Js::ScriptFunction * function, Js::Arguments& args, bool bailedOut, bool inlinee)
- : function(function), inParams(args.Values), inSlotsCount(args.Info.Count), executeFunction(function->GetFunctionBody()), callFlags(args.Info.Flags), bailedOutOfInlinee(inlinee), bailedOut(bailedOut)
- {
- SetupInternal();
- }
- InterpreterStackFrame::Setup::Setup(Js::ScriptFunction * function, Var * inParams, int inSlotsCount)
- : function(function), inParams(inParams), inSlotsCount(inSlotsCount), executeFunction(function->GetFunctionBody()), callFlags(CallFlags_None), bailedOutOfInlinee(false), bailedOut(false)
- {
- SetupInternal();
- }
- void InterpreterStackFrame::Setup::SetupInternal()
- {
- if (this->function->GetHasInlineCaches() && Js::ScriptFunctionWithInlineCache::Is(this->function))
- {
- this->inlineCaches = Js::ScriptFunctionWithInlineCache::FromVar(this->function)->GetInlineCaches();
- }
- else
- {
- this->inlineCaches = this->executeFunction->GetInlineCaches();
- }
- this->inlineCacheCount = this->executeFunction->GetInlineCacheCount();
- //
- // Compute the amount of memory needed on the stack:
- // - We compute this in 'Atoms' instead of 'bytes' to keep everything natural word aligned.
- //
- this->localCount = this->executeFunction->GetLocalsCount();
- uint extraVarCount = 0;
- #if ENABLE_PROFILE_INFO
- if (Js::DynamicProfileInfo::EnableImplicitCallFlags(this->executeFunction))
- {
- extraVarCount += (sizeof(ImplicitCallFlags) * this->executeFunction->GetLoopCount() + sizeof(Var) - 1) / sizeof(Var);
- }
- #endif
- // If we bailed out, we will use the JIT frame's for..in enumerators
- uint forInVarCount = bailedOut? 0 : (this->executeFunction->GetForInLoopDepth() * (sizeof(Js::ForInObjectEnumerator) / sizeof(Var)));
- this->varAllocCount = k_stackFrameVarCount + localCount + this->executeFunction->GetOutParamMaxDepth() + forInVarCount +
- extraVarCount + this->executeFunction->GetInnerScopeCount();
- if (this->executeFunction->DoStackNestedFunc() && this->executeFunction->GetNestedCount() != 0)
- {
- // Track stack funcs...
- this->varAllocCount += (sizeof(StackScriptFunction) * this->executeFunction->GetNestedCount()) / sizeof(Var);
- if (!this->bailedOutOfInlinee)
- {
- // Frame display (if environment depth is statically known)...
- if (this->executeFunction->DoStackFrameDisplay())
- {
- uint16 envDepth = this->executeFunction->GetEnvDepth();
- Assert(envDepth != (uint16)-1);
- this->varAllocCount += sizeof(FrameDisplay) / sizeof(Var) + (envDepth + 1);
- }
- // ...and scope slots (if any)
- if (this->executeFunction->DoStackScopeSlots())
- {
- uint32 scopeSlots = this->executeFunction->scopeSlotArraySize;
- Assert(scopeSlots != 0);
- this->varAllocCount += scopeSlots + Js::ScopeSlots::FirstSlotIndex;
- }
- }
- }
- }
- InterpreterStackFrame *
- InterpreterStackFrame::Setup::InitializeAllocation(__in_ecount(varAllocCount) Var * allocation, bool initParams, bool profileParams, Var loopHeaderArray, DWORD_PTR stackAddr
- #if DBG
- , Var invalidStackVar
- #endif
- )
- {
- //
- // Initialize the new InterpreterStackFrame instance on the program stack.
- //
- //This will fail if InterpreterStackFrame ever gets a non-empty ctor (you'll need to use
- //placement_new(allocation, InterpreterStackFrame) instead, though that will cause problems
- //if the placement_new is surrounded by a try/finally since this would mix C++/SEH exception
- //handling.
- __analysis_assume(varAllocCount >= k_stackFrameVarCount + localCount);
- InterpreterStackFrame* newInstance = (InterpreterStackFrame*)allocation;
- newInstance->scriptContext = this->executeFunction->GetScriptContext();
- newInstance->m_inSlotsCount = this->inSlotsCount;
- newInstance->m_inParams = this->inParams;
- newInstance->m_callFlags = this->callFlags;
- newInstance->m_outParams = newInstance->m_localSlots + localCount;
- newInstance->m_outSp = newInstance->m_outParams;
- newInstance->m_outSpCached = nullptr;
- newInstance->m_arguments = NULL;
- newInstance->function = this->function;
- newInstance->m_functionBody = this->executeFunction;
- newInstance->inlineCaches = this->inlineCaches;
- newInstance->inlineCacheCount = this->inlineCacheCount;
- newInstance->currentLoopNum = LoopHeader::NoLoop;
- newInstance->currentLoopCounter = 0;
- newInstance->m_flags = InterpreterStackFrameFlags_None;
- newInstance->closureInitDone = false;
- newInstance->isParamScopeDone = false;
- newInstance->shouldCacheSP = true;
- #if ENABLE_PROFILE_INFO
- newInstance->switchProfileMode = false;
- newInstance->isAutoProfiling = false;
- newInstance->switchProfileModeOnLoopEndNumber = 0u - 1;
- #endif
- newInstance->ehBailoutData = nullptr;
- newInstance->nestedTryDepth = -1;
- newInstance->nestedCatchDepth = -1;
- newInstance->nestedFinallyDepth = -1;
- newInstance->retOffset = 0;
- newInstance->localFrameDisplay = nullptr;
- newInstance->localClosure = nullptr;
- newInstance->paramClosure = nullptr;
- newInstance->innerScopeArray = nullptr;
- bool doInterruptProbe = newInstance->scriptContext->GetThreadContext()->DoInterruptProbe(this->executeFunction);
- #if ENABLE_NATIVE_CODEGEN
- bool doJITLoopBody =
- !this->executeFunction->GetScriptContext()->GetConfig()->IsNoNative() &&
- !(this->executeFunction->GetHasTry() && (PHASE_OFF((Js::JITLoopBodyInTryCatchPhase), this->executeFunction) || this->executeFunction->GetHasFinally())) &&
- (this->executeFunction->ForceJITLoopBody() || this->executeFunction->IsJitLoopBodyPhaseEnabled()) &&
- !this->executeFunction->IsInDebugMode();
- #endif
- // Pick a version of the LoopBodyStart OpCode handlers that is hardcoded to do loop body JIT and
- // interrupt probes as needed.
- if (doInterruptProbe)
- {
- #if ENABLE_NATIVE_CODEGEN
- if (doJITLoopBody)
- {
- newInstance->opProfiledLoopBodyStart = &InterpreterStackFrame::ProfiledLoopBodyStart<true, true>;
- newInstance->opLoopBodyStart = &InterpreterStackFrame::LoopBodyStart<true, true>;
- }
- else
- #endif
- {
- #if ENABLE_PROFILE_INFO
- newInstance->opProfiledLoopBodyStart = &InterpreterStackFrame::ProfiledLoopBodyStart<true, false>;
- #endif
- newInstance->opLoopBodyStart = &InterpreterStackFrame::LoopBodyStart<true, false>;
- }
- }
- else
- {
- #if ENABLE_NATIVE_CODEGEN
- if (doJITLoopBody)
- {
- newInstance->opProfiledLoopBodyStart = &InterpreterStackFrame::ProfiledLoopBodyStart<false, true>;
- newInstance->opLoopBodyStart = &InterpreterStackFrame::LoopBodyStart<false, true>;
- }
- else
- #endif
- {
- #if ENABLE_PROFILE_INFO
- newInstance->opProfiledLoopBodyStart = &InterpreterStackFrame::ProfiledLoopBodyStart<false, false>;
- #endif
- newInstance->opLoopBodyStart = &InterpreterStackFrame::LoopBodyStart<false, false>;
- }
- }
- newInstance->loopHeaderArray = loopHeaderArray;
- newInstance->m_stackAddress = stackAddr;
- #if ENABLE_PROFILE_INFO
- // the savedLoopImplicitCallFlags is allocated at the end of the out param array
- newInstance->savedLoopImplicitCallFlags = nullptr;
- #endif
- char * nextAllocBytes = (char *)(newInstance->m_outParams + this->executeFunction->GetOutParamMaxDepth());
- // If we bailed out, we will use the JIT frame's for..in enumerators
- if (bailedOut || this->executeFunction->GetForInLoopDepth() == 0)
- {
- newInstance->forInObjectEnumerators = nullptr;
- }
- else
- {
- newInstance->forInObjectEnumerators = (ForInObjectEnumerator *)nextAllocBytes;
- nextAllocBytes += sizeof(ForInObjectEnumerator) * this->executeFunction->GetForInLoopDepth();
- }
- if (this->executeFunction->GetInnerScopeCount())
- {
- newInstance->innerScopeArray = (Var*)nextAllocBytes;
- nextAllocBytes += this->executeFunction->GetInnerScopeCount() * sizeof(Var);
- }
- if (this->executeFunction->DoStackNestedFunc() && this->executeFunction->GetNestedCount() != 0)
- {
- newInstance->InitializeStackFunctions((StackScriptFunction *)nextAllocBytes);
- nextAllocBytes = nextAllocBytes + sizeof(StackScriptFunction) * this->executeFunction->GetNestedCount();
- if (!this->bailedOutOfInlinee)
- {
- if (this->executeFunction->DoStackFrameDisplay())
- {
- uint16 envDepth = this->executeFunction->GetEnvDepth();
- Assert(envDepth != (uint16)-1);
- newInstance->localFrameDisplay = (FrameDisplay*)nextAllocBytes;
- nextAllocBytes += sizeof(FrameDisplay) + (envDepth + 1) * sizeof(Var);
- }
- if (this->executeFunction->DoStackScopeSlots())
- {
- uint32 scopeSlots = this->executeFunction->scopeSlotArraySize;
- Assert(scopeSlots != 0);
- ScopeSlots((Var*)nextAllocBytes).SetCount(scopeSlots);
- newInstance->localClosure = nextAllocBytes;
- nextAllocBytes += (scopeSlots + ScopeSlots::FirstSlotIndex) * sizeof(Var);
- }
- }
- }
- #if ENABLE_PROFILE_INFO
- if (Js::DynamicProfileInfo::EnableImplicitCallFlags(this->executeFunction))
- {
- /*
- __analysis_assume(varAllocCount == (k_stackFrameVarCount + localCount + executeFunction->GetOutParamMaxDepth()
- + ((sizeof(ImplicitCallFlags) * executeFunction->GetLoopCount() + sizeof(Var) - 1) / sizeof(Var))));
- */
- newInstance->savedLoopImplicitCallFlags = (ImplicitCallFlags *)nextAllocBytes;
- for (uint i = 0; i < this->executeFunction->GetLoopCount(); i++)
- {
- #pragma prefast(suppress:26015, "Above analysis assume doesn't work")
- newInstance->savedLoopImplicitCallFlags[i] = ImplicitCall_None;
- }
- }
- #endif
- #if DBG
- if (CONFIG_ISENABLED(InitializeInterpreterSlotsWithInvalidStackVarFlag))
- {
- // Fill the local slots with the invalid stack var so that we will crash deterministically if something goes wrong
- for (uint i = 0; i < localCount; ++i)
- {
- newInstance->m_localSlots[i] = invalidStackVar;
- }
- }
- else
- {
- memset(newInstance->m_localSlots, 0, sizeof(Js::Var) * localCount);
- }
- #else
- if (newInstance->m_functionBody->IsInDebugMode())
- {
- // In the debug mode zero out the local slot, so this could prevent locals being uninitialized in the case of setNextStatement.
- memset(newInstance->m_localSlots, 0, sizeof(Js::Var) * localCount);
- }
- // Zero out only the return slot. This is not a user local, so the byte code will not initialize
- // it to "undefined". And it's not an expression temp, so, for instance, a jitted loop body may expect
- // it to be valid on entry to the loop, where "valid" means either a var or null.
- newInstance->SetNonVarReg(0, NULL);
- #endif
- // Wasm doesn't use const table
- if (!executeFunction->IsWasmFunction())
- {
- // Initialize the low end of the local slots from the constant table.
- // Skip the slot for the return value register.
- this->executeFunction->InitConstantSlots(&newInstance->m_localSlots[FunctionBody::FirstRegSlot]);
- }
- // Set local FD/SS pointers to null until after we've successfully probed the stack in the process loop.
- // That way we avoid trying to box these structures before they've been initialized in the byte code.
- if (this->executeFunction->DoStackFrameDisplay())
- {
- newInstance->SetNonVarReg(executeFunction->GetLocalFrameDisplayRegister(), nullptr);
- }
- if (this->executeFunction->DoStackScopeSlots())
- {
- Assert(!executeFunction->HasScopeObject());
- newInstance->SetNonVarReg(executeFunction->GetLocalClosureRegister(), nullptr);
- }
- Var *prestDest = &newInstance->m_localSlots[this->executeFunction->GetConstantCount()];
- if (initParams)
- {
- #if ENABLE_PROFILE_INFO
- Assert(!this->executeFunction->NeedEnsureDynamicProfileInfo());
- #endif
- if (profileParams)
- {
- #if ENABLE_PROFILE_INFO
- Assert(this->executeFunction->HasExecutionDynamicProfileInfo());
- #endif
- FunctionBody* functionBody = this->executeFunction;
- InitializeParams(newInstance, [functionBody](Var param, ArgSlot index)
- {
- #if ENABLE_PROFILE_INFO
- functionBody->GetDynamicProfileInfo()->RecordParameterInfo(functionBody, index - 1, param);
- #endif
- }, &prestDest);
- }
- else
- {
- InitializeParams(newInstance, [](Var param, ArgSlot index) {}, &prestDest);
- }
- }
- if (this->executeFunction->GetHasRestParameter())
- {
- InitializeRestParam(newInstance, prestDest);
- }
- Js::RegSlot envReg = executeFunction->GetEnvRegister();
- if (envReg != Js::Constants::NoRegister && envReg < executeFunction->GetConstantCount())
- {
- Assert(this->executeFunction->GetThisRegisterForEventHandler() == Constants::NoRegister);
- // The correct FD (possibly distinct from the one on the function) is passed in the constant table.
- this->function->SetEnvironment((Js::FrameDisplay*)newInstance->GetNonVarReg(envReg));
- }
- return newInstance;
- }
- template <class Fn>
- void InterpreterStackFrame::Setup::InitializeParams(InterpreterStackFrame * newInstance, Fn callback, Var **pprestDest)
- {
- ArgSlot requiredInParamCount = executeFunction->GetInParamsCount();
- Assert(requiredInParamCount > 1);
- if (this->inSlotsCount >= requiredInParamCount)
- {
- Var * pArg = &newInstance->m_localSlots[executeFunction->GetConstantCount()];
- Var * paGivenSrc = this->inParams + 1;
- ArgSlot paramIndex = 1;
- do
- {
- Var src = *paGivenSrc++;
- callback(src, paramIndex);
- *pArg++ = src;
- paramIndex++;
- }
- while (paramIndex < requiredInParamCount);
- *pprestDest = pArg;
- }
- else
- {
- InitializeParamsAndUndef(newInstance, callback, pprestDest);
- }
- }
- template <class Fn>
- void InterpreterStackFrame::Setup::InitializeParamsAndUndef(InterpreterStackFrame * newInstance, Fn callback, Var **pprestDest)
- {
- Var * pArg = &newInstance->m_localSlots[executeFunction->GetConstantCount()];
- Var * paGivenSrc = this->inParams + 1;
- ArgSlot requiredInParamCount = executeFunction->GetInParamsCount();
- ArgSlot paramIndex = 1;
- while (paramIndex < this->inSlotsCount)
- {
- Var src = *paGivenSrc++;
- callback(src, paramIndex);
- *pArg++ = src;
- paramIndex++;
- }
- Var varUndef = executeFunction->GetScriptContext()->GetLibrary()->GetUndefined();
- do
- {
- callback(varUndef, paramIndex);
- *pArg++ = varUndef;
- paramIndex++;
- }
- while (paramIndex < requiredInParamCount);
- *pprestDest = pArg;
- }
- void InterpreterStackFrame::Setup::InitializeRestParam(InterpreterStackFrame * newInstance, Var *dest)
- {
- Var *src = this->inParams + executeFunction->GetInParamsCount();
- if (this->inSlotsCount > executeFunction->GetInParamsCount())
- {
- // Create the rest array and copy the args directly into the contiguous head segment.
- int excess = this->inSlotsCount - executeFunction->GetInParamsCount();
- *dest = JavascriptArray::OP_NewScArray(excess, executeFunction->GetScriptContext());
- JavascriptArray *array = static_cast<JavascriptArray *>(*dest);
- Var *elements = ((SparseArraySegment<Var>*)array->GetHead())->elements;
- js_memcpy_s(elements, excess * sizeof(Var), src, excess * sizeof(Var));
- }
- else
- {
- // Rest is an empty array when there are no excess parameters.
- *dest = JavascriptArray::OP_NewScArray(0, executeFunction->GetScriptContext());
- }
- }
- FrameDisplay * InterpreterStackFrame::GetEnvForEvalCode()
- {
- FrameDisplay *pScope;
- if (m_functionBody->GetIsStrictMode() && m_functionBody->GetIsGlobalFunc())
- {
- pScope = this->GetLocalFrameDisplay();
- }
- else
- {
- pScope = (FrameDisplay*)this->LdEnv();
- }
- return pScope;
- }
- void InterpreterStackFrame::InitializeClosures()
- {
- FunctionBody *executeFunction = this->function->GetFunctionBody();
- Var environment;
- if (executeFunction->IsParamAndBodyScopeMerged())
- {
- this->SetIsParamScopeDone(true);
- }
- RegSlot thisRegForEventHandler = executeFunction->GetThisRegisterForEventHandler();
- if (thisRegForEventHandler != Constants::NoRegister)
- {
- Var varThis = OP_ArgIn0();
- SetReg(thisRegForEventHandler, varThis);
- environment = JavascriptOperators::OP_LdHandlerScope(varThis, GetScriptContext());
- this->SetEnv((FrameDisplay*)environment);
- }
- else if (this->paramClosure != nullptr)
- {
- // When paramClosure is non-null we are calling this method to initialize the closure for body scope.
- // In this case we have to use the param scope's closure as the parent for the body scope's frame display.
- Assert(!executeFunction->IsParamAndBodyScopeMerged());
- environment = this->GetLocalFrameDisplay();
- }
- else
- {
- environment = this->LdEnv();
- }
- Var funcExprScope = nullptr;
- Js::RegSlot funcExprScopeReg = executeFunction->GetFuncExprScopeRegister();
- if (funcExprScopeReg != Constants::NoRegister && this->paramClosure == nullptr)
- {
- // t0 = NewPseudoScope
- // t1 = LdFrameDisplay t0 env
- funcExprScope = JavascriptOperators::OP_NewPseudoScope(GetScriptContext());
- SetReg(funcExprScopeReg, funcExprScope);
- }
- RegSlot closureReg = executeFunction->GetLocalClosureRegister();
- if (closureReg != Js::Constants::NoRegister)
- {
- Assert(closureReg >= executeFunction->GetConstantCount());
- if (executeFunction->HasScopeObject())
- {
- this->NewScopeObject();
- }
- else
- {
- this->NewScopeSlots();
- }
- this->SetNonVarReg(closureReg, nullptr);
- }
- Js::RegSlot frameDisplayReg = executeFunction->GetLocalFrameDisplayRegister();
- if (frameDisplayReg != Js::Constants::NoRegister)
- {
- Assert(frameDisplayReg >= executeFunction->GetConstantCount());
- if (funcExprScope != nullptr)
- {
- environment = OP_LdFrameDisplay(funcExprScope, environment, GetScriptContext());
- }
- if (closureReg != Js::Constants::NoRegister)
- {
- void *argHead = this->GetLocalClosure();
- environment = this->NewFrameDisplay(argHead, environment);
- }
- this->SetLocalFrameDisplay((Js::FrameDisplay*)environment);
- this->SetNonVarReg(frameDisplayReg, nullptr);
- }
- this->closureInitDone = true;
- }
- #ifdef _M_IX86
- #ifdef ASMJS_PLAT
- int InterpreterStackFrame::GetAsmJsArgSize(AsmJsCallStackLayout* stack)
- {
- JavascriptFunction * func = stack->functionObject;
- AsmJsFunctionInfo* asmInfo = func->GetFunctionBody()->GetAsmJsFunctionInfo();
- uint argSize = (uint)(asmInfo->GetArgByteSize());
- argSize = ::Math::Align<int32>(argSize, 8);
- // 2 * sizeof(Var) is for functionObject, and another push that DynamicInterpreterThunk does
- return argSize + 2 * sizeof(Var);
- }
- int InterpreterStackFrame::GetDynamicRetType(AsmJsCallStackLayout* stack)
- {
- return GetRetType(stack->functionObject);
- }
- int InterpreterStackFrame::GetRetType(JavascriptFunction* func)
- {
- AsmJsFunctionInfo* asmInfo = func->GetFunctionBody()->GetAsmJsFunctionInfo();
- return asmInfo->GetReturnType().which();
- }
- DWORD InterpreterStackFrame::GetAsmJsReturnValueOffset(AsmJsCallStackLayout* stack)
- {
- JavascriptFunction * func = stack->functionObject;
- ScriptContext* scriptContext = func->GetScriptContext();
- return (DWORD)scriptContext + ScriptContext::GetAsmJsReturnValueOffset();
- }
- #ifdef ASMJS_PLAT
- /*
- AsmInterpreterThunk
- -------------------
- This is the entrypoint for all Asm Interpreter calls (external and internal)
- TODO - Make this a dynamic Interpreter thunk to support ETW
- Functionality:
- 1) Prolog
- 2) call AsmInterpreter passing the function object
- 3) Get The return type
- 4) Check for Double or Float return type
- 5) If true then retrieve the value stored at a constant offset from the ScriptContext
- 6) Get Argument Size for callee cleanup
- 7) EpiLog
- a) Retrieve the frame pointer
- b) Store the return address in register (edx)
- c) Clean the arguments based on the arguments size
- d) push the return address back into the stack
- */
- __declspec(naked)
- void InterpreterStackFrame::InterpreterAsmThunk(AsmJsCallStackLayout* layout)
- {
- enum {
- IsFloat = 1 << AsmJsRetType::Float,
- IsDouble = 1 << AsmJsRetType::Double,
- IsInt64 = 1 << AsmJsRetType::Int64,
- IsSimd =
- 1 << AsmJsRetType::Int32x4 |
- 1 << AsmJsRetType::Bool32x4 |
- 1 << AsmJsRetType::Bool16x8 |
- 1 << AsmJsRetType::Bool8x16 |
- 1 << AsmJsRetType::Float32x4 |
- 1 << AsmJsRetType::Float64x2 |
- 1 << AsmJsRetType::Int16x8 |
- 1 << AsmJsRetType::Int8x16 |
- 1 << AsmJsRetType::Uint32x4 |
- 1 << AsmJsRetType::Uint16x8 |
- 1 << AsmJsRetType::Uint8x16,
- CannotUseEax = IsFloat | IsDouble | IsInt64 | IsSimd
- };
- //Prolog
- __asm
- {
- //Prologue
- push ebp;
- mov ebp, esp;
- push layout; // push stack layout
- call InterpreterStackFrame::AsmJsInterpreter;
- push eax; // push the return value into the stack
- push layout; // push arg1
- call InterpreterStackFrame::GetDynamicRetType;
- // setup return type mask from enum. e.g.: 3 => 0x8
- mov ecx, eax;
- mov eax, 1
- shl eax, cl;
- and eax, CannotUseEax; // Keep only types that need to read from memory
- jz end; // if nothing is left, that means we simply use eax as return value
- push eax; // save return type mask
- push layout; // push arg1
- call InterpreterStackFrame::GetAsmJsReturnValueOffset;
- pop ecx; // restore return type mask
- and ecx, ~IsFloat; // Remove float bit
- jz ToXmmWord; // if nothing is left, that means the return type is float
- and ecx, ~IsDouble; // Remove double bit
- jz ToXmmDWord; // if nothing is left, that means the return type is double
- and ecx, ~IsInt64; // Remove int64 bit
- jz readHighWord; // if nothing is left, that means the return type is int64
- jmp doSimd; // Otherwise, the return type is simd
- ToXmmWord:
- // float
- cvtsd2ss xmm0, [eax];
- jmp end;
- ToXmmDWord:
- // double
- movsd xmm0, [eax];
- jmp end;
- readHighWord:
- // save high int64 bits into ecx
- mov edx, [eax + 4];
- jmp end;
- doSimd:
- // simd value
- movups xmm0, [eax];
- end:
- push edx; // save possible int64 return value
- push layout;
- call InterpreterStackFrame::GetAsmJsArgSize;
- mov ecx, eax;
- pop edx; // restore possible int64 return value
- pop eax; // pop the return value from AsmJsInterpreter to eax
- // Epilog, callee cleanup
- mov esp, ebp;
- pop ebp;
- // we need to move stack around in order to do callee cleanup
- // unfortunately, we don't really have enough registers to do this cleanly
- //
- // we are rearranging the stack from this:
- // 0x14 caller push scriptArg1
- // 0x10 caller push functionObject
- // 0x0C DynamicInterpreterThunk return address
- // 0x08 DynamicInterpreterThunk push ebp
- // 0x04 DynamicInterpreterThunk push functionObject
- // 0x00 InterpreterAsmThunk return address <- stack pointer
- // to this:
- // 0x14 DynamicInterpreterThunk return address
- // 0x10 DynamicInterpreterThunk push ebp
- // 0x0C InterpreterAsmThunk return address <- stack pointer
- push eax; // save eax
- push edx; // save edx
- // we have to do +0x8 on all stack addresses because we saved 2 registers
- lea eax, [esp + ecx * 1 + (0x8 + 0x8)]; // eax will be our stack destination. we need to move backwards because memory might overlap
- mov edx, [esp + (0xC + 0x8)];
- mov [eax], edx; // move the dynamic interpreter thunk return location
- sub eax, 0x4;
- mov edx, [esp + (0x8 + 0x8)];
- mov [eax], edx; // move the dynamic interpreter thunk "push ebp" location
- // skip "push functionObject"
- sub eax, 0x4;
- mov edx, [esp + (0x0 + 0x8)];
- mov [eax], edx; // move the return location
- pop edx; // restore possible int64 return value
- pop eax; // restore return value
- add esp, ecx; // cleanup arguments
- ret;
- }
- }
- #endif
- #endif
- #endif
- #if DYNAMIC_INTERPRETER_THUNK
- #ifdef _M_IX86
- __declspec(naked)
- Var InterpreterStackFrame::DelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
- {
- __asm
- {
- push ebp
- mov ebp, esp
- push [esp+8] // push function object
- call InterpreterStackFrame::EnsureDynamicInterpreterThunk;
- #ifdef _CONTROL_FLOW_GUARD
- // verify that the call target is valid
- push eax
- mov ecx, eax
- call[__guard_check_icall_fptr]
- pop eax
- #endif
- pop ebp
- jmp eax
- }
- }
- #endif
- #endif
- #if ENABLE_PROFILE_INFO
- JavascriptMethod InterpreterStackFrame::EnsureDynamicInterpreterThunk(Js::ScriptFunction * function)
- {
- #if DYNAMIC_INTERPRETER_THUNK
- Assert(function);
- Js::FunctionBody *functionBody = function->GetFunctionBody();
- JavascriptMethod entrypoint = functionBody->EnsureDynamicInterpreterThunk(function->GetFunctionEntryPointInfo());
- Assert(!IsDelayDynamicInterpreterThunk(functionBody->GetDirectEntryPoint(function->GetEntryPointInfo())));
- if (function->GetEntryPoint() == InterpreterStackFrame::DelayDynamicInterpreterThunk)
- {
- // If we are not profiling, or the function object is not cross site, this is the direct entry point.
- // Change the entry point on the object
- Assert(functionBody->GetDirectEntryPoint(function->GetEntryPointInfo()) == entrypoint);
- function->ChangeEntryPoint(function->GetEntryPointInfo(), entrypoint);
- }
- // Return the original entry point to be called
- return entrypoint;
- #else
- return function->GetEntryPoint();
- #endif
- }
- #endif
- bool InterpreterStackFrame::IsDelayDynamicInterpreterThunk(JavascriptMethod entryPoint)
- {
- return
- #if DYNAMIC_INTERPRETER_THUNK
- #if _M_X64
- entryPoint == InterpreterStackFrame::AsmJsDelayDynamicInterpreterThunk ||
- #endif
- entryPoint == InterpreterStackFrame::DelayDynamicInterpreterThunk;
- #else
- false;
- #endif
- }
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- THREAD_LOCAL int InterpreterThunkStackCountTracker::s_count = 0;
- #endif
- #if DYNAMIC_INTERPRETER_THUNK
- Var InterpreterStackFrame::InterpreterThunk(JavascriptCallStackLayout* layout)
- {
- Js::ScriptFunction * function = Js::ScriptFunction::FromVar(layout->functionObject);
- Js::ArgumentReader args(&layout->callInfo, layout->args);
- void* localReturnAddress = _ReturnAddress();
- void* localAddressOfReturnAddress = _AddressOfReturnAddress();
- return InterpreterHelper(function, args, localReturnAddress, localAddressOfReturnAddress);
- }
- #else
- #pragma optimize("", off)
- Var InterpreterStackFrame::InterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
- {
- ARGUMENTS(args, callInfo);
- void* localReturnAddress = _ReturnAddress();
- void* localAddressOfReturnAddress = _AddressOfReturnAddress();
- Assert(ScriptFunction::Is(function));
- return InterpreterHelper(ScriptFunction::FromVar(function), args, localReturnAddress, localAddressOfReturnAddress);
- }
- #pragma optimize("", on)
- #endif
- Var InterpreterStackFrame::InterpreterHelper(ScriptFunction* function, ArgumentReader args, void* returnAddress, void* addressOfReturnAddress, const bool isAsmJs)
- {
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- // Support for simulating partially initialized interpreter stack frame.
- InterpreterThunkStackCountTracker tracker;
- if (CONFIG_ISENABLED(InjectPartiallyInitializedInterpreterFrameErrorFlag) &&
- CONFIG_FLAG(InjectPartiallyInitializedInterpreterFrameError) == InterpreterThunkStackCountTracker::GetCount())
- {
- switch (CONFIG_FLAG(InjectPartiallyInitializedInterpreterFrameErrorType))
- {
- case 0:
- DebugBreak();
- break;
- case 1:
- Js::JavascriptError::MapAndThrowError(function->GetScriptContext(), VBSERR_InternalError);
- break;
- default:
- DebugBreak();
- }
- }
- #endif
- ScriptContext* functionScriptContext = function->GetScriptContext();
- ThreadContext * threadContext = functionScriptContext->GetThreadContext();
- Assert(!threadContext->IsDisableImplicitException());
- functionScriptContext->VerifyAlive(!function->IsExternal());
- Assert(threadContext->IsScriptActive());
- Assert(threadContext->IsInScript());
- FunctionBody* executeFunction = JavascriptFunction::FromVar(function)->GetFunctionBody();
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- if (!isAsmJs && executeFunction->IsInDebugMode() != functionScriptContext->IsScriptContextInDebugMode()) // debug mode mismatch
- {
- if (executeFunction->GetUtf8SourceInfo()->GetIsLibraryCode())
- {
- Assert(!executeFunction->IsInDebugMode()); // Library script byteCode is never in debug mode
- }
- else
- {
- Throw::FatalInternalError();
- }
- }
- #endif
- if (executeFunction->GetInterpretedCount() == 0)
- {
- executeFunction->TraceInterpreterExecutionMode();
- }
- class AutoRestore
- {
- private:
- ThreadContext *const threadContext;
- const uint8 savedLoopDepth;
- public:
- AutoRestore(ThreadContext *const threadContext, FunctionBody *const executeFunction)
- : threadContext(threadContext),
- savedLoopDepth(threadContext->LoopDepth())
- {
- if (savedLoopDepth != 0 && !executeFunction->GetIsAsmJsFunction())
- {
- executeFunction->SetWasCalledFromLoop();
- }
- }
- ~AutoRestore()
- {
- threadContext->SetLoopDepth(savedLoopDepth);
- }
- } autoRestore(threadContext, executeFunction);
- #if ENABLE_PROFILE_INFO
- DynamicProfileInfo * dynamicProfileInfo = nullptr;
- const bool doProfile = executeFunction->GetInterpreterExecutionMode(false) == ExecutionMode::ProfilingInterpreter ||
- (executeFunction->IsInDebugMode() && DynamicProfileInfo::IsEnabled(executeFunction));
- if (doProfile)
- {
- #if !DYNAMIC_INTERPRETER_THUNK
- executeFunction->EnsureDynamicProfileInfo();
- #endif
- dynamicProfileInfo = executeFunction->GetDynamicProfileInfo();
- threadContext->ClearImplicitCallFlags();
- }
- #else
- const bool doProfile = false;
- #endif
- executeFunction->IncreaseInterpretedCount();
- #ifdef BGJIT_STATS
- functionScriptContext->interpretedCount++;
- functionScriptContext->maxFuncInterpret = max(functionScriptContext->maxFuncInterpret, executeFunction->GetInterpretedCount());
- #endif
- AssertMsg(!executeFunction->IsDeferredParseFunction(),
- "Non-intrinsic functions must provide byte-code to execute");
- executeFunction->BeginExecution();
- bool fReleaseAlloc = false;
- InterpreterStackFrame* newInstance = nullptr;
- Var* allocation = nullptr;
- if (!isAsmJs && executeFunction->IsCoroutine())
- {
- // If the FunctionBody is a generator then this call is being made by one of the three
- // generator resuming methods: next(), throw(), or return(). They all pass the generator
- // object as the first of two arguments. The real user arguments are obtained from the
- // generator object. The second argument is the ResumeYieldData which is only needed
- // when resuming a generator and so it only used here if a frame already exists on the
- // generator object.
- AssertMsg(args.Info.Count == 2, "Generator ScriptFunctions should only be invoked by generator APIs with the pair of arguments they pass in -- the generator object and a ResumeYieldData pointer");
- JavascriptGenerator* generator = JavascriptGenerator::FromVar(args[0]);
- newInstance = generator->GetFrame();
- if (newInstance != nullptr)
- {
- ResumeYieldData* resumeYieldData = static_cast<ResumeYieldData*>(args[1]);
- newInstance->SetNonVarReg(executeFunction->GetYieldRegister(), resumeYieldData);
- // The debugger relies on comparing stack addresses of frames to decide when a step_out is complete so
- // give the InterpreterStackFrame a legit enough stack address to make this comparison work.
- newInstance->m_stackAddress = reinterpret_cast<DWORD_PTR>(&generator);
- }
- else
- {
- //
- // Allocate a new InterpreterStackFrame instance on the recycler heap.
- // It will live with the JavascriptGenerator object.
- //
- Arguments generatorArgs = generator->GetArguments();
- InterpreterStackFrame::Setup setup(function, generatorArgs);
- size_t varAllocCount = setup.GetAllocationVarCount();
- size_t varSizeInBytes = varAllocCount * sizeof(Var);
- DWORD_PTR stackAddr = reinterpret_cast<DWORD_PTR>(&generator); // as mentioned above, use any stack address from this frame to ensure correct debugging functionality
- Var loopHeaderArray = executeFunction->GetHasAllocatedLoopHeaders() ? executeFunction->GetLoopHeaderArrayPtr() : nullptr;
- allocation = RecyclerNewPlus(functionScriptContext->GetRecycler(), varSizeInBytes, Var);
- AnalysisAssert(allocation);
- #if DBG
- // Allocate invalidVar on GC instead of stack since this InterpreterStackFrame will out live the current real frame
- Js::RecyclableObject* invalidVar = (Js::RecyclableObject*)RecyclerNewPlusLeaf(functionScriptContext->GetRecycler(), sizeof(Js::RecyclableObject), Var);
- AnalysisAssert(invalidVar);
- memset(reinterpret_cast<void*>(invalidVar), 0xFE, sizeof(Js::RecyclableObject));
- newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns(), doProfile, loopHeaderArray, stackAddr, invalidVar);
- #else
- newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns(), doProfile, loopHeaderArray, stackAddr);
- #endif
- newInstance->m_reader.Create(executeFunction);
- generator->SetFrame(newInstance);
- }
- }
- else
- {
- InterpreterStackFrame::Setup setup(function, args);
- size_t varAllocCount = setup.GetAllocationVarCount();
- size_t varSizeInBytes = varAllocCount * sizeof(Var);
- //
- // Allocate a new InterpreterStackFrame instance on the interpreter's virtual stack.
- //
- DWORD_PTR stackAddr;
- // If the locals area exceeds a certain limit, allocate it from a private arena rather than
- // this frame. The current limit is based on an old assert on the number of locals we would allow here.
- if (varAllocCount > InterpreterStackFrame::LocalsThreshold)
- {
- ArenaAllocator *tmpAlloc = nullptr;
- fReleaseAlloc = functionScriptContext->EnsureInterpreterArena(&tmpAlloc);
- allocation = (Var*)tmpAlloc->Alloc(varSizeInBytes);
- stackAddr = reinterpret_cast<DWORD_PTR>(&allocation); // use a stack address so the debugger stepping logic works (step-out, for example, compares stack depths to determine when to complete the step)
- }
- else
- {
- PROBE_STACK_PARTIAL_INITIALIZED_INTERPRETER_FRAME(functionScriptContext, Js::Constants::MinStackInterpreter + varSizeInBytes);
- allocation = (Var*)_alloca(varSizeInBytes);
- stackAddr = reinterpret_cast<DWORD_PTR>(allocation);
- }
- /*
- * If the function has any loop headers, we allocate an array for the loop headers wrappers, and
- * reference the wrappers in the array. We then push the pointer to the array onto the stack itself.
- * We do this so that while the function is being interpreted, we don't want the jitted loop
- * bodies to be collected, even if the loop body isn't being executed. The loop body will
- * get collected when the function has been JITted, and when the function exits the interpreter.
- * The array contains nulls if the loop body isn't jitted (or hasn't been jitted yet) but
- * it's cheaper to just copy them all into the recycler array rather than just the ones that
- * have been jitted.
- */
- Var loopHeaderArray = nullptr;
- if (executeFunction->GetHasAllocatedLoopHeaders())
- {
- // Loop header array is recycler allocated, so we push it on the stack
- // When we scan the stack, we'll recognize it as a recycler allocated
- // object, and mark it's contents and keep the individual loop header
- // wrappers alive
- loopHeaderArray = executeFunction->GetLoopHeaderArrayPtr();
- }
- #if DBG
- Js::RecyclableObject * invalidStackVar = (Js::RecyclableObject*)_alloca(sizeof(Js::RecyclableObject));
- memset(reinterpret_cast<void*>(invalidStackVar), 0xFE, sizeof(Js::RecyclableObject));
- newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns() && !isAsmJs, doProfile, loopHeaderArray, stackAddr, invalidStackVar);
- #else
- newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns() && !isAsmJs, doProfile, loopHeaderArray, stackAddr);
- #endif
- newInstance->m_reader.Create(executeFunction);
- }
- //
- // Execute the function's byte-code, returning the return-value:
- // - Mark that the function is current executing and may not be modified.
- //
- #if ENABLE_TTD
- TTD::TTDExceptionFramePopper exceptionFramePopper;
- if(SHOULD_DO_TTD_STACK_STMT_OP(functionScriptContext))
- {
- bool isInFinally = ((newInstance->m_flags & Js::InterpreterStackFrameFlags_WithinFinallyBlock) == Js::InterpreterStackFrameFlags_WithinFinallyBlock);
- threadContext->TTDLog->PushCallEvent(function, args.Info.Count, args.Values, isInFinally);
- exceptionFramePopper.PushInfo(threadContext->TTDLog, function);
- }
- #endif
- Var aReturn = nullptr;
- {
- if (!isAsmJs && executeFunction->IsInDebugMode())
- {
- #if DYNAMIC_INTERPRETER_THUNK
- PushPopFrameHelper pushPopFrameHelper(newInstance, returnAddress, addressOfReturnAddress);
- aReturn = newInstance->DebugProcess();
- #else
- aReturn = newInstance->DebugProcessThunk(_ReturnAddress(), _AddressOfReturnAddress());
- #endif
- }
- else
- {
- #if DYNAMIC_INTERPRETER_THUNK
- PushPopFrameHelper pushPopFrameHelper(newInstance, returnAddress, addressOfReturnAddress);
- aReturn = newInstance->Process();
- #else
- aReturn = newInstance->ProcessThunk(_ReturnAddress(), _AddressOfReturnAddress());
- #endif
- }
- }
- executeFunction->EndExecution();
- #if ENABLE_TTD
- if(SHOULD_DO_TTD_STACK_STMT_OP(functionScriptContext))
- {
- exceptionFramePopper.PopInfo();
- threadContext->TTDLog->PopCallEvent(function, aReturn);
- }
- #endif
- if (fReleaseAlloc)
- {
- functionScriptContext->ReleaseInterpreterArena();
- }
- #if ENABLE_PROFILE_INFO
- if (doProfile)
- {
- dynamicProfileInfo->RecordImplicitCallFlags(threadContext->GetImplicitCallFlags());
- }
- #endif
- if (isAsmJs)
- {
- return newInstance;
- }
- return aReturn;
- }
- #ifdef ASMJS_PLAT
- template<>
- int InterpreterStackFrame::GetAsmJsRetVal<int>(InterpreterStackFrame* instance)
- {
- return instance->m_localIntSlots[0];
- }
- template<>
- int64 InterpreterStackFrame::GetAsmJsRetVal<int64>(InterpreterStackFrame* instance)
- {
- return instance->m_localInt64Slots[0];
- }
- template<>
- double InterpreterStackFrame::GetAsmJsRetVal<double>(InterpreterStackFrame* instance)
- {
- return instance->m_localDoubleSlots[0];
- }
- template<>
- float InterpreterStackFrame::GetAsmJsRetVal<float>(InterpreterStackFrame* instance)
- {
- return instance->m_localFloatSlots[0];
- }
- template<>
- AsmJsSIMDValue InterpreterStackFrame::GetAsmJsRetVal<AsmJsSIMDValue>(InterpreterStackFrame* instance)
- {
- return instance->m_localSimdSlots[0];
- }
- #if _M_IX86 || _M_X64
- template<>
- X86SIMDValue InterpreterStackFrame::GetAsmJsRetVal<X86SIMDValue>(InterpreterStackFrame* instance)
- {
- return X86SIMDValue::ToX86SIMDValue(instance->m_localSimdSlots[0]);
- }
- #endif
- #if _M_IX86
- int InterpreterStackFrame::AsmJsInterpreter(AsmJsCallStackLayout* stack)
- {
- ScriptFunction * function = (ScriptFunction*)stack->functionObject;
- Var* paramsAddr = stack->args;
- int flags = CallFlags_Value;
- ArgSlot nbArgs = UInt16Math::Add(function->GetFunctionBody()->GetAsmJsFunctionInfo()->GetArgCount(), 1);
- CallInfo callInfo((CallFlags)flags, nbArgs);
- ArgumentReader args(&callInfo, paramsAddr);
- void* returnAddress = _ReturnAddress();
- void* addressOfReturnAddress = _AddressOfReturnAddress();
- #if ENABLE_PROFILE_INFO
- function->GetFunctionBody()->EnsureDynamicProfileInfo();
- #endif
- InterpreterStackFrame* newInstance = (InterpreterStackFrame*)InterpreterHelper(function, args, returnAddress, addressOfReturnAddress, true);
- //Handle return value
- AsmJsRetType::Which retType = (AsmJsRetType::Which) GetRetType(function);
- int retVal = 0;
- switch (retType)
- {
- case AsmJsRetType::Int32x4:
- case AsmJsRetType::Bool32x4:
- case AsmJsRetType::Bool16x8:
- case AsmJsRetType::Bool8x16:
- case AsmJsRetType::Float32x4:
- case AsmJsRetType::Float64x2:
- case AsmJsRetType::Int16x8:
- case AsmJsRetType::Int8x16:
- case AsmJsRetType::Uint32x4:
- case AsmJsRetType::Uint16x8:
- case AsmJsRetType::Uint8x16:
- if (function->GetScriptContext()->GetConfig()->IsSimdjsEnabled())
- {
- function->GetScriptContext()->asmJsReturnValue.simdVal = GetAsmJsRetVal<AsmJsSIMDValue>(newInstance);
- break;
- }
- Assert(UNREACHED);
- // double return
- case AsmJsRetType::Double:
- function->GetScriptContext()->asmJsReturnValue.dbVal = GetAsmJsRetVal<double>(newInstance);
- break;
- // float return
- case AsmJsRetType::Float:
- function->GetScriptContext()->asmJsReturnValue.dbVal = (double)GetAsmJsRetVal<float>(newInstance);
- break;
- // signed or void return
- case AsmJsRetType::Signed:
- case AsmJsRetType::Void:
- retVal = GetAsmJsRetVal<int>(newInstance);
- break;
- case AsmJsRetType::Int64:
- {
- int64 int64RetVal = GetAsmJsRetVal<int64>(newInstance);
- function->GetScriptContext()->asmJsReturnValue.int64Val = int64RetVal;
- // put the lower bits into eax
- // we'll read the higher bits from memory
- retVal = (int)int64RetVal;
- break;
- }
- default:
- Assume(false);
- }
- return retVal;
- }
- #elif _M_X64
- typedef double(*AsmJsInterpreterDoubleEP)(AsmJsCallStackLayout*, void *);
- typedef float(*AsmJsInterpreterFloatEP)(AsmJsCallStackLayout*, void *);
- typedef int(*AsmJsInterpreterIntEP)(AsmJsCallStackLayout*, void *);
- typedef int64(*AsmJsInterpreterInt64EP)(AsmJsCallStackLayout*, void *);
- void * InterpreterStackFrame::GetAsmJsInterpreterEntryPoint(AsmJsCallStackLayout* stack)
- {
- JavascriptFunction * function = stack->functionObject;
- void * entryPoint = nullptr;
- switch (function->GetFunctionBody()->GetAsmJsFunctionInfo()->GetReturnType().which())
- {
- case Js::AsmJsRetType::Double:
- {
- entryPoint = (void*)(AsmJsInterpreterDoubleEP)Js::InterpreterStackFrame::AsmJsInterpreter < double > ;
- break;
- }
- case Js::AsmJsRetType::Float:
- {
- entryPoint = (void*)(AsmJsInterpreterFloatEP)Js::InterpreterStackFrame::AsmJsInterpreter < float > ;
- break;
- }
- case Js::AsmJsRetType::Signed:
- case Js::AsmJsRetType::Void:
- {
- entryPoint = (void*)(AsmJsInterpreterIntEP)Js::InterpreterStackFrame::AsmJsInterpreter < int > ;
- break;
- }
- case Js::AsmJsRetType::Int64:
- {
- entryPoint = (void*)(AsmJsInterpreterInt64EP)Js::InterpreterStackFrame::AsmJsInterpreter < int64 > ;
- break;
- }
- case Js::AsmJsRetType::Int32x4:
- case Js::AsmJsRetType::Bool32x4:
- case Js::AsmJsRetType::Bool16x8:
- case Js::AsmJsRetType::Bool8x16:
- case Js::AsmJsRetType::Float32x4:
- case Js::AsmJsRetType::Float64x2:
- case Js::AsmJsRetType::Int16x8:
- case Js::AsmJsRetType::Int8x16:
- case Js::AsmJsRetType::Uint32x4:
- case Js::AsmJsRetType::Uint16x8:
- case Js::AsmJsRetType::Uint8x16:
- {
- entryPoint = (void*)Js::InterpreterStackFrame::AsmJsInterpreterSimdJs;
- break;
- }
- default:
- Assume(UNREACHED);
- }
- return entryPoint;
- }
- template<typename T>
- T InterpreterStackFrame::AsmJsInterpreter(AsmJsCallStackLayout* layout)
- {
- Js::ScriptFunction * function = Js::ScriptFunction::FromVar(layout->functionObject);
- int flags = CallFlags_Value;
- ArgSlot nbArgs = UInt16Math::Add(function->GetFunctionBody()->GetAsmJsFunctionInfo()->GetArgCount(), 1);
- CallInfo callInfo((CallFlags)flags, nbArgs);
- ArgumentReader args(&callInfo, (Var*)layout->args);
- void* returnAddress = _ReturnAddress();
- void* addressOfReturnAddress = _AddressOfReturnAddress();
- function->GetFunctionBody()->EnsureDynamicProfileInfo();
- InterpreterStackFrame* newInstance = (InterpreterStackFrame*)InterpreterHelper(function, args, returnAddress, addressOfReturnAddress, true);
- return GetAsmJsRetVal<T>(newInstance);
- }
- __m128 InterpreterStackFrame::AsmJsInterpreterSimdJs(AsmJsCallStackLayout* layout)
- {
- return AsmJsInterpreter<X86SIMDValue>(layout).m128_value;
- }
- #endif
- #endif
- ///----------------------------------------------------------------------------
- ///
- /// InterpreterStackFrame::SetOut()
- ///
- /// SetOut() change the Var value stored in the specified "out parameter"
- /// register.
- ///
- ///----------------------------------------------------------------------------
- inline void InterpreterStackFrame::SetOut(ArgSlot outRegisterID, Var aValue)
- {
- //
- // The "out" parameter slots are located at the end of the local register range, counting
- // forwards. This results in the "in" parameter slots being disjoint from the rest of the
- // InterpreterStackFrame.
- // ..., InterpreterStackFrame A, Locals A[], ..., Out A:0, Out A:1, Out A:2, ...
- // | In B:0, In B:1, ..., InterpreterStackFrame B, Locals B[], ...
- // (current 'this') |
- // (new 'this' after call)
- //
- Assert(m_outParams + outRegisterID < m_outSp);
- m_outParams[outRegisterID] = aValue;
- }
- inline void InterpreterStackFrame::SetOut(ArgSlot_OneByte outRegisterID, Var aValue)
- {
- Assert(m_outParams + outRegisterID < m_outSp);
- m_outParams[outRegisterID] = aValue;
- }
- inline void InterpreterStackFrame::OP_SetOutAsmDb( RegSlot outRegisterID, double val )
- {
- Assert(m_outParams + outRegisterID < m_outSp);
- m_outParams[outRegisterID] = JavascriptNumber::NewWithCheck( val, scriptContext );
- }
- inline void InterpreterStackFrame::OP_SetOutAsmInt( RegSlot outRegisterID, int val )
- {
- Assert( m_outParams + outRegisterID < m_outSp );
- m_outParams[outRegisterID] = JavascriptNumber::ToVar( val, scriptContext );
- }
- void InterpreterStackFrame::OP_SetOutAsmFlt(RegSlot outRegisterID, float val)
- {
- OP_SetOutAsmDb(outRegisterID, (double)val);
- }
- inline void InterpreterStackFrame::OP_I_SetOutAsmFlt(RegSlot outRegisterID, float val)
- {
- Assert(m_outParams + outRegisterID < m_outSp);
- *(float*)(&(m_outParams[outRegisterID])) = val;
- }
- inline void InterpreterStackFrame::OP_I_SetOutAsmLong(RegSlot outRegisterID, int64 val)
- {
- Assert(m_outParams + outRegisterID < m_outSp);
- *(int64*)(&(m_outParams[outRegisterID])) = val;
- }
- inline void InterpreterStackFrame::OP_I_SetOutAsmInt(RegSlot outRegisterID, int val)
- {
- Assert(m_outParams + outRegisterID < m_outSp);
- *(int*)(&(m_outParams[outRegisterID])) = val;
- }
- inline void InterpreterStackFrame::OP_I_SetOutAsmDb(RegSlot outRegisterID, double val)
- {
- Assert(m_outParams + outRegisterID < m_outSp);
- *(double*)(&(m_outParams[outRegisterID])) = val;
- }
- inline void InterpreterStackFrame::OP_I_SetOutAsmSimd(RegSlot outRegisterID, AsmJsSIMDValue val)
- {
- Assert(m_outParams + outRegisterID < m_outSp);
- *(AsmJsSIMDValue*)(&(m_outParams[outRegisterID])) = val;
- }
- template<bool toJs>
- void InterpreterStackFrame::OP_InvalidWasmTypeConversion(...)
- {
- // Right now the only invalid wasm type conversion is with int64
- const char16* fromType = toJs ? _u("int64") : _u("Javascript Variable");
- const char16* toType = toJs ? _u("Javascript Variable") : _u("int64");
- JavascriptError::ThrowTypeErrorVar(scriptContext, WASMERR_InvalidTypeConversion, fromType, toType);
- }
- // This will be called in the beginning of the try_finally.
- inline void InterpreterStackFrame::CacheSp()
- {
- // Before caching the current m_outSp, we will be storing the previous the previously stored value in the m_outSpCached.
- *m_outSp++ = (Var)m_outSpCached;
- *m_outSp++ = (Var)m_outParams;
- m_outSpCached = m_outSp - 2;
- }
- inline void InterpreterStackFrame::RestoreSp()
- {
- // This will be called in the Finally block to restore from the previous SP cached.
- // m_outSpCached can be null if the catch block is called.
- if (m_outSpCached != nullptr)
- {
- Assert(m_outSpCached < m_outSp);
- m_outSp = m_outSpCached;
- m_outSpCached = (Var*)*m_outSp;
- Assert(m_outSpCached == nullptr || m_outSpCached <= m_outSp);
- m_outParams = (Var*)*(m_outSp + 1);
- }
- else
- {
- ResetOut();
- }
- }
- inline void InterpreterStackFrame::PushOut(Var aValue)
- {
- *m_outSp++ = aValue;
- }
- inline void InterpreterStackFrame::PopOut(ArgSlot argCount)
- {
- m_outSp -= (argCount+1);
- m_outParams = (Var*)*m_outSp;
- AssertMsg(m_localSlots + this->m_functionBody->GetLocalsCount() <= m_outSp &&
- m_outSp < (m_localSlots + this->m_functionBody->GetLocalsCount() + this->m_functionBody->GetOutParamMaxDepth()),
- "out args Stack pointer not in range after Pop");
- }
- void InterpreterStackFrame::ResetOut()
- {
- //
- // Reset the m_outParams and m_outSp
- //
- m_outParams = m_localSlots + this->m_functionBody->GetLocalsCount();
- m_outSp = m_outParams;
- m_outSpCached = nullptr;
- }
- _NOINLINE
- Var InterpreterStackFrame::DebugProcessThunk(void* returnAddress, void* addressOfReturnAddress)
- {
- PushPopFrameHelper pushPopFrameHelper(this, returnAddress, addressOfReturnAddress);
- return this->DebugProcess();
- }
- //
- // Under debug mode allow the exception to be swallowed and execution to continue
- // if the debugger has specified that behavior.
- //
- Var InterpreterStackFrame::DebugProcess()
- {
- Assert(this->returnAddress != nullptr);
- while (true)
- {
- JavascriptExceptionObject *exception = nullptr;
- try
- {
- #if ENABLE_TTD
- if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
- {
- return this->ProcessWithDebugging_PreviousStmtTracking();
- }
- else
- {
- return this->ProcessWithDebugging();
- }
- #else
- return this->ProcessWithDebugging();
- #endif
- }
- catch (const Js::JavascriptException& err)
- {
- JavascriptExceptionObject *exception_ = err.GetAndClear();
- Assert(exception_);
- exception = exception_;
- }
- if (exception)
- {
- bool skipException = false;
- if (exception != scriptContext->GetThreadContext()->GetPendingSOErrorObject()
- && exception != scriptContext->GetThreadContext()->GetPendingOOMErrorObject())
- {
- skipException = exception->IsDebuggerSkip();
- }
- if (skipException)
- {
- // If we are going to swallow the exception then advance to the beginning of the next user statement
- if (exception->IsIgnoreAdvanceToNextStatement()
- || this->scriptContext->GetDebugContext()->GetProbeContainer()->AdvanceToNextUserStatement(this->m_functionBody, &this->m_reader))
- {
- // We must fix up the return value to at least be undefined:
- this->SetReg((RegSlot)0,this->scriptContext->GetLibrary()->GetUndefined());
- // If we recover from the exception, there may be a chance the out pointers in the InterpreterStackframe are not in a proper state.
- // Reset them to correct the stack.
- ResetOut();
- // If we can successfully advance then continuing processing
- continue;
- }
- }
- JavascriptExceptionOperators::DoThrowCheckClone(exception, scriptContext);
- }
- }
- }
- template<typename OpCodeType, Js::OpCode (ReadOpFunc)(const byte*&), void (TracingFunc)(InterpreterStackFrame*, OpCodeType)>
- OpCodeType InterpreterStackFrame::ReadOp(const byte *& ip)
- {
- #if DBG || DBG_DUMP
- //
- // For debugging byte-code, store the current offset before the instruction is read:
- // - We convert this to "void *" to encourage the debugger to always display in hex,
- // which matches the displayed offsets used by ByteCodeDumper.
- //
- this->DEBUG_currentByteOffset = (void *) m_reader.GetCurrentOffset();
- #endif
- #if ENABLE_TTD
- AssertMsg(!SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext), "We never be fetching an opcode via this path if this is true!!!");
- #endif
- OpCodeType op = (OpCodeType)ReadOpFunc(ip);
- #if DBG_DUMP
- TracingFunc(this, op);
- #endif
- return op;
- }
- void InterpreterStackFrame::TraceOpCode(InterpreterStackFrame* that, Js::OpCode op)
- {
- #if DBG_DUMP
- that->scriptContext->byteCodeHistogram[(int)op]++;
- if (PHASE_TRACE(Js::InterpreterPhase, that->m_functionBody))
- {
- Output::Print(_u("%d.%d:Executing %s at offset 0x%X\n"), that->m_functionBody->GetSourceContextId(), that->m_functionBody->GetLocalFunctionId(), Js::OpCodeUtil::GetOpCodeName(op), that->DEBUG_currentByteOffset);
- }
- #endif
- }
- void InterpreterStackFrame::TraceAsmJsOpCode(InterpreterStackFrame* that, Js::OpCodeAsmJs op)
- {
- #if DBG_DUMP && defined(ASMJS_PLAT)
- if(PHASE_TRACE(Js::AsmjsInterpreterPhase, that->m_functionBody))
- {
- Output::Print(_u("%d.%d:Executing %s at offset 0x%X\n"), that->m_functionBody->GetSourceContextId(), that->m_functionBody->GetLocalFunctionId(), Js::OpCodeUtilAsmJs::GetOpCodeName(op), that->DEBUG_currentByteOffset);
- }
- #endif
- }
- #if ENABLE_TTD
- template<typename OpCodeType, Js::OpCode(ReadOpFunc)(const byte*&), void (TracingFunc)(InterpreterStackFrame*, OpCodeType)>
- OpCodeType InterpreterStackFrame::ReadOp_WPreviousStmtTracking(const byte *& ip)
- {
- #if DBG || DBG_DUMP
- //
- // For debugging byte-code, store the current offset before the instruction is read:
- // - We convert this to "void *" to encourage the debugger to always display in hex,
- // which matches the displayed offsets used by ByteCodeDumper.
- //
- this->DEBUG_currentByteOffset = (void *)m_reader.GetCurrentOffset();
- #endif
- #if ENABLE_TTD
- AssertMsg(this->scriptContext->GetThreadContext()->IsRuntimeInTTDMode(), "We never be fetching an opcode via this path if this is not true!!!");
- #endif
- if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
- {
- this->scriptContext->GetThreadContext()->TTDLog->UpdateCurrentStatementInfo(m_reader.GetCurrentOffset());
- }
- OpCodeType op = (OpCodeType)ReadOpFunc(ip);
- #if DBG_DUMP
- TracingFunc(this, op);
- #endif
- return op;
- }
- #endif
- _NOINLINE
- Var InterpreterStackFrame::ProcessThunk(void* address, void* addressOfReturnAddress)
- {
- PushPopFrameHelper pushPopFrameHelper(this, address, addressOfReturnAddress);
- return this->Process();
- }
- Var InterpreterStackFrame::ProcessAsmJsModule()
- {
- #ifdef ASMJS_PLAT
- Js::FunctionBody* asmJsModuleFunctionBody = GetFunctionBody();
- AsmJsModuleInfo* info = asmJsModuleFunctionBody->GetAsmJsModuleInfo();
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- if (Configuration::Global.flags.ForceAsmJsLinkFail)
- {
- AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Forcing link failure"));
- return this->ProcessLinkFailedAsmJsModule();
- }
- #endif
- if( m_inSlotsCount != info->GetArgInCount() + 1 )
- {
- // Error reparse without asm.js
- AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Invalid module argument count"));
- return this->ProcessLinkFailedAsmJsModule();
- }
- const AsmJsModuleMemory& moduleMemory = info->GetModuleMemory();
- Var* moduleMemoryPtr = RecyclerNewArray( scriptContext->GetRecycler(), Var, moduleMemory.mMemorySize );
- Var* arrayBufferPtr = moduleMemoryPtr + moduleMemory.mArrayBufferOffset;
- Assert(moduleMemory.mArrayBufferOffset == AsmJsModuleMemory::MemoryTableBeginOffset);
- Var* stdLibPtr = moduleMemoryPtr + moduleMemory.mStdLibOffset;
- int* localIntSlots = (int*)(moduleMemoryPtr + moduleMemory.mIntOffset);
- float* localFloatSlots = (float*)(moduleMemoryPtr + moduleMemory.mFloatOffset);
- double* localDoubleSlots = (double*)(moduleMemoryPtr + moduleMemory.mDoubleOffset);
- Var* localFunctionImports = moduleMemoryPtr + moduleMemory.mFFIOffset ;
- Var* localModuleFunctions = moduleMemoryPtr + moduleMemory.mFuncOffset ;
- Var** localFunctionTables = (Var**)(moduleMemoryPtr + moduleMemory.mFuncPtrOffset) ;
- AsmJsSIMDValue* localSimdSlots = nullptr;
- if (scriptContext->GetConfig()->IsSimdjsEnabled())
- {
- localSimdSlots = ((AsmJsSIMDValue*)moduleMemoryPtr) + moduleMemory.mSimdOffset; // simdOffset is in SIMDValues
- }
- ThreadContext* threadContext = this->scriptContext->GetThreadContext();
- *stdLibPtr = (m_inSlotsCount > 1) ? m_inParams[1] : nullptr;
- Var foreign = (m_inSlotsCount > 2) ? m_inParams[2] : nullptr;
- *arrayBufferPtr = (m_inSlotsCount > 3) ? m_inParams[3] : nullptr;
- //cache the current state of the disable implicit call flag
- DisableImplicitFlags prevDisableImplicitFlags = threadContext->GetDisableImplicitFlags();
- ImplicitCallFlags saveImplicitcallFlags = threadContext->GetImplicitCallFlags();
- // Disable implicit calls to check if any of the VarImport or Function Import leads to implicit calls
- threadContext->DisableImplicitCall();
- threadContext->SetImplicitCallFlags(ImplicitCallFlags::ImplicitCall_None);
- bool checkParamResult = ASMLink::CheckParams(this->scriptContext, info, *stdLibPtr, foreign, *arrayBufferPtr);
- if (!checkParamResult)
- {
- // don't need to print, because checkParams will do it for us
- goto linkFailure;
- }
- else if(this->CheckAndResetImplicitCall(prevDisableImplicitFlags, saveImplicitcallFlags))
- {
- AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Params have side effects"));
- return this->ProcessLinkFailedAsmJsModule();
- }
- // Initialize Variables
- for (int i = 0; i < info->GetVarCount(); i++)
- {
- const auto& var = info->GetVar( i );
- const AsmJsVarType type(var.type);
- if(type.isInt() )
- {
- localIntSlots[var.location] = var.initialiser.intInit;
- }
- else if (type.isFloat())
- {
- localFloatSlots[var.location] = var.initialiser.floatInit;
- }
- else if (type.isDouble())
- {
- localDoubleSlots[var.location] = var.initialiser.doubleInit;
- }
- else if (scriptContext->GetConfig()->IsSimdjsEnabled() && type.isSIMD())
- {
- // e.g. var g = f4(0.0, 0.0, 0.0, 0.0);
- localSimdSlots[var.location] = var.initialiser.simdInit;
- }
- else {
- Assert(UNREACHED);
- }
- }
- // Load constant variables
- for( int i = 0; i < info->GetVarImportCount(); i++ )
- {
- const auto& import = info->GetVarImport( i );
- const AsmJsVarType type(import.type);
- // this might throw, but it would anyway in non-asm.js
- Var value = JavascriptOperators::OP_GetProperty( foreign, import.field, scriptContext );
- // check if there is implicit call and if there is implicit call then clear the disableimplicitcall flag
- if (this->CheckAndResetImplicitCall(prevDisableImplicitFlags, saveImplicitcallFlags))
- {
- AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Accessing var import %s has side effects"), this->scriptContext->GetPropertyName(import.field)->GetBuffer());
- return this->ProcessLinkFailedAsmJsModule();
- }
- if (CONFIG_FLAG(AsmJsEdge))
- {
- // emscripten had a bug which caused this check to fail in some circumstances, so this check fails for some demos
- if (!TaggedNumber::Is(value) && (!RecyclableObject::Is(value) || DynamicType::Is(RecyclableObject::FromVar(value)->GetTypeId())))
- {
- AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Var import %s must be primitive"), this->scriptContext->GetPropertyName(import.field)->GetBuffer());
- goto linkFailure;
- }
- }
- if(type.isInt() )
- {
- int val = JavascriptMath::ToInt32( value, scriptContext );
- localIntSlots[import.location] = val;
- }
- else if (type.isFloat())
- {
- float val = (float)JavascriptConversion::ToNumber(value, scriptContext);
- localFloatSlots[import.location] = val;
- }
- else if (type.isDouble())
- {
- double val = JavascriptConversion::ToNumber( value, scriptContext );
- localDoubleSlots[import.location] = val;
- }
- else if (scriptContext->GetConfig()->IsSimdjsEnabled() && type.isSIMD())
- {
- // e.g. var g = f4(imports.v);
- bool valid = false;
- AsmJsSIMDValue val;
- val.Zero();
- switch (type.which())
- {
- case AsmJsVarType::Int32x4:
- valid = JavascriptSIMDInt32x4::Is(value);
- val = (valid) ? ((JavascriptSIMDInt32x4*)value)->GetValue() : val;
- break;
- case AsmJsVarType::Bool32x4:
- valid = JavascriptSIMDBool32x4::Is(value);
- val = (valid) ? ((JavascriptSIMDBool32x4*)value)->GetValue() : val;
- break;
- case AsmJsVarType::Bool16x8:
- valid = JavascriptSIMDBool16x8::Is(value);
- val = (valid) ? ((JavascriptSIMDBool16x8*)value)->GetValue() : val;
- break;
- case AsmJsVarType::Bool8x16:
- valid = JavascriptSIMDBool8x16::Is(value);
- val = (valid) ? ((JavascriptSIMDBool8x16*)value)->GetValue() : val;
- break;
- case AsmJsVarType::Float32x4:
- valid = JavascriptSIMDFloat32x4::Is(value);
- val = (valid) ? ((JavascriptSIMDFloat32x4*)value)->GetValue() : val;
- break;
- case AsmJsVarType::Float64x2:
- valid = JavascriptSIMDFloat64x2::Is(value);
- val = (valid) ? ((JavascriptSIMDFloat64x2*)value)->GetValue() : val;
- break;
- case AsmJsVarType::Int16x8:
- valid = JavascriptSIMDInt16x8::Is(value);
- val = (valid) ? ((JavascriptSIMDInt16x8*)value)->GetValue() : val;
- break;
- case AsmJsVarType::Int8x16:
- valid = JavascriptSIMDInt8x16::Is(value);
- val = ((JavascriptSIMDInt8x16*)value)->GetValue();
- break;
- case AsmJsVarType::Uint32x4:
- valid = JavascriptSIMDUint32x4::Is(value);
- val = (valid) ? ((JavascriptSIMDUint32x4*)value)->GetValue() : val;
- break;
- case AsmJsVarType::Uint16x8:
- valid = JavascriptSIMDUint16x8::Is(value);
- val = (valid) ? ((JavascriptSIMDUint16x8*)value)->GetValue() : val;
- break;
- case AsmJsVarType::Uint8x16:
- valid = JavascriptSIMDUint8x16::Is(value);
- val = (valid) ? ((JavascriptSIMDUint8x16*)value)->GetValue() : val;
- break;
- default:
- Assert(UNREACHED);
- };
- if (!valid)
- {
- // link failure of SIMD values imports.
- AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Foreign var import %s is not SIMD type"), this->scriptContext->GetPropertyName(import.field)->GetBuffer());
- goto linkFailure;
- }
- localSimdSlots[import.location] = val;
- }
- // check for implicit call after converting to number
- if (this->CheckAndResetImplicitCall(prevDisableImplicitFlags, saveImplicitcallFlags))
- {
- // Runtime error
- AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Accessing var import %s has side effects"), this->scriptContext->GetPropertyName(import.field)->GetBuffer());
- return this->ProcessLinkFailedAsmJsModule();
- }
- }
- // Load external functions
- for( int i = 0; i < info->GetFunctionImportCount(); i++ )
- {
- const auto& import = info->GetFunctionImport( i );
- // this might throw, but it would anyway in non-asm.js
- Var importFunc = JavascriptOperators::OP_GetProperty( foreign, import.field, scriptContext );
- // check if there is implicit call and if there is implicit call then clear the disableimplicitcall flag
- if (this->CheckAndResetImplicitCall(prevDisableImplicitFlags, saveImplicitcallFlags))
- {
- AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Accessing foreign function import %s has side effects"), this->scriptContext->GetPropertyName(import.field)->GetBuffer());
- return this->ProcessLinkFailedAsmJsModule();
- }
- if( !JavascriptFunction::Is( importFunc ) )
- {
- AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Foreign function import %s is not a function"), this->scriptContext->GetPropertyName(import.field)->GetBuffer());
- goto linkFailure;
- }
- localFunctionImports[import.location] = importFunc;
- }
- if (*arrayBufferPtr)
- {
- (*(ArrayBuffer**)arrayBufferPtr)->SetIsAsmJsBuffer();
- }
- threadContext->SetDisableImplicitFlags(prevDisableImplicitFlags);
- threadContext->SetImplicitCallFlags(saveImplicitcallFlags);
- // scope
- {
- FrameDisplay* pDisplay = RecyclerNewPlus(scriptContext->GetRecycler(), sizeof(void*), FrameDisplay, 1);
- pDisplay->SetItem( 0, moduleMemoryPtr );
- for (int i = 0; i < info->GetFunctionCount(); i++)
- {
- const auto& modFunc = info->GetFunction(i);
- // TODO: add more runtime checks here
- FunctionInfoPtrPtr functionInfo = m_functionBody->GetNestedFuncReference(i);
- AsmJsScriptFunction* scriptFuncObj = (AsmJsScriptFunction*)ScriptFunction::OP_NewScFunc(pDisplay, functionInfo);
- localModuleFunctions[modFunc.location] = scriptFuncObj;
- if (i == 0 && info->GetUsesChangeHeap())
- {
- scriptFuncObj->GetDynamicType()->SetEntryPoint(AsmJsChangeHeapBuffer);
- }
- else
- {
- if (scriptFuncObj->GetDynamicType()->GetEntryPoint() == DefaultDeferredDeserializeThunk)
- {
- JavascriptFunction::DeferredDeserialize(scriptFuncObj);
- }
- scriptFuncObj->GetDynamicType()->SetEntryPoint(AsmJsExternalEntryPoint);
- scriptFuncObj->GetFunctionBody()->GetAsmJsFunctionInfo()->SetModuleFunctionBody(asmJsModuleFunctionBody);
- }
- scriptFuncObj->SetModuleMemory(moduleMemoryPtr);
- if (!info->IsRuntimeProcessed())
- {
- // don't reset entrypoint upon relinking
- FunctionEntryPointInfo* entrypointInfo = (FunctionEntryPointInfo*)scriptFuncObj->GetEntryPointInfo();
- entrypointInfo->SetIsAsmJSFunction(true);
- #if DYNAMIC_INTERPRETER_THUNK
- if (!PHASE_ON1(AsmJsJITTemplatePhase))
- {
- entrypointInfo->jsMethod = AsmJsDefaultEntryThunk;
- }
- #endif
- }
- }
- }
- // Initialize function table arrays
- for( int i = 0; i < info->GetFunctionTableCount(); i++ )
- {
- const auto& modFuncTable = info->GetFunctionTable( i );
- Var* funcTableArray = RecyclerNewArray( scriptContext->GetRecycler(), Var, modFuncTable.size );
- for (uint j = 0; j < modFuncTable.size ; j++)
- {
- // get the module function index
- const RegSlot index = modFuncTable.moduleFunctionIndex[j];
- // assign the module function pointer to the array
- Var functionPtr = localModuleFunctions[index];
- funcTableArray[j] = functionPtr;
- }
- localFunctionTables[i] = funcTableArray;
- }
- // Do MTJRC/MAIC:0 check
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (
- (PHASE_ON1(Js::AsmJsJITTemplatePhase) && CONFIG_FLAG(MaxTemplatizedJitRunCount) == 0) ||
- (!PHASE_ON1(Js::AsmJsJITTemplatePhase) && (CONFIG_FLAG(MaxAsmJsInterpreterRunCount) == 0 || CONFIG_FLAG(ForceNative)))
- )
- {
- if (PHASE_TRACE1(AsmjsEntryPointInfoPhase))
- {
- Output::Print(_u("%s Scheduling For Full JIT at callcount:%d\n"), asmJsModuleFunctionBody->GetDisplayName(), 0);
- Output::Flush();
- }
- for (int i = 0; i < info->GetFunctionCount(); i++)
- {
- ScriptFunction* functionObj = (ScriptFunction*)localModuleFunctions[i];
- AnalysisAssert(functionObj != nullptr);
- // don't want to generate code for APIs like changeHeap
- if (functionObj->GetEntryPoint() == Js::AsmJsExternalEntryPoint)
- {
- GenerateFunction(asmJsModuleFunctionBody->GetScriptContext()->GetNativeCodeGenerator(), functionObj->GetFunctionBody(), functionObj);
- }
- }
- }
- #endif
- info->SetIsRuntimeProcessed(true);
- // create export object
- if( info->GetExportsCount() )
- {
- Var newObj = JavascriptOperators::NewScObjectLiteral( GetScriptContext(), info->GetExportsIdArray(),
- this->GetFunctionBody()->GetObjectLiteralTypeRef( 0 ) );
- for( int i = 0; i < info->GetExportsCount(); i++ )
- {
- auto ex = info->GetExport( i );
- Var func = localModuleFunctions[*ex.location];
- JavascriptOperators::OP_InitProperty( newObj, *ex.id, func );
- }
- SetReg( (RegSlot) 0, newObj );
- return newObj;
- }
- // export only 1 function
- {
- Var exportFunc = localModuleFunctions[info->GetExportFunctionIndex()];
- SetReg((RegSlot)0, exportFunc);
- return exportFunc;
- }
- linkFailure:
- threadContext->SetDisableImplicitFlags(prevDisableImplicitFlags);
- threadContext->SetImplicitCallFlags(saveImplicitcallFlags);
- return this->ProcessLinkFailedAsmJsModule();
- }
- Var InterpreterStackFrame::ProcessLinkFailedAsmJsModule()
- {
- AsmJSCompiler::OutputError(this->scriptContext, _u("asm.js linking failed."));
- Js::FunctionBody* asmJsModuleFunctionBody = GetFunctionBody();
- AsmJsModuleInfo* info = asmJsModuleFunctionBody->GetAsmJsModuleInfo();
- // do not support relinking with failed relink
- if (info->IsRuntimeProcessed())
- {
- Js::Throw::OutOfMemory();
- }
- ScriptFunction * funcObj = GetJavascriptFunction();
- ScriptFunction::ReparseAsmJsModule(&funcObj);
- const bool doProfile =
- funcObj->GetFunctionBody()->GetInterpreterExecutionMode(false) == ExecutionMode::ProfilingInterpreter ||
- (funcObj->GetFunctionBody()->IsInDebugMode() && DynamicProfileInfo::IsEnabled(funcObj->GetFunctionBody()));
- DynamicProfileInfo * dynamicProfileInfo = nullptr;
- if (doProfile)
- {
- dynamicProfileInfo = funcObj->GetFunctionBody()->GetDynamicProfileInfo();
- funcObj->GetScriptContext()->GetThreadContext()->ClearImplicitCallFlags();
- }
- // after reparsing, we want to also use a new interpreter stack frame, as it will have different characteristics than the asm.js version
- InterpreterStackFrame::Setup setup(funcObj, m_inParams, m_inSlotsCount);
- size_t varAllocCount = setup.GetAllocationVarCount();
- size_t varSizeInBytes = varAllocCount * sizeof(Var);
- Var* allocation = nullptr;
- DWORD_PTR stackAddr;
- bool fReleaseAlloc = false;
- if (varAllocCount > InterpreterStackFrame::LocalsThreshold)
- {
- ArenaAllocator *tmpAlloc = nullptr;
- fReleaseAlloc = GetScriptContext()->EnsureInterpreterArena(&tmpAlloc);
- allocation = (Var*)tmpAlloc->Alloc(varSizeInBytes);
- // use a stack address so the debugger stepping logic works (step-out, for example, compares stack depths to determine when to complete the step)
- // debugger stepping does not matter here, but it's worth being consistent with normal stack frame
- stackAddr = reinterpret_cast<DWORD_PTR>(&allocation);
- }
- else
- {
- PROBE_STACK_PARTIAL_INITIALIZED_INTERPRETER_FRAME(GetScriptContext(), Js::Constants::MinStackInterpreter + varSizeInBytes);
- allocation = (Var*)_alloca(varSizeInBytes);
- stackAddr = reinterpret_cast<DWORD_PTR>(allocation);
- }
- #if DBG
- Var invalidStackVar = (Js::RecyclableObject*)_alloca(sizeof(Js::RecyclableObject));
- memset(invalidStackVar, 0xFE, sizeof(Js::RecyclableObject));
- InterpreterStackFrame * newInstance = newInstance = setup.InitializeAllocation(allocation, funcObj->GetFunctionBody()->GetHasImplicitArgIns(), doProfile, nullptr, stackAddr, invalidStackVar);
- #else
- InterpreterStackFrame * newInstance = newInstance = setup.InitializeAllocation(allocation, funcObj->GetFunctionBody()->GetHasImplicitArgIns(), doProfile, nullptr, stackAddr);
- #endif
- newInstance->m_reader.Create(funcObj->GetFunctionBody());
- // now that we have set up the new frame, let's interpret it!
- funcObj->GetFunctionBody()->BeginExecution();
- PushPopFrameHelper(newInstance, _ReturnAddress(), _AddressOfReturnAddress());
- Var retVal = newInstance->ProcessUnprofiled();
- if (doProfile)
- {
- dynamicProfileInfo->RecordImplicitCallFlags(GetScriptContext()->GetThreadContext()->GetImplicitCallFlags());
- }
- if (fReleaseAlloc)
- {
- GetScriptContext()->ReleaseInterpreterArena();
- }
- return retVal;
- #else
- Assert(UNREACHED);
- return nullptr;
- #endif
- }
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- int AsmJsCallDepth = 0;
- #endif
- #ifdef ASMJS_PLAT
- // Function memory allocation should be done the same way as
- // T AsmJsCommunEntryPoint(Js::ScriptFunction* func, ...) (AsmJSJitTemplate.cpp)
- // update any changes there
- /*
- This function does the following fixup
- Stack Before Stack After
- ============== ================
- | VarConstants | | VarConstants |
- |--------------| |-----------------
- | IntConstants | | IntConstants |
- |--------------| | ------------ |
- | FloatConst | | Int Vars+Tmps |
- |--------------| |----------------|
- | DoubleConst | | FloatConst |
- |--------------| | ---------- |
- | Var&Temps | | Flt Vars+tmps |
- |==============| |----------------|
- | DoubleConst |
- | ----------- |
- | Dbl Vars+Tmps |
- ================
- intSrc,FltSrc&DblSrc are pointers to the stack before the change
- m_localIntSlots,m_localFloatSlots,m_localDoubleSlots are pointers to the stack after the change
- */
- void InterpreterStackFrame::AlignMemoryForAsmJs()
- {
- FunctionBody *const functionBody = GetFunctionBody();
- ScriptFunction* func = GetJavascriptFunction();
- //schedule for codegen here only if TJ is collected
- if (!functionBody->GetIsAsmJsFullJitScheduled() && !PHASE_OFF(BackEndPhase, functionBody)
- && !PHASE_OFF(FullJitPhase, functionBody) && !this->scriptContext->GetConfig()->IsNoNative())
- {
- int callCount = ++((FunctionEntryPointInfo*)func->GetEntryPointInfo())->callsCount;
- bool doSchedule = false;
- const int minAsmJsInterpretRunCount = (int)CONFIG_FLAG(MinAsmJsInterpreterRunCount);
- if (callCount >= minAsmJsInterpretRunCount)
- {
- doSchedule = true;
- }
- if (doSchedule && !functionBody->GetIsAsmJsFullJitScheduled())
- {
- #if ENABLE_NATIVE_CODEGEN
- if (PHASE_TRACE1(AsmjsEntryPointInfoPhase))
- {
- Output::Print(_u("Scheduling For Full JIT from Interpreter at callcount:%d\n"), callCount);
- }
- GenerateFunction(functionBody->GetScriptContext()->GetNativeCodeGenerator(), functionBody, func);
- #endif
- functionBody->SetIsAsmJsFullJitScheduled(true);
- }
- }
- AsmJsFunctionInfo* info = functionBody->GetAsmJsFunctionInfo();
- // The const table is copied after the FirstRegSlot
- byte* constTable = (byte*)(m_localSlots + FunctionBody::FirstRegSlot);
- byte* slotsStart = (byte*)m_localSlots;
- // Must do in reverse order to avoid overwriting const of other type as we move things around
- for (int i = WAsmJs::LIMIT - 1; i >= 0; --i)
- {
- WAsmJs::Types type = (WAsmJs::Types)i;
- auto typeInfo = info->GetTypedSlotInfo(type);
- byte* destination = slotsStart + typeInfo->byteOffset;
- switch (type)
- {
- case WAsmJs::INT32: m_localIntSlots = (int*)destination; break;
- case WAsmJs::INT64: m_localInt64Slots = (int64*)destination; break;
- case WAsmJs::FLOAT32: m_localFloatSlots = (float*)destination; break;
- case WAsmJs::FLOAT64: m_localDoubleSlots = (double*)destination; break;
- case WAsmJs::SIMD: m_localSimdSlots = (AsmJsSIMDValue*)destination; break;
- default:
- CompileAssert(WAsmJs::SIMD == WAsmJs::LastType);
- Assert(false);
- break;
- }
- // Make sure slots are aligned for this type
- Assert(::Math::Align<intptr_t>((intptr_t)destination, (intptr_t)WAsmJs::GetTypeByteSize(type)) == (intptr_t)destination);
- byte* source = constTable + typeInfo->constSrcByteOffset;
- if (typeInfo->constCount > 0 && source != destination)
- {
- Assert(typeInfo->constSrcByteOffset != Js::Constants::InvalidOffset);
- uint constByteSize = typeInfo->constCount * WAsmJs::GetTypeByteSize(type);
- memcpy_s(destination, constByteSize, source, constByteSize);
- }
- }
- // Load module environment
- FrameDisplay* frame = this->function->GetEnvironment();
- m_localSlots[AsmJsFunctionMemory::ModuleEnvRegister] = frame->GetItem(0);
- #ifdef ENABLE_WASM
- if (func->GetFunctionBody()->IsWasmFunction())
- {
- WebAssemblyMemory * wasmMem = *(WebAssemblyMemory**)((Var*)frame->GetItem(0) + AsmJsModuleMemory::MemoryTableBeginOffset);
- Var * val = nullptr;
- if (wasmMem != nullptr)
- {
- val = (Var*)((BYTE*)wasmMem + WebAssemblyMemory::GetOffsetOfArrayBuffer());
- }
- m_localSlots[AsmJsFunctionMemory::ArrayBufferRegister] = val;
- m_signatures = func->GetFunctionBody()->GetAsmJsFunctionInfo()->GetWebAssemblyModule()->GetSignatures();
- m_wasmMemory = wasmMem;
- }
- else
- #endif
- {
- m_localSlots[AsmJsFunctionMemory::ArrayBufferRegister] = (Var*)frame->GetItem(0) + AsmJsModuleMemory::MemoryTableBeginOffset;
- }
- m_localSlots[AsmJsFunctionMemory::ArraySizeRegister] = 0; // do not cache ArraySize in the interpreter
- m_localSlots[AsmJsFunctionMemory::ScriptContextBufferRegister] = functionBody->GetScriptContext();
- int* intArg = m_localIntSlots + info->GetTypedSlotInfo(WAsmJs::INT32)->constCount;
- int64* int64Arg = m_localInt64Slots + info->GetTypedSlotInfo(WAsmJs::INT64)->constCount;
- double* doubleArg = m_localDoubleSlots + info->GetTypedSlotInfo(WAsmJs::FLOAT64)->constCount;
- float* floatArg = m_localFloatSlots + info->GetTypedSlotInfo(WAsmJs::FLOAT32)->constCount;
- AsmJsSIMDValue* simdArg = m_localSimdSlots + info->GetTypedSlotInfo(WAsmJs::SIMD)->constCount;
- // Move the arguments to the right location
- ArgSlot argCount = info->GetArgCount();
- #if _M_X64
- uint homingAreaSize = 0;
- #endif
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- const bool tracingFunc = PHASE_TRACE(AsmjsFunctionEntryPhase, functionBody);
- if (tracingFunc)
- {
- if (AsmJsCallDepth)
- {
- Output::Print(_u("%*c"), AsmJsCallDepth, ' ');
- }
- Output::Print(_u("Executing function %s("), functionBody->GetDisplayName());
- ++AsmJsCallDepth;
- }
- #endif
- uintptr_t argAddress = (uintptr_t)m_inParams;
- for (ArgSlot i = 0; i < argCount; i++)
- {
- #if _M_X64
- // 3rd Argument should be at the end of the homing area.
- Assert(i != 3 || argAddress == (uintptr_t)m_inParams + homingAreaSize);
- if (i < 3)
- {
- // for x64 we spill the first 3 floating point args below the rest of the arguments on the stack
- // m_inParams will be from DynamicInterpreterThunk's frame. Floats are in InterpreterAsmThunk's frame. Stack will be set up like so:
- // DIT arg2 <- first scriptArg, m_inParams points here
- // DIT arg1
- // padding
- // IAT r9 home
- // IAT r8 home
- // IAT rdx home
- // IAT rcx home
- // IAT return address
- // IAT push rbp
- // IAT padding
- // IAT xmm3 spill
- // IAT xmm2 spill
- // IAT xmm1 spill <- floatSpillAddress for arg1
- #ifdef _WIN32
- #define FLOAT_SPILL_ADDRESS_OFFSET_WORDS 15
- #else
- // On Sys V x64 we have 4 words less (4 reg shadow)
- #define FLOAT_SPILL_ADDRESS_OFFSET_WORDS 11
- #endif
- // floats are spilled as xmmwords
- uintptr_t floatSpillAddress = (uintptr_t)m_inParams - MachPtr * (FLOAT_SPILL_ADDRESS_OFFSET_WORDS - 2*i);
- if (info->GetArgType(i).isInt())
- {
- *intArg = *(int*)argAddress;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (tracingFunc)
- {
- Output::Print(_u("%d, "), *intArg);
- }
- #endif
- ++intArg;
- homingAreaSize += MachPtr;
- }
- else if (info->GetArgType(i).isInt64())
- {
- *int64Arg = *(int64*)argAddress;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (tracingFunc)
- {
- Output::Print(_u("%lld, "), *int64Arg);
- }
- #endif
- ++int64Arg;
- homingAreaSize += MachPtr;
- }
- else if (info->GetArgType(i).isFloat())
- {
- *floatArg = *(float*)floatSpillAddress;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (tracingFunc)
- {
- Output::Print(_u("%.2f, "), *floatArg);
- }
- #endif
- ++floatArg;
- homingAreaSize += MachPtr;
- }
- else if (info->GetArgType(i).isDouble())
- {
- *doubleArg = *(double*)floatSpillAddress;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (tracingFunc)
- {
- Output::Print(_u("%.2f, "), *doubleArg);
- }
- #endif
- ++doubleArg;
- homingAreaSize += MachPtr;
- }
- else
- {
- Assert(info->GetArgType(i).isSIMD());
- *simdArg = *(AsmJsSIMDValue*)floatSpillAddress;
- ++simdArg;
- homingAreaSize += sizeof(AsmJsSIMDValue);
- }
- if (scriptContext->GetConfig()->IsSimdjsEnabled() && i == 2) // last argument ?
- {
- // If we have simd arguments, the homing area in m_inParams can be larger than 3 64-bit slots. This is because SIMD values are unboxed there too.
- // After unboxing, the homing area is overwritten by rdx, r8 and r9, and we read/skip 64-bit slots from the homing area (argAddress += MachPtr).
- // After the last argument of the 3 is read, we need to advance argAddress to skip over the possible extra space and to the start of the rest of the arguments.
- argAddress = (uintptr_t)m_inParams + homingAreaSize;
- }
- else
- {
- argAddress += MachPtr;
- }
- }
- else
- #endif
- if (info->GetArgType(i).isInt())
- {
- *intArg = *(int*)argAddress;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (tracingFunc)
- {
- Output::Print(_u("%d, "), *intArg);
- }
- #endif
- ++intArg;
- argAddress += MachPtr;
- }
- else if (info->GetArgType(i).isInt64())
- {
- *int64Arg = *(int64*)argAddress;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (tracingFunc)
- {
- Output::Print(_u("%lld, "), *int64Arg);
- }
- #endif
- ++int64Arg;
- argAddress += sizeof(int64);
- }
- else if (info->GetArgType(i).isFloat())
- {
- *floatArg = *(float*)argAddress;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (tracingFunc)
- {
- Output::Print(_u("%.2f, "), *floatArg);
- }
- #endif
- ++floatArg;
- argAddress += MachPtr;
- }
- else if (info->GetArgType(i).isDouble())
- {
- Assert(info->GetArgType(i).isDouble());
- *doubleArg = *(double*)argAddress;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (tracingFunc)
- {
- Output::Print(_u("%.2f, "), *doubleArg);
- }
- #endif
- ++doubleArg;
- argAddress += sizeof(double);
- }
- else if (scriptContext->GetConfig()->IsSimdjsEnabled() && info->GetArgType(i).isSIMD())
- {
- *simdArg = *(AsmJsSIMDValue*)argAddress;
- ++simdArg;
- argAddress += sizeof(AsmJsSIMDValue);
- }
- else
- {
- AssertMsg(UNREACHED, "Invalid function arg type.");
- }
- }
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (tracingFunc)
- {
- Output::Print(_u("){\n"));
- Output::Flush();
- }
- #endif
- if( info->GetReturnType() == AsmJsRetType::Void )
- {
- m_localSlots[0] = JavascriptOperators::OP_LdUndef( scriptContext );
- }
- }
- #endif
- ///----------------------------------------------------------------------------
- ///
- /// InterpreterStackFrame::Process
- ///
- /// Process() processes a single loop of execution for the current
- /// JavascriptFunction being executed:
- /// - Individual instructions are dispatched to specific handlers for different
- /// OpCodes.
- ///
- ///----------------------------------------------------------------------------
- #if ENABLE_PROFILE_INFO
- #define INTERPRETERLOOPNAME ProcessProfiled
- #define PROVIDE_INTERPRETERPROFILE
- #include "InterpreterLoop.inl"
- #undef PROVIDE_INTERPRETERPROFILE
- #undef INTERPRETERLOOPNAME
- #endif
- #define INTERPRETERLOOPNAME ProcessUnprofiled
- #include "InterpreterLoop.inl"
- #undef INTERPRETERLOOPNAME
- #if ENABLE_TTD_DIAGNOSTICS_TRACING
- #define PROVIDE_INTERPRETER_STMTS
- #define INTERPRETERLOOPNAME ProcessUnprofiled_PreviousStmtTracking
- #include "InterpreterLoop.inl"
- #undef INTERPRETERLOOPNAME
- #undef PROVIDE_INTERPRETER_STMTS
- #endif
- #ifdef ASMJS_PLAT
- #define INTERPRETERLOOPNAME ProcessAsmJs
- #define INTERPRETER_ASMJS
- #include "InterpreterProcessOpCodeAsmJs.h"
- #include "InterpreterLoop.inl"
- #undef INTERPRETER_ASMJS
- #undef INTERPRETERLOOPNAME
- #endif
- // For now, always collect profile data when debugging,
- // otherwise the backend will be confused if there's no profile data.
- #define INTERPRETERLOOPNAME ProcessWithDebugging
- #define PROVIDE_DEBUGGING
- #if ENABLE_PROFILE_INFO
- #define PROVIDE_INTERPRETERPROFILE
- #endif
- #include "InterpreterLoop.inl"
- #if ENABLE_PROFILE_INFO
- #undef PROVIDE_INTERPRETERPROFILE
- #endif
- #undef PROVIDE_DEBUGGING
- #undef INTERPRETERLOOPNAME
- #if ENABLE_TTD
- #define PROVIDE_INTERPRETER_STMTS
- #define INTERPRETERLOOPNAME ProcessWithDebugging_PreviousStmtTracking
- #define PROVIDE_DEBUGGING
- #if ENABLE_PROFILE_INFO
- #define PROVIDE_INTERPRETERPROFILE
- #endif
- #include "InterpreterLoop.inl"
- #if ENABLE_PROFILE_INFO
- #undef PROVIDE_INTERPRETERPROFILE
- #endif
- #undef PROVIDE_DEBUGGING
- #undef INTERPRETERLOOPNAME
- #undef PROVIDE_INTERPRETER_STMTS
- #endif
- Var InterpreterStackFrame::Process()
- {
- #if ENABLE_PROFILE_INFO
- class AutoRestore
- {
- private:
- InterpreterStackFrame *const interpreterStackFrame;
- const uint32 savedSwitchProfileModeOnLoopEndNumber;
- const bool savedIsAutoProfiling;
- const bool savedSwitchProfileMode;
- public:
- AutoRestore(InterpreterStackFrame *const interpreterStackFrame)
- : interpreterStackFrame(interpreterStackFrame),
- savedIsAutoProfiling(interpreterStackFrame->isAutoProfiling),
- savedSwitchProfileMode(interpreterStackFrame->switchProfileMode),
- savedSwitchProfileModeOnLoopEndNumber(interpreterStackFrame->switchProfileModeOnLoopEndNumber)
- {
- }
- ~AutoRestore()
- {
- interpreterStackFrame->isAutoProfiling = savedIsAutoProfiling;
- interpreterStackFrame->switchProfileMode = savedSwitchProfileMode;
- interpreterStackFrame->switchProfileModeOnLoopEndNumber = savedSwitchProfileModeOnLoopEndNumber;
- }
- } autoRestore(this);
- #endif
- if ((m_flags & Js::InterpreterStackFrameFlags_FromBailOut) && !(m_flags & InterpreterStackFrameFlags_ProcessingBailOutFromEHCode))
- {
- if (this->ehBailoutData)
- {
- m_flags |= Js::InterpreterStackFrameFlags_ProcessingBailOutFromEHCode;
- EHBailoutData * topLevelEHBailoutData = this->ehBailoutData;
- while (topLevelEHBailoutData->parent->nestingDepth != -1)
- {
- topLevelEHBailoutData->parent->child = topLevelEHBailoutData;
- topLevelEHBailoutData = topLevelEHBailoutData->parent;
- }
- ProcessTryCatchBailout(topLevelEHBailoutData, this->ehBailoutData->nestingDepth);
- m_flags &= ~Js::InterpreterStackFrameFlags_ProcessingBailOutFromEHCode;
- this->ehBailoutData = nullptr;
- }
- }
- #ifdef ASMJS_PLAT
- if( GetFunctionBody()->GetIsAsmjsMode() )
- {
- FunctionBody *const functionBody = GetFunctionBody();
- AsmJsFunctionInfo* asmInfo = functionBody->GetAsmJsFunctionInfo();
- if (asmInfo)
- {
- AlignMemoryForAsmJs();
- Var returnVar = ProcessAsmJs();
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if( PHASE_TRACE( AsmjsFunctionEntryPhase, functionBody ) )
- {
- --AsmJsCallDepth;
- if( AsmJsCallDepth )
- {
- Output::Print( _u("%*c}"), AsmJsCallDepth, ' ' );
- }
- else
- {
- Output::Print( _u("}") );
- }
- switch( asmInfo->GetReturnType().which() )
- {
- case AsmJsRetType::Void:
- break;
- case AsmJsRetType::Signed:
- Output::Print( _u(" = %d"), m_localIntSlots[0] );
- break;
- case AsmJsRetType::Int64:
- Output::Print( _u(" = %lld"), m_localInt64Slots[0] );
- break;
- case AsmJsRetType::Float:
- Output::Print(_u(" = %.4f"), m_localFloatSlots[0]);
- break;
- case AsmJsRetType::Double:
- Output::Print( _u(" = %.4f"), m_localDoubleSlots[0]);
- break;
- default:
- break;
- }
- Output::Print( _u(";\n") );
- Output::Flush();
- }
- #endif
- return returnVar;
- }
- else
- {
- Assert(functionBody->GetAsmJsModuleInfo());
- return ProcessAsmJsModule();
- }
- }
- #endif
- #if ENABLE_PROFILE_INFO
- switchProfileMode = false;
- switchProfileModeOnLoopEndNumber = 0u - 1;
- #endif
- #if ENABLE_PROFILE_INFO
- FunctionBody *const functionBody = GetFunctionBody();
- const ExecutionMode interpreterExecutionMode =
- functionBody->GetInterpreterExecutionMode(!!(GetFlags() & InterpreterStackFrameFlags_FromBailOut));
- if(interpreterExecutionMode == ExecutionMode::ProfilingInterpreter)
- {
- #if ENABLE_TTD
- AssertMsg(!SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext), "We should have pinned into Interpreter mode in this case!!!");
- #endif
- isAutoProfiling = false;
- return ProcessProfiled();
- }
- Assert(
- interpreterExecutionMode == ExecutionMode::Interpreter ||
- interpreterExecutionMode == ExecutionMode::AutoProfilingInterpreter);
- isAutoProfiling = interpreterExecutionMode == ExecutionMode::AutoProfilingInterpreter;
- Var result;
- while(true)
- {
- Assert(!switchProfileMode);
- #if ENABLE_TTD_DIAGNOSTICS_TRACING
- if(this->scriptContext->ShouldPerformRecordOrReplayAction())
- {
- result = ProcessUnprofiled_PreviousStmtTracking();
- }
- else
- {
- result = ProcessUnprofiled();
- }
- #else
- result = ProcessUnprofiled();
- #endif
- Assert(!(switchProfileMode && result));
- if(switchProfileMode)
- {
- switchProfileMode = false;
- }
- else
- {
- break;
- }
- Assert(isAutoProfiling);
- #if DBG_DUMP
- if(PHASE_TRACE(InterpreterAutoProfilePhase, functionBody))
- {
- char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
- Output::Print(_u("InterpreterAutoProfile - Func %s - Started profiling\n"), functionBody->GetDebugNumberSet(debugStringBuffer));
- Output::Flush();
- }
- #endif
- Assert(!switchProfileMode);
- result = ProcessProfiled();
- Assert(!(switchProfileMode && result));
- if(switchProfileMode)
- {
- switchProfileMode = false;
- }
- else
- {
- break;
- }
- Assert(isAutoProfiling);
- #if DBG_DUMP
- if(PHASE_TRACE(InterpreterAutoProfilePhase, functionBody))
- {
- char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
- Output::Print(_u("InterpreterAutoProfile - Func %s - Stopped profiling\n"), functionBody->GetDebugNumberSet(debugStringBuffer));
- Output::Flush();
- }
- #endif
- }
- return result;
- #else
- #if ENABLE_TTD_DIAGNOSTICS_TRACING
- if(this->scriptContext->ShouldPerformRecordOrReplayAction())
- {
- return ProcessUnprofiled_PreviousStmtTracking();
- }
- else
- {
- return ProcessUnprofiled();
- }
- #else
- return ProcessUnprofiled();
- #endif
- #endif
- }
- template <class T>
- void InterpreterStackFrame::OP_GetMethodProperty(unaligned T *playout)
- {
- Var varInstance = GetReg(playout->Instance);
- OP_GetMethodProperty(varInstance, playout);
- }
- template <class T>
- void InterpreterStackFrame::OP_GetLocalMethodProperty(unaligned T *playout)
- {
- OP_GetMethodProperty(this->localClosure, playout);
- }
- template <class T>
- void InterpreterStackFrame::OP_GetMethodProperty(Var varInstance, unaligned T *playout)
- {
- #if ENABLE_COPYONACCESS_ARRAY
- JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(varInstance);
- #endif
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- RecyclableObject* obj = NULL;
- if (RecyclableObject::Is(varInstance))
- {
- obj = RecyclableObject::FromVar(varInstance);
- if ((propertyId == PropertyIds::apply || propertyId == PropertyIds::call) && ScriptFunction::Is(obj))
- {
- // If the property being loaded is "apply"/"call", make an optimistic assumption that apply/call is not overridden and
- // undefer the function right here if it was defer parsed before. This is required so that the load of "apply"/"call"
- // happens from the same "type". Otherwise, we will have a polymorphic cache for load of "apply"/"call".
- ScriptFunction *fn = ScriptFunction::FromVar(obj);
- if(fn->GetType()->GetEntryPoint() == JavascriptFunction::DeferredParsingThunk)
- {
- JavascriptFunction::DeferredParse(&fn);
- }
- }
- }
- InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
- PropertyValueInfo info;
- PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
- Var aValue;
- if (obj &&
- CacheOperators::TryGetProperty<true, true, false, false, false, false, true, false, false>(
- obj, false, obj, propertyId, &aValue, GetScriptContext(), nullptr, &info))
- {
- SetReg(playout->Value, aValue);
- return;
- }
- OP_GetMethodProperty_NoFastPath(varInstance, playout);
- }
- template <class T>
- _NOINLINE void InterpreterStackFrame::OP_GetMethodProperty_NoFastPath(Var instance, unaligned T *playout)
- {
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- Var value = JavascriptOperators::PatchGetMethod<false>(
- GetFunctionBody(),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- instance,
- propertyId
- );
- #ifdef TELEMETRY_INTERPRETER
- if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
- {
- // `successful` will be true as PatchGetMethod throws an exception if not found.
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetMethodProperty(instance, propertyId, value, true);
- }
- #endif
- SetReg(playout->Value, value);
- }
- template <class T>
- void InterpreterStackFrame::OP_GetRootMethodProperty(unaligned T *playout)
- {
- Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
- Js::Var instance = this->GetRootObject();
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
- DynamicObject *obj = DynamicObject::FromVar(instance);
- PropertyValueInfo info;
- PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
- Var aValue;
- if (CacheOperators::TryGetProperty<true, true, false, false, false, false, true, false, false>(
- obj, true, obj, propertyId, &aValue, GetScriptContext(), nullptr, &info))
- {
- SetReg(playout->Value, aValue);
- return;
- }
- OP_GetRootMethodProperty_NoFastPath(playout);
- }
- template <class T>
- _NOINLINE void InterpreterStackFrame::OP_GetRootMethodProperty_NoFastPath(unaligned T *playout)
- {
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- Var rootInstance = this->GetRootObject();
- Var value = JavascriptOperators::PatchGetRootMethod<false>(
- GetFunctionBody(),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- DynamicObject::FromVar(rootInstance),
- propertyId
- );
- #ifdef TELEMETRY_INTERPRETER
- if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
- {
- // `successful` will be true as PatchGetMethod throws an exception if not found.
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetMethodProperty(rootInstance, propertyId, value, true);
- }
- #endif
- SetReg(playout->Value, value);
- }
- template <class T>
- void InterpreterStackFrame::OP_GetMethodPropertyScoped(unaligned T *playout)
- {
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- Var varInstance = GetReg(playout->Instance);
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- RecyclableObject* obj = NULL;
- if (RecyclableObject::Is(varInstance))
- {
- obj = RecyclableObject::FromVar(varInstance);
- }
- InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
- PropertyValueInfo info;
- PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
- Var aValue;
- if (obj &&
- CacheOperators::TryGetProperty<true, true, false, false, false, false, true, false, false>(
- obj, false, obj, propertyId, &aValue, GetScriptContext(), nullptr, &info))
- {
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- SetReg(playout->Value, aValue);
- return;
- }
- OP_GetMethodPropertyScoped_NoFastPath(playout);
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- }
- template <class T>
- _NOINLINE void InterpreterStackFrame::OP_GetMethodPropertyScoped_NoFastPath(unaligned T *playout)
- {
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- Js::Var instance = GetReg(playout->Instance);
- Js::Var value = JavascriptOperators::PatchScopedGetMethod<false>(
- GetFunctionBody(),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- instance,
- propertyId
- );
- SetReg(playout->Value, value);
- #ifdef TELEMETRY_INTERPRETER
- if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
- {
- // `successful` will be true as PatchGetMethod throws an exception if not found.
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetMethodProperty(instance, propertyId, value, true);
- }
- #endif
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledGetMethodProperty(unaligned T *playout)
- {
- ProfiledGetProperty<T, false, true, false>(playout, GetReg(playout->Instance));
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledGetLocalMethodProperty(unaligned T *playout)
- {
- ProfiledGetProperty<T, false, true, false>(playout, this->localClosure);
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledGetRootMethodProperty(unaligned T *playout)
- {
- ProfiledGetProperty<T, true, true, false>(playout, GetRootObject());
- }
- RecyclableObject *
- InterpreterStackFrame::OP_CallGetFunc(Var target)
- {
- return JavascriptOperators::GetCallableObjectOrThrow(target, GetScriptContext());
- }
- void InterpreterStackFrame::OP_AsmStartCall( const unaligned OpLayoutStartCall * playout )
- {
- OP_StartCall( playout->ArgCount/sizeof(Var) );
- m_outParams[0] = scriptContext->GetLibrary()->GetUndefined();
- }
- void InterpreterStackFrame::OP_StartCall(const unaligned OpLayoutStartCall * playout)
- {
- OP_StartCall(playout->ArgCount);
- }
- void InterpreterStackFrame::OP_StartCall(uint outParamCount)
- {
- // Save the outParams for the current callsite on the outparam stack
- PushOut(m_outParams);
- // Update outParams for the indicated callsite
- m_outParams = m_outSp;
- m_outSp += outParamCount;
- AssertMsg(m_localSlots + this->m_functionBody->GetLocalsCount() < m_outSp &&
- m_outSp <= (m_localSlots + this->m_functionBody->GetLocalsCount() + this->m_functionBody->GetOutParamMaxDepth()),
- "out args Stack pointer not in range after Push");
- }
- #ifdef ASMJS_PLAT
- #if _M_X64 || _M_IX86
- void InterpreterStackFrame::OP_CallAsmInternal(RecyclableObject * function)
- {
- AsmJsFunctionInfo* asmInfo = ((ScriptFunction*)function)->GetFunctionBody()->GetAsmJsFunctionInfo();
- uint argsSize = asmInfo->GetArgByteSize();
- ScriptFunction* scriptFunc = (ScriptFunction*)function;
- ScriptContext * scriptContext = function->GetScriptContext();
- PROBE_STACK_CALL(scriptContext, function, argsSize);
- Js::FunctionEntryPointInfo* entrypointInfo = (Js::FunctionEntryPointInfo*)scriptFunc->GetEntryPointInfo();
- switch (asmInfo->GetReturnType().which())
- {
- case AsmJsRetType::Void:
- case AsmJsRetType::Signed:
- m_localIntSlots[0] = JavascriptFunction::CallAsmJsFunction<int>(function, entrypointInfo->jsMethod, asmInfo->GetArgCount(), m_outParams);
- break;
- case AsmJsRetType::Int64:
- m_localInt64Slots[0] = JavascriptFunction::CallAsmJsFunction<int64>(function, entrypointInfo->jsMethod, asmInfo->GetArgCount(), m_outParams);
- break;
- case AsmJsRetType::Double:
- m_localDoubleSlots[0] = JavascriptFunction::CallAsmJsFunction<double>(function, entrypointInfo->jsMethod, asmInfo->GetArgCount(), m_outParams);
- break;
- case AsmJsRetType::Float:
- m_localFloatSlots[0] = JavascriptFunction::CallAsmJsFunction<float>(function, entrypointInfo->jsMethod, asmInfo->GetArgCount(), m_outParams);
- break;
- #ifdef ENABLE_SIMDJS
- case AsmJsRetType::Float32x4:
- case AsmJsRetType::Int32x4:
- case AsmJsRetType::Bool32x4:
- case AsmJsRetType::Bool16x8:
- case AsmJsRetType::Bool8x16:
- case AsmJsRetType::Float64x2:
- case AsmJsRetType::Int16x8:
- case AsmJsRetType::Int8x16:
- case AsmJsRetType::Uint32x4:
- case AsmJsRetType::Uint16x8:
- case AsmJsRetType::Uint8x16:
- #if _M_X64
- X86SIMDValue simdVal;
- simdVal.m128_value = JavascriptFunction::CallAsmJsFunction<__m128>(function, entrypointInfo->jsMethod, asmInfo->GetArgCount(), m_outParams);
- m_localSimdSlots[0] = X86SIMDValue::ToSIMDValue(simdVal);
- #else
- m_localSimdSlots[0] = JavascriptFunction::CallAsmJsFunction<AsmJsSIMDValue>(function, entrypointInfo->jsMethod, asmInfo->GetArgCount(), m_outParams);
- #endif
- break;
- #endif
- default:
- Assume(UNREACHED);
- }
- Assert((uint)((ArgSlot)asmInfo->GetArgCount() + 1) == (uint)(asmInfo->GetArgCount() + 1));
- #if _M_X64
- if (scriptContext->GetConfig()->IsSimdjsEnabled())
- #endif
- {
- PopOut((ArgSlot)(argsSize / sizeof(Var)) + 1);
- }
- #if _M_X64
- else
- {
- PopOut((ArgSlot)asmInfo->GetArgCount() + 1);
- }
- #endif
- Assert(function);
- }
- #else
- void InterpreterStackFrame::OP_CallAsmInternal(RecyclableObject * function)
- {
- __debugbreak();
- }
- #endif
- #endif
- template <class T>
- void InterpreterStackFrame::OP_AsmCall(const unaligned T* playout)
- {
- OP_CallCommon(playout, OP_CallGetFunc(GetRegAllowStackVar(playout->Function)), CallFlags_None);
- AsmJsModuleInfo::EnsureHeapAttached(this->function);
- }
- template <class T>
- void InterpreterStackFrame::OP_CallCommon(const unaligned T * playout, RecyclableObject * function, unsigned flags, const Js::AuxArray<uint32> *spreadIndices)
- {
- // Always save and restore implicit call flags when calling out
- // REVIEW: Can we avoid it if we don't collect dynamic profile info?
- ThreadContext * threadContext = scriptContext->GetThreadContext();
- Js::ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- #if DBG
- if (this->IsInDebugMode())
- {
- JavascriptFunction::CheckValidDebugThunk(scriptContext, function);
- }
- #endif
- if (playout->Return == Js::Constants::NoRegister)
- {
- flags |= CallFlags_NotUsed;
- Arguments args(CallInfo((CallFlags)flags, playout->ArgCount), m_outParams);
- AssertMsg(static_cast<unsigned>(args.Info.Flags) == flags, "Flags don't fit into the CallInfo field?");
- if (spreadIndices != nullptr)
- {
- JavascriptFunction::CallSpreadFunction(function, args, spreadIndices);
- }
- else
- {
- JavascriptFunction::CallFunction<true>(function, function->GetEntryPoint(), args);
- }
- }
- else
- {
- flags |= CallFlags_Value;
- Arguments args(CallInfo((CallFlags)flags, playout->ArgCount), m_outParams);
- AssertMsg(static_cast<unsigned>(args.Info.Flags) == flags, "Flags don't fit into the CallInfo field?");
- if (spreadIndices != nullptr)
- {
- SetReg((RegSlot)playout->Return, JavascriptFunction::CallSpreadFunction(function, args, spreadIndices));
- }
- else
- {
- SetReg((RegSlot)playout->Return, JavascriptFunction::CallFunction<true>(function, function->GetEntryPoint(), args));
- }
- }
- threadContext->SetImplicitCallFlags(savedImplicitCallFlags);
- PopOut(playout->ArgCount);
- }
- template <class T>
- void InterpreterStackFrame::OP_CallCommonI(const unaligned T * playout, RecyclableObject * function, unsigned flags)
- {
- OP_CallCommon(playout, function, flags); // CallCommon doesn't do anything with Member
- }
- #if ENABLE_PROFILE_INFO
- template <class T>
- void InterpreterStackFrame::OP_ProfileCallCommon(const unaligned T * playout, RecyclableObject * function, unsigned flags, ProfileId profileId, InlineCacheIndex inlineCacheIndex, const Js::AuxArray<uint32> *spreadIndices)
- {
- FunctionBody* functionBody = this->m_functionBody;
- DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
- FunctionInfo* functionInfo = function->GetTypeId() == TypeIds_Function?
- JavascriptFunction::FromVar(function)->GetFunctionInfo() : nullptr;
- bool isConstructorCall = (CallFlags_New & flags) == CallFlags_New;
- dynamicProfileInfo->RecordCallSiteInfo(functionBody, profileId, functionInfo, functionInfo ? static_cast<JavascriptFunction*>(function) : nullptr, playout->ArgCount, isConstructorCall, inlineCacheIndex);
- OP_CallCommon<T>(playout, function, flags, spreadIndices);
- if (playout->Return != Js::Constants::NoRegister)
- {
- dynamicProfileInfo->RecordReturnTypeOnCallSiteInfo(functionBody, profileId, GetReg((RegSlot)playout->Return));
- }
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfileReturnTypeCallCommon(const unaligned T * playout, RecyclableObject * function, unsigned flags, ProfileId profileId, const Js::AuxArray<uint32> *spreadIndices)
- {
- OP_CallCommon<T>(playout, function, flags, spreadIndices);
- FunctionBody* functionBody = this->m_functionBody;
- DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
- if (playout->Return != Js::Constants::NoRegister)
- {
- dynamicProfileInfo->RecordReturnType(functionBody, profileId, GetReg((RegSlot)playout->Return));
- }
- }
- #endif
- template <class T>
- void InterpreterStackFrame::OP_CallPutCommon(const unaligned T *playout, RecyclableObject * function)
- {
- Arguments args(CallInfo(CallFlags_None, playout->ArgCount), m_outParams);
- SetReg((RegSlot)playout->Return, function->InvokePut(args));
- PopOut(playout->ArgCount);
- }
- template <class T>
- void InterpreterStackFrame::OP_CallPutCommonI(const unaligned T *playout, RecyclableObject * function)
- {
- OP_CallPutCommon(playout, function);
- }
- template <class T>
- void InterpreterStackFrame::OP_GetRootProperty(unaligned T* playout)
- {
- // Same fast path as in the backend.
- Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
- Js::Var instance = this->GetRootObject();
- InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- DynamicObject * obj = DynamicObject::FromVar(instance);
- PropertyValueInfo info;
- PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
- Var value;
- if(CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
- obj, true, obj, propertyId, &value, GetScriptContext(), nullptr, &info))
- {
- SetReg(playout->Value, value);
- return;
- }
- OP_GetRootProperty_NoFastPath(playout);
- }
- template <class T>
- void InterpreterStackFrame::OP_GetRootPropertyForTypeOf(unaligned T* playout)
- {
- Var rootInstance = GetRootObject();
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- Var value = JavascriptOperators::PatchGetRootValueForTypeOf<false>(
- GetFunctionBody(),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- DynamicObject::FromVar(rootInstance),
- propertyId
- );
- SetReg(playout->Value, value);
- #ifdef TELEMETRY_INTERPRETER
- if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
- {
- // `successful` will be true as PatchGetRootValue throws an exception if not found.
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(rootInstance, propertyId, value, /*successful:*/true);
- }
- #endif
- }
- template <class T>
- _NOINLINE void InterpreterStackFrame::OP_GetRootProperty_NoFastPath(unaligned T* playout)
- {
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- Var rootInstance = this->GetRootObject();
- Var value = JavascriptOperators::PatchGetRootValue<false>(
- GetFunctionBody(),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- DynamicObject::FromVar(rootInstance),
- propertyId
- );
- SetReg(playout->Value, value);
- #ifdef TELEMETRY_INTERPRETER
- if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
- {
- // `successful` will be true as PatchGetRootValue throws an exception if not found.
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(rootInstance, propertyId, value, /*successful:*/true);
- }
- #endif
- }
- #if ENABLE_PROFILE_INFO
- template <class T>
- void InterpreterStackFrame::UpdateFldInfoFlagsForGetSetInlineCandidate(unaligned T* playout, FldInfoFlags& fldInfoFlags, CacheType cacheType,
- DynamicProfileInfo * dynamicProfileInfo, uint inlineCacheIndex, RecyclableObject * obj)
- {
- RecyclableObject *callee = nullptr;
- //TODO: Setter case once we stop sharing inline caches for these callsites.
- if ((cacheType & (CacheType_Getter | CacheType_Setter)) && GetInlineCache(inlineCacheIndex)->GetGetterSetter(obj->GetType(), &callee))
- {
- const auto functionBody = this->m_functionBody;
- bool canInline = dynamicProfileInfo->RecordLdFldCallSiteInfo(functionBody, callee, false /*callApplyTarget*/);
- if (canInline)
- {
- //updates this fldInfoFlags passed by reference.
- fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_InlineCandidate);
- }
- }
- }
- template <class T>
- void InterpreterStackFrame::UpdateFldInfoFlagsForCallApplyInlineCandidate(unaligned T* playout, FldInfoFlags& fldInfoFlags, CacheType cacheType,
- DynamicProfileInfo * dynamicProfileInfo, uint inlineCacheIndex, RecyclableObject * obj)
- {
- RecyclableObject *callee = nullptr;
- if (!(fldInfoFlags & FldInfo_Polymorphic) && GetInlineCache(inlineCacheIndex)->GetCallApplyTarget(obj, &callee))
- {
- const auto functionBody = this->m_functionBody;
- bool canInline = dynamicProfileInfo->RecordLdFldCallSiteInfo(functionBody, callee, true /*callApplyTarget*/);
- if (canInline)
- {
- //updates this fldInfoFlags passed by reference.
- fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_InlineCandidate);
- }
- }
- }
- template <class T, bool Root, bool Method, bool CallApplyTarget>
- void InterpreterStackFrame::ProfiledGetProperty(unaligned T* playout, const Var instance)
- {
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- Var value = ProfilingHelpers::ProfiledLdFld<Root, Method, CallApplyTarget>(
- instance,
- propertyId,
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- GetFunctionBody(),
- instance);
- SetReg(playout->Value, value);
- #ifdef TELEMETRY_INTERPRETER
- if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
- {
- // `successful` will be true as PatchGetRootValue throws an exception if not found.
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, /*successful:*/true);
- }
- #endif
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledGetRootProperty(unaligned T* playout)
- {
- ProfiledGetProperty<T, true, false, false>(playout, GetRootObject());
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledGetRootPropertyForTypeOf(unaligned T* playout)
- {
- Var rootInstance = GetRootObject();
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- Var value = ProfilingHelpers::ProfiledLdFldForTypeOf<true, false, false>(
- rootInstance,
- propertyId,
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- GetFunctionBody());
- SetReg(playout->Value, value);
- #ifdef TELEMETRY_INTERPRETER
- if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
- {
- // `successful` will be true as PatchGetRootValue throws an exception if not found.
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(rootInstance, propertyId, value, /*successful:*/true);
- }
- #endif
- }
- #endif
- template <class T>
- void InterpreterStackFrame::OP_GetPropertyForTypeOf(unaligned T* playout)
- {
- Var instance = GetReg(playout->Instance);
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- Var value = JavascriptOperators::PatchGetValueForTypeOf<false>(
- GetFunctionBody(),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- instance,
- propertyId
- );
- SetReg(playout->Value, value);
- #ifdef TELEMETRY_INTERPRETER
- if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
- {
- // `successful` will be true as PatchGetRootValue throws an exception if not found.
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, /*successful:*/true);
- }
- #endif
- }
- template <class T>
- void InterpreterStackFrame::OP_GetProperty(unaligned T* playout)
- {
- // Same fast path as in the backend.
- Var instance = GetReg(playout->Instance);
- OP_GetProperty(instance, playout);
- }
- template <class T>
- void InterpreterStackFrame::OP_GetLocalProperty(unaligned T* playout)
- {
- // Same fast path as in the backend.
- Var instance = this->localClosure;
- OP_GetProperty(instance, playout);
- }
- template <class T>
- void InterpreterStackFrame::OP_GetProperty(Var instance, unaligned T* playout)
- {
- InlineCache *inlineCache = GetInlineCache(playout->inlineCacheIndex);
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- if (RecyclableObject::Is(instance))
- {
- RecyclableObject* obj = RecyclableObject::FromVar(instance);
- PropertyValueInfo info;
- PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
- Var value;
- if (CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
- obj, false, obj, propertyId, &value, GetScriptContext(), nullptr, &info))
- {
- SetReg(playout->Value, value);
- return;
- }
- }
- OP_GetProperty_NoFastPath(instance, playout);
- }
- template <class T>
- void InterpreterStackFrame::OP_GetSuperProperty(unaligned T* playout)
- {
- // Same fast path as in the backend.
- Var instance = GetReg(playout->Instance);
- Var thisInstance = GetReg(playout->Value2);
- InlineCache *inlineCache = GetInlineCache(playout->PropertyIdIndex);
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->PropertyIdIndex);
- if (RecyclableObject::Is(instance) && RecyclableObject::Is(thisInstance))
- {
- RecyclableObject* superObj = RecyclableObject::FromVar(instance);
- RecyclableObject* thisObj = RecyclableObject::FromVar(thisInstance);
- PropertyValueInfo info;
- PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->PropertyIdIndex, true);
- Var value;
- if (CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
- thisObj, false, superObj, propertyId, &value, GetScriptContext(), nullptr, &info))
- {
- SetReg(playout->Value, value);
- return;
- }
- }
- SetReg(
- playout->Value,
- JavascriptOperators::PatchGetValueWithThisPtr<false>(
- GetFunctionBody(),
- GetInlineCache(playout->PropertyIdIndex),
- playout->PropertyIdIndex,
- GetReg(playout->Instance),
- GetPropertyIdFromCacheId(playout->PropertyIdIndex),
- GetReg(playout->Value2)));
- }
- template <class T>
- _NOINLINE void InterpreterStackFrame::OP_GetProperty_NoFastPath(Var instance, unaligned T* playout)
- {
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- Var value = JavascriptOperators::PatchGetValue<false>(
- GetFunctionBody(),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- instance,
- propertyId
- );
- #ifdef TELEMETRY_INTERPRETER
- if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
- {
- // `successful` will be true as PatchGetMethod throws an exception if not found.
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, true);
- }
- #endif
- SetReg(playout->Value, value);
- }
- #if ENABLE_PROFILE_INFO
- template <class T>
- void InterpreterStackFrame::OP_ProfiledGetProperty(unaligned T* playout)
- {
- ProfiledGetProperty<T, false, false, false>(playout, GetReg(playout->Instance));
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledGetLocalProperty(unaligned T* playout)
- {
- ProfiledGetProperty<T, false, false, false>(playout, this->localClosure);
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledGetSuperProperty(unaligned T* playout)
- {
- SetReg(
- playout->Value,
- ProfilingHelpers::ProfiledLdFld<false, false, false>(
- GetReg(playout->Instance),
- GetPropertyIdFromCacheId(playout->PropertyIdIndex),
- GetInlineCache(playout->PropertyIdIndex),
- playout->PropertyIdIndex,
- GetFunctionBody(),
- GetReg(playout->Value2)));
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledGetPropertyForTypeOf(unaligned T* playout)
- {
- Var instance = GetReg(playout->Instance);
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- Var value = ProfilingHelpers::ProfiledLdFldForTypeOf<false, false, false>(
- instance,
- propertyId,
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- GetFunctionBody()
- );
- SetReg(playout->Value, value);
- #ifdef TELEMETRY_INTERPRETER
- if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
- {
- // `successful` will be true as PatchGetMethod throws an exception if not found.
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, true);
- }
- #endif
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledGetPropertyCallApplyTarget(unaligned T* playout)
- {
- ProfiledGetProperty<T, false, false, true>(playout, GetReg(playout->Instance));
- }
- #endif
- template <typename T>
- void InterpreterStackFrame::OP_GetPropertyScoped(const unaligned OpLayoutT_ElementP<T>* playout)
- {
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- // Get the property, using a scope stack rather than an individual instance.
- // Use the cache
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- FrameDisplay *pScope = this->GetEnvForEvalCode();
- InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
- ScriptContext* scriptContext = GetScriptContext();
- int length = pScope->GetLength();
- if ( 1 == length )
- {
- DynamicObject *obj = (DynamicObject*)pScope->GetItem(0);
- PropertyValueInfo info;
- PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
- Var value;
- if (CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
- obj, false, obj, propertyId, &value, scriptContext, nullptr, &info))
- {
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- SetReg(playout->Value, value);
- return;
- }
- }
- OP_GetPropertyScoped_NoFastPath(playout);
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- }
- template <typename T>
- void InterpreterStackFrame::OP_GetPropertyForTypeOfScoped(const unaligned OpLayoutT_ElementP<T>* playout)
- {
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- // Get the property, using a scope stack rather than an individual instance.
- // Use the cache
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- FrameDisplay *pScope = this->GetEnvForEvalCode();
- InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
- ScriptContext* scriptContext = GetScriptContext();
- int length = pScope->GetLength();
- if (1 == length)
- {
- DynamicObject *obj = (DynamicObject*)pScope->GetItem(0);
- PropertyValueInfo info;
- PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
- Var value;
- if (CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
- obj, false, obj, propertyId, &value, scriptContext, nullptr, &info))
- {
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- SetReg(playout->Value, value);
- return;
- }
- }
- SetReg(
- playout->Value,
- JavascriptOperators::PatchGetPropertyForTypeOfScoped<false>(
- GetFunctionBody(),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- GetEnvForEvalCode(),
- GetPropertyIdFromCacheId(playout->inlineCacheIndex),
- GetReg(Js::FunctionBody::RootObjectRegSlot)));
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- }
- template <typename T>
- _NOINLINE void InterpreterStackFrame::OP_GetPropertyScoped_NoFastPath(const unaligned OpLayoutT_ElementP<T>* playout)
- {
- // Implicit root object as default instance
- Var defaultInstance = GetReg(Js::FunctionBody::RootObjectRegSlot);
- // PatchGetPropertyScoped doesn't update type and slotIndex if the scope is not an array of length 1.
- SetReg(
- playout->Value,
- JavascriptOperators::PatchGetPropertyScoped<false>(
- GetFunctionBody(),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- GetEnvForEvalCode(),
- GetPropertyIdFromCacheId(playout->inlineCacheIndex),
- defaultInstance));
- }
- template <class T>
- void InterpreterStackFrame::OP_SetPropertyScoped(unaligned T* playout, PropertyOperationFlags flags)
- {
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- // Set the property, using a scope stack rather than an individual instance.
- // Use the cache
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- FrameDisplay *pScope = this->GetEnvForEvalCode();
- InlineCache *inlineCache = GetInlineCache(playout->inlineCacheIndex);
- ScriptContext* scriptContext = GetScriptContext();
- Var value = GetReg(playout->Value);
- DynamicObject *obj;
- int length = pScope->GetLength();
- if ( 1 == length )
- {
- obj = (DynamicObject*)pScope->GetItem(0);
- PropertyValueInfo info;
- PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
- if (CacheOperators::TrySetProperty<true, false, false, false, false, true, false, false>(
- obj, false, propertyId, value, scriptContext, flags, nullptr, &info))
- {
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- return;
- }
- }
- OP_SetPropertyScoped_NoFastPath(playout, flags);
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- }
- template <class T>
- _NOINLINE void InterpreterStackFrame::OP_SetPropertyScoped_NoFastPath(unaligned T* playout, PropertyOperationFlags flags)
- {
- // Implicit root object as default instance
- Var defaultInstance = GetReg(Js::FunctionBody::RootObjectRegSlot);
- // PatchSetPropertyScoped doesn't update type and slotIndex if the scope is not an array of length 1.
- JavascriptOperators::PatchSetPropertyScoped<false>(
- GetFunctionBody(),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- GetEnvForEvalCode(),
- GetPropertyIdFromCacheId(playout->inlineCacheIndex),
- GetReg(playout->Value),
- defaultInstance,
- flags);
- }
- template <class T>
- void InterpreterStackFrame::OP_SetPropertyScopedStrict(unaligned T* playout)
- {
- OP_SetPropertyScoped(playout, PropertyOperation_StrictMode);
- }
- template <class T>
- void InterpreterStackFrame::OP_ConsoleSetPropertyScoped(unaligned T* playout)
- {
- OP_SetPropertyScoped(playout, PropertyOperation_AllowUndeclInConsoleScope);
- }
- template <class T>
- inline bool InterpreterStackFrame::TrySetPropertyLocalFastPath(unaligned T* playout, PropertyId pid, Var instance, InlineCache*& inlineCache, PropertyOperationFlags flags)
- {
- Assert(!TaggedNumber::Is(instance));
- RecyclableObject* obj = RecyclableObject::FromVar(instance);
- inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
- PropertyValueInfo info;
- PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
- return
- CacheOperators::TrySetProperty<true, false, false, false, false, true, false, false>(
- obj,
- !!(flags & PropertyOperation_Root),
- pid,
- GetReg(playout->Value),
- GetScriptContext(),
- flags,
- nullptr,
- &info);
- }
- template <class T>
- inline void InterpreterStackFrame::DoSetProperty(unaligned T* playout, Var instance, PropertyOperationFlags flags)
- {
- // Same fast path as in the backend.
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- InlineCache *inlineCache;
- if (!TaggedNumber::Is(instance)
- && TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache, flags))
- {
- if(GetJavascriptFunction()->GetConstructorCache()->NeedsUpdateAfterCtor())
- {
- // This function has only 'this' statements and is being used as a constructor. When the constructor exits, the
- // function object's constructor cache will be updated with the type produced by the constructor. From that
- // point on, when the same function object is used as a constructor, the a new object with the final type will
- // be created. Whatever is stored in the inline cache currently will cause cache misses after the constructor
- // cache update. So, just clear it now so that the caches won't be flagged as polymorphic.
- inlineCache->Clear();
- }
- return;
- }
- DoSetProperty_NoFastPath(playout, instance, flags);
- }
- template <class T>
- inline void InterpreterStackFrame::DoSetSuperProperty(unaligned T* playout, Var instance, PropertyOperationFlags flags)
- {
- DoSetSuperProperty_NoFastPath(playout, instance, m_functionBody->GetIsStrictMode() ?
- (PropertyOperationFlags)(flags | PropertyOperation_StrictMode) : flags);
- }
- template <class T>
- _NOINLINE void InterpreterStackFrame::DoSetProperty_NoFastPath(unaligned T* playout, Var instance, PropertyOperationFlags flags)
- {
- #if ENABLE_COPYONACCESS_ARRAY
- JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
- #endif
- InlineCache *const inlineCache = GetInlineCache(playout->inlineCacheIndex);
- const auto PatchPutRootValue = &JavascriptOperators::PatchPutRootValueNoLocalFastPath<false, InlineCache>;
- const auto PatchPutValue = &JavascriptOperators::PatchPutValueNoLocalFastPath<false, InlineCache>;
- const auto PatchPut = flags & PropertyOperation_Root ? PatchPutRootValue : PatchPutValue;
- PatchPut(
- GetFunctionBody(),
- inlineCache,
- playout->inlineCacheIndex,
- instance,
- GetPropertyIdFromCacheId(playout->inlineCacheIndex),
- GetReg(playout->Value),
- flags);
- if(!TaggedNumber::Is(instance) && GetJavascriptFunction()->GetConstructorCache()->NeedsUpdateAfterCtor())
- {
- // This function has only 'this' statements and is being used as a constructor. When the constructor exits, the
- // function object's constructor cache will be updated with the type produced by the constructor. From that
- // point on, when the same function object is used as a constructor, the a new object with the final type will
- // be created. Whatever is stored in the inline cache currently will cause cache misses after the constructor
- // cache update. So, just clear it now so that the caches won't be flagged as polymorphic.
- inlineCache->Clear();
- }
- }
- template <class T>
- _NOINLINE void InterpreterStackFrame::DoSetSuperProperty_NoFastPath(unaligned T* playout, Var instance, PropertyOperationFlags flags)
- {
- #if ENABLE_COPYONACCESS_ARRAY
- JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
- #endif
- InlineCache *const inlineCache = GetInlineCache(playout->PropertyIdIndex);
- JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPath<false, InlineCache>(
- GetFunctionBody(),
- inlineCache,
- playout->PropertyIdIndex,
- instance,
- GetPropertyIdFromCacheId(playout->PropertyIdIndex),
- GetReg(playout->Value),
- GetReg(playout->Value2),
- flags);
- if (!TaggedNumber::Is(instance) && GetJavascriptFunction()->GetConstructorCache()->NeedsUpdateAfterCtor())
- {
- // This function has only 'this' statements and is being used as a constructor. When the constructor exits, the
- // function object's constructor cache will be updated with the type produced by the constructor. From that
- // point on, when the same function object is used as a constructor, the a new object with the final type will
- // be created. Whatever is stored in the inline cache currently will cause cache misses after the constructor
- // cache update. So, just clear it now so that the caches won't be flagged as polymorphic.
- inlineCache->Clear();
- }
- }
- #if ENABLE_PROFILE_INFO
- template <class T, bool Root>
- void InterpreterStackFrame::ProfiledSetProperty(unaligned T* playout, Var instance, PropertyOperationFlags flags)
- {
- Assert(!Root || flags & PropertyOperation_Root);
- ProfilingHelpers::ProfiledStFld<Root>(
- instance,
- GetPropertyIdFromCacheId(playout->inlineCacheIndex),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- GetReg(playout->Value),
- flags,
- GetJavascriptFunction(),
- instance);
- }
- template <class T, bool Root>
- void InterpreterStackFrame::ProfiledSetSuperProperty(unaligned T* playout, Var instance, Var thisInstance, PropertyOperationFlags flags)
- {
- Assert(!Root || flags & PropertyOperation_Root);
- ProfilingHelpers::ProfiledStFld<Root>(
- instance,
- GetPropertyIdFromCacheId(playout->PropertyIdIndex),
- GetInlineCache(playout->PropertyIdIndex),
- playout->PropertyIdIndex,
- GetReg(playout->Value),
- m_functionBody->GetIsStrictMode() ?
- (PropertyOperationFlags)(flags | PropertyOperation_StrictMode ) : flags,
- GetJavascriptFunction(),
- thisInstance);
- }
- #endif
- template <class T>
- void InterpreterStackFrame::OP_SetProperty(unaligned T* playout)
- {
- DoSetProperty(playout, GetReg(playout->Instance), PropertyOperation_None);
- }
- template <class T>
- void InterpreterStackFrame::OP_SetLocalProperty(unaligned T* playout)
- {
- DoSetProperty(playout, this->localClosure, PropertyOperation_None);
- }
- template <class T>
- void InterpreterStackFrame::OP_SetSuperProperty(unaligned T* playout)
- {
- DoSetSuperProperty(playout, GetReg(playout->Instance), PropertyOperation_None);
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledSetProperty(unaligned T* playout)
- {
- ProfiledSetProperty<T, false>(playout, GetReg(playout->Instance), PropertyOperation_None);
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledSetLocalProperty(unaligned T* playout)
- {
- ProfiledSetProperty<T, false>(playout, this->localClosure, PropertyOperation_None);
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledSetSuperProperty(unaligned T* playout)
- {
- ProfiledSetSuperProperty<T, false>(playout, GetReg(playout->Instance), GetReg(playout->Value2), PropertyOperation_None);
- }
- template <class T>
- void InterpreterStackFrame::OP_SetRootProperty(unaligned T* playout)
- {
- DoSetProperty(playout, this->GetRootObject(), PropertyOperation_Root);
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledSetRootProperty(unaligned T* playout)
- {
- ProfiledSetProperty<T, true>(playout, this->GetRootObject(), PropertyOperation_Root);
- }
- template <class T>
- void InterpreterStackFrame::OP_SetPropertyStrict(unaligned T* playout)
- {
- DoSetProperty(playout, GetReg(playout->Instance), PropertyOperation_StrictMode);
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledSetPropertyStrict(unaligned T* playout)
- {
- ProfiledSetProperty<T, false>(playout, GetReg(playout->Instance), PropertyOperation_StrictMode);
- }
- template <class T>
- void InterpreterStackFrame::OP_SetRootPropertyStrict(unaligned T* playout)
- {
- DoSetProperty(playout, this->GetRootObject(), PropertyOperation_StrictModeRoot);
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledSetRootPropertyStrict(unaligned T* playout)
- {
- ProfiledSetProperty<T, true>(playout, this->GetRootObject(), PropertyOperation_StrictModeRoot);
- }
- #if ENABLE_PROFILE_INFO
- template <bool doProfile>
- Var InterpreterStackFrame::ProfiledDivide(Var aLeft, Var aRight, ScriptContext* scriptContext, ProfileId profileId)
- {
- Var result = JavascriptMath::Divide(aLeft, aRight,scriptContext);
- if (doProfile)
- {
- Js::FunctionBody* body = this->m_functionBody;
- body->GetDynamicProfileInfo()->RecordDivideResultType(body, profileId, result);
- }
- return result;
- }
- template <bool doProfile>
- Var InterpreterStackFrame::ProfileModulus(Var aLeft, Var aRight, ScriptContext* scriptContext, ProfileId profileId)
- {
- // If both arguments are TaggedInt, then try to do integer division
- // This case is not handled by the lowerer.
- if (doProfile)
- {
- Js::FunctionBody* body = this->function->GetFunctionBody();
- if(TaggedInt::IsPair(aLeft, aRight))
- {
- int nLeft = TaggedInt::ToInt32(aLeft);
- int nRight = TaggedInt::ToInt32(aRight);
- // nLeft is positive and nRight is +2^i
- // Fast path for Power of 2 divisor
- if (nLeft > 0 && ::Math::IsPow2(nRight))
- {
- body->GetDynamicProfileInfo()->RecordModulusOpType(body, profileId, /*isModByPowerOf2*/ true);
- return TaggedInt::ToVarUnchecked(nLeft & (nRight - 1));
- }
- }
- body->GetDynamicProfileInfo()->RecordModulusOpType(body, profileId, /*isModByPowerOf2*/ false);
- }
- return JavascriptMath::Modulus(aLeft, aRight,scriptContext);
- }
- template <bool doProfile>
- Var InterpreterStackFrame::ProfiledSwitch(Var exp, ProfileId profileId)
- {
- if (doProfile)
- {
- Js::FunctionBody* body = this->m_functionBody;
- body->GetDynamicProfileInfo()->RecordSwitchType(body, profileId, exp);
- }
- return exp;
- }
- #else
- template <bool doProfile>
- Var InterpreterStackFrame::ProfiledDivide(Var aLeft, Var aRight, ScriptContext* scriptContext, ProfileId profileId)
- {
- Assert(!doProfile);
- return JavascriptMath::Divide(aLeft, aRight, scriptContext);
- }
- template <bool doProfile>
- Var InterpreterStackFrame::ProfileModulus(Var aLeft, Var aRight, ScriptContext* scriptContext, ProfileId profileId)
- {
- Assert(!doProfile);
- return JavascriptMath::Modulus(aLeft, aRight, scriptContext);
- }
- template <bool doProfile>
- Var InterpreterStackFrame::ProfiledSwitch(Var exp, ProfileId profileId)
- {
- Assert(!doProfile);
- return exp;
- }
- #endif
- template <class T>
- void InterpreterStackFrame::DoInitProperty(unaligned T* playout, Var instance)
- {
- // Same fast path as in the backend.
- InlineCache *inlineCache = nullptr;
- Assert(!TaggedNumber::Is(instance));
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- if (TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache))
- {
- return;
- }
- DoInitProperty_NoFastPath(playout, instance);
- }
- template <class T>
- _NOINLINE void InterpreterStackFrame::DoInitProperty_NoFastPath(unaligned T* playout, Var instance)
- {
- JavascriptOperators::PatchInitValue<false>(
- GetFunctionBody(),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- RecyclableObject::FromVar(instance),
- GetPropertyIdFromCacheId(playout->inlineCacheIndex),
- GetReg(playout->Value));
- }
- template <class T>
- void InterpreterStackFrame::OP_InitClassMember(const unaligned T * playout)
- {
- uint inlineCacheIndex = playout->inlineCacheIndex;
- InlineCache * inlineCache = this->GetInlineCache(inlineCacheIndex);
- Var instance = GetReg(playout->Instance);
- PropertyOperationFlags flags = PropertyOperation_None;
- Assert(!TaggedNumber::Is(instance));
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- if (!TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache, flags))
- {
- JavascriptOperators::OP_InitClassMember(instance, propertyId, GetReg(playout->Value));
- }
- }
- template <class T>
- void InterpreterStackFrame::OP_InitClassMemberGet(const unaligned T * playout)
- {
- JavascriptOperators::OP_InitClassMemberGet(
- GetReg(playout->Instance),
- m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
- GetReg(playout->Value));
- }
- template <class T>
- void InterpreterStackFrame::OP_InitClassMemberSet(const unaligned T * playout)
- {
- JavascriptOperators::OP_InitClassMemberSet(
- GetReg(playout->Instance),
- m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
- GetReg(playout->Value));
- }
- template <class T>
- void InterpreterStackFrame::OP_InitClassMemberSetComputedName(const unaligned T * playout)
- {
- JavascriptOperators::OP_InitClassMemberSetComputedName(
- GetReg(playout->Instance),
- GetReg(playout->Element),
- GetReg(playout->Value),
- m_functionBody->GetScriptContext());
- }
- template <class T>
- void InterpreterStackFrame::OP_InitClassMemberGetComputedName(const unaligned T * playout)
- {
- JavascriptOperators::OP_InitClassMemberGetComputedName(
- GetReg(playout->Instance),
- GetReg(playout->Element),
- GetReg(playout->Value),
- m_functionBody->GetScriptContext());
- }
- template <class T>
- void InterpreterStackFrame::OP_InitClassMemberComputedName(const unaligned T * playout)
- {
- JavascriptOperators::OP_InitClassMemberComputedName(
- GetReg(playout->Instance),
- GetReg(playout->Element),
- GetReg(playout->Value),
- m_functionBody->GetScriptContext());
- }
- template <class T>
- void InterpreterStackFrame::DoInitLetFld(const unaligned T * playout, Var instance, PropertyOperationFlags flags)
- {
- uint inlineCacheIndex = playout->inlineCacheIndex;
- InlineCache * inlineCache = this->GetInlineCache(inlineCacheIndex);
- Assert(!TaggedNumber::Is(instance));
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- if (!TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache, flags))
- {
- JavascriptOperators::OP_InitLetProperty(instance, propertyId, GetReg(playout->Value));
- }
- }
- template <class T>
- void InterpreterStackFrame::DoInitConstFld(const unaligned T * playout, Var instance, PropertyOperationFlags flags)
- {
- uint inlineCacheIndex = playout->inlineCacheIndex;
- InlineCache * inlineCache = this->GetInlineCache(inlineCacheIndex);
- Assert(!TaggedNumber::Is(instance));
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- if (!TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache, flags))
- {
- JavascriptOperators::OP_InitConstProperty(instance, propertyId, GetReg(playout->Value));
- }
- }
- template <class T>
- void InterpreterStackFrame::OP_InitProperty(unaligned T* playout)
- {
- DoInitProperty(playout, GetReg(playout->Instance));
- }
- template <class T>
- void InterpreterStackFrame::OP_InitLocalProperty(unaligned T* playout)
- {
- DoInitProperty(playout, this->localClosure);
- }
- template <class T>
- void InterpreterStackFrame::OP_InitInnerFld(const unaligned T* playout)
- {
- DoInitProperty(playout, InnerScopeFromIndex(playout->scopeIndex));
- }
- template <class T>
- void InterpreterStackFrame::OP_InitLetFld(const unaligned T * playout)
- {
- DoInitLetFld(playout, GetReg(playout->Instance));
- }
- template <class T>
- void InterpreterStackFrame::OP_InitInnerLetFld(const unaligned T * playout)
- {
- DoInitLetFld(playout, InnerScopeFromIndex(playout->scopeIndex));
- }
- template <class T>
- void InterpreterStackFrame::OP_InitLocalLetFld(const unaligned T * playout)
- {
- DoInitLetFld(playout, this->localClosure);
- }
- template <class T>
- void InterpreterStackFrame::OP_InitConstFld(const unaligned T * playout)
- {
- DoInitConstFld(playout, GetReg(playout->Instance));
- }
- template <class T>
- void InterpreterStackFrame::OP_InitRootProperty(unaligned T* playout)
- {
- Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
- DoInitProperty(playout, this->GetRootObject());
- }
- template <class T>
- void InterpreterStackFrame::OP_InitRootLetFld(const unaligned T * playout)
- {
- Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
- DoInitLetFld(playout, this->GetRootObject(), PropertyOperation_Root);
- }
- template <class T>
- void InterpreterStackFrame::OP_InitRootConstFld(const unaligned T * playout)
- {
- Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
- DoInitConstFld(playout, this->GetRootObject(), PropertyOperation_Root);
- }
- template <class T>
- void InterpreterStackFrame::OP_InitUndeclLetProperty(unaligned T* playout)
- {
- Var instance = InnerScopeFromIndex(playout->scopeIndex);
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- JavascriptOperators::OP_InitLetProperty(instance, propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
- }
- template <class T>
- void InterpreterStackFrame::OP_InitUndeclLocalLetProperty(unaligned T* playout)
- {
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- JavascriptOperators::OP_InitLetProperty(this->localClosure, propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
- }
- void InterpreterStackFrame::OP_InitUndeclRootLetProperty(uint propertyIdIndex)
- {
- Var instance = this->GetRootObject();
- PropertyId propertyId = this->m_functionBody->GetReferencedPropertyId(propertyIdIndex);
- JavascriptOperators::OP_InitUndeclRootLetProperty(instance, propertyId);
- }
- template <class T>
- void InterpreterStackFrame::OP_InitUndeclConstProperty(unaligned T* playout)
- {
- Var instance = InnerScopeFromIndex(playout->scopeIndex);
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- JavascriptOperators::OP_InitConstProperty(instance, propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
- }
- template <class T>
- void InterpreterStackFrame::OP_InitUndeclLocalConstProperty(unaligned T* playout)
- {
- PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
- JavascriptOperators::OP_InitConstProperty(this->localClosure, propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
- }
- void InterpreterStackFrame::OP_InitUndeclRootConstProperty(uint propertyIdIndex)
- {
- Var instance = this->GetRootObject();
- PropertyId propertyId = this->m_functionBody->GetReferencedPropertyId(propertyIdIndex);
- JavascriptOperators::OP_InitUndeclRootConstProperty(instance, propertyId);
- }
- template <class T>
- void InterpreterStackFrame::OP_InitUndeclConsoleLetProperty(unaligned T* playout)
- {
- FrameDisplay* pScope = (FrameDisplay*)this->LdEnv();
- AssertMsg(ConsoleScopeActivationObject::Is((DynamicObject*)pScope->GetItem(pScope->GetLength() - 1)), "How come we got this opcode without ConsoleScopeActivationObject?");
- PropertyId propertyId = m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex);
- JavascriptOperators::OP_InitLetProperty(pScope->GetItem(0), propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
- }
- template <class T>
- void InterpreterStackFrame::OP_InitUndeclConsoleConstProperty(unaligned T* playout)
- {
- FrameDisplay* pScope = (FrameDisplay*)this->LdEnv();
- AssertMsg(ConsoleScopeActivationObject::Is((DynamicObject*)pScope->GetItem(pScope->GetLength() - 1)), "How come we got this opcode without ConsoleScopeActivationObject?");
- PropertyId propertyId = m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex);
- JavascriptOperators::OP_InitConstProperty(pScope->GetItem(0), propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
- }
- #if ENABLE_PROFILE_INFO
- template <class T>
- void InterpreterStackFrame::ProfiledInitProperty(unaligned T* playout, Var instance)
- {
- ProfilingHelpers::ProfiledInitFld(
- RecyclableObject::FromVar(instance),
- GetPropertyIdFromCacheId(playout->inlineCacheIndex),
- GetInlineCache(playout->inlineCacheIndex),
- playout->inlineCacheIndex,
- GetReg(playout->Value),
- GetFunctionBody());
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledInitProperty(unaligned T* playout)
- {
- ProfiledInitProperty(playout, GetReg(playout->Instance));
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledInitLocalProperty(unaligned T* playout)
- {
- ProfiledInitProperty(playout, this->localClosure);
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledInitRootProperty(unaligned T* playout)
- {
- ProfiledInitProperty(playout, this->GetRootObject());
- }
- template <class T>
- void InterpreterStackFrame::OP_ProfiledGetElementI(const unaligned OpLayoutDynamicProfile<T>* playout)
- {
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- SetReg(
- playout->Value,
- ProfilingHelpers::ProfiledLdElem(
- GetReg(playout->Instance),
- GetReg(playout->Element),
- m_functionBody,
- playout->profileId));
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- }
- #endif
- template <typename T>
- void InterpreterStackFrame::OP_GetElementI(const unaligned T* playout)
- {
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- // Same fast path as in the backend.
- Var instance = GetReg(playout->Instance);
- // Only enable fast path if the javascript array is not cross site
- Var element;
- #if ENABLE_PROFILE_INFO
- if (!TaggedNumber::Is(instance) && VirtualTableInfo<JavascriptArray>::HasVirtualTable(instance))
- {
- element =
- ProfilingHelpers::ProfiledLdElem_FastPath(
- JavascriptArray::FromVar(instance),
- GetReg(playout->Element),
- GetScriptContext());
- }
- else
- #endif
- {
- element = JavascriptOperators::OP_GetElementI(instance, GetReg(playout->Element), GetScriptContext());
- }
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- SetReg(playout->Value, element);
- }
- template <typename T>
- void InterpreterStackFrame::OP_SetElementI(const unaligned T* playout, PropertyOperationFlags flags)
- {
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- // Same fast path as in the backend.
- Var instance = GetReg(playout->Instance);
- const Var varIndex = GetReg(playout->Element);
- const Var value = GetReg(playout->Value);
- #if ENABLE_PROFILE_INFO
- // Only enable fast path if the javascript array is not cross site
- if (!TaggedNumber::Is(instance) &&
- VirtualTableInfo<JavascriptArray>::HasVirtualTable(instance) &&
- !JavascriptOperators::SetElementMayHaveImplicitCalls(GetScriptContext()))
- {
- ProfilingHelpers::ProfiledStElem_FastPath(
- JavascriptArray::FromVar(instance),
- varIndex,
- value,
- GetScriptContext(),
- flags);
- }
- else
- #endif
- {
- JavascriptOperators::OP_SetElementI(instance, varIndex, value, GetScriptContext(), flags);
- }
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- }
- #if ENABLE_PROFILE_INFO
- template <typename T>
- void InterpreterStackFrame::OP_ProfiledSetElementI(
- const unaligned OpLayoutDynamicProfile<T>* playout,
- PropertyOperationFlags flags)
- {
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- ProfilingHelpers::ProfiledStElem(
- GetReg(playout->Instance),
- GetReg(playout->Element),
- GetReg(playout->Value),
- m_functionBody,
- playout->profileId,
- flags);
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- }
- #endif
- template <typename T>
- void InterpreterStackFrame::OP_SetElementIStrict(const unaligned T* playout)
- {
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- OP_SetElementI(playout, PropertyOperation_StrictMode);
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- }
- #if ENABLE_PROFILE_INFO
- template <typename T>
- void InterpreterStackFrame::OP_ProfiledSetElementIStrict(const unaligned OpLayoutDynamicProfile<T>* playout)
- {
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- OP_ProfiledSetElementI(playout, PropertyOperation_StrictMode);
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- }
- #endif
- template <class T>
- void InterpreterStackFrame::OP_LdArrayHeadSegment(const unaligned T* playout)
- {
- JavascriptArray* array = JavascriptArray::FromAnyArray(GetReg(playout->R1));
- // The array is create by the built-in on the same script context
- Assert(array->GetScriptContext() == GetScriptContext());
- SetNonVarReg(playout->R0, array->GetHead());
- }
- template <class T>
- void InterpreterStackFrame::OP_SetArraySegmentItem_CI4(const unaligned T* playout)
- {
- SparseArraySegment<Var> * segment = (SparseArraySegment<Var> *)GetNonVarReg(playout->Instance);
- uint32 index = playout->Element;
- Var value = GetReg(playout->Value);
- Assert(segment->left == 0);
- Assert(index < segment->length);
- segment->elements[index] = value;
- }
- template <class T>
- void InterpreterStackFrame::OP_NewScArray(const unaligned T * playout)
- {
- JavascriptArray *arr;
- arr = scriptContext->GetLibrary()->CreateArrayLiteral(playout->C1);
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- arr->CheckForceES5Array();
- #endif
- SetReg(playout->R0, arr);
- }
- #if ENABLE_PROFILE_INFO
- template <bool Profiled, class T>
- void InterpreterStackFrame::ProfiledNewScArray(const unaligned OpLayoutDynamicProfile<T> * playout)
- {
- if(!Profiled && !isAutoProfiling)
- {
- OP_NewScArray(playout);
- return;
- }
- SetReg(
- playout->R0,
- ProfilingHelpers::ProfiledNewScArray(
- playout->C1,
- m_functionBody,
- playout->profileId));
- }
- #else
- template <bool Profiled, class T>
- void InterpreterStackFrame::ProfiledNewScArray(const unaligned OpLayoutDynamicProfile<T> * playout)
- {
- Assert(!Profiled);
- OP_NewScArray(playout);
- }
- #endif
- void InterpreterStackFrame::OP_NewScIntArray(const unaligned OpLayoutAuxiliary * playout)
- {
- #if ENABLE_PROFILE_INFO
- if(isAutoProfiling)
- {
- OP_ProfiledNewScIntArray(static_cast<const unaligned OpLayoutDynamicProfile<OpLayoutAuxiliary> *>(playout));
- return;
- }
- #endif
- const Js::AuxArray<int32> *ints = Js::ByteCodeReader::ReadAuxArray<int32>(playout->Offset, this->GetFunctionBody());
- JavascriptNativeIntArray *arr = scriptContext->GetLibrary()->CreateNativeIntArrayLiteral(ints->count);
- SparseArraySegment<int32> * segment = (SparseArraySegment<int32>*)arr->GetHead();
- JavascriptOperators::AddIntsToArraySegment(segment, ints);
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- arr->CheckForceES5Array();
- #endif
- SetReg(playout->R0, arr);
- }
- #if ENABLE_PROFILE_INFO
- void InterpreterStackFrame::OP_ProfiledNewScIntArray(const unaligned OpLayoutDynamicProfile<OpLayoutAuxiliary> * playout)
- {
- const Js::AuxArray<int32> *ints = Js::ByteCodeReader::ReadAuxArray<int32>(playout->Offset, this->GetFunctionBody());
- Js::ProfileId profileId = playout->profileId;
- FunctionBody *functionBody = this->m_functionBody;
- ArrayCallSiteInfo *arrayInfo = functionBody->GetDynamicProfileInfo()->GetArrayCallSiteInfo(functionBody, profileId);
- Assert(arrayInfo);
- JavascriptArray *arr;
- if (arrayInfo && arrayInfo->IsNativeIntArray())
- {
- #if ENABLE_COPYONACCESS_ARRAY
- JavascriptLibrary *lib = scriptContext->GetLibrary();
- if (JavascriptLibrary::IsCopyOnAccessArrayCallSite(lib, arrayInfo, ints->count))
- {
- Assert(lib->cacheForCopyOnAccessArraySegments);
- arr = scriptContext->GetLibrary()->CreateCopyOnAccessNativeIntArrayLiteral(arrayInfo, functionBody, ints);
- }
- else
- #endif
- {
- arr = scriptContext->GetLibrary()->CreateNativeIntArrayLiteral(ints->count);
- SparseArraySegment<int32> *segment = (SparseArraySegment<int32>*)arr->GetHead();
- JavascriptOperators::AddIntsToArraySegment(segment, ints);
- }
- JavascriptNativeIntArray *intArray = reinterpret_cast<JavascriptNativeIntArray*>(arr);
- Recycler *recycler = scriptContext->GetRecycler();
- intArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
- }
- else if (arrayInfo && arrayInfo->IsNativeFloatArray())
- {
- arr = scriptContext->GetLibrary()->CreateNativeFloatArrayLiteral(ints->count);
- SparseArraySegment<double> * segment = (SparseArraySegment<double>*)arr->GetHead();
- for (uint i = 0; i < ints->count; i++)
- {
- segment->elements[i] = (double)ints->elements[i];
- }
- JavascriptNativeFloatArray *floatArray = reinterpret_cast<JavascriptNativeFloatArray*>(arr);
- Recycler *recycler = scriptContext->GetRecycler();
- floatArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
- }
- else
- {
- arr = scriptContext->GetLibrary()->CreateArrayLiteral(ints->count);
- SparseArraySegment<Var> * segment = (SparseArraySegment<Var>*)arr->GetHead();
- for (uint i = 0; i < ints->count; i++)
- {
- segment->elements[i] = JavascriptNumber::ToVar(ints->elements[i], scriptContext);
- }
- }
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- arr->CheckForceES5Array();
- #endif
- SetReg(playout->R0, arr);
- }
- #endif
- void InterpreterStackFrame::OP_NewScFltArray(const unaligned OpLayoutAuxiliary * playout )
- {
- #if ENABLE_PROFILE_INFO
- if(isAutoProfiling)
- {
- OP_ProfiledNewScFltArray(static_cast<const unaligned OpLayoutDynamicProfile<OpLayoutAuxiliary> *>(playout));
- return;
- }
- #endif
- const Js::AuxArray<double> *doubles = Js::ByteCodeReader::ReadAuxArray<double>(playout->Offset, this->GetFunctionBody());
- JavascriptNativeFloatArray *arr = scriptContext->GetLibrary()->CreateNativeFloatArrayLiteral(doubles->count);
- SparseArraySegment<double> * segment = (SparseArraySegment<double>*)arr->GetHead();
- JavascriptOperators::AddFloatsToArraySegment(segment, doubles);
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- arr->CheckForceES5Array();
- #endif
- SetReg(playout->R0, arr);
- }
- #if ENABLE_PROFILE_INFO
- void InterpreterStackFrame::OP_ProfiledNewScFltArray(const unaligned OpLayoutDynamicProfile<OpLayoutAuxiliary> * playout)
- {
- const Js::AuxArray<double> *doubles = Js::ByteCodeReader::ReadAuxArray<double>(playout->Offset, this->GetFunctionBody());
- Js::ProfileId profileId = playout->profileId;
- FunctionBody *functionBody = this->m_functionBody;
- ArrayCallSiteInfo *arrayInfo = functionBody->GetDynamicProfileInfo()->GetArrayCallSiteInfo(functionBody, profileId);
- Assert(arrayInfo);
- JavascriptArray *arr;
- if (arrayInfo && arrayInfo->IsNativeFloatArray())
- {
- arrayInfo->SetIsNotNativeIntArray();
- arr = scriptContext->GetLibrary()->CreateNativeFloatArrayLiteral(doubles->count);
- SparseArraySegment<double> * segment = (SparseArraySegment<double>*)arr->GetHead();
- JavascriptOperators::AddFloatsToArraySegment(segment, doubles);
- JavascriptNativeFloatArray *floatArray = reinterpret_cast<JavascriptNativeFloatArray*>(arr);
- Recycler *recycler = scriptContext->GetRecycler();
- floatArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
- }
- else
- {
- arr = scriptContext->GetLibrary()->CreateArrayLiteral(doubles->count);
- SparseArraySegment<Var> * segment = (SparseArraySegment<Var>*)arr->GetHead();
- for (uint i = 0; i < doubles->count; i++)
- {
- segment->elements[i] = JavascriptNumber::ToVarNoCheck(doubles->elements[i], scriptContext);
- }
- }
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- arr->CheckForceES5Array();
- #endif
- SetReg(playout->R0, arr);
- }
- #endif
- void InterpreterStackFrame::OP_SetArraySegmentVars(const unaligned OpLayoutAuxiliary * playout)
- {
- const Js::VarArray *vars = Js::ByteCodeReader::ReadAuxArray<Var>(playout->Offset, this->GetFunctionBody());
- SparseArraySegment<Var> * segment =(SparseArraySegment<Var> *)GetNonVarReg(playout->R0);
- JavascriptOperators::AddVarsToArraySegment(segment, vars);
- }
- template <class T>
- void InterpreterStackFrame::OP_SetArrayItemC_CI4(const unaligned T* playout)
- {
- JavascriptArray* array = JavascriptArray::FromAnyArray(GetReg(playout->Instance));
- uint32 index = playout->Element;
- Var value = GetReg(playout->Value);
- #if ENABLE_COPYONACCESS_ARRAY
- JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(value);
- #endif
- // The array is create by the built-in on the same script context
- Assert(array->GetScriptContext() == GetScriptContext());
- TypeId typeId = array->GetTypeId();
- if (typeId == TypeIds_NativeIntArray)
- {
- JavascriptArray::OP_SetNativeIntElementC(reinterpret_cast<JavascriptNativeIntArray*>(array), index, value, array->GetScriptContext());
- }
- else if (typeId == TypeIds_NativeFloatArray)
- {
- JavascriptArray::OP_SetNativeFloatElementC(reinterpret_cast<JavascriptNativeFloatArray*>(array), index, value, array->GetScriptContext());
- }
- else
- {
- array->SetArrayLiteralItem(index, value);
- }
- }
- template <class T>
- void InterpreterStackFrame::OP_SetArrayItemI_CI4(const unaligned T* playout)
- {
- // Note that this code assumes that we only get here when we see an array literal,
- // so we know that the instance is truly an array, and the index is a uint32.
- // If/when we use this for cases like "a[0] = x", we'll at least have to check
- // whether "a" is really an array.
- JavascriptArray* array = JavascriptArray::FromAnyArray(GetReg(playout->Instance));
- // The array is create by the built-in on the same script context
- Assert(array->GetScriptContext() == GetScriptContext());
- uint32 index = playout->Element;
- Var value = GetReg(playout->Value);
- Assert(VirtualTableInfo<JavascriptArray>::HasVirtualTable(array));
- SparseArraySegment<Var>* lastUsedSeg = (SparseArraySegment<Var>*)array->GetLastUsedSegment();
- if (index >= lastUsedSeg->left)
- {
- uint32 index2 = index - lastUsedSeg->left;
- if (index2 < lastUsedSeg->size)
- {
- // Successful fastpath
- array->DirectSetItemInLastUsedSegmentAt(index2, value);
- return;
- }
- }
- ScriptContext* scriptContext = array->GetScriptContext();
- JavascriptOperators::SetItem(array, array, index, value, scriptContext);
- }
- #if ENABLE_PROFILE_INFO
- Var InterpreterStackFrame::OP_ProfiledLdThis(Var thisVar, int moduleID, ScriptContext *scriptContext)
- {
- FunctionBody * functionBody = this->m_functionBody;
- DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
- TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
- if (JavascriptOperators::IsThisSelf(typeId))
- {
- Assert(typeId != TypeIds_GlobalObject || ((Js::GlobalObject*)thisVar)->ToThis() == thisVar);
- Assert(typeId != TypeIds_ModuleRoot || JavascriptOperators::GetThisFromModuleRoot(thisVar) == thisVar);
- // Record the fact that we saw a trivial LdThis.
- dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Simple);
- return thisVar;
- }
- thisVar = JavascriptOperators::OP_GetThis(thisVar, moduleID, scriptContext);
- // Record the fact that we saw a LdThis that had to map its source to something else, or at least
- // forced us to call a helper, e.g., a FastDOM object with an unrecognized type ID.
- dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Mapped);
- return thisVar;
- }
- Var InterpreterStackFrame::OP_ProfiledStrictLdThis(Var thisVar, ScriptContext* scriptContext)
- {
- FunctionBody * functionBody = this->m_functionBody;
- DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
- TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
- if (typeId == TypeIds_ActivationObject)
- {
- thisVar = scriptContext->GetLibrary()->GetUndefined();
- dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Mapped);
- return thisVar;
- }
- dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Simple);
- return thisVar;
- }
- #endif
- void InterpreterStackFrame::OP_InitCachedFuncs(const unaligned OpLayoutAuxNoReg * playout)
- {
- const FuncInfoArray *info = Js::ByteCodeReader::ReadAuxArray<FuncInfoEntry>(playout->Offset, this->GetFunctionBody());
- JavascriptOperators::OP_InitCachedFuncs(this->localClosure, GetLocalFrameDisplay(), info, GetScriptContext());
- }
- Var InterpreterStackFrame::OP_GetCachedFunc(Var instance, int32 index)
- {
- ActivationObjectEx *obj = (ActivationObjectEx*)ActivationObjectEx::FromVar(instance);
- FuncCacheEntry *entry = obj->GetFuncCacheEntry((uint)index);
- return entry->func;
- }
- void InterpreterStackFrame::OP_CommitScope()
- {
- const Js::PropertyIdArray *propIds = this->m_functionBody->GetFormalsPropIdArray();
- this->OP_CommitScopeHelper(propIds);
- }
- void InterpreterStackFrame::OP_CommitScopeHelper(const PropertyIdArray *propIds)
- {
- ActivationObjectEx *obj = (ActivationObjectEx*)ActivationObjectEx::FromVar(this->localClosure);
- ScriptFunction *func = obj->GetParentFunc();
- Assert(obj->GetParentFunc() == func);
- if (func->GetCachedScope() == obj)
- {
- PropertyId firstVarSlot = ActivationObjectEx::GetFirstVarSlot(propIds);
- Var undef = scriptContext->GetLibrary()->GetUndefined();
- for (uint i = firstVarSlot; i < propIds->count; i++)
- {
- obj->SetSlot(SetSlotArguments(propIds->elements[i], i, undef));
- }
- obj->SetCommit(true);
- }
- }
- Var InterpreterStackFrame::OP_NewScObjectSimple()
- {
- Var object = scriptContext->GetLibrary()->CreateObject(true);
- JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(object));
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
- {
- object = JavascriptProxy::AutoProxyWrapper(object);
- }
- #endif
- return object;
- }
- void InterpreterStackFrame::OP_NewScObjectLiteral(const unaligned OpLayoutAuxiliary * playout )
- {
- const Js::PropertyIdArray *propIds = Js::ByteCodeReader::ReadPropertyIdArray(playout->Offset, this->GetFunctionBody());
- Var newObj = JavascriptOperators::NewScObjectLiteral(GetScriptContext(), propIds,
- this->GetFunctionBody()->GetObjectLiteralTypeRef(playout->C1));
- SetReg(playout->R0, newObj);
- }
- void InterpreterStackFrame::OP_NewScObjectLiteral_LS(const unaligned OpLayoutAuxiliary * playout, RegSlot& target)
- {
- const Js::PropertyIdArray *propIds = Js::ByteCodeReader::ReadPropertyIdArray(playout->Offset, this->GetFunctionBody());
- target = playout->R0;
- Var newObj = JavascriptOperators::NewScObjectLiteral(GetScriptContext(), propIds,
- this->GetFunctionBody()->GetObjectLiteralTypeRef(playout->C1));
- SetReg(playout->R0, newObj);
- target = Js::Constants::NoRegister;
- }
- void InterpreterStackFrame::OP_LdPropIds(const unaligned OpLayoutAuxiliary * playout)
- {
- const Js::PropertyIdArray *propIds = Js::ByteCodeReader::ReadPropertyIdArray(playout->Offset, this->GetFunctionBody());
- SetNonVarReg(playout->R0, (Var)propIds);
- }
- bool InterpreterStackFrame::IsCurrentLoopNativeAddr(void * codeAddr) const
- {
- if (this->GetCurrentLoopNum() == LoopHeader::NoLoop)
- {
- return false;
- }
- // TODO: Do more verification?
- return true;
- }
- #if ENABLE_PROFILE_INFO
- void InterpreterStackFrame::OP_RecordImplicitCall(uint loopNumber)
- {
- Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()));
- Assert(loopNumber < this->m_functionBody->GetLoopCount());
- FunctionBody* functionBody = this->m_functionBody;
- DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
- ThreadContext * threadContext = scriptContext->GetThreadContext();
- dynamicProfileInfo->RecordLoopImplicitCallFlags(functionBody, loopNumber, threadContext->GetImplicitCallFlags());
- }
- template <LayoutSize layoutSize, bool profiled>
- const byte * InterpreterStackFrame::OP_ProfiledLoopStart(const byte * ip)
- {
- const uint32 C1 = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
- if(!profiled && !isAutoProfiling)
- {
- return ip;
- }
- ThreadContext *const threadContext = GetScriptContext()->GetThreadContext();
- threadContext->IncrementLoopDepth();
- // Save the implicit call flags. The interpreter may switch to profiling mode during LoopBodyStart, so always do this.
- Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()));
- this->savedLoopImplicitCallFlags[C1] = threadContext->GetImplicitCallFlags();
- threadContext->SetImplicitCallFlags(ImplicitCall_None);
- this->currentLoopCounter = 0;
- if(!profiled)
- {
- return ip;
- }
- LayoutSize localLayoutSize;
- OpCode peekOp = m_reader.PeekOp(ip, localLayoutSize);
- Assert(peekOp != OpCode::LoopBodyStart);
- if (peekOp == OpCode::ProfiledLoopBodyStart)
- {
- Assert(localLayoutSize == layoutSize);
- ip += Js::OpCodeUtil::EncodedSize(peekOp, layoutSize);
- // We are doing JIT loop body. Process the first ProfiledLoopBodyStart to avoid recording
- // the implicit call before the first iteration
- uint32 C2 = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
- Assert(C1 == C2);
- (this->*opProfiledLoopBodyStart)(C1, layoutSize, true /* isFirstIteration */);
- return m_reader.GetIP();
- }
- return ip;
- }
- template <LayoutSize layoutSize, bool profiled>
- const byte * InterpreterStackFrame::OP_ProfiledLoopEnd(const byte * ip)
- {
- uint32 loopNumber = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
- if(!profiled && !isAutoProfiling)
- {
- return ip;
- }
- this->CheckIfLoopIsHot(this->currentLoopCounter);
- Js::FunctionBody *fn = this->function->GetFunctionBody();
- if (fn->HasDynamicProfileInfo())
- {
- fn->GetAnyDynamicProfileInfo()->SetLoopInterpreted(loopNumber);
- // If the counter is 0, there is a high chance that some config disabled tracking that information. (ie: -off:jitloopbody)
- // Assume it is valid for memop in this case.
- if (this->currentLoopCounter >= (uint)CONFIG_FLAG(MinMemOpCount) ||
- (this->currentLoopCounter == 0 && !this->m_functionBody->DoJITLoopBody())
- )
- {
- // This flag becomes relevant only if the loop has been interpreted
- fn->GetAnyDynamicProfileInfo()->SetMemOpMinReached(loopNumber);
- }
- }
- this->currentLoopCounter = 0;
- if (profiled)
- {
- Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()));
- OP_RecordImplicitCall(loopNumber);
- if(switchProfileModeOnLoopEndNumber == loopNumber)
- {
- // Stop profiling since the jitted loop body would be exiting the loop
- Assert(!switchProfileMode);
- switchProfileMode = true;
- switchProfileModeOnLoopEndNumber = 0u - 1;
- }
- }
- // Restore the implicit call flags state and add with flags in the loop as well
- ThreadContext *const threadContext = GetScriptContext()->GetThreadContext();
- threadContext->AddImplicitCallFlags(this->savedLoopImplicitCallFlags[loopNumber]);
- threadContext->DecrementLoopDepth();
- return ip;
- }
- template <LayoutSize layoutSize, bool profiled>
- const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
- {
- uint32 C1 = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
- if(profiled || isAutoProfiling)
- {
- this->currentLoopCounter++;
- }
- if (profiled)
- {
- OP_RecordImplicitCall(C1);
- }
- (this->*(profiled ? opProfiledLoopBodyStart : opLoopBodyStart))(C1, layoutSize, false /* isFirstIteration */);
- return m_reader.GetIP();
- }
- template<bool InterruptProbe, bool JITLoopBody>
- void InterpreterStackFrame::ProfiledLoopBodyStart(uint32 loopNumber, LayoutSize layoutSize, bool isFirstIteration)
- {
- Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()));
- if (InterruptProbe)
- {
- this->DoInterruptProbe();
- }
- #if ENABLE_TTD
- if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
- {
- this->scriptContext->GetThreadContext()->TTDLog->UpdateLoopCountInfo();
- }
- #endif
- if (!JITLoopBody || this->IsInCatchOrFinallyBlock())
- {
- // For functions having try-catch-finally, jit loop bodies for loops that are contained only in a try block,
- // not even indirect containment in a Catch or Finally.
- return;
- }
- LoopHeader const * loopHeader = DoLoopBodyStart(loopNumber, layoutSize, false, isFirstIteration);
- Assert(loopHeader == nullptr || this->m_functionBody->GetLoopNumber(loopHeader) == loopNumber);
- if (loopHeader != nullptr)
- {
- // We executed jitted loop body, no implicit call information available for this loop
- uint currentOffset = m_reader.GetCurrentOffset();
- if (!loopHeader->Contains(currentOffset) || (m_reader.PeekOp() == OpCode::ProfiledLoopEnd))
- {
- // Restore the outer loop's implicit call flags
- scriptContext->GetThreadContext()->SetImplicitCallFlags(this->savedLoopImplicitCallFlags[loopNumber]);
- }
- else
- {
- // We bailout from the loop, just continue collect implicit call flags for this loop
- }
- }
- }
- #else
- template <LayoutSize layoutSize, bool profiled>
- const byte * InterpreterStackFrame::OP_ProfiledLoopStart(const byte * ip)
- {
- Assert(!profiled);
- return ip;
- }
- template <LayoutSize layoutSize, bool profiled>
- const byte * InterpreterStackFrame::OP_ProfiledLoopEnd(const byte * ip)
- {
- Assert(!profiled);
- return ip;
- }
- template <LayoutSize layoutSize, bool profiled>
- const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
- {
- uint32 C1 = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
- Assert(!profiled);
- (this->*opLoopBodyStart)(C1, layoutSize, false /* isFirstIteration */);
- return m_reader.GetIP();
- }
- #endif
- template<bool InterruptProbe, bool JITLoopBody>
- void InterpreterStackFrame::LoopBodyStart(uint32 loopNumber, LayoutSize layoutSize, bool isFirstIteration)
- {
- if (InterruptProbe)
- {
- this->DoInterruptProbe();
- }
- #if ENABLE_TTD
- if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
- {
- this->scriptContext->GetThreadContext()->TTDLog->UpdateLoopCountInfo();
- }
- #endif
- if (!JITLoopBody || this->IsInCatchOrFinallyBlock())
- {
- // For functions having try-catch-finally, jit loop bodies for loops that are contained only in a try block,
- // not even indirect containment in a Catch or Finally.
- return;
- }
- DoLoopBodyStart(loopNumber, layoutSize, true, isFirstIteration);
- }
- LoopHeader const * InterpreterStackFrame::DoLoopBodyStart(uint32 loopNumber, LayoutSize layoutSize, const bool doProfileLoopCheck, const bool isFirstIteration)
- {
- #if ENABLE_PROFILE_INFO
- class AutoRestoreLoopNumbers
- {
- private:
- InterpreterStackFrame *const interpreterStackFrame;
- uint32 loopNumber;
- bool doProfileLoopCheck;
- public:
- AutoRestoreLoopNumbers(InterpreterStackFrame *const interpreterStackFrame, uint32 loopNumber, bool doProfileLoopCheck)
- : interpreterStackFrame(interpreterStackFrame), loopNumber(loopNumber), doProfileLoopCheck(doProfileLoopCheck)
- {
- Assert(interpreterStackFrame->currentLoopNum == LoopHeader::NoLoop);
- interpreterStackFrame->currentLoopNum = loopNumber;
- interpreterStackFrame->m_functionBody->SetRecentlyBailedOutOfJittedLoopBody(false);
- }
- ~AutoRestoreLoopNumbers()
- {
- interpreterStackFrame->currentLoopNum = LoopHeader::NoLoop;
- interpreterStackFrame->currentLoopCounter = 0;
- Js::FunctionBody* fn = interpreterStackFrame->m_functionBody;
- if (fn->RecentlyBailedOutOfJittedLoopBody())
- {
- if (doProfileLoopCheck && interpreterStackFrame->isAutoProfiling)
- {
- // Start profiling the loop after a bailout. Some bailouts require subsequent profile data collection such
- // that the rejitted loop body would not bail out again for the same reason.
- Assert(!interpreterStackFrame->switchProfileMode);
- interpreterStackFrame->switchProfileMode = true;
- Assert(interpreterStackFrame->switchProfileModeOnLoopEndNumber == 0u - 1);
- interpreterStackFrame->switchProfileModeOnLoopEndNumber = loopNumber;
- }
- }
- else
- {
- if (interpreterStackFrame->switchProfileModeOnLoopEndNumber == loopNumber)
- {
- // Stop profiling since the jitted loop body would be exiting the loop
- Assert(!interpreterStackFrame->switchProfileMode);
- interpreterStackFrame->switchProfileMode = true;
- interpreterStackFrame->switchProfileModeOnLoopEndNumber = 0u - 1;
- }
- interpreterStackFrame->scriptContext->GetThreadContext()->DecrementLoopDepth();
- }
- }
- };
- #endif
- Js::FunctionBody* fn = this->m_functionBody;
- Assert(loopNumber < fn->GetLoopCount());
- Assert(!this->IsInCatchOrFinallyBlock());
- Js::LoopHeader *loopHeader = fn->GetLoopHeader(loopNumber);
- loopHeader->isInTry = (this->m_flags & Js::InterpreterStackFrameFlags_WithinTryBlock);
- Js::LoopEntryPointInfo * entryPointInfo = loopHeader->GetCurrentEntryPointInfo();
- if (fn->ForceJITLoopBody() && loopHeader->interpretCount == 0 &&
- (entryPointInfo != NULL && entryPointInfo->IsNotScheduled()))
- {
- #if ENABLE_PROFILE_INFO
- if (Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()))
- {
- scriptContext->GetThreadContext()->AddImplicitCallFlags(this->savedLoopImplicitCallFlags[loopNumber]);
- }
- #endif
- #if ENABLE_NATIVE_CODEGEN
- GenerateLoopBody(scriptContext->GetNativeCodeGenerator(), fn, loopHeader, entryPointInfo, fn->GetLocalsCount(), this->m_localSlots);
- #endif
- }
- #if ENABLE_NATIVE_CODEGEN
- // If we have JITted the loop, call the JITted code
- if (entryPointInfo != NULL && entryPointInfo->IsCodeGenDone())
- {
- #if DBG_DUMP
- if (PHASE_TRACE1(Js::JITLoopBodyPhase) && CONFIG_FLAG(Verbose))
- {
- fn->DumpFunctionId(true);
- Output::Print(_u(": %-20s LoopBody Execute Loop: %2d\n"), fn->GetDisplayName(), loopNumber);
- Output::Flush();
- }
- loopHeader->nativeCount++;
- #endif
- #ifdef BGJIT_STATS
- entryPointInfo->MarkAsUsed();
- #endif
- entryPointInfo->EnsureIsReadyToCall();
- entryPointInfo->nativeEntryPointProcessed = true;
- RegSlot envReg = this->m_functionBody->GetEnvRegister();
- if (envReg != Constants::NoRegister)
- {
- this->SetNonVarReg(envReg, this->LdEnv());
- }
- RegSlot localClosureReg = this->m_functionBody->GetLocalClosureRegister();
- RegSlot localFrameDisplayReg = this->m_functionBody->GetLocalFrameDisplayRegister();
- RegSlot paramClosureReg = this->m_functionBody->GetParamClosureRegister();
- if (entryPointInfo->HasJittedStackClosure())
- {
- // The jitted code is expecting the closure registers to point to known stack locations where
- // the closures can be found and possibly boxed.
- // In a jitted loop body, those locations are the local closure fields on the interpreter instance.
- if (localClosureReg != Constants::NoRegister)
- {
- this->SetNonVarReg(localClosureReg, &this->localClosure);
- }
- if (localFrameDisplayReg != Constants::NoRegister)
- {
- this->SetNonVarReg(localFrameDisplayReg, &this->localFrameDisplay);
- }
- if (paramClosureReg != Constants::NoRegister)
- {
- this->SetNonVarReg(paramClosureReg, &this->paramClosure);
- }
- }
- else
- {
- // In non-stack-closure jitted code, the closure registers are expected to hold the addresses
- // of the actual structures.
- if (localClosureReg != Constants::NoRegister)
- {
- this->SetNonVarReg(localClosureReg, this->localClosure);
- }
- if (localFrameDisplayReg != Constants::NoRegister)
- {
- this->SetNonVarReg(localFrameDisplayReg, this->localFrameDisplay);
- }
- if (paramClosureReg != Constants::NoRegister)
- {
- this->SetNonVarReg(paramClosureReg, this->paramClosure);
- }
- }
- uint32 innerScopeCount = this->m_functionBody->GetInnerScopeCount();
- for (uint32 i = 0; i < innerScopeCount; i++)
- {
- // As with the function-level scope, transfer the inner scopes from the interpreter's side storage
- // to their dedicated register slots.
- SetNonVarReg(this->m_functionBody->GetFirstInnerScopeRegister() + i, InnerScopeFromIndex(i));
- }
- uint newOffset = 0;
- if (fn->GetIsAsmJsFunction())
- {
- AutoRestoreLoopNumbers autoRestore(this, loopNumber, doProfileLoopCheck);
- newOffset = this->CallAsmJsLoopBody(entryPointInfo->jsMethod);
- }
- else
- {
- AutoRestoreLoopNumbers autoRestore(this, loopNumber, doProfileLoopCheck);
- newOffset = this->CallLoopBody(entryPointInfo->jsMethod);
- }
- if (envReg != Constants::NoRegister)
- {
- SetNonVarReg(envReg, nullptr);
- }
- if (localClosureReg != Constants::NoRegister)
- {
- SetNonVarReg(localClosureReg, nullptr);
- }
- if (localFrameDisplayReg != Constants::NoRegister)
- {
- SetNonVarReg(localFrameDisplayReg, nullptr);
- }
- if (paramClosureReg != Constants::NoRegister)
- {
- SetNonVarReg(paramClosureReg, nullptr);
- }
- for (uint32 i = 0; i < innerScopeCount; i++)
- {
- // Get the (possibly updated) scopes from their registers and put them back in side storage.
- // (Getting the updated values may not be necessary, actually, but it can't hurt.)
- // Then null out the registers.
- RegSlot reg = this->m_functionBody->GetFirstInnerScopeRegister() + i;
- SetInnerScopeFromIndex(i, GetNonVarReg(reg));
- SetNonVarReg(reg, nullptr);
- }
- Assert(Js::OpCodeUtil::GetOpCodeLayout(OpCode::ProfiledLoopBodyStart) == Js::OpLayoutType::Unsigned1);
- Assert(Js::OpCodeUtil::GetOpCodeLayout(OpCode::LoopBodyStart) == Js::OpLayoutType::Unsigned1);
- Assert(Js::OpCodeUtil::EncodedSize(Js::OpCode::LoopBodyStart, layoutSize) == Js::OpCodeUtil::EncodedSize(Js::OpCode::ProfiledLoopBodyStart, layoutSize));
- uint byteCodeSize = Js::OpCodeUtil::EncodedSize(Js::OpCode::LoopBodyStart, layoutSize);
- if (layoutSize == SmallLayout)
- {
- byteCodeSize += sizeof(OpLayoutUnsigned1_Small);
- }
- else if (layoutSize == MediumLayout)
- {
- byteCodeSize += sizeof(OpLayoutUnsigned1_Medium);
- }
- else
- {
- byteCodeSize += sizeof(OpLayoutUnsigned1_Large);
- }
- if (newOffset == loopHeader->startOffset || newOffset == m_reader.GetCurrentOffset() - byteCodeSize)
- {
- // If we bail out back the start of the loop, or start of this LoopBodyStart just skip and interpret the loop
- // instead of trying to start the loop body again
- // Increment the interpret count of the loop
- loopHeader->interpretCount++;
- }
- else
- {
- // we do not support this in asmjs, need to add support in IrBuilderAsmjs if we need this support for asmjs
- if (!entryPointInfo->GetIsAsmJSFunction())
- {
- this->CheckIfLoopIsHot(loopHeader->profiledLoopCounter);
- }
- if (newOffset >= loopHeader->endOffset)
- {
- // Reset the totalJittedLoopIterations for the next invocation of this loop entry point
- entryPointInfo->totalJittedLoopIterations =
- static_cast<uint8>(
- min(
- static_cast<uint>(static_cast<uint8>(CONFIG_FLAG(MinBailOutsBeforeRejit))) *
- (Js::LoopEntryPointInfo::GetDecrLoopCountPerBailout() - 1),
- entryPointInfo->totalJittedLoopIterations));
- entryPointInfo->jittedLoopIterationsSinceLastBailout = 0;
- }
- m_reader.SetCurrentOffset(newOffset);
- }
- return loopHeader;
- }
- #endif
- // Increment the interpret count of the loop
- loopHeader->interpretCount += !isFirstIteration;
- const uint loopInterpretCount = GetFunctionBody()->GetLoopInterpretCount(loopHeader);
- if (loopHeader->interpretCount > loopInterpretCount)
- {
- if (this->scriptContext->GetConfig()->IsNoNative())
- {
- return nullptr;
- }
- if (!fn->DoJITLoopBody())
- {
- return nullptr;
- }
- #if ENABLE_NATIVE_CODEGEN
- // If the job is not scheduled then we need to schedule it now.
- // It is possible a job was scheduled earlier and we find ourselves looking at the same entry point
- // again. For example, if the function with the loop was JITed and bailed out then as we finish
- // the call in the interpreter we might encounter a loop for which we had scheduled a JIT job before
- // the function was initially scheduled. In such cases, that old JIT job will complete. If it completes
- // successfully then we can go ahead and use it. If it fails then it will eventually revert to the
- // NotScheduled state. Since transitions from NotScheduled can only occur on the main thread,
- // by checking the state we are safe from racing with the JIT thread when looking at the other fields
- // of the entry point.
- if (entryPointInfo != NULL && entryPointInfo->IsNotScheduled())
- {
- GenerateLoopBody(scriptContext->GetNativeCodeGenerator(), fn, loopHeader, entryPointInfo, fn->GetLocalsCount(), this->m_localSlots);
- }
- #endif
- }
- #if ENABLE_PROFILE_INFO
- else if(
- doProfileLoopCheck &&
- isAutoProfiling &&
- loopHeader->interpretCount > fn->GetLoopProfileThreshold(loopInterpretCount))
- {
- // Start profiling the loop so that the jitted loop body will have some profile data to use
- Assert(!switchProfileMode);
- switchProfileMode = true;
- Assert(switchProfileModeOnLoopEndNumber == 0u - 1);
- switchProfileModeOnLoopEndNumber = loopNumber;
- }
- #endif
- return nullptr;
- }
- void
- InterpreterStackFrame::CheckIfLoopIsHot(uint profiledLoopCounter)
- {
- Js::FunctionBody *fn = this->function->GetFunctionBody();
- if (!fn->GetHasHotLoop() && profiledLoopCounter > (uint)CONFIG_FLAG(JitLoopBodyHotLoopThreshold))
- {
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- if(PHASE_TRACE(Js::JITLoopBodyPhase, fn))
- {
- char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
- Output::Print(
- _u("Speculate Jit set for this function with loopbody: function: %s (%s)\n"),
- fn->GetDisplayName(),
- fn->GetDebugNumberSet(debugStringBuffer));
- Output::Flush();
- }
- #endif
- fn->SetHasHotLoop();
- }
- }
- bool InterpreterStackFrame::CheckAndResetImplicitCall(DisableImplicitFlags prevDisableImplicitFlags, ImplicitCallFlags savedImplicitCallFlags)
- {
- ImplicitCallFlags curImplicitCallFlags = this->scriptContext->GetThreadContext()->GetImplicitCallFlags();
- if (curImplicitCallFlags > ImplicitCall_None)
- {
- //error implicit bit is set , reparse without asmjs
- this->scriptContext->GetThreadContext()->SetDisableImplicitFlags(prevDisableImplicitFlags);
- this->scriptContext->GetThreadContext()->SetImplicitCallFlags(savedImplicitCallFlags);
- return true;
- }
- return false;
- }
- uint
- InterpreterStackFrame::CallLoopBody(JavascriptMethod address)
- {
- #ifdef _M_IX86
- void *savedEsp = NULL;
- __asm
- {
- // Save ESP
- mov savedEsp, esp
- // 8-byte align frame to improve floating point perf of our JIT'd code.
- and esp, -8
- // Add an extra 4-bytes to the stack since we'll be pushing 3 arguments
- push eax
- }
- #endif
- #if defined(_M_ARM32_OR_ARM64)
- // For ARM we need to make sure that pipeline is synchronized with memory/cache for newly jitted code.
- // Note: this does not seem to affect perf, but if it was, we could add a boolean isCalled to EntryPointInfo
- // and do ISB only for 1st time this entry point is called (potential working set regression though).
- _InstructionSynchronizationBarrier();
- #endif
- uint newOffset = ::Math::PointerCastToIntegral<uint>(
- CALL_ENTRYPOINT(address, function, CallInfo(CallFlags_InternalFrame, 1), this));
- #ifdef _M_IX86
- _asm
- {
- // Restore ESP
- mov esp, savedEsp
- }
- #endif
- return newOffset;
- }
- uint
- InterpreterStackFrame::CallAsmJsLoopBody(JavascriptMethod address)
- {
- #ifdef _M_IX86
- void *savedEsp = NULL;
- __asm
- {
- // Save ESP
- mov savedEsp, esp
- // Add an extra 4-bytes to the stack since we'll be pushing 3 arguments
- push eax
- }
- #endif
- #if defined(_M_ARM32_OR_ARM64)
- // For ARM we need to make sure that pipeline is synchronized with memory/cache for newly jitted code.
- // Note: this does not seem to affect perf, but if it was, we could add a boolean isCalled to EntryPointInfo
- // and do ISB only for 1st time this entry point is called (potential working set regression though).
- _InstructionSynchronizationBarrier();
- #endif
- uint newOffset = ::Math::PointerCastToIntegral<uint>(
- CALL_ENTRYPOINT(address, function, CallInfo(CallFlags_InternalFrame, 1), this));
- #ifdef _M_IX86
- _asm
- {
- // Restore ESP
- mov esp, savedEsp
- }
- #endif
- return newOffset;
- }
- template <class T>
- void InterpreterStackFrame::OP_NewScObjectNoCtorFull(const unaligned T* playout)
- {
- Var function = GetReg(playout->R1);
- Var newObj = JavascriptOperators::NewScObjectNoCtorFull(function, GetScriptContext());
- SetReg(playout->R0, newObj);
- }
- ///----------------------------------------------------------------------------
- ///
- /// InterpreterStackFrame::OP_NewScObject
- ///
- /// OP_NewScObject() allocates a new DynamicObject and initializes it with an
- /// optional "constructor" function.
- ///
- /// NOTE: The return register must be carefully chosen to ensure proper
- /// behavior:
- /// 1. OpCode::NewInstance should never specify "R0" as the register to
- /// store the new instance, because it will get whacked from the
- /// "constructor" function's return value:
- ///
- /// var a1 = Date(); <-- a1 = string returned from Date() function
- /// var a2 = new Date(); <-- a2 = instance return from NewInstance.
- /// Date()'s return value is thrown away.
- ///
- /// 2. If an exception is thrown during construction, the destination
- /// variable / field should __not__ be modified. Therefore, the destination
- /// register should always be a temporary and never a valid local variable.
- /// After successfully returning from the constructor function, the new
- /// instance is valid and may be stored in its final destination variable /
- /// field.
- ///
- /// OPCODE NewObject:
- /// T1 = new DynamicObject(Function.Prototype)
- /// OutArg[0] = T1
- /// Call(Function, ArgCount)
- /// Local[Return] = T1
- ///
- /// - R0: Destination "local" register
- /// - R1: Optional constructor JavascriptFunction instance or 'null'
- ///
- ///----------------------------------------------------------------------------
- template <class T, bool Profiled, bool ICIndex>
- void InterpreterStackFrame::OP_NewScObject_Impl(const unaligned T* playout, InlineCacheIndex inlineCacheIndex, const Js::AuxArray<uint32> *spreadIndices)
- {
- if (ICIndex)
- {
- Assert(inlineCacheIndex != Js::Constants::NoInlineCacheIndex);
- }
- Var newVarInstance =
- #if ENABLE_PROFILE_INFO
- Profiled ?
- ProfiledNewScObject_Helper(
- GetReg(playout->Function),
- playout->ArgCount,
- static_cast<const unaligned OpLayoutDynamicProfile<T> *>(playout)->profileId,
- inlineCacheIndex,
- spreadIndices) :
- #endif
- NewScObject_Helper(GetReg(playout->Function), playout->ArgCount, spreadIndices);
- SetReg((RegSlot)playout->Return, newVarInstance);
- }
- template <class T, bool Profiled>
- void InterpreterStackFrame::OP_NewScObjArray_Impl(const unaligned T* playout, const Js::AuxArray<uint32> *spreadIndices)
- {
- // Always profile this operation when auto-profiling so that array type changes are tracked
- #if ENABLE_PROFILE_INFO
- if (!Profiled && !isAutoProfiling)
- #else
- Assert(!Profiled);
- #endif
- {
- OP_NewScObject_Impl<T, Profiled, false>(playout, Js::Constants::NoInlineCacheIndex, spreadIndices);
- return;
- }
- #if ENABLE_PROFILE_INFO
- Arguments args(CallInfo(CallFlags_New, playout->ArgCount), m_outParams);
- uint32 spreadSize = 0;
- if (spreadIndices != nullptr)
- {
- spreadSize = JavascriptFunction::GetSpreadSize(args, spreadIndices, scriptContext);
- // Allocate room on the stack for the spread args.
- Arguments outArgs(CallInfo(CallFlags_New, 0), nullptr);
- outArgs.Info.Count = spreadSize;
- const unsigned STACK_ARGS_ALLOCA_THRESHOLD = 8; // Number of stack args we allow before using _alloca
- Var stackArgs[STACK_ARGS_ALLOCA_THRESHOLD];
- size_t outArgsSize = 0;
- if (outArgs.Info.Count > STACK_ARGS_ALLOCA_THRESHOLD)
- {
- PROBE_STACK(scriptContext, outArgs.Info.Count * sizeof(Var) + Js::Constants::MinStackDefault); // args + function call
- outArgsSize = outArgs.Info.Count * sizeof(Var);
- outArgs.Values = (Var*)_alloca(outArgsSize);
- }
- else
- {
- outArgs.Values = stackArgs;
- outArgsSize = STACK_ARGS_ALLOCA_THRESHOLD * sizeof(Var);
- ZeroMemory(outArgs.Values, outArgsSize); // We may not use all of the elements
- }
- JavascriptFunction::SpreadArgs(args, outArgs, spreadIndices, scriptContext);
- SetReg(
- (RegSlot)playout->Return,
- ProfilingHelpers::ProfiledNewScObjArray(
- GetReg(playout->Function),
- outArgs,
- function,
- static_cast<const unaligned OpLayoutDynamicProfile2<T> *>(playout)->profileId,
- static_cast<const unaligned OpLayoutDynamicProfile2<T> *>(playout)->profileId2));
- }
- else
- {
- SetReg(
- (RegSlot)playout->Return,
- ProfilingHelpers::ProfiledNewScObjArray(
- GetReg(playout->Function),
- args,
- function,
- static_cast<const unaligned OpLayoutDynamicProfile2<T> *>(playout)->profileId,
- static_cast<const unaligned OpLayoutDynamicProfile2<T> *>(playout)->profileId2));
- }
- PopOut(playout->ArgCount);
- #endif
- }
- void InterpreterStackFrame::OP_NewScObject_A_Impl(const unaligned OpLayoutAuxiliary * playout, RegSlot *target)
- {
- const Js::VarArrayVarCount * vars = Js::ByteCodeReader::ReadVarArrayVarCount(playout->Offset, this->GetFunctionBody());
- int count = Js::TaggedInt::ToInt32(vars->count);
- // Push the parameters to stack
- for (int i=0;i<count; i++)
- {
- SetOut( (ArgSlot)(i+1), vars->elements[i]);
- }
- Var newVarInstance = NewScObject_Helper(GetReg((RegSlot)playout->C1), (ArgSlot)count+1);
- SetReg((RegSlot)playout->R0, newVarInstance);
- }
- Var InterpreterStackFrame::NewScObject_Helper(Var target, ArgSlot ArgCount, const Js::AuxArray<uint32> *spreadIndices)
- {
- Arguments args(CallInfo(CallFlags_New, ArgCount), m_outParams);
- Var newVarInstance = JavascriptOperators::NewScObject(target, args, GetScriptContext(), spreadIndices);
- PopOut(ArgCount);
- JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(newVarInstance));
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
- {
- newVarInstance = JavascriptProxy::AutoProxyWrapper(newVarInstance);
- // this might come from a different scriptcontext.
- newVarInstance = CrossSite::MarshalVar(GetScriptContext(), newVarInstance);
- }
- #endif
- #ifdef ENABLE_BASIC_TELEMETRY
- {
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().NewScriptObject( target, args, newVarInstance );
- }
- #endif
- return newVarInstance;
- }
- #if ENABLE_PROFILE_INFO
- Var InterpreterStackFrame::ProfiledNewScObject_Helper(Var target, ArgSlot ArgCount, ProfileId profileId, InlineCacheIndex inlineCacheIndex, const Js::AuxArray<uint32> *spreadIndices)
- {
- Arguments args(CallInfo(CallFlags_New, ArgCount), m_outParams);
- Var newVarInstance =
- ProfilingHelpers::ProfiledNewScObject(
- target,
- args,
- GetFunctionBody(),
- profileId,
- inlineCacheIndex,
- spreadIndices);
- PopOut(ArgCount);
- JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(newVarInstance));
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
- {
- newVarInstance = JavascriptProxy::AutoProxyWrapper(newVarInstance);
- // this might come from a different scriptcontext.
- newVarInstance = CrossSite::MarshalVar(GetScriptContext(), newVarInstance);
- }
- #endif
- #ifdef TELEMETRY_PROFILED
- {
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().NewScriptObject( target, args, newVarInstance );
- }
- #endif
- return newVarInstance;
- }
- #endif
- template <typename T>
- void InterpreterStackFrame::OP_LdElementUndefined(const unaligned OpLayoutT_ElementU<T>* playout)
- {
- if (this->m_functionBody->IsEval())
- {
- JavascriptOperators::OP_LoadUndefinedToElementDynamic(GetReg(playout->Instance),
- this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
- }
- else
- {
- JavascriptOperators::OP_LoadUndefinedToElement(GetReg(playout->Instance),
- this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex));
- }
- }
- template <typename T>
- void InterpreterStackFrame::OP_LdLocalElementUndefined(const unaligned OpLayoutT_ElementRootU<T>* playout)
- {
- if (this->m_functionBody->IsEval())
- {
- JavascriptOperators::OP_LoadUndefinedToElementDynamic(this->localClosure,
- this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
- }
- else
- {
- JavascriptOperators::OP_LoadUndefinedToElement(this->localClosure,
- this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex));
- }
- }
- template <typename T>
- void InterpreterStackFrame::OP_LdElementUndefinedScoped(const unaligned OpLayoutT_ElementScopedU<T>* playout)
- {
- // Implicit root object as default instance
- JavascriptOperators::OP_LoadUndefinedToElementScoped(GetEnvForEvalCode(),
- this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetReg(Js::FunctionBody::RootObjectRegSlot), GetScriptContext());
- }
- void InterpreterStackFrame::OP_ChkUndecl(Var aValue)
- {
- if (this->scriptContext->IsUndeclBlockVar(aValue))
- {
- JavascriptError::ThrowReferenceError(scriptContext, JSERR_UseBeforeDeclaration);
- }
- }
- void InterpreterStackFrame::OP_ChkNewCallFlag()
- {
- if (!(this->m_callFlags & CallFlags_New))
- {
- JavascriptError::ThrowTypeError(scriptContext, JSERR_ClassConstructorCannotBeCalledWithoutNew);
- }
- }
- void InterpreterStackFrame::OP_EnsureNoRootProperty(uint propertyIdIndex)
- {
- Var instance = this->GetRootObject();
- JavascriptOperators::OP_EnsureNoRootProperty(instance, this->m_functionBody->GetReferencedPropertyId(propertyIdIndex));
- }
- void InterpreterStackFrame::OP_EnsureNoRootRedeclProperty(uint propertyIdIndex)
- {
- Var instance = this->GetRootObject();
- JavascriptOperators::OP_EnsureNoRootRedeclProperty(instance, this->m_functionBody->GetReferencedPropertyId(propertyIdIndex));
- }
- void InterpreterStackFrame::OP_ScopedEnsureNoRedeclProperty(Var aValue, uint propertyIdIndex, Var aValue2)
- {
- Js::PropertyId propertyId = this->m_functionBody->GetReferencedPropertyId(propertyIdIndex);
- JavascriptOperators::OP_ScopedEnsureNoRedeclProperty((FrameDisplay*)aValue, propertyId, aValue2);
- }
- Var InterpreterStackFrame::OP_InitUndecl()
- {
- return this->scriptContext->GetLibrary()->GetUndeclBlockVar();
- }
- void InterpreterStackFrame::OP_InitUndeclSlot(Var aValue, int32 slot)
- {
- this->OP_StSlot(aValue, slot, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
- }
- void InterpreterStackFrame::OP_TryCatch(const unaligned OpLayoutBr* playout)
- {
- Js::JavascriptExceptionObject* exception = NULL;
- try
- {
- this->nestedTryDepth++;
- // mark the stackFrame as 'in try block'
- this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
- Js::JavascriptExceptionOperators::AutoCatchHandlerExists autoCatchHandlerExists(scriptContext);
- if (this->IsInDebugMode())
- {
- #if ENABLE_TTD
- if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
- {
- this->ProcessWithDebugging_PreviousStmtTracking();
- }
- else
- {
- this->ProcessWithDebugging();
- }
- #else
- this->ProcessWithDebugging();
- #endif
- this->TrySetRetOffset();
- }
- else
- {
- this->Process();
- this->TrySetRetOffset();
- }
- }
- catch (const Js::JavascriptException& err)
- {
- // We are using C++ exception handling which does not unwind the stack in the catch block.
- // For stack overflow and OOM exceptions, we cannot run user code here because the stack is not unwind.
- exception = err.GetAndClear();
- }
- if (--this->nestedTryDepth == -1)
- {
- // unmark the stackFrame as 'in try block'
- this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
- }
- // Now that the stack is unwound, let's run the catch block.
- if (exception)
- {
- if (exception->IsGeneratorReturnException())
- {
- // Generator return scenario, so no need to go into the catch block and we must rethrow to propagate the exception to down level
- JavascriptExceptionOperators::DoThrow(exception, scriptContext);
- }
- exception = exception->CloneIfStaticExceptionObject(scriptContext);
- // We've got a JS exception. Grab the exception object and assign it to the
- // catch object's location, then call the handler (i.e., we consume the Catch op here).
- Var catchObject = exception->GetThrownObject(scriptContext);
- m_reader.SetCurrentRelativeOffset((const byte *)(playout + 1), playout->RelativeJumpOffset);
- LayoutSize layoutSize;
- OpCode catchOp = m_reader.ReadOp(layoutSize);
- #ifdef BYTECODE_BRANCH_ISLAND
- if (catchOp == Js::OpCode::BrLong)
- {
- Assert(layoutSize == SmallLayout);
- auto playoutBrLong = m_reader.BrLong();
- m_reader.SetCurrentRelativeOffset((const byte *)(playoutBrLong + 1), playoutBrLong->RelativeJumpOffset);
- catchOp = m_reader.ReadOp(layoutSize);
- }
- #endif
- AssertMsg(catchOp == OpCode::Catch, "Catch op not found at catch offset");
- RegSlot reg = layoutSize == SmallLayout ? m_reader.Reg1_Small()->R0 :
- layoutSize == MediumLayout ? m_reader.Reg1_Medium()->R0 : m_reader.Reg1_Large()->R0;
- SetReg(reg, catchObject);
- ResetOut();
- this->nestedCatchDepth++;
- // mark the stackFrame as 'in catch block'
- this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
- this->ProcessCatch();
- if (--this->nestedCatchDepth == -1)
- {
- // unmark the stackFrame as 'in catch block'
- this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
- }
- }
- }
- void InterpreterStackFrame::ProcessCatch()
- {
- #if ENABLE_TTD
- //Clear any previous Exception Info
- if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
- {
- this->scriptContext->GetThreadContext()->TTDLog->ClearExceptionFrames();
- }
- #endif
- if (this->IsInDebugMode())
- {
- this->DebugProcess();
- }
- else
- {
- this->Process();
- }
- }
- int InterpreterStackFrame::ProcessFinally()
- {
- this->nestedFinallyDepth++;
- // mark the stackFrame as 'in finally block'
- this->m_flags |= InterpreterStackFrameFlags_WithinFinallyBlock;
- int newOffset = 0;
- if (this->IsInDebugMode())
- {
- newOffset = ::Math::PointerCastToIntegral<int>(this->DebugProcess());
- }
- else
- {
- newOffset = ::Math::PointerCastToIntegral<int>(this->Process());
- }
- if (--this->nestedFinallyDepth == -1)
- {
- // unmark the stackFrame as 'in finally block'
- this->m_flags &= ~InterpreterStackFrameFlags_WithinFinallyBlock;
- }
- return newOffset;
- }
- void InterpreterStackFrame::ProcessTryCatchBailout(EHBailoutData * ehBailoutData, uint32 tryNestingDepth)
- {
- int catchOffset = ehBailoutData->catchOffset;
- Js::JavascriptExceptionObject* exception = NULL;
- if (catchOffset != 0)
- {
- try
- {
- this->nestedTryDepth++;
- // mark the stackFrame as 'in try block'
- this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
- if (tryNestingDepth != 0)
- {
- this->ProcessTryCatchBailout(ehBailoutData->child, --tryNestingDepth);
- }
- Js::JavascriptExceptionOperators::AutoCatchHandlerExists autoCatchHandlerExists(scriptContext);
- if (this->IsInDebugMode())
- {
- #if ENABLE_TTD
- if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
- {
- this->ProcessWithDebugging_PreviousStmtTracking();
- }
- else
- {
- this->ProcessWithDebugging();
- }
- #else
- this->ProcessWithDebugging();
- #endif
- this->TrySetRetOffset();
- }
- else
- {
- this->Process();
- this->TrySetRetOffset();
- }
- }
- catch (const Js::JavascriptException& err)
- {
- // We are using C++ exception handling which does not unwind the stack in the catch block.
- // For stack overflow and OOM exceptions, we cannot run user code here because the stack is not unwind.
- exception = err.GetAndClear();
- }
- }
- else
- {
- this->nestedCatchDepth++;
- // mark the stackFrame as 'in catch block'
- this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
- if (tryNestingDepth != 0)
- {
- this->ProcessTryCatchBailout(ehBailoutData->child, --tryNestingDepth);
- }
- this->ProcessCatch();
- if (--this->nestedCatchDepth == -1)
- {
- // unmark the stackFrame as 'in catch block'
- this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
- }
- return;
- }
- if (--this->nestedTryDepth == -1)
- {
- // unmark the stackFrame as 'in try block'
- this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
- }
- // Now that the stack is unwound, let's run the catch block.
- if (exception)
- {
- if (exception->IsGeneratorReturnException())
- {
- // Generator return scenario, so no need to go into the catch block and we must rethrow to propagate the exception to down level
- JavascriptExceptionOperators::DoThrow(exception, scriptContext);
- }
- exception = exception->CloneIfStaticExceptionObject(scriptContext);
- // We've got a JS exception. Grab the exception object and assign it to the
- // catch object's location, then call the handler (i.e., we consume the Catch op here).
- Var catchObject = exception->GetThrownObject(scriptContext);
- m_reader.SetCurrentOffset(catchOffset);
- LayoutSize layoutSize;
- OpCode catchOp = m_reader.ReadOp(layoutSize);
- #ifdef BYTECODE_BRANCH_ISLAND
- if (catchOp == Js::OpCode::BrLong)
- {
- Assert(layoutSize == SmallLayout);
- auto playoutBrLong = m_reader.BrLong();
- m_reader.SetCurrentRelativeOffset((const byte *)(playoutBrLong + 1), playoutBrLong->RelativeJumpOffset);
- catchOp = m_reader.ReadOp(layoutSize);
- }
- #endif
- AssertMsg(catchOp == OpCode::Catch, "Catch op not found at catch offset");
- RegSlot reg = layoutSize == SmallLayout ? m_reader.Reg1_Small()->R0 :
- layoutSize == MediumLayout ? m_reader.Reg1_Medium()->R0 : m_reader.Reg1_Large()->R0;
- SetReg(reg, catchObject);
- ResetOut();
- this->nestedCatchDepth++;
- // mark the stackFrame as 'in catch block'
- this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
- this->ProcessCatch();
- if (--this->nestedCatchDepth == -1)
- {
- // unmark the stackFrame as 'in catch block'
- this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
- }
- }
- }
- void InterpreterStackFrame::TrySetRetOffset()
- {
- Assert(this->m_flags & Js::InterpreterStackFrameFlags_WithinTryBlock);
- // It may happen that a JITted loop body returned the offset of RET. If the loop body was
- // called from a try, the interpreter "Process()" should also just return.
- if (this->retOffset != 0)
- {
- m_reader.SetCurrentOffset(this->retOffset);
- }
- }
- bool InterpreterStackFrame::IsInCatchOrFinallyBlock()
- {
- return (this->m_flags & Js::InterpreterStackFrameFlags_WithinCatchBlock) ||
- (this->m_flags & Js::InterpreterStackFrameFlags_WithinFinallyBlock);
- }
- void InterpreterStackFrame::OP_BeginBodyScope()
- {
- // Currently we are using the closures created for the param scope.
- // This marks the beginning of the body scope, so let's create new closures for the body scope.
- FunctionBody *executeFunction = this->function->GetFunctionBody();
- Assert(!this->IsParamScopeDone() && !executeFunction->IsParamAndBodyScopeMerged());
- // Save the current closure. We have to use this while copying the initial value of body symbols
- // from the corresponding symbols in the param.
- this->SetParamClosure(this->GetLocalClosure());
- this->SetNonVarReg(executeFunction->GetParamClosureRegister(), nullptr);
- this->SetIsParamScopeDone(true);
- if (executeFunction->scopeSlotArraySize > 0)
- {
- this->InitializeClosures();
- }
- }
- void InterpreterStackFrame::OP_ResumeCatch()
- {
- this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
- if (this->IsInDebugMode())
- {
- this->DebugProcess();
- }
- else
- {
- this->Process();
- }
- this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
- }
- /// ---------------------------------------------------------------------------------------------------
- /// The behavior we want is the following:
- /// - If the control leaves the user's try without throwing, execute the finally and continue
- /// after the end of the try.
- /// - If the user code throws, catch this exception and then execute this finally while unwinding to
- /// the handler (if any).
- /// ---------------------------------------------------------------------------------------------------
- void InterpreterStackFrame::ProcessTryFinally(const byte* ip, Js::JumpOffset jumpOffset, Js::RegSlot regException, Js::RegSlot regOffset, bool hasYield)
- {
- Js::JavascriptExceptionObject* pExceptionObject = nullptr;
- bool skipFinallyBlock = false;
- try
- {
- Js::Var result = nullptr;
- this->nestedTryDepth++;
- // mark the stackFrame as 'in try block'
- this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
- if (shouldCacheSP)
- {
- CacheSp();
- }
- if (this->IsInDebugMode())
- {
- #if ENABLE_TTD
- if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
- {
- result = this->ProcessWithDebugging_PreviousStmtTracking();
- }
- else
- {
- result = this->ProcessWithDebugging();
- }
- #else
- result = this->ProcessWithDebugging();
- #endif
- }
- else
- {
- result = this->Process();
- }
- if (result == nullptr)
- {
- Assert(hasYield);
- skipFinallyBlock = true;
- }
- }
- catch (const Js::JavascriptException& err)
- {
- pExceptionObject = err.GetAndClear();
- }
- if (--this->nestedTryDepth == -1)
- {
- // unmark the stackFrame as 'in try block'
- this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
- }
- shouldCacheSP = !skipFinallyBlock;
- if (skipFinallyBlock)
- {
- // A leave occurred due to a yield
- return;
- }
- // Save the current IP so execution can continue there if the finally doesn't
- // take control of the flow.
- int newOffset = 0;
- int currOffset = m_reader.GetCurrentOffset();
- if (hasYield)
- {
- // save the exception if there is one to a register in case we yield during the finally block
- // and need to get that exception object back upon resume in OP_ResumeFinally
- SetNonVarReg(regException, pExceptionObject);
- SetNonVarReg(regOffset, reinterpret_cast<Js::Var>(currOffset));
- }
- if (pExceptionObject && !pExceptionObject->IsGeneratorReturnException())
- {
- // Clone static exception object early in case finally block overwrites it
- pExceptionObject = pExceptionObject->CloneIfStaticExceptionObject(scriptContext);
- }
- if (pExceptionObject && this->IsInDebugMode() &&
- pExceptionObject != scriptContext->GetThreadContext()->GetPendingSOErrorObject())
- {
- // Swallowing an exception that has triggered a finally is not implemented
- // (This appears to be the same behavior as ie8)
- pExceptionObject->SetDebuggerSkip(false);
- }
- // Call into the finally by setting the IP, consuming the Finally, and letting the interpreter recurse.
- m_reader.SetCurrentRelativeOffset(ip, jumpOffset);
- RestoreSp();
- newOffset = this->ProcessFinally();
- bool endOfFinallyBlock = newOffset == 0;
- if (endOfFinallyBlock)
- {
- // Finally completed without taking over the flow. Resume where we left off before calling it.
- m_reader.SetCurrentOffset(currOffset);
- }
- else
- {
- // Finally seized the flow with a jump out of its scope. Resume at the jump target and
- // force the runtime to return to this frame without executing the catch.
- m_reader.SetCurrentOffset(newOffset);
- return;
- }
- if (pExceptionObject && (endOfFinallyBlock || !pExceptionObject->IsGeneratorReturnException()))
- {
- JavascriptExceptionOperators::DoThrow(pExceptionObject, scriptContext);
- }
- }
- void InterpreterStackFrame::OP_TryFinally(const unaligned OpLayoutBr* playout)
- {
- ProcessTryFinally((const byte*)(playout + 1), playout->RelativeJumpOffset);
- }
- void InterpreterStackFrame::OP_TryFinallyWithYield(const byte* ip, Js::JumpOffset jumpOffset, Js::RegSlot regException, Js::RegSlot regOffset)
- {
- ProcessTryFinally(ip, jumpOffset, regException, regOffset, true);
- }
- void InterpreterStackFrame::OP_ResumeFinally(const byte* ip, Js::JumpOffset jumpOffset, RegSlot exceptionRegSlot, RegSlot offsetRegSlot)
- {
- this->m_flags |= InterpreterStackFrameFlags_WithinFinallyBlock;
- int newOffset = 0;
- if (this->IsInDebugMode())
- {
- newOffset = ::Math::PointerCastToIntegral<int>(this->DebugProcess());
- }
- else
- {
- newOffset = ::Math::PointerCastToIntegral<int>(this->Process());
- }
- this->m_flags &= ~InterpreterStackFrameFlags_WithinFinallyBlock;
- bool endOfFinallyBlock = newOffset == 0;
- if (endOfFinallyBlock)
- {
- // Finally completed without taking over the flow. Resume where we left off before calling it.
- int currOffset = ::Math::PointerCastToIntegral<int>(GetNonVarReg(offsetRegSlot));
- m_reader.SetCurrentOffset(currOffset);
- }
- else
- {
- // Finally seized the flow with a jump out of its scope. Resume at the jump target and
- // force the runtime to return to this frame without executing the catch.
- m_reader.SetCurrentOffset(newOffset);
- return;
- }
- Js::JavascriptExceptionObject* exceptionObj = (Js::JavascriptExceptionObject*)GetNonVarReg(exceptionRegSlot);
- if (exceptionObj && (endOfFinallyBlock || !exceptionObj->IsGeneratorReturnException()))
- {
- JavascriptExceptionOperators::DoThrow(exceptionObj, scriptContext);
- }
- }
- template <typename T>
- void InterpreterStackFrame::OP_IsInst(const unaligned T* playout)
- {
- Var instance = GetReg(playout->R1);
- Var function = GetReg(playout->R2);
- IsInstInlineCache *inlineCache = this->GetIsInstInlineCache(playout->inlineCacheIndex);
- ScriptContext* scriptContext = GetScriptContext();
- Var result = JavascriptOperators::OP_IsInst(instance, function, scriptContext, inlineCache);
- #ifdef ENABLE_BASIC_TELEMETRY
- {
- this->scriptContext->GetTelemetry().GetOpcodeTelemetry().IsInstanceOf(instance, function, result);
- }
- #endif
- SetReg(playout->R0, result);
- }
- template <typename T>
- void InterpreterStackFrame::OP_ApplyArgs(const unaligned OpLayoutT_Reg5<T> * playout)
- {
- // Always save and restore implicit call flags when calling out
- // REVIEW: Can we avoid it if we don't collect dynamic profile info?
- ThreadContext * threadContext = scriptContext->GetThreadContext();
- Js::ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- // Currently ApplyArgs is equivalent to CallFldVoid (where we don't use the return value)
- Var v=GetNonVarReg(playout->R4);
- JavascriptOperators::OP_ApplyArgs(GetReg(playout->R1),GetReg(playout->R2),
- (void**)GetNonVarReg(playout->R3),*((CallInfo*)&v),GetScriptContext());
- threadContext->SetImplicitCallFlags(savedImplicitCallFlags);
- }
- void InterpreterStackFrame::OP_SpreadArrayLiteral(const unaligned OpLayoutReg2Aux * playout)
- {
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- Var instance = GetReg(playout->R1);
- #if ENABLE_COPYONACCESS_ARRAY
- JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
- #endif
- const Js::AuxArray<uint32> *spreadIndices = m_reader.ReadAuxArray<uint32>(playout->Offset, this->GetFunctionBody());
- ScriptContext* scriptContext = GetScriptContext();
- Var result = JavascriptArray::SpreadArrayArgs(instance, spreadIndices, scriptContext);
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- SetReg(playout->R0, result);
- }
- FrameDisplay *
- InterpreterStackFrame::OP_LdInnerFrameDisplay(void *argHead, void *argEnv, ScriptContext *scriptContext)
- {
- JavascriptOperators::CheckInnerFrameDisplayArgument(argHead);
- return OP_LdFrameDisplay(argHead, argEnv, scriptContext);
- }
- FrameDisplay *
- InterpreterStackFrame::OP_LdInnerFrameDisplayNoParent(void *argHead, ScriptContext *scriptContext)
- {
- JavascriptOperators::CheckInnerFrameDisplayArgument(argHead);
- return OP_LdFrameDisplayNoParent<true>(argHead, scriptContext);
- }
- FrameDisplay *
- InterpreterStackFrame::OP_LdFrameDisplay(void *argHead, void *argEnv, ScriptContext *scriptContext)
- {
- FrameDisplay *frameDisplay;
- bool strict = this->m_functionBody->GetIsStrictMode();
- if (strict)
- {
- frameDisplay = JavascriptOperators::OP_LdStrictFrameDisplay(argHead, argEnv, scriptContext);
- }
- else
- {
- frameDisplay = JavascriptOperators::OP_LdFrameDisplay(argHead, argEnv, scriptContext);
- }
- return frameDisplay;
- }
- FrameDisplay *
- InterpreterStackFrame::OP_LdFrameDisplaySetLocal(void *argHead, void *argEnv, ScriptContext *scriptContext)
- {
- FrameDisplay *frameDisplay = OP_LdFrameDisplay(argHead, argEnv, scriptContext);
- this->SetLocalFrameDisplay(frameDisplay);
- return frameDisplay;
- }
- FrameDisplay *
- InterpreterStackFrame::NewFrameDisplay(void *argHead, void *argEnv)
- {
- FrameDisplay *frameDisplay;
- bool strict = this->m_functionBody->GetIsStrictMode();
- if (!this->m_functionBody->DoStackFrameDisplay() || !this->GetLocalFrameDisplay())
- {
- // Null local frame display probably indicates that we bailed out of an inlinee.
- // Once we support stack closures in inlined functions, we can just assert that this value
- // is never null if we should be allocating on the stack.
- return this->OP_LdFrameDisplaySetLocal(argHead, argEnv, this->GetScriptContext());
- }
- frameDisplay = this->GetLocalFrameDisplay();
- Assert(frameDisplay != nullptr);
- frameDisplay->SetTag(true);
- frameDisplay->SetStrictMode(strict);
- frameDisplay->SetLength(this->m_functionBody->GetEnvDepth() + 1);
- Assert(frameDisplay->GetLength() == ((FrameDisplay*)argEnv)->GetLength() + 1);
- for (uint i = 0; i < ((FrameDisplay*)argEnv)->GetLength(); i++)
- {
- frameDisplay->SetItem(i + 1, ((FrameDisplay*)argEnv)->GetItem(i));
- }
- frameDisplay->SetItem(0, argHead);
- return frameDisplay;
- }
- template<bool innerFD>
- FrameDisplay *
- InterpreterStackFrame::OP_LdFrameDisplayNoParent(void *argHead, ScriptContext *scriptContext)
- {
- FrameDisplay *frameDisplay;
- bool strict = this->m_functionBody->GetIsStrictMode();
- Var argEnv = nullptr;
- if (innerFD && this->m_functionBody->GetLocalFrameDisplayRegister() != Constants::NoRegister)
- {
- argEnv = this->GetLocalFrameDisplay();
- }
- if (argEnv == nullptr && this->m_functionBody->GetEnvRegister() != Constants::NoRegister)
- {
- argEnv = this->LdEnv();
- }
- if (argEnv == nullptr)
- {
- if (strict)
- {
- frameDisplay = JavascriptOperators::OP_LdStrictFrameDisplayNoParent(argHead, scriptContext);
- }
- else
- {
- frameDisplay = JavascriptOperators::OP_LdFrameDisplayNoParent(argHead, scriptContext);
- }
- }
- else
- {
- if (strict)
- {
- frameDisplay = JavascriptOperators::OP_LdStrictFrameDisplay(argHead, argEnv, scriptContext);
- }
- else
- {
- frameDisplay = JavascriptOperators::OP_LdFrameDisplay(argHead, argEnv, scriptContext);
- }
- }
- return frameDisplay;
- }
- FrameDisplay *
- InterpreterStackFrame::OP_LdFuncExprFrameDisplaySetLocal(void *argHead1, void *argHead2, ScriptContext *scriptContext)
- {
- FrameDisplay *frameDisplay = OP_LdFrameDisplayNoParent<false>(argHead2, scriptContext);
- frameDisplay = OP_LdFrameDisplay(argHead1, frameDisplay, scriptContext);
- this->SetLocalFrameDisplay(frameDisplay);
- return frameDisplay;
- }
- FrameDisplay* InterpreterStackFrame::GetLocalFrameDisplay() const
- {
- return this->localFrameDisplay;
- }
- void InterpreterStackFrame::SetLocalFrameDisplay(FrameDisplay* frameDisplay)
- {
- this->localFrameDisplay = frameDisplay;
- }
- Var InterpreterStackFrame::GetLocalClosure() const
- {
- return this->localClosure;
- }
- void InterpreterStackFrame::SetLocalClosure(Var closure)
- {
- this->localClosure = closure;
- }
- Var InterpreterStackFrame::GetParamClosure() const
- {
- return this->paramClosure;
- }
- void InterpreterStackFrame::SetParamClosure(Var closure)
- {
- this->paramClosure = closure;
- }
- void
- InterpreterStackFrame::OP_NewInnerScopeSlots(uint innerScopeIndex, uint count, int scopeIndex, ScriptContext *scriptContext, FunctionBody *functionBody)
- {
- Var * slotArray;
- slotArray =
- JavascriptOperators::OP_NewScopeSlotsWithoutPropIds(count, scopeIndex, scriptContext, functionBody);
- this->SetInnerScopeFromIndex(innerScopeIndex, slotArray);
- }
- template <typename T>
- void InterpreterStackFrame::OP_CloneInnerScopeSlots(const unaligned OpLayoutT_Unsigned1<T> *playout)
- {
- uint innerScopeIndex = playout->C1;
- Var * slotArray;
- slotArray = (Var*)this->InnerScopeFromIndex(innerScopeIndex);
- slotArray = JavascriptOperators::OP_CloneScopeSlots(slotArray, scriptContext);
- this->SetInnerScopeFromIndex(innerScopeIndex, slotArray);
- }
- template <typename T>
- void InterpreterStackFrame::OP_CloneBlockScope(const unaligned OpLayoutT_Unsigned1<T> *playout)
- {
- uint innerScopeIndex = playout->C1;
- Var scope = this->InnerScopeFromIndex(innerScopeIndex);
- BlockActivationObject* blockScope = BlockActivationObject::FromVar(scope);
- scope = JavascriptOperators::OP_CloneBlockScope(blockScope, scriptContext);
- this->SetInnerScopeFromIndex(innerScopeIndex, scope);
- }
- Var *
- InterpreterStackFrame::NewScopeSlots(unsigned int size, ScriptContext *scriptContext, Var scope)
- {
- Var * slotArray;
- slotArray = JavascriptOperators::OP_NewScopeSlots(size, scriptContext, scope);
- this->SetLocalClosure(slotArray);
- return slotArray;
- }
- Var *
- InterpreterStackFrame::NewScopeSlots()
- {
- Var * slotArray;
- FunctionBody * functionBody = this->m_functionBody;
- uint scopeSlotCount = this->IsParamScopeDone() ? functionBody->scopeSlotArraySize : functionBody->paramScopeSlotArraySize;
- Assert(scopeSlotCount != 0);
- if (!functionBody->DoStackScopeSlots())
- {
- return this->NewScopeSlots(
- scopeSlotCount + ScopeSlots::FirstSlotIndex, this->GetScriptContext(), (Var)functionBody->GetFunctionInfo());
- }
- slotArray = (Var*)this->GetLocalClosure();
- Assert(slotArray != nullptr);
- ScopeSlots scopeSlots(slotArray);
- scopeSlots.SetCount(scopeSlotCount);
- scopeSlots.SetScopeMetadata((Var)functionBody->GetFunctionInfo());
- Var undef = functionBody->GetScriptContext()->GetLibrary()->GetUndefined();
- for (unsigned int i = 0; i < scopeSlotCount; i++)
- {
- scopeSlots.Set(i, undef);
- }
- return slotArray;
- }
- Var
- InterpreterStackFrame::NewScopeObject()
- {
- Var scopeObject;
- if (m_functionBody->HasCachedScopePropIds())
- {
- const Js::PropertyIdArray *propIds = this->m_functionBody->GetFormalsPropIdArray();
- Var funcExpr = this->GetFunctionExpression();
- PropertyId objectId = ActivationObjectEx::GetLiteralObjectRef(propIds);
- scopeObject = JavascriptOperators::OP_InitCachedScope(funcExpr, propIds,
- this->GetFunctionBody()->GetObjectLiteralTypeRef(objectId),
- propIds->hasNonSimpleParams, GetScriptContext());
- }
- else
- {
- scopeObject = JavascriptOperators::OP_NewScopeObject(GetScriptContext());
- }
- this->SetLocalClosure(scopeObject);
- return scopeObject;
- }
- FrameDisplay *
- InterpreterStackFrame::GetFrameDisplayForNestedFunc() const
- {
- if (this->localFrameDisplay == nullptr)
- {
- return (FrameDisplay*)LdEnv();
- }
- return this->localFrameDisplay;
- }
- template <class T>
- void InterpreterStackFrame::OP_NewStackScFunc(const unaligned T * playout)
- {
- uint funcIndex = playout->SlotIndex;
- FrameDisplay *frameDisplay = this->GetFrameDisplayForNestedFunc();
- SetRegAllowStackVarEnableOnly(playout->Value,
- StackScriptFunction::OP_NewStackScFunc(frameDisplay,
- this->m_functionBody->GetNestedFuncReference(funcIndex),
- this->GetStackNestedFunction(funcIndex)));
- }
- template <class T>
- void InterpreterStackFrame::OP_NewInnerStackScFunc(const unaligned T * playout)
- {
- uint funcIndex = playout->SlotIndex;
- FrameDisplay *frameDisplay = (FrameDisplay*)GetNonVarReg(playout->Instance);
- SetRegAllowStackVarEnableOnly(playout->Value,
- StackScriptFunction::OP_NewStackScFunc(frameDisplay,
- this->m_functionBody->GetNestedFuncReference(funcIndex),
- this->GetStackNestedFunction(funcIndex)));
- }
- template <class T>
- void InterpreterStackFrame::OP_DeleteFld(const unaligned T * playout)
- {
- Var result = JavascriptOperators::OP_DeleteProperty(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
- SetReg(playout->Value, result);
- }
- template <class T>
- void InterpreterStackFrame::OP_DeleteLocalFld(const unaligned T * playout)
- {
- Var result = JavascriptOperators::OP_DeleteProperty(this->localClosure, m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
- SetReg(playout->Instance, result);
- }
- template <class T>
- void InterpreterStackFrame::OP_DeleteRootFld(const unaligned T * playout)
- {
- Var result = JavascriptOperators::OP_DeleteRootProperty(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
- SetReg(playout->Value, result);
- }
- template <class T>
- void InterpreterStackFrame::OP_DeleteFldStrict(const unaligned T * playout)
- {
- Var result = JavascriptOperators::OP_DeleteProperty(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext(), PropertyOperation_StrictMode);
- SetReg(playout->Value, result);
- }
- template <class T>
- void InterpreterStackFrame::OP_DeleteRootFldStrict(const unaligned T * playout)
- {
- Var result = JavascriptOperators::OP_DeleteRootProperty(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext(), PropertyOperation_StrictMode);
- SetReg(playout->Value, result);
- }
- template <typename T>
- void InterpreterStackFrame::OP_ScopedDeleteFld(const unaligned OpLayoutT_ElementScopedC<T> * playout)
- {
- // Implicit root object as default instance
- Var result = JavascriptOperators::OP_DeletePropertyScoped(GetEnvForEvalCode(),
- m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
- GetReg(Js::FunctionBody::RootObjectRegSlot), GetScriptContext());
- SetReg(playout->Value, result);
- }
- template <typename T>
- void InterpreterStackFrame::OP_ScopedDeleteFldStrict(const unaligned OpLayoutT_ElementScopedC<T> * playout)
- {
- // Implicit root object as default instance
- Var result = JavascriptOperators::OP_DeletePropertyScoped(GetEnvForEvalCode(),
- m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
- GetReg(Js::FunctionBody::RootObjectRegSlot), GetScriptContext(), PropertyOperation_StrictMode);
- SetReg(playout->Value, result);
- }
- template <class T>
- void InterpreterStackFrame::OP_ScopedLdInst(const unaligned T * playout)
- {
- Var thisVar;
- Var rootObject = GetFunctionBody()->GetRootObject();
- Var result = JavascriptOperators::OP_GetInstanceScoped(GetEnvForEvalCode(),
- m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), rootObject, &thisVar, GetScriptContext());
- SetReg(playout->Value, result);
- SetReg(playout->Value2, thisVar);
- }
- template <typename T>
- void InterpreterStackFrame::OP_ScopedInitFunc(const unaligned OpLayoutT_ElementScopedC<T> * playout)
- {
- JavascriptOperators::OP_InitFuncScoped(GetEnvForEvalCode(),
- m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
- GetReg(playout->Value), GetReg(Js::FunctionBody::RootObjectRegSlot), GetScriptContext());
- }
- template <class T>
- void InterpreterStackFrame::OP_ClearAttributes(const unaligned T * playout)
- {
- JavascriptOperators::OP_ClearAttributes(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex));
- }
- template <class T>
- void InterpreterStackFrame::OP_InitGetFld(const unaligned T * playout)
- {
- JavascriptOperators::OP_InitGetter(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetReg(playout->Value));
- }
- template <class T>
- void InterpreterStackFrame::OP_InitSetFld(const unaligned T * playout)
- {
- JavascriptOperators::OP_InitSetter(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetReg(playout->Value));
- }
- template <class T>
- void InterpreterStackFrame::OP_InitSetElemI(const unaligned T * playout)
- {
- JavascriptOperators::OP_InitElemSetter(
- GetReg(playout->Instance),
- GetReg(playout->Element),
- GetReg(playout->Value),
- m_functionBody->GetScriptContext()
- );
- }
- template <class T>
- void InterpreterStackFrame::OP_InitGetElemI(const unaligned T * playout)
- {
- JavascriptOperators::OP_InitElemGetter(
- GetReg(playout->Instance),
- GetReg(playout->Element),
- GetReg(playout->Value),
- m_functionBody->GetScriptContext()
- );
- }
- template <class T>
- void InterpreterStackFrame::OP_InitComputedProperty(const unaligned T * playout)
- {
- JavascriptOperators::OP_InitComputedProperty(
- GetReg(playout->Instance),
- GetReg(playout->Element),
- GetReg(playout->Value),
- m_functionBody->GetScriptContext()
- );
- }
- template <class T>
- void InterpreterStackFrame::OP_InitProto(const unaligned T * playout)
- {
- JavascriptOperators::OP_InitProto(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetReg(playout->Value));
- }
- void InterpreterStackFrame::DoInterruptProbe()
- {
- PROBE_STACK(scriptContext, 0);
- }
- void InterpreterStackFrame::InitializeStackFunctions(StackScriptFunction * scriptFunctions)
- {
- this->stackNestedFunctions = scriptFunctions;
- FunctionBody * functionBody = this->m_functionBody;
- uint nestedCount = functionBody->GetNestedCount();
- for (uint i = 0; i < nestedCount; i++)
- {
- StackScriptFunction * stackScriptFunction = scriptFunctions + i;
- FunctionProxy* nestedProxy = functionBody->GetNestedFunctionProxy(i);
- ScriptFunctionType* type = nestedProxy->EnsureDeferredPrototypeType();
- new (stackScriptFunction)StackScriptFunction(nestedProxy, type);
- }
- }
- StackScriptFunction * InterpreterStackFrame::GetStackNestedFunction(uint index)
- {
- Assert(index < this->m_functionBody->GetNestedCount());
- // Re-check if we have disable stack nested function
- if (this->m_functionBody->DoStackNestedFunc())
- {
- return this->stackNestedFunctions + index;
- }
- return nullptr;
- }
- void InterpreterStackFrame::SetExecutingStackFunction(ScriptFunction * scriptFunction)
- {
- Assert(ThreadContext::IsOnStack(this->function));
- Assert(this->m_functionBody == scriptFunction->GetFunctionBody());
- this->function = scriptFunction;
- }
- DWORD_PTR InterpreterStackFrame::GetStackAddress() const
- {
- return m_stackAddress;
- }
- void* InterpreterStackFrame::GetAddressOfReturnAddress() const
- {
- return this->addressOfReturnAddress;
- }
- template <class T>
- const byte * InterpreterStackFrame::OP_Br(const unaligned T * playout)
- {
- return m_reader.SetCurrentRelativeOffset((const byte *)(playout + 1), playout->RelativeJumpOffset);
- }
- template <class T>
- void InterpreterStackFrame::OP_InitClass(const unaligned OpLayoutT_Class<T> * playout)
- {
- JavascriptOperators::OP_InitClass(GetReg(playout->Constructor), playout->Extends != Js::Constants::NoRegister ? GetReg(playout->Extends) : NULL, GetScriptContext());
- }
- template <class T>
- void InterpreterStackFrame::OP_EmitTmpRegCount(const unaligned OpLayoutT_Unsigned1<T> * playout)
- {
- this->scriptContext->GetDebugContext()->GetProbeContainer()->SetCurrentTmpRegCount(playout->C1);
- }
- Var InterpreterStackFrame::OP_LdHomeObj(ScriptContext * scriptContext)
- {
- return JavascriptOperators::OP_LdHomeObj(function, scriptContext);
- }
- Var InterpreterStackFrame::OP_LdFuncObj(ScriptContext * scriptContext)
- {
- return JavascriptOperators::OP_LdFuncObj(function, scriptContext);
- }
- Var InterpreterStackFrame::OP_ScopedLdHomeObj(ScriptContext * scriptContext)
- {
- return JavascriptOperators::OP_ScopedLdHomeObj(function, scriptContext);
- }
- Var InterpreterStackFrame::OP_ScopedLdFuncObj(ScriptContext * scriptContext)
- {
- return JavascriptOperators::OP_ScopedLdFuncObj(function, scriptContext);
- }
- void InterpreterStackFrame::ValidateRegValue(Var value, bool allowStackVar, bool allowStackVarOnDisabledStackNestedFunc) const
- {
- #if DBG
- if (value != nullptr && !TaggedNumber::Is(value))
- {
- if (!allowStackVar || !this->m_functionBody->DoStackNestedFunc())
- {
- Assert(!ThreadContext::IsOnStack(value)
- || (allowStackVar && allowStackVarOnDisabledStackNestedFunc && StackScriptFunction::IsBoxed(value)));
- }
- Assert(!CrossSite::NeedMarshalVar(value, GetScriptContext()));
- }
- #endif
- }
- template <typename RegSlotType>
- Var InterpreterStackFrame::GetReg(RegSlotType localRegisterID) const
- {
- Var value = m_localSlots[localRegisterID];
- ValidateRegValue(value);
- return value;
- }
- template <typename RegSlotType>
- void InterpreterStackFrame::SetReg(RegSlotType localRegisterID, Var value)
- {
- Assert(localRegisterID == 0 || localRegisterID >= m_functionBody->GetConstantCount());
- ValidateRegValue(value);
- m_localSlots[localRegisterID] = value;
- #if ENABLE_OBJECT_SOURCE_TRACKING
- if(value != nullptr && DynamicType::Is(Js::JavascriptOperators::GetTypeId(value)))
- {
- static_cast<DynamicObject*>(value)->SetDiagOriginInfoAsNeeded();
- }
- #endif
- #if ENABLE_VALUE_TRACE
- if(this->function->GetScriptContext()->ShouldPerformRecordOrReplayAction())
- {
- this->function->GetScriptContext()->GetThreadContext()->TTDLog->GetTraceLogger()->WriteTraceValue(value);
- }
- #endif
- }
- template <typename T>
- T InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
- {
- return (T)m_localIntSlots[localRegisterID];
- }
- // specialized version for doubles
- template <>
- double InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
- {
- return (double)m_localDoubleSlots[localRegisterID];
- }
- template <>
- float InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
- {
- return (float)m_localFloatSlots[localRegisterID];
- }
- template <>
- int64 InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
- {
- return m_localInt64Slots[localRegisterID];
- }
- template <typename T>
- void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, T bValue)
- {
- m_localIntSlots[localRegisterID] = (int)bValue;
- }
- template <>
- void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, float bValue)
- {
- m_localFloatSlots[localRegisterID] = (float)bValue;
- }
- template <>
- void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, double bValue)
- {
- m_localDoubleSlots[localRegisterID] = bValue;
- }
- template <>
- void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, int64 bValue)
- {
- m_localInt64Slots[localRegisterID] = bValue;
- }
- template <typename RegSlotType>
- int InterpreterStackFrame::GetRegRawInt(RegSlotType localRegisterID) const
- {
- return m_localIntSlots[localRegisterID];
- }
- template <typename RegSlotType>
- double InterpreterStackFrame::GetRegRawDouble(RegSlotType localRegisterID) const
- {
- return m_localDoubleSlots[localRegisterID];
- }
- template <typename RegSlotType>
- float InterpreterStackFrame::GetRegRawFloat(RegSlotType localRegisterID) const
- {
- return m_localFloatSlots[localRegisterID];
- }
- template <typename RegSlotType>
- void InterpreterStackFrame::SetRegRawInt(RegSlotType localRegisterID, int bValue)
- {
- m_localIntSlots[localRegisterID] = bValue;
- }
- template <typename RegSlotType>
- int64 InterpreterStackFrame::GetRegRawInt64(RegSlotType localRegisterID) const
- {
- return m_localInt64Slots[localRegisterID];
- }
- template <typename RegSlotType>
- void InterpreterStackFrame::SetRegRawInt64(RegSlotType localRegisterID, int64 bValue)
- {
- m_localInt64Slots[localRegisterID] = bValue;
- }
- template <typename RegSlotType>
- void InterpreterStackFrame::SetRegRawDouble(RegSlotType localRegisterID, double bValue)
- {
- m_localDoubleSlots[localRegisterID] = bValue;
- }
- template <typename RegSlotType>
- void InterpreterStackFrame::SetRegRawFloat(RegSlotType localRegisterID, float bValue)
- {
- m_localFloatSlots[localRegisterID] = bValue;
- }
- template <typename RegSlotType>
- Var InterpreterStackFrame::GetRegAllowStackVar(RegSlotType localRegisterID) const
- {
- Var value = m_localSlots[localRegisterID];
- ValidateRegValue(value, true);
- return value;
- }
- template <typename RegSlotType>
- void InterpreterStackFrame::SetRegAllowStackVar(RegSlotType localRegisterID, Var value)
- {
- Assert(localRegisterID == 0 || localRegisterID >= m_functionBody->GetConstantCount());
- ValidateRegValue(value, true);
- m_localSlots[localRegisterID] = value;
- #if ENABLE_OBJECT_SOURCE_TRACKING
- if(value != nullptr && DynamicType::Is(Js::JavascriptOperators::GetTypeId(value)))
- {
- static_cast<DynamicObject*>(value)->SetDiagOriginInfoAsNeeded();
- }
- #endif
- #if ENABLE_VALUE_TRACE
- if(this->function->GetScriptContext()->ShouldPerformRecordOrReplayAction())
- {
- this->function->GetScriptContext()->GetThreadContext()->TTDLog->GetTraceLogger()->WriteTraceValue(value);
- }
- #endif
- }
- template <typename RegSlotType>
- Var InterpreterStackFrame::GetRegAllowStackVarEnableOnly(RegSlotType localRegisterID) const
- {
- Var value = m_localSlots[localRegisterID];
- ValidateRegValue(value, true, false);
- return value;
- }
- template <typename RegSlotType>
- void InterpreterStackFrame::SetRegAllowStackVarEnableOnly(RegSlotType localRegisterID, Var value)
- {
- Assert(localRegisterID == 0 || localRegisterID >= m_functionBody->GetConstantCount());
- ValidateRegValue(value, true, false);
- m_localSlots[localRegisterID] = value;
- #if ENABLE_OBJECT_SOURCE_TRACKING
- if(value != nullptr && DynamicType::Is(Js::JavascriptOperators::GetTypeId(value)))
- {
- static_cast<DynamicObject*>(value)->SetDiagOriginInfoAsNeeded();
- }
- #endif
- #if ENABLE_VALUE_TRACE
- if(this->function->GetScriptContext()->ShouldPerformRecordOrReplayAction())
- {
- this->function->GetScriptContext()->GetThreadContext()->TTDLog->GetTraceLogger()->WriteTraceValue(value);
- }
- #endif
- }
- template <>
- AsmJsSIMDValue InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
- {
- return (AsmJsSIMDValue)m_localSimdSlots[localRegisterID];
- }
- template<>
- void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, AsmJsSIMDValue bValue)
- {
- m_localSimdSlots[localRegisterID] = bValue;
- }
- template <typename RegSlotType>
- AsmJsSIMDValue InterpreterStackFrame::GetRegRawSimd(RegSlotType localRegisterID) const
- {
- return m_localSimdSlots[localRegisterID];
- }
- template <typename RegSlotType>
- void InterpreterStackFrame::SetRegRawSimd(RegSlotType localRegisterID, AsmJsSIMDValue bValue)
- {
- m_localSimdSlots[localRegisterID] = bValue;
- }
- int InterpreterStackFrame::OP_GetMemorySize()
- {
- #ifdef ASMJS_PLAT
- JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
- return arr ? arr->GetByteLength() >> 16 : 0;
- #else
- return 0;
- #endif
- }
- int InterpreterStackFrame::OP_GrowMemory(int32 delta)
- {
- #ifdef ENABLE_WASM
- int32 oldPageCount = m_wasmMemory->GrowInternal((uint32)delta);
- SetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister, m_wasmMemory->GetBuffer());
- return oldPageCount;
- #else
- Assert(UNREACHED);
- return 0;
- #endif
- }
- template <typename T, InterpreterStackFrame::AsmJsMathPtr<T> func> T InterpreterStackFrame::OP_DivRemCheck(T aLeft, T aRight, ScriptContext* scriptContext)
- {
- if (aRight == 0)
- {
- JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, WASMERR_DivideByZero);
- }
- return func(aLeft, aRight);
- }
- template <typename T, InterpreterStackFrame::AsmJsMathPtr<T> func, T MIN> T InterpreterStackFrame::OP_DivOverflow(T aLeft, T aRight, ScriptContext* scriptContext)
- {
- if (aRight == 0)
- {
- JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, WASMERR_DivideByZero);
- }
- if (aLeft == MIN && aRight == -1)
- {
- JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, VBSERR_Overflow);
- }
- return func(aLeft, aRight);
- }
- void InterpreterStackFrame::OP_Unreachable()
- {
- JavascriptError::ThrowUnreachable(scriptContext);
- }
- template <class T>
- void InterpreterStackFrame::OP_SimdLdArrGeneric(const unaligned T* playout)
- {
- Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
- const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex) & ArrayBufferView::ViewMask[playout->ViewType];
- JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
- BYTE* buffer = arr->GetBuffer();
- uint8 dataWidth = playout->DataWidth;
- RegSlot dstReg = playout->Value;
- if (index < 0 || index + dataWidth > arr->GetByteLength())
- {
- JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, _u("Simd typed array access"));
- }
- AsmJsSIMDValue *data = (AsmJsSIMDValue*)(buffer + index);
- AsmJsSIMDValue value;
- value = SIMDUtils::SIMDLdData(data, dataWidth);
- SetRegRawSimd(dstReg, value);
- }
- template <class T>
- void InterpreterStackFrame::OP_SimdLdArrConstIndex(const unaligned T* playout)
- {
- Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
- const uint32 index = playout->SlotIndex;
- JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
- BYTE* buffer = arr->GetBuffer();
- uint8 dataWidth = playout->DataWidth;
- RegSlot dstReg = playout->Value;
- if (index < 0 || index + dataWidth > arr->GetByteLength())
- {
- JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, _u("Simd typed array access"));
- }
- AsmJsSIMDValue *data = (AsmJsSIMDValue*)(buffer + index);
- AsmJsSIMDValue value;
- value = SIMDUtils::SIMDLdData(data, dataWidth);
- SetRegRawSimd(dstReg, value);
- }
- template <class T>
- void InterpreterStackFrame::OP_SimdStArrGeneric(const unaligned T* playout)
- {
- Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
- const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex) & ArrayBufferView::ViewMask[playout->ViewType];
- JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
- BYTE* buffer = arr->GetBuffer();
- uint8 dataWidth = playout->DataWidth;
- RegSlot srcReg = playout->Value;
- if (index < 0 || index + dataWidth > arr->GetByteLength())
- {
- JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, _u("Simd typed array access"));
- }
- AsmJsSIMDValue *data = (AsmJsSIMDValue*)(buffer + index);
- AsmJsSIMDValue value = GetRegRawSimd(srcReg);
- SIMDUtils::SIMDStData(data, value, dataWidth);
- }
- template <class T>
- void InterpreterStackFrame::OP_SimdStArrConstIndex(const unaligned T* playout)
- {
- Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
- const uint32 index = playout->SlotIndex;
- JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
- BYTE* buffer = arr->GetBuffer();
- uint8 dataWidth = playout->DataWidth;
- RegSlot srcReg = playout->Value;
- if (index < 0 || index + dataWidth > arr->GetByteLength())
- {
- JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, _u("Simd typed array access"));
- }
- AsmJsSIMDValue *data = (AsmJsSIMDValue*)(buffer + index);
- AsmJsSIMDValue value = GetRegRawSimd(srcReg);
- SIMDUtils::SIMDStData(data, value, dataWidth);
- }
- // handler for SIMD.Int32x4.FromFloat32x4
- template <class T>
- void InterpreterStackFrame::OP_SimdInt32x4FromFloat32x4(const unaligned T* playout)
- {
- bool throws = false;
- AsmJsSIMDValue input = GetRegRawSimd(playout->F4_1);
- AsmJsSIMDValue result = SIMDInt32x4Operation::OpFromFloat32x4(input, throws);
- // value is out of bound
- if (throws)
- {
- JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, _u("SIMD.Int32x4.FromFloat32x4"));
- }
- SetRegRawSimd(playout->I4_0, result);
- }
- // handler for SIMD.Uint32x4.FromFloat32x4
- template <class T>
- void InterpreterStackFrame::OP_SimdUint32x4FromFloat32x4(const unaligned T* playout)
- {
- bool throws = false;
- AsmJsSIMDValue input = GetRegRawSimd(playout->F4_1);
- AsmJsSIMDValue result = SIMDUint32x4Operation::OpFromFloat32x4(input, throws);
- // value is out of bound
- if (throws)
- {
- JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, _u("SIMD.Int32x4.FromFloat32x4"));
- }
- SetRegRawSimd(playout->U4_0, result);
- }
- template <class T>
- void InterpreterStackFrame::OP_SimdInt16x8(const unaligned T* playout)
- {
- int16 values[8];
- values[0] = (int16) GetRegRawInt(playout->I1);
- values[1] = (int16) GetRegRawInt(playout->I2);
- values[2] = (int16) GetRegRawInt(playout->I3);
- values[3] = (int16) GetRegRawInt(playout->I4);
- values[4] = (int16) GetRegRawInt(playout->I5);
- values[5] = (int16) GetRegRawInt(playout->I6);
- values[6] = (int16) GetRegRawInt(playout->I7);
- values[7] = (int16) GetRegRawInt(playout->I8);
- AsmJsSIMDValue result = SIMDInt16x8Operation::OpInt16x8(values);
- SetRegRawSimd(playout->I8_0, result);
- }
- template <class T>
- void InterpreterStackFrame::OP_SimdInt8x16(const unaligned T* playout)
- {
- int8 values[16];
- values[0] = (int8)GetRegRawInt(playout->I1);
- values[1] = (int8)GetRegRawInt(playout->I2);
- values[2] = (int8)GetRegRawInt(playout->I3);
- values[3] = (int8)GetRegRawInt(playout->I4);
- values[4] = (int8)GetRegRawInt(playout->I5);
- values[5] = (int8)GetRegRawInt(playout->I6);
- values[6] = (int8)GetRegRawInt(playout->I7);
- values[7] = (int8)GetRegRawInt(playout->I8);
- values[8] = (int8)GetRegRawInt(playout->I9);
- values[9] = (int8)GetRegRawInt(playout->I10);
- values[10] = (int8)GetRegRawInt(playout->I11);
- values[11] = (int8)GetRegRawInt(playout->I12);
- values[12] = (int8)GetRegRawInt(playout->I13);
- values[13] = (int8)GetRegRawInt(playout->I14);
- values[14] = (int8)GetRegRawInt(playout->I15);
- values[15] = (int8)GetRegRawInt(playout->I16);
- AsmJsSIMDValue result = SIMDInt8x16Operation::OpInt8x16(values);
- SetRegRawSimd(playout->I16_0, result);
- }
- template <class T>
- void InterpreterStackFrame::OP_SimdUint16x8(const unaligned T* playout)
- {
- uint16 values[8];
- values[0] = (uint16) GetRegRawInt(playout->I1);
- values[1] = (uint16) GetRegRawInt(playout->I2);
- values[2] = (uint16) GetRegRawInt(playout->I3);
- values[3] = (uint16) GetRegRawInt(playout->I4);
- values[4] = (uint16) GetRegRawInt(playout->I5);
- values[5] = (uint16) GetRegRawInt(playout->I6);
- values[6] = (uint16) GetRegRawInt(playout->I7);
- values[7] = (uint16) GetRegRawInt(playout->I8);
- AsmJsSIMDValue result = SIMDUint16x8Operation::OpUint16x8(values);
- SetRegRawSimd(playout->U8_0, result);
- }
- template <class T>
- void InterpreterStackFrame::OP_SimdUint8x16(const unaligned T* playout)
- {
- uint8 values[16];
- values[0] = (uint8) GetRegRawInt(playout->I1);
- values[1] = (uint8) GetRegRawInt(playout->I2);
- values[2] = (uint8) GetRegRawInt(playout->I3);
- values[3] = (uint8) GetRegRawInt(playout->I4);
- values[4] = (uint8) GetRegRawInt(playout->I5);
- values[5] = (uint8) GetRegRawInt(playout->I6);
- values[6] = (uint8) GetRegRawInt(playout->I7);
- values[7] = (uint8) GetRegRawInt(playout->I8);
- values[8] = (uint8) GetRegRawInt(playout->I9);
- values[9] = (uint8) GetRegRawInt(playout->I10);
- values[10] = (uint8) GetRegRawInt(playout->I11);
- values[11] = (uint8) GetRegRawInt(playout->I12);
- values[12] = (uint8) GetRegRawInt(playout->I13);
- values[13] = (uint8) GetRegRawInt(playout->I14);
- values[14] = (uint8) GetRegRawInt(playout->I15);
- values[15] = (uint8) GetRegRawInt(playout->I16);
- AsmJsSIMDValue result = SIMDUint8x16Operation::OpUint8x16(values);
- SetRegRawSimd(playout->U16_0, result);
- }
- // Bool constructors
- template <class T>
- void InterpreterStackFrame::OP_SimdBool32x4(const unaligned T* playout)
- {
- bool arg1 = GetRegRawInt(playout->I1) ? true : false;
- bool arg2 = GetRegRawInt(playout->I2) ? true : false;
- bool arg3 = GetRegRawInt(playout->I3) ? true : false;
- bool arg4 = GetRegRawInt(playout->I4) ? true : false;
- AsmJsSIMDValue result = SIMDBool32x4Operation::OpBool32x4(arg1, arg2, arg3, arg4);
- SetRegRawSimd(playout->B4_0, result);
- }
- template <class T>
- void InterpreterStackFrame::OP_SimdBool16x8(const unaligned T* playout)
- {
- bool values[8];
- values[0] = GetRegRawInt(playout->I1) ? true : false;
- values[1] = GetRegRawInt(playout->I2) ? true : false;
- values[2] = GetRegRawInt(playout->I3) ? true : false;
- values[3] = GetRegRawInt(playout->I4) ? true : false;
- values[4] = GetRegRawInt(playout->I5) ? true : false;
- values[5] = GetRegRawInt(playout->I6) ? true : false;
- values[6] = GetRegRawInt(playout->I7) ? true : false;
- values[7] = GetRegRawInt(playout->I8) ? true : false;
- AsmJsSIMDValue result = SIMDBool16x8Operation::OpBool16x8(values);
- SetRegRawSimd(playout->B8_0, result);
- }
- template <class T>
- void InterpreterStackFrame::OP_SimdBool8x16(const unaligned T* playout)
- {
- bool values[16];
- values[0] = GetRegRawInt(playout->I1) ? true : false;
- values[1] = GetRegRawInt(playout->I2) ? true : false;
- values[2] = GetRegRawInt(playout->I3) ? true : false;
- values[3] = GetRegRawInt(playout->I4) ? true : false;
- values[4] = GetRegRawInt(playout->I5) ? true : false;
- values[5] = GetRegRawInt(playout->I6) ? true : false;
- values[6] = GetRegRawInt(playout->I7) ? true : false;
- values[7] = GetRegRawInt(playout->I8) ? true : false;
- values[8] = GetRegRawInt(playout->I9) ? true : false;
- values[9] = GetRegRawInt(playout->I10) ? true : false;
- values[10] = GetRegRawInt(playout->I11) ? true : false;
- values[11] = GetRegRawInt(playout->I12) ? true : false;
- values[12] = GetRegRawInt(playout->I13) ? true : false;
- values[13] = GetRegRawInt(playout->I14) ? true : false;
- values[14] = GetRegRawInt(playout->I15) ? true : false;
- values[15] = GetRegRawInt(playout->I16) ? true : false;
- AsmJsSIMDValue result = SIMDBool8x16Operation::OpBool8x16(values);
- SetRegRawSimd(playout->B16_0, result);
- }
- Var InterpreterStackFrame::GetNonVarReg(RegSlot localRegisterID) const
- {
- return m_localSlots[localRegisterID];
- }
- void InterpreterStackFrame::SetNonVarReg(RegSlot localRegisterID, Var aValue)
- {
- m_localSlots[localRegisterID] = aValue;
- }
- Var InterpreterStackFrame::GetRootObject() const
- {
- Var rootObject = GetReg(Js::FunctionBody::RootObjectRegSlot);
- Assert(rootObject == this->GetFunctionBody()->LoadRootObject());
- return rootObject;
- }
- Var InterpreterStackFrame::OP_ArgIn0()
- {
- return m_inParams[0];
- }
- #if ENABLE_PROFILE_INFO
- template <class T>
- void InterpreterStackFrame::OP_ProfiledArgOut_A(const unaligned T * playout)
- {
- FunctionBody* functionBody = this->m_functionBody;
- DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
- Assert(playout->Reg > FunctionBody::FirstRegSlot && playout->Reg < functionBody->GetConstantCount());
- Var value = GetReg(playout->Reg);
- if (value != nullptr && TaggedInt::Is(value))
- {
- dynamicProfileInfo->RecordConstParameterAtCallSite(playout->profileId, playout->Arg);
- }
- SetOut(playout->Arg, GetReg(playout->Reg));
- }
- #endif
- template <class T>
- void InterpreterStackFrame::OP_ArgOut_A(const unaligned T * playout)
- {
- SetOut(playout->Arg, GetReg(playout->Reg));
- }
- #if DBG
- template <class T>
- void InterpreterStackFrame::OP_ArgOut_ANonVar(const unaligned T * playout)
- {
- SetOut(playout->Arg, GetNonVarReg(playout->Reg));
- }
- #endif
- template <class T>
- void InterpreterStackFrame::OP_ArgOut_Env(const unaligned T * playout)
- {
- Var argEnv;
- if (this->m_functionBody->GetLocalFrameDisplayRegister() != Constants::NoRegister)
- {
- argEnv = this->GetLocalFrameDisplay();
- }
- else
- {
- argEnv = this->LdEnv();
- }
- SetOut(playout->Arg, argEnv);
- }
- BOOL InterpreterStackFrame::OP_BrFalse_A(Var aValue, ScriptContext* scriptContext)
- {
- return !JavascriptConversion::ToBoolean(aValue, scriptContext);
- }
- BOOL InterpreterStackFrame::OP_BrTrue_A(Var aValue, ScriptContext* scriptContext)
- {
- return JavascriptConversion::ToBoolean(aValue, scriptContext);
- }
- BOOL InterpreterStackFrame::OP_BrNotNull_A(Var aValue)
- {
- return aValue != NULL;
- }
- BOOL InterpreterStackFrame::OP_BrUndecl_A(Var aValue)
- {
- return this->scriptContext->GetLibrary()->IsUndeclBlockVar(aValue);
- }
- BOOL InterpreterStackFrame::OP_BrNotUndecl_A(Var aValue)
- {
- return !this->scriptContext->GetLibrary()->IsUndeclBlockVar(aValue);
- }
- BOOL InterpreterStackFrame::OP_BrOnHasProperty(Var argInstance, uint propertyIdIndex, ScriptContext* scriptContext)
- {
- return JavascriptOperators::OP_HasProperty(argInstance,
- this->m_functionBody->GetReferencedPropertyId(propertyIdIndex), scriptContext);
- }
- BOOL InterpreterStackFrame::OP_BrOnNoProperty(Var argInstance, uint propertyIdIndex, ScriptContext* scriptContext)
- {
- return !JavascriptOperators::OP_HasProperty(argInstance,
- this->m_functionBody->GetReferencedPropertyId(propertyIdIndex), scriptContext);
- }
- BOOL InterpreterStackFrame::OP_BrOnNoEnvProperty(Var envInstance, int32 slotIndex, uint propertyIdIndex, ScriptContext* scriptContext)
- {
- Var instance = OP_LdFrameDisplaySlot(envInstance, slotIndex);
- return !JavascriptOperators::OP_HasProperty(instance,
- this->m_functionBody->GetReferencedPropertyId(propertyIdIndex), scriptContext);
- }
- BOOL InterpreterStackFrame::OP_BrOnClassConstructor(Var aValue)
- {
- return JavascriptOperators::IsClassConstructor(aValue);
- }
- template<class T>
- void InterpreterStackFrame::OP_LdLen(const unaligned T * const playout)
- {
- Assert(playout);
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- const auto instance = GetReg(playout->R1);
- Var length = JavascriptOperators::OP_GetLength(instance, GetScriptContext());
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- SetReg(playout->R0, length);
- }
- #if ENABLE_PROFILE_INFO
- template<class T>
- void InterpreterStackFrame::OP_ProfiledLdLen(const unaligned OpLayoutDynamicProfile<T> *const playout)
- {
- Assert(playout);
- const auto functionBody = m_functionBody;
- const auto profileData = functionBody->GetDynamicProfileInfo();
- const auto instance = GetReg(playout->R1);
- LdElemInfo ldElemInfo;
- ldElemInfo.arrayType = ValueType::Uninitialized.Merge(instance);
- ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
- ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
- threadContext->ClearImplicitCallFlags();
- Var length = JavascriptOperators::OP_GetLength(instance, GetScriptContext());
- threadContext->CheckAndResetImplicitCallAccessorFlag();
- threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
- ldElemInfo.elemType = ldElemInfo.elemType.Merge(length);
- profileData->RecordElementLoad(functionBody, playout->profileId, ldElemInfo);
- SetReg(playout->R0, length);
- }
- #endif
- Var InterpreterStackFrame::GetFunctionExpression()
- {
- // Make sure we get the boxed function object if is there, (or the function itself)
- return StackScriptFunction::GetCurrentFunctionObject(this->function->GetRealFunctionObject());
- }
- template <class T>
- void InterpreterStackFrame::OP_LdFunctionExpression(const unaligned T * playout)
- {
- SetRegAllowStackVar(playout->R0, this->GetFunctionExpression());
- }
- template <class T>
- void InterpreterStackFrame::OP_StFunctionExpression(const unaligned T * playout)
- {
- OP_StFunctionExpression(GetReg(playout->Instance), GetReg(playout->Value), playout->PropertyIdIndex);
- }
- template <class T>
- void InterpreterStackFrame::OP_StLocalFunctionExpression(const unaligned T * playout)
- {
- OP_StFunctionExpression(this->localClosure, GetReg(playout->Instance), playout->PropertyIdIndex);
- }
- void InterpreterStackFrame::OP_StFunctionExpression(Var instance, Var value, PropertyIdIndexType index)
- {
- JavascriptOperators::OP_StFunctionExpression(instance,
- this->m_functionBody->GetReferencedPropertyId(index), value);
- }
- template <class T>
- void InterpreterStackFrame::OP_LdNewTarget(const unaligned T* playout)
- {
- if (this->m_callFlags & CallFlags_NewTarget)
- {
- SetRegAllowStackVar(playout->R0, (Js::RecyclableObject*)this->m_inParams[this->m_inSlotsCount]);
- }
- else if (this->m_callFlags & CallFlags_New)
- {
- SetRegAllowStackVar(playout->R0, this->GetFunctionExpression());
- }
- else
- {
- SetReg(playout->R0, this->GetScriptContext()->GetLibrary()->GetUndefined());
- }
- }
- Var InterpreterStackFrame::OP_Ld_A(Var aValue)
- {
- return aValue;
- }
- Var InterpreterStackFrame::LdEnv() const
- {
- return this->function->GetEnvironment();
- }
- void InterpreterStackFrame::SetEnv(FrameDisplay *frameDisplay)
- {
- this->function->SetEnvironment(frameDisplay);
- }
- Var InterpreterStackFrame::OP_LdLocalObj()
- {
- if (!VirtualTableInfo<ActivationObject>::HasVirtualTable(this->localClosure) &&
- !VirtualTableInfo<ActivationObjectEx>::HasVirtualTable(this->localClosure))
- {
- Js::Throw::FatalInternalError();
- }
- return this->localClosure;
- }
- #ifdef ASMJS_PLAT
- template <typename ArrayType, typename RegType>
- void InterpreterStackFrame::OP_StArr(uint32 index, RegSlot regSlot)
- {
- CompileAssert(Js::ArrayBufferView::TYPE_COUNT == (sizeof(InterpreterStackFrame::StArrFunc) / sizeof(InterpreterStackFrame::ArrFunc)));
- JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
- if (index < arr->GetByteLength())
- {
- BYTE* buffer = arr->GetBuffer();
- *(ArrayType*)(buffer + index) = (ArrayType)GetRegRaw<RegType>(regSlot);
- }
- }
- #endif
- template<> inline double InterpreterStackFrame::GetArrayViewOverflowVal()
- {
- return *(double*)&NumberConstants::k_Nan;
- }
- template<> inline float InterpreterStackFrame::GetArrayViewOverflowVal()
- {
- return (float)*(double*)&NumberConstants::k_Nan;
- }
- template<typename T> T InterpreterStackFrame::GetArrayViewOverflowVal()
- {
- return 0;
- }
- template <class T>
- void InterpreterStackFrame::OP_LdArrFunc(const unaligned T* playout)
- {
- Var* arr = (Var*)GetNonVarReg(playout->Instance);
- const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex);
- m_localSlots[playout->Value] = arr[index];
- }
- template <class T>
- void InterpreterStackFrame::OP_LdArrWasmFunc(const unaligned T* playout)
- {
- #ifdef ENABLE_WASM
- WebAssemblyTable * table = WebAssemblyTable::FromVar(GetNonVarReg(playout->Instance));
- const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex);
- if (index >= table->GetCurrentLength())
- {
- JavascriptError::ThrowWebAssemblyRuntimeError(GetScriptContext(), WASMERR_TableIndexOutOfRange);
- }
- Var func = table->DirectGetValue(index);
- if (!func)
- {
- JavascriptError::ThrowWebAssemblyRuntimeError(GetScriptContext(), WASMERR_NeedWebAssemblyFunc);
- }
- m_localSlots[playout->Value] = func;
- #endif
- }
- template <class T>
- void InterpreterStackFrame::OP_CheckSignature(const unaligned T* playout)
- {
- #ifdef ENABLE_WASM
- ScriptFunction * func = ScriptFunction::FromVar(GetNonVarReg(playout->R0));
- int sigIndex = playout->C1;
- Wasm::WasmSignature * expected = &m_signatures[sigIndex];
- if (func->GetFunctionInfo()->IsDeferredParseFunction())
- {
- // TODO: should be able to assert this once imports are converted to wasm functions
- JavascriptError::ThrowWebAssemblyRuntimeError(GetScriptContext(), WASMERR_NeedWebAssemblyFunc);
- }
- AsmJsFunctionInfo * asmInfo = func->GetFunctionBody()->GetAsmJsFunctionInfo();
- if (!asmInfo)
- {
- // TODO: should be able to assert this once imports are converted to wasm functions
- JavascriptError::ThrowWebAssemblyRuntimeError(GetScriptContext(), WASMERR_NeedWebAssemblyFunc);
- }
- if (!expected->IsEquivalent(asmInfo->GetWasmSignature()))
- {
- JavascriptError::ThrowWebAssemblyRuntimeError(GetScriptContext(), WASMERR_SignatureMismatch);
- }
- #endif
- }
- #ifdef ASMJS_PLAT
- template <typename ArrayType, typename RegType>
- void InterpreterStackFrame::OP_LdArr(uint32 index, RegSlot regSlot)
- {
- CompileAssert(Js::ArrayBufferView::TYPE_COUNT == (sizeof(InterpreterStackFrame::LdArrFunc) / sizeof(InterpreterStackFrame::ArrFunc)));
- JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
- BYTE* buffer = arr->GetBuffer();
- ArrayType val = index < (arr->GetByteLength()) ? *(ArrayType*)(buffer + index) : GetArrayViewOverflowVal<ArrayType>();
- SetRegRaw<RegType>(regSlot, (RegType)val);
- }
- #endif
- template <class T, typename T2>
- void InterpreterStackFrame::OP_StSlotPrimitive(const unaligned T* playout)
- {
- T2* buffer = (T2*)GetNonVarReg(playout->Instance);
- buffer[playout->SlotIndex] = GetRegRaw<T2>(playout->Value);
- }
- template <class T>
- Var InterpreterStackFrame::OP_LdAsmJsSlot(Var instance, const unaligned T* playout)
- {
- return ((Var*)instance)[playout->SlotIndex];
- }
- template <class T, typename T2>
- void InterpreterStackFrame::OP_LdSlotPrimitive(const unaligned T* playout)
- {
- T2* buffer = (T2*)GetNonVarReg(playout->Instance);
- SetRegRaw<T2>(playout->Value, buffer[playout->SlotIndex]);
- }
- #ifndef TEMP_DISABLE_ASMJS
- template <class T>
- void InterpreterStackFrame::OP_LdArrGeneric(const unaligned T* playout)
- {
- Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
- const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex) & ArrayBufferView::ViewMask[playout->ViewType];
- (this->*LdArrFunc[playout->ViewType])(index, playout->Value);
- }
- template <class T>
- void InterpreterStackFrame::OP_LdArrWasm(const unaligned T* playout)
- {
- Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
- const uint64 index = (uint64)GetRegRawInt64(playout->SlotIndex);
- JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
- if (index + TypeToSizeMap[playout->ViewType] > arr->GetByteLength())
- {
- JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, WASMERR_ArrayIndexOutOfRange);
- }
- BYTE* buffer = arr->GetBuffer();
- switch (playout->ViewType)
- {
- case ArrayBufferView::ViewType::TYPE_INT8: SetRegRaw<int32>(playout->Value, (int32)*(int8*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_UINT8 : SetRegRaw<int32>(playout->Value, (int32)*(uint8*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_INT16 : SetRegRaw<int32>(playout->Value, (int32)*(int16*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_UINT16 : SetRegRaw<int32>(playout->Value, (int32)*(uint16*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_INT32 : SetRegRaw<int32>(playout->Value, (int32)*(int32*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_UINT32 : SetRegRaw<int32>(playout->Value, (int32)*(uint32*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_FLOAT32 : SetRegRaw<float>(playout->Value, (float)*(float*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_FLOAT64 : SetRegRaw<double>(playout->Value, (double)*(double*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(int64*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_INT8_TO_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(int8*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_UINT8_TO_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(uint8*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_INT16_TO_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(int16*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_UINT16_TO_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(uint16*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_INT32_TO_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(int32*)(buffer + index)); return;
- case ArrayBufferView::ViewType::TYPE_UINT32_TO_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(uint32*)(buffer + index)); return;
- default:Assert(UNREACHED);
- }
- }
- template <class T>
- void InterpreterStackFrame::OP_LdArrConstIndex(const unaligned T* playout)
- {
- const uint32 index = playout->SlotIndex;
- Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
- (this->*LdArrFunc[playout->ViewType])(index, playout->Value);
- }
- template <class T>
- void InterpreterStackFrame::OP_StArrGeneric(const unaligned T* playout)
- {
- Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
- const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex) & ArrayBufferView::ViewMask[playout->ViewType];
- (this->*StArrFunc[playout->ViewType])(index, playout->Value);
- }
- template <class T>
- void InterpreterStackFrame::OP_StArrWasm(const unaligned T* playout)
- {
- Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
- const uint64 index = (uint64)GetRegRawInt64(playout->SlotIndex);
- JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
- if (index + TypeToSizeMap[playout->ViewType] > arr->GetByteLength())
- {
- JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, WASMERR_ArrayIndexOutOfRange);
- }
- BYTE* buffer = arr->GetBuffer();
- switch (playout->ViewType)
- {
- case ArrayBufferView::ViewType::TYPE_INT8: *(int8*)(buffer + index) = (int8) (GetRegRaw<int32>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_UINT8: *(uint8*)(buffer + index) = (uint8) (GetRegRaw<int32>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_INT16: *(int16*)(buffer + index) = (int16) (GetRegRaw<int32>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_UINT16: *(uint16*)(buffer + index) = (uint16) (GetRegRaw<int32>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_INT32: *(int32*)(buffer + index) = (int32) (GetRegRaw<int32>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_UINT32: *(uint32*)(buffer + index) = (uint32) (GetRegRaw<int32>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_FLOAT32: *(float*)(buffer + index) = (float) (GetRegRaw<float>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_FLOAT64: *(double*)(buffer + index) = (double) (GetRegRaw<double>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_INT64: *(int64*)(buffer + index) = (int64) (GetRegRaw<int64>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_INT8_TO_INT64: *(int8*)(buffer + index) = (int8) (GetRegRaw<int64>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_UINT8_TO_INT64: *(uint8*)(buffer + index) = (uint8) (GetRegRaw<int64>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_INT16_TO_INT64: *(int16*)(buffer + index) = (int16) (GetRegRaw<int64>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_UINT16_TO_INT64: *(uint16*)(buffer + index) = (uint16) (GetRegRaw<int64>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_INT32_TO_INT64: *(int32*)(buffer + index) = (int32) (GetRegRaw<int64>(playout->Value)); return;
- case ArrayBufferView::ViewType::TYPE_UINT32_TO_INT64: *(uint32*)(buffer + index) = (uint32) (GetRegRaw<int64>(playout->Value)); return;
- default:Assert(UNREACHED);
- }
- }
- template <class T>
- void InterpreterStackFrame::OP_StArrConstIndex(const unaligned T* playout)
- {
- const uint32 index = playout->SlotIndex;
- Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
- (this->*StArrFunc[playout->ViewType])(index, playout->Value);
- }
- #endif
- Var InterpreterStackFrame::OP_LdSlot(Var instance, int32 slotIndex)
- {
- if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
- {
- if ((uintptr_t)((Var*)instance)[ScopeSlots::EncodedSlotCountSlotIndex] <= (uintptr_t)(slotIndex - ScopeSlots::FirstSlotIndex))
- {
- Js::Throw::FatalInternalError();
- }
- }
- return ((Var*)(instance))[slotIndex];
- }
- template <class T>
- Var InterpreterStackFrame::OP_LdSlot(Var instance, const unaligned T* playout)
- {
- return OP_LdSlot(instance, playout->SlotIndex);
- }
- #if ENABLE_PROFILE_INFO
- template <class T>
- Var InterpreterStackFrame::OP_ProfiledLdSlot(Var instance, const unaligned T* playout)
- {
- Var value = OP_LdSlot(instance, playout->SlotIndex);
- ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
- return value;
- }
- #endif
- template <class T>
- Var InterpreterStackFrame::OP_LdInnerSlot(Var slotArray, const unaligned T* playout)
- {
- return OP_LdSlot(slotArray, playout->SlotIndex2);
- }
- #if ENABLE_PROFILE_INFO
- template <class T>
- Var InterpreterStackFrame::OP_ProfiledLdInnerSlot(Var slotArray, const unaligned T* playout)
- {
- Var value = OP_LdInnerSlot(slotArray, playout);
- ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
- return value;
- }
- #endif
- template <class T>
- Var InterpreterStackFrame::OP_LdInnerObjSlot(Var slotArray, const unaligned T* playout)
- {
- return OP_LdObjSlot(slotArray, playout->SlotIndex2);
- }
- #if ENABLE_PROFILE_INFO
- template <class T>
- Var InterpreterStackFrame::OP_ProfiledLdInnerObjSlot(Var slotArray, const unaligned T* playout)
- {
- Var value = OP_LdInnerObjSlot(slotArray, playout);
- ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
- return value;
- }
- #endif
- Var InterpreterStackFrame::OP_LdFrameDisplaySlot(Var instance, int32 slotIndex)
- {
- if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
- {
- if (((FrameDisplay*)instance)->GetLength() < slotIndex - Js::FrameDisplay::GetOffsetOfScopes()/sizeof(Var))
- {
- Js::Throw::FatalInternalError();
- }
- }
- return ((Var*)instance)[slotIndex];
- }
- template <class T>
- Var InterpreterStackFrame::OP_LdEnvObj(Var instance, const unaligned T* playout)
- {
- return OP_LdFrameDisplaySlot(instance, playout->SlotIndex);
- }
- template <class T>
- Var InterpreterStackFrame::OP_LdEnvSlot(Var instance, const unaligned T* playout)
- {
- Var slotArray = OP_LdFrameDisplaySlot(instance, playout->SlotIndex1);
- return OP_LdSlot(slotArray, playout->SlotIndex2);
- }
- #if ENABLE_PROFILE_INFO
- template <class T>
- Var InterpreterStackFrame::OP_ProfiledLdEnvSlot(Var instance, const unaligned T* playout)
- {
- Var value = OP_LdEnvSlot(instance, playout);
- ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
- return value;
- }
- #endif
- Var InterpreterStackFrame::OP_LdObjSlot(Var instance, int32 slotIndex)
- {
- Var *slotArray = *(Var**)((char*)instance + DynamicObject::GetOffsetOfAuxSlots());
- return slotArray[slotIndex];
- }
- template <class T>
- Var InterpreterStackFrame::OP_LdObjSlot(Var instance, const unaligned T* playout)
- {
- return OP_LdObjSlot(instance, playout->SlotIndex);
- }
- #if ENABLE_PROFILE_INFO
- template <class T>
- Var InterpreterStackFrame::OP_ProfiledLdObjSlot(Var instance, const unaligned T* playout)
- {
- Var value = OP_LdObjSlot(instance, playout->SlotIndex);
- ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
- return value;
- }
- #endif
- template <class T>
- Var InterpreterStackFrame::OP_LdEnvObjSlot(Var instance, const unaligned T* playout)
- {
- Var slotArray = OP_LdFrameDisplaySlot(instance, playout->SlotIndex1);
- return OP_LdObjSlot(slotArray, playout->SlotIndex2);
- }
- template <class T>
- Var InterpreterStackFrame::OP_LdModuleSlot(Var instance, const unaligned T* playout)
- {
- return JavascriptOperators::OP_LdModuleSlot(playout->SlotIndex1, playout->SlotIndex2, scriptContext);
- }
- inline void InterpreterStackFrame::OP_StModuleSlot(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
- {
- JavascriptOperators::OP_StModuleSlot(slotIndex1, slotIndex2, value, scriptContext);
- }
- #if ENABLE_PROFILE_INFO
- template <class T>
- Var InterpreterStackFrame::OP_ProfiledLdEnvObjSlot(Var instance, const unaligned T* playout)
- {
- Var value = OP_LdEnvObjSlot(instance, playout);
- ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
- return value;
- }
- #endif
- void InterpreterStackFrame::OP_StSlot(Var instance, int32 slotIndex, Var value)
- {
- // We emit OpCode::StSlot in the bytecode only for scope slot arrays, which are not recyclable objects.
- if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
- {
- if ((uintptr_t)((Var*)instance)[ScopeSlots::EncodedSlotCountSlotIndex] <= (uintptr_t)(slotIndex - ScopeSlots::FirstSlotIndex))
- {
- Js::Throw::FatalInternalError();
- }
- }
- ((Var*)(instance))[slotIndex] = value;
- }
- void InterpreterStackFrame::OP_StEnvSlot(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
- {
- Var slotArray = (Var*)OP_LdFrameDisplaySlot(instance, slotIndex1);
- OP_StSlot(slotArray, slotIndex2, value);
- }
- void InterpreterStackFrame::OP_StSlotChkUndecl(Var instance, int32 slotIndex, Var value)
- {
- // We emit OpCode::StSlot in the bytecode only for scope slot arrays, which are not recyclable objects.
- if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
- {
- if ((uintptr_t)((Var*)instance)[ScopeSlots::EncodedSlotCountSlotIndex] <= (uintptr_t)(slotIndex - ScopeSlots::FirstSlotIndex))
- {
- Js::Throw::FatalInternalError();
- }
- }
- OP_ChkUndecl(((Var*)instance)[slotIndex]);
- ((Var*)(instance))[slotIndex] = value;
- }
- void InterpreterStackFrame::OP_StEnvSlotChkUndecl(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
- {
- Var slotArray = (Var*)OP_LdFrameDisplaySlot(instance, slotIndex1);
- OP_StSlotChkUndecl(slotArray, slotIndex2, value);
- }
- void InterpreterStackFrame::OP_StObjSlot(Var instance, int32 slotIndex, Var value)
- {
- // It would be nice to assert that it's ok to store directly to slot, but we don't have the propertyId.
- Var *slotArray = *(Var**)((char*)instance + DynamicObject::GetOffsetOfAuxSlots());
- slotArray[slotIndex] = value;
- }
- void InterpreterStackFrame::OP_StObjSlotChkUndecl(Var instance, int32 slotIndex, Var value)
- {
- // It would be nice to assert that it's ok to store directly to slot, but we don't have the propertyId.
- Var *slotArray = *(Var**)((char*)instance + DynamicObject::GetOffsetOfAuxSlots());
- OP_ChkUndecl(slotArray[slotIndex]);
- slotArray[slotIndex] = value;
- }
- void InterpreterStackFrame::OP_StEnvObjSlot(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
- {
- // It would be nice to assert that it's ok to store directly to slot, but we don't have the propertyId.
- Var envInstance = (Var*)OP_LdFrameDisplaySlot(instance, slotIndex1);
- OP_StObjSlot(envInstance, slotIndex2, value);
- }
- void InterpreterStackFrame::OP_StEnvObjSlotChkUndecl(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
- {
- // It would be nice to assert that it's ok to store directly to slot, but we don't have the propertyId.
- Var envInstance = (Var*)OP_LdFrameDisplaySlot(instance, slotIndex1);
- OP_StObjSlotChkUndecl(envInstance, slotIndex2, value);
- }
- Var InterpreterStackFrame::OP_LdStackArgPtr(void)
- {
- // Return the address of the first param after "this".
- return m_inParams + 1;
- }
- ForInObjectEnumerator * InterpreterStackFrame::GetForInEnumerator(uint forInLoopLevel)
- {
- Assert(forInLoopLevel < this->m_functionBody->GetForInLoopDepth());
- return &this->forInObjectEnumerators[forInLoopLevel];
- }
- void InterpreterStackFrame::OP_InitForInEnumerator(Var object, uint forInLoopLevel)
- {
- JavascriptOperators::OP_InitForInEnumerator(object, GetForInEnumerator(forInLoopLevel), this->GetScriptContext());
- }
- void InterpreterStackFrame::OP_InitForInEnumeratorWithCache(Var object, uint forInLoopLevel, ProfileId profileId)
- {
- JavascriptOperators::OP_InitForInEnumerator(object, GetForInEnumerator(forInLoopLevel), this->GetScriptContext(),
- m_functionBody->GetForInCache(profileId));
- }
- // Called for the debug purpose, to create the arguments object explicitly even though script has not declared it.
- Var InterpreterStackFrame::CreateHeapArguments(ScriptContext* scriptContext)
- {
- return JavascriptOperators::LoadHeapArguments(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, &this->m_inParams[1], scriptContext->GetLibrary()->GetNull(), (PropertyId*)scriptContext->GetLibrary()->GetNull(), scriptContext, false);
- }
- template <bool letArgs>
- Var InterpreterStackFrame::LdHeapArgumentsImpl(Var argsArray, ScriptContext* scriptContext)
- {
- Var frameObj;
- if (m_functionBody->HasScopeObject() && argsArray != scriptContext->GetLibrary()->GetNull())
- {
- frameObj = this->localClosure;
- Assert(frameObj);
- }
- else
- {
- frameObj = scriptContext->GetLibrary()->GetNull();
- }
- Var args = JavascriptOperators::LoadHeapArguments(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, &this->m_inParams[1], frameObj, (PropertyId*)argsArray, scriptContext, letArgs);
- this->m_arguments = args;
- return args;
- }
- Var InterpreterStackFrame::OP_LdHeapArguments(ScriptContext* scriptContext)
- {
- Var argsArray = m_functionBody->GetFormalsPropIdArrayOrNullObj();
- return LdHeapArgumentsImpl<false>(argsArray, scriptContext);
- }
- Var InterpreterStackFrame::OP_LdLetHeapArguments(ScriptContext* scriptContext)
- {
- Var argsArray = m_functionBody->GetFormalsPropIdArrayOrNullObj();
- return LdHeapArgumentsImpl<true>(argsArray, scriptContext);
- }
- Var InterpreterStackFrame::OP_LdHeapArgsCached(ScriptContext* scriptContext)
- {
- uint32 formalsCount = this->m_functionBody->GetInParamsCount() - 1;
- Var args = JavascriptOperators::LoadHeapArgsCached(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, formalsCount, &this->m_inParams[1], this->localClosure, scriptContext, false);
- this->m_arguments = args;
- return args;
- }
- Var InterpreterStackFrame::OP_LdLetHeapArgsCached(ScriptContext* scriptContext)
- {
- uint32 formalsCount = this->m_functionBody->GetInParamsCount() - 1;
- Var args = JavascriptOperators::LoadHeapArgsCached(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, formalsCount, &this->m_inParams[1], this->localClosure, scriptContext, true);
- this->m_arguments = args;
- return args;
- }
- HeapArgumentsObject * InterpreterStackFrame::CreateEmptyHeapArgumentsObject(ScriptContext* scriptContext)
- {
- HeapArgumentsObject * args = JavascriptOperators::CreateHeapArguments(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, 0, nullptr, scriptContext);
- this->m_arguments = args;
- return args;
- }
- void InterpreterStackFrame::TrySetFrameObjectInHeapArgObj(ScriptContext * scriptContext, bool hasNonSimpleParams, bool isScopeObjRestored)
- {
- ActivationObject * frameObject = nullptr;
- uint32 formalsCount = this->m_functionBody->GetInParamsCount() - 1;
- Js::PropertyIdArray * propIds = nullptr;
- Js::HeapArgumentsObject* heapArgObj = nullptr;
- //We always set the Frame object to nullptr in BailOutRecord::EnsureArguments for stack args optimization.
- if (m_arguments != nullptr && ((Js::HeapArgumentsObject*)(m_arguments))->GetFrameObject() == nullptr)
- {
- heapArgObj = (Js::HeapArgumentsObject*)m_arguments;
- }
- bool isCachedScope = false;
- //For Non-simple params, we don't have a scope object created.
- if (this->m_functionBody->NeedScopeObjectForArguments(hasNonSimpleParams))
- {
- frameObject = (ActivationObject*)GetLocalClosure();
- isCachedScope = m_functionBody->HasCachedScopePropIds();
- propIds = this->m_functionBody->GetFormalsPropIdArray();
- if(isScopeObjRestored && ActivationObject::Is(frameObject))
- {
- Assert(this->GetFunctionBody()->GetDoScopeObjectCreation());
- isCachedScope = true;
- if (PHASE_VERBOSE_TRACE1(Js::StackArgFormalsOptPhase) && m_functionBody->GetInParamsCount() > 1)
- {
- Output::Print(_u("StackArgFormals : %s (%d) :Using the restored scope object in the bail out path. \n"), m_functionBody->GetDisplayName(), m_functionBody->GetFunctionNumber());
- Output::Flush();
- }
- }
- else
- {
- if (isCachedScope)
- {
- Js::DynamicType *literalType = nullptr;
- Assert(!propIds->hasNonSimpleParams && !hasNonSimpleParams);
- frameObject = (ActivationObject*)JavascriptOperators::OP_InitCachedScope(this->GetJavascriptFunction(), propIds, &literalType, hasNonSimpleParams, scriptContext);
- }
- else
- {
- frameObject = (ActivationObject*)JavascriptOperators::OP_NewScopeObject(GetScriptContext());
- }
- Assert(propIds != nullptr);
- SetLocalClosure(frameObject);
- if (PHASE_VERBOSE_TRACE1(Js::StackArgFormalsOptPhase) && m_functionBody->GetInParamsCount() > 1)
- {
- Output::Print(_u("StackArgFormals : %s (%d) :Creating scope object in the bail out path. \n"), m_functionBody->GetDisplayName(), m_functionBody->GetFunctionNumber());
- Output::Flush();
- }
- }
- }
- else
- {
- //We reached here because, either we don't have any formals or we don't have a scope object (it could be in strict mode or have non-simple param list)
- Assert(formalsCount == 0 || (m_functionBody->GetIsStrictMode() || hasNonSimpleParams));
- frameObject = (ActivationObject*)scriptContext->GetLibrary()->GetNull();
- formalsCount = 0;
- if (PHASE_VERBOSE_TRACE1(Js::StackArgOptPhase))
- {
- Output::Print(_u("StackArgOpt : %s (%d) :Creating NULL scope object in the bail out path. \n"), m_functionBody->GetDisplayName(), m_functionBody->GetFunctionNumber());
- Output::Flush();
- }
- }
- if (heapArgObj)
- {
- heapArgObj->SetFormalCount(formalsCount);
- heapArgObj->SetFrameObject(frameObject);
- if (PHASE_TRACE1(Js::StackArgFormalsOptPhase) && formalsCount > 0)
- {
- Output::Print(_u("StackArgFormals : %s (%d) :Attaching the scope object with the heap arguments object in the bail out path. \n"), m_functionBody->GetDisplayName(), m_functionBody->GetFunctionNumber());
- Output::Flush();
- }
- }
- //Fill the Heap arguments and scope object with values
- // If there is no heap arguments object, then fill only the scope object with actuals.
- JavascriptOperators::FillScopeObject(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, formalsCount, frameObject, &this->m_inParams[1], propIds, heapArgObj, scriptContext, hasNonSimpleParams, isCachedScope);
- }
- Var InterpreterStackFrame::OP_LdArgumentsFromFrame()
- {
- return this->m_arguments;
- }
- void* InterpreterStackFrame::OP_LdArgCnt()
- {
- return (void*)m_inSlotsCount;
- }
- Var InterpreterStackFrame::OP_ResumeYield(Var yieldDataVar, RegSlot yieldStarIterator)
- {
- ResumeYieldData* yieldData = static_cast<ResumeYieldData*>(yieldDataVar);
- RecyclableObject* iterator = yieldStarIterator != Constants::NoRegister ? RecyclableObject::FromVar(GetNonVarReg(yieldStarIterator)) : nullptr;
- return JavascriptOperators::OP_ResumeYield(yieldData, iterator);
- }
- void* InterpreterStackFrame::operator new(size_t byteSize, void* previousAllocation) throw()
- {
- //
- // Placement 'new' is used by InterpreterStackFrame to initialize the C++ object on the RcInterpreter's
- // program stack:
- // - Unlike most other allocations, the previously allocated memory will __not__ be
- // zero-initialized, as we do not want the overhead of zero-initializing the frame when
- // calling functions.
- //
- // NOTE: If we wanted to add C# semantics of all locals are automatically zero-initialized,
- // need to determine the most efficient mechanism for this.
- //
- return previousAllocation;
- }
- void __cdecl InterpreterStackFrame::operator delete(void * allocationToFree, void * previousAllocation) throw()
- {
- AssertMsg(allocationToFree == previousAllocation, "Memory locations should match");
- AssertMsg(false, "This function should never actually be called");
- }
- template void* Js::InterpreterStackFrame::GetReg<unsigned int>(unsigned int) const;
- template void Js::InterpreterStackFrame::SetReg<unsigned int>(unsigned int, void*);
- } // namespace Js
- // Make sure the macro and the layout for the op is consistent
- #define DEF2(x, op, ...) \
- CompileAssert(!Js::OpCodeInfo<Js::OpCode::op>::HasMultiSizeLayout); \
- CompileAssert(!Js::OpCodeInfo<Js::OpCode::op>::IsExtendedOpcode);
- #define DEF3(x, op, ...) DEF2(x, op)
- #define EXDEF2(x, op, ...) \
- CompileAssert(!Js::OpCodeInfo<Js::OpCode::op>::HasMultiSizeLayout); \
- CompileAssert(Js::OpCodeInfo<Js::OpCode::op>::IsExtendedOpcode);
- #define EXDEF3(x, op, ...) EXDEF2(x, op)
- #define DEF2_WMS(x, op, ...) \
- CompileAssert(Js::OpCodeInfo<Js::OpCode::op>::HasMultiSizeLayout); \
- CompileAssert(!Js::OpCodeInfo<Js::OpCode::op>::IsExtendedOpcode);
- #define DEF3_WMS(x, op, ...) DEF2_WMS(x, op)
- #define EXDEF2_WMS(x, op, ...) \
- CompileAssert(Js::OpCodeInfo<Js::OpCode::op>::HasMultiSizeLayout); \
- CompileAssert(Js::OpCodeInfo<Js::OpCode::op>::IsExtendedOpcode);
- #define EXDEF3_WMS(x, op, ...) EXDEF2_WMS(x, op)
- #include "InterpreterHandler.inl"
- // Make sure the macro and the layout for the op is consistent
- #define DEF2(x, op, ...) \
- CompileAssert(!Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::HasMultiSizeLayout); \
- CompileAssert(!Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::IsExtendedOpcode);
- #define DEF3(x, op, ...) DEF2(x, op)
- #define DEF4(x, op, ...) DEF2(x, op)
- #define EXDEF2(x, op, ...) \
- CompileAssert(!Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::HasMultiSizeLayout); \
- CompileAssert(Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::IsExtendedOpcode);
- #define EXDEF3(x, op, ...) EXDEF2(x, op)
- #define EXDEF4(x, op, ...) EXDEF2(x, op)
- #define DEF2_WMS(x, op, ...) \
- CompileAssert(Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::HasMultiSizeLayout); \
- CompileAssert(!Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::IsExtendedOpcode);
- #define DEF3_WMS(x, op, ...) DEF2_WMS(x, op)
- #define DEF4_WMS(x, op, ...) DEF2_WMS(x, op)
- #define EXDEF2_WMS(x, op, ...) \
- CompileAssert(Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::HasMultiSizeLayout); \
- CompileAssert(Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::IsExtendedOpcode);
- #define EXDEF3_WMS(x, op, ...) EXDEF2_WMS(x, op)
- #define EXDEF4_WMS(x, op, ...) EXDEF2_WMS(x, op)
- #include "InterpreterHandlerAsmJs.inl"
|