JavascriptOperators.cpp 498 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. 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 "Types/PathTypeHandler.h"
  7. #include "Types/PropertyIndexRanges.h"
  8. #include "Types/WithScopeObject.h"
  9. #include "Types/SpreadArgument.h"
  10. #include "Library/JavascriptPromise.h"
  11. #include "Library/JavascriptRegularExpression.h"
  12. #include "Library/ThrowErrorObject.h"
  13. #include "Library/JavascriptGeneratorFunction.h"
  14. #include "Library/ForInObjectEnumerator.h"
  15. #include "Library/ES5Array.h"
  16. #include "Types/SimpleDictionaryPropertyDescriptor.h"
  17. #include "Types/SimpleDictionaryTypeHandler.h"
  18. #include "Language/ModuleNamespace.h"
  19. #ifndef SCRIPT_DIRECT_TYPE
  20. typedef enum JsNativeValueType: int
  21. {
  22. JsInt8Type,
  23. JsUint8Type,
  24. JsInt16Type,
  25. JsUint16Type,
  26. JsInt32Type,
  27. JsUint32Type,
  28. JsInt64Type,
  29. JsUint64Type,
  30. JsFloatType,
  31. JsDoubleType,
  32. JsNativeStringType
  33. } JsNativeValueType;
  34. typedef struct JsNativeString
  35. {
  36. unsigned int length;
  37. LPCWSTR str;
  38. } JsNativeString;
  39. #endif
  40. using namespace Js;
  41. DEFINE_RECYCLER_TRACKER_ARRAY_PERF_COUNTER(Var);
  42. DEFINE_RECYCLER_TRACKER_PERF_COUNTER(FrameDisplay);
  43. enum IndexType
  44. {
  45. IndexType_Number,
  46. IndexType_PropertyId,
  47. IndexType_JavascriptString
  48. };
  49. IndexType GetIndexTypeFromString(char16 const * propertyName, charcount_t propertyLength, ScriptContext* scriptContext, uint32* index, PropertyRecord const** propertyRecord, bool createIfNotFound)
  50. {
  51. if (JavascriptOperators::TryConvertToUInt32(propertyName, propertyLength, index) &&
  52. (*index != JavascriptArray::InvalidIndex))
  53. {
  54. return IndexType_Number;
  55. }
  56. else
  57. {
  58. if (createIfNotFound)
  59. {
  60. scriptContext->GetOrAddPropertyRecord(propertyName, propertyLength, propertyRecord);
  61. }
  62. else
  63. {
  64. scriptContext->FindPropertyRecord(propertyName, propertyLength, propertyRecord);
  65. }
  66. return IndexType_PropertyId;
  67. }
  68. }
  69. IndexType GetIndexTypeFromPrimitive(Var indexVar, ScriptContext* scriptContext, uint32* index, PropertyRecord const ** propertyRecord, JavascriptString ** propertyNameString, bool createIfNotFound, bool preferJavascriptStringOverPropertyRecord)
  70. {
  71. // CONSIDER: Only OP_SetElementI and OP_GetElementI use and take advantage of the
  72. // IndexType_JavascriptString result. Consider modifying other callers of GetIndexType to take
  73. // advantage of non-interned property strings where appropriate.
  74. if (TaggedInt::Is(indexVar))
  75. {
  76. int indexInt = TaggedInt::ToInt32(indexVar);
  77. if (indexInt >= 0)
  78. {
  79. *index = (uint)indexInt;
  80. return IndexType_Number;
  81. }
  82. else
  83. {
  84. char16 stringBuffer[22];
  85. int pos = TaggedInt::ToBuffer(indexInt, stringBuffer, _countof(stringBuffer));
  86. charcount_t length = (_countof(stringBuffer) - 1) - pos;
  87. if (createIfNotFound || preferJavascriptStringOverPropertyRecord)
  88. {
  89. // When preferring JavascriptString objects, just return a PropertyRecord instead
  90. // of creating temporary JavascriptString objects for every negative integer that
  91. // comes through here.
  92. scriptContext->GetOrAddPropertyRecord(stringBuffer + pos, length, propertyRecord);
  93. }
  94. else
  95. {
  96. scriptContext->FindPropertyRecord(stringBuffer + pos, length, propertyRecord);
  97. }
  98. return IndexType_PropertyId;
  99. }
  100. }
  101. else
  102. {
  103. JavascriptSymbol * symbol = JavascriptOperators::TryFromVar<JavascriptSymbol>(indexVar);
  104. if (symbol)
  105. {
  106. // JavascriptSymbols cannot add a new PropertyRecord - they correspond to one and only one existing PropertyRecord.
  107. // We already know what the PropertyRecord is since it is stored in the JavascriptSymbol itself so just return it.
  108. *propertyRecord = symbol->GetValue();
  109. return IndexType_PropertyId;
  110. }
  111. else
  112. {
  113. JavascriptString* indexStr = JavascriptConversion::ToString(indexVar, scriptContext);
  114. char16 const * propertyName = indexStr->GetString();
  115. charcount_t const propertyLength = indexStr->GetLength();
  116. if (!createIfNotFound && preferJavascriptStringOverPropertyRecord)
  117. {
  118. if (JavascriptOperators::TryConvertToUInt32(propertyName, propertyLength, index) &&
  119. (*index != JavascriptArray::InvalidIndex))
  120. {
  121. return IndexType_Number;
  122. }
  123. *propertyNameString = indexStr;
  124. return IndexType_JavascriptString;
  125. }
  126. return GetIndexTypeFromString(propertyName, propertyLength, scriptContext, index, propertyRecord, createIfNotFound);
  127. }
  128. }
  129. }
  130. IndexType GetIndexTypeFromPrimitive(Var indexVar, ScriptContext* scriptContext, uint32* index, PropertyRecord const ** propertyRecord, bool createIfNotFound)
  131. {
  132. return GetIndexTypeFromPrimitive(indexVar, scriptContext, index, propertyRecord, nullptr, createIfNotFound, false);
  133. }
  134. IndexType GetIndexType(Var& indexVar, ScriptContext* scriptContext, uint32* index, PropertyRecord const ** propertyRecord, JavascriptString ** propertyNameString, bool createIfNotFound, bool preferJavascriptStringOverPropertyRecord)
  135. {
  136. indexVar = JavascriptConversion::ToPrimitive<JavascriptHint::HintString>(indexVar, scriptContext);
  137. return GetIndexTypeFromPrimitive(indexVar, scriptContext, index, propertyRecord, propertyNameString, createIfNotFound, preferJavascriptStringOverPropertyRecord);
  138. }
  139. IndexType GetIndexType(Var& indexVar, ScriptContext* scriptContext, uint32* index, PropertyRecord const ** propertyRecord, bool createIfNotFound)
  140. {
  141. return GetIndexType(indexVar, scriptContext, index, propertyRecord, nullptr, createIfNotFound, false);
  142. }
  143. BOOL FEqualDbl(double dbl1, double dbl2)
  144. {
  145. // If the low ulongs don't match, they can't be equal.
  146. if (Js::NumberUtilities::LuLoDbl(dbl1) != Js::NumberUtilities::LuLoDbl(dbl2))
  147. return FALSE;
  148. // If the high ulongs don't match, they can be equal iff one is -0 and
  149. // the other is +0.
  150. if (Js::NumberUtilities::LuHiDbl(dbl1) != Js::NumberUtilities::LuHiDbl(dbl2))
  151. {
  152. return 0x80000000 == (Js::NumberUtilities::LuHiDbl(dbl1) | Js::NumberUtilities::LuHiDbl(dbl2)) &&
  153. 0 == Js::NumberUtilities::LuLoDbl(dbl1);
  154. }
  155. // The bit patterns match. They are equal iff they are not Nan.
  156. return !Js::NumberUtilities::IsNan(dbl1);
  157. }
  158. Var JavascriptOperators::OP_ApplyArgs(Var func, Var instance, __in_xcount(8) void** stackPtr, CallInfo callInfo, ScriptContext* scriptContext)
  159. {
  160. JIT_HELPER_REENTRANT_HEADER(Op_OP_ApplyArgs);
  161. int argCount = callInfo.Count;
  162. ///
  163. /// Check func has internal [[Call]] property
  164. /// If not, throw TypeError
  165. ///
  166. if (!JavascriptConversion::IsCallable(func)) {
  167. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction);
  168. }
  169. // Fix callInfo: expect result/value, and none of other flags are currently applicable.
  170. // OP_ApplyArgs expects a result. Neither of {jit, interpreted} mode sends correct callFlags:
  171. // LdArgCnt -- jit sends whatever was passed to current function, interpreter always sends 0.
  172. // See Win8 bug 490489.
  173. callInfo.Flags = CallFlags_Value;
  174. RecyclableObject *funcPtr = RecyclableObject::UnsafeFromVar(func);
  175. PROBE_STACK(scriptContext, Js::Constants::MinStackDefault + argCount * 4);
  176. JavascriptMethod entryPoint = funcPtr->GetEntryPoint();
  177. Var ret;
  178. switch (argCount) {
  179. case 0:
  180. Assert(false);
  181. ret = CALL_ENTRYPOINT_NOASSERT(entryPoint, funcPtr, callInfo);
  182. break;
  183. case 1:
  184. ret = CALL_ENTRYPOINT_NOASSERT(entryPoint, funcPtr, callInfo, instance);
  185. break;
  186. case 2:
  187. ret = CALL_ENTRYPOINT_NOASSERT(entryPoint, funcPtr, callInfo, instance, stackPtr[0]);
  188. break;
  189. case 3:
  190. ret = CALL_ENTRYPOINT_NOASSERT(entryPoint, funcPtr, callInfo, instance, stackPtr[0], stackPtr[1]);
  191. break;
  192. case 4:
  193. ret = CALL_ENTRYPOINT_NOASSERT(entryPoint, funcPtr, callInfo, instance, stackPtr[0], stackPtr[1], stackPtr[2]);
  194. break;
  195. case 5:
  196. ret = CALL_ENTRYPOINT_NOASSERT(entryPoint, funcPtr, callInfo, instance, stackPtr[0], stackPtr[1], stackPtr[2], stackPtr[3]);
  197. break;
  198. case 6:
  199. ret = CALL_ENTRYPOINT_NOASSERT(entryPoint, funcPtr, callInfo, instance, stackPtr[0], stackPtr[1], stackPtr[2], stackPtr[3], stackPtr[4]);
  200. break;
  201. case 7:
  202. ret = CALL_ENTRYPOINT_NOASSERT(entryPoint, funcPtr, callInfo, instance, stackPtr[0], stackPtr[1], stackPtr[2], stackPtr[3], stackPtr[4], stackPtr[5]);
  203. break;
  204. default:
  205. {
  206. // Don't need stack probe here- we just did so above
  207. Arguments args(callInfo, stackPtr - 1);
  208. BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
  209. {
  210. ret = JavascriptFunction::CallFunction<false>(funcPtr, entryPoint, args);
  211. }
  212. END_SAFE_REENTRANT_CALL
  213. break;
  214. }
  215. }
  216. return ret;
  217. JIT_HELPER_END(Op_OP_ApplyArgs);
  218. }
  219. #ifdef _M_IX86
  220. // Alias for overloaded JavascriptNumber::ToVar so it can be called unambiguously from native code
  221. Var JavascriptOperators::Int32ToVar(int32 value, ScriptContext* scriptContext)
  222. {
  223. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_Int32ToAtom);
  224. return JavascriptNumber::ToVar(value, scriptContext);
  225. JIT_HELPER_END(Op_Int32ToAtom);
  226. }
  227. // Alias for overloaded JavascriptNumber::ToVar so it can be called unambiguously from native code
  228. Var JavascriptOperators::Int32ToVarInPlace(int32 value, ScriptContext* scriptContext, JavascriptNumber* result)
  229. {
  230. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_Int32ToAtomInPlace);
  231. return JavascriptNumber::ToVarInPlace(value, scriptContext, result);
  232. JIT_HELPER_END(Op_Int32ToAtomInPlace);
  233. }
  234. // Alias for overloaded JavascriptNumber::ToVar so it can be called unambiguously from native code
  235. Var JavascriptOperators::UInt32ToVar(uint32 value, ScriptContext* scriptContext)
  236. {
  237. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_UInt32ToAtom);
  238. return JavascriptNumber::ToVar(value, scriptContext);
  239. JIT_HELPER_END(Op_UInt32ToAtom);
  240. }
  241. // Alias for overloaded JavascriptNumber::ToVar so it can be called unambiguously from native code
  242. Var JavascriptOperators::UInt32ToVarInPlace(uint32 value, ScriptContext* scriptContext, JavascriptNumber* result)
  243. {
  244. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_UInt32ToAtomInPlace);
  245. return JavascriptNumber::ToVarInPlace(value, scriptContext, result);
  246. JIT_HELPER_END(Op_UInt32ToAtomInPlace);
  247. }
  248. #endif
  249. Var JavascriptOperators::OP_FinishOddDivBy2(uint32 value, ScriptContext *scriptContext)
  250. {
  251. return JavascriptNumber::New((double)(value + 0.5), scriptContext);
  252. }
  253. Var JavascriptOperators::ToNumberInPlace(Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  254. {
  255. JIT_HELPER_REENTRANT_HEADER(Op_ConvNumberInPlace);
  256. if (TaggedInt::Is(aRight) || JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  257. {
  258. return aRight;
  259. }
  260. return JavascriptNumber::ToVarInPlace(JavascriptConversion::ToNumber(aRight, scriptContext), scriptContext, result);
  261. JIT_HELPER_END(Op_ConvNumberInPlace);
  262. }
  263. Var JavascriptOperators::Typeof(Var var, ScriptContext* scriptContext)
  264. {
  265. JIT_HELPER_REENTRANT_HEADER(Op_Typeof);
  266. switch (JavascriptOperators::GetTypeId(var))
  267. {
  268. case TypeIds_Undefined:
  269. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  270. case TypeIds_Null:
  271. //null
  272. return scriptContext->GetLibrary()->GetObjectTypeDisplayString();
  273. case TypeIds_Integer:
  274. case TypeIds_Number:
  275. case TypeIds_Int64Number:
  276. case TypeIds_UInt64Number:
  277. return scriptContext->GetLibrary()->GetNumberTypeDisplayString();
  278. default:
  279. // Falsy objects are typeof 'undefined'.
  280. if (RecyclableObject::FromVar(var)->GetType()->IsFalsy())
  281. {
  282. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  283. }
  284. else
  285. {
  286. return RecyclableObject::FromVar(var)->GetTypeOfString(scriptContext);
  287. }
  288. }
  289. JIT_HELPER_END(Op_Typeof);
  290. }
  291. Var JavascriptOperators::TypeofFld(Var instance, PropertyId propertyId, ScriptContext* scriptContext)
  292. {
  293. return TypeofFld_Internal(instance, false, propertyId, scriptContext);
  294. }
  295. Var JavascriptOperators::TypeofRootFld(Var instance, PropertyId propertyId, ScriptContext* scriptContext)
  296. {
  297. return TypeofFld_Internal(instance, true, propertyId, scriptContext);
  298. }
  299. Var JavascriptOperators::TypeofFld_Internal(Var instance, const bool isRoot, PropertyId propertyId, ScriptContext* scriptContext)
  300. {
  301. RecyclableObject* object = nullptr;
  302. if (FALSE == JavascriptOperators::GetPropertyObject(instance, scriptContext, &object))
  303. {
  304. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotGet_NullOrUndefined , scriptContext->GetPropertyName(propertyId)->GetBuffer());
  305. }
  306. Var value = nullptr;
  307. try
  308. {
  309. Js::JavascriptExceptionOperators::AutoCatchHandlerExists autoCatchHandlerExists(scriptContext);
  310. // In edge mode, spec compat is more important than backward compat. Use spec/web behavior here
  311. if (isRoot
  312. ? !JavascriptOperators::GetRootProperty(instance, propertyId, &value, scriptContext)
  313. : !JavascriptOperators::GetProperty(instance, object, propertyId, &value, scriptContext))
  314. {
  315. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  316. }
  317. if (!scriptContext->IsUndeclBlockVar(value))
  318. {
  319. return JavascriptOperators::Typeof(value, scriptContext);
  320. }
  321. }
  322. catch(const JavascriptException& err)
  323. {
  324. err.GetAndClear(); // discard exception object
  325. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  326. }
  327. Assert(scriptContext->IsUndeclBlockVar(value));
  328. JavascriptError::ThrowReferenceError(scriptContext, JSERR_UseBeforeDeclaration);
  329. }
  330. Var JavascriptOperators::TypeofElem_UInt32(Var instance, uint32 index, ScriptContext* scriptContext)
  331. {
  332. JIT_HELPER_REENTRANT_HEADER(Op_TypeofElem_UInt32);
  333. if (JavascriptOperators::IsNumberFromNativeArray(instance, index, scriptContext))
  334. return scriptContext->GetLibrary()->GetNumberTypeDisplayString();
  335. #if FLOATVAR
  336. return TypeofElem(instance, Js::JavascriptNumber::ToVar(index, scriptContext), scriptContext);
  337. #else
  338. char buffer[sizeof(Js::JavascriptNumber)];
  339. return TypeofElem(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  340. (Js::JavascriptNumber *)buffer), scriptContext);
  341. #endif
  342. JIT_HELPER_END(Op_TypeofElem_UInt32);
  343. }
  344. Var JavascriptOperators::TypeofElem_Int32(Var instance, int32 index, ScriptContext* scriptContext)
  345. {
  346. JIT_HELPER_REENTRANT_HEADER(Op_TypeofElem_Int32);
  347. if (JavascriptOperators::IsNumberFromNativeArray(instance, index, scriptContext))
  348. return scriptContext->GetLibrary()->GetNumberTypeDisplayString();
  349. #if FLOATVAR
  350. return TypeofElem(instance, Js::JavascriptNumber::ToVar(index, scriptContext), scriptContext);
  351. #else
  352. char buffer[sizeof(Js::JavascriptNumber)];
  353. return TypeofElem(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  354. (Js::JavascriptNumber *)buffer), scriptContext);
  355. #endif
  356. JIT_HELPER_END(Op_TypeofElem_Int32);
  357. }
  358. Js::JavascriptString* GetPropertyDisplayNameForError(Var prop, ScriptContext* scriptContext)
  359. {
  360. JavascriptString* str;
  361. JavascriptSymbol *symbol = JavascriptOperators::TryFromVar<JavascriptSymbol>(prop);
  362. if (symbol)
  363. {
  364. str = JavascriptSymbol::ToString(symbol->GetValue(), scriptContext);
  365. }
  366. else
  367. {
  368. str = JavascriptConversion::ToString(prop, scriptContext);
  369. }
  370. return str;
  371. }
  372. Var JavascriptOperators::TypeofElem(Var instance, Var index, ScriptContext* scriptContext)
  373. {
  374. JIT_HELPER_REENTRANT_HEADER(Op_TypeofElem);
  375. RecyclableObject* object = nullptr;
  376. if (FALSE == JavascriptOperators::GetPropertyObject(instance, scriptContext, &object))
  377. {
  378. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotGet_NullOrUndefined, GetPropertyDisplayNameForError(index, scriptContext));
  379. }
  380. Var member = nullptr;
  381. uint32 indexVal;
  382. PropertyRecord const * propertyRecord = nullptr;
  383. ThreadContext* threadContext = scriptContext->GetThreadContext();
  384. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  385. threadContext->ClearImplicitCallFlags();
  386. try
  387. {
  388. Js::JavascriptExceptionOperators::AutoCatchHandlerExists autoCatchHandlerExists(scriptContext);
  389. IndexType indexType = GetIndexType(index, scriptContext, &indexVal, &propertyRecord, false);
  390. // For JS Objects, don't create the propertyId if not already added
  391. if (indexType == IndexType_Number)
  392. {
  393. // In edge mode, we don't need to worry about the special "unknown" behavior. If the item is not available from Get,
  394. // just return undefined.
  395. if (!JavascriptOperators::GetItem(instance, object, indexVal, &member, scriptContext))
  396. {
  397. // If the instance doesn't have the item, typeof result is "undefined".
  398. threadContext->CheckAndResetImplicitCallAccessorFlag();
  399. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  400. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  401. }
  402. }
  403. else
  404. {
  405. Assert(indexType == IndexType_PropertyId);
  406. if (propertyRecord == nullptr && !JavascriptOperators::CanShortcutOnUnknownPropertyName(object))
  407. {
  408. indexType = GetIndexTypeFromPrimitive(index, scriptContext, &indexVal, &propertyRecord, true);
  409. Assert(indexType == IndexType_PropertyId);
  410. Assert(propertyRecord != nullptr);
  411. }
  412. if (propertyRecord != nullptr)
  413. {
  414. if (!JavascriptOperators::GetProperty(instance, object, propertyRecord->GetPropertyId(), &member, scriptContext))
  415. {
  416. // If the instance doesn't have the property, typeof result is "undefined".
  417. threadContext->CheckAndResetImplicitCallAccessorFlag();
  418. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  419. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  420. }
  421. }
  422. else
  423. {
  424. #if DBG
  425. JavascriptString* indexStr = JavascriptConversion::ToString(index, scriptContext);
  426. PropertyRecord const * debugPropertyRecord;
  427. scriptContext->GetOrAddPropertyRecord(indexStr, &debugPropertyRecord);
  428. AssertMsg(!JavascriptOperators::GetProperty(instance, object, debugPropertyRecord->GetPropertyId(), &member, scriptContext), "how did this property come? See OS Bug 2727708 if you see this come from the web");
  429. #endif
  430. // If the instance doesn't have the property, typeof result is "undefined".
  431. threadContext->CheckAndResetImplicitCallAccessorFlag();
  432. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  433. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  434. }
  435. }
  436. threadContext->CheckAndResetImplicitCallAccessorFlag();
  437. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  438. return JavascriptOperators::Typeof(member, scriptContext);
  439. }
  440. catch(const JavascriptException& err)
  441. {
  442. err.GetAndClear(); // discard exception object
  443. threadContext->CheckAndResetImplicitCallAccessorFlag();
  444. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  445. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  446. }
  447. JIT_HELPER_END(Op_TypeofElem);
  448. }
  449. //
  450. // Delete the given Var
  451. //
  452. Var JavascriptOperators::Delete(Var var, ScriptContext* scriptContext)
  453. {
  454. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_Delete);
  455. return scriptContext->GetLibrary()->GetTrue();
  456. JIT_HELPER_END(Op_Delete);
  457. }
  458. BOOL JavascriptOperators::Equal_Full(Var aLeft, Var aRight, ScriptContext* requestContext)
  459. {
  460. JIT_HELPER_REENTRANT_HEADER(Op_Equal_Full);
  461. //
  462. // Fast-path SmInts and paired Number combinations.
  463. //
  464. if (aLeft == aRight)
  465. {
  466. if (JavascriptNumber::Is(aLeft) && JavascriptNumber::IsNan(JavascriptNumber::GetValue(aLeft)))
  467. {
  468. return false;
  469. }
  470. else if (JavascriptVariantDate::Is(aLeft) == false) // only need to check on aLeft - since they are the same var, aRight would do the same
  471. {
  472. return true;
  473. }
  474. else
  475. {
  476. //In ES5 mode strict equals (===) on same instance of object type VariantDate succeeds.
  477. //Hence equals needs to succeed.
  478. return true;
  479. }
  480. }
  481. BOOL result = false;
  482. if (TaggedInt::Is(aLeft))
  483. {
  484. if (TaggedInt::Is(aRight))
  485. {
  486. // If aLeft == aRight, we would already have returned true above.
  487. return false;
  488. }
  489. else if (JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  490. {
  491. return TaggedInt::ToDouble(aLeft) == JavascriptNumber::GetValue(aRight);
  492. }
  493. else
  494. {
  495. BOOL res = RecyclableObject::UnsafeFromVar(aRight)->Equals(aLeft, &result, requestContext);
  496. AssertMsg(res, "Should have handled this");
  497. return result;
  498. }
  499. }
  500. else if (JavascriptNumber::Is_NoTaggedIntCheck(aLeft))
  501. {
  502. if (TaggedInt::Is(aRight))
  503. {
  504. return TaggedInt::ToDouble(aRight) == JavascriptNumber::GetValue(aLeft);
  505. }
  506. else if(JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  507. {
  508. return JavascriptNumber::GetValue(aLeft) == JavascriptNumber::GetValue(aRight);
  509. }
  510. else
  511. {
  512. BOOL res = RecyclableObject::UnsafeFromVar(aRight)->Equals(aLeft, &result, requestContext);
  513. AssertMsg(res, "Should have handled this");
  514. return result;
  515. }
  516. }
  517. if (RecyclableObject::UnsafeFromVar(aLeft)->Equals(aRight, &result, requestContext))
  518. {
  519. return result;
  520. }
  521. else
  522. {
  523. return false;
  524. }
  525. JIT_HELPER_END(Op_Equal_Full);
  526. }
  527. BOOL JavascriptOperators::Greater_Full(Var aLeft,Var aRight,ScriptContext* scriptContext)
  528. {
  529. JIT_HELPER_REENTRANT_HEADER(Op_Greater_Full);
  530. return RelationalComparisonHelper(aRight, aLeft, scriptContext, false, false);
  531. JIT_HELPER_END(Op_Greater_Full);
  532. }
  533. BOOL JavascriptOperators::Less_Full(Var aLeft, Var aRight, ScriptContext* scriptContext)
  534. {
  535. return RelationalComparisonHelper(aLeft, aRight, scriptContext, true, false);
  536. }
  537. BOOL JavascriptOperators::RelationalComparisonHelper(Var aLeft, Var aRight, ScriptContext* scriptContext, bool leftFirst, bool undefinedAs)
  538. {
  539. TypeId typeId = JavascriptOperators::GetTypeId(aLeft);
  540. if (typeId == TypeIds_Null)
  541. {
  542. aLeft=TaggedInt::ToVarUnchecked(0);
  543. }
  544. else if (typeId == TypeIds_Undefined)
  545. {
  546. aLeft=scriptContext->GetLibrary()->GetNaN();
  547. }
  548. typeId = JavascriptOperators::GetTypeId(aRight);
  549. if (typeId == TypeIds_Null)
  550. {
  551. aRight=TaggedInt::ToVarUnchecked(0);
  552. }
  553. else if (typeId == TypeIds_Undefined)
  554. {
  555. aRight=scriptContext->GetLibrary()->GetNaN();
  556. }
  557. double dblLeft, dblRight;
  558. TypeId leftType = JavascriptOperators::GetTypeId(aLeft);
  559. TypeId rightType = JavascriptOperators::GetTypeId(aRight);
  560. switch (leftType)
  561. {
  562. case TypeIds_Integer:
  563. dblLeft = TaggedInt::ToDouble(aLeft);
  564. switch (rightType)
  565. {
  566. case TypeIds_Integer:
  567. dblRight = TaggedInt::ToDouble(aRight);
  568. break;
  569. case TypeIds_Number:
  570. dblRight = JavascriptNumber::GetValue(aRight);
  571. break;
  572. default:
  573. dblRight = JavascriptConversion::ToNumber(aRight, scriptContext);
  574. break;
  575. }
  576. break;
  577. case TypeIds_Number:
  578. dblLeft = JavascriptNumber::GetValue(aLeft);
  579. switch (rightType)
  580. {
  581. case TypeIds_Integer:
  582. dblRight = TaggedInt::ToDouble(aRight);
  583. break;
  584. case TypeIds_Number:
  585. dblRight = JavascriptNumber::GetValue(aRight);
  586. break;
  587. default:
  588. dblRight = JavascriptConversion::ToNumber(aRight, scriptContext);
  589. break;
  590. }
  591. break;
  592. case TypeIds_Int64Number:
  593. {
  594. switch (rightType)
  595. {
  596. case TypeIds_Int64Number:
  597. {
  598. __int64 leftValue = JavascriptInt64Number::UnsafeFromVar(aLeft)->GetValue();
  599. __int64 rightValue = JavascriptInt64Number::UnsafeFromVar(aRight)->GetValue();
  600. return leftValue < rightValue;
  601. }
  602. break;
  603. case TypeIds_UInt64Number:
  604. {
  605. __int64 leftValue = JavascriptInt64Number::UnsafeFromVar(aLeft)->GetValue();
  606. unsigned __int64 rightValue = JavascriptUInt64Number::UnsafeFromVar(aRight)->GetValue();
  607. if (rightValue <= INT_MAX && leftValue >= 0)
  608. {
  609. return leftValue < (__int64)rightValue;
  610. }
  611. }
  612. break;
  613. }
  614. dblLeft = (double)JavascriptInt64Number::UnsafeFromVar(aLeft)->GetValue();
  615. dblRight = JavascriptConversion::ToNumber(aRight, scriptContext);
  616. }
  617. break;
  618. // we cannot do double conversion between 2 int64 numbers as we can get wrong result after conversion
  619. // i.e., two different numbers become the same after losing precision. We'll continue dbl comparison
  620. // if either number is not an int64 number.
  621. case TypeIds_UInt64Number:
  622. {
  623. switch (rightType)
  624. {
  625. case TypeIds_Int64Number:
  626. {
  627. unsigned __int64 leftValue = JavascriptUInt64Number::UnsafeFromVar(aLeft)->GetValue();
  628. __int64 rightValue = JavascriptInt64Number::UnsafeFromVar(aRight)->GetValue();
  629. if (leftValue < INT_MAX && rightValue >= 0)
  630. {
  631. return (__int64)leftValue < rightValue;
  632. }
  633. }
  634. break;
  635. case TypeIds_UInt64Number:
  636. {
  637. unsigned __int64 leftValue = JavascriptUInt64Number::UnsafeFromVar(aLeft)->GetValue();
  638. unsigned __int64 rightValue = JavascriptUInt64Number::UnsafeFromVar(aRight)->GetValue();
  639. return leftValue < rightValue;
  640. }
  641. break;
  642. }
  643. dblLeft = (double)JavascriptUInt64Number::UnsafeFromVar(aLeft)->GetValue();
  644. dblRight = JavascriptConversion::ToNumber(aRight, scriptContext);
  645. }
  646. break;
  647. case TypeIds_String:
  648. switch (rightType)
  649. {
  650. case TypeIds_Integer:
  651. case TypeIds_Number:
  652. case TypeIds_Boolean:
  653. break;
  654. default:
  655. aRight = JavascriptConversion::ToPrimitive<JavascriptHint::HintNumber>(aRight, scriptContext);
  656. rightType = JavascriptOperators::GetTypeId(aRight);
  657. if (rightType != TypeIds_String)
  658. {
  659. dblRight = JavascriptConversion::ToNumber(aRight, scriptContext);
  660. break;
  661. }
  662. case TypeIds_String:
  663. return JavascriptString::LessThan(aLeft, aRight);
  664. }
  665. dblLeft = JavascriptConversion::ToNumber(aLeft, scriptContext);
  666. dblRight = JavascriptConversion::ToNumber(aRight, scriptContext);
  667. break;
  668. case TypeIds_Boolean:
  669. case TypeIds_Null:
  670. case TypeIds_Undefined:
  671. case TypeIds_Symbol:
  672. dblLeft = JavascriptConversion::ToNumber(aLeft, scriptContext);
  673. dblRight = JavascriptConversion::ToNumber(aRight, scriptContext);
  674. break;
  675. default:
  676. if (leftFirst)
  677. {
  678. aLeft = JavascriptConversion::ToPrimitive<JavascriptHint::HintNumber>(aLeft, scriptContext);
  679. aRight = JavascriptConversion::ToPrimitive<JavascriptHint::HintNumber>(aRight, scriptContext);
  680. }
  681. else
  682. {
  683. aRight = JavascriptConversion::ToPrimitive<JavascriptHint::HintNumber>(aRight, scriptContext);
  684. aLeft = JavascriptConversion::ToPrimitive<JavascriptHint::HintNumber>(aLeft, scriptContext);
  685. }
  686. //BugFix: When @@ToPrimitive of an object is overridden with a function that returns null/undefined
  687. //this helper will fall into a inescapable goto loop as the checks for null/undefined were outside of the path
  688. return RelationalComparisonHelper(aLeft, aRight, scriptContext, leftFirst, undefinedAs);
  689. }
  690. //
  691. // And +0,-0 that is not implemented fully
  692. //
  693. if (JavascriptNumber::IsNan(dblLeft) || JavascriptNumber::IsNan(dblRight))
  694. {
  695. return undefinedAs;
  696. }
  697. // this will succeed for -0.0 == 0.0 case as well
  698. if (dblLeft == dblRight)
  699. {
  700. return false;
  701. }
  702. return dblLeft < dblRight;
  703. }
  704. BOOL JavascriptOperators::StrictEqualString(Var aLeft, JavascriptString* aRight)
  705. {
  706. JavascriptString* leftStr = TryFromVar<JavascriptString>(aLeft);
  707. if (!leftStr)
  708. {
  709. return false;
  710. }
  711. JIT_HELPER_REENTRANT_HEADER(Op_StrictEqualString);
  712. JIT_HELPER_SAME_ATTRIBUTES(Op_StrictEqualString, Op_StrictEqual);
  713. return JavascriptString::Equals(leftStr, aRight);
  714. JIT_HELPER_END(Op_StrictEqualString);
  715. }
  716. BOOL JavascriptOperators::StrictEqualEmptyString(Var aLeft)
  717. {
  718. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_StrictEqualEmptyString);
  719. JavascriptString * string = JavascriptOperators::TryFromVar<JavascriptString>(aLeft);
  720. if (!string)
  721. {
  722. return false;
  723. }
  724. Assert(string);
  725. return string->GetLength() == 0;
  726. JIT_HELPER_END(Op_StrictEqualEmptyString);
  727. }
  728. BOOL JavascriptOperators::StrictEqual(Var aLeft, Var aRight, ScriptContext* requestContext)
  729. {
  730. JIT_HELPER_REENTRANT_HEADER(Op_StrictEqual);
  731. double dblLeft, dblRight;
  732. TypeId rightType, leftType;
  733. leftType = JavascriptOperators::GetTypeId(aLeft);
  734. // Because NaN !== NaN, we may not return TRUE when typeId is Number
  735. if (aLeft == aRight && leftType != TypeIds_Number) return TRUE;
  736. rightType = JavascriptOperators::GetTypeId(aRight);
  737. switch (leftType)
  738. {
  739. case TypeIds_String:
  740. switch (rightType)
  741. {
  742. case TypeIds_String:
  743. return JavascriptString::Equals(JavascriptString::UnsafeFromVar(aLeft), JavascriptString::UnsafeFromVar(aRight));
  744. }
  745. return FALSE;
  746. case TypeIds_Integer:
  747. switch (rightType)
  748. {
  749. case TypeIds_Integer:
  750. return aLeft == aRight;
  751. // we don't need to worry about int64: it cannot equal as we create
  752. // JavascriptInt64Number only in overflow scenarios.
  753. case TypeIds_Number:
  754. dblLeft = TaggedInt::ToDouble(aLeft);
  755. dblRight = JavascriptNumber::GetValue(aRight);
  756. goto CommonNumber;
  757. }
  758. return FALSE;
  759. case TypeIds_Int64Number:
  760. switch (rightType)
  761. {
  762. case TypeIds_Int64Number:
  763. {
  764. __int64 leftValue = JavascriptInt64Number::UnsafeFromVar(aLeft)->GetValue();
  765. __int64 rightValue = JavascriptInt64Number::UnsafeFromVar(aRight)->GetValue();
  766. return leftValue == rightValue;
  767. }
  768. case TypeIds_UInt64Number:
  769. {
  770. __int64 leftValue = JavascriptInt64Number::UnsafeFromVar(aLeft)->GetValue();
  771. unsigned __int64 rightValue = JavascriptInt64Number::FromVar(aRight)->GetValue();
  772. return ((unsigned __int64)leftValue == rightValue);
  773. }
  774. case TypeIds_Number:
  775. dblLeft = (double)JavascriptInt64Number::UnsafeFromVar(aLeft)->GetValue();
  776. dblRight = JavascriptNumber::GetValue(aRight);
  777. goto CommonNumber;
  778. }
  779. return FALSE;
  780. case TypeIds_UInt64Number:
  781. switch (rightType)
  782. {
  783. case TypeIds_Int64Number:
  784. {
  785. unsigned __int64 leftValue = JavascriptUInt64Number::UnsafeFromVar(aLeft)->GetValue();
  786. __int64 rightValue = JavascriptInt64Number::UnsafeFromVar(aRight)->GetValue();
  787. return (leftValue == (unsigned __int64)rightValue);
  788. }
  789. case TypeIds_UInt64Number:
  790. {
  791. unsigned __int64 leftValue = JavascriptUInt64Number::UnsafeFromVar(aLeft)->GetValue();
  792. unsigned __int64 rightValue = JavascriptInt64Number::FromVar(aRight)->GetValue();
  793. return leftValue == rightValue;
  794. }
  795. case TypeIds_Number:
  796. dblLeft = (double)JavascriptUInt64Number::UnsafeFromVar(aLeft)->GetValue();
  797. dblRight = JavascriptNumber::GetValue(aRight);
  798. goto CommonNumber;
  799. }
  800. return FALSE;
  801. case TypeIds_Number:
  802. switch (rightType)
  803. {
  804. case TypeIds_Integer:
  805. dblLeft = JavascriptNumber::GetValue(aLeft);
  806. dblRight = TaggedInt::ToDouble(aRight);
  807. goto CommonNumber;
  808. case TypeIds_Int64Number:
  809. dblLeft = JavascriptNumber::GetValue(aLeft);
  810. dblRight = (double)JavascriptInt64Number::FromVar(aRight)->GetValue();
  811. goto CommonNumber;
  812. case TypeIds_UInt64Number:
  813. dblLeft = JavascriptNumber::GetValue(aLeft);
  814. dblRight = (double)JavascriptUInt64Number::UnsafeFromVar(aRight)->GetValue();
  815. goto CommonNumber;
  816. case TypeIds_Number:
  817. dblLeft = JavascriptNumber::GetValue(aLeft);
  818. dblRight = JavascriptNumber::GetValue(aRight);
  819. CommonNumber:
  820. return FEqualDbl(dblLeft, dblRight);
  821. }
  822. return FALSE;
  823. case TypeIds_Boolean:
  824. switch (rightType)
  825. {
  826. case TypeIds_Boolean:
  827. return aLeft == aRight;
  828. }
  829. return FALSE;
  830. case TypeIds_Undefined:
  831. return rightType == TypeIds_Undefined;
  832. case TypeIds_Null:
  833. return rightType == TypeIds_Null;
  834. case TypeIds_Array:
  835. return (rightType == TypeIds_Array && aLeft == aRight);
  836. #if DBG
  837. case TypeIds_Symbol:
  838. if (rightType == TypeIds_Symbol)
  839. {
  840. const PropertyRecord* leftValue = JavascriptSymbol::UnsafeFromVar(aLeft)->GetValue();
  841. const PropertyRecord* rightValue = JavascriptSymbol::UnsafeFromVar(aRight)->GetValue();
  842. Assert(leftValue != rightValue);
  843. }
  844. break;
  845. #endif
  846. case TypeIds_GlobalObject:
  847. case TypeIds_HostDispatch:
  848. switch (rightType)
  849. {
  850. case TypeIds_HostDispatch:
  851. case TypeIds_GlobalObject:
  852. {
  853. BOOL result;
  854. if(RecyclableObject::UnsafeFromVar(aLeft)->StrictEquals(aRight, &result, requestContext))
  855. {
  856. return result;
  857. }
  858. return false;
  859. }
  860. }
  861. break;
  862. }
  863. if (RecyclableObject::FromVar(aLeft)->IsExternal())
  864. {
  865. BOOL result;
  866. if (RecyclableObject::FromVar(aLeft)->StrictEquals(aRight, &result, requestContext))
  867. {
  868. if (result)
  869. {
  870. return TRUE;
  871. }
  872. }
  873. }
  874. if (!TaggedNumber::Is(aRight) && RecyclableObject::FromVar(aRight)->IsExternal())
  875. {
  876. BOOL result;
  877. if (RecyclableObject::FromVar(aRight)->StrictEquals(aLeft, &result, requestContext))
  878. {
  879. if (result)
  880. {
  881. return TRUE;
  882. }
  883. }
  884. }
  885. return aLeft == aRight;
  886. JIT_HELPER_END(Op_StrictEqual);
  887. }
  888. BOOL JavascriptOperators::HasOwnProperty(
  889. Var instance,
  890. PropertyId propertyId,
  891. _In_ ScriptContext* requestContext,
  892. _In_opt_ PropertyString* propString)
  893. {
  894. if (TaggedNumber::Is(instance))
  895. {
  896. return FALSE;
  897. }
  898. RecyclableObject* object = RecyclableObject::UnsafeFromVar(instance);
  899. if (JavascriptProxy::Is(instance))
  900. {
  901. PropertyDescriptor desc;
  902. return GetOwnPropertyDescriptor(object, propertyId, requestContext, &desc);
  903. }
  904. // If we have a PropertyString, attempt to shortcut the lookup by using its caches
  905. if (propString != nullptr)
  906. {
  907. PropertyCacheOperationInfo info;
  908. if (propString->GetLdElemInlineCache()->PretendTryGetProperty(object->GetType(), &info))
  909. {
  910. switch (info.cacheType)
  911. {
  912. case CacheType_Local:
  913. Assert(object->HasOwnProperty(propertyId));
  914. return TRUE;
  915. case CacheType_Proto:
  916. Assert(!object->HasOwnProperty(propertyId));
  917. return FALSE;
  918. default:
  919. // We had a cache hit, but cache doesn't tell us if we have an own property
  920. break;
  921. }
  922. }
  923. if (propString->GetStElemInlineCache()->PretendTrySetProperty(object->GetType(), object->GetType(), &info))
  924. {
  925. switch (info.cacheType)
  926. {
  927. case CacheType_Local:
  928. Assert(object->HasOwnProperty(propertyId));
  929. return TRUE;
  930. case CacheType_LocalWithoutProperty:
  931. Assert(!object->HasOwnProperty(propertyId));
  932. return FALSE;
  933. default:
  934. // We had a cache hit, but cache doesn't tell us if we have an own property
  935. break;
  936. }
  937. }
  938. }
  939. return object && object->HasOwnProperty(propertyId);
  940. }
  941. BOOL JavascriptOperators::GetOwnAccessors(Var instance, PropertyId propertyId, Var* getter, Var* setter, ScriptContext * requestContext)
  942. {
  943. BOOL result;
  944. if (TaggedNumber::Is(instance))
  945. {
  946. result = false;
  947. }
  948. else
  949. {
  950. RecyclableObject* object = RecyclableObject::UnsafeFromVar(instance);
  951. result = object && object->GetAccessors(propertyId, getter, setter, requestContext);
  952. }
  953. return result;
  954. }
  955. JavascriptArray* JavascriptOperators::GetOwnPropertyNames(Var instance, ScriptContext *scriptContext)
  956. {
  957. RecyclableObject *object = RecyclableObject::FromVar(ToObject(instance, scriptContext));
  958. JavascriptProxy * proxy = JavascriptOperators::TryFromVar<JavascriptProxy>(instance);
  959. if (proxy)
  960. {
  961. return proxy->PropertyKeysTrap(JavascriptProxy::KeysTrapKind::GetOwnPropertyNamesKind, scriptContext);
  962. }
  963. return JavascriptObject::CreateOwnStringPropertiesHelper(object, scriptContext);
  964. }
  965. JavascriptArray* JavascriptOperators::GetOwnPropertySymbols(Var instance, ScriptContext *scriptContext)
  966. {
  967. RecyclableObject *object = RecyclableObject::FromVar(ToObject(instance, scriptContext));
  968. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Object_Constructor_getOwnPropertySymbols);
  969. JavascriptProxy* proxy = JavascriptOperators::TryFromVar<JavascriptProxy>(instance);
  970. if (proxy)
  971. {
  972. return proxy->PropertyKeysTrap(JavascriptProxy::KeysTrapKind::GetOwnPropertySymbolKind, scriptContext);
  973. }
  974. return JavascriptObject::CreateOwnSymbolPropertiesHelper(object, scriptContext);
  975. }
  976. JavascriptArray* JavascriptOperators::GetOwnPropertyKeys(Var instance, ScriptContext* scriptContext)
  977. {
  978. RecyclableObject *object = RecyclableObject::FromVar(ToObject(instance, scriptContext));
  979. JavascriptProxy* proxy = JavascriptOperators::TryFromVar<JavascriptProxy>(instance);
  980. if (proxy)
  981. {
  982. return proxy->PropertyKeysTrap(JavascriptProxy::KeysTrapKind::KeysKind, scriptContext);
  983. }
  984. return JavascriptObject::CreateOwnStringSymbolPropertiesHelper(object, scriptContext);
  985. }
  986. JavascriptArray* JavascriptOperators::GetOwnEnumerablePropertyNames(RecyclableObject* object, ScriptContext* scriptContext)
  987. {
  988. JavascriptProxy* proxy = JavascriptOperators::TryFromVar<JavascriptProxy>(object);
  989. if (proxy)
  990. {
  991. JavascriptArray* proxyResult = proxy->PropertyKeysTrap(JavascriptProxy::KeysTrapKind::GetOwnPropertyNamesKind, scriptContext);
  992. JavascriptArray* proxyResultToReturn = scriptContext->GetLibrary()->CreateArray(0);
  993. // filter enumerable keys
  994. uint32 resultLength = proxyResult->GetLength();
  995. Var element;
  996. const Js::PropertyRecord *propertyRecord = nullptr;
  997. uint32 index = 0;
  998. for (uint32 i = 0; i < resultLength; i++)
  999. {
  1000. element = proxyResult->DirectGetItem(i);
  1001. Assert(!JavascriptSymbol::Is(element));
  1002. PropertyDescriptor propertyDescriptor;
  1003. JavascriptConversion::ToPropertyKey(element, scriptContext, &propertyRecord, nullptr);
  1004. if (JavascriptOperators::GetOwnPropertyDescriptor(object, propertyRecord->GetPropertyId(), scriptContext, &propertyDescriptor))
  1005. {
  1006. if (propertyDescriptor.IsEnumerable())
  1007. {
  1008. proxyResultToReturn->DirectSetItemAt(index++, CrossSite::MarshalVar(scriptContext, element));
  1009. }
  1010. }
  1011. }
  1012. return proxyResultToReturn;
  1013. }
  1014. return JavascriptObject::CreateOwnEnumerableStringPropertiesHelper(object, scriptContext);
  1015. }
  1016. JavascriptArray* JavascriptOperators::GetOwnEnumerablePropertyNamesSymbols(RecyclableObject* object, ScriptContext* scriptContext)
  1017. {
  1018. JavascriptProxy* proxy = JavascriptOperators::TryFromVar<JavascriptProxy>(object);
  1019. if (proxy)
  1020. {
  1021. return proxy->PropertyKeysTrap(JavascriptProxy::KeysTrapKind::KeysKind, scriptContext);
  1022. }
  1023. return JavascriptObject::CreateOwnEnumerableStringSymbolPropertiesHelper(object, scriptContext);
  1024. }
  1025. BOOL JavascriptOperators::GetOwnProperty(Var instance, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo * propertyValueInfo)
  1026. {
  1027. BOOL result;
  1028. if (TaggedNumber::Is(instance))
  1029. {
  1030. result = false;
  1031. }
  1032. else
  1033. {
  1034. RecyclableObject* object = RecyclableObject::FromVar(instance);
  1035. result = object && object->GetProperty(object, propertyId, value, propertyValueInfo, requestContext);
  1036. if (propertyValueInfo && result)
  1037. {
  1038. // We can only update the cache in case a property was found, because if it wasn't found, we don't know if it is missing or on a prototype
  1039. CacheOperators::CachePropertyRead(instance, object, false /* isRoot */, propertyId, false /* isMissing */, propertyValueInfo, requestContext);
  1040. }
  1041. }
  1042. return result;
  1043. }
  1044. BOOL JavascriptOperators::GetOwnPropertyDescriptor(RecyclableObject* obj, JavascriptString* propertyKey, ScriptContext* scriptContext, PropertyDescriptor* propertyDescriptor)
  1045. {
  1046. return JavascriptOperators::GetOwnPropertyDescriptor(obj, JavascriptOperators::GetPropertyId(propertyKey, scriptContext), scriptContext, propertyDescriptor);
  1047. }
  1048. // ES5's [[GetOwnProperty]].
  1049. // Return value:
  1050. // FALSE means "undefined" PD.
  1051. // TRUE means success. The propertyDescriptor parameter gets the descriptor.
  1052. //
  1053. BOOL JavascriptOperators::GetOwnPropertyDescriptor(RecyclableObject* obj, PropertyId propertyId, ScriptContext* scriptContext, PropertyDescriptor* propertyDescriptor)
  1054. {
  1055. Assert(obj);
  1056. Assert(scriptContext);
  1057. Assert(propertyDescriptor);
  1058. if (JavascriptProxy::Is(obj))
  1059. {
  1060. return JavascriptProxy::GetOwnPropertyDescriptor(obj, propertyId, scriptContext, propertyDescriptor);
  1061. }
  1062. Var getter, setter;
  1063. if (false == JavascriptOperators::GetOwnAccessors(obj, propertyId, &getter, &setter, scriptContext))
  1064. {
  1065. Var value = nullptr;
  1066. if (false == JavascriptOperators::GetOwnProperty(obj, propertyId, &value, scriptContext, nullptr))
  1067. {
  1068. return FALSE;
  1069. }
  1070. if (nullptr != value)
  1071. {
  1072. propertyDescriptor->SetValue(value);
  1073. }
  1074. //CONSIDER : Its expensive to query for each flag from type system. Combine this with the GetOwnProperty to get all the flags
  1075. //at once. This will require a new API from type system and override in all the types which overrides IsEnumerable etc.
  1076. //Currently there is no performance tuning for ES5. This should be ok.
  1077. propertyDescriptor->SetWritable(FALSE != obj->IsWritable(propertyId));
  1078. }
  1079. else
  1080. {
  1081. if (nullptr == getter)
  1082. {
  1083. getter = scriptContext->GetLibrary()->GetUndefined();
  1084. }
  1085. propertyDescriptor->SetGetter(getter);
  1086. if (nullptr == setter)
  1087. {
  1088. setter = scriptContext->GetLibrary()->GetUndefined();
  1089. }
  1090. propertyDescriptor->SetSetter(setter);
  1091. }
  1092. propertyDescriptor->SetConfigurable(FALSE != obj->IsConfigurable(propertyId));
  1093. propertyDescriptor->SetEnumerable(FALSE != obj->IsEnumerable(propertyId));
  1094. return TRUE;
  1095. }
  1096. inline RecyclableObject* JavascriptOperators::GetPrototypeNoTrap(RecyclableObject* instance)
  1097. {
  1098. Type* type = instance->GetType();
  1099. if (type->HasSpecialPrototype())
  1100. {
  1101. if (type->GetTypeId() == TypeIds_Proxy)
  1102. {
  1103. // get back null
  1104. Assert(type->GetPrototype() == instance->GetScriptContext()->GetLibrary()->GetNull());
  1105. return type->GetPrototype();
  1106. }
  1107. else
  1108. {
  1109. return instance->GetPrototypeSpecial();
  1110. }
  1111. }
  1112. return type->GetPrototype();
  1113. }
  1114. BOOL JavascriptOperators::IsRemoteArray(RecyclableObject* instance)
  1115. {
  1116. TypeId remoteTypeId = TypeIds_Limit;
  1117. return (JavascriptOperators::GetRemoteTypeId(instance, &remoteTypeId) &&
  1118. DynamicObject::IsAnyArrayTypeId(remoteTypeId));
  1119. }
  1120. bool JavascriptOperators::IsArray(_In_ JavascriptProxy * instance)
  1121. {
  1122. // If it is a proxy, follow to the end of the proxy chain before checking if it is an array again.
  1123. JavascriptProxy * proxy = instance;
  1124. while (true)
  1125. {
  1126. RecyclableObject * targetInstance = proxy->GetTarget();
  1127. proxy = JavascriptOperators::TryFromVar<JavascriptProxy>(targetInstance);
  1128. if (proxy == nullptr)
  1129. {
  1130. return DynamicObject::IsAnyArray(targetInstance) || IsRemoteArray(targetInstance);
  1131. }
  1132. }
  1133. }
  1134. bool JavascriptOperators::IsArray(_In_ RecyclableObject* instance)
  1135. {
  1136. if (DynamicObject::IsAnyArray(instance))
  1137. {
  1138. return TRUE;
  1139. }
  1140. JavascriptProxy* proxy = JavascriptOperators::TryFromVar<JavascriptProxy>(instance);
  1141. if (proxy)
  1142. {
  1143. return IsArray(proxy);
  1144. }
  1145. return IsRemoteArray(instance);
  1146. }
  1147. bool JavascriptOperators::IsArray(_In_ Var instanceVar)
  1148. {
  1149. RecyclableObject* instanceObj = TryFromVar<RecyclableObject>(instanceVar);
  1150. return instanceObj && IsArray(instanceObj);
  1151. }
  1152. bool JavascriptOperators::IsConstructor(_In_ JavascriptProxy * instance)
  1153. {
  1154. // If it is a proxy, follow to the end of the proxy chain before checking if it is a constructor again.
  1155. JavascriptProxy * proxy = instance;
  1156. while (true)
  1157. {
  1158. RecyclableObject* targetInstance = proxy->GetTarget();
  1159. proxy = JavascriptOperators::TryFromVar<JavascriptProxy>(targetInstance);
  1160. if (proxy == nullptr)
  1161. {
  1162. JavascriptFunction* function = JavascriptOperators::TryFromVar<JavascriptFunction>(targetInstance);
  1163. return function && function->IsConstructor();
  1164. }
  1165. }
  1166. }
  1167. bool JavascriptOperators::IsConstructor(_In_ RecyclableObject* instanceObj)
  1168. {
  1169. JavascriptProxy* proxy = JavascriptOperators::TryFromVar<JavascriptProxy>(instanceObj);
  1170. if (proxy)
  1171. {
  1172. return IsConstructor(proxy);
  1173. }
  1174. JavascriptFunction* function = JavascriptOperators::TryFromVar<JavascriptFunction>(instanceObj);
  1175. return function && function->IsConstructor();
  1176. }
  1177. bool JavascriptOperators::IsConstructor(_In_ Var instanceVar)
  1178. {
  1179. RecyclableObject* instanceObj = TryFromVar<RecyclableObject>(instanceVar);
  1180. return instanceObj && IsConstructor(instanceObj);
  1181. }
  1182. BOOL JavascriptOperators::IsConcatSpreadable(Var instanceVar)
  1183. {
  1184. // an object is spreadable under two condition, either it is a JsArray
  1185. // or you define an isconcatSpreadable flag on it.
  1186. if (!JavascriptOperators::IsObject(instanceVar))
  1187. {
  1188. return false;
  1189. }
  1190. RecyclableObject* instance = RecyclableObject::UnsafeFromVar(instanceVar);
  1191. ScriptContext* scriptContext = instance->GetScriptContext();
  1192. if (!PHASE_OFF1(IsConcatSpreadableCachePhase))
  1193. {
  1194. BOOL retVal = FALSE;
  1195. Type *instanceType = instance->GetType();
  1196. IsConcatSpreadableCache *isConcatSpreadableCache = scriptContext->GetThreadContext()->GetIsConcatSpreadableCache();
  1197. if (isConcatSpreadableCache->TryGetIsConcatSpreadable(instanceType, &retVal))
  1198. {
  1199. OUTPUT_TRACE(Phase::IsConcatSpreadableCachePhase, _u("IsConcatSpreadableCache hit: %p\n"), instanceType);
  1200. return retVal;
  1201. }
  1202. Var spreadable = nullptr;
  1203. BOOL hasUserDefinedSpreadable = JavascriptOperators::GetProperty(instance, instance, PropertyIds::_symbolIsConcatSpreadable, &spreadable, scriptContext);
  1204. if (hasUserDefinedSpreadable && spreadable != scriptContext->GetLibrary()->GetUndefined())
  1205. {
  1206. return JavascriptConversion::ToBoolean(spreadable, scriptContext);
  1207. }
  1208. retVal = JavascriptOperators::IsArray(instance);
  1209. if (!hasUserDefinedSpreadable)
  1210. {
  1211. OUTPUT_TRACE(Phase::IsConcatSpreadableCachePhase, _u("IsConcatSpreadableCache saved: %p\n"), instanceType);
  1212. isConcatSpreadableCache->CacheIsConcatSpreadable(instanceType, retVal);
  1213. }
  1214. return retVal;
  1215. }
  1216. Var spreadable = JavascriptOperators::GetProperty(instance, PropertyIds::_symbolIsConcatSpreadable, scriptContext);
  1217. if (spreadable != scriptContext->GetLibrary()->GetUndefined())
  1218. {
  1219. return JavascriptConversion::ToBoolean(spreadable, scriptContext);
  1220. }
  1221. return JavascriptOperators::IsArray(instance);
  1222. }
  1223. bool JavascriptOperators::IsConstructorSuperCall(Arguments args)
  1224. {
  1225. Var newTarget = args.GetNewTarget();
  1226. return args.IsNewCall() && newTarget != nullptr
  1227. && !JavascriptOperators::IsUndefined(newTarget);
  1228. }
  1229. bool JavascriptOperators::GetAndAssertIsConstructorSuperCall(Arguments args)
  1230. {
  1231. bool isCtorSuperCall = JavascriptOperators::IsConstructorSuperCall(args);
  1232. Assert(isCtorSuperCall || !args.IsNewCall()
  1233. || args[0] == nullptr || JavascriptOperators::GetTypeId(args[0]) == TypeIds_HostDispatch);
  1234. return isCtorSuperCall;
  1235. }
  1236. Var JavascriptOperators::OP_LdCustomSpreadIteratorList(Var aRight, ScriptContext* scriptContext)
  1237. {
  1238. JIT_HELPER_REENTRANT_HEADER(Op_ToSpreadedFunctionArgument);
  1239. #if ENABLE_COPYONACCESS_ARRAY
  1240. // We know we're going to read from this array. Do the conversion before we try to perform checks on the head segment.
  1241. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray(aRight);
  1242. #endif
  1243. #ifdef ENABLE_JS_BUILTINS
  1244. scriptContext->GetLibrary()->EnsureBuiltInEngineIsReady();
  1245. #endif
  1246. RecyclableObject* function = GetIteratorFunction(aRight, scriptContext);
  1247. JavascriptMethod method = function->GetEntryPoint();
  1248. if (((JavascriptArray::Is(aRight) &&
  1249. (
  1250. JavascriptLibrary::IsDefaultArrayValuesFunction(function, scriptContext)
  1251. // Verify that the head segment of the array covers all elements with no gaps.
  1252. // Accessing an element on the prototype could have side-effects that would invalidate the optimization.
  1253. && JavascriptArray::UnsafeFromVar(aRight)->GetHead()->next == nullptr
  1254. && JavascriptArray::UnsafeFromVar(aRight)->GetHead()->left == 0
  1255. && JavascriptArray::UnsafeFromVar(aRight)->GetHead()->length == JavascriptArray::FromVar(aRight)->GetLength()
  1256. && JavascriptArray::UnsafeFromVar(aRight)->HasNoMissingValues()
  1257. && !JavascriptArray::UnsafeFromVar(aRight)->IsCrossSiteObject()
  1258. )) ||
  1259. (TypedArrayBase::Is(aRight) && method == TypedArrayBase::EntryInfo::Values.GetOriginalEntryPoint()))
  1260. // We can't optimize away the iterator if the array iterator prototype is user defined.
  1261. && !JavascriptLibrary::ArrayIteratorPrototypeHasUserDefinedNext(scriptContext))
  1262. {
  1263. return RecyclerNew(scriptContext->GetRecycler(), SpreadArgument, aRight, true /*useDirectCall*/, scriptContext->GetLibrary()->GetSpreadArgumentType());
  1264. }
  1265. ThreadContext *threadContext = scriptContext->GetThreadContext();
  1266. Var iteratorVar =
  1267. threadContext->ExecuteImplicitCall(function, ImplicitCall_Accessor, [=]() -> Var
  1268. {
  1269. return CALL_FUNCTION(threadContext, function, CallInfo(Js::CallFlags_Value, 1), aRight);
  1270. });
  1271. if (!JavascriptOperators::IsObject(iteratorVar))
  1272. {
  1273. if (!threadContext->RecordImplicitException())
  1274. {
  1275. return scriptContext->GetLibrary()->GetUndefined();
  1276. }
  1277. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject);
  1278. }
  1279. return RecyclerNew(scriptContext->GetRecycler(), SpreadArgument, iteratorVar, false /*useDirectCall*/, scriptContext->GetLibrary()->GetSpreadArgumentType());
  1280. JIT_HELPER_END(Op_ToSpreadedFunctionArgument);
  1281. }
  1282. BOOL JavascriptOperators::IsPropertyUnscopable(Var instanceVar, JavascriptString *propertyString)
  1283. {
  1284. // This never gets called.
  1285. Throw::InternalError();
  1286. }
  1287. BOOL JavascriptOperators::IsPropertyUnscopable(Var instanceVar, PropertyId propertyId)
  1288. {
  1289. RecyclableObject* instance = RecyclableObject::FromVar(instanceVar);
  1290. ScriptContext * scriptContext = instance->GetScriptContext();
  1291. Var unscopables = JavascriptOperators::GetProperty(instance, PropertyIds::_symbolUnscopables, scriptContext);
  1292. if (JavascriptOperators::IsObject(unscopables))
  1293. {
  1294. DynamicObject *unscopablesList = DynamicObject::FromVar(unscopables);
  1295. Var value = nullptr;
  1296. //8.1.1.2.1.9.c If blocked is not undefined
  1297. if (JavascriptOperators::GetProperty(unscopablesList, propertyId, &value, scriptContext))
  1298. {
  1299. return JavascriptConversion::ToBoolean(value, scriptContext);
  1300. }
  1301. }
  1302. return false;
  1303. }
  1304. BOOL JavascriptOperators::HasProperty(RecyclableObject* instance, PropertyId propertyId)
  1305. {
  1306. while (!JavascriptOperators::IsNull(instance))
  1307. {
  1308. PropertyQueryFlags result = instance->HasPropertyQuery(propertyId, nullptr /*info*/);
  1309. if (result != PropertyQueryFlags::Property_NotFound)
  1310. {
  1311. return JavascriptConversion::PropertyQueryFlagsToBoolean(result); // return false if instance is typed array and HasPropertyQuery() returns PropertyQueryFlags::Property_Found_Undefined
  1312. }
  1313. instance = JavascriptOperators::GetPrototypeNoTrap(instance);
  1314. }
  1315. return false;
  1316. }
  1317. BOOL JavascriptOperators::HasPropertyUnscopables(RecyclableObject* instance, PropertyId propertyId)
  1318. {
  1319. return JavascriptOperators::HasProperty(instance, propertyId)
  1320. && !IsPropertyUnscopable(instance, propertyId);
  1321. }
  1322. BOOL JavascriptOperators::HasRootProperty(RecyclableObject* instance, PropertyId propertyId)
  1323. {
  1324. Assert(RootObjectBase::Is(instance));
  1325. RootObjectBase* rootObject = static_cast<RootObjectBase*>(instance);
  1326. if (rootObject->HasRootProperty(propertyId))
  1327. {
  1328. return true;
  1329. }
  1330. instance = instance->GetPrototype();
  1331. return HasProperty(instance, propertyId);
  1332. }
  1333. BOOL JavascriptOperators::HasProxyOrPrototypeInlineCacheProperty(RecyclableObject* instance, PropertyId propertyId)
  1334. {
  1335. TypeId typeId;
  1336. typeId = JavascriptOperators::GetTypeId(instance);
  1337. if (typeId == Js::TypeIds_Proxy)
  1338. {
  1339. // let's be more aggressive to disable inline prototype cache when proxy is presented in the prototypechain
  1340. return true;
  1341. }
  1342. do
  1343. {
  1344. instance = instance->GetPrototype();
  1345. typeId = JavascriptOperators::GetTypeId(instance);
  1346. if (typeId == Js::TypeIds_Proxy)
  1347. {
  1348. // let's be more aggressive to disable inline prototype cache when proxy is presented in the prototypechain
  1349. return true;
  1350. }
  1351. if (typeId == TypeIds_Null)
  1352. {
  1353. break;
  1354. }
  1355. /* We can rule out object with deferred type handler, because they would have expanded if they are in the cache */
  1356. if (!instance->HasDeferredTypeHandler() && instance->HasProperty(propertyId)) { return true; }
  1357. } while (typeId != TypeIds_Null);
  1358. return false;
  1359. }
  1360. BOOL JavascriptOperators::OP_HasProperty(Var instance, PropertyId propertyId, ScriptContext* scriptContext)
  1361. {
  1362. JIT_HELPER_REENTRANT_HEADER(Op_HasProperty);
  1363. RecyclableObject* object = TaggedNumber::Is(instance) ?
  1364. scriptContext->GetLibrary()->GetNumberPrototype() :
  1365. RecyclableObject::FromVar(instance);
  1366. BOOL result = HasProperty(object, propertyId);
  1367. return result;
  1368. JIT_HELPER_END(Op_HasProperty);
  1369. }
  1370. BOOL JavascriptOperators::OP_HasOwnProperty(Var instance, PropertyId propertyId, ScriptContext* scriptContext)
  1371. {
  1372. RecyclableObject* object = TaggedNumber::Is(instance) ?
  1373. scriptContext->GetLibrary()->GetNumberPrototype() :
  1374. RecyclableObject::FromVar(instance);
  1375. BOOL result = HasOwnProperty(object, propertyId, scriptContext, nullptr);
  1376. return result;
  1377. }
  1378. // CONSIDER: Have logic similar to HasOwnPropertyNoHostObjectForHeapEnum
  1379. BOOL JavascriptOperators::HasOwnPropertyNoHostObject(Var instance, PropertyId propertyId)
  1380. {
  1381. AssertMsg(!TaggedNumber::Is(instance), "HasOwnPropertyNoHostObject int passed");
  1382. RecyclableObject* object = RecyclableObject::FromVar(instance);
  1383. return object && object->HasOwnPropertyNoHostObject(propertyId);
  1384. }
  1385. // CONSIDER: Remove HasOwnPropertyNoHostObjectForHeapEnum and use GetOwnPropertyNoHostObjectForHeapEnum in its place by changing it
  1386. // to return BOOL, true or false with whether the property exists or not, and return the value if not getter/setter as an out param.
  1387. BOOL JavascriptOperators::HasOwnPropertyNoHostObjectForHeapEnum(Var instance, PropertyId propertyId, ScriptContext* requestContext, Var& getter, Var& setter)
  1388. {
  1389. AssertMsg(!TaggedNumber::Is(instance), "HasOwnPropertyNoHostObjectForHeapEnum int passed");
  1390. RecyclableObject * object = RecyclableObject::FromVar(instance);
  1391. if (StaticType::Is(object->GetTypeId()))
  1392. {
  1393. return FALSE;
  1394. }
  1395. getter = setter = NULL;
  1396. DynamicObject* dynamicObject = DynamicObject::FromVar(instance);
  1397. Assert(dynamicObject->GetScriptContext()->IsHeapEnumInProgress());
  1398. if (dynamicObject->UseDynamicObjectForNoHostObjectAccess())
  1399. {
  1400. if (!dynamicObject->DynamicObject::GetAccessors(propertyId, &getter, &setter, requestContext))
  1401. {
  1402. Var value = nullptr;
  1403. if (!JavascriptConversion::PropertyQueryFlagsToBoolean(dynamicObject->DynamicObject::GetPropertyQuery(instance, propertyId, &value, NULL, requestContext)) ||
  1404. (requestContext->IsUndeclBlockVar(value) && (ActivationObject::Is(instance) || RootObjectBase::Is(instance))))
  1405. {
  1406. return FALSE;
  1407. }
  1408. }
  1409. }
  1410. else
  1411. {
  1412. if (!object->GetAccessors(propertyId, &getter, &setter, requestContext))
  1413. {
  1414. Var value = nullptr;
  1415. if (!object->GetProperty(instance, propertyId, &value, NULL, requestContext) ||
  1416. (requestContext->IsUndeclBlockVar(value) && (ActivationObject::Is(instance) || RootObjectBase::Is(instance))))
  1417. {
  1418. return FALSE;
  1419. }
  1420. }
  1421. }
  1422. return TRUE;
  1423. }
  1424. Var JavascriptOperators::GetOwnPropertyNoHostObjectForHeapEnum(Var instance, PropertyId propertyId, ScriptContext* requestContext, Var& getter, Var& setter)
  1425. {
  1426. AssertMsg(!TaggedNumber::Is(instance), "GetDataPropertyNoHostObject int passed");
  1427. Assert(HasOwnPropertyNoHostObjectForHeapEnum(instance, propertyId, requestContext, getter, setter) || getter || setter);
  1428. DynamicObject* dynamicObject = DynamicObject::FromVar(instance);
  1429. getter = setter = NULL;
  1430. if (NULL == dynamicObject)
  1431. {
  1432. return requestContext->GetLibrary()->GetUndefined();
  1433. }
  1434. Var returnVar = requestContext->GetLibrary()->GetUndefined();
  1435. BOOL result = FALSE;
  1436. if (dynamicObject->UseDynamicObjectForNoHostObjectAccess())
  1437. {
  1438. if (! dynamicObject->DynamicObject::GetAccessors(propertyId, &getter, &setter, requestContext))
  1439. {
  1440. result = JavascriptConversion::PropertyQueryFlagsToBoolean((dynamicObject->DynamicObject::GetPropertyQuery(instance, propertyId, &returnVar, NULL, requestContext)));
  1441. }
  1442. }
  1443. else
  1444. {
  1445. if (! dynamicObject->GetAccessors(propertyId, &getter, &setter, requestContext))
  1446. {
  1447. result = dynamicObject->GetProperty(instance, propertyId, &returnVar, NULL, requestContext);
  1448. }
  1449. }
  1450. if (result)
  1451. {
  1452. return returnVar;
  1453. }
  1454. return requestContext->GetLibrary()->GetUndefined();
  1455. }
  1456. BOOL JavascriptOperators::OP_HasOwnPropScoped(Var scope, PropertyId propertyId, Var defaultInstance, ScriptContext* scriptContext)
  1457. {
  1458. AssertMsg(scope == scriptContext->GetLibrary()->GetNull() || JavascriptArray::Is(scope),
  1459. "Invalid scope chain pointer passed - should be null or an array");
  1460. JavascriptArray* arrScope = JavascriptOperators::TryFromVar<JavascriptArray>(scope);
  1461. if (arrScope)
  1462. {
  1463. Var instance = arrScope->DirectGetItem(0);
  1464. return JavascriptOperators::OP_HasOwnProperty(instance, propertyId, scriptContext);
  1465. }
  1466. return JavascriptOperators::OP_HasOwnProperty(defaultInstance, propertyId, scriptContext);
  1467. }
  1468. BOOL JavascriptOperators::GetPropertyUnscopable(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info)
  1469. {
  1470. return GetProperty_Internal<true>(instance, propertyObject, false, propertyId, value, requestContext, info);
  1471. }
  1472. BOOL JavascriptOperators::GetProperty(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info)
  1473. {
  1474. return GetProperty_Internal<false>(instance, propertyObject, false, propertyId, value, requestContext, info);
  1475. }
  1476. BOOL JavascriptOperators::GetRootProperty(Var instance, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info)
  1477. {
  1478. return GetProperty_Internal<false>(instance, RecyclableObject::FromVar(instance), true, propertyId, value, requestContext, info);
  1479. }
  1480. BOOL JavascriptOperators::GetProperty_InternalSimple(Var instance, RecyclableObject* object, PropertyId propertyId, _Outptr_result_maybenull_ Var* value, ScriptContext* requestContext)
  1481. {
  1482. BOOL foundProperty = FALSE;
  1483. Assert(value != nullptr);
  1484. while (!JavascriptOperators::IsNull(object))
  1485. {
  1486. PropertyQueryFlags result = object->GetPropertyQuery(instance, propertyId, value, nullptr, requestContext);
  1487. if (result != PropertyQueryFlags::Property_NotFound)
  1488. {
  1489. foundProperty = JavascriptConversion::PropertyQueryFlagsToBoolean(result);
  1490. break;
  1491. }
  1492. if (object->SkipsPrototype())
  1493. {
  1494. break;
  1495. }
  1496. object = JavascriptOperators::GetPrototypeNoTrap(object);
  1497. }
  1498. if (!foundProperty)
  1499. {
  1500. *value = requestContext->GetMissingPropertyResult();
  1501. }
  1502. return foundProperty;
  1503. }
  1504. template <bool unscopables>
  1505. BOOL JavascriptOperators::GetProperty_Internal(Var instance, RecyclableObject* propertyObject, const bool isRoot, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info)
  1506. {
  1507. if (TaggedNumber::Is(instance))
  1508. {
  1509. PropertyValueInfo::ClearCacheInfo(info);
  1510. }
  1511. RecyclableObject* object = propertyObject;
  1512. BOOL foundProperty = FALSE;
  1513. if (isRoot)
  1514. {
  1515. Assert(RootObjectBase::Is(object));
  1516. RootObjectBase* rootObject = static_cast<RootObjectBase*>(object);
  1517. foundProperty = rootObject->GetRootProperty(instance, propertyId, value, info, requestContext);
  1518. }
  1519. while (!foundProperty && !JavascriptOperators::IsNull(object))
  1520. {
  1521. if (unscopables && IsPropertyUnscopable(object, propertyId))
  1522. {
  1523. break;
  1524. }
  1525. else
  1526. {
  1527. PropertyQueryFlags result = object->GetPropertyQuery(instance, propertyId, value, info, requestContext);
  1528. if (result != PropertyQueryFlags::Property_NotFound)
  1529. {
  1530. foundProperty = JavascriptConversion::PropertyQueryFlagsToBoolean(result);
  1531. break;
  1532. }
  1533. }
  1534. if (object->SkipsPrototype())
  1535. {
  1536. break;
  1537. }
  1538. object = JavascriptOperators::GetPrototypeNoTrap(object);
  1539. }
  1540. if (foundProperty)
  1541. {
  1542. #if ENABLE_FIXED_FIELDS && DBG
  1543. if (DynamicObject::Is(object))
  1544. {
  1545. DynamicObject* dynamicObject = (DynamicObject*)object;
  1546. DynamicTypeHandler* dynamicTypeHandler = dynamicObject->GetDynamicType()->GetTypeHandler();
  1547. Var property;
  1548. if (dynamicTypeHandler->CheckFixedProperty(requestContext->GetPropertyName(propertyId), &property, requestContext))
  1549. {
  1550. bool skipAssert = false;
  1551. if (value != nullptr && Js::RecyclableObject::Is(property))
  1552. {
  1553. Js::RecyclableObject* pObject = Js::RecyclableObject::FromVar(property);
  1554. Js::RecyclableObject* pValue = Js::RecyclableObject::FromVar(*value);
  1555. if (pValue->GetScriptContext() != pObject->GetScriptContext())
  1556. {
  1557. // value was marshaled. skip check
  1558. skipAssert = true;
  1559. }
  1560. }
  1561. Assert(skipAssert || value == nullptr || *value == property);
  1562. }
  1563. }
  1564. #endif
  1565. // Don't cache the information if the value is undecl block var
  1566. // REVIEW: We might want to only check this if we need to (For LdRootFld or ScopedLdFld)
  1567. // Also we might want to throw here instead of checking it again in the caller
  1568. if (value && !requestContext->IsUndeclBlockVar(*value) && !WithScopeObject::Is(object))
  1569. {
  1570. CacheOperators::CachePropertyRead(propertyObject, object, isRoot, propertyId, false, info, requestContext);
  1571. }
  1572. #ifdef TELEMETRY_JSO
  1573. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  1574. {
  1575. requestContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, /*successful: */true);
  1576. }
  1577. #endif
  1578. return TRUE;
  1579. }
  1580. else
  1581. {
  1582. #ifdef MISSING_PROPERTY_STATS
  1583. if (PHASE_STATS1(MissingPropertyCachePhase))
  1584. {
  1585. requestContext->RecordMissingPropertyMiss();
  1586. }
  1587. #endif
  1588. if (PHASE_TRACE1(MissingPropertyCachePhase))
  1589. {
  1590. Output::Print(_u("MissingPropertyCaching: Missing property %d on slow path.\n"), propertyId);
  1591. }
  1592. TryCacheMissingProperty(instance, propertyObject, isRoot, propertyId, requestContext, info);
  1593. #if defined(TELEMETRY_JSO) || defined(TELEMETRY_AddToCache) // enabled for `TELEMETRY_AddToCache`, because this is the property-not-found codepath where the normal TELEMETRY_AddToCache code wouldn't be executed.
  1594. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  1595. {
  1596. if (info && info->AllowResizingPolymorphicInlineCache()) // If in interpreted mode, not JIT.
  1597. {
  1598. requestContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, nullptr);
  1599. }
  1600. }
  1601. #endif
  1602. *value = requestContext->GetMissingPropertyResult();
  1603. return FALSE;
  1604. }
  1605. }
  1606. // If the given instance is a type where we can cache missing properties, then cache that the given property ID is missing.
  1607. // cacheInstance is used as startingObject in CachePropertyRead, and might be instance's proto if we are fetching a super property (see #3064).
  1608. void JavascriptOperators::TryCacheMissingProperty(Var instance, Var cacheInstance, bool isRoot, PropertyId propertyId, ScriptContext* requestContext, _Inout_ PropertyValueInfo * info)
  1609. {
  1610. // Here, any well-behaved subclasses of DynamicObject can opt in to getting included in the missing property cache.
  1611. // For now, we only include basic objects and arrays. CustomExternalObject in particular is problematic because in
  1612. // some cases it can add new properties without transitioning its type handler.
  1613. if (PHASE_OFF1(MissingPropertyCachePhase) || isRoot || !(DynamicObject::Is(instance) || DynamicObject::IsAnyArray(instance)))
  1614. {
  1615. return;
  1616. }
  1617. DynamicTypeHandler* handler = DynamicObject::UnsafeFromVar(instance)->GetDynamicType()->GetTypeHandler();
  1618. // Only cache missing property lookups for non-root field loads on objects that have PathTypeHandlers, because only these types have the right behavior
  1619. // when the missing property is later added. DictionaryTypeHandler's introduce the possibility that a stale TypePropertyCache entry with isMissing==true can
  1620. // be left in the cache after the property has been installed in the object's prototype chain. Other changes to optimize accesses to objects that don't
  1621. // override special symbols make it unnecessary to introduce an invalidation scheme to deal with DictionaryTypeHandler's.
  1622. if (!handler->IsPathTypeHandler())
  1623. {
  1624. return;
  1625. }
  1626. #ifdef MISSING_PROPERTY_STATS
  1627. if (PHASE_STATS1(MissingPropertyCachePhase))
  1628. {
  1629. requestContext->RecordMissingPropertyCacheAttempt();
  1630. }
  1631. #endif
  1632. if (PHASE_TRACE1(MissingPropertyCachePhase))
  1633. {
  1634. Output::Print(_u("MissingPropertyCache: Caching missing property for property %d.\n"), propertyId);
  1635. }
  1636. PropertyValueInfo::Set(info, requestContext->GetLibrary()->GetMissingPropertyHolder(), 0);
  1637. CacheOperators::CachePropertyRead(cacheInstance, requestContext->GetLibrary()->GetMissingPropertyHolder(), isRoot, propertyId, true /*isMissing*/, info, requestContext);
  1638. }
  1639. template<bool OutputExistence, typename PropertyKeyType> PropertyQueryFlags QueryGetOrHasProperty(
  1640. Var originalInstance, RecyclableObject* object, PropertyKeyType propertyKey, Var* value, PropertyValueInfo* info, ScriptContext* requestContext);
  1641. template<> PropertyQueryFlags QueryGetOrHasProperty<false /*OutputExistence*/, PropertyId /*PropertyKeyType*/>(
  1642. Var originalInstance, RecyclableObject* object, PropertyId propertyKey, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  1643. {
  1644. return object->GetPropertyQuery(originalInstance, propertyKey, value, info, requestContext);
  1645. }
  1646. template<> PropertyQueryFlags QueryGetOrHasProperty<false /*OutputExistence*/, JavascriptString* /*PropertyKeyType*/>(
  1647. Var originalInstance, RecyclableObject* object, JavascriptString* propertyKey, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  1648. {
  1649. return object->GetPropertyQuery(originalInstance, propertyKey, value, info, requestContext);
  1650. }
  1651. template<> PropertyQueryFlags QueryGetOrHasProperty<true /*OutputExistence*/, PropertyId /*PropertyKeyType*/>(
  1652. Var originalInstance, RecyclableObject* object, PropertyId propertyKey, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  1653. {
  1654. PropertyQueryFlags result = object->HasPropertyQuery(propertyKey, info);
  1655. *value = JavascriptBoolean::ToVar(JavascriptConversion::PropertyQueryFlagsToBoolean(result), requestContext);
  1656. return result;
  1657. }
  1658. template<bool OutputExistence, typename PropertyKeyType>
  1659. BOOL JavascriptOperators::GetPropertyWPCache(Var instance, RecyclableObject* propertyObject, PropertyKeyType propertyKey, Var* value, ScriptContext* requestContext, _Inout_ PropertyValueInfo * info)
  1660. {
  1661. Assert(value);
  1662. RecyclableObject* object = propertyObject;
  1663. while (!JavascriptOperators::IsNull(object))
  1664. {
  1665. PropertyQueryFlags result = QueryGetOrHasProperty<OutputExistence>(instance, object, propertyKey, value, info, requestContext);
  1666. if (result != PropertyQueryFlags::Property_NotFound)
  1667. {
  1668. if (!WithScopeObject::Is(object) && info->GetPropertyRecordUsageCache())
  1669. {
  1670. PropertyId propertyId = info->GetPropertyRecordUsageCache()->GetPropertyRecord()->GetPropertyId();
  1671. CacheOperators::CachePropertyRead(instance, object, false, propertyId, false, info, requestContext);
  1672. }
  1673. return JavascriptConversion::PropertyQueryFlagsToBoolean(result);
  1674. }
  1675. // SkipsPrototype refers only to the Get operation, not Has. Some objects like CustomExternalObject respond
  1676. // to HasPropertyQuery with info only about the object itself and GetPropertyQuery with info about its prototype chain.
  1677. // For consistency with the behavior of JavascriptOperators::HasProperty, don't skip prototypes when outputting existence.
  1678. if (!OutputExistence && object->SkipsPrototype())
  1679. {
  1680. break;
  1681. }
  1682. object = JavascriptOperators::GetPrototypeNoTrap(object);
  1683. }
  1684. if (info->GetPropertyRecordUsageCache())
  1685. {
  1686. TryCacheMissingProperty(instance, instance, false /*isRoot*/, info->GetPropertyRecordUsageCache()->GetPropertyRecord()->GetPropertyId(), requestContext, info);
  1687. }
  1688. *value = OutputExistence
  1689. ? requestContext->GetLibrary()->GetFalse()
  1690. : requestContext->GetMissingPropertyResult();
  1691. return FALSE;
  1692. }
  1693. bool JavascriptOperators::GetPropertyObjectForElementAccess(
  1694. _In_ Var instance,
  1695. _In_ Var index,
  1696. _In_ ScriptContext* scriptContext,
  1697. _Out_ RecyclableObject** propertyObject,
  1698. _In_ rtErrors error)
  1699. {
  1700. BOOL isNullOrUndefined = !GetPropertyObject(instance, scriptContext, propertyObject);
  1701. Assert(*propertyObject == instance || TaggedNumber::Is(instance));
  1702. if (isNullOrUndefined)
  1703. {
  1704. if (!scriptContext->GetThreadContext()->RecordImplicitException())
  1705. {
  1706. return false;
  1707. }
  1708. JavascriptError::ThrowTypeError(scriptContext, error, GetPropertyDisplayNameForError(index, scriptContext));
  1709. }
  1710. return true;
  1711. }
  1712. bool JavascriptOperators::GetPropertyObjectForSetElementI(
  1713. _In_ Var instance,
  1714. _In_ Var index,
  1715. _In_ ScriptContext* scriptContext,
  1716. _Out_ RecyclableObject** propertyObject)
  1717. {
  1718. return GetPropertyObjectForElementAccess(instance, index, scriptContext, propertyObject, JSERR_Property_CannotSet_NullOrUndefined);
  1719. }
  1720. bool JavascriptOperators::GetPropertyObjectForGetElementI(
  1721. _In_ Var instance,
  1722. _In_ Var index,
  1723. _In_ ScriptContext* scriptContext,
  1724. _Out_ RecyclableObject** propertyObject)
  1725. {
  1726. return GetPropertyObjectForElementAccess(instance, index, scriptContext, propertyObject, JSERR_Property_CannotGet_NullOrUndefined);
  1727. }
  1728. BOOL JavascriptOperators::GetPropertyObject(Var instance, ScriptContext * scriptContext, RecyclableObject** propertyObject)
  1729. {
  1730. Assert(propertyObject);
  1731. if (TaggedNumber::Is(instance))
  1732. {
  1733. *propertyObject = scriptContext->GetLibrary()->GetNumberPrototype();
  1734. return TRUE;
  1735. }
  1736. RecyclableObject* object = RecyclableObject::UnsafeFromVar(instance);
  1737. *propertyObject = object;
  1738. if (JavascriptOperators::IsUndefinedOrNull(object))
  1739. {
  1740. return FALSE;
  1741. }
  1742. return TRUE;
  1743. }
  1744. #if DBG
  1745. BOOL JavascriptOperators::IsPropertyObject(RecyclableObject * instance)
  1746. {
  1747. TypeId typeId = JavascriptOperators::GetTypeId(instance);
  1748. return (typeId != TypeIds_Integer && typeId != TypeIds_Null && typeId != TypeIds_Undefined);
  1749. }
  1750. #endif
  1751. Var JavascriptOperators::OP_GetProperty(Var instance, PropertyId propertyId, ScriptContext* scriptContext)
  1752. {
  1753. JIT_HELPER_REENTRANT_HEADER(Op_GetProperty);
  1754. RecyclableObject* object = nullptr;
  1755. if (FALSE == JavascriptOperators::GetPropertyObject(instance, scriptContext, &object))
  1756. {
  1757. if (scriptContext->GetThreadContext()->RecordImplicitException())
  1758. {
  1759. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotGet_NullOrUndefined, scriptContext->GetPropertyName(propertyId)->GetBuffer());
  1760. }
  1761. else
  1762. {
  1763. return scriptContext->GetLibrary()->GetUndefined();
  1764. }
  1765. }
  1766. Var result = JavascriptOperators::GetPropertyNoCache(instance, object, propertyId, scriptContext);
  1767. AssertMsg(result != nullptr, "result null in OP_GetProperty");
  1768. return result;
  1769. JIT_HELPER_END(Op_GetProperty);
  1770. }
  1771. Var JavascriptOperators::OP_GetRootProperty(Var instance, PropertyId propertyId, PropertyValueInfo * info, ScriptContext* scriptContext)
  1772. {
  1773. AssertMsg(RootObjectBase::Is(instance), "Root must be an object!");
  1774. Var value = nullptr;
  1775. if (JavascriptOperators::GetRootProperty(RecyclableObject::FromVar(instance), propertyId, &value, scriptContext, info))
  1776. {
  1777. if (scriptContext->IsUndeclBlockVar(value) && scriptContext->GetThreadContext()->RecordImplicitException())
  1778. {
  1779. JavascriptError::ThrowReferenceError(scriptContext, JSERR_UseBeforeDeclaration);
  1780. }
  1781. return value;
  1782. }
  1783. const char16* propertyName = scriptContext->GetPropertyName(propertyId)->GetBuffer();
  1784. JavascriptFunction * caller = nullptr;
  1785. if (JavascriptStackWalker::GetCaller(&caller, scriptContext))
  1786. {
  1787. FunctionBody * callerBody = caller->GetFunctionBody();
  1788. if (callerBody && callerBody->GetUtf8SourceInfo()->GetIsXDomain())
  1789. {
  1790. propertyName = nullptr;
  1791. }
  1792. }
  1793. // Don't error if we disabled implicit calls
  1794. if (scriptContext->GetThreadContext()->RecordImplicitException())
  1795. {
  1796. JavascriptError::ThrowReferenceError(scriptContext, JSERR_UndefVariable, propertyName);
  1797. }
  1798. return scriptContext->GetMissingPropertyResult();
  1799. }
  1800. Var JavascriptOperators::OP_GetThisScoped(FrameDisplay *pScope, Var defaultInstance, ScriptContext* scriptContext)
  1801. {
  1802. // NOTE: If changes are made to this logic be sure to update the debuggers as well
  1803. int length = pScope->GetLength();
  1804. for (int i = 0; i < length; i += 1)
  1805. {
  1806. Var value = nullptr;
  1807. RecyclableObject *obj = RecyclableObject::FromVar(pScope->GetItem(i));
  1808. if (JavascriptOperators::GetProperty(obj, Js::PropertyIds::_this, &value, scriptContext))
  1809. {
  1810. return value;
  1811. }
  1812. }
  1813. return defaultInstance;
  1814. }
  1815. Var JavascriptOperators::OP_UnwrapWithObj(Var aValue)
  1816. {
  1817. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_UnwrapWithObj);
  1818. return RecyclableObject::FromVar(aValue)->GetThisObjectOrUnWrap();
  1819. JIT_HELPER_END(Op_UnwrapWithObj);
  1820. }
  1821. Var JavascriptOperators::OP_GetInstanceScoped(FrameDisplay *pScope, PropertyId propertyId, Var rootObject, Var* thisVar, ScriptContext* scriptContext)
  1822. {
  1823. JIT_HELPER_REENTRANT_HEADER(Op_GetInstanceScoped);
  1824. // Similar to GetPropertyScoped, but instead of returning the property value, we return the instance that
  1825. // owns it, or the global object if no instance is found.
  1826. int i;
  1827. int length = pScope->GetLength();
  1828. for (i = 0; i < length; i++)
  1829. {
  1830. RecyclableObject *obj = (RecyclableObject*)pScope->GetItem(i);
  1831. if (JavascriptOperators::HasProperty(obj, propertyId))
  1832. {
  1833. // HasProperty will call WithObjects HasProperty which will do the filtering
  1834. // All we have to do here is unwrap the object hence the api call
  1835. *thisVar = obj->GetThisObjectOrUnWrap();
  1836. return *thisVar;
  1837. }
  1838. }
  1839. *thisVar = scriptContext->GetLibrary()->GetUndefined();
  1840. if (rootObject != scriptContext->GetGlobalObject())
  1841. {
  1842. if (JavascriptOperators::OP_HasProperty(rootObject, propertyId, scriptContext))
  1843. {
  1844. return rootObject;
  1845. }
  1846. }
  1847. return scriptContext->GetGlobalObject();
  1848. JIT_HELPER_END(Op_GetInstanceScoped);
  1849. }
  1850. Var JavascriptOperators::GetPropertyReference(RecyclableObject *instance, PropertyId propertyId, ScriptContext* requestContext)
  1851. {
  1852. Var value = nullptr;
  1853. PropertyValueInfo info;
  1854. if (JavascriptOperators::GetPropertyReference(instance, propertyId, &value, requestContext, &info))
  1855. {
  1856. Assert(value != nullptr);
  1857. return value;
  1858. }
  1859. return requestContext->GetMissingPropertyResult();
  1860. }
  1861. BOOL JavascriptOperators::GetPropertyReference(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info)
  1862. {
  1863. return GetPropertyReference_Internal(instance, propertyObject, false, propertyId, value, requestContext, info);
  1864. }
  1865. BOOL JavascriptOperators::GetRootPropertyReference(RecyclableObject* instance, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info)
  1866. {
  1867. return GetPropertyReference_Internal(instance, instance, true, propertyId, value, requestContext, info);
  1868. }
  1869. BOOL JavascriptOperators::PropertyReferenceWalkUnscopable(Var instance, RecyclableObject** propertyObject, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  1870. {
  1871. return PropertyReferenceWalk_Impl<true>(instance, propertyObject, propertyId, value, info, requestContext);
  1872. }
  1873. BOOL JavascriptOperators::PropertyReferenceWalk(Var instance, RecyclableObject** propertyObject, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  1874. {
  1875. return PropertyReferenceWalk_Impl<false>(instance, propertyObject, propertyId, value, info, requestContext);
  1876. }
  1877. template <bool unscopables>
  1878. BOOL JavascriptOperators::PropertyReferenceWalk_Impl(Var instance, RecyclableObject** propertyObject, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  1879. {
  1880. BOOL foundProperty = false;
  1881. RecyclableObject* object = *propertyObject;
  1882. while (!foundProperty && !JavascriptOperators::IsNull(object))
  1883. {
  1884. if (unscopables && JavascriptOperators::IsPropertyUnscopable(object, propertyId))
  1885. {
  1886. break;
  1887. }
  1888. else
  1889. {
  1890. PropertyQueryFlags result = object->GetPropertyReferenceQuery(instance, propertyId, value, info, requestContext);
  1891. if (result != PropertyQueryFlags::Property_NotFound)
  1892. {
  1893. foundProperty = JavascriptConversion::PropertyQueryFlagsToBoolean(result);
  1894. break;
  1895. }
  1896. }
  1897. if (object->SkipsPrototype())
  1898. {
  1899. break; // will return false
  1900. }
  1901. object = JavascriptOperators::GetPrototypeNoTrap(object);
  1902. }
  1903. *propertyObject = object;
  1904. return foundProperty;
  1905. }
  1906. BOOL JavascriptOperators::GetPropertyReference_Internal(Var instance, RecyclableObject* propertyObject, const bool isRoot, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info)
  1907. {
  1908. if (TaggedNumber::Is(instance))
  1909. {
  1910. PropertyValueInfo::ClearCacheInfo(info);
  1911. }
  1912. BOOL foundProperty = FALSE;
  1913. RecyclableObject* object = propertyObject;
  1914. if (isRoot)
  1915. {
  1916. foundProperty = RootObjectBase::FromVar(object)->GetRootPropertyReference(instance, propertyId, value, info, requestContext);
  1917. }
  1918. if (!foundProperty)
  1919. {
  1920. foundProperty = PropertyReferenceWalk(instance, &object, propertyId, value, info, requestContext);
  1921. }
  1922. if (!foundProperty)
  1923. {
  1924. #if defined(TELEMETRY_JSO) || defined(TELEMETRY_AddToCache) // enabled for `TELEMETRY_AddToCache`, because this is the property-not-found codepath where the normal TELEMETRY_AddToCache code wouldn't be executed.
  1925. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  1926. {
  1927. if (info && info->AllowResizingPolymorphicInlineCache()) // If in interpreted mode, not JIT.
  1928. {
  1929. requestContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, nullptr);
  1930. }
  1931. }
  1932. #endif
  1933. *value = requestContext->GetMissingPropertyResult();
  1934. return foundProperty;
  1935. }
  1936. if (requestContext->IsUndeclBlockVar(*value))
  1937. {
  1938. JavascriptError::ThrowReferenceError(requestContext, JSERR_UseBeforeDeclaration);
  1939. }
  1940. #if ENABLE_FIXED_FIELDS && DBG
  1941. if (DynamicObject::Is(object))
  1942. {
  1943. DynamicObject* dynamicObject = (DynamicObject*)object;
  1944. DynamicTypeHandler* dynamicTypeHandler = dynamicObject->GetDynamicType()->GetTypeHandler();
  1945. Var property = nullptr;
  1946. if (dynamicTypeHandler->CheckFixedProperty(requestContext->GetPropertyName(propertyId), &property, requestContext))
  1947. {
  1948. Assert(value == nullptr || *value == property);
  1949. }
  1950. }
  1951. #endif
  1952. CacheOperators::CachePropertyRead(instance, object, isRoot, propertyId, false, info, requestContext);
  1953. return TRUE;
  1954. }
  1955. template <typename PropertyKeyType, bool unscopable>
  1956. DescriptorFlags JavascriptOperators::GetterSetter_Impl(RecyclableObject* instance, PropertyKeyType propertyKey, Var* setterValue, PropertyValueInfo* info, ScriptContext* scriptContext)
  1957. {
  1958. DescriptorFlags flags = None;
  1959. RecyclableObject* object = instance;
  1960. while (flags == None && !JavascriptOperators::IsNull(object))
  1961. {
  1962. if (unscopable && IsPropertyUnscopable(object, propertyKey))
  1963. {
  1964. break;
  1965. }
  1966. else
  1967. {
  1968. flags = object->GetSetter(propertyKey, setterValue, info, scriptContext);
  1969. if (flags != None)
  1970. {
  1971. break;
  1972. }
  1973. }
  1974. // CONSIDER: we should add SkipsPrototype support. DOM has no ES 5 concepts built in that aren't
  1975. // already part of our prototype objects which are chakra objects.
  1976. object = object->GetPrototype();
  1977. }
  1978. return flags;
  1979. }
  1980. DescriptorFlags JavascriptOperators::GetterSetterUnscopable(RecyclableObject* instance, PropertyId propertyId, Var* setterValue, PropertyValueInfo* info, ScriptContext* scriptContext)
  1981. {
  1982. return GetterSetter_Impl<PropertyId, true>(instance, propertyId, setterValue, info, scriptContext);
  1983. }
  1984. DescriptorFlags JavascriptOperators::GetterSetter(RecyclableObject* instance, PropertyId propertyId, Var* setterValue, PropertyValueInfo* info, ScriptContext* scriptContext)
  1985. {
  1986. return GetterSetter_Impl<PropertyId, false>(instance, propertyId, setterValue, info, scriptContext);
  1987. }
  1988. DescriptorFlags JavascriptOperators::GetterSetter(RecyclableObject* instance, JavascriptString * propertyName, Var* setterValue, PropertyValueInfo* info, ScriptContext* scriptContext)
  1989. {
  1990. return GetterSetter_Impl<JavascriptString*, false>(instance, propertyName, setterValue, info, scriptContext);
  1991. }
  1992. void JavascriptOperators::OP_InvalidateProtoCaches(PropertyId propertyId, ScriptContext *scriptContext)
  1993. {
  1994. JIT_HELPER_NOT_REENTRANT_HEADER(InvalidateProtoCaches, reentrancylock, scriptContext->GetThreadContext());
  1995. scriptContext->InvalidateProtoCaches(propertyId);
  1996. JIT_HELPER_END(InvalidateProtoCaches);
  1997. }
  1998. // Checks to see if any object in the prototype chain has a property descriptor for the given index
  1999. // that specifies either an accessor or a non-writable attribute.
  2000. // If TRUE, check flags for details.
  2001. BOOL JavascriptOperators::CheckPrototypesForAccessorOrNonWritableItem(RecyclableObject* instance, uint32 index,
  2002. Var* setterValue, DescriptorFlags *flags, ScriptContext* scriptContext, BOOL skipPrototypeCheck /* = FALSE */)
  2003. {
  2004. Assert(setterValue);
  2005. Assert(flags);
  2006. // Do a quick walk up the prototype chain to see if any of the prototypes has ever had ANY setter or non-writable property.
  2007. if (CheckIfObjectAndPrototypeChainHasOnlyWritableDataProperties(instance))
  2008. {
  2009. return FALSE;
  2010. }
  2011. RecyclableObject* object = instance;
  2012. while (!JavascriptOperators::IsNull(object))
  2013. {
  2014. *flags = object->GetItemSetter(index, setterValue, scriptContext);
  2015. if (*flags != None || skipPrototypeCheck)
  2016. {
  2017. break;
  2018. }
  2019. object = object->GetPrototype();
  2020. }
  2021. return ((*flags & Accessor) == Accessor) || ((*flags & Proxy) == Proxy) || ((*flags & Data) == Data && (*flags & Writable) == None);
  2022. }
  2023. BOOL JavascriptOperators::SetGlobalPropertyNoHost(char16 const * propertyName, charcount_t propertyLength, Var value, ScriptContext * scriptContext)
  2024. {
  2025. GlobalObject * globalObject = scriptContext->GetGlobalObject();
  2026. uint32 index;
  2027. PropertyRecord const * propertyRecord = nullptr;
  2028. IndexType indexType = GetIndexTypeFromString(propertyName, propertyLength, scriptContext, &index, &propertyRecord, true);
  2029. if (indexType == IndexType_Number)
  2030. {
  2031. return globalObject->DynamicObject::SetItem(index, value, PropertyOperation_None);
  2032. }
  2033. return globalObject->DynamicObject::SetProperty(propertyRecord->GetPropertyId(), value, PropertyOperation_None, NULL);
  2034. }
  2035. template<typename PropertyKeyType>
  2036. BOOL JavascriptOperators::SetPropertyWPCache(Var receiver, RecyclableObject* object, PropertyKeyType propertyKey, Var newValue, ScriptContext* requestContext, PropertyOperationFlags propertyOperationFlags, _Inout_ PropertyValueInfo * info)
  2037. {
  2038. if (receiver)
  2039. {
  2040. AnalysisAssert(object);
  2041. Assert(!TaggedNumber::Is(receiver));
  2042. Var setterValueOrProxy = nullptr;
  2043. DescriptorFlags flags = None;
  2044. if (JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(object, propertyKey, &setterValueOrProxy, &flags, info, requestContext))
  2045. {
  2046. if ((flags & Accessor) == Accessor)
  2047. {
  2048. if (JavascriptError::ThrowIfStrictModeUndefinedSetter(propertyOperationFlags, setterValueOrProxy, requestContext))
  2049. {
  2050. return TRUE;
  2051. }
  2052. if (setterValueOrProxy)
  2053. {
  2054. if (!WithScopeObject::Is(receiver) && info->GetPropertyRecordUsageCache() && !JavascriptOperators::IsUndefinedAccessor(setterValueOrProxy, requestContext))
  2055. {
  2056. CacheOperators::CachePropertyWrite(RecyclableObject::FromVar(receiver), false, object->GetType(), info->GetPropertyRecordUsageCache()->GetPropertyRecord()->GetPropertyId(), info, requestContext);
  2057. }
  2058. receiver = (RecyclableObject::FromVar(receiver))->GetThisObjectOrUnWrap();
  2059. RecyclableObject* func = RecyclableObject::FromVar(setterValueOrProxy);
  2060. JavascriptOperators::CallSetter(func, receiver, newValue, requestContext);
  2061. }
  2062. return TRUE;
  2063. }
  2064. else if ((flags & Proxy) == Proxy)
  2065. {
  2066. Assert(JavascriptProxy::Is(setterValueOrProxy));
  2067. JavascriptProxy* proxy = JavascriptProxy::FromVar(setterValueOrProxy);
  2068. auto fn = [&](RecyclableObject* target) -> BOOL {
  2069. return JavascriptOperators::SetPropertyWPCache(receiver, target, propertyKey, newValue, requestContext, propertyOperationFlags, info);
  2070. };
  2071. if (info->GetPropertyRecordUsageCache())
  2072. {
  2073. PropertyValueInfo::SetNoCache(info, proxy);
  2074. PropertyValueInfo::DisablePrototypeCache(info, proxy);
  2075. }
  2076. return proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetPropertyWPCacheKind, propertyKey, newValue, requestContext);
  2077. }
  2078. else
  2079. {
  2080. Assert((flags & Data) == Data && (flags & Writable) == None);
  2081. requestContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_NoOpSet);
  2082. JavascriptError::ThrowCantAssignIfStrictMode(propertyOperationFlags, requestContext);
  2083. return FALSE;
  2084. }
  2085. }
  2086. else if (!JavascriptOperators::IsObject(receiver))
  2087. {
  2088. JavascriptError::ThrowCantAssignIfStrictMode(propertyOperationFlags, requestContext);
  2089. return FALSE;
  2090. }
  2091. RecyclableObject* receiverObject = RecyclableObject::FromVar(receiver);
  2092. if (receiver != object)
  2093. {
  2094. // If the receiver object has the property and it is an accessor then return false
  2095. PropertyDescriptor existingDesc;
  2096. if (JavascriptOperators::GetOwnPropertyDescriptor(receiverObject, propertyKey, requestContext, &existingDesc)
  2097. && existingDesc.IsAccessorDescriptor())
  2098. {
  2099. return FALSE;
  2100. }
  2101. }
  2102. Type *typeWithoutProperty = object->GetType();
  2103. // in 9.1.9, step 5, we should return false if receiver is not object, and that will happen in default RecyclableObject operation anyhow.
  2104. if (receiverObject->SetProperty(propertyKey, newValue, propertyOperationFlags, info))
  2105. {
  2106. if (!JavascriptProxy::Is(receiver) && info->GetPropertyRecordUsageCache() && info->GetFlags() != InlineCacheSetterFlag && !object->IsExternal())
  2107. {
  2108. CacheOperators::CachePropertyWrite(RecyclableObject::FromVar(receiver), false, typeWithoutProperty, info->GetPropertyRecordUsageCache()->GetPropertyRecord()->GetPropertyId(), info, requestContext);
  2109. if (info->GetInstance() == receiverObject)
  2110. {
  2111. PropertyValueInfo::SetCacheInfo(info, info->GetPropertyRecordUsageCache()->GetLdElemInlineCache(), info->AllowResizingPolymorphicInlineCache());
  2112. CacheOperators::CachePropertyRead(object, receiverObject, false, info->GetPropertyRecordUsageCache()->GetPropertyRecord()->GetPropertyId(), false, info, requestContext);
  2113. }
  2114. }
  2115. return TRUE;
  2116. }
  2117. }
  2118. return FALSE;
  2119. }
  2120. BOOL JavascriptOperators::SetItemOnTaggedNumber(Var receiver, RecyclableObject* object, uint32 index, Var newValue, ScriptContext* requestContext,
  2121. PropertyOperationFlags propertyOperationFlags)
  2122. {
  2123. Assert(TaggedNumber::Is(receiver));
  2124. if (requestContext->optimizationOverrides.GetSideEffects() & SideEffects_Accessor)
  2125. {
  2126. Var setterValueOrProxy = nullptr;
  2127. DescriptorFlags flags = None;
  2128. if (object == nullptr)
  2129. {
  2130. GetPropertyObject(receiver, requestContext, &object);
  2131. }
  2132. if (JavascriptOperators::CheckPrototypesForAccessorOrNonWritableItem(object, index, &setterValueOrProxy, &flags, requestContext))
  2133. {
  2134. if ((flags & Accessor) == Accessor)
  2135. {
  2136. if (JavascriptError::ThrowIfStrictModeUndefinedSetter(propertyOperationFlags, setterValueOrProxy, requestContext))
  2137. {
  2138. return TRUE;
  2139. }
  2140. if (setterValueOrProxy)
  2141. {
  2142. RecyclableObject* func = RecyclableObject::FromVar(setterValueOrProxy);
  2143. JavascriptOperators::CallSetter(func, receiver, newValue, requestContext);
  2144. return TRUE;
  2145. }
  2146. }
  2147. else if ((flags & Proxy) == Proxy)
  2148. {
  2149. Assert(JavascriptProxy::Is(setterValueOrProxy));
  2150. JavascriptProxy* proxy = JavascriptProxy::FromVar(setterValueOrProxy);
  2151. const PropertyRecord* propertyRecord = nullptr;
  2152. proxy->PropertyIdFromInt(index, &propertyRecord);
  2153. return proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetItemOnTaggedNumberKind, propertyRecord->GetPropertyId(), newValue, requestContext);
  2154. }
  2155. else
  2156. {
  2157. Assert((flags & Data) == Data && (flags & Writable) == None);
  2158. JavascriptError::ThrowCantAssignIfStrictMode(propertyOperationFlags, requestContext);
  2159. }
  2160. }
  2161. }
  2162. JavascriptError::ThrowCantAssignIfStrictMode(propertyOperationFlags, requestContext);
  2163. return FALSE;
  2164. }
  2165. BOOL JavascriptOperators::SetPropertyOnTaggedNumber(Var receiver, RecyclableObject* object, PropertyId propertyId, Var newValue, ScriptContext* requestContext,
  2166. PropertyOperationFlags propertyOperationFlags)
  2167. {
  2168. Assert (TaggedNumber::Is(receiver));
  2169. if (requestContext->optimizationOverrides.GetSideEffects() & SideEffects_Accessor)
  2170. {
  2171. Var setterValueOrProxy = nullptr;
  2172. PropertyValueInfo info;
  2173. DescriptorFlags flags = None;
  2174. if (object == nullptr)
  2175. {
  2176. GetPropertyObject(receiver, requestContext, &object);
  2177. }
  2178. if (JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(object, propertyId, &setterValueOrProxy, &flags, &info, requestContext))
  2179. {
  2180. if ((flags & Accessor) == Accessor)
  2181. {
  2182. if (JavascriptError::ThrowIfStrictModeUndefinedSetter(propertyOperationFlags, setterValueOrProxy, requestContext))
  2183. {
  2184. return TRUE;
  2185. }
  2186. if (setterValueOrProxy)
  2187. {
  2188. RecyclableObject* func = RecyclableObject::FromVar(setterValueOrProxy);
  2189. Assert(info.GetFlags() == InlineCacheSetterFlag || info.GetPropertyIndex() == Constants::NoSlot);
  2190. JavascriptOperators::CallSetter(func, receiver, newValue, requestContext);
  2191. return TRUE;
  2192. }
  2193. }
  2194. else if ((flags & Proxy) == Proxy)
  2195. {
  2196. Assert(JavascriptProxy::Is(setterValueOrProxy));
  2197. JavascriptProxy* proxy = JavascriptProxy::FromVar(setterValueOrProxy);
  2198. return proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetPropertyOnTaggedNumberKind, propertyId, newValue, requestContext);
  2199. }
  2200. else
  2201. {
  2202. Assert((flags & Data) == Data && (flags & Writable) == None);
  2203. JavascriptError::ThrowCantAssignIfStrictMode(propertyOperationFlags, requestContext);
  2204. }
  2205. }
  2206. }
  2207. // Add implicit call flags, to bail out if field copy prop may propagate the wrong value.
  2208. requestContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_NoOpSet);
  2209. JavascriptError::ThrowCantAssignIfStrictMode(propertyOperationFlags, requestContext);
  2210. return FALSE;
  2211. }
  2212. BOOL JavascriptOperators::SetPropertyUnscopable(Var instance, RecyclableObject* receiver, PropertyId propertyId, Var newValue, PropertyValueInfo * info, ScriptContext* requestContext, PropertyOperationFlags propertyOperationFlags)
  2213. {
  2214. return SetProperty_Internal<true>(instance, receiver, false, propertyId, newValue, info, requestContext, propertyOperationFlags);
  2215. }
  2216. BOOL JavascriptOperators::SetProperty(Var receiver, RecyclableObject* object, PropertyId propertyId, Var newValue, PropertyValueInfo * info, ScriptContext* requestContext, PropertyOperationFlags propertyOperationFlags)
  2217. {
  2218. return SetProperty_Internal<false>(receiver, object, false, propertyId, newValue, info, requestContext, propertyOperationFlags);
  2219. }
  2220. BOOL JavascriptOperators::SetRootProperty(RecyclableObject* instance, PropertyId propertyId, Var newValue, PropertyValueInfo * info, ScriptContext* requestContext, PropertyOperationFlags propertyOperationFlags)
  2221. {
  2222. return SetProperty_Internal<false>(instance, instance, true, propertyId, newValue, info, requestContext, propertyOperationFlags);
  2223. }
  2224. // Returns true if a result was written.
  2225. bool JavascriptOperators::SetAccessorOrNonWritableProperty(
  2226. Var receiver,
  2227. RecyclableObject* object,
  2228. PropertyId propertyId,
  2229. Var newValue,
  2230. PropertyValueInfo * info,
  2231. ScriptContext* requestContext,
  2232. PropertyOperationFlags propertyOperationFlags,
  2233. bool isRoot,
  2234. bool allowUndecInConsoleScope,
  2235. BOOL *result)
  2236. {
  2237. *result = FALSE;
  2238. Var setterValueOrProxy = nullptr;
  2239. DescriptorFlags flags = None;
  2240. if ((isRoot && JavascriptOperators::CheckPrototypesForAccessorOrNonWritableRootProperty(object, propertyId, &setterValueOrProxy, &flags, info, requestContext)) ||
  2241. (!isRoot && JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(object, propertyId, &setterValueOrProxy, &flags, info, requestContext)))
  2242. {
  2243. if ((flags & Accessor) == Accessor)
  2244. {
  2245. if (JavascriptError::ThrowIfStrictModeUndefinedSetter(propertyOperationFlags, setterValueOrProxy, requestContext) ||
  2246. JavascriptError::ThrowIfNotExtensibleUndefinedSetter(propertyOperationFlags, setterValueOrProxy, requestContext))
  2247. {
  2248. *result = TRUE;
  2249. return true;
  2250. }
  2251. if (setterValueOrProxy)
  2252. {
  2253. RecyclableObject* func = RecyclableObject::FromVar(setterValueOrProxy);
  2254. Assert(!info || info->GetFlags() == InlineCacheSetterFlag || info->GetPropertyIndex() == Constants::NoSlot);
  2255. if (WithScopeObject::Is(receiver))
  2256. {
  2257. receiver = (RecyclableObject::FromVar(receiver))->GetThisObjectOrUnWrap();
  2258. }
  2259. else if (!JavascriptOperators::IsUndefinedAccessor(setterValueOrProxy, requestContext))
  2260. {
  2261. CacheOperators::CachePropertyWrite(RecyclableObject::FromVar(receiver), isRoot, object->GetType(), propertyId, info, requestContext);
  2262. }
  2263. #ifdef ENABLE_MUTATION_BREAKPOINT
  2264. if (MutationBreakpoint::IsFeatureEnabled(requestContext))
  2265. {
  2266. MutationBreakpoint::HandleSetProperty(requestContext, object, propertyId, newValue);
  2267. }
  2268. #endif
  2269. JavascriptOperators::CallSetter(func, receiver, newValue, requestContext);
  2270. }
  2271. *result = TRUE;
  2272. return true;
  2273. }
  2274. else if ((flags & Proxy) == Proxy)
  2275. {
  2276. Assert(JavascriptProxy::Is(setterValueOrProxy));
  2277. JavascriptProxy* proxy = JavascriptProxy::FromVar(setterValueOrProxy);
  2278. // We can't cache the property at this time. both target and handler can be changed outside of the proxy, so the inline cache needs to be
  2279. // invalidate when target, handler, or handler prototype has changed. We don't have a way to achieve this yet.
  2280. PropertyValueInfo::SetNoCache(info, proxy);
  2281. PropertyValueInfo::DisablePrototypeCache(info, proxy); // We can't cache prototype property either
  2282. *result = proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetPropertyKind, propertyId, newValue, requestContext);
  2283. return true;
  2284. }
  2285. else
  2286. {
  2287. Assert((flags & Data) == Data && (flags & Writable) == None);
  2288. if (!allowUndecInConsoleScope)
  2289. {
  2290. if (flags & Const)
  2291. {
  2292. JavascriptError::ThrowTypeError(requestContext, ERRAssignmentToConst);
  2293. }
  2294. JavascriptError::ThrowCantAssign(propertyOperationFlags, requestContext, propertyId);
  2295. JavascriptError::ThrowCantAssignIfStrictMode(propertyOperationFlags, requestContext);
  2296. *result = FALSE;
  2297. return true;
  2298. }
  2299. }
  2300. }
  2301. return false;
  2302. }
  2303. template <bool unscopables>
  2304. BOOL JavascriptOperators::SetProperty_Internal(Var receiver, RecyclableObject* object, const bool isRoot, PropertyId propertyId, Var newValue, PropertyValueInfo * info, ScriptContext* requestContext, PropertyOperationFlags propertyOperationFlags)
  2305. {
  2306. if (receiver == nullptr)
  2307. {
  2308. return FALSE;
  2309. }
  2310. Assert(!TaggedNumber::Is(receiver));
  2311. BOOL setAccessorResult = FALSE;
  2312. if (SetAccessorOrNonWritableProperty(receiver, object, propertyId, newValue, info, requestContext, propertyOperationFlags, isRoot, false, &setAccessorResult))
  2313. {
  2314. return setAccessorResult;
  2315. }
  2316. else if (!JavascriptOperators::IsObject(receiver))
  2317. {
  2318. JavascriptError::ThrowCantAssignIfStrictMode(propertyOperationFlags, requestContext);
  2319. return FALSE;
  2320. }
  2321. #ifdef ENABLE_MUTATION_BREAKPOINT
  2322. // Break on mutation if needed
  2323. bool doNotUpdateCacheForMbp = MutationBreakpoint::IsFeatureEnabled(requestContext) ?
  2324. MutationBreakpoint::HandleSetProperty(requestContext, object, propertyId, newValue) : false;
  2325. #endif
  2326. // Get the original type before setting the property
  2327. Type *typeWithoutProperty = object->GetType();
  2328. BOOL didSetProperty = false;
  2329. if (isRoot)
  2330. {
  2331. AssertMsg(JavascriptOperators::GetTypeId(receiver) == TypeIds_GlobalObject
  2332. || JavascriptOperators::GetTypeId(receiver) == TypeIds_ModuleRoot,
  2333. "Root must be a global object!");
  2334. RootObjectBase* rootObject = static_cast<RootObjectBase*>(receiver);
  2335. didSetProperty = rootObject->SetRootProperty(propertyId, newValue, propertyOperationFlags, info);
  2336. }
  2337. else
  2338. {
  2339. RecyclableObject* instanceObject = RecyclableObject::FromVar(receiver);
  2340. while (!JavascriptOperators::IsNull(instanceObject))
  2341. {
  2342. if (unscopables && JavascriptOperators::IsPropertyUnscopable(instanceObject, propertyId))
  2343. {
  2344. break;
  2345. }
  2346. else
  2347. {
  2348. didSetProperty = instanceObject->SetProperty(propertyId, newValue, propertyOperationFlags, info);
  2349. if (didSetProperty || !unscopables)
  2350. {
  2351. break;
  2352. }
  2353. }
  2354. instanceObject = JavascriptOperators::GetPrototypeNoTrap(instanceObject);
  2355. }
  2356. }
  2357. if (didSetProperty)
  2358. {
  2359. bool updateCache = true;
  2360. #ifdef ENABLE_MUTATION_BREAKPOINT
  2361. updateCache = updateCache && !doNotUpdateCacheForMbp;
  2362. #endif
  2363. if (updateCache)
  2364. {
  2365. if (!JavascriptProxy::Is(receiver))
  2366. {
  2367. CacheOperators::CachePropertyWrite(RecyclableObject::FromVar(receiver), isRoot, typeWithoutProperty, propertyId, info, requestContext);
  2368. }
  2369. }
  2370. return TRUE;
  2371. }
  2372. return FALSE;
  2373. }
  2374. BOOL JavascriptOperators::IsNumberFromNativeArray(Var instance, uint32 index, ScriptContext* scriptContext)
  2375. {
  2376. #if ENABLE_COPYONACCESS_ARRAY
  2377. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  2378. #endif
  2379. Js::TypeId instanceType = JavascriptOperators::GetTypeId(instance);
  2380. // Fast path for native and typed arrays.
  2381. bool isNativeArray = instanceType == TypeIds_NativeIntArray || instanceType == TypeIds_NativeFloatArray;
  2382. bool isTypedArray = instanceType >= TypeIds_Int8Array && instanceType <= TypeIds_Uint64Array;
  2383. if (isNativeArray || isTypedArray)
  2384. {
  2385. // Check if the typed array is detached to prevent an exception in GetOwnItem
  2386. if (isTypedArray && TypedArrayBase::IsDetachedTypedArray(instance))
  2387. {
  2388. return FALSE;
  2389. }
  2390. RecyclableObject* object = RecyclableObject::FromVar(instance);
  2391. Var member = nullptr;
  2392. // If the item is found in the array own body, then it is a number
  2393. if (JavascriptOperators::GetOwnItem(object, index, &member, scriptContext)
  2394. && !JavascriptOperators::IsUndefined(member))
  2395. {
  2396. return TRUE;
  2397. }
  2398. }
  2399. return FALSE;
  2400. }
  2401. BOOL _Check_return_ _Success_(return) JavascriptOperators::GetAccessors(RecyclableObject* instance, PropertyId propertyId, ScriptContext* requestContext, _Out_ Var* getter, _Out_ Var* setter)
  2402. {
  2403. RecyclableObject* object = instance;
  2404. while (!JavascriptOperators::IsNull(object))
  2405. {
  2406. if (object->GetAccessors(propertyId, getter, setter, requestContext))
  2407. {
  2408. *getter = JavascriptOperators::CanonicalizeAccessor(*getter, requestContext);
  2409. *setter = JavascriptOperators::CanonicalizeAccessor(*setter, requestContext);
  2410. return TRUE;
  2411. }
  2412. if (object->SkipsPrototype())
  2413. {
  2414. break;
  2415. }
  2416. object = JavascriptOperators::GetPrototype(object);
  2417. }
  2418. return FALSE;
  2419. }
  2420. BOOL JavascriptOperators::SetAccessors(RecyclableObject* instance, PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags)
  2421. {
  2422. BOOL result = instance && instance->SetAccessors(propertyId, getter, setter, flags);
  2423. return result;
  2424. }
  2425. BOOL JavascriptOperators::OP_SetProperty(Var instance, PropertyId propertyId, Var newValue, ScriptContext* scriptContext, PropertyValueInfo * info, PropertyOperationFlags flags, Var thisInstance)
  2426. {
  2427. // The call into ToObject(dynamicObject) is avoided here by checking for null and undefined and doing nothing when dynamicObject is a primitive value.
  2428. if (thisInstance == nullptr)
  2429. {
  2430. thisInstance = instance;
  2431. }
  2432. TypeId typeId = JavascriptOperators::GetTypeId(instance);
  2433. if (JavascriptOperators::IsUndefinedOrNullType(typeId))
  2434. {
  2435. if (scriptContext->GetThreadContext()->RecordImplicitException())
  2436. {
  2437. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotSet_NullOrUndefined, scriptContext->GetPropertyName(propertyId)->GetBuffer());
  2438. }
  2439. return TRUE;
  2440. }
  2441. else if (typeId == TypeIds_VariantDate)
  2442. {
  2443. if (scriptContext->GetThreadContext()->RecordImplicitException())
  2444. {
  2445. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_VarDate, scriptContext->GetPropertyName(propertyId)->GetBuffer());
  2446. }
  2447. return TRUE;
  2448. }
  2449. if (!TaggedNumber::Is(instance) && !TaggedNumber::Is(thisInstance))
  2450. {
  2451. return JavascriptOperators::SetProperty(RecyclableObject::UnsafeFromVar(thisInstance), RecyclableObject::UnsafeFromVar(instance), propertyId, newValue, info, scriptContext, flags);
  2452. }
  2453. JavascriptError::ThrowCantAssignIfStrictMode(flags, scriptContext);
  2454. return false;
  2455. }
  2456. BOOL JavascriptOperators::OP_StFunctionExpression(Var obj, PropertyId propertyId, Var newValue)
  2457. {
  2458. RecyclableObject* instance = RecyclableObject::FromVar(obj);
  2459. JIT_HELPER_NOT_REENTRANT_HEADER(Op_StFunctionExpression, reentrancylock, instance->GetScriptContext()->GetThreadContext());
  2460. instance->SetProperty(propertyId, newValue, PropertyOperation_None, NULL);
  2461. instance->SetWritable(propertyId, FALSE);
  2462. instance->SetConfigurable(propertyId, FALSE);
  2463. return TRUE;
  2464. JIT_HELPER_END(Op_StFunctionExpression);
  2465. }
  2466. BOOL JavascriptOperators::OP_InitClassMember(Var obj, PropertyId propertyId, Var newValue)
  2467. {
  2468. JIT_HELPER_REENTRANT_HEADER(Op_InitClassMember);
  2469. RecyclableObject* instance = RecyclableObject::FromVar(obj);
  2470. PropertyOperationFlags flags = PropertyOperation_None;
  2471. PropertyAttributes attributes = PropertyClassMemberDefaults;
  2472. instance->SetPropertyWithAttributes(propertyId, newValue, attributes, NULL, flags);
  2473. return TRUE;
  2474. JIT_HELPER_END(Op_InitClassMember);
  2475. }
  2476. BOOL JavascriptOperators::OP_InitLetProperty(Var obj, PropertyId propertyId, Var newValue)
  2477. {
  2478. JIT_HELPER_REENTRANT_HEADER(Op_InitLetFld);
  2479. RecyclableObject* instance = RecyclableObject::FromVar(obj);
  2480. PropertyOperationFlags flags = instance->GetScriptContext()->IsUndeclBlockVar(newValue) ? PropertyOperation_SpecialValue : PropertyOperation_None;
  2481. PropertyAttributes attributes = PropertyLetDefaults;
  2482. if (RootObjectBase::Is(instance))
  2483. {
  2484. attributes |= PropertyLetConstGlobal;
  2485. }
  2486. instance->SetPropertyWithAttributes(propertyId, newValue, attributes, NULL, (PropertyOperationFlags)(flags | PropertyOperation_AllowUndecl));
  2487. return TRUE;
  2488. JIT_HELPER_END(Op_InitLetFld);
  2489. }
  2490. BOOL JavascriptOperators::OP_InitConstProperty(Var obj, PropertyId propertyId, Var newValue)
  2491. {
  2492. RecyclableObject* instance = RecyclableObject::FromVar(obj);
  2493. JIT_HELPER_REENTRANT_HEADER(Op_InitConstFld);
  2494. PropertyOperationFlags flags = instance->GetScriptContext()->IsUndeclBlockVar(newValue) ? PropertyOperation_SpecialValue : PropertyOperation_None;
  2495. PropertyAttributes attributes = PropertyConstDefaults;
  2496. if (RootObjectBase::Is(instance))
  2497. {
  2498. attributes |= PropertyLetConstGlobal;
  2499. }
  2500. instance->SetPropertyWithAttributes(propertyId, newValue, attributes, NULL, (PropertyOperationFlags)(flags | PropertyOperation_AllowUndecl));
  2501. return TRUE;
  2502. JIT_HELPER_END(Op_InitConstFld);
  2503. }
  2504. BOOL JavascriptOperators::OP_InitUndeclRootLetProperty(Var obj, PropertyId propertyId)
  2505. {
  2506. RecyclableObject* instance = RecyclableObject::FromVar(obj);
  2507. JIT_HELPER_NOT_REENTRANT_HEADER(Op_InitUndeclRootLetFld, reentrancylock, instance->GetScriptContext()->GetThreadContext());
  2508. PropertyOperationFlags flags = static_cast<PropertyOperationFlags>(PropertyOperation_SpecialValue | PropertyOperation_AllowUndecl);
  2509. PropertyAttributes attributes = PropertyLetDefaults | PropertyLetConstGlobal;
  2510. instance->SetPropertyWithAttributes(propertyId, instance->GetLibrary()->GetUndeclBlockVar(), attributes, NULL, flags);
  2511. return TRUE;
  2512. JIT_HELPER_END(Op_InitUndeclRootLetFld);
  2513. }
  2514. BOOL JavascriptOperators::OP_InitUndeclRootConstProperty(Var obj, PropertyId propertyId)
  2515. {
  2516. RecyclableObject* instance = RecyclableObject::FromVar(obj);
  2517. JIT_HELPER_NOT_REENTRANT_HEADER(Op_InitUndeclRootConstFld, reentrancylock, instance->GetScriptContext()->GetThreadContext());
  2518. PropertyOperationFlags flags = static_cast<PropertyOperationFlags>(PropertyOperation_SpecialValue | PropertyOperation_AllowUndecl);
  2519. PropertyAttributes attributes = PropertyConstDefaults | PropertyLetConstGlobal;
  2520. instance->SetPropertyWithAttributes(propertyId, instance->GetLibrary()->GetUndeclBlockVar(), attributes, NULL, flags);
  2521. return TRUE;
  2522. JIT_HELPER_END(Op_InitUndeclRootConstFld);
  2523. }
  2524. BOOL JavascriptOperators::OP_InitUndeclConsoleLetProperty(Var obj, PropertyId propertyId)
  2525. {
  2526. FrameDisplay *pScope = (FrameDisplay*)obj;
  2527. AssertMsg(ConsoleScopeActivationObject::Is((DynamicObject*)pScope->GetItem(pScope->GetLength() - 1)), "How come we got this opcode without ConsoleScopeActivationObject?");
  2528. RecyclableObject* instance = RecyclableObject::FromVar(pScope->GetItem(0));
  2529. JIT_HELPER_NOT_REENTRANT_HEADER(Op_InitUndeclConsoleLetFld, reentrancylock, instance->GetScriptContext()->GetThreadContext());
  2530. PropertyOperationFlags flags = static_cast<PropertyOperationFlags>(PropertyOperation_SpecialValue | PropertyOperation_AllowUndecl);
  2531. PropertyAttributes attributes = PropertyLetDefaults;
  2532. instance->SetPropertyWithAttributes(propertyId, instance->GetLibrary()->GetUndeclBlockVar(), attributes, NULL, flags);
  2533. return TRUE;
  2534. JIT_HELPER_END(Op_InitUndeclConsoleLetFld);
  2535. }
  2536. BOOL JavascriptOperators::OP_InitUndeclConsoleConstProperty(Var obj, PropertyId propertyId)
  2537. {
  2538. FrameDisplay *pScope = (FrameDisplay*)obj;
  2539. AssertMsg(ConsoleScopeActivationObject::Is((DynamicObject*)pScope->GetItem(pScope->GetLength() - 1)), "How come we got this opcode without ConsoleScopeActivationObject?");
  2540. RecyclableObject* instance = RecyclableObject::FromVar(pScope->GetItem(0));
  2541. JIT_HELPER_NOT_REENTRANT_HEADER(Op_InitUndeclConsoleConstFld, reentrancylock, instance->GetScriptContext()->GetThreadContext());
  2542. PropertyOperationFlags flags = static_cast<PropertyOperationFlags>(PropertyOperation_SpecialValue | PropertyOperation_AllowUndecl);
  2543. PropertyAttributes attributes = PropertyConstDefaults;
  2544. instance->SetPropertyWithAttributes(propertyId, instance->GetLibrary()->GetUndeclBlockVar(), attributes, NULL, flags);
  2545. return TRUE;
  2546. JIT_HELPER_END(Op_InitUndeclConsoleConstFld);
  2547. }
  2548. BOOL JavascriptOperators::InitProperty(RecyclableObject* instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags)
  2549. {
  2550. return instance && instance->InitProperty(propertyId, newValue, flags);
  2551. }
  2552. BOOL JavascriptOperators::OP_InitProperty(Var instance, PropertyId propertyId, Var newValue)
  2553. {
  2554. if(TaggedNumber::Is(instance)) { return false; }
  2555. return JavascriptOperators::InitProperty(RecyclableObject::FromVar(instance), propertyId, newValue);
  2556. }
  2557. BOOL JavascriptOperators::DeleteProperty(RecyclableObject* instance, PropertyId propertyId, PropertyOperationFlags propertyOperationFlags)
  2558. {
  2559. return DeleteProperty_Impl<false>(instance, propertyId, propertyOperationFlags);
  2560. }
  2561. bool JavascriptOperators::ShouldTryDeleteProperty(RecyclableObject* instance, JavascriptString *propertyNameString, PropertyRecord const **pPropertyRecord)
  2562. {
  2563. PropertyRecord const *propertyRecord = nullptr;
  2564. if (!JavascriptOperators::CanShortcutOnUnknownPropertyName(instance))
  2565. {
  2566. instance->GetScriptContext()->GetOrAddPropertyRecord(propertyNameString, &propertyRecord);
  2567. }
  2568. else
  2569. {
  2570. instance->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
  2571. }
  2572. if (propertyRecord == nullptr)
  2573. {
  2574. return false;
  2575. }
  2576. *pPropertyRecord = propertyRecord;
  2577. return true;
  2578. }
  2579. BOOL JavascriptOperators::DeleteProperty(RecyclableObject* instance, JavascriptString *propertyNameString, PropertyOperationFlags propertyOperationFlags)
  2580. {
  2581. #ifdef ENABLE_MUTATION_BREAKPOINT
  2582. ScriptContext *scriptContext = instance->GetScriptContext();
  2583. if (MutationBreakpoint::IsFeatureEnabled(scriptContext)
  2584. && scriptContext->HasMutationBreakpoints())
  2585. {
  2586. MutationBreakpoint::HandleDeleteProperty(scriptContext, instance, propertyNameString);
  2587. }
  2588. #endif
  2589. return instance->DeleteProperty(propertyNameString, propertyOperationFlags);
  2590. }
  2591. BOOL JavascriptOperators::DeletePropertyUnscopables(RecyclableObject* instance, PropertyId propertyId, PropertyOperationFlags propertyOperationFlags)
  2592. {
  2593. return DeleteProperty_Impl<true>(instance, propertyId, propertyOperationFlags);
  2594. }
  2595. template<bool unscopables>
  2596. BOOL JavascriptOperators::DeleteProperty_Impl(RecyclableObject* instance, PropertyId propertyId, PropertyOperationFlags propertyOperationFlags)
  2597. {
  2598. if (unscopables && JavascriptOperators::IsPropertyUnscopable(instance, propertyId))
  2599. {
  2600. return false;
  2601. }
  2602. #ifdef ENABLE_MUTATION_BREAKPOINT
  2603. ScriptContext *scriptContext = instance->GetScriptContext();
  2604. if (MutationBreakpoint::IsFeatureEnabled(scriptContext)
  2605. && scriptContext->HasMutationBreakpoints())
  2606. {
  2607. MutationBreakpoint::HandleDeleteProperty(scriptContext, instance, propertyId);
  2608. }
  2609. #endif
  2610. // !unscopables will hit the return statement on the first iteration
  2611. return instance->DeleteProperty(propertyId, propertyOperationFlags);
  2612. }
  2613. Var JavascriptOperators::OP_DeleteProperty(Var instance, PropertyId propertyId, ScriptContext* scriptContext, PropertyOperationFlags propertyOperationFlags)
  2614. {
  2615. JIT_HELPER_REENTRANT_HEADER(Op_DeleteProperty);
  2616. if(TaggedNumber::Is(instance))
  2617. {
  2618. return scriptContext->GetLibrary()->GetTrue();
  2619. }
  2620. RecyclableObject* recyclableObject = RecyclableObject::FromVar(instance);
  2621. if (JavascriptOperators::IsUndefinedOrNull(recyclableObject))
  2622. {
  2623. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotDelete_NullOrUndefined,
  2624. scriptContext->GetPropertyName(propertyId)->GetBuffer());
  2625. }
  2626. return scriptContext->GetLibrary()->CreateBoolean(
  2627. JavascriptOperators::DeleteProperty(recyclableObject, propertyId, propertyOperationFlags));
  2628. JIT_HELPER_END(Op_DeleteProperty);
  2629. }
  2630. Var JavascriptOperators::OP_DeleteRootProperty(Var instance, PropertyId propertyId, ScriptContext* scriptContext, PropertyOperationFlags propertyOperationFlags)
  2631. {
  2632. // In Edge the root is an External Object which can call Dispose and thus, can have reentrancy.
  2633. JIT_HELPER_REENTRANT_HEADER(Op_DeleteRootProperty);
  2634. AssertMsg(RootObjectBase::Is(instance), "Root must be a global object!");
  2635. RootObjectBase* rootObject = static_cast<RootObjectBase*>(instance);
  2636. return scriptContext->GetLibrary()->CreateBoolean(
  2637. rootObject->DeleteRootProperty(propertyId, propertyOperationFlags));
  2638. JIT_HELPER_END(Op_DeleteRootProperty);
  2639. }
  2640. template <bool IsFromFullJit, class TInlineCache>
  2641. inline void JavascriptOperators::PatchSetPropertyScoped(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var newValue, Var defaultInstance, PropertyOperationFlags propertyOperationFlags)
  2642. {
  2643. JIT_HELPER_REENTRANT_HEADER(Op_PatchSetPropertyScoped);
  2644. // Set the property using a scope stack rather than an individual instance.
  2645. // Walk the stack until we find an instance that has the property and store
  2646. // the new value there.
  2647. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  2648. uint16 length = pDisplay->GetLength();
  2649. RecyclableObject *object;
  2650. PropertyValueInfo info;
  2651. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  2652. bool allowUndecInConsoleScope = (propertyOperationFlags & PropertyOperation_AllowUndeclInConsoleScope) == PropertyOperation_AllowUndeclInConsoleScope;
  2653. bool isLexicalThisSlotSymbol = (propertyId == PropertyIds::_this);
  2654. for (uint16 i = 0; i < length; i++)
  2655. {
  2656. object = RecyclableObject::UnsafeFromVar(pDisplay->GetItem(i));
  2657. AssertMsg(!ConsoleScopeActivationObject::Is(object) || (i == length - 1), "Invalid location for ConsoleScopeActivationObject");
  2658. Type* type = object->GetType();
  2659. if (CacheOperators::TrySetProperty<true, true, true, true, true, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false>(
  2660. object, false, propertyId, newValue, scriptContext, propertyOperationFlags, nullptr, &info))
  2661. {
  2662. return;
  2663. }
  2664. // In scoped set property, we need to set the property when it is available; it could be a setter
  2665. // or normal property. we need to check setter first, and if no setter is available, but HasProperty
  2666. // is true, this must be a normal property.
  2667. // TODO: merge OP_HasProperty and GetSetter in one pass if there is perf problem. In fastDOM we have quite
  2668. // a lot of setters so separating the two might be actually faster.
  2669. BOOL setAccessorResult = FALSE;
  2670. if (SetAccessorOrNonWritableProperty(object, object, propertyId, newValue, &info, scriptContext, propertyOperationFlags, false, allowUndecInConsoleScope, &setAccessorResult))
  2671. {
  2672. return;
  2673. }
  2674. else if (!JavascriptOperators::IsObject(object))
  2675. {
  2676. JavascriptError::ThrowCantAssignIfStrictMode(propertyOperationFlags, scriptContext);
  2677. }
  2678. // Need to do a "get" of the current value (if any) to make sure that we're not writing to
  2679. // let/const before declaration, but we need to disable implicit calls around the "get",
  2680. // so we need to do a "has" first to make sure the "get" is valid (e.g., "get" on a HostDispatch
  2681. // with implicit calls disabled will always "succeed").
  2682. if (JavascriptOperators::HasProperty(object, propertyId))
  2683. {
  2684. DisableImplicitFlags disableImplicitFlags = scriptContext->GetThreadContext()->GetDisableImplicitFlags();
  2685. scriptContext->GetThreadContext()->SetDisableImplicitFlags(DisableImplicitCallAndExceptionFlag);
  2686. Var value;
  2687. BOOL result = JavascriptOperators::GetProperty(object, propertyId, &value, scriptContext, nullptr);
  2688. scriptContext->GetThreadContext()->SetDisableImplicitFlags(disableImplicitFlags);
  2689. if (result && scriptContext->IsUndeclBlockVar(value) && !allowUndecInConsoleScope && !isLexicalThisSlotSymbol)
  2690. {
  2691. JavascriptError::ThrowReferenceError(scriptContext, JSERR_UseBeforeDeclaration);
  2692. }
  2693. PropertyValueInfo info2;
  2694. PropertyValueInfo::SetCacheInfo(&info2, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  2695. PropertyOperationFlags setPropertyOpFlags = allowUndecInConsoleScope ? PropertyOperation_AllowUndeclInConsoleScope : PropertyOperation_None;
  2696. object->SetProperty(propertyId, newValue, setPropertyOpFlags, &info2);
  2697. #if DBG_DUMP
  2698. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  2699. {
  2700. CacheOperators::TraceCache(inlineCache, _u("PatchSetPropertyScoped"), propertyId, scriptContext, object);
  2701. }
  2702. #endif
  2703. if (!JavascriptProxy::Is(object) && !allowUndecInConsoleScope)
  2704. {
  2705. CacheOperators::CachePropertyWrite(object, false, type, propertyId, &info2, scriptContext);
  2706. }
  2707. return;
  2708. }
  2709. }
  2710. Assert(!isLexicalThisSlotSymbol);
  2711. // If we have console scope and no one in the scope had the property add it to console scope
  2712. if ((length > 0) && ConsoleScopeActivationObject::Is(pDisplay->GetItem(length - 1)))
  2713. {
  2714. // CheckPrototypesForAccessorOrNonWritableProperty does not check for const in global object. We should check it here.
  2715. if (length > 1)
  2716. {
  2717. Js::GlobalObject * globalObject = JavascriptOperators::TryFromVar<Js::GlobalObject>(pDisplay->GetItem(length - 2));
  2718. if (globalObject)
  2719. {
  2720. Var setterValue = nullptr;
  2721. DescriptorFlags flags = JavascriptOperators::GetRootSetter(globalObject, propertyId, &setterValue, &info, scriptContext);
  2722. Assert((flags & Accessor) != Accessor);
  2723. Assert((flags & Proxy) != Proxy);
  2724. if ((flags & Data) == Data && (flags & Writable) == None)
  2725. {
  2726. if (!allowUndecInConsoleScope)
  2727. {
  2728. if (flags & Const)
  2729. {
  2730. JavascriptError::ThrowTypeError(scriptContext, ERRAssignmentToConst);
  2731. }
  2732. Assert(!isLexicalThisSlotSymbol);
  2733. return;
  2734. }
  2735. }
  2736. }
  2737. }
  2738. RecyclableObject* obj = RecyclableObject::FromVar((DynamicObject*)pDisplay->GetItem(length - 1));
  2739. OUTPUT_TRACE(Js::ConsoleScopePhase, _u("Adding property '%s' to console scope object\n"), scriptContext->GetPropertyName(propertyId)->GetBuffer());
  2740. JavascriptOperators::SetProperty(obj, obj, propertyId, newValue, scriptContext, propertyOperationFlags);
  2741. return;
  2742. }
  2743. // No one in the scope stack has the property, so add it to the default instance provided by the caller.
  2744. AssertMsg(!TaggedNumber::Is(defaultInstance), "Root object is an int or tagged float?");
  2745. Assert(defaultInstance != nullptr);
  2746. RecyclableObject* obj = RecyclableObject::FromVar(defaultInstance);
  2747. {
  2748. //SetPropertyScoped does not use inline cache for default instance
  2749. PropertyValueInfo info2;
  2750. JavascriptOperators::SetRootProperty(obj, propertyId, newValue, &info2, scriptContext, (PropertyOperationFlags)(propertyOperationFlags | PropertyOperation_Root));
  2751. }
  2752. JIT_HELPER_END(Op_PatchSetPropertyScoped);
  2753. }
  2754. JIT_HELPER_TEMPLATE(Op_PatchSetPropertyScoped, Op_ConsolePatchSetPropertyScoped)
  2755. template void JavascriptOperators::PatchSetPropertyScoped<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var newValue, Var defaultInstance, PropertyOperationFlags propertyOperationFlags);
  2756. template void JavascriptOperators::PatchSetPropertyScoped<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var newValue, Var defaultInstance, PropertyOperationFlags propertyOperationFlags);
  2757. template void JavascriptOperators::PatchSetPropertyScoped<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var newValue, Var defaultInstance, PropertyOperationFlags propertyOperationFlags);
  2758. template void JavascriptOperators::PatchSetPropertyScoped<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var newValue, Var defaultInstance, PropertyOperationFlags propertyOperationFlags);
  2759. BOOL JavascriptOperators::OP_InitFuncScoped(FrameDisplay *pScope, PropertyId propertyId, Var newValue, Var defaultInstance, ScriptContext* scriptContext)
  2760. {
  2761. JIT_HELPER_NOT_REENTRANT_HEADER(Op_InitFuncScoped, reentrancylock, scriptContext->GetThreadContext());
  2762. int i;
  2763. int length = pScope->GetLength();
  2764. DynamicObject *obj;
  2765. for (i = 0; i < length; i++)
  2766. {
  2767. obj = (DynamicObject*)pScope->GetItem(i);
  2768. if (obj->InitFuncScoped(propertyId, newValue))
  2769. {
  2770. return TRUE;
  2771. }
  2772. }
  2773. AssertMsg(!TaggedNumber::Is(defaultInstance), "Root object is an int or tagged float?");
  2774. return RecyclableObject::FromVar(defaultInstance)->InitFuncScoped(propertyId, newValue);
  2775. JIT_HELPER_END(Op_InitFuncScoped);
  2776. }
  2777. BOOL JavascriptOperators::OP_InitPropertyScoped(FrameDisplay *pScope, PropertyId propertyId, Var newValue, Var defaultInstance, ScriptContext* scriptContext)
  2778. {
  2779. int i;
  2780. int length = pScope->GetLength();
  2781. DynamicObject *obj;
  2782. for (i = 0; i < length; i++)
  2783. {
  2784. obj = (DynamicObject*)pScope->GetItem(i);
  2785. if (obj->InitPropertyScoped(propertyId, newValue))
  2786. {
  2787. return TRUE;
  2788. }
  2789. }
  2790. AssertMsg(!TaggedNumber::Is(defaultInstance), "Root object is an int or tagged float?");
  2791. return RecyclableObject::FromVar(defaultInstance)->InitPropertyScoped(propertyId, newValue);
  2792. }
  2793. Var JavascriptOperators::OP_DeletePropertyScoped(
  2794. FrameDisplay *pScope,
  2795. PropertyId propertyId,
  2796. Var defaultInstance,
  2797. ScriptContext* scriptContext,
  2798. PropertyOperationFlags propertyOperationFlags)
  2799. {
  2800. JIT_HELPER_REENTRANT_HEADER(Op_DeletePropertyScoped);
  2801. JIT_HELPER_SAME_ATTRIBUTES(Op_DeleteRootProperty, Op_DeletePropertyScoped);
  2802. int i;
  2803. int length = pScope->GetLength();
  2804. for (i = 0; i < length; i++)
  2805. {
  2806. DynamicObject *obj = (DynamicObject*)pScope->GetItem(i);
  2807. if (JavascriptOperators::HasProperty(obj, propertyId))
  2808. {
  2809. return scriptContext->GetLibrary()->CreateBoolean(JavascriptOperators::DeleteProperty(obj, propertyId, propertyOperationFlags));
  2810. }
  2811. }
  2812. return JavascriptOperators::OP_DeleteRootProperty(RecyclableObject::FromVar(defaultInstance), propertyId, scriptContext, propertyOperationFlags);
  2813. JIT_HELPER_END(Op_DeletePropertyScoped);
  2814. }
  2815. Var JavascriptOperators::OP_TypeofPropertyScoped(FrameDisplay *pScope, PropertyId propertyId, Var defaultInstance, ScriptContext* scriptContext)
  2816. {
  2817. JIT_HELPER_REENTRANT_HEADER(Op_TypeofPropertyScoped);
  2818. int i;
  2819. int length = pScope->GetLength();
  2820. for (i = 0; i < length; i++)
  2821. {
  2822. DynamicObject *obj = (DynamicObject*)pScope->GetItem(i);
  2823. if (JavascriptOperators::HasProperty(obj, propertyId))
  2824. {
  2825. return JavascriptOperators::TypeofFld(obj, propertyId, scriptContext);
  2826. }
  2827. }
  2828. return JavascriptOperators::TypeofRootFld(RecyclableObject::FromVar(defaultInstance), propertyId, scriptContext);
  2829. JIT_HELPER_END(Op_TypeofPropertyScoped);
  2830. }
  2831. BOOL JavascriptOperators::HasOwnItem(RecyclableObject* object, uint32 index)
  2832. {
  2833. return object->HasOwnItem(index);
  2834. }
  2835. BOOL JavascriptOperators::HasItem(RecyclableObject* object, uint64 index)
  2836. {
  2837. PropertyRecord const * propertyRecord = nullptr;
  2838. ScriptContext* scriptContext = object->GetScriptContext();
  2839. JavascriptOperators::GetPropertyIdForInt(index, scriptContext, &propertyRecord);
  2840. return JavascriptOperators::HasProperty(object, propertyRecord->GetPropertyId());
  2841. }
  2842. BOOL JavascriptOperators::HasItem(RecyclableObject* object, uint32 index)
  2843. {
  2844. #if ENABLE_COPYONACCESS_ARRAY
  2845. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(object);
  2846. #endif
  2847. while (!JavascriptOperators::IsNull(object))
  2848. {
  2849. PropertyQueryFlags result;
  2850. if ((result = object->HasItemQuery(index)) != PropertyQueryFlags::Property_NotFound)
  2851. {
  2852. return JavascriptConversion::PropertyQueryFlagsToBoolean(result);
  2853. }
  2854. // CONSIDER: Numeric property values shouldn't be on the prototype for now but if this changes
  2855. // we should add SkipsPrototype support here as well
  2856. object = JavascriptOperators::GetPrototypeNoTrap(object);
  2857. }
  2858. return false;
  2859. }
  2860. BOOL JavascriptOperators::GetOwnItem(RecyclableObject* object, uint32 index, Var* value, ScriptContext* requestContext)
  2861. {
  2862. return object->GetItem(object, index, value, requestContext);
  2863. }
  2864. BOOL JavascriptOperators::GetItem(Var instance, RecyclableObject* propertyObject, uint32 index, Var* value, ScriptContext* requestContext)
  2865. {
  2866. RecyclableObject* object = propertyObject;
  2867. while (!JavascriptOperators::IsNull(object))
  2868. {
  2869. PropertyQueryFlags result;
  2870. if ((result = object->GetItemQuery(instance, index, value, requestContext)) != PropertyQueryFlags::Property_NotFound)
  2871. {
  2872. return JavascriptConversion::PropertyQueryFlagsToBoolean(result);
  2873. }
  2874. if (object->SkipsPrototype())
  2875. {
  2876. break;
  2877. }
  2878. object = JavascriptOperators::GetPrototypeNoTrap(object);
  2879. }
  2880. *value = requestContext->GetMissingItemResult();
  2881. return false;
  2882. }
  2883. BOOL JavascriptOperators::GetItemReference(Var instance, RecyclableObject* propertyObject, uint32 index, Var* value, ScriptContext* requestContext)
  2884. {
  2885. RecyclableObject* object = propertyObject;
  2886. while (!JavascriptOperators::IsNull(object))
  2887. {
  2888. PropertyQueryFlags result;
  2889. if ((result = object->GetItemReferenceQuery(instance, index, value, requestContext)) != PropertyQueryFlags::Property_NotFound)
  2890. {
  2891. return JavascriptConversion::PropertyQueryFlagsToBoolean(result);
  2892. }
  2893. if (object->SkipsPrototype())
  2894. {
  2895. break;
  2896. }
  2897. object = JavascriptOperators::GetPrototypeNoTrap(object);
  2898. }
  2899. *value = requestContext->GetMissingItemResult();
  2900. return false;
  2901. }
  2902. BOOL JavascriptOperators::SetItem(Var receiver, RecyclableObject* object, uint64 index, Var value, ScriptContext* scriptContext, PropertyOperationFlags propertyOperationFlags)
  2903. {
  2904. PropertyRecord const * propertyRecord = nullptr;
  2905. JavascriptOperators::GetPropertyIdForInt(index, scriptContext, &propertyRecord);
  2906. return JavascriptOperators::SetProperty(receiver, object, propertyRecord->GetPropertyId(), value, scriptContext, propertyOperationFlags);
  2907. }
  2908. BOOL JavascriptOperators::SetItem(Var receiver, RecyclableObject* object, uint32 index, Var value, ScriptContext* scriptContext, PropertyOperationFlags propertyOperationFlags, BOOL skipPrototypeCheck /* = FALSE */)
  2909. {
  2910. Var setterValueOrProxy = nullptr;
  2911. DescriptorFlags flags = None;
  2912. Assert(!TaggedNumber::Is(receiver));
  2913. if (JavascriptOperators::CheckPrototypesForAccessorOrNonWritableItem(object, index, &setterValueOrProxy, &flags, scriptContext, skipPrototypeCheck))
  2914. {
  2915. scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_NoOpSet);
  2916. if ((flags & Accessor) == Accessor)
  2917. {
  2918. if (JavascriptError::ThrowIfStrictModeUndefinedSetter(propertyOperationFlags, setterValueOrProxy, scriptContext) ||
  2919. JavascriptError::ThrowIfNotExtensibleUndefinedSetter(propertyOperationFlags, setterValueOrProxy, scriptContext))
  2920. {
  2921. return TRUE;
  2922. }
  2923. if (setterValueOrProxy)
  2924. {
  2925. RecyclableObject* func = RecyclableObject::FromVar(setterValueOrProxy);
  2926. JavascriptOperators::CallSetter(func, receiver, value, scriptContext);
  2927. }
  2928. return TRUE;
  2929. }
  2930. else if ((flags & Proxy) == Proxy)
  2931. {
  2932. Assert(JavascriptProxy::Is(setterValueOrProxy));
  2933. JavascriptProxy* proxy = JavascriptProxy::FromVar(setterValueOrProxy);
  2934. const PropertyRecord* propertyRecord = nullptr;
  2935. proxy->PropertyIdFromInt(index, &propertyRecord);
  2936. return proxy->SetPropertyTrap(receiver, JavascriptProxy::SetPropertyTrapKind::SetItemKind, propertyRecord->GetPropertyId(), value, scriptContext, skipPrototypeCheck);
  2937. }
  2938. else
  2939. {
  2940. Assert((flags & Data) == Data && (flags & Writable) == None);
  2941. if ((propertyOperationFlags & PropertyOperationFlags::PropertyOperation_ThrowIfNotExtensible) == PropertyOperationFlags::PropertyOperation_ThrowIfNotExtensible)
  2942. {
  2943. JavascriptError::ThrowTypeError(scriptContext, JSERR_NonExtensibleObject);
  2944. }
  2945. JavascriptError::ThrowCantAssign(propertyOperationFlags, scriptContext, index);
  2946. JavascriptError::ThrowCantAssignIfStrictMode(propertyOperationFlags, scriptContext);
  2947. return FALSE;
  2948. }
  2949. }
  2950. else if (!JavascriptOperators::IsObject(receiver))
  2951. {
  2952. JavascriptError::ThrowCantAssignIfStrictMode(propertyOperationFlags, scriptContext);
  2953. return FALSE;
  2954. }
  2955. return (RecyclableObject::FromVar(receiver))->SetItem(index, value, propertyOperationFlags);
  2956. }
  2957. BOOL JavascriptOperators::DeleteItem(RecyclableObject* object, uint32 index, PropertyOperationFlags propertyOperationFlags)
  2958. {
  2959. return object->DeleteItem(index, propertyOperationFlags);
  2960. }
  2961. BOOL JavascriptOperators::DeleteItem(RecyclableObject* object, uint64 index, PropertyOperationFlags propertyOperationFlags)
  2962. {
  2963. PropertyRecord const * propertyRecord = nullptr;
  2964. JavascriptOperators::GetPropertyIdForInt(index, object->GetScriptContext(), &propertyRecord);
  2965. return JavascriptOperators::DeleteProperty(object, propertyRecord->GetPropertyId(), propertyOperationFlags);
  2966. }
  2967. BOOL JavascriptOperators::OP_HasItem(Var instance, Var index, ScriptContext* scriptContext)
  2968. {
  2969. RecyclableObject* object = TaggedNumber::Is(instance) ?
  2970. scriptContext->GetLibrary()->GetNumberPrototype() :
  2971. RecyclableObject::FromVar(instance);
  2972. uint32 indexVal;
  2973. PropertyRecord const * propertyRecord = nullptr;
  2974. IndexType indexType = GetIndexType(index, scriptContext, &indexVal, &propertyRecord, false);
  2975. if (indexType == IndexType_Number)
  2976. {
  2977. return HasItem(object, indexVal);
  2978. }
  2979. else
  2980. {
  2981. Assert(indexType == IndexType_PropertyId);
  2982. if (propertyRecord == nullptr && !JavascriptOperators::CanShortcutOnUnknownPropertyName(object))
  2983. {
  2984. indexType = GetIndexTypeFromPrimitive(index, scriptContext, &indexVal, &propertyRecord, true);
  2985. Assert(indexType == IndexType_PropertyId);
  2986. Assert(propertyRecord != nullptr);
  2987. }
  2988. if (propertyRecord != nullptr)
  2989. {
  2990. return HasProperty(object, propertyRecord->GetPropertyId());
  2991. }
  2992. else
  2993. {
  2994. #if DBG
  2995. JavascriptString* indexStr = JavascriptConversion::ToString(index, scriptContext);
  2996. PropertyRecord const * debugPropertyRecord;
  2997. scriptContext->GetOrAddPropertyRecord(indexStr, &debugPropertyRecord);
  2998. AssertMsg(!JavascriptOperators::HasProperty(object, debugPropertyRecord->GetPropertyId()), "how did this property come? See OS Bug 2727708 if you see this come from the web");
  2999. #endif
  3000. return FALSE;
  3001. }
  3002. }
  3003. }
  3004. #if ENABLE_PROFILE_INFO
  3005. void JavascriptOperators::UpdateNativeArrayProfileInfoToCreateVarArray(Var instance, const bool expectingNativeFloatArray, const bool expectingVarArray)
  3006. {
  3007. Assert(instance);
  3008. Assert(expectingNativeFloatArray ^ expectingVarArray);
  3009. JavascriptNativeArray * nativeArr = JavascriptOperators::TryFromVar<JavascriptNativeArray>(instance);
  3010. if (!nativeArr)
  3011. {
  3012. return;
  3013. }
  3014. ArrayCallSiteInfo *const arrayCallSiteInfo = nativeArr->GetArrayCallSiteInfo();
  3015. if (!arrayCallSiteInfo)
  3016. {
  3017. return;
  3018. }
  3019. if (expectingNativeFloatArray)
  3020. {
  3021. // Profile data is expecting a native float array. Ensure that at the array's creation site, that a native int array
  3022. // is not created, such that the profiled array type would be correct.
  3023. arrayCallSiteInfo->SetIsNotNativeIntArray();
  3024. }
  3025. else
  3026. {
  3027. // Profile data is expecting a var array. Ensure that at the array's creation site, that a native array is not
  3028. // created, such that the profiled array type would be correct.
  3029. Assert(expectingVarArray);
  3030. arrayCallSiteInfo->SetIsNotNativeArray();
  3031. }
  3032. }
  3033. bool JavascriptOperators::SetElementMayHaveImplicitCalls(ScriptContext *const scriptContext)
  3034. {
  3035. return
  3036. scriptContext->optimizationOverrides.GetArraySetElementFastPathVtable() ==
  3037. ScriptContextOptimizationOverrideInfo::InvalidVtable;
  3038. }
  3039. #endif
  3040. RecyclableObject *JavascriptOperators::GetCallableObjectOrThrow(const Var callee, ScriptContext *const scriptContext)
  3041. {
  3042. Assert(callee);
  3043. Assert(scriptContext);
  3044. if (TaggedNumber::Is(callee))
  3045. {
  3046. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction /* TODO-ERROR: get arg name - aFunc */);
  3047. }
  3048. return RecyclableObject::UnsafeFromVar(callee);
  3049. }
  3050. Var JavascriptOperators::OP_GetElementI_JIT(Var instance, Var index, ScriptContext *scriptContext)
  3051. {
  3052. JIT_HELPER_REENTRANT_HEADER(Op_GetElementI);
  3053. #if ENABLE_NATIVE_CODEGEN
  3054. Assert(Js::JavascriptStackWalker::ValidateTopJitFrame(scriptContext));
  3055. #endif
  3056. return OP_GetElementI(instance, index, scriptContext);
  3057. JIT_HELPER_END(Op_GetElementI);
  3058. }
  3059. Var JavascriptOperators::OP_GetElementI_UInt32(Var instance, uint32 index, ScriptContext* scriptContext)
  3060. {
  3061. JIT_HELPER_REENTRANT_HEADER(Op_GetElementI_UInt32);
  3062. #if FLOATVAR
  3063. return OP_GetElementI_JIT(instance, Js::JavascriptNumber::ToVar(index, scriptContext), scriptContext);
  3064. #else
  3065. char buffer[sizeof(Js::JavascriptNumber)];
  3066. return OP_GetElementI_JIT(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  3067. (Js::JavascriptNumber *)buffer), scriptContext);
  3068. #endif
  3069. JIT_HELPER_END(Op_GetElementI_UInt32);
  3070. }
  3071. Var JavascriptOperators::OP_GetElementI_Int32(Var instance, int32 index, ScriptContext* scriptContext)
  3072. {
  3073. JIT_HELPER_REENTRANT_HEADER(Op_GetElementI_Int32);
  3074. #if FLOATVAR
  3075. return OP_GetElementI_JIT(instance, Js::JavascriptNumber::ToVar(index, scriptContext), scriptContext);
  3076. #else
  3077. char buffer[sizeof(Js::JavascriptNumber)];
  3078. return OP_GetElementI_JIT(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  3079. (Js::JavascriptNumber *)buffer), scriptContext);
  3080. #endif
  3081. JIT_HELPER_END(Op_GetElementI_Int32);
  3082. }
  3083. BOOL JavascriptOperators::GetItemFromArrayPrototype(JavascriptArray * arr, int32 indexInt, Var * result, ScriptContext * scriptContext)
  3084. {
  3085. // try get from Array prototype
  3086. RecyclableObject* prototype = arr->GetPrototype();
  3087. if (JavascriptOperators::GetTypeId(prototype) != TypeIds_Array) //This can be TypeIds_ES5Array (or any other object changed through __proto__).
  3088. {
  3089. return false;
  3090. }
  3091. JavascriptArray* arrayPrototype = JavascriptArray::UnsafeFromVar(prototype); //Prototype must be Array.prototype (unless changed through __proto__)
  3092. if (arrayPrototype->GetLength() && arrayPrototype->GetItem(arrayPrototype, (uint32)indexInt, result, scriptContext))
  3093. {
  3094. return true;
  3095. }
  3096. prototype = arrayPrototype->GetPrototype(); //Its prototype must be Object.prototype (unless changed through __proto__)
  3097. if (prototype->GetScriptContext()->GetLibrary()->GetObjectPrototype() != prototype)
  3098. {
  3099. return false;
  3100. }
  3101. if (DynamicObject::FromVar(prototype)->HasNonEmptyObjectArray())
  3102. {
  3103. if (prototype->GetItem(arr, (uint32)indexInt, result, scriptContext))
  3104. {
  3105. return true;
  3106. }
  3107. }
  3108. *result = scriptContext->GetMissingItemResult();
  3109. return true;
  3110. }
  3111. Var JavascriptOperators::GetElementIIntIndex(_In_ Var instance, _In_ Var index, _In_ ScriptContext* scriptContext)
  3112. {
  3113. Assert(TaggedInt::Is(index));
  3114. switch (JavascriptOperators::GetTypeId(instance))
  3115. {
  3116. case TypeIds_Array: //fast path for array
  3117. {
  3118. Var result;
  3119. if (OP_GetElementI_ArrayFastPath(JavascriptArray::UnsafeFromVar(instance), TaggedInt::ToInt32(index), &result, scriptContext))
  3120. {
  3121. return result;
  3122. }
  3123. break;
  3124. }
  3125. case TypeIds_NativeIntArray:
  3126. {
  3127. #if ENABLE_COPYONACCESS_ARRAY
  3128. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  3129. #endif
  3130. Var result;
  3131. if (OP_GetElementI_ArrayFastPath(JavascriptNativeIntArray::UnsafeFromVar(instance), TaggedInt::ToInt32(index), &result, scriptContext))
  3132. {
  3133. return result;
  3134. }
  3135. break;
  3136. }
  3137. case TypeIds_NativeFloatArray:
  3138. {
  3139. Var result;
  3140. if (OP_GetElementI_ArrayFastPath(JavascriptNativeFloatArray::UnsafeFromVar(instance), TaggedInt::ToInt32(index), &result, scriptContext))
  3141. {
  3142. return result;
  3143. }
  3144. break;
  3145. }
  3146. case TypeIds_String: // fast path for string
  3147. {
  3148. charcount_t indexInt = TaggedInt::ToUInt32(index);
  3149. JavascriptString* string = JavascriptString::UnsafeFromVar(instance);
  3150. Var result;
  3151. if (JavascriptConversion::PropertyQueryFlagsToBoolean(string->JavascriptString::GetItemQuery(instance, indexInt, &result, scriptContext)))
  3152. {
  3153. return result;
  3154. }
  3155. break;
  3156. }
  3157. case TypeIds_Int8Array:
  3158. {
  3159. // The typed array will deal with all possible values for the index
  3160. int32 indexInt = TaggedInt::ToInt32(index);
  3161. if (VirtualTableInfo<Int8VirtualArray>::HasVirtualTable(instance))
  3162. {
  3163. Int8VirtualArray* int8Array = Int8VirtualArray::UnsafeFromVar(instance);
  3164. if (indexInt >= 0)
  3165. {
  3166. return int8Array->DirectGetItem(indexInt);
  3167. }
  3168. }
  3169. else if (VirtualTableInfo<Int8Array>::HasVirtualTable(instance))
  3170. {
  3171. Int8Array* int8Array = Int8Array::UnsafeFromVar(instance);
  3172. if (indexInt >= 0)
  3173. {
  3174. return int8Array->DirectGetItem(indexInt);
  3175. }
  3176. }
  3177. break;
  3178. }
  3179. case TypeIds_Uint8Array:
  3180. {
  3181. // The typed array will deal with all possible values for the index
  3182. int32 indexInt = TaggedInt::ToInt32(index);
  3183. if (VirtualTableInfo<Uint8VirtualArray>::HasVirtualTable(instance))
  3184. {
  3185. Uint8VirtualArray* uint8Array = Uint8VirtualArray::UnsafeFromVar(instance);
  3186. if (indexInt >= 0)
  3187. {
  3188. return uint8Array->DirectGetItem(indexInt);
  3189. }
  3190. }
  3191. else if (VirtualTableInfo<Uint8Array>::HasVirtualTable(instance))
  3192. {
  3193. Uint8Array* uint8Array = Uint8Array::UnsafeFromVar(instance);
  3194. if (indexInt >= 0)
  3195. {
  3196. return uint8Array->DirectGetItem(indexInt);
  3197. }
  3198. }
  3199. break;
  3200. }
  3201. case TypeIds_Uint8ClampedArray:
  3202. {
  3203. // The typed array will deal with all possible values for the index
  3204. int32 indexInt = TaggedInt::ToInt32(index);
  3205. if (VirtualTableInfo<Uint8ClampedVirtualArray>::HasVirtualTable(instance))
  3206. {
  3207. Uint8ClampedVirtualArray* uint8ClampedArray = Uint8ClampedVirtualArray::UnsafeFromVar(instance);
  3208. if (indexInt >= 0)
  3209. {
  3210. return uint8ClampedArray->DirectGetItem(indexInt);
  3211. }
  3212. }
  3213. else if (VirtualTableInfo<Uint8ClampedArray>::HasVirtualTable(instance))
  3214. {
  3215. Uint8ClampedArray* uint8ClampedArray = Uint8ClampedArray::UnsafeFromVar(instance);
  3216. if (indexInt >= 0)
  3217. {
  3218. return uint8ClampedArray->DirectGetItem(indexInt);
  3219. }
  3220. }
  3221. break;
  3222. }
  3223. case TypeIds_Int16Array:
  3224. {
  3225. // The type array will deal with all possible values for the index
  3226. int32 indexInt = TaggedInt::ToInt32(index);
  3227. if (VirtualTableInfo<Int16VirtualArray>::HasVirtualTable(instance))
  3228. {
  3229. Int16VirtualArray* int16Array = Int16VirtualArray::UnsafeFromVar(instance);
  3230. if (indexInt >= 0)
  3231. {
  3232. return int16Array->DirectGetItem(indexInt);
  3233. }
  3234. }
  3235. else if (VirtualTableInfo<Int16Array>::HasVirtualTable(instance))
  3236. {
  3237. Int16Array* int16Array = Int16Array::UnsafeFromVar(instance);
  3238. if (indexInt >= 0)
  3239. {
  3240. return int16Array->DirectGetItem(indexInt);
  3241. }
  3242. }
  3243. break;
  3244. }
  3245. case TypeIds_Uint16Array:
  3246. {
  3247. // The type array will deal with all possible values for the index
  3248. int32 indexInt = TaggedInt::ToInt32(index);
  3249. if (VirtualTableInfo<Uint16VirtualArray>::HasVirtualTable(instance))
  3250. {
  3251. Uint16VirtualArray* uint16Array = Uint16VirtualArray::UnsafeFromVar(instance);
  3252. if (indexInt >= 0)
  3253. {
  3254. return uint16Array->DirectGetItem(indexInt);
  3255. }
  3256. }
  3257. else if (VirtualTableInfo<Uint16Array>::HasVirtualTable(instance))
  3258. {
  3259. Uint16Array* uint16Array = Uint16Array::UnsafeFromVar(instance);
  3260. if (indexInt >= 0)
  3261. {
  3262. return uint16Array->DirectGetItem(indexInt);
  3263. }
  3264. }
  3265. break;
  3266. }
  3267. case TypeIds_Int32Array:
  3268. {
  3269. // The type array will deal with all possible values for the index
  3270. int32 indexInt = TaggedInt::ToInt32(index);
  3271. if (VirtualTableInfo<Int32VirtualArray>::HasVirtualTable(instance))
  3272. {
  3273. Int32VirtualArray* int32Array = Int32VirtualArray::UnsafeFromVar(instance);
  3274. if (indexInt >= 0)
  3275. {
  3276. return int32Array->DirectGetItem(indexInt);
  3277. }
  3278. }
  3279. else if (VirtualTableInfo<Int32Array>::HasVirtualTable(instance))
  3280. {
  3281. Int32Array* int32Array = Int32Array::UnsafeFromVar(instance);
  3282. if (indexInt >= 0)
  3283. {
  3284. return int32Array->DirectGetItem(indexInt);
  3285. }
  3286. }
  3287. break;
  3288. }
  3289. case TypeIds_Uint32Array:
  3290. {
  3291. // The type array will deal with all possible values for the index
  3292. int32 indexInt = TaggedInt::ToInt32(index);
  3293. if (VirtualTableInfo<Uint32VirtualArray>::HasVirtualTable(instance))
  3294. {
  3295. Uint32VirtualArray* uint32Array = Uint32VirtualArray::UnsafeFromVar(instance);
  3296. if (indexInt >= 0)
  3297. {
  3298. return uint32Array->DirectGetItem(indexInt);
  3299. }
  3300. }
  3301. else if (VirtualTableInfo<Uint32Array>::HasVirtualTable(instance))
  3302. {
  3303. Uint32Array* uint32Array = Uint32Array::UnsafeFromVar(instance);
  3304. if (indexInt >= 0)
  3305. {
  3306. return uint32Array->DirectGetItem(indexInt);
  3307. }
  3308. }
  3309. break;
  3310. }
  3311. case TypeIds_Float32Array:
  3312. {
  3313. // The type array will deal with all possible values for the index
  3314. int32 indexInt = TaggedInt::ToInt32(index);
  3315. if (VirtualTableInfo<Float32VirtualArray>::HasVirtualTable(instance))
  3316. {
  3317. Float32VirtualArray* float32Array = Float32VirtualArray::UnsafeFromVar(instance);
  3318. if (indexInt >= 0)
  3319. {
  3320. return float32Array->DirectGetItem(indexInt);
  3321. }
  3322. }
  3323. else if (VirtualTableInfo<Float32Array>::HasVirtualTable(instance))
  3324. {
  3325. Float32Array* float32Array = Float32Array::UnsafeFromVar(instance);
  3326. if (indexInt >= 0)
  3327. {
  3328. return float32Array->DirectGetItem(indexInt);
  3329. }
  3330. }
  3331. break;
  3332. }
  3333. case TypeIds_Float64Array:
  3334. {
  3335. // The type array will deal with all possible values for the index
  3336. int32 indexInt = TaggedInt::ToInt32(index);
  3337. if (VirtualTableInfo<Float64VirtualArray>::HasVirtualTable(instance))
  3338. {
  3339. Float64VirtualArray* float64Array = Float64VirtualArray::UnsafeFromVar(instance);
  3340. if (indexInt >= 0)
  3341. {
  3342. return float64Array->DirectGetItem(indexInt);
  3343. }
  3344. }
  3345. else if (VirtualTableInfo<Float64Array>::HasVirtualTable(instance))
  3346. {
  3347. Float64Array* float64Array = Float64Array::UnsafeFromVar(instance);
  3348. if (indexInt >= 0)
  3349. {
  3350. return float64Array->DirectGetItem(indexInt);
  3351. }
  3352. }
  3353. break;
  3354. }
  3355. default:
  3356. break;
  3357. }
  3358. return JavascriptOperators::GetElementIHelper(instance, index, instance, scriptContext);
  3359. }
  3360. template <typename T>
  3361. BOOL JavascriptOperators::OP_GetElementI_ArrayFastPath(T * arr, int indexInt, Var * result, ScriptContext * scriptContext)
  3362. {
  3363. #if ENABLE_COPYONACCESS_ARRAY
  3364. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(arr);
  3365. #endif
  3366. if (indexInt >= 0)
  3367. {
  3368. if (!CrossSite::IsCrossSiteObjectTyped(arr))
  3369. {
  3370. if (arr->T::DirectGetVarItemAt((uint32)indexInt, result, scriptContext))
  3371. {
  3372. return true;
  3373. }
  3374. }
  3375. else
  3376. {
  3377. if (arr->GetItem(arr, (uint32)indexInt, result, scriptContext))
  3378. {
  3379. return true;
  3380. }
  3381. }
  3382. return GetItemFromArrayPrototype(arr, indexInt, result, scriptContext);
  3383. }
  3384. return false;
  3385. }
  3386. Var JavascriptOperators::OP_GetElementI(Var instance, Var index, ScriptContext* scriptContext)
  3387. {
  3388. if (TaggedInt::Is(index))
  3389. {
  3390. return GetElementIIntIndex(instance, index, scriptContext);
  3391. }
  3392. if (JavascriptNumber::Is_NoTaggedIntCheck(index))
  3393. {
  3394. uint32 uint32Index = JavascriptConversion::ToUInt32(index, scriptContext);
  3395. if ((double)uint32Index == JavascriptNumber::GetValue(index) && !TaggedInt::IsOverflow(uint32Index))
  3396. {
  3397. index = TaggedInt::ToVarUnchecked(uint32Index);
  3398. return GetElementIIntIndex(instance, index, scriptContext);
  3399. }
  3400. }
  3401. else if (RecyclableObject::Is(instance))
  3402. {
  3403. RecyclableObject* cacheOwner;
  3404. PropertyRecordUsageCache* propertyRecordUsageCache;
  3405. if (GetPropertyRecordUsageCache(index, scriptContext, &propertyRecordUsageCache, &cacheOwner))
  3406. {
  3407. return GetElementIWithCache<false /* ReturnOperationInfo */>(instance, cacheOwner, propertyRecordUsageCache, scriptContext, nullptr);
  3408. }
  3409. }
  3410. return JavascriptOperators::GetElementIHelper(instance, index, instance, scriptContext);
  3411. }
  3412. _Success_(return) bool JavascriptOperators::GetPropertyRecordUsageCache(Var index, ScriptContext* scriptContext, _Outptr_ PropertyRecordUsageCache** propertyRecordUsageCache, _Outptr_ RecyclableObject** cacheOwner)
  3413. {
  3414. JavascriptString* string = JavascriptOperators::TryFromVar<JavascriptString>(index);
  3415. if (string)
  3416. {
  3417. PropertyString * propertyString = nullptr;
  3418. if (VirtualTableInfo<Js::PropertyString>::HasVirtualTable(string))
  3419. {
  3420. propertyString = (PropertyString*)string;
  3421. }
  3422. else if (VirtualTableInfo<Js::LiteralStringWithPropertyStringPtr>::HasVirtualTable(string))
  3423. {
  3424. LiteralStringWithPropertyStringPtr * strWithPtr = (LiteralStringWithPropertyStringPtr *)string;
  3425. if (!strWithPtr->HasPropertyRecord())
  3426. {
  3427. PropertyRecord const * propertyRecord;
  3428. strWithPtr->GetPropertyRecord(&propertyRecord); // lookup-cache propertyRecord
  3429. }
  3430. else
  3431. {
  3432. propertyString = strWithPtr->GetOrAddPropertyString();
  3433. // this is the second time this property string is used
  3434. // we already had created the propertyRecord..
  3435. // now create the propertyString!
  3436. }
  3437. }
  3438. if (propertyString != nullptr)
  3439. {
  3440. *propertyRecordUsageCache = propertyString->GetPropertyRecordUsageCache();
  3441. *cacheOwner = propertyString;
  3442. return true;
  3443. }
  3444. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  3445. if (PHASE_TRACE1(PropertyCachePhase))
  3446. {
  3447. Output::Print(_u("PropertyCache: GetElem No property string for '%s'\n"), string->GetString());
  3448. }
  3449. #endif
  3450. #if DBG_DUMP
  3451. scriptContext->forinNoCache++;
  3452. #endif
  3453. }
  3454. JavascriptSymbol* symbol = JavascriptOperators::TryFromVar<JavascriptSymbol>(index);
  3455. if (symbol)
  3456. {
  3457. *propertyRecordUsageCache = symbol->GetPropertyRecordUsageCache();
  3458. *cacheOwner = symbol;
  3459. return true;
  3460. }
  3461. return false;
  3462. }
  3463. bool JavascriptOperators::SetElementIOnTaggedNumber(
  3464. _In_ Var receiver,
  3465. _In_ RecyclableObject* object,
  3466. _In_ Var index,
  3467. _In_ Var value,
  3468. _In_ ScriptContext* requestContext,
  3469. _In_ PropertyOperationFlags propertyOperationFlags)
  3470. {
  3471. Assert(TaggedNumber::Is(receiver));
  3472. uint32 indexVal = 0;
  3473. PropertyRecord const * propertyRecord = nullptr;
  3474. IndexType indexType = GetIndexType(index, requestContext, &indexVal, &propertyRecord, true);
  3475. if (indexType == IndexType_Number)
  3476. {
  3477. return JavascriptOperators::SetItemOnTaggedNumber(receiver, object, indexVal, value, requestContext, propertyOperationFlags);
  3478. }
  3479. else
  3480. {
  3481. return JavascriptOperators::SetPropertyOnTaggedNumber(receiver, object, propertyRecord->GetPropertyId(), value, requestContext, propertyOperationFlags);
  3482. }
  3483. }
  3484. template <bool ReturnOperationInfo>
  3485. bool JavascriptOperators::SetElementIWithCache(
  3486. _In_ Var receiver,
  3487. _In_ RecyclableObject* object,
  3488. _In_ RecyclableObject* index,
  3489. _In_ Var value,
  3490. _In_ PropertyRecordUsageCache* propertyRecordUsageCache,
  3491. _In_ ScriptContext* scriptContext,
  3492. _In_ PropertyOperationFlags flags,
  3493. _Inout_opt_ PropertyCacheOperationInfo* operationInfo)
  3494. {
  3495. if (TaggedNumber::Is(receiver))
  3496. {
  3497. return JavascriptOperators::SetElementIOnTaggedNumber(receiver, object, index, value, scriptContext, flags);
  3498. }
  3499. PropertyRecord const * propertyRecord = propertyRecordUsageCache->GetPropertyRecord();
  3500. if (propertyRecord->IsNumeric())
  3501. {
  3502. return JavascriptOperators::SetItem(receiver, object, propertyRecord->GetNumericValue(), value, scriptContext, flags);
  3503. }
  3504. PropertyValueInfo info;
  3505. if (receiver == object)
  3506. {
  3507. if (propertyRecordUsageCache->TrySetPropertyFromCache<ReturnOperationInfo>(object, value, scriptContext, flags, &info, index, operationInfo))
  3508. {
  3509. return true;
  3510. }
  3511. }
  3512. PropertyId propId = propertyRecord->GetPropertyId();
  3513. if (propId == PropertyIds::NaN || propId == PropertyIds::Infinity)
  3514. {
  3515. // As we no longer convert o[x] into o.x for NaN and Infinity, we need to follow SetProperty convention for these,
  3516. // which would check for read-only properties, strict mode, etc.
  3517. // Note that "-Infinity" does not qualify as property name, so we don't have to take care of it.
  3518. return JavascriptOperators::SetProperty(receiver, object, propId, value, scriptContext, flags);
  3519. }
  3520. return JavascriptOperators::SetPropertyWPCache(receiver, object, propId, value, scriptContext, flags, &info);
  3521. }
  3522. template bool JavascriptOperators::SetElementIWithCache<false>(Var receiver, RecyclableObject* object, RecyclableObject* index, Var value, PropertyRecordUsageCache* propertyRecordUsageCache, ScriptContext* scriptContext, PropertyOperationFlags flags, PropertyCacheOperationInfo* operationInfo);
  3523. template bool JavascriptOperators::SetElementIWithCache<true>(Var receiver, RecyclableObject* object, RecyclableObject* index, Var value, PropertyRecordUsageCache* propertyRecordUsageCache, ScriptContext* scriptContext, PropertyOperationFlags flags, PropertyCacheOperationInfo* operationInfo);
  3524. template <bool ReturnOperationInfo>
  3525. Var JavascriptOperators::GetElementIWithCache(
  3526. _In_ Var instance,
  3527. _In_ RecyclableObject* index,
  3528. _In_ PropertyRecordUsageCache* propertyRecordUsageCache,
  3529. _In_ ScriptContext* scriptContext,
  3530. _Inout_opt_ PropertyCacheOperationInfo* operationInfo)
  3531. {
  3532. RecyclableObject* object = nullptr;
  3533. if (!JavascriptOperators::GetPropertyObjectForGetElementI(instance, index, scriptContext, &object))
  3534. {
  3535. return scriptContext->GetLibrary()->GetUndefined();
  3536. }
  3537. PropertyRecord const * propertyRecord = propertyRecordUsageCache->GetPropertyRecord();
  3538. Var value;
  3539. if (propertyRecord->IsNumeric())
  3540. {
  3541. if (JavascriptOperators::GetItem(instance, object, propertyRecord->GetNumericValue(), &value, scriptContext))
  3542. {
  3543. return value;
  3544. }
  3545. }
  3546. else
  3547. {
  3548. PropertyValueInfo info;
  3549. if (propertyRecordUsageCache->TryGetPropertyFromCache<false /* OwnPropertyOnly */, false /* OutputExistence */, ReturnOperationInfo>(instance, object, &value, scriptContext, &info, index, operationInfo))
  3550. {
  3551. return value;
  3552. }
  3553. if (JavascriptOperators::GetPropertyWPCache<false /* OutputExistence */>(instance, object, propertyRecord->GetPropertyId(), &value, scriptContext, &info))
  3554. {
  3555. return value;
  3556. }
  3557. }
  3558. return scriptContext->GetLibrary()->GetUndefined();
  3559. }
  3560. template Var JavascriptOperators::GetElementIWithCache<false>(Var instance, RecyclableObject* index, PropertyRecordUsageCache* propertyRecordUsageCache, ScriptContext* scriptContext, PropertyCacheOperationInfo* operationInfo);
  3561. template Var JavascriptOperators::GetElementIWithCache<true>(Var instance, RecyclableObject* index, PropertyRecordUsageCache* propertyRecordUsageCache, ScriptContext* scriptContext, PropertyCacheOperationInfo* operationInfo);
  3562. Var JavascriptOperators::GetElementIHelper(Var instance, Var index, Var receiver, ScriptContext* scriptContext)
  3563. {
  3564. RecyclableObject* object = nullptr;
  3565. if (!JavascriptOperators::GetPropertyObjectForGetElementI(instance, index, scriptContext, &object))
  3566. {
  3567. return scriptContext->GetLibrary()->GetUndefined();
  3568. }
  3569. uint32 indexVal;
  3570. PropertyRecord const * propertyRecord = nullptr;
  3571. JavascriptString * propertyNameString = nullptr;
  3572. Var value = nullptr;
  3573. IndexType indexType = GetIndexType(index, scriptContext, &indexVal, &propertyRecord, &propertyNameString, false, true);
  3574. if (indexType == IndexType_Number)
  3575. {
  3576. if (JavascriptOperators::GetItem(receiver, object, indexVal, &value, scriptContext))
  3577. {
  3578. return value;
  3579. }
  3580. }
  3581. else if (indexType == IndexType_JavascriptString)
  3582. {
  3583. PropertyValueInfo info;
  3584. if (JavascriptOperators::GetPropertyWPCache<false /* OutputExistence */>(receiver, object, propertyNameString, &value, scriptContext, &info))
  3585. {
  3586. return value;
  3587. }
  3588. }
  3589. else
  3590. {
  3591. Assert(indexType == IndexType_PropertyId);
  3592. if (propertyRecord == nullptr && !JavascriptOperators::CanShortcutOnUnknownPropertyName(object))
  3593. {
  3594. indexType = GetIndexTypeFromPrimitive(index, scriptContext, &indexVal, &propertyRecord, &propertyNameString, true, true);
  3595. Assert(indexType == IndexType_PropertyId);
  3596. Assert(propertyRecord != nullptr);
  3597. }
  3598. if (propertyRecord != nullptr)
  3599. {
  3600. PropertyValueInfo info;
  3601. if (JavascriptOperators::GetPropertyWPCache<false /* OutputExistence */>(receiver, object, propertyRecord->GetPropertyId(), &value, scriptContext, &info))
  3602. {
  3603. return value;
  3604. }
  3605. }
  3606. #if DBG
  3607. else
  3608. {
  3609. JavascriptString* indexStr = JavascriptConversion::ToString(index, scriptContext);
  3610. PropertyRecord const * debugPropertyRecord;
  3611. scriptContext->GetOrAddPropertyRecord(indexStr, &debugPropertyRecord);
  3612. AssertMsg(!JavascriptOperators::GetProperty(receiver, object, debugPropertyRecord->GetPropertyId(), &value, scriptContext), "how did this property come? See OS Bug 2727708 if you see this come from the web");
  3613. }
  3614. #endif
  3615. }
  3616. return scriptContext->GetMissingItemResult();
  3617. }
  3618. int32 JavascriptOperators::OP_GetNativeIntElementI(Var instance, Var index)
  3619. {
  3620. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_GetNativeIntElementI);
  3621. #if ENABLE_COPYONACCESS_ARRAY
  3622. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  3623. #endif
  3624. if (TaggedInt::Is(index))
  3625. {
  3626. int32 indexInt = TaggedInt::ToInt32(index);
  3627. if (indexInt < 0)
  3628. {
  3629. return JavascriptNativeIntArray::MissingItem;
  3630. }
  3631. JavascriptArray * arr = JavascriptArray::FromVar(instance);
  3632. int32 result;
  3633. if (arr->DirectGetItemAt((uint32)indexInt, &result))
  3634. {
  3635. return result;
  3636. }
  3637. }
  3638. else if (JavascriptNumber::Is_NoTaggedIntCheck(index))
  3639. {
  3640. int32 indexInt;
  3641. bool isInt32;
  3642. double dIndex = JavascriptNumber::GetValue(index);
  3643. if (JavascriptNumber::TryGetInt32OrUInt32Value(dIndex, &indexInt, &isInt32))
  3644. {
  3645. if (isInt32 && indexInt < 0)
  3646. {
  3647. return JavascriptNativeIntArray::MissingItem;
  3648. }
  3649. JavascriptArray * arr = JavascriptArray::FromVar(instance);
  3650. int32 result;
  3651. if (arr->DirectGetItemAt((uint32)indexInt, &result))
  3652. {
  3653. return result;
  3654. }
  3655. }
  3656. }
  3657. else
  3658. {
  3659. AssertMsg(false, "Non-numerical index in this helper?");
  3660. }
  3661. return JavascriptNativeIntArray::MissingItem;
  3662. JIT_HELPER_END(Op_GetNativeIntElementI);
  3663. }
  3664. int32 JavascriptOperators::OP_GetNativeIntElementI_UInt32(Var instance, uint32 index, ScriptContext* scriptContext)
  3665. {
  3666. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_GetNativeIntElementI_UInt32);
  3667. JIT_HELPER_SAME_ATTRIBUTES(Op_GetNativeIntElementI_UInt32, Op_GetNativeIntElementI);
  3668. #if FLOATVAR
  3669. return OP_GetNativeIntElementI(instance, Js::JavascriptNumber::ToVar(index, scriptContext));
  3670. #else
  3671. char buffer[sizeof(Js::JavascriptNumber)];
  3672. return OP_GetNativeIntElementI(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  3673. (Js::JavascriptNumber *)buffer));
  3674. #endif
  3675. JIT_HELPER_END(Op_GetNativeIntElementI_UInt32);
  3676. }
  3677. int32 JavascriptOperators::OP_GetNativeIntElementI_Int32(Var instance, int32 index, ScriptContext* scriptContext)
  3678. {
  3679. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_GetNativeIntElementI_Int32);
  3680. JIT_HELPER_SAME_ATTRIBUTES(Op_GetNativeIntElementI_Int32, Op_GetNativeIntElementI);
  3681. #if FLOATVAR
  3682. return OP_GetNativeIntElementI(instance, Js::JavascriptNumber::ToVar(index, scriptContext));
  3683. #else
  3684. char buffer[sizeof(Js::JavascriptNumber)];
  3685. return OP_GetNativeIntElementI(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  3686. (Js::JavascriptNumber *)buffer));
  3687. #endif
  3688. JIT_HELPER_END(Op_GetNativeIntElementI_Int32);
  3689. }
  3690. double JavascriptOperators::OP_GetNativeFloatElementI(Var instance, Var index)
  3691. {
  3692. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_GetNativeFloatElementI);
  3693. double result = 0;
  3694. if (TaggedInt::Is(index))
  3695. {
  3696. int32 indexInt = TaggedInt::ToInt32(index);
  3697. if (indexInt < 0)
  3698. {
  3699. result = JavascriptNativeFloatArray::MissingItem;
  3700. }
  3701. else
  3702. {
  3703. JavascriptArray * arr = JavascriptArray::FromVar(instance);
  3704. if (!arr->DirectGetItemAt((uint32)indexInt, &result))
  3705. {
  3706. result = JavascriptNativeFloatArray::MissingItem;
  3707. }
  3708. }
  3709. }
  3710. else if (JavascriptNumber::Is_NoTaggedIntCheck(index))
  3711. {
  3712. int32 indexInt;
  3713. bool isInt32;
  3714. double dIndex = JavascriptNumber::GetValue(index);
  3715. if (JavascriptNumber::TryGetInt32OrUInt32Value(dIndex, &indexInt, &isInt32))
  3716. {
  3717. if (isInt32 && indexInt < 0)
  3718. {
  3719. result = JavascriptNativeFloatArray::MissingItem;
  3720. }
  3721. else
  3722. {
  3723. JavascriptArray * arr = JavascriptArray::FromVar(instance);
  3724. if (!arr->DirectGetItemAt((uint32)indexInt, &result))
  3725. {
  3726. result = JavascriptNativeFloatArray::MissingItem;
  3727. }
  3728. }
  3729. }
  3730. }
  3731. else
  3732. {
  3733. AssertMsg(false, "Non-numerical index in this helper?");
  3734. }
  3735. return result;
  3736. JIT_HELPER_END(Op_GetNativeFloatElementI);
  3737. }
  3738. double JavascriptOperators::OP_GetNativeFloatElementI_UInt32(Var instance, uint32 index, ScriptContext* scriptContext)
  3739. {
  3740. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_GetNativeFloatElementI_UInt32);
  3741. JIT_HELPER_SAME_ATTRIBUTES(Op_GetNativeFloatElementI_UInt32, Op_GetNativeFloatElementI);
  3742. #if FLOATVAR
  3743. return OP_GetNativeFloatElementI(instance, Js::JavascriptNumber::ToVar(index, scriptContext));
  3744. #else
  3745. char buffer[sizeof(Js::JavascriptNumber)];
  3746. return OP_GetNativeFloatElementI(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  3747. (Js::JavascriptNumber *)buffer));
  3748. #endif
  3749. JIT_HELPER_END(Op_GetNativeFloatElementI_UInt32);
  3750. }
  3751. double JavascriptOperators::OP_GetNativeFloatElementI_Int32(Var instance, int32 index, ScriptContext* scriptContext)
  3752. {
  3753. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_GetNativeFloatElementI_Int32);
  3754. JIT_HELPER_SAME_ATTRIBUTES(Op_GetNativeFloatElementI_Int32, Op_GetNativeFloatElementI);
  3755. #if FLOATVAR
  3756. return OP_GetNativeFloatElementI(instance, Js::JavascriptNumber::ToVar(index, scriptContext));
  3757. #else
  3758. char buffer[sizeof(Js::JavascriptNumber)];
  3759. return OP_GetNativeFloatElementI(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  3760. (Js::JavascriptNumber *)buffer));
  3761. #endif
  3762. JIT_HELPER_END(Op_GetNativeFloatElementI_Int32);
  3763. }
  3764. Var JavascriptOperators::OP_GetMethodElement_UInt32(Var instance, uint32 index, ScriptContext* scriptContext)
  3765. {
  3766. JIT_HELPER_REENTRANT_HEADER(Op_GetMethodElement_UInt32);
  3767. JIT_HELPER_SAME_ATTRIBUTES(Op_GetMethodElement_UInt32, Op_GetMethodElement);
  3768. #if FLOATVAR
  3769. return OP_GetMethodElement(instance, Js::JavascriptNumber::ToVar(index, scriptContext), scriptContext);
  3770. #else
  3771. char buffer[sizeof(Js::JavascriptNumber)];
  3772. return OP_GetMethodElement(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  3773. (Js::JavascriptNumber *)buffer), scriptContext);
  3774. #endif
  3775. JIT_HELPER_END(Op_GetMethodElement_UInt32);
  3776. }
  3777. Var JavascriptOperators::OP_GetMethodElement_Int32(Var instance, int32 index, ScriptContext* scriptContext)
  3778. {
  3779. JIT_HELPER_REENTRANT_HEADER(Op_GetMethodElement_Int32);
  3780. JIT_HELPER_SAME_ATTRIBUTES(Op_GetMethodElement_Int32, Op_GetMethodElement);
  3781. #if FLOATVAR
  3782. return OP_GetElementI(instance, Js::JavascriptNumber::ToVar(index, scriptContext), scriptContext);
  3783. #else
  3784. char buffer[sizeof(Js::JavascriptNumber)];
  3785. return OP_GetMethodElement(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  3786. (Js::JavascriptNumber *)buffer), scriptContext);
  3787. #endif
  3788. JIT_HELPER_END(Op_GetMethodElement_Int32);
  3789. }
  3790. Var JavascriptOperators::OP_GetMethodElement(Var instance, Var index, ScriptContext* scriptContext)
  3791. {
  3792. JIT_HELPER_REENTRANT_HEADER(Op_GetMethodElement);
  3793. RecyclableObject* object = nullptr;
  3794. if (FALSE == JavascriptOperators::GetPropertyObject(instance, scriptContext, &object))
  3795. {
  3796. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotGet_NullOrUndefined, GetPropertyDisplayNameForError(index, scriptContext));
  3797. }
  3798. ThreadContext* threadContext = scriptContext->GetThreadContext();
  3799. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  3800. threadContext->ClearImplicitCallFlags();
  3801. uint32 indexVal;
  3802. PropertyRecord const * propertyRecord = nullptr;
  3803. Var value = NULL;
  3804. BOOL hasProperty = FALSE;
  3805. IndexType indexType = GetIndexType(index, scriptContext, &indexVal, &propertyRecord, false);
  3806. if (indexType == IndexType_Number)
  3807. {
  3808. hasProperty = JavascriptOperators::GetItemReference(instance, object, indexVal, &value, scriptContext);
  3809. }
  3810. else
  3811. {
  3812. Assert(indexType == IndexType_PropertyId);
  3813. if (propertyRecord == nullptr && !JavascriptOperators::CanShortcutOnUnknownPropertyName(object))
  3814. {
  3815. indexType = GetIndexTypeFromPrimitive(index, scriptContext, &indexVal, &propertyRecord, true);
  3816. Assert(indexType == IndexType_PropertyId);
  3817. Assert(propertyRecord != nullptr);
  3818. }
  3819. if (propertyRecord != nullptr)
  3820. {
  3821. hasProperty = JavascriptOperators::GetPropertyReference(instance, object, propertyRecord->GetPropertyId(), &value, scriptContext, NULL);
  3822. }
  3823. #if DBG
  3824. else
  3825. {
  3826. JavascriptString* indexStr = JavascriptConversion::ToString(index, scriptContext);
  3827. PropertyRecord const * debugPropertyRecord;
  3828. scriptContext->GetOrAddPropertyRecord(indexStr, &debugPropertyRecord);
  3829. AssertMsg(!JavascriptOperators::GetPropertyReference(instance, object, debugPropertyRecord->GetPropertyId(), &value, scriptContext, NULL),
  3830. "how did this property come? See OS Bug 2727708 if you see this come from the web");
  3831. }
  3832. #endif
  3833. }
  3834. if (!hasProperty)
  3835. {
  3836. JavascriptString* varName = nullptr;
  3837. if (indexType == IndexType_PropertyId && propertyRecord != nullptr && propertyRecord->IsSymbol())
  3838. {
  3839. varName = JavascriptSymbol::ToString(propertyRecord, scriptContext);
  3840. }
  3841. else
  3842. {
  3843. varName = JavascriptConversion::ToString(index, scriptContext);
  3844. }
  3845. // ES5 11.2.3 #2: We evaluate the call target but don't throw yet if target member is missing. We need to evaluate argList
  3846. // first (#3). Postpone throwing error to invoke time.
  3847. value = ThrowErrorObject::CreateThrowTypeErrorObject(scriptContext, VBSERR_OLENoPropOrMethod, varName);
  3848. }
  3849. else if(!JavascriptConversion::IsCallable(value))
  3850. {
  3851. // ES5 11.2.3 #2: We evaluate the call target but don't throw yet if target member is missing. We need to evaluate argList
  3852. // first (#3). Postpone throwing error to invoke time.
  3853. JavascriptString* varName = JavascriptConversion::ToString(index, scriptContext);
  3854. value = ThrowErrorObject::CreateThrowTypeErrorObject(scriptContext, JSERR_Property_NeedFunction, varName);
  3855. }
  3856. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3857. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3858. return value;
  3859. JIT_HELPER_END(Op_GetMethodElement);
  3860. }
  3861. BOOL JavascriptOperators::OP_SetElementI_UInt32(Var instance, uint32 index, Var value, ScriptContext* scriptContext, PropertyOperationFlags flags)
  3862. {
  3863. JIT_HELPER_REENTRANT_HEADER(Op_SetElementI_UInt32);
  3864. JIT_HELPER_SAME_ATTRIBUTES(Op_SetElementI_UInt32, Op_SetElementI);
  3865. #if FLOATVAR
  3866. return OP_SetElementI_JIT(instance, Js::JavascriptNumber::ToVar(index, scriptContext), value, scriptContext, flags);
  3867. #else
  3868. char buffer[sizeof(Js::JavascriptNumber)];
  3869. return OP_SetElementI_JIT(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  3870. (Js::JavascriptNumber *)buffer), value, scriptContext, flags);
  3871. #endif
  3872. JIT_HELPER_END(Op_SetElementI_UInt32);
  3873. }
  3874. BOOL JavascriptOperators::OP_SetElementI_Int32(Var instance, int32 index, Var value, ScriptContext* scriptContext, PropertyOperationFlags flags)
  3875. {
  3876. JIT_HELPER_REENTRANT_HEADER(Op_SetElementI_Int32);
  3877. JIT_HELPER_SAME_ATTRIBUTES(Op_SetElementI_Int32, Op_SetElementI);
  3878. #if FLOATVAR
  3879. return OP_SetElementI_JIT(instance, Js::JavascriptNumber::ToVar(index, scriptContext), value, scriptContext, flags);
  3880. #else
  3881. char buffer[sizeof(Js::JavascriptNumber)];
  3882. return OP_SetElementI_JIT(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  3883. (Js::JavascriptNumber *)buffer), value, scriptContext, flags);
  3884. #endif
  3885. JIT_HELPER_END(Op_SetElementI_Int32);
  3886. }
  3887. BOOL JavascriptOperators::OP_SetElementI_JIT(Var instance, Var index, Var value, ScriptContext* scriptContext, PropertyOperationFlags flags)
  3888. {
  3889. JIT_HELPER_REENTRANT_HEADER(Op_SetElementI);
  3890. if (TaggedNumber::Is(instance))
  3891. {
  3892. return OP_SetElementI(instance, index, value, scriptContext, flags);
  3893. }
  3894. INT_PTR vt = VirtualTableInfoBase::GetVirtualTable(instance);
  3895. OP_SetElementI(instance, index, value, scriptContext, flags);
  3896. return vt != VirtualTableInfoBase::GetVirtualTable(instance);
  3897. JIT_HELPER_END(Op_SetElementI);
  3898. }
  3899. BOOL JavascriptOperators::OP_SetElementI(Var instance, Var index, Var value, ScriptContext* scriptContext, PropertyOperationFlags flags)
  3900. {
  3901. #if ENABLE_COPYONACCESS_ARRAY
  3902. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  3903. #endif
  3904. TypeId instanceType = JavascriptOperators::GetTypeId(instance);
  3905. bool isTypedArray = (instanceType >= TypeIds_Int8Array && instanceType <= TypeIds_Float64Array);
  3906. if (isTypedArray)
  3907. {
  3908. if (TaggedInt::Is(index) || JavascriptNumber::Is_NoTaggedIntCheck(index) || JavascriptString::Is(index))
  3909. {
  3910. BOOL returnValue = FALSE;
  3911. bool isNumericIndex = false;
  3912. // CrossSite types will go down the slow path.
  3913. switch (instanceType)
  3914. {
  3915. case TypeIds_Int8Array:
  3916. {
  3917. // The typed array will deal with all possible values for the index
  3918. if (VirtualTableInfo<Int8VirtualArray>::HasVirtualTable(instance))
  3919. {
  3920. Int8VirtualArray* int8Array = Int8VirtualArray::UnsafeFromVar(instance);
  3921. returnValue = int8Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  3922. }
  3923. else if( VirtualTableInfo<Int8Array>::HasVirtualTable(instance))
  3924. {
  3925. Int8Array* int8Array = Int8Array::UnsafeFromVar(instance);
  3926. returnValue = int8Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  3927. }
  3928. break;
  3929. }
  3930. case TypeIds_Uint8Array:
  3931. {
  3932. // The typed array will deal with all possible values for the index
  3933. if (VirtualTableInfo<Uint8VirtualArray>::HasVirtualTable(instance))
  3934. {
  3935. Uint8VirtualArray* uint8Array = Uint8VirtualArray::UnsafeFromVar(instance);
  3936. returnValue = uint8Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  3937. }
  3938. else if (VirtualTableInfo<Uint8Array>::HasVirtualTable(instance))
  3939. {
  3940. Uint8Array* uint8Array = Uint8Array::UnsafeFromVar(instance);
  3941. returnValue = uint8Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  3942. }
  3943. break;
  3944. }
  3945. case TypeIds_Uint8ClampedArray:
  3946. {
  3947. // The typed array will deal with all possible values for the index
  3948. if (VirtualTableInfo<Uint8ClampedVirtualArray>::HasVirtualTable(instance))
  3949. {
  3950. Uint8ClampedVirtualArray* uint8ClampedArray = Uint8ClampedVirtualArray::UnsafeFromVar(instance);
  3951. returnValue = uint8ClampedArray->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  3952. }
  3953. else if(VirtualTableInfo<Uint8ClampedArray>::HasVirtualTable(instance))
  3954. {
  3955. Uint8ClampedArray* uint8ClampedArray = Uint8ClampedArray::UnsafeFromVar(instance);
  3956. returnValue = uint8ClampedArray->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  3957. }
  3958. break;
  3959. }
  3960. case TypeIds_Int16Array:
  3961. {
  3962. // The type array will deal with all possible values for the index
  3963. if (VirtualTableInfo<Int16VirtualArray>::HasVirtualTable(instance))
  3964. {
  3965. Int16VirtualArray* int16Array = Int16VirtualArray::UnsafeFromVar(instance);
  3966. returnValue = int16Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  3967. }
  3968. else if (VirtualTableInfo<Int16Array>::HasVirtualTable(instance))
  3969. {
  3970. Int16Array* int16Array = Int16Array::UnsafeFromVar(instance);
  3971. returnValue = int16Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  3972. }
  3973. break;
  3974. }
  3975. case TypeIds_Uint16Array:
  3976. {
  3977. // The type array will deal with all possible values for the index
  3978. if (VirtualTableInfo<Uint16VirtualArray>::HasVirtualTable(instance))
  3979. {
  3980. Uint16VirtualArray* uint16Array = Uint16VirtualArray::UnsafeFromVar(instance);
  3981. returnValue = uint16Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  3982. }
  3983. else if (VirtualTableInfo<Uint16Array>::HasVirtualTable(instance))
  3984. {
  3985. Uint16Array* uint16Array = Uint16Array::UnsafeFromVar(instance);
  3986. returnValue = uint16Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  3987. }
  3988. break;
  3989. }
  3990. case TypeIds_Int32Array:
  3991. {
  3992. // The type array will deal with all possible values for the index
  3993. if (VirtualTableInfo<Int32VirtualArray>::HasVirtualTable(instance))
  3994. {
  3995. Int32VirtualArray* int32Array = Int32VirtualArray::UnsafeFromVar(instance);
  3996. returnValue = int32Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  3997. }
  3998. else if(VirtualTableInfo<Int32Array>::HasVirtualTable(instance))
  3999. {
  4000. Int32Array* int32Array = Int32Array::UnsafeFromVar(instance);
  4001. returnValue = int32Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  4002. }
  4003. break;
  4004. }
  4005. case TypeIds_Uint32Array:
  4006. {
  4007. // The type array will deal with all possible values for the index
  4008. if (VirtualTableInfo<Uint32VirtualArray>::HasVirtualTable(instance))
  4009. {
  4010. Uint32VirtualArray* uint32Array = Uint32VirtualArray::UnsafeFromVar(instance);
  4011. returnValue = uint32Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  4012. }
  4013. else if (VirtualTableInfo<Uint32Array>::HasVirtualTable(instance))
  4014. {
  4015. Uint32Array* uint32Array = Uint32Array::UnsafeFromVar(instance);
  4016. returnValue = uint32Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  4017. }
  4018. break;
  4019. }
  4020. case TypeIds_Float32Array:
  4021. {
  4022. // The type array will deal with all possible values for the index
  4023. if (VirtualTableInfo<Float32VirtualArray>::HasVirtualTable(instance))
  4024. {
  4025. Float32VirtualArray* float32Array = Float32VirtualArray::UnsafeFromVar(instance);
  4026. returnValue = float32Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  4027. }
  4028. else if (VirtualTableInfo<Float32Array>::HasVirtualTable(instance))
  4029. {
  4030. Float32Array* float32Array = Float32Array::UnsafeFromVar(instance);
  4031. returnValue = float32Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  4032. }
  4033. break;
  4034. }
  4035. case TypeIds_Float64Array:
  4036. {
  4037. // The type array will deal with all possible values for the index
  4038. if (VirtualTableInfo<Float64VirtualArray>::HasVirtualTable(instance))
  4039. {
  4040. Float64VirtualArray* float64Array = Float64VirtualArray::UnsafeFromVar(instance);
  4041. returnValue = float64Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  4042. }
  4043. else if (VirtualTableInfo<Float64Array>::HasVirtualTable(instance))
  4044. {
  4045. Float64Array* float64Array = Float64Array::UnsafeFromVar(instance);
  4046. returnValue = float64Array->ValidateIndexAndDirectSetItem(index, value, &isNumericIndex);
  4047. }
  4048. break;
  4049. }
  4050. }
  4051. // if this was numeric index, return operation status else
  4052. // Return the result of calling the default ordinary object [[Set]] internal method (9.1.8) on O passing P, V, and Receiver as arguments.
  4053. if (isNumericIndex)
  4054. return returnValue;
  4055. }
  4056. }
  4057. else
  4058. {
  4059. if (TaggedInt::Is(index))
  4060. {
  4061. TaggedIntIndex:
  4062. switch (instanceType)
  4063. {
  4064. case TypeIds_NativeIntArray:
  4065. case TypeIds_NativeFloatArray:
  4066. case TypeIds_Array: // fast path for array
  4067. {
  4068. int indexInt = TaggedInt::ToInt32(index);
  4069. if (indexInt >= 0 && scriptContext->optimizationOverrides.IsEnabledArraySetElementFastPath())
  4070. {
  4071. JavascriptArray::UnsafeFromVar(instance)->SetItem((uint32)indexInt, value, flags);
  4072. return TRUE;
  4073. }
  4074. break;
  4075. }
  4076. }
  4077. }
  4078. else if (JavascriptNumber::Is_NoTaggedIntCheck(index))
  4079. {
  4080. double dIndexValue = JavascriptNumber::GetValue(index);
  4081. uint32 uint32Index = JavascriptConversion::ToUInt32(index, scriptContext);
  4082. if ((double)uint32Index == dIndexValue && !TaggedInt::IsOverflow(uint32Index))
  4083. {
  4084. index = TaggedInt::ToVarUnchecked(uint32Index);
  4085. goto TaggedIntIndex;
  4086. }
  4087. }
  4088. }
  4089. RecyclableObject* object = nullptr;
  4090. if (!GetPropertyObjectForSetElementI(instance, index, scriptContext, &object))
  4091. {
  4092. return FALSE;
  4093. }
  4094. return JavascriptOperators::SetElementIHelper(instance, object, index, value, scriptContext, flags);
  4095. }
  4096. BOOL JavascriptOperators::SetElementIHelper(Var receiver, RecyclableObject* object, Var index, Var value, ScriptContext* scriptContext, PropertyOperationFlags flags)
  4097. {
  4098. IndexType indexType;
  4099. uint32 indexVal = 0;
  4100. PropertyRecord const * propertyRecord = nullptr;
  4101. JavascriptString * propertyNameString = nullptr;
  4102. PropertyValueInfo propertyValueInfo;
  4103. RecyclableObject* cacheOwner;
  4104. PropertyRecordUsageCache* propertyRecordUsageCache;
  4105. if (JavascriptOperators::GetPropertyRecordUsageCache(index, scriptContext, &propertyRecordUsageCache, &cacheOwner))
  4106. {
  4107. return JavascriptOperators::SetElementIWithCache<false>(receiver, object, cacheOwner, value, propertyRecordUsageCache, scriptContext, flags, nullptr);
  4108. }
  4109. if (TaggedNumber::Is(receiver))
  4110. {
  4111. return JavascriptOperators::SetElementIOnTaggedNumber(receiver, object, index, value, scriptContext, flags);
  4112. }
  4113. #if DBG_DUMP
  4114. scriptContext->forinNoCache += (!TaggedInt::Is(index) && JavascriptString::Is(index));
  4115. #endif
  4116. indexType = GetIndexType(index, scriptContext, &indexVal, &propertyRecord, &propertyNameString, false, true);
  4117. if (scriptContext->GetThreadContext()->IsDisableImplicitCall() &&
  4118. scriptContext->GetThreadContext()->GetImplicitCallFlags() != ImplicitCall_None)
  4119. {
  4120. // We hit an implicit call trying to convert the index, and implicit calls are disabled, so
  4121. // quit before we try to store the element.
  4122. return FALSE;
  4123. }
  4124. if (indexType == IndexType_Number)
  4125. {
  4126. SetElementIHelper_INDEX_TYPE_IS_NUMBER:
  4127. return JavascriptOperators::SetItem(receiver, object, indexVal, value, scriptContext, flags);
  4128. }
  4129. else if (indexType == IndexType_JavascriptString)
  4130. {
  4131. Assert(propertyNameString);
  4132. // At this point, we know that the propertyNameString is neither PropertyString
  4133. // or LiteralStringWithPropertyStringPtr.. Get PropertyRecord!
  4134. // we will get it anyways otherwise. (Also, 1:1 string comparison for Builtin types will be expensive.)
  4135. if (propertyRecord == nullptr)
  4136. {
  4137. scriptContext->GetOrAddPropertyRecord(propertyNameString, &propertyRecord);
  4138. if (propertyRecord->IsNumeric())
  4139. {
  4140. indexVal = propertyRecord->GetNumericValue();
  4141. goto SetElementIHelper_INDEX_TYPE_IS_NUMBER;
  4142. }
  4143. }
  4144. }
  4145. Assert(indexType == IndexType_PropertyId || indexType == IndexType_JavascriptString);
  4146. Assert(propertyRecord);
  4147. return JavascriptOperators::SetProperty(receiver, object, propertyRecord->GetPropertyId(), value, scriptContext, flags);
  4148. }
  4149. BOOL JavascriptOperators::OP_SetNativeIntElementI(
  4150. Var instance,
  4151. Var aElementIndex,
  4152. int32 iValue,
  4153. ScriptContext* scriptContext,
  4154. PropertyOperationFlags flags)
  4155. {
  4156. JIT_HELPER_REENTRANT_HEADER(Op_SetNativeIntElementI);
  4157. INT_PTR vt = (INT_PTR)nullptr;
  4158. vt = VirtualTableInfoBase::GetVirtualTable(instance);
  4159. if (TaggedInt::Is(aElementIndex))
  4160. {
  4161. int32 indexInt = TaggedInt::ToInt32(aElementIndex);
  4162. if (indexInt >= 0 && scriptContext->optimizationOverrides.IsEnabledArraySetElementFastPath())
  4163. {
  4164. JavascriptNativeIntArray *arr = JavascriptNativeIntArray::FromVar(instance);
  4165. if (!(arr->TryGrowHeadSegmentAndSetItem<int32, JavascriptNativeIntArray>((uint32)indexInt, iValue)))
  4166. {
  4167. arr->SetItem(indexInt, iValue);
  4168. }
  4169. return vt != VirtualTableInfoBase::GetVirtualTable(instance);
  4170. }
  4171. }
  4172. JavascriptOperators::OP_SetElementI(instance, aElementIndex, JavascriptNumber::ToVar(iValue, scriptContext), scriptContext, flags);
  4173. return vt != VirtualTableInfoBase::GetVirtualTable(instance);
  4174. JIT_HELPER_END(Op_SetNativeIntElementI);
  4175. }
  4176. BOOL JavascriptOperators::OP_SetNativeIntElementI_UInt32(
  4177. Var instance,
  4178. uint32 aElementIndex,
  4179. int32 iValue,
  4180. ScriptContext* scriptContext,
  4181. PropertyOperationFlags flags)
  4182. {
  4183. JIT_HELPER_REENTRANT_HEADER(Op_SetNativeIntElementI_UInt32);
  4184. JIT_HELPER_SAME_ATTRIBUTES(Op_SetNativeIntElementI_UInt32, Op_SetNativeIntElementI);
  4185. #if FLOATVAR
  4186. return OP_SetNativeIntElementI(instance, Js::JavascriptNumber::ToVar(aElementIndex, scriptContext), iValue, scriptContext, flags);
  4187. #else
  4188. char buffer[sizeof(Js::JavascriptNumber)];
  4189. return OP_SetNativeIntElementI(instance, Js::JavascriptNumber::ToVarInPlace(aElementIndex, scriptContext,
  4190. (Js::JavascriptNumber *)buffer), iValue, scriptContext, flags);
  4191. #endif
  4192. JIT_HELPER_END(Op_SetNativeIntElementI_UInt32);
  4193. }
  4194. BOOL JavascriptOperators::OP_SetNativeIntElementI_Int32(
  4195. Var instance,
  4196. int aElementIndex,
  4197. int32 iValue,
  4198. ScriptContext* scriptContext,
  4199. PropertyOperationFlags flags)
  4200. {
  4201. JIT_HELPER_REENTRANT_HEADER(Op_SetNativeIntElementI_Int32);
  4202. JIT_HELPER_SAME_ATTRIBUTES(Op_SetNativeIntElementI_Int32, Op_SetNativeIntElementI);
  4203. #if FLOATVAR
  4204. return OP_SetNativeIntElementI(instance, Js::JavascriptNumber::ToVar(aElementIndex, scriptContext), iValue, scriptContext, flags);
  4205. #else
  4206. char buffer[sizeof(Js::JavascriptNumber)];
  4207. return OP_SetNativeIntElementI(instance, Js::JavascriptNumber::ToVarInPlace(aElementIndex, scriptContext,
  4208. (Js::JavascriptNumber *)buffer), iValue, scriptContext, flags);
  4209. #endif
  4210. JIT_HELPER_END(Op_SetNativeIntElementI_Int32);
  4211. }
  4212. BOOL JavascriptOperators::OP_SetNativeFloatElementI(
  4213. Var instance,
  4214. Var aElementIndex,
  4215. ScriptContext* scriptContext,
  4216. PropertyOperationFlags flags,
  4217. double dValue)
  4218. {
  4219. JIT_HELPER_REENTRANT_HEADER(Op_SetNativeFloatElementI);
  4220. INT_PTR vt = (INT_PTR)nullptr;
  4221. vt = VirtualTableInfoBase::GetVirtualTable(instance);
  4222. if (TaggedInt::Is(aElementIndex))
  4223. {
  4224. int32 indexInt = TaggedInt::ToInt32(aElementIndex);
  4225. if (indexInt >= 0 && scriptContext->optimizationOverrides.IsEnabledArraySetElementFastPath())
  4226. {
  4227. JavascriptNativeFloatArray *arr = JavascriptNativeFloatArray::FromVar(instance);
  4228. if (!(arr->TryGrowHeadSegmentAndSetItem<double, JavascriptNativeFloatArray>((uint32)indexInt, dValue)))
  4229. {
  4230. arr->SetItem(indexInt, dValue);
  4231. }
  4232. return vt != VirtualTableInfoBase::GetVirtualTable(instance);
  4233. }
  4234. }
  4235. JavascriptOperators::OP_SetElementI(instance, aElementIndex, JavascriptNumber::ToVarWithCheck(dValue, scriptContext), scriptContext, flags);
  4236. return vt != VirtualTableInfoBase::GetVirtualTable(instance);
  4237. JIT_HELPER_END(Op_SetNativeFloatElementI);
  4238. }
  4239. BOOL JavascriptOperators::OP_SetNativeFloatElementI_UInt32(
  4240. Var instance,
  4241. uint32 aElementIndex,
  4242. ScriptContext* scriptContext,
  4243. PropertyOperationFlags flags,
  4244. double dValue)
  4245. {
  4246. JIT_HELPER_REENTRANT_HEADER(Op_SetNativeFloatElementI_UInt32);
  4247. JIT_HELPER_SAME_ATTRIBUTES(Op_SetNativeFloatElementI_UInt32, Op_SetNativeFloatElementI);
  4248. #if FLOATVAR
  4249. return OP_SetNativeFloatElementI(instance, JavascriptNumber::ToVar(aElementIndex, scriptContext), scriptContext, flags, dValue);
  4250. #else
  4251. char buffer[sizeof(Js::JavascriptNumber)];
  4252. return OP_SetNativeFloatElementI(instance, JavascriptNumber::ToVarInPlace(aElementIndex, scriptContext,
  4253. (Js::JavascriptNumber *)buffer), scriptContext, flags, dValue);
  4254. #endif
  4255. JIT_HELPER_END(Op_SetNativeFloatElementI_UInt32);
  4256. }
  4257. BOOL JavascriptOperators::OP_SetNativeFloatElementI_Int32(
  4258. Var instance,
  4259. int aElementIndex,
  4260. ScriptContext* scriptContext,
  4261. PropertyOperationFlags flags,
  4262. double dValue)
  4263. {
  4264. JIT_HELPER_REENTRANT_HEADER(Op_SetNativeFloatElementI_Int32);
  4265. JIT_HELPER_SAME_ATTRIBUTES(Op_SetNativeFloatElementI_Int32, Op_SetNativeFloatElementI);
  4266. #if FLOATVAR
  4267. return OP_SetNativeFloatElementI(instance, JavascriptNumber::ToVar(aElementIndex, scriptContext), scriptContext, flags, dValue);
  4268. #else
  4269. char buffer[sizeof(Js::JavascriptNumber)];
  4270. return OP_SetNativeFloatElementI(instance, JavascriptNumber::ToVarInPlace(aElementIndex, scriptContext,
  4271. (Js::JavascriptNumber *)buffer), scriptContext, flags, dValue);
  4272. #endif
  4273. JIT_HELPER_END(Op_SetNativeFloatElementI_Int32);
  4274. }
  4275. BOOL JavascriptOperators::OP_Memcopy(Var dstInstance, int32 dstStart, Var srcInstance, int32 srcStart, int32 length, ScriptContext* scriptContext)
  4276. {
  4277. JIT_HELPER_NOT_REENTRANT_HEADER(Op_Memcopy, reentrancylock, scriptContext->GetThreadContext());
  4278. if (length <= 0)
  4279. {
  4280. return false;
  4281. }
  4282. TypeId instanceType = JavascriptOperators::GetTypeId(srcInstance);
  4283. if (instanceType != JavascriptOperators::GetTypeId(dstInstance))
  4284. {
  4285. return false;
  4286. }
  4287. if (srcStart != dstStart)
  4288. {
  4289. return false;
  4290. }
  4291. BOOL returnValue = false;
  4292. #define MEMCOPY_TYPED_ARRAY(type, conversion) type ## ::FromVar(dstInstance)->DirectSetItemAtRange( type ## ::FromVar(srcInstance), srcStart, dstStart, length, JavascriptConversion:: ## conversion)
  4293. switch (instanceType)
  4294. {
  4295. case TypeIds_Int8Array:
  4296. {
  4297. returnValue = MEMCOPY_TYPED_ARRAY(Int8Array, ToInt8);
  4298. break;
  4299. }
  4300. case TypeIds_Uint8Array:
  4301. {
  4302. returnValue = MEMCOPY_TYPED_ARRAY(Uint8Array, ToUInt8);
  4303. break;
  4304. }
  4305. case TypeIds_Uint8ClampedArray:
  4306. {
  4307. returnValue = MEMCOPY_TYPED_ARRAY(Uint8ClampedArray, ToUInt8Clamped);
  4308. break;
  4309. }
  4310. case TypeIds_Int16Array:
  4311. {
  4312. returnValue = MEMCOPY_TYPED_ARRAY(Int16Array, ToInt16);
  4313. break;
  4314. }
  4315. case TypeIds_Uint16Array:
  4316. {
  4317. returnValue = MEMCOPY_TYPED_ARRAY(Uint16Array, ToUInt16);
  4318. break;
  4319. }
  4320. case TypeIds_Int32Array:
  4321. {
  4322. returnValue = MEMCOPY_TYPED_ARRAY(Int32Array, ToInt32);
  4323. break;
  4324. }
  4325. case TypeIds_Uint32Array:
  4326. {
  4327. returnValue = MEMCOPY_TYPED_ARRAY(Uint32Array, ToUInt32);
  4328. break;
  4329. }
  4330. case TypeIds_Float32Array:
  4331. {
  4332. returnValue = MEMCOPY_TYPED_ARRAY(Float32Array, ToFloat);
  4333. break;
  4334. }
  4335. case TypeIds_Float64Array:
  4336. {
  4337. returnValue = MEMCOPY_TYPED_ARRAY(Float64Array, ToNumber);
  4338. break;
  4339. }
  4340. case TypeIds_Array:
  4341. case TypeIds_NativeFloatArray:
  4342. case TypeIds_NativeIntArray:
  4343. {
  4344. if (dstStart < 0 || srcStart < 0)
  4345. {
  4346. // This is not supported, Bailout
  4347. break;
  4348. }
  4349. // Upper bounds check for source array
  4350. JavascriptArray* srcArray = JavascriptArray::UnsafeFromVar(srcInstance);
  4351. JavascriptArray* dstArray = JavascriptArray::FromVar(dstInstance);
  4352. if (scriptContext->optimizationOverrides.IsEnabledArraySetElementFastPath())
  4353. {
  4354. INT_PTR vt = VirtualTableInfoBase::GetVirtualTable(dstInstance);
  4355. if (instanceType == TypeIds_Array)
  4356. {
  4357. returnValue = dstArray->DirectSetItemAtRangeFromArray<Var>(dstStart, length, srcArray, srcStart);
  4358. }
  4359. else if (instanceType == TypeIds_NativeIntArray)
  4360. {
  4361. returnValue = dstArray->DirectSetItemAtRangeFromArray<int32>(dstStart, length, srcArray, srcStart);
  4362. }
  4363. else
  4364. {
  4365. returnValue = dstArray->DirectSetItemAtRangeFromArray<double>(dstStart, length, srcArray, srcStart);
  4366. }
  4367. returnValue &= vt == VirtualTableInfoBase::GetVirtualTable(dstInstance);
  4368. }
  4369. break;
  4370. }
  4371. default:
  4372. AssertMsg(false, "We don't support this type for memcopy yet.");
  4373. break;
  4374. }
  4375. #undef MEMCOPY_TYPED_ARRAY
  4376. return returnValue;
  4377. JIT_HELPER_END(Op_Memcopy);
  4378. }
  4379. template<typename T, T(*func)(Var, ScriptContext*)> bool MemsetConversion(Var value, ScriptContext* scriptContext, T* result)
  4380. {
  4381. ImplicitCallFlags flags = scriptContext->GetThreadContext()->TryWithDisabledImplicitCall([&]
  4382. {
  4383. *result = func(value, scriptContext);
  4384. });
  4385. return (flags & (~ImplicitCall_None)) == 0;
  4386. }
  4387. BOOL JavascriptOperators::OP_Memset(Var instance, int32 start, Var value, int32 length, ScriptContext* scriptContext)
  4388. {
  4389. JIT_HELPER_NOT_REENTRANT_HEADER(Op_Memset, reentrancylock, scriptContext->GetThreadContext());
  4390. if (length <= 0)
  4391. {
  4392. return false;
  4393. }
  4394. TypeId instanceType = JavascriptOperators::GetTypeId(instance);
  4395. BOOL returnValue = false;
  4396. // The typed array will deal with all possible values for the index
  4397. #define MEMSET_TYPED_ARRAY_CASE(type, conversion) \
  4398. case TypeIds_##type: \
  4399. { \
  4400. type## ::TypedArrayType typedValue = 0; \
  4401. if (!MemsetConversion<type## ::TypedArrayType, JavascriptConversion:: ##conversion>(value, scriptContext, &typedValue)) return false; \
  4402. returnValue = type## ::FromVar(instance)->DirectSetItemAtRange(start, length, typedValue); \
  4403. break; \
  4404. }
  4405. switch (instanceType)
  4406. {
  4407. MEMSET_TYPED_ARRAY_CASE(Int8Array, ToInt8)
  4408. MEMSET_TYPED_ARRAY_CASE(Uint8Array, ToUInt8)
  4409. MEMSET_TYPED_ARRAY_CASE(Uint8ClampedArray, ToUInt8Clamped)
  4410. MEMSET_TYPED_ARRAY_CASE(Int16Array, ToInt16)
  4411. MEMSET_TYPED_ARRAY_CASE(Uint16Array, ToUInt16)
  4412. MEMSET_TYPED_ARRAY_CASE(Int32Array, ToInt32)
  4413. MEMSET_TYPED_ARRAY_CASE(Uint32Array, ToUInt32)
  4414. MEMSET_TYPED_ARRAY_CASE(Float32Array, ToFloat)
  4415. MEMSET_TYPED_ARRAY_CASE(Float64Array, ToNumber)
  4416. case TypeIds_NativeFloatArray:
  4417. case TypeIds_NativeIntArray:
  4418. case TypeIds_Array:
  4419. {
  4420. if (start < 0)
  4421. {
  4422. for (start; start < 0 && length > 0; ++start, --length)
  4423. {
  4424. if (!OP_SetElementI(instance, JavascriptNumber::ToVar(start, scriptContext), value, scriptContext))
  4425. {
  4426. return false;
  4427. }
  4428. }
  4429. }
  4430. if (scriptContext->optimizationOverrides.IsEnabledArraySetElementFastPath())
  4431. {
  4432. INT_PTR vt = VirtualTableInfoBase::GetVirtualTable(instance);
  4433. if (instanceType == TypeIds_Array)
  4434. {
  4435. returnValue = JavascriptArray::UnsafeFromVar(instance)->DirectSetItemAtRange<Var>(start, length, value);
  4436. }
  4437. else if (instanceType == TypeIds_NativeIntArray)
  4438. {
  4439. // Only accept tagged int. Also covers case for MissingItem
  4440. if (!TaggedInt::Is(value))
  4441. {
  4442. return false;
  4443. }
  4444. int32 intValue = 0;
  4445. if (!MemsetConversion<int32, JavascriptConversion::ToInt32>(value, scriptContext, &intValue))
  4446. {
  4447. return false;
  4448. }
  4449. returnValue = JavascriptArray::UnsafeFromVar(instance)->DirectSetItemAtRange<int32>(start, length, intValue);
  4450. }
  4451. else
  4452. {
  4453. // For native float arrays, the jit doesn't check the type of the source so we have to do it here
  4454. if (!JavascriptNumber::Is(value) && !TaggedNumber::Is(value))
  4455. {
  4456. return false;
  4457. }
  4458. double doubleValue = 0;
  4459. if (!MemsetConversion<double, JavascriptConversion::ToNumber>(value, scriptContext, &doubleValue))
  4460. {
  4461. return false;
  4462. }
  4463. // Special case for missing item
  4464. if (SparseArraySegment<double>::IsMissingItem(&doubleValue))
  4465. {
  4466. return false;
  4467. }
  4468. returnValue = JavascriptArray::UnsafeFromVar(instance)->DirectSetItemAtRange<double>(start, length, doubleValue);
  4469. }
  4470. returnValue &= vt == VirtualTableInfoBase::GetVirtualTable(instance);
  4471. }
  4472. break;
  4473. }
  4474. default:
  4475. AssertMsg(false, "We don't support this type for memset yet.");
  4476. break;
  4477. }
  4478. #undef MEMSET_TYPED_ARRAY
  4479. return returnValue;
  4480. JIT_HELPER_END(Op_Memset);
  4481. }
  4482. Var JavascriptOperators::OP_DeleteElementI_UInt32(Var instance, uint32 index, ScriptContext* scriptContext, PropertyOperationFlags propertyOperationFlags)
  4483. {
  4484. JIT_HELPER_REENTRANT_HEADER(Op_DeleteElementI_UInt32);
  4485. JIT_HELPER_SAME_ATTRIBUTES(Op_DeleteElementI_UInt32, Op_DeleteElementI);
  4486. #if FLOATVAR
  4487. return OP_DeleteElementI(instance, Js::JavascriptNumber::ToVar(index, scriptContext), scriptContext, propertyOperationFlags);
  4488. #else
  4489. char buffer[sizeof(Js::JavascriptNumber)];
  4490. return OP_DeleteElementI(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  4491. (Js::JavascriptNumber *)buffer), scriptContext, propertyOperationFlags);
  4492. #endif
  4493. JIT_HELPER_END(Op_DeleteElementI_UInt32);
  4494. }
  4495. Var JavascriptOperators::OP_DeleteElementI_Int32(Var instance, int32 index, ScriptContext* scriptContext, PropertyOperationFlags propertyOperationFlags)
  4496. {
  4497. JIT_HELPER_REENTRANT_HEADER(Op_DeleteElementI_Int32);
  4498. JIT_HELPER_SAME_ATTRIBUTES(Op_DeleteElementI_Int32, Op_DeleteElementI);
  4499. #if FLOATVAR
  4500. return OP_DeleteElementI(instance, Js::JavascriptNumber::ToVar(index, scriptContext), scriptContext, propertyOperationFlags);
  4501. #else
  4502. char buffer[sizeof(Js::JavascriptNumber)];
  4503. return OP_DeleteElementI(instance, Js::JavascriptNumber::ToVarInPlace(index, scriptContext,
  4504. (Js::JavascriptNumber *)buffer), scriptContext, propertyOperationFlags);
  4505. #endif
  4506. JIT_HELPER_END(Op_DeleteElementI_Int32);
  4507. }
  4508. Var JavascriptOperators::OP_DeleteElementI(Var instance, Var index, ScriptContext* scriptContext, PropertyOperationFlags propertyOperationFlags)
  4509. {
  4510. JIT_HELPER_REENTRANT_HEADER(Op_DeleteElementI);
  4511. if(TaggedNumber::Is(instance))
  4512. {
  4513. return scriptContext->GetLibrary()->GetTrue();
  4514. }
  4515. #if ENABLE_COPYONACCESS_ARRAY
  4516. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  4517. #endif
  4518. RecyclableObject* object = RecyclableObject::FromVar(instance);
  4519. if (JavascriptOperators::IsUndefinedOrNull(object))
  4520. {
  4521. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotDelete_NullOrUndefined, GetPropertyDisplayNameForError(index, scriptContext));
  4522. }
  4523. uint32 indexVal;
  4524. PropertyRecord const * propertyRecord = nullptr;
  4525. JavascriptString * propertyNameString = nullptr;
  4526. BOOL result = TRUE;
  4527. IndexType indexType = GetIndexType(index, scriptContext, &indexVal, &propertyRecord, &propertyNameString, false, true);
  4528. if (indexType == IndexType_Number)
  4529. {
  4530. result = JavascriptOperators::DeleteItem(object, indexVal, propertyOperationFlags);
  4531. }
  4532. else if (indexType == IndexType_JavascriptString)
  4533. {
  4534. result = JavascriptOperators::DeleteProperty(object, propertyNameString, propertyOperationFlags);
  4535. }
  4536. else
  4537. {
  4538. Assert(indexType == IndexType_PropertyId);
  4539. if (propertyRecord == nullptr && !JavascriptOperators::CanShortcutOnUnknownPropertyName(object))
  4540. {
  4541. indexType = GetIndexTypeFromPrimitive(index, scriptContext, &indexVal, &propertyRecord, true);
  4542. Assert(indexType == IndexType_PropertyId);
  4543. Assert(propertyRecord != nullptr);
  4544. }
  4545. if (propertyRecord != nullptr)
  4546. {
  4547. result = JavascriptOperators::DeleteProperty(object, propertyRecord->GetPropertyId(), propertyOperationFlags);
  4548. }
  4549. #if DBG
  4550. else
  4551. {
  4552. JavascriptString* indexStr = JavascriptConversion::ToString(index, scriptContext);
  4553. PropertyRecord const * debugPropertyRecord;
  4554. scriptContext->GetOrAddPropertyRecord(indexStr, &debugPropertyRecord);
  4555. AssertMsg(JavascriptOperators::DeleteProperty(object, debugPropertyRecord->GetPropertyId(), propertyOperationFlags), "delete should have been true. See OS Bug 2727708 if you see this come from the web");
  4556. }
  4557. #endif
  4558. }
  4559. Assert(result || !(propertyOperationFlags & (PropertyOperation_StrictMode | PropertyOperation_ThrowOnDeleteIfNotConfig)));
  4560. return scriptContext->GetLibrary()->CreateBoolean(result);
  4561. JIT_HELPER_END(Op_DeleteElementI);
  4562. }
  4563. Var JavascriptOperators::OP_GetLength(Var instance, ScriptContext* scriptContext)
  4564. {
  4565. return JavascriptOperators::OP_GetProperty(instance, PropertyIds::length, scriptContext);
  4566. }
  4567. Var JavascriptOperators::GetThisFromModuleRoot(Var thisVar)
  4568. {
  4569. RootObjectBase * rootObject = static_cast<RootObjectBase*>(thisVar);
  4570. RecyclableObject* hostObject = rootObject->GetHostObject();
  4571. //
  4572. // if the module root has the host object, use that as "this"
  4573. //
  4574. if (hostObject)
  4575. {
  4576. thisVar = hostObject->GetHostDispatchVar();
  4577. }
  4578. return thisVar;
  4579. }
  4580. inline void JavascriptOperators::TryLoadRoot(Var& thisVar, TypeId typeId, int moduleID, ScriptContextInfo* scriptContext)
  4581. {
  4582. bool loadRoot = false;
  4583. if (JavascriptOperators::IsUndefinedOrNullType(typeId) || typeId == TypeIds_ActivationObject)
  4584. {
  4585. loadRoot = true;
  4586. }
  4587. else if (typeId == TypeIds_HostDispatch)
  4588. {
  4589. TypeId remoteTypeId = TypeIds_Limit;
  4590. if (RecyclableObject::FromVar(thisVar)->GetRemoteTypeId(&remoteTypeId))
  4591. {
  4592. if (remoteTypeId == TypeIds_Null || remoteTypeId == TypeIds_Undefined || remoteTypeId == TypeIds_ActivationObject)
  4593. {
  4594. loadRoot = true;
  4595. }
  4596. }
  4597. }
  4598. if (loadRoot)
  4599. {
  4600. if (moduleID == 0)
  4601. {
  4602. thisVar = (Js::Var)scriptContext->GetGlobalObjectThisAddr();
  4603. }
  4604. else
  4605. {
  4606. // TODO: OOP JIT, create a copy of module roots in server side
  4607. Js::ModuleRoot * moduleRoot = JavascriptOperators::GetModuleRoot(moduleID, (ScriptContext*)scriptContext);
  4608. if (moduleRoot == nullptr)
  4609. {
  4610. Assert(false);
  4611. thisVar = (Js::Var)scriptContext->GetUndefinedAddr();
  4612. }
  4613. else
  4614. {
  4615. thisVar = GetThisFromModuleRoot(moduleRoot);
  4616. }
  4617. }
  4618. }
  4619. }
  4620. Var JavascriptOperators::OP_GetThis(Var thisVar, int moduleID, ScriptContextInfo* scriptContext)
  4621. {
  4622. JIT_HELPER_REENTRANT_HEADER(LdThis);
  4623. //
  4624. // if "this" is null or undefined
  4625. // Pass the global object
  4626. // Else
  4627. // Pass ToObject(this)
  4628. //
  4629. TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
  4630. Assert(!JavascriptOperators::IsThisSelf(typeId));
  4631. return JavascriptOperators::GetThisHelper(thisVar, typeId, moduleID, scriptContext);
  4632. JIT_HELPER_END(LdThis);
  4633. }
  4634. Var JavascriptOperators::OP_GetThisNoFastPath(Var thisVar, int moduleID, ScriptContext* scriptContext)
  4635. {
  4636. JIT_HELPER_REENTRANT_HEADER(LdThisNoFastPath);
  4637. TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
  4638. if (JavascriptOperators::IsThisSelf(typeId))
  4639. {
  4640. Assert(typeId != TypeIds_GlobalObject || ((Js::GlobalObject*)thisVar)->ToThis() == thisVar);
  4641. Assert(typeId != TypeIds_ModuleRoot || JavascriptOperators::GetThisFromModuleRoot(thisVar) == thisVar);
  4642. return thisVar;
  4643. }
  4644. return JavascriptOperators::GetThisHelper(thisVar, typeId, moduleID, scriptContext);
  4645. JIT_HELPER_END(LdThisNoFastPath);
  4646. }
  4647. bool JavascriptOperators::IsThisSelf(TypeId typeId)
  4648. {
  4649. return (JavascriptOperators::IsObjectType(typeId) && ! JavascriptOperators::IsSpecialObjectType(typeId));
  4650. }
  4651. Var JavascriptOperators::GetThisHelper(Var thisVar, TypeId typeId, int moduleID, ScriptContextInfo *scriptContext)
  4652. {
  4653. if (! JavascriptOperators::IsObjectType(typeId) && ! JavascriptOperators::IsUndefinedOrNullType(typeId))
  4654. {
  4655. #if ENABLE_NATIVE_CODEGEN
  4656. Assert(!JITManager::GetJITManager()->IsJITServer());
  4657. #endif
  4658. #if !FLOATVAR
  4659. // We allowed stack number to be used as the "this" for getter and setter activation of
  4660. // n.x and n[prop], where n is the Javascript Number
  4661. return JavascriptOperators::ToObject(
  4662. JavascriptNumber::BoxStackNumber(thisVar, (ScriptContext*)scriptContext), (ScriptContext*)scriptContext);
  4663. #else
  4664. return JavascriptOperators::ToObject(thisVar, (ScriptContext*)scriptContext);
  4665. #endif
  4666. }
  4667. else
  4668. {
  4669. TryLoadRoot(thisVar, typeId, moduleID, scriptContext);
  4670. return thisVar;
  4671. }
  4672. }
  4673. Var JavascriptOperators::OP_StrictGetThis(Var thisVar, ScriptContext* scriptContext)
  4674. {
  4675. JIT_HELPER_NOT_REENTRANT_HEADER(StrictLdThis, reentrancylock, scriptContext->GetThreadContext());
  4676. TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
  4677. if (typeId == TypeIds_ActivationObject)
  4678. {
  4679. return scriptContext->GetLibrary()->GetUndefined();
  4680. }
  4681. return thisVar;
  4682. JIT_HELPER_END(StrictLdThis);
  4683. }
  4684. BOOL JavascriptOperators::GetRemoteTypeId(Var aValue, __out TypeId* typeId)
  4685. {
  4686. *typeId = TypeIds_Limit;
  4687. if (GetTypeId(aValue) != TypeIds_HostDispatch)
  4688. {
  4689. return FALSE;
  4690. }
  4691. return RecyclableObject::FromVar(aValue)->GetRemoteTypeId(typeId);
  4692. }
  4693. BOOL JavascriptOperators::IsJsNativeType(TypeId type)
  4694. {
  4695. switch(type)
  4696. {
  4697. case TypeIds_Object:
  4698. case TypeIds_Function:
  4699. case TypeIds_Array:
  4700. case TypeIds_NativeIntArray:
  4701. #if ENABLE_COPYONACCESS_ARRAY
  4702. case TypeIds_CopyOnAccessNativeIntArray:
  4703. #endif
  4704. case TypeIds_NativeFloatArray:
  4705. case TypeIds_ES5Array:
  4706. case TypeIds_Date:
  4707. case TypeIds_WinRTDate:
  4708. case TypeIds_RegEx:
  4709. case TypeIds_Error:
  4710. case TypeIds_BooleanObject:
  4711. case TypeIds_NumberObject:
  4712. case TypeIds_StringObject:
  4713. case TypeIds_Symbol:
  4714. case TypeIds_SymbolObject:
  4715. //case TypeIds_GlobalObject:
  4716. //case TypeIds_ModuleRoot:
  4717. //case TypeIds_HostObject:
  4718. case TypeIds_Arguments:
  4719. case TypeIds_ActivationObject:
  4720. case TypeIds_Map:
  4721. case TypeIds_Set:
  4722. case TypeIds_WeakMap:
  4723. case TypeIds_WeakSet:
  4724. case TypeIds_ArrayIterator:
  4725. case TypeIds_MapIterator:
  4726. case TypeIds_SetIterator:
  4727. case TypeIds_StringIterator:
  4728. case TypeIds_Generator:
  4729. case TypeIds_Promise:
  4730. case TypeIds_Proxy:
  4731. return true;
  4732. default:
  4733. return false;
  4734. }
  4735. }
  4736. BOOL JavascriptOperators::IsJsNativeObject(Var instance)
  4737. {
  4738. return IsJsNativeType(GetTypeId(instance));
  4739. }
  4740. BOOL JavascriptOperators::IsJsNativeObject(_In_ RecyclableObject* instance)
  4741. {
  4742. return IsJsNativeType(GetTypeId(instance));
  4743. }
  4744. bool JavascriptOperators::CanShortcutOnUnknownPropertyName(RecyclableObject *instance)
  4745. {
  4746. if (!CanShortcutInstanceOnUnknownPropertyName(instance))
  4747. {
  4748. return false;
  4749. }
  4750. return CanShortcutPrototypeChainOnUnknownPropertyName(instance->GetPrototype());
  4751. }
  4752. bool JavascriptOperators::CanShortcutInstanceOnUnknownPropertyName(RecyclableObject *instance)
  4753. {
  4754. if (PHASE_OFF1(Js::OptUnknownElementNamePhase))
  4755. {
  4756. return false;
  4757. }
  4758. TypeId typeId = instance->GetTypeId();
  4759. if (typeId == TypeIds_Proxy || typeId == TypeIds_HostDispatch)
  4760. {
  4761. return false;
  4762. }
  4763. if (DynamicType::Is(typeId) &&
  4764. static_cast<DynamicObject*>(instance)->GetTypeHandler()->IsStringTypeHandler())
  4765. {
  4766. return false;
  4767. }
  4768. if (instance->IsExternal())
  4769. {
  4770. return false;
  4771. }
  4772. if (!(instance->HasDeferredTypeHandler()))
  4773. {
  4774. JavascriptFunction * function = JavascriptOperators::TryFromVar<JavascriptFunction>(instance);
  4775. return function && function->IsExternalFunction();
  4776. }
  4777. return false;
  4778. }
  4779. bool JavascriptOperators::CanShortcutPrototypeChainOnUnknownPropertyName(RecyclableObject *prototype)
  4780. {
  4781. Assert(prototype);
  4782. for (; !JavascriptOperators::IsNull(prototype); prototype = prototype->GetPrototype())
  4783. {
  4784. if (!CanShortcutInstanceOnUnknownPropertyName(prototype))
  4785. {
  4786. return false;
  4787. }
  4788. }
  4789. return true;
  4790. }
  4791. RecyclableObject* JavascriptOperators::GetPrototype(RecyclableObject* instance)
  4792. {
  4793. if (JavascriptOperators::GetTypeId(instance) == TypeIds_Null)
  4794. {
  4795. return instance;
  4796. }
  4797. return instance->GetPrototype();
  4798. }
  4799. RecyclableObject* JavascriptOperators::OP_GetPrototype(Var instance, ScriptContext* scriptContext)
  4800. {
  4801. if (TaggedNumber::Is(instance))
  4802. {
  4803. return scriptContext->GetLibrary()->GetNumberPrototype();
  4804. }
  4805. else
  4806. {
  4807. RecyclableObject* object = RecyclableObject::FromVar(instance);
  4808. if (JavascriptOperators::IsNull(object))
  4809. {
  4810. return object;
  4811. }
  4812. return JavascriptOperators::GetPrototype(object);
  4813. }
  4814. }
  4815. BOOL JavascriptOperators::OP_BrFncEqApply(Var instance, ScriptContext *scriptContext)
  4816. {
  4817. JIT_HELPER_NOT_REENTRANT_HEADER(Op_OP_BrFncEqApply, reentrancylock, scriptContext->GetThreadContext());
  4818. // JavascriptFunction && !HostDispatch
  4819. if (JavascriptOperators::GetTypeId(instance) == TypeIds_Function)
  4820. {
  4821. FunctionProxy *bod= ((JavascriptFunction*)instance)->GetFunctionProxy();
  4822. if (bod != nullptr)
  4823. {
  4824. return bod->GetDirectEntryPoint(bod->GetDefaultEntryPointInfo()) == &Js::JavascriptFunction::EntryApply;
  4825. }
  4826. else
  4827. {
  4828. FunctionInfo* info = ((JavascriptFunction *)instance)->GetFunctionInfo();
  4829. if (info != nullptr)
  4830. {
  4831. return &Js::JavascriptFunction::EntryApply == info->GetOriginalEntryPoint();
  4832. }
  4833. else
  4834. {
  4835. return false;
  4836. }
  4837. }
  4838. }
  4839. return false;
  4840. JIT_HELPER_END(Op_OP_BrFncEqApply);
  4841. }
  4842. BOOL JavascriptOperators::OP_BrFncNeqApply(Var instance, ScriptContext *scriptContext)
  4843. {
  4844. JIT_HELPER_NOT_REENTRANT_HEADER(Op_OP_BrFncNeqApply, reentrancylock, scriptContext->GetThreadContext());
  4845. // JavascriptFunction and !HostDispatch
  4846. if (JavascriptOperators::GetTypeId(instance) == TypeIds_Function)
  4847. {
  4848. FunctionProxy *bod = ((JavascriptFunction *)instance)->GetFunctionProxy();
  4849. if (bod != nullptr)
  4850. {
  4851. return bod->GetDirectEntryPoint(bod->GetDefaultEntryPointInfo()) != &Js::JavascriptFunction::EntryApply;
  4852. }
  4853. else
  4854. {
  4855. FunctionInfo* info = ((JavascriptFunction *)instance)->GetFunctionInfo();
  4856. if (info != nullptr)
  4857. {
  4858. return &Js::JavascriptFunction::EntryApply != info->GetOriginalEntryPoint();
  4859. }
  4860. else
  4861. {
  4862. return true;
  4863. }
  4864. }
  4865. }
  4866. return true;
  4867. JIT_HELPER_END(Op_OP_BrFncNeqApply);
  4868. }
  4869. BOOL JavascriptOperators::OP_BrHasSideEffects(int se, ScriptContext* scriptContext)
  4870. {
  4871. return (scriptContext->optimizationOverrides.GetSideEffects() & se) != SideEffects_None;
  4872. }
  4873. BOOL JavascriptOperators::OP_BrNotHasSideEffects(int se, ScriptContext* scriptContext)
  4874. {
  4875. return (scriptContext->optimizationOverrides.GetSideEffects() & se) == SideEffects_None;
  4876. }
  4877. // returns NULL if there is no more elements to enumerate.
  4878. Var JavascriptOperators::OP_BrOnEmpty(ForInObjectEnumerator * aEnumerator)
  4879. {
  4880. JIT_HELPER_REENTRANT_HEADER(Op_OP_BrOnEmpty);
  4881. PropertyId id;
  4882. return aEnumerator->MoveAndGetNext(id);
  4883. JIT_HELPER_END(Op_OP_BrOnEmpty);
  4884. }
  4885. void JavascriptOperators::OP_InitForInEnumerator(Var enumerable, ForInObjectEnumerator * enumerator, ScriptContext* scriptContext, EnumeratorCache * forInCache)
  4886. {
  4887. JIT_HELPER_REENTRANT_HEADER(Op_OP_InitForInEnumerator);
  4888. RecyclableObject* enumerableObject;
  4889. #if ENABLE_COPYONACCESS_ARRAY
  4890. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(enumerable);
  4891. #endif
  4892. if (!GetPropertyObject(enumerable, scriptContext, &enumerableObject))
  4893. {
  4894. enumerableObject = nullptr;
  4895. }
  4896. enumerator->Initialize(enumerableObject, scriptContext, false, forInCache);
  4897. JIT_HELPER_END(Op_OP_InitForInEnumerator);
  4898. }
  4899. Js::Var JavascriptOperators::OP_CmEq_A(Var a, Var b, ScriptContext* scriptContext)
  4900. {
  4901. JIT_HELPER_REENTRANT_HEADER(OP_CmEq_A);
  4902. return JavascriptBoolean::ToVar(JavascriptOperators::Equal(a, b, scriptContext), scriptContext);
  4903. JIT_HELPER_END(OP_CmEq_A);
  4904. }
  4905. Var JavascriptOperators::OP_CmNeq_A(Var a, Var b, ScriptContext* scriptContext)
  4906. {
  4907. JIT_HELPER_REENTRANT_HEADER(OP_CmNeq_A);
  4908. return JavascriptBoolean::ToVar(JavascriptOperators::NotEqual(a,b,scriptContext), scriptContext);
  4909. JIT_HELPER_END(OP_CmNeq_A);
  4910. }
  4911. Var JavascriptOperators::OP_CmSrEq_A(Var a, Var b, ScriptContext* scriptContext)
  4912. {
  4913. JIT_HELPER_REENTRANT_HEADER(OP_CmSrEq_A);
  4914. return JavascriptBoolean::ToVar(JavascriptOperators::StrictEqual(a, b, scriptContext), scriptContext);
  4915. JIT_HELPER_END(OP_CmSrEq_A);
  4916. }
  4917. Var JavascriptOperators::OP_CmSrEq_String(Var a, JavascriptString* b, ScriptContext *scriptContext)
  4918. {
  4919. JIT_HELPER_REENTRANT_HEADER(OP_CmSrEq_String);
  4920. return JavascriptBoolean::ToVar(JavascriptOperators::StrictEqualString(a, b), scriptContext);
  4921. JIT_HELPER_END(OP_CmSrEq_String);
  4922. }
  4923. Var JavascriptOperators::OP_CmSrEq_EmptyString(Var a, ScriptContext *scriptContext)
  4924. {
  4925. JIT_HELPER_REENTRANT_HEADER(OP_CmSrEq_EmptyString);
  4926. return JavascriptBoolean::ToVar(JavascriptOperators::StrictEqualEmptyString(a), scriptContext);
  4927. JIT_HELPER_END(OP_CmSrEq_EmptyString);
  4928. }
  4929. Var JavascriptOperators::OP_CmSrNeq_A(Var a, Var b, ScriptContext* scriptContext)
  4930. {
  4931. JIT_HELPER_REENTRANT_HEADER(OP_CmSrNeq_A);
  4932. return JavascriptBoolean::ToVar(JavascriptOperators::NotStrictEqual(a, b, scriptContext), scriptContext);
  4933. JIT_HELPER_END(OP_CmSrNeq_A);
  4934. }
  4935. Var JavascriptOperators::OP_CmLt_A(Var a, Var b, ScriptContext* scriptContext)
  4936. {
  4937. JIT_HELPER_REENTRANT_HEADER(OP_CmLt_A);
  4938. return JavascriptBoolean::ToVar(JavascriptOperators::Less(a, b, scriptContext), scriptContext);
  4939. JIT_HELPER_END(OP_CmLt_A);
  4940. }
  4941. Var JavascriptOperators::OP_CmLe_A(Var a, Var b, ScriptContext* scriptContext)
  4942. {
  4943. JIT_HELPER_REENTRANT_HEADER(OP_CmLe_A);
  4944. return JavascriptBoolean::ToVar(JavascriptOperators::LessEqual(a, b, scriptContext), scriptContext);
  4945. JIT_HELPER_END(OP_CmLe_A);
  4946. }
  4947. Var JavascriptOperators::OP_CmGt_A(Var a, Var b, ScriptContext* scriptContext)
  4948. {
  4949. JIT_HELPER_REENTRANT_HEADER(OP_CmGt_A);
  4950. return JavascriptBoolean::ToVar(JavascriptOperators::Greater(a, b, scriptContext), scriptContext);
  4951. JIT_HELPER_END(OP_CmGt_A);
  4952. }
  4953. Var JavascriptOperators::OP_CmGe_A(Var a, Var b, ScriptContext* scriptContext)
  4954. {
  4955. JIT_HELPER_REENTRANT_HEADER(OP_CmGe_A);
  4956. return JavascriptBoolean::ToVar(JavascriptOperators::GreaterEqual(a, b, scriptContext), scriptContext);
  4957. JIT_HELPER_END(OP_CmGe_A);
  4958. }
  4959. DetachedStateBase* JavascriptOperators::DetachVarAndGetState(Var var)
  4960. {
  4961. switch (GetTypeId(var))
  4962. {
  4963. case TypeIds_ArrayBuffer:
  4964. return Js::ArrayBuffer::FromVar(var)->DetachAndGetState();
  4965. default:
  4966. if (!Js::RecyclableObject::FromVar(var)->IsExternal())
  4967. {
  4968. AssertMsg(false, "We should explicitly have a case statement for each non-external object that can be detached.");
  4969. }
  4970. return nullptr;
  4971. }
  4972. }
  4973. bool JavascriptOperators::IsObjectDetached(Var var)
  4974. {
  4975. switch (GetTypeId(var))
  4976. {
  4977. case TypeIds_ArrayBuffer:
  4978. return Js::ArrayBuffer::FromVar(var)->IsDetached();
  4979. default:
  4980. return false;
  4981. }
  4982. }
  4983. Var JavascriptOperators::NewVarFromDetachedState(DetachedStateBase* state, JavascriptLibrary *library)
  4984. {
  4985. AssertOrFailFastMsg(state->GetTypeId() == TypeIds_ArrayBuffer, "We should only re-activate detached ArrayBuffer");
  4986. return Js::ArrayBuffer::NewFromDetachedState(state, library);
  4987. }
  4988. DynamicType *
  4989. JavascriptOperators::EnsureObjectLiteralType(ScriptContext* scriptContext, const Js::PropertyIdArray *propIds, Field(DynamicType*)* literalType)
  4990. {
  4991. JIT_HELPER_NOT_REENTRANT_HEADER(EnsureObjectLiteralType, reentrancylock, scriptContext->GetThreadContext());
  4992. DynamicType * newType = *literalType;
  4993. if (newType != nullptr)
  4994. {
  4995. if (!newType->GetIsShared())
  4996. {
  4997. newType->ShareType();
  4998. }
  4999. }
  5000. else
  5001. {
  5002. DynamicType* objectType =
  5003. FunctionBody::DoObjectHeaderInliningForObjectLiteral(propIds)
  5004. ? scriptContext->GetLibrary()->GetObjectHeaderInlinedLiteralType((uint16)propIds->count)
  5005. : scriptContext->GetLibrary()->GetObjectLiteralType(
  5006. static_cast<PropertyIndex>(
  5007. min(propIds->count, static_cast<uint32>(MaxPreInitializedObjectTypeInlineSlotCount))));
  5008. newType = PathTypeHandlerBase::CreateTypeForNewScObject(scriptContext, objectType, propIds, false);
  5009. *literalType = newType;
  5010. }
  5011. Assert(scriptContext);
  5012. Assert(GetLiteralInlineSlotCapacity(propIds) == newType->GetTypeHandler()->GetInlineSlotCapacity());
  5013. Assert(newType->GetTypeHandler()->GetSlotCapacity() >= 0);
  5014. Assert(GetLiteralSlotCapacity(propIds) == (uint)newType->GetTypeHandler()->GetSlotCapacity());
  5015. return newType;
  5016. JIT_HELPER_END(EnsureObjectLiteralType);
  5017. }
  5018. Var JavascriptOperators::NewScObjectLiteral(ScriptContext* scriptContext, const Js::PropertyIdArray *propIds, Field(DynamicType*)* literalType)
  5019. {
  5020. Assert(propIds->count != 0);
  5021. Assert(!propIds->hadDuplicates); // duplicates are removed by parser
  5022. #ifdef PROFILE_OBJECT_LITERALS
  5023. // Empty objects not counted in the object literal counts
  5024. scriptContext->objectLiteralInstanceCount++;
  5025. if (propIds->count > scriptContext->objectLiteralMaxLength)
  5026. {
  5027. scriptContext->objectLiteralMaxLength = propIds->count;
  5028. }
  5029. #endif
  5030. DynamicType* newType = EnsureObjectLiteralType(scriptContext, propIds, literalType);
  5031. DynamicObject* instance = DynamicObject::New(scriptContext->GetRecycler(), newType);
  5032. if (!newType->GetIsShared())
  5033. {
  5034. #if ENABLE_FIXED_FIELDS
  5035. newType->GetTypeHandler()->SetSingletonInstanceIfNeeded(instance);
  5036. #endif
  5037. }
  5038. #ifdef PROFILE_OBJECT_LITERALS
  5039. else
  5040. {
  5041. scriptContext->objectLiteralCacheCount++;
  5042. }
  5043. #endif
  5044. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(instance));
  5045. // can't auto-proxy here as object literal is not exactly "new" object and cannot be intercepted as proxy.
  5046. return instance;
  5047. }
  5048. uint JavascriptOperators::GetLiteralSlotCapacity(Js::PropertyIdArray const * propIds)
  5049. {
  5050. const uint inlineSlotCapacity = GetLiteralInlineSlotCapacity(propIds);
  5051. return DynamicTypeHandler::RoundUpSlotCapacity(propIds->count, static_cast<PropertyIndex>(inlineSlotCapacity));
  5052. }
  5053. uint JavascriptOperators::GetLiteralInlineSlotCapacity(
  5054. Js::PropertyIdArray const * propIds)
  5055. {
  5056. if (propIds->hadDuplicates)
  5057. {
  5058. return 0;
  5059. }
  5060. return
  5061. FunctionBody::DoObjectHeaderInliningForObjectLiteral(propIds)
  5062. ? DynamicTypeHandler::RoundUpObjectHeaderInlinedInlineSlotCapacity(static_cast<PropertyIndex>(propIds->count))
  5063. : DynamicTypeHandler::RoundUpInlineSlotCapacity(
  5064. static_cast<PropertyIndex>(
  5065. min(propIds->count, static_cast<uint32>(MaxPreInitializedObjectTypeInlineSlotCount))));
  5066. }
  5067. Var JavascriptOperators::OP_InitCachedScope(Var varFunc, const Js::PropertyIdArray *propIds, Field(DynamicType*)* literalType, bool formalsAreLetDecls, ScriptContext *scriptContext)
  5068. {
  5069. JIT_HELPER_NOT_REENTRANT_HEADER(OP_InitCachedScope, reentrancylock, scriptContext->GetThreadContext());
  5070. bool isGAFunction = JavascriptFunction::Is(varFunc);
  5071. Assert(isGAFunction);
  5072. if (isGAFunction)
  5073. {
  5074. JavascriptFunction *function = JavascriptFunction::FromVar(varFunc);
  5075. isGAFunction = JavascriptGeneratorFunction::Test(function) || JavascriptAsyncFunction::Test(function);
  5076. }
  5077. ScriptFunction *func = isGAFunction ?
  5078. JavascriptGeneratorFunction::FromVar(varFunc)->GetGeneratorVirtualScriptFunction() :
  5079. ScriptFunction::FromVar(varFunc);
  5080. #ifdef PROFILE_OBJECT_LITERALS
  5081. // Empty objects not counted in the object literal counts
  5082. scriptContext->objectLiteralInstanceCount++;
  5083. if (propIds->count > scriptContext->objectLiteralMaxLength)
  5084. {
  5085. scriptContext->objectLiteralMaxLength = propIds->count;
  5086. }
  5087. #endif
  5088. PropertyId cachedFuncCount = ActivationObjectEx::GetCachedFuncCount(propIds);
  5089. PropertyId firstFuncSlot = ActivationObjectEx::GetFirstFuncSlot(propIds);
  5090. PropertyId firstVarSlot = ActivationObjectEx::GetFirstVarSlot(propIds);
  5091. PropertyId lastFuncSlot = Constants::NoProperty;
  5092. if (firstFuncSlot != Constants::NoProperty)
  5093. {
  5094. if (firstVarSlot == Constants::NoProperty || firstVarSlot < firstFuncSlot)
  5095. {
  5096. lastFuncSlot = propIds->count - 1;
  5097. }
  5098. else
  5099. {
  5100. lastFuncSlot = firstVarSlot - 1;
  5101. }
  5102. }
  5103. DynamicType *type = *literalType;
  5104. if (type != nullptr)
  5105. {
  5106. #ifdef PROFILE_OBJECT_LITERALS
  5107. scriptContext->objectLiteralCacheCount++;
  5108. #endif
  5109. }
  5110. else
  5111. {
  5112. type = scriptContext->GetLibrary()->GetActivationObjectType();
  5113. if (formalsAreLetDecls)
  5114. {
  5115. uint formalsSlotLimit = (firstFuncSlot != Constants::NoProperty) ? (uint)firstFuncSlot :
  5116. (firstVarSlot != Constants::NoProperty) ? (uint)firstVarSlot :
  5117. propIds->count;
  5118. type = PathTypeHandlerBase::CreateNewScopeObject(scriptContext, type, propIds, PropertyLet, formalsSlotLimit);
  5119. }
  5120. else
  5121. {
  5122. type = PathTypeHandlerBase::CreateNewScopeObject(scriptContext, type, propIds);
  5123. }
  5124. *literalType = type;
  5125. }
  5126. Var undef = scriptContext->GetLibrary()->GetUndefined();
  5127. ActivationObjectEx *scopeObjEx = func->GetCachedScope();
  5128. if (scopeObjEx && scopeObjEx->IsCommitted())
  5129. {
  5130. scopeObjEx->ReplaceType(type);
  5131. scopeObjEx->SetCommit(false);
  5132. #if DBG
  5133. for (uint i = firstVarSlot; i < propIds->count; i++)
  5134. {
  5135. AssertMsg(scopeObjEx->GetSlot(i) == undef, "Var attached to cached scope");
  5136. }
  5137. #endif
  5138. }
  5139. else
  5140. {
  5141. ActivationObjectEx *tmp = RecyclerNewPlus(scriptContext->GetRecycler(), (cachedFuncCount == 0 ? 0 : cachedFuncCount - 1) * sizeof(FuncCacheEntry), ActivationObjectEx, type, func, cachedFuncCount, firstFuncSlot, lastFuncSlot);
  5142. if (!scopeObjEx)
  5143. {
  5144. func->SetCachedScope(tmp);
  5145. }
  5146. scopeObjEx = tmp;
  5147. for (uint i = firstVarSlot; i < propIds->count; i++)
  5148. {
  5149. scopeObjEx->SetSlot(SetSlotArguments(propIds->elements[i], i, undef));
  5150. }
  5151. }
  5152. return scopeObjEx;
  5153. JIT_HELPER_END(OP_InitCachedScope);
  5154. }
  5155. void JavascriptOperators::OP_InvalidateCachedScope(void* varEnv, int32 envIndex)
  5156. {
  5157. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(OP_InvalidateCachedScope);
  5158. FrameDisplay *disp = (FrameDisplay*)varEnv;
  5159. Var item = disp->GetItem(envIndex);
  5160. if (item != nullptr)
  5161. {
  5162. Assert(ActivationObjectEx::Is(item));
  5163. RecyclableObject *objScope = RecyclableObject::FromVar(item);
  5164. objScope->InvalidateCachedScope();
  5165. }
  5166. JIT_HELPER_END(OP_InvalidateCachedScope);
  5167. }
  5168. void JavascriptOperators::OP_InitCachedFuncs(Var varScope, FrameDisplay *pDisplay, const FuncInfoArray *info, ScriptContext *scriptContext)
  5169. {
  5170. JIT_HELPER_NOT_REENTRANT_HEADER(OP_InitCachedFuncs, reentrancylock, scriptContext->GetThreadContext());
  5171. ActivationObjectEx *scopeObj = ActivationObjectEx::FromVar(varScope);
  5172. Assert(scopeObj->GetTypeHandler()->GetInlineSlotCapacity() == 0);
  5173. uint funcCount = info->count;
  5174. if (funcCount == 0)
  5175. {
  5176. // Degenerate case: no nested funcs at all
  5177. return;
  5178. }
  5179. if (scopeObj->HasCachedFuncs())
  5180. {
  5181. for (uint i = 0; i < funcCount; i++)
  5182. {
  5183. const FuncCacheEntry *entry = scopeObj->GetFuncCacheEntry(i);
  5184. ScriptFunction *func = entry->func;
  5185. FunctionProxy * proxy = func->GetFunctionProxy();
  5186. // Reset the function's type to the default type with no properties
  5187. // Use the cached type on the function proxy rather than the type in the func cache entry
  5188. // CONSIDER: Stop caching the function types in the scope object
  5189. func->ReplaceType(proxy->EnsureDeferredPrototypeType());
  5190. func->ResetConstructorCacheToDefault();
  5191. uint scopeSlot = info->elements[i].scopeSlot;
  5192. if (scopeSlot != Constants::NoProperty)
  5193. {
  5194. // CONSIDER: Store property IDs in FuncInfoArray in debug builds so we can properly assert in SetAuxSlot
  5195. scopeObj->SetAuxSlot(SetSlotArguments(Constants::NoProperty, scopeSlot, entry->func));
  5196. }
  5197. }
  5198. return;
  5199. }
  5200. // No cached functions, so create them and cache them.
  5201. JavascriptFunction *funcParent = scopeObj->GetParentFunc();
  5202. for (uint i = 0; i < funcCount; i++)
  5203. {
  5204. const FuncInfoEntry *entry = &info->elements[i];
  5205. uint nestedIndex = entry->nestedIndex;
  5206. uint scopeSlot = entry->scopeSlot;
  5207. FunctionProxy * proxy = funcParent->GetFunctionBody()->GetNestedFunctionProxy(nestedIndex);
  5208. ScriptFunction *func = scriptContext->GetLibrary()->CreateScriptFunction(proxy);
  5209. func->SetEnvironment(pDisplay);
  5210. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_FUNCTION(func, EtwTrace::GetFunctionId(proxy)));
  5211. scopeObj->SetCachedFunc(i, func);
  5212. if (scopeSlot != Constants::NoProperty)
  5213. {
  5214. // CONSIDER: Store property IDs in FuncInfoArray in debug builds so we can properly assert in SetAuxSlot
  5215. scopeObj->SetAuxSlot(SetSlotArguments(Constants::NoProperty, scopeSlot, func));
  5216. }
  5217. }
  5218. JIT_HELPER_END(OP_InitCachedFuncs);
  5219. }
  5220. Var JavascriptOperators::AddVarsToArraySegment(SparseArraySegment<Var> * segment, const Js::VarArray *vars)
  5221. {
  5222. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(ArraySegmentVars);
  5223. uint32 count = vars->count;
  5224. Assert(segment->left == 0);
  5225. Assert(count <= segment->size);
  5226. if(count > segment->length)
  5227. {
  5228. segment->length = count;
  5229. segment->CheckLengthvsSize();
  5230. }
  5231. CopyArray(segment->elements, segment->length, vars->elements, count);
  5232. return segment;
  5233. JIT_HELPER_END(ArraySegmentVars);
  5234. }
  5235. void JavascriptOperators::AddIntsToArraySegment(SparseArraySegment<int32> * segment, const Js::AuxArray<int32> *ints)
  5236. {
  5237. uint32 count = ints->count;
  5238. Assert(segment->left == 0);
  5239. Assert(count <= segment->size);
  5240. if(count > segment->length)
  5241. {
  5242. segment->length = count;
  5243. segment->CheckLengthvsSize();
  5244. }
  5245. js_memcpy_s(segment->elements, sizeof(int32) * segment->length, ints->elements, sizeof(int32) * count);
  5246. }
  5247. void JavascriptOperators::AddFloatsToArraySegment(SparseArraySegment<double> * segment, const Js::AuxArray<double> *doubles)
  5248. {
  5249. uint32 count = doubles->count;
  5250. Assert(segment->left == 0);
  5251. Assert(count <= segment->size);
  5252. if(count > segment->length)
  5253. {
  5254. segment->length = count;
  5255. segment->CheckLengthvsSize();
  5256. }
  5257. js_memcpy_s(segment->elements, sizeof(double) * segment->length, doubles->elements, sizeof(double) * count);
  5258. }
  5259. RecyclableObject * JavascriptOperators::GetPrototypeObject(RecyclableObject * constructorFunction, ScriptContext * scriptContext)
  5260. {
  5261. Var prototypeProperty = JavascriptOperators::GetProperty(constructorFunction, PropertyIds::prototype, scriptContext);
  5262. RecyclableObject* prototypeObject;
  5263. PrototypeObject(prototypeProperty, constructorFunction, scriptContext, &prototypeObject);
  5264. return prototypeObject;
  5265. }
  5266. RecyclableObject * JavascriptOperators::GetPrototypeObjectForConstructorCache(RecyclableObject * constructor, ScriptContext* requestContext, bool& canBeCached)
  5267. {
  5268. PropertyValueInfo info;
  5269. Var prototypeValue;
  5270. RecyclableObject* prototypeObject;
  5271. canBeCached = false;
  5272. // Do a local property lookup. Since a function's prototype property is a non-configurable data property, we don't need to worry
  5273. // about the prototype being an accessor property, whose getter returns different values every time it's called.
  5274. if (constructor->GetProperty(constructor, PropertyIds::prototype, &prototypeValue, &info, requestContext))
  5275. {
  5276. if (!JavascriptOperators::PrototypeObject(prototypeValue, constructor, requestContext, &prototypeObject))
  5277. {
  5278. // The value returned by the property lookup is not a valid prototype object, default to object prototype.
  5279. Assert(prototypeObject == constructor->GetLibrary()->GetObjectPrototype());
  5280. }
  5281. // For these scenarios, we do not want to populate the cache.
  5282. if (constructor->GetScriptContext() != requestContext || info.GetInstance() != constructor)
  5283. {
  5284. return prototypeObject;
  5285. }
  5286. }
  5287. else
  5288. {
  5289. // It's ok to cache Object.prototype, because Object.prototype cannot be overwritten.
  5290. prototypeObject = constructor->GetLibrary()->GetObjectPrototype();
  5291. }
  5292. canBeCached = true;
  5293. return prototypeObject;
  5294. }
  5295. bool JavascriptOperators::PrototypeObject(Var prototypeProperty, RecyclableObject * constructorFunction, ScriptContext * scriptContext, RecyclableObject** prototypeObject)
  5296. {
  5297. TypeId prototypeType = JavascriptOperators::GetTypeId(prototypeProperty);
  5298. if (JavascriptOperators::IsObjectType(prototypeType))
  5299. {
  5300. *prototypeObject = RecyclableObject::FromVar(prototypeProperty);
  5301. return true;
  5302. }
  5303. *prototypeObject = constructorFunction->GetLibrary()->GetObjectPrototype();
  5304. return false;
  5305. }
  5306. FunctionInfo* JavascriptOperators::GetConstructorFunctionInfo(Var instance, ScriptContext * scriptContext)
  5307. {
  5308. TypeId typeId = JavascriptOperators::GetTypeId(instance);
  5309. if (typeId == TypeIds_Function)
  5310. {
  5311. JavascriptFunction * function = JavascriptFunction::UnsafeFromVar(instance);
  5312. return function->GetFunctionInfo();
  5313. }
  5314. if (typeId != TypeIds_HostDispatch && typeId != TypeIds_Proxy)
  5315. {
  5316. if (typeId == TypeIds_Null)
  5317. {
  5318. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject);
  5319. }
  5320. JavascriptError::ThrowTypeError(scriptContext, VBSERR_ActionNotSupported);
  5321. }
  5322. return nullptr;
  5323. }
  5324. Var JavascriptOperators::NewJavascriptObjectNoArg(ScriptContext* requestContext)
  5325. {
  5326. JIT_HELPER_NOT_REENTRANT_HEADER(NewJavascriptObjectNoArg, reentrancylock, requestContext->GetThreadContext());
  5327. DynamicObject * newObject = requestContext->GetLibrary()->CreateObject(true);
  5328. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(newObject));
  5329. #if ENABLE_DEBUG_CONFIG_OPTIONS
  5330. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  5331. {
  5332. newObject = DynamicObject::FromVar(JavascriptProxy::AutoProxyWrapper(newObject));
  5333. }
  5334. #endif
  5335. return newObject;
  5336. JIT_HELPER_END(NewJavascriptObjectNoArg);
  5337. }
  5338. Var JavascriptOperators::NewJavascriptArrayNoArg(ScriptContext* requestContext)
  5339. {
  5340. JIT_HELPER_NOT_REENTRANT_HEADER(NewJavascriptArrayNoArg, reentrancylock, requestContext->GetThreadContext());
  5341. JavascriptArray * newArray = requestContext->GetLibrary()->CreateArray();
  5342. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(newArray));
  5343. #if ENABLE_DEBUG_CONFIG_OPTIONS
  5344. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  5345. {
  5346. newArray = static_cast<JavascriptArray*>(JavascriptProxy::AutoProxyWrapper(newArray));
  5347. }
  5348. #endif
  5349. return newArray;
  5350. JIT_HELPER_END(NewJavascriptArrayNoArg);
  5351. }
  5352. Var JavascriptOperators::NewScObjectNoArgNoCtorFull(Var instance, ScriptContext* requestContext)
  5353. {
  5354. // This helper can be reentrant because although we don't call the Constructor, we might have to parse it if bytecode is missing
  5355. // In which case, we would leave script. When we leave script we DisposeObjects which can dispose of Edge objects that could
  5356. // have a javascript onDispose handler and call that handler.
  5357. JIT_HELPER_REENTRANT_HEADER(NewScObjectNoArgNoCtorFull);
  5358. return NewScObjectNoArgNoCtorCommon(instance, requestContext, true);
  5359. JIT_HELPER_END(NewScObjectNoArgNoCtorFull);
  5360. }
  5361. Var JavascriptOperators::NewScObjectNoArgNoCtor(Var instance, ScriptContext* requestContext)
  5362. {
  5363. // This helper can be reentrant because although we don't call the Constructor, we might have to parse it if bytecode is missing
  5364. // In which case, we would leave script. When we leave script we DisposeObjects which can dispose of Edge objects that could
  5365. // have a javascript onDispose handler and call that handler.
  5366. JIT_HELPER_REENTRANT_HEADER(NewScObjectNoArgNoCtor);
  5367. return NewScObjectNoArgNoCtorCommon(instance, requestContext, false);
  5368. JIT_HELPER_END(NewScObjectNoArgNoCtor);
  5369. }
  5370. Var JavascriptOperators::NewScObjectNoArgNoCtorCommon(Var instance, ScriptContext* requestContext, bool isBaseClassConstructorNewScObject)
  5371. {
  5372. RecyclableObject * object = RecyclableObject::FromVar(instance);
  5373. FunctionInfo* functionInfo = JavascriptOperators::GetConstructorFunctionInfo(instance, requestContext);
  5374. Assert(functionInfo != &JavascriptObject::EntryInfo::NewInstance); // built-ins are not inlined
  5375. Assert(functionInfo != &JavascriptArray::EntryInfo::NewInstance); // built-ins are not inlined
  5376. return functionInfo != nullptr ?
  5377. JavascriptOperators::NewScObjectCommon(object, functionInfo, requestContext, isBaseClassConstructorNewScObject) :
  5378. JavascriptOperators::NewScObjectHostDispatchOrProxy(object, requestContext);
  5379. }
  5380. Var JavascriptOperators::NewScObjectNoArg(Var instance, ScriptContext * requestContext)
  5381. {
  5382. JIT_HELPER_REENTRANT_HEADER(NewScObjectNoArg);
  5383. JavascriptProxy * proxy = JavascriptOperators::TryFromVar<JavascriptProxy>(instance);
  5384. if (proxy)
  5385. {
  5386. Arguments args(CallInfo(CallFlags_New, 1), &instance);
  5387. return requestContext->GetThreadContext()->ExecuteImplicitCall(proxy, Js::ImplicitCall_Accessor, [=]()->Js::Var
  5388. {
  5389. return proxy->ConstructorTrap(args, requestContext, 0);
  5390. });
  5391. }
  5392. FunctionInfo* functionInfo = JavascriptOperators::GetConstructorFunctionInfo(instance, requestContext);
  5393. RecyclableObject * object = RecyclableObject::FromVar(instance);
  5394. if (functionInfo == &JavascriptObject::EntryInfo::NewInstance)
  5395. {
  5396. // Fast path for new Object()
  5397. Assert((functionInfo->GetAttributes() & FunctionInfo::ErrorOnNew) == 0);
  5398. JavascriptLibrary* library = object->GetLibrary();
  5399. DynamicObject * newObject = library->CreateObject(true);
  5400. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(newObject));
  5401. #if ENABLE_DEBUG_CONFIG_OPTIONS
  5402. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  5403. {
  5404. newObject = DynamicObject::FromVar(JavascriptProxy::AutoProxyWrapper(newObject));
  5405. }
  5406. #endif
  5407. #if DBG
  5408. DynamicType* newObjectType = newObject->GetDynamicType();
  5409. Assert(newObjectType->GetIsShared());
  5410. JavascriptFunction* constructor = JavascriptFunction::FromVar(instance);
  5411. Assert(!constructor->GetConstructorCache()->NeedsUpdateAfterCtor());
  5412. #endif
  5413. ScriptContext * scriptContext = library->GetScriptContext();
  5414. if (scriptContext != requestContext)
  5415. {
  5416. CrossSite::MarshalDynamicObjectAndPrototype(requestContext, newObject);
  5417. }
  5418. return newObject;
  5419. }
  5420. else if (functionInfo == &JavascriptArray::EntryInfo::NewInstance)
  5421. {
  5422. Assert((functionInfo->GetAttributes() & FunctionInfo::ErrorOnNew) == 0);
  5423. JavascriptLibrary* library = object->GetLibrary();
  5424. JavascriptArray * newArray = library->CreateArray();
  5425. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(newArray));
  5426. #if ENABLE_DEBUG_CONFIG_OPTIONS
  5427. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  5428. {
  5429. newArray = static_cast<JavascriptArray*>(JavascriptProxy::AutoProxyWrapper(newArray));
  5430. }
  5431. #endif
  5432. #if DBG
  5433. DynamicType* newArrayType = newArray->GetDynamicType();
  5434. Assert(newArrayType->GetIsShared());
  5435. JavascriptFunction* constructor = JavascriptFunction::FromVar(instance);
  5436. Assert(!constructor->GetConstructorCache()->NeedsUpdateAfterCtor());
  5437. #endif
  5438. ScriptContext * scriptContext = library->GetScriptContext();
  5439. if (scriptContext != requestContext)
  5440. {
  5441. CrossSite::MarshalDynamicObjectAndPrototype(requestContext, newArray);
  5442. }
  5443. return newArray;
  5444. }
  5445. Var newObject = functionInfo != nullptr ?
  5446. JavascriptOperators::NewScObjectCommon(object, functionInfo, requestContext) :
  5447. JavascriptOperators::NewScObjectHostDispatchOrProxy(object, requestContext);
  5448. ThreadContext * threadContext = object->GetScriptContext()->GetThreadContext();
  5449. Var returnVar = threadContext->ExecuteImplicitCall(object, Js::ImplicitCall_Accessor, [=]()->Js::Var
  5450. {
  5451. return CALL_FUNCTION(threadContext, object, CallInfo(CallFlags_New, 1), newObject);
  5452. });
  5453. if (JavascriptOperators::IsObject(returnVar))
  5454. {
  5455. newObject = returnVar;
  5456. }
  5457. ConstructorCache * constructorCache = nullptr;
  5458. JavascriptFunction *function = JavascriptOperators::TryFromVar<JavascriptFunction>(instance);
  5459. if (function)
  5460. {
  5461. constructorCache = function->GetConstructorCache();
  5462. }
  5463. if (constructorCache != nullptr && constructorCache->NeedsUpdateAfterCtor())
  5464. {
  5465. JavascriptOperators::UpdateNewScObjectCache(object, newObject, requestContext);
  5466. }
  5467. #if ENABLE_DEBUG_CONFIG_OPTIONS
  5468. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  5469. {
  5470. DynamicObject* newDynamicObject = DynamicObject::FromVar(JavascriptProxy::AutoProxyWrapper(newObject));
  5471. // this might come from a different scriptcontext.
  5472. newObject = CrossSite::MarshalVar(requestContext, newDynamicObject, newDynamicObject->GetScriptContext());
  5473. }
  5474. #endif
  5475. return newObject;
  5476. JIT_HELPER_END(NewScObjectNoArg);
  5477. }
  5478. Var JavascriptOperators::NewScObjectNoCtorFull(Var instance, ScriptContext* requestContext)
  5479. {
  5480. // This helper can be reentrant because although we don't call the Constructor, we might have to parse it if bytecode is missing
  5481. // In which case, we would leave script. When we leave script we DisposeObjects which can dispose of Edge objects that could
  5482. // have a javascript onDispose handler and call that handler.
  5483. JIT_HELPER_REENTRANT_HEADER(NewScObjectNoCtorFull);
  5484. return NewScObjectNoCtorCommon(instance, requestContext, true);
  5485. JIT_HELPER_END(NewScObjectNoCtorFull);
  5486. }
  5487. Var JavascriptOperators::NewScObjectNoCtor(Var instance, ScriptContext * requestContext)
  5488. {
  5489. // This helper can be reentrant because although we don't call the Constructor, we might have to parse it if bytecode is missing
  5490. // In which case, we would leave script. When we leave script we DisposeObjects which can dispose of Edge objects that could
  5491. // have a javascript onDispose handler and call that handler.
  5492. JIT_HELPER_REENTRANT_HEADER(NewScObjectNoCtor);
  5493. // We can still call into NewScObjectNoCtor variations in JIT code for performance; however for proxy we don't
  5494. // really need the new object as the trap will handle the "this" pointer separately. pass back nullptr to ensure
  5495. // failure in invalid case.
  5496. return (JavascriptProxy::Is(instance)) ? nullptr : NewScObjectNoCtorCommon(instance, requestContext, false);
  5497. JIT_HELPER_END(NewScObjectNoCtor);
  5498. }
  5499. Var JavascriptOperators::NewScObjectNoCtorCommon(Var instance, ScriptContext* requestContext, bool isBaseClassConstructorNewScObject)
  5500. {
  5501. FunctionInfo* functionInfo = JavascriptOperators::GetConstructorFunctionInfo(instance, requestContext);
  5502. if (functionInfo)
  5503. {
  5504. return JavascriptOperators::NewScObjectCommon(RecyclableObject::UnsafeFromVar(instance), functionInfo, requestContext, isBaseClassConstructorNewScObject);
  5505. }
  5506. else
  5507. {
  5508. return JavascriptOperators::NewScObjectHostDispatchOrProxy(RecyclableObject::FromVar(instance), requestContext);
  5509. }
  5510. }
  5511. Var JavascriptOperators::NewScObjectHostDispatchOrProxy(RecyclableObject * function, ScriptContext * requestContext)
  5512. {
  5513. ScriptContext* functionScriptContext = function->GetScriptContext();
  5514. RecyclableObject * prototype = JavascriptOperators::GetPrototypeObject(function, functionScriptContext);
  5515. prototype = RecyclableObject::FromVar(CrossSite::MarshalVar(requestContext, prototype, functionScriptContext));
  5516. Var object = requestContext->GetLibrary()->CreateObject(prototype);
  5517. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(object));
  5518. #if ENABLE_DEBUG_CONFIG_OPTIONS
  5519. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  5520. {
  5521. object = DynamicObject::FromVar(JavascriptProxy::AutoProxyWrapper(object));
  5522. }
  5523. #endif
  5524. return object;
  5525. }
  5526. Var JavascriptOperators::NewScObjectCommon(RecyclableObject * function, FunctionInfo* functionInfo, ScriptContext * requestContext, bool isBaseClassConstructorNewScObject)
  5527. {
  5528. // CONSIDER: Allow for the cache to be repopulated if the type got collected, and a new one got populated with
  5529. // the same number of inlined slots. This requires that the JIT-ed code actually load the type from the cache
  5530. // (instead of hard-coding it), but it can (and must) keep the hard-coded number of inline slots.
  5531. // CONSIDER: Consider also not pinning the type in the cache. This can be done by using a registration based
  5532. // weak reference (we need to control the memory address), which we don't yet have, or by allocating the cache from
  5533. // the inline cache arena to allow it to be zeroed, but retain a recycler-allocated portion to hold on to the size of
  5534. // inlined slots.
  5535. JavascriptFunction* constructor = JavascriptFunction::UnsafeFromVar(function);
  5536. if (functionInfo->IsClassConstructor() && !isBaseClassConstructorNewScObject)
  5537. {
  5538. // If we are calling new on a class constructor, the contract is that we pass new.target as the 'this' argument.
  5539. // function is the constructor on which we called new - which is new.target.
  5540. // If we are trying to construct the object for a base class constructor as part of a super call, we should not
  5541. // store new.target in the 'this' argument.
  5542. return function;
  5543. }
  5544. ConstructorCache* constructorCache = constructor->GetConstructorCache();
  5545. AssertMsg(constructorCache->GetScriptContext() == nullptr || constructorCache->GetScriptContext() == constructor->GetScriptContext(),
  5546. "Why did we populate a constructor cache with a mismatched script context?");
  5547. Assert(constructorCache != nullptr);
  5548. DynamicType* type = constructorCache->GetGuardValueAsType();
  5549. if (type != nullptr && constructorCache->GetScriptContext() == requestContext)
  5550. {
  5551. #if DBG
  5552. bool cachedProtoCanBeCached;
  5553. Assert(type->GetPrototype() == JavascriptOperators::GetPrototypeObjectForConstructorCache(constructor, requestContext, cachedProtoCanBeCached));
  5554. Assert(cachedProtoCanBeCached);
  5555. Assert(type->GetIsShared());
  5556. #endif
  5557. #if DBG_DUMP
  5558. TraceUseConstructorCache(constructorCache, constructor, true);
  5559. #endif
  5560. Var object = DynamicObject::New(requestContext->GetRecycler(), type);
  5561. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(object));
  5562. #if ENABLE_DEBUG_CONFIG_OPTIONS
  5563. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  5564. {
  5565. object = DynamicObject::FromVar(JavascriptProxy::AutoProxyWrapper(object));
  5566. }
  5567. #endif
  5568. return object;
  5569. }
  5570. if (constructorCache->SkipDefaultNewObject())
  5571. {
  5572. Assert(!constructorCache->NeedsUpdateAfterCtor());
  5573. #if DBG_DUMP
  5574. TraceUseConstructorCache(constructorCache, constructor, true);
  5575. #endif
  5576. if (isBaseClassConstructorNewScObject)
  5577. {
  5578. return JavascriptOperators::CreateFromConstructor(function, requestContext);
  5579. }
  5580. return nullptr;
  5581. }
  5582. #if DBG_DUMP
  5583. TraceUseConstructorCache(constructorCache, constructor, false);
  5584. #endif
  5585. ScriptContext* constructorScriptContext = function->GetScriptContext();
  5586. Assert(!constructorScriptContext->GetThreadContext()->IsDisableImplicitException());
  5587. // we shouldn't try to call the constructor if it's closed already.
  5588. constructorScriptContext->VerifyAlive(TRUE, requestContext);
  5589. FunctionInfo::Attributes attributes = functionInfo->GetAttributes();
  5590. if (attributes & FunctionInfo::ErrorOnNew)
  5591. {
  5592. JavascriptError::ThrowTypeError(requestContext, JSERR_ErrorOnNew);
  5593. }
  5594. // Slow path
  5595. FunctionProxy * ctorProxy = constructor->GetFunctionProxy();
  5596. FunctionBody * functionBody = ctorProxy != nullptr ? ctorProxy->EnsureDeserialized()->Parse() : nullptr;
  5597. if (attributes & FunctionInfo::SkipDefaultNewObject)
  5598. {
  5599. // The constructor doesn't use the default new object.
  5600. #pragma prefast(suppress:6236, "DevDiv bug 830883. False positive when PHASE_OFF is #defined as '(false)'.")
  5601. if (!PHASE_OFF1(ConstructorCachePhase) && (functionBody == nullptr || !PHASE_OFF(ConstructorCachePhase, functionBody)))
  5602. {
  5603. constructorCache = constructor->EnsureValidConstructorCache();
  5604. constructorCache->PopulateForSkipDefaultNewObject(constructorScriptContext);
  5605. #if DBG_DUMP
  5606. if ((functionBody != nullptr && PHASE_TRACE(Js::ConstructorCachePhase, functionBody)) || (functionBody == nullptr && PHASE_TRACE1(Js::ConstructorCachePhase)))
  5607. {
  5608. const char16* ctorName = functionBody != nullptr ? functionBody->GetDisplayName() : _u("<unknown>");
  5609. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  5610. Output::Print(_u("CtorCache: populated cache (0x%p) for ctor %s (%s): "), constructorCache, ctorName,
  5611. functionBody ? functionBody->GetDebugNumberSet(debugStringBuffer) : _u("(null)"));
  5612. constructorCache->Dump();
  5613. Output::Print(_u("\n"));
  5614. Output::Flush();
  5615. }
  5616. #endif
  5617. }
  5618. Assert(!constructorCache->NeedsUpdateAfterCtor());
  5619. return nullptr;
  5620. }
  5621. // CONSIDER: Create some form of PatchGetProtoObjForCtorCache, which actually caches the prototype object in the constructor cache.
  5622. // Make sure that it does NOT populate the guard field. On the slow path (the only path for cross-context calls) we can do a faster lookup
  5623. // after we fail the guard check. When invalidating the cache for proto change, make sure we zap the prototype field of the cache in
  5624. // addition to the guard value.
  5625. bool prototypeCanBeCached;
  5626. RecyclableObject* prototype = JavascriptOperators::GetPrototypeObjectForConstructorCache(
  5627. function, constructorScriptContext, prototypeCanBeCached);
  5628. prototype = RecyclableObject::FromVar(CrossSite::MarshalVar(requestContext,
  5629. prototype, constructorScriptContext));
  5630. DynamicObject* newObject = requestContext->GetLibrary()->CreateObject(prototype, 8);
  5631. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(newObject));
  5632. #if ENABLE_DEBUG_CONFIG_OPTIONS
  5633. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  5634. {
  5635. newObject = DynamicObject::FromVar(JavascriptProxy::AutoProxyWrapper(newObject));
  5636. }
  5637. #endif
  5638. Assert(newObject->GetTypeHandler()->GetPropertyCount() == 0);
  5639. if (prototypeCanBeCached && functionBody != nullptr && requestContext == constructorScriptContext &&
  5640. !Js::JavascriptProxy::Is(newObject) &&
  5641. !PHASE_OFF1(ConstructorCachePhase) && !PHASE_OFF(ConstructorCachePhase, functionBody))
  5642. {
  5643. DynamicType* newObjectType = newObject->GetDynamicType();
  5644. // Initial type (without any properties) should always be shared up-front. This allows us to populate the cache right away.
  5645. Assert(newObjectType->GetIsShared());
  5646. // Populate the cache here and set the updateAfterCtor flag. This way, if the ctor is called recursively the
  5647. // recursive calls will hit the cache and use the initial type. On the unwind path, we will update the cache
  5648. // after the innermost ctor and clear the flag. After subsequent ctors we won't attempt an update anymore.
  5649. // As long as the updateAfterCtor flag is set it is safe to update the cache, because it would not have been
  5650. // hard-coded in the JIT-ed code.
  5651. constructorCache = constructor->EnsureValidConstructorCache();
  5652. constructorCache->Populate(newObjectType, constructorScriptContext, functionBody->GetHasNoExplicitReturnValue(), true);
  5653. Assert(constructorCache->IsConsistent());
  5654. #if DBG_DUMP
  5655. if ((functionBody != nullptr && PHASE_TRACE(Js::ConstructorCachePhase, functionBody)) || (functionBody == nullptr && PHASE_TRACE1(Js::ConstructorCachePhase)))
  5656. {
  5657. const char16* ctorName = functionBody != nullptr ? functionBody->GetDisplayName() : _u("<unknown>");
  5658. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  5659. Output::Print(_u("CtorCache: populated cache (0x%p) for ctor %s (%s): "), constructorCache, ctorName,
  5660. functionBody ? functionBody->GetDebugNumberSet(debugStringBuffer) : _u("(null)"));
  5661. constructorCache->Dump();
  5662. Output::Print(_u("\n"));
  5663. Output::Flush();
  5664. }
  5665. #endif
  5666. }
  5667. else
  5668. {
  5669. #if DBG_DUMP
  5670. if ((functionBody != nullptr && PHASE_TRACE(Js::ConstructorCachePhase, functionBody)) || (functionBody == nullptr && PHASE_TRACE1(Js::ConstructorCachePhase)))
  5671. {
  5672. const char16* ctorName = functionBody != nullptr ? functionBody->GetDisplayName() : _u("<unknown>");
  5673. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  5674. Output::Print(_u("CtorCache: did not populate cache (0x%p) for ctor %s (%s), because %s: prototype = 0x%p, functionBody = 0x%p, ctor context = 0x%p, request context = 0x%p"),
  5675. constructorCache, ctorName, functionBody ? functionBody->GetDebugNumberSet(debugStringBuffer) : _u("(null)"),
  5676. !prototypeCanBeCached ? _u("prototype cannot be cached") :
  5677. functionBody == nullptr ? _u("function has no body") :
  5678. requestContext != constructorScriptContext ? _u("of cross-context call") : _u("constructor cache phase is off"),
  5679. prototype, functionBody, constructorScriptContext, requestContext);
  5680. Output::Print(_u("\n"));
  5681. Output::Flush();
  5682. }
  5683. #endif
  5684. }
  5685. return newObject;
  5686. }
  5687. void JavascriptOperators::UpdateNewScObjectCache(Var function, Var instance, ScriptContext* requestContext)
  5688. {
  5689. JIT_HELPER_NOT_REENTRANT_HEADER(UpdateNewScObjectCache, reentrancylock, requestContext->GetThreadContext());
  5690. JavascriptFunction* constructor = JavascriptFunction::FromVar(function);
  5691. if(constructor->GetScriptContext() != requestContext)
  5692. {
  5693. // The cache is populated only when the constructor function's context is the same as the calling context. However,
  5694. // the cached type is not finalized yet and may not be until multiple calls to the constructor have been made (see
  5695. // flag ConstructorCallsRequiredToFinalizeCachedType). A subsequent call to the constructor may be made from a
  5696. // different context, so ignore those cross-context calls and wait for the constructor to be called from its own
  5697. // context again to finalize the cached type.
  5698. return;
  5699. }
  5700. // Review : What happens if the cache got invalidated between NewScObject and here?
  5701. // Should we allocate new? Should we mark it as polymorphic?
  5702. ConstructorCache* constructorCache = constructor->GetConstructorCache();
  5703. Assert(constructorCache->IsConsistent());
  5704. Assert(!ConstructorCache::IsDefault(constructorCache));
  5705. AssertMsg(constructorCache->GetScriptContext() == constructor->GetScriptContext(), "Why did we populate a constructor cache with a mismatched script context?");
  5706. AssertMsg(constructorCache->IsPopulated(), "Why are we updating a constructor cache that hasn't been populated?");
  5707. // The presence of the updateAfterCtor flag guarantees that this cache hasn't been used in JIT-ed fast path. Even, if the
  5708. // cache is invalidated, this flag is not changed.
  5709. AssertMsg(constructorCache->NeedsUpdateAfterCtor(), "Why are we updating a constructor cache that doesn't need to be updated?");
  5710. const bool finalizeCachedType =
  5711. constructorCache->CallCount() >= CONFIG_FLAG(ConstructorCallsRequiredToFinalizeCachedType);
  5712. if(!finalizeCachedType)
  5713. {
  5714. constructorCache->IncCallCount();
  5715. }
  5716. else
  5717. {
  5718. constructorCache->ClearUpdateAfterCtor();
  5719. }
  5720. FunctionBody* constructorBody = constructor->GetFunctionBody();
  5721. AssertMsg(constructorBody != nullptr, "Constructor function doesn't have a function body.");
  5722. Assert(RecyclableObject::Is(instance));
  5723. // The cache might have been invalidated between NewScObjectCommon and UpdateNewScObjectCache. This could occur, for example, if
  5724. // the constructor updates its own prototype property. If that happens we don't want to re-populate it here. A new cache will
  5725. // be created when the constructor is called again.
  5726. if (constructorCache->IsInvalidated())
  5727. {
  5728. #if DBG_DUMP
  5729. TraceUpdateConstructorCache(constructorCache, constructorBody, false, _u("because cache is invalidated"));
  5730. #endif
  5731. return;
  5732. }
  5733. Assert(constructorCache->GetGuardValueAsType() != nullptr);
  5734. if (DynamicType::Is(RecyclableObject::FromVar(instance)->GetTypeId()))
  5735. {
  5736. DynamicObject *object = DynamicObject::UnsafeFromVar(instance);
  5737. DynamicType* type = object->GetDynamicType();
  5738. DynamicTypeHandler* typeHandler = type->GetTypeHandler();
  5739. if (constructorBody->GetHasOnlyThisStmts())
  5740. {
  5741. if (typeHandler->IsSharable())
  5742. {
  5743. #if DBG
  5744. bool cachedProtoCanBeCached = false;
  5745. Assert(type->GetPrototype() == JavascriptOperators::GetPrototypeObjectForConstructorCache(constructor, requestContext, cachedProtoCanBeCached));
  5746. Assert(cachedProtoCanBeCached);
  5747. Assert(type->GetScriptContext() == constructorCache->GetScriptContext());
  5748. Assert(type->GetPrototype() == constructorCache->GetType()->GetPrototype());
  5749. #endif
  5750. typeHandler->SetMayBecomeShared();
  5751. // CONSIDER: Remove only this for delayed type sharing.
  5752. type->ShareType();
  5753. #if ENABLE_PROFILE_INFO
  5754. DynamicProfileInfo* profileInfo = constructorBody->HasDynamicProfileInfo() ? constructorBody->GetAnyDynamicProfileInfo() : nullptr;
  5755. if ((profileInfo != nullptr && profileInfo->GetImplicitCallFlags() <= ImplicitCall_None) ||
  5756. CheckIfPrototypeChainHasOnlyWritableDataProperties(type->GetPrototype()))
  5757. {
  5758. Assert(typeHandler->GetPropertyCount() < Js::PropertyIndexRanges<PropertyIndex>::MaxValue);
  5759. for (PropertyIndex pi = 0; pi < typeHandler->GetPropertyCount(); pi++)
  5760. {
  5761. requestContext->RegisterConstructorCache(typeHandler->GetPropertyId(requestContext, pi), constructorCache);
  5762. }
  5763. Assert(constructorBody->GetUtf8SourceInfo()->GetIsLibraryCode() || !constructor->GetScriptContext()->IsScriptContextInDebugMode());
  5764. if (constructorCache->TryUpdateAfterConstructor(type, constructor->GetScriptContext()))
  5765. {
  5766. #if DBG_DUMP
  5767. TraceUpdateConstructorCache(constructorCache, constructorBody, true, _u(""));
  5768. #endif
  5769. }
  5770. else
  5771. {
  5772. #if DBG_DUMP
  5773. TraceUpdateConstructorCache(constructorCache, constructorBody, false, _u("because number of slots > MaxCachedSlotCount"));
  5774. #endif
  5775. }
  5776. }
  5777. #if DBG_DUMP
  5778. else
  5779. {
  5780. if (profileInfo &&
  5781. ((profileInfo->GetImplicitCallFlags() & ~(Js::ImplicitCall_External | Js::ImplicitCall_Accessor)) == 0) &&
  5782. profileInfo != nullptr && CheckIfPrototypeChainHasOnlyWritableDataProperties(type->GetPrototype()) &&
  5783. Js::Configuration::Global.flags.Trace.IsEnabled(Js::HostOptPhase))
  5784. {
  5785. const char16* ctorName = constructorBody->GetDisplayName();
  5786. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  5787. Output::Print(_u("CtorCache: %s cache (0x%p) for ctor %s (#%u) did not update because external call"),
  5788. constructorCache, constructorBody, ctorName, constructorBody ? constructorBody->GetDebugNumberSet(debugStringBuffer) : _u("(null)"));
  5789. Output::Print(_u("\n"));
  5790. Output::Flush();
  5791. }
  5792. }
  5793. #endif
  5794. #endif
  5795. }
  5796. else
  5797. {
  5798. // Dynamic type created is not sharable.
  5799. // So in future don't try to check for "this assignment optimization".
  5800. constructorBody->SetHasOnlyThisStmts(false);
  5801. #if DBG_DUMP
  5802. TraceUpdateConstructorCache(constructorCache, constructorBody, false, _u("because final type is not shareable"));
  5803. #endif
  5804. }
  5805. }
  5806. else
  5807. {
  5808. #if DBG_DUMP
  5809. TraceUpdateConstructorCache(constructorCache, constructorBody, false, _u("because ctor has not only this statements"));
  5810. #endif
  5811. }
  5812. }
  5813. else
  5814. {
  5815. // Even though this constructor apparently returned something other than the default object we created,
  5816. // it still makes sense to cache the parameters of the default object, since we must create it every time, anyway.
  5817. #if DBG_DUMP
  5818. TraceUpdateConstructorCache(constructorCache, constructorBody, false, _u("because ctor return a non-object value"));
  5819. #endif
  5820. return;
  5821. }
  5822. // Whatever the constructor returned, if we're caching a type we want to be sure we shrink its inline slot capacity.
  5823. if (finalizeCachedType && constructorCache->IsEnabled())
  5824. {
  5825. DynamicType* cachedType = constructorCache->NeedsTypeUpdate() ? constructorCache->GetPendingType() : constructorCache->GetType();
  5826. DynamicTypeHandler* cachedTypeHandler = cachedType->GetTypeHandler();
  5827. // Consider: We could delay inline slot capacity shrinking until the second time this constructor is invoked. In some cases
  5828. // this might permit more properties to remain inlined if the objects grow after constructor. This would require flagging
  5829. // the cache as special (already possible) and forcing the shrinking during work item creation if we happen to JIT this
  5830. // constructor while the cache is in this special state.
  5831. if (cachedTypeHandler->GetInlineSlotCapacity())
  5832. {
  5833. #if DBG_DUMP
  5834. int inlineSlotCapacityBeforeShrink = cachedTypeHandler->GetInlineSlotCapacity();
  5835. #endif
  5836. // Note that after the cache has been updated and might have been used in the JIT-ed code, it is no longer legal to
  5837. // shrink the inline slot capacity of the type. That's because we allocate memory for a fixed number of inlined properties
  5838. // and if that number changed on the type, this update wouldn't get reflected in JIT-ed code and we would allocate objects
  5839. // of a wrong size. This could conceivably happen if the original object got collected, and with it some of the successor
  5840. // types also. If then another constructor has the same prototype and needs to populate its own cache, it would attempt to
  5841. // shrink inlined slots again. If all surviving type handlers have smaller inline slot capacity, we would shrink it further.
  5842. // To address this problem the type handler has a bit indicating its inline slots have been shrunk already. If that bit is
  5843. // set ShrinkSlotAndInlineSlotCapacity does nothing.
  5844. cachedTypeHandler->ShrinkSlotAndInlineSlotCapacity();
  5845. constructorCache->UpdateInlineSlotCount();
  5846. #if DBG_DUMP
  5847. Assert(inlineSlotCapacityBeforeShrink >= cachedTypeHandler->GetInlineSlotCapacity());
  5848. if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::InlineSlotsPhase))
  5849. {
  5850. if (inlineSlotCapacityBeforeShrink != cachedTypeHandler->GetInlineSlotCapacity())
  5851. {
  5852. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  5853. Output::Print(_u("Inline slot capacity shrunk: Function:%04s Before:%d After:%d\n"),
  5854. constructorBody->GetDebugNumberSet(debugStringBuffer), inlineSlotCapacityBeforeShrink, cachedTypeHandler->GetInlineSlotCapacity());
  5855. }
  5856. }
  5857. #endif
  5858. }
  5859. }
  5860. JIT_HELPER_END(UpdateNewScObjectCache);
  5861. }
  5862. void JavascriptOperators::TraceUseConstructorCache(const ConstructorCache* ctorCache, const JavascriptFunction* ctor, bool isHit)
  5863. {
  5864. #if DBG_DUMP
  5865. // We are under debug, so we can incur the extra check here.
  5866. FunctionProxy* ctorBody = ctor->GetFunctionProxy();
  5867. if (ctorBody != nullptr && !ctorBody->GetScriptContext()->IsClosed())
  5868. {
  5869. ctorBody = ctorBody->EnsureDeserialized();
  5870. }
  5871. if ((ctorBody != nullptr && PHASE_TRACE(Js::ConstructorCachePhase, ctorBody)) || (ctorBody == nullptr && PHASE_TRACE1(Js::ConstructorCachePhase)))
  5872. {
  5873. const char16* ctorName = ctorBody != nullptr ? ctorBody->GetDisplayName() : _u("<unknown>");
  5874. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  5875. Output::Print(_u("CtorCache: %s cache (0x%p) for ctor %s (%s): "), isHit ? _u("hit") : _u("missed"), ctorCache, ctorName,
  5876. ctorBody ? ctorBody->GetDebugNumberSet(debugStringBuffer) : _u("(null)"));
  5877. ctorCache->Dump();
  5878. Output::Print(_u("\n"));
  5879. Output::Flush();
  5880. }
  5881. #endif
  5882. }
  5883. void JavascriptOperators::TraceUpdateConstructorCache(const ConstructorCache* ctorCache, const FunctionBody* ctorBody, bool updated, const char16* reason)
  5884. {
  5885. #if DBG_DUMP
  5886. if (PHASE_TRACE(Js::ConstructorCachePhase, ctorBody))
  5887. {
  5888. const char16* ctorName = ctorBody->GetDisplayName();
  5889. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  5890. Output::Print(_u("CtorCache: %s cache (0x%p) for ctor %s (%s)%s %s: "),
  5891. updated ? _u("updated") : _u("did not update"), ctorBody, ctorName,
  5892. ctorBody ? const_cast<Js::FunctionBody *>(ctorBody)->GetDebugNumberSet(debugStringBuffer) : _u("(null)"),
  5893. updated ? _u("") : _u(", because") , reason);
  5894. ctorCache->Dump();
  5895. Output::Print(_u("\n"));
  5896. Output::Flush();
  5897. }
  5898. #endif
  5899. }
  5900. Var JavascriptOperators::NewScObject(const Var callee, const Arguments args, ScriptContext *const scriptContext, const Js::AuxArray<uint32> *spreadIndices)
  5901. {
  5902. Assert(callee);
  5903. Assert(args.Info.Count != 0);
  5904. Assert(scriptContext);
  5905. // Always save and restore implicit call flags when calling out
  5906. // REVIEW: Can we avoid it if we don't collect dynamic profile info?
  5907. ThreadContext *const threadContext = scriptContext->GetThreadContext();
  5908. const ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  5909. const Var newVarInstance = JavascriptFunction::CallAsConstructor(callee, /* overridingNewTarget = */nullptr, args, scriptContext, spreadIndices);
  5910. threadContext->SetImplicitCallFlags(savedImplicitCallFlags);
  5911. return newVarInstance;
  5912. }
  5913. Js::GlobalObject * JavascriptOperators::OP_LdRoot(ScriptContext* scriptContext)
  5914. {
  5915. return scriptContext->GetGlobalObject();
  5916. }
  5917. Js::ModuleRoot * JavascriptOperators::GetModuleRoot(int moduleID, ScriptContext* scriptContext)
  5918. {
  5919. Assert(moduleID != kmodGlobal);
  5920. JavascriptLibrary* library = scriptContext->GetLibrary();
  5921. HostObjectBase *hostObject = library->GetGlobalObject()->GetHostObject();
  5922. if (hostObject)
  5923. {
  5924. Js::ModuleRoot * moduleRoot = hostObject->GetModuleRoot(moduleID);
  5925. Assert(!CrossSite::NeedMarshalVar(moduleRoot, scriptContext));
  5926. return moduleRoot;
  5927. }
  5928. HostScriptContext *hostScriptContext = scriptContext->GetHostScriptContext();
  5929. if (hostScriptContext)
  5930. {
  5931. Js::ModuleRoot * moduleRoot = hostScriptContext->GetModuleRoot(moduleID);
  5932. Assert(!CrossSite::NeedMarshalVar(moduleRoot, scriptContext));
  5933. return moduleRoot;
  5934. }
  5935. Assert(FALSE);
  5936. return nullptr;
  5937. }
  5938. Var JavascriptOperators::OP_LoadModuleRoot(int moduleID, ScriptContext* scriptContext)
  5939. {
  5940. Js::ModuleRoot * moduleRoot = GetModuleRoot(moduleID, scriptContext);
  5941. if (moduleRoot)
  5942. {
  5943. return moduleRoot;
  5944. }
  5945. Assert(false);
  5946. return scriptContext->GetLibrary()->GetUndefined();
  5947. }
  5948. Var JavascriptOperators::OP_LdNull(ScriptContext* scriptContext)
  5949. {
  5950. return scriptContext->GetLibrary()->GetNull();
  5951. }
  5952. Var JavascriptOperators::OP_LdUndef(ScriptContext* scriptContext)
  5953. {
  5954. return scriptContext->GetLibrary()->GetUndefined();
  5955. }
  5956. Var JavascriptOperators::OP_LdNaN(ScriptContext* scriptContext)
  5957. {
  5958. return scriptContext->GetLibrary()->GetNaN();
  5959. }
  5960. Var JavascriptOperators::OP_LdChakraLib(ScriptContext* scriptContext)
  5961. {
  5962. return scriptContext->GetLibrary()->GetChakraLib();
  5963. }
  5964. Var JavascriptOperators::OP_LdInfinity(ScriptContext* scriptContext)
  5965. {
  5966. return scriptContext->GetLibrary()->GetPositiveInfinite();
  5967. }
  5968. void JavascriptOperators::BuildHandlerScope(Var argThis, RecyclableObject * hostObject, FrameDisplay * pDisplay, ScriptContext * scriptContext)
  5969. {
  5970. Assert(argThis != nullptr);
  5971. pDisplay->SetItem(0, TaggedNumber::Is(argThis) ? scriptContext->GetLibrary()->CreateNumberObject(argThis) : argThis);
  5972. uint16 i = 1;
  5973. Var aChild = argThis;
  5974. uint16 length = pDisplay->GetLength();
  5975. // Now add any parent scopes
  5976. // We need to support the namespace parent lookup in both fastDOM on and off scenario.
  5977. while (aChild != NULL)
  5978. {
  5979. Var aParent = hostObject->GetNamespaceParent(aChild);
  5980. if (aParent == nullptr)
  5981. {
  5982. break;
  5983. }
  5984. aParent = CrossSite::MarshalVar(scriptContext, aParent);
  5985. if (i == length)
  5986. {
  5987. length = UInt16Math::Add(length, 8);
  5988. FrameDisplay * tmp = RecyclerNewPlus(scriptContext->GetRecycler(), length * sizeof(void*), FrameDisplay, length);
  5989. js_memcpy_s((char*)tmp + tmp->GetOffsetOfScopes(), tmp->GetLength() * sizeof(void *), (char*)pDisplay + pDisplay->GetOffsetOfScopes(), pDisplay->GetLength() * sizeof(void*));
  5990. pDisplay = tmp;
  5991. }
  5992. pDisplay->SetItem(i, aParent);
  5993. aChild = aParent;
  5994. i++;
  5995. }
  5996. Assert(i <= pDisplay->GetLength());
  5997. pDisplay->SetLength(i);
  5998. }
  5999. FrameDisplay * JavascriptOperators::OP_LdHandlerScope(Var argThis, ScriptContext* scriptContext)
  6000. {
  6001. JIT_HELPER_REENTRANT_HEADER(ScrObj_LdHandlerScope);
  6002. // The idea here is to build a stack of nested scopes in the form of a JS array.
  6003. //
  6004. // The scope stack for an event handler looks like this:
  6005. //
  6006. // implicit "this"
  6007. // implicit namespace parent scopes
  6008. // Put the implicit "this"
  6009. if (argThis != NULL)
  6010. {
  6011. RecyclableObject* hostObject = scriptContext->GetGlobalObject()->GetHostObject();
  6012. if (hostObject == nullptr)
  6013. {
  6014. hostObject = scriptContext->GetGlobalObject()->GetDirectHostObject();
  6015. }
  6016. if (hostObject != nullptr)
  6017. {
  6018. uint16 length = 7;
  6019. FrameDisplay *pDisplay =
  6020. RecyclerNewPlus(scriptContext->GetRecycler(), length * sizeof(void*), FrameDisplay, length);
  6021. BuildHandlerScope(argThis, hostObject, pDisplay, scriptContext);
  6022. return pDisplay;
  6023. }
  6024. }
  6025. return const_cast<FrameDisplay *>(&Js::NullFrameDisplay);
  6026. JIT_HELPER_END(ScrObj_LdHandlerScope);
  6027. }
  6028. FrameDisplay* JavascriptOperators::OP_LdFrameDisplay(void *argHead, void *argEnv, ScriptContext* scriptContext)
  6029. {
  6030. JIT_HELPER_NOT_REENTRANT_HEADER(ScrObj_LdFrameDisplay, reentrancylock, scriptContext->GetThreadContext());
  6031. // Build a display of nested frame objects.
  6032. // argHead is the current scope; argEnv is either the lone trailing scope or an array of scopes
  6033. // which we append to the new display.
  6034. // Note that there are cases in which a function with no local frame must construct a display to pass
  6035. // to the function(s) nested within it. In such a case, argHead will be a null object, and it's not
  6036. // strictly necessary to include it. But such cases are rare and not perf critical, so it's not
  6037. // worth the extra complexity to notify the nested functions that they can "skip" this slot in the
  6038. // frame display when they're loading scopes nested outside it.
  6039. FrameDisplay *pDisplay = nullptr;
  6040. FrameDisplay *envDisplay = (FrameDisplay*)argEnv;
  6041. uint16 length = UInt16Math::Add(envDisplay->GetLength(), 1);
  6042. pDisplay = RecyclerNewPlus(scriptContext->GetRecycler(), length * sizeof(void*), FrameDisplay, length);
  6043. for (uint16 j = 0; j < length - 1; j++)
  6044. {
  6045. pDisplay->SetItem(j + 1, envDisplay->GetItem(j));
  6046. }
  6047. pDisplay->SetItem(0, argHead);
  6048. return pDisplay;
  6049. JIT_HELPER_END(ScrObj_LdFrameDisplay);
  6050. }
  6051. FrameDisplay* JavascriptOperators::OP_LdFrameDisplayNoParent(void *argHead, ScriptContext* scriptContext)
  6052. {
  6053. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(ScrObj_LdFrameDisplayNoParent);
  6054. return OP_LdFrameDisplay(argHead, (void*)&NullFrameDisplay, scriptContext);
  6055. JIT_HELPER_END(ScrObj_LdFrameDisplayNoParent);
  6056. }
  6057. FrameDisplay* JavascriptOperators::OP_LdStrictFrameDisplay(void *argHead, void *argEnv, ScriptContext* scriptContext)
  6058. {
  6059. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(ScrObj_LdStrictFrameDisplay);
  6060. FrameDisplay * pDisplay = OP_LdFrameDisplay(argHead, argEnv, scriptContext);
  6061. pDisplay->SetStrictMode(true);
  6062. return pDisplay;
  6063. JIT_HELPER_END(ScrObj_LdStrictFrameDisplay);
  6064. }
  6065. FrameDisplay* JavascriptOperators::OP_LdStrictFrameDisplayNoParent(void *argHead, ScriptContext* scriptContext)
  6066. {
  6067. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(ScrObj_LdStrictFrameDisplayNoParent);
  6068. return OP_LdStrictFrameDisplay(argHead, (void*)&StrictNullFrameDisplay, scriptContext);
  6069. JIT_HELPER_END(ScrObj_LdStrictFrameDisplayNoParent);
  6070. }
  6071. FrameDisplay* JavascriptOperators::OP_LdInnerFrameDisplay(void *argHead, void *argEnv, ScriptContext* scriptContext)
  6072. {
  6073. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(ScrObj_LdInnerFrameDisplay);
  6074. CheckInnerFrameDisplayArgument(argHead);
  6075. return OP_LdFrameDisplay(argHead, argEnv, scriptContext);
  6076. JIT_HELPER_END(ScrObj_LdInnerFrameDisplay);
  6077. }
  6078. FrameDisplay* JavascriptOperators::OP_LdInnerFrameDisplayNoParent(void *argHead, ScriptContext* scriptContext)
  6079. {
  6080. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(ScrObj_LdInnerFrameDisplayNoParent);
  6081. CheckInnerFrameDisplayArgument(argHead);
  6082. return OP_LdFrameDisplayNoParent(argHead, scriptContext);
  6083. JIT_HELPER_END(ScrObj_LdInnerFrameDisplayNoParent);
  6084. }
  6085. FrameDisplay* JavascriptOperators::OP_LdStrictInnerFrameDisplay(void *argHead, void *argEnv, ScriptContext* scriptContext)
  6086. {
  6087. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(ScrObj_LdStrictInnerFrameDisplay);
  6088. CheckInnerFrameDisplayArgument(argHead);
  6089. return OP_LdStrictFrameDisplay(argHead, argEnv, scriptContext);
  6090. JIT_HELPER_END(ScrObj_LdStrictInnerFrameDisplay);
  6091. }
  6092. FrameDisplay* JavascriptOperators::OP_LdStrictInnerFrameDisplayNoParent(void *argHead, ScriptContext* scriptContext)
  6093. {
  6094. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(ScrObj_LdStrictInnerFrameDisplayNoParent);
  6095. CheckInnerFrameDisplayArgument(argHead);
  6096. return OP_LdStrictFrameDisplayNoParent(argHead, scriptContext);
  6097. JIT_HELPER_END(ScrObj_LdStrictInnerFrameDisplayNoParent);
  6098. }
  6099. void JavascriptOperators::CheckInnerFrameDisplayArgument(void *argHead)
  6100. {
  6101. if (ThreadContext::IsOnStack(argHead))
  6102. {
  6103. AssertMsg(false, "Illegal byte code: stack object as with scope");
  6104. Js::Throw::FatalInternalError();
  6105. }
  6106. if (!RecyclableObject::Is(argHead))
  6107. {
  6108. AssertMsg(false, "Illegal byte code: non-object as with scope");
  6109. Js::Throw::FatalInternalError();
  6110. }
  6111. }
  6112. Js::PropertyId JavascriptOperators::GetPropertyId(Var propertyName, ScriptContext* scriptContext)
  6113. {
  6114. PropertyRecord const * propertyRecord = nullptr;
  6115. JavascriptSymbol * symbol = JavascriptOperators::TryFromVar<Js::JavascriptSymbol>(propertyName);
  6116. if (symbol)
  6117. {
  6118. propertyRecord = symbol->GetValue();
  6119. }
  6120. else
  6121. {
  6122. JavascriptSymbolObject * symbolObject = JavascriptOperators::TryFromVar<JavascriptSymbolObject>(propertyName);
  6123. if (symbolObject)
  6124. {
  6125. propertyRecord = symbolObject->GetValue();
  6126. }
  6127. else
  6128. {
  6129. JavascriptString * indexStr = JavascriptConversion::ToString(propertyName, scriptContext);
  6130. scriptContext->GetOrAddPropertyRecord(indexStr, &propertyRecord);
  6131. }
  6132. }
  6133. return propertyRecord->GetPropertyId();
  6134. }
  6135. void JavascriptOperators::OP_InitSetter(Var object, PropertyId propertyId, Var setter)
  6136. {
  6137. AssertMsg(!TaggedNumber::Is(object), "SetMember on a non-object?");
  6138. RecyclableObject* recylableObject = RecyclableObject::FromVar(object);
  6139. JIT_HELPER_NOT_REENTRANT_HEADER(OP_InitSetter, reentrancylock, recylableObject->GetScriptContext()->GetThreadContext());
  6140. recylableObject->SetAccessors(propertyId, nullptr, setter);
  6141. JIT_HELPER_END(OP_InitSetter);
  6142. }
  6143. void JavascriptOperators::OP_InitClassMemberSet(Var object, PropertyId propertyId, Var setter)
  6144. {
  6145. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_InitClassMemberSet);
  6146. JIT_HELPER_SAME_ATTRIBUTES(Op_InitClassMemberSet, OP_InitSetter);
  6147. JavascriptOperators::OP_InitSetter(object, propertyId, setter);
  6148. RecyclableObject::FromVar(object)->SetAttributes(propertyId, PropertyClassMemberDefaults);
  6149. JIT_HELPER_END(Op_InitClassMemberSet);
  6150. }
  6151. Js::PropertyId JavascriptOperators::OP_InitElemSetter(Var object, Var elementName, Var setter, ScriptContext* scriptContext, PropertyOperationFlags flags)
  6152. {
  6153. JIT_HELPER_REENTRANT_HEADER(OP_InitElemSetter);
  6154. AssertMsg(!TaggedNumber::Is(object), "SetMember on a non-object?");
  6155. PropertyId propertyId = JavascriptOperators::GetPropertyId(elementName, scriptContext);
  6156. RecyclableObject::FromVar(object)->SetAccessors(propertyId, nullptr, setter);
  6157. return propertyId;
  6158. JIT_HELPER_END(OP_InitElemSetter);
  6159. }
  6160. Field(Var)* JavascriptOperators::OP_GetModuleExportSlotArrayAddress(uint moduleIndex, uint slotIndex, ScriptContextInfo* scriptContext)
  6161. {
  6162. return scriptContext->GetModuleExportSlotArrayAddress(moduleIndex, slotIndex);
  6163. }
  6164. Field(Var)* JavascriptOperators::OP_GetModuleExportSlotAddress(uint moduleIndex, uint slotIndex, ScriptContext* scriptContext)
  6165. {
  6166. Field(Var)* moduleRecordSlots = OP_GetModuleExportSlotArrayAddress(moduleIndex, slotIndex, scriptContext);
  6167. Assert(moduleRecordSlots != nullptr);
  6168. return &moduleRecordSlots[slotIndex];
  6169. }
  6170. Var JavascriptOperators::OP_LdModuleSlot(uint moduleIndex, uint slotIndex, ScriptContext* scriptContext)
  6171. {
  6172. Field(Var)* addr = OP_GetModuleExportSlotAddress(moduleIndex, slotIndex, scriptContext);
  6173. Assert(addr != nullptr);
  6174. return *addr;
  6175. }
  6176. void JavascriptOperators::OP_StModuleSlot(uint moduleIndex, uint slotIndex, Var value, ScriptContext* scriptContext)
  6177. {
  6178. Assert(value != nullptr);
  6179. Field(Var)* addr = OP_GetModuleExportSlotAddress(moduleIndex, slotIndex, scriptContext);
  6180. Assert(addr != nullptr);
  6181. *addr = value;
  6182. }
  6183. void JavascriptOperators::OP_InitClassMemberSetComputedName(Var object, Var elementName, Var value, ScriptContext* scriptContext, PropertyOperationFlags flags)
  6184. {
  6185. JIT_HELPER_REENTRANT_HEADER(Op_InitClassMemberSetComputedName);
  6186. Js::PropertyId propertyId = JavascriptOperators::OP_InitElemSetter(object, elementName, value, scriptContext);
  6187. RecyclableObject* instance = RecyclableObject::FromVar(object);
  6188. // instance will be a function if it is the class constructor (otherwise it would be an object)
  6189. if (JavascriptFunction::Is(instance) && Js::PropertyIds::prototype == propertyId)
  6190. {
  6191. // It is a TypeError to have a static member with a computed name that evaluates to 'prototype'
  6192. JavascriptError::ThrowTypeError(scriptContext, JSERR_ClassStaticMethodCannotBePrototype);
  6193. }
  6194. instance->SetAttributes(propertyId, PropertyClassMemberDefaults);
  6195. JIT_HELPER_END(Op_InitClassMemberSetComputedName);
  6196. }
  6197. BOOL JavascriptOperators::IsClassConstructor(Var instance)
  6198. {
  6199. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_IsClassConstructor);
  6200. JavascriptFunction * function = JavascriptOperators::TryFromVar<JavascriptFunction>(instance);
  6201. return function && (function->GetFunctionInfo()->IsClassConstructor() || (!function->IsScriptFunction() && !function->IsExternalFunction()));
  6202. JIT_HELPER_END(Op_IsClassConstructor);
  6203. }
  6204. BOOL JavascriptOperators::IsClassMethod(Var instance)
  6205. {
  6206. JavascriptFunction * function = JavascriptOperators::TryFromVar<JavascriptFunction>(instance);
  6207. return function && function->GetFunctionInfo()->IsClassMethod();
  6208. }
  6209. BOOL JavascriptOperators::IsBaseConstructorKind(Var instance)
  6210. {
  6211. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_IsBaseConstructorKind);
  6212. JavascriptFunction * function = JavascriptOperators::TryFromVar<JavascriptFunction>(instance);
  6213. return function && (function->GetFunctionInfo()->GetBaseConstructorKind());
  6214. JIT_HELPER_END(Op_IsBaseConstructorKind);
  6215. }
  6216. void JavascriptOperators::OP_InitGetter(Var object, PropertyId propertyId, Var getter)
  6217. {
  6218. AssertMsg(!TaggedNumber::Is(object), "GetMember on a non-object?");
  6219. RecyclableObject* recylableObject = RecyclableObject::FromVar(object);
  6220. JIT_HELPER_NOT_REENTRANT_HEADER(OP_InitGetter, reentrancylock, recylableObject->GetScriptContext()->GetThreadContext());
  6221. recylableObject->SetAccessors(propertyId, getter, nullptr);
  6222. JIT_HELPER_END(OP_InitGetter);
  6223. }
  6224. void JavascriptOperators::OP_InitClassMemberGet(Var object, PropertyId propertyId, Var getter)
  6225. {
  6226. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_InitClassMemberGet);
  6227. JIT_HELPER_SAME_ATTRIBUTES(Op_InitClassMemberGet, OP_InitGetter);
  6228. JavascriptOperators::OP_InitGetter(object, propertyId, getter);
  6229. RecyclableObject::FromVar(object)->SetAttributes(propertyId, PropertyClassMemberDefaults);
  6230. JIT_HELPER_END(Op_InitClassMemberGet);
  6231. }
  6232. Js::PropertyId JavascriptOperators::OP_InitElemGetter(Var object, Var elementName, Var getter, ScriptContext* scriptContext, PropertyOperationFlags flags)
  6233. {
  6234. JIT_HELPER_REENTRANT_HEADER(OP_InitElemGetter);
  6235. AssertMsg(!TaggedNumber::Is(object), "GetMember on a non-object?");
  6236. PropertyId propertyId = JavascriptOperators::GetPropertyId(elementName, scriptContext);
  6237. RecyclableObject::FromVar(object)->SetAccessors(propertyId, getter, nullptr);
  6238. return propertyId;
  6239. JIT_HELPER_END(OP_InitElemGetter);
  6240. }
  6241. void JavascriptOperators::OP_InitClassMemberGetComputedName(Var object, Var elementName, Var value, ScriptContext* scriptContext, PropertyOperationFlags flags)
  6242. {
  6243. JIT_HELPER_REENTRANT_HEADER(Op_InitClassMemberGetComputedName);
  6244. Js::PropertyId propertyId = JavascriptOperators::OP_InitElemGetter(object, elementName, value, scriptContext);
  6245. RecyclableObject* instance = RecyclableObject::FromVar(object);
  6246. // instance will be a function if it is the class constructor (otherwise it would be an object)
  6247. if (JavascriptFunction::Is(instance) && Js::PropertyIds::prototype == propertyId)
  6248. {
  6249. // It is a TypeError to have a static member with a computed name that evaluates to 'prototype'
  6250. JavascriptError::ThrowTypeError(scriptContext, JSERR_ClassStaticMethodCannotBePrototype);
  6251. }
  6252. instance->SetAttributes(propertyId, PropertyClassMemberDefaults);
  6253. JIT_HELPER_END(Op_InitClassMemberGetComputedName);
  6254. }
  6255. void JavascriptOperators::OP_InitComputedProperty(Var object, Var elementName, Var value, ScriptContext* scriptContext, PropertyOperationFlags flags)
  6256. {
  6257. JIT_HELPER_REENTRANT_HEADER(OP_InitComputedProperty);
  6258. PropertyId propertyId = JavascriptOperators::GetPropertyId(elementName, scriptContext);
  6259. RecyclableObject::FromVar(object)->InitProperty(propertyId, value, flags);
  6260. JIT_HELPER_END(OP_InitComputedProperty);
  6261. }
  6262. void JavascriptOperators::OP_InitClassMemberComputedName(Var object, Var elementName, Var value, ScriptContext* scriptContext, PropertyOperationFlags flags)
  6263. {
  6264. JIT_HELPER_REENTRANT_HEADER(Op_InitClassMemberComputedName);
  6265. PropertyId propertyId = JavascriptOperators::GetPropertyId(elementName, scriptContext);
  6266. RecyclableObject* instance = RecyclableObject::FromVar(object);
  6267. // instance will be a function if it is the class constructor (otherwise it would be an object)
  6268. if (JavascriptFunction::Is(instance) && Js::PropertyIds::prototype == propertyId)
  6269. {
  6270. // It is a TypeError to have a static member with a computed name that evaluates to 'prototype'
  6271. JavascriptError::ThrowTypeError(scriptContext, JSERR_ClassStaticMethodCannotBePrototype);
  6272. }
  6273. instance->SetPropertyWithAttributes(propertyId, value, PropertyClassMemberDefaults, NULL, flags);
  6274. JIT_HELPER_END(Op_InitClassMemberComputedName);
  6275. }
  6276. //
  6277. // Used by object literal {..., __proto__: ..., }.
  6278. //
  6279. void JavascriptOperators::OP_InitProto(Var instance, PropertyId propertyId, Var value)
  6280. {
  6281. AssertMsg(RecyclableObject::Is(instance), "__proto__ member on a non-object?");
  6282. Assert(propertyId == PropertyIds::__proto__);
  6283. RecyclableObject* object = RecyclableObject::FromVar(instance);
  6284. ScriptContext* scriptContext = object->GetScriptContext();
  6285. JIT_HELPER_NOT_REENTRANT_HEADER(OP_InitProto, reentrancylock, scriptContext->GetThreadContext());
  6286. // B.3.1 __proto___ Property Names in Object Initializers
  6287. //6.If propKey is the string value "__proto__" and if isComputedPropertyName(propKey) is false, then
  6288. // a.If Type(v) is either Object or Null, then
  6289. // i.Return the result of calling the [[SetInheritance]] internal method of object with argument propValue.
  6290. // b.Return NormalCompletion(empty).
  6291. if (JavascriptOperators::IsObjectOrNull(value))
  6292. {
  6293. JavascriptObject::ChangePrototype(object, RecyclableObject::FromVar(value), /*validate*/false, scriptContext);
  6294. }
  6295. JIT_HELPER_END(OP_InitProto);
  6296. }
  6297. Var JavascriptOperators::ConvertToUnmappedArguments(HeapArgumentsObject *argumentsObject,
  6298. uint32 paramCount,
  6299. Var *paramAddr,
  6300. DynamicObject* frameObject,
  6301. Js::PropertyIdArray *propIds,
  6302. uint32 formalsCount,
  6303. ScriptContext* scriptContext)
  6304. {
  6305. Var *paramIter = paramAddr;
  6306. uint32 i = 0;
  6307. for (paramIter = paramAddr + i; i < paramCount; i++, paramIter++)
  6308. {
  6309. JavascriptOperators::SetItem(argumentsObject, argumentsObject, i, *paramIter, scriptContext, PropertyOperation_None, /* skipPrototypeCheck = */ TRUE);
  6310. }
  6311. argumentsObject = argumentsObject->ConvertToUnmappedArgumentsObject();
  6312. // Now as the unmapping is done we need to fill those frame object with Undecl
  6313. for (i = 0; i < formalsCount; i++)
  6314. {
  6315. frameObject->SetSlot(SetSlotArguments(propIds != nullptr ? propIds->elements[i] : Js::Constants::NoProperty, i, scriptContext->GetLibrary()->GetUndeclBlockVar()));
  6316. }
  6317. return argumentsObject;
  6318. }
  6319. Var JavascriptOperators::LoadHeapArguments(JavascriptFunction *funcCallee, uint32 actualsCount, Var *paramAddr, Var frameObj, Var vArray, ScriptContext* scriptContext, bool nonSimpleParamList)
  6320. {
  6321. JIT_HELPER_NOT_REENTRANT_HEADER(Op_LoadHeapArguments, reentrancylock, scriptContext->GetThreadContext());
  6322. AssertMsg(actualsCount != (unsigned int)-1, "Loading the arguments object in the global function?");
  6323. // Create and initialize the Arguments object.
  6324. uint32 formalsCount = 0;
  6325. Js::PropertyIdArray *propIds = nullptr;
  6326. if (vArray != scriptContext->GetLibrary()->GetNull())
  6327. {
  6328. propIds = (Js::PropertyIdArray *)vArray;
  6329. formalsCount = propIds->count;
  6330. Assert(formalsCount != 0 && propIds != nullptr);
  6331. }
  6332. HeapArgumentsObject *argsObj = JavascriptOperators::CreateHeapArguments(funcCallee, actualsCount, formalsCount, frameObj, scriptContext);
  6333. return FillScopeObject(funcCallee, actualsCount, formalsCount, frameObj, paramAddr, propIds, argsObj, scriptContext, nonSimpleParamList, false);
  6334. JIT_HELPER_END(Op_LoadHeapArguments);
  6335. }
  6336. Var JavascriptOperators::LoadHeapArgsCached(JavascriptFunction *funcCallee, uint32 actualsCount, uint32 formalsCount, Var *paramAddr, Var frameObj, ScriptContext* scriptContext, bool nonSimpleParamList)
  6337. {
  6338. JIT_HELPER_NOT_REENTRANT_HEADER(Op_LoadHeapArgsCached, reentrancylock, scriptContext->GetThreadContext());
  6339. // Disregard the "this" param.
  6340. AssertMsg(actualsCount != (uint32)-1 && formalsCount != (uint32)-1,
  6341. "Loading the arguments object in the global function?");
  6342. HeapArgumentsObject *argsObj = JavascriptOperators::CreateHeapArguments(funcCallee, actualsCount, formalsCount, frameObj, scriptContext);
  6343. return FillScopeObject(funcCallee, actualsCount, formalsCount, frameObj, paramAddr, nullptr, argsObj, scriptContext, nonSimpleParamList, true);
  6344. JIT_HELPER_END(Op_LoadHeapArgsCached);
  6345. }
  6346. Var JavascriptOperators::FillScopeObject(JavascriptFunction *funcCallee, uint32 actualsCount, uint32 formalsCount, Var frameObj, Var * paramAddr,
  6347. Js::PropertyIdArray *propIds, HeapArgumentsObject * argsObj, ScriptContext * scriptContext, bool nonSimpleParamList, bool useCachedScope)
  6348. {
  6349. Assert(formalsCount == 0 || frameObj != nullptr);
  6350. // Transfer formal arguments (that were actually passed) from their ArgIn slots to the local frame object.
  6351. uint32 i;
  6352. Var *tmpAddr = paramAddr;
  6353. if (formalsCount != 0)
  6354. {
  6355. DynamicObject* frameObject = nullptr;
  6356. if (useCachedScope)
  6357. {
  6358. frameObject = DynamicObject::FromVar(frameObj);
  6359. __analysis_assume((uint32)frameObject->GetDynamicType()->GetTypeHandler()->GetSlotCapacity() >= formalsCount);
  6360. }
  6361. else
  6362. {
  6363. frameObject = (DynamicObject*)frameObj;
  6364. // No fixed fields for formal parameters of the arguments object. Also, mark all fields as initialized up-front, because
  6365. // we will set them directly using SetSlot below, so the type handler will not have a chance to mark them as initialized later.
  6366. // CONSIDER : When we delay type sharing until the second instance is created, pass an argument indicating we want the types
  6367. // and handlers created here to be marked as shared up-front. This is to ensure we don't get any fixed fields and that the handler
  6368. // is ready for storing values directly to slots.
  6369. DynamicType* newType = PathTypeHandlerBase::CreateNewScopeObject(scriptContext, frameObject->GetDynamicType(), propIds, nonSimpleParamList ? PropertyLetDefaults : PropertyNone);
  6370. int oldSlotCapacity = frameObject->GetDynamicType()->GetTypeHandler()->GetSlotCapacity();
  6371. int newSlotCapacity = newType->GetTypeHandler()->GetSlotCapacity();
  6372. __analysis_assume((uint32)newSlotCapacity >= formalsCount);
  6373. frameObject->EnsureSlots(oldSlotCapacity, newSlotCapacity, scriptContext, newType->GetTypeHandler());
  6374. frameObject->ReplaceType(newType);
  6375. }
  6376. if (argsObj && nonSimpleParamList)
  6377. {
  6378. return ConvertToUnmappedArguments(argsObj, actualsCount, paramAddr, frameObject, propIds, formalsCount, scriptContext);
  6379. }
  6380. for (i = 0; i < formalsCount && i < actualsCount; i++, tmpAddr++)
  6381. {
  6382. frameObject->SetSlot(SetSlotArguments(propIds != nullptr? propIds->elements[i] : Constants::NoProperty, i, *tmpAddr));
  6383. }
  6384. if (i < formalsCount)
  6385. {
  6386. // The formals that weren't passed still need to be put in the frame object so that
  6387. // their names will be found. Initialize them to "undefined".
  6388. for (; i < formalsCount; i++)
  6389. {
  6390. frameObject->SetSlot(SetSlotArguments(propIds != nullptr? propIds->elements[i] : Constants::NoProperty, i, scriptContext->GetLibrary()->GetUndefined()));
  6391. }
  6392. }
  6393. }
  6394. if (argsObj != nullptr)
  6395. {
  6396. // Transfer the unnamed actual arguments, if any, to the Arguments object itself.
  6397. for (i = formalsCount, tmpAddr = paramAddr + i; i < actualsCount; i++, tmpAddr++)
  6398. {
  6399. // ES5 10.6.11: use [[DefineOwnProperty]] semantics (instead of [[Put]]):
  6400. // do not check whether property is non-writable/etc in the prototype.
  6401. // ES3 semantics is same.
  6402. JavascriptOperators::SetItem(argsObj, argsObj, i, *tmpAddr, scriptContext, PropertyOperation_None, /* skipPrototypeCheck = */ TRUE);
  6403. }
  6404. if (funcCallee->IsStrictMode())
  6405. {
  6406. // If the formals are let decls, then we just overwrote the frame object slots with
  6407. // Undecl sentinels, and we can use the original arguments that were passed to the HeapArgumentsObject.
  6408. return argsObj->ConvertToUnmappedArgumentsObject(!nonSimpleParamList);
  6409. }
  6410. }
  6411. return argsObj;
  6412. }
  6413. HeapArgumentsObject *JavascriptOperators::CreateHeapArguments(JavascriptFunction *funcCallee, uint32 actualsCount, uint32 formalsCount, Var frameObj, ScriptContext* scriptContext)
  6414. {
  6415. JavascriptLibrary *library = scriptContext->GetLibrary();
  6416. HeapArgumentsObject *argsObj = library->CreateHeapArguments(frameObj, formalsCount, !!funcCallee->IsStrictMode());
  6417. #if DBG
  6418. DynamicTypeHandler* typeHandler = argsObj->GetTypeHandler();
  6419. #endif
  6420. //
  6421. // Set the number of arguments of Arguments Object
  6422. //
  6423. argsObj->SetNumberOfArguments(actualsCount);
  6424. JavascriptOperators::SetProperty(argsObj, argsObj, PropertyIds::length, JavascriptNumber::ToVar(actualsCount, scriptContext), scriptContext);
  6425. JavascriptOperators::SetProperty(argsObj, argsObj, PropertyIds::_symbolIterator, library->EnsureArrayPrototypeValuesFunction(), scriptContext);
  6426. if (funcCallee->IsStrictMode())
  6427. {
  6428. JavascriptFunction* restrictedPropertyAccessor = library->GetThrowTypeErrorRestrictedPropertyAccessorFunction();
  6429. argsObj->SetAccessors(PropertyIds::callee, restrictedPropertyAccessor, restrictedPropertyAccessor, PropertyOperation_NonFixedValue);
  6430. }
  6431. else
  6432. {
  6433. JavascriptOperators::SetProperty(argsObj, argsObj, PropertyIds::callee,
  6434. StackScriptFunction::EnsureBoxed(BOX_PARAM(funcCallee, nullptr, _u("callee"))), scriptContext);
  6435. }
  6436. AssertMsg(argsObj->GetTypeHandler() == typeHandler || scriptContext->IsScriptContextInDebugMode(), "type handler should not transition because we initialized it correctly");
  6437. return argsObj;
  6438. }
  6439. Var JavascriptOperators::OP_NewScopeObject(ScriptContext* scriptContext)
  6440. {
  6441. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(OP_NewScopeObject);
  6442. return scriptContext->GetLibrary()->CreateActivationObject();
  6443. JIT_HELPER_END(OP_NewScopeObject);
  6444. }
  6445. Var JavascriptOperators::OP_NewScopeObjectWithFormals(ScriptContext* scriptContext, FunctionBody * calleeBody, bool nonSimpleParamList)
  6446. {
  6447. JIT_HELPER_NOT_REENTRANT_HEADER(OP_NewScopeObjectWithFormals, reentrancylock, scriptContext->GetThreadContext());
  6448. Js::ActivationObject * frameObject = (ActivationObject*)OP_NewScopeObject(scriptContext);
  6449. // No fixed fields for formal parameters of the arguments object. Also, mark all fields as initialized up-front, because
  6450. // we will set them directly using SetSlot below, so the type handler will not have a chance to mark them as initialized later.
  6451. // CONSIDER : When we delay type sharing until the second instance is created, pass an argument indicating we want the types
  6452. // and handlers created here to be marked as shared up-front. This is to ensure we don't get any fixed fields and that the handler
  6453. // is ready for storing values directly to slots.
  6454. DynamicType* newType = PathTypeHandlerBase::CreateNewScopeObject(scriptContext, frameObject->GetDynamicType(), calleeBody->GetFormalsPropIdArray(), nonSimpleParamList ? PropertyLetDefaults : PropertyNone);
  6455. int oldSlotCapacity = frameObject->GetDynamicType()->GetTypeHandler()->GetSlotCapacity();
  6456. int newSlotCapacity = newType->GetTypeHandler()->GetSlotCapacity();
  6457. frameObject->EnsureSlots(oldSlotCapacity, newSlotCapacity, scriptContext, newType->GetTypeHandler());
  6458. frameObject->ReplaceType(newType);
  6459. return frameObject;
  6460. JIT_HELPER_END(OP_NewScopeObjectWithFormals);
  6461. }
  6462. Field(Var)* JavascriptOperators::OP_NewScopeSlots(unsigned int size, ScriptContext *scriptContext, Var scope)
  6463. {
  6464. JIT_HELPER_NOT_REENTRANT_HEADER(OP_NewScopeSlots, reentrancylock, scriptContext->GetThreadContext());
  6465. Assert(size > ScopeSlots::FirstSlotIndex); // Should never see empty slot array
  6466. Field(Var)* slotArray = RecyclerNewArray(scriptContext->GetRecycler(), Field(Var), size); // last initialized slot contains reference to array of propertyIds, correspondent to objects in previous slots
  6467. uint count = size - ScopeSlots::FirstSlotIndex;
  6468. ScopeSlots slots(slotArray);
  6469. slots.SetCount(count);
  6470. AssertMsg(!FunctionBody::Is(scope), "Scope should only be FunctionInfo or DebuggerScope, not FunctionBody");
  6471. slots.SetScopeMetadata(scope);
  6472. Var undef = scriptContext->GetLibrary()->GetUndefined();
  6473. for (unsigned int i = 0; i < count; i++)
  6474. {
  6475. slots.Set(i, undef);
  6476. }
  6477. return slotArray;
  6478. JIT_HELPER_END(OP_NewScopeSlots);
  6479. }
  6480. Field(Var)* JavascriptOperators::OP_NewScopeSlotsWithoutPropIds(unsigned int count, int scopeIndex, ScriptContext *scriptContext, FunctionBody *functionBody)
  6481. {
  6482. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(OP_NewScopeSlotsWithoutPropIds);
  6483. DebuggerScope* scope = reinterpret_cast<DebuggerScope*>(Constants::FunctionBodyUnavailable);
  6484. if (scopeIndex != DebuggerScope::InvalidScopeIndex)
  6485. {
  6486. AssertMsg(functionBody->GetScopeObjectChain(), "A scope chain should always be created when there are new scope slots for blocks.");
  6487. scope = functionBody->GetScopeObjectChain()->pScopeChain->Item(scopeIndex);
  6488. }
  6489. return OP_NewScopeSlots(count, scriptContext, scope);
  6490. JIT_HELPER_END(OP_NewScopeSlotsWithoutPropIds);
  6491. }
  6492. Field(Var)* JavascriptOperators::OP_CloneScopeSlots(Field(Var) *slotArray, ScriptContext *scriptContext)
  6493. {
  6494. JIT_HELPER_NOT_REENTRANT_HEADER(OP_CloneInnerScopeSlots, reentrancylock, scriptContext->GetThreadContext());
  6495. ScopeSlots slots(slotArray);
  6496. uint size = ScopeSlots::FirstSlotIndex + static_cast<uint>(slots.GetCount());
  6497. Field(Var)* slotArrayClone = RecyclerNewArray(scriptContext->GetRecycler(), Field(Var), size);
  6498. CopyArray(slotArrayClone, size, slotArray, size);
  6499. return slotArrayClone;
  6500. JIT_HELPER_END(OP_CloneInnerScopeSlots);
  6501. }
  6502. Var JavascriptOperators::OP_NewPseudoScope(ScriptContext *scriptContext)
  6503. {
  6504. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(OP_NewPseudoScope);
  6505. return scriptContext->GetLibrary()->CreatePseudoActivationObject();
  6506. JIT_HELPER_END(OP_NewPseudoScope);
  6507. }
  6508. Var JavascriptOperators::OP_NewBlockScope(ScriptContext *scriptContext)
  6509. {
  6510. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(OP_NewBlockScope);
  6511. return scriptContext->GetLibrary()->CreateBlockActivationObject();
  6512. JIT_HELPER_END(OP_NewBlockScope);
  6513. }
  6514. Var JavascriptOperators::OP_CloneBlockScope(BlockActivationObject *blockScope, ScriptContext *scriptContext)
  6515. {
  6516. JIT_HELPER_NOT_REENTRANT_HEADER(OP_CloneBlockScope, reentrancylock, scriptContext->GetThreadContext());
  6517. return blockScope->Clone(scriptContext);
  6518. JIT_HELPER_END(OP_CloneBlockScope);
  6519. }
  6520. Var JavascriptOperators::OP_IsInst(Var instance, Var aClass, ScriptContext* scriptContext, IsInstInlineCache* inlineCache)
  6521. {
  6522. JIT_HELPER_REENTRANT_HEADER(ScrObj_OP_IsInst);
  6523. if (!RecyclableObject::Is(aClass))
  6524. {
  6525. JavascriptError::ThrowTypeError(scriptContext, JSERR_Operand_Invalid_NeedFunction, _u("instanceof"));
  6526. }
  6527. RecyclableObject* constructor = RecyclableObject::FromVar(aClass);
  6528. if (scriptContext->GetConfig()->IsES6HasInstanceEnabled())
  6529. {
  6530. Var instOfHandler = JavascriptOperators::GetPropertyNoCache(constructor,
  6531. PropertyIds::_symbolHasInstance, scriptContext);
  6532. if (JavascriptOperators::IsUndefinedObject(instOfHandler)
  6533. || instOfHandler == scriptContext->GetBuiltInLibraryFunction(JavascriptFunction::EntryInfo::SymbolHasInstance.GetOriginalEntryPoint()))
  6534. {
  6535. return JavascriptBoolean::ToVar(constructor->HasInstance(instance, scriptContext, inlineCache), scriptContext);
  6536. }
  6537. else
  6538. {
  6539. if (!JavascriptConversion::IsCallable(instOfHandler))
  6540. {
  6541. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction, _u("Symbol[Symbol.hasInstance]"));
  6542. }
  6543. ThreadContext * threadContext = scriptContext->GetThreadContext();
  6544. RecyclableObject *instFunc = RecyclableObject::FromVar(instOfHandler);
  6545. Var result = threadContext->ExecuteImplicitCall(instFunc, ImplicitCall_Accessor, [=]()->Js::Var
  6546. {
  6547. return CALL_FUNCTION(scriptContext->GetThreadContext(), instFunc, CallInfo(CallFlags_Value, 2), constructor, instance);
  6548. });
  6549. return JavascriptBoolean::ToVar(JavascriptConversion::ToBoolean(result, scriptContext) ? TRUE : FALSE, scriptContext);
  6550. }
  6551. }
  6552. else
  6553. {
  6554. return JavascriptBoolean::ToVar(constructor->HasInstance(instance, scriptContext, inlineCache), scriptContext);
  6555. }
  6556. JIT_HELPER_END(ScrObj_OP_IsInst);
  6557. }
  6558. void JavascriptOperators::OP_InitClass(Var constructor, Var extends, ScriptContext * scriptContext)
  6559. {
  6560. JIT_HELPER_REENTRANT_HEADER(OP_InitClass);
  6561. if (JavascriptOperators::GetTypeId(constructor) != Js::TypeId::TypeIds_Function)
  6562. {
  6563. JavascriptError::ThrowTypeError(scriptContext, JSERR_Operand_Invalid_NeedFunction, _u("class"));
  6564. }
  6565. RecyclableObject * ctor = RecyclableObject::FromVar(constructor);
  6566. if (extends)
  6567. {
  6568. switch (JavascriptOperators::GetTypeId(extends))
  6569. {
  6570. case Js::TypeId::TypeIds_Null:
  6571. {
  6572. Var ctorProto = JavascriptOperators::GetProperty(constructor, ctor, Js::PropertyIds::prototype, scriptContext);
  6573. RecyclableObject * ctorProtoObj = RecyclableObject::FromVar(ctorProto);
  6574. ctorProtoObj->SetPrototype(RecyclableObject::FromVar(extends));
  6575. ctorProtoObj->EnsureProperty(Js::PropertyIds::constructor);
  6576. ctorProtoObj->SetEnumerable(Js::PropertyIds::constructor, FALSE);
  6577. break;
  6578. }
  6579. default:
  6580. {
  6581. if (!RecyclableObject::Is(extends))
  6582. {
  6583. JavascriptError::ThrowTypeError(scriptContext, JSERR_ErrorOnNew);
  6584. }
  6585. RecyclableObject * extendsObj = RecyclableObject::FromVar(extends);
  6586. if (!JavascriptOperators::IsConstructor(extendsObj))
  6587. {
  6588. JavascriptError::ThrowTypeError(scriptContext, JSERR_ErrorOnNew);
  6589. }
  6590. if (!extendsObj->HasProperty(Js::PropertyIds::prototype))
  6591. {
  6592. JavascriptError::ThrowTypeError(scriptContext, JSERR_InvalidPrototype);
  6593. }
  6594. Var extendsProto = JavascriptOperators::GetPropertyNoCache(extends, extendsObj, Js::PropertyIds::prototype, scriptContext);
  6595. uint extendsProtoTypeId = JavascriptOperators::GetTypeId(extendsProto);
  6596. if (extendsProtoTypeId <= Js::TypeId::TypeIds_LastJavascriptPrimitiveType && extendsProtoTypeId != Js::TypeId::TypeIds_Null)
  6597. {
  6598. JavascriptError::ThrowTypeError(scriptContext, JSERR_InvalidPrototype);
  6599. }
  6600. Var ctorProto = JavascriptOperators::GetPropertyNoCache(constructor, ctor, Js::PropertyIds::prototype, scriptContext);
  6601. RecyclableObject * ctorProtoObj = RecyclableObject::FromVar(ctorProto);
  6602. ctorProtoObj->SetPrototype(RecyclableObject::FromVar(extendsProto));
  6603. ctorProtoObj->EnsureProperty(Js::PropertyIds::constructor);
  6604. ctorProtoObj->SetEnumerable(Js::PropertyIds::constructor, FALSE);
  6605. Var protoCtor = JavascriptOperators::GetPropertyNoCache(ctorProto, ctorProtoObj, Js::PropertyIds::constructor, scriptContext);
  6606. RecyclableObject * protoCtorObj = RecyclableObject::FromVar(protoCtor);
  6607. protoCtorObj->SetPrototype(extendsObj);
  6608. break;
  6609. }
  6610. }
  6611. }
  6612. Var proto = JavascriptOperators::GetProperty(constructor, ctor, Js::PropertyIds::prototype, scriptContext);
  6613. JavascriptOperators::OP_SetHomeObj(constructor, proto);
  6614. JIT_HELPER_END(OP_InitClass);
  6615. }
  6616. void JavascriptOperators::OP_LoadUndefinedToElement(Var instance, PropertyId propertyId)
  6617. {
  6618. JIT_HELPER_NOT_REENTRANT_HEADER(Op_LdElemUndef, reentrancylock, RecyclableObject::FromVar(instance)->GetScriptContext()->GetThreadContext());
  6619. AssertMsg(!TaggedNumber::Is(instance), "Invalid scope/root object");
  6620. JavascriptOperators::EnsureProperty(instance, propertyId);
  6621. JIT_HELPER_END(Op_LdElemUndef);
  6622. }
  6623. void JavascriptOperators::OP_LoadUndefinedToElementScoped(FrameDisplay *pScope, PropertyId propertyId, Var defaultInstance, ScriptContext* scriptContext)
  6624. {
  6625. JIT_HELPER_NOT_REENTRANT_HEADER(Op_LdElemUndefScoped, reentrancylock, scriptContext->GetThreadContext());
  6626. int i;
  6627. int length = pScope->GetLength();
  6628. Var argInstance;
  6629. for (i = 0; i < length; i++)
  6630. {
  6631. argInstance = pScope->GetItem(i);
  6632. if (JavascriptOperators::EnsureProperty(argInstance, propertyId))
  6633. {
  6634. return;
  6635. }
  6636. }
  6637. if (!JavascriptOperators::HasOwnPropertyNoHostObject(defaultInstance, propertyId))
  6638. {
  6639. // CONSIDER : Consider adding pre-initialization support to activation objects.
  6640. JavascriptOperators::OP_InitPropertyScoped(pScope, propertyId, scriptContext->GetLibrary()->GetUndefined(), defaultInstance, scriptContext);
  6641. }
  6642. JIT_HELPER_END(Op_LdElemUndefScoped);
  6643. }
  6644. void JavascriptOperators::OP_LoadUndefinedToElementDynamic(Var instance, PropertyId propertyId, ScriptContext *scriptContext)
  6645. {
  6646. JIT_HELPER_NOT_REENTRANT_HEADER(Op_LdElemUndefDynamic, reentrancylock, scriptContext->GetThreadContext());
  6647. if (!JavascriptOperators::HasOwnPropertyNoHostObject(instance, propertyId))
  6648. {
  6649. RecyclableObject::FromVar(instance)->InitPropertyScoped(propertyId, scriptContext->GetLibrary()->GetUndefined());
  6650. }
  6651. JIT_HELPER_END(Op_LdElemUndefDynamic);
  6652. }
  6653. BOOL JavascriptOperators::EnsureProperty(Var instance, PropertyId propertyId)
  6654. {
  6655. RecyclableObject *obj = RecyclableObject::FromVar(instance);
  6656. return (obj && obj->EnsureProperty(propertyId));
  6657. }
  6658. void JavascriptOperators::OP_EnsureNoRootProperty(Var instance, PropertyId propertyId)
  6659. {
  6660. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_EnsureNoRootProperty);
  6661. Assert(RootObjectBase::Is(instance));
  6662. RootObjectBase *obj = RootObjectBase::FromVar(instance);
  6663. obj->EnsureNoProperty(propertyId);
  6664. JIT_HELPER_END(Op_EnsureNoRootProperty);
  6665. }
  6666. void JavascriptOperators::OP_EnsureNoRootRedeclProperty(Var instance, PropertyId propertyId)
  6667. {
  6668. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_EnsureNoRootRedeclProperty);
  6669. Assert(RootObjectBase::Is(instance));
  6670. RecyclableObject *obj = RecyclableObject::FromVar(instance);
  6671. obj->EnsureNoRedeclProperty(propertyId);
  6672. JIT_HELPER_END(Op_EnsureNoRootRedeclProperty);
  6673. }
  6674. void JavascriptOperators::OP_ScopedEnsureNoRedeclProperty(FrameDisplay *pDisplay, PropertyId propertyId, Var defaultInstance)
  6675. {
  6676. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_EnsureNoRedeclPropertyScoped);
  6677. int i;
  6678. int length = pDisplay->GetLength();
  6679. RecyclableObject *object;
  6680. for (i = 0; i < length; i++)
  6681. {
  6682. object = RecyclableObject::FromVar(pDisplay->GetItem(i));
  6683. if (object->EnsureNoRedeclProperty(propertyId))
  6684. {
  6685. return;
  6686. }
  6687. }
  6688. object = RecyclableObject::FromVar(defaultInstance);
  6689. object->EnsureNoRedeclProperty(propertyId);
  6690. JIT_HELPER_END(Op_EnsureNoRedeclPropertyScoped);
  6691. }
  6692. Var JavascriptOperators::IsIn(Var argProperty, Var instance, ScriptContext* scriptContext)
  6693. {
  6694. JIT_HELPER_REENTRANT_HEADER(Op_IsIn);
  6695. // Note that the fact that we haven't seen a given name before doesn't mean that the instance doesn't
  6696. if (!IsObject(instance))
  6697. {
  6698. JavascriptError::ThrowTypeError(scriptContext, JSERR_Operand_Invalid_NeedObject, _u("in"));
  6699. }
  6700. RecyclableObject* object = RecyclableObject::FromVar(instance);
  6701. BOOL result;
  6702. PropertyRecord const * propertyRecord = nullptr;
  6703. uint32 index;
  6704. IndexType indexType;
  6705. // Fast path for JavascriptSymbols and PropertyStrings
  6706. RecyclableObject* cacheOwner;
  6707. PropertyRecordUsageCache* propertyRecordUsageCache;
  6708. if (GetPropertyRecordUsageCache(argProperty, scriptContext, &propertyRecordUsageCache, &cacheOwner))
  6709. {
  6710. Var value;
  6711. propertyRecord = propertyRecordUsageCache->GetPropertyRecord();
  6712. if (!propertyRecord->IsNumeric())
  6713. {
  6714. PropertyValueInfo info;
  6715. if (propertyRecordUsageCache->TryGetPropertyFromCache<false /* OwnPropertyOnly */, true /* OutputExistence */, false /* ReturnOperationInfo */>(instance, object, &value, scriptContext, &info, cacheOwner, nullptr))
  6716. {
  6717. Assert(JavascriptBoolean::Is(value));
  6718. return value;
  6719. }
  6720. result = JavascriptOperators::GetPropertyWPCache<true /* OutputExistence */>(instance, object, propertyRecordUsageCache->GetPropertyRecord()->GetPropertyId(), &value, scriptContext, &info);
  6721. Assert(value == JavascriptBoolean::ToVar(result, scriptContext));
  6722. return value;
  6723. }
  6724. // We don't cache numeric property lookups, so fall through to the IndexType_Number case
  6725. index = propertyRecord->GetNumericValue();
  6726. indexType = IndexType_Number;
  6727. }
  6728. else
  6729. {
  6730. indexType = GetIndexType(argProperty, scriptContext, &index, &propertyRecord, true);
  6731. }
  6732. if (indexType == IndexType_Number)
  6733. {
  6734. result = JavascriptOperators::HasItem(object, index);
  6735. }
  6736. else
  6737. {
  6738. result = JavascriptOperators::HasProperty(object, propertyRecord->GetPropertyId());
  6739. #ifdef TELEMETRY_JSO
  6740. {
  6741. Assert(indexType != Js::IndexType_JavascriptString);
  6742. if (indexType == Js::IndexType_PropertyId)
  6743. {
  6744. scriptContext->GetTelemetry().GetOpcodeTelemetry().IsIn(instance, propertyId, result != 0);
  6745. }
  6746. }
  6747. #endif
  6748. }
  6749. return JavascriptBoolean::ToVar(result, scriptContext);
  6750. JIT_HELPER_END(Op_IsIn);
  6751. }
  6752. template <bool IsFromFullJit, class TInlineCache>
  6753. inline Var JavascriptOperators::PatchGetValue(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId)
  6754. {
  6755. JIT_HELPER_REENTRANT_HEADER(Op_PatchGetValue);
  6756. return PatchGetValueWithThisPtr<IsFromFullJit, TInlineCache>(functionBody, inlineCache, inlineCacheIndex, instance, propertyId, instance);
  6757. JIT_HELPER_END(Op_PatchGetValue);
  6758. }
  6759. JIT_HELPER_TEMPLATE(Op_PatchGetValue, Op_PatchGetValuePolymorphic)
  6760. template <bool IsFromFullJit, class TInlineCache>
  6761. __forceinline Var JavascriptOperators::PatchGetValueWithThisPtr(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var thisInstance)
  6762. {
  6763. JIT_HELPER_REENTRANT_HEADER(Op_PatchGetValueWithThisPtr);
  6764. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  6765. Assert(Js::JavascriptStackWalker::ValidateTopJitFrame(scriptContext));
  6766. RecyclableObject* object = nullptr;
  6767. if (FALSE == JavascriptOperators::GetPropertyObject(instance, scriptContext, &object))
  6768. {
  6769. if (scriptContext->GetThreadContext()->RecordImplicitException())
  6770. {
  6771. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotGet_NullOrUndefined,
  6772. scriptContext->GetPropertyName(propertyId)->GetBuffer());
  6773. }
  6774. else
  6775. {
  6776. return scriptContext->GetLibrary()->GetUndefined();
  6777. }
  6778. }
  6779. PropertyValueInfo info;
  6780. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  6781. Var value;
  6782. if (CacheOperators::TryGetProperty<true, true, true, true, true, true, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false, false>(
  6783. instance, false, object, propertyId, &value, scriptContext, nullptr, &info))
  6784. {
  6785. return value;
  6786. }
  6787. #if DBG_DUMP
  6788. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  6789. {
  6790. CacheOperators::TraceCache(inlineCache, _u("PatchGetValue"), propertyId, scriptContext, object);
  6791. }
  6792. #endif
  6793. return JavascriptOperators::GetProperty(thisInstance, object, propertyId, scriptContext, &info);
  6794. JIT_HELPER_END(Op_PatchGetValueWithThisPtr);
  6795. }
  6796. JIT_HELPER_TEMPLATE(Op_PatchGetValueWithThisPtr, Op_PatchGetValuePolymorphicWithThisPtr)
  6797. template Var JavascriptOperators::PatchGetValue<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  6798. template Var JavascriptOperators::PatchGetValue<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  6799. template Var JavascriptOperators::PatchGetValue<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  6800. template Var JavascriptOperators::PatchGetValue<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  6801. template Var JavascriptOperators::PatchGetValueWithThisPtr<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var thisInstance);
  6802. template Var JavascriptOperators::PatchGetValueWithThisPtr<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var thisInstance);
  6803. template Var JavascriptOperators::PatchGetValueWithThisPtr<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var thisInstance);
  6804. template Var JavascriptOperators::PatchGetValueWithThisPtr<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var thisInstance);
  6805. template <bool IsFromFullJit, class TInlineCache>
  6806. Var JavascriptOperators::PatchGetValueForTypeOf(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId)
  6807. {
  6808. JIT_HELPER_REENTRANT_HEADER(Op_PatchGetValueForTypeOf);
  6809. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  6810. Assert(Js::JavascriptStackWalker::ValidateTopJitFrame(scriptContext));
  6811. RecyclableObject* object = nullptr;
  6812. if (FALSE == JavascriptOperators::GetPropertyObject(instance, scriptContext, &object))
  6813. {
  6814. if (scriptContext->GetThreadContext()->RecordImplicitException())
  6815. {
  6816. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotGet_NullOrUndefined,
  6817. scriptContext->GetPropertyName(propertyId)->GetBuffer());
  6818. }
  6819. else
  6820. {
  6821. return scriptContext->GetLibrary()->GetUndefined();
  6822. }
  6823. }
  6824. PropertyValueInfo info;
  6825. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  6826. Var value;
  6827. if (CacheOperators::TryGetProperty<true, true, true, true, true, true, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false, false>(
  6828. instance, false, object, propertyId, &value, scriptContext, nullptr, &info))
  6829. {
  6830. return value;
  6831. }
  6832. #if DBG_DUMP
  6833. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  6834. {
  6835. CacheOperators::TraceCache(inlineCache, _u("PatchGetValueForTypeOf"), propertyId, scriptContext, object);
  6836. }
  6837. #endif
  6838. Var prop = nullptr;
  6839. BEGIN_TYPEOF_ERROR_HANDLER(scriptContext);
  6840. prop = JavascriptOperators::GetProperty(instance, object, propertyId, scriptContext, &info);
  6841. END_TYPEOF_ERROR_HANDLER(scriptContext, prop);
  6842. return prop;
  6843. JIT_HELPER_END(Op_PatchGetValueForTypeOf);
  6844. }
  6845. JIT_HELPER_TEMPLATE(Op_PatchGetValueForTypeOf, Op_PatchGetValuePolymorphicForTypeOf)
  6846. template Var JavascriptOperators::PatchGetValueForTypeOf<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  6847. template Var JavascriptOperators::PatchGetValueForTypeOf<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  6848. template Var JavascriptOperators::PatchGetValueForTypeOf<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  6849. template Var JavascriptOperators::PatchGetValueForTypeOf<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  6850. Var JavascriptOperators::PatchGetValueUsingSpecifiedInlineCache(InlineCache * inlineCache, Var instance, RecyclableObject * object, PropertyId propertyId, ScriptContext* scriptContext)
  6851. {
  6852. PropertyValueInfo info;
  6853. PropertyValueInfo::SetCacheInfo(&info, inlineCache);
  6854. Var value;
  6855. if (CacheOperators::TryGetProperty<true, true, true, true, false, true, !InlineCache::IsPolymorphic, InlineCache::IsPolymorphic, false, false>(
  6856. instance, false, object, propertyId, &value, scriptContext, nullptr, &info))
  6857. {
  6858. return value;
  6859. }
  6860. #if DBG_DUMP
  6861. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  6862. {
  6863. CacheOperators::TraceCache(inlineCache, _u("PatchGetValue"), propertyId, scriptContext, object);
  6864. }
  6865. #endif
  6866. return JavascriptOperators::GetProperty(instance, object, propertyId, scriptContext, &info);
  6867. }
  6868. Var JavascriptOperators::PatchGetValueNoFastPath(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId)
  6869. {
  6870. return PatchGetValueWithThisPtrNoFastPath(functionBody, inlineCache, inlineCacheIndex, instance, propertyId, instance);
  6871. }
  6872. Var JavascriptOperators::PatchGetValueWithThisPtrNoFastPath(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var thisInstance)
  6873. {
  6874. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  6875. RecyclableObject* object = nullptr;
  6876. if (FALSE == JavascriptOperators::GetPropertyObject(instance, scriptContext, &object))
  6877. {
  6878. if (scriptContext->GetThreadContext()->RecordImplicitException())
  6879. {
  6880. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotGet_NullOrUndefined,
  6881. scriptContext->GetPropertyName(propertyId)->GetBuffer());
  6882. }
  6883. else
  6884. {
  6885. return scriptContext->GetLibrary()->GetUndefined();
  6886. }
  6887. }
  6888. PropertyValueInfo info;
  6889. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, true);
  6890. return JavascriptOperators::GetProperty(thisInstance, object, propertyId, scriptContext, &info);
  6891. }
  6892. template <bool IsFromFullJit, class TInlineCache>
  6893. inline Var JavascriptOperators::PatchGetRootValue(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject * object, PropertyId propertyId)
  6894. {
  6895. JIT_HELPER_REENTRANT_HEADER(Op_PatchGetRootValue);
  6896. AssertMsg(RootObjectBase::Is(object), "Root must be a global object!");
  6897. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  6898. PropertyValueInfo info;
  6899. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  6900. Var value;
  6901. if (CacheOperators::TryGetProperty<true, true, true, false, true, false, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false, false>(
  6902. object, true, object, propertyId, &value, scriptContext, nullptr, &info))
  6903. {
  6904. return value;
  6905. }
  6906. #if DBG_DUMP
  6907. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  6908. {
  6909. CacheOperators::TraceCache(inlineCache, _u("PatchGetRootValue"), propertyId, scriptContext, object);
  6910. }
  6911. #endif
  6912. return JavascriptOperators::OP_GetRootProperty(object, propertyId, &info, scriptContext);
  6913. JIT_HELPER_END(Op_PatchGetRootValue);
  6914. }
  6915. JIT_HELPER_TEMPLATE(Op_PatchGetRootValue, Op_PatchGetRootValuePolymorphic)
  6916. template Var JavascriptOperators::PatchGetRootValue<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject * object, PropertyId propertyId);
  6917. template Var JavascriptOperators::PatchGetRootValue<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject * object, PropertyId propertyId);
  6918. template Var JavascriptOperators::PatchGetRootValue<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject * object, PropertyId propertyId);
  6919. template Var JavascriptOperators::PatchGetRootValue<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject * object, PropertyId propertyId);
  6920. template <bool IsFromFullJit, class TInlineCache>
  6921. Var JavascriptOperators::PatchGetRootValueForTypeOf(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject * object, PropertyId propertyId)
  6922. {
  6923. JIT_HELPER_REENTRANT_HEADER(Op_PatchGetRootValueForTypeOf);
  6924. AssertMsg(RootObjectBase::Is(object), "Root must be a global object!");
  6925. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  6926. PropertyValueInfo info;
  6927. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  6928. Var value = nullptr;
  6929. if (CacheOperators::TryGetProperty<true, true, true, false, true, false, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false, false>(
  6930. object, true, object, propertyId, &value, scriptContext, nullptr, &info))
  6931. {
  6932. return value;
  6933. }
  6934. #if DBG_DUMP
  6935. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  6936. {
  6937. CacheOperators::TraceCache(inlineCache, _u("PatchGetRootValueForTypeOf"), propertyId, scriptContext, object);
  6938. }
  6939. #endif
  6940. value = nullptr;
  6941. BEGIN_TYPEOF_ERROR_HANDLER(scriptContext);
  6942. if (JavascriptOperators::GetRootProperty(RecyclableObject::FromVar(object), propertyId, &value, scriptContext, &info))
  6943. {
  6944. if (scriptContext->IsUndeclBlockVar(value))
  6945. {
  6946. JavascriptError::ThrowReferenceError(scriptContext, JSERR_UseBeforeDeclaration);
  6947. }
  6948. return value;
  6949. }
  6950. END_TYPEOF_ERROR_HANDLER(scriptContext, value);
  6951. value = scriptContext->GetLibrary()->GetUndefined();
  6952. return value;
  6953. JIT_HELPER_END(Op_PatchGetRootValueForTypeOf);
  6954. }
  6955. JIT_HELPER_TEMPLATE(Op_PatchGetRootValueForTypeOf, Op_PatchGetRootValuePolymorphicForTypeOf)
  6956. template Var JavascriptOperators::PatchGetRootValueForTypeOf<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject * object, PropertyId propertyId);
  6957. template Var JavascriptOperators::PatchGetRootValueForTypeOf<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject * object, PropertyId propertyId);
  6958. template Var JavascriptOperators::PatchGetRootValueForTypeOf<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject * object, PropertyId propertyId);
  6959. template Var JavascriptOperators::PatchGetRootValueForTypeOf<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject * object, PropertyId propertyId);
  6960. Var JavascriptOperators::PatchGetRootValueNoFastPath_Var(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId)
  6961. {
  6962. return
  6963. PatchGetRootValueNoFastPath(
  6964. functionBody,
  6965. inlineCache,
  6966. inlineCacheIndex,
  6967. DynamicObject::FromVar(instance),
  6968. propertyId);
  6969. }
  6970. Var JavascriptOperators::PatchGetRootValueNoFastPath(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject* object, PropertyId propertyId)
  6971. {
  6972. AssertMsg(RootObjectBase::Is(object), "Root must be a global object!");
  6973. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  6974. PropertyValueInfo info;
  6975. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, true);
  6976. return JavascriptOperators::OP_GetRootProperty(object, propertyId, &info, scriptContext);
  6977. }
  6978. template <bool IsFromFullJit, class TInlineCache>
  6979. inline Var JavascriptOperators::PatchGetPropertyScoped(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var defaultInstance)
  6980. {
  6981. JIT_HELPER_REENTRANT_HEADER(Op_PatchGetPropertyScoped);
  6982. // Get the property, using a scope stack rather than an individual instance.
  6983. // Walk the stack until we find an instance that has the property.
  6984. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  6985. uint16 length = pDisplay->GetLength();
  6986. PropertyValueInfo info;
  6987. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  6988. for (uint16 i = 0; i < length; i++)
  6989. {
  6990. RecyclableObject* object = RecyclableObject::UnsafeFromVar(pDisplay->GetItem(i));
  6991. Var value;
  6992. if (CacheOperators::TryGetProperty<true, true, true, false, true, true, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false, false>(
  6993. object, false, object, propertyId, &value, scriptContext, nullptr, &info))
  6994. {
  6995. return value;
  6996. }
  6997. #if DBG_DUMP
  6998. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  6999. {
  7000. CacheOperators::TraceCache(inlineCache, _u("PatchGetPropertyScoped"), propertyId, scriptContext, object);
  7001. }
  7002. #endif
  7003. if (JavascriptOperators::GetProperty(object, propertyId, &value, scriptContext, &info))
  7004. {
  7005. if (scriptContext->IsUndeclBlockVar(value) && propertyId != PropertyIds::_this)
  7006. {
  7007. JavascriptError::ThrowReferenceError(scriptContext, JSERR_UseBeforeDeclaration);
  7008. }
  7009. return value;
  7010. }
  7011. }
  7012. // There is no root decl for 'this', we should instead load the global 'this' value.
  7013. if (propertyId == PropertyIds::_this)
  7014. {
  7015. Var varNull = OP_LdNull(scriptContext);
  7016. return JavascriptOperators::OP_GetThis(varNull, functionBody->GetModuleID(), scriptContext);
  7017. }
  7018. else if (propertyId == PropertyIds::_super)
  7019. {
  7020. JavascriptError::ThrowReferenceError(scriptContext, JSERR_BadSuperReference);
  7021. }
  7022. // No one in the scope stack has the property, so get it from the default instance provided by the caller.
  7023. Var value = JavascriptOperators::PatchGetRootValue<IsFromFullJit>(functionBody, inlineCache, inlineCacheIndex, DynamicObject::FromVar(defaultInstance), propertyId);
  7024. if (scriptContext->IsUndeclBlockVar(value))
  7025. {
  7026. JavascriptError::ThrowReferenceError(scriptContext, JSERR_UseBeforeDeclaration);
  7027. }
  7028. return value;
  7029. JIT_HELPER_END(Op_PatchGetPropertyScoped);
  7030. }
  7031. template Var JavascriptOperators::PatchGetPropertyScoped<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var defaultInstance);
  7032. template Var JavascriptOperators::PatchGetPropertyScoped<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var defaultInstance);
  7033. template Var JavascriptOperators::PatchGetPropertyScoped<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var defaultInstance);
  7034. template Var JavascriptOperators::PatchGetPropertyScoped<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var defaultInstance);
  7035. template <bool IsFromFullJit, class TInlineCache>
  7036. Var JavascriptOperators::PatchGetPropertyForTypeOfScoped(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var defaultInstance)
  7037. {
  7038. JIT_HELPER_REENTRANT_HEADER(Op_PatchGetPropertyForTypeOfScoped);
  7039. Var value = nullptr;
  7040. ScriptContext *scriptContext = functionBody->GetScriptContext();
  7041. BEGIN_TYPEOF_ERROR_HANDLER(scriptContext);
  7042. value = JavascriptOperators::PatchGetPropertyScoped<IsFromFullJit, TInlineCache>(functionBody, inlineCache, inlineCacheIndex, pDisplay, propertyId, defaultInstance);
  7043. END_TYPEOF_ERROR_HANDLER(scriptContext, value)
  7044. return value;
  7045. JIT_HELPER_END(Op_PatchGetPropertyForTypeOfScoped);
  7046. }
  7047. template Var JavascriptOperators::PatchGetPropertyForTypeOfScoped<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var defaultInstance);
  7048. template Var JavascriptOperators::PatchGetPropertyForTypeOfScoped<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var defaultInstance);
  7049. template Var JavascriptOperators::PatchGetPropertyForTypeOfScoped<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var defaultInstance);
  7050. template Var JavascriptOperators::PatchGetPropertyForTypeOfScoped<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, FrameDisplay *pDisplay, PropertyId propertyId, Var defaultInstance);
  7051. template <bool IsFromFullJit, class TInlineCache>
  7052. inline Var JavascriptOperators::PatchGetMethod(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId)
  7053. {
  7054. JIT_HELPER_REENTRANT_HEADER(Op_PatchGetMethod);
  7055. Assert(inlineCache != nullptr);
  7056. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  7057. RecyclableObject* object = nullptr;
  7058. #if ENABLE_COPYONACCESS_ARRAY
  7059. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  7060. #endif
  7061. if (FALSE == JavascriptOperators::GetPropertyObject(instance, scriptContext, &object))
  7062. {
  7063. // Don't error if we disabled implicit calls
  7064. if (scriptContext->GetThreadContext()->RecordImplicitException())
  7065. {
  7066. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotGet_NullOrUndefined,
  7067. scriptContext->GetPropertyName(propertyId)->GetBuffer());
  7068. }
  7069. else
  7070. {
  7071. #ifdef TELEMETRY_JSO
  7072. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  7073. {
  7074. // `successful` will be true as PatchGetMethod throws an exception if not found.
  7075. scriptContext->GetTelemetry().GetOpcodeTelemetry().GetMethodProperty(object, propertyId, value, /*successful:*/false);
  7076. }
  7077. #endif
  7078. return scriptContext->GetLibrary()->GetUndefined();
  7079. }
  7080. }
  7081. PropertyValueInfo info;
  7082. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  7083. Var value;
  7084. if (CacheOperators::TryGetProperty<true, true, true, false, true, true, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false, false>(
  7085. instance, false, object, propertyId, &value, scriptContext, nullptr, &info))
  7086. {
  7087. return value;
  7088. }
  7089. #if DBG_DUMP
  7090. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  7091. {
  7092. CacheOperators::TraceCache(inlineCache, _u("PatchGetMethod"), propertyId, scriptContext, object);
  7093. }
  7094. #endif
  7095. value = Js::JavascriptOperators::PatchGetMethodFromObject(instance, object, propertyId, &info, scriptContext, false);
  7096. #ifdef TELEMETRY_JSO
  7097. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  7098. {
  7099. // `successful` will be true as PatchGetMethod throws an exception if not found.
  7100. scriptContext->GetTelemetry().GetOpcodeTelemetry().GetMethodProperty(object, propertyId, value, /*successful:*/true);
  7101. }
  7102. #endif
  7103. return value;
  7104. JIT_HELPER_END(Op_PatchGetMethod);
  7105. }
  7106. JIT_HELPER_TEMPLATE(Op_PatchGetMethod, Op_PatchGetMethodPolymorphic)
  7107. template Var JavascriptOperators::PatchGetMethod<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  7108. template Var JavascriptOperators::PatchGetMethod<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  7109. template Var JavascriptOperators::PatchGetMethod<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  7110. template Var JavascriptOperators::PatchGetMethod<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  7111. template <bool IsFromFullJit, class TInlineCache>
  7112. inline Var JavascriptOperators::PatchGetRootMethod(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject* object, PropertyId propertyId)
  7113. {
  7114. JIT_HELPER_REENTRANT_HEADER(Op_PatchGetRootMethod);
  7115. Assert(inlineCache != nullptr);
  7116. AssertMsg(RootObjectBase::Is(object), "Root must be a global object!");
  7117. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  7118. PropertyValueInfo info;
  7119. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  7120. Var value;
  7121. if (CacheOperators::TryGetProperty<true, true, true, false, true, false, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false, false>(
  7122. object, true, object, propertyId, &value, scriptContext, nullptr, &info))
  7123. {
  7124. return value;
  7125. }
  7126. #if DBG_DUMP
  7127. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  7128. {
  7129. CacheOperators::TraceCache(inlineCache, _u("PatchGetRootMethod"), propertyId, scriptContext, object);
  7130. }
  7131. #endif
  7132. value = Js::JavascriptOperators::PatchGetMethodFromObject(object, object, propertyId, &info, scriptContext, true);
  7133. #ifdef TELEMETRY_JSO
  7134. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  7135. {
  7136. // `successful` will be true as PatchGetMethod throws an exception if not found.
  7137. scriptContext->GetTelemetry().GetOpcodeTelemetry().GetMethodProperty(object, propertyId, value, /*successful:*/ true);
  7138. }
  7139. #endif
  7140. return value;
  7141. JIT_HELPER_END(Op_PatchGetRootMethod);
  7142. }
  7143. JIT_HELPER_TEMPLATE(Op_PatchGetRootMethod, Op_PatchGetRootMethodPolymorphic)
  7144. template Var JavascriptOperators::PatchGetRootMethod<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject* object, PropertyId propertyId);
  7145. template Var JavascriptOperators::PatchGetRootMethod<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject* object, PropertyId propertyId);
  7146. template Var JavascriptOperators::PatchGetRootMethod<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject* object, PropertyId propertyId);
  7147. template Var JavascriptOperators::PatchGetRootMethod<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject* object, PropertyId propertyId);
  7148. template <bool IsFromFullJit, class TInlineCache>
  7149. inline Var JavascriptOperators::PatchScopedGetMethod(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId)
  7150. {
  7151. JIT_HELPER_REENTRANT_HEADER(Op_ScopedGetMethod);
  7152. Assert(inlineCache != nullptr);
  7153. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  7154. RecyclableObject* object = nullptr;
  7155. if (FALSE == JavascriptOperators::GetPropertyObject(instance, scriptContext, &object))
  7156. {
  7157. // Don't error if we disabled implicit calls
  7158. if (scriptContext->GetThreadContext()->RecordImplicitException())
  7159. {
  7160. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotGet_NullOrUndefined,
  7161. scriptContext->GetPropertyName(propertyId)->GetBuffer());
  7162. }
  7163. else
  7164. {
  7165. return scriptContext->GetLibrary()->GetUndefined();
  7166. }
  7167. }
  7168. PropertyValueInfo info;
  7169. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  7170. const bool isRoot = RootObjectBase::Is(object);
  7171. Var value;
  7172. if (CacheOperators::TryGetProperty<true, true, true, false, true, false, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false, false>(
  7173. instance, isRoot, object, propertyId, &value, scriptContext, nullptr, &info))
  7174. {
  7175. return value;
  7176. }
  7177. #if DBG_DUMP
  7178. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  7179. {
  7180. CacheOperators::TraceCache(inlineCache, _u("PatchGetMethod"), propertyId, scriptContext, object);
  7181. }
  7182. #endif
  7183. return Js::JavascriptOperators::PatchGetMethodFromObject(instance, object, propertyId, &info, scriptContext, isRoot);
  7184. JIT_HELPER_END(Op_ScopedGetMethod);
  7185. }
  7186. JIT_HELPER_TEMPLATE(Op_ScopedGetMethod, Op_ScopedGetMethodPolymorphic)
  7187. template Var JavascriptOperators::PatchScopedGetMethod<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  7188. template Var JavascriptOperators::PatchScopedGetMethod<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  7189. template Var JavascriptOperators::PatchScopedGetMethod<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  7190. template Var JavascriptOperators::PatchScopedGetMethod<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId);
  7191. Var JavascriptOperators::PatchGetMethodNoFastPath(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId)
  7192. {
  7193. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  7194. RecyclableObject* object = nullptr;
  7195. if (FALSE == JavascriptOperators::GetPropertyObject(instance, scriptContext, &object))
  7196. {
  7197. // Don't error if we disabled implicit calls
  7198. if (scriptContext->GetThreadContext()->RecordImplicitException())
  7199. {
  7200. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotGet_NullOrUndefined,
  7201. scriptContext->GetPropertyName(propertyId)->GetBuffer());
  7202. }
  7203. else
  7204. {
  7205. return scriptContext->GetLibrary()->GetUndefined();
  7206. }
  7207. }
  7208. PropertyValueInfo info;
  7209. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, true);
  7210. return Js::JavascriptOperators::PatchGetMethodFromObject(instance, object, propertyId, &info, scriptContext, false);
  7211. }
  7212. Var JavascriptOperators::PatchGetRootMethodNoFastPath_Var(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId)
  7213. {
  7214. return
  7215. PatchGetRootMethodNoFastPath(
  7216. functionBody,
  7217. inlineCache,
  7218. inlineCacheIndex,
  7219. DynamicObject::FromVar(instance),
  7220. propertyId);
  7221. }
  7222. Var JavascriptOperators::PatchGetRootMethodNoFastPath(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject* object, PropertyId propertyId)
  7223. {
  7224. AssertMsg(RootObjectBase::Is(object), "Root must be a global object!");
  7225. PropertyValueInfo info;
  7226. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, true);
  7227. return Js::JavascriptOperators::PatchGetMethodFromObject(object, object, propertyId, &info, functionBody->GetScriptContext(), true);
  7228. }
  7229. Var JavascriptOperators::PatchGetMethodFromObject(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, PropertyValueInfo * info, ScriptContext* scriptContext, bool isRootLd)
  7230. {
  7231. Assert(IsPropertyObject(propertyObject));
  7232. Var value = nullptr;
  7233. BOOL foundValue = FALSE;
  7234. if (isRootLd)
  7235. {
  7236. RootObjectBase* rootObject = RootObjectBase::FromVar(instance);
  7237. foundValue = JavascriptOperators::GetRootPropertyReference(rootObject, propertyId, &value, scriptContext, info);
  7238. }
  7239. else
  7240. {
  7241. foundValue = JavascriptOperators::GetPropertyReference(instance, propertyObject, propertyId, &value, scriptContext, info);
  7242. }
  7243. if (!foundValue)
  7244. {
  7245. // Don't error if we disabled implicit calls
  7246. if (scriptContext->GetThreadContext()->RecordImplicitException())
  7247. {
  7248. const char16* propertyName = scriptContext->GetPropertyName(propertyId)->GetBuffer();
  7249. value = scriptContext->GetLibrary()->GetUndefined();
  7250. JavascriptFunction * caller = NULL;
  7251. if (JavascriptStackWalker::GetCaller(&caller, scriptContext))
  7252. {
  7253. FunctionBody * callerBody = caller->GetFunctionBody();
  7254. if (callerBody && callerBody->GetUtf8SourceInfo()->GetIsXDomain())
  7255. {
  7256. propertyName = NULL;
  7257. }
  7258. }
  7259. // Prior to version 12 we had mistakenly immediately thrown an error for property reference method calls
  7260. // (i.e. <expr>.foo() form) when the target object is the global object. The spec says that a GetValue
  7261. // on a reference should throw if the reference is unresolved, of which a property reference can never be,
  7262. // however it can be unresolved in the case of an identifier expression, e.g. foo() with no qualification.
  7263. // Such a case would come down to the global object if foo was undefined, hence the check for root object,
  7264. // except that it should have been a check for isRootLd to be correct.
  7265. //
  7266. // // (at global scope)
  7267. // foo(x());
  7268. //
  7269. // should throw an error before evaluating x() if foo is not defined, but
  7270. //
  7271. // // (at global scope)
  7272. // this.foo(x());
  7273. //
  7274. // should evaluate x() before throwing an error if foo is not a property on the global object.
  7275. // Maintain old behavior prior to version 12.
  7276. bool isPropertyReference = !isRootLd;
  7277. if (!isPropertyReference)
  7278. {
  7279. JavascriptError::ThrowReferenceError(scriptContext, JSERR_UndefVariable, propertyName);
  7280. }
  7281. else
  7282. {
  7283. // ES5 11.2.3 #2: We evaluate the call target but don't throw yet if target member is missing. We need to evaluate argList
  7284. // first (#3). Postpone throwing error to invoke time.
  7285. value = ThrowErrorObject::CreateThrowTypeErrorObject(scriptContext, VBSERR_OLENoPropOrMethod, propertyName);
  7286. }
  7287. }
  7288. }
  7289. return value;
  7290. }
  7291. template <bool IsFromFullJit, class TInlineCache>
  7292. inline void JavascriptOperators::PatchPutValue(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags)
  7293. {
  7294. JIT_HELPER_REENTRANT_HEADER(Op_PatchPutValue);
  7295. JIT_HELPER_SAME_ATTRIBUTES(Op_PatchPutValue, Op_PatchPutValueWithThisPtr);
  7296. return PatchPutValueWithThisPtr<IsFromFullJit, TInlineCache>(functionBody, inlineCache, inlineCacheIndex, instance, propertyId, newValue, instance, flags);
  7297. JIT_HELPER_END(Op_PatchPutValue);
  7298. }
  7299. JIT_HELPER_TEMPLATE(Op_PatchPutValue, Op_PatchPutValuePolymorphic)
  7300. template <bool IsFromFullJit, class TInlineCache>
  7301. inline void JavascriptOperators::PatchPutValueWithThisPtr(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags)
  7302. {
  7303. JIT_HELPER_REENTRANT_HEADER(Op_PatchPutValueWithThisPtr);
  7304. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  7305. if (TaggedNumber::Is(instance))
  7306. {
  7307. JavascriptOperators::SetPropertyOnTaggedNumber(instance, nullptr, propertyId, newValue, scriptContext, flags);
  7308. return;
  7309. }
  7310. #if ENABLE_COPYONACCESS_ARRAY
  7311. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  7312. #endif
  7313. RecyclableObject* object = RecyclableObject::FromVar(instance);
  7314. PropertyValueInfo info;
  7315. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  7316. if (CacheOperators::TrySetProperty<true, true, true, true, true, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false>(
  7317. object, false, propertyId, newValue, scriptContext, flags, nullptr, &info))
  7318. {
  7319. return;
  7320. }
  7321. #if DBG_DUMP
  7322. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  7323. {
  7324. CacheOperators::TraceCache(inlineCache, _u("PatchPutValue"), propertyId, scriptContext, object);
  7325. }
  7326. #endif
  7327. ImplicitCallFlags prevImplicitCallFlags = ImplicitCall_None;
  7328. ImplicitCallFlags currImplicitCallFlags = ImplicitCall_None;
  7329. bool hasThisOnlyStatements = functionBody->GetHasOnlyThisStmts();
  7330. if (hasThisOnlyStatements)
  7331. {
  7332. prevImplicitCallFlags = CacheAndClearImplicitBit(scriptContext);
  7333. }
  7334. if (!JavascriptOperators::OP_SetProperty(object, propertyId, newValue, scriptContext, &info, flags, thisInstance))
  7335. {
  7336. // Add implicit call flags, to bail out if field copy prop may propagate the wrong value.
  7337. scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_NoOpSet);
  7338. }
  7339. if (hasThisOnlyStatements)
  7340. {
  7341. currImplicitCallFlags = CheckAndUpdateFunctionBodyWithImplicitFlag(functionBody);
  7342. RestoreImplicitFlag(scriptContext, prevImplicitCallFlags, currImplicitCallFlags);
  7343. }
  7344. JIT_HELPER_END(Op_PatchPutValueWithThisPtr);
  7345. }
  7346. JIT_HELPER_TEMPLATE(Op_PatchPutValueWithThisPtr, Op_PatchPutValueWithThisPtrPolymorphic)
  7347. template void JavascriptOperators::PatchPutValue<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7348. template void JavascriptOperators::PatchPutValue<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7349. template void JavascriptOperators::PatchPutValue<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7350. template void JavascriptOperators::PatchPutValue<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7351. template <bool IsFromFullJit, class TInlineCache>
  7352. inline void JavascriptOperators::PatchPutRootValue(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags)
  7353. {
  7354. JIT_HELPER_REENTRANT_HEADER(Op_PatchPutRootValue);
  7355. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  7356. RecyclableObject* object = RecyclableObject::FromVar(instance);
  7357. PropertyValueInfo info;
  7358. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  7359. if (CacheOperators::TrySetProperty<true, true, true, true, false, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false>(
  7360. object, true, propertyId, newValue, scriptContext, flags, nullptr, &info))
  7361. {
  7362. return;
  7363. }
  7364. #if DBG_DUMP
  7365. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  7366. {
  7367. CacheOperators::TraceCache(inlineCache, _u("PatchPutRootValue"), propertyId, scriptContext, object);
  7368. }
  7369. #endif
  7370. ImplicitCallFlags prevImplicitCallFlags = ImplicitCall_None;
  7371. ImplicitCallFlags currImplicitCallFlags = ImplicitCall_None;
  7372. bool hasThisOnlyStatements = functionBody->GetHasOnlyThisStmts();
  7373. if (hasThisOnlyStatements)
  7374. {
  7375. prevImplicitCallFlags = CacheAndClearImplicitBit(scriptContext);
  7376. }
  7377. if (!JavascriptOperators::SetRootProperty(object, propertyId, newValue, &info, scriptContext, flags))
  7378. {
  7379. // Add implicit call flags, to bail out if field copy prop may propagate the wrong value.
  7380. scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_NoOpSet);
  7381. }
  7382. if (hasThisOnlyStatements)
  7383. {
  7384. currImplicitCallFlags = CheckAndUpdateFunctionBodyWithImplicitFlag(functionBody);
  7385. RestoreImplicitFlag(scriptContext, prevImplicitCallFlags, currImplicitCallFlags);
  7386. }
  7387. JIT_HELPER_END(Op_PatchPutRootValue);
  7388. }
  7389. JIT_HELPER_TEMPLATE(Op_PatchPutRootValue, Op_PatchPutRootValuePolymorphic)
  7390. template void JavascriptOperators::PatchPutRootValue<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7391. template void JavascriptOperators::PatchPutRootValue<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7392. template void JavascriptOperators::PatchPutRootValue<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7393. template void JavascriptOperators::PatchPutRootValue<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7394. template <bool IsFromFullJit, class TInlineCache>
  7395. inline void JavascriptOperators::PatchPutValueNoLocalFastPath(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags)
  7396. {
  7397. JIT_HELPER_REENTRANT_HEADER(Op_PatchPutValueNoLocalFastPath);
  7398. JIT_HELPER_SAME_ATTRIBUTES(Op_PatchPutValueNoLocalFastPath, Op_PatchPutValueWithThisPtrNoLocalFastPath);
  7399. PatchPutValueWithThisPtrNoLocalFastPath<IsFromFullJit, TInlineCache>(functionBody, inlineCache, inlineCacheIndex, instance, propertyId, newValue, instance, flags);
  7400. JIT_HELPER_END(Op_PatchPutValueNoLocalFastPath);
  7401. }
  7402. JIT_HELPER_TEMPLATE(Op_PatchPutValueNoLocalFastPath, Op_PatchPutValueNoLocalFastPathPolymorphic)
  7403. template void JavascriptOperators::PatchPutValueNoLocalFastPath<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7404. template void JavascriptOperators::PatchPutValueNoLocalFastPath<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7405. template void JavascriptOperators::PatchPutValueNoLocalFastPath<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7406. template void JavascriptOperators::PatchPutValueNoLocalFastPath<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7407. template <bool IsFromFullJit, class TInlineCache>
  7408. inline void JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPath(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags)
  7409. {
  7410. JIT_HELPER_REENTRANT_HEADER(Op_PatchPutValueWithThisPtrNoLocalFastPath);
  7411. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  7412. if (TaggedNumber::Is(instance))
  7413. {
  7414. JavascriptOperators::SetPropertyOnTaggedNumber(instance,
  7415. nullptr,
  7416. propertyId,
  7417. newValue,
  7418. scriptContext,
  7419. flags);
  7420. return;
  7421. }
  7422. #if ENABLE_COPYONACCESS_ARRAY
  7423. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  7424. #endif
  7425. RecyclableObject *object = RecyclableObject::UnsafeFromVar(instance);
  7426. PropertyValueInfo info;
  7427. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  7428. if (CacheOperators::TrySetProperty<!TInlineCache::IsPolymorphic, true, true, true, true, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false>(
  7429. object, false, propertyId, newValue, scriptContext, flags, nullptr, &info))
  7430. {
  7431. return;
  7432. }
  7433. #if DBG_DUMP
  7434. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  7435. {
  7436. CacheOperators::TraceCache(inlineCache, _u("PatchPutValueNoLocalFastPath"), propertyId, scriptContext, object);
  7437. }
  7438. #endif
  7439. ImplicitCallFlags prevImplicitCallFlags = ImplicitCall_None;
  7440. ImplicitCallFlags currImplicitCallFlags = ImplicitCall_None;
  7441. bool hasThisOnlyStatements = functionBody->GetHasOnlyThisStmts();
  7442. if (hasThisOnlyStatements)
  7443. {
  7444. prevImplicitCallFlags = CacheAndClearImplicitBit(scriptContext);
  7445. }
  7446. if (!JavascriptOperators::OP_SetProperty(instance, propertyId, newValue, scriptContext, &info, flags, thisInstance))
  7447. {
  7448. // Add implicit call flags, to bail out if field copy prop may propagate the wrong value.
  7449. scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_NoOpSet);
  7450. }
  7451. if (hasThisOnlyStatements)
  7452. {
  7453. currImplicitCallFlags = CheckAndUpdateFunctionBodyWithImplicitFlag(functionBody);
  7454. RestoreImplicitFlag(scriptContext, prevImplicitCallFlags, currImplicitCallFlags);
  7455. }
  7456. JIT_HELPER_END(Op_PatchPutValueWithThisPtrNoLocalFastPath);
  7457. }
  7458. JIT_HELPER_TEMPLATE(Op_PatchPutValueWithThisPtrNoLocalFastPath, Op_PatchPutValueWithThisPtrNoLocalFastPathPolymorphic)
  7459. template void JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPath<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags);
  7460. template void JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPath<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags);
  7461. template void JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPath<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags);
  7462. template void JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPath<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags);
  7463. template <bool IsFromFullJit, class TInlineCache>
  7464. inline void JavascriptOperators::PatchPutRootValueNoLocalFastPath(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags)
  7465. {
  7466. JIT_HELPER_REENTRANT_HEADER(Op_PatchPutRootValueNoLocalFastPath);
  7467. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  7468. RecyclableObject *object = RecyclableObject::FromVar(instance);
  7469. PropertyValueInfo info;
  7470. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  7471. if (CacheOperators::TrySetProperty<!TInlineCache::IsPolymorphic, true, true, true, false, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false>(
  7472. object, true, propertyId, newValue, scriptContext, flags, nullptr, &info))
  7473. {
  7474. return;
  7475. }
  7476. #if DBG_DUMP
  7477. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  7478. {
  7479. CacheOperators::TraceCache(inlineCache, _u("PatchPutRootValueNoLocalFastPath"), propertyId, scriptContext, object);
  7480. }
  7481. #endif
  7482. ImplicitCallFlags prevImplicitCallFlags = ImplicitCall_None;
  7483. ImplicitCallFlags currImplicitCallFlags = ImplicitCall_None;
  7484. bool hasThisOnlyStatements = functionBody->GetHasOnlyThisStmts();
  7485. if (hasThisOnlyStatements)
  7486. {
  7487. prevImplicitCallFlags = CacheAndClearImplicitBit(scriptContext);
  7488. }
  7489. if (!JavascriptOperators::SetRootProperty(object, propertyId, newValue, &info, scriptContext, flags))
  7490. {
  7491. // Add implicit call flags, to bail out if field copy prop may propagate the wrong value.
  7492. scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_NoOpSet);
  7493. }
  7494. if (hasThisOnlyStatements)
  7495. {
  7496. currImplicitCallFlags = CheckAndUpdateFunctionBodyWithImplicitFlag(functionBody);
  7497. RestoreImplicitFlag(scriptContext, prevImplicitCallFlags, currImplicitCallFlags);
  7498. }
  7499. JIT_HELPER_END(Op_PatchPutRootValueNoLocalFastPath);
  7500. }
  7501. JIT_HELPER_TEMPLATE(Op_PatchPutRootValueNoLocalFastPath, Op_PatchPutRootValueNoLocalFastPathPolymorphic)
  7502. template void JavascriptOperators::PatchPutRootValueNoLocalFastPath<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7503. template void JavascriptOperators::PatchPutRootValueNoLocalFastPath<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7504. template void JavascriptOperators::PatchPutRootValueNoLocalFastPath<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7505. template void JavascriptOperators::PatchPutRootValueNoLocalFastPath<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags);
  7506. void JavascriptOperators::PatchPutValueNoFastPath(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags)
  7507. {
  7508. PatchPutValueWithThisPtrNoFastPath(functionBody, inlineCache, inlineCacheIndex, instance, propertyId, newValue, instance, flags);
  7509. }
  7510. void JavascriptOperators::PatchPutValueWithThisPtrNoFastPath(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags)
  7511. {
  7512. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  7513. if (TaggedNumber::Is(instance))
  7514. {
  7515. JavascriptOperators::SetPropertyOnTaggedNumber(instance, nullptr, propertyId, newValue, scriptContext, flags);
  7516. return;
  7517. }
  7518. RecyclableObject* object = RecyclableObject::FromVar(instance);
  7519. PropertyValueInfo info;
  7520. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, true);
  7521. if (!JavascriptOperators::OP_SetProperty(object, propertyId, newValue, scriptContext, &info, flags, thisInstance))
  7522. {
  7523. // Add implicit call flags, to bail out if field copy prop may propagate the wrong value.
  7524. scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_NoOpSet);
  7525. }
  7526. }
  7527. void JavascriptOperators::PatchPutRootValueNoFastPath(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags)
  7528. {
  7529. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  7530. RecyclableObject* object = RecyclableObject::FromVar(instance);
  7531. PropertyValueInfo info;
  7532. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, true);
  7533. if (!JavascriptOperators::SetRootProperty(object, propertyId, newValue, &info, scriptContext, flags))
  7534. {
  7535. // Add implicit call flags, to bail out if field copy prop may propagate the wrong value.
  7536. scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_NoOpSet);
  7537. }
  7538. }
  7539. template <bool IsFromFullJit, class TInlineCache>
  7540. inline void JavascriptOperators::PatchInitValue(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue)
  7541. {
  7542. JIT_HELPER_REENTRANT_HEADER(Op_PatchInitValue);
  7543. ScriptContext *const scriptContext = functionBody->GetScriptContext();
  7544. const PropertyOperationFlags flags = newValue == NULL ? PropertyOperation_SpecialValue : PropertyOperation_None;
  7545. PropertyValueInfo info;
  7546. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, !IsFromFullJit);
  7547. if (CacheOperators::TrySetProperty<true, true, false, true, true, !TInlineCache::IsPolymorphic, TInlineCache::IsPolymorphic, false>(
  7548. object, false, propertyId, newValue, scriptContext, flags, nullptr, &info))
  7549. {
  7550. return;
  7551. }
  7552. #if DBG_DUMP
  7553. if (PHASE_VERBOSE_TRACE1(Js::InlineCachePhase))
  7554. {
  7555. CacheOperators::TraceCache(inlineCache, _u("PatchInitValue"), propertyId, scriptContext, object);
  7556. }
  7557. #endif
  7558. Type *typeWithoutProperty = object->GetType();
  7559. if (functionBody->IsEval())
  7560. {
  7561. if (object->InitPropertyInEval(propertyId, newValue, flags, &info))
  7562. {
  7563. CacheOperators::CachePropertyWrite(object, false, typeWithoutProperty, propertyId, &info, scriptContext);
  7564. return;
  7565. }
  7566. }
  7567. // Ideally the lowerer would emit a call to the right flavor of PatchInitValue, so that we can ensure that we only
  7568. // ever initialize to NULL in the right cases. But the backend uses the StFld opcode for initialization, and it
  7569. // would be cumbersome to thread the different helper calls all the way down
  7570. if (object->InitProperty(propertyId, newValue, flags, &info))
  7571. {
  7572. CacheOperators::CachePropertyWrite(object, false, typeWithoutProperty, propertyId, &info, scriptContext);
  7573. }
  7574. JIT_HELPER_END(Op_PatchInitValue);
  7575. }
  7576. JIT_HELPER_TEMPLATE(Op_PatchInitValue, Op_PatchInitValuePolymorphic)
  7577. template void JavascriptOperators::PatchInitValue<false, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue);
  7578. template void JavascriptOperators::PatchInitValue<true, InlineCache>(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue);
  7579. template void JavascriptOperators::PatchInitValue<false, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue);
  7580. template void JavascriptOperators::PatchInitValue<true, PolymorphicInlineCache>(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue);
  7581. void JavascriptOperators::PatchInitValueNoFastPath(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue)
  7582. {
  7583. PropertyValueInfo info;
  7584. PropertyValueInfo::SetCacheInfo(&info, functionBody, inlineCache, inlineCacheIndex, true);
  7585. Type *typeWithoutProperty = object->GetType();
  7586. if (functionBody->IsEval())
  7587. {
  7588. if (object->InitPropertyInEval(propertyId, newValue, PropertyOperation_None, &info))
  7589. {
  7590. CacheOperators::CachePropertyWrite(object, false, typeWithoutProperty, propertyId, &info, functionBody->GetScriptContext());
  7591. return;
  7592. }
  7593. }
  7594. if (object->InitProperty(propertyId, newValue, PropertyOperation_None, &info))
  7595. {
  7596. CacheOperators::CachePropertyWrite(object, false, typeWithoutProperty, propertyId, &info, functionBody->GetScriptContext());
  7597. }
  7598. }
  7599. void JavascriptOperators::GetPropertyIdForInt(uint64 value, ScriptContext* scriptContext, PropertyRecord const ** propertyRecord)
  7600. {
  7601. char16 buffer[20];
  7602. ::_ui64tow_s(value, buffer, sizeof(buffer)/sizeof(char16), 10);
  7603. scriptContext->GetOrAddPropertyRecord(buffer, JavascriptString::GetBufferLength(buffer), propertyRecord);
  7604. }
  7605. void JavascriptOperators::GetPropertyIdForInt(uint32 value, ScriptContext* scriptContext, PropertyRecord const ** propertyRecord)
  7606. {
  7607. GetPropertyIdForInt(static_cast<uint64>(value), scriptContext, propertyRecord);
  7608. }
  7609. Var JavascriptOperators::FromPropertyDescriptor(const PropertyDescriptor& descriptor, ScriptContext* scriptContext)
  7610. {
  7611. DynamicObject* object = scriptContext->GetLibrary()->CreateObject();
  7612. // ES5 Section 8.10.4 specifies the order for adding these properties.
  7613. if (descriptor.IsDataDescriptor())
  7614. {
  7615. if (descriptor.ValueSpecified())
  7616. {
  7617. JavascriptOperators::InitProperty(object, PropertyIds::value, descriptor.GetValue());
  7618. }
  7619. JavascriptOperators::InitProperty(object, PropertyIds::writable, JavascriptBoolean::ToVar(descriptor.IsWritable(),scriptContext));
  7620. }
  7621. else if (descriptor.IsAccessorDescriptor())
  7622. {
  7623. JavascriptOperators::InitProperty(object, PropertyIds::get, JavascriptOperators::CanonicalizeAccessor(descriptor.GetGetter(), scriptContext));
  7624. JavascriptOperators::InitProperty(object, PropertyIds::set, JavascriptOperators::CanonicalizeAccessor(descriptor.GetSetter(), scriptContext));
  7625. }
  7626. if (descriptor.EnumerableSpecified())
  7627. {
  7628. JavascriptOperators::InitProperty(object, PropertyIds::enumerable, JavascriptBoolean::ToVar(descriptor.IsEnumerable(), scriptContext));
  7629. }
  7630. if (descriptor.ConfigurableSpecified())
  7631. {
  7632. JavascriptOperators::InitProperty(object, PropertyIds::configurable, JavascriptBoolean::ToVar(descriptor.IsConfigurable(), scriptContext));
  7633. }
  7634. return object;
  7635. }
  7636. // ES5 8.12.9 [[DefineOwnProperty]].
  7637. // Return value:
  7638. // - TRUE = success.
  7639. // - FALSE (can throw depending on throwOnError parameter) = unsuccessful.
  7640. BOOL JavascriptOperators::DefineOwnPropertyDescriptor(RecyclableObject* obj, PropertyId propId, const PropertyDescriptor& descriptor, bool throwOnError, ScriptContext* scriptContext)
  7641. {
  7642. Assert(obj);
  7643. Assert(scriptContext);
  7644. if (JavascriptProxy::Is(obj))
  7645. {
  7646. return JavascriptProxy::DefineOwnPropertyDescriptor(obj, propId, descriptor, throwOnError, scriptContext);
  7647. }
  7648. PropertyDescriptor currentDescriptor;
  7649. BOOL isCurrentDescriptorDefined = JavascriptOperators::GetOwnPropertyDescriptor(obj, propId, scriptContext, &currentDescriptor);
  7650. bool isExtensible = !!obj->IsExtensible();
  7651. return ValidateAndApplyPropertyDescriptor<true>(obj, propId, descriptor, isCurrentDescriptorDefined ? &currentDescriptor : nullptr, isExtensible, throwOnError, scriptContext);
  7652. }
  7653. BOOL JavascriptOperators::IsCompatiblePropertyDescriptor(const PropertyDescriptor& descriptor, PropertyDescriptor* currentDescriptor, bool isExtensible, bool throwOnError, ScriptContext* scriptContext)
  7654. {
  7655. return ValidateAndApplyPropertyDescriptor<false>(nullptr, Constants::NoProperty, descriptor, currentDescriptor, isExtensible, throwOnError, scriptContext);
  7656. }
  7657. template<bool needToSetProperty>
  7658. BOOL JavascriptOperators::ValidateAndApplyPropertyDescriptor(RecyclableObject* obj, PropertyId propId, const PropertyDescriptor& descriptor,
  7659. PropertyDescriptor* currentDescriptor, bool isExtensible, bool throwOnError, ScriptContext* scriptContext)
  7660. {
  7661. Var defaultDataValue = scriptContext->GetLibrary()->GetUndefined();
  7662. Var defaultAccessorValue = scriptContext->GetLibrary()->GetDefaultAccessorFunction();
  7663. if (currentDescriptor == nullptr)
  7664. {
  7665. if (!isExtensible) // ES5 8.12.9.3.
  7666. {
  7667. return Reject(throwOnError, scriptContext, JSERR_DefineProperty_NotExtensible, propId);
  7668. }
  7669. else // ES5 8.12.9.4.
  7670. {
  7671. if (needToSetProperty)
  7672. {
  7673. if (descriptor.IsGenericDescriptor() || descriptor.IsDataDescriptor())
  7674. {
  7675. // ES5 8.12.9.4a: Create an own data property named P of object O whose [[Value]], [[Writable]],
  7676. // [[Enumerable]] and [[Configurable]] attribute values are described by Desc.
  7677. // If the value of an attribute field of Desc is absent, the attribute of the newly created property
  7678. // is set to its default value.
  7679. PropertyDescriptor filledDescriptor = FillMissingPropertyDescriptorFields<false>(descriptor, scriptContext);
  7680. BOOL tempResult = obj->SetPropertyWithAttributes(propId, filledDescriptor.GetValue(), filledDescriptor.GetAttributes(), nullptr);
  7681. if (!obj->IsExternal() && !tempResult)
  7682. {
  7683. Assert(TypedArrayBase::Is(obj)); // typed array returns false when canonical numeric index is not integer or out of range
  7684. return FALSE;
  7685. }
  7686. }
  7687. else
  7688. {
  7689. // ES5 8.12.9.4b: Create an own accessor property named P of object O whose [[Get]], [[Set]], [[Enumerable]]
  7690. // and [[Configurable]] attribute values are described by Desc. If the value of an attribute field of Desc is absent,
  7691. // the attribute of the newly created property is set to its default value.
  7692. Assert(descriptor.IsAccessorDescriptor());
  7693. PropertyDescriptor filledDescriptor = FillMissingPropertyDescriptorFields<true>(descriptor, scriptContext);
  7694. BOOL isSetAccessorsSuccess = obj->SetAccessors(propId, filledDescriptor.GetGetter(), filledDescriptor.GetSetter());
  7695. // It is valid for some objects to not-support getters and setters, specifically, for projection of an ABI method
  7696. // (CustomExternalObject => MapWithStringKey) which SetAccessors returns VBSErr_ActionNotSupported.
  7697. // But for non-external objects SetAccessors should succeed.
  7698. Assert(isSetAccessorsSuccess || obj->IsExternal());
  7699. // If SetAccessors failed, the property wasn't created, so no need to change the attributes.
  7700. if (isSetAccessorsSuccess)
  7701. {
  7702. JavascriptOperators::SetAttributes(obj, propId, filledDescriptor, true); // use 'force' as default attributes in type system are different from ES5.
  7703. }
  7704. }
  7705. }
  7706. return TRUE;
  7707. }
  7708. }
  7709. // ES5 8.12.9.5: Return true, if every field in Desc is absent.
  7710. if (!descriptor.ConfigurableSpecified() && !descriptor.EnumerableSpecified() && !descriptor.WritableSpecified() &&
  7711. !descriptor.ValueSpecified() && !descriptor.GetterSpecified() && !descriptor.SetterSpecified())
  7712. {
  7713. return TRUE;
  7714. }
  7715. // ES5 8.12.9.6: Return true, if every field in Desc also occurs in current and the value of every field in Desc is the same value
  7716. // as the corresponding field in current when compared using the SameValue algorithm (9.12).
  7717. PropertyDescriptor filledDescriptor = descriptor.IsAccessorDescriptor() ? FillMissingPropertyDescriptorFields<true>(descriptor, scriptContext)
  7718. : FillMissingPropertyDescriptorFields<false>(descriptor, scriptContext);
  7719. if (JavascriptOperators::AreSamePropertyDescriptors(&filledDescriptor, currentDescriptor, scriptContext))
  7720. {
  7721. return TRUE;
  7722. }
  7723. if (!currentDescriptor->IsConfigurable()) // ES5 8.12.9.7.
  7724. {
  7725. if (descriptor.ConfigurableSpecified() && descriptor.IsConfigurable())
  7726. {
  7727. return Reject(throwOnError, scriptContext, JSERR_DefineProperty_NotConfigurable, propId);
  7728. }
  7729. if (descriptor.EnumerableSpecified() && descriptor.IsEnumerable() != currentDescriptor->IsEnumerable())
  7730. {
  7731. return Reject(throwOnError, scriptContext, JSERR_DefineProperty_NotConfigurable, propId);
  7732. }
  7733. }
  7734. // Whether to merge attributes from tempDescriptor into descriptor to keep original values
  7735. // of some attributes from the object/use tempDescriptor for SetAttributes, or just use descriptor.
  7736. // This is optimization to avoid 2 calls to SetAttributes.
  7737. bool mergeDescriptors = false;
  7738. // Whether to call SetAttributes with 'force' flag which forces setting all attributes
  7739. // rather than only specified or which have true values.
  7740. // This is to make sure that the object has correct attributes, as default values in the object are not for ES5.
  7741. bool forceSetAttributes = false;
  7742. PropertyDescriptor tempDescriptor;
  7743. // ES5 8.12.9.8: If IsGenericDescriptor(Desc) is true, then no further validation is required.
  7744. if (!descriptor.IsGenericDescriptor())
  7745. {
  7746. if (currentDescriptor->IsDataDescriptor() != descriptor.IsDataDescriptor())
  7747. {
  7748. // ES5 8.12.9.9: Else, if IsDataDescriptor(current) and IsDataDescriptor(Desc) have different results...
  7749. if (!currentDescriptor->IsConfigurable())
  7750. {
  7751. return Reject(throwOnError, scriptContext, JSERR_DefineProperty_NotConfigurable, propId);
  7752. }
  7753. if (needToSetProperty)
  7754. {
  7755. if (currentDescriptor->IsDataDescriptor())
  7756. {
  7757. // ES5 8.12.9.9.b: Convert the property named P of object O from a data property to an accessor property.
  7758. // Preserve the existing values of the converted property's [[Configurable]] and [[Enumerable]] attributes
  7759. // and set the rest of the property's attributes to their default values.
  7760. PropertyAttributes preserveFromObject = currentDescriptor->GetAttributes() & (PropertyConfigurable | PropertyEnumerable);
  7761. BOOL isSetAccessorsSuccess = obj->SetAccessors(propId, defaultAccessorValue, defaultAccessorValue);
  7762. // It is valid for some objects to not-support getters and setters, specifically, for projection of an ABI method
  7763. // (CustomExternalObject => MapWithStringKey) which SetAccessors returns VBSErr_ActionNotSupported.
  7764. // But for non-external objects SetAccessors should succeed.
  7765. Assert(isSetAccessorsSuccess || obj->IsExternal());
  7766. if (isSetAccessorsSuccess)
  7767. {
  7768. tempDescriptor.SetAttributes(preserveFromObject, PropertyConfigurable | PropertyEnumerable);
  7769. forceSetAttributes = true; // use SetAttrbiutes with 'force' as default attributes in type system are different from ES5.
  7770. mergeDescriptors = true;
  7771. }
  7772. }
  7773. else
  7774. {
  7775. // ES5 8.12.9.9.c: Convert the property named P of object O from an accessor property to a data property.
  7776. // Preserve the existing values of the converted property's [[Configurable]] and [[Enumerable]] attributes
  7777. // and set the rest of the property's attributes to their default values.
  7778. // Note: avoid using SetProperty/SetPropertyWithAttributes here because they has undesired side-effects:
  7779. // it calls previous setter and in some cases of attribute values throws.
  7780. // To walk around, call DeleteProperty and then AddProperty.
  7781. PropertyAttributes preserveFromObject = currentDescriptor->GetAttributes() & (PropertyConfigurable | PropertyEnumerable);
  7782. tempDescriptor.SetAttributes(preserveFromObject, PropertyConfigurable | PropertyEnumerable);
  7783. tempDescriptor.MergeFrom(descriptor); // Update only fields specified in 'descriptor'.
  7784. Var descriptorValue = descriptor.ValueSpecified() ? descriptor.GetValue() : defaultDataValue;
  7785. // Note: HostDispath'es implementation of DeleteProperty currently throws E_NOTIMPL.
  7786. obj->DeleteProperty(propId, PropertyOperation_None);
  7787. BOOL tempResult = obj->SetPropertyWithAttributes(propId, descriptorValue, tempDescriptor.GetAttributes(), NULL, PropertyOperation_Force);
  7788. Assert(tempResult);
  7789. // At this time we already set value and attributes to desired values,
  7790. // thus we can skip step ES5 8.12.9.12 and simply return true.
  7791. return TRUE;
  7792. }
  7793. }
  7794. }
  7795. else if (currentDescriptor->IsDataDescriptor() && descriptor.IsDataDescriptor())
  7796. {
  7797. // ES5 8.12.9.10: Else, if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true...
  7798. if (!currentDescriptor->IsConfigurable())
  7799. {
  7800. if (!currentDescriptor->IsWritable())
  7801. {
  7802. if (descriptor.WritableSpecified() && descriptor.IsWritable()) // ES5 8.12.9.10.a.i
  7803. {
  7804. return Reject(throwOnError, scriptContext, JSERR_DefineProperty_NotConfigurable, propId);
  7805. }
  7806. else if (descriptor.ValueSpecified() &&
  7807. !JavascriptConversion::SameValue(descriptor.GetValue(), currentDescriptor->GetValue())) // ES5 8.12.9.10.a.ii
  7808. {
  7809. return Reject(throwOnError, scriptContext, JSERR_DefineProperty_NotWritable, propId);
  7810. }
  7811. }
  7812. }
  7813. // ES5 8.12.9.10.b: else, the [[Configurable]] field of current is true, so any change is acceptable.
  7814. }
  7815. else
  7816. {
  7817. // ES5 8.12.9.11: Else, IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true, so...
  7818. Assert(currentDescriptor->IsAccessorDescriptor() && descriptor.IsAccessorDescriptor());
  7819. if (!currentDescriptor->IsConfigurable())
  7820. {
  7821. if ((descriptor.SetterSpecified() &&
  7822. !JavascriptConversion::SameValue(
  7823. JavascriptOperators::CanonicalizeAccessor(descriptor.GetSetter(), scriptContext),
  7824. JavascriptOperators::CanonicalizeAccessor(currentDescriptor->GetSetter(), scriptContext))) ||
  7825. (descriptor.GetterSpecified() &&
  7826. !JavascriptConversion::SameValue(
  7827. JavascriptOperators::CanonicalizeAccessor(descriptor.GetGetter(), scriptContext),
  7828. JavascriptOperators::CanonicalizeAccessor(currentDescriptor->GetGetter(), scriptContext))))
  7829. {
  7830. return Reject(throwOnError, scriptContext, JSERR_DefineProperty_NotConfigurable, propId);
  7831. }
  7832. }
  7833. }
  7834. // This part is only for non-generic descriptors:
  7835. // ES5 8.12.9.12: For each attribute field of Desc that is present,
  7836. // set the correspondingly named attribute of the property named P of object O to the value of the field.
  7837. if (descriptor.IsDataDescriptor())
  7838. {
  7839. if (descriptor.ValueSpecified() && needToSetProperty)
  7840. {
  7841. // Set just the value by passing the current attributes of the property.
  7842. // If the property's attributes are also changing (perhaps becoming non-writable),
  7843. // this will be taken care of in the call to JavascriptOperators::SetAttributes below.
  7844. // Built-in Function.prototype properties 'length', 'arguments', and 'caller' are special cases.
  7845. BOOL tempResult = obj->SetPropertyWithAttributes(propId, descriptor.GetValue(), currentDescriptor->GetAttributes(), nullptr);
  7846. AssertMsg(tempResult || JavascriptFunction::IsBuiltinProperty(obj, propId), "If you hit this assert, most likely there is something wrong with the object/type.");
  7847. }
  7848. }
  7849. else if (descriptor.IsAccessorDescriptor() && needToSetProperty)
  7850. {
  7851. Assert(descriptor.GetterSpecified() || descriptor.SetterSpecified());
  7852. Var oldGetter = defaultAccessorValue, oldSetter = defaultAccessorValue;
  7853. if (!descriptor.GetterSpecified() || !descriptor.SetterSpecified())
  7854. {
  7855. // Unless both getter and setter are specified, make sure we don't overwrite old accessor.
  7856. #pragma prefast(suppress:6031, "We defaulted oldGetter and oldSetter already, so ignoring the return value here is safe")
  7857. obj->GetAccessors(propId, &oldGetter, &oldSetter, scriptContext);
  7858. }
  7859. Var getter = descriptor.GetterSpecified() ? descriptor.GetGetter() : oldGetter;
  7860. Var setter = descriptor.SetterSpecified() ? descriptor.GetSetter() : oldSetter;
  7861. obj->SetAccessors(propId, getter, setter);
  7862. }
  7863. } // if (!descriptor.IsGenericDescriptor())
  7864. // Continue for all descriptors including generic:
  7865. // ES5 8.12.9.12: For each attribute field of Desc that is present,
  7866. // set the correspondingly named attribute of the property named P of object O to the value of the field.
  7867. if (needToSetProperty)
  7868. {
  7869. if (mergeDescriptors)
  7870. {
  7871. tempDescriptor.MergeFrom(descriptor);
  7872. JavascriptOperators::SetAttributes(obj, propId, tempDescriptor, forceSetAttributes);
  7873. }
  7874. else
  7875. {
  7876. JavascriptOperators::SetAttributes(obj, propId, descriptor, forceSetAttributes);
  7877. }
  7878. }
  7879. return TRUE;
  7880. }
  7881. template <bool isAccessor>
  7882. PropertyDescriptor JavascriptOperators::FillMissingPropertyDescriptorFields(PropertyDescriptor descriptor, ScriptContext* scriptContext)
  7883. {
  7884. PropertyDescriptor newDescriptor;
  7885. const PropertyDescriptor* defaultDescriptor = scriptContext->GetLibrary()->GetDefaultPropertyDescriptor();
  7886. if (isAccessor)
  7887. {
  7888. newDescriptor.SetGetter(descriptor.GetterSpecified() ? descriptor.GetGetter() : defaultDescriptor->GetGetter());
  7889. newDescriptor.SetSetter(descriptor.SetterSpecified() ? descriptor.GetSetter() : defaultDescriptor->GetSetter());
  7890. }
  7891. else
  7892. {
  7893. newDescriptor.SetValue(descriptor.ValueSpecified() ? descriptor.GetValue() : defaultDescriptor->GetValue());
  7894. newDescriptor.SetWritable(descriptor.WritableSpecified() ? descriptor.IsWritable() : defaultDescriptor->IsWritable());
  7895. }
  7896. newDescriptor.SetConfigurable(descriptor.ConfigurableSpecified() ? descriptor.IsConfigurable() : defaultDescriptor->IsConfigurable());
  7897. newDescriptor.SetEnumerable(descriptor.EnumerableSpecified() ? descriptor.IsEnumerable() : defaultDescriptor->IsEnumerable());
  7898. return newDescriptor;
  7899. }
  7900. // ES5: 15.4.5.1
  7901. BOOL JavascriptOperators::DefineOwnPropertyForArray(JavascriptArray* arr, PropertyId propId, const PropertyDescriptor& descriptor, bool throwOnError, ScriptContext* scriptContext)
  7902. {
  7903. if (propId == PropertyIds::length)
  7904. {
  7905. if (!descriptor.ValueSpecified())
  7906. {
  7907. return DefineOwnPropertyDescriptor(arr, PropertyIds::length, descriptor, throwOnError, scriptContext);
  7908. }
  7909. PropertyDescriptor newLenDesc = descriptor;
  7910. uint32 newLen = ES5Array::ToLengthValue(descriptor.GetValue(), scriptContext);
  7911. newLenDesc.SetValue(JavascriptNumber::ToVar(newLen, scriptContext));
  7912. uint32 oldLen = arr->GetLength();
  7913. if (newLen >= oldLen)
  7914. {
  7915. return DefineOwnPropertyDescriptor(arr, PropertyIds::length, newLenDesc, throwOnError, scriptContext);
  7916. }
  7917. BOOL oldLenWritable = arr->IsWritable(PropertyIds::length);
  7918. if (!oldLenWritable)
  7919. {
  7920. return Reject(throwOnError, scriptContext, JSERR_DefineProperty_NotWritable, propId);
  7921. }
  7922. bool newWritable = (!newLenDesc.WritableSpecified() || newLenDesc.IsWritable());
  7923. if (!newWritable)
  7924. {
  7925. // Need to defer setting writable to false in case any elements cannot be deleted
  7926. newLenDesc.SetWritable(true);
  7927. }
  7928. BOOL succeeded = DefineOwnPropertyDescriptor(arr, PropertyIds::length, newLenDesc, throwOnError, scriptContext);
  7929. //
  7930. // Our SetProperty(length) is also responsible to trim elements. When succeeded is
  7931. //
  7932. // false:
  7933. // * length attributes rejected
  7934. // * elements not touched
  7935. // true:
  7936. // * length attributes are set successfully
  7937. // * elements trimming may be either completed or incompleted, length value is correct
  7938. //
  7939. // * Strict mode TODO: Currently SetProperty(length) does not throw. If that throws, we need
  7940. // to update here to set correct newWritable even on exception.
  7941. //
  7942. if (!succeeded)
  7943. {
  7944. return false;
  7945. }
  7946. if (!newWritable) // Now set requested newWritable.
  7947. {
  7948. PropertyDescriptor newWritableDesc;
  7949. newWritableDesc.SetWritable(false);
  7950. DefineOwnPropertyDescriptor(arr, PropertyIds::length, newWritableDesc, false, scriptContext);
  7951. }
  7952. if (arr->GetLength() > newLen) // Delete incompleted
  7953. {
  7954. // Since SetProperty(length) not throwing, we'll reject here
  7955. return Reject(throwOnError, scriptContext, JSERR_DefineProperty_Default, propId);
  7956. }
  7957. return true;
  7958. }
  7959. uint32 index;
  7960. if (scriptContext->IsNumericPropertyId(propId, &index))
  7961. {
  7962. if (index >= arr->GetLength() && !arr->IsWritable(PropertyIds::length))
  7963. {
  7964. return Reject(throwOnError, scriptContext, JSERR_DefineProperty_LengthNotWritable, propId);
  7965. }
  7966. BOOL succeeded = DefineOwnPropertyDescriptor(arr, propId, descriptor, false, scriptContext);
  7967. if (!succeeded)
  7968. {
  7969. return Reject(throwOnError, scriptContext, JSERR_DefineProperty_Default, propId);
  7970. }
  7971. // Out SetItem takes care of growing "length". we are done.
  7972. return true;
  7973. }
  7974. return DefineOwnPropertyDescriptor(arr, propId, descriptor, throwOnError, scriptContext);
  7975. }
  7976. BOOL JavascriptOperators::SetPropertyDescriptor(RecyclableObject* object, PropertyId propId, const PropertyDescriptor& descriptor)
  7977. {
  7978. if (descriptor.ValueSpecified())
  7979. {
  7980. ScriptContext* requestContext = object->GetScriptContext(); // Real requestContext?
  7981. JavascriptOperators::SetProperty(object, object, propId, descriptor.GetValue(), requestContext);
  7982. }
  7983. else if (descriptor.GetterSpecified() || descriptor.SetterSpecified())
  7984. {
  7985. JavascriptOperators::SetAccessors(object, propId, descriptor.GetGetter(), descriptor.GetSetter());
  7986. }
  7987. if (descriptor.EnumerableSpecified())
  7988. {
  7989. object->SetEnumerable(propId, descriptor.IsEnumerable());
  7990. }
  7991. if (descriptor.ConfigurableSpecified())
  7992. {
  7993. object->SetConfigurable(propId, descriptor.IsConfigurable());
  7994. }
  7995. if (descriptor.WritableSpecified())
  7996. {
  7997. object->SetWritable(propId, descriptor.IsWritable());
  7998. }
  7999. return true;
  8000. }
  8001. BOOL JavascriptOperators::ToPropertyDescriptorForProxyObjects(Var propertySpec, PropertyDescriptor* descriptor, ScriptContext* scriptContext)
  8002. {
  8003. if (!JavascriptOperators::IsObject(propertySpec))
  8004. {
  8005. return FALSE;
  8006. }
  8007. Var value;
  8008. RecyclableObject* propertySpecObj = RecyclableObject::FromVar(propertySpec);
  8009. if (JavascriptOperators::HasProperty(propertySpecObj, PropertyIds::enumerable) == TRUE)
  8010. {
  8011. if (JavascriptOperators::GetProperty(propertySpecObj, PropertyIds::enumerable, &value, scriptContext))
  8012. {
  8013. descriptor->SetEnumerable(JavascriptConversion::ToBoolean(value, scriptContext) ? true : false);
  8014. }
  8015. else
  8016. {
  8017. // The proxy said we have the property, so we try to read the property and get the default value.
  8018. descriptor->SetEnumerable(false);
  8019. }
  8020. }
  8021. if (JavascriptOperators::HasProperty(propertySpecObj, PropertyIds::configurable) == TRUE)
  8022. {
  8023. if (JavascriptOperators::GetProperty(propertySpecObj, PropertyIds::configurable, &value, scriptContext))
  8024. {
  8025. descriptor->SetConfigurable(JavascriptConversion::ToBoolean(value, scriptContext) ? true : false);
  8026. }
  8027. else
  8028. {
  8029. // The proxy said we have the property, so we try to read the property and get the default value.
  8030. descriptor->SetConfigurable(false);
  8031. }
  8032. }
  8033. if (JavascriptOperators::HasProperty(propertySpecObj, PropertyIds::value) == TRUE)
  8034. {
  8035. if (JavascriptOperators::GetProperty(propertySpecObj, PropertyIds::value, &value, scriptContext))
  8036. {
  8037. descriptor->SetValue(value);
  8038. }
  8039. else
  8040. {
  8041. // The proxy said we have the property, so we try to read the property and get the default value.
  8042. descriptor->SetValue(scriptContext->GetLibrary()->GetUndefined());
  8043. }
  8044. }
  8045. if (JavascriptOperators::HasProperty(propertySpecObj, PropertyIds::writable) == TRUE)
  8046. {
  8047. if (JavascriptOperators::GetProperty(propertySpecObj, PropertyIds::writable, &value, scriptContext))
  8048. {
  8049. descriptor->SetWritable(JavascriptConversion::ToBoolean(value, scriptContext) ? true : false);
  8050. }
  8051. else
  8052. {
  8053. // The proxy said we have the property, so we try to read the property and get the default value.
  8054. descriptor->SetWritable(false);
  8055. }
  8056. }
  8057. if (JavascriptOperators::HasProperty(propertySpecObj, PropertyIds::get) == TRUE)
  8058. {
  8059. if (JavascriptOperators::GetProperty(propertySpecObj, PropertyIds::get, &value, scriptContext))
  8060. {
  8061. if (JavascriptOperators::GetTypeId(value) != TypeIds_Undefined && (false == JavascriptConversion::IsCallable(value)))
  8062. {
  8063. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction, scriptContext->GetPropertyName(PropertyIds::get)->GetBuffer());
  8064. }
  8065. descriptor->SetGetter(value);
  8066. }
  8067. else
  8068. {
  8069. // The proxy said we have the property, so we try to read the property and get the default value.
  8070. descriptor->SetGetter(scriptContext->GetLibrary()->GetUndefined());
  8071. }
  8072. }
  8073. if (JavascriptOperators::HasProperty(propertySpecObj, PropertyIds::set) == TRUE)
  8074. {
  8075. if (JavascriptOperators::GetProperty(propertySpecObj, PropertyIds::set, &value, scriptContext))
  8076. {
  8077. if (JavascriptOperators::GetTypeId(value) != TypeIds_Undefined && (false == JavascriptConversion::IsCallable(value)))
  8078. {
  8079. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction, scriptContext->GetPropertyName(PropertyIds::set)->GetBuffer());
  8080. }
  8081. descriptor->SetSetter(value);
  8082. }
  8083. else
  8084. {
  8085. // The proxy said we have the property, so we try to read the property and get the default value.
  8086. descriptor->SetSetter(scriptContext->GetLibrary()->GetUndefined());
  8087. }
  8088. }
  8089. return TRUE;
  8090. }
  8091. BOOL JavascriptOperators::ToPropertyDescriptorForGenericObjects(Var propertySpec, PropertyDescriptor* descriptor, ScriptContext* scriptContext)
  8092. {
  8093. if (!JavascriptOperators::IsObject(propertySpec))
  8094. {
  8095. return FALSE;
  8096. }
  8097. Var value;
  8098. RecyclableObject* propertySpecObj = RecyclableObject::FromVar(propertySpec);
  8099. if (JavascriptOperators::GetPropertyNoCache(propertySpecObj, PropertyIds::enumerable, &value, scriptContext))
  8100. {
  8101. descriptor->SetEnumerable(JavascriptConversion::ToBoolean(value, scriptContext) ? true : false);
  8102. }
  8103. if (JavascriptOperators::GetPropertyNoCache(propertySpecObj, PropertyIds::configurable, &value, scriptContext))
  8104. {
  8105. descriptor->SetConfigurable(JavascriptConversion::ToBoolean(value, scriptContext) ? true : false);
  8106. }
  8107. if (JavascriptOperators::GetPropertyNoCache(propertySpecObj, PropertyIds::value, &value, scriptContext))
  8108. {
  8109. descriptor->SetValue(value);
  8110. }
  8111. if (JavascriptOperators::GetPropertyNoCache(propertySpecObj, PropertyIds::writable, &value, scriptContext))
  8112. {
  8113. descriptor->SetWritable(JavascriptConversion::ToBoolean(value, scriptContext) ? true : false);
  8114. }
  8115. if (JavascriptOperators::GetPropertyNoCache(propertySpecObj, PropertyIds::get, &value, scriptContext))
  8116. {
  8117. if (JavascriptOperators::GetTypeId(value) != TypeIds_Undefined && (false == JavascriptConversion::IsCallable(value)))
  8118. {
  8119. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction, scriptContext->GetPropertyName(PropertyIds::get)->GetBuffer());
  8120. }
  8121. descriptor->SetGetter(value);
  8122. }
  8123. if (JavascriptOperators::GetPropertyNoCache(propertySpecObj, PropertyIds::set, &value, scriptContext))
  8124. {
  8125. if (JavascriptOperators::GetTypeId(value) != TypeIds_Undefined && (false == JavascriptConversion::IsCallable(value)))
  8126. {
  8127. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction, scriptContext->GetPropertyName(PropertyIds::set)->GetBuffer());
  8128. }
  8129. descriptor->SetSetter(value);
  8130. }
  8131. return TRUE;
  8132. }
  8133. BOOL JavascriptOperators::ToPropertyDescriptor(Var propertySpec, PropertyDescriptor* descriptor, ScriptContext* scriptContext)
  8134. {
  8135. if (JavascriptProxy::Is(propertySpec) || (
  8136. RecyclableObject::Is(propertySpec) &&
  8137. JavascriptOperators::CheckIfPrototypeChainContainsProxyObject(RecyclableObject::FromVar(propertySpec)->GetPrototype())))
  8138. {
  8139. if (ToPropertyDescriptorForProxyObjects(propertySpec, descriptor, scriptContext) == FALSE)
  8140. {
  8141. return FALSE;
  8142. }
  8143. }
  8144. else
  8145. {
  8146. if (ToPropertyDescriptorForGenericObjects(propertySpec, descriptor, scriptContext) == FALSE)
  8147. {
  8148. return FALSE;
  8149. }
  8150. }
  8151. if (descriptor->GetterSpecified() || descriptor->SetterSpecified())
  8152. {
  8153. if (descriptor->ValueSpecified())
  8154. {
  8155. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_CannotHaveAccessorsAndValue);
  8156. }
  8157. if (descriptor->WritableSpecified())
  8158. {
  8159. int32 hCode = descriptor->IsWritable() ? JSERR_InvalidAttributeTrue : JSERR_InvalidAttributeFalse;
  8160. JavascriptError::ThrowTypeError(scriptContext, hCode, _u("writable"));
  8161. }
  8162. }
  8163. descriptor->SetOriginal(propertySpec);
  8164. return TRUE;
  8165. }
  8166. void JavascriptOperators::CompletePropertyDescriptor(PropertyDescriptor* resultDescriptor, PropertyDescriptor* likeDescriptor, ScriptContext* requestContext)
  8167. {
  8168. const PropertyDescriptor* likePropertyDescriptor = likeDescriptor;
  8169. // 1. Assert: LikeDesc is either a Property Descriptor or undefined.
  8170. // 2. ReturnIfAbrupt(Desc).
  8171. // 3. Assert : Desc is a Property Descriptor
  8172. // 4. If LikeDesc is undefined, then set LikeDesc to Record{ [[Value]]: undefined, [[Writable]] : false, [[Get]] : undefined, [[Set]] : undefined, [[Enumerable]] : false, [[Configurable]] : false }.
  8173. if (likePropertyDescriptor == nullptr)
  8174. {
  8175. likePropertyDescriptor = requestContext->GetLibrary()->GetDefaultPropertyDescriptor();
  8176. }
  8177. // 5. If either IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then
  8178. if (resultDescriptor->IsDataDescriptor() || resultDescriptor->IsGenericDescriptor())
  8179. {
  8180. // a.If Desc does not have a[[Value]] field, then set Desc.[[Value]] to LikeDesc.[[Value]].
  8181. // b.If Desc does not have a[[Writable]] field, then set Desc.[[Writable]] to LikeDesc.[[Writable]].
  8182. if (!resultDescriptor->ValueSpecified())
  8183. {
  8184. resultDescriptor->SetValue(likePropertyDescriptor->GetValue());
  8185. }
  8186. if (!resultDescriptor->WritableSpecified())
  8187. {
  8188. resultDescriptor->SetWritable(likePropertyDescriptor->IsWritable());
  8189. }
  8190. }
  8191. else
  8192. {
  8193. // 6. Else,
  8194. // a.If Desc does not have a[[Get]] field, then set Desc.[[Get]] to LikeDesc.[[Get]].
  8195. // b.If Desc does not have a[[Set]] field, then set Desc.[[Set]] to LikeDesc.[[Set]].
  8196. if (!resultDescriptor->GetterSpecified())
  8197. {
  8198. resultDescriptor->SetGetter(likePropertyDescriptor->GetGetter());
  8199. }
  8200. if (!resultDescriptor->SetterSpecified())
  8201. {
  8202. resultDescriptor->SetSetter(likePropertyDescriptor->GetSetter());
  8203. }
  8204. }
  8205. // 7. If Desc does not have an[[Enumerable]] field, then set Desc.[[Enumerable]] to LikeDesc.[[Enumerable]].
  8206. // 8. If Desc does not have a[[Configurable]] field, then set Desc.[[Configurable]] to LikeDesc.[[Configurable]].
  8207. // 9. Return Desc.
  8208. if (!resultDescriptor->EnumerableSpecified())
  8209. {
  8210. resultDescriptor->SetEnumerable(likePropertyDescriptor->IsEnumerable());
  8211. }
  8212. if (!resultDescriptor->ConfigurableSpecified())
  8213. {
  8214. resultDescriptor->SetConfigurable(likePropertyDescriptor->IsConfigurable());
  8215. }
  8216. }
  8217. // Conformance to: ES5 8.6.1.
  8218. // Set attributes on the object as provided by property descriptor.
  8219. // If force parameter is true, we force SetAttributes call even if none of the attributes are defined by the descriptor.
  8220. // NOTE: does not set [[Get]], [Set]], [[Value]]
  8221. void JavascriptOperators::SetAttributes(RecyclableObject* object, PropertyId propId, const PropertyDescriptor& descriptor, bool force)
  8222. {
  8223. Assert(object);
  8224. BOOL isWritable = FALSE;
  8225. if (descriptor.IsDataDescriptor())
  8226. {
  8227. isWritable = descriptor.WritableSpecified() ? descriptor.IsWritable() : FALSE;
  8228. }
  8229. else if (descriptor.IsAccessorDescriptor())
  8230. {
  8231. // The reason is that JavascriptOperators::OP_SetProperty checks for RecyclableObject::FromVar(instance)->IsWritableOrAccessor(propertyId),
  8232. // which should in fact check for 'is writable or accessor' but since there is no GetAttributes, we can't do that efficiently.
  8233. isWritable = TRUE;
  8234. }
  8235. // CONSIDER: call object->SetAttributes which is much more efficient as that's 1 call instead of 3.
  8236. // Can't do that now as object->SetAttributes doesn't provide a way which attributes to modify and which not.
  8237. if (force || descriptor.ConfigurableSpecified())
  8238. {
  8239. object->SetConfigurable(propId, descriptor.ConfigurableSpecified() ? descriptor.IsConfigurable() : FALSE);
  8240. }
  8241. if (force || descriptor.EnumerableSpecified())
  8242. {
  8243. object->SetEnumerable(propId, descriptor.EnumerableSpecified() ? descriptor.IsEnumerable() : FALSE);
  8244. }
  8245. if (force || descriptor.WritableSpecified() || isWritable)
  8246. {
  8247. object->SetWritable(propId, isWritable);
  8248. }
  8249. }
  8250. void JavascriptOperators::OP_ClearAttributes(Var instance, PropertyId propertyId)
  8251. {
  8252. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(OP_ClearAttributes);
  8253. Assert(instance);
  8254. if (RecyclableObject::Is(instance))
  8255. {
  8256. RecyclableObject* obj = RecyclableObject::FromVar(instance);
  8257. obj->SetAttributes(propertyId, PropertyNone);
  8258. }
  8259. JIT_HELPER_END(OP_ClearAttributes);
  8260. }
  8261. BOOL JavascriptOperators::Reject(bool throwOnError, ScriptContext* scriptContext, int32 errorCode, PropertyId propertyId)
  8262. {
  8263. Assert(scriptContext);
  8264. if (throwOnError)
  8265. {
  8266. JavascriptError::ThrowTypeError(scriptContext, errorCode, scriptContext->GetThreadContext()->GetPropertyName(propertyId)->GetBuffer());
  8267. }
  8268. return FALSE;
  8269. }
  8270. bool JavascriptOperators::AreSamePropertyDescriptors(const PropertyDescriptor* x, const PropertyDescriptor* y, ScriptContext* scriptContext)
  8271. {
  8272. Assert(scriptContext);
  8273. if (x->ConfigurableSpecified() != y->ConfigurableSpecified() || x->IsConfigurable() != y->IsConfigurable() ||
  8274. x->EnumerableSpecified() != y->EnumerableSpecified() || x->IsEnumerable() != y->IsEnumerable())
  8275. {
  8276. return false;
  8277. }
  8278. if (x->IsDataDescriptor())
  8279. {
  8280. if (!y->IsDataDescriptor() || x->WritableSpecified() != y->WritableSpecified() || x->IsWritable() != y->IsWritable())
  8281. {
  8282. return false;
  8283. }
  8284. if (x->ValueSpecified())
  8285. {
  8286. if (!y->ValueSpecified() || !JavascriptConversion::SameValue(x->GetValue(), y->GetValue()))
  8287. {
  8288. return false;
  8289. }
  8290. }
  8291. }
  8292. else if (x->IsAccessorDescriptor())
  8293. {
  8294. if (!y->IsAccessorDescriptor())
  8295. {
  8296. return false;
  8297. }
  8298. if (x->GetterSpecified())
  8299. {
  8300. if (!y->GetterSpecified() || !JavascriptConversion::SameValue(
  8301. JavascriptOperators::CanonicalizeAccessor(x->GetGetter(), scriptContext),
  8302. JavascriptOperators::CanonicalizeAccessor(y->GetGetter(), scriptContext)))
  8303. {
  8304. return false;
  8305. }
  8306. }
  8307. if (x->SetterSpecified())
  8308. {
  8309. if (!y->SetterSpecified() || !JavascriptConversion::SameValue(
  8310. JavascriptOperators::CanonicalizeAccessor(x->GetSetter(), scriptContext),
  8311. JavascriptOperators::CanonicalizeAccessor(y->GetSetter(), scriptContext)))
  8312. {
  8313. return false;
  8314. }
  8315. }
  8316. }
  8317. return true;
  8318. }
  8319. // Check if an accessor is undefined (null or defaultAccessor)
  8320. bool JavascriptOperators::IsUndefinedAccessor(Var accessor, ScriptContext* scriptContext)
  8321. {
  8322. return nullptr == accessor || scriptContext->GetLibrary()->GetDefaultAccessorFunction() == accessor;
  8323. }
  8324. // Converts default accessor to undefined.
  8325. // Can be used when comparing accessors.
  8326. Var JavascriptOperators::CanonicalizeAccessor(Var accessor, ScriptContext* scriptContext)
  8327. {
  8328. Assert(scriptContext);
  8329. if (IsUndefinedAccessor(accessor, scriptContext))
  8330. {
  8331. return scriptContext->GetLibrary()->GetUndefined();
  8332. }
  8333. return accessor;
  8334. }
  8335. Var JavascriptOperators::DefaultAccessor(RecyclableObject* function, CallInfo callInfo, ...)
  8336. {
  8337. return function->GetLibrary()->GetUndefined();
  8338. }
  8339. void FrameDisplay::SetItem(uint index, void* item)
  8340. {
  8341. AssertMsg(index < this->length, "Invalid frame display access");
  8342. scopes[index] = item;
  8343. }
  8344. void *FrameDisplay::GetItem(uint index)
  8345. {
  8346. AssertMsg(index < this->length, "Invalid frame display access");
  8347. return scopes[index];
  8348. }
  8349. // Grab the "this" pointer, mapping a root object to its associated host object.
  8350. Var JavascriptOperators::RootToThisObject(const Var object, ScriptContext* scriptContext)
  8351. {
  8352. Js::Var thisVar = object;
  8353. TypeId typeId = Js::JavascriptOperators::GetTypeId(thisVar);
  8354. switch (typeId)
  8355. {
  8356. case Js::TypeIds_GlobalObject:
  8357. return ((Js::GlobalObject*)thisVar)->ToThis();
  8358. case Js::TypeIds_ModuleRoot:
  8359. return Js::JavascriptOperators::GetThisFromModuleRoot(thisVar);
  8360. default:
  8361. if (typeId == scriptContext->GetDirectHostTypeId())
  8362. {
  8363. return ((RecyclableObject*)thisVar)->GetLibrary()->GetGlobalObject()->ToThis();
  8364. }
  8365. }
  8366. return thisVar;
  8367. }
  8368. Var JavascriptOperators::CallGetter(RecyclableObject * const function, Var const object, ScriptContext * requestContext)
  8369. {
  8370. #if ENABLE_TTD
  8371. if(function->GetScriptContext()->ShouldSuppressGetterInvocationForDebuggerEvaluation())
  8372. {
  8373. return requestContext->GetLibrary()->GetUndefined();
  8374. }
  8375. #endif
  8376. ScriptContext * scriptContext = function->GetScriptContext();
  8377. ThreadContext * threadContext = scriptContext->GetThreadContext();
  8378. return threadContext->ExecuteImplicitCall(function, ImplicitCall_Accessor, [=]() -> Js::Var
  8379. {
  8380. // Stack object should have a pre-op bail on implicit call. We shouldn't see them here.
  8381. // Stack numbers are ok, as we will call ToObject to wrap it in a number object anyway
  8382. // See JavascriptOperators::GetThisHelper
  8383. Assert(JavascriptOperators::GetTypeId(object) == TypeIds_Integer ||
  8384. JavascriptOperators::GetTypeId(object) == TypeIds_Number ||
  8385. threadContext->HasNoSideEffect(function) ||
  8386. !ThreadContext::IsOnStack(object));
  8387. // Verify that the scriptcontext is alive before firing getter/setter
  8388. if (!scriptContext->VerifyAlive(!function->IsExternal(), requestContext))
  8389. {
  8390. return nullptr;
  8391. }
  8392. CallFlags flags = CallFlags_Value;
  8393. Var thisVar = RootToThisObject(object, scriptContext);
  8394. RecyclableObject* marshalledFunction = RecyclableObject::UnsafeFromVar(
  8395. CrossSite::MarshalVar(requestContext, function, scriptContext));
  8396. Var result = CALL_ENTRYPOINT(threadContext, marshalledFunction->GetEntryPoint(), function, CallInfo(flags, 1), thisVar);
  8397. result = CrossSite::MarshalVar(requestContext, result);
  8398. return result;
  8399. });
  8400. }
  8401. void JavascriptOperators::CallSetter(RecyclableObject * const function, Var const object, Var const value, ScriptContext * requestContext)
  8402. {
  8403. ScriptContext * scriptContext = function->GetScriptContext();
  8404. ThreadContext * threadContext = scriptContext->GetThreadContext();
  8405. threadContext->ExecuteImplicitCall(function, ImplicitCall_Accessor, [=]() -> Js::Var
  8406. {
  8407. // Stack object should have a pre-op bail on implicit call. We shouldn't see them here.
  8408. // Stack numbers are ok, as we will call ToObject to wrap it in a number object anyway
  8409. // See JavascriptOperators::GetThisHelper
  8410. Assert(JavascriptOperators::GetTypeId(object) == TypeIds_Integer ||
  8411. JavascriptOperators::GetTypeId(object) == TypeIds_Number || !ThreadContext::IsOnStack(object));
  8412. // Verify that the scriptcontext is alive before firing getter/setter
  8413. if (!scriptContext->VerifyAlive(!function->IsExternal(), requestContext))
  8414. {
  8415. return nullptr;
  8416. }
  8417. CallFlags flags = CallFlags_Value;
  8418. Var putValue = value;
  8419. // CONSIDER: Have requestContext everywhere, even in the setProperty related codepath.
  8420. if (requestContext)
  8421. {
  8422. putValue = CrossSite::MarshalVar(requestContext, value);
  8423. }
  8424. Var thisVar = RootToThisObject(object, scriptContext);
  8425. RecyclableObject* marshalledFunction = function;
  8426. if (requestContext)
  8427. {
  8428. marshalledFunction = RecyclableObject::UnsafeFromVar(CrossSite::MarshalVar(requestContext, function, function->GetScriptContext()));
  8429. }
  8430. Var result = CALL_ENTRYPOINT(threadContext, marshalledFunction->GetEntryPoint(), function, CallInfo(flags, 2), thisVar, putValue);
  8431. Assert(result);
  8432. return nullptr;
  8433. });
  8434. }
  8435. void * JavascriptOperators::AllocMemForVarArray(size_t size, Recycler* recycler)
  8436. {
  8437. TRACK_ALLOC_INFO(recycler, Js::Var, Recycler, 0, (size_t)(size / sizeof(Js::Var)));
  8438. return recycler->AllocZero(size);
  8439. }
  8440. #if !FLOATVAR
  8441. void * JavascriptOperators::AllocUninitializedNumber(Js::RecyclerJavascriptNumberAllocator * allocator)
  8442. {
  8443. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(AllocUninitializedNumber);
  8444. TRACK_ALLOC_INFO(allocator->GetRecycler(), Js::JavascriptNumber, Recycler, 0, (size_t)-1);
  8445. return allocator->Alloc(sizeof(Js::JavascriptNumber));
  8446. JIT_HELPER_END(AllocUninitializedNumber);
  8447. }
  8448. #endif
  8449. void JavascriptOperators::ScriptAbort()
  8450. {
  8451. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(ScriptAbort);
  8452. throw ScriptAbortException();
  8453. JIT_HELPER_END(ScriptAbort);
  8454. }
  8455. JavascriptString * JavascriptOperators::Concat3(Var aLeft, Var aCenter, Var aRight, ScriptContext * scriptContext)
  8456. {
  8457. // Make sure we do the conversion in order from left to right
  8458. JavascriptString * strLeft = JavascriptConversion::ToPrimitiveString(aLeft, scriptContext);
  8459. JavascriptString * strCenter = JavascriptConversion::ToPrimitiveString(aCenter, scriptContext);
  8460. JavascriptString * strRight = JavascriptConversion::ToPrimitiveString(aRight, scriptContext);
  8461. return JavascriptString::Concat3(strLeft, strCenter, strRight);
  8462. }
  8463. JavascriptString *
  8464. JavascriptOperators::NewConcatStrMulti(Var a1, Var a2, uint count, ScriptContext * scriptContext)
  8465. {
  8466. // Make sure we do the conversion in order
  8467. JavascriptString * str1 = JavascriptConversion::ToPrimitiveString(a1, scriptContext);
  8468. JavascriptString * str2 = JavascriptConversion::ToPrimitiveString(a2, scriptContext);
  8469. return ConcatStringMulti::New(count, str1, str2, scriptContext);
  8470. }
  8471. void
  8472. JavascriptOperators::SetConcatStrMultiItem(Var concatStr, Var str, uint index, ScriptContext * scriptContext)
  8473. {
  8474. ConcatStringMulti::FromVar(concatStr)->SetItem(index,
  8475. JavascriptConversion::ToPrimitiveString(str, scriptContext));
  8476. }
  8477. void
  8478. JavascriptOperators::SetConcatStrMultiItem2(Var concatStr, Var str1, Var str2, uint index, ScriptContext * scriptContext)
  8479. {
  8480. ConcatStringMulti * cs = ConcatStringMulti::FromVar(concatStr);
  8481. cs->SetItem(index, JavascriptConversion::ToPrimitiveString(str1, scriptContext));
  8482. cs->SetItem(index + 1, JavascriptConversion::ToPrimitiveString(str2, scriptContext));
  8483. }
  8484. void JavascriptOperators::OP_SetComputedNameVar(Var method, Var computedNameVar)
  8485. {
  8486. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(SetComputedNameVar);
  8487. ScriptFunctionBase *scriptFunction = ScriptFunctionBase::FromVar(method);
  8488. scriptFunction->SetComputedNameVar(computedNameVar);
  8489. JIT_HELPER_END(SetComputedNameVar);
  8490. }
  8491. void JavascriptOperators::OP_SetHomeObj(Var method, Var homeObj)
  8492. {
  8493. ScriptFunctionBase *scriptFunction = ScriptFunctionBase::FromVar(method);
  8494. scriptFunction->SetHomeObj(homeObj);
  8495. }
  8496. Var JavascriptOperators::OP_LdHomeObj(Var scriptFunction, ScriptContext * scriptContext)
  8497. {
  8498. JIT_HELPER_NOT_REENTRANT_HEADER(LdHomeObj, reentrancylock, scriptContext->GetThreadContext());
  8499. // Ensure this is not a stack ScriptFunction
  8500. if (!ScriptFunction::Is(scriptFunction) || ThreadContext::IsOnStack(scriptFunction))
  8501. {
  8502. return scriptContext->GetLibrary()->GetUndefined();
  8503. }
  8504. ScriptFunction *instance = ScriptFunction::UnsafeFromVar(scriptFunction);
  8505. // We keep a reference to the current class rather than its super prototype
  8506. // since the prototype could change.
  8507. Var homeObj = instance->GetHomeObj();
  8508. return (homeObj != nullptr) ? homeObj : scriptContext->GetLibrary()->GetUndefined();
  8509. JIT_HELPER_END(LdHomeObj);
  8510. }
  8511. Var JavascriptOperators::OP_LdHomeObjProto(Var homeObj, ScriptContext* scriptContext)
  8512. {
  8513. JIT_HELPER_NOT_REENTRANT_HEADER(LdHomeObjProto, reentrancylock, scriptContext->GetThreadContext());
  8514. if (homeObj == nullptr || !RecyclableObject::Is(homeObj))
  8515. {
  8516. return scriptContext->GetLibrary()->GetUndefined();
  8517. }
  8518. RecyclableObject *thisObjPrototype = RecyclableObject::FromVar(homeObj);
  8519. TypeId typeId = thisObjPrototype->GetTypeId();
  8520. if (typeId == TypeIds_Null || typeId == TypeIds_Undefined)
  8521. {
  8522. JavascriptError::ThrowReferenceError(scriptContext, JSERR_BadSuperReference);
  8523. }
  8524. Assert(thisObjPrototype != nullptr);
  8525. RecyclableObject *superBase = thisObjPrototype->GetPrototype();
  8526. if (superBase == nullptr || !RecyclableObject::Is(superBase))
  8527. {
  8528. return scriptContext->GetLibrary()->GetUndefined();
  8529. }
  8530. return superBase;
  8531. JIT_HELPER_END(LdHomeObjProto);
  8532. }
  8533. Var JavascriptOperators::OP_LdFuncObj(Var scriptFunction, ScriptContext * scriptContext)
  8534. {
  8535. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(LdFuncObj);
  8536. // use self as value of [[FunctionObject]] - this is true only for constructors
  8537. Assert(RecyclableObject::Is(scriptFunction));
  8538. return scriptFunction;
  8539. JIT_HELPER_END(LdFuncObj);
  8540. }
  8541. Var JavascriptOperators::OP_LdFuncObjProto(Var funcObj, ScriptContext* scriptContext)
  8542. {
  8543. JIT_HELPER_NOT_REENTRANT_HEADER(LdFuncObjProto, reentrancylock, scriptContext->GetThreadContext());
  8544. RecyclableObject *superCtor = RecyclableObject::FromVar(funcObj)->GetPrototype();
  8545. if (superCtor == nullptr || !IsConstructor(superCtor))
  8546. {
  8547. JavascriptError::ThrowTypeError(scriptContext, JSERR_NotAConstructor);
  8548. }
  8549. return superCtor;
  8550. JIT_HELPER_END(LdFuncObjProto);
  8551. }
  8552. Var JavascriptOperators::OP_ImportCall(__in JavascriptFunction *function, __in Var specifier, __in ScriptContext* scriptContext)
  8553. {
  8554. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(ImportCall);
  8555. ModuleRecordBase *moduleRecordBase = nullptr;
  8556. SourceTextModuleRecord *moduleRecord = nullptr;
  8557. FunctionBody* parentFuncBody = function->GetFunctionBody();
  8558. JavascriptString *specifierString = nullptr;
  8559. try
  8560. {
  8561. specifierString = JavascriptConversion::ToString(specifier, scriptContext);
  8562. }
  8563. catch (const JavascriptException &err)
  8564. {
  8565. Var errorObject = err.GetAndClear()->GetThrownObject(scriptContext);
  8566. AssertMsg(errorObject != nullptr, "OP_ImportCall: null error object thrown by ToString(specifier)");
  8567. if (errorObject != nullptr)
  8568. {
  8569. return SourceTextModuleRecord::ResolveOrRejectDynamicImportPromise(false, errorObject, scriptContext);
  8570. }
  8571. Throw::InternalError();
  8572. }
  8573. DWORD_PTR dwReferencingSourceContext = parentFuncBody->GetHostSourceContext();
  8574. if (!parentFuncBody->IsES6ModuleCode() && dwReferencingSourceContext == Js::Constants::NoHostSourceContext)
  8575. {
  8576. // import() called from eval
  8577. if (parentFuncBody->GetUtf8SourceInfo()->GetCallerUtf8SourceInfo() == nullptr)
  8578. {
  8579. JavascriptError *error = scriptContext->GetLibrary()->CreateError();
  8580. JavascriptError::SetErrorMessageProperties(error, E_FAIL, _u("Unable to locate active script or module that calls import()"), scriptContext);
  8581. return SourceTextModuleRecord::ResolveOrRejectDynamicImportPromise(false, error, scriptContext);
  8582. }
  8583. dwReferencingSourceContext = parentFuncBody->GetUtf8SourceInfo()->GetCallerUtf8SourceInfo()->GetSourceContextInfo()->dwHostSourceContext;
  8584. if (dwReferencingSourceContext == Js::Constants::NoHostSourceContext)
  8585. {
  8586. // Walk the call stack if caller function is neither module code nor having host source context
  8587. JavascriptFunction* caller = nullptr;
  8588. Js::JavascriptStackWalker walker(scriptContext);
  8589. walker.GetCaller(&caller);
  8590. do
  8591. {
  8592. if (walker.GetCaller(&caller) && caller != nullptr && caller->IsScriptFunction())
  8593. {
  8594. parentFuncBody = caller->GetFunctionBody();
  8595. dwReferencingSourceContext = parentFuncBody->GetHostSourceContext();
  8596. }
  8597. else
  8598. {
  8599. JavascriptError *error = scriptContext->GetLibrary()->CreateError();
  8600. JavascriptError::SetErrorMessageProperties(error, E_FAIL, _u("Unable to locate active script or module that calls import()"), scriptContext);
  8601. return SourceTextModuleRecord::ResolveOrRejectDynamicImportPromise(false, error, scriptContext);
  8602. }
  8603. } while (!parentFuncBody->IsES6ModuleCode() && dwReferencingSourceContext == Js::Constants::NoHostSourceContext);
  8604. }
  8605. }
  8606. LPCOLESTR moduleName = specifierString->GetSz();
  8607. HRESULT hr = 0;
  8608. if (parentFuncBody->IsES6ModuleCode())
  8609. {
  8610. SourceTextModuleRecord *referenceModuleRecord = parentFuncBody->GetScriptContext()->GetLibrary()->GetModuleRecord(parentFuncBody->GetModuleID());
  8611. BEGIN_LEAVE_SCRIPT(scriptContext);
  8612. BEGIN_TRANSLATE_TO_HRESULT(static_cast<ExceptionType>(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
  8613. hr = scriptContext->GetHostScriptContext()->FetchImportedModule(referenceModuleRecord, moduleName, &moduleRecordBase);
  8614. END_TRANSLATE_EXCEPTION_TO_HRESULT(hr);
  8615. END_LEAVE_SCRIPT(scriptContext);
  8616. }
  8617. else
  8618. {
  8619. Assert(dwReferencingSourceContext != Js::Constants::NoHostSourceContext);
  8620. BEGIN_LEAVE_SCRIPT(scriptContext);
  8621. BEGIN_TRANSLATE_TO_HRESULT(static_cast<ExceptionType>(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
  8622. hr = scriptContext->GetHostScriptContext()->FetchImportedModuleFromScript(dwReferencingSourceContext, moduleName, &moduleRecordBase);
  8623. END_TRANSLATE_EXCEPTION_TO_HRESULT(hr);
  8624. END_LEAVE_SCRIPT(scriptContext);
  8625. }
  8626. if (FAILED(hr))
  8627. {
  8628. // We cannot just use the buffer in the specifier string - need to make a copy here.
  8629. size_t length = wcslen(moduleName);
  8630. char16* allocatedString = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, length + 1);
  8631. wmemcpy_s(allocatedString, length + 1, moduleName, length);
  8632. allocatedString[length] = _u('\0');
  8633. Js::JavascriptError *error = scriptContext->GetLibrary()->CreateURIError();
  8634. JavascriptError::SetErrorMessageProperties(error, hr, allocatedString, scriptContext);
  8635. return SourceTextModuleRecord::ResolveOrRejectDynamicImportPromise(false, error, scriptContext);
  8636. }
  8637. moduleRecord = SourceTextModuleRecord::FromHost(moduleRecordBase);
  8638. if (moduleRecord->GetErrorObject() != nullptr)
  8639. {
  8640. return SourceTextModuleRecord::ResolveOrRejectDynamicImportPromise(false, moduleRecord->GetErrorObject(), scriptContext, moduleRecord);
  8641. }
  8642. else if (moduleRecord->WasEvaluated())
  8643. {
  8644. return SourceTextModuleRecord::ResolveOrRejectDynamicImportPromise(true, moduleRecord->GetNamespace(), scriptContext, moduleRecord);
  8645. }
  8646. return moduleRecord->PostProcessDynamicModuleImport();
  8647. JIT_HELPER_END(ImportCall);
  8648. }
  8649. Var JavascriptOperators::OP_ResumeYield(ResumeYieldData* yieldData, RecyclableObject* iterator)
  8650. {
  8651. JIT_HELPER_REENTRANT_HEADER(ResumeYield);
  8652. bool isNext = yieldData->exceptionObj == nullptr;
  8653. bool isThrow = !isNext && !yieldData->exceptionObj->IsGeneratorReturnException();
  8654. if (iterator != nullptr) // yield*
  8655. {
  8656. ScriptContext* scriptContext = iterator->GetScriptContext();
  8657. PropertyId propertyId = isNext ? PropertyIds::next : isThrow ? PropertyIds::throw_ : PropertyIds::return_;
  8658. Var prop = JavascriptOperators::GetProperty(iterator, propertyId, scriptContext);
  8659. if (!isNext && JavascriptOperators::IsUndefinedOrNull(prop))
  8660. {
  8661. if (isThrow)
  8662. {
  8663. // 5.b.iii.2
  8664. // NOTE: If iterator does not have a throw method, this throw is going to terminate the yield* loop.
  8665. // But first we need to give iterator a chance to clean up.
  8666. prop = JavascriptOperators::GetProperty(iterator, PropertyIds::return_, scriptContext);
  8667. if (!JavascriptOperators::IsUndefinedOrNull(prop))
  8668. {
  8669. if (!JavascriptConversion::IsCallable(prop))
  8670. {
  8671. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction, _u("return"));
  8672. }
  8673. Var result = nullptr;
  8674. RecyclableObject* method = RecyclableObject::FromVar(prop);
  8675. BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
  8676. {
  8677. Var args[] = { iterator, yieldData->data };
  8678. CallInfo callInfo(CallFlags_Value, _countof(args));
  8679. result = JavascriptFunction::CallFunction<true>(method, method->GetEntryPoint(), Arguments(callInfo, args));
  8680. }
  8681. END_SAFE_REENTRANT_CALL
  8682. if (!JavascriptOperators::IsObject(result))
  8683. {
  8684. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject);
  8685. }
  8686. }
  8687. // 5.b.iii.3
  8688. // NOTE: The next step throws a TypeError to indicate that there was a yield* protocol violation:
  8689. // iterator does not have a throw method.
  8690. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction, _u("throw"));
  8691. }
  8692. // Do not use ThrowExceptionObject for return() API exceptions since these exceptions are not real exceptions
  8693. JavascriptExceptionOperators::DoThrow(yieldData->exceptionObj, scriptContext);
  8694. }
  8695. if (!JavascriptConversion::IsCallable(prop))
  8696. {
  8697. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction, isNext ? _u("next") : isThrow ? _u("throw") : _u("return"));
  8698. }
  8699. RecyclableObject* method = RecyclableObject::FromVar(prop);
  8700. Var result = scriptContext->GetThreadContext()->ExecuteImplicitCall(method, Js::ImplicitCall_Accessor, [=]()->Js::Var
  8701. {
  8702. Var args[] = { iterator, yieldData->data };
  8703. CallInfo callInfo(CallFlags_Value, _countof(args));
  8704. return JavascriptFunction::CallFunction<true>(method, method->GetEntryPoint(), Arguments(callInfo, args));
  8705. });
  8706. if (!JavascriptOperators::IsObject(result))
  8707. {
  8708. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject);
  8709. }
  8710. if (isThrow || isNext)
  8711. {
  8712. // 5.b.ii.2
  8713. // NOTE: Exceptions from the inner iterator throw method are propagated.
  8714. // Normal completions from an inner throw method are processed similarly to an inner next.
  8715. return result;
  8716. }
  8717. RecyclableObject* obj = RecyclableObject::FromVar(result);
  8718. Var done = JavascriptOperators::GetProperty(obj, PropertyIds::done, scriptContext);
  8719. if (done == iterator->GetLibrary()->GetTrue())
  8720. {
  8721. Var value = JavascriptOperators::GetProperty(obj, PropertyIds::value, scriptContext);
  8722. yieldData->exceptionObj->SetThrownObject(value);
  8723. // Do not use ThrowExceptionObject for return() API exceptions since these exceptions are not real exceptions
  8724. JavascriptExceptionOperators::DoThrow(yieldData->exceptionObj, scriptContext);
  8725. }
  8726. return result;
  8727. }
  8728. // CONSIDER: Fast path this early out return path in JITed code before helper call to avoid the helper call overhead in the common case e.g. next() calls.
  8729. if (isNext)
  8730. {
  8731. return yieldData->data;
  8732. }
  8733. if (isThrow)
  8734. {
  8735. // Use ThrowExceptionObject() to get debugger support for breaking on throw
  8736. JavascriptExceptionOperators::ThrowExceptionObject(yieldData->exceptionObj, yieldData->exceptionObj->GetScriptContext(), true);
  8737. }
  8738. // CONSIDER: Using an exception to carry the return value and force finally code to execute is a bit of a janky
  8739. // solution since we have to override the value here in the case of yield* expressions. It works but is there
  8740. // a more elegant way?
  8741. //
  8742. // Instead what if ResumeYield was a "set Dst then optionally branch" opcode, that could also throw? Then we could
  8743. // avoid using a special exception entirely with byte code something like this:
  8744. //
  8745. // ;; Ry is the yieldData
  8746. //
  8747. // ResumeYield Rx Ry $returnPathLabel
  8748. // ... code like normal
  8749. // $returnPathLabel:
  8750. // Ld_A R0 Rx
  8751. // Br $exitFinallyAndReturn
  8752. //
  8753. // This would probably give better performance for the common case of calling next() on generators since we wouldn't
  8754. // have to wrap the call to the generator code in a try catch.
  8755. // Do not use ThrowExceptionObject for return() API exceptions since these exceptions are not real exceptions
  8756. JavascriptExceptionOperators::DoThrow(yieldData->exceptionObj, yieldData->exceptionObj->GetScriptContext());
  8757. JIT_HELPER_END(ResumeYield);
  8758. }
  8759. Js::Var
  8760. JavascriptOperators::BoxStackInstance(Js::Var instance, ScriptContext * scriptContext, bool allowStackFunction, bool deepCopy)
  8761. {
  8762. if (!ThreadContext::IsOnStack(instance) || (allowStackFunction && !TaggedNumber::Is(instance) && (*(int*)instance & 1)))
  8763. {
  8764. return instance;
  8765. }
  8766. TypeId typeId = JavascriptOperators::GetTypeId(instance);
  8767. switch (typeId)
  8768. {
  8769. case Js::TypeIds_Number:
  8770. #if !FLOATVAR
  8771. return JavascriptNumber::BoxStackInstance(instance, scriptContext);
  8772. #endif
  8773. // fall-through
  8774. case Js::TypeIds_Integer:
  8775. return instance;
  8776. case Js::TypeIds_RegEx:
  8777. return JavascriptRegExp::BoxStackInstance(JavascriptRegExp::FromVar(instance), deepCopy);
  8778. case Js::TypeIds_Object:
  8779. return DynamicObject::BoxStackInstance(DynamicObject::FromVar(instance), deepCopy);
  8780. case Js::TypeIds_Array:
  8781. return JavascriptArray::BoxStackInstance(JavascriptArray::UnsafeFromVar(instance), deepCopy);
  8782. case Js::TypeIds_NativeIntArray:
  8783. return JavascriptNativeIntArray::BoxStackInstance(JavascriptNativeIntArray::UnsafeFromVar(instance), deepCopy);
  8784. case Js::TypeIds_NativeFloatArray:
  8785. return JavascriptNativeFloatArray::BoxStackInstance(JavascriptNativeFloatArray::UnsafeFromVar(instance), deepCopy);
  8786. case Js::TypeIds_Function:
  8787. Assert(allowStackFunction);
  8788. // Stack functions are deal with not mar mark them, but by nested function escape analysis
  8789. // in the front end. No need to box here.
  8790. return instance;
  8791. #if ENABLE_COPYONACCESS_ARRAY
  8792. case Js::TypeIds_CopyOnAccessNativeIntArray:
  8793. Assert(false);
  8794. // fall-through
  8795. #endif
  8796. default:
  8797. Assert(false);
  8798. return instance;
  8799. };
  8800. }
  8801. ImplicitCallFlags
  8802. JavascriptOperators::CacheAndClearImplicitBit(ScriptContext* scriptContext)
  8803. {
  8804. ImplicitCallFlags prevImplicitCallFlags = scriptContext->GetThreadContext()->GetImplicitCallFlags();
  8805. scriptContext->GetThreadContext()->ClearImplicitCallFlags();
  8806. return prevImplicitCallFlags;
  8807. }
  8808. ImplicitCallFlags
  8809. JavascriptOperators::CheckAndUpdateFunctionBodyWithImplicitFlag(FunctionBody* functionBody)
  8810. {
  8811. ScriptContext* scriptContext = functionBody->GetScriptContext();
  8812. ImplicitCallFlags currImplicitCallFlags = scriptContext->GetThreadContext()->GetImplicitCallFlags();
  8813. if ((currImplicitCallFlags > ImplicitCall_None))
  8814. {
  8815. functionBody->SetHasOnlyThisStmts(false);
  8816. }
  8817. return currImplicitCallFlags;
  8818. }
  8819. void
  8820. JavascriptOperators::RestoreImplicitFlag(ScriptContext* scriptContext, ImplicitCallFlags prevImplicitCallFlags, ImplicitCallFlags currImplicitCallFlags)
  8821. {
  8822. scriptContext->GetThreadContext()->SetImplicitCallFlags((ImplicitCallFlags)(prevImplicitCallFlags | currImplicitCallFlags));
  8823. }
  8824. FunctionProxy*
  8825. JavascriptOperators::GetDeferredDeserializedFunctionProxy(JavascriptFunction* func)
  8826. {
  8827. FunctionProxy* proxy = func->GetFunctionProxy();
  8828. Assert(proxy->GetFunctionInfo()->GetFunctionProxy() != proxy);
  8829. return proxy;
  8830. }
  8831. template <>
  8832. Js::Var JavascriptOperators::GetElementAtIndex(Js::JavascriptArray* arrayObject, UINT index, Js::ScriptContext* scriptContext)
  8833. {
  8834. Js::Var result;
  8835. if (Js::JavascriptOperators::OP_GetElementI_ArrayFastPath(arrayObject, index, &result, scriptContext))
  8836. {
  8837. return result;
  8838. }
  8839. return scriptContext->GetMissingItemResult();
  8840. }
  8841. template<>
  8842. Js::Var JavascriptOperators::GetElementAtIndex(Js::JavascriptNativeIntArray* arrayObject, UINT index, Js::ScriptContext* scriptContext)
  8843. {
  8844. Js::Var result;
  8845. if (Js::JavascriptOperators::OP_GetElementI_ArrayFastPath(arrayObject, index, &result, scriptContext))
  8846. {
  8847. return result;
  8848. }
  8849. return scriptContext->GetMissingItemResult();
  8850. }
  8851. template<>
  8852. Js::Var JavascriptOperators::GetElementAtIndex(Js::JavascriptNativeFloatArray* arrayObject, UINT index, Js::ScriptContext* scriptContext)
  8853. {
  8854. Js::Var result;
  8855. if (Js::JavascriptOperators::OP_GetElementI_ArrayFastPath(arrayObject, index, &result, scriptContext))
  8856. {
  8857. return result;
  8858. }
  8859. return scriptContext->GetMissingItemResult();
  8860. }
  8861. template<>
  8862. Js::Var JavascriptOperators::GetElementAtIndex(Js::Var* arrayObject, UINT index, Js::ScriptContext* scriptContext)
  8863. {
  8864. return Js::JavascriptOperators::OP_GetElementI_Int32(*arrayObject, index, scriptContext);
  8865. }
  8866. template<typename T>
  8867. void JavascriptOperators::ObjectToNativeArray(T* arrayObject,
  8868. JsNativeValueType valueType,
  8869. __in UINT length,
  8870. __in UINT elementSize,
  8871. __out_bcount(length*elementSize) byte* buffer,
  8872. Js::ScriptContext* scriptContext)
  8873. {
  8874. Var element;
  8875. uint64 allocSize = UInt32Math::Mul(length, elementSize);
  8876. // TODO:further fast path the call for things like IntArray convert to int, floatarray convert to float etc.
  8877. // such that we don't need boxing.
  8878. switch (valueType)
  8879. {
  8880. case JsInt8Type:
  8881. AnalysisAssert(elementSize == sizeof(int8));
  8882. for (UINT i = 0; i < length; i++)
  8883. {
  8884. element = GetElementAtIndex(arrayObject, i, scriptContext);
  8885. AnalysisAssert((i + 1) * sizeof(int8) <= allocSize);
  8886. #pragma prefast(suppress:22102)
  8887. ((int8*)buffer)[i] = Js::JavascriptConversion::ToInt8(element, scriptContext);
  8888. }
  8889. break;
  8890. case JsUint8Type:
  8891. AnalysisAssert(elementSize == sizeof(uint8));
  8892. for (UINT i = 0; i < length; i++)
  8893. {
  8894. element = GetElementAtIndex(arrayObject, i, scriptContext);
  8895. AnalysisAssert((i + 1) * sizeof(uint8) <= allocSize);
  8896. ((uint8*)buffer)[i] = Js::JavascriptConversion::ToUInt8(element, scriptContext);
  8897. }
  8898. break;
  8899. case JsInt16Type:
  8900. AnalysisAssert(elementSize == sizeof(int16));
  8901. for (UINT i = 0; i < length; i++)
  8902. {
  8903. element = GetElementAtIndex(arrayObject, i, scriptContext);
  8904. AnalysisAssert((i + 1) * sizeof(int16) <= allocSize);
  8905. ((int16*)buffer)[i] = Js::JavascriptConversion::ToInt16(element, scriptContext);
  8906. }
  8907. break;
  8908. case JsUint16Type:
  8909. AnalysisAssert(elementSize == sizeof(uint16));
  8910. for (UINT i = 0; i < length; i++)
  8911. {
  8912. element = GetElementAtIndex(arrayObject, i, scriptContext);
  8913. AnalysisAssert((i + 1) * sizeof(uint16) <= allocSize);
  8914. ((uint16*)buffer)[i] = Js::JavascriptConversion::ToUInt16(element, scriptContext);
  8915. }
  8916. break;
  8917. case JsInt32Type:
  8918. AnalysisAssert(elementSize == sizeof(int32));
  8919. for (UINT i = 0; i < length; i++)
  8920. {
  8921. element = GetElementAtIndex(arrayObject, i, scriptContext);
  8922. AnalysisAssert((i + 1) * sizeof(int32) <= allocSize);
  8923. ((int32*)buffer)[i] = Js::JavascriptConversion::ToInt32(element, scriptContext);
  8924. }
  8925. break;
  8926. case JsUint32Type:
  8927. AnalysisAssert(elementSize == sizeof(uint32));
  8928. for (UINT i = 0; i < length; i++)
  8929. {
  8930. element = GetElementAtIndex(arrayObject, i, scriptContext);
  8931. AnalysisAssert((i + 1) * sizeof(uint32) <= allocSize);
  8932. ((uint32*)buffer)[i] = Js::JavascriptConversion::ToUInt32(element, scriptContext);
  8933. }
  8934. break;
  8935. case JsInt64Type:
  8936. AnalysisAssert(elementSize == sizeof(int64));
  8937. for (UINT i = 0; i < length; i++)
  8938. {
  8939. element = GetElementAtIndex(arrayObject, i, scriptContext);
  8940. AnalysisAssert((i + 1) * sizeof(int64) <= allocSize);
  8941. ((int64*)buffer)[i] = Js::JavascriptConversion::ToInt64(element, scriptContext);
  8942. }
  8943. break;
  8944. case JsUint64Type:
  8945. AnalysisAssert(elementSize == sizeof(uint64));
  8946. for (UINT i = 0; i < length; i++)
  8947. {
  8948. element = GetElementAtIndex(arrayObject, i, scriptContext);
  8949. AnalysisAssert((i + 1) * sizeof(uint64) <= allocSize);
  8950. ((uint64*)buffer)[i] = Js::JavascriptConversion::ToUInt64(element, scriptContext);
  8951. }
  8952. break;
  8953. case JsFloatType:
  8954. AnalysisAssert(elementSize == sizeof(float));
  8955. for (UINT i = 0; i < length; i++)
  8956. {
  8957. element = GetElementAtIndex(arrayObject, i, scriptContext);
  8958. AnalysisAssert((i + 1) * sizeof(float) <= allocSize);
  8959. ((float*)buffer)[i] = Js::JavascriptConversion::ToFloat(element, scriptContext);
  8960. }
  8961. break;
  8962. case JsDoubleType:
  8963. AnalysisAssert(elementSize == sizeof(double));
  8964. for (UINT i = 0; i < length; i++)
  8965. {
  8966. element = GetElementAtIndex(arrayObject, i, scriptContext);
  8967. AnalysisAssert((i + 1) * sizeof(double) <= allocSize);
  8968. ((double*)buffer)[i] = Js::JavascriptConversion::ToNumber(element, scriptContext);
  8969. }
  8970. break;
  8971. case JsNativeStringType:
  8972. AnalysisAssert(elementSize == sizeof(JsNativeString));
  8973. for (UINT i = 0; i < length; i++)
  8974. {
  8975. element = GetElementAtIndex(arrayObject, i, scriptContext);
  8976. AnalysisAssert((i + 1) * sizeof(JsNativeString) <= allocSize);
  8977. Js::JavascriptString* string = Js::JavascriptConversion::ToString(element, scriptContext);
  8978. (((JsNativeString*)buffer)[i]).str = string->GetSz();
  8979. (((JsNativeString*)buffer)[i]).length = string->GetLength();
  8980. }
  8981. break;
  8982. default:
  8983. Assert(FALSE);
  8984. }
  8985. }
  8986. void JavascriptOperators::VarToNativeArray(Var arrayObject,
  8987. JsNativeValueType valueType,
  8988. __in UINT length,
  8989. __in UINT elementSize,
  8990. __out_bcount(length*elementSize) byte* buffer,
  8991. Js::ScriptContext* scriptContext)
  8992. {
  8993. Js::DynamicObject* dynamicObject = DynamicObject::FromVar(arrayObject);
  8994. if (dynamicObject->IsCrossSiteObject() || Js::TaggedInt::IsOverflow(length))
  8995. {
  8996. Js::JavascriptOperators::ObjectToNativeArray(&arrayObject, valueType, length, elementSize, buffer, scriptContext);
  8997. }
  8998. else
  8999. {
  9000. #if ENABLE_COPYONACCESS_ARRAY
  9001. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(arrayObject);
  9002. #endif
  9003. switch (Js::JavascriptOperators::GetTypeId(arrayObject))
  9004. {
  9005. case TypeIds_Array:
  9006. Js::JavascriptOperators::ObjectToNativeArray(Js::JavascriptArray::UnsafeFromVar(arrayObject), valueType, length, elementSize, buffer, scriptContext);
  9007. break;
  9008. case TypeIds_NativeFloatArray:
  9009. Js::JavascriptOperators::ObjectToNativeArray(Js::JavascriptNativeFloatArray::UnsafeFromVar(arrayObject), valueType, length, elementSize, buffer, scriptContext);
  9010. break;
  9011. case TypeIds_NativeIntArray:
  9012. Js::JavascriptOperators::ObjectToNativeArray(Js::JavascriptNativeIntArray::UnsafeFromVar(arrayObject), valueType, length, elementSize, buffer, scriptContext);
  9013. break;
  9014. // We can have more specialized template if needed.
  9015. default:
  9016. Js::JavascriptOperators::ObjectToNativeArray(&arrayObject, valueType, length, elementSize, buffer, scriptContext);
  9017. }
  9018. }
  9019. }
  9020. // SpeciesConstructor abstract operation as described in ES6.0 Section 7.3.20
  9021. RecyclableObject* JavascriptOperators::SpeciesConstructor(_In_ RecyclableObject* object, _In_ JavascriptFunction* defaultConstructor, _In_ ScriptContext* scriptContext)
  9022. {
  9023. //1.Assert: Type(O) is Object.
  9024. Assert(JavascriptOperators::IsObject(object));
  9025. //2.Let C be Get(O, "constructor").
  9026. //3.ReturnIfAbrupt(C).
  9027. Var constructor = JavascriptOperators::GetProperty(object, PropertyIds::constructor, scriptContext);
  9028. if (scriptContext->GetConfig()->IsES6SpeciesEnabled())
  9029. {
  9030. //4.If C is undefined, return defaultConstructor.
  9031. if (JavascriptOperators::IsUndefinedObject(constructor))
  9032. {
  9033. return defaultConstructor;
  9034. }
  9035. //5.If Type(C) is not Object, throw a TypeError exception.
  9036. if (!JavascriptOperators::IsObject(constructor))
  9037. {
  9038. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject, _u("[constructor]"));
  9039. }
  9040. //6.Let S be Get(C, @@species).
  9041. //7.ReturnIfAbrupt(S).
  9042. Var species = nullptr;
  9043. if (!JavascriptOperators::GetProperty(RecyclableObject::FromVar(constructor),
  9044. PropertyIds::_symbolSpecies, &species, scriptContext)
  9045. || JavascriptOperators::IsUndefinedOrNull(species))
  9046. {
  9047. //8.If S is either undefined or null, return defaultConstructor.
  9048. return defaultConstructor;
  9049. }
  9050. constructor = species;
  9051. }
  9052. //9.If IsConstructor(S) is true, return S.
  9053. RecyclableObject* constructorObj = JavascriptOperators::TryFromVar<RecyclableObject>(constructor);
  9054. if (constructorObj && JavascriptOperators::IsConstructor(constructorObj))
  9055. {
  9056. return constructorObj;
  9057. }
  9058. //10.Throw a TypeError exception.
  9059. JavascriptError::ThrowTypeError(scriptContext, JSERR_NotAConstructor, _u("constructor[Symbol.species]"));
  9060. }
  9061. BOOL JavascriptOperators::GreaterEqual(Var aLeft, Var aRight, ScriptContext* scriptContext)
  9062. {
  9063. JIT_HELPER_REENTRANT_HEADER(Op_GreaterEqual);
  9064. if (TaggedInt::Is(aLeft))
  9065. {
  9066. if (TaggedInt::Is(aRight))
  9067. {
  9068. // Works whether it is TaggedInt31 or TaggedInt32
  9069. return ::Math::PointerCastToIntegralTruncate<int>(aLeft) >= ::Math::PointerCastToIntegralTruncate<int>(aRight);
  9070. }
  9071. if (JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  9072. {
  9073. return TaggedInt::ToDouble(aLeft) >= JavascriptNumber::GetValue(aRight);
  9074. }
  9075. }
  9076. else if (TaggedInt::Is(aRight))
  9077. {
  9078. if (JavascriptNumber::Is_NoTaggedIntCheck(aLeft))
  9079. {
  9080. return JavascriptNumber::GetValue(aLeft) >= TaggedInt::ToDouble(aRight);
  9081. }
  9082. }
  9083. else
  9084. {
  9085. if (JavascriptNumber::Is_NoTaggedIntCheck(aLeft) && JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  9086. {
  9087. return JavascriptNumber::GetValue(aLeft) >= JavascriptNumber::GetValue(aRight);
  9088. }
  9089. }
  9090. return !RelationalComparisonHelper(aLeft, aRight, scriptContext, true, true);
  9091. JIT_HELPER_END(Op_GreaterEqual);
  9092. }
  9093. BOOL JavascriptOperators::LessEqual(Var aLeft, Var aRight, ScriptContext* scriptContext)
  9094. {
  9095. JIT_HELPER_REENTRANT_HEADER(Op_LessEqual);
  9096. if (TaggedInt::Is(aLeft))
  9097. {
  9098. if (TaggedInt::Is(aRight))
  9099. {
  9100. // Works whether it is TaggedInt31 or TaggedInt32
  9101. return ::Math::PointerCastToIntegralTruncate<int>(aLeft) <= ::Math::PointerCastToIntegralTruncate<int>(aRight);
  9102. }
  9103. if (JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  9104. {
  9105. return TaggedInt::ToDouble(aLeft) <= JavascriptNumber::GetValue(aRight);
  9106. }
  9107. }
  9108. else if (TaggedInt::Is(aRight))
  9109. {
  9110. if (JavascriptNumber::Is_NoTaggedIntCheck(aLeft))
  9111. {
  9112. return JavascriptNumber::GetValue(aLeft) <= TaggedInt::ToDouble(aRight);
  9113. }
  9114. }
  9115. else
  9116. {
  9117. if (JavascriptNumber::Is_NoTaggedIntCheck(aLeft) && JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  9118. {
  9119. return JavascriptNumber::GetValue(aLeft) <= JavascriptNumber::GetValue(aRight);
  9120. }
  9121. }
  9122. return !RelationalComparisonHelper(aRight, aLeft, scriptContext, false, true);
  9123. JIT_HELPER_END(Op_LessEqual);
  9124. }
  9125. BOOL JavascriptOperators::NotEqual(Var aLeft, Var aRight, ScriptContext* scriptContext)
  9126. {
  9127. JIT_HELPER_REENTRANT_HEADER(Op_NotEqual);
  9128. JIT_HELPER_SAME_ATTRIBUTES(Op_NotEqual, Op_Equal);
  9129. //
  9130. // TODO: Change to use Abstract Equality Comparison Algorithm (ES3.0: S11.9.3):
  9131. // - Evaluate left, then right, operands to preserve correct evaluation order.
  9132. // - Call algorithm, potentially reversing arguments.
  9133. //
  9134. return !Equal(aLeft, aRight, scriptContext);
  9135. JIT_HELPER_END(Op_NotEqual);
  9136. }
  9137. // NotStrictEqual() returns whether the two vars have strict equality, as
  9138. // described in (ES3.0: S11.9.5, S11.9.6).
  9139. BOOL JavascriptOperators::NotStrictEqual(Var aLeft, Var aRight, ScriptContext* scriptContext)
  9140. {
  9141. JIT_HELPER_REENTRANT_HEADER(Op_NotStrictEqual);
  9142. JIT_HELPER_SAME_ATTRIBUTES(Op_NotStrictEqual, Op_StrictEqual);
  9143. return !StrictEqual(aLeft, aRight, scriptContext);
  9144. JIT_HELPER_END(Op_NotStrictEqual);
  9145. }
  9146. bool JavascriptOperators::CheckIfObjectAndPrototypeChainHasOnlyWritableDataProperties(_In_ RecyclableObject* object)
  9147. {
  9148. return object->GetLibrary()->GetTypesWithOnlyWritablePropertyProtoChainCache()->Check(object);
  9149. }
  9150. bool JavascriptOperators::CheckIfPrototypeChainHasOnlyWritableDataProperties(_In_ RecyclableObject* prototype)
  9151. {
  9152. return prototype->GetLibrary()->GetTypesWithOnlyWritablePropertyProtoChainCache()->CheckProtoChain(prototype);
  9153. }
  9154. bool JavascriptOperators::CheckIfObjectAndProtoChainHasNoSpecialProperties(_In_ RecyclableObject* object)
  9155. {
  9156. return object->GetLibrary()->GetTypesWithNoSpecialPropertyProtoChainCache()->Check(object);
  9157. }
  9158. // Checks to see if the specified object (which should be a prototype object)
  9159. // contains a proxy anywhere in the prototype chain.
  9160. bool JavascriptOperators::CheckIfPrototypeChainContainsProxyObject(RecyclableObject* prototype)
  9161. {
  9162. if (prototype == nullptr)
  9163. {
  9164. return false;
  9165. }
  9166. Assert(JavascriptOperators::IsObjectOrNull(prototype));
  9167. while (prototype->GetTypeId() != TypeIds_Null)
  9168. {
  9169. if (prototype->GetTypeId() == TypeIds_Proxy)
  9170. {
  9171. return true;
  9172. }
  9173. prototype = prototype->GetPrototype();
  9174. }
  9175. return false;
  9176. }
  9177. BOOL JavascriptOperators::Equal(Var aLeft, Var aRight, ScriptContext* scriptContext)
  9178. {
  9179. JIT_HELPER_REENTRANT_HEADER(Op_Equal);
  9180. JIT_HELPER_SAME_ATTRIBUTES(Op_Equal, Op_Equal_Full);
  9181. if (aLeft == aRight)
  9182. {
  9183. if (TaggedInt::Is(aLeft) || JavascriptObject::Is(aLeft))
  9184. {
  9185. return true;
  9186. }
  9187. else
  9188. {
  9189. return Equal_Full(aLeft, aRight, scriptContext);
  9190. }
  9191. }
  9192. if (JavascriptString::Is(aLeft) && JavascriptString::Is(aRight))
  9193. {
  9194. JavascriptString* left = (JavascriptString*)aLeft;
  9195. JavascriptString* right = (JavascriptString*)aRight;
  9196. if (left->GetLength() == right->GetLength())
  9197. {
  9198. if (left->UnsafeGetBuffer() != NULL && right->UnsafeGetBuffer() != NULL)
  9199. {
  9200. if (left->GetLength() == 1)
  9201. {
  9202. return left->UnsafeGetBuffer()[0] == right->UnsafeGetBuffer()[0];
  9203. }
  9204. return memcmp(left->UnsafeGetBuffer(), right->UnsafeGetBuffer(), left->GetLength() * sizeof(left->UnsafeGetBuffer()[0])) == 0;
  9205. }
  9206. // fall through to Equal_Full
  9207. }
  9208. else
  9209. {
  9210. return false;
  9211. }
  9212. }
  9213. return Equal_Full(aLeft, aRight, scriptContext);
  9214. JIT_HELPER_END(Op_Equal);
  9215. }
  9216. BOOL JavascriptOperators::Greater(Var aLeft, Var aRight, ScriptContext* scriptContext)
  9217. {
  9218. JIT_HELPER_REENTRANT_HEADER(Op_Greater);
  9219. if (TaggedInt::Is(aLeft))
  9220. {
  9221. if (TaggedInt::Is(aRight))
  9222. {
  9223. // Works whether it is TaggedInt31 or TaggedInt32
  9224. return ::Math::PointerCastToIntegralTruncate<int>(aLeft) > ::Math::PointerCastToIntegralTruncate<int>(aRight);
  9225. }
  9226. if (JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  9227. {
  9228. return TaggedInt::ToDouble(aLeft) > JavascriptNumber::GetValue(aRight);
  9229. }
  9230. }
  9231. else if (TaggedInt::Is(aRight))
  9232. {
  9233. if (JavascriptNumber::Is_NoTaggedIntCheck(aLeft))
  9234. {
  9235. return JavascriptNumber::GetValue(aLeft) > TaggedInt::ToDouble(aRight);
  9236. }
  9237. }
  9238. else
  9239. {
  9240. if (JavascriptNumber::Is_NoTaggedIntCheck(aLeft) && JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  9241. {
  9242. return JavascriptNumber::GetValue(aLeft) > JavascriptNumber::GetValue(aRight);
  9243. }
  9244. }
  9245. return Greater_Full(aLeft, aRight, scriptContext);
  9246. JIT_HELPER_END(Op_Greater);
  9247. }
  9248. BOOL JavascriptOperators::Less(Var aLeft, Var aRight, ScriptContext* scriptContext)
  9249. {
  9250. JIT_HELPER_REENTRANT_HEADER(Op_Less);
  9251. if (TaggedInt::Is(aLeft))
  9252. {
  9253. if (TaggedInt::Is(aRight))
  9254. {
  9255. // Works whether it is TaggedInt31 or TaggedInt32
  9256. return ::Math::PointerCastToIntegralTruncate<int>(aLeft) < ::Math::PointerCastToIntegralTruncate<int>(aRight);
  9257. }
  9258. if (JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  9259. {
  9260. return TaggedInt::ToDouble(aLeft) < JavascriptNumber::GetValue(aRight);
  9261. }
  9262. }
  9263. else if (TaggedInt::Is(aRight))
  9264. {
  9265. if (JavascriptNumber::Is_NoTaggedIntCheck(aLeft))
  9266. {
  9267. return JavascriptNumber::GetValue(aLeft) < TaggedInt::ToDouble(aRight);
  9268. }
  9269. }
  9270. else
  9271. {
  9272. if (JavascriptNumber::Is_NoTaggedIntCheck(aLeft) && JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  9273. {
  9274. return JavascriptNumber::GetValue(aLeft) < JavascriptNumber::GetValue(aRight);
  9275. }
  9276. }
  9277. return Less_Full(aLeft, aRight, scriptContext);
  9278. JIT_HELPER_END(Op_Less);
  9279. }
  9280. RecyclableObject* JavascriptOperators::ToObject(Var aRight, ScriptContext* scriptContext)
  9281. {
  9282. JIT_HELPER_NOT_REENTRANT_HEADER(Op_ConvObject, reentrancylock, scriptContext->GetThreadContext());
  9283. RecyclableObject* object = nullptr;
  9284. if (FALSE == JavascriptConversion::ToObject(aRight, scriptContext, &object))
  9285. {
  9286. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject /* TODO-ERROR: get arg name - aValue */);
  9287. }
  9288. return object;
  9289. JIT_HELPER_END(Op_ConvObject);
  9290. }
  9291. Var JavascriptOperators::ToWithObject(Var aRight, ScriptContext* scriptContext)
  9292. {
  9293. JIT_HELPER_NOT_REENTRANT_HEADER(Op_NewWithObject, reentrancylock, scriptContext->GetThreadContext());
  9294. RecyclableObject* object = RecyclableObject::FromVar(aRight);
  9295. WithScopeObject* withWrapper = RecyclerNew(scriptContext->GetRecycler(), WithScopeObject, object, scriptContext->GetLibrary()->GetWithType());
  9296. return withWrapper;
  9297. JIT_HELPER_END(Op_NewWithObject);
  9298. }
  9299. Var JavascriptOperators::ToNumber(Var aRight, ScriptContext* scriptContext)
  9300. {
  9301. JIT_HELPER_REENTRANT_HEADER(Op_ConvNumber_Full);
  9302. if (TaggedInt::Is(aRight) || (JavascriptNumber::Is_NoTaggedIntCheck(aRight)))
  9303. {
  9304. return aRight;
  9305. }
  9306. return JavascriptNumber::ToVarNoCheck(JavascriptConversion::ToNumber_Full(aRight, scriptContext), scriptContext);
  9307. JIT_HELPER_END(Op_ConvNumber_Full);
  9308. }
  9309. BOOL JavascriptOperators::IsObject(_In_ RecyclableObject* instance)
  9310. {
  9311. return GetTypeId(instance) > TypeIds_LastJavascriptPrimitiveType;
  9312. }
  9313. BOOL JavascriptOperators::IsObject(_In_ Var instance)
  9314. {
  9315. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(Op_IsObject);
  9316. return GetTypeId(instance) > TypeIds_LastJavascriptPrimitiveType;
  9317. JIT_HELPER_END(Op_IsObject);
  9318. }
  9319. BOOL JavascriptOperators::IsObjectType(TypeId typeId)
  9320. {
  9321. return typeId > TypeIds_LastJavascriptPrimitiveType;
  9322. }
  9323. BOOL JavascriptOperators::IsExposedType(TypeId typeId)
  9324. {
  9325. return typeId <= TypeIds_LastTrueJavascriptObjectType && typeId != TypeIds_HostDispatch;
  9326. }
  9327. BOOL JavascriptOperators::IsObjectOrNull(Var instance)
  9328. {
  9329. TypeId typeId = GetTypeId(instance);
  9330. return IsObjectType(typeId) || typeId == TypeIds_Null;
  9331. }
  9332. BOOL JavascriptOperators::IsUndefined(_In_ RecyclableObject* instance)
  9333. {
  9334. return JavascriptOperators::GetTypeId(instance) == TypeIds_Undefined;
  9335. }
  9336. BOOL JavascriptOperators::IsUndefined(Var instance)
  9337. {
  9338. return JavascriptOperators::GetTypeId(instance) == TypeIds_Undefined;
  9339. }
  9340. BOOL JavascriptOperators::IsUndefinedOrNullType(TypeId typeId)
  9341. {
  9342. return typeId <= TypeIds_UndefinedOrNull;
  9343. }
  9344. BOOL JavascriptOperators::IsUndefinedOrNull(Var instance)
  9345. {
  9346. return IsUndefinedOrNullType(JavascriptOperators::GetTypeId(instance));
  9347. }
  9348. BOOL JavascriptOperators::IsUndefinedOrNull(RecyclableObject* instance)
  9349. {
  9350. return JavascriptOperators::IsUndefinedOrNullType(instance->GetTypeId());
  9351. }
  9352. BOOL JavascriptOperators::IsUndefinedOrNull(Var instance, ScriptContext* scriptContext)
  9353. {
  9354. JavascriptLibrary* library = scriptContext->GetLibrary();
  9355. return IsUndefinedObject(instance, library) || IsNull(instance, library);
  9356. }
  9357. BOOL JavascriptOperators::IsUndefinedOrNull(Var instance, JavascriptLibrary* library)
  9358. {
  9359. return IsUndefinedObject(instance, library) || IsNull(instance, library);
  9360. }
  9361. BOOL JavascriptOperators::IsNull(Var instance)
  9362. {
  9363. return JavascriptOperators::GetTypeId(instance) == TypeIds_Null;
  9364. }
  9365. BOOL JavascriptOperators::IsNull(Var instance, ScriptContext* scriptContext)
  9366. {
  9367. return JavascriptOperators::IsNull(instance, scriptContext->GetLibrary());
  9368. }
  9369. BOOL JavascriptOperators::IsNull(Var instance, JavascriptLibrary* library)
  9370. {
  9371. Assert(!RecyclableObject::Is(instance) ? TRUE : ((RecyclableObject*)instance)->GetScriptContext()->GetLibrary() == library );
  9372. return library->GetNull() == instance;
  9373. }
  9374. BOOL JavascriptOperators::IsNull(RecyclableObject* instance)
  9375. {
  9376. return instance->GetType()->GetTypeId() == TypeIds_Null;
  9377. }
  9378. BOOL JavascriptOperators::IsSpecialObjectType(TypeId typeId)
  9379. {
  9380. return typeId > TypeIds_LastTrueJavascriptObjectType;
  9381. }
  9382. BOOL JavascriptOperators::IsUndefinedObject(Var instance)
  9383. {
  9384. return JavascriptOperators::GetTypeId(instance) == TypeIds_Undefined;
  9385. }
  9386. BOOL JavascriptOperators::IsUndefinedObject(RecyclableObject* instance)
  9387. {
  9388. return instance->GetType()->GetTypeId() == TypeIds_Undefined;
  9389. }
  9390. BOOL JavascriptOperators::IsUndefinedObject(Var instance, RecyclableObject *libraryUndefined)
  9391. {
  9392. Assert(JavascriptOperators::IsUndefinedObject(libraryUndefined));
  9393. AssertMsg((instance == libraryUndefined)
  9394. == JavascriptOperators::IsUndefinedObject(instance), "Wrong ScriptContext?");
  9395. return instance == libraryUndefined;
  9396. }
  9397. BOOL JavascriptOperators::IsUndefinedObject(Var instance, ScriptContext *scriptContext)
  9398. {
  9399. return JavascriptOperators::IsUndefinedObject(instance, scriptContext->GetLibrary());
  9400. }
  9401. BOOL JavascriptOperators::IsUndefinedObject(Var instance, JavascriptLibrary* library)
  9402. {
  9403. Assert(!RecyclableObject::Is(instance) ? TRUE : ((RecyclableObject*)instance)->GetScriptContext()->GetLibrary() == library );
  9404. return JavascriptOperators::IsUndefinedObject(instance, library->GetUndefined());
  9405. }
  9406. BOOL JavascriptOperators::IsAnyNumberValue(Var instance)
  9407. {
  9408. TypeId typeId = GetTypeId(instance);
  9409. return TypeIds_FirstNumberType <= typeId && typeId <= TypeIds_LastNumberType;
  9410. }
  9411. // GetIterator as described in ES6.0 (draft 22) Section 7.4.1
  9412. RecyclableObject* JavascriptOperators::GetIterator(Var iterable, ScriptContext* scriptContext, bool optional)
  9413. {
  9414. RecyclableObject* iterableObj = JavascriptOperators::ToObject(iterable, scriptContext);
  9415. return JavascriptOperators::GetIterator(iterableObj, scriptContext, optional);
  9416. }
  9417. RecyclableObject* JavascriptOperators::GetIteratorFunction(Var iterable, ScriptContext* scriptContext, bool optional)
  9418. {
  9419. RecyclableObject* iterableObj = JavascriptOperators::ToObject(iterable, scriptContext);
  9420. return JavascriptOperators::GetIteratorFunction(iterableObj, scriptContext, optional);
  9421. }
  9422. RecyclableObject* JavascriptOperators::GetIteratorFunction(RecyclableObject* instance, ScriptContext * scriptContext, bool optional)
  9423. {
  9424. Var func = JavascriptOperators::GetPropertyNoCache(instance, PropertyIds::_symbolIterator, scriptContext);
  9425. if (optional && JavascriptOperators::IsUndefinedOrNull(func))
  9426. {
  9427. return nullptr;
  9428. }
  9429. if (!JavascriptConversion::IsCallable(func))
  9430. {
  9431. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction);
  9432. }
  9433. RecyclableObject* function = RecyclableObject::FromVar(func);
  9434. return function;
  9435. }
  9436. RecyclableObject* JavascriptOperators::GetIterator(RecyclableObject* instance, ScriptContext * scriptContext, bool optional)
  9437. {
  9438. RecyclableObject* function = GetIteratorFunction(instance, scriptContext, optional);
  9439. if (function == nullptr)
  9440. {
  9441. Assert(optional);
  9442. return nullptr;
  9443. }
  9444. Var iterator = scriptContext->GetThreadContext()->ExecuteImplicitCall(function, Js::ImplicitCall_Accessor, [=]()->Js::Var
  9445. {
  9446. return CALL_FUNCTION(scriptContext->GetThreadContext(), function, CallInfo(Js::CallFlags_Value, 1), instance);
  9447. });
  9448. if (!JavascriptOperators::IsObject(iterator))
  9449. {
  9450. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject);
  9451. }
  9452. return RecyclableObject::FromVar(iterator);
  9453. }
  9454. void JavascriptOperators::IteratorClose(RecyclableObject* iterator, ScriptContext* scriptContext)
  9455. {
  9456. try
  9457. {
  9458. Var func = JavascriptOperators::GetProperty(iterator, PropertyIds::return_, scriptContext);
  9459. if (JavascriptConversion::IsCallable(func))
  9460. {
  9461. RecyclableObject* callable = RecyclableObject::FromVar(func);
  9462. scriptContext->GetThreadContext()->ExecuteImplicitCall(callable, ImplicitCall_Accessor, [=]()->Var
  9463. {
  9464. Js::Var args[] = { iterator };
  9465. Js::CallInfo callInfo(Js::CallFlags_Value, _countof(args));
  9466. return JavascriptFunction::CallFunction<true>(callable, callable->GetEntryPoint(), Js::Arguments(callInfo, args));
  9467. });
  9468. }
  9469. }
  9470. catch (const JavascriptException& err)
  9471. {
  9472. err.GetAndClear(); // discard exception object
  9473. // We have arrived in this function due to AbruptCompletion (which is an exception), so we don't need to
  9474. // propagate the exception of calling return function
  9475. }
  9476. }
  9477. // IteratorNext as described in ES6.0 (draft 22) Section 7.4.2
  9478. RecyclableObject* JavascriptOperators::IteratorNext(RecyclableObject* iterator, ScriptContext* scriptContext, Var value)
  9479. {
  9480. Var func = JavascriptOperators::GetPropertyNoCache(iterator, PropertyIds::next, scriptContext);
  9481. ThreadContext *threadContext = scriptContext->GetThreadContext();
  9482. if (!JavascriptConversion::IsCallable(func))
  9483. {
  9484. if (!threadContext->RecordImplicitException())
  9485. {
  9486. return scriptContext->GetLibrary()->GetUndefined();
  9487. }
  9488. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction);
  9489. }
  9490. RecyclableObject* callable = RecyclableObject::FromVar(func);
  9491. Var result = threadContext->ExecuteImplicitCall(callable, ImplicitCall_Accessor, [=]() -> Var
  9492. {
  9493. Js::Var args[] = { iterator, value };
  9494. Js::CallInfo callInfo(Js::CallFlags_Value, _countof(args) + (value == nullptr ? -1 : 0));
  9495. return JavascriptFunction::CallFunction<true>(callable, callable->GetEntryPoint(), Arguments(callInfo, args));
  9496. });
  9497. if (!JavascriptOperators::IsObject(result))
  9498. {
  9499. if (!threadContext->RecordImplicitException())
  9500. {
  9501. return scriptContext->GetLibrary()->GetUndefined();
  9502. }
  9503. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject);
  9504. }
  9505. return RecyclableObject::FromVar(result);
  9506. }
  9507. // IteratorComplete as described in ES6.0 (draft 22) Section 7.4.3
  9508. bool JavascriptOperators::IteratorComplete(RecyclableObject* iterResult, ScriptContext* scriptContext)
  9509. {
  9510. Var done = JavascriptOperators::GetPropertyNoCache(iterResult, Js::PropertyIds::done, scriptContext);
  9511. return JavascriptConversion::ToBool(done, scriptContext);
  9512. }
  9513. // IteratorValue as described in ES6.0 (draft 22) Section 7.4.4
  9514. Var JavascriptOperators::IteratorValue(RecyclableObject* iterResult, ScriptContext* scriptContext)
  9515. {
  9516. return JavascriptOperators::GetPropertyNoCache(iterResult, Js::PropertyIds::value, scriptContext);
  9517. }
  9518. // IteratorStep as described in ES6.0 (draft 22) Section 7.4.5
  9519. bool JavascriptOperators::IteratorStep(RecyclableObject* iterator, ScriptContext* scriptContext, RecyclableObject** result)
  9520. {
  9521. Assert(result);
  9522. *result = JavascriptOperators::IteratorNext(iterator, scriptContext);
  9523. return !JavascriptOperators::IteratorComplete(*result, scriptContext);
  9524. }
  9525. bool JavascriptOperators::IteratorStepAndValue(RecyclableObject* iterator, ScriptContext* scriptContext, Var* resultValue)
  9526. {
  9527. // CONSIDER: Fast-pathing for iterators that are built-ins?
  9528. RecyclableObject* result = JavascriptOperators::IteratorNext(iterator, scriptContext);
  9529. if (!JavascriptOperators::IteratorComplete(result, scriptContext))
  9530. {
  9531. *resultValue = JavascriptOperators::IteratorValue(result, scriptContext);
  9532. return true;
  9533. }
  9534. return false;
  9535. }
  9536. RecyclableObject* JavascriptOperators::CreateFromConstructor(RecyclableObject* constructor, ScriptContext* scriptContext)
  9537. {
  9538. // Create a regular object and set the internal proto from the constructor
  9539. return JavascriptOperators::OrdinaryCreateFromConstructor(constructor, scriptContext->GetLibrary()->CreateObject(), nullptr, scriptContext);
  9540. }
  9541. RecyclableObject* JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject* constructor, RecyclableObject* obj, DynamicObject* intrinsicProto, ScriptContext* scriptContext)
  9542. {
  9543. // There isn't a good way for us to add internal properties to objects in Chakra.
  9544. // Thus, caller should take care to create obj with the correct internal properties.
  9545. Var proto = JavascriptOperators::GetPropertyNoCache(constructor, Js::PropertyIds::prototype, scriptContext);
  9546. // If constructor.prototype is an object, we should use that as the [[Prototype]] for our obj.
  9547. // Else, we set the [[Prototype]] internal slot of obj to %intrinsicProto% - which should be the default.
  9548. if (JavascriptOperators::IsObjectType(JavascriptOperators::GetTypeId(proto)) &&
  9549. DynamicObject::FromVar(proto) != intrinsicProto)
  9550. {
  9551. JavascriptObject::ChangePrototype(obj, RecyclableObject::FromVar(proto), /*validate*/true, scriptContext);
  9552. }
  9553. return obj;
  9554. }
  9555. Var JavascriptOperators::GetProperty(RecyclableObject* instance, PropertyId propertyId, ScriptContext* requestContext, PropertyValueInfo* info)
  9556. {
  9557. return JavascriptOperators::GetProperty(instance, instance, propertyId, requestContext, info);
  9558. }
  9559. BOOL JavascriptOperators::GetProperty(RecyclableObject* instance, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info)
  9560. {
  9561. return JavascriptOperators::GetProperty(instance, instance, propertyId, value, requestContext, info);
  9562. }
  9563. Var JavascriptOperators::GetProperty(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, ScriptContext* requestContext, PropertyValueInfo* info)
  9564. {
  9565. Var value;
  9566. if (JavascriptOperators::GetProperty(instance, propertyObject, propertyId, &value, requestContext, info))
  9567. {
  9568. return value;
  9569. }
  9570. return requestContext->GetMissingPropertyResult();
  9571. }
  9572. Var JavascriptOperators::GetPropertyNoCache(RecyclableObject* instance, PropertyId propertyId, ScriptContext* requestContext)
  9573. {
  9574. return JavascriptOperators::GetPropertyNoCache(instance, instance, propertyId, requestContext);
  9575. }
  9576. Var JavascriptOperators::GetPropertyNoCache(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, ScriptContext* requestContext)
  9577. {
  9578. Var value;
  9579. JavascriptOperators::GetProperty_InternalSimple(instance, propertyObject, propertyId, &value, requestContext);
  9580. return value;
  9581. }
  9582. BOOL JavascriptOperators::GetPropertyNoCache(RecyclableObject* instance, PropertyId propertyId, Var* value, ScriptContext* requestContext)
  9583. {
  9584. return JavascriptOperators::GetPropertyNoCache(instance, instance, propertyId, value, requestContext);
  9585. }
  9586. BOOL JavascriptOperators::GetPropertyNoCache(Var instance, RecyclableObject* propertyObject, PropertyId propertyId, Var* value, ScriptContext* requestContext)
  9587. {
  9588. return JavascriptOperators::GetProperty_InternalSimple(instance, propertyObject, propertyId, value, requestContext);
  9589. }
  9590. Var JavascriptOperators::GetRootProperty(RecyclableObject* instance, PropertyId propertyId, ScriptContext* requestContext, PropertyValueInfo* info)
  9591. {
  9592. Var value;
  9593. if (JavascriptOperators::GetRootProperty(instance, propertyId, &value, requestContext, info))
  9594. {
  9595. return value;
  9596. }
  9597. return requestContext->GetMissingPropertyResult();
  9598. }
  9599. BOOL JavascriptOperators::GetPropertyReference(RecyclableObject *instance, PropertyId propertyId, Var* value, ScriptContext* requestContext, PropertyValueInfo* info)
  9600. {
  9601. return JavascriptOperators::GetPropertyReference(instance, instance, propertyId, value, requestContext, info);
  9602. }
  9603. Var JavascriptOperators::GetItem(RecyclableObject* instance, uint32 index, ScriptContext* requestContext)
  9604. {
  9605. Var value;
  9606. if (GetItem(instance, index, &value, requestContext))
  9607. {
  9608. return value;
  9609. }
  9610. return requestContext->GetMissingItemResult();
  9611. }
  9612. Var JavascriptOperators::GetItem(RecyclableObject* instance, uint64 index, ScriptContext* requestContext)
  9613. {
  9614. Var value;
  9615. if (GetItem(instance, index, &value, requestContext))
  9616. {
  9617. return value;
  9618. }
  9619. return requestContext->GetMissingItemResult();
  9620. }
  9621. BOOL JavascriptOperators::GetItem(RecyclableObject* instance, uint64 index, Var* value, ScriptContext* requestContext)
  9622. {
  9623. if (index < JavascriptArray::InvalidIndex)
  9624. {
  9625. // In case index fits in uint32, we can avoid the (slower) big-index path
  9626. return GetItem(instance, static_cast<uint32>(index), value, requestContext);
  9627. }
  9628. PropertyRecord const * propertyRecord = nullptr;
  9629. JavascriptOperators::GetPropertyIdForInt(index, requestContext, &propertyRecord);
  9630. return JavascriptOperators::GetProperty(instance, propertyRecord->GetPropertyId(), value, requestContext);
  9631. }
  9632. BOOL JavascriptOperators::GetItem(RecyclableObject* instance, uint32 index, Var* value, ScriptContext* requestContext)
  9633. {
  9634. return JavascriptOperators::GetItem(instance, instance, index, value, requestContext);
  9635. }
  9636. BOOL JavascriptOperators::GetItemReference(RecyclableObject* instance, uint32 index, Var* value, ScriptContext* requestContext)
  9637. {
  9638. return GetItemReference(instance, instance, index, value, requestContext);
  9639. }
  9640. BOOL JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(RecyclableObject* instance, PropertyId propertyId, Var* setterValue, DescriptorFlags* flags, PropertyValueInfo* info, ScriptContext* scriptContext)
  9641. {
  9642. if (propertyId == Js::PropertyIds::__proto__)
  9643. {
  9644. return CheckPrototypesForAccessorOrNonWritablePropertyCore<PropertyId, false, false>(instance, propertyId, setterValue, flags, info, scriptContext);
  9645. }
  9646. else
  9647. {
  9648. return CheckPrototypesForAccessorOrNonWritablePropertyCore<PropertyId, true, false>(instance, propertyId, setterValue, flags, info, scriptContext);
  9649. }
  9650. }
  9651. BOOL JavascriptOperators::CheckPrototypesForAccessorOrNonWritableRootProperty(RecyclableObject* instance, PropertyId propertyId, Var* setterValue, DescriptorFlags* flags, PropertyValueInfo* info, ScriptContext* scriptContext)
  9652. {
  9653. if (propertyId == Js::PropertyIds::__proto__)
  9654. {
  9655. return CheckPrototypesForAccessorOrNonWritablePropertyCore<PropertyId, false, true>(instance, propertyId, setterValue, flags, info, scriptContext);
  9656. }
  9657. else
  9658. {
  9659. return CheckPrototypesForAccessorOrNonWritablePropertyCore<PropertyId, true, true>(instance, propertyId, setterValue, flags, info, scriptContext);
  9660. }
  9661. }
  9662. BOOL JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(RecyclableObject* instance, JavascriptString* propertyNameString, Var* setterValue, DescriptorFlags* flags, PropertyValueInfo* info, ScriptContext* scriptContext)
  9663. {
  9664. Js::PropertyRecord const * localPropertyRecord;
  9665. propertyNameString->GetPropertyRecord(&localPropertyRecord);
  9666. PropertyId propertyId = localPropertyRecord->GetPropertyId();
  9667. return CheckPrototypesForAccessorOrNonWritableProperty(instance, propertyId, setterValue, flags, info, scriptContext);
  9668. }
  9669. BOOL JavascriptOperators::SetProperty(Var instance, RecyclableObject* object, PropertyId propertyId, Var newValue, ScriptContext* requestContext, PropertyOperationFlags propertyOperationFlags)
  9670. {
  9671. PropertyValueInfo info;
  9672. return JavascriptOperators::SetProperty(instance, object, propertyId, newValue, &info, requestContext, propertyOperationFlags);
  9673. }
  9674. BOOL JavascriptOperators::TryConvertToUInt32(const char16* str, int length, uint32* intVal)
  9675. {
  9676. return NumberUtilities::TryConvertToUInt32(str, length, intVal);
  9677. }
  9678. template <typename TPropertyKey>
  9679. DescriptorFlags JavascriptOperators::GetRootSetter(RecyclableObject* instance, TPropertyKey propertyKey, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  9680. {
  9681. // This is provided only so that CheckPrototypesForAccessorOrNonWritablePropertyCore will compile.
  9682. // It will never be called.
  9683. Throw::FatalInternalError();
  9684. }
  9685. template <>
  9686. inline DescriptorFlags JavascriptOperators::GetRootSetter(RecyclableObject* instance, PropertyId propertyId, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  9687. {
  9688. AssertMsg(JavascriptOperators::GetTypeId(instance) == TypeIds_GlobalObject
  9689. || JavascriptOperators::GetTypeId(instance) == TypeIds_ModuleRoot,
  9690. "Root must be a global object!");
  9691. RootObjectBase* rootObject = static_cast<RootObjectBase*>(instance);
  9692. return rootObject->GetRootSetter(propertyId, setterValue, info, requestContext);
  9693. }
  9694. // Helper to fetch @@species from a constructor object
  9695. Var JavascriptOperators::GetSpecies(RecyclableObject* constructor, ScriptContext* scriptContext)
  9696. {
  9697. if (scriptContext->GetConfig()->IsES6SpeciesEnabled())
  9698. {
  9699. Var species = nullptr;
  9700. // Let S be Get(C, @@species)
  9701. if (JavascriptOperators::GetProperty(constructor, PropertyIds::_symbolSpecies, &species, scriptContext)
  9702. && !JavascriptOperators::IsUndefinedOrNull(species))
  9703. {
  9704. // If S is neither undefined nor null, let C be S
  9705. return species;
  9706. }
  9707. }
  9708. return constructor;
  9709. }