JavascriptOperators.cpp 489 KB

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