JavascriptOperators.cpp 459 KB

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