JavascriptOperators.cpp 505 KB

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