InterpreterStackFrame.cpp 353 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeLanguagePch.h"
  6. #include "EHBailoutData.h"
  7. #include "Library/JavascriptRegularExpression.h"
  8. #if DBG_DUMP
  9. #include "ByteCode/OpCodeUtilAsmJs.h"
  10. #endif
  11. #include "Language/InterpreterStackFrame.h"
  12. #include "Library/JavascriptGeneratorFunction.h"
  13. #include "Library/ForInObjectEnumerator.h"
  14. ///----------------------------------------------------------------------------
  15. ///
  16. /// macros PROCESS_INtoOUT
  17. ///
  18. /// This set of macros defines standard patterns for processing OpCodes in
  19. /// RcInterpreter::Run(). Each macro is named for "in" - "out":
  20. /// - A: Var
  21. /// - I: Integer
  22. /// - R: Double
  23. /// - X: Nothing
  24. ///
  25. /// Examples:
  26. /// - "A2toA1" reads two registers, each storing an Var, and writes a single
  27. /// register with a new Var.
  28. /// - "A1I1toA2" reads two registers, first an Var and second an Int32, then
  29. /// writes two Var registers.
  30. ///
  31. /// Although these could use lookup tables to standard OpLayout types, this
  32. /// additional indirection would slow the main interpreter loop further by
  33. /// preventing the main 'switch' statement from using the OpCode to become a
  34. /// direct local-function jump.
  35. ///----------------------------------------------------------------------------
  36. #define PROCESS_FALLTHROUGH(name, func) \
  37. case OpCode::name:
  38. #define PROCESS_FALLTHROUGH_COMMON(name, func, suffix) \
  39. case OpCode::name:
  40. #define PROCESS_READ_LAYOUT(name, layout, suffix) \
  41. CompileAssert(OpCodeInfo<OpCode::name>::Layout == OpLayoutType::layout); \
  42. const unaligned OpLayout##layout##suffix * playout = m_reader.layout##suffix(ip); \
  43. Assert((playout != nullptr) == (Js::OpLayoutType::##layout != Js::OpLayoutType::Empty)); // Make sure playout is used
  44. #define PROCESS_NOP_COMMON(name, layout, suffix) \
  45. case OpCode::name: \
  46. { \
  47. PROCESS_READ_LAYOUT(name, layout, suffix); \
  48. break; \
  49. }
  50. #define PROCESS_NOP(name, layout) PROCESS_NOP_COMMON(name, layout,)
  51. #define PROCESS_CUSTOM_COMMON(name, func, layout, suffix) \
  52. case OpCode::name: \
  53. { \
  54. PROCESS_READ_LAYOUT(name, layout, suffix); \
  55. func(playout); \
  56. break; \
  57. }
  58. #define PROCESS_CUSTOM(name, func, layout) PROCESS_CUSTOM_COMMON(name, func, layout,)
  59. #define PROCESS_CUSTOM_L_COMMON(name, func, layout, regslot, suffix) \
  60. case OpCode::name: \
  61. { \
  62. PROCESS_READ_LAYOUT(name, layout, suffix); \
  63. func(playout); \
  64. break; \
  65. }
  66. #define PROCESS_CUSTOM_L(name, func, layout, regslot) PROCESS_CUSTOM_L_COMMON(name, func, layout, regslot,)
  67. #define PROCESS_CUSTOM_L_Arg_COMMON(name, func, suffix) PROCESS_CUSTOM_L_COMMON(name, func, Arg, Arg, suffix)
  68. #define PROCESS_CUSTOM_L_Arg2_COMMON(name, func, layout, suffix) PROCESS_CUSTOM_L_COMMON(name, func, layout, Arg, suffix)
  69. #define PROCESS_CUSTOM_L_Arg(name, func) PROCESS_CUSTOM_L_COMMON(name, func, Arg, Arg,)
  70. #define PROCESS_CUSTOM_ArgNoSrc_COMMON(name, func, suffix) PROCESS_CUSTOM_COMMON(name, func, ArgNoSrc, suffix)
  71. #define PROCESS_CUSTOM_ArgNoSrc(name, func) PROCESS_CUSTOM_COMMON(name, func, ArgNoSrc,)
  72. #define PROCESS_CUSTOM_L_R0_COMMON(name, func, layout, suffix) PROCESS_CUSTOM_L_COMMON(name, func, layout, R0, suffix)
  73. #define PROCESS_CUSTOM_L_R0(name, func, layout) PROCESS_CUSTOM_L_COMMON(name, func, layout, R0,)
  74. #define PROCESS_CUSTOM_L_Value_COMMON(name, func, layout, suffix) PROCESS_CUSTOM_L_COMMON(name, func, layout, Value, suffix)
  75. #define PROCESS_CUSTOM_L_Value(name, func, layout) PROCESS_CUSTOM_L_COMMON(name, func, layout, Value,)
  76. #define PROCESS_TRY(name, func) \
  77. case OpCode::name: \
  78. { \
  79. PROCESS_READ_LAYOUT(name, Br,); \
  80. func(playout); \
  81. ip = m_reader.GetIP(); \
  82. break; \
  83. }
  84. #define PROCESS_EMPTY(name, func) \
  85. case OpCode::name: \
  86. { \
  87. PROCESS_READ_LAYOUT(name, Empty, ); \
  88. func(); \
  89. ip = m_reader.GetIP(); \
  90. break; \
  91. }
  92. #define PROCESS_TRYBR2_COMMON(name, func, suffix) \
  93. case OpCode::name: \
  94. { \
  95. PROCESS_READ_LAYOUT(name, BrReg2, suffix); \
  96. func((const byte*)(playout + 1), playout->RelativeJumpOffset, playout->R1, playout->R2); \
  97. ip = m_reader.GetIP(); \
  98. break; \
  99. }
  100. #define PROCESS_CALL_COMMON(name, func, layout, suffix) \
  101. case OpCode::name: \
  102. { \
  103. PROCESS_READ_LAYOUT(name, layout, suffix); \
  104. func(playout); \
  105. break; \
  106. }
  107. #define PROCESS_CALL(name, func, layout) PROCESS_CALL_COMMON(name, func, layout,)
  108. #define PROCESS_CALL_FLAGS_COMMON(name, func, layout, flags, suffix) \
  109. case OpCode::name: \
  110. { \
  111. PROCESS_READ_LAYOUT(name, layout, suffix); \
  112. func(playout, flags); \
  113. break; \
  114. }
  115. #define PROCESS_CALL_FLAGS(name, func, layout, regslot) PROCESS_CALL_FLAGS_COMMON(name, func, layout, regslot,)
  116. #define PROCESS_CALL_FLAGS_None_COMMON(name, func, layout, suffix) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_None, suffix)
  117. #define PROCESS_CALL_FLAGS_None(name, func, layout) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_None,)
  118. #define PROCESS_CALL_FLAGS_Value_COMMON(name, func, layout, suffix) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_Value, suffix)
  119. #define PROCESS_CALL_FLAGS_Value(name, func, layout) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_Value,)
  120. #define PROCESS_CALL_FLAGS_CallEval_COMMON(name, func, layout, suffix) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_ExtraArg, suffix)
  121. #define PROCESS_CALL_FLAGS_CallEval(name, func, layout) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_ExtraArg,)
  122. #define PROCESS_A1toXX_ALLOW_STACK_COMMON(name, func, suffix) \
  123. case OpCode::name: \
  124. { \
  125. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  126. func(GetRegAllowStackVar(playout->R0)); \
  127. break; \
  128. }
  129. #define PROCESS_A1toXX_COMMON(name, func, suffix) \
  130. case OpCode::name: \
  131. { \
  132. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  133. func(GetReg(playout->R0)); \
  134. break; \
  135. }
  136. #define PROCESS_A1toXX(name, func) PROCESS_A1toXX_COMMON(name, func,)
  137. #define PROCESS_A1toXXMem_COMMON(name, func, suffix) \
  138. case OpCode::name: \
  139. { \
  140. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  141. func(GetReg(playout->R0), GetScriptContext()); \
  142. break; \
  143. }
  144. #define PROCESS_A1toXXMem(name, func) PROCESS_A1toXXMem_COMMON(name, func,)
  145. #define PROCESS_A1toXXMemNonVar_COMMON(name, func, type, suffix) \
  146. case OpCode::name: \
  147. { \
  148. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  149. func((type)GetNonVarReg(playout->R0), GetScriptContext()); \
  150. break; \
  151. }
  152. #define PROCESS_A1toXXMemNonVar(name, func, type) PROCESS_A1toXXMemNonVar_COMMON(name, func, type,)
  153. #define PROCESS_XXtoA1_COMMON(name, func, suffix) \
  154. case OpCode::name: \
  155. { \
  156. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  157. SetReg(playout->R0, \
  158. func()); \
  159. break; \
  160. }
  161. #define PROCESS_XXtoA1(name, func) PROCESS_XXtoA1_COMMON(name, func,)
  162. #define PROCESS_XXtoA1NonVar_COMMON(name, func, suffix) \
  163. case OpCode::name: \
  164. { \
  165. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  166. SetNonVarReg(playout->R0, \
  167. func()); \
  168. break; \
  169. }
  170. #define PROCESS_XXtoA1NonVar(name, func) PROCESS_XXtoA1NonVar_COMMON(name, func,)
  171. #define PROCESS_XXtoA1Mem_COMMON(name, func, suffix) \
  172. case OpCode::name: \
  173. { \
  174. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  175. SetReg(playout->R0, \
  176. func(GetScriptContext())); \
  177. break; \
  178. }
  179. #define PROCESS_XXtoA1Mem(name, func) PROCESS_XXtoA1Mem_COMMON(name, func,)
  180. #define PROCESS_A1toA1_ALLOW_STACK_COMMON(name, func, suffix) \
  181. case OpCode::name: \
  182. { \
  183. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  184. SetRegAllowStackVar(playout->R0, \
  185. func(GetRegAllowStackVar(playout->R1))); \
  186. break; \
  187. }
  188. #define PROCESS_A1toA1_ALLOW_STACK(name, func) PROCESS_A1toA1_ALLOW_STACK_COMMON(name, func,)
  189. #define PROCESS_A1toA1_COMMON(name, func, suffix) \
  190. case OpCode::name: \
  191. { \
  192. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  193. SetReg(playout->R0, \
  194. func(GetReg(playout->R1))); \
  195. break; \
  196. }
  197. #define PROCESS_A1toA1(name, func) PROCESS_A1toA1_COMMON(name, func,)
  198. #define PROCESS_A1toA1Profiled_COMMON(name, func, suffix) \
  199. case OpCode::name: \
  200. { \
  201. PROCESS_READ_LAYOUT(name, ProfiledReg2, suffix); \
  202. SetReg(playout->R0, \
  203. func(GetReg(playout->R1), playout->profileId)); \
  204. break; \
  205. }
  206. #define PROCESS_A1toA1Profiled(name, func) PROCESS_A1toA1Profiled_COMMON(name, func,)
  207. #define PROCESS_A1toA1CallNoArg_COMMON(name, func, layout, suffix) \
  208. case OpCode::name: \
  209. { \
  210. PROCESS_READ_LAYOUT(name, layout, suffix); \
  211. SetReg(playout->R0, \
  212. func(playout)); \
  213. break; \
  214. }
  215. #define PROCESS_A1toA1CallNoArg(name, func, layout) PROCESS_A1toA1CallNoArg_COMMON(name, func, layout,)
  216. #define PROCESS_A1toA1Mem_COMMON(name, func, suffix) \
  217. case OpCode::name: \
  218. { \
  219. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  220. SetReg(playout->R0, \
  221. func(GetReg(playout->R1),GetScriptContext())); \
  222. break; \
  223. }
  224. #define PROCESS_A1toA1Mem(name, func) PROCESS_A1toA1Mem_COMMON(name, func,)
  225. #define PROCESS_A1toA1NonVar_COMMON(name, func, suffix) \
  226. case OpCode::name: \
  227. { \
  228. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  229. SetNonVarReg(playout->R0, \
  230. func(GetNonVarReg(playout->R1))); \
  231. break; \
  232. }
  233. #define PROCESS_A1toA1NonVar(name, func) PROCESS_A1toA1NonVar_COMMON(name, func,)
  234. #define PROCESS_A1toA1MemNonVar_COMMON(name, func, suffix) \
  235. case OpCode::name: \
  236. { \
  237. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  238. SetNonVarReg(playout->R0, \
  239. func(GetNonVarReg(playout->R1),GetScriptContext())); \
  240. break; \
  241. }
  242. #define PROCESS_A1toA1MemNonVar(name, func) PROCESS_A1toA1MemNonVar_COMMON(name, func,)
  243. #define PROCESS_INNERtoA1_COMMON(name, func, suffix) \
  244. case OpCode::name: \
  245. { \
  246. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  247. SetReg(playout->R0, InnerScopeFromIndex(playout->C1)); \
  248. break; \
  249. }
  250. #define PROCESS_INNERtoA1(name, fun) PROCESS_INNERtoA1_COMMON(name, func,)
  251. #define PROCESS_U1toINNERMemNonVar_COMMON(name, func, suffix) \
  252. case OpCode::name: \
  253. { \
  254. PROCESS_READ_LAYOUT(name, Unsigned1, suffix); \
  255. SetInnerScopeFromIndex(playout->C1, func(GetScriptContext())); \
  256. break; \
  257. }
  258. #define PROCESS_U1toINNERMemNonVar(name, func) PROCESS_U1toINNERMemNonVar_COMMON(name, func,)
  259. #define PROCESS_XXINNERtoA1MemNonVar_COMMON(name, func, suffix) \
  260. case OpCode::name: \
  261. { \
  262. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  263. SetNonVarReg(playout->R0, \
  264. func(InnerScopeFromIndex(playout->C1), GetScriptContext())); \
  265. break; \
  266. }
  267. #define PROCESS_XXINNERtoA1MemNonVar(name, func) PROCESS_XXINNERtoA1MemNonVar_COMMON(name, func,)
  268. #define PROCESS_A1INNERtoA1MemNonVar_COMMON(name, func, suffix) \
  269. case OpCode::name: \
  270. { \
  271. PROCESS_READ_LAYOUT(name, Reg2Int1, suffix); \
  272. SetNonVarReg(playout->R0, \
  273. func(InnerScopeFromIndex(playout->C1), GetNonVarReg(playout->R1), GetScriptContext())); \
  274. break; \
  275. }
  276. #define PROCESS_A1LOCALtoA1MemNonVar(name, func) PROCESS_A1LOCALtoA1MemNonVar_COMMON(name, func,)
  277. #define PROCESS_LOCALI1toA1_COMMON(name, func, suffix) \
  278. case OpCode::name: \
  279. { \
  280. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  281. SetReg(playout->R0, \
  282. func(this->localClosure, playout->C1)); \
  283. break; \
  284. }
  285. #define PROCESS_LOCALI1toA1(name, func) PROCESS_LOCALI1toA1_COMMON(name, func,)
  286. #define PROCESS_A1I1toA1_COMMON(name, func, suffix) \
  287. case OpCode::name: \
  288. { \
  289. PROCESS_READ_LAYOUT(name, Reg2Int1, suffix); \
  290. SetReg(playout->R0, \
  291. func(GetReg(playout->R1), playout->C1)); \
  292. break; \
  293. }
  294. #define PROCESS_A1I1toA1(name, func) PROCESS_A1I1toA1_COMMON(name, func,)
  295. #define PROCESS_A1I1toA1Mem_COMMON(name, func, suffix) \
  296. case OpCode::name: \
  297. { \
  298. PROCESS_READ_LAYOUT(name, Reg2Int1, suffix); \
  299. SetReg(playout->R0, \
  300. func(GetReg(playout->R1), playout->C1, GetScriptContext())); \
  301. break; \
  302. }
  303. #define PROCESS_A1I1toA1Mem(name, func) PROCESS_A1I1toA1Mem_COMMON(name, func,)
  304. #define PROCESS_RegextoA1_COMMON(name, func, suffix) \
  305. case OpCode::name: \
  306. { \
  307. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  308. SetReg(playout->R0, \
  309. func(this->m_functionBody->GetLiteralRegex(playout->C1), GetScriptContext())); \
  310. break; \
  311. }
  312. #define PROCESS_RegextoA1(name, func) PROCESS_RegextoA1_COMMON(name, func,)
  313. #define PROCESS_A2toXX_COMMON(name, func, suffix) \
  314. case OpCode::name: \
  315. { \
  316. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  317. func(GetReg(playout->R0), GetReg(playout->R1)); \
  318. break; \
  319. }
  320. #define PROCESS_A2toXX(name, func) PROCESS_A2toXX_COMMON(name, func,)
  321. #define PROCESS_A2toXXMemNonVar_COMMON(name, func, suffix) \
  322. case OpCode::name: \
  323. { \
  324. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  325. func(GetNonVarReg(playout->R0), GetNonVarReg(playout->R1), GetScriptContext()); \
  326. break; \
  327. }
  328. #define PROCESS_A2toXXMemNonVar(name, func) PROCESS_A2toXXMemNonVar_COMMON(name, func,)
  329. #define PROCESS_A1NonVarToA1_COMMON(name, func, suffix) \
  330. case OpCode::name: \
  331. { \
  332. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  333. SetReg(playout->R0, \
  334. func(GetNonVarReg(playout->R1))); \
  335. break; \
  336. }
  337. #define PROCESS_A2NonVarToA1Reg_COMMON(name, func, suffix) \
  338. case OpCode::name: \
  339. { \
  340. PROCESS_READ_LAYOUT(name, Reg3, suffix); \
  341. SetReg(playout->R0, \
  342. func(GetNonVarReg(playout->R1), playout->R2)); \
  343. break; \
  344. }
  345. #define PROCESS_A2toA1Mem_COMMON(name, func, suffix) \
  346. case OpCode::name: \
  347. { \
  348. PROCESS_READ_LAYOUT(name, Reg3, suffix); \
  349. SetReg(playout->R0, \
  350. func(GetReg(playout->R1), GetReg(playout->R2),GetScriptContext())); \
  351. break; \
  352. }
  353. #define PROCESS_A2toA1Mem(name, func) PROCESS_A2toA1Mem_COMMON(name, func,)
  354. #define PROCESS_A2toA1MemProfiled_COMMON(name, func, suffix) \
  355. case OpCode::name: \
  356. { \
  357. PROCESS_READ_LAYOUT(name, ProfiledReg3, suffix); \
  358. SetReg(playout->R0, \
  359. func(GetReg(playout->R1), GetReg(playout->R2),GetScriptContext(), playout->profileId)); \
  360. break; \
  361. }
  362. #define PROCESS_A2toA1MemProfiled(name, func) PROCESS_A2toA1MemProfiled_COMMON(name, func,)
  363. #define PROCESS_A2toA1NonVar_COMMON(name, func, suffix) \
  364. case OpCode::name: \
  365. { \
  366. PROCESS_READ_LAYOUT(name, Reg3, suffix); \
  367. SetNonVarReg(playout->R0, \
  368. func(GetNonVarReg(playout->R1), GetNonVarReg(playout->R2))); \
  369. break; \
  370. }
  371. #define PROCESS_A2toA1NonVar(name, func) PROCESS_A2toA1NonVar_COMMON(name, func,)
  372. #define PROCESS_A2toA1MemNonVar_COMMON(name, func, suffix) \
  373. case OpCode::name: \
  374. { \
  375. PROCESS_READ_LAYOUT(name, Reg3, suffix); \
  376. SetNonVarReg(playout->R0, \
  377. func(GetNonVarReg(playout->R1), GetNonVarReg(playout->R2),GetScriptContext())); \
  378. break; \
  379. }
  380. #define PROCESS_A2toA1MemNonVar(name, func) PROCESS_A2toA1MemNonVar_COMMON(name, func,)
  381. #define PROCESS_CMMem_COMMON(name, func, suffix) \
  382. case OpCode::name: \
  383. { \
  384. PROCESS_READ_LAYOUT(name, Reg3, suffix); \
  385. SetReg(playout->R0, \
  386. func(GetReg(playout->R1), GetReg(playout->R2), GetScriptContext()) ? JavascriptBoolean::OP_LdTrue(GetScriptContext()) : \
  387. JavascriptBoolean::OP_LdFalse(GetScriptContext())); \
  388. break; \
  389. }
  390. #define PROCESS_CMMem(name, func) PROCESS_CMMem_COMMON(name, func,)
  391. #define PROCESS_ELEM_RtU_to_XX_COMMON(name, func, suffix) \
  392. case OpCode::name: \
  393. { \
  394. PROCESS_READ_LAYOUT(name, ElementRootU, suffix); \
  395. func(playout->PropertyIdIndex); \
  396. break; \
  397. }
  398. #define PROCESS_ELEM_RtU_to_XX(name, func) PROCESS_ELEM_RtU_to_XX_COMMON(name, func,)
  399. #define PROCESS_ELEM_C2_to_XX_COMMON(name, func, suffix) \
  400. case OpCode::name: \
  401. { \
  402. PROCESS_READ_LAYOUT(name, ElementScopedC, suffix); \
  403. func(GetEnvForEvalCode(), playout->PropertyIdIndex, GetReg(playout->Value)); \
  404. break; \
  405. }
  406. #define PROCESS_ELEM_C2_to_XX(name, func) PROCESS_ELEM_C2_to_XX_COMMON(name, func,)
  407. #define PROCESS_GET_ELEM_SLOT_FB_COMMON(name, func, suffix) \
  408. case OpCode::name: \
  409. { \
  410. PROCESS_READ_LAYOUT(name, ElementSlot, suffix); \
  411. SetReg(playout->Value, \
  412. func((FrameDisplay*)GetNonVarReg(playout->Instance), this->m_functionBody->GetNestedFuncReference(playout->SlotIndex))); \
  413. break; \
  414. }
  415. #define PROCESS_GET_ELEM_SLOT_FB(name, func) PROCESS_GET_ELEM_SLOT_FB_COMMON(name, func,)
  416. #define PROCESS_GET_SLOT_FB_COMMON(name, func, suffix) \
  417. case OpCode::name: \
  418. { \
  419. PROCESS_READ_LAYOUT(name, ElementSlotI1, suffix); \
  420. SetReg(playout->Value, \
  421. func(this->GetFrameDisplayForNestedFunc(), this->m_functionBody->GetNestedFuncReference(playout->SlotIndex))); \
  422. break; \
  423. }
  424. #define PROCESS_GET_SLOT_FB(name, func) PROCESS_GET_SLOT_FB_COMMON(name, func,)
  425. #define PROCESS_GET_ELEM_IMem_COMMON(name, func, suffix) \
  426. case OpCode::name: \
  427. { \
  428. PROCESS_READ_LAYOUT(name, ElementI, suffix); \
  429. SetReg(playout->Value, \
  430. func(GetReg(playout->Instance), GetReg(playout->Element), GetScriptContext())); \
  431. break; \
  432. }
  433. #define PROCESS_GET_ELEM_IMem(name, func) PROCESS_GET_ELEM_IMem_COMMON(name, func,)
  434. #define PROCESS_GET_ELEM_IMem_Strict_COMMON(name, func, suffix) \
  435. case OpCode::name: \
  436. { \
  437. PROCESS_READ_LAYOUT(name, ElementI, suffix); \
  438. SetReg(playout->Value, \
  439. func(GetReg(playout->Instance), GetReg(playout->Element), GetScriptContext(), PropertyOperation_StrictMode)); \
  440. break; \
  441. }
  442. #define PROCESS_GET_ELEM_IMem_Strict(name, func) PROCESS_GET_ELEM_IMem_Strict_COMMON(name, func,)
  443. #define PROCESS_BR(name, func) \
  444. case OpCode::name: \
  445. { \
  446. PROCESS_READ_LAYOUT(name, Br,); \
  447. ip = func(playout); \
  448. break; \
  449. }
  450. #ifdef BYTECODE_BRANCH_ISLAND
  451. #define PROCESS_BRLONG(name, func) \
  452. case OpCode::name: \
  453. { \
  454. PROCESS_READ_LAYOUT(name, BrLong,); \
  455. ip = func(playout); \
  456. break; \
  457. }
  458. #endif
  459. #define PROCESS_BRS(name,func) \
  460. case OpCode::name: \
  461. { \
  462. PROCESS_READ_LAYOUT(name, BrS,); \
  463. if (func(playout->val,GetScriptContext())) \
  464. { \
  465. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  466. } \
  467. break; \
  468. }
  469. #define PROCESS_BRB_COMMON(name, func, suffix) \
  470. case OpCode::name: \
  471. { \
  472. PROCESS_READ_LAYOUT(name, BrReg1, suffix); \
  473. if (func(GetReg(playout->R1))) \
  474. { \
  475. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  476. } \
  477. break; \
  478. }
  479. #define PROCESS_BRB(name, func) PROCESS_BRB_COMMON(name, func,)
  480. #define PROCESS_BRB_ALLOW_STACK_COMMON(name, func, suffix) \
  481. case OpCode::name: \
  482. { \
  483. PROCESS_READ_LAYOUT(name, BrReg1, suffix); \
  484. if (func(GetRegAllowStackVar(playout->R1))) \
  485. { \
  486. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  487. } \
  488. break; \
  489. }
  490. #define PROCESS_BRB_ALLOW_STACK(name, func) PROCESS_BRB_ALLOW_STACK_COMMON(name, func,)
  491. #define PROCESS_BRBS_COMMON(name, func, suffix) \
  492. case OpCode::name: \
  493. { \
  494. PROCESS_READ_LAYOUT(name, BrReg1, suffix); \
  495. if (func(GetReg(playout->R1), GetScriptContext())) \
  496. { \
  497. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  498. } \
  499. break; \
  500. }
  501. #define PROCESS_BRBS(name, func) PROCESS_BRBS_COMMON(name, func,)
  502. #define PROCESS_BRBReturnP1toA1_COMMON(name, func, suffix) \
  503. case OpCode::name: \
  504. { \
  505. PROCESS_READ_LAYOUT(name, BrReg1Unsigned1, suffix); \
  506. SetReg(playout->R1, func(GetForInEnumerator(playout->C2))); \
  507. if (!GetReg(playout->R1)) \
  508. { \
  509. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  510. } \
  511. break; \
  512. }
  513. #define PROCESS_BRBReturnP1toA1(name, func) PROCESS_BRBReturnP1toA1_COMMON(name, func,)
  514. #define PROCESS_BRBMem_ALLOW_STACK_COMMON(name, func, suffix) \
  515. case OpCode::name: \
  516. { \
  517. PROCESS_READ_LAYOUT(name, BrReg1, suffix); \
  518. if (func(GetRegAllowStackVar(playout->R1),GetScriptContext())) \
  519. { \
  520. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  521. } \
  522. break; \
  523. }
  524. #define PROCESS_BRBMem_ALLOW_STACK(name, func) PROCESS_BRBMem_ALLOW_STACK_COMMON(name, func,)
  525. #define PROCESS_BRCMem_COMMON(name, func,suffix) \
  526. case OpCode::name: \
  527. { \
  528. PROCESS_READ_LAYOUT(name, BrReg2, suffix); \
  529. if (func(GetReg(playout->R1), GetReg(playout->R2),GetScriptContext())) \
  530. { \
  531. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  532. } \
  533. break; \
  534. }
  535. #define PROCESS_BRCMem(name, func) PROCESS_BRCMem_COMMON(name, func,)
  536. #define PROCESS_BRPROP(name, func) \
  537. case OpCode::name: \
  538. { \
  539. PROCESS_READ_LAYOUT(name, BrProperty,); \
  540. if (func(GetReg(playout->Instance), playout->PropertyIdIndex, GetScriptContext())) \
  541. { \
  542. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  543. } \
  544. break; \
  545. }
  546. #define PROCESS_BRLOCALPROP(name, func) \
  547. case OpCode::name: \
  548. { \
  549. PROCESS_READ_LAYOUT(name, BrLocalProperty,); \
  550. if (func(this->localClosure, playout->PropertyIdIndex, GetScriptContext())) \
  551. { \
  552. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  553. } \
  554. break; \
  555. }
  556. #define PROCESS_BRENVPROP(name, func) \
  557. case OpCode::name: \
  558. { \
  559. PROCESS_READ_LAYOUT(name, BrEnvProperty,); \
  560. if (func(LdEnv(), playout->SlotIndex, playout->PropertyIdIndex, GetScriptContext())) \
  561. { \
  562. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  563. } \
  564. break; \
  565. }
  566. #define PROCESS_W1(name, func) \
  567. case OpCode::name: \
  568. { \
  569. PROCESS_READ_LAYOUT(name, W1,); \
  570. func(playout->C1, GetScriptContext()); \
  571. break; \
  572. }
  573. #define PROCESS_U1toA1_COMMON(name, func, suffix) \
  574. case OpCode::name: \
  575. { \
  576. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  577. SetReg(playout->R0, \
  578. func(playout->C1,GetScriptContext())); \
  579. break; \
  580. }
  581. #define PROCESS_U1toA1(name, func) PROCESS_U1toA1_COMMON(name, func,)
  582. #define PROCESS_U1toA1NonVar_COMMON(name, func, suffix) \
  583. case OpCode::name: \
  584. { \
  585. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  586. SetNonVarReg(playout->R0, \
  587. func(playout->C1)); \
  588. break; \
  589. }
  590. #define PROCESS_U1toA1NonVar(name, func) PROCESS_U1toA1NonVar_COMMON(name, func,)
  591. #define PROCESS_U1toA1NonVar_FuncBody_COMMON(name, func, suffix) \
  592. case OpCode::name: \
  593. { \
  594. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  595. SetNonVarReg(playout->R0, \
  596. func(playout->C1,GetScriptContext(), this->m_functionBody)); \
  597. break; \
  598. }
  599. #define PROCESS_U1toA1NonVar_FuncBody(name, func) PROCESS_U1toA1NonVar_FuncBody_COMMON(name, func,)
  600. #define PROCESS_A1I2toXXNonVar_FuncBody(name, func) PROCESS_A1I2toXXNonVar_FuncBody_COMMON(name, func,)
  601. #define PROCESS_A1I2toXXNonVar_FuncBody_COMMON(name, func, suffix) \
  602. case OpCode::name: \
  603. { \
  604. PROCESS_READ_LAYOUT(name, Reg3, suffix); \
  605. func(playout->R0, playout->R1, playout->R2, GetScriptContext(), this->m_functionBody); \
  606. break; \
  607. }
  608. #define PROCESS_A1U1toXX_COMMON(name, func, suffix) \
  609. case OpCode::name: \
  610. { \
  611. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  612. func(GetReg(playout->R0), playout->C1); \
  613. break; \
  614. }
  615. #define PROCESS_A1U1toXX(name, func) PROCESS_A1U1toXX_COMMON(name, func,)
  616. #define PROCESS_A1U1toXXWithCache_COMMON(name, func, suffix) \
  617. case OpCode::name: \
  618. { \
  619. PROCESS_READ_LAYOUT(name, ProfiledReg1Unsigned1, suffix); \
  620. func(GetReg(playout->R0), playout->C1, playout->profileId); \
  621. break; \
  622. }
  623. #define PROCESS_A1U1toXXWithCache(name, func) PROCESS_A1U1toXXWithCache_COMMON(name, func,)
  624. #define PROCESS_EnvU1toXX_COMMON(name, func, suffix) \
  625. case OpCode::name: \
  626. { \
  627. PROCESS_READ_LAYOUT(name, Unsigned1, suffix); \
  628. func(LdEnv(), playout->C1); \
  629. break; \
  630. }
  631. #define PROCESS_EnvU1toXX(name, func) PROCESS_EnvU1toXX_COMMON(name, func,)
  632. #define PROCESS_GET_ELEM_SLOTNonVar_COMMON(name, func, layout, suffix) \
  633. case OpCode::name: \
  634. { \
  635. PROCESS_READ_LAYOUT(name, layout, suffix); \
  636. SetNonVarReg(playout->Value, func(GetNonVarReg(playout->Instance), playout)); \
  637. break; \
  638. }
  639. #define PROCESS_GET_ELEM_SLOTNonVar(name, func, layout) PROCESS_GET_ELEM_SLOTNonVar_COMMON(name, func, layout,)
  640. #define PROCESS_GET_ELEM_LOCALSLOTNonVar_COMMON(name, func, layout, suffix) \
  641. case OpCode::name: \
  642. { \
  643. PROCESS_READ_LAYOUT(name, layout, suffix); \
  644. SetNonVarReg(playout->Value, func((Var*)GetLocalClosure(), playout)); \
  645. break; \
  646. }
  647. #define PROCESS_GET_ELEM_LOCALSLOTNonVar(name, func, layout) PROCESS_GET_ELEM_LOCALSLOTNonVar_COMMON(name, func, layout,)
  648. #define PROCESS_GET_ELEM_PARAMSLOTNonVar_COMMON(name, func, layout, suffix) \
  649. case OpCode::name: \
  650. { \
  651. PROCESS_READ_LAYOUT(name, layout, suffix); \
  652. SetNonVarReg(playout->Value, func((Var*)GetParamClosure(), playout)); \
  653. break; \
  654. }
  655. #define PROCESS_GET_ELEM_PARAMSLOTNonVar(name, func, layout) PROCESS_GET_ELEM_PARAMSLOTNonVar_COMMON(name, func, layout,)
  656. #define PROCESS_GET_ELEM_INNERSLOTNonVar_COMMON(name, func, layout, suffix) \
  657. case OpCode::name: \
  658. { \
  659. PROCESS_READ_LAYOUT(name, layout, suffix); \
  660. SetNonVarReg(playout->Value, func(InnerScopeFromIndex(playout->SlotIndex1), playout)); \
  661. break; \
  662. }
  663. #define PROCESS_GET_ELEM_INNERSLOTNonVar(name, func, layout) PROCESS_GET_ELEM_INNERSLOTNonVar_COMMON(name, func, layout,)
  664. #define PROCESS_GET_ELEM_ENVSLOTNonVar_COMMON(name, func, layout, suffix) \
  665. case OpCode::name: \
  666. { \
  667. PROCESS_READ_LAYOUT(name, layout, suffix); \
  668. SetNonVarReg(playout->Value, func(LdEnv(), playout)); \
  669. break; \
  670. }
  671. #define PROCESS_GET_ELEM_ENVSLOTNonVar(name, func, layout) PROCESS_GET_ELEM_ENVSLOTNonVar_COMMON(name, func, layout,)
  672. #define PROCESS_SET_ELEM_SLOTNonVar_COMMON(name, func, suffix) \
  673. case OpCode::name: \
  674. { \
  675. PROCESS_READ_LAYOUT(name, ElementSlot, suffix); \
  676. func(GetNonVarReg(playout->Instance), playout->SlotIndex, GetRegAllowStackVarEnableOnly(playout->Value)); \
  677. break; \
  678. }
  679. #define PROCESS_SET_ELEM_SLOTNonVar(name, func) PROCESS_SET_ELEM_SLOTNonVar_COMMON(name, func,)
  680. #define PROCESS_SET_ELEM_LOCALSLOTNonVar_COMMON(name, func, suffix) \
  681. case OpCode::name: \
  682. { \
  683. PROCESS_READ_LAYOUT(name, ElementSlotI1, suffix); \
  684. func((Var*)GetLocalClosure(), playout->SlotIndex, GetRegAllowStackVarEnableOnly(playout->Value)); \
  685. break; \
  686. }
  687. #define PROCESS_SET_ELEM_LOCALSLOTNonVar(name, func) PROCESS_SET_ELEM_LOCALSLOTNonVar_COMMON(name, func,)
  688. #define PROCESS_SET_ELEM_INNERSLOTNonVar_COMMON(name, func, suffix) \
  689. case OpCode::name: \
  690. { \
  691. PROCESS_READ_LAYOUT(name, ElementSlotI2, suffix); \
  692. func(InnerScopeFromIndex(playout->SlotIndex1), playout->SlotIndex2, GetRegAllowStackVarEnableOnly(playout->Value)); \
  693. break; \
  694. }
  695. #define PROCESS_SET_ELEM_INNERSLOTNonVar(name, func) PROCESS_SET_ELEM_INNERSLOTNonVar_COMMON(name, func,)
  696. #define PROCESS_SET_ELEM_ENVSLOTNonVar_COMMON(name, func, suffix) \
  697. case OpCode::name: \
  698. { \
  699. PROCESS_READ_LAYOUT(name, ElementSlotI2, suffix); \
  700. func(LdEnv(), playout->SlotIndex1, playout->SlotIndex2, GetRegAllowStackVarEnableOnly(playout->Value)); \
  701. break; \
  702. }
  703. #define PROCESS_SET_ELEM_ENVSLOTNonVar(name, func) PROCESS_SET_ELEM_ENVSLOTNonVar_COMMON(name, func,)
  704. /*---------------------------------------------------------------------------------------------- */
  705. #define PROCESS_A3toA1Mem_COMMON(name, func, suffix) \
  706. case OpCode::name: \
  707. { \
  708. PROCESS_READ_LAYOUT(name, Reg4, suffix); \
  709. SetReg(playout->R0, \
  710. func(GetReg(playout->R1), GetReg(playout->R2), GetReg(playout->R3), GetScriptContext())); \
  711. break; \
  712. }
  713. #define PROCESS_A3toA1Mem(name, func) PROCESS_A3toA1Mem_COMMON(name, func,)
  714. /*---------------------------------------------------------------------------------------------- */
  715. #define PROCESS_A2I1toA1Mem_COMMON(name, func, suffix) \
  716. case OpCode::name: \
  717. { \
  718. PROCESS_READ_LAYOUT(name, Reg3B1, suffix); \
  719. SetReg(playout->R0, \
  720. func(GetReg(playout->R1), GetReg(playout->R2), playout->B3, GetScriptContext())); \
  721. break; \
  722. }
  723. #define PROCESS_A2I1toA1Mem(name, func) PROCESS_A2I1toA1Mem_COMMON(name, func,)
  724. /*---------------------------------------------------------------------------------------------- */
  725. #define PROCESS_A2I1toXXMem_COMMON(name, func, suffix) \
  726. case OpCode::name: \
  727. { \
  728. PROCESS_READ_LAYOUT(name, Reg2B1, suffix); \
  729. func(GetReg(playout->R0), GetReg(playout->R1), playout->B2, scriptContext); \
  730. break; \
  731. }
  732. #define PROCESS_A2I1toXXMem(name, func) PROCESS_A2I1toXXMem_COMMON(name, func,)
  733. /*---------------------------------------------------------------------------------------------- */
  734. #define PROCESS_A3I1toXXMem_COMMON(name, func, suffix) \
  735. case OpCode::name: \
  736. { \
  737. PROCESS_READ_LAYOUT(name, Reg3B1, suffix); \
  738. func(GetReg(playout->R0), GetReg(playout->R1), GetReg(playout->R2), playout->B3, scriptContext); \
  739. break; \
  740. }
  741. #define PROCESS_A3I1toXXMem(name, func) PROCESS_A3I1toXXMem_COMMON(name, func,)
  742. #if ENABLE_PROFILE_INFO
  743. #define PROCESS_IP_TARG_IMPL(name, func, layoutSize) \
  744. case OpCode::name: \
  745. { \
  746. Assert(!switchProfileMode); \
  747. ip = func<layoutSize, INTERPRETERPROFILE>(ip); \
  748. if(switchProfileMode) \
  749. { \
  750. m_reader.SetIP(ip); \
  751. return nullptr; \
  752. } \
  753. break; \
  754. }
  755. #else
  756. #define PROCESS_IP_TARG_IMPL(name, func, layoutSize) \
  757. case OpCode::name: \
  758. { \
  759. ip = func<layoutSize, INTERPRETERPROFILE>(ip); \
  760. break; \
  761. }
  762. #endif
  763. #define PROCESS_IP_TARG_COMMON(name, func, suffix) PROCESS_IP_TARG##suffix(name, func)
  764. #define PROCESS_IP_TARG_Large(name, func) PROCESS_IP_TARG_IMPL(name, func, Js::LargeLayout)
  765. #define PROCESS_IP_TARG_Medium(name, func) PROCESS_IP_TARG_IMPL(name, func, Js::MediumLayout)
  766. #define PROCESS_IP_TARG_Small(name, func) PROCESS_IP_TARG_IMPL(name, func, Js::SmallLayout)
  767. #if ENABLE_TTD
  768. #if ENABLE_TTD_DIAGNOSTICS_TRACING
  769. #define SHOULD_DO_TTD_STACK_STMT_OP(CTX) ((CTX)->ShouldPerformRecordOrReplayAction())
  770. #else
  771. #define SHOULD_DO_TTD_STACK_STMT_OP(CTX) ((CTX)->ShouldPerformDebuggerAction())
  772. #endif
  773. #endif
  774. namespace Js
  775. {
  776. #ifdef ASMJS_PLAT
  777. typedef void(InterpreterStackFrame::*ArrFunc)(uint32, RegSlot);
  778. CompileAssert(Js::ArrayBufferView::TYPE_INT8 == 0);
  779. CompileAssert(Js::ArrayBufferView::TYPE_UINT8 == 1);
  780. CompileAssert(Js::ArrayBufferView::TYPE_INT16 == 2);
  781. CompileAssert(Js::ArrayBufferView::TYPE_UINT16 == 3);
  782. CompileAssert(Js::ArrayBufferView::TYPE_INT32 == 4);
  783. CompileAssert(Js::ArrayBufferView::TYPE_UINT32 == 5);
  784. CompileAssert(Js::ArrayBufferView::TYPE_FLOAT32 == 6);
  785. CompileAssert(Js::ArrayBufferView::TYPE_FLOAT64 == 7);
  786. CompileAssert(Js::ArrayBufferView::TYPE_INT64 == 8);
  787. CompileAssert(Js::ArrayBufferView::TYPE_INT8_TO_INT64 == 9);
  788. CompileAssert(Js::ArrayBufferView::TYPE_UINT8_TO_INT64 == 10);
  789. CompileAssert(Js::ArrayBufferView::TYPE_INT16_TO_INT64 == 11);
  790. CompileAssert(Js::ArrayBufferView::TYPE_UINT16_TO_INT64 == 12);
  791. CompileAssert(Js::ArrayBufferView::TYPE_INT32_TO_INT64 == 13);
  792. CompileAssert(Js::ArrayBufferView::TYPE_UINT32_TO_INT64 == 14);
  793. const InterpreterStackFrame::ArrFunc InterpreterStackFrame::StArrFunc[] =
  794. {
  795. &InterpreterStackFrame::OP_StArr<int8, int32>,
  796. &InterpreterStackFrame::OP_StArr<uint8, int32>,
  797. &InterpreterStackFrame::OP_StArr<int16, int32>,
  798. &InterpreterStackFrame::OP_StArr<uint16, int32>,
  799. &InterpreterStackFrame::OP_StArr<int32>,
  800. &InterpreterStackFrame::OP_StArr<uint32, int32>,
  801. &InterpreterStackFrame::OP_StArr<float>,
  802. &InterpreterStackFrame::OP_StArr<double>,
  803. &InterpreterStackFrame::OP_StArr<int64>,
  804. &InterpreterStackFrame::OP_StArr<int8, int64>,
  805. &InterpreterStackFrame::OP_StArr<uint8, int64>,
  806. &InterpreterStackFrame::OP_StArr<int16, int64>,
  807. &InterpreterStackFrame::OP_StArr<uint16, int64>,
  808. &InterpreterStackFrame::OP_StArr<int32, int64>,
  809. &InterpreterStackFrame::OP_StArr<uint32, int64>,
  810. };
  811. const InterpreterStackFrame::ArrFunc InterpreterStackFrame::LdArrFunc[] =
  812. {
  813. &InterpreterStackFrame::OP_LdArr<int8, int32>,
  814. &InterpreterStackFrame::OP_LdArr<uint8, int32>,
  815. &InterpreterStackFrame::OP_LdArr<int16, int32>,
  816. &InterpreterStackFrame::OP_LdArr<uint16, int32>,
  817. &InterpreterStackFrame::OP_LdArr<int32>,
  818. &InterpreterStackFrame::OP_LdArr<uint32, int32>,
  819. &InterpreterStackFrame::OP_LdArr<float>,
  820. &InterpreterStackFrame::OP_LdArr<double>,
  821. &InterpreterStackFrame::OP_LdArr<int64>,
  822. &InterpreterStackFrame::OP_LdArr<int8, int64>,
  823. &InterpreterStackFrame::OP_LdArr<uint8, int64>,
  824. &InterpreterStackFrame::OP_LdArr<int16, int64>,
  825. &InterpreterStackFrame::OP_LdArr<uint16, int64>,
  826. &InterpreterStackFrame::OP_LdArr<int32, int64>,
  827. &InterpreterStackFrame::OP_LdArr<uint32, int64>,
  828. };
  829. const int InterpreterStackFrame::TypeToSizeMap[] =
  830. {
  831. /*int8*/ 1,
  832. /*uint8*/ 1,
  833. /*int16*/ 2,
  834. /*uint16*/ 2,
  835. /*int32*/ 4,
  836. /*uint32*/ 4,
  837. /*float*/ 4,
  838. /*double*/ 8,
  839. /*int64*/ 8,
  840. /*int8*/ 1,
  841. /*uint8*/ 1,
  842. /*int16*/ 2,
  843. /*uint16*/ 2,
  844. /*int32*/ 4,
  845. /*uint32*/ 4,
  846. };
  847. #endif
  848. Var InterpreterStackFrame::InnerScopeFromRegSlot(RegSlot reg) const
  849. {
  850. return InnerScopeFromIndex(reg - m_functionBody->GetFirstInnerScopeRegister());
  851. }
  852. Var InterpreterStackFrame::InnerScopeFromIndex(uint32 index) const
  853. {
  854. if (index >= m_functionBody->GetInnerScopeCount())
  855. {
  856. AssertMsg(false, "Illegal byte code: bad inner scope index");
  857. Js::Throw::FatalInternalError();
  858. }
  859. Assert(this->innerScopeArray != nullptr);
  860. return this->innerScopeArray[index];
  861. }
  862. void InterpreterStackFrame::SetInnerScopeFromIndex(uint32 index, Var scope)
  863. {
  864. if (index >= m_functionBody->GetInnerScopeCount())
  865. {
  866. AssertMsg(false, "Illegal byte code: bad inner scope index");
  867. Js::Throw::FatalInternalError();
  868. }
  869. Assert(this->innerScopeArray != nullptr);
  870. this->innerScopeArray[index] = scope;
  871. }
  872. const int k_stackFrameVarCount = (sizeof(InterpreterStackFrame) + sizeof(Var) - 1) / sizeof(Var);
  873. InterpreterStackFrame::Setup::Setup(Js::ScriptFunction * function, Js::Arguments& args, bool bailedOut, bool inlinee)
  874. : function(function), inParams(args.Values), inSlotsCount(args.Info.Count), executeFunction(function->GetFunctionBody()), callFlags(args.Info.Flags), bailedOutOfInlinee(inlinee), bailedOut(bailedOut)
  875. {
  876. SetupInternal();
  877. }
  878. InterpreterStackFrame::Setup::Setup(Js::ScriptFunction * function, Var * inParams, int inSlotsCount)
  879. : function(function), inParams(inParams), inSlotsCount(inSlotsCount), executeFunction(function->GetFunctionBody()), callFlags(CallFlags_None), bailedOutOfInlinee(false), bailedOut(false)
  880. {
  881. SetupInternal();
  882. }
  883. void InterpreterStackFrame::Setup::SetupInternal()
  884. {
  885. if (this->function->GetHasInlineCaches() && Js::ScriptFunctionWithInlineCache::Is(this->function))
  886. {
  887. this->inlineCaches = Js::ScriptFunctionWithInlineCache::FromVar(this->function)->GetInlineCaches();
  888. }
  889. else
  890. {
  891. this->inlineCaches = this->executeFunction->GetInlineCaches();
  892. }
  893. this->inlineCacheCount = this->executeFunction->GetInlineCacheCount();
  894. //
  895. // Compute the amount of memory needed on the stack:
  896. // - We compute this in 'Atoms' instead of 'bytes' to keep everything natural word aligned.
  897. //
  898. this->localCount = this->executeFunction->GetLocalsCount();
  899. uint extraVarCount = 0;
  900. #if ENABLE_PROFILE_INFO
  901. if (Js::DynamicProfileInfo::EnableImplicitCallFlags(this->executeFunction))
  902. {
  903. extraVarCount += (sizeof(ImplicitCallFlags) * this->executeFunction->GetLoopCount() + sizeof(Var) - 1) / sizeof(Var);
  904. }
  905. #endif
  906. // If we bailed out, we will use the JIT frame's for..in enumerators
  907. uint forInVarCount = bailedOut? 0 : (this->executeFunction->GetForInLoopDepth() * (sizeof(Js::ForInObjectEnumerator) / sizeof(Var)));
  908. this->varAllocCount = k_stackFrameVarCount + localCount + this->executeFunction->GetOutParamMaxDepth() + forInVarCount +
  909. extraVarCount + this->executeFunction->GetInnerScopeCount();
  910. if (this->executeFunction->DoStackNestedFunc() && this->executeFunction->GetNestedCount() != 0)
  911. {
  912. // Track stack funcs...
  913. this->varAllocCount += (sizeof(StackScriptFunction) * this->executeFunction->GetNestedCount()) / sizeof(Var);
  914. if (!this->bailedOutOfInlinee)
  915. {
  916. // Frame display (if environment depth is statically known)...
  917. if (this->executeFunction->DoStackFrameDisplay())
  918. {
  919. uint16 envDepth = this->executeFunction->GetEnvDepth();
  920. Assert(envDepth != (uint16)-1);
  921. this->varAllocCount += sizeof(FrameDisplay) / sizeof(Var) + (envDepth + 1);
  922. }
  923. // ...and scope slots (if any)
  924. if (this->executeFunction->DoStackScopeSlots())
  925. {
  926. uint32 scopeSlots = this->executeFunction->scopeSlotArraySize;
  927. Assert(scopeSlots != 0);
  928. this->varAllocCount += scopeSlots + Js::ScopeSlots::FirstSlotIndex;
  929. }
  930. }
  931. }
  932. }
  933. InterpreterStackFrame *
  934. InterpreterStackFrame::Setup::InitializeAllocation(__in_ecount(varAllocCount) Var * allocation, bool initParams, bool profileParams, Var loopHeaderArray, DWORD_PTR stackAddr
  935. #if DBG
  936. , Var invalidStackVar
  937. #endif
  938. )
  939. {
  940. //
  941. // Initialize the new InterpreterStackFrame instance on the program stack.
  942. //
  943. //This will fail if InterpreterStackFrame ever gets a non-empty ctor (you'll need to use
  944. //placement_new(allocation, InterpreterStackFrame) instead, though that will cause problems
  945. //if the placement_new is surrounded by a try/finally since this would mix C++/SEH exception
  946. //handling.
  947. __analysis_assume(varAllocCount >= k_stackFrameVarCount + localCount);
  948. InterpreterStackFrame* newInstance = (InterpreterStackFrame*)allocation;
  949. newInstance->scriptContext = this->executeFunction->GetScriptContext();
  950. newInstance->m_inSlotsCount = this->inSlotsCount;
  951. newInstance->m_inParams = this->inParams;
  952. newInstance->m_callFlags = this->callFlags;
  953. newInstance->m_outParams = newInstance->m_localSlots + localCount;
  954. newInstance->m_outSp = newInstance->m_outParams;
  955. newInstance->m_outSpCached = nullptr;
  956. newInstance->m_arguments = NULL;
  957. newInstance->function = this->function;
  958. newInstance->m_functionBody = this->executeFunction;
  959. newInstance->inlineCaches = this->inlineCaches;
  960. newInstance->inlineCacheCount = this->inlineCacheCount;
  961. newInstance->currentLoopNum = LoopHeader::NoLoop;
  962. newInstance->currentLoopCounter = 0;
  963. newInstance->m_flags = InterpreterStackFrameFlags_None;
  964. newInstance->closureInitDone = false;
  965. newInstance->isParamScopeDone = false;
  966. newInstance->shouldCacheSP = true;
  967. #if ENABLE_PROFILE_INFO
  968. newInstance->switchProfileMode = false;
  969. newInstance->isAutoProfiling = false;
  970. newInstance->switchProfileModeOnLoopEndNumber = 0u - 1;
  971. #endif
  972. newInstance->ehBailoutData = nullptr;
  973. newInstance->nestedTryDepth = -1;
  974. newInstance->nestedCatchDepth = -1;
  975. newInstance->nestedFinallyDepth = -1;
  976. newInstance->retOffset = 0;
  977. newInstance->localFrameDisplay = nullptr;
  978. newInstance->localClosure = nullptr;
  979. newInstance->paramClosure = nullptr;
  980. newInstance->innerScopeArray = nullptr;
  981. bool doInterruptProbe = newInstance->scriptContext->GetThreadContext()->DoInterruptProbe(this->executeFunction);
  982. #if ENABLE_NATIVE_CODEGEN
  983. bool doJITLoopBody =
  984. !this->executeFunction->GetScriptContext()->GetConfig()->IsNoNative() &&
  985. !(this->executeFunction->GetHasTry() && (PHASE_OFF((Js::JITLoopBodyInTryCatchPhase), this->executeFunction) || this->executeFunction->GetHasFinally())) &&
  986. (this->executeFunction->ForceJITLoopBody() || this->executeFunction->IsJitLoopBodyPhaseEnabled()) &&
  987. !this->executeFunction->IsInDebugMode();
  988. #endif
  989. // Pick a version of the LoopBodyStart OpCode handlers that is hardcoded to do loop body JIT and
  990. // interrupt probes as needed.
  991. if (doInterruptProbe)
  992. {
  993. #if ENABLE_NATIVE_CODEGEN
  994. if (doJITLoopBody)
  995. {
  996. newInstance->opProfiledLoopBodyStart = &InterpreterStackFrame::ProfiledLoopBodyStart<true, true>;
  997. newInstance->opLoopBodyStart = &InterpreterStackFrame::LoopBodyStart<true, true>;
  998. }
  999. else
  1000. #endif
  1001. {
  1002. #if ENABLE_PROFILE_INFO
  1003. newInstance->opProfiledLoopBodyStart = &InterpreterStackFrame::ProfiledLoopBodyStart<true, false>;
  1004. #endif
  1005. newInstance->opLoopBodyStart = &InterpreterStackFrame::LoopBodyStart<true, false>;
  1006. }
  1007. }
  1008. else
  1009. {
  1010. #if ENABLE_NATIVE_CODEGEN
  1011. if (doJITLoopBody)
  1012. {
  1013. newInstance->opProfiledLoopBodyStart = &InterpreterStackFrame::ProfiledLoopBodyStart<false, true>;
  1014. newInstance->opLoopBodyStart = &InterpreterStackFrame::LoopBodyStart<false, true>;
  1015. }
  1016. else
  1017. #endif
  1018. {
  1019. #if ENABLE_PROFILE_INFO
  1020. newInstance->opProfiledLoopBodyStart = &InterpreterStackFrame::ProfiledLoopBodyStart<false, false>;
  1021. #endif
  1022. newInstance->opLoopBodyStart = &InterpreterStackFrame::LoopBodyStart<false, false>;
  1023. }
  1024. }
  1025. newInstance->loopHeaderArray = loopHeaderArray;
  1026. newInstance->m_stackAddress = stackAddr;
  1027. #if ENABLE_PROFILE_INFO
  1028. // the savedLoopImplicitCallFlags is allocated at the end of the out param array
  1029. newInstance->savedLoopImplicitCallFlags = nullptr;
  1030. #endif
  1031. char * nextAllocBytes = (char *)(newInstance->m_outParams + this->executeFunction->GetOutParamMaxDepth());
  1032. // If we bailed out, we will use the JIT frame's for..in enumerators
  1033. if (bailedOut || this->executeFunction->GetForInLoopDepth() == 0)
  1034. {
  1035. newInstance->forInObjectEnumerators = nullptr;
  1036. }
  1037. else
  1038. {
  1039. newInstance->forInObjectEnumerators = (ForInObjectEnumerator *)nextAllocBytes;
  1040. nextAllocBytes += sizeof(ForInObjectEnumerator) * this->executeFunction->GetForInLoopDepth();
  1041. }
  1042. if (this->executeFunction->GetInnerScopeCount())
  1043. {
  1044. newInstance->innerScopeArray = (Var*)nextAllocBytes;
  1045. nextAllocBytes += this->executeFunction->GetInnerScopeCount() * sizeof(Var);
  1046. }
  1047. if (this->executeFunction->DoStackNestedFunc() && this->executeFunction->GetNestedCount() != 0)
  1048. {
  1049. newInstance->InitializeStackFunctions((StackScriptFunction *)nextAllocBytes);
  1050. nextAllocBytes = nextAllocBytes + sizeof(StackScriptFunction) * this->executeFunction->GetNestedCount();
  1051. if (!this->bailedOutOfInlinee)
  1052. {
  1053. if (this->executeFunction->DoStackFrameDisplay())
  1054. {
  1055. uint16 envDepth = this->executeFunction->GetEnvDepth();
  1056. Assert(envDepth != (uint16)-1);
  1057. newInstance->localFrameDisplay = (FrameDisplay*)nextAllocBytes;
  1058. nextAllocBytes += sizeof(FrameDisplay) + (envDepth + 1) * sizeof(Var);
  1059. }
  1060. if (this->executeFunction->DoStackScopeSlots())
  1061. {
  1062. uint32 scopeSlots = this->executeFunction->scopeSlotArraySize;
  1063. Assert(scopeSlots != 0);
  1064. ScopeSlots((Var*)nextAllocBytes).SetCount(scopeSlots);
  1065. newInstance->localClosure = nextAllocBytes;
  1066. nextAllocBytes += (scopeSlots + ScopeSlots::FirstSlotIndex) * sizeof(Var);
  1067. }
  1068. }
  1069. }
  1070. #if ENABLE_PROFILE_INFO
  1071. if (Js::DynamicProfileInfo::EnableImplicitCallFlags(this->executeFunction))
  1072. {
  1073. /*
  1074. __analysis_assume(varAllocCount == (k_stackFrameVarCount + localCount + executeFunction->GetOutParamMaxDepth()
  1075. + ((sizeof(ImplicitCallFlags) * executeFunction->GetLoopCount() + sizeof(Var) - 1) / sizeof(Var))));
  1076. */
  1077. newInstance->savedLoopImplicitCallFlags = (ImplicitCallFlags *)nextAllocBytes;
  1078. for (uint i = 0; i < this->executeFunction->GetLoopCount(); i++)
  1079. {
  1080. #pragma prefast(suppress:26015, "Above analysis assume doesn't work")
  1081. newInstance->savedLoopImplicitCallFlags[i] = ImplicitCall_None;
  1082. }
  1083. }
  1084. #endif
  1085. #if DBG
  1086. if (CONFIG_ISENABLED(InitializeInterpreterSlotsWithInvalidStackVarFlag))
  1087. {
  1088. // Fill the local slots with the invalid stack var so that we will crash deterministically if something goes wrong
  1089. for (uint i = 0; i < localCount; ++i)
  1090. {
  1091. newInstance->m_localSlots[i] = invalidStackVar;
  1092. }
  1093. }
  1094. else
  1095. {
  1096. memset(newInstance->m_localSlots, 0, sizeof(Js::Var) * localCount);
  1097. }
  1098. #else
  1099. if (newInstance->m_functionBody->IsInDebugMode())
  1100. {
  1101. // In the debug mode zero out the local slot, so this could prevent locals being uninitialized in the case of setNextStatement.
  1102. memset(newInstance->m_localSlots, 0, sizeof(Js::Var) * localCount);
  1103. }
  1104. // Zero out only the return slot. This is not a user local, so the byte code will not initialize
  1105. // it to "undefined". And it's not an expression temp, so, for instance, a jitted loop body may expect
  1106. // it to be valid on entry to the loop, where "valid" means either a var or null.
  1107. newInstance->SetNonVarReg(0, NULL);
  1108. #endif
  1109. // Wasm doesn't use const table
  1110. if (!executeFunction->IsWasmFunction())
  1111. {
  1112. // Initialize the low end of the local slots from the constant table.
  1113. // Skip the slot for the return value register.
  1114. this->executeFunction->InitConstantSlots(&newInstance->m_localSlots[FunctionBody::FirstRegSlot]);
  1115. }
  1116. // Set local FD/SS pointers to null until after we've successfully probed the stack in the process loop.
  1117. // That way we avoid trying to box these structures before they've been initialized in the byte code.
  1118. if (this->executeFunction->DoStackFrameDisplay())
  1119. {
  1120. newInstance->SetNonVarReg(executeFunction->GetLocalFrameDisplayRegister(), nullptr);
  1121. }
  1122. if (this->executeFunction->DoStackScopeSlots())
  1123. {
  1124. Assert(!executeFunction->HasScopeObject());
  1125. newInstance->SetNonVarReg(executeFunction->GetLocalClosureRegister(), nullptr);
  1126. }
  1127. Var *prestDest = &newInstance->m_localSlots[this->executeFunction->GetConstantCount()];
  1128. if (initParams)
  1129. {
  1130. #if ENABLE_PROFILE_INFO
  1131. Assert(!this->executeFunction->NeedEnsureDynamicProfileInfo());
  1132. #endif
  1133. if (profileParams)
  1134. {
  1135. #if ENABLE_PROFILE_INFO
  1136. Assert(this->executeFunction->HasExecutionDynamicProfileInfo());
  1137. #endif
  1138. FunctionBody* functionBody = this->executeFunction;
  1139. InitializeParams(newInstance, [functionBody](Var param, ArgSlot index)
  1140. {
  1141. #if ENABLE_PROFILE_INFO
  1142. functionBody->GetDynamicProfileInfo()->RecordParameterInfo(functionBody, index - 1, param);
  1143. #endif
  1144. }, &prestDest);
  1145. }
  1146. else
  1147. {
  1148. InitializeParams(newInstance, [](Var param, ArgSlot index) {}, &prestDest);
  1149. }
  1150. }
  1151. if (this->executeFunction->GetHasRestParameter())
  1152. {
  1153. InitializeRestParam(newInstance, prestDest);
  1154. }
  1155. Js::RegSlot envReg = executeFunction->GetEnvRegister();
  1156. if (envReg != Js::Constants::NoRegister && envReg < executeFunction->GetConstantCount())
  1157. {
  1158. Assert(this->executeFunction->GetThisRegisterForEventHandler() == Constants::NoRegister);
  1159. // The correct FD (possibly distinct from the one on the function) is passed in the constant table.
  1160. this->function->SetEnvironment((Js::FrameDisplay*)newInstance->GetNonVarReg(envReg));
  1161. }
  1162. return newInstance;
  1163. }
  1164. template <class Fn>
  1165. void InterpreterStackFrame::Setup::InitializeParams(InterpreterStackFrame * newInstance, Fn callback, Var **pprestDest)
  1166. {
  1167. ArgSlot requiredInParamCount = executeFunction->GetInParamsCount();
  1168. Assert(requiredInParamCount > 1);
  1169. if (this->inSlotsCount >= requiredInParamCount)
  1170. {
  1171. Var * pArg = &newInstance->m_localSlots[executeFunction->GetConstantCount()];
  1172. Var * paGivenSrc = this->inParams + 1;
  1173. ArgSlot paramIndex = 1;
  1174. do
  1175. {
  1176. Var src = *paGivenSrc++;
  1177. callback(src, paramIndex);
  1178. *pArg++ = src;
  1179. paramIndex++;
  1180. }
  1181. while (paramIndex < requiredInParamCount);
  1182. *pprestDest = pArg;
  1183. }
  1184. else
  1185. {
  1186. InitializeParamsAndUndef(newInstance, callback, pprestDest);
  1187. }
  1188. }
  1189. template <class Fn>
  1190. void InterpreterStackFrame::Setup::InitializeParamsAndUndef(InterpreterStackFrame * newInstance, Fn callback, Var **pprestDest)
  1191. {
  1192. Var * pArg = &newInstance->m_localSlots[executeFunction->GetConstantCount()];
  1193. Var * paGivenSrc = this->inParams + 1;
  1194. ArgSlot requiredInParamCount = executeFunction->GetInParamsCount();
  1195. ArgSlot paramIndex = 1;
  1196. while (paramIndex < this->inSlotsCount)
  1197. {
  1198. Var src = *paGivenSrc++;
  1199. callback(src, paramIndex);
  1200. *pArg++ = src;
  1201. paramIndex++;
  1202. }
  1203. Var varUndef = executeFunction->GetScriptContext()->GetLibrary()->GetUndefined();
  1204. do
  1205. {
  1206. callback(varUndef, paramIndex);
  1207. *pArg++ = varUndef;
  1208. paramIndex++;
  1209. }
  1210. while (paramIndex < requiredInParamCount);
  1211. *pprestDest = pArg;
  1212. }
  1213. void InterpreterStackFrame::Setup::InitializeRestParam(InterpreterStackFrame * newInstance, Var *dest)
  1214. {
  1215. Var *src = this->inParams + executeFunction->GetInParamsCount();
  1216. if (this->inSlotsCount > executeFunction->GetInParamsCount())
  1217. {
  1218. // Create the rest array and copy the args directly into the contiguous head segment.
  1219. int excess = this->inSlotsCount - executeFunction->GetInParamsCount();
  1220. *dest = JavascriptArray::OP_NewScArray(excess, executeFunction->GetScriptContext());
  1221. JavascriptArray *array = static_cast<JavascriptArray *>(*dest);
  1222. Var *elements = ((SparseArraySegment<Var>*)array->GetHead())->elements;
  1223. js_memcpy_s(elements, excess * sizeof(Var), src, excess * sizeof(Var));
  1224. }
  1225. else
  1226. {
  1227. // Rest is an empty array when there are no excess parameters.
  1228. *dest = JavascriptArray::OP_NewScArray(0, executeFunction->GetScriptContext());
  1229. }
  1230. }
  1231. FrameDisplay * InterpreterStackFrame::GetEnvForEvalCode()
  1232. {
  1233. FrameDisplay *pScope;
  1234. if (m_functionBody->GetIsStrictMode() && m_functionBody->GetIsGlobalFunc())
  1235. {
  1236. pScope = this->GetLocalFrameDisplay();
  1237. }
  1238. else
  1239. {
  1240. pScope = (FrameDisplay*)this->LdEnv();
  1241. }
  1242. return pScope;
  1243. }
  1244. void InterpreterStackFrame::InitializeClosures()
  1245. {
  1246. FunctionBody *executeFunction = this->function->GetFunctionBody();
  1247. Var environment;
  1248. if (executeFunction->IsParamAndBodyScopeMerged())
  1249. {
  1250. this->SetIsParamScopeDone(true);
  1251. }
  1252. RegSlot thisRegForEventHandler = executeFunction->GetThisRegisterForEventHandler();
  1253. if (thisRegForEventHandler != Constants::NoRegister)
  1254. {
  1255. Var varThis = OP_ArgIn0();
  1256. SetReg(thisRegForEventHandler, varThis);
  1257. environment = JavascriptOperators::OP_LdHandlerScope(varThis, GetScriptContext());
  1258. this->SetEnv((FrameDisplay*)environment);
  1259. }
  1260. else if (this->paramClosure != nullptr)
  1261. {
  1262. // When paramClosure is non-null we are calling this method to initialize the closure for body scope.
  1263. // In this case we have to use the param scope's closure as the parent for the body scope's frame display.
  1264. Assert(!executeFunction->IsParamAndBodyScopeMerged());
  1265. environment = this->GetLocalFrameDisplay();
  1266. }
  1267. else
  1268. {
  1269. environment = this->LdEnv();
  1270. }
  1271. Var funcExprScope = nullptr;
  1272. Js::RegSlot funcExprScopeReg = executeFunction->GetFuncExprScopeRegister();
  1273. if (funcExprScopeReg != Constants::NoRegister && this->paramClosure == nullptr)
  1274. {
  1275. // t0 = NewPseudoScope
  1276. // t1 = LdFrameDisplay t0 env
  1277. funcExprScope = JavascriptOperators::OP_NewPseudoScope(GetScriptContext());
  1278. SetReg(funcExprScopeReg, funcExprScope);
  1279. }
  1280. RegSlot closureReg = executeFunction->GetLocalClosureRegister();
  1281. if (closureReg != Js::Constants::NoRegister)
  1282. {
  1283. Assert(closureReg >= executeFunction->GetConstantCount());
  1284. if (executeFunction->HasScopeObject())
  1285. {
  1286. this->NewScopeObject();
  1287. }
  1288. else
  1289. {
  1290. this->NewScopeSlots();
  1291. }
  1292. this->SetNonVarReg(closureReg, nullptr);
  1293. }
  1294. Js::RegSlot frameDisplayReg = executeFunction->GetLocalFrameDisplayRegister();
  1295. if (frameDisplayReg != Js::Constants::NoRegister)
  1296. {
  1297. Assert(frameDisplayReg >= executeFunction->GetConstantCount());
  1298. if (funcExprScope != nullptr)
  1299. {
  1300. environment = OP_LdFrameDisplay(funcExprScope, environment, GetScriptContext());
  1301. }
  1302. if (closureReg != Js::Constants::NoRegister)
  1303. {
  1304. void *argHead = this->GetLocalClosure();
  1305. environment = this->NewFrameDisplay(argHead, environment);
  1306. }
  1307. this->SetLocalFrameDisplay((Js::FrameDisplay*)environment);
  1308. this->SetNonVarReg(frameDisplayReg, nullptr);
  1309. }
  1310. this->closureInitDone = true;
  1311. }
  1312. #ifdef _M_IX86
  1313. #ifdef ASMJS_PLAT
  1314. int InterpreterStackFrame::GetAsmJsArgSize(AsmJsCallStackLayout* stack)
  1315. {
  1316. JavascriptFunction * func = stack->functionObject;
  1317. AsmJsFunctionInfo* asmInfo = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  1318. uint argSize = (uint)(asmInfo->GetArgByteSize());
  1319. argSize = ::Math::Align<int32>(argSize, 8);
  1320. // 2 * sizeof(Var) is for functionObject, and another push that DynamicInterpreterThunk does
  1321. return argSize + 2 * sizeof(Var);
  1322. }
  1323. int InterpreterStackFrame::GetDynamicRetType(AsmJsCallStackLayout* stack)
  1324. {
  1325. return GetRetType(stack->functionObject);
  1326. }
  1327. int InterpreterStackFrame::GetRetType(JavascriptFunction* func)
  1328. {
  1329. AsmJsFunctionInfo* asmInfo = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  1330. return asmInfo->GetReturnType().which();
  1331. }
  1332. DWORD InterpreterStackFrame::GetAsmJsReturnValueOffset(AsmJsCallStackLayout* stack)
  1333. {
  1334. JavascriptFunction * func = stack->functionObject;
  1335. ScriptContext* scriptContext = func->GetScriptContext();
  1336. return (DWORD)scriptContext + ScriptContext::GetAsmJsReturnValueOffset();
  1337. }
  1338. #ifdef ASMJS_PLAT
  1339. /*
  1340. AsmInterpreterThunk
  1341. -------------------
  1342. This is the entrypoint for all Asm Interpreter calls (external and internal)
  1343. TODO - Make this a dynamic Interpreter thunk to support ETW
  1344. Functionality:
  1345. 1) Prolog
  1346. 2) call AsmInterpreter passing the function object
  1347. 3) Get The return type
  1348. 4) Check for Double or Float return type
  1349. 5) If true then retrieve the value stored at a constant offset from the ScriptContext
  1350. 6) Get Argument Size for callee cleanup
  1351. 7) EpiLog
  1352. a) Retrieve the frame pointer
  1353. b) Store the return address in register (edx)
  1354. c) Clean the arguments based on the arguments size
  1355. d) push the return address back into the stack
  1356. */
  1357. __declspec(naked)
  1358. void InterpreterStackFrame::InterpreterAsmThunk(AsmJsCallStackLayout* layout)
  1359. {
  1360. enum {
  1361. IsFloat = 1 << AsmJsRetType::Float,
  1362. IsDouble = 1 << AsmJsRetType::Double,
  1363. IsInt64 = 1 << AsmJsRetType::Int64,
  1364. IsSimd =
  1365. 1 << AsmJsRetType::Int32x4 |
  1366. 1 << AsmJsRetType::Bool32x4 |
  1367. 1 << AsmJsRetType::Bool16x8 |
  1368. 1 << AsmJsRetType::Bool8x16 |
  1369. 1 << AsmJsRetType::Float32x4 |
  1370. 1 << AsmJsRetType::Float64x2 |
  1371. 1 << AsmJsRetType::Int16x8 |
  1372. 1 << AsmJsRetType::Int8x16 |
  1373. 1 << AsmJsRetType::Uint32x4 |
  1374. 1 << AsmJsRetType::Uint16x8 |
  1375. 1 << AsmJsRetType::Uint8x16,
  1376. CannotUseEax = IsFloat | IsDouble | IsInt64 | IsSimd
  1377. };
  1378. //Prolog
  1379. __asm
  1380. {
  1381. //Prologue
  1382. push ebp;
  1383. mov ebp, esp;
  1384. push layout; // push stack layout
  1385. call InterpreterStackFrame::AsmJsInterpreter;
  1386. push eax; // push the return value into the stack
  1387. push layout; // push arg1
  1388. call InterpreterStackFrame::GetDynamicRetType;
  1389. // setup return type mask from enum. e.g.: 3 => 0x8
  1390. mov ecx, eax;
  1391. mov eax, 1
  1392. shl eax, cl;
  1393. and eax, CannotUseEax; // Keep only types that need to read from memory
  1394. jz end; // if nothing is left, that means we simply use eax as return value
  1395. push eax; // save return type mask
  1396. push layout; // push arg1
  1397. call InterpreterStackFrame::GetAsmJsReturnValueOffset;
  1398. pop ecx; // restore return type mask
  1399. and ecx, ~IsFloat; // Remove float bit
  1400. jz ToXmmWord; // if nothing is left, that means the return type is float
  1401. and ecx, ~IsDouble; // Remove double bit
  1402. jz ToXmmDWord; // if nothing is left, that means the return type is double
  1403. and ecx, ~IsInt64; // Remove int64 bit
  1404. jz readHighWord; // if nothing is left, that means the return type is int64
  1405. jmp doSimd; // Otherwise, the return type is simd
  1406. ToXmmWord:
  1407. // float
  1408. cvtsd2ss xmm0, [eax];
  1409. jmp end;
  1410. ToXmmDWord:
  1411. // double
  1412. movsd xmm0, [eax];
  1413. jmp end;
  1414. readHighWord:
  1415. // save high int64 bits into ecx
  1416. mov edx, [eax + 4];
  1417. jmp end;
  1418. doSimd:
  1419. // simd value
  1420. movups xmm0, [eax];
  1421. end:
  1422. push edx; // save possible int64 return value
  1423. push layout;
  1424. call InterpreterStackFrame::GetAsmJsArgSize;
  1425. mov ecx, eax;
  1426. pop edx; // restore possible int64 return value
  1427. pop eax; // pop the return value from AsmJsInterpreter to eax
  1428. // Epilog, callee cleanup
  1429. mov esp, ebp;
  1430. pop ebp;
  1431. // we need to move stack around in order to do callee cleanup
  1432. // unfortunately, we don't really have enough registers to do this cleanly
  1433. //
  1434. // we are rearranging the stack from this:
  1435. // 0x14 caller push scriptArg1
  1436. // 0x10 caller push functionObject
  1437. // 0x0C DynamicInterpreterThunk return address
  1438. // 0x08 DynamicInterpreterThunk push ebp
  1439. // 0x04 DynamicInterpreterThunk push functionObject
  1440. // 0x00 InterpreterAsmThunk return address <- stack pointer
  1441. // to this:
  1442. // 0x14 DynamicInterpreterThunk return address
  1443. // 0x10 DynamicInterpreterThunk push ebp
  1444. // 0x0C InterpreterAsmThunk return address <- stack pointer
  1445. push eax; // save eax
  1446. push edx; // save edx
  1447. // we have to do +0x8 on all stack addresses because we saved 2 registers
  1448. lea eax, [esp + ecx * 1 + (0x8 + 0x8)]; // eax will be our stack destination. we need to move backwards because memory might overlap
  1449. mov edx, [esp + (0xC + 0x8)];
  1450. mov [eax], edx; // move the dynamic interpreter thunk return location
  1451. sub eax, 0x4;
  1452. mov edx, [esp + (0x8 + 0x8)];
  1453. mov [eax], edx; // move the dynamic interpreter thunk "push ebp" location
  1454. // skip "push functionObject"
  1455. sub eax, 0x4;
  1456. mov edx, [esp + (0x0 + 0x8)];
  1457. mov [eax], edx; // move the return location
  1458. pop edx; // restore possible int64 return value
  1459. pop eax; // restore return value
  1460. add esp, ecx; // cleanup arguments
  1461. ret;
  1462. }
  1463. }
  1464. #endif
  1465. #endif
  1466. #endif
  1467. #if DYNAMIC_INTERPRETER_THUNK
  1468. #ifdef _M_IX86
  1469. __declspec(naked)
  1470. Var InterpreterStackFrame::DelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
  1471. {
  1472. __asm
  1473. {
  1474. push ebp
  1475. mov ebp, esp
  1476. push [esp+8] // push function object
  1477. call InterpreterStackFrame::EnsureDynamicInterpreterThunk;
  1478. #ifdef _CONTROL_FLOW_GUARD
  1479. // verify that the call target is valid
  1480. push eax
  1481. mov ecx, eax
  1482. call[__guard_check_icall_fptr]
  1483. pop eax
  1484. #endif
  1485. pop ebp
  1486. jmp eax
  1487. }
  1488. }
  1489. #endif
  1490. #endif
  1491. #if ENABLE_PROFILE_INFO
  1492. JavascriptMethod InterpreterStackFrame::EnsureDynamicInterpreterThunk(Js::ScriptFunction * function)
  1493. {
  1494. #if DYNAMIC_INTERPRETER_THUNK
  1495. Assert(function);
  1496. Js::FunctionBody *functionBody = function->GetFunctionBody();
  1497. JavascriptMethod entrypoint = functionBody->EnsureDynamicInterpreterThunk(function->GetFunctionEntryPointInfo());
  1498. Assert(!IsDelayDynamicInterpreterThunk(functionBody->GetDirectEntryPoint(function->GetEntryPointInfo())));
  1499. if (function->GetEntryPoint() == InterpreterStackFrame::DelayDynamicInterpreterThunk)
  1500. {
  1501. // If we are not profiling, or the function object is not cross site, this is the direct entry point.
  1502. // Change the entry point on the object
  1503. Assert(functionBody->GetDirectEntryPoint(function->GetEntryPointInfo()) == entrypoint);
  1504. function->ChangeEntryPoint(function->GetEntryPointInfo(), entrypoint);
  1505. }
  1506. // Return the original entry point to be called
  1507. return entrypoint;
  1508. #else
  1509. return function->GetEntryPoint();
  1510. #endif
  1511. }
  1512. #endif
  1513. bool InterpreterStackFrame::IsDelayDynamicInterpreterThunk(JavascriptMethod entryPoint)
  1514. {
  1515. return
  1516. #if DYNAMIC_INTERPRETER_THUNK
  1517. #if _M_X64
  1518. entryPoint == InterpreterStackFrame::AsmJsDelayDynamicInterpreterThunk ||
  1519. #endif
  1520. entryPoint == InterpreterStackFrame::DelayDynamicInterpreterThunk;
  1521. #else
  1522. false;
  1523. #endif
  1524. }
  1525. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1526. THREAD_LOCAL int InterpreterThunkStackCountTracker::s_count = 0;
  1527. #endif
  1528. #if DYNAMIC_INTERPRETER_THUNK
  1529. Var InterpreterStackFrame::InterpreterThunk(JavascriptCallStackLayout* layout)
  1530. {
  1531. Js::ScriptFunction * function = Js::ScriptFunction::FromVar(layout->functionObject);
  1532. Js::ArgumentReader args(&layout->callInfo, layout->args);
  1533. void* localReturnAddress = _ReturnAddress();
  1534. void* localAddressOfReturnAddress = _AddressOfReturnAddress();
  1535. return InterpreterHelper(function, args, localReturnAddress, localAddressOfReturnAddress);
  1536. }
  1537. #else
  1538. #pragma optimize("", off)
  1539. Var InterpreterStackFrame::InterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
  1540. {
  1541. ARGUMENTS(args, callInfo);
  1542. void* localReturnAddress = _ReturnAddress();
  1543. void* localAddressOfReturnAddress = _AddressOfReturnAddress();
  1544. Assert(ScriptFunction::Is(function));
  1545. return InterpreterHelper(ScriptFunction::FromVar(function), args, localReturnAddress, localAddressOfReturnAddress);
  1546. }
  1547. #pragma optimize("", on)
  1548. #endif
  1549. Var InterpreterStackFrame::InterpreterHelper(ScriptFunction* function, ArgumentReader args, void* returnAddress, void* addressOfReturnAddress, const bool isAsmJs)
  1550. {
  1551. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1552. // Support for simulating partially initialized interpreter stack frame.
  1553. InterpreterThunkStackCountTracker tracker;
  1554. if (CONFIG_ISENABLED(InjectPartiallyInitializedInterpreterFrameErrorFlag) &&
  1555. CONFIG_FLAG(InjectPartiallyInitializedInterpreterFrameError) == InterpreterThunkStackCountTracker::GetCount())
  1556. {
  1557. switch (CONFIG_FLAG(InjectPartiallyInitializedInterpreterFrameErrorType))
  1558. {
  1559. case 0:
  1560. DebugBreak();
  1561. break;
  1562. case 1:
  1563. Js::JavascriptError::MapAndThrowError(function->GetScriptContext(), VBSERR_InternalError);
  1564. break;
  1565. default:
  1566. DebugBreak();
  1567. }
  1568. }
  1569. #endif
  1570. ScriptContext* functionScriptContext = function->GetScriptContext();
  1571. ThreadContext * threadContext = functionScriptContext->GetThreadContext();
  1572. Assert(!threadContext->IsDisableImplicitException());
  1573. functionScriptContext->VerifyAlive(!function->IsExternal());
  1574. Assert(threadContext->IsScriptActive());
  1575. Assert(threadContext->IsInScript());
  1576. FunctionBody* executeFunction = JavascriptFunction::FromVar(function)->GetFunctionBody();
  1577. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1578. if (!isAsmJs && executeFunction->IsInDebugMode() != functionScriptContext->IsScriptContextInDebugMode()) // debug mode mismatch
  1579. {
  1580. if (executeFunction->GetUtf8SourceInfo()->GetIsLibraryCode())
  1581. {
  1582. Assert(!executeFunction->IsInDebugMode()); // Library script byteCode is never in debug mode
  1583. }
  1584. else
  1585. {
  1586. Throw::FatalInternalError();
  1587. }
  1588. }
  1589. #endif
  1590. if (executeFunction->GetInterpretedCount() == 0)
  1591. {
  1592. executeFunction->TraceInterpreterExecutionMode();
  1593. }
  1594. class AutoRestore
  1595. {
  1596. private:
  1597. ThreadContext *const threadContext;
  1598. const uint8 savedLoopDepth;
  1599. public:
  1600. AutoRestore(ThreadContext *const threadContext, FunctionBody *const executeFunction)
  1601. : threadContext(threadContext),
  1602. savedLoopDepth(threadContext->LoopDepth())
  1603. {
  1604. if (savedLoopDepth != 0 && !executeFunction->GetIsAsmJsFunction())
  1605. {
  1606. executeFunction->SetWasCalledFromLoop();
  1607. }
  1608. }
  1609. ~AutoRestore()
  1610. {
  1611. threadContext->SetLoopDepth(savedLoopDepth);
  1612. }
  1613. } autoRestore(threadContext, executeFunction);
  1614. #if ENABLE_PROFILE_INFO
  1615. DynamicProfileInfo * dynamicProfileInfo = nullptr;
  1616. const bool doProfile = executeFunction->GetInterpreterExecutionMode(false) == ExecutionMode::ProfilingInterpreter ||
  1617. (executeFunction->IsInDebugMode() && DynamicProfileInfo::IsEnabled(executeFunction));
  1618. if (doProfile)
  1619. {
  1620. #if !DYNAMIC_INTERPRETER_THUNK
  1621. executeFunction->EnsureDynamicProfileInfo();
  1622. #endif
  1623. dynamicProfileInfo = executeFunction->GetDynamicProfileInfo();
  1624. threadContext->ClearImplicitCallFlags();
  1625. }
  1626. #else
  1627. const bool doProfile = false;
  1628. #endif
  1629. executeFunction->IncreaseInterpretedCount();
  1630. #ifdef BGJIT_STATS
  1631. functionScriptContext->interpretedCount++;
  1632. functionScriptContext->maxFuncInterpret = max(functionScriptContext->maxFuncInterpret, executeFunction->GetInterpretedCount());
  1633. #endif
  1634. AssertMsg(!executeFunction->IsDeferredParseFunction(),
  1635. "Non-intrinsic functions must provide byte-code to execute");
  1636. executeFunction->BeginExecution();
  1637. bool fReleaseAlloc = false;
  1638. InterpreterStackFrame* newInstance = nullptr;
  1639. Var* allocation = nullptr;
  1640. if (!isAsmJs && executeFunction->IsCoroutine())
  1641. {
  1642. // If the FunctionBody is a generator then this call is being made by one of the three
  1643. // generator resuming methods: next(), throw(), or return(). They all pass the generator
  1644. // object as the first of two arguments. The real user arguments are obtained from the
  1645. // generator object. The second argument is the ResumeYieldData which is only needed
  1646. // when resuming a generator and so it only used here if a frame already exists on the
  1647. // generator object.
  1648. 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");
  1649. JavascriptGenerator* generator = JavascriptGenerator::FromVar(args[0]);
  1650. newInstance = generator->GetFrame();
  1651. if (newInstance != nullptr)
  1652. {
  1653. ResumeYieldData* resumeYieldData = static_cast<ResumeYieldData*>(args[1]);
  1654. newInstance->SetNonVarReg(executeFunction->GetYieldRegister(), resumeYieldData);
  1655. // The debugger relies on comparing stack addresses of frames to decide when a step_out is complete so
  1656. // give the InterpreterStackFrame a legit enough stack address to make this comparison work.
  1657. newInstance->m_stackAddress = reinterpret_cast<DWORD_PTR>(&generator);
  1658. }
  1659. else
  1660. {
  1661. //
  1662. // Allocate a new InterpreterStackFrame instance on the recycler heap.
  1663. // It will live with the JavascriptGenerator object.
  1664. //
  1665. Arguments generatorArgs = generator->GetArguments();
  1666. InterpreterStackFrame::Setup setup(function, generatorArgs);
  1667. size_t varAllocCount = setup.GetAllocationVarCount();
  1668. size_t varSizeInBytes = varAllocCount * sizeof(Var);
  1669. DWORD_PTR stackAddr = reinterpret_cast<DWORD_PTR>(&generator); // as mentioned above, use any stack address from this frame to ensure correct debugging functionality
  1670. Var loopHeaderArray = executeFunction->GetHasAllocatedLoopHeaders() ? executeFunction->GetLoopHeaderArrayPtr() : nullptr;
  1671. allocation = RecyclerNewPlus(functionScriptContext->GetRecycler(), varSizeInBytes, Var);
  1672. AnalysisAssert(allocation);
  1673. #if DBG
  1674. // Allocate invalidVar on GC instead of stack since this InterpreterStackFrame will out live the current real frame
  1675. Js::RecyclableObject* invalidVar = (Js::RecyclableObject*)RecyclerNewPlusLeaf(functionScriptContext->GetRecycler(), sizeof(Js::RecyclableObject), Var);
  1676. AnalysisAssert(invalidVar);
  1677. memset(reinterpret_cast<void*>(invalidVar), 0xFE, sizeof(Js::RecyclableObject));
  1678. newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns(), doProfile, loopHeaderArray, stackAddr, invalidVar);
  1679. #else
  1680. newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns(), doProfile, loopHeaderArray, stackAddr);
  1681. #endif
  1682. newInstance->m_reader.Create(executeFunction);
  1683. generator->SetFrame(newInstance);
  1684. }
  1685. }
  1686. else
  1687. {
  1688. InterpreterStackFrame::Setup setup(function, args);
  1689. size_t varAllocCount = setup.GetAllocationVarCount();
  1690. size_t varSizeInBytes = varAllocCount * sizeof(Var);
  1691. //
  1692. // Allocate a new InterpreterStackFrame instance on the interpreter's virtual stack.
  1693. //
  1694. DWORD_PTR stackAddr;
  1695. // If the locals area exceeds a certain limit, allocate it from a private arena rather than
  1696. // this frame. The current limit is based on an old assert on the number of locals we would allow here.
  1697. if (varAllocCount > InterpreterStackFrame::LocalsThreshold)
  1698. {
  1699. ArenaAllocator *tmpAlloc = nullptr;
  1700. fReleaseAlloc = functionScriptContext->EnsureInterpreterArena(&tmpAlloc);
  1701. allocation = (Var*)tmpAlloc->Alloc(varSizeInBytes);
  1702. 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)
  1703. }
  1704. else
  1705. {
  1706. PROBE_STACK_PARTIAL_INITIALIZED_INTERPRETER_FRAME(functionScriptContext, Js::Constants::MinStackInterpreter + varSizeInBytes);
  1707. allocation = (Var*)_alloca(varSizeInBytes);
  1708. stackAddr = reinterpret_cast<DWORD_PTR>(allocation);
  1709. }
  1710. /*
  1711. * If the function has any loop headers, we allocate an array for the loop headers wrappers, and
  1712. * reference the wrappers in the array. We then push the pointer to the array onto the stack itself.
  1713. * We do this so that while the function is being interpreted, we don't want the jitted loop
  1714. * bodies to be collected, even if the loop body isn't being executed. The loop body will
  1715. * get collected when the function has been JITted, and when the function exits the interpreter.
  1716. * The array contains nulls if the loop body isn't jitted (or hasn't been jitted yet) but
  1717. * it's cheaper to just copy them all into the recycler array rather than just the ones that
  1718. * have been jitted.
  1719. */
  1720. Var loopHeaderArray = nullptr;
  1721. if (executeFunction->GetHasAllocatedLoopHeaders())
  1722. {
  1723. // Loop header array is recycler allocated, so we push it on the stack
  1724. // When we scan the stack, we'll recognize it as a recycler allocated
  1725. // object, and mark it's contents and keep the individual loop header
  1726. // wrappers alive
  1727. loopHeaderArray = executeFunction->GetLoopHeaderArrayPtr();
  1728. }
  1729. #if DBG
  1730. Js::RecyclableObject * invalidStackVar = (Js::RecyclableObject*)_alloca(sizeof(Js::RecyclableObject));
  1731. memset(reinterpret_cast<void*>(invalidStackVar), 0xFE, sizeof(Js::RecyclableObject));
  1732. newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns() && !isAsmJs, doProfile, loopHeaderArray, stackAddr, invalidStackVar);
  1733. #else
  1734. newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns() && !isAsmJs, doProfile, loopHeaderArray, stackAddr);
  1735. #endif
  1736. newInstance->m_reader.Create(executeFunction);
  1737. }
  1738. //
  1739. // Execute the function's byte-code, returning the return-value:
  1740. // - Mark that the function is current executing and may not be modified.
  1741. //
  1742. #if ENABLE_TTD
  1743. TTD::TTDExceptionFramePopper exceptionFramePopper;
  1744. if(SHOULD_DO_TTD_STACK_STMT_OP(functionScriptContext))
  1745. {
  1746. bool isInFinally = ((newInstance->m_flags & Js::InterpreterStackFrameFlags_WithinFinallyBlock) == Js::InterpreterStackFrameFlags_WithinFinallyBlock);
  1747. threadContext->TTDLog->PushCallEvent(function, args.Info.Count, args.Values, isInFinally);
  1748. exceptionFramePopper.PushInfo(threadContext->TTDLog, function);
  1749. }
  1750. #endif
  1751. Var aReturn = nullptr;
  1752. {
  1753. if (!isAsmJs && executeFunction->IsInDebugMode())
  1754. {
  1755. #if DYNAMIC_INTERPRETER_THUNK
  1756. PushPopFrameHelper pushPopFrameHelper(newInstance, returnAddress, addressOfReturnAddress);
  1757. aReturn = newInstance->DebugProcess();
  1758. #else
  1759. aReturn = newInstance->DebugProcessThunk(_ReturnAddress(), _AddressOfReturnAddress());
  1760. #endif
  1761. }
  1762. else
  1763. {
  1764. #if DYNAMIC_INTERPRETER_THUNK
  1765. PushPopFrameHelper pushPopFrameHelper(newInstance, returnAddress, addressOfReturnAddress);
  1766. aReturn = newInstance->Process();
  1767. #else
  1768. aReturn = newInstance->ProcessThunk(_ReturnAddress(), _AddressOfReturnAddress());
  1769. #endif
  1770. }
  1771. }
  1772. executeFunction->EndExecution();
  1773. #if ENABLE_TTD
  1774. if(SHOULD_DO_TTD_STACK_STMT_OP(functionScriptContext))
  1775. {
  1776. exceptionFramePopper.PopInfo();
  1777. threadContext->TTDLog->PopCallEvent(function, aReturn);
  1778. }
  1779. #endif
  1780. if (fReleaseAlloc)
  1781. {
  1782. functionScriptContext->ReleaseInterpreterArena();
  1783. }
  1784. #if ENABLE_PROFILE_INFO
  1785. if (doProfile)
  1786. {
  1787. dynamicProfileInfo->RecordImplicitCallFlags(threadContext->GetImplicitCallFlags());
  1788. }
  1789. #endif
  1790. if (isAsmJs)
  1791. {
  1792. return newInstance;
  1793. }
  1794. return aReturn;
  1795. }
  1796. #ifdef ASMJS_PLAT
  1797. template<>
  1798. int InterpreterStackFrame::GetAsmJsRetVal<int>(InterpreterStackFrame* instance)
  1799. {
  1800. return instance->m_localIntSlots[0];
  1801. }
  1802. template<>
  1803. int64 InterpreterStackFrame::GetAsmJsRetVal<int64>(InterpreterStackFrame* instance)
  1804. {
  1805. return instance->m_localInt64Slots[0];
  1806. }
  1807. template<>
  1808. double InterpreterStackFrame::GetAsmJsRetVal<double>(InterpreterStackFrame* instance)
  1809. {
  1810. return instance->m_localDoubleSlots[0];
  1811. }
  1812. template<>
  1813. float InterpreterStackFrame::GetAsmJsRetVal<float>(InterpreterStackFrame* instance)
  1814. {
  1815. return instance->m_localFloatSlots[0];
  1816. }
  1817. template<>
  1818. AsmJsSIMDValue InterpreterStackFrame::GetAsmJsRetVal<AsmJsSIMDValue>(InterpreterStackFrame* instance)
  1819. {
  1820. return instance->m_localSimdSlots[0];
  1821. }
  1822. #if _M_IX86 || _M_X64
  1823. template<>
  1824. X86SIMDValue InterpreterStackFrame::GetAsmJsRetVal<X86SIMDValue>(InterpreterStackFrame* instance)
  1825. {
  1826. return X86SIMDValue::ToX86SIMDValue(instance->m_localSimdSlots[0]);
  1827. }
  1828. #endif
  1829. #if _M_IX86
  1830. int InterpreterStackFrame::AsmJsInterpreter(AsmJsCallStackLayout* stack)
  1831. {
  1832. ScriptFunction * function = (ScriptFunction*)stack->functionObject;
  1833. Var* paramsAddr = stack->args;
  1834. int flags = CallFlags_Value;
  1835. ArgSlot nbArgs = UInt16Math::Add(function->GetFunctionBody()->GetAsmJsFunctionInfo()->GetArgCount(), 1);
  1836. CallInfo callInfo((CallFlags)flags, nbArgs);
  1837. ArgumentReader args(&callInfo, paramsAddr);
  1838. void* returnAddress = _ReturnAddress();
  1839. void* addressOfReturnAddress = _AddressOfReturnAddress();
  1840. #if ENABLE_PROFILE_INFO
  1841. function->GetFunctionBody()->EnsureDynamicProfileInfo();
  1842. #endif
  1843. InterpreterStackFrame* newInstance = (InterpreterStackFrame*)InterpreterHelper(function, args, returnAddress, addressOfReturnAddress, true);
  1844. //Handle return value
  1845. AsmJsRetType::Which retType = (AsmJsRetType::Which) GetRetType(function);
  1846. int retVal = 0;
  1847. switch (retType)
  1848. {
  1849. case AsmJsRetType::Int32x4:
  1850. case AsmJsRetType::Bool32x4:
  1851. case AsmJsRetType::Bool16x8:
  1852. case AsmJsRetType::Bool8x16:
  1853. case AsmJsRetType::Float32x4:
  1854. case AsmJsRetType::Float64x2:
  1855. case AsmJsRetType::Int16x8:
  1856. case AsmJsRetType::Int8x16:
  1857. case AsmJsRetType::Uint32x4:
  1858. case AsmJsRetType::Uint16x8:
  1859. case AsmJsRetType::Uint8x16:
  1860. if (function->GetScriptContext()->GetConfig()->IsSimdjsEnabled())
  1861. {
  1862. function->GetScriptContext()->asmJsReturnValue.simdVal = GetAsmJsRetVal<AsmJsSIMDValue>(newInstance);
  1863. break;
  1864. }
  1865. Assert(UNREACHED);
  1866. // double return
  1867. case AsmJsRetType::Double:
  1868. function->GetScriptContext()->asmJsReturnValue.dbVal = GetAsmJsRetVal<double>(newInstance);
  1869. break;
  1870. // float return
  1871. case AsmJsRetType::Float:
  1872. function->GetScriptContext()->asmJsReturnValue.dbVal = (double)GetAsmJsRetVal<float>(newInstance);
  1873. break;
  1874. // signed or void return
  1875. case AsmJsRetType::Signed:
  1876. case AsmJsRetType::Void:
  1877. retVal = GetAsmJsRetVal<int>(newInstance);
  1878. break;
  1879. case AsmJsRetType::Int64:
  1880. {
  1881. int64 int64RetVal = GetAsmJsRetVal<int64>(newInstance);
  1882. function->GetScriptContext()->asmJsReturnValue.int64Val = int64RetVal;
  1883. // put the lower bits into eax
  1884. // we'll read the higher bits from memory
  1885. retVal = (int)int64RetVal;
  1886. break;
  1887. }
  1888. default:
  1889. Assume(false);
  1890. }
  1891. return retVal;
  1892. }
  1893. #elif _M_X64
  1894. typedef double(*AsmJsInterpreterDoubleEP)(AsmJsCallStackLayout*, void *);
  1895. typedef float(*AsmJsInterpreterFloatEP)(AsmJsCallStackLayout*, void *);
  1896. typedef int(*AsmJsInterpreterIntEP)(AsmJsCallStackLayout*, void *);
  1897. typedef int64(*AsmJsInterpreterInt64EP)(AsmJsCallStackLayout*, void *);
  1898. void * InterpreterStackFrame::GetAsmJsInterpreterEntryPoint(AsmJsCallStackLayout* stack)
  1899. {
  1900. JavascriptFunction * function = stack->functionObject;
  1901. void * entryPoint = nullptr;
  1902. switch (function->GetFunctionBody()->GetAsmJsFunctionInfo()->GetReturnType().which())
  1903. {
  1904. case Js::AsmJsRetType::Double:
  1905. {
  1906. entryPoint = (void*)(AsmJsInterpreterDoubleEP)Js::InterpreterStackFrame::AsmJsInterpreter < double > ;
  1907. break;
  1908. }
  1909. case Js::AsmJsRetType::Float:
  1910. {
  1911. entryPoint = (void*)(AsmJsInterpreterFloatEP)Js::InterpreterStackFrame::AsmJsInterpreter < float > ;
  1912. break;
  1913. }
  1914. case Js::AsmJsRetType::Signed:
  1915. case Js::AsmJsRetType::Void:
  1916. {
  1917. entryPoint = (void*)(AsmJsInterpreterIntEP)Js::InterpreterStackFrame::AsmJsInterpreter < int > ;
  1918. break;
  1919. }
  1920. case Js::AsmJsRetType::Int64:
  1921. {
  1922. entryPoint = (void*)(AsmJsInterpreterInt64EP)Js::InterpreterStackFrame::AsmJsInterpreter < int64 > ;
  1923. break;
  1924. }
  1925. case Js::AsmJsRetType::Int32x4:
  1926. case Js::AsmJsRetType::Bool32x4:
  1927. case Js::AsmJsRetType::Bool16x8:
  1928. case Js::AsmJsRetType::Bool8x16:
  1929. case Js::AsmJsRetType::Float32x4:
  1930. case Js::AsmJsRetType::Float64x2:
  1931. case Js::AsmJsRetType::Int16x8:
  1932. case Js::AsmJsRetType::Int8x16:
  1933. case Js::AsmJsRetType::Uint32x4:
  1934. case Js::AsmJsRetType::Uint16x8:
  1935. case Js::AsmJsRetType::Uint8x16:
  1936. {
  1937. entryPoint = (void*)Js::InterpreterStackFrame::AsmJsInterpreterSimdJs;
  1938. break;
  1939. }
  1940. default:
  1941. Assume(UNREACHED);
  1942. }
  1943. return entryPoint;
  1944. }
  1945. template<typename T>
  1946. T InterpreterStackFrame::AsmJsInterpreter(AsmJsCallStackLayout* layout)
  1947. {
  1948. Js::ScriptFunction * function = Js::ScriptFunction::FromVar(layout->functionObject);
  1949. int flags = CallFlags_Value;
  1950. ArgSlot nbArgs = UInt16Math::Add(function->GetFunctionBody()->GetAsmJsFunctionInfo()->GetArgCount(), 1);
  1951. CallInfo callInfo((CallFlags)flags, nbArgs);
  1952. ArgumentReader args(&callInfo, (Var*)layout->args);
  1953. void* returnAddress = _ReturnAddress();
  1954. void* addressOfReturnAddress = _AddressOfReturnAddress();
  1955. function->GetFunctionBody()->EnsureDynamicProfileInfo();
  1956. InterpreterStackFrame* newInstance = (InterpreterStackFrame*)InterpreterHelper(function, args, returnAddress, addressOfReturnAddress, true);
  1957. return GetAsmJsRetVal<T>(newInstance);
  1958. }
  1959. __m128 InterpreterStackFrame::AsmJsInterpreterSimdJs(AsmJsCallStackLayout* layout)
  1960. {
  1961. return AsmJsInterpreter<X86SIMDValue>(layout).m128_value;
  1962. }
  1963. #endif
  1964. #endif
  1965. ///----------------------------------------------------------------------------
  1966. ///
  1967. /// InterpreterStackFrame::SetOut()
  1968. ///
  1969. /// SetOut() change the Var value stored in the specified "out parameter"
  1970. /// register.
  1971. ///
  1972. ///----------------------------------------------------------------------------
  1973. inline void InterpreterStackFrame::SetOut(ArgSlot outRegisterID, Var aValue)
  1974. {
  1975. //
  1976. // The "out" parameter slots are located at the end of the local register range, counting
  1977. // forwards. This results in the "in" parameter slots being disjoint from the rest of the
  1978. // InterpreterStackFrame.
  1979. // ..., InterpreterStackFrame A, Locals A[], ..., Out A:0, Out A:1, Out A:2, ...
  1980. // | In B:0, In B:1, ..., InterpreterStackFrame B, Locals B[], ...
  1981. // (current 'this') |
  1982. // (new 'this' after call)
  1983. //
  1984. Assert(m_outParams + outRegisterID < m_outSp);
  1985. m_outParams[outRegisterID] = aValue;
  1986. }
  1987. inline void InterpreterStackFrame::SetOut(ArgSlot_OneByte outRegisterID, Var aValue)
  1988. {
  1989. Assert(m_outParams + outRegisterID < m_outSp);
  1990. m_outParams[outRegisterID] = aValue;
  1991. }
  1992. inline void InterpreterStackFrame::OP_SetOutAsmDb( RegSlot outRegisterID, double val )
  1993. {
  1994. Assert(m_outParams + outRegisterID < m_outSp);
  1995. m_outParams[outRegisterID] = JavascriptNumber::NewWithCheck( val, scriptContext );
  1996. }
  1997. inline void InterpreterStackFrame::OP_SetOutAsmInt( RegSlot outRegisterID, int val )
  1998. {
  1999. Assert( m_outParams + outRegisterID < m_outSp );
  2000. m_outParams[outRegisterID] = JavascriptNumber::ToVar( val, scriptContext );
  2001. }
  2002. void InterpreterStackFrame::OP_SetOutAsmFlt(RegSlot outRegisterID, float val)
  2003. {
  2004. OP_SetOutAsmDb(outRegisterID, (double)val);
  2005. }
  2006. inline void InterpreterStackFrame::OP_I_SetOutAsmFlt(RegSlot outRegisterID, float val)
  2007. {
  2008. Assert(m_outParams + outRegisterID < m_outSp);
  2009. *(float*)(&(m_outParams[outRegisterID])) = val;
  2010. }
  2011. inline void InterpreterStackFrame::OP_I_SetOutAsmLong(RegSlot outRegisterID, int64 val)
  2012. {
  2013. Assert(m_outParams + outRegisterID < m_outSp);
  2014. *(int64*)(&(m_outParams[outRegisterID])) = val;
  2015. }
  2016. inline void InterpreterStackFrame::OP_I_SetOutAsmInt(RegSlot outRegisterID, int val)
  2017. {
  2018. Assert(m_outParams + outRegisterID < m_outSp);
  2019. *(int*)(&(m_outParams[outRegisterID])) = val;
  2020. }
  2021. inline void InterpreterStackFrame::OP_I_SetOutAsmDb(RegSlot outRegisterID, double val)
  2022. {
  2023. Assert(m_outParams + outRegisterID < m_outSp);
  2024. *(double*)(&(m_outParams[outRegisterID])) = val;
  2025. }
  2026. inline void InterpreterStackFrame::OP_I_SetOutAsmSimd(RegSlot outRegisterID, AsmJsSIMDValue val)
  2027. {
  2028. Assert(m_outParams + outRegisterID < m_outSp);
  2029. *(AsmJsSIMDValue*)(&(m_outParams[outRegisterID])) = val;
  2030. }
  2031. template<bool toJs>
  2032. void InterpreterStackFrame::OP_InvalidWasmTypeConversion(...)
  2033. {
  2034. // Right now the only invalid wasm type conversion is with int64
  2035. const char16* fromType = toJs ? _u("int64") : _u("Javascript Variable");
  2036. const char16* toType = toJs ? _u("Javascript Variable") : _u("int64");
  2037. JavascriptError::ThrowTypeErrorVar(scriptContext, WASMERR_InvalidTypeConversion, fromType, toType);
  2038. }
  2039. // This will be called in the beginning of the try_finally.
  2040. inline void InterpreterStackFrame::CacheSp()
  2041. {
  2042. // Before caching the current m_outSp, we will be storing the previous the previously stored value in the m_outSpCached.
  2043. *m_outSp++ = (Var)m_outSpCached;
  2044. *m_outSp++ = (Var)m_outParams;
  2045. m_outSpCached = m_outSp - 2;
  2046. }
  2047. inline void InterpreterStackFrame::RestoreSp()
  2048. {
  2049. // This will be called in the Finally block to restore from the previous SP cached.
  2050. // m_outSpCached can be null if the catch block is called.
  2051. if (m_outSpCached != nullptr)
  2052. {
  2053. Assert(m_outSpCached < m_outSp);
  2054. m_outSp = m_outSpCached;
  2055. m_outSpCached = (Var*)*m_outSp;
  2056. Assert(m_outSpCached == nullptr || m_outSpCached <= m_outSp);
  2057. m_outParams = (Var*)*(m_outSp + 1);
  2058. }
  2059. else
  2060. {
  2061. ResetOut();
  2062. }
  2063. }
  2064. inline void InterpreterStackFrame::PushOut(Var aValue)
  2065. {
  2066. *m_outSp++ = aValue;
  2067. }
  2068. inline void InterpreterStackFrame::PopOut(ArgSlot argCount)
  2069. {
  2070. m_outSp -= (argCount+1);
  2071. m_outParams = (Var*)*m_outSp;
  2072. AssertMsg(m_localSlots + this->m_functionBody->GetLocalsCount() <= m_outSp &&
  2073. m_outSp < (m_localSlots + this->m_functionBody->GetLocalsCount() + this->m_functionBody->GetOutParamMaxDepth()),
  2074. "out args Stack pointer not in range after Pop");
  2075. }
  2076. void InterpreterStackFrame::ResetOut()
  2077. {
  2078. //
  2079. // Reset the m_outParams and m_outSp
  2080. //
  2081. m_outParams = m_localSlots + this->m_functionBody->GetLocalsCount();
  2082. m_outSp = m_outParams;
  2083. m_outSpCached = nullptr;
  2084. }
  2085. _NOINLINE
  2086. Var InterpreterStackFrame::DebugProcessThunk(void* returnAddress, void* addressOfReturnAddress)
  2087. {
  2088. PushPopFrameHelper pushPopFrameHelper(this, returnAddress, addressOfReturnAddress);
  2089. return this->DebugProcess();
  2090. }
  2091. //
  2092. // Under debug mode allow the exception to be swallowed and execution to continue
  2093. // if the debugger has specified that behavior.
  2094. //
  2095. Var InterpreterStackFrame::DebugProcess()
  2096. {
  2097. Assert(this->returnAddress != nullptr);
  2098. while (true)
  2099. {
  2100. JavascriptExceptionObject *exception = nullptr;
  2101. try
  2102. {
  2103. #if ENABLE_TTD
  2104. if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
  2105. {
  2106. return this->ProcessWithDebugging_PreviousStmtTracking();
  2107. }
  2108. else
  2109. {
  2110. return this->ProcessWithDebugging();
  2111. }
  2112. #else
  2113. return this->ProcessWithDebugging();
  2114. #endif
  2115. }
  2116. catch (const Js::JavascriptException& err)
  2117. {
  2118. JavascriptExceptionObject *exception_ = err.GetAndClear();
  2119. Assert(exception_);
  2120. exception = exception_;
  2121. }
  2122. if (exception)
  2123. {
  2124. bool skipException = false;
  2125. if (exception != scriptContext->GetThreadContext()->GetPendingSOErrorObject()
  2126. && exception != scriptContext->GetThreadContext()->GetPendingOOMErrorObject())
  2127. {
  2128. skipException = exception->IsDebuggerSkip();
  2129. }
  2130. if (skipException)
  2131. {
  2132. // If we are going to swallow the exception then advance to the beginning of the next user statement
  2133. if (exception->IsIgnoreAdvanceToNextStatement()
  2134. || this->scriptContext->GetDebugContext()->GetProbeContainer()->AdvanceToNextUserStatement(this->m_functionBody, &this->m_reader))
  2135. {
  2136. // We must fix up the return value to at least be undefined:
  2137. this->SetReg((RegSlot)0,this->scriptContext->GetLibrary()->GetUndefined());
  2138. // If we recover from the exception, there may be a chance the out pointers in the InterpreterStackframe are not in a proper state.
  2139. // Reset them to correct the stack.
  2140. ResetOut();
  2141. // If we can successfully advance then continuing processing
  2142. continue;
  2143. }
  2144. }
  2145. JavascriptExceptionOperators::DoThrowCheckClone(exception, scriptContext);
  2146. }
  2147. }
  2148. }
  2149. template<typename OpCodeType, Js::OpCode (ReadOpFunc)(const byte*&), void (TracingFunc)(InterpreterStackFrame*, OpCodeType)>
  2150. OpCodeType InterpreterStackFrame::ReadOp(const byte *& ip)
  2151. {
  2152. #if DBG || DBG_DUMP
  2153. //
  2154. // For debugging byte-code, store the current offset before the instruction is read:
  2155. // - We convert this to "void *" to encourage the debugger to always display in hex,
  2156. // which matches the displayed offsets used by ByteCodeDumper.
  2157. //
  2158. this->DEBUG_currentByteOffset = (void *) m_reader.GetCurrentOffset();
  2159. #endif
  2160. #if ENABLE_TTD
  2161. AssertMsg(!SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext), "We never be fetching an opcode via this path if this is true!!!");
  2162. #endif
  2163. OpCodeType op = (OpCodeType)ReadOpFunc(ip);
  2164. #if DBG_DUMP
  2165. TracingFunc(this, op);
  2166. #endif
  2167. return op;
  2168. }
  2169. void InterpreterStackFrame::TraceOpCode(InterpreterStackFrame* that, Js::OpCode op)
  2170. {
  2171. #if DBG_DUMP
  2172. that->scriptContext->byteCodeHistogram[(int)op]++;
  2173. if (PHASE_TRACE(Js::InterpreterPhase, that->m_functionBody))
  2174. {
  2175. 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);
  2176. }
  2177. #endif
  2178. }
  2179. void InterpreterStackFrame::TraceAsmJsOpCode(InterpreterStackFrame* that, Js::OpCodeAsmJs op)
  2180. {
  2181. #if DBG_DUMP && defined(ASMJS_PLAT)
  2182. if(PHASE_TRACE(Js::AsmjsInterpreterPhase, that->m_functionBody))
  2183. {
  2184. 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);
  2185. }
  2186. #endif
  2187. }
  2188. #if ENABLE_TTD
  2189. template<typename OpCodeType, Js::OpCode(ReadOpFunc)(const byte*&), void (TracingFunc)(InterpreterStackFrame*, OpCodeType)>
  2190. OpCodeType InterpreterStackFrame::ReadOp_WPreviousStmtTracking(const byte *& ip)
  2191. {
  2192. #if DBG || DBG_DUMP
  2193. //
  2194. // For debugging byte-code, store the current offset before the instruction is read:
  2195. // - We convert this to "void *" to encourage the debugger to always display in hex,
  2196. // which matches the displayed offsets used by ByteCodeDumper.
  2197. //
  2198. this->DEBUG_currentByteOffset = (void *)m_reader.GetCurrentOffset();
  2199. #endif
  2200. #if ENABLE_TTD
  2201. AssertMsg(this->scriptContext->GetThreadContext()->IsRuntimeInTTDMode(), "We never be fetching an opcode via this path if this is not true!!!");
  2202. #endif
  2203. if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
  2204. {
  2205. this->scriptContext->GetThreadContext()->TTDLog->UpdateCurrentStatementInfo(m_reader.GetCurrentOffset());
  2206. }
  2207. OpCodeType op = (OpCodeType)ReadOpFunc(ip);
  2208. #if DBG_DUMP
  2209. TracingFunc(this, op);
  2210. #endif
  2211. return op;
  2212. }
  2213. #endif
  2214. _NOINLINE
  2215. Var InterpreterStackFrame::ProcessThunk(void* address, void* addressOfReturnAddress)
  2216. {
  2217. PushPopFrameHelper pushPopFrameHelper(this, address, addressOfReturnAddress);
  2218. return this->Process();
  2219. }
  2220. Var InterpreterStackFrame::ProcessAsmJsModule()
  2221. {
  2222. #ifdef ASMJS_PLAT
  2223. Js::FunctionBody* asmJsModuleFunctionBody = GetFunctionBody();
  2224. AsmJsModuleInfo* info = asmJsModuleFunctionBody->GetAsmJsModuleInfo();
  2225. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  2226. if (Configuration::Global.flags.ForceAsmJsLinkFail)
  2227. {
  2228. AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Forcing link failure"));
  2229. return this->ProcessLinkFailedAsmJsModule();
  2230. }
  2231. #endif
  2232. if( m_inSlotsCount != info->GetArgInCount() + 1 )
  2233. {
  2234. // Error reparse without asm.js
  2235. AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Invalid module argument count"));
  2236. return this->ProcessLinkFailedAsmJsModule();
  2237. }
  2238. const AsmJsModuleMemory& moduleMemory = info->GetModuleMemory();
  2239. Var* moduleMemoryPtr = RecyclerNewArray( scriptContext->GetRecycler(), Var, moduleMemory.mMemorySize );
  2240. Var* arrayBufferPtr = moduleMemoryPtr + moduleMemory.mArrayBufferOffset;
  2241. Assert(moduleMemory.mArrayBufferOffset == AsmJsModuleMemory::MemoryTableBeginOffset);
  2242. Var* stdLibPtr = moduleMemoryPtr + moduleMemory.mStdLibOffset;
  2243. int* localIntSlots = (int*)(moduleMemoryPtr + moduleMemory.mIntOffset);
  2244. float* localFloatSlots = (float*)(moduleMemoryPtr + moduleMemory.mFloatOffset);
  2245. double* localDoubleSlots = (double*)(moduleMemoryPtr + moduleMemory.mDoubleOffset);
  2246. Var* localFunctionImports = moduleMemoryPtr + moduleMemory.mFFIOffset ;
  2247. Var* localModuleFunctions = moduleMemoryPtr + moduleMemory.mFuncOffset ;
  2248. Var** localFunctionTables = (Var**)(moduleMemoryPtr + moduleMemory.mFuncPtrOffset) ;
  2249. AsmJsSIMDValue* localSimdSlots = nullptr;
  2250. if (scriptContext->GetConfig()->IsSimdjsEnabled())
  2251. {
  2252. localSimdSlots = ((AsmJsSIMDValue*)moduleMemoryPtr) + moduleMemory.mSimdOffset; // simdOffset is in SIMDValues
  2253. }
  2254. ThreadContext* threadContext = this->scriptContext->GetThreadContext();
  2255. *stdLibPtr = (m_inSlotsCount > 1) ? m_inParams[1] : nullptr;
  2256. Var foreign = (m_inSlotsCount > 2) ? m_inParams[2] : nullptr;
  2257. *arrayBufferPtr = (m_inSlotsCount > 3) ? m_inParams[3] : nullptr;
  2258. //cache the current state of the disable implicit call flag
  2259. DisableImplicitFlags prevDisableImplicitFlags = threadContext->GetDisableImplicitFlags();
  2260. ImplicitCallFlags saveImplicitcallFlags = threadContext->GetImplicitCallFlags();
  2261. // Disable implicit calls to check if any of the VarImport or Function Import leads to implicit calls
  2262. threadContext->DisableImplicitCall();
  2263. threadContext->SetImplicitCallFlags(ImplicitCallFlags::ImplicitCall_None);
  2264. bool checkParamResult = ASMLink::CheckParams(this->scriptContext, info, *stdLibPtr, foreign, *arrayBufferPtr);
  2265. if (!checkParamResult)
  2266. {
  2267. // don't need to print, because checkParams will do it for us
  2268. goto linkFailure;
  2269. }
  2270. else if(this->CheckAndResetImplicitCall(prevDisableImplicitFlags, saveImplicitcallFlags))
  2271. {
  2272. AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Params have side effects"));
  2273. return this->ProcessLinkFailedAsmJsModule();
  2274. }
  2275. // Initialize Variables
  2276. for (int i = 0; i < info->GetVarCount(); i++)
  2277. {
  2278. const auto& var = info->GetVar( i );
  2279. const AsmJsVarType type(var.type);
  2280. if(type.isInt() )
  2281. {
  2282. localIntSlots[var.location] = var.initialiser.intInit;
  2283. }
  2284. else if (type.isFloat())
  2285. {
  2286. localFloatSlots[var.location] = var.initialiser.floatInit;
  2287. }
  2288. else if (type.isDouble())
  2289. {
  2290. localDoubleSlots[var.location] = var.initialiser.doubleInit;
  2291. }
  2292. else if (scriptContext->GetConfig()->IsSimdjsEnabled() && type.isSIMD())
  2293. {
  2294. // e.g. var g = f4(0.0, 0.0, 0.0, 0.0);
  2295. localSimdSlots[var.location] = var.initialiser.simdInit;
  2296. }
  2297. else {
  2298. Assert(UNREACHED);
  2299. }
  2300. }
  2301. // Load constant variables
  2302. for( int i = 0; i < info->GetVarImportCount(); i++ )
  2303. {
  2304. const auto& import = info->GetVarImport( i );
  2305. const AsmJsVarType type(import.type);
  2306. // this might throw, but it would anyway in non-asm.js
  2307. Var value = JavascriptOperators::OP_GetProperty( foreign, import.field, scriptContext );
  2308. // check if there is implicit call and if there is implicit call then clear the disableimplicitcall flag
  2309. if (this->CheckAndResetImplicitCall(prevDisableImplicitFlags, saveImplicitcallFlags))
  2310. {
  2311. AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Accessing var import %s has side effects"), this->scriptContext->GetPropertyName(import.field)->GetBuffer());
  2312. return this->ProcessLinkFailedAsmJsModule();
  2313. }
  2314. if (CONFIG_FLAG(AsmJsEdge))
  2315. {
  2316. // emscripten had a bug which caused this check to fail in some circumstances, so this check fails for some demos
  2317. if (!TaggedNumber::Is(value) && (!RecyclableObject::Is(value) || DynamicType::Is(RecyclableObject::FromVar(value)->GetTypeId())))
  2318. {
  2319. AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Var import %s must be primitive"), this->scriptContext->GetPropertyName(import.field)->GetBuffer());
  2320. goto linkFailure;
  2321. }
  2322. }
  2323. if(type.isInt() )
  2324. {
  2325. int val = JavascriptMath::ToInt32( value, scriptContext );
  2326. localIntSlots[import.location] = val;
  2327. }
  2328. else if (type.isFloat())
  2329. {
  2330. float val = (float)JavascriptConversion::ToNumber(value, scriptContext);
  2331. localFloatSlots[import.location] = val;
  2332. }
  2333. else if (type.isDouble())
  2334. {
  2335. double val = JavascriptConversion::ToNumber( value, scriptContext );
  2336. localDoubleSlots[import.location] = val;
  2337. }
  2338. else if (scriptContext->GetConfig()->IsSimdjsEnabled() && type.isSIMD())
  2339. {
  2340. // e.g. var g = f4(imports.v);
  2341. bool valid = false;
  2342. AsmJsSIMDValue val;
  2343. val.Zero();
  2344. switch (type.which())
  2345. {
  2346. case AsmJsVarType::Int32x4:
  2347. valid = JavascriptSIMDInt32x4::Is(value);
  2348. val = (valid) ? ((JavascriptSIMDInt32x4*)value)->GetValue() : val;
  2349. break;
  2350. case AsmJsVarType::Bool32x4:
  2351. valid = JavascriptSIMDBool32x4::Is(value);
  2352. val = (valid) ? ((JavascriptSIMDBool32x4*)value)->GetValue() : val;
  2353. break;
  2354. case AsmJsVarType::Bool16x8:
  2355. valid = JavascriptSIMDBool16x8::Is(value);
  2356. val = (valid) ? ((JavascriptSIMDBool16x8*)value)->GetValue() : val;
  2357. break;
  2358. case AsmJsVarType::Bool8x16:
  2359. valid = JavascriptSIMDBool8x16::Is(value);
  2360. val = (valid) ? ((JavascriptSIMDBool8x16*)value)->GetValue() : val;
  2361. break;
  2362. case AsmJsVarType::Float32x4:
  2363. valid = JavascriptSIMDFloat32x4::Is(value);
  2364. val = (valid) ? ((JavascriptSIMDFloat32x4*)value)->GetValue() : val;
  2365. break;
  2366. case AsmJsVarType::Float64x2:
  2367. valid = JavascriptSIMDFloat64x2::Is(value);
  2368. val = (valid) ? ((JavascriptSIMDFloat64x2*)value)->GetValue() : val;
  2369. break;
  2370. case AsmJsVarType::Int16x8:
  2371. valid = JavascriptSIMDInt16x8::Is(value);
  2372. val = (valid) ? ((JavascriptSIMDInt16x8*)value)->GetValue() : val;
  2373. break;
  2374. case AsmJsVarType::Int8x16:
  2375. valid = JavascriptSIMDInt8x16::Is(value);
  2376. val = ((JavascriptSIMDInt8x16*)value)->GetValue();
  2377. break;
  2378. case AsmJsVarType::Uint32x4:
  2379. valid = JavascriptSIMDUint32x4::Is(value);
  2380. val = (valid) ? ((JavascriptSIMDUint32x4*)value)->GetValue() : val;
  2381. break;
  2382. case AsmJsVarType::Uint16x8:
  2383. valid = JavascriptSIMDUint16x8::Is(value);
  2384. val = (valid) ? ((JavascriptSIMDUint16x8*)value)->GetValue() : val;
  2385. break;
  2386. case AsmJsVarType::Uint8x16:
  2387. valid = JavascriptSIMDUint8x16::Is(value);
  2388. val = (valid) ? ((JavascriptSIMDUint8x16*)value)->GetValue() : val;
  2389. break;
  2390. default:
  2391. Assert(UNREACHED);
  2392. };
  2393. if (!valid)
  2394. {
  2395. // link failure of SIMD values imports.
  2396. AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Foreign var import %s is not SIMD type"), this->scriptContext->GetPropertyName(import.field)->GetBuffer());
  2397. goto linkFailure;
  2398. }
  2399. localSimdSlots[import.location] = val;
  2400. }
  2401. // check for implicit call after converting to number
  2402. if (this->CheckAndResetImplicitCall(prevDisableImplicitFlags, saveImplicitcallFlags))
  2403. {
  2404. // Runtime error
  2405. AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Accessing var import %s has side effects"), this->scriptContext->GetPropertyName(import.field)->GetBuffer());
  2406. return this->ProcessLinkFailedAsmJsModule();
  2407. }
  2408. }
  2409. // Load external functions
  2410. for( int i = 0; i < info->GetFunctionImportCount(); i++ )
  2411. {
  2412. const auto& import = info->GetFunctionImport( i );
  2413. // this might throw, but it would anyway in non-asm.js
  2414. Var importFunc = JavascriptOperators::OP_GetProperty( foreign, import.field, scriptContext );
  2415. // check if there is implicit call and if there is implicit call then clear the disableimplicitcall flag
  2416. if (this->CheckAndResetImplicitCall(prevDisableImplicitFlags, saveImplicitcallFlags))
  2417. {
  2418. AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Accessing foreign function import %s has side effects"), this->scriptContext->GetPropertyName(import.field)->GetBuffer());
  2419. return this->ProcessLinkFailedAsmJsModule();
  2420. }
  2421. if( !JavascriptFunction::Is( importFunc ) )
  2422. {
  2423. AsmJSCompiler::OutputError(this->scriptContext, _u("Asm.js Runtime Error : Foreign function import %s is not a function"), this->scriptContext->GetPropertyName(import.field)->GetBuffer());
  2424. goto linkFailure;
  2425. }
  2426. localFunctionImports[import.location] = importFunc;
  2427. }
  2428. if (*arrayBufferPtr)
  2429. {
  2430. (*(ArrayBuffer**)arrayBufferPtr)->SetIsAsmJsBuffer();
  2431. }
  2432. threadContext->SetDisableImplicitFlags(prevDisableImplicitFlags);
  2433. threadContext->SetImplicitCallFlags(saveImplicitcallFlags);
  2434. // scope
  2435. {
  2436. FrameDisplay* pDisplay = RecyclerNewPlus(scriptContext->GetRecycler(), sizeof(void*), FrameDisplay, 1);
  2437. pDisplay->SetItem( 0, moduleMemoryPtr );
  2438. for (int i = 0; i < info->GetFunctionCount(); i++)
  2439. {
  2440. const auto& modFunc = info->GetFunction(i);
  2441. // TODO: add more runtime checks here
  2442. FunctionInfoPtrPtr functionInfo = m_functionBody->GetNestedFuncReference(i);
  2443. AsmJsScriptFunction* scriptFuncObj = (AsmJsScriptFunction*)ScriptFunction::OP_NewScFunc(pDisplay, functionInfo);
  2444. localModuleFunctions[modFunc.location] = scriptFuncObj;
  2445. if (i == 0 && info->GetUsesChangeHeap())
  2446. {
  2447. scriptFuncObj->GetDynamicType()->SetEntryPoint(AsmJsChangeHeapBuffer);
  2448. }
  2449. else
  2450. {
  2451. if (scriptFuncObj->GetDynamicType()->GetEntryPoint() == DefaultDeferredDeserializeThunk)
  2452. {
  2453. JavascriptFunction::DeferredDeserialize(scriptFuncObj);
  2454. }
  2455. scriptFuncObj->GetDynamicType()->SetEntryPoint(AsmJsExternalEntryPoint);
  2456. scriptFuncObj->GetFunctionBody()->GetAsmJsFunctionInfo()->SetModuleFunctionBody(asmJsModuleFunctionBody);
  2457. }
  2458. scriptFuncObj->SetModuleMemory(moduleMemoryPtr);
  2459. if (!info->IsRuntimeProcessed())
  2460. {
  2461. // don't reset entrypoint upon relinking
  2462. FunctionEntryPointInfo* entrypointInfo = (FunctionEntryPointInfo*)scriptFuncObj->GetEntryPointInfo();
  2463. entrypointInfo->SetIsAsmJSFunction(true);
  2464. #if DYNAMIC_INTERPRETER_THUNK
  2465. if (!PHASE_ON1(AsmJsJITTemplatePhase))
  2466. {
  2467. entrypointInfo->jsMethod = AsmJsDefaultEntryThunk;
  2468. }
  2469. #endif
  2470. }
  2471. }
  2472. }
  2473. // Initialize function table arrays
  2474. for( int i = 0; i < info->GetFunctionTableCount(); i++ )
  2475. {
  2476. const auto& modFuncTable = info->GetFunctionTable( i );
  2477. Var* funcTableArray = RecyclerNewArray( scriptContext->GetRecycler(), Var, modFuncTable.size );
  2478. for (uint j = 0; j < modFuncTable.size ; j++)
  2479. {
  2480. // get the module function index
  2481. const RegSlot index = modFuncTable.moduleFunctionIndex[j];
  2482. // assign the module function pointer to the array
  2483. Var functionPtr = localModuleFunctions[index];
  2484. funcTableArray[j] = functionPtr;
  2485. }
  2486. localFunctionTables[i] = funcTableArray;
  2487. }
  2488. // Do MTJRC/MAIC:0 check
  2489. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2490. if (
  2491. (PHASE_ON1(Js::AsmJsJITTemplatePhase) && CONFIG_FLAG(MaxTemplatizedJitRunCount) == 0) ||
  2492. (!PHASE_ON1(Js::AsmJsJITTemplatePhase) && (CONFIG_FLAG(MaxAsmJsInterpreterRunCount) == 0 || CONFIG_FLAG(ForceNative)))
  2493. )
  2494. {
  2495. if (PHASE_TRACE1(AsmjsEntryPointInfoPhase))
  2496. {
  2497. Output::Print(_u("%s Scheduling For Full JIT at callcount:%d\n"), asmJsModuleFunctionBody->GetDisplayName(), 0);
  2498. Output::Flush();
  2499. }
  2500. for (int i = 0; i < info->GetFunctionCount(); i++)
  2501. {
  2502. ScriptFunction* functionObj = (ScriptFunction*)localModuleFunctions[i];
  2503. AnalysisAssert(functionObj != nullptr);
  2504. // don't want to generate code for APIs like changeHeap
  2505. if (functionObj->GetEntryPoint() == Js::AsmJsExternalEntryPoint)
  2506. {
  2507. GenerateFunction(asmJsModuleFunctionBody->GetScriptContext()->GetNativeCodeGenerator(), functionObj->GetFunctionBody(), functionObj);
  2508. }
  2509. }
  2510. }
  2511. #endif
  2512. info->SetIsRuntimeProcessed(true);
  2513. // create export object
  2514. if( info->GetExportsCount() )
  2515. {
  2516. Var newObj = JavascriptOperators::NewScObjectLiteral( GetScriptContext(), info->GetExportsIdArray(),
  2517. this->GetFunctionBody()->GetObjectLiteralTypeRef( 0 ) );
  2518. for( int i = 0; i < info->GetExportsCount(); i++ )
  2519. {
  2520. auto ex = info->GetExport( i );
  2521. Var func = localModuleFunctions[*ex.location];
  2522. JavascriptOperators::OP_InitProperty( newObj, *ex.id, func );
  2523. }
  2524. SetReg( (RegSlot) 0, newObj );
  2525. return newObj;
  2526. }
  2527. // export only 1 function
  2528. {
  2529. Var exportFunc = localModuleFunctions[info->GetExportFunctionIndex()];
  2530. SetReg((RegSlot)0, exportFunc);
  2531. return exportFunc;
  2532. }
  2533. linkFailure:
  2534. threadContext->SetDisableImplicitFlags(prevDisableImplicitFlags);
  2535. threadContext->SetImplicitCallFlags(saveImplicitcallFlags);
  2536. return this->ProcessLinkFailedAsmJsModule();
  2537. }
  2538. Var InterpreterStackFrame::ProcessLinkFailedAsmJsModule()
  2539. {
  2540. AsmJSCompiler::OutputError(this->scriptContext, _u("asm.js linking failed."));
  2541. Js::FunctionBody* asmJsModuleFunctionBody = GetFunctionBody();
  2542. AsmJsModuleInfo* info = asmJsModuleFunctionBody->GetAsmJsModuleInfo();
  2543. // do not support relinking with failed relink
  2544. if (info->IsRuntimeProcessed())
  2545. {
  2546. Js::Throw::OutOfMemory();
  2547. }
  2548. ScriptFunction * funcObj = GetJavascriptFunction();
  2549. ScriptFunction::ReparseAsmJsModule(&funcObj);
  2550. const bool doProfile =
  2551. funcObj->GetFunctionBody()->GetInterpreterExecutionMode(false) == ExecutionMode::ProfilingInterpreter ||
  2552. (funcObj->GetFunctionBody()->IsInDebugMode() && DynamicProfileInfo::IsEnabled(funcObj->GetFunctionBody()));
  2553. DynamicProfileInfo * dynamicProfileInfo = nullptr;
  2554. if (doProfile)
  2555. {
  2556. dynamicProfileInfo = funcObj->GetFunctionBody()->GetDynamicProfileInfo();
  2557. funcObj->GetScriptContext()->GetThreadContext()->ClearImplicitCallFlags();
  2558. }
  2559. // after reparsing, we want to also use a new interpreter stack frame, as it will have different characteristics than the asm.js version
  2560. InterpreterStackFrame::Setup setup(funcObj, m_inParams, m_inSlotsCount);
  2561. size_t varAllocCount = setup.GetAllocationVarCount();
  2562. size_t varSizeInBytes = varAllocCount * sizeof(Var);
  2563. Var* allocation = nullptr;
  2564. DWORD_PTR stackAddr;
  2565. bool fReleaseAlloc = false;
  2566. if (varAllocCount > InterpreterStackFrame::LocalsThreshold)
  2567. {
  2568. ArenaAllocator *tmpAlloc = nullptr;
  2569. fReleaseAlloc = GetScriptContext()->EnsureInterpreterArena(&tmpAlloc);
  2570. allocation = (Var*)tmpAlloc->Alloc(varSizeInBytes);
  2571. // use a stack address so the debugger stepping logic works (step-out, for example, compares stack depths to determine when to complete the step)
  2572. // debugger stepping does not matter here, but it's worth being consistent with normal stack frame
  2573. stackAddr = reinterpret_cast<DWORD_PTR>(&allocation);
  2574. }
  2575. else
  2576. {
  2577. PROBE_STACK_PARTIAL_INITIALIZED_INTERPRETER_FRAME(GetScriptContext(), Js::Constants::MinStackInterpreter + varSizeInBytes);
  2578. allocation = (Var*)_alloca(varSizeInBytes);
  2579. stackAddr = reinterpret_cast<DWORD_PTR>(allocation);
  2580. }
  2581. #if DBG
  2582. Var invalidStackVar = (Js::RecyclableObject*)_alloca(sizeof(Js::RecyclableObject));
  2583. memset(invalidStackVar, 0xFE, sizeof(Js::RecyclableObject));
  2584. InterpreterStackFrame * newInstance = newInstance = setup.InitializeAllocation(allocation, funcObj->GetFunctionBody()->GetHasImplicitArgIns(), doProfile, nullptr, stackAddr, invalidStackVar);
  2585. #else
  2586. InterpreterStackFrame * newInstance = newInstance = setup.InitializeAllocation(allocation, funcObj->GetFunctionBody()->GetHasImplicitArgIns(), doProfile, nullptr, stackAddr);
  2587. #endif
  2588. newInstance->m_reader.Create(funcObj->GetFunctionBody());
  2589. // now that we have set up the new frame, let's interpret it!
  2590. funcObj->GetFunctionBody()->BeginExecution();
  2591. PushPopFrameHelper(newInstance, _ReturnAddress(), _AddressOfReturnAddress());
  2592. Var retVal = newInstance->ProcessUnprofiled();
  2593. if (doProfile)
  2594. {
  2595. dynamicProfileInfo->RecordImplicitCallFlags(GetScriptContext()->GetThreadContext()->GetImplicitCallFlags());
  2596. }
  2597. if (fReleaseAlloc)
  2598. {
  2599. GetScriptContext()->ReleaseInterpreterArena();
  2600. }
  2601. return retVal;
  2602. #else
  2603. Assert(UNREACHED);
  2604. return nullptr;
  2605. #endif
  2606. }
  2607. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2608. int AsmJsCallDepth = 0;
  2609. #endif
  2610. #ifdef ASMJS_PLAT
  2611. // Function memory allocation should be done the same way as
  2612. // T AsmJsCommunEntryPoint(Js::ScriptFunction* func, ...) (AsmJSJitTemplate.cpp)
  2613. // update any changes there
  2614. /*
  2615. This function does the following fixup
  2616. Stack Before Stack After
  2617. ============== ================
  2618. | VarConstants | | VarConstants |
  2619. |--------------| |-----------------
  2620. | IntConstants | | IntConstants |
  2621. |--------------| | ------------ |
  2622. | FloatConst | | Int Vars+Tmps |
  2623. |--------------| |----------------|
  2624. | DoubleConst | | FloatConst |
  2625. |--------------| | ---------- |
  2626. | Var&Temps | | Flt Vars+tmps |
  2627. |==============| |----------------|
  2628. | DoubleConst |
  2629. | ----------- |
  2630. | Dbl Vars+Tmps |
  2631. ================
  2632. intSrc,FltSrc&DblSrc are pointers to the stack before the change
  2633. m_localIntSlots,m_localFloatSlots,m_localDoubleSlots are pointers to the stack after the change
  2634. */
  2635. void InterpreterStackFrame::AlignMemoryForAsmJs()
  2636. {
  2637. FunctionBody *const functionBody = GetFunctionBody();
  2638. ScriptFunction* func = GetJavascriptFunction();
  2639. //schedule for codegen here only if TJ is collected
  2640. if (!functionBody->GetIsAsmJsFullJitScheduled() && !PHASE_OFF(BackEndPhase, functionBody)
  2641. && !PHASE_OFF(FullJitPhase, functionBody) && !this->scriptContext->GetConfig()->IsNoNative())
  2642. {
  2643. int callCount = ++((FunctionEntryPointInfo*)func->GetEntryPointInfo())->callsCount;
  2644. bool doSchedule = false;
  2645. const int minAsmJsInterpretRunCount = (int)CONFIG_FLAG(MinAsmJsInterpreterRunCount);
  2646. if (callCount >= minAsmJsInterpretRunCount)
  2647. {
  2648. doSchedule = true;
  2649. }
  2650. if (doSchedule && !functionBody->GetIsAsmJsFullJitScheduled())
  2651. {
  2652. #if ENABLE_NATIVE_CODEGEN
  2653. if (PHASE_TRACE1(AsmjsEntryPointInfoPhase))
  2654. {
  2655. Output::Print(_u("Scheduling For Full JIT from Interpreter at callcount:%d\n"), callCount);
  2656. }
  2657. GenerateFunction(functionBody->GetScriptContext()->GetNativeCodeGenerator(), functionBody, func);
  2658. #endif
  2659. functionBody->SetIsAsmJsFullJitScheduled(true);
  2660. }
  2661. }
  2662. AsmJsFunctionInfo* info = functionBody->GetAsmJsFunctionInfo();
  2663. // The const table is copied after the FirstRegSlot
  2664. byte* constTable = (byte*)(m_localSlots + FunctionBody::FirstRegSlot);
  2665. byte* slotsStart = (byte*)m_localSlots;
  2666. // Must do in reverse order to avoid overwriting const of other type as we move things around
  2667. for (int i = WAsmJs::LIMIT - 1; i >= 0; --i)
  2668. {
  2669. WAsmJs::Types type = (WAsmJs::Types)i;
  2670. auto typeInfo = info->GetTypedSlotInfo(type);
  2671. byte* destination = slotsStart + typeInfo->byteOffset;
  2672. switch (type)
  2673. {
  2674. case WAsmJs::INT32: m_localIntSlots = (int*)destination; break;
  2675. case WAsmJs::INT64: m_localInt64Slots = (int64*)destination; break;
  2676. case WAsmJs::FLOAT32: m_localFloatSlots = (float*)destination; break;
  2677. case WAsmJs::FLOAT64: m_localDoubleSlots = (double*)destination; break;
  2678. case WAsmJs::SIMD: m_localSimdSlots = (AsmJsSIMDValue*)destination; break;
  2679. default:
  2680. CompileAssert(WAsmJs::SIMD == WAsmJs::LastType);
  2681. Assert(false);
  2682. break;
  2683. }
  2684. // Make sure slots are aligned for this type
  2685. Assert(::Math::Align<intptr_t>((intptr_t)destination, (intptr_t)WAsmJs::GetTypeByteSize(type)) == (intptr_t)destination);
  2686. byte* source = constTable + typeInfo->constSrcByteOffset;
  2687. if (typeInfo->constCount > 0 && source != destination)
  2688. {
  2689. Assert(typeInfo->constSrcByteOffset != Js::Constants::InvalidOffset);
  2690. uint constByteSize = typeInfo->constCount * WAsmJs::GetTypeByteSize(type);
  2691. memcpy_s(destination, constByteSize, source, constByteSize);
  2692. }
  2693. }
  2694. // Load module environment
  2695. FrameDisplay* frame = this->function->GetEnvironment();
  2696. m_localSlots[AsmJsFunctionMemory::ModuleEnvRegister] = frame->GetItem(0);
  2697. #ifdef ENABLE_WASM
  2698. if (func->GetFunctionBody()->IsWasmFunction())
  2699. {
  2700. WebAssemblyMemory * wasmMem = *(WebAssemblyMemory**)((Var*)frame->GetItem(0) + AsmJsModuleMemory::MemoryTableBeginOffset);
  2701. Var * val = nullptr;
  2702. if (wasmMem != nullptr)
  2703. {
  2704. val = (Var*)((BYTE*)wasmMem + WebAssemblyMemory::GetOffsetOfArrayBuffer());
  2705. }
  2706. m_localSlots[AsmJsFunctionMemory::ArrayBufferRegister] = val;
  2707. m_signatures = func->GetFunctionBody()->GetAsmJsFunctionInfo()->GetWebAssemblyModule()->GetSignatures();
  2708. m_wasmMemory = wasmMem;
  2709. }
  2710. else
  2711. #endif
  2712. {
  2713. m_localSlots[AsmJsFunctionMemory::ArrayBufferRegister] = (Var*)frame->GetItem(0) + AsmJsModuleMemory::MemoryTableBeginOffset;
  2714. }
  2715. m_localSlots[AsmJsFunctionMemory::ArraySizeRegister] = 0; // do not cache ArraySize in the interpreter
  2716. m_localSlots[AsmJsFunctionMemory::ScriptContextBufferRegister] = functionBody->GetScriptContext();
  2717. int* intArg = m_localIntSlots + info->GetTypedSlotInfo(WAsmJs::INT32)->constCount;
  2718. int64* int64Arg = m_localInt64Slots + info->GetTypedSlotInfo(WAsmJs::INT64)->constCount;
  2719. double* doubleArg = m_localDoubleSlots + info->GetTypedSlotInfo(WAsmJs::FLOAT64)->constCount;
  2720. float* floatArg = m_localFloatSlots + info->GetTypedSlotInfo(WAsmJs::FLOAT32)->constCount;
  2721. AsmJsSIMDValue* simdArg = m_localSimdSlots + info->GetTypedSlotInfo(WAsmJs::SIMD)->constCount;
  2722. // Move the arguments to the right location
  2723. ArgSlot argCount = info->GetArgCount();
  2724. #if _M_X64
  2725. uint homingAreaSize = 0;
  2726. #endif
  2727. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2728. const bool tracingFunc = PHASE_TRACE(AsmjsFunctionEntryPhase, functionBody);
  2729. if (tracingFunc)
  2730. {
  2731. if (AsmJsCallDepth)
  2732. {
  2733. Output::Print(_u("%*c"), AsmJsCallDepth, ' ');
  2734. }
  2735. Output::Print(_u("Executing function %s("), functionBody->GetDisplayName());
  2736. ++AsmJsCallDepth;
  2737. }
  2738. #endif
  2739. uintptr_t argAddress = (uintptr_t)m_inParams;
  2740. for (ArgSlot i = 0; i < argCount; i++)
  2741. {
  2742. #if _M_X64
  2743. // 3rd Argument should be at the end of the homing area.
  2744. Assert(i != 3 || argAddress == (uintptr_t)m_inParams + homingAreaSize);
  2745. if (i < 3)
  2746. {
  2747. // for x64 we spill the first 3 floating point args below the rest of the arguments on the stack
  2748. // m_inParams will be from DynamicInterpreterThunk's frame. Floats are in InterpreterAsmThunk's frame. Stack will be set up like so:
  2749. // DIT arg2 <- first scriptArg, m_inParams points here
  2750. // DIT arg1
  2751. // padding
  2752. // IAT r9 home
  2753. // IAT r8 home
  2754. // IAT rdx home
  2755. // IAT rcx home
  2756. // IAT return address
  2757. // IAT push rbp
  2758. // IAT padding
  2759. // IAT xmm3 spill
  2760. // IAT xmm2 spill
  2761. // IAT xmm1 spill <- floatSpillAddress for arg1
  2762. #ifdef _WIN32
  2763. #define FLOAT_SPILL_ADDRESS_OFFSET_WORDS 15
  2764. #else
  2765. // On Sys V x64 we have 4 words less (4 reg shadow)
  2766. #define FLOAT_SPILL_ADDRESS_OFFSET_WORDS 11
  2767. #endif
  2768. // floats are spilled as xmmwords
  2769. uintptr_t floatSpillAddress = (uintptr_t)m_inParams - MachPtr * (FLOAT_SPILL_ADDRESS_OFFSET_WORDS - 2*i);
  2770. if (info->GetArgType(i).isInt())
  2771. {
  2772. *intArg = *(int*)argAddress;
  2773. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2774. if (tracingFunc)
  2775. {
  2776. Output::Print(_u("%d, "), *intArg);
  2777. }
  2778. #endif
  2779. ++intArg;
  2780. homingAreaSize += MachPtr;
  2781. }
  2782. else if (info->GetArgType(i).isInt64())
  2783. {
  2784. *int64Arg = *(int64*)argAddress;
  2785. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2786. if (tracingFunc)
  2787. {
  2788. Output::Print(_u("%lld, "), *int64Arg);
  2789. }
  2790. #endif
  2791. ++int64Arg;
  2792. homingAreaSize += MachPtr;
  2793. }
  2794. else if (info->GetArgType(i).isFloat())
  2795. {
  2796. *floatArg = *(float*)floatSpillAddress;
  2797. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2798. if (tracingFunc)
  2799. {
  2800. Output::Print(_u("%.2f, "), *floatArg);
  2801. }
  2802. #endif
  2803. ++floatArg;
  2804. homingAreaSize += MachPtr;
  2805. }
  2806. else if (info->GetArgType(i).isDouble())
  2807. {
  2808. *doubleArg = *(double*)floatSpillAddress;
  2809. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2810. if (tracingFunc)
  2811. {
  2812. Output::Print(_u("%.2f, "), *doubleArg);
  2813. }
  2814. #endif
  2815. ++doubleArg;
  2816. homingAreaSize += MachPtr;
  2817. }
  2818. else
  2819. {
  2820. Assert(info->GetArgType(i).isSIMD());
  2821. *simdArg = *(AsmJsSIMDValue*)floatSpillAddress;
  2822. ++simdArg;
  2823. homingAreaSize += sizeof(AsmJsSIMDValue);
  2824. }
  2825. if (scriptContext->GetConfig()->IsSimdjsEnabled() && i == 2) // last argument ?
  2826. {
  2827. // 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.
  2828. // 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).
  2829. // 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.
  2830. argAddress = (uintptr_t)m_inParams + homingAreaSize;
  2831. }
  2832. else
  2833. {
  2834. argAddress += MachPtr;
  2835. }
  2836. }
  2837. else
  2838. #endif
  2839. if (info->GetArgType(i).isInt())
  2840. {
  2841. *intArg = *(int*)argAddress;
  2842. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2843. if (tracingFunc)
  2844. {
  2845. Output::Print(_u("%d, "), *intArg);
  2846. }
  2847. #endif
  2848. ++intArg;
  2849. argAddress += MachPtr;
  2850. }
  2851. else if (info->GetArgType(i).isInt64())
  2852. {
  2853. *int64Arg = *(int64*)argAddress;
  2854. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2855. if (tracingFunc)
  2856. {
  2857. Output::Print(_u("%lld, "), *int64Arg);
  2858. }
  2859. #endif
  2860. ++int64Arg;
  2861. argAddress += sizeof(int64);
  2862. }
  2863. else if (info->GetArgType(i).isFloat())
  2864. {
  2865. *floatArg = *(float*)argAddress;
  2866. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2867. if (tracingFunc)
  2868. {
  2869. Output::Print(_u("%.2f, "), *floatArg);
  2870. }
  2871. #endif
  2872. ++floatArg;
  2873. argAddress += MachPtr;
  2874. }
  2875. else if (info->GetArgType(i).isDouble())
  2876. {
  2877. Assert(info->GetArgType(i).isDouble());
  2878. *doubleArg = *(double*)argAddress;
  2879. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2880. if (tracingFunc)
  2881. {
  2882. Output::Print(_u("%.2f, "), *doubleArg);
  2883. }
  2884. #endif
  2885. ++doubleArg;
  2886. argAddress += sizeof(double);
  2887. }
  2888. else if (scriptContext->GetConfig()->IsSimdjsEnabled() && info->GetArgType(i).isSIMD())
  2889. {
  2890. *simdArg = *(AsmJsSIMDValue*)argAddress;
  2891. ++simdArg;
  2892. argAddress += sizeof(AsmJsSIMDValue);
  2893. }
  2894. else
  2895. {
  2896. AssertMsg(UNREACHED, "Invalid function arg type.");
  2897. }
  2898. }
  2899. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2900. if (tracingFunc)
  2901. {
  2902. Output::Print(_u("){\n"));
  2903. Output::Flush();
  2904. }
  2905. #endif
  2906. if( info->GetReturnType() == AsmJsRetType::Void )
  2907. {
  2908. m_localSlots[0] = JavascriptOperators::OP_LdUndef( scriptContext );
  2909. }
  2910. }
  2911. #endif
  2912. ///----------------------------------------------------------------------------
  2913. ///
  2914. /// InterpreterStackFrame::Process
  2915. ///
  2916. /// Process() processes a single loop of execution for the current
  2917. /// JavascriptFunction being executed:
  2918. /// - Individual instructions are dispatched to specific handlers for different
  2919. /// OpCodes.
  2920. ///
  2921. ///----------------------------------------------------------------------------
  2922. #if ENABLE_PROFILE_INFO
  2923. #define INTERPRETERLOOPNAME ProcessProfiled
  2924. #define PROVIDE_INTERPRETERPROFILE
  2925. #include "InterpreterLoop.inl"
  2926. #undef PROVIDE_INTERPRETERPROFILE
  2927. #undef INTERPRETERLOOPNAME
  2928. #endif
  2929. #define INTERPRETERLOOPNAME ProcessUnprofiled
  2930. #include "InterpreterLoop.inl"
  2931. #undef INTERPRETERLOOPNAME
  2932. #if ENABLE_TTD_DIAGNOSTICS_TRACING
  2933. #define PROVIDE_INTERPRETER_STMTS
  2934. #define INTERPRETERLOOPNAME ProcessUnprofiled_PreviousStmtTracking
  2935. #include "InterpreterLoop.inl"
  2936. #undef INTERPRETERLOOPNAME
  2937. #undef PROVIDE_INTERPRETER_STMTS
  2938. #endif
  2939. #ifdef ASMJS_PLAT
  2940. #define INTERPRETERLOOPNAME ProcessAsmJs
  2941. #define INTERPRETER_ASMJS
  2942. #include "InterpreterProcessOpCodeAsmJs.h"
  2943. #include "InterpreterLoop.inl"
  2944. #undef INTERPRETER_ASMJS
  2945. #undef INTERPRETERLOOPNAME
  2946. #endif
  2947. // For now, always collect profile data when debugging,
  2948. // otherwise the backend will be confused if there's no profile data.
  2949. #define INTERPRETERLOOPNAME ProcessWithDebugging
  2950. #define PROVIDE_DEBUGGING
  2951. #if ENABLE_PROFILE_INFO
  2952. #define PROVIDE_INTERPRETERPROFILE
  2953. #endif
  2954. #include "InterpreterLoop.inl"
  2955. #if ENABLE_PROFILE_INFO
  2956. #undef PROVIDE_INTERPRETERPROFILE
  2957. #endif
  2958. #undef PROVIDE_DEBUGGING
  2959. #undef INTERPRETERLOOPNAME
  2960. #if ENABLE_TTD
  2961. #define PROVIDE_INTERPRETER_STMTS
  2962. #define INTERPRETERLOOPNAME ProcessWithDebugging_PreviousStmtTracking
  2963. #define PROVIDE_DEBUGGING
  2964. #if ENABLE_PROFILE_INFO
  2965. #define PROVIDE_INTERPRETERPROFILE
  2966. #endif
  2967. #include "InterpreterLoop.inl"
  2968. #if ENABLE_PROFILE_INFO
  2969. #undef PROVIDE_INTERPRETERPROFILE
  2970. #endif
  2971. #undef PROVIDE_DEBUGGING
  2972. #undef INTERPRETERLOOPNAME
  2973. #undef PROVIDE_INTERPRETER_STMTS
  2974. #endif
  2975. Var InterpreterStackFrame::Process()
  2976. {
  2977. #if ENABLE_PROFILE_INFO
  2978. class AutoRestore
  2979. {
  2980. private:
  2981. InterpreterStackFrame *const interpreterStackFrame;
  2982. const uint32 savedSwitchProfileModeOnLoopEndNumber;
  2983. const bool savedIsAutoProfiling;
  2984. const bool savedSwitchProfileMode;
  2985. public:
  2986. AutoRestore(InterpreterStackFrame *const interpreterStackFrame)
  2987. : interpreterStackFrame(interpreterStackFrame),
  2988. savedIsAutoProfiling(interpreterStackFrame->isAutoProfiling),
  2989. savedSwitchProfileMode(interpreterStackFrame->switchProfileMode),
  2990. savedSwitchProfileModeOnLoopEndNumber(interpreterStackFrame->switchProfileModeOnLoopEndNumber)
  2991. {
  2992. }
  2993. ~AutoRestore()
  2994. {
  2995. interpreterStackFrame->isAutoProfiling = savedIsAutoProfiling;
  2996. interpreterStackFrame->switchProfileMode = savedSwitchProfileMode;
  2997. interpreterStackFrame->switchProfileModeOnLoopEndNumber = savedSwitchProfileModeOnLoopEndNumber;
  2998. }
  2999. } autoRestore(this);
  3000. #endif
  3001. if ((m_flags & Js::InterpreterStackFrameFlags_FromBailOut) && !(m_flags & InterpreterStackFrameFlags_ProcessingBailOutFromEHCode))
  3002. {
  3003. if (this->ehBailoutData)
  3004. {
  3005. m_flags |= Js::InterpreterStackFrameFlags_ProcessingBailOutFromEHCode;
  3006. EHBailoutData * topLevelEHBailoutData = this->ehBailoutData;
  3007. while (topLevelEHBailoutData->parent->nestingDepth != -1)
  3008. {
  3009. topLevelEHBailoutData->parent->child = topLevelEHBailoutData;
  3010. topLevelEHBailoutData = topLevelEHBailoutData->parent;
  3011. }
  3012. ProcessTryCatchBailout(topLevelEHBailoutData, this->ehBailoutData->nestingDepth);
  3013. m_flags &= ~Js::InterpreterStackFrameFlags_ProcessingBailOutFromEHCode;
  3014. this->ehBailoutData = nullptr;
  3015. }
  3016. }
  3017. #ifdef ASMJS_PLAT
  3018. if( GetFunctionBody()->GetIsAsmjsMode() )
  3019. {
  3020. FunctionBody *const functionBody = GetFunctionBody();
  3021. AsmJsFunctionInfo* asmInfo = functionBody->GetAsmJsFunctionInfo();
  3022. if (asmInfo)
  3023. {
  3024. AlignMemoryForAsmJs();
  3025. Var returnVar = ProcessAsmJs();
  3026. #if ENABLE_DEBUG_CONFIG_OPTIONS
  3027. if( PHASE_TRACE( AsmjsFunctionEntryPhase, functionBody ) )
  3028. {
  3029. --AsmJsCallDepth;
  3030. if( AsmJsCallDepth )
  3031. {
  3032. Output::Print( _u("%*c}"), AsmJsCallDepth, ' ' );
  3033. }
  3034. else
  3035. {
  3036. Output::Print( _u("}") );
  3037. }
  3038. switch( asmInfo->GetReturnType().which() )
  3039. {
  3040. case AsmJsRetType::Void:
  3041. break;
  3042. case AsmJsRetType::Signed:
  3043. Output::Print( _u(" = %d"), m_localIntSlots[0] );
  3044. break;
  3045. case AsmJsRetType::Int64:
  3046. Output::Print( _u(" = %lld"), m_localInt64Slots[0] );
  3047. break;
  3048. case AsmJsRetType::Float:
  3049. Output::Print(_u(" = %.4f"), m_localFloatSlots[0]);
  3050. break;
  3051. case AsmJsRetType::Double:
  3052. Output::Print( _u(" = %.4f"), m_localDoubleSlots[0]);
  3053. break;
  3054. default:
  3055. break;
  3056. }
  3057. Output::Print( _u(";\n") );
  3058. Output::Flush();
  3059. }
  3060. #endif
  3061. return returnVar;
  3062. }
  3063. else
  3064. {
  3065. Assert(functionBody->GetAsmJsModuleInfo());
  3066. return ProcessAsmJsModule();
  3067. }
  3068. }
  3069. #endif
  3070. #if ENABLE_PROFILE_INFO
  3071. switchProfileMode = false;
  3072. switchProfileModeOnLoopEndNumber = 0u - 1;
  3073. #endif
  3074. #if ENABLE_PROFILE_INFO
  3075. FunctionBody *const functionBody = GetFunctionBody();
  3076. const ExecutionMode interpreterExecutionMode =
  3077. functionBody->GetInterpreterExecutionMode(!!(GetFlags() & InterpreterStackFrameFlags_FromBailOut));
  3078. if(interpreterExecutionMode == ExecutionMode::ProfilingInterpreter)
  3079. {
  3080. #if ENABLE_TTD
  3081. AssertMsg(!SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext), "We should have pinned into Interpreter mode in this case!!!");
  3082. #endif
  3083. isAutoProfiling = false;
  3084. return ProcessProfiled();
  3085. }
  3086. Assert(
  3087. interpreterExecutionMode == ExecutionMode::Interpreter ||
  3088. interpreterExecutionMode == ExecutionMode::AutoProfilingInterpreter);
  3089. isAutoProfiling = interpreterExecutionMode == ExecutionMode::AutoProfilingInterpreter;
  3090. Var result;
  3091. while(true)
  3092. {
  3093. Assert(!switchProfileMode);
  3094. #if ENABLE_TTD_DIAGNOSTICS_TRACING
  3095. if(this->scriptContext->ShouldPerformRecordOrReplayAction())
  3096. {
  3097. result = ProcessUnprofiled_PreviousStmtTracking();
  3098. }
  3099. else
  3100. {
  3101. result = ProcessUnprofiled();
  3102. }
  3103. #else
  3104. result = ProcessUnprofiled();
  3105. #endif
  3106. Assert(!(switchProfileMode && result));
  3107. if(switchProfileMode)
  3108. {
  3109. switchProfileMode = false;
  3110. }
  3111. else
  3112. {
  3113. break;
  3114. }
  3115. Assert(isAutoProfiling);
  3116. #if DBG_DUMP
  3117. if(PHASE_TRACE(InterpreterAutoProfilePhase, functionBody))
  3118. {
  3119. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  3120. Output::Print(_u("InterpreterAutoProfile - Func %s - Started profiling\n"), functionBody->GetDebugNumberSet(debugStringBuffer));
  3121. Output::Flush();
  3122. }
  3123. #endif
  3124. Assert(!switchProfileMode);
  3125. result = ProcessProfiled();
  3126. Assert(!(switchProfileMode && result));
  3127. if(switchProfileMode)
  3128. {
  3129. switchProfileMode = false;
  3130. }
  3131. else
  3132. {
  3133. break;
  3134. }
  3135. Assert(isAutoProfiling);
  3136. #if DBG_DUMP
  3137. if(PHASE_TRACE(InterpreterAutoProfilePhase, functionBody))
  3138. {
  3139. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  3140. Output::Print(_u("InterpreterAutoProfile - Func %s - Stopped profiling\n"), functionBody->GetDebugNumberSet(debugStringBuffer));
  3141. Output::Flush();
  3142. }
  3143. #endif
  3144. }
  3145. return result;
  3146. #else
  3147. #if ENABLE_TTD_DIAGNOSTICS_TRACING
  3148. if(this->scriptContext->ShouldPerformRecordOrReplayAction())
  3149. {
  3150. return ProcessUnprofiled_PreviousStmtTracking();
  3151. }
  3152. else
  3153. {
  3154. return ProcessUnprofiled();
  3155. }
  3156. #else
  3157. return ProcessUnprofiled();
  3158. #endif
  3159. #endif
  3160. }
  3161. template <class T>
  3162. void InterpreterStackFrame::OP_GetMethodProperty(unaligned T *playout)
  3163. {
  3164. Var varInstance = GetReg(playout->Instance);
  3165. OP_GetMethodProperty(varInstance, playout);
  3166. }
  3167. template <class T>
  3168. void InterpreterStackFrame::OP_GetLocalMethodProperty(unaligned T *playout)
  3169. {
  3170. OP_GetMethodProperty(this->localClosure, playout);
  3171. }
  3172. template <class T>
  3173. void InterpreterStackFrame::OP_GetMethodProperty(Var varInstance, unaligned T *playout)
  3174. {
  3175. #if ENABLE_COPYONACCESS_ARRAY
  3176. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(varInstance);
  3177. #endif
  3178. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3179. RecyclableObject* obj = NULL;
  3180. if (RecyclableObject::Is(varInstance))
  3181. {
  3182. obj = RecyclableObject::FromVar(varInstance);
  3183. if ((propertyId == PropertyIds::apply || propertyId == PropertyIds::call) && ScriptFunction::Is(obj))
  3184. {
  3185. // If the property being loaded is "apply"/"call", make an optimistic assumption that apply/call is not overridden and
  3186. // undefer the function right here if it was defer parsed before. This is required so that the load of "apply"/"call"
  3187. // happens from the same "type". Otherwise, we will have a polymorphic cache for load of "apply"/"call".
  3188. ScriptFunction *fn = ScriptFunction::FromVar(obj);
  3189. if(fn->GetType()->GetEntryPoint() == JavascriptFunction::DeferredParsingThunk)
  3190. {
  3191. JavascriptFunction::DeferredParse(&fn);
  3192. }
  3193. }
  3194. }
  3195. InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  3196. PropertyValueInfo info;
  3197. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3198. Var aValue;
  3199. if (obj &&
  3200. CacheOperators::TryGetProperty<true, true, false, false, false, false, true, false, false>(
  3201. obj, false, obj, propertyId, &aValue, GetScriptContext(), nullptr, &info))
  3202. {
  3203. SetReg(playout->Value, aValue);
  3204. return;
  3205. }
  3206. OP_GetMethodProperty_NoFastPath(varInstance, playout);
  3207. }
  3208. template <class T>
  3209. _NOINLINE void InterpreterStackFrame::OP_GetMethodProperty_NoFastPath(Var instance, unaligned T *playout)
  3210. {
  3211. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3212. Var value = JavascriptOperators::PatchGetMethod<false>(
  3213. GetFunctionBody(),
  3214. GetInlineCache(playout->inlineCacheIndex),
  3215. playout->inlineCacheIndex,
  3216. instance,
  3217. propertyId
  3218. );
  3219. #ifdef TELEMETRY_INTERPRETER
  3220. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3221. {
  3222. // `successful` will be true as PatchGetMethod throws an exception if not found.
  3223. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetMethodProperty(instance, propertyId, value, true);
  3224. }
  3225. #endif
  3226. SetReg(playout->Value, value);
  3227. }
  3228. template <class T>
  3229. void InterpreterStackFrame::OP_GetRootMethodProperty(unaligned T *playout)
  3230. {
  3231. Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
  3232. Js::Var instance = this->GetRootObject();
  3233. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3234. InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  3235. DynamicObject *obj = DynamicObject::FromVar(instance);
  3236. PropertyValueInfo info;
  3237. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3238. Var aValue;
  3239. if (CacheOperators::TryGetProperty<true, true, false, false, false, false, true, false, false>(
  3240. obj, true, obj, propertyId, &aValue, GetScriptContext(), nullptr, &info))
  3241. {
  3242. SetReg(playout->Value, aValue);
  3243. return;
  3244. }
  3245. OP_GetRootMethodProperty_NoFastPath(playout);
  3246. }
  3247. template <class T>
  3248. _NOINLINE void InterpreterStackFrame::OP_GetRootMethodProperty_NoFastPath(unaligned T *playout)
  3249. {
  3250. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3251. Var rootInstance = this->GetRootObject();
  3252. Var value = JavascriptOperators::PatchGetRootMethod<false>(
  3253. GetFunctionBody(),
  3254. GetInlineCache(playout->inlineCacheIndex),
  3255. playout->inlineCacheIndex,
  3256. DynamicObject::FromVar(rootInstance),
  3257. propertyId
  3258. );
  3259. #ifdef TELEMETRY_INTERPRETER
  3260. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3261. {
  3262. // `successful` will be true as PatchGetMethod throws an exception if not found.
  3263. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetMethodProperty(rootInstance, propertyId, value, true);
  3264. }
  3265. #endif
  3266. SetReg(playout->Value, value);
  3267. }
  3268. template <class T>
  3269. void InterpreterStackFrame::OP_GetMethodPropertyScoped(unaligned T *playout)
  3270. {
  3271. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  3272. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  3273. threadContext->ClearImplicitCallFlags();
  3274. Var varInstance = GetReg(playout->Instance);
  3275. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3276. RecyclableObject* obj = NULL;
  3277. if (RecyclableObject::Is(varInstance))
  3278. {
  3279. obj = RecyclableObject::FromVar(varInstance);
  3280. }
  3281. InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  3282. PropertyValueInfo info;
  3283. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3284. Var aValue;
  3285. if (obj &&
  3286. CacheOperators::TryGetProperty<true, true, false, false, false, false, true, false, false>(
  3287. obj, false, obj, propertyId, &aValue, GetScriptContext(), nullptr, &info))
  3288. {
  3289. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3290. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3291. SetReg(playout->Value, aValue);
  3292. return;
  3293. }
  3294. OP_GetMethodPropertyScoped_NoFastPath(playout);
  3295. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3296. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3297. }
  3298. template <class T>
  3299. _NOINLINE void InterpreterStackFrame::OP_GetMethodPropertyScoped_NoFastPath(unaligned T *playout)
  3300. {
  3301. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3302. Js::Var instance = GetReg(playout->Instance);
  3303. Js::Var value = JavascriptOperators::PatchScopedGetMethod<false>(
  3304. GetFunctionBody(),
  3305. GetInlineCache(playout->inlineCacheIndex),
  3306. playout->inlineCacheIndex,
  3307. instance,
  3308. propertyId
  3309. );
  3310. SetReg(playout->Value, value);
  3311. #ifdef TELEMETRY_INTERPRETER
  3312. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3313. {
  3314. // `successful` will be true as PatchGetMethod throws an exception if not found.
  3315. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetMethodProperty(instance, propertyId, value, true);
  3316. }
  3317. #endif
  3318. }
  3319. template <class T>
  3320. void InterpreterStackFrame::OP_ProfiledGetMethodProperty(unaligned T *playout)
  3321. {
  3322. ProfiledGetProperty<T, false, true, false>(playout, GetReg(playout->Instance));
  3323. }
  3324. template <class T>
  3325. void InterpreterStackFrame::OP_ProfiledGetLocalMethodProperty(unaligned T *playout)
  3326. {
  3327. ProfiledGetProperty<T, false, true, false>(playout, this->localClosure);
  3328. }
  3329. template <class T>
  3330. void InterpreterStackFrame::OP_ProfiledGetRootMethodProperty(unaligned T *playout)
  3331. {
  3332. ProfiledGetProperty<T, true, true, false>(playout, GetRootObject());
  3333. }
  3334. RecyclableObject *
  3335. InterpreterStackFrame::OP_CallGetFunc(Var target)
  3336. {
  3337. return JavascriptOperators::GetCallableObjectOrThrow(target, GetScriptContext());
  3338. }
  3339. void InterpreterStackFrame::OP_AsmStartCall( const unaligned OpLayoutStartCall * playout )
  3340. {
  3341. OP_StartCall( playout->ArgCount/sizeof(Var) );
  3342. m_outParams[0] = scriptContext->GetLibrary()->GetUndefined();
  3343. }
  3344. void InterpreterStackFrame::OP_StartCall(const unaligned OpLayoutStartCall * playout)
  3345. {
  3346. OP_StartCall(playout->ArgCount);
  3347. }
  3348. void InterpreterStackFrame::OP_StartCall(uint outParamCount)
  3349. {
  3350. // Save the outParams for the current callsite on the outparam stack
  3351. PushOut(m_outParams);
  3352. // Update outParams for the indicated callsite
  3353. m_outParams = m_outSp;
  3354. m_outSp += outParamCount;
  3355. AssertMsg(m_localSlots + this->m_functionBody->GetLocalsCount() < m_outSp &&
  3356. m_outSp <= (m_localSlots + this->m_functionBody->GetLocalsCount() + this->m_functionBody->GetOutParamMaxDepth()),
  3357. "out args Stack pointer not in range after Push");
  3358. }
  3359. #ifdef ASMJS_PLAT
  3360. #if _M_X64 || _M_IX86
  3361. void InterpreterStackFrame::OP_CallAsmInternal(RecyclableObject * function)
  3362. {
  3363. AsmJsFunctionInfo* asmInfo = ((ScriptFunction*)function)->GetFunctionBody()->GetAsmJsFunctionInfo();
  3364. uint argsSize = asmInfo->GetArgByteSize();
  3365. ScriptFunction* scriptFunc = (ScriptFunction*)function;
  3366. ScriptContext * scriptContext = function->GetScriptContext();
  3367. PROBE_STACK_CALL(scriptContext, function, argsSize);
  3368. Js::FunctionEntryPointInfo* entrypointInfo = (Js::FunctionEntryPointInfo*)scriptFunc->GetEntryPointInfo();
  3369. switch (asmInfo->GetReturnType().which())
  3370. {
  3371. case AsmJsRetType::Void:
  3372. case AsmJsRetType::Signed:
  3373. m_localIntSlots[0] = JavascriptFunction::CallAsmJsFunction<int>(function, entrypointInfo->jsMethod, asmInfo->GetArgCount(), m_outParams);
  3374. break;
  3375. case AsmJsRetType::Int64:
  3376. m_localInt64Slots[0] = JavascriptFunction::CallAsmJsFunction<int64>(function, entrypointInfo->jsMethod, asmInfo->GetArgCount(), m_outParams);
  3377. break;
  3378. case AsmJsRetType::Double:
  3379. m_localDoubleSlots[0] = JavascriptFunction::CallAsmJsFunction<double>(function, entrypointInfo->jsMethod, asmInfo->GetArgCount(), m_outParams);
  3380. break;
  3381. case AsmJsRetType::Float:
  3382. m_localFloatSlots[0] = JavascriptFunction::CallAsmJsFunction<float>(function, entrypointInfo->jsMethod, asmInfo->GetArgCount(), m_outParams);
  3383. break;
  3384. #ifdef ENABLE_SIMDJS
  3385. case AsmJsRetType::Float32x4:
  3386. case AsmJsRetType::Int32x4:
  3387. case AsmJsRetType::Bool32x4:
  3388. case AsmJsRetType::Bool16x8:
  3389. case AsmJsRetType::Bool8x16:
  3390. case AsmJsRetType::Float64x2:
  3391. case AsmJsRetType::Int16x8:
  3392. case AsmJsRetType::Int8x16:
  3393. case AsmJsRetType::Uint32x4:
  3394. case AsmJsRetType::Uint16x8:
  3395. case AsmJsRetType::Uint8x16:
  3396. #if _M_X64
  3397. X86SIMDValue simdVal;
  3398. simdVal.m128_value = JavascriptFunction::CallAsmJsFunction<__m128>(function, entrypointInfo->jsMethod, asmInfo->GetArgCount(), m_outParams);
  3399. m_localSimdSlots[0] = X86SIMDValue::ToSIMDValue(simdVal);
  3400. #else
  3401. m_localSimdSlots[0] = JavascriptFunction::CallAsmJsFunction<AsmJsSIMDValue>(function, entrypointInfo->jsMethod, asmInfo->GetArgCount(), m_outParams);
  3402. #endif
  3403. break;
  3404. #endif
  3405. default:
  3406. Assume(UNREACHED);
  3407. }
  3408. Assert((uint)((ArgSlot)asmInfo->GetArgCount() + 1) == (uint)(asmInfo->GetArgCount() + 1));
  3409. #if _M_X64
  3410. if (scriptContext->GetConfig()->IsSimdjsEnabled())
  3411. #endif
  3412. {
  3413. PopOut((ArgSlot)(argsSize / sizeof(Var)) + 1);
  3414. }
  3415. #if _M_X64
  3416. else
  3417. {
  3418. PopOut((ArgSlot)asmInfo->GetArgCount() + 1);
  3419. }
  3420. #endif
  3421. Assert(function);
  3422. }
  3423. #else
  3424. void InterpreterStackFrame::OP_CallAsmInternal(RecyclableObject * function)
  3425. {
  3426. __debugbreak();
  3427. }
  3428. #endif
  3429. #endif
  3430. template <class T>
  3431. void InterpreterStackFrame::OP_AsmCall(const unaligned T* playout)
  3432. {
  3433. OP_CallCommon(playout, OP_CallGetFunc(GetRegAllowStackVar(playout->Function)), CallFlags_None);
  3434. AsmJsModuleInfo::EnsureHeapAttached(this->function);
  3435. }
  3436. template <class T>
  3437. void InterpreterStackFrame::OP_CallCommon(const unaligned T * playout, RecyclableObject * function, unsigned flags, const Js::AuxArray<uint32> *spreadIndices)
  3438. {
  3439. // Always save and restore implicit call flags when calling out
  3440. // REVIEW: Can we avoid it if we don't collect dynamic profile info?
  3441. ThreadContext * threadContext = scriptContext->GetThreadContext();
  3442. Js::ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  3443. #if DBG
  3444. if (this->IsInDebugMode())
  3445. {
  3446. JavascriptFunction::CheckValidDebugThunk(scriptContext, function);
  3447. }
  3448. #endif
  3449. if (playout->Return == Js::Constants::NoRegister)
  3450. {
  3451. flags |= CallFlags_NotUsed;
  3452. Arguments args(CallInfo((CallFlags)flags, playout->ArgCount), m_outParams);
  3453. AssertMsg(static_cast<unsigned>(args.Info.Flags) == flags, "Flags don't fit into the CallInfo field?");
  3454. if (spreadIndices != nullptr)
  3455. {
  3456. JavascriptFunction::CallSpreadFunction(function, args, spreadIndices);
  3457. }
  3458. else
  3459. {
  3460. JavascriptFunction::CallFunction<true>(function, function->GetEntryPoint(), args);
  3461. }
  3462. }
  3463. else
  3464. {
  3465. flags |= CallFlags_Value;
  3466. Arguments args(CallInfo((CallFlags)flags, playout->ArgCount), m_outParams);
  3467. AssertMsg(static_cast<unsigned>(args.Info.Flags) == flags, "Flags don't fit into the CallInfo field?");
  3468. if (spreadIndices != nullptr)
  3469. {
  3470. SetReg((RegSlot)playout->Return, JavascriptFunction::CallSpreadFunction(function, args, spreadIndices));
  3471. }
  3472. else
  3473. {
  3474. SetReg((RegSlot)playout->Return, JavascriptFunction::CallFunction<true>(function, function->GetEntryPoint(), args));
  3475. }
  3476. }
  3477. threadContext->SetImplicitCallFlags(savedImplicitCallFlags);
  3478. PopOut(playout->ArgCount);
  3479. }
  3480. template <class T>
  3481. void InterpreterStackFrame::OP_CallCommonI(const unaligned T * playout, RecyclableObject * function, unsigned flags)
  3482. {
  3483. OP_CallCommon(playout, function, flags); // CallCommon doesn't do anything with Member
  3484. }
  3485. #if ENABLE_PROFILE_INFO
  3486. template <class T>
  3487. void InterpreterStackFrame::OP_ProfileCallCommon(const unaligned T * playout, RecyclableObject * function, unsigned flags, ProfileId profileId, InlineCacheIndex inlineCacheIndex, const Js::AuxArray<uint32> *spreadIndices)
  3488. {
  3489. FunctionBody* functionBody = this->m_functionBody;
  3490. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  3491. FunctionInfo* functionInfo = function->GetTypeId() == TypeIds_Function?
  3492. JavascriptFunction::FromVar(function)->GetFunctionInfo() : nullptr;
  3493. bool isConstructorCall = (CallFlags_New & flags) == CallFlags_New;
  3494. dynamicProfileInfo->RecordCallSiteInfo(functionBody, profileId, functionInfo, functionInfo ? static_cast<JavascriptFunction*>(function) : nullptr, playout->ArgCount, isConstructorCall, inlineCacheIndex);
  3495. OP_CallCommon<T>(playout, function, flags, spreadIndices);
  3496. if (playout->Return != Js::Constants::NoRegister)
  3497. {
  3498. dynamicProfileInfo->RecordReturnTypeOnCallSiteInfo(functionBody, profileId, GetReg((RegSlot)playout->Return));
  3499. }
  3500. }
  3501. template <class T>
  3502. void InterpreterStackFrame::OP_ProfileReturnTypeCallCommon(const unaligned T * playout, RecyclableObject * function, unsigned flags, ProfileId profileId, const Js::AuxArray<uint32> *spreadIndices)
  3503. {
  3504. OP_CallCommon<T>(playout, function, flags, spreadIndices);
  3505. FunctionBody* functionBody = this->m_functionBody;
  3506. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  3507. if (playout->Return != Js::Constants::NoRegister)
  3508. {
  3509. dynamicProfileInfo->RecordReturnType(functionBody, profileId, GetReg((RegSlot)playout->Return));
  3510. }
  3511. }
  3512. #endif
  3513. template <class T>
  3514. void InterpreterStackFrame::OP_CallPutCommon(const unaligned T *playout, RecyclableObject * function)
  3515. {
  3516. Arguments args(CallInfo(CallFlags_None, playout->ArgCount), m_outParams);
  3517. SetReg((RegSlot)playout->Return, function->InvokePut(args));
  3518. PopOut(playout->ArgCount);
  3519. }
  3520. template <class T>
  3521. void InterpreterStackFrame::OP_CallPutCommonI(const unaligned T *playout, RecyclableObject * function)
  3522. {
  3523. OP_CallPutCommon(playout, function);
  3524. }
  3525. template <class T>
  3526. void InterpreterStackFrame::OP_GetRootProperty(unaligned T* playout)
  3527. {
  3528. // Same fast path as in the backend.
  3529. Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
  3530. Js::Var instance = this->GetRootObject();
  3531. InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  3532. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3533. DynamicObject * obj = DynamicObject::FromVar(instance);
  3534. PropertyValueInfo info;
  3535. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3536. Var value;
  3537. if(CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
  3538. obj, true, obj, propertyId, &value, GetScriptContext(), nullptr, &info))
  3539. {
  3540. SetReg(playout->Value, value);
  3541. return;
  3542. }
  3543. OP_GetRootProperty_NoFastPath(playout);
  3544. }
  3545. template <class T>
  3546. void InterpreterStackFrame::OP_GetRootPropertyForTypeOf(unaligned T* playout)
  3547. {
  3548. Var rootInstance = GetRootObject();
  3549. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3550. Var value = JavascriptOperators::PatchGetRootValueForTypeOf<false>(
  3551. GetFunctionBody(),
  3552. GetInlineCache(playout->inlineCacheIndex),
  3553. playout->inlineCacheIndex,
  3554. DynamicObject::FromVar(rootInstance),
  3555. propertyId
  3556. );
  3557. SetReg(playout->Value, value);
  3558. #ifdef TELEMETRY_INTERPRETER
  3559. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3560. {
  3561. // `successful` will be true as PatchGetRootValue throws an exception if not found.
  3562. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(rootInstance, propertyId, value, /*successful:*/true);
  3563. }
  3564. #endif
  3565. }
  3566. template <class T>
  3567. _NOINLINE void InterpreterStackFrame::OP_GetRootProperty_NoFastPath(unaligned T* playout)
  3568. {
  3569. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3570. Var rootInstance = this->GetRootObject();
  3571. Var value = JavascriptOperators::PatchGetRootValue<false>(
  3572. GetFunctionBody(),
  3573. GetInlineCache(playout->inlineCacheIndex),
  3574. playout->inlineCacheIndex,
  3575. DynamicObject::FromVar(rootInstance),
  3576. propertyId
  3577. );
  3578. SetReg(playout->Value, value);
  3579. #ifdef TELEMETRY_INTERPRETER
  3580. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3581. {
  3582. // `successful` will be true as PatchGetRootValue throws an exception if not found.
  3583. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(rootInstance, propertyId, value, /*successful:*/true);
  3584. }
  3585. #endif
  3586. }
  3587. #if ENABLE_PROFILE_INFO
  3588. template <class T>
  3589. void InterpreterStackFrame::UpdateFldInfoFlagsForGetSetInlineCandidate(unaligned T* playout, FldInfoFlags& fldInfoFlags, CacheType cacheType,
  3590. DynamicProfileInfo * dynamicProfileInfo, uint inlineCacheIndex, RecyclableObject * obj)
  3591. {
  3592. RecyclableObject *callee = nullptr;
  3593. //TODO: Setter case once we stop sharing inline caches for these callsites.
  3594. if ((cacheType & (CacheType_Getter | CacheType_Setter)) && GetInlineCache(inlineCacheIndex)->GetGetterSetter(obj->GetType(), &callee))
  3595. {
  3596. const auto functionBody = this->m_functionBody;
  3597. bool canInline = dynamicProfileInfo->RecordLdFldCallSiteInfo(functionBody, callee, false /*callApplyTarget*/);
  3598. if (canInline)
  3599. {
  3600. //updates this fldInfoFlags passed by reference.
  3601. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_InlineCandidate);
  3602. }
  3603. }
  3604. }
  3605. template <class T>
  3606. void InterpreterStackFrame::UpdateFldInfoFlagsForCallApplyInlineCandidate(unaligned T* playout, FldInfoFlags& fldInfoFlags, CacheType cacheType,
  3607. DynamicProfileInfo * dynamicProfileInfo, uint inlineCacheIndex, RecyclableObject * obj)
  3608. {
  3609. RecyclableObject *callee = nullptr;
  3610. if (!(fldInfoFlags & FldInfo_Polymorphic) && GetInlineCache(inlineCacheIndex)->GetCallApplyTarget(obj, &callee))
  3611. {
  3612. const auto functionBody = this->m_functionBody;
  3613. bool canInline = dynamicProfileInfo->RecordLdFldCallSiteInfo(functionBody, callee, true /*callApplyTarget*/);
  3614. if (canInline)
  3615. {
  3616. //updates this fldInfoFlags passed by reference.
  3617. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_InlineCandidate);
  3618. }
  3619. }
  3620. }
  3621. template <class T, bool Root, bool Method, bool CallApplyTarget>
  3622. void InterpreterStackFrame::ProfiledGetProperty(unaligned T* playout, const Var instance)
  3623. {
  3624. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3625. Var value = ProfilingHelpers::ProfiledLdFld<Root, Method, CallApplyTarget>(
  3626. instance,
  3627. propertyId,
  3628. GetInlineCache(playout->inlineCacheIndex),
  3629. playout->inlineCacheIndex,
  3630. GetFunctionBody(),
  3631. instance);
  3632. SetReg(playout->Value, value);
  3633. #ifdef TELEMETRY_INTERPRETER
  3634. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3635. {
  3636. // `successful` will be true as PatchGetRootValue throws an exception if not found.
  3637. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, /*successful:*/true);
  3638. }
  3639. #endif
  3640. }
  3641. template <class T>
  3642. void InterpreterStackFrame::OP_ProfiledGetRootProperty(unaligned T* playout)
  3643. {
  3644. ProfiledGetProperty<T, true, false, false>(playout, GetRootObject());
  3645. }
  3646. template <class T>
  3647. void InterpreterStackFrame::OP_ProfiledGetRootPropertyForTypeOf(unaligned T* playout)
  3648. {
  3649. Var rootInstance = GetRootObject();
  3650. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3651. Var value = ProfilingHelpers::ProfiledLdFldForTypeOf<true, false, false>(
  3652. rootInstance,
  3653. propertyId,
  3654. GetInlineCache(playout->inlineCacheIndex),
  3655. playout->inlineCacheIndex,
  3656. GetFunctionBody());
  3657. SetReg(playout->Value, value);
  3658. #ifdef TELEMETRY_INTERPRETER
  3659. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3660. {
  3661. // `successful` will be true as PatchGetRootValue throws an exception if not found.
  3662. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(rootInstance, propertyId, value, /*successful:*/true);
  3663. }
  3664. #endif
  3665. }
  3666. #endif
  3667. template <class T>
  3668. void InterpreterStackFrame::OP_GetPropertyForTypeOf(unaligned T* playout)
  3669. {
  3670. Var instance = GetReg(playout->Instance);
  3671. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3672. Var value = JavascriptOperators::PatchGetValueForTypeOf<false>(
  3673. GetFunctionBody(),
  3674. GetInlineCache(playout->inlineCacheIndex),
  3675. playout->inlineCacheIndex,
  3676. instance,
  3677. propertyId
  3678. );
  3679. SetReg(playout->Value, value);
  3680. #ifdef TELEMETRY_INTERPRETER
  3681. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3682. {
  3683. // `successful` will be true as PatchGetRootValue throws an exception if not found.
  3684. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, /*successful:*/true);
  3685. }
  3686. #endif
  3687. }
  3688. template <class T>
  3689. void InterpreterStackFrame::OP_GetProperty(unaligned T* playout)
  3690. {
  3691. // Same fast path as in the backend.
  3692. Var instance = GetReg(playout->Instance);
  3693. OP_GetProperty(instance, playout);
  3694. }
  3695. template <class T>
  3696. void InterpreterStackFrame::OP_GetLocalProperty(unaligned T* playout)
  3697. {
  3698. // Same fast path as in the backend.
  3699. Var instance = this->localClosure;
  3700. OP_GetProperty(instance, playout);
  3701. }
  3702. template <class T>
  3703. void InterpreterStackFrame::OP_GetProperty(Var instance, unaligned T* playout)
  3704. {
  3705. InlineCache *inlineCache = GetInlineCache(playout->inlineCacheIndex);
  3706. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3707. if (RecyclableObject::Is(instance))
  3708. {
  3709. RecyclableObject* obj = RecyclableObject::FromVar(instance);
  3710. PropertyValueInfo info;
  3711. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3712. Var value;
  3713. if (CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
  3714. obj, false, obj, propertyId, &value, GetScriptContext(), nullptr, &info))
  3715. {
  3716. SetReg(playout->Value, value);
  3717. return;
  3718. }
  3719. }
  3720. OP_GetProperty_NoFastPath(instance, playout);
  3721. }
  3722. template <class T>
  3723. void InterpreterStackFrame::OP_GetSuperProperty(unaligned T* playout)
  3724. {
  3725. // Same fast path as in the backend.
  3726. Var instance = GetReg(playout->Instance);
  3727. Var thisInstance = GetReg(playout->Value2);
  3728. InlineCache *inlineCache = GetInlineCache(playout->PropertyIdIndex);
  3729. PropertyId propertyId = GetPropertyIdFromCacheId(playout->PropertyIdIndex);
  3730. if (RecyclableObject::Is(instance) && RecyclableObject::Is(thisInstance))
  3731. {
  3732. RecyclableObject* superObj = RecyclableObject::FromVar(instance);
  3733. RecyclableObject* thisObj = RecyclableObject::FromVar(thisInstance);
  3734. PropertyValueInfo info;
  3735. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->PropertyIdIndex, true);
  3736. Var value;
  3737. if (CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
  3738. thisObj, false, superObj, propertyId, &value, GetScriptContext(), nullptr, &info))
  3739. {
  3740. SetReg(playout->Value, value);
  3741. return;
  3742. }
  3743. }
  3744. SetReg(
  3745. playout->Value,
  3746. JavascriptOperators::PatchGetValueWithThisPtr<false>(
  3747. GetFunctionBody(),
  3748. GetInlineCache(playout->PropertyIdIndex),
  3749. playout->PropertyIdIndex,
  3750. GetReg(playout->Instance),
  3751. GetPropertyIdFromCacheId(playout->PropertyIdIndex),
  3752. GetReg(playout->Value2)));
  3753. }
  3754. template <class T>
  3755. _NOINLINE void InterpreterStackFrame::OP_GetProperty_NoFastPath(Var instance, unaligned T* playout)
  3756. {
  3757. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3758. Var value = JavascriptOperators::PatchGetValue<false>(
  3759. GetFunctionBody(),
  3760. GetInlineCache(playout->inlineCacheIndex),
  3761. playout->inlineCacheIndex,
  3762. instance,
  3763. propertyId
  3764. );
  3765. #ifdef TELEMETRY_INTERPRETER
  3766. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3767. {
  3768. // `successful` will be true as PatchGetMethod throws an exception if not found.
  3769. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, true);
  3770. }
  3771. #endif
  3772. SetReg(playout->Value, value);
  3773. }
  3774. #if ENABLE_PROFILE_INFO
  3775. template <class T>
  3776. void InterpreterStackFrame::OP_ProfiledGetProperty(unaligned T* playout)
  3777. {
  3778. ProfiledGetProperty<T, false, false, false>(playout, GetReg(playout->Instance));
  3779. }
  3780. template <class T>
  3781. void InterpreterStackFrame::OP_ProfiledGetLocalProperty(unaligned T* playout)
  3782. {
  3783. ProfiledGetProperty<T, false, false, false>(playout, this->localClosure);
  3784. }
  3785. template <class T>
  3786. void InterpreterStackFrame::OP_ProfiledGetSuperProperty(unaligned T* playout)
  3787. {
  3788. SetReg(
  3789. playout->Value,
  3790. ProfilingHelpers::ProfiledLdFld<false, false, false>(
  3791. GetReg(playout->Instance),
  3792. GetPropertyIdFromCacheId(playout->PropertyIdIndex),
  3793. GetInlineCache(playout->PropertyIdIndex),
  3794. playout->PropertyIdIndex,
  3795. GetFunctionBody(),
  3796. GetReg(playout->Value2)));
  3797. }
  3798. template <class T>
  3799. void InterpreterStackFrame::OP_ProfiledGetPropertyForTypeOf(unaligned T* playout)
  3800. {
  3801. Var instance = GetReg(playout->Instance);
  3802. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3803. Var value = ProfilingHelpers::ProfiledLdFldForTypeOf<false, false, false>(
  3804. instance,
  3805. propertyId,
  3806. GetInlineCache(playout->inlineCacheIndex),
  3807. playout->inlineCacheIndex,
  3808. GetFunctionBody()
  3809. );
  3810. SetReg(playout->Value, value);
  3811. #ifdef TELEMETRY_INTERPRETER
  3812. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3813. {
  3814. // `successful` will be true as PatchGetMethod throws an exception if not found.
  3815. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, true);
  3816. }
  3817. #endif
  3818. }
  3819. template <class T>
  3820. void InterpreterStackFrame::OP_ProfiledGetPropertyCallApplyTarget(unaligned T* playout)
  3821. {
  3822. ProfiledGetProperty<T, false, false, true>(playout, GetReg(playout->Instance));
  3823. }
  3824. #endif
  3825. template <typename T>
  3826. void InterpreterStackFrame::OP_GetPropertyScoped(const unaligned OpLayoutT_ElementP<T>* playout)
  3827. {
  3828. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  3829. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  3830. threadContext->ClearImplicitCallFlags();
  3831. // Get the property, using a scope stack rather than an individual instance.
  3832. // Use the cache
  3833. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3834. FrameDisplay *pScope = this->GetEnvForEvalCode();
  3835. InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  3836. ScriptContext* scriptContext = GetScriptContext();
  3837. int length = pScope->GetLength();
  3838. if ( 1 == length )
  3839. {
  3840. DynamicObject *obj = (DynamicObject*)pScope->GetItem(0);
  3841. PropertyValueInfo info;
  3842. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3843. Var value;
  3844. if (CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
  3845. obj, false, obj, propertyId, &value, scriptContext, nullptr, &info))
  3846. {
  3847. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3848. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3849. SetReg(playout->Value, value);
  3850. return;
  3851. }
  3852. }
  3853. OP_GetPropertyScoped_NoFastPath(playout);
  3854. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3855. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3856. }
  3857. template <typename T>
  3858. void InterpreterStackFrame::OP_GetPropertyForTypeOfScoped(const unaligned OpLayoutT_ElementP<T>* playout)
  3859. {
  3860. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  3861. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  3862. threadContext->ClearImplicitCallFlags();
  3863. // Get the property, using a scope stack rather than an individual instance.
  3864. // Use the cache
  3865. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3866. FrameDisplay *pScope = this->GetEnvForEvalCode();
  3867. InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  3868. ScriptContext* scriptContext = GetScriptContext();
  3869. int length = pScope->GetLength();
  3870. if (1 == length)
  3871. {
  3872. DynamicObject *obj = (DynamicObject*)pScope->GetItem(0);
  3873. PropertyValueInfo info;
  3874. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3875. Var value;
  3876. if (CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
  3877. obj, false, obj, propertyId, &value, scriptContext, nullptr, &info))
  3878. {
  3879. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3880. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3881. SetReg(playout->Value, value);
  3882. return;
  3883. }
  3884. }
  3885. SetReg(
  3886. playout->Value,
  3887. JavascriptOperators::PatchGetPropertyForTypeOfScoped<false>(
  3888. GetFunctionBody(),
  3889. GetInlineCache(playout->inlineCacheIndex),
  3890. playout->inlineCacheIndex,
  3891. GetEnvForEvalCode(),
  3892. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  3893. GetReg(Js::FunctionBody::RootObjectRegSlot)));
  3894. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3895. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3896. }
  3897. template <typename T>
  3898. _NOINLINE void InterpreterStackFrame::OP_GetPropertyScoped_NoFastPath(const unaligned OpLayoutT_ElementP<T>* playout)
  3899. {
  3900. // Implicit root object as default instance
  3901. Var defaultInstance = GetReg(Js::FunctionBody::RootObjectRegSlot);
  3902. // PatchGetPropertyScoped doesn't update type and slotIndex if the scope is not an array of length 1.
  3903. SetReg(
  3904. playout->Value,
  3905. JavascriptOperators::PatchGetPropertyScoped<false>(
  3906. GetFunctionBody(),
  3907. GetInlineCache(playout->inlineCacheIndex),
  3908. playout->inlineCacheIndex,
  3909. GetEnvForEvalCode(),
  3910. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  3911. defaultInstance));
  3912. }
  3913. template <class T>
  3914. void InterpreterStackFrame::OP_SetPropertyScoped(unaligned T* playout, PropertyOperationFlags flags)
  3915. {
  3916. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  3917. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  3918. threadContext->ClearImplicitCallFlags();
  3919. // Set the property, using a scope stack rather than an individual instance.
  3920. // Use the cache
  3921. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3922. FrameDisplay *pScope = this->GetEnvForEvalCode();
  3923. InlineCache *inlineCache = GetInlineCache(playout->inlineCacheIndex);
  3924. ScriptContext* scriptContext = GetScriptContext();
  3925. Var value = GetReg(playout->Value);
  3926. DynamicObject *obj;
  3927. int length = pScope->GetLength();
  3928. if ( 1 == length )
  3929. {
  3930. obj = (DynamicObject*)pScope->GetItem(0);
  3931. PropertyValueInfo info;
  3932. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3933. if (CacheOperators::TrySetProperty<true, false, false, false, false, true, false, false>(
  3934. obj, false, propertyId, value, scriptContext, flags, nullptr, &info))
  3935. {
  3936. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3937. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3938. return;
  3939. }
  3940. }
  3941. OP_SetPropertyScoped_NoFastPath(playout, flags);
  3942. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3943. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3944. }
  3945. template <class T>
  3946. _NOINLINE void InterpreterStackFrame::OP_SetPropertyScoped_NoFastPath(unaligned T* playout, PropertyOperationFlags flags)
  3947. {
  3948. // Implicit root object as default instance
  3949. Var defaultInstance = GetReg(Js::FunctionBody::RootObjectRegSlot);
  3950. // PatchSetPropertyScoped doesn't update type and slotIndex if the scope is not an array of length 1.
  3951. JavascriptOperators::PatchSetPropertyScoped<false>(
  3952. GetFunctionBody(),
  3953. GetInlineCache(playout->inlineCacheIndex),
  3954. playout->inlineCacheIndex,
  3955. GetEnvForEvalCode(),
  3956. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  3957. GetReg(playout->Value),
  3958. defaultInstance,
  3959. flags);
  3960. }
  3961. template <class T>
  3962. void InterpreterStackFrame::OP_SetPropertyScopedStrict(unaligned T* playout)
  3963. {
  3964. OP_SetPropertyScoped(playout, PropertyOperation_StrictMode);
  3965. }
  3966. template <class T>
  3967. void InterpreterStackFrame::OP_ConsoleSetPropertyScoped(unaligned T* playout)
  3968. {
  3969. OP_SetPropertyScoped(playout, PropertyOperation_AllowUndeclInConsoleScope);
  3970. }
  3971. template <class T>
  3972. inline bool InterpreterStackFrame::TrySetPropertyLocalFastPath(unaligned T* playout, PropertyId pid, Var instance, InlineCache*& inlineCache, PropertyOperationFlags flags)
  3973. {
  3974. Assert(!TaggedNumber::Is(instance));
  3975. RecyclableObject* obj = RecyclableObject::FromVar(instance);
  3976. inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  3977. PropertyValueInfo info;
  3978. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3979. return
  3980. CacheOperators::TrySetProperty<true, false, false, false, false, true, false, false>(
  3981. obj,
  3982. !!(flags & PropertyOperation_Root),
  3983. pid,
  3984. GetReg(playout->Value),
  3985. GetScriptContext(),
  3986. flags,
  3987. nullptr,
  3988. &info);
  3989. }
  3990. template <class T>
  3991. inline void InterpreterStackFrame::DoSetProperty(unaligned T* playout, Var instance, PropertyOperationFlags flags)
  3992. {
  3993. // Same fast path as in the backend.
  3994. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3995. InlineCache *inlineCache;
  3996. if (!TaggedNumber::Is(instance)
  3997. && TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache, flags))
  3998. {
  3999. if(GetJavascriptFunction()->GetConstructorCache()->NeedsUpdateAfterCtor())
  4000. {
  4001. // This function has only 'this' statements and is being used as a constructor. When the constructor exits, the
  4002. // function object's constructor cache will be updated with the type produced by the constructor. From that
  4003. // point on, when the same function object is used as a constructor, the a new object with the final type will
  4004. // be created. Whatever is stored in the inline cache currently will cause cache misses after the constructor
  4005. // cache update. So, just clear it now so that the caches won't be flagged as polymorphic.
  4006. inlineCache->Clear();
  4007. }
  4008. return;
  4009. }
  4010. DoSetProperty_NoFastPath(playout, instance, flags);
  4011. }
  4012. template <class T>
  4013. inline void InterpreterStackFrame::DoSetSuperProperty(unaligned T* playout, Var instance, PropertyOperationFlags flags)
  4014. {
  4015. DoSetSuperProperty_NoFastPath(playout, instance, m_functionBody->GetIsStrictMode() ?
  4016. (PropertyOperationFlags)(flags | PropertyOperation_StrictMode) : flags);
  4017. }
  4018. template <class T>
  4019. _NOINLINE void InterpreterStackFrame::DoSetProperty_NoFastPath(unaligned T* playout, Var instance, PropertyOperationFlags flags)
  4020. {
  4021. #if ENABLE_COPYONACCESS_ARRAY
  4022. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  4023. #endif
  4024. InlineCache *const inlineCache = GetInlineCache(playout->inlineCacheIndex);
  4025. const auto PatchPutRootValue = &JavascriptOperators::PatchPutRootValueNoLocalFastPath<false, InlineCache>;
  4026. const auto PatchPutValue = &JavascriptOperators::PatchPutValueNoLocalFastPath<false, InlineCache>;
  4027. const auto PatchPut = flags & PropertyOperation_Root ? PatchPutRootValue : PatchPutValue;
  4028. PatchPut(
  4029. GetFunctionBody(),
  4030. inlineCache,
  4031. playout->inlineCacheIndex,
  4032. instance,
  4033. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  4034. GetReg(playout->Value),
  4035. flags);
  4036. if(!TaggedNumber::Is(instance) && GetJavascriptFunction()->GetConstructorCache()->NeedsUpdateAfterCtor())
  4037. {
  4038. // This function has only 'this' statements and is being used as a constructor. When the constructor exits, the
  4039. // function object's constructor cache will be updated with the type produced by the constructor. From that
  4040. // point on, when the same function object is used as a constructor, the a new object with the final type will
  4041. // be created. Whatever is stored in the inline cache currently will cause cache misses after the constructor
  4042. // cache update. So, just clear it now so that the caches won't be flagged as polymorphic.
  4043. inlineCache->Clear();
  4044. }
  4045. }
  4046. template <class T>
  4047. _NOINLINE void InterpreterStackFrame::DoSetSuperProperty_NoFastPath(unaligned T* playout, Var instance, PropertyOperationFlags flags)
  4048. {
  4049. #if ENABLE_COPYONACCESS_ARRAY
  4050. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  4051. #endif
  4052. InlineCache *const inlineCache = GetInlineCache(playout->PropertyIdIndex);
  4053. JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPath<false, InlineCache>(
  4054. GetFunctionBody(),
  4055. inlineCache,
  4056. playout->PropertyIdIndex,
  4057. instance,
  4058. GetPropertyIdFromCacheId(playout->PropertyIdIndex),
  4059. GetReg(playout->Value),
  4060. GetReg(playout->Value2),
  4061. flags);
  4062. if (!TaggedNumber::Is(instance) && GetJavascriptFunction()->GetConstructorCache()->NeedsUpdateAfterCtor())
  4063. {
  4064. // This function has only 'this' statements and is being used as a constructor. When the constructor exits, the
  4065. // function object's constructor cache will be updated with the type produced by the constructor. From that
  4066. // point on, when the same function object is used as a constructor, the a new object with the final type will
  4067. // be created. Whatever is stored in the inline cache currently will cause cache misses after the constructor
  4068. // cache update. So, just clear it now so that the caches won't be flagged as polymorphic.
  4069. inlineCache->Clear();
  4070. }
  4071. }
  4072. #if ENABLE_PROFILE_INFO
  4073. template <class T, bool Root>
  4074. void InterpreterStackFrame::ProfiledSetProperty(unaligned T* playout, Var instance, PropertyOperationFlags flags)
  4075. {
  4076. Assert(!Root || flags & PropertyOperation_Root);
  4077. ProfilingHelpers::ProfiledStFld<Root>(
  4078. instance,
  4079. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  4080. GetInlineCache(playout->inlineCacheIndex),
  4081. playout->inlineCacheIndex,
  4082. GetReg(playout->Value),
  4083. flags,
  4084. GetJavascriptFunction(),
  4085. instance);
  4086. }
  4087. template <class T, bool Root>
  4088. void InterpreterStackFrame::ProfiledSetSuperProperty(unaligned T* playout, Var instance, Var thisInstance, PropertyOperationFlags flags)
  4089. {
  4090. Assert(!Root || flags & PropertyOperation_Root);
  4091. ProfilingHelpers::ProfiledStFld<Root>(
  4092. instance,
  4093. GetPropertyIdFromCacheId(playout->PropertyIdIndex),
  4094. GetInlineCache(playout->PropertyIdIndex),
  4095. playout->PropertyIdIndex,
  4096. GetReg(playout->Value),
  4097. m_functionBody->GetIsStrictMode() ?
  4098. (PropertyOperationFlags)(flags | PropertyOperation_StrictMode ) : flags,
  4099. GetJavascriptFunction(),
  4100. thisInstance);
  4101. }
  4102. #endif
  4103. template <class T>
  4104. void InterpreterStackFrame::OP_SetProperty(unaligned T* playout)
  4105. {
  4106. DoSetProperty(playout, GetReg(playout->Instance), PropertyOperation_None);
  4107. }
  4108. template <class T>
  4109. void InterpreterStackFrame::OP_SetLocalProperty(unaligned T* playout)
  4110. {
  4111. DoSetProperty(playout, this->localClosure, PropertyOperation_None);
  4112. }
  4113. template <class T>
  4114. void InterpreterStackFrame::OP_SetSuperProperty(unaligned T* playout)
  4115. {
  4116. DoSetSuperProperty(playout, GetReg(playout->Instance), PropertyOperation_None);
  4117. }
  4118. template <class T>
  4119. void InterpreterStackFrame::OP_ProfiledSetProperty(unaligned T* playout)
  4120. {
  4121. ProfiledSetProperty<T, false>(playout, GetReg(playout->Instance), PropertyOperation_None);
  4122. }
  4123. template <class T>
  4124. void InterpreterStackFrame::OP_ProfiledSetLocalProperty(unaligned T* playout)
  4125. {
  4126. ProfiledSetProperty<T, false>(playout, this->localClosure, PropertyOperation_None);
  4127. }
  4128. template <class T>
  4129. void InterpreterStackFrame::OP_ProfiledSetSuperProperty(unaligned T* playout)
  4130. {
  4131. ProfiledSetSuperProperty<T, false>(playout, GetReg(playout->Instance), GetReg(playout->Value2), PropertyOperation_None);
  4132. }
  4133. template <class T>
  4134. void InterpreterStackFrame::OP_SetRootProperty(unaligned T* playout)
  4135. {
  4136. DoSetProperty(playout, this->GetRootObject(), PropertyOperation_Root);
  4137. }
  4138. template <class T>
  4139. void InterpreterStackFrame::OP_ProfiledSetRootProperty(unaligned T* playout)
  4140. {
  4141. ProfiledSetProperty<T, true>(playout, this->GetRootObject(), PropertyOperation_Root);
  4142. }
  4143. template <class T>
  4144. void InterpreterStackFrame::OP_SetPropertyStrict(unaligned T* playout)
  4145. {
  4146. DoSetProperty(playout, GetReg(playout->Instance), PropertyOperation_StrictMode);
  4147. }
  4148. template <class T>
  4149. void InterpreterStackFrame::OP_ProfiledSetPropertyStrict(unaligned T* playout)
  4150. {
  4151. ProfiledSetProperty<T, false>(playout, GetReg(playout->Instance), PropertyOperation_StrictMode);
  4152. }
  4153. template <class T>
  4154. void InterpreterStackFrame::OP_SetRootPropertyStrict(unaligned T* playout)
  4155. {
  4156. DoSetProperty(playout, this->GetRootObject(), PropertyOperation_StrictModeRoot);
  4157. }
  4158. template <class T>
  4159. void InterpreterStackFrame::OP_ProfiledSetRootPropertyStrict(unaligned T* playout)
  4160. {
  4161. ProfiledSetProperty<T, true>(playout, this->GetRootObject(), PropertyOperation_StrictModeRoot);
  4162. }
  4163. #if ENABLE_PROFILE_INFO
  4164. template <bool doProfile>
  4165. Var InterpreterStackFrame::ProfiledDivide(Var aLeft, Var aRight, ScriptContext* scriptContext, ProfileId profileId)
  4166. {
  4167. Var result = JavascriptMath::Divide(aLeft, aRight,scriptContext);
  4168. if (doProfile)
  4169. {
  4170. Js::FunctionBody* body = this->m_functionBody;
  4171. body->GetDynamicProfileInfo()->RecordDivideResultType(body, profileId, result);
  4172. }
  4173. return result;
  4174. }
  4175. template <bool doProfile>
  4176. Var InterpreterStackFrame::ProfileModulus(Var aLeft, Var aRight, ScriptContext* scriptContext, ProfileId profileId)
  4177. {
  4178. // If both arguments are TaggedInt, then try to do integer division
  4179. // This case is not handled by the lowerer.
  4180. if (doProfile)
  4181. {
  4182. Js::FunctionBody* body = this->function->GetFunctionBody();
  4183. if(TaggedInt::IsPair(aLeft, aRight))
  4184. {
  4185. int nLeft = TaggedInt::ToInt32(aLeft);
  4186. int nRight = TaggedInt::ToInt32(aRight);
  4187. // nLeft is positive and nRight is +2^i
  4188. // Fast path for Power of 2 divisor
  4189. if (nLeft > 0 && ::Math::IsPow2(nRight))
  4190. {
  4191. body->GetDynamicProfileInfo()->RecordModulusOpType(body, profileId, /*isModByPowerOf2*/ true);
  4192. return TaggedInt::ToVarUnchecked(nLeft & (nRight - 1));
  4193. }
  4194. }
  4195. body->GetDynamicProfileInfo()->RecordModulusOpType(body, profileId, /*isModByPowerOf2*/ false);
  4196. }
  4197. return JavascriptMath::Modulus(aLeft, aRight,scriptContext);
  4198. }
  4199. template <bool doProfile>
  4200. Var InterpreterStackFrame::ProfiledSwitch(Var exp, ProfileId profileId)
  4201. {
  4202. if (doProfile)
  4203. {
  4204. Js::FunctionBody* body = this->m_functionBody;
  4205. body->GetDynamicProfileInfo()->RecordSwitchType(body, profileId, exp);
  4206. }
  4207. return exp;
  4208. }
  4209. #else
  4210. template <bool doProfile>
  4211. Var InterpreterStackFrame::ProfiledDivide(Var aLeft, Var aRight, ScriptContext* scriptContext, ProfileId profileId)
  4212. {
  4213. Assert(!doProfile);
  4214. return JavascriptMath::Divide(aLeft, aRight, scriptContext);
  4215. }
  4216. template <bool doProfile>
  4217. Var InterpreterStackFrame::ProfileModulus(Var aLeft, Var aRight, ScriptContext* scriptContext, ProfileId profileId)
  4218. {
  4219. Assert(!doProfile);
  4220. return JavascriptMath::Modulus(aLeft, aRight, scriptContext);
  4221. }
  4222. template <bool doProfile>
  4223. Var InterpreterStackFrame::ProfiledSwitch(Var exp, ProfileId profileId)
  4224. {
  4225. Assert(!doProfile);
  4226. return exp;
  4227. }
  4228. #endif
  4229. template <class T>
  4230. void InterpreterStackFrame::DoInitProperty(unaligned T* playout, Var instance)
  4231. {
  4232. // Same fast path as in the backend.
  4233. InlineCache *inlineCache = nullptr;
  4234. Assert(!TaggedNumber::Is(instance));
  4235. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4236. if (TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache))
  4237. {
  4238. return;
  4239. }
  4240. DoInitProperty_NoFastPath(playout, instance);
  4241. }
  4242. template <class T>
  4243. _NOINLINE void InterpreterStackFrame::DoInitProperty_NoFastPath(unaligned T* playout, Var instance)
  4244. {
  4245. JavascriptOperators::PatchInitValue<false>(
  4246. GetFunctionBody(),
  4247. GetInlineCache(playout->inlineCacheIndex),
  4248. playout->inlineCacheIndex,
  4249. RecyclableObject::FromVar(instance),
  4250. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  4251. GetReg(playout->Value));
  4252. }
  4253. template <class T>
  4254. void InterpreterStackFrame::OP_InitClassMember(const unaligned T * playout)
  4255. {
  4256. uint inlineCacheIndex = playout->inlineCacheIndex;
  4257. InlineCache * inlineCache = this->GetInlineCache(inlineCacheIndex);
  4258. Var instance = GetReg(playout->Instance);
  4259. PropertyOperationFlags flags = PropertyOperation_None;
  4260. Assert(!TaggedNumber::Is(instance));
  4261. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4262. if (!TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache, flags))
  4263. {
  4264. JavascriptOperators::OP_InitClassMember(instance, propertyId, GetReg(playout->Value));
  4265. }
  4266. }
  4267. template <class T>
  4268. void InterpreterStackFrame::OP_InitClassMemberGet(const unaligned T * playout)
  4269. {
  4270. JavascriptOperators::OP_InitClassMemberGet(
  4271. GetReg(playout->Instance),
  4272. m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
  4273. GetReg(playout->Value));
  4274. }
  4275. template <class T>
  4276. void InterpreterStackFrame::OP_InitClassMemberSet(const unaligned T * playout)
  4277. {
  4278. JavascriptOperators::OP_InitClassMemberSet(
  4279. GetReg(playout->Instance),
  4280. m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
  4281. GetReg(playout->Value));
  4282. }
  4283. template <class T>
  4284. void InterpreterStackFrame::OP_InitClassMemberSetComputedName(const unaligned T * playout)
  4285. {
  4286. JavascriptOperators::OP_InitClassMemberSetComputedName(
  4287. GetReg(playout->Instance),
  4288. GetReg(playout->Element),
  4289. GetReg(playout->Value),
  4290. m_functionBody->GetScriptContext());
  4291. }
  4292. template <class T>
  4293. void InterpreterStackFrame::OP_InitClassMemberGetComputedName(const unaligned T * playout)
  4294. {
  4295. JavascriptOperators::OP_InitClassMemberGetComputedName(
  4296. GetReg(playout->Instance),
  4297. GetReg(playout->Element),
  4298. GetReg(playout->Value),
  4299. m_functionBody->GetScriptContext());
  4300. }
  4301. template <class T>
  4302. void InterpreterStackFrame::OP_InitClassMemberComputedName(const unaligned T * playout)
  4303. {
  4304. JavascriptOperators::OP_InitClassMemberComputedName(
  4305. GetReg(playout->Instance),
  4306. GetReg(playout->Element),
  4307. GetReg(playout->Value),
  4308. m_functionBody->GetScriptContext());
  4309. }
  4310. template <class T>
  4311. void InterpreterStackFrame::DoInitLetFld(const unaligned T * playout, Var instance, PropertyOperationFlags flags)
  4312. {
  4313. uint inlineCacheIndex = playout->inlineCacheIndex;
  4314. InlineCache * inlineCache = this->GetInlineCache(inlineCacheIndex);
  4315. Assert(!TaggedNumber::Is(instance));
  4316. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4317. if (!TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache, flags))
  4318. {
  4319. JavascriptOperators::OP_InitLetProperty(instance, propertyId, GetReg(playout->Value));
  4320. }
  4321. }
  4322. template <class T>
  4323. void InterpreterStackFrame::DoInitConstFld(const unaligned T * playout, Var instance, PropertyOperationFlags flags)
  4324. {
  4325. uint inlineCacheIndex = playout->inlineCacheIndex;
  4326. InlineCache * inlineCache = this->GetInlineCache(inlineCacheIndex);
  4327. Assert(!TaggedNumber::Is(instance));
  4328. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4329. if (!TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache, flags))
  4330. {
  4331. JavascriptOperators::OP_InitConstProperty(instance, propertyId, GetReg(playout->Value));
  4332. }
  4333. }
  4334. template <class T>
  4335. void InterpreterStackFrame::OP_InitProperty(unaligned T* playout)
  4336. {
  4337. DoInitProperty(playout, GetReg(playout->Instance));
  4338. }
  4339. template <class T>
  4340. void InterpreterStackFrame::OP_InitLocalProperty(unaligned T* playout)
  4341. {
  4342. DoInitProperty(playout, this->localClosure);
  4343. }
  4344. template <class T>
  4345. void InterpreterStackFrame::OP_InitInnerFld(const unaligned T* playout)
  4346. {
  4347. DoInitProperty(playout, InnerScopeFromIndex(playout->scopeIndex));
  4348. }
  4349. template <class T>
  4350. void InterpreterStackFrame::OP_InitLetFld(const unaligned T * playout)
  4351. {
  4352. DoInitLetFld(playout, GetReg(playout->Instance));
  4353. }
  4354. template <class T>
  4355. void InterpreterStackFrame::OP_InitInnerLetFld(const unaligned T * playout)
  4356. {
  4357. DoInitLetFld(playout, InnerScopeFromIndex(playout->scopeIndex));
  4358. }
  4359. template <class T>
  4360. void InterpreterStackFrame::OP_InitLocalLetFld(const unaligned T * playout)
  4361. {
  4362. DoInitLetFld(playout, this->localClosure);
  4363. }
  4364. template <class T>
  4365. void InterpreterStackFrame::OP_InitConstFld(const unaligned T * playout)
  4366. {
  4367. DoInitConstFld(playout, GetReg(playout->Instance));
  4368. }
  4369. template <class T>
  4370. void InterpreterStackFrame::OP_InitRootProperty(unaligned T* playout)
  4371. {
  4372. Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
  4373. DoInitProperty(playout, this->GetRootObject());
  4374. }
  4375. template <class T>
  4376. void InterpreterStackFrame::OP_InitRootLetFld(const unaligned T * playout)
  4377. {
  4378. Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
  4379. DoInitLetFld(playout, this->GetRootObject(), PropertyOperation_Root);
  4380. }
  4381. template <class T>
  4382. void InterpreterStackFrame::OP_InitRootConstFld(const unaligned T * playout)
  4383. {
  4384. Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
  4385. DoInitConstFld(playout, this->GetRootObject(), PropertyOperation_Root);
  4386. }
  4387. template <class T>
  4388. void InterpreterStackFrame::OP_InitUndeclLetProperty(unaligned T* playout)
  4389. {
  4390. Var instance = InnerScopeFromIndex(playout->scopeIndex);
  4391. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4392. JavascriptOperators::OP_InitLetProperty(instance, propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  4393. }
  4394. template <class T>
  4395. void InterpreterStackFrame::OP_InitUndeclLocalLetProperty(unaligned T* playout)
  4396. {
  4397. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4398. JavascriptOperators::OP_InitLetProperty(this->localClosure, propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  4399. }
  4400. void InterpreterStackFrame::OP_InitUndeclRootLetProperty(uint propertyIdIndex)
  4401. {
  4402. Var instance = this->GetRootObject();
  4403. PropertyId propertyId = this->m_functionBody->GetReferencedPropertyId(propertyIdIndex);
  4404. JavascriptOperators::OP_InitUndeclRootLetProperty(instance, propertyId);
  4405. }
  4406. template <class T>
  4407. void InterpreterStackFrame::OP_InitUndeclConstProperty(unaligned T* playout)
  4408. {
  4409. Var instance = InnerScopeFromIndex(playout->scopeIndex);
  4410. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4411. JavascriptOperators::OP_InitConstProperty(instance, propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  4412. }
  4413. template <class T>
  4414. void InterpreterStackFrame::OP_InitUndeclLocalConstProperty(unaligned T* playout)
  4415. {
  4416. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4417. JavascriptOperators::OP_InitConstProperty(this->localClosure, propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  4418. }
  4419. void InterpreterStackFrame::OP_InitUndeclRootConstProperty(uint propertyIdIndex)
  4420. {
  4421. Var instance = this->GetRootObject();
  4422. PropertyId propertyId = this->m_functionBody->GetReferencedPropertyId(propertyIdIndex);
  4423. JavascriptOperators::OP_InitUndeclRootConstProperty(instance, propertyId);
  4424. }
  4425. template <class T>
  4426. void InterpreterStackFrame::OP_InitUndeclConsoleLetProperty(unaligned T* playout)
  4427. {
  4428. FrameDisplay* pScope = (FrameDisplay*)this->LdEnv();
  4429. AssertMsg(ConsoleScopeActivationObject::Is((DynamicObject*)pScope->GetItem(pScope->GetLength() - 1)), "How come we got this opcode without ConsoleScopeActivationObject?");
  4430. PropertyId propertyId = m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex);
  4431. JavascriptOperators::OP_InitLetProperty(pScope->GetItem(0), propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  4432. }
  4433. template <class T>
  4434. void InterpreterStackFrame::OP_InitUndeclConsoleConstProperty(unaligned T* playout)
  4435. {
  4436. FrameDisplay* pScope = (FrameDisplay*)this->LdEnv();
  4437. AssertMsg(ConsoleScopeActivationObject::Is((DynamicObject*)pScope->GetItem(pScope->GetLength() - 1)), "How come we got this opcode without ConsoleScopeActivationObject?");
  4438. PropertyId propertyId = m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex);
  4439. JavascriptOperators::OP_InitConstProperty(pScope->GetItem(0), propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  4440. }
  4441. #if ENABLE_PROFILE_INFO
  4442. template <class T>
  4443. void InterpreterStackFrame::ProfiledInitProperty(unaligned T* playout, Var instance)
  4444. {
  4445. ProfilingHelpers::ProfiledInitFld(
  4446. RecyclableObject::FromVar(instance),
  4447. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  4448. GetInlineCache(playout->inlineCacheIndex),
  4449. playout->inlineCacheIndex,
  4450. GetReg(playout->Value),
  4451. GetFunctionBody());
  4452. }
  4453. template <class T>
  4454. void InterpreterStackFrame::OP_ProfiledInitProperty(unaligned T* playout)
  4455. {
  4456. ProfiledInitProperty(playout, GetReg(playout->Instance));
  4457. }
  4458. template <class T>
  4459. void InterpreterStackFrame::OP_ProfiledInitLocalProperty(unaligned T* playout)
  4460. {
  4461. ProfiledInitProperty(playout, this->localClosure);
  4462. }
  4463. template <class T>
  4464. void InterpreterStackFrame::OP_ProfiledInitRootProperty(unaligned T* playout)
  4465. {
  4466. ProfiledInitProperty(playout, this->GetRootObject());
  4467. }
  4468. template <class T>
  4469. void InterpreterStackFrame::OP_ProfiledGetElementI(const unaligned OpLayoutDynamicProfile<T>* playout)
  4470. {
  4471. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  4472. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  4473. threadContext->ClearImplicitCallFlags();
  4474. SetReg(
  4475. playout->Value,
  4476. ProfilingHelpers::ProfiledLdElem(
  4477. GetReg(playout->Instance),
  4478. GetReg(playout->Element),
  4479. m_functionBody,
  4480. playout->profileId));
  4481. threadContext->CheckAndResetImplicitCallAccessorFlag();
  4482. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  4483. }
  4484. #endif
  4485. template <typename T>
  4486. void InterpreterStackFrame::OP_GetElementI(const unaligned T* playout)
  4487. {
  4488. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  4489. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  4490. threadContext->ClearImplicitCallFlags();
  4491. // Same fast path as in the backend.
  4492. Var instance = GetReg(playout->Instance);
  4493. // Only enable fast path if the javascript array is not cross site
  4494. Var element;
  4495. #if ENABLE_PROFILE_INFO
  4496. if (!TaggedNumber::Is(instance) && VirtualTableInfo<JavascriptArray>::HasVirtualTable(instance))
  4497. {
  4498. element =
  4499. ProfilingHelpers::ProfiledLdElem_FastPath(
  4500. JavascriptArray::FromVar(instance),
  4501. GetReg(playout->Element),
  4502. GetScriptContext());
  4503. }
  4504. else
  4505. #endif
  4506. {
  4507. element = JavascriptOperators::OP_GetElementI(instance, GetReg(playout->Element), GetScriptContext());
  4508. }
  4509. threadContext->CheckAndResetImplicitCallAccessorFlag();
  4510. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  4511. SetReg(playout->Value, element);
  4512. }
  4513. template <typename T>
  4514. void InterpreterStackFrame::OP_SetElementI(const unaligned T* playout, PropertyOperationFlags flags)
  4515. {
  4516. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  4517. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  4518. threadContext->ClearImplicitCallFlags();
  4519. // Same fast path as in the backend.
  4520. Var instance = GetReg(playout->Instance);
  4521. const Var varIndex = GetReg(playout->Element);
  4522. const Var value = GetReg(playout->Value);
  4523. #if ENABLE_PROFILE_INFO
  4524. // Only enable fast path if the javascript array is not cross site
  4525. if (!TaggedNumber::Is(instance) &&
  4526. VirtualTableInfo<JavascriptArray>::HasVirtualTable(instance) &&
  4527. !JavascriptOperators::SetElementMayHaveImplicitCalls(GetScriptContext()))
  4528. {
  4529. ProfilingHelpers::ProfiledStElem_FastPath(
  4530. JavascriptArray::FromVar(instance),
  4531. varIndex,
  4532. value,
  4533. GetScriptContext(),
  4534. flags);
  4535. }
  4536. else
  4537. #endif
  4538. {
  4539. JavascriptOperators::OP_SetElementI(instance, varIndex, value, GetScriptContext(), flags);
  4540. }
  4541. threadContext->CheckAndResetImplicitCallAccessorFlag();
  4542. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  4543. }
  4544. #if ENABLE_PROFILE_INFO
  4545. template <typename T>
  4546. void InterpreterStackFrame::OP_ProfiledSetElementI(
  4547. const unaligned OpLayoutDynamicProfile<T>* playout,
  4548. PropertyOperationFlags flags)
  4549. {
  4550. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  4551. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  4552. threadContext->ClearImplicitCallFlags();
  4553. ProfilingHelpers::ProfiledStElem(
  4554. GetReg(playout->Instance),
  4555. GetReg(playout->Element),
  4556. GetReg(playout->Value),
  4557. m_functionBody,
  4558. playout->profileId,
  4559. flags);
  4560. threadContext->CheckAndResetImplicitCallAccessorFlag();
  4561. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  4562. }
  4563. #endif
  4564. template <typename T>
  4565. void InterpreterStackFrame::OP_SetElementIStrict(const unaligned T* playout)
  4566. {
  4567. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  4568. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  4569. threadContext->ClearImplicitCallFlags();
  4570. OP_SetElementI(playout, PropertyOperation_StrictMode);
  4571. threadContext->CheckAndResetImplicitCallAccessorFlag();
  4572. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  4573. }
  4574. #if ENABLE_PROFILE_INFO
  4575. template <typename T>
  4576. void InterpreterStackFrame::OP_ProfiledSetElementIStrict(const unaligned OpLayoutDynamicProfile<T>* playout)
  4577. {
  4578. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  4579. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  4580. threadContext->ClearImplicitCallFlags();
  4581. OP_ProfiledSetElementI(playout, PropertyOperation_StrictMode);
  4582. threadContext->CheckAndResetImplicitCallAccessorFlag();
  4583. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  4584. }
  4585. #endif
  4586. template <class T>
  4587. void InterpreterStackFrame::OP_LdArrayHeadSegment(const unaligned T* playout)
  4588. {
  4589. JavascriptArray* array = JavascriptArray::FromAnyArray(GetReg(playout->R1));
  4590. // The array is create by the built-in on the same script context
  4591. Assert(array->GetScriptContext() == GetScriptContext());
  4592. SetNonVarReg(playout->R0, array->GetHead());
  4593. }
  4594. template <class T>
  4595. void InterpreterStackFrame::OP_SetArraySegmentItem_CI4(const unaligned T* playout)
  4596. {
  4597. SparseArraySegment<Var> * segment = (SparseArraySegment<Var> *)GetNonVarReg(playout->Instance);
  4598. uint32 index = playout->Element;
  4599. Var value = GetReg(playout->Value);
  4600. Assert(segment->left == 0);
  4601. Assert(index < segment->length);
  4602. segment->elements[index] = value;
  4603. }
  4604. template <class T>
  4605. void InterpreterStackFrame::OP_NewScArray(const unaligned T * playout)
  4606. {
  4607. JavascriptArray *arr;
  4608. arr = scriptContext->GetLibrary()->CreateArrayLiteral(playout->C1);
  4609. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  4610. arr->CheckForceES5Array();
  4611. #endif
  4612. SetReg(playout->R0, arr);
  4613. }
  4614. #if ENABLE_PROFILE_INFO
  4615. template <bool Profiled, class T>
  4616. void InterpreterStackFrame::ProfiledNewScArray(const unaligned OpLayoutDynamicProfile<T> * playout)
  4617. {
  4618. if(!Profiled && !isAutoProfiling)
  4619. {
  4620. OP_NewScArray(playout);
  4621. return;
  4622. }
  4623. SetReg(
  4624. playout->R0,
  4625. ProfilingHelpers::ProfiledNewScArray(
  4626. playout->C1,
  4627. m_functionBody,
  4628. playout->profileId));
  4629. }
  4630. #else
  4631. template <bool Profiled, class T>
  4632. void InterpreterStackFrame::ProfiledNewScArray(const unaligned OpLayoutDynamicProfile<T> * playout)
  4633. {
  4634. Assert(!Profiled);
  4635. OP_NewScArray(playout);
  4636. }
  4637. #endif
  4638. void InterpreterStackFrame::OP_NewScIntArray(const unaligned OpLayoutAuxiliary * playout)
  4639. {
  4640. #if ENABLE_PROFILE_INFO
  4641. if(isAutoProfiling)
  4642. {
  4643. OP_ProfiledNewScIntArray(static_cast<const unaligned OpLayoutDynamicProfile<OpLayoutAuxiliary> *>(playout));
  4644. return;
  4645. }
  4646. #endif
  4647. const Js::AuxArray<int32> *ints = Js::ByteCodeReader::ReadAuxArray<int32>(playout->Offset, this->GetFunctionBody());
  4648. JavascriptNativeIntArray *arr = scriptContext->GetLibrary()->CreateNativeIntArrayLiteral(ints->count);
  4649. SparseArraySegment<int32> * segment = (SparseArraySegment<int32>*)arr->GetHead();
  4650. JavascriptOperators::AddIntsToArraySegment(segment, ints);
  4651. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  4652. arr->CheckForceES5Array();
  4653. #endif
  4654. SetReg(playout->R0, arr);
  4655. }
  4656. #if ENABLE_PROFILE_INFO
  4657. void InterpreterStackFrame::OP_ProfiledNewScIntArray(const unaligned OpLayoutDynamicProfile<OpLayoutAuxiliary> * playout)
  4658. {
  4659. const Js::AuxArray<int32> *ints = Js::ByteCodeReader::ReadAuxArray<int32>(playout->Offset, this->GetFunctionBody());
  4660. Js::ProfileId profileId = playout->profileId;
  4661. FunctionBody *functionBody = this->m_functionBody;
  4662. ArrayCallSiteInfo *arrayInfo = functionBody->GetDynamicProfileInfo()->GetArrayCallSiteInfo(functionBody, profileId);
  4663. Assert(arrayInfo);
  4664. JavascriptArray *arr;
  4665. if (arrayInfo && arrayInfo->IsNativeIntArray())
  4666. {
  4667. #if ENABLE_COPYONACCESS_ARRAY
  4668. JavascriptLibrary *lib = scriptContext->GetLibrary();
  4669. if (JavascriptLibrary::IsCopyOnAccessArrayCallSite(lib, arrayInfo, ints->count))
  4670. {
  4671. Assert(lib->cacheForCopyOnAccessArraySegments);
  4672. arr = scriptContext->GetLibrary()->CreateCopyOnAccessNativeIntArrayLiteral(arrayInfo, functionBody, ints);
  4673. }
  4674. else
  4675. #endif
  4676. {
  4677. arr = scriptContext->GetLibrary()->CreateNativeIntArrayLiteral(ints->count);
  4678. SparseArraySegment<int32> *segment = (SparseArraySegment<int32>*)arr->GetHead();
  4679. JavascriptOperators::AddIntsToArraySegment(segment, ints);
  4680. }
  4681. JavascriptNativeIntArray *intArray = reinterpret_cast<JavascriptNativeIntArray*>(arr);
  4682. Recycler *recycler = scriptContext->GetRecycler();
  4683. intArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
  4684. }
  4685. else if (arrayInfo && arrayInfo->IsNativeFloatArray())
  4686. {
  4687. arr = scriptContext->GetLibrary()->CreateNativeFloatArrayLiteral(ints->count);
  4688. SparseArraySegment<double> * segment = (SparseArraySegment<double>*)arr->GetHead();
  4689. for (uint i = 0; i < ints->count; i++)
  4690. {
  4691. segment->elements[i] = (double)ints->elements[i];
  4692. }
  4693. JavascriptNativeFloatArray *floatArray = reinterpret_cast<JavascriptNativeFloatArray*>(arr);
  4694. Recycler *recycler = scriptContext->GetRecycler();
  4695. floatArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
  4696. }
  4697. else
  4698. {
  4699. arr = scriptContext->GetLibrary()->CreateArrayLiteral(ints->count);
  4700. SparseArraySegment<Var> * segment = (SparseArraySegment<Var>*)arr->GetHead();
  4701. for (uint i = 0; i < ints->count; i++)
  4702. {
  4703. segment->elements[i] = JavascriptNumber::ToVar(ints->elements[i], scriptContext);
  4704. }
  4705. }
  4706. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  4707. arr->CheckForceES5Array();
  4708. #endif
  4709. SetReg(playout->R0, arr);
  4710. }
  4711. #endif
  4712. void InterpreterStackFrame::OP_NewScFltArray(const unaligned OpLayoutAuxiliary * playout )
  4713. {
  4714. #if ENABLE_PROFILE_INFO
  4715. if(isAutoProfiling)
  4716. {
  4717. OP_ProfiledNewScFltArray(static_cast<const unaligned OpLayoutDynamicProfile<OpLayoutAuxiliary> *>(playout));
  4718. return;
  4719. }
  4720. #endif
  4721. const Js::AuxArray<double> *doubles = Js::ByteCodeReader::ReadAuxArray<double>(playout->Offset, this->GetFunctionBody());
  4722. JavascriptNativeFloatArray *arr = scriptContext->GetLibrary()->CreateNativeFloatArrayLiteral(doubles->count);
  4723. SparseArraySegment<double> * segment = (SparseArraySegment<double>*)arr->GetHead();
  4724. JavascriptOperators::AddFloatsToArraySegment(segment, doubles);
  4725. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  4726. arr->CheckForceES5Array();
  4727. #endif
  4728. SetReg(playout->R0, arr);
  4729. }
  4730. #if ENABLE_PROFILE_INFO
  4731. void InterpreterStackFrame::OP_ProfiledNewScFltArray(const unaligned OpLayoutDynamicProfile<OpLayoutAuxiliary> * playout)
  4732. {
  4733. const Js::AuxArray<double> *doubles = Js::ByteCodeReader::ReadAuxArray<double>(playout->Offset, this->GetFunctionBody());
  4734. Js::ProfileId profileId = playout->profileId;
  4735. FunctionBody *functionBody = this->m_functionBody;
  4736. ArrayCallSiteInfo *arrayInfo = functionBody->GetDynamicProfileInfo()->GetArrayCallSiteInfo(functionBody, profileId);
  4737. Assert(arrayInfo);
  4738. JavascriptArray *arr;
  4739. if (arrayInfo && arrayInfo->IsNativeFloatArray())
  4740. {
  4741. arrayInfo->SetIsNotNativeIntArray();
  4742. arr = scriptContext->GetLibrary()->CreateNativeFloatArrayLiteral(doubles->count);
  4743. SparseArraySegment<double> * segment = (SparseArraySegment<double>*)arr->GetHead();
  4744. JavascriptOperators::AddFloatsToArraySegment(segment, doubles);
  4745. JavascriptNativeFloatArray *floatArray = reinterpret_cast<JavascriptNativeFloatArray*>(arr);
  4746. Recycler *recycler = scriptContext->GetRecycler();
  4747. floatArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
  4748. }
  4749. else
  4750. {
  4751. arr = scriptContext->GetLibrary()->CreateArrayLiteral(doubles->count);
  4752. SparseArraySegment<Var> * segment = (SparseArraySegment<Var>*)arr->GetHead();
  4753. for (uint i = 0; i < doubles->count; i++)
  4754. {
  4755. segment->elements[i] = JavascriptNumber::ToVarNoCheck(doubles->elements[i], scriptContext);
  4756. }
  4757. }
  4758. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  4759. arr->CheckForceES5Array();
  4760. #endif
  4761. SetReg(playout->R0, arr);
  4762. }
  4763. #endif
  4764. void InterpreterStackFrame::OP_SetArraySegmentVars(const unaligned OpLayoutAuxiliary * playout)
  4765. {
  4766. const Js::VarArray *vars = Js::ByteCodeReader::ReadAuxArray<Var>(playout->Offset, this->GetFunctionBody());
  4767. SparseArraySegment<Var> * segment =(SparseArraySegment<Var> *)GetNonVarReg(playout->R0);
  4768. JavascriptOperators::AddVarsToArraySegment(segment, vars);
  4769. }
  4770. template <class T>
  4771. void InterpreterStackFrame::OP_SetArrayItemC_CI4(const unaligned T* playout)
  4772. {
  4773. JavascriptArray* array = JavascriptArray::FromAnyArray(GetReg(playout->Instance));
  4774. uint32 index = playout->Element;
  4775. Var value = GetReg(playout->Value);
  4776. #if ENABLE_COPYONACCESS_ARRAY
  4777. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(value);
  4778. #endif
  4779. // The array is create by the built-in on the same script context
  4780. Assert(array->GetScriptContext() == GetScriptContext());
  4781. TypeId typeId = array->GetTypeId();
  4782. if (typeId == TypeIds_NativeIntArray)
  4783. {
  4784. JavascriptArray::OP_SetNativeIntElementC(reinterpret_cast<JavascriptNativeIntArray*>(array), index, value, array->GetScriptContext());
  4785. }
  4786. else if (typeId == TypeIds_NativeFloatArray)
  4787. {
  4788. JavascriptArray::OP_SetNativeFloatElementC(reinterpret_cast<JavascriptNativeFloatArray*>(array), index, value, array->GetScriptContext());
  4789. }
  4790. else
  4791. {
  4792. array->SetArrayLiteralItem(index, value);
  4793. }
  4794. }
  4795. template <class T>
  4796. void InterpreterStackFrame::OP_SetArrayItemI_CI4(const unaligned T* playout)
  4797. {
  4798. // Note that this code assumes that we only get here when we see an array literal,
  4799. // so we know that the instance is truly an array, and the index is a uint32.
  4800. // If/when we use this for cases like "a[0] = x", we'll at least have to check
  4801. // whether "a" is really an array.
  4802. JavascriptArray* array = JavascriptArray::FromAnyArray(GetReg(playout->Instance));
  4803. // The array is create by the built-in on the same script context
  4804. Assert(array->GetScriptContext() == GetScriptContext());
  4805. uint32 index = playout->Element;
  4806. Var value = GetReg(playout->Value);
  4807. Assert(VirtualTableInfo<JavascriptArray>::HasVirtualTable(array));
  4808. SparseArraySegment<Var>* lastUsedSeg = (SparseArraySegment<Var>*)array->GetLastUsedSegment();
  4809. if (index >= lastUsedSeg->left)
  4810. {
  4811. uint32 index2 = index - lastUsedSeg->left;
  4812. if (index2 < lastUsedSeg->size)
  4813. {
  4814. // Successful fastpath
  4815. array->DirectSetItemInLastUsedSegmentAt(index2, value);
  4816. return;
  4817. }
  4818. }
  4819. ScriptContext* scriptContext = array->GetScriptContext();
  4820. JavascriptOperators::SetItem(array, array, index, value, scriptContext);
  4821. }
  4822. #if ENABLE_PROFILE_INFO
  4823. Var InterpreterStackFrame::OP_ProfiledLdThis(Var thisVar, int moduleID, ScriptContext *scriptContext)
  4824. {
  4825. FunctionBody * functionBody = this->m_functionBody;
  4826. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  4827. TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
  4828. if (JavascriptOperators::IsThisSelf(typeId))
  4829. {
  4830. Assert(typeId != TypeIds_GlobalObject || ((Js::GlobalObject*)thisVar)->ToThis() == thisVar);
  4831. Assert(typeId != TypeIds_ModuleRoot || JavascriptOperators::GetThisFromModuleRoot(thisVar) == thisVar);
  4832. // Record the fact that we saw a trivial LdThis.
  4833. dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Simple);
  4834. return thisVar;
  4835. }
  4836. thisVar = JavascriptOperators::OP_GetThis(thisVar, moduleID, scriptContext);
  4837. // Record the fact that we saw a LdThis that had to map its source to something else, or at least
  4838. // forced us to call a helper, e.g., a FastDOM object with an unrecognized type ID.
  4839. dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Mapped);
  4840. return thisVar;
  4841. }
  4842. Var InterpreterStackFrame::OP_ProfiledStrictLdThis(Var thisVar, ScriptContext* scriptContext)
  4843. {
  4844. FunctionBody * functionBody = this->m_functionBody;
  4845. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  4846. TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
  4847. if (typeId == TypeIds_ActivationObject)
  4848. {
  4849. thisVar = scriptContext->GetLibrary()->GetUndefined();
  4850. dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Mapped);
  4851. return thisVar;
  4852. }
  4853. dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Simple);
  4854. return thisVar;
  4855. }
  4856. #endif
  4857. void InterpreterStackFrame::OP_InitCachedFuncs(const unaligned OpLayoutAuxNoReg * playout)
  4858. {
  4859. const FuncInfoArray *info = Js::ByteCodeReader::ReadAuxArray<FuncInfoEntry>(playout->Offset, this->GetFunctionBody());
  4860. JavascriptOperators::OP_InitCachedFuncs(this->localClosure, GetLocalFrameDisplay(), info, GetScriptContext());
  4861. }
  4862. Var InterpreterStackFrame::OP_GetCachedFunc(Var instance, int32 index)
  4863. {
  4864. ActivationObjectEx *obj = (ActivationObjectEx*)ActivationObjectEx::FromVar(instance);
  4865. FuncCacheEntry *entry = obj->GetFuncCacheEntry((uint)index);
  4866. return entry->func;
  4867. }
  4868. void InterpreterStackFrame::OP_CommitScope()
  4869. {
  4870. const Js::PropertyIdArray *propIds = this->m_functionBody->GetFormalsPropIdArray();
  4871. this->OP_CommitScopeHelper(propIds);
  4872. }
  4873. void InterpreterStackFrame::OP_CommitScopeHelper(const PropertyIdArray *propIds)
  4874. {
  4875. ActivationObjectEx *obj = (ActivationObjectEx*)ActivationObjectEx::FromVar(this->localClosure);
  4876. ScriptFunction *func = obj->GetParentFunc();
  4877. Assert(obj->GetParentFunc() == func);
  4878. if (func->GetCachedScope() == obj)
  4879. {
  4880. PropertyId firstVarSlot = ActivationObjectEx::GetFirstVarSlot(propIds);
  4881. Var undef = scriptContext->GetLibrary()->GetUndefined();
  4882. for (uint i = firstVarSlot; i < propIds->count; i++)
  4883. {
  4884. obj->SetSlot(SetSlotArguments(propIds->elements[i], i, undef));
  4885. }
  4886. obj->SetCommit(true);
  4887. }
  4888. }
  4889. Var InterpreterStackFrame::OP_NewScObjectSimple()
  4890. {
  4891. Var object = scriptContext->GetLibrary()->CreateObject(true);
  4892. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(object));
  4893. #if ENABLE_DEBUG_CONFIG_OPTIONS
  4894. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  4895. {
  4896. object = JavascriptProxy::AutoProxyWrapper(object);
  4897. }
  4898. #endif
  4899. return object;
  4900. }
  4901. void InterpreterStackFrame::OP_NewScObjectLiteral(const unaligned OpLayoutAuxiliary * playout )
  4902. {
  4903. const Js::PropertyIdArray *propIds = Js::ByteCodeReader::ReadPropertyIdArray(playout->Offset, this->GetFunctionBody());
  4904. Var newObj = JavascriptOperators::NewScObjectLiteral(GetScriptContext(), propIds,
  4905. this->GetFunctionBody()->GetObjectLiteralTypeRef(playout->C1));
  4906. SetReg(playout->R0, newObj);
  4907. }
  4908. void InterpreterStackFrame::OP_NewScObjectLiteral_LS(const unaligned OpLayoutAuxiliary * playout, RegSlot& target)
  4909. {
  4910. const Js::PropertyIdArray *propIds = Js::ByteCodeReader::ReadPropertyIdArray(playout->Offset, this->GetFunctionBody());
  4911. target = playout->R0;
  4912. Var newObj = JavascriptOperators::NewScObjectLiteral(GetScriptContext(), propIds,
  4913. this->GetFunctionBody()->GetObjectLiteralTypeRef(playout->C1));
  4914. SetReg(playout->R0, newObj);
  4915. target = Js::Constants::NoRegister;
  4916. }
  4917. void InterpreterStackFrame::OP_LdPropIds(const unaligned OpLayoutAuxiliary * playout)
  4918. {
  4919. const Js::PropertyIdArray *propIds = Js::ByteCodeReader::ReadPropertyIdArray(playout->Offset, this->GetFunctionBody());
  4920. SetNonVarReg(playout->R0, (Var)propIds);
  4921. }
  4922. bool InterpreterStackFrame::IsCurrentLoopNativeAddr(void * codeAddr) const
  4923. {
  4924. if (this->GetCurrentLoopNum() == LoopHeader::NoLoop)
  4925. {
  4926. return false;
  4927. }
  4928. // TODO: Do more verification?
  4929. return true;
  4930. }
  4931. #if ENABLE_PROFILE_INFO
  4932. void InterpreterStackFrame::OP_RecordImplicitCall(uint loopNumber)
  4933. {
  4934. Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()));
  4935. Assert(loopNumber < this->m_functionBody->GetLoopCount());
  4936. FunctionBody* functionBody = this->m_functionBody;
  4937. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  4938. ThreadContext * threadContext = scriptContext->GetThreadContext();
  4939. dynamicProfileInfo->RecordLoopImplicitCallFlags(functionBody, loopNumber, threadContext->GetImplicitCallFlags());
  4940. }
  4941. template <LayoutSize layoutSize, bool profiled>
  4942. const byte * InterpreterStackFrame::OP_ProfiledLoopStart(const byte * ip)
  4943. {
  4944. const uint32 C1 = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
  4945. if(!profiled && !isAutoProfiling)
  4946. {
  4947. return ip;
  4948. }
  4949. ThreadContext *const threadContext = GetScriptContext()->GetThreadContext();
  4950. threadContext->IncrementLoopDepth();
  4951. // Save the implicit call flags. The interpreter may switch to profiling mode during LoopBodyStart, so always do this.
  4952. Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()));
  4953. this->savedLoopImplicitCallFlags[C1] = threadContext->GetImplicitCallFlags();
  4954. threadContext->SetImplicitCallFlags(ImplicitCall_None);
  4955. this->currentLoopCounter = 0;
  4956. if(!profiled)
  4957. {
  4958. return ip;
  4959. }
  4960. LayoutSize localLayoutSize;
  4961. OpCode peekOp = m_reader.PeekOp(ip, localLayoutSize);
  4962. Assert(peekOp != OpCode::LoopBodyStart);
  4963. if (peekOp == OpCode::ProfiledLoopBodyStart)
  4964. {
  4965. Assert(localLayoutSize == layoutSize);
  4966. ip += Js::OpCodeUtil::EncodedSize(peekOp, layoutSize);
  4967. // We are doing JIT loop body. Process the first ProfiledLoopBodyStart to avoid recording
  4968. // the implicit call before the first iteration
  4969. uint32 C2 = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
  4970. Assert(C1 == C2);
  4971. (this->*opProfiledLoopBodyStart)(C1, layoutSize, true /* isFirstIteration */);
  4972. return m_reader.GetIP();
  4973. }
  4974. return ip;
  4975. }
  4976. template <LayoutSize layoutSize, bool profiled>
  4977. const byte * InterpreterStackFrame::OP_ProfiledLoopEnd(const byte * ip)
  4978. {
  4979. uint32 loopNumber = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
  4980. if(!profiled && !isAutoProfiling)
  4981. {
  4982. return ip;
  4983. }
  4984. this->CheckIfLoopIsHot(this->currentLoopCounter);
  4985. Js::FunctionBody *fn = this->function->GetFunctionBody();
  4986. if (fn->HasDynamicProfileInfo())
  4987. {
  4988. fn->GetAnyDynamicProfileInfo()->SetLoopInterpreted(loopNumber);
  4989. // If the counter is 0, there is a high chance that some config disabled tracking that information. (ie: -off:jitloopbody)
  4990. // Assume it is valid for memop in this case.
  4991. if (this->currentLoopCounter >= (uint)CONFIG_FLAG(MinMemOpCount) ||
  4992. (this->currentLoopCounter == 0 && !this->m_functionBody->DoJITLoopBody())
  4993. )
  4994. {
  4995. // This flag becomes relevant only if the loop has been interpreted
  4996. fn->GetAnyDynamicProfileInfo()->SetMemOpMinReached(loopNumber);
  4997. }
  4998. }
  4999. this->currentLoopCounter = 0;
  5000. if (profiled)
  5001. {
  5002. Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()));
  5003. OP_RecordImplicitCall(loopNumber);
  5004. if(switchProfileModeOnLoopEndNumber == loopNumber)
  5005. {
  5006. // Stop profiling since the jitted loop body would be exiting the loop
  5007. Assert(!switchProfileMode);
  5008. switchProfileMode = true;
  5009. switchProfileModeOnLoopEndNumber = 0u - 1;
  5010. }
  5011. }
  5012. // Restore the implicit call flags state and add with flags in the loop as well
  5013. ThreadContext *const threadContext = GetScriptContext()->GetThreadContext();
  5014. threadContext->AddImplicitCallFlags(this->savedLoopImplicitCallFlags[loopNumber]);
  5015. threadContext->DecrementLoopDepth();
  5016. return ip;
  5017. }
  5018. template <LayoutSize layoutSize, bool profiled>
  5019. const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
  5020. {
  5021. uint32 C1 = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
  5022. if(profiled || isAutoProfiling)
  5023. {
  5024. this->currentLoopCounter++;
  5025. }
  5026. if (profiled)
  5027. {
  5028. OP_RecordImplicitCall(C1);
  5029. }
  5030. (this->*(profiled ? opProfiledLoopBodyStart : opLoopBodyStart))(C1, layoutSize, false /* isFirstIteration */);
  5031. return m_reader.GetIP();
  5032. }
  5033. template<bool InterruptProbe, bool JITLoopBody>
  5034. void InterpreterStackFrame::ProfiledLoopBodyStart(uint32 loopNumber, LayoutSize layoutSize, bool isFirstIteration)
  5035. {
  5036. Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()));
  5037. if (InterruptProbe)
  5038. {
  5039. this->DoInterruptProbe();
  5040. }
  5041. #if ENABLE_TTD
  5042. if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
  5043. {
  5044. this->scriptContext->GetThreadContext()->TTDLog->UpdateLoopCountInfo();
  5045. }
  5046. #endif
  5047. if (!JITLoopBody || this->IsInCatchOrFinallyBlock())
  5048. {
  5049. // For functions having try-catch-finally, jit loop bodies for loops that are contained only in a try block,
  5050. // not even indirect containment in a Catch or Finally.
  5051. return;
  5052. }
  5053. LoopHeader const * loopHeader = DoLoopBodyStart(loopNumber, layoutSize, false, isFirstIteration);
  5054. Assert(loopHeader == nullptr || this->m_functionBody->GetLoopNumber(loopHeader) == loopNumber);
  5055. if (loopHeader != nullptr)
  5056. {
  5057. // We executed jitted loop body, no implicit call information available for this loop
  5058. uint currentOffset = m_reader.GetCurrentOffset();
  5059. if (!loopHeader->Contains(currentOffset) || (m_reader.PeekOp() == OpCode::ProfiledLoopEnd))
  5060. {
  5061. // Restore the outer loop's implicit call flags
  5062. scriptContext->GetThreadContext()->SetImplicitCallFlags(this->savedLoopImplicitCallFlags[loopNumber]);
  5063. }
  5064. else
  5065. {
  5066. // We bailout from the loop, just continue collect implicit call flags for this loop
  5067. }
  5068. }
  5069. }
  5070. #else
  5071. template <LayoutSize layoutSize, bool profiled>
  5072. const byte * InterpreterStackFrame::OP_ProfiledLoopStart(const byte * ip)
  5073. {
  5074. Assert(!profiled);
  5075. return ip;
  5076. }
  5077. template <LayoutSize layoutSize, bool profiled>
  5078. const byte * InterpreterStackFrame::OP_ProfiledLoopEnd(const byte * ip)
  5079. {
  5080. Assert(!profiled);
  5081. return ip;
  5082. }
  5083. template <LayoutSize layoutSize, bool profiled>
  5084. const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
  5085. {
  5086. uint32 C1 = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
  5087. Assert(!profiled);
  5088. (this->*opLoopBodyStart)(C1, layoutSize, false /* isFirstIteration */);
  5089. return m_reader.GetIP();
  5090. }
  5091. #endif
  5092. template<bool InterruptProbe, bool JITLoopBody>
  5093. void InterpreterStackFrame::LoopBodyStart(uint32 loopNumber, LayoutSize layoutSize, bool isFirstIteration)
  5094. {
  5095. if (InterruptProbe)
  5096. {
  5097. this->DoInterruptProbe();
  5098. }
  5099. #if ENABLE_TTD
  5100. if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
  5101. {
  5102. this->scriptContext->GetThreadContext()->TTDLog->UpdateLoopCountInfo();
  5103. }
  5104. #endif
  5105. if (!JITLoopBody || this->IsInCatchOrFinallyBlock())
  5106. {
  5107. // For functions having try-catch-finally, jit loop bodies for loops that are contained only in a try block,
  5108. // not even indirect containment in a Catch or Finally.
  5109. return;
  5110. }
  5111. DoLoopBodyStart(loopNumber, layoutSize, true, isFirstIteration);
  5112. }
  5113. LoopHeader const * InterpreterStackFrame::DoLoopBodyStart(uint32 loopNumber, LayoutSize layoutSize, const bool doProfileLoopCheck, const bool isFirstIteration)
  5114. {
  5115. #if ENABLE_PROFILE_INFO
  5116. class AutoRestoreLoopNumbers
  5117. {
  5118. private:
  5119. InterpreterStackFrame *const interpreterStackFrame;
  5120. uint32 loopNumber;
  5121. bool doProfileLoopCheck;
  5122. public:
  5123. AutoRestoreLoopNumbers(InterpreterStackFrame *const interpreterStackFrame, uint32 loopNumber, bool doProfileLoopCheck)
  5124. : interpreterStackFrame(interpreterStackFrame), loopNumber(loopNumber), doProfileLoopCheck(doProfileLoopCheck)
  5125. {
  5126. Assert(interpreterStackFrame->currentLoopNum == LoopHeader::NoLoop);
  5127. interpreterStackFrame->currentLoopNum = loopNumber;
  5128. interpreterStackFrame->m_functionBody->SetRecentlyBailedOutOfJittedLoopBody(false);
  5129. }
  5130. ~AutoRestoreLoopNumbers()
  5131. {
  5132. interpreterStackFrame->currentLoopNum = LoopHeader::NoLoop;
  5133. interpreterStackFrame->currentLoopCounter = 0;
  5134. Js::FunctionBody* fn = interpreterStackFrame->m_functionBody;
  5135. if (fn->RecentlyBailedOutOfJittedLoopBody())
  5136. {
  5137. if (doProfileLoopCheck && interpreterStackFrame->isAutoProfiling)
  5138. {
  5139. // Start profiling the loop after a bailout. Some bailouts require subsequent profile data collection such
  5140. // that the rejitted loop body would not bail out again for the same reason.
  5141. Assert(!interpreterStackFrame->switchProfileMode);
  5142. interpreterStackFrame->switchProfileMode = true;
  5143. Assert(interpreterStackFrame->switchProfileModeOnLoopEndNumber == 0u - 1);
  5144. interpreterStackFrame->switchProfileModeOnLoopEndNumber = loopNumber;
  5145. }
  5146. }
  5147. else
  5148. {
  5149. if (interpreterStackFrame->switchProfileModeOnLoopEndNumber == loopNumber)
  5150. {
  5151. // Stop profiling since the jitted loop body would be exiting the loop
  5152. Assert(!interpreterStackFrame->switchProfileMode);
  5153. interpreterStackFrame->switchProfileMode = true;
  5154. interpreterStackFrame->switchProfileModeOnLoopEndNumber = 0u - 1;
  5155. }
  5156. interpreterStackFrame->scriptContext->GetThreadContext()->DecrementLoopDepth();
  5157. }
  5158. }
  5159. };
  5160. #endif
  5161. Js::FunctionBody* fn = this->m_functionBody;
  5162. Assert(loopNumber < fn->GetLoopCount());
  5163. Assert(!this->IsInCatchOrFinallyBlock());
  5164. Js::LoopHeader *loopHeader = fn->GetLoopHeader(loopNumber);
  5165. loopHeader->isInTry = (this->m_flags & Js::InterpreterStackFrameFlags_WithinTryBlock);
  5166. Js::LoopEntryPointInfo * entryPointInfo = loopHeader->GetCurrentEntryPointInfo();
  5167. if (fn->ForceJITLoopBody() && loopHeader->interpretCount == 0 &&
  5168. (entryPointInfo != NULL && entryPointInfo->IsNotScheduled()))
  5169. {
  5170. #if ENABLE_PROFILE_INFO
  5171. if (Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()))
  5172. {
  5173. scriptContext->GetThreadContext()->AddImplicitCallFlags(this->savedLoopImplicitCallFlags[loopNumber]);
  5174. }
  5175. #endif
  5176. #if ENABLE_NATIVE_CODEGEN
  5177. GenerateLoopBody(scriptContext->GetNativeCodeGenerator(), fn, loopHeader, entryPointInfo, fn->GetLocalsCount(), this->m_localSlots);
  5178. #endif
  5179. }
  5180. #if ENABLE_NATIVE_CODEGEN
  5181. // If we have JITted the loop, call the JITted code
  5182. if (entryPointInfo != NULL && entryPointInfo->IsCodeGenDone())
  5183. {
  5184. #if DBG_DUMP
  5185. if (PHASE_TRACE1(Js::JITLoopBodyPhase) && CONFIG_FLAG(Verbose))
  5186. {
  5187. fn->DumpFunctionId(true);
  5188. Output::Print(_u(": %-20s LoopBody Execute Loop: %2d\n"), fn->GetDisplayName(), loopNumber);
  5189. Output::Flush();
  5190. }
  5191. loopHeader->nativeCount++;
  5192. #endif
  5193. #ifdef BGJIT_STATS
  5194. entryPointInfo->MarkAsUsed();
  5195. #endif
  5196. entryPointInfo->EnsureIsReadyToCall();
  5197. entryPointInfo->nativeEntryPointProcessed = true;
  5198. RegSlot envReg = this->m_functionBody->GetEnvRegister();
  5199. if (envReg != Constants::NoRegister)
  5200. {
  5201. this->SetNonVarReg(envReg, this->LdEnv());
  5202. }
  5203. RegSlot localClosureReg = this->m_functionBody->GetLocalClosureRegister();
  5204. RegSlot localFrameDisplayReg = this->m_functionBody->GetLocalFrameDisplayRegister();
  5205. RegSlot paramClosureReg = this->m_functionBody->GetParamClosureRegister();
  5206. if (entryPointInfo->HasJittedStackClosure())
  5207. {
  5208. // The jitted code is expecting the closure registers to point to known stack locations where
  5209. // the closures can be found and possibly boxed.
  5210. // In a jitted loop body, those locations are the local closure fields on the interpreter instance.
  5211. if (localClosureReg != Constants::NoRegister)
  5212. {
  5213. this->SetNonVarReg(localClosureReg, &this->localClosure);
  5214. }
  5215. if (localFrameDisplayReg != Constants::NoRegister)
  5216. {
  5217. this->SetNonVarReg(localFrameDisplayReg, &this->localFrameDisplay);
  5218. }
  5219. if (paramClosureReg != Constants::NoRegister)
  5220. {
  5221. this->SetNonVarReg(paramClosureReg, &this->paramClosure);
  5222. }
  5223. }
  5224. else
  5225. {
  5226. // In non-stack-closure jitted code, the closure registers are expected to hold the addresses
  5227. // of the actual structures.
  5228. if (localClosureReg != Constants::NoRegister)
  5229. {
  5230. this->SetNonVarReg(localClosureReg, this->localClosure);
  5231. }
  5232. if (localFrameDisplayReg != Constants::NoRegister)
  5233. {
  5234. this->SetNonVarReg(localFrameDisplayReg, this->localFrameDisplay);
  5235. }
  5236. if (paramClosureReg != Constants::NoRegister)
  5237. {
  5238. this->SetNonVarReg(paramClosureReg, this->paramClosure);
  5239. }
  5240. }
  5241. uint32 innerScopeCount = this->m_functionBody->GetInnerScopeCount();
  5242. for (uint32 i = 0; i < innerScopeCount; i++)
  5243. {
  5244. // As with the function-level scope, transfer the inner scopes from the interpreter's side storage
  5245. // to their dedicated register slots.
  5246. SetNonVarReg(this->m_functionBody->GetFirstInnerScopeRegister() + i, InnerScopeFromIndex(i));
  5247. }
  5248. uint newOffset = 0;
  5249. if (fn->GetIsAsmJsFunction())
  5250. {
  5251. AutoRestoreLoopNumbers autoRestore(this, loopNumber, doProfileLoopCheck);
  5252. newOffset = this->CallAsmJsLoopBody(entryPointInfo->jsMethod);
  5253. }
  5254. else
  5255. {
  5256. AutoRestoreLoopNumbers autoRestore(this, loopNumber, doProfileLoopCheck);
  5257. newOffset = this->CallLoopBody(entryPointInfo->jsMethod);
  5258. }
  5259. if (envReg != Constants::NoRegister)
  5260. {
  5261. SetNonVarReg(envReg, nullptr);
  5262. }
  5263. if (localClosureReg != Constants::NoRegister)
  5264. {
  5265. SetNonVarReg(localClosureReg, nullptr);
  5266. }
  5267. if (localFrameDisplayReg != Constants::NoRegister)
  5268. {
  5269. SetNonVarReg(localFrameDisplayReg, nullptr);
  5270. }
  5271. if (paramClosureReg != Constants::NoRegister)
  5272. {
  5273. SetNonVarReg(paramClosureReg, nullptr);
  5274. }
  5275. for (uint32 i = 0; i < innerScopeCount; i++)
  5276. {
  5277. // Get the (possibly updated) scopes from their registers and put them back in side storage.
  5278. // (Getting the updated values may not be necessary, actually, but it can't hurt.)
  5279. // Then null out the registers.
  5280. RegSlot reg = this->m_functionBody->GetFirstInnerScopeRegister() + i;
  5281. SetInnerScopeFromIndex(i, GetNonVarReg(reg));
  5282. SetNonVarReg(reg, nullptr);
  5283. }
  5284. Assert(Js::OpCodeUtil::GetOpCodeLayout(OpCode::ProfiledLoopBodyStart) == Js::OpLayoutType::Unsigned1);
  5285. Assert(Js::OpCodeUtil::GetOpCodeLayout(OpCode::LoopBodyStart) == Js::OpLayoutType::Unsigned1);
  5286. Assert(Js::OpCodeUtil::EncodedSize(Js::OpCode::LoopBodyStart, layoutSize) == Js::OpCodeUtil::EncodedSize(Js::OpCode::ProfiledLoopBodyStart, layoutSize));
  5287. uint byteCodeSize = Js::OpCodeUtil::EncodedSize(Js::OpCode::LoopBodyStart, layoutSize);
  5288. if (layoutSize == SmallLayout)
  5289. {
  5290. byteCodeSize += sizeof(OpLayoutUnsigned1_Small);
  5291. }
  5292. else if (layoutSize == MediumLayout)
  5293. {
  5294. byteCodeSize += sizeof(OpLayoutUnsigned1_Medium);
  5295. }
  5296. else
  5297. {
  5298. byteCodeSize += sizeof(OpLayoutUnsigned1_Large);
  5299. }
  5300. if (newOffset == loopHeader->startOffset || newOffset == m_reader.GetCurrentOffset() - byteCodeSize)
  5301. {
  5302. // If we bail out back the start of the loop, or start of this LoopBodyStart just skip and interpret the loop
  5303. // instead of trying to start the loop body again
  5304. // Increment the interpret count of the loop
  5305. loopHeader->interpretCount++;
  5306. }
  5307. else
  5308. {
  5309. // we do not support this in asmjs, need to add support in IrBuilderAsmjs if we need this support for asmjs
  5310. if (!entryPointInfo->GetIsAsmJSFunction())
  5311. {
  5312. this->CheckIfLoopIsHot(loopHeader->profiledLoopCounter);
  5313. }
  5314. if (newOffset >= loopHeader->endOffset)
  5315. {
  5316. // Reset the totalJittedLoopIterations for the next invocation of this loop entry point
  5317. entryPointInfo->totalJittedLoopIterations =
  5318. static_cast<uint8>(
  5319. min(
  5320. static_cast<uint>(static_cast<uint8>(CONFIG_FLAG(MinBailOutsBeforeRejit))) *
  5321. (Js::LoopEntryPointInfo::GetDecrLoopCountPerBailout() - 1),
  5322. entryPointInfo->totalJittedLoopIterations));
  5323. entryPointInfo->jittedLoopIterationsSinceLastBailout = 0;
  5324. }
  5325. m_reader.SetCurrentOffset(newOffset);
  5326. }
  5327. return loopHeader;
  5328. }
  5329. #endif
  5330. // Increment the interpret count of the loop
  5331. loopHeader->interpretCount += !isFirstIteration;
  5332. const uint loopInterpretCount = GetFunctionBody()->GetLoopInterpretCount(loopHeader);
  5333. if (loopHeader->interpretCount > loopInterpretCount)
  5334. {
  5335. if (this->scriptContext->GetConfig()->IsNoNative())
  5336. {
  5337. return nullptr;
  5338. }
  5339. if (!fn->DoJITLoopBody())
  5340. {
  5341. return nullptr;
  5342. }
  5343. #if ENABLE_NATIVE_CODEGEN
  5344. // If the job is not scheduled then we need to schedule it now.
  5345. // It is possible a job was scheduled earlier and we find ourselves looking at the same entry point
  5346. // again. For example, if the function with the loop was JITed and bailed out then as we finish
  5347. // the call in the interpreter we might encounter a loop for which we had scheduled a JIT job before
  5348. // the function was initially scheduled. In such cases, that old JIT job will complete. If it completes
  5349. // successfully then we can go ahead and use it. If it fails then it will eventually revert to the
  5350. // NotScheduled state. Since transitions from NotScheduled can only occur on the main thread,
  5351. // by checking the state we are safe from racing with the JIT thread when looking at the other fields
  5352. // of the entry point.
  5353. if (entryPointInfo != NULL && entryPointInfo->IsNotScheduled())
  5354. {
  5355. GenerateLoopBody(scriptContext->GetNativeCodeGenerator(), fn, loopHeader, entryPointInfo, fn->GetLocalsCount(), this->m_localSlots);
  5356. }
  5357. #endif
  5358. }
  5359. #if ENABLE_PROFILE_INFO
  5360. else if(
  5361. doProfileLoopCheck &&
  5362. isAutoProfiling &&
  5363. loopHeader->interpretCount > fn->GetLoopProfileThreshold(loopInterpretCount))
  5364. {
  5365. // Start profiling the loop so that the jitted loop body will have some profile data to use
  5366. Assert(!switchProfileMode);
  5367. switchProfileMode = true;
  5368. Assert(switchProfileModeOnLoopEndNumber == 0u - 1);
  5369. switchProfileModeOnLoopEndNumber = loopNumber;
  5370. }
  5371. #endif
  5372. return nullptr;
  5373. }
  5374. void
  5375. InterpreterStackFrame::CheckIfLoopIsHot(uint profiledLoopCounter)
  5376. {
  5377. Js::FunctionBody *fn = this->function->GetFunctionBody();
  5378. if (!fn->GetHasHotLoop() && profiledLoopCounter > (uint)CONFIG_FLAG(JitLoopBodyHotLoopThreshold))
  5379. {
  5380. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  5381. if(PHASE_TRACE(Js::JITLoopBodyPhase, fn))
  5382. {
  5383. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  5384. Output::Print(
  5385. _u("Speculate Jit set for this function with loopbody: function: %s (%s)\n"),
  5386. fn->GetDisplayName(),
  5387. fn->GetDebugNumberSet(debugStringBuffer));
  5388. Output::Flush();
  5389. }
  5390. #endif
  5391. fn->SetHasHotLoop();
  5392. }
  5393. }
  5394. bool InterpreterStackFrame::CheckAndResetImplicitCall(DisableImplicitFlags prevDisableImplicitFlags, ImplicitCallFlags savedImplicitCallFlags)
  5395. {
  5396. ImplicitCallFlags curImplicitCallFlags = this->scriptContext->GetThreadContext()->GetImplicitCallFlags();
  5397. if (curImplicitCallFlags > ImplicitCall_None)
  5398. {
  5399. //error implicit bit is set , reparse without asmjs
  5400. this->scriptContext->GetThreadContext()->SetDisableImplicitFlags(prevDisableImplicitFlags);
  5401. this->scriptContext->GetThreadContext()->SetImplicitCallFlags(savedImplicitCallFlags);
  5402. return true;
  5403. }
  5404. return false;
  5405. }
  5406. uint
  5407. InterpreterStackFrame::CallLoopBody(JavascriptMethod address)
  5408. {
  5409. #ifdef _M_IX86
  5410. void *savedEsp = NULL;
  5411. __asm
  5412. {
  5413. // Save ESP
  5414. mov savedEsp, esp
  5415. // 8-byte align frame to improve floating point perf of our JIT'd code.
  5416. and esp, -8
  5417. // Add an extra 4-bytes to the stack since we'll be pushing 3 arguments
  5418. push eax
  5419. }
  5420. #endif
  5421. #if defined(_M_ARM32_OR_ARM64)
  5422. // For ARM we need to make sure that pipeline is synchronized with memory/cache for newly jitted code.
  5423. // Note: this does not seem to affect perf, but if it was, we could add a boolean isCalled to EntryPointInfo
  5424. // and do ISB only for 1st time this entry point is called (potential working set regression though).
  5425. _InstructionSynchronizationBarrier();
  5426. #endif
  5427. uint newOffset = ::Math::PointerCastToIntegral<uint>(
  5428. CALL_ENTRYPOINT(address, function, CallInfo(CallFlags_InternalFrame, 1), this));
  5429. #ifdef _M_IX86
  5430. _asm
  5431. {
  5432. // Restore ESP
  5433. mov esp, savedEsp
  5434. }
  5435. #endif
  5436. return newOffset;
  5437. }
  5438. uint
  5439. InterpreterStackFrame::CallAsmJsLoopBody(JavascriptMethod address)
  5440. {
  5441. #ifdef _M_IX86
  5442. void *savedEsp = NULL;
  5443. __asm
  5444. {
  5445. // Save ESP
  5446. mov savedEsp, esp
  5447. // Add an extra 4-bytes to the stack since we'll be pushing 3 arguments
  5448. push eax
  5449. }
  5450. #endif
  5451. #if defined(_M_ARM32_OR_ARM64)
  5452. // For ARM we need to make sure that pipeline is synchronized with memory/cache for newly jitted code.
  5453. // Note: this does not seem to affect perf, but if it was, we could add a boolean isCalled to EntryPointInfo
  5454. // and do ISB only for 1st time this entry point is called (potential working set regression though).
  5455. _InstructionSynchronizationBarrier();
  5456. #endif
  5457. uint newOffset = ::Math::PointerCastToIntegral<uint>(
  5458. CALL_ENTRYPOINT(address, function, CallInfo(CallFlags_InternalFrame, 1), this));
  5459. #ifdef _M_IX86
  5460. _asm
  5461. {
  5462. // Restore ESP
  5463. mov esp, savedEsp
  5464. }
  5465. #endif
  5466. return newOffset;
  5467. }
  5468. template <class T>
  5469. void InterpreterStackFrame::OP_NewScObjectNoCtorFull(const unaligned T* playout)
  5470. {
  5471. Var function = GetReg(playout->R1);
  5472. Var newObj = JavascriptOperators::NewScObjectNoCtorFull(function, GetScriptContext());
  5473. SetReg(playout->R0, newObj);
  5474. }
  5475. ///----------------------------------------------------------------------------
  5476. ///
  5477. /// InterpreterStackFrame::OP_NewScObject
  5478. ///
  5479. /// OP_NewScObject() allocates a new DynamicObject and initializes it with an
  5480. /// optional "constructor" function.
  5481. ///
  5482. /// NOTE: The return register must be carefully chosen to ensure proper
  5483. /// behavior:
  5484. /// 1. OpCode::NewInstance should never specify "R0" as the register to
  5485. /// store the new instance, because it will get whacked from the
  5486. /// "constructor" function's return value:
  5487. ///
  5488. /// var a1 = Date(); <-- a1 = string returned from Date() function
  5489. /// var a2 = new Date(); <-- a2 = instance return from NewInstance.
  5490. /// Date()'s return value is thrown away.
  5491. ///
  5492. /// 2. If an exception is thrown during construction, the destination
  5493. /// variable / field should __not__ be modified. Therefore, the destination
  5494. /// register should always be a temporary and never a valid local variable.
  5495. /// After successfully returning from the constructor function, the new
  5496. /// instance is valid and may be stored in its final destination variable /
  5497. /// field.
  5498. ///
  5499. /// OPCODE NewObject:
  5500. /// T1 = new DynamicObject(Function.Prototype)
  5501. /// OutArg[0] = T1
  5502. /// Call(Function, ArgCount)
  5503. /// Local[Return] = T1
  5504. ///
  5505. /// - R0: Destination "local" register
  5506. /// - R1: Optional constructor JavascriptFunction instance or 'null'
  5507. ///
  5508. ///----------------------------------------------------------------------------
  5509. template <class T, bool Profiled, bool ICIndex>
  5510. void InterpreterStackFrame::OP_NewScObject_Impl(const unaligned T* playout, InlineCacheIndex inlineCacheIndex, const Js::AuxArray<uint32> *spreadIndices)
  5511. {
  5512. if (ICIndex)
  5513. {
  5514. Assert(inlineCacheIndex != Js::Constants::NoInlineCacheIndex);
  5515. }
  5516. Var newVarInstance =
  5517. #if ENABLE_PROFILE_INFO
  5518. Profiled ?
  5519. ProfiledNewScObject_Helper(
  5520. GetReg(playout->Function),
  5521. playout->ArgCount,
  5522. static_cast<const unaligned OpLayoutDynamicProfile<T> *>(playout)->profileId,
  5523. inlineCacheIndex,
  5524. spreadIndices) :
  5525. #endif
  5526. NewScObject_Helper(GetReg(playout->Function), playout->ArgCount, spreadIndices);
  5527. SetReg((RegSlot)playout->Return, newVarInstance);
  5528. }
  5529. template <class T, bool Profiled>
  5530. void InterpreterStackFrame::OP_NewScObjArray_Impl(const unaligned T* playout, const Js::AuxArray<uint32> *spreadIndices)
  5531. {
  5532. // Always profile this operation when auto-profiling so that array type changes are tracked
  5533. #if ENABLE_PROFILE_INFO
  5534. if (!Profiled && !isAutoProfiling)
  5535. #else
  5536. Assert(!Profiled);
  5537. #endif
  5538. {
  5539. OP_NewScObject_Impl<T, Profiled, false>(playout, Js::Constants::NoInlineCacheIndex, spreadIndices);
  5540. return;
  5541. }
  5542. #if ENABLE_PROFILE_INFO
  5543. Arguments args(CallInfo(CallFlags_New, playout->ArgCount), m_outParams);
  5544. uint32 spreadSize = 0;
  5545. if (spreadIndices != nullptr)
  5546. {
  5547. spreadSize = JavascriptFunction::GetSpreadSize(args, spreadIndices, scriptContext);
  5548. // Allocate room on the stack for the spread args.
  5549. Arguments outArgs(CallInfo(CallFlags_New, 0), nullptr);
  5550. outArgs.Info.Count = spreadSize;
  5551. const unsigned STACK_ARGS_ALLOCA_THRESHOLD = 8; // Number of stack args we allow before using _alloca
  5552. Var stackArgs[STACK_ARGS_ALLOCA_THRESHOLD];
  5553. size_t outArgsSize = 0;
  5554. if (outArgs.Info.Count > STACK_ARGS_ALLOCA_THRESHOLD)
  5555. {
  5556. PROBE_STACK(scriptContext, outArgs.Info.Count * sizeof(Var) + Js::Constants::MinStackDefault); // args + function call
  5557. outArgsSize = outArgs.Info.Count * sizeof(Var);
  5558. outArgs.Values = (Var*)_alloca(outArgsSize);
  5559. }
  5560. else
  5561. {
  5562. outArgs.Values = stackArgs;
  5563. outArgsSize = STACK_ARGS_ALLOCA_THRESHOLD * sizeof(Var);
  5564. ZeroMemory(outArgs.Values, outArgsSize); // We may not use all of the elements
  5565. }
  5566. JavascriptFunction::SpreadArgs(args, outArgs, spreadIndices, scriptContext);
  5567. SetReg(
  5568. (RegSlot)playout->Return,
  5569. ProfilingHelpers::ProfiledNewScObjArray(
  5570. GetReg(playout->Function),
  5571. outArgs,
  5572. function,
  5573. static_cast<const unaligned OpLayoutDynamicProfile2<T> *>(playout)->profileId,
  5574. static_cast<const unaligned OpLayoutDynamicProfile2<T> *>(playout)->profileId2));
  5575. }
  5576. else
  5577. {
  5578. SetReg(
  5579. (RegSlot)playout->Return,
  5580. ProfilingHelpers::ProfiledNewScObjArray(
  5581. GetReg(playout->Function),
  5582. args,
  5583. function,
  5584. static_cast<const unaligned OpLayoutDynamicProfile2<T> *>(playout)->profileId,
  5585. static_cast<const unaligned OpLayoutDynamicProfile2<T> *>(playout)->profileId2));
  5586. }
  5587. PopOut(playout->ArgCount);
  5588. #endif
  5589. }
  5590. void InterpreterStackFrame::OP_NewScObject_A_Impl(const unaligned OpLayoutAuxiliary * playout, RegSlot *target)
  5591. {
  5592. const Js::VarArrayVarCount * vars = Js::ByteCodeReader::ReadVarArrayVarCount(playout->Offset, this->GetFunctionBody());
  5593. int count = Js::TaggedInt::ToInt32(vars->count);
  5594. // Push the parameters to stack
  5595. for (int i=0;i<count; i++)
  5596. {
  5597. SetOut( (ArgSlot)(i+1), vars->elements[i]);
  5598. }
  5599. Var newVarInstance = NewScObject_Helper(GetReg((RegSlot)playout->C1), (ArgSlot)count+1);
  5600. SetReg((RegSlot)playout->R0, newVarInstance);
  5601. }
  5602. Var InterpreterStackFrame::NewScObject_Helper(Var target, ArgSlot ArgCount, const Js::AuxArray<uint32> *spreadIndices)
  5603. {
  5604. Arguments args(CallInfo(CallFlags_New, ArgCount), m_outParams);
  5605. Var newVarInstance = JavascriptOperators::NewScObject(target, args, GetScriptContext(), spreadIndices);
  5606. PopOut(ArgCount);
  5607. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(newVarInstance));
  5608. #if ENABLE_DEBUG_CONFIG_OPTIONS
  5609. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  5610. {
  5611. newVarInstance = JavascriptProxy::AutoProxyWrapper(newVarInstance);
  5612. // this might come from a different scriptcontext.
  5613. newVarInstance = CrossSite::MarshalVar(GetScriptContext(), newVarInstance);
  5614. }
  5615. #endif
  5616. #ifdef ENABLE_BASIC_TELEMETRY
  5617. {
  5618. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().NewScriptObject( target, args, newVarInstance );
  5619. }
  5620. #endif
  5621. return newVarInstance;
  5622. }
  5623. #if ENABLE_PROFILE_INFO
  5624. Var InterpreterStackFrame::ProfiledNewScObject_Helper(Var target, ArgSlot ArgCount, ProfileId profileId, InlineCacheIndex inlineCacheIndex, const Js::AuxArray<uint32> *spreadIndices)
  5625. {
  5626. Arguments args(CallInfo(CallFlags_New, ArgCount), m_outParams);
  5627. Var newVarInstance =
  5628. ProfilingHelpers::ProfiledNewScObject(
  5629. target,
  5630. args,
  5631. GetFunctionBody(),
  5632. profileId,
  5633. inlineCacheIndex,
  5634. spreadIndices);
  5635. PopOut(ArgCount);
  5636. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(newVarInstance));
  5637. #if ENABLE_DEBUG_CONFIG_OPTIONS
  5638. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  5639. {
  5640. newVarInstance = JavascriptProxy::AutoProxyWrapper(newVarInstance);
  5641. // this might come from a different scriptcontext.
  5642. newVarInstance = CrossSite::MarshalVar(GetScriptContext(), newVarInstance);
  5643. }
  5644. #endif
  5645. #ifdef TELEMETRY_PROFILED
  5646. {
  5647. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().NewScriptObject( target, args, newVarInstance );
  5648. }
  5649. #endif
  5650. return newVarInstance;
  5651. }
  5652. #endif
  5653. template <typename T>
  5654. void InterpreterStackFrame::OP_LdElementUndefined(const unaligned OpLayoutT_ElementU<T>* playout)
  5655. {
  5656. if (this->m_functionBody->IsEval())
  5657. {
  5658. JavascriptOperators::OP_LoadUndefinedToElementDynamic(GetReg(playout->Instance),
  5659. this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
  5660. }
  5661. else
  5662. {
  5663. JavascriptOperators::OP_LoadUndefinedToElement(GetReg(playout->Instance),
  5664. this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex));
  5665. }
  5666. }
  5667. template <typename T>
  5668. void InterpreterStackFrame::OP_LdLocalElementUndefined(const unaligned OpLayoutT_ElementRootU<T>* playout)
  5669. {
  5670. if (this->m_functionBody->IsEval())
  5671. {
  5672. JavascriptOperators::OP_LoadUndefinedToElementDynamic(this->localClosure,
  5673. this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
  5674. }
  5675. else
  5676. {
  5677. JavascriptOperators::OP_LoadUndefinedToElement(this->localClosure,
  5678. this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex));
  5679. }
  5680. }
  5681. template <typename T>
  5682. void InterpreterStackFrame::OP_LdElementUndefinedScoped(const unaligned OpLayoutT_ElementScopedU<T>* playout)
  5683. {
  5684. // Implicit root object as default instance
  5685. JavascriptOperators::OP_LoadUndefinedToElementScoped(GetEnvForEvalCode(),
  5686. this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetReg(Js::FunctionBody::RootObjectRegSlot), GetScriptContext());
  5687. }
  5688. void InterpreterStackFrame::OP_ChkUndecl(Var aValue)
  5689. {
  5690. if (this->scriptContext->IsUndeclBlockVar(aValue))
  5691. {
  5692. JavascriptError::ThrowReferenceError(scriptContext, JSERR_UseBeforeDeclaration);
  5693. }
  5694. }
  5695. void InterpreterStackFrame::OP_ChkNewCallFlag()
  5696. {
  5697. if (!(this->m_callFlags & CallFlags_New))
  5698. {
  5699. JavascriptError::ThrowTypeError(scriptContext, JSERR_ClassConstructorCannotBeCalledWithoutNew);
  5700. }
  5701. }
  5702. void InterpreterStackFrame::OP_EnsureNoRootProperty(uint propertyIdIndex)
  5703. {
  5704. Var instance = this->GetRootObject();
  5705. JavascriptOperators::OP_EnsureNoRootProperty(instance, this->m_functionBody->GetReferencedPropertyId(propertyIdIndex));
  5706. }
  5707. void InterpreterStackFrame::OP_EnsureNoRootRedeclProperty(uint propertyIdIndex)
  5708. {
  5709. Var instance = this->GetRootObject();
  5710. JavascriptOperators::OP_EnsureNoRootRedeclProperty(instance, this->m_functionBody->GetReferencedPropertyId(propertyIdIndex));
  5711. }
  5712. void InterpreterStackFrame::OP_ScopedEnsureNoRedeclProperty(Var aValue, uint propertyIdIndex, Var aValue2)
  5713. {
  5714. Js::PropertyId propertyId = this->m_functionBody->GetReferencedPropertyId(propertyIdIndex);
  5715. JavascriptOperators::OP_ScopedEnsureNoRedeclProperty((FrameDisplay*)aValue, propertyId, aValue2);
  5716. }
  5717. Var InterpreterStackFrame::OP_InitUndecl()
  5718. {
  5719. return this->scriptContext->GetLibrary()->GetUndeclBlockVar();
  5720. }
  5721. void InterpreterStackFrame::OP_InitUndeclSlot(Var aValue, int32 slot)
  5722. {
  5723. this->OP_StSlot(aValue, slot, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  5724. }
  5725. void InterpreterStackFrame::OP_TryCatch(const unaligned OpLayoutBr* playout)
  5726. {
  5727. Js::JavascriptExceptionObject* exception = NULL;
  5728. try
  5729. {
  5730. this->nestedTryDepth++;
  5731. // mark the stackFrame as 'in try block'
  5732. this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
  5733. Js::JavascriptExceptionOperators::AutoCatchHandlerExists autoCatchHandlerExists(scriptContext);
  5734. if (this->IsInDebugMode())
  5735. {
  5736. #if ENABLE_TTD
  5737. if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
  5738. {
  5739. this->ProcessWithDebugging_PreviousStmtTracking();
  5740. }
  5741. else
  5742. {
  5743. this->ProcessWithDebugging();
  5744. }
  5745. #else
  5746. this->ProcessWithDebugging();
  5747. #endif
  5748. this->TrySetRetOffset();
  5749. }
  5750. else
  5751. {
  5752. this->Process();
  5753. this->TrySetRetOffset();
  5754. }
  5755. }
  5756. catch (const Js::JavascriptException& err)
  5757. {
  5758. // We are using C++ exception handling which does not unwind the stack in the catch block.
  5759. // For stack overflow and OOM exceptions, we cannot run user code here because the stack is not unwind.
  5760. exception = err.GetAndClear();
  5761. }
  5762. if (--this->nestedTryDepth == -1)
  5763. {
  5764. // unmark the stackFrame as 'in try block'
  5765. this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
  5766. }
  5767. // Now that the stack is unwound, let's run the catch block.
  5768. if (exception)
  5769. {
  5770. if (exception->IsGeneratorReturnException())
  5771. {
  5772. // Generator return scenario, so no need to go into the catch block and we must rethrow to propagate the exception to down level
  5773. JavascriptExceptionOperators::DoThrow(exception, scriptContext);
  5774. }
  5775. exception = exception->CloneIfStaticExceptionObject(scriptContext);
  5776. // We've got a JS exception. Grab the exception object and assign it to the
  5777. // catch object's location, then call the handler (i.e., we consume the Catch op here).
  5778. Var catchObject = exception->GetThrownObject(scriptContext);
  5779. m_reader.SetCurrentRelativeOffset((const byte *)(playout + 1), playout->RelativeJumpOffset);
  5780. LayoutSize layoutSize;
  5781. OpCode catchOp = m_reader.ReadOp(layoutSize);
  5782. #ifdef BYTECODE_BRANCH_ISLAND
  5783. if (catchOp == Js::OpCode::BrLong)
  5784. {
  5785. Assert(layoutSize == SmallLayout);
  5786. auto playoutBrLong = m_reader.BrLong();
  5787. m_reader.SetCurrentRelativeOffset((const byte *)(playoutBrLong + 1), playoutBrLong->RelativeJumpOffset);
  5788. catchOp = m_reader.ReadOp(layoutSize);
  5789. }
  5790. #endif
  5791. AssertMsg(catchOp == OpCode::Catch, "Catch op not found at catch offset");
  5792. RegSlot reg = layoutSize == SmallLayout ? m_reader.Reg1_Small()->R0 :
  5793. layoutSize == MediumLayout ? m_reader.Reg1_Medium()->R0 : m_reader.Reg1_Large()->R0;
  5794. SetReg(reg, catchObject);
  5795. ResetOut();
  5796. this->nestedCatchDepth++;
  5797. // mark the stackFrame as 'in catch block'
  5798. this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
  5799. this->ProcessCatch();
  5800. if (--this->nestedCatchDepth == -1)
  5801. {
  5802. // unmark the stackFrame as 'in catch block'
  5803. this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
  5804. }
  5805. }
  5806. }
  5807. void InterpreterStackFrame::ProcessCatch()
  5808. {
  5809. #if ENABLE_TTD
  5810. //Clear any previous Exception Info
  5811. if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
  5812. {
  5813. this->scriptContext->GetThreadContext()->TTDLog->ClearExceptionFrames();
  5814. }
  5815. #endif
  5816. if (this->IsInDebugMode())
  5817. {
  5818. this->DebugProcess();
  5819. }
  5820. else
  5821. {
  5822. this->Process();
  5823. }
  5824. }
  5825. int InterpreterStackFrame::ProcessFinally()
  5826. {
  5827. this->nestedFinallyDepth++;
  5828. // mark the stackFrame as 'in finally block'
  5829. this->m_flags |= InterpreterStackFrameFlags_WithinFinallyBlock;
  5830. int newOffset = 0;
  5831. if (this->IsInDebugMode())
  5832. {
  5833. newOffset = ::Math::PointerCastToIntegral<int>(this->DebugProcess());
  5834. }
  5835. else
  5836. {
  5837. newOffset = ::Math::PointerCastToIntegral<int>(this->Process());
  5838. }
  5839. if (--this->nestedFinallyDepth == -1)
  5840. {
  5841. // unmark the stackFrame as 'in finally block'
  5842. this->m_flags &= ~InterpreterStackFrameFlags_WithinFinallyBlock;
  5843. }
  5844. return newOffset;
  5845. }
  5846. void InterpreterStackFrame::ProcessTryCatchBailout(EHBailoutData * ehBailoutData, uint32 tryNestingDepth)
  5847. {
  5848. int catchOffset = ehBailoutData->catchOffset;
  5849. Js::JavascriptExceptionObject* exception = NULL;
  5850. if (catchOffset != 0)
  5851. {
  5852. try
  5853. {
  5854. this->nestedTryDepth++;
  5855. // mark the stackFrame as 'in try block'
  5856. this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
  5857. if (tryNestingDepth != 0)
  5858. {
  5859. this->ProcessTryCatchBailout(ehBailoutData->child, --tryNestingDepth);
  5860. }
  5861. Js::JavascriptExceptionOperators::AutoCatchHandlerExists autoCatchHandlerExists(scriptContext);
  5862. if (this->IsInDebugMode())
  5863. {
  5864. #if ENABLE_TTD
  5865. if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
  5866. {
  5867. this->ProcessWithDebugging_PreviousStmtTracking();
  5868. }
  5869. else
  5870. {
  5871. this->ProcessWithDebugging();
  5872. }
  5873. #else
  5874. this->ProcessWithDebugging();
  5875. #endif
  5876. this->TrySetRetOffset();
  5877. }
  5878. else
  5879. {
  5880. this->Process();
  5881. this->TrySetRetOffset();
  5882. }
  5883. }
  5884. catch (const Js::JavascriptException& err)
  5885. {
  5886. // We are using C++ exception handling which does not unwind the stack in the catch block.
  5887. // For stack overflow and OOM exceptions, we cannot run user code here because the stack is not unwind.
  5888. exception = err.GetAndClear();
  5889. }
  5890. }
  5891. else
  5892. {
  5893. this->nestedCatchDepth++;
  5894. // mark the stackFrame as 'in catch block'
  5895. this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
  5896. if (tryNestingDepth != 0)
  5897. {
  5898. this->ProcessTryCatchBailout(ehBailoutData->child, --tryNestingDepth);
  5899. }
  5900. this->ProcessCatch();
  5901. if (--this->nestedCatchDepth == -1)
  5902. {
  5903. // unmark the stackFrame as 'in catch block'
  5904. this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
  5905. }
  5906. return;
  5907. }
  5908. if (--this->nestedTryDepth == -1)
  5909. {
  5910. // unmark the stackFrame as 'in try block'
  5911. this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
  5912. }
  5913. // Now that the stack is unwound, let's run the catch block.
  5914. if (exception)
  5915. {
  5916. if (exception->IsGeneratorReturnException())
  5917. {
  5918. // Generator return scenario, so no need to go into the catch block and we must rethrow to propagate the exception to down level
  5919. JavascriptExceptionOperators::DoThrow(exception, scriptContext);
  5920. }
  5921. exception = exception->CloneIfStaticExceptionObject(scriptContext);
  5922. // We've got a JS exception. Grab the exception object and assign it to the
  5923. // catch object's location, then call the handler (i.e., we consume the Catch op here).
  5924. Var catchObject = exception->GetThrownObject(scriptContext);
  5925. m_reader.SetCurrentOffset(catchOffset);
  5926. LayoutSize layoutSize;
  5927. OpCode catchOp = m_reader.ReadOp(layoutSize);
  5928. #ifdef BYTECODE_BRANCH_ISLAND
  5929. if (catchOp == Js::OpCode::BrLong)
  5930. {
  5931. Assert(layoutSize == SmallLayout);
  5932. auto playoutBrLong = m_reader.BrLong();
  5933. m_reader.SetCurrentRelativeOffset((const byte *)(playoutBrLong + 1), playoutBrLong->RelativeJumpOffset);
  5934. catchOp = m_reader.ReadOp(layoutSize);
  5935. }
  5936. #endif
  5937. AssertMsg(catchOp == OpCode::Catch, "Catch op not found at catch offset");
  5938. RegSlot reg = layoutSize == SmallLayout ? m_reader.Reg1_Small()->R0 :
  5939. layoutSize == MediumLayout ? m_reader.Reg1_Medium()->R0 : m_reader.Reg1_Large()->R0;
  5940. SetReg(reg, catchObject);
  5941. ResetOut();
  5942. this->nestedCatchDepth++;
  5943. // mark the stackFrame as 'in catch block'
  5944. this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
  5945. this->ProcessCatch();
  5946. if (--this->nestedCatchDepth == -1)
  5947. {
  5948. // unmark the stackFrame as 'in catch block'
  5949. this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
  5950. }
  5951. }
  5952. }
  5953. void InterpreterStackFrame::TrySetRetOffset()
  5954. {
  5955. Assert(this->m_flags & Js::InterpreterStackFrameFlags_WithinTryBlock);
  5956. // It may happen that a JITted loop body returned the offset of RET. If the loop body was
  5957. // called from a try, the interpreter "Process()" should also just return.
  5958. if (this->retOffset != 0)
  5959. {
  5960. m_reader.SetCurrentOffset(this->retOffset);
  5961. }
  5962. }
  5963. bool InterpreterStackFrame::IsInCatchOrFinallyBlock()
  5964. {
  5965. return (this->m_flags & Js::InterpreterStackFrameFlags_WithinCatchBlock) ||
  5966. (this->m_flags & Js::InterpreterStackFrameFlags_WithinFinallyBlock);
  5967. }
  5968. void InterpreterStackFrame::OP_BeginBodyScope()
  5969. {
  5970. // Currently we are using the closures created for the param scope.
  5971. // This marks the beginning of the body scope, so let's create new closures for the body scope.
  5972. FunctionBody *executeFunction = this->function->GetFunctionBody();
  5973. Assert(!this->IsParamScopeDone() && !executeFunction->IsParamAndBodyScopeMerged());
  5974. // Save the current closure. We have to use this while copying the initial value of body symbols
  5975. // from the corresponding symbols in the param.
  5976. this->SetParamClosure(this->GetLocalClosure());
  5977. this->SetNonVarReg(executeFunction->GetParamClosureRegister(), nullptr);
  5978. this->SetIsParamScopeDone(true);
  5979. if (executeFunction->scopeSlotArraySize > 0)
  5980. {
  5981. this->InitializeClosures();
  5982. }
  5983. }
  5984. void InterpreterStackFrame::OP_ResumeCatch()
  5985. {
  5986. this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
  5987. if (this->IsInDebugMode())
  5988. {
  5989. this->DebugProcess();
  5990. }
  5991. else
  5992. {
  5993. this->Process();
  5994. }
  5995. this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
  5996. }
  5997. /// ---------------------------------------------------------------------------------------------------
  5998. /// The behavior we want is the following:
  5999. /// - If the control leaves the user's try without throwing, execute the finally and continue
  6000. /// after the end of the try.
  6001. /// - If the user code throws, catch this exception and then execute this finally while unwinding to
  6002. /// the handler (if any).
  6003. /// ---------------------------------------------------------------------------------------------------
  6004. void InterpreterStackFrame::ProcessTryFinally(const byte* ip, Js::JumpOffset jumpOffset, Js::RegSlot regException, Js::RegSlot regOffset, bool hasYield)
  6005. {
  6006. Js::JavascriptExceptionObject* pExceptionObject = nullptr;
  6007. bool skipFinallyBlock = false;
  6008. try
  6009. {
  6010. Js::Var result = nullptr;
  6011. this->nestedTryDepth++;
  6012. // mark the stackFrame as 'in try block'
  6013. this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
  6014. if (shouldCacheSP)
  6015. {
  6016. CacheSp();
  6017. }
  6018. if (this->IsInDebugMode())
  6019. {
  6020. #if ENABLE_TTD
  6021. if(SHOULD_DO_TTD_STACK_STMT_OP(this->scriptContext))
  6022. {
  6023. result = this->ProcessWithDebugging_PreviousStmtTracking();
  6024. }
  6025. else
  6026. {
  6027. result = this->ProcessWithDebugging();
  6028. }
  6029. #else
  6030. result = this->ProcessWithDebugging();
  6031. #endif
  6032. }
  6033. else
  6034. {
  6035. result = this->Process();
  6036. }
  6037. if (result == nullptr)
  6038. {
  6039. Assert(hasYield);
  6040. skipFinallyBlock = true;
  6041. }
  6042. }
  6043. catch (const Js::JavascriptException& err)
  6044. {
  6045. pExceptionObject = err.GetAndClear();
  6046. }
  6047. if (--this->nestedTryDepth == -1)
  6048. {
  6049. // unmark the stackFrame as 'in try block'
  6050. this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
  6051. }
  6052. shouldCacheSP = !skipFinallyBlock;
  6053. if (skipFinallyBlock)
  6054. {
  6055. // A leave occurred due to a yield
  6056. return;
  6057. }
  6058. // Save the current IP so execution can continue there if the finally doesn't
  6059. // take control of the flow.
  6060. int newOffset = 0;
  6061. int currOffset = m_reader.GetCurrentOffset();
  6062. if (hasYield)
  6063. {
  6064. // save the exception if there is one to a register in case we yield during the finally block
  6065. // and need to get that exception object back upon resume in OP_ResumeFinally
  6066. SetNonVarReg(regException, pExceptionObject);
  6067. SetNonVarReg(regOffset, reinterpret_cast<Js::Var>(currOffset));
  6068. }
  6069. if (pExceptionObject && !pExceptionObject->IsGeneratorReturnException())
  6070. {
  6071. // Clone static exception object early in case finally block overwrites it
  6072. pExceptionObject = pExceptionObject->CloneIfStaticExceptionObject(scriptContext);
  6073. }
  6074. if (pExceptionObject && this->IsInDebugMode() &&
  6075. pExceptionObject != scriptContext->GetThreadContext()->GetPendingSOErrorObject())
  6076. {
  6077. // Swallowing an exception that has triggered a finally is not implemented
  6078. // (This appears to be the same behavior as ie8)
  6079. pExceptionObject->SetDebuggerSkip(false);
  6080. }
  6081. // Call into the finally by setting the IP, consuming the Finally, and letting the interpreter recurse.
  6082. m_reader.SetCurrentRelativeOffset(ip, jumpOffset);
  6083. RestoreSp();
  6084. newOffset = this->ProcessFinally();
  6085. bool endOfFinallyBlock = newOffset == 0;
  6086. if (endOfFinallyBlock)
  6087. {
  6088. // Finally completed without taking over the flow. Resume where we left off before calling it.
  6089. m_reader.SetCurrentOffset(currOffset);
  6090. }
  6091. else
  6092. {
  6093. // Finally seized the flow with a jump out of its scope. Resume at the jump target and
  6094. // force the runtime to return to this frame without executing the catch.
  6095. m_reader.SetCurrentOffset(newOffset);
  6096. return;
  6097. }
  6098. if (pExceptionObject && (endOfFinallyBlock || !pExceptionObject->IsGeneratorReturnException()))
  6099. {
  6100. JavascriptExceptionOperators::DoThrow(pExceptionObject, scriptContext);
  6101. }
  6102. }
  6103. void InterpreterStackFrame::OP_TryFinally(const unaligned OpLayoutBr* playout)
  6104. {
  6105. ProcessTryFinally((const byte*)(playout + 1), playout->RelativeJumpOffset);
  6106. }
  6107. void InterpreterStackFrame::OP_TryFinallyWithYield(const byte* ip, Js::JumpOffset jumpOffset, Js::RegSlot regException, Js::RegSlot regOffset)
  6108. {
  6109. ProcessTryFinally(ip, jumpOffset, regException, regOffset, true);
  6110. }
  6111. void InterpreterStackFrame::OP_ResumeFinally(const byte* ip, Js::JumpOffset jumpOffset, RegSlot exceptionRegSlot, RegSlot offsetRegSlot)
  6112. {
  6113. this->m_flags |= InterpreterStackFrameFlags_WithinFinallyBlock;
  6114. int newOffset = 0;
  6115. if (this->IsInDebugMode())
  6116. {
  6117. newOffset = ::Math::PointerCastToIntegral<int>(this->DebugProcess());
  6118. }
  6119. else
  6120. {
  6121. newOffset = ::Math::PointerCastToIntegral<int>(this->Process());
  6122. }
  6123. this->m_flags &= ~InterpreterStackFrameFlags_WithinFinallyBlock;
  6124. bool endOfFinallyBlock = newOffset == 0;
  6125. if (endOfFinallyBlock)
  6126. {
  6127. // Finally completed without taking over the flow. Resume where we left off before calling it.
  6128. int currOffset = ::Math::PointerCastToIntegral<int>(GetNonVarReg(offsetRegSlot));
  6129. m_reader.SetCurrentOffset(currOffset);
  6130. }
  6131. else
  6132. {
  6133. // Finally seized the flow with a jump out of its scope. Resume at the jump target and
  6134. // force the runtime to return to this frame without executing the catch.
  6135. m_reader.SetCurrentOffset(newOffset);
  6136. return;
  6137. }
  6138. Js::JavascriptExceptionObject* exceptionObj = (Js::JavascriptExceptionObject*)GetNonVarReg(exceptionRegSlot);
  6139. if (exceptionObj && (endOfFinallyBlock || !exceptionObj->IsGeneratorReturnException()))
  6140. {
  6141. JavascriptExceptionOperators::DoThrow(exceptionObj, scriptContext);
  6142. }
  6143. }
  6144. template <typename T>
  6145. void InterpreterStackFrame::OP_IsInst(const unaligned T* playout)
  6146. {
  6147. Var instance = GetReg(playout->R1);
  6148. Var function = GetReg(playout->R2);
  6149. IsInstInlineCache *inlineCache = this->GetIsInstInlineCache(playout->inlineCacheIndex);
  6150. ScriptContext* scriptContext = GetScriptContext();
  6151. Var result = JavascriptOperators::OP_IsInst(instance, function, scriptContext, inlineCache);
  6152. #ifdef ENABLE_BASIC_TELEMETRY
  6153. {
  6154. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().IsInstanceOf(instance, function, result);
  6155. }
  6156. #endif
  6157. SetReg(playout->R0, result);
  6158. }
  6159. template <typename T>
  6160. void InterpreterStackFrame::OP_ApplyArgs(const unaligned OpLayoutT_Reg5<T> * playout)
  6161. {
  6162. // Always save and restore implicit call flags when calling out
  6163. // REVIEW: Can we avoid it if we don't collect dynamic profile info?
  6164. ThreadContext * threadContext = scriptContext->GetThreadContext();
  6165. Js::ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  6166. // Currently ApplyArgs is equivalent to CallFldVoid (where we don't use the return value)
  6167. Var v=GetNonVarReg(playout->R4);
  6168. JavascriptOperators::OP_ApplyArgs(GetReg(playout->R1),GetReg(playout->R2),
  6169. (void**)GetNonVarReg(playout->R3),*((CallInfo*)&v),GetScriptContext());
  6170. threadContext->SetImplicitCallFlags(savedImplicitCallFlags);
  6171. }
  6172. void InterpreterStackFrame::OP_SpreadArrayLiteral(const unaligned OpLayoutReg2Aux * playout)
  6173. {
  6174. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  6175. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  6176. threadContext->ClearImplicitCallFlags();
  6177. Var instance = GetReg(playout->R1);
  6178. #if ENABLE_COPYONACCESS_ARRAY
  6179. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  6180. #endif
  6181. const Js::AuxArray<uint32> *spreadIndices = m_reader.ReadAuxArray<uint32>(playout->Offset, this->GetFunctionBody());
  6182. ScriptContext* scriptContext = GetScriptContext();
  6183. Var result = JavascriptArray::SpreadArrayArgs(instance, spreadIndices, scriptContext);
  6184. threadContext->CheckAndResetImplicitCallAccessorFlag();
  6185. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  6186. SetReg(playout->R0, result);
  6187. }
  6188. FrameDisplay *
  6189. InterpreterStackFrame::OP_LdInnerFrameDisplay(void *argHead, void *argEnv, ScriptContext *scriptContext)
  6190. {
  6191. JavascriptOperators::CheckInnerFrameDisplayArgument(argHead);
  6192. return OP_LdFrameDisplay(argHead, argEnv, scriptContext);
  6193. }
  6194. FrameDisplay *
  6195. InterpreterStackFrame::OP_LdInnerFrameDisplayNoParent(void *argHead, ScriptContext *scriptContext)
  6196. {
  6197. JavascriptOperators::CheckInnerFrameDisplayArgument(argHead);
  6198. return OP_LdFrameDisplayNoParent<true>(argHead, scriptContext);
  6199. }
  6200. FrameDisplay *
  6201. InterpreterStackFrame::OP_LdFrameDisplay(void *argHead, void *argEnv, ScriptContext *scriptContext)
  6202. {
  6203. FrameDisplay *frameDisplay;
  6204. bool strict = this->m_functionBody->GetIsStrictMode();
  6205. if (strict)
  6206. {
  6207. frameDisplay = JavascriptOperators::OP_LdStrictFrameDisplay(argHead, argEnv, scriptContext);
  6208. }
  6209. else
  6210. {
  6211. frameDisplay = JavascriptOperators::OP_LdFrameDisplay(argHead, argEnv, scriptContext);
  6212. }
  6213. return frameDisplay;
  6214. }
  6215. FrameDisplay *
  6216. InterpreterStackFrame::OP_LdFrameDisplaySetLocal(void *argHead, void *argEnv, ScriptContext *scriptContext)
  6217. {
  6218. FrameDisplay *frameDisplay = OP_LdFrameDisplay(argHead, argEnv, scriptContext);
  6219. this->SetLocalFrameDisplay(frameDisplay);
  6220. return frameDisplay;
  6221. }
  6222. FrameDisplay *
  6223. InterpreterStackFrame::NewFrameDisplay(void *argHead, void *argEnv)
  6224. {
  6225. FrameDisplay *frameDisplay;
  6226. bool strict = this->m_functionBody->GetIsStrictMode();
  6227. if (!this->m_functionBody->DoStackFrameDisplay() || !this->GetLocalFrameDisplay())
  6228. {
  6229. // Null local frame display probably indicates that we bailed out of an inlinee.
  6230. // Once we support stack closures in inlined functions, we can just assert that this value
  6231. // is never null if we should be allocating on the stack.
  6232. return this->OP_LdFrameDisplaySetLocal(argHead, argEnv, this->GetScriptContext());
  6233. }
  6234. frameDisplay = this->GetLocalFrameDisplay();
  6235. Assert(frameDisplay != nullptr);
  6236. frameDisplay->SetTag(true);
  6237. frameDisplay->SetStrictMode(strict);
  6238. frameDisplay->SetLength(this->m_functionBody->GetEnvDepth() + 1);
  6239. Assert(frameDisplay->GetLength() == ((FrameDisplay*)argEnv)->GetLength() + 1);
  6240. for (uint i = 0; i < ((FrameDisplay*)argEnv)->GetLength(); i++)
  6241. {
  6242. frameDisplay->SetItem(i + 1, ((FrameDisplay*)argEnv)->GetItem(i));
  6243. }
  6244. frameDisplay->SetItem(0, argHead);
  6245. return frameDisplay;
  6246. }
  6247. template<bool innerFD>
  6248. FrameDisplay *
  6249. InterpreterStackFrame::OP_LdFrameDisplayNoParent(void *argHead, ScriptContext *scriptContext)
  6250. {
  6251. FrameDisplay *frameDisplay;
  6252. bool strict = this->m_functionBody->GetIsStrictMode();
  6253. Var argEnv = nullptr;
  6254. if (innerFD && this->m_functionBody->GetLocalFrameDisplayRegister() != Constants::NoRegister)
  6255. {
  6256. argEnv = this->GetLocalFrameDisplay();
  6257. }
  6258. if (argEnv == nullptr && this->m_functionBody->GetEnvRegister() != Constants::NoRegister)
  6259. {
  6260. argEnv = this->LdEnv();
  6261. }
  6262. if (argEnv == nullptr)
  6263. {
  6264. if (strict)
  6265. {
  6266. frameDisplay = JavascriptOperators::OP_LdStrictFrameDisplayNoParent(argHead, scriptContext);
  6267. }
  6268. else
  6269. {
  6270. frameDisplay = JavascriptOperators::OP_LdFrameDisplayNoParent(argHead, scriptContext);
  6271. }
  6272. }
  6273. else
  6274. {
  6275. if (strict)
  6276. {
  6277. frameDisplay = JavascriptOperators::OP_LdStrictFrameDisplay(argHead, argEnv, scriptContext);
  6278. }
  6279. else
  6280. {
  6281. frameDisplay = JavascriptOperators::OP_LdFrameDisplay(argHead, argEnv, scriptContext);
  6282. }
  6283. }
  6284. return frameDisplay;
  6285. }
  6286. FrameDisplay *
  6287. InterpreterStackFrame::OP_LdFuncExprFrameDisplaySetLocal(void *argHead1, void *argHead2, ScriptContext *scriptContext)
  6288. {
  6289. FrameDisplay *frameDisplay = OP_LdFrameDisplayNoParent<false>(argHead2, scriptContext);
  6290. frameDisplay = OP_LdFrameDisplay(argHead1, frameDisplay, scriptContext);
  6291. this->SetLocalFrameDisplay(frameDisplay);
  6292. return frameDisplay;
  6293. }
  6294. FrameDisplay* InterpreterStackFrame::GetLocalFrameDisplay() const
  6295. {
  6296. return this->localFrameDisplay;
  6297. }
  6298. void InterpreterStackFrame::SetLocalFrameDisplay(FrameDisplay* frameDisplay)
  6299. {
  6300. this->localFrameDisplay = frameDisplay;
  6301. }
  6302. Var InterpreterStackFrame::GetLocalClosure() const
  6303. {
  6304. return this->localClosure;
  6305. }
  6306. void InterpreterStackFrame::SetLocalClosure(Var closure)
  6307. {
  6308. this->localClosure = closure;
  6309. }
  6310. Var InterpreterStackFrame::GetParamClosure() const
  6311. {
  6312. return this->paramClosure;
  6313. }
  6314. void InterpreterStackFrame::SetParamClosure(Var closure)
  6315. {
  6316. this->paramClosure = closure;
  6317. }
  6318. void
  6319. InterpreterStackFrame::OP_NewInnerScopeSlots(uint innerScopeIndex, uint count, int scopeIndex, ScriptContext *scriptContext, FunctionBody *functionBody)
  6320. {
  6321. Var * slotArray;
  6322. slotArray =
  6323. JavascriptOperators::OP_NewScopeSlotsWithoutPropIds(count, scopeIndex, scriptContext, functionBody);
  6324. this->SetInnerScopeFromIndex(innerScopeIndex, slotArray);
  6325. }
  6326. template <typename T>
  6327. void InterpreterStackFrame::OP_CloneInnerScopeSlots(const unaligned OpLayoutT_Unsigned1<T> *playout)
  6328. {
  6329. uint innerScopeIndex = playout->C1;
  6330. Var * slotArray;
  6331. slotArray = (Var*)this->InnerScopeFromIndex(innerScopeIndex);
  6332. slotArray = JavascriptOperators::OP_CloneScopeSlots(slotArray, scriptContext);
  6333. this->SetInnerScopeFromIndex(innerScopeIndex, slotArray);
  6334. }
  6335. template <typename T>
  6336. void InterpreterStackFrame::OP_CloneBlockScope(const unaligned OpLayoutT_Unsigned1<T> *playout)
  6337. {
  6338. uint innerScopeIndex = playout->C1;
  6339. Var scope = this->InnerScopeFromIndex(innerScopeIndex);
  6340. BlockActivationObject* blockScope = BlockActivationObject::FromVar(scope);
  6341. scope = JavascriptOperators::OP_CloneBlockScope(blockScope, scriptContext);
  6342. this->SetInnerScopeFromIndex(innerScopeIndex, scope);
  6343. }
  6344. Var *
  6345. InterpreterStackFrame::NewScopeSlots(unsigned int size, ScriptContext *scriptContext, Var scope)
  6346. {
  6347. Var * slotArray;
  6348. slotArray = JavascriptOperators::OP_NewScopeSlots(size, scriptContext, scope);
  6349. this->SetLocalClosure(slotArray);
  6350. return slotArray;
  6351. }
  6352. Var *
  6353. InterpreterStackFrame::NewScopeSlots()
  6354. {
  6355. Var * slotArray;
  6356. FunctionBody * functionBody = this->m_functionBody;
  6357. uint scopeSlotCount = this->IsParamScopeDone() ? functionBody->scopeSlotArraySize : functionBody->paramScopeSlotArraySize;
  6358. Assert(scopeSlotCount != 0);
  6359. if (!functionBody->DoStackScopeSlots())
  6360. {
  6361. return this->NewScopeSlots(
  6362. scopeSlotCount + ScopeSlots::FirstSlotIndex, this->GetScriptContext(), (Var)functionBody->GetFunctionInfo());
  6363. }
  6364. slotArray = (Var*)this->GetLocalClosure();
  6365. Assert(slotArray != nullptr);
  6366. ScopeSlots scopeSlots(slotArray);
  6367. scopeSlots.SetCount(scopeSlotCount);
  6368. scopeSlots.SetScopeMetadata((Var)functionBody->GetFunctionInfo());
  6369. Var undef = functionBody->GetScriptContext()->GetLibrary()->GetUndefined();
  6370. for (unsigned int i = 0; i < scopeSlotCount; i++)
  6371. {
  6372. scopeSlots.Set(i, undef);
  6373. }
  6374. return slotArray;
  6375. }
  6376. Var
  6377. InterpreterStackFrame::NewScopeObject()
  6378. {
  6379. Var scopeObject;
  6380. if (m_functionBody->HasCachedScopePropIds())
  6381. {
  6382. const Js::PropertyIdArray *propIds = this->m_functionBody->GetFormalsPropIdArray();
  6383. Var funcExpr = this->GetFunctionExpression();
  6384. PropertyId objectId = ActivationObjectEx::GetLiteralObjectRef(propIds);
  6385. scopeObject = JavascriptOperators::OP_InitCachedScope(funcExpr, propIds,
  6386. this->GetFunctionBody()->GetObjectLiteralTypeRef(objectId),
  6387. propIds->hasNonSimpleParams, GetScriptContext());
  6388. }
  6389. else
  6390. {
  6391. scopeObject = JavascriptOperators::OP_NewScopeObject(GetScriptContext());
  6392. }
  6393. this->SetLocalClosure(scopeObject);
  6394. return scopeObject;
  6395. }
  6396. FrameDisplay *
  6397. InterpreterStackFrame::GetFrameDisplayForNestedFunc() const
  6398. {
  6399. if (this->localFrameDisplay == nullptr)
  6400. {
  6401. return (FrameDisplay*)LdEnv();
  6402. }
  6403. return this->localFrameDisplay;
  6404. }
  6405. template <class T>
  6406. void InterpreterStackFrame::OP_NewStackScFunc(const unaligned T * playout)
  6407. {
  6408. uint funcIndex = playout->SlotIndex;
  6409. FrameDisplay *frameDisplay = this->GetFrameDisplayForNestedFunc();
  6410. SetRegAllowStackVarEnableOnly(playout->Value,
  6411. StackScriptFunction::OP_NewStackScFunc(frameDisplay,
  6412. this->m_functionBody->GetNestedFuncReference(funcIndex),
  6413. this->GetStackNestedFunction(funcIndex)));
  6414. }
  6415. template <class T>
  6416. void InterpreterStackFrame::OP_NewInnerStackScFunc(const unaligned T * playout)
  6417. {
  6418. uint funcIndex = playout->SlotIndex;
  6419. FrameDisplay *frameDisplay = (FrameDisplay*)GetNonVarReg(playout->Instance);
  6420. SetRegAllowStackVarEnableOnly(playout->Value,
  6421. StackScriptFunction::OP_NewStackScFunc(frameDisplay,
  6422. this->m_functionBody->GetNestedFuncReference(funcIndex),
  6423. this->GetStackNestedFunction(funcIndex)));
  6424. }
  6425. template <class T>
  6426. void InterpreterStackFrame::OP_DeleteFld(const unaligned T * playout)
  6427. {
  6428. Var result = JavascriptOperators::OP_DeleteProperty(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
  6429. SetReg(playout->Value, result);
  6430. }
  6431. template <class T>
  6432. void InterpreterStackFrame::OP_DeleteLocalFld(const unaligned T * playout)
  6433. {
  6434. Var result = JavascriptOperators::OP_DeleteProperty(this->localClosure, m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
  6435. SetReg(playout->Instance, result);
  6436. }
  6437. template <class T>
  6438. void InterpreterStackFrame::OP_DeleteRootFld(const unaligned T * playout)
  6439. {
  6440. Var result = JavascriptOperators::OP_DeleteRootProperty(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
  6441. SetReg(playout->Value, result);
  6442. }
  6443. template <class T>
  6444. void InterpreterStackFrame::OP_DeleteFldStrict(const unaligned T * playout)
  6445. {
  6446. Var result = JavascriptOperators::OP_DeleteProperty(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext(), PropertyOperation_StrictMode);
  6447. SetReg(playout->Value, result);
  6448. }
  6449. template <class T>
  6450. void InterpreterStackFrame::OP_DeleteRootFldStrict(const unaligned T * playout)
  6451. {
  6452. Var result = JavascriptOperators::OP_DeleteRootProperty(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext(), PropertyOperation_StrictMode);
  6453. SetReg(playout->Value, result);
  6454. }
  6455. template <typename T>
  6456. void InterpreterStackFrame::OP_ScopedDeleteFld(const unaligned OpLayoutT_ElementScopedC<T> * playout)
  6457. {
  6458. // Implicit root object as default instance
  6459. Var result = JavascriptOperators::OP_DeletePropertyScoped(GetEnvForEvalCode(),
  6460. m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
  6461. GetReg(Js::FunctionBody::RootObjectRegSlot), GetScriptContext());
  6462. SetReg(playout->Value, result);
  6463. }
  6464. template <typename T>
  6465. void InterpreterStackFrame::OP_ScopedDeleteFldStrict(const unaligned OpLayoutT_ElementScopedC<T> * playout)
  6466. {
  6467. // Implicit root object as default instance
  6468. Var result = JavascriptOperators::OP_DeletePropertyScoped(GetEnvForEvalCode(),
  6469. m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
  6470. GetReg(Js::FunctionBody::RootObjectRegSlot), GetScriptContext(), PropertyOperation_StrictMode);
  6471. SetReg(playout->Value, result);
  6472. }
  6473. template <class T>
  6474. void InterpreterStackFrame::OP_ScopedLdInst(const unaligned T * playout)
  6475. {
  6476. Var thisVar;
  6477. Var rootObject = GetFunctionBody()->GetRootObject();
  6478. Var result = JavascriptOperators::OP_GetInstanceScoped(GetEnvForEvalCode(),
  6479. m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), rootObject, &thisVar, GetScriptContext());
  6480. SetReg(playout->Value, result);
  6481. SetReg(playout->Value2, thisVar);
  6482. }
  6483. template <typename T>
  6484. void InterpreterStackFrame::OP_ScopedInitFunc(const unaligned OpLayoutT_ElementScopedC<T> * playout)
  6485. {
  6486. JavascriptOperators::OP_InitFuncScoped(GetEnvForEvalCode(),
  6487. m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
  6488. GetReg(playout->Value), GetReg(Js::FunctionBody::RootObjectRegSlot), GetScriptContext());
  6489. }
  6490. template <class T>
  6491. void InterpreterStackFrame::OP_ClearAttributes(const unaligned T * playout)
  6492. {
  6493. JavascriptOperators::OP_ClearAttributes(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex));
  6494. }
  6495. template <class T>
  6496. void InterpreterStackFrame::OP_InitGetFld(const unaligned T * playout)
  6497. {
  6498. JavascriptOperators::OP_InitGetter(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetReg(playout->Value));
  6499. }
  6500. template <class T>
  6501. void InterpreterStackFrame::OP_InitSetFld(const unaligned T * playout)
  6502. {
  6503. JavascriptOperators::OP_InitSetter(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetReg(playout->Value));
  6504. }
  6505. template <class T>
  6506. void InterpreterStackFrame::OP_InitSetElemI(const unaligned T * playout)
  6507. {
  6508. JavascriptOperators::OP_InitElemSetter(
  6509. GetReg(playout->Instance),
  6510. GetReg(playout->Element),
  6511. GetReg(playout->Value),
  6512. m_functionBody->GetScriptContext()
  6513. );
  6514. }
  6515. template <class T>
  6516. void InterpreterStackFrame::OP_InitGetElemI(const unaligned T * playout)
  6517. {
  6518. JavascriptOperators::OP_InitElemGetter(
  6519. GetReg(playout->Instance),
  6520. GetReg(playout->Element),
  6521. GetReg(playout->Value),
  6522. m_functionBody->GetScriptContext()
  6523. );
  6524. }
  6525. template <class T>
  6526. void InterpreterStackFrame::OP_InitComputedProperty(const unaligned T * playout)
  6527. {
  6528. JavascriptOperators::OP_InitComputedProperty(
  6529. GetReg(playout->Instance),
  6530. GetReg(playout->Element),
  6531. GetReg(playout->Value),
  6532. m_functionBody->GetScriptContext()
  6533. );
  6534. }
  6535. template <class T>
  6536. void InterpreterStackFrame::OP_InitProto(const unaligned T * playout)
  6537. {
  6538. JavascriptOperators::OP_InitProto(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetReg(playout->Value));
  6539. }
  6540. void InterpreterStackFrame::DoInterruptProbe()
  6541. {
  6542. PROBE_STACK(scriptContext, 0);
  6543. }
  6544. void InterpreterStackFrame::InitializeStackFunctions(StackScriptFunction * scriptFunctions)
  6545. {
  6546. this->stackNestedFunctions = scriptFunctions;
  6547. FunctionBody * functionBody = this->m_functionBody;
  6548. uint nestedCount = functionBody->GetNestedCount();
  6549. for (uint i = 0; i < nestedCount; i++)
  6550. {
  6551. StackScriptFunction * stackScriptFunction = scriptFunctions + i;
  6552. FunctionProxy* nestedProxy = functionBody->GetNestedFunctionProxy(i);
  6553. ScriptFunctionType* type = nestedProxy->EnsureDeferredPrototypeType();
  6554. new (stackScriptFunction)StackScriptFunction(nestedProxy, type);
  6555. }
  6556. }
  6557. StackScriptFunction * InterpreterStackFrame::GetStackNestedFunction(uint index)
  6558. {
  6559. Assert(index < this->m_functionBody->GetNestedCount());
  6560. // Re-check if we have disable stack nested function
  6561. if (this->m_functionBody->DoStackNestedFunc())
  6562. {
  6563. return this->stackNestedFunctions + index;
  6564. }
  6565. return nullptr;
  6566. }
  6567. void InterpreterStackFrame::SetExecutingStackFunction(ScriptFunction * scriptFunction)
  6568. {
  6569. Assert(ThreadContext::IsOnStack(this->function));
  6570. Assert(this->m_functionBody == scriptFunction->GetFunctionBody());
  6571. this->function = scriptFunction;
  6572. }
  6573. DWORD_PTR InterpreterStackFrame::GetStackAddress() const
  6574. {
  6575. return m_stackAddress;
  6576. }
  6577. void* InterpreterStackFrame::GetAddressOfReturnAddress() const
  6578. {
  6579. return this->addressOfReturnAddress;
  6580. }
  6581. template <class T>
  6582. const byte * InterpreterStackFrame::OP_Br(const unaligned T * playout)
  6583. {
  6584. return m_reader.SetCurrentRelativeOffset((const byte *)(playout + 1), playout->RelativeJumpOffset);
  6585. }
  6586. template <class T>
  6587. void InterpreterStackFrame::OP_InitClass(const unaligned OpLayoutT_Class<T> * playout)
  6588. {
  6589. JavascriptOperators::OP_InitClass(GetReg(playout->Constructor), playout->Extends != Js::Constants::NoRegister ? GetReg(playout->Extends) : NULL, GetScriptContext());
  6590. }
  6591. template <class T>
  6592. void InterpreterStackFrame::OP_EmitTmpRegCount(const unaligned OpLayoutT_Unsigned1<T> * playout)
  6593. {
  6594. this->scriptContext->GetDebugContext()->GetProbeContainer()->SetCurrentTmpRegCount(playout->C1);
  6595. }
  6596. Var InterpreterStackFrame::OP_LdHomeObj(ScriptContext * scriptContext)
  6597. {
  6598. return JavascriptOperators::OP_LdHomeObj(function, scriptContext);
  6599. }
  6600. Var InterpreterStackFrame::OP_LdFuncObj(ScriptContext * scriptContext)
  6601. {
  6602. return JavascriptOperators::OP_LdFuncObj(function, scriptContext);
  6603. }
  6604. Var InterpreterStackFrame::OP_ScopedLdHomeObj(ScriptContext * scriptContext)
  6605. {
  6606. return JavascriptOperators::OP_ScopedLdHomeObj(function, scriptContext);
  6607. }
  6608. Var InterpreterStackFrame::OP_ScopedLdFuncObj(ScriptContext * scriptContext)
  6609. {
  6610. return JavascriptOperators::OP_ScopedLdFuncObj(function, scriptContext);
  6611. }
  6612. void InterpreterStackFrame::ValidateRegValue(Var value, bool allowStackVar, bool allowStackVarOnDisabledStackNestedFunc) const
  6613. {
  6614. #if DBG
  6615. if (value != nullptr && !TaggedNumber::Is(value))
  6616. {
  6617. if (!allowStackVar || !this->m_functionBody->DoStackNestedFunc())
  6618. {
  6619. Assert(!ThreadContext::IsOnStack(value)
  6620. || (allowStackVar && allowStackVarOnDisabledStackNestedFunc && StackScriptFunction::IsBoxed(value)));
  6621. }
  6622. Assert(!CrossSite::NeedMarshalVar(value, GetScriptContext()));
  6623. }
  6624. #endif
  6625. }
  6626. template <typename RegSlotType>
  6627. Var InterpreterStackFrame::GetReg(RegSlotType localRegisterID) const
  6628. {
  6629. Var value = m_localSlots[localRegisterID];
  6630. ValidateRegValue(value);
  6631. return value;
  6632. }
  6633. template <typename RegSlotType>
  6634. void InterpreterStackFrame::SetReg(RegSlotType localRegisterID, Var value)
  6635. {
  6636. Assert(localRegisterID == 0 || localRegisterID >= m_functionBody->GetConstantCount());
  6637. ValidateRegValue(value);
  6638. m_localSlots[localRegisterID] = value;
  6639. #if ENABLE_OBJECT_SOURCE_TRACKING
  6640. if(value != nullptr && DynamicType::Is(Js::JavascriptOperators::GetTypeId(value)))
  6641. {
  6642. static_cast<DynamicObject*>(value)->SetDiagOriginInfoAsNeeded();
  6643. }
  6644. #endif
  6645. #if ENABLE_VALUE_TRACE
  6646. if(this->function->GetScriptContext()->ShouldPerformRecordOrReplayAction())
  6647. {
  6648. this->function->GetScriptContext()->GetThreadContext()->TTDLog->GetTraceLogger()->WriteTraceValue(value);
  6649. }
  6650. #endif
  6651. }
  6652. template <typename T>
  6653. T InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
  6654. {
  6655. return (T)m_localIntSlots[localRegisterID];
  6656. }
  6657. // specialized version for doubles
  6658. template <>
  6659. double InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
  6660. {
  6661. return (double)m_localDoubleSlots[localRegisterID];
  6662. }
  6663. template <>
  6664. float InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
  6665. {
  6666. return (float)m_localFloatSlots[localRegisterID];
  6667. }
  6668. template <>
  6669. int64 InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
  6670. {
  6671. return m_localInt64Slots[localRegisterID];
  6672. }
  6673. template <typename T>
  6674. void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, T bValue)
  6675. {
  6676. m_localIntSlots[localRegisterID] = (int)bValue;
  6677. }
  6678. template <>
  6679. void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, float bValue)
  6680. {
  6681. m_localFloatSlots[localRegisterID] = (float)bValue;
  6682. }
  6683. template <>
  6684. void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, double bValue)
  6685. {
  6686. m_localDoubleSlots[localRegisterID] = bValue;
  6687. }
  6688. template <>
  6689. void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, int64 bValue)
  6690. {
  6691. m_localInt64Slots[localRegisterID] = bValue;
  6692. }
  6693. template <typename RegSlotType>
  6694. int InterpreterStackFrame::GetRegRawInt(RegSlotType localRegisterID) const
  6695. {
  6696. return m_localIntSlots[localRegisterID];
  6697. }
  6698. template <typename RegSlotType>
  6699. double InterpreterStackFrame::GetRegRawDouble(RegSlotType localRegisterID) const
  6700. {
  6701. return m_localDoubleSlots[localRegisterID];
  6702. }
  6703. template <typename RegSlotType>
  6704. float InterpreterStackFrame::GetRegRawFloat(RegSlotType localRegisterID) const
  6705. {
  6706. return m_localFloatSlots[localRegisterID];
  6707. }
  6708. template <typename RegSlotType>
  6709. void InterpreterStackFrame::SetRegRawInt(RegSlotType localRegisterID, int bValue)
  6710. {
  6711. m_localIntSlots[localRegisterID] = bValue;
  6712. }
  6713. template <typename RegSlotType>
  6714. int64 InterpreterStackFrame::GetRegRawInt64(RegSlotType localRegisterID) const
  6715. {
  6716. return m_localInt64Slots[localRegisterID];
  6717. }
  6718. template <typename RegSlotType>
  6719. void InterpreterStackFrame::SetRegRawInt64(RegSlotType localRegisterID, int64 bValue)
  6720. {
  6721. m_localInt64Slots[localRegisterID] = bValue;
  6722. }
  6723. template <typename RegSlotType>
  6724. void InterpreterStackFrame::SetRegRawDouble(RegSlotType localRegisterID, double bValue)
  6725. {
  6726. m_localDoubleSlots[localRegisterID] = bValue;
  6727. }
  6728. template <typename RegSlotType>
  6729. void InterpreterStackFrame::SetRegRawFloat(RegSlotType localRegisterID, float bValue)
  6730. {
  6731. m_localFloatSlots[localRegisterID] = bValue;
  6732. }
  6733. template <typename RegSlotType>
  6734. Var InterpreterStackFrame::GetRegAllowStackVar(RegSlotType localRegisterID) const
  6735. {
  6736. Var value = m_localSlots[localRegisterID];
  6737. ValidateRegValue(value, true);
  6738. return value;
  6739. }
  6740. template <typename RegSlotType>
  6741. void InterpreterStackFrame::SetRegAllowStackVar(RegSlotType localRegisterID, Var value)
  6742. {
  6743. Assert(localRegisterID == 0 || localRegisterID >= m_functionBody->GetConstantCount());
  6744. ValidateRegValue(value, true);
  6745. m_localSlots[localRegisterID] = value;
  6746. #if ENABLE_OBJECT_SOURCE_TRACKING
  6747. if(value != nullptr && DynamicType::Is(Js::JavascriptOperators::GetTypeId(value)))
  6748. {
  6749. static_cast<DynamicObject*>(value)->SetDiagOriginInfoAsNeeded();
  6750. }
  6751. #endif
  6752. #if ENABLE_VALUE_TRACE
  6753. if(this->function->GetScriptContext()->ShouldPerformRecordOrReplayAction())
  6754. {
  6755. this->function->GetScriptContext()->GetThreadContext()->TTDLog->GetTraceLogger()->WriteTraceValue(value);
  6756. }
  6757. #endif
  6758. }
  6759. template <typename RegSlotType>
  6760. Var InterpreterStackFrame::GetRegAllowStackVarEnableOnly(RegSlotType localRegisterID) const
  6761. {
  6762. Var value = m_localSlots[localRegisterID];
  6763. ValidateRegValue(value, true, false);
  6764. return value;
  6765. }
  6766. template <typename RegSlotType>
  6767. void InterpreterStackFrame::SetRegAllowStackVarEnableOnly(RegSlotType localRegisterID, Var value)
  6768. {
  6769. Assert(localRegisterID == 0 || localRegisterID >= m_functionBody->GetConstantCount());
  6770. ValidateRegValue(value, true, false);
  6771. m_localSlots[localRegisterID] = value;
  6772. #if ENABLE_OBJECT_SOURCE_TRACKING
  6773. if(value != nullptr && DynamicType::Is(Js::JavascriptOperators::GetTypeId(value)))
  6774. {
  6775. static_cast<DynamicObject*>(value)->SetDiagOriginInfoAsNeeded();
  6776. }
  6777. #endif
  6778. #if ENABLE_VALUE_TRACE
  6779. if(this->function->GetScriptContext()->ShouldPerformRecordOrReplayAction())
  6780. {
  6781. this->function->GetScriptContext()->GetThreadContext()->TTDLog->GetTraceLogger()->WriteTraceValue(value);
  6782. }
  6783. #endif
  6784. }
  6785. template <>
  6786. AsmJsSIMDValue InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
  6787. {
  6788. return (AsmJsSIMDValue)m_localSimdSlots[localRegisterID];
  6789. }
  6790. template<>
  6791. void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, AsmJsSIMDValue bValue)
  6792. {
  6793. m_localSimdSlots[localRegisterID] = bValue;
  6794. }
  6795. template <typename RegSlotType>
  6796. AsmJsSIMDValue InterpreterStackFrame::GetRegRawSimd(RegSlotType localRegisterID) const
  6797. {
  6798. return m_localSimdSlots[localRegisterID];
  6799. }
  6800. template <typename RegSlotType>
  6801. void InterpreterStackFrame::SetRegRawSimd(RegSlotType localRegisterID, AsmJsSIMDValue bValue)
  6802. {
  6803. m_localSimdSlots[localRegisterID] = bValue;
  6804. }
  6805. int InterpreterStackFrame::OP_GetMemorySize()
  6806. {
  6807. #ifdef ASMJS_PLAT
  6808. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  6809. return arr ? arr->GetByteLength() >> 16 : 0;
  6810. #else
  6811. return 0;
  6812. #endif
  6813. }
  6814. int InterpreterStackFrame::OP_GrowMemory(int32 delta)
  6815. {
  6816. #ifdef ENABLE_WASM
  6817. int32 oldPageCount = m_wasmMemory->GrowInternal((uint32)delta);
  6818. SetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister, m_wasmMemory->GetBuffer());
  6819. return oldPageCount;
  6820. #else
  6821. Assert(UNREACHED);
  6822. return 0;
  6823. #endif
  6824. }
  6825. template <typename T, InterpreterStackFrame::AsmJsMathPtr<T> func> T InterpreterStackFrame::OP_DivRemCheck(T aLeft, T aRight, ScriptContext* scriptContext)
  6826. {
  6827. if (aRight == 0)
  6828. {
  6829. JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, WASMERR_DivideByZero);
  6830. }
  6831. return func(aLeft, aRight);
  6832. }
  6833. template <typename T, InterpreterStackFrame::AsmJsMathPtr<T> func, T MIN> T InterpreterStackFrame::OP_DivOverflow(T aLeft, T aRight, ScriptContext* scriptContext)
  6834. {
  6835. if (aRight == 0)
  6836. {
  6837. JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, WASMERR_DivideByZero);
  6838. }
  6839. if (aLeft == MIN && aRight == -1)
  6840. {
  6841. JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, VBSERR_Overflow);
  6842. }
  6843. return func(aLeft, aRight);
  6844. }
  6845. void InterpreterStackFrame::OP_Unreachable()
  6846. {
  6847. JavascriptError::ThrowUnreachable(scriptContext);
  6848. }
  6849. template <class T>
  6850. void InterpreterStackFrame::OP_SimdLdArrGeneric(const unaligned T* playout)
  6851. {
  6852. Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
  6853. const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex) & ArrayBufferView::ViewMask[playout->ViewType];
  6854. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  6855. BYTE* buffer = arr->GetBuffer();
  6856. uint8 dataWidth = playout->DataWidth;
  6857. RegSlot dstReg = playout->Value;
  6858. if (index < 0 || index + dataWidth > arr->GetByteLength())
  6859. {
  6860. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, _u("Simd typed array access"));
  6861. }
  6862. AsmJsSIMDValue *data = (AsmJsSIMDValue*)(buffer + index);
  6863. AsmJsSIMDValue value;
  6864. value = SIMDUtils::SIMDLdData(data, dataWidth);
  6865. SetRegRawSimd(dstReg, value);
  6866. }
  6867. template <class T>
  6868. void InterpreterStackFrame::OP_SimdLdArrConstIndex(const unaligned T* playout)
  6869. {
  6870. Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
  6871. const uint32 index = playout->SlotIndex;
  6872. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  6873. BYTE* buffer = arr->GetBuffer();
  6874. uint8 dataWidth = playout->DataWidth;
  6875. RegSlot dstReg = playout->Value;
  6876. if (index < 0 || index + dataWidth > arr->GetByteLength())
  6877. {
  6878. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, _u("Simd typed array access"));
  6879. }
  6880. AsmJsSIMDValue *data = (AsmJsSIMDValue*)(buffer + index);
  6881. AsmJsSIMDValue value;
  6882. value = SIMDUtils::SIMDLdData(data, dataWidth);
  6883. SetRegRawSimd(dstReg, value);
  6884. }
  6885. template <class T>
  6886. void InterpreterStackFrame::OP_SimdStArrGeneric(const unaligned T* playout)
  6887. {
  6888. Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
  6889. const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex) & ArrayBufferView::ViewMask[playout->ViewType];
  6890. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  6891. BYTE* buffer = arr->GetBuffer();
  6892. uint8 dataWidth = playout->DataWidth;
  6893. RegSlot srcReg = playout->Value;
  6894. if (index < 0 || index + dataWidth > arr->GetByteLength())
  6895. {
  6896. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, _u("Simd typed array access"));
  6897. }
  6898. AsmJsSIMDValue *data = (AsmJsSIMDValue*)(buffer + index);
  6899. AsmJsSIMDValue value = GetRegRawSimd(srcReg);
  6900. SIMDUtils::SIMDStData(data, value, dataWidth);
  6901. }
  6902. template <class T>
  6903. void InterpreterStackFrame::OP_SimdStArrConstIndex(const unaligned T* playout)
  6904. {
  6905. Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
  6906. const uint32 index = playout->SlotIndex;
  6907. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  6908. BYTE* buffer = arr->GetBuffer();
  6909. uint8 dataWidth = playout->DataWidth;
  6910. RegSlot srcReg = playout->Value;
  6911. if (index < 0 || index + dataWidth > arr->GetByteLength())
  6912. {
  6913. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, _u("Simd typed array access"));
  6914. }
  6915. AsmJsSIMDValue *data = (AsmJsSIMDValue*)(buffer + index);
  6916. AsmJsSIMDValue value = GetRegRawSimd(srcReg);
  6917. SIMDUtils::SIMDStData(data, value, dataWidth);
  6918. }
  6919. // handler for SIMD.Int32x4.FromFloat32x4
  6920. template <class T>
  6921. void InterpreterStackFrame::OP_SimdInt32x4FromFloat32x4(const unaligned T* playout)
  6922. {
  6923. bool throws = false;
  6924. AsmJsSIMDValue input = GetRegRawSimd(playout->F4_1);
  6925. AsmJsSIMDValue result = SIMDInt32x4Operation::OpFromFloat32x4(input, throws);
  6926. // value is out of bound
  6927. if (throws)
  6928. {
  6929. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, _u("SIMD.Int32x4.FromFloat32x4"));
  6930. }
  6931. SetRegRawSimd(playout->I4_0, result);
  6932. }
  6933. // handler for SIMD.Uint32x4.FromFloat32x4
  6934. template <class T>
  6935. void InterpreterStackFrame::OP_SimdUint32x4FromFloat32x4(const unaligned T* playout)
  6936. {
  6937. bool throws = false;
  6938. AsmJsSIMDValue input = GetRegRawSimd(playout->F4_1);
  6939. AsmJsSIMDValue result = SIMDUint32x4Operation::OpFromFloat32x4(input, throws);
  6940. // value is out of bound
  6941. if (throws)
  6942. {
  6943. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, _u("SIMD.Int32x4.FromFloat32x4"));
  6944. }
  6945. SetRegRawSimd(playout->U4_0, result);
  6946. }
  6947. template <class T>
  6948. void InterpreterStackFrame::OP_SimdInt16x8(const unaligned T* playout)
  6949. {
  6950. int16 values[8];
  6951. values[0] = (int16) GetRegRawInt(playout->I1);
  6952. values[1] = (int16) GetRegRawInt(playout->I2);
  6953. values[2] = (int16) GetRegRawInt(playout->I3);
  6954. values[3] = (int16) GetRegRawInt(playout->I4);
  6955. values[4] = (int16) GetRegRawInt(playout->I5);
  6956. values[5] = (int16) GetRegRawInt(playout->I6);
  6957. values[6] = (int16) GetRegRawInt(playout->I7);
  6958. values[7] = (int16) GetRegRawInt(playout->I8);
  6959. AsmJsSIMDValue result = SIMDInt16x8Operation::OpInt16x8(values);
  6960. SetRegRawSimd(playout->I8_0, result);
  6961. }
  6962. template <class T>
  6963. void InterpreterStackFrame::OP_SimdInt8x16(const unaligned T* playout)
  6964. {
  6965. int8 values[16];
  6966. values[0] = (int8)GetRegRawInt(playout->I1);
  6967. values[1] = (int8)GetRegRawInt(playout->I2);
  6968. values[2] = (int8)GetRegRawInt(playout->I3);
  6969. values[3] = (int8)GetRegRawInt(playout->I4);
  6970. values[4] = (int8)GetRegRawInt(playout->I5);
  6971. values[5] = (int8)GetRegRawInt(playout->I6);
  6972. values[6] = (int8)GetRegRawInt(playout->I7);
  6973. values[7] = (int8)GetRegRawInt(playout->I8);
  6974. values[8] = (int8)GetRegRawInt(playout->I9);
  6975. values[9] = (int8)GetRegRawInt(playout->I10);
  6976. values[10] = (int8)GetRegRawInt(playout->I11);
  6977. values[11] = (int8)GetRegRawInt(playout->I12);
  6978. values[12] = (int8)GetRegRawInt(playout->I13);
  6979. values[13] = (int8)GetRegRawInt(playout->I14);
  6980. values[14] = (int8)GetRegRawInt(playout->I15);
  6981. values[15] = (int8)GetRegRawInt(playout->I16);
  6982. AsmJsSIMDValue result = SIMDInt8x16Operation::OpInt8x16(values);
  6983. SetRegRawSimd(playout->I16_0, result);
  6984. }
  6985. template <class T>
  6986. void InterpreterStackFrame::OP_SimdUint16x8(const unaligned T* playout)
  6987. {
  6988. uint16 values[8];
  6989. values[0] = (uint16) GetRegRawInt(playout->I1);
  6990. values[1] = (uint16) GetRegRawInt(playout->I2);
  6991. values[2] = (uint16) GetRegRawInt(playout->I3);
  6992. values[3] = (uint16) GetRegRawInt(playout->I4);
  6993. values[4] = (uint16) GetRegRawInt(playout->I5);
  6994. values[5] = (uint16) GetRegRawInt(playout->I6);
  6995. values[6] = (uint16) GetRegRawInt(playout->I7);
  6996. values[7] = (uint16) GetRegRawInt(playout->I8);
  6997. AsmJsSIMDValue result = SIMDUint16x8Operation::OpUint16x8(values);
  6998. SetRegRawSimd(playout->U8_0, result);
  6999. }
  7000. template <class T>
  7001. void InterpreterStackFrame::OP_SimdUint8x16(const unaligned T* playout)
  7002. {
  7003. uint8 values[16];
  7004. values[0] = (uint8) GetRegRawInt(playout->I1);
  7005. values[1] = (uint8) GetRegRawInt(playout->I2);
  7006. values[2] = (uint8) GetRegRawInt(playout->I3);
  7007. values[3] = (uint8) GetRegRawInt(playout->I4);
  7008. values[4] = (uint8) GetRegRawInt(playout->I5);
  7009. values[5] = (uint8) GetRegRawInt(playout->I6);
  7010. values[6] = (uint8) GetRegRawInt(playout->I7);
  7011. values[7] = (uint8) GetRegRawInt(playout->I8);
  7012. values[8] = (uint8) GetRegRawInt(playout->I9);
  7013. values[9] = (uint8) GetRegRawInt(playout->I10);
  7014. values[10] = (uint8) GetRegRawInt(playout->I11);
  7015. values[11] = (uint8) GetRegRawInt(playout->I12);
  7016. values[12] = (uint8) GetRegRawInt(playout->I13);
  7017. values[13] = (uint8) GetRegRawInt(playout->I14);
  7018. values[14] = (uint8) GetRegRawInt(playout->I15);
  7019. values[15] = (uint8) GetRegRawInt(playout->I16);
  7020. AsmJsSIMDValue result = SIMDUint8x16Operation::OpUint8x16(values);
  7021. SetRegRawSimd(playout->U16_0, result);
  7022. }
  7023. // Bool constructors
  7024. template <class T>
  7025. void InterpreterStackFrame::OP_SimdBool32x4(const unaligned T* playout)
  7026. {
  7027. bool arg1 = GetRegRawInt(playout->I1) ? true : false;
  7028. bool arg2 = GetRegRawInt(playout->I2) ? true : false;
  7029. bool arg3 = GetRegRawInt(playout->I3) ? true : false;
  7030. bool arg4 = GetRegRawInt(playout->I4) ? true : false;
  7031. AsmJsSIMDValue result = SIMDBool32x4Operation::OpBool32x4(arg1, arg2, arg3, arg4);
  7032. SetRegRawSimd(playout->B4_0, result);
  7033. }
  7034. template <class T>
  7035. void InterpreterStackFrame::OP_SimdBool16x8(const unaligned T* playout)
  7036. {
  7037. bool values[8];
  7038. values[0] = GetRegRawInt(playout->I1) ? true : false;
  7039. values[1] = GetRegRawInt(playout->I2) ? true : false;
  7040. values[2] = GetRegRawInt(playout->I3) ? true : false;
  7041. values[3] = GetRegRawInt(playout->I4) ? true : false;
  7042. values[4] = GetRegRawInt(playout->I5) ? true : false;
  7043. values[5] = GetRegRawInt(playout->I6) ? true : false;
  7044. values[6] = GetRegRawInt(playout->I7) ? true : false;
  7045. values[7] = GetRegRawInt(playout->I8) ? true : false;
  7046. AsmJsSIMDValue result = SIMDBool16x8Operation::OpBool16x8(values);
  7047. SetRegRawSimd(playout->B8_0, result);
  7048. }
  7049. template <class T>
  7050. void InterpreterStackFrame::OP_SimdBool8x16(const unaligned T* playout)
  7051. {
  7052. bool values[16];
  7053. values[0] = GetRegRawInt(playout->I1) ? true : false;
  7054. values[1] = GetRegRawInt(playout->I2) ? true : false;
  7055. values[2] = GetRegRawInt(playout->I3) ? true : false;
  7056. values[3] = GetRegRawInt(playout->I4) ? true : false;
  7057. values[4] = GetRegRawInt(playout->I5) ? true : false;
  7058. values[5] = GetRegRawInt(playout->I6) ? true : false;
  7059. values[6] = GetRegRawInt(playout->I7) ? true : false;
  7060. values[7] = GetRegRawInt(playout->I8) ? true : false;
  7061. values[8] = GetRegRawInt(playout->I9) ? true : false;
  7062. values[9] = GetRegRawInt(playout->I10) ? true : false;
  7063. values[10] = GetRegRawInt(playout->I11) ? true : false;
  7064. values[11] = GetRegRawInt(playout->I12) ? true : false;
  7065. values[12] = GetRegRawInt(playout->I13) ? true : false;
  7066. values[13] = GetRegRawInt(playout->I14) ? true : false;
  7067. values[14] = GetRegRawInt(playout->I15) ? true : false;
  7068. values[15] = GetRegRawInt(playout->I16) ? true : false;
  7069. AsmJsSIMDValue result = SIMDBool8x16Operation::OpBool8x16(values);
  7070. SetRegRawSimd(playout->B16_0, result);
  7071. }
  7072. Var InterpreterStackFrame::GetNonVarReg(RegSlot localRegisterID) const
  7073. {
  7074. return m_localSlots[localRegisterID];
  7075. }
  7076. void InterpreterStackFrame::SetNonVarReg(RegSlot localRegisterID, Var aValue)
  7077. {
  7078. m_localSlots[localRegisterID] = aValue;
  7079. }
  7080. Var InterpreterStackFrame::GetRootObject() const
  7081. {
  7082. Var rootObject = GetReg(Js::FunctionBody::RootObjectRegSlot);
  7083. Assert(rootObject == this->GetFunctionBody()->LoadRootObject());
  7084. return rootObject;
  7085. }
  7086. Var InterpreterStackFrame::OP_ArgIn0()
  7087. {
  7088. return m_inParams[0];
  7089. }
  7090. #if ENABLE_PROFILE_INFO
  7091. template <class T>
  7092. void InterpreterStackFrame::OP_ProfiledArgOut_A(const unaligned T * playout)
  7093. {
  7094. FunctionBody* functionBody = this->m_functionBody;
  7095. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  7096. Assert(playout->Reg > FunctionBody::FirstRegSlot && playout->Reg < functionBody->GetConstantCount());
  7097. Var value = GetReg(playout->Reg);
  7098. if (value != nullptr && TaggedInt::Is(value))
  7099. {
  7100. dynamicProfileInfo->RecordConstParameterAtCallSite(playout->profileId, playout->Arg);
  7101. }
  7102. SetOut(playout->Arg, GetReg(playout->Reg));
  7103. }
  7104. #endif
  7105. template <class T>
  7106. void InterpreterStackFrame::OP_ArgOut_A(const unaligned T * playout)
  7107. {
  7108. SetOut(playout->Arg, GetReg(playout->Reg));
  7109. }
  7110. #if DBG
  7111. template <class T>
  7112. void InterpreterStackFrame::OP_ArgOut_ANonVar(const unaligned T * playout)
  7113. {
  7114. SetOut(playout->Arg, GetNonVarReg(playout->Reg));
  7115. }
  7116. #endif
  7117. template <class T>
  7118. void InterpreterStackFrame::OP_ArgOut_Env(const unaligned T * playout)
  7119. {
  7120. Var argEnv;
  7121. if (this->m_functionBody->GetLocalFrameDisplayRegister() != Constants::NoRegister)
  7122. {
  7123. argEnv = this->GetLocalFrameDisplay();
  7124. }
  7125. else
  7126. {
  7127. argEnv = this->LdEnv();
  7128. }
  7129. SetOut(playout->Arg, argEnv);
  7130. }
  7131. BOOL InterpreterStackFrame::OP_BrFalse_A(Var aValue, ScriptContext* scriptContext)
  7132. {
  7133. return !JavascriptConversion::ToBoolean(aValue, scriptContext);
  7134. }
  7135. BOOL InterpreterStackFrame::OP_BrTrue_A(Var aValue, ScriptContext* scriptContext)
  7136. {
  7137. return JavascriptConversion::ToBoolean(aValue, scriptContext);
  7138. }
  7139. BOOL InterpreterStackFrame::OP_BrNotNull_A(Var aValue)
  7140. {
  7141. return aValue != NULL;
  7142. }
  7143. BOOL InterpreterStackFrame::OP_BrUndecl_A(Var aValue)
  7144. {
  7145. return this->scriptContext->GetLibrary()->IsUndeclBlockVar(aValue);
  7146. }
  7147. BOOL InterpreterStackFrame::OP_BrNotUndecl_A(Var aValue)
  7148. {
  7149. return !this->scriptContext->GetLibrary()->IsUndeclBlockVar(aValue);
  7150. }
  7151. BOOL InterpreterStackFrame::OP_BrOnHasProperty(Var argInstance, uint propertyIdIndex, ScriptContext* scriptContext)
  7152. {
  7153. return JavascriptOperators::OP_HasProperty(argInstance,
  7154. this->m_functionBody->GetReferencedPropertyId(propertyIdIndex), scriptContext);
  7155. }
  7156. BOOL InterpreterStackFrame::OP_BrOnNoProperty(Var argInstance, uint propertyIdIndex, ScriptContext* scriptContext)
  7157. {
  7158. return !JavascriptOperators::OP_HasProperty(argInstance,
  7159. this->m_functionBody->GetReferencedPropertyId(propertyIdIndex), scriptContext);
  7160. }
  7161. BOOL InterpreterStackFrame::OP_BrOnNoEnvProperty(Var envInstance, int32 slotIndex, uint propertyIdIndex, ScriptContext* scriptContext)
  7162. {
  7163. Var instance = OP_LdFrameDisplaySlot(envInstance, slotIndex);
  7164. return !JavascriptOperators::OP_HasProperty(instance,
  7165. this->m_functionBody->GetReferencedPropertyId(propertyIdIndex), scriptContext);
  7166. }
  7167. BOOL InterpreterStackFrame::OP_BrOnClassConstructor(Var aValue)
  7168. {
  7169. return JavascriptOperators::IsClassConstructor(aValue);
  7170. }
  7171. template<class T>
  7172. void InterpreterStackFrame::OP_LdLen(const unaligned T * const playout)
  7173. {
  7174. Assert(playout);
  7175. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  7176. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  7177. threadContext->ClearImplicitCallFlags();
  7178. const auto instance = GetReg(playout->R1);
  7179. Var length = JavascriptOperators::OP_GetLength(instance, GetScriptContext());
  7180. threadContext->CheckAndResetImplicitCallAccessorFlag();
  7181. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  7182. SetReg(playout->R0, length);
  7183. }
  7184. #if ENABLE_PROFILE_INFO
  7185. template<class T>
  7186. void InterpreterStackFrame::OP_ProfiledLdLen(const unaligned OpLayoutDynamicProfile<T> *const playout)
  7187. {
  7188. Assert(playout);
  7189. const auto functionBody = m_functionBody;
  7190. const auto profileData = functionBody->GetDynamicProfileInfo();
  7191. const auto instance = GetReg(playout->R1);
  7192. LdElemInfo ldElemInfo;
  7193. ldElemInfo.arrayType = ValueType::Uninitialized.Merge(instance);
  7194. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  7195. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  7196. threadContext->ClearImplicitCallFlags();
  7197. Var length = JavascriptOperators::OP_GetLength(instance, GetScriptContext());
  7198. threadContext->CheckAndResetImplicitCallAccessorFlag();
  7199. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  7200. ldElemInfo.elemType = ldElemInfo.elemType.Merge(length);
  7201. profileData->RecordElementLoad(functionBody, playout->profileId, ldElemInfo);
  7202. SetReg(playout->R0, length);
  7203. }
  7204. #endif
  7205. Var InterpreterStackFrame::GetFunctionExpression()
  7206. {
  7207. // Make sure we get the boxed function object if is there, (or the function itself)
  7208. return StackScriptFunction::GetCurrentFunctionObject(this->function->GetRealFunctionObject());
  7209. }
  7210. template <class T>
  7211. void InterpreterStackFrame::OP_LdFunctionExpression(const unaligned T * playout)
  7212. {
  7213. SetRegAllowStackVar(playout->R0, this->GetFunctionExpression());
  7214. }
  7215. template <class T>
  7216. void InterpreterStackFrame::OP_StFunctionExpression(const unaligned T * playout)
  7217. {
  7218. OP_StFunctionExpression(GetReg(playout->Instance), GetReg(playout->Value), playout->PropertyIdIndex);
  7219. }
  7220. template <class T>
  7221. void InterpreterStackFrame::OP_StLocalFunctionExpression(const unaligned T * playout)
  7222. {
  7223. OP_StFunctionExpression(this->localClosure, GetReg(playout->Instance), playout->PropertyIdIndex);
  7224. }
  7225. void InterpreterStackFrame::OP_StFunctionExpression(Var instance, Var value, PropertyIdIndexType index)
  7226. {
  7227. JavascriptOperators::OP_StFunctionExpression(instance,
  7228. this->m_functionBody->GetReferencedPropertyId(index), value);
  7229. }
  7230. template <class T>
  7231. void InterpreterStackFrame::OP_LdNewTarget(const unaligned T* playout)
  7232. {
  7233. if (this->m_callFlags & CallFlags_NewTarget)
  7234. {
  7235. SetRegAllowStackVar(playout->R0, (Js::RecyclableObject*)this->m_inParams[this->m_inSlotsCount]);
  7236. }
  7237. else if (this->m_callFlags & CallFlags_New)
  7238. {
  7239. SetRegAllowStackVar(playout->R0, this->GetFunctionExpression());
  7240. }
  7241. else
  7242. {
  7243. SetReg(playout->R0, this->GetScriptContext()->GetLibrary()->GetUndefined());
  7244. }
  7245. }
  7246. Var InterpreterStackFrame::OP_Ld_A(Var aValue)
  7247. {
  7248. return aValue;
  7249. }
  7250. Var InterpreterStackFrame::LdEnv() const
  7251. {
  7252. return this->function->GetEnvironment();
  7253. }
  7254. void InterpreterStackFrame::SetEnv(FrameDisplay *frameDisplay)
  7255. {
  7256. this->function->SetEnvironment(frameDisplay);
  7257. }
  7258. Var InterpreterStackFrame::OP_LdLocalObj()
  7259. {
  7260. if (!VirtualTableInfo<ActivationObject>::HasVirtualTable(this->localClosure) &&
  7261. !VirtualTableInfo<ActivationObjectEx>::HasVirtualTable(this->localClosure))
  7262. {
  7263. Js::Throw::FatalInternalError();
  7264. }
  7265. return this->localClosure;
  7266. }
  7267. #ifdef ASMJS_PLAT
  7268. template <typename ArrayType, typename RegType>
  7269. void InterpreterStackFrame::OP_StArr(uint32 index, RegSlot regSlot)
  7270. {
  7271. CompileAssert(Js::ArrayBufferView::TYPE_COUNT == (sizeof(InterpreterStackFrame::StArrFunc) / sizeof(InterpreterStackFrame::ArrFunc)));
  7272. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  7273. if (index < arr->GetByteLength())
  7274. {
  7275. BYTE* buffer = arr->GetBuffer();
  7276. *(ArrayType*)(buffer + index) = (ArrayType)GetRegRaw<RegType>(regSlot);
  7277. }
  7278. }
  7279. #endif
  7280. template<> inline double InterpreterStackFrame::GetArrayViewOverflowVal()
  7281. {
  7282. return *(double*)&NumberConstants::k_Nan;
  7283. }
  7284. template<> inline float InterpreterStackFrame::GetArrayViewOverflowVal()
  7285. {
  7286. return (float)*(double*)&NumberConstants::k_Nan;
  7287. }
  7288. template<typename T> T InterpreterStackFrame::GetArrayViewOverflowVal()
  7289. {
  7290. return 0;
  7291. }
  7292. template <class T>
  7293. void InterpreterStackFrame::OP_LdArrFunc(const unaligned T* playout)
  7294. {
  7295. Var* arr = (Var*)GetNonVarReg(playout->Instance);
  7296. const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex);
  7297. m_localSlots[playout->Value] = arr[index];
  7298. }
  7299. template <class T>
  7300. void InterpreterStackFrame::OP_LdArrWasmFunc(const unaligned T* playout)
  7301. {
  7302. #ifdef ENABLE_WASM
  7303. WebAssemblyTable * table = WebAssemblyTable::FromVar(GetNonVarReg(playout->Instance));
  7304. const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex);
  7305. if (index >= table->GetCurrentLength())
  7306. {
  7307. JavascriptError::ThrowWebAssemblyRuntimeError(GetScriptContext(), WASMERR_TableIndexOutOfRange);
  7308. }
  7309. Var func = table->DirectGetValue(index);
  7310. if (!func)
  7311. {
  7312. JavascriptError::ThrowWebAssemblyRuntimeError(GetScriptContext(), WASMERR_NeedWebAssemblyFunc);
  7313. }
  7314. m_localSlots[playout->Value] = func;
  7315. #endif
  7316. }
  7317. template <class T>
  7318. void InterpreterStackFrame::OP_CheckSignature(const unaligned T* playout)
  7319. {
  7320. #ifdef ENABLE_WASM
  7321. ScriptFunction * func = ScriptFunction::FromVar(GetNonVarReg(playout->R0));
  7322. int sigIndex = playout->C1;
  7323. Wasm::WasmSignature * expected = &m_signatures[sigIndex];
  7324. if (func->GetFunctionInfo()->IsDeferredParseFunction())
  7325. {
  7326. // TODO: should be able to assert this once imports are converted to wasm functions
  7327. JavascriptError::ThrowWebAssemblyRuntimeError(GetScriptContext(), WASMERR_NeedWebAssemblyFunc);
  7328. }
  7329. AsmJsFunctionInfo * asmInfo = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  7330. if (!asmInfo)
  7331. {
  7332. // TODO: should be able to assert this once imports are converted to wasm functions
  7333. JavascriptError::ThrowWebAssemblyRuntimeError(GetScriptContext(), WASMERR_NeedWebAssemblyFunc);
  7334. }
  7335. if (!expected->IsEquivalent(asmInfo->GetWasmSignature()))
  7336. {
  7337. JavascriptError::ThrowWebAssemblyRuntimeError(GetScriptContext(), WASMERR_SignatureMismatch);
  7338. }
  7339. #endif
  7340. }
  7341. #ifdef ASMJS_PLAT
  7342. template <typename ArrayType, typename RegType>
  7343. void InterpreterStackFrame::OP_LdArr(uint32 index, RegSlot regSlot)
  7344. {
  7345. CompileAssert(Js::ArrayBufferView::TYPE_COUNT == (sizeof(InterpreterStackFrame::LdArrFunc) / sizeof(InterpreterStackFrame::ArrFunc)));
  7346. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  7347. BYTE* buffer = arr->GetBuffer();
  7348. ArrayType val = index < (arr->GetByteLength()) ? *(ArrayType*)(buffer + index) : GetArrayViewOverflowVal<ArrayType>();
  7349. SetRegRaw<RegType>(regSlot, (RegType)val);
  7350. }
  7351. #endif
  7352. template <class T, typename T2>
  7353. void InterpreterStackFrame::OP_StSlotPrimitive(const unaligned T* playout)
  7354. {
  7355. T2* buffer = (T2*)GetNonVarReg(playout->Instance);
  7356. buffer[playout->SlotIndex] = GetRegRaw<T2>(playout->Value);
  7357. }
  7358. template <class T>
  7359. Var InterpreterStackFrame::OP_LdAsmJsSlot(Var instance, const unaligned T* playout)
  7360. {
  7361. return ((Var*)instance)[playout->SlotIndex];
  7362. }
  7363. template <class T, typename T2>
  7364. void InterpreterStackFrame::OP_LdSlotPrimitive(const unaligned T* playout)
  7365. {
  7366. T2* buffer = (T2*)GetNonVarReg(playout->Instance);
  7367. SetRegRaw<T2>(playout->Value, buffer[playout->SlotIndex]);
  7368. }
  7369. #ifndef TEMP_DISABLE_ASMJS
  7370. template <class T>
  7371. void InterpreterStackFrame::OP_LdArrGeneric(const unaligned T* playout)
  7372. {
  7373. Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
  7374. const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex) & ArrayBufferView::ViewMask[playout->ViewType];
  7375. (this->*LdArrFunc[playout->ViewType])(index, playout->Value);
  7376. }
  7377. template <class T>
  7378. void InterpreterStackFrame::OP_LdArrWasm(const unaligned T* playout)
  7379. {
  7380. Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
  7381. const uint64 index = (uint64)GetRegRawInt64(playout->SlotIndex);
  7382. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  7383. if (index + TypeToSizeMap[playout->ViewType] > arr->GetByteLength())
  7384. {
  7385. JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, WASMERR_ArrayIndexOutOfRange);
  7386. }
  7387. BYTE* buffer = arr->GetBuffer();
  7388. switch (playout->ViewType)
  7389. {
  7390. case ArrayBufferView::ViewType::TYPE_INT8: SetRegRaw<int32>(playout->Value, (int32)*(int8*)(buffer + index)); return;
  7391. case ArrayBufferView::ViewType::TYPE_UINT8 : SetRegRaw<int32>(playout->Value, (int32)*(uint8*)(buffer + index)); return;
  7392. case ArrayBufferView::ViewType::TYPE_INT16 : SetRegRaw<int32>(playout->Value, (int32)*(int16*)(buffer + index)); return;
  7393. case ArrayBufferView::ViewType::TYPE_UINT16 : SetRegRaw<int32>(playout->Value, (int32)*(uint16*)(buffer + index)); return;
  7394. case ArrayBufferView::ViewType::TYPE_INT32 : SetRegRaw<int32>(playout->Value, (int32)*(int32*)(buffer + index)); return;
  7395. case ArrayBufferView::ViewType::TYPE_UINT32 : SetRegRaw<int32>(playout->Value, (int32)*(uint32*)(buffer + index)); return;
  7396. case ArrayBufferView::ViewType::TYPE_FLOAT32 : SetRegRaw<float>(playout->Value, (float)*(float*)(buffer + index)); return;
  7397. case ArrayBufferView::ViewType::TYPE_FLOAT64 : SetRegRaw<double>(playout->Value, (double)*(double*)(buffer + index)); return;
  7398. case ArrayBufferView::ViewType::TYPE_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(int64*)(buffer + index)); return;
  7399. case ArrayBufferView::ViewType::TYPE_INT8_TO_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(int8*)(buffer + index)); return;
  7400. case ArrayBufferView::ViewType::TYPE_UINT8_TO_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(uint8*)(buffer + index)); return;
  7401. case ArrayBufferView::ViewType::TYPE_INT16_TO_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(int16*)(buffer + index)); return;
  7402. case ArrayBufferView::ViewType::TYPE_UINT16_TO_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(uint16*)(buffer + index)); return;
  7403. case ArrayBufferView::ViewType::TYPE_INT32_TO_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(int32*)(buffer + index)); return;
  7404. case ArrayBufferView::ViewType::TYPE_UINT32_TO_INT64 : SetRegRaw<int64>(playout->Value, (int64)*(uint32*)(buffer + index)); return;
  7405. default:Assert(UNREACHED);
  7406. }
  7407. }
  7408. template <class T>
  7409. void InterpreterStackFrame::OP_LdArrConstIndex(const unaligned T* playout)
  7410. {
  7411. const uint32 index = playout->SlotIndex;
  7412. Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
  7413. (this->*LdArrFunc[playout->ViewType])(index, playout->Value);
  7414. }
  7415. template <class T>
  7416. void InterpreterStackFrame::OP_StArrGeneric(const unaligned T* playout)
  7417. {
  7418. Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
  7419. const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex) & ArrayBufferView::ViewMask[playout->ViewType];
  7420. (this->*StArrFunc[playout->ViewType])(index, playout->Value);
  7421. }
  7422. template <class T>
  7423. void InterpreterStackFrame::OP_StArrWasm(const unaligned T* playout)
  7424. {
  7425. Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
  7426. const uint64 index = (uint64)GetRegRawInt64(playout->SlotIndex);
  7427. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  7428. if (index + TypeToSizeMap[playout->ViewType] > arr->GetByteLength())
  7429. {
  7430. JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, WASMERR_ArrayIndexOutOfRange);
  7431. }
  7432. BYTE* buffer = arr->GetBuffer();
  7433. switch (playout->ViewType)
  7434. {
  7435. case ArrayBufferView::ViewType::TYPE_INT8: *(int8*)(buffer + index) = (int8) (GetRegRaw<int32>(playout->Value)); return;
  7436. case ArrayBufferView::ViewType::TYPE_UINT8: *(uint8*)(buffer + index) = (uint8) (GetRegRaw<int32>(playout->Value)); return;
  7437. case ArrayBufferView::ViewType::TYPE_INT16: *(int16*)(buffer + index) = (int16) (GetRegRaw<int32>(playout->Value)); return;
  7438. case ArrayBufferView::ViewType::TYPE_UINT16: *(uint16*)(buffer + index) = (uint16) (GetRegRaw<int32>(playout->Value)); return;
  7439. case ArrayBufferView::ViewType::TYPE_INT32: *(int32*)(buffer + index) = (int32) (GetRegRaw<int32>(playout->Value)); return;
  7440. case ArrayBufferView::ViewType::TYPE_UINT32: *(uint32*)(buffer + index) = (uint32) (GetRegRaw<int32>(playout->Value)); return;
  7441. case ArrayBufferView::ViewType::TYPE_FLOAT32: *(float*)(buffer + index) = (float) (GetRegRaw<float>(playout->Value)); return;
  7442. case ArrayBufferView::ViewType::TYPE_FLOAT64: *(double*)(buffer + index) = (double) (GetRegRaw<double>(playout->Value)); return;
  7443. case ArrayBufferView::ViewType::TYPE_INT64: *(int64*)(buffer + index) = (int64) (GetRegRaw<int64>(playout->Value)); return;
  7444. case ArrayBufferView::ViewType::TYPE_INT8_TO_INT64: *(int8*)(buffer + index) = (int8) (GetRegRaw<int64>(playout->Value)); return;
  7445. case ArrayBufferView::ViewType::TYPE_UINT8_TO_INT64: *(uint8*)(buffer + index) = (uint8) (GetRegRaw<int64>(playout->Value)); return;
  7446. case ArrayBufferView::ViewType::TYPE_INT16_TO_INT64: *(int16*)(buffer + index) = (int16) (GetRegRaw<int64>(playout->Value)); return;
  7447. case ArrayBufferView::ViewType::TYPE_UINT16_TO_INT64: *(uint16*)(buffer + index) = (uint16) (GetRegRaw<int64>(playout->Value)); return;
  7448. case ArrayBufferView::ViewType::TYPE_INT32_TO_INT64: *(int32*)(buffer + index) = (int32) (GetRegRaw<int64>(playout->Value)); return;
  7449. case ArrayBufferView::ViewType::TYPE_UINT32_TO_INT64: *(uint32*)(buffer + index) = (uint32) (GetRegRaw<int64>(playout->Value)); return;
  7450. default:Assert(UNREACHED);
  7451. }
  7452. }
  7453. template <class T>
  7454. void InterpreterStackFrame::OP_StArrConstIndex(const unaligned T* playout)
  7455. {
  7456. const uint32 index = playout->SlotIndex;
  7457. Assert(playout->ViewType < Js::ArrayBufferView::TYPE_COUNT);
  7458. (this->*StArrFunc[playout->ViewType])(index, playout->Value);
  7459. }
  7460. #endif
  7461. Var InterpreterStackFrame::OP_LdSlot(Var instance, int32 slotIndex)
  7462. {
  7463. if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
  7464. {
  7465. if ((uintptr_t)((Var*)instance)[ScopeSlots::EncodedSlotCountSlotIndex] <= (uintptr_t)(slotIndex - ScopeSlots::FirstSlotIndex))
  7466. {
  7467. Js::Throw::FatalInternalError();
  7468. }
  7469. }
  7470. return ((Var*)(instance))[slotIndex];
  7471. }
  7472. template <class T>
  7473. Var InterpreterStackFrame::OP_LdSlot(Var instance, const unaligned T* playout)
  7474. {
  7475. return OP_LdSlot(instance, playout->SlotIndex);
  7476. }
  7477. #if ENABLE_PROFILE_INFO
  7478. template <class T>
  7479. Var InterpreterStackFrame::OP_ProfiledLdSlot(Var instance, const unaligned T* playout)
  7480. {
  7481. Var value = OP_LdSlot(instance, playout->SlotIndex);
  7482. ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
  7483. return value;
  7484. }
  7485. #endif
  7486. template <class T>
  7487. Var InterpreterStackFrame::OP_LdInnerSlot(Var slotArray, const unaligned T* playout)
  7488. {
  7489. return OP_LdSlot(slotArray, playout->SlotIndex2);
  7490. }
  7491. #if ENABLE_PROFILE_INFO
  7492. template <class T>
  7493. Var InterpreterStackFrame::OP_ProfiledLdInnerSlot(Var slotArray, const unaligned T* playout)
  7494. {
  7495. Var value = OP_LdInnerSlot(slotArray, playout);
  7496. ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
  7497. return value;
  7498. }
  7499. #endif
  7500. template <class T>
  7501. Var InterpreterStackFrame::OP_LdInnerObjSlot(Var slotArray, const unaligned T* playout)
  7502. {
  7503. return OP_LdObjSlot(slotArray, playout->SlotIndex2);
  7504. }
  7505. #if ENABLE_PROFILE_INFO
  7506. template <class T>
  7507. Var InterpreterStackFrame::OP_ProfiledLdInnerObjSlot(Var slotArray, const unaligned T* playout)
  7508. {
  7509. Var value = OP_LdInnerObjSlot(slotArray, playout);
  7510. ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
  7511. return value;
  7512. }
  7513. #endif
  7514. Var InterpreterStackFrame::OP_LdFrameDisplaySlot(Var instance, int32 slotIndex)
  7515. {
  7516. if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
  7517. {
  7518. if (((FrameDisplay*)instance)->GetLength() < slotIndex - Js::FrameDisplay::GetOffsetOfScopes()/sizeof(Var))
  7519. {
  7520. Js::Throw::FatalInternalError();
  7521. }
  7522. }
  7523. return ((Var*)instance)[slotIndex];
  7524. }
  7525. template <class T>
  7526. Var InterpreterStackFrame::OP_LdEnvObj(Var instance, const unaligned T* playout)
  7527. {
  7528. return OP_LdFrameDisplaySlot(instance, playout->SlotIndex);
  7529. }
  7530. template <class T>
  7531. Var InterpreterStackFrame::OP_LdEnvSlot(Var instance, const unaligned T* playout)
  7532. {
  7533. Var slotArray = OP_LdFrameDisplaySlot(instance, playout->SlotIndex1);
  7534. return OP_LdSlot(slotArray, playout->SlotIndex2);
  7535. }
  7536. #if ENABLE_PROFILE_INFO
  7537. template <class T>
  7538. Var InterpreterStackFrame::OP_ProfiledLdEnvSlot(Var instance, const unaligned T* playout)
  7539. {
  7540. Var value = OP_LdEnvSlot(instance, playout);
  7541. ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
  7542. return value;
  7543. }
  7544. #endif
  7545. Var InterpreterStackFrame::OP_LdObjSlot(Var instance, int32 slotIndex)
  7546. {
  7547. Var *slotArray = *(Var**)((char*)instance + DynamicObject::GetOffsetOfAuxSlots());
  7548. return slotArray[slotIndex];
  7549. }
  7550. template <class T>
  7551. Var InterpreterStackFrame::OP_LdObjSlot(Var instance, const unaligned T* playout)
  7552. {
  7553. return OP_LdObjSlot(instance, playout->SlotIndex);
  7554. }
  7555. #if ENABLE_PROFILE_INFO
  7556. template <class T>
  7557. Var InterpreterStackFrame::OP_ProfiledLdObjSlot(Var instance, const unaligned T* playout)
  7558. {
  7559. Var value = OP_LdObjSlot(instance, playout->SlotIndex);
  7560. ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
  7561. return value;
  7562. }
  7563. #endif
  7564. template <class T>
  7565. Var InterpreterStackFrame::OP_LdEnvObjSlot(Var instance, const unaligned T* playout)
  7566. {
  7567. Var slotArray = OP_LdFrameDisplaySlot(instance, playout->SlotIndex1);
  7568. return OP_LdObjSlot(slotArray, playout->SlotIndex2);
  7569. }
  7570. template <class T>
  7571. Var InterpreterStackFrame::OP_LdModuleSlot(Var instance, const unaligned T* playout)
  7572. {
  7573. return JavascriptOperators::OP_LdModuleSlot(playout->SlotIndex1, playout->SlotIndex2, scriptContext);
  7574. }
  7575. inline void InterpreterStackFrame::OP_StModuleSlot(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
  7576. {
  7577. JavascriptOperators::OP_StModuleSlot(slotIndex1, slotIndex2, value, scriptContext);
  7578. }
  7579. #if ENABLE_PROFILE_INFO
  7580. template <class T>
  7581. Var InterpreterStackFrame::OP_ProfiledLdEnvObjSlot(Var instance, const unaligned T* playout)
  7582. {
  7583. Var value = OP_LdEnvObjSlot(instance, playout);
  7584. ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
  7585. return value;
  7586. }
  7587. #endif
  7588. void InterpreterStackFrame::OP_StSlot(Var instance, int32 slotIndex, Var value)
  7589. {
  7590. // We emit OpCode::StSlot in the bytecode only for scope slot arrays, which are not recyclable objects.
  7591. if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
  7592. {
  7593. if ((uintptr_t)((Var*)instance)[ScopeSlots::EncodedSlotCountSlotIndex] <= (uintptr_t)(slotIndex - ScopeSlots::FirstSlotIndex))
  7594. {
  7595. Js::Throw::FatalInternalError();
  7596. }
  7597. }
  7598. ((Var*)(instance))[slotIndex] = value;
  7599. }
  7600. void InterpreterStackFrame::OP_StEnvSlot(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
  7601. {
  7602. Var slotArray = (Var*)OP_LdFrameDisplaySlot(instance, slotIndex1);
  7603. OP_StSlot(slotArray, slotIndex2, value);
  7604. }
  7605. void InterpreterStackFrame::OP_StSlotChkUndecl(Var instance, int32 slotIndex, Var value)
  7606. {
  7607. // We emit OpCode::StSlot in the bytecode only for scope slot arrays, which are not recyclable objects.
  7608. if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
  7609. {
  7610. if ((uintptr_t)((Var*)instance)[ScopeSlots::EncodedSlotCountSlotIndex] <= (uintptr_t)(slotIndex - ScopeSlots::FirstSlotIndex))
  7611. {
  7612. Js::Throw::FatalInternalError();
  7613. }
  7614. }
  7615. OP_ChkUndecl(((Var*)instance)[slotIndex]);
  7616. ((Var*)(instance))[slotIndex] = value;
  7617. }
  7618. void InterpreterStackFrame::OP_StEnvSlotChkUndecl(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
  7619. {
  7620. Var slotArray = (Var*)OP_LdFrameDisplaySlot(instance, slotIndex1);
  7621. OP_StSlotChkUndecl(slotArray, slotIndex2, value);
  7622. }
  7623. void InterpreterStackFrame::OP_StObjSlot(Var instance, int32 slotIndex, Var value)
  7624. {
  7625. // It would be nice to assert that it's ok to store directly to slot, but we don't have the propertyId.
  7626. Var *slotArray = *(Var**)((char*)instance + DynamicObject::GetOffsetOfAuxSlots());
  7627. slotArray[slotIndex] = value;
  7628. }
  7629. void InterpreterStackFrame::OP_StObjSlotChkUndecl(Var instance, int32 slotIndex, Var value)
  7630. {
  7631. // It would be nice to assert that it's ok to store directly to slot, but we don't have the propertyId.
  7632. Var *slotArray = *(Var**)((char*)instance + DynamicObject::GetOffsetOfAuxSlots());
  7633. OP_ChkUndecl(slotArray[slotIndex]);
  7634. slotArray[slotIndex] = value;
  7635. }
  7636. void InterpreterStackFrame::OP_StEnvObjSlot(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
  7637. {
  7638. // It would be nice to assert that it's ok to store directly to slot, but we don't have the propertyId.
  7639. Var envInstance = (Var*)OP_LdFrameDisplaySlot(instance, slotIndex1);
  7640. OP_StObjSlot(envInstance, slotIndex2, value);
  7641. }
  7642. void InterpreterStackFrame::OP_StEnvObjSlotChkUndecl(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
  7643. {
  7644. // It would be nice to assert that it's ok to store directly to slot, but we don't have the propertyId.
  7645. Var envInstance = (Var*)OP_LdFrameDisplaySlot(instance, slotIndex1);
  7646. OP_StObjSlotChkUndecl(envInstance, slotIndex2, value);
  7647. }
  7648. Var InterpreterStackFrame::OP_LdStackArgPtr(void)
  7649. {
  7650. // Return the address of the first param after "this".
  7651. return m_inParams + 1;
  7652. }
  7653. ForInObjectEnumerator * InterpreterStackFrame::GetForInEnumerator(uint forInLoopLevel)
  7654. {
  7655. Assert(forInLoopLevel < this->m_functionBody->GetForInLoopDepth());
  7656. return &this->forInObjectEnumerators[forInLoopLevel];
  7657. }
  7658. void InterpreterStackFrame::OP_InitForInEnumerator(Var object, uint forInLoopLevel)
  7659. {
  7660. JavascriptOperators::OP_InitForInEnumerator(object, GetForInEnumerator(forInLoopLevel), this->GetScriptContext());
  7661. }
  7662. void InterpreterStackFrame::OP_InitForInEnumeratorWithCache(Var object, uint forInLoopLevel, ProfileId profileId)
  7663. {
  7664. JavascriptOperators::OP_InitForInEnumerator(object, GetForInEnumerator(forInLoopLevel), this->GetScriptContext(),
  7665. m_functionBody->GetForInCache(profileId));
  7666. }
  7667. // Called for the debug purpose, to create the arguments object explicitly even though script has not declared it.
  7668. Var InterpreterStackFrame::CreateHeapArguments(ScriptContext* scriptContext)
  7669. {
  7670. return JavascriptOperators::LoadHeapArguments(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, &this->m_inParams[1], scriptContext->GetLibrary()->GetNull(), (PropertyId*)scriptContext->GetLibrary()->GetNull(), scriptContext, false);
  7671. }
  7672. template <bool letArgs>
  7673. Var InterpreterStackFrame::LdHeapArgumentsImpl(Var argsArray, ScriptContext* scriptContext)
  7674. {
  7675. Var frameObj;
  7676. if (m_functionBody->HasScopeObject() && argsArray != scriptContext->GetLibrary()->GetNull())
  7677. {
  7678. frameObj = this->localClosure;
  7679. Assert(frameObj);
  7680. }
  7681. else
  7682. {
  7683. frameObj = scriptContext->GetLibrary()->GetNull();
  7684. }
  7685. Var args = JavascriptOperators::LoadHeapArguments(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, &this->m_inParams[1], frameObj, (PropertyId*)argsArray, scriptContext, letArgs);
  7686. this->m_arguments = args;
  7687. return args;
  7688. }
  7689. Var InterpreterStackFrame::OP_LdHeapArguments(ScriptContext* scriptContext)
  7690. {
  7691. Var argsArray = m_functionBody->GetFormalsPropIdArrayOrNullObj();
  7692. return LdHeapArgumentsImpl<false>(argsArray, scriptContext);
  7693. }
  7694. Var InterpreterStackFrame::OP_LdLetHeapArguments(ScriptContext* scriptContext)
  7695. {
  7696. Var argsArray = m_functionBody->GetFormalsPropIdArrayOrNullObj();
  7697. return LdHeapArgumentsImpl<true>(argsArray, scriptContext);
  7698. }
  7699. Var InterpreterStackFrame::OP_LdHeapArgsCached(ScriptContext* scriptContext)
  7700. {
  7701. uint32 formalsCount = this->m_functionBody->GetInParamsCount() - 1;
  7702. Var args = JavascriptOperators::LoadHeapArgsCached(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, formalsCount, &this->m_inParams[1], this->localClosure, scriptContext, false);
  7703. this->m_arguments = args;
  7704. return args;
  7705. }
  7706. Var InterpreterStackFrame::OP_LdLetHeapArgsCached(ScriptContext* scriptContext)
  7707. {
  7708. uint32 formalsCount = this->m_functionBody->GetInParamsCount() - 1;
  7709. Var args = JavascriptOperators::LoadHeapArgsCached(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, formalsCount, &this->m_inParams[1], this->localClosure, scriptContext, true);
  7710. this->m_arguments = args;
  7711. return args;
  7712. }
  7713. HeapArgumentsObject * InterpreterStackFrame::CreateEmptyHeapArgumentsObject(ScriptContext* scriptContext)
  7714. {
  7715. HeapArgumentsObject * args = JavascriptOperators::CreateHeapArguments(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, 0, nullptr, scriptContext);
  7716. this->m_arguments = args;
  7717. return args;
  7718. }
  7719. void InterpreterStackFrame::TrySetFrameObjectInHeapArgObj(ScriptContext * scriptContext, bool hasNonSimpleParams, bool isScopeObjRestored)
  7720. {
  7721. ActivationObject * frameObject = nullptr;
  7722. uint32 formalsCount = this->m_functionBody->GetInParamsCount() - 1;
  7723. Js::PropertyIdArray * propIds = nullptr;
  7724. Js::HeapArgumentsObject* heapArgObj = nullptr;
  7725. //We always set the Frame object to nullptr in BailOutRecord::EnsureArguments for stack args optimization.
  7726. if (m_arguments != nullptr && ((Js::HeapArgumentsObject*)(m_arguments))->GetFrameObject() == nullptr)
  7727. {
  7728. heapArgObj = (Js::HeapArgumentsObject*)m_arguments;
  7729. }
  7730. bool isCachedScope = false;
  7731. //For Non-simple params, we don't have a scope object created.
  7732. if (this->m_functionBody->NeedScopeObjectForArguments(hasNonSimpleParams))
  7733. {
  7734. frameObject = (ActivationObject*)GetLocalClosure();
  7735. isCachedScope = m_functionBody->HasCachedScopePropIds();
  7736. propIds = this->m_functionBody->GetFormalsPropIdArray();
  7737. if(isScopeObjRestored && ActivationObject::Is(frameObject))
  7738. {
  7739. Assert(this->GetFunctionBody()->GetDoScopeObjectCreation());
  7740. isCachedScope = true;
  7741. if (PHASE_VERBOSE_TRACE1(Js::StackArgFormalsOptPhase) && m_functionBody->GetInParamsCount() > 1)
  7742. {
  7743. Output::Print(_u("StackArgFormals : %s (%d) :Using the restored scope object in the bail out path. \n"), m_functionBody->GetDisplayName(), m_functionBody->GetFunctionNumber());
  7744. Output::Flush();
  7745. }
  7746. }
  7747. else
  7748. {
  7749. if (isCachedScope)
  7750. {
  7751. Js::DynamicType *literalType = nullptr;
  7752. Assert(!propIds->hasNonSimpleParams && !hasNonSimpleParams);
  7753. frameObject = (ActivationObject*)JavascriptOperators::OP_InitCachedScope(this->GetJavascriptFunction(), propIds, &literalType, hasNonSimpleParams, scriptContext);
  7754. }
  7755. else
  7756. {
  7757. frameObject = (ActivationObject*)JavascriptOperators::OP_NewScopeObject(GetScriptContext());
  7758. }
  7759. Assert(propIds != nullptr);
  7760. SetLocalClosure(frameObject);
  7761. if (PHASE_VERBOSE_TRACE1(Js::StackArgFormalsOptPhase) && m_functionBody->GetInParamsCount() > 1)
  7762. {
  7763. Output::Print(_u("StackArgFormals : %s (%d) :Creating scope object in the bail out path. \n"), m_functionBody->GetDisplayName(), m_functionBody->GetFunctionNumber());
  7764. Output::Flush();
  7765. }
  7766. }
  7767. }
  7768. else
  7769. {
  7770. //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)
  7771. Assert(formalsCount == 0 || (m_functionBody->GetIsStrictMode() || hasNonSimpleParams));
  7772. frameObject = (ActivationObject*)scriptContext->GetLibrary()->GetNull();
  7773. formalsCount = 0;
  7774. if (PHASE_VERBOSE_TRACE1(Js::StackArgOptPhase))
  7775. {
  7776. Output::Print(_u("StackArgOpt : %s (%d) :Creating NULL scope object in the bail out path. \n"), m_functionBody->GetDisplayName(), m_functionBody->GetFunctionNumber());
  7777. Output::Flush();
  7778. }
  7779. }
  7780. if (heapArgObj)
  7781. {
  7782. heapArgObj->SetFormalCount(formalsCount);
  7783. heapArgObj->SetFrameObject(frameObject);
  7784. if (PHASE_TRACE1(Js::StackArgFormalsOptPhase) && formalsCount > 0)
  7785. {
  7786. 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());
  7787. Output::Flush();
  7788. }
  7789. }
  7790. //Fill the Heap arguments and scope object with values
  7791. // If there is no heap arguments object, then fill only the scope object with actuals.
  7792. JavascriptOperators::FillScopeObject(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, formalsCount, frameObject, &this->m_inParams[1], propIds, heapArgObj, scriptContext, hasNonSimpleParams, isCachedScope);
  7793. }
  7794. Var InterpreterStackFrame::OP_LdArgumentsFromFrame()
  7795. {
  7796. return this->m_arguments;
  7797. }
  7798. void* InterpreterStackFrame::OP_LdArgCnt()
  7799. {
  7800. return (void*)m_inSlotsCount;
  7801. }
  7802. Var InterpreterStackFrame::OP_ResumeYield(Var yieldDataVar, RegSlot yieldStarIterator)
  7803. {
  7804. ResumeYieldData* yieldData = static_cast<ResumeYieldData*>(yieldDataVar);
  7805. RecyclableObject* iterator = yieldStarIterator != Constants::NoRegister ? RecyclableObject::FromVar(GetNonVarReg(yieldStarIterator)) : nullptr;
  7806. return JavascriptOperators::OP_ResumeYield(yieldData, iterator);
  7807. }
  7808. void* InterpreterStackFrame::operator new(size_t byteSize, void* previousAllocation) throw()
  7809. {
  7810. //
  7811. // Placement 'new' is used by InterpreterStackFrame to initialize the C++ object on the RcInterpreter's
  7812. // program stack:
  7813. // - Unlike most other allocations, the previously allocated memory will __not__ be
  7814. // zero-initialized, as we do not want the overhead of zero-initializing the frame when
  7815. // calling functions.
  7816. //
  7817. // NOTE: If we wanted to add C# semantics of all locals are automatically zero-initialized,
  7818. // need to determine the most efficient mechanism for this.
  7819. //
  7820. return previousAllocation;
  7821. }
  7822. void __cdecl InterpreterStackFrame::operator delete(void * allocationToFree, void * previousAllocation) throw()
  7823. {
  7824. AssertMsg(allocationToFree == previousAllocation, "Memory locations should match");
  7825. AssertMsg(false, "This function should never actually be called");
  7826. }
  7827. template void* Js::InterpreterStackFrame::GetReg<unsigned int>(unsigned int) const;
  7828. template void Js::InterpreterStackFrame::SetReg<unsigned int>(unsigned int, void*);
  7829. } // namespace Js
  7830. // Make sure the macro and the layout for the op is consistent
  7831. #define DEF2(x, op, ...) \
  7832. CompileAssert(!Js::OpCodeInfo<Js::OpCode::op>::HasMultiSizeLayout); \
  7833. CompileAssert(!Js::OpCodeInfo<Js::OpCode::op>::IsExtendedOpcode);
  7834. #define DEF3(x, op, ...) DEF2(x, op)
  7835. #define EXDEF2(x, op, ...) \
  7836. CompileAssert(!Js::OpCodeInfo<Js::OpCode::op>::HasMultiSizeLayout); \
  7837. CompileAssert(Js::OpCodeInfo<Js::OpCode::op>::IsExtendedOpcode);
  7838. #define EXDEF3(x, op, ...) EXDEF2(x, op)
  7839. #define DEF2_WMS(x, op, ...) \
  7840. CompileAssert(Js::OpCodeInfo<Js::OpCode::op>::HasMultiSizeLayout); \
  7841. CompileAssert(!Js::OpCodeInfo<Js::OpCode::op>::IsExtendedOpcode);
  7842. #define DEF3_WMS(x, op, ...) DEF2_WMS(x, op)
  7843. #define EXDEF2_WMS(x, op, ...) \
  7844. CompileAssert(Js::OpCodeInfo<Js::OpCode::op>::HasMultiSizeLayout); \
  7845. CompileAssert(Js::OpCodeInfo<Js::OpCode::op>::IsExtendedOpcode);
  7846. #define EXDEF3_WMS(x, op, ...) EXDEF2_WMS(x, op)
  7847. #include "InterpreterHandler.inl"
  7848. // Make sure the macro and the layout for the op is consistent
  7849. #define DEF2(x, op, ...) \
  7850. CompileAssert(!Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::HasMultiSizeLayout); \
  7851. CompileAssert(!Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::IsExtendedOpcode);
  7852. #define DEF3(x, op, ...) DEF2(x, op)
  7853. #define DEF4(x, op, ...) DEF2(x, op)
  7854. #define EXDEF2(x, op, ...) \
  7855. CompileAssert(!Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::HasMultiSizeLayout); \
  7856. CompileAssert(Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::IsExtendedOpcode);
  7857. #define EXDEF3(x, op, ...) EXDEF2(x, op)
  7858. #define EXDEF4(x, op, ...) EXDEF2(x, op)
  7859. #define DEF2_WMS(x, op, ...) \
  7860. CompileAssert(Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::HasMultiSizeLayout); \
  7861. CompileAssert(!Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::IsExtendedOpcode);
  7862. #define DEF3_WMS(x, op, ...) DEF2_WMS(x, op)
  7863. #define DEF4_WMS(x, op, ...) DEF2_WMS(x, op)
  7864. #define EXDEF2_WMS(x, op, ...) \
  7865. CompileAssert(Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::HasMultiSizeLayout); \
  7866. CompileAssert(Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::IsExtendedOpcode);
  7867. #define EXDEF3_WMS(x, op, ...) EXDEF2_WMS(x, op)
  7868. #define EXDEF4_WMS(x, op, ...) EXDEF2_WMS(x, op)
  7869. #include "InterpreterHandlerAsmJs.inl"