| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842298432984429845298462984729848298492985029851298522985329854298552985629857298582985929860298612986229863298642986529866298672986829869298702987129872298732987429875298762987729878298792988029881298822988329884298852988629887298882988929890298912989229893298942989529896298972989829899299002990129902299032990429905299062990729908299092991029911299122991329914299152991629917299182991929920299212992229923299242992529926299272992829929299302993129932299332993429935299362993729938299392994029941299422994329944299452994629947299482994929950299512995229953299542995529956299572995829959299602996129962299632996429965299662996729968299692997029971299722997329974299752997629977299782997929980299812998229983299842998529986299872998829989299902999129992299932999429995299962999729998299993000030001300023000330004300053000630007300083000930010300113001230013300143001530016300173001830019300203002130022300233002430025300263002730028300293003030031300323003330034300353003630037300383003930040300413004230043300443004530046300473004830049300503005130052300533005430055300563005730058300593006030061300623006330064300653006630067300683006930070300713007230073300743007530076300773007830079300803008130082300833008430085300863008730088300893009030091300923009330094300953009630097300983009930100301013010230103301043010530106301073010830109301103011130112301133011430115301163011730118301193012030121301223012330124301253012630127301283012930130301313013230133301343013530136301373013830139301403014130142301433014430145301463014730148301493015030151301523015330154301553015630157301583015930160301613016230163301643016530166301673016830169301703017130172301733017430175301763017730178301793018030181301823018330184301853018630187301883018930190301913019230193301943019530196301973019830199302003020130202302033020430205302063020730208302093021030211302123021330214302153021630217302183021930220302213022230223302243022530226302273022830229302303023130232302333023430235302363023730238302393024030241302423024330244302453024630247302483024930250302513025230253302543025530256302573025830259302603026130262302633026430265302663026730268302693027030271302723027330274302753027630277302783027930280302813028230283302843028530286302873028830289302903029130292302933029430295302963029730298302993030030301303023030330304303053030630307303083030930310303113031230313303143031530316303173031830319303203032130322303233032430325303263032730328303293033030331303323033330334303353033630337303383033930340303413034230343303443034530346303473034830349303503035130352303533035430355303563035730358303593036030361303623036330364303653036630367303683036930370303713037230373303743037530376303773037830379303803038130382303833038430385303863038730388303893039030391303923039330394303953039630397303983039930400304013040230403304043040530406304073040830409304103041130412304133041430415304163041730418304193042030421304223042330424304253042630427304283042930430304313043230433304343043530436304373043830439304403044130442304433044430445304463044730448304493045030451304523045330454304553045630457304583045930460304613046230463304643046530466304673046830469304703047130472304733047430475304763047730478304793048030481304823048330484304853048630487304883048930490304913049230493304943049530496304973049830499305003050130502305033050430505305063050730508305093051030511305123051330514305153051630517305183051930520305213052230523305243052530526305273052830529305303053130532305333053430535305363053730538305393054030541305423054330544305453054630547305483054930550305513055230553305543055530556305573055830559305603056130562305633056430565305663056730568305693057030571305723057330574305753057630577305783057930580305813058230583305843058530586305873058830589305903059130592305933059430595305963059730598305993060030601306023060330604306053060630607306083060930610306113061230613306143061530616306173061830619306203062130622306233062430625306263062730628306293063030631306323063330634306353063630637306383063930640306413064230643306443064530646306473064830649306503065130652306533065430655306563065730658306593066030661306623066330664306653066630667306683066930670306713067230673306743067530676306773067830679306803068130682306833068430685306863068730688306893069030691306923069330694306953069630697306983069930700307013070230703307043070530706307073070830709307103071130712307133071430715307163071730718307193072030721307223072330724307253072630727307283072930730307313073230733307343073530736307373073830739307403074130742307433074430745307463074730748307493075030751307523075330754307553075630757307583075930760307613076230763307643076530766307673076830769307703077130772307733077430775307763077730778307793078030781307823078330784307853078630787307883078930790307913079230793307943079530796307973079830799308003080130802308033080430805308063080730808308093081030811308123081330814308153081630817308183081930820308213082230823308243082530826308273082830829308303083130832308333083430835308363083730838308393084030841308423084330844308453084630847308483084930850308513085230853308543085530856308573085830859308603086130862308633086430865308663086730868308693087030871308723087330874308753087630877308783087930880308813088230883308843088530886308873088830889308903089130892308933089430895308963089730898308993090030901309023090330904309053090630907309083090930910309113091230913309143091530916309173091830919309203092130922309233092430925309263092730928309293093030931309323093330934309353093630937309383093930940309413094230943309443094530946309473094830949309503095130952309533095430955309563095730958309593096030961309623096330964309653096630967309683096930970309713097230973309743097530976309773097830979309803098130982309833098430985309863098730988309893099030991309923099330994309953099630997309983099931000310013100231003310043100531006310073100831009310103101131012310133101431015310163101731018310193102031021310223102331024310253102631027310283102931030310313103231033310343103531036310373103831039310403104131042310433104431045310463104731048310493105031051310523105331054310553105631057310583105931060310613106231063310643106531066310673106831069310703107131072310733107431075310763107731078310793108031081310823108331084310853108631087310883108931090310913109231093310943109531096310973109831099311003110131102311033110431105311063110731108311093111031111311123111331114311153111631117311183111931120311213112231123311243112531126311273112831129311303113131132311333113431135311363113731138311393114031141311423114331144311453114631147311483114931150311513115231153311543115531156311573115831159311603116131162311633116431165311663116731168311693117031171311723117331174311753117631177311783117931180311813118231183311843118531186311873118831189311903119131192311933119431195311963119731198311993120031201312023120331204312053120631207312083120931210312113121231213312143121531216312173121831219312203122131222312233122431225312263122731228312293123031231312323123331234312353123631237312383123931240312413124231243312443124531246312473124831249312503125131252312533125431255312563125731258312593126031261312623126331264312653126631267312683126931270312713127231273312743127531276312773127831279312803128131282312833128431285312863128731288312893129031291312923129331294312953129631297312983129931300313013130231303313043130531306313073130831309313103131131312313133131431315313163131731318313193132031321313223132331324313253132631327313283132931330313313133231333313343133531336313373133831339313403134131342313433134431345313463134731348313493135031351313523135331354313553135631357313583135931360313613136231363313643136531366313673136831369313703137131372313733137431375313763137731378313793138031381313823138331384313853138631387313883138931390313913139231393313943139531396313973139831399314003140131402314033140431405314063140731408314093141031411314123141331414314153141631417314183141931420314213142231423314243142531426314273142831429314303143131432314333143431435314363143731438314393144031441314423144331444314453144631447314483144931450314513145231453314543145531456314573145831459314603146131462314633146431465314663146731468314693147031471314723147331474314753147631477314783147931480314813148231483314843148531486314873148831489314903149131492314933149431495314963149731498314993150031501315023150331504315053150631507315083150931510315113151231513315143151531516315173151831519315203152131522315233152431525315263152731528315293153031531315323153331534315353153631537315383153931540315413154231543315443154531546315473154831549315503155131552315533155431555315563155731558315593156031561315623156331564315653156631567315683156931570315713157231573315743157531576315773157831579315803158131582315833158431585315863158731588315893159031591315923159331594315953159631597315983159931600316013160231603316043160531606316073160831609316103161131612316133161431615316163161731618316193162031621316223162331624316253162631627316283162931630316313163231633316343163531636316373163831639316403164131642316433164431645316463164731648316493165031651316523165331654316553165631657316583165931660316613166231663316643166531666316673166831669316703167131672316733167431675316763167731678316793168031681316823168331684316853168631687316883168931690316913169231693316943169531696316973169831699317003170131702317033170431705317063170731708317093171031711317123171331714317153171631717317183171931720317213172231723317243172531726317273172831729317303173131732317333173431735317363173731738317393174031741317423174331744317453174631747317483174931750317513175231753317543175531756317573175831759317603176131762317633176431765317663176731768317693177031771317723177331774317753177631777317783177931780317813178231783317843178531786317873178831789317903179131792317933179431795317963179731798317993180031801318023180331804318053180631807318083180931810318113181231813318143181531816318173181831819318203182131822318233182431825318263182731828318293183031831318323183331834318353183631837318383183931840318413184231843318443184531846318473184831849318503185131852318533185431855318563185731858318593186031861318623186331864318653186631867318683186931870318713187231873318743187531876318773187831879318803188131882318833188431885318863188731888318893189031891318923189331894318953189631897318983189931900319013190231903319043190531906319073190831909319103191131912319133191431915319163191731918319193192031921319223192331924319253192631927319283192931930319313193231933319343193531936319373193831939319403194131942319433194431945319463194731948319493195031951319523195331954319553195631957319583195931960319613196231963319643196531966319673196831969319703197131972319733197431975319763197731978319793198031981319823198331984319853198631987319883198931990319913199231993319943199531996319973199831999320003200132002320033200432005320063200732008320093201032011320123201332014320153201632017320183201932020320213202232023320243202532026320273202832029320303203132032320333203432035320363203732038320393204032041320423204332044320453204632047320483204932050320513205232053320543205532056320573205832059320603206132062320633206432065320663206732068320693207032071320723207332074320753207632077320783207932080320813208232083320843208532086320873208832089320903209132092320933209432095320963209732098320993210032101321023210332104321053210632107321083210932110321113211232113321143211532116321173211832119321203212132122321233212432125321263212732128321293213032131321323213332134321353213632137321383213932140321413214232143321443214532146321473214832149321503215132152321533215432155321563215732158321593216032161321623216332164321653216632167321683216932170321713217232173321743217532176321773217832179321803218132182321833218432185321863218732188321893219032191321923219332194321953219632197321983219932200322013220232203322043220532206322073220832209322103221132212322133221432215322163221732218322193222032221322223222332224322253222632227322283222932230322313223232233322343223532236322373223832239322403224132242322433224432245322463224732248322493225032251322523225332254322553225632257322583225932260322613226232263322643226532266322673226832269322703227132272322733227432275322763227732278322793228032281322823228332284322853228632287322883228932290322913229232293322943229532296322973229832299323003230132302323033230432305323063230732308323093231032311323123231332314323153231632317323183231932320323213232232323323243232532326323273232832329323303233132332323333233432335323363233732338323393234032341323423234332344323453234632347323483234932350323513235232353323543235532356323573235832359323603236132362323633236432365323663236732368323693237032371323723237332374323753237632377323783237932380323813238232383323843238532386323873238832389323903239132392323933239432395323963239732398323993240032401324023240332404324053240632407324083240932410324113241232413324143241532416324173241832419324203242132422324233242432425324263242732428324293243032431324323243332434324353243632437324383243932440324413244232443324443244532446324473244832449324503245132452324533245432455324563245732458324593246032461324623246332464324653246632467324683246932470324713247232473324743247532476324773247832479324803248132482324833248432485324863248732488324893249032491324923249332494324953249632497324983249932500325013250232503325043250532506325073250832509325103251132512325133251432515325163251732518325193252032521325223252332524325253252632527325283252932530325313253232533325343253532536325373253832539325403254132542325433254432545325463254732548325493255032551325523255332554325553255632557325583255932560325613256232563325643256532566325673256832569325703257132572325733257432575325763257732578325793258032581325823258332584325853258632587325883258932590325913259232593325943259532596325973259832599326003260132602326033260432605326063260732608326093261032611326123261332614326153261632617326183261932620326213262232623326243262532626326273262832629326303263132632326333263432635326363263732638326393264032641326423264332644326453264632647326483264932650326513265232653326543265532656326573265832659326603266132662326633266432665326663266732668326693267032671326723267332674326753267632677326783267932680326813268232683326843268532686326873268832689326903269132692326933269432695326963269732698326993270032701327023270332704327053270632707327083270932710327113271232713327143271532716327173271832719327203272132722327233272432725327263272732728327293273032731327323273332734327353273632737327383273932740327413274232743327443274532746327473274832749327503275132752327533275432755327563275732758327593276032761327623276332764327653276632767327683276932770327713277232773327743277532776327773277832779327803278132782327833278432785327863278732788327893279032791327923279332794327953279632797327983279932800328013280232803328043280532806328073280832809328103281132812328133281432815328163281732818328193282032821328223282332824328253282632827328283282932830328313283232833328343283532836328373283832839328403284132842328433284432845328463284732848328493285032851328523285332854328553285632857328583285932860328613286232863328643286532866328673286832869328703287132872328733287432875328763287732878328793288032881328823288332884328853288632887328883288932890328913289232893328943289532896328973289832899329003290132902329033290432905329063290732908329093291032911329123291332914329153291632917329183291932920329213292232923329243292532926329273292832929329303293132932329333293432935329363293732938329393294032941329423294332944329453294632947329483294932950329513295232953329543295532956329573295832959329603296132962329633296432965329663296732968329693297032971329723297332974329753297632977329783297932980329813298232983329843298532986329873298832989329903299132992329933299432995329963299732998329993300033001330023300333004330053300633007330083300933010330113301233013330143301533016330173301833019330203302133022330233302433025330263302733028330293303033031330323303333034330353303633037330383303933040330413304233043330443304533046330473304833049330503305133052330533305433055330563305733058330593306033061330623306333064330653306633067330683306933070330713307233073330743307533076330773307833079330803308133082330833308433085330863308733088330893309033091330923309333094330953309633097330983309933100331013310233103331043310533106331073310833109331103311133112331133311433115331163311733118331193312033121331223312333124331253312633127331283312933130331313313233133331343313533136331373313833139331403314133142331433314433145331463314733148331493315033151331523315333154331553315633157331583315933160331613316233163331643316533166331673316833169331703317133172331733317433175331763317733178331793318033181331823318333184331853318633187331883318933190331913319233193331943319533196331973319833199332003320133202332033320433205332063320733208332093321033211332123321333214332153321633217332183321933220332213322233223332243322533226332273322833229332303323133232332333323433235332363323733238332393324033241332423324333244332453324633247332483324933250332513325233253332543325533256332573325833259332603326133262332633326433265332663326733268332693327033271332723327333274332753327633277332783327933280332813328233283332843328533286332873328833289332903329133292332933329433295332963329733298332993330033301333023330333304333053330633307333083330933310333113331233313333143331533316333173331833319333203332133322333233332433325333263332733328333293333033331333323333333334333353333633337333383333933340333413334233343333443334533346333473334833349333503335133352333533335433355333563335733358333593336033361333623336333364333653336633367333683336933370333713337233373333743337533376333773337833379333803338133382333833338433385333863338733388333893339033391333923339333394333953339633397333983339933400334013340233403334043340533406334073340833409334103341133412334133341433415334163341733418334193342033421334223342333424334253342633427334283342933430334313343233433334343343533436334373343833439334403344133442334433344433445334463344733448334493345033451334523345333454334553345633457334583345933460334613346233463334643346533466334673346833469334703347133472334733347433475334763347733478334793348033481334823348333484334853348633487334883348933490334913349233493334943349533496334973349833499335003350133502335033350433505335063350733508335093351033511335123351333514335153351633517335183351933520335213352233523335243352533526335273352833529335303353133532335333353433535335363353733538335393354033541335423354333544335453354633547335483354933550335513355233553335543355533556335573355833559335603356133562335633356433565335663356733568335693357033571335723357333574335753357633577335783357933580335813358233583335843358533586335873358833589335903359133592335933359433595335963359733598335993360033601336023360333604336053360633607336083360933610336113361233613336143361533616336173361833619336203362133622336233362433625336263362733628336293363033631336323363333634336353363633637336383363933640336413364233643336443364533646336473364833649336503365133652336533365433655336563365733658336593366033661336623366333664336653366633667336683366933670336713367233673336743367533676336773367833679336803368133682336833368433685336863368733688336893369033691336923369333694336953369633697336983369933700337013370233703337043370533706337073370833709337103371133712337133371433715337163371733718337193372033721337223372333724337253372633727337283372933730337313373233733337343373533736337373373833739337403374133742337433374433745337463374733748337493375033751337523375333754337553375633757337583375933760337613376233763337643376533766337673376833769337703377133772337733377433775337763377733778337793378033781337823378333784337853378633787337883378933790337913379233793337943379533796337973379833799338003380133802338033380433805338063380733808338093381033811338123381333814338153381633817338183381933820338213382233823338243382533826338273382833829338303383133832338333383433835338363383733838338393384033841338423384333844338453384633847338483384933850338513385233853338543385533856338573385833859338603386133862338633386433865338663386733868338693387033871338723387333874338753387633877338783387933880338813388233883338843388533886338873388833889338903389133892338933389433895338963389733898338993390033901339023390333904339053390633907339083390933910339113391233913339143391533916339173391833919339203392133922339233392433925339263392733928339293393033931339323393333934339353393633937339383393933940339413394233943339443394533946339473394833949339503395133952339533395433955339563395733958339593396033961339623396333964339653396633967339683396933970339713397233973339743397533976339773397833979339803398133982339833398433985339863398733988339893399033991339923399333994339953399633997339983399934000340013400234003340043400534006340073400834009340103401134012340133401434015340163401734018340193402034021340223402334024340253402634027340283402934030340313403234033340343403534036340373403834039340403404134042340433404434045340463404734048340493405034051340523405334054340553405634057340583405934060340613406234063340643406534066340673406834069340703407134072340733407434075340763407734078340793408034081340823408334084340853408634087340883408934090340913409234093340943409534096340973409834099341003410134102341033410434105341063410734108341093411034111341123411334114341153411634117341183411934120341213412234123341243412534126341273412834129341303413134132341333413434135341363413734138341393414034141341423414334144341453414634147341483414934150341513415234153341543415534156341573415834159341603416134162341633416434165341663416734168341693417034171341723417334174341753417634177341783417934180341813418234183341843418534186341873418834189341903419134192341933419434195341963419734198341993420034201342023420334204342053420634207342083420934210342113421234213342143421534216342173421834219342203422134222342233422434225342263422734228342293423034231342323423334234342353423634237342383423934240342413424234243342443424534246342473424834249342503425134252342533425434255342563425734258342593426034261342623426334264342653426634267342683426934270342713427234273342743427534276342773427834279342803428134282342833428434285342863428734288342893429034291342923429334294342953429634297342983429934300343013430234303343043430534306343073430834309343103431134312343133431434315343163431734318343193432034321343223432334324343253432634327343283432934330343313433234333343343433534336343373433834339343403434134342343433434434345343463434734348343493435034351343523435334354343553435634357343583435934360343613436234363343643436534366343673436834369343703437134372343733437434375343763437734378343793438034381343823438334384343853438634387343883438934390343913439234393343943439534396343973439834399344003440134402344033440434405344063440734408344093441034411344123441334414344153441634417344183441934420344213442234423344243442534426344273442834429344303443134432344333443434435344363443734438344393444034441344423444334444344453444634447344483444934450344513445234453344543445534456344573445834459344603446134462344633446434465344663446734468344693447034471344723447334474344753447634477344783447934480344813448234483344843448534486344873448834489344903449134492344933449434495344963449734498344993450034501345023450334504345053450634507345083450934510345113451234513345143451534516345173451834519345203452134522345233452434525345263452734528345293453034531345323453334534345353453634537345383453934540345413454234543345443454534546345473454834549345503455134552345533455434555345563455734558345593456034561345623456334564345653456634567345683456934570345713457234573345743457534576345773457834579345803458134582345833458434585345863458734588345893459034591345923459334594345953459634597345983459934600346013460234603346043460534606346073460834609346103461134612346133461434615346163461734618346193462034621346223462334624346253462634627346283462934630346313463234633346343463534636346373463834639346403464134642346433464434645346463464734648346493465034651346523465334654346553465634657346583465934660346613466234663346643466534666346673466834669346703467134672346733467434675346763467734678346793468034681346823468334684346853468634687346883468934690346913469234693346943469534696346973469834699347003470134702347033470434705347063470734708347093471034711347123471334714347153471634717347183471934720347213472234723347243472534726347273472834729347303473134732347333473434735347363473734738347393474034741347423474334744347453474634747347483474934750347513475234753347543475534756347573475834759347603476134762347633476434765347663476734768347693477034771347723477334774347753477634777347783477934780347813478234783347843478534786347873478834789347903479134792347933479434795347963479734798347993480034801348023480334804348053480634807348083480934810348113481234813348143481534816348173481834819348203482134822348233482434825348263482734828348293483034831348323483334834348353483634837348383483934840348413484234843348443484534846348473484834849348503485134852348533485434855348563485734858348593486034861348623486334864348653486634867348683486934870348713487234873348743487534876348773487834879348803488134882348833488434885348863488734888348893489034891348923489334894348953489634897348983489934900349013490234903349043490534906349073490834909349103491134912349133491434915349163491734918349193492034921349223492334924349253492634927349283492934930349313493234933349343493534936349373493834939349403494134942349433494434945349463494734948349493495034951349523495334954349553495634957349583495934960349613496234963349643496534966349673496834969349703497134972349733497434975349763497734978349793498034981349823498334984349853498634987349883498934990349913499234993349943499534996349973499834999350003500135002350033500435005350063500735008350093501035011350123501335014350153501635017350183501935020350213502235023350243502535026350273502835029350303503135032350333503435035350363503735038350393504035041350423504335044350453504635047350483504935050350513505235053350543505535056350573505835059350603506135062350633506435065350663506735068350693507035071350723507335074350753507635077350783507935080350813508235083350843508535086350873508835089350903509135092350933509435095350963509735098350993510035101351023510335104351053510635107351083510935110351113511235113351143511535116351173511835119351203512135122351233512435125351263512735128351293513035131351323513335134351353513635137351383513935140351413514235143351443514535146351473514835149351503515135152351533515435155351563515735158351593516035161351623516335164351653516635167351683516935170351713517235173351743517535176351773517835179351803518135182351833518435185351863518735188351893519035191351923519335194351953519635197351983519935200352013520235203352043520535206352073520835209352103521135212352133521435215352163521735218352193522035221352223522335224352253522635227352283522935230352313523235233352343523535236352373523835239352403524135242352433524435245352463524735248352493525035251352523525335254352553525635257352583525935260352613526235263352643526535266352673526835269352703527135272352733527435275352763527735278352793528035281352823528335284352853528635287352883528935290352913529235293352943529535296352973529835299353003530135302353033530435305353063530735308353093531035311353123531335314353153531635317353183531935320353213532235323353243532535326353273532835329353303533135332353333533435335353363533735338353393534035341353423534335344353453534635347353483534935350353513535235353353543535535356353573535835359353603536135362353633536435365353663536735368353693537035371353723537335374353753537635377353783537935380353813538235383353843538535386353873538835389353903539135392353933539435395353963539735398353993540035401354023540335404354053540635407354083540935410354113541235413354143541535416354173541835419354203542135422354233542435425354263542735428354293543035431354323543335434354353543635437354383543935440354413544235443354443544535446354473544835449354503545135452354533545435455354563545735458354593546035461354623546335464354653546635467354683546935470354713547235473354743547535476354773547835479354803548135482354833548435485354863548735488354893549035491354923549335494354953549635497354983549935500355013550235503355043550535506355073550835509355103551135512355133551435515355163551735518355193552035521355223552335524355253552635527355283552935530355313553235533355343553535536355373553835539355403554135542355433554435545355463554735548355493555035551355523555335554355553555635557355583555935560355613556235563355643556535566355673556835569355703557135572355733557435575355763557735578355793558035581355823558335584355853558635587355883558935590355913559235593355943559535596355973559835599356003560135602356033560435605356063560735608356093561035611356123561335614356153561635617356183561935620356213562235623356243562535626356273562835629356303563135632356333563435635356363563735638356393564035641356423564335644356453564635647356483564935650356513565235653356543565535656356573565835659356603566135662356633566435665356663566735668356693567035671356723567335674356753567635677356783567935680356813568235683356843568535686356873568835689356903569135692356933569435695356963569735698356993570035701357023570335704357053570635707357083570935710357113571235713357143571535716357173571835719357203572135722357233572435725357263572735728357293573035731357323573335734357353573635737357383573935740357413574235743357443574535746357473574835749357503575135752357533575435755357563575735758357593576035761357623576335764357653576635767357683576935770357713577235773357743577535776357773577835779357803578135782357833578435785357863578735788357893579035791357923579335794357953579635797357983579935800358013580235803358043580535806358073580835809358103581135812358133581435815358163581735818358193582035821358223582335824358253582635827358283582935830358313583235833358343583535836358373583835839358403584135842358433584435845358463584735848358493585035851358523585335854358553585635857358583585935860358613586235863358643586535866358673586835869358703587135872358733587435875358763587735878358793588035881358823588335884358853588635887358883588935890358913589235893358943589535896358973589835899359003590135902359033590435905359063590735908359093591035911359123591335914359153591635917359183591935920359213592235923359243592535926359273592835929359303593135932359333593435935359363593735938359393594035941359423594335944359453594635947359483594935950359513595235953359543595535956359573595835959359603596135962359633596435965359663596735968359693597035971359723597335974359753597635977359783597935980359813598235983359843598535986359873598835989359903599135992359933599435995359963599735998359993600036001360023600336004360053600636007360083600936010360113601236013360143601536016360173601836019360203602136022360233602436025360263602736028360293603036031360323603336034360353603636037360383603936040360413604236043360443604536046360473604836049360503605136052360533605436055360563605736058360593606036061360623606336064360653606636067360683606936070360713607236073360743607536076360773607836079360803608136082360833608436085360863608736088360893609036091360923609336094360953609636097360983609936100361013610236103361043610536106361073610836109361103611136112361133611436115361163611736118361193612036121361223612336124361253612636127361283612936130361313613236133361343613536136361373613836139361403614136142361433614436145361463614736148361493615036151361523615336154361553615636157361583615936160361613616236163361643616536166361673616836169361703617136172361733617436175361763617736178361793618036181361823618336184361853618636187361883618936190361913619236193361943619536196361973619836199362003620136202362033620436205362063620736208362093621036211362123621336214362153621636217362183621936220362213622236223362243622536226362273622836229362303623136232362333623436235362363623736238362393624036241362423624336244362453624636247362483624936250362513625236253362543625536256362573625836259362603626136262362633626436265362663626736268362693627036271362723627336274362753627636277362783627936280362813628236283362843628536286362873628836289362903629136292362933629436295362963629736298362993630036301363023630336304363053630636307363083630936310363113631236313363143631536316363173631836319363203632136322363233632436325363263632736328363293633036331363323633336334363353633636337363383633936340363413634236343363443634536346363473634836349363503635136352363533635436355363563635736358363593636036361363623636336364363653636636367363683636936370363713637236373363743637536376363773637836379363803638136382363833638436385363863638736388363893639036391363923639336394363953639636397363983639936400364013640236403364043640536406364073640836409364103641136412364133641436415364163641736418364193642036421364223642336424364253642636427364283642936430364313643236433364343643536436364373643836439364403644136442364433644436445364463644736448364493645036451364523645336454364553645636457364583645936460364613646236463364643646536466364673646836469364703647136472364733647436475364763647736478364793648036481364823648336484364853648636487364883648936490364913649236493364943649536496364973649836499365003650136502365033650436505365063650736508365093651036511365123651336514365153651636517365183651936520365213652236523365243652536526365273652836529365303653136532365333653436535365363653736538365393654036541365423654336544365453654636547365483654936550365513655236553365543655536556365573655836559365603656136562365633656436565365663656736568365693657036571365723657336574365753657636577365783657936580365813658236583365843658536586365873658836589365903659136592365933659436595365963659736598365993660036601366023660336604366053660636607366083660936610366113661236613366143661536616366173661836619366203662136622366233662436625366263662736628366293663036631366323663336634366353663636637366383663936640366413664236643366443664536646366473664836649366503665136652366533665436655366563665736658366593666036661366623666336664366653666636667366683666936670366713667236673366743667536676366773667836679366803668136682366833668436685366863668736688366893669036691366923669336694366953669636697366983669936700367013670236703367043670536706367073670836709367103671136712367133671436715367163671736718367193672036721367223672336724367253672636727367283672936730367313673236733367343673536736367373673836739367403674136742367433674436745367463674736748367493675036751367523675336754367553675636757367583675936760367613676236763367643676536766367673676836769367703677136772367733677436775367763677736778367793678036781367823678336784367853678636787367883678936790367913679236793367943679536796367973679836799368003680136802368033680436805368063680736808368093681036811368123681336814368153681636817368183681936820368213682236823368243682536826368273682836829368303683136832368333683436835368363683736838368393684036841368423684336844368453684636847368483684936850368513685236853368543685536856368573685836859368603686136862368633686436865368663686736868368693687036871368723687336874368753687636877368783687936880368813688236883368843688536886368873688836889368903689136892368933689436895368963689736898368993690036901369023690336904369053690636907369083690936910369113691236913369143691536916369173691836919369203692136922369233692436925369263692736928369293693036931369323693336934369353693636937369383693936940369413694236943369443694536946369473694836949369503695136952369533695436955369563695736958369593696036961369623696336964369653696636967369683696936970369713697236973369743697536976369773697836979369803698136982369833698436985369863698736988369893699036991369923699336994369953699636997369983699937000370013700237003370043700537006370073700837009370103701137012370133701437015370163701737018370193702037021370223702337024370253702637027370283702937030370313703237033370343703537036370373703837039370403704137042370433704437045370463704737048370493705037051370523705337054370553705637057370583705937060370613706237063370643706537066370673706837069370703707137072370733707437075370763707737078370793708037081370823708337084370853708637087370883708937090370913709237093370943709537096370973709837099371003710137102371033710437105371063710737108371093711037111371123711337114371153711637117371183711937120371213712237123371243712537126371273712837129371303713137132371333713437135371363713737138371393714037141371423714337144371453714637147371483714937150371513715237153371543715537156371573715837159371603716137162371633716437165371663716737168371693717037171371723717337174371753717637177371783717937180371813718237183371843718537186371873718837189371903719137192371933719437195371963719737198371993720037201372023720337204372053720637207372083720937210372113721237213372143721537216372173721837219372203722137222372233722437225372263722737228372293723037231372323723337234372353723637237372383723937240372413724237243372443724537246372473724837249372503725137252372533725437255372563725737258372593726037261372623726337264372653726637267372683726937270372713727237273372743727537276372773727837279372803728137282372833728437285372863728737288372893729037291372923729337294372953729637297372983729937300373013730237303373043730537306373073730837309373103731137312373133731437315373163731737318373193732037321373223732337324373253732637327373283732937330373313733237333373343733537336373373733837339373403734137342373433734437345373463734737348373493735037351373523735337354373553735637357373583735937360373613736237363373643736537366373673736837369373703737137372373733737437375373763737737378373793738037381373823738337384373853738637387373883738937390373913739237393373943739537396373973739837399374003740137402374033740437405374063740737408374093741037411374123741337414374153741637417374183741937420374213742237423374243742537426374273742837429374303743137432374333743437435374363743737438374393744037441374423744337444374453744637447374483744937450374513745237453374543745537456374573745837459374603746137462374633746437465374663746737468374693747037471374723747337474374753747637477374783747937480374813748237483374843748537486374873748837489374903749137492374933749437495374963749737498374993750037501375023750337504375053750637507375083750937510375113751237513375143751537516375173751837519375203752137522375233752437525375263752737528375293753037531375323753337534375353753637537375383753937540375413754237543375443754537546375473754837549375503755137552375533755437555375563755737558375593756037561375623756337564375653756637567375683756937570375713757237573375743757537576375773757837579375803758137582375833758437585375863758737588375893759037591375923759337594375953759637597375983759937600376013760237603376043760537606376073760837609376103761137612376133761437615376163761737618376193762037621376223762337624376253762637627376283762937630376313763237633376343763537636376373763837639376403764137642376433764437645376463764737648376493765037651376523765337654376553765637657376583765937660376613766237663376643766537666376673766837669376703767137672376733767437675376763767737678376793768037681376823768337684376853768637687376883768937690376913769237693376943769537696376973769837699377003770137702377033770437705377063770737708377093771037711377123771337714377153771637717377183771937720377213772237723377243772537726377273772837729377303773137732377333773437735377363773737738377393774037741377423774337744377453774637747377483774937750377513775237753377543775537756377573775837759377603776137762377633776437765377663776737768377693777037771377723777337774377753777637777377783777937780377813778237783377843778537786377873778837789377903779137792377933779437795377963779737798377993780037801378023780337804378053780637807378083780937810378113781237813378143781537816378173781837819378203782137822378233782437825378263782737828378293783037831378323783337834378353783637837378383783937840378413784237843378443784537846378473784837849378503785137852378533785437855378563785737858378593786037861378623786337864378653786637867378683786937870378713787237873378743787537876378773787837879378803788137882378833788437885378863788737888378893789037891378923789337894378953789637897378983789937900379013790237903379043790537906379073790837909379103791137912379133791437915379163791737918379193792037921379223792337924379253792637927379283792937930379313793237933379343793537936379373793837939379403794137942379433794437945379463794737948379493795037951379523795337954379553795637957379583795937960379613796237963379643796537966379673796837969379703797137972379733797437975379763797737978379793798037981379823798337984379853798637987379883798937990379913799237993379943799537996379973799837999380003800138002380033800438005380063800738008380093801038011380123801338014380153801638017380183801938020380213802238023380243802538026380273802838029380303803138032380333803438035380363803738038380393804038041380423804338044380453804638047380483804938050380513805238053380543805538056380573805838059380603806138062380633806438065380663806738068380693807038071380723807338074380753807638077380783807938080380813808238083380843808538086380873808838089380903809138092380933809438095380963809738098380993810038101381023810338104381053810638107381083810938110381113811238113381143811538116381173811838119381203812138122381233812438125381263812738128381293813038131381323813338134381353813638137381383813938140381413814238143381443814538146381473814838149381503815138152381533815438155381563815738158381593816038161381623816338164381653816638167381683816938170381713817238173381743817538176381773817838179381803818138182381833818438185381863818738188381893819038191381923819338194381953819638197381983819938200382013820238203382043820538206382073820838209382103821138212382133821438215382163821738218382193822038221382223822338224382253822638227382283822938230382313823238233382343823538236382373823838239382403824138242382433824438245382463824738248382493825038251382523825338254382553825638257382583825938260382613826238263382643826538266382673826838269382703827138272382733827438275382763827738278382793828038281382823828338284382853828638287382883828938290382913829238293382943829538296382973829838299383003830138302383033830438305383063830738308383093831038311383123831338314383153831638317383183831938320383213832238323383243832538326383273832838329383303833138332383333833438335383363833738338383393834038341383423834338344383453834638347383483834938350383513835238353383543835538356383573835838359383603836138362383633836438365383663836738368383693837038371383723837338374383753837638377383783837938380383813838238383383843838538386383873838838389383903839138392383933839438395383963839738398383993840038401384023840338404384053840638407384083840938410384113841238413384143841538416384173841838419384203842138422384233842438425384263842738428384293843038431384323843338434384353843638437384383843938440384413844238443384443844538446384473844838449384503845138452384533845438455384563845738458384593846038461384623846338464384653846638467384683846938470384713847238473384743847538476384773847838479384803848138482384833848438485384863848738488384893849038491384923849338494384953849638497384983849938500385013850238503385043850538506385073850838509385103851138512385133851438515385163851738518385193852038521385223852338524385253852638527385283852938530385313853238533385343853538536385373853838539385403854138542385433854438545385463854738548385493855038551385523855338554385553855638557385583855938560385613856238563385643856538566385673856838569385703857138572385733857438575385763857738578385793858038581385823858338584385853858638587385883858938590385913859238593385943859538596385973859838599386003860138602386033860438605386063860738608386093861038611386123861338614386153861638617386183861938620386213862238623386243862538626386273862838629386303863138632386333863438635386363863738638386393864038641386423864338644386453864638647386483864938650386513865238653386543865538656386573865838659386603866138662386633866438665386663866738668386693867038671386723867338674386753867638677386783867938680386813868238683386843868538686386873868838689386903869138692386933869438695386963869738698386993870038701387023870338704387053870638707387083870938710387113871238713387143871538716387173871838719387203872138722387233872438725387263872738728387293873038731387323873338734387353873638737387383873938740387413874238743387443874538746387473874838749387503875138752387533875438755387563875738758387593876038761387623876338764387653876638767387683876938770387713877238773387743877538776387773877838779387803878138782387833878438785387863878738788387893879038791387923879338794387953879638797387983879938800388013880238803388043880538806388073880838809388103881138812388133881438815388163881738818388193882038821388223882338824388253882638827388283882938830388313883238833388343883538836388373883838839388403884138842388433884438845388463884738848388493885038851388523885338854388553885638857388583885938860388613886238863388643886538866388673886838869388703887138872388733887438875388763887738878388793888038881388823888338884388853888638887388883888938890388913889238893388943889538896388973889838899389003890138902389033890438905389063890738908389093891038911389123891338914389153891638917389183891938920389213892238923389243892538926389273892838929389303893138932389333893438935389363893738938389393894038941389423894338944389453894638947389483894938950389513895238953389543895538956389573895838959389603896138962389633896438965389663896738968389693897038971389723897338974389753897638977389783897938980389813898238983389843898538986389873898838989389903899138992389933899438995389963899738998389993900039001390023900339004390053900639007390083900939010390113901239013390143901539016390173901839019390203902139022390233902439025390263902739028390293903039031390323903339034390353903639037390383903939040390413904239043390443904539046390473904839049390503905139052390533905439055390563905739058390593906039061390623906339064390653906639067390683906939070390713907239073390743907539076390773907839079390803908139082390833908439085390863908739088390893909039091390923909339094390953909639097390983909939100391013910239103391043910539106391073910839109391103911139112391133911439115391163911739118391193912039121391223912339124391253912639127391283912939130391313913239133391343913539136391373913839139391403914139142391433914439145391463914739148391493915039151391523915339154391553915639157391583915939160391613916239163391643916539166391673916839169391703917139172391733917439175391763917739178391793918039181391823918339184391853918639187391883918939190391913919239193391943919539196391973919839199392003920139202392033920439205392063920739208392093921039211392123921339214392153921639217392183921939220392213922239223392243922539226392273922839229392303923139232392333923439235392363923739238392393924039241392423924339244392453924639247392483924939250392513925239253392543925539256392573925839259392603926139262392633926439265392663926739268392693927039271392723927339274392753927639277392783927939280392813928239283392843928539286392873928839289392903929139292392933929439295392963929739298392993930039301393023930339304393053930639307393083930939310393113931239313393143931539316393173931839319393203932139322393233932439325393263932739328393293933039331393323933339334393353933639337393383933939340393413934239343393443934539346393473934839349393503935139352393533935439355393563935739358393593936039361393623936339364393653936639367393683936939370393713937239373393743937539376393773937839379393803938139382393833938439385393863938739388393893939039391393923939339394393953939639397393983939939400394013940239403394043940539406394073940839409394103941139412394133941439415394163941739418394193942039421394223942339424394253942639427394283942939430394313943239433394343943539436394373943839439394403944139442394433944439445394463944739448394493945039451394523945339454394553945639457394583945939460394613946239463394643946539466394673946839469394703947139472394733947439475394763947739478394793948039481394823948339484394853948639487394883948939490394913949239493394943949539496394973949839499395003950139502395033950439505395063950739508395093951039511395123951339514395153951639517395183951939520395213952239523395243952539526395273952839529395303953139532395333953439535395363953739538395393954039541395423954339544395453954639547395483954939550395513955239553395543955539556395573955839559395603956139562395633956439565395663956739568395693957039571395723957339574395753957639577395783957939580395813958239583395843958539586395873958839589395903959139592395933959439595395963959739598395993960039601396023960339604396053960639607396083960939610396113961239613396143961539616396173961839619396203962139622396233962439625396263962739628396293963039631396323963339634396353963639637396383963939640396413964239643396443964539646396473964839649396503965139652396533965439655396563965739658396593966039661396623966339664396653966639667396683966939670396713967239673396743967539676396773967839679396803968139682396833968439685396863968739688396893969039691396923969339694396953969639697396983969939700397013970239703397043970539706397073970839709397103971139712397133971439715397163971739718397193972039721397223972339724397253972639727397283972939730397313973239733397343973539736397373973839739397403974139742397433974439745397463974739748397493975039751397523975339754397553975639757397583975939760397613976239763397643976539766397673976839769397703977139772397733977439775397763977739778397793978039781397823978339784397853978639787397883978939790397913979239793397943979539796397973979839799398003980139802398033980439805398063980739808398093981039811398123981339814398153981639817398183981939820398213982239823398243982539826398273982839829398303983139832398333983439835398363983739838398393984039841398423984339844398453984639847398483984939850398513985239853398543985539856398573985839859398603986139862398633986439865398663986739868398693987039871398723987339874398753987639877398783987939880398813988239883398843988539886398873988839889398903989139892398933989439895398963989739898398993990039901399023990339904399053990639907399083990939910399113991239913399143991539916399173991839919399203992139922399233992439925399263992739928399293993039931399323993339934399353993639937399383993939940399413994239943399443994539946399473994839949399503995139952399533995439955399563995739958399593996039961399623996339964399653996639967399683996939970399713997239973399743997539976399773997839979399803998139982399833998439985399863998739988399893999039991399923999339994399953999639997399983999940000400014000240003400044000540006400074000840009400104001140012400134001440015400164001740018400194002040021400224002340024400254002640027400284002940030400314003240033400344003540036400374003840039400404004140042400434004440045400464004740048400494005040051400524005340054400554005640057400584005940060400614006240063400644006540066400674006840069400704007140072400734007440075400764007740078400794008040081400824008340084400854008640087400884008940090400914009240093400944009540096400974009840099401004010140102401034010440105401064010740108401094011040111401124011340114401154011640117401184011940120401214012240123401244012540126401274012840129401304013140132401334013440135401364013740138401394014040141401424014340144401454014640147401484014940150401514015240153401544015540156401574015840159401604016140162401634016440165401664016740168401694017040171401724017340174401754017640177401784017940180401814018240183401844018540186401874018840189401904019140192401934019440195401964019740198401994020040201402024020340204402054020640207402084020940210402114021240213402144021540216402174021840219402204022140222402234022440225402264022740228402294023040231402324023340234402354023640237402384023940240402414024240243402444024540246402474024840249402504025140252402534025440255402564025740258402594026040261402624026340264402654026640267402684026940270402714027240273402744027540276402774027840279402804028140282402834028440285402864028740288402894029040291402924029340294402954029640297402984029940300403014030240303403044030540306403074030840309403104031140312403134031440315403164031740318403194032040321403224032340324403254032640327403284032940330403314033240333403344033540336403374033840339403404034140342403434034440345403464034740348403494035040351403524035340354403554035640357403584035940360403614036240363403644036540366403674036840369403704037140372403734037440375403764037740378403794038040381403824038340384403854038640387403884038940390403914039240393403944039540396403974039840399404004040140402404034040440405404064040740408404094041040411404124041340414404154041640417404184041940420404214042240423404244042540426404274042840429404304043140432404334043440435404364043740438404394044040441404424044340444404454044640447404484044940450404514045240453404544045540456404574045840459404604046140462404634046440465404664046740468404694047040471404724047340474404754047640477404784047940480404814048240483404844048540486404874048840489404904049140492404934049440495404964049740498404994050040501405024050340504405054050640507405084050940510405114051240513405144051540516405174051840519405204052140522405234052440525405264052740528405294053040531405324053340534405354053640537405384053940540405414054240543405444054540546405474054840549405504055140552405534055440555405564055740558405594056040561405624056340564405654056640567405684056940570405714057240573405744057540576405774057840579405804058140582405834058440585405864058740588405894059040591405924059340594405954059640597405984059940600406014060240603406044060540606406074060840609406104061140612406134061440615406164061740618406194062040621406224062340624406254062640627406284062940630406314063240633406344063540636406374063840639406404064140642406434064440645406464064740648406494065040651406524065340654406554065640657406584065940660406614066240663406644066540666406674066840669406704067140672406734067440675406764067740678406794068040681406824068340684406854068640687406884068940690406914069240693406944069540696406974069840699407004070140702407034070440705407064070740708407094071040711407124071340714407154071640717407184071940720407214072240723407244072540726407274072840729407304073140732407334073440735407364073740738407394074040741407424074340744407454074640747407484074940750407514075240753407544075540756407574075840759407604076140762407634076440765407664076740768407694077040771407724077340774407754077640777407784077940780407814078240783407844078540786407874078840789407904079140792407934079440795407964079740798407994080040801408024080340804408054080640807408084080940810408114081240813408144081540816408174081840819408204082140822408234082440825408264082740828408294083040831408324083340834408354083640837408384083940840408414084240843408444084540846408474084840849408504085140852408534085440855408564085740858408594086040861408624086340864408654086640867408684086940870408714087240873408744087540876408774087840879408804088140882408834088440885408864088740888408894089040891408924089340894408954089640897408984089940900409014090240903409044090540906409074090840909409104091140912409134091440915409164091740918409194092040921409224092340924409254092640927409284092940930409314093240933409344093540936409374093840939409404094140942409434094440945409464094740948409494095040951409524095340954409554095640957409584095940960409614096240963409644096540966409674096840969409704097140972409734097440975409764097740978409794098040981409824098340984409854098640987409884098940990409914099240993409944099540996409974099840999410004100141002410034100441005410064100741008410094101041011410124101341014410154101641017410184101941020410214102241023410244102541026410274102841029410304103141032410334103441035410364103741038410394104041041410424104341044410454104641047410484104941050410514105241053410544105541056410574105841059410604106141062410634106441065410664106741068410694107041071410724107341074410754107641077410784107941080410814108241083410844108541086410874108841089410904109141092410934109441095410964109741098410994110041101411024110341104411054110641107411084110941110411114111241113411144111541116411174111841119411204112141122411234112441125411264112741128411294113041131411324113341134411354113641137411384113941140411414114241143411444114541146411474114841149411504115141152411534115441155411564115741158411594116041161411624116341164411654116641167411684116941170411714117241173411744117541176411774117841179411804118141182411834118441185411864118741188411894119041191411924119341194411954119641197411984119941200412014120241203412044120541206412074120841209412104121141212412134121441215412164121741218412194122041221412224122341224412254122641227412284122941230412314123241233412344123541236412374123841239412404124141242412434124441245412464124741248412494125041251412524125341254412554125641257412584125941260412614126241263412644126541266412674126841269412704127141272412734127441275412764127741278412794128041281412824128341284412854128641287412884128941290412914129241293412944129541296412974129841299413004130141302413034130441305413064130741308413094131041311413124131341314413154131641317413184131941320413214132241323413244132541326413274132841329413304133141332413334133441335413364133741338413394134041341413424134341344413454134641347413484134941350413514135241353413544135541356413574135841359413604136141362413634136441365413664136741368413694137041371413724137341374413754137641377413784137941380413814138241383413844138541386413874138841389413904139141392413934139441395413964139741398413994140041401414024140341404414054140641407414084140941410414114141241413414144141541416414174141841419414204142141422414234142441425414264142741428414294143041431414324143341434414354143641437414384143941440414414144241443414444144541446414474144841449414504145141452414534145441455414564145741458414594146041461414624146341464414654146641467414684146941470414714147241473414744147541476414774147841479414804148141482414834148441485414864148741488414894149041491414924149341494414954149641497414984149941500415014150241503415044150541506415074150841509415104151141512415134151441515415164151741518415194152041521415224152341524415254152641527415284152941530415314153241533415344153541536415374153841539415404154141542415434154441545415464154741548415494155041551415524155341554415554155641557415584155941560415614156241563415644156541566415674156841569415704157141572415734157441575415764157741578415794158041581415824158341584415854158641587415884158941590415914159241593415944159541596415974159841599416004160141602416034160441605416064160741608416094161041611416124161341614416154161641617416184161941620416214162241623416244162541626416274162841629416304163141632416334163441635416364163741638416394164041641416424164341644416454164641647416484164941650416514165241653416544165541656416574165841659416604166141662416634166441665416664166741668416694167041671416724167341674416754167641677416784167941680416814168241683416844168541686416874168841689416904169141692416934169441695416964169741698416994170041701417024170341704417054170641707417084170941710417114171241713417144171541716417174171841719417204172141722417234172441725417264172741728417294173041731417324173341734417354173641737417384173941740417414174241743417444174541746417474174841749417504175141752417534175441755417564175741758417594176041761417624176341764417654176641767417684176941770417714177241773417744177541776417774177841779417804178141782417834178441785417864178741788417894179041791417924179341794417954179641797417984179941800418014180241803418044180541806418074180841809418104181141812418134181441815418164181741818418194182041821418224182341824418254182641827418284182941830418314183241833418344183541836418374183841839418404184141842418434184441845418464184741848418494185041851418524185341854418554185641857418584185941860418614186241863418644186541866418674186841869418704187141872418734187441875418764187741878418794188041881418824188341884418854188641887418884188941890418914189241893418944189541896418974189841899419004190141902419034190441905419064190741908419094191041911419124191341914419154191641917419184191941920419214192241923419244192541926419274192841929419304193141932419334193441935419364193741938419394194041941419424194341944419454194641947419484194941950419514195241953419544195541956419574195841959419604196141962419634196441965419664196741968419694197041971419724197341974419754197641977419784197941980419814198241983419844198541986419874198841989419904199141992419934199441995419964199741998419994200042001420024200342004420054200642007420084200942010420114201242013420144201542016420174201842019420204202142022420234202442025420264202742028420294203042031420324203342034420354203642037420384203942040420414204242043420444204542046420474204842049420504205142052420534205442055420564205742058420594206042061420624206342064420654206642067420684206942070420714207242073420744207542076420774207842079420804208142082420834208442085420864208742088420894209042091420924209342094420954209642097420984209942100421014210242103421044210542106421074210842109421104211142112421134211442115421164211742118421194212042121421224212342124421254212642127421284212942130421314213242133421344213542136421374213842139421404214142142421434214442145421464214742148421494215042151421524215342154421554215642157421584215942160421614216242163421644216542166421674216842169421704217142172421734217442175421764217742178421794218042181421824218342184421854218642187421884218942190421914219242193421944219542196421974219842199422004220142202422034220442205422064220742208422094221042211422124221342214422154221642217422184221942220422214222242223422244222542226422274222842229422304223142232422334223442235422364223742238422394224042241422424224342244422454224642247422484224942250422514225242253422544225542256422574225842259422604226142262422634226442265422664226742268422694227042271422724227342274422754227642277422784227942280422814228242283422844228542286422874228842289422904229142292422934229442295422964229742298422994230042301423024230342304423054230642307423084230942310423114231242313423144231542316423174231842319423204232142322423234232442325423264232742328423294233042331423324233342334423354233642337423384233942340423414234242343423444234542346423474234842349423504235142352423534235442355423564235742358423594236042361423624236342364423654236642367423684236942370423714237242373423744237542376423774237842379423804238142382423834238442385423864238742388423894239042391423924239342394423954239642397423984239942400424014240242403424044240542406424074240842409424104241142412424134241442415424164241742418424194242042421424224242342424424254242642427424284242942430424314243242433424344243542436424374243842439424404244142442424434244442445424464244742448424494245042451424524245342454424554245642457424584245942460424614246242463424644246542466424674246842469424704247142472424734247442475424764247742478424794248042481424824248342484424854248642487424884248942490424914249242493424944249542496424974249842499425004250142502425034250442505425064250742508425094251042511425124251342514425154251642517425184251942520425214252242523425244252542526425274252842529425304253142532425334253442535425364253742538425394254042541425424254342544425454254642547425484254942550425514255242553425544255542556425574255842559425604256142562425634256442565425664256742568425694257042571425724257342574425754257642577425784257942580425814258242583425844258542586425874258842589425904259142592425934259442595425964259742598425994260042601426024260342604426054260642607426084260942610426114261242613426144261542616426174261842619426204262142622426234262442625426264262742628426294263042631426324263342634426354263642637426384263942640426414264242643426444264542646426474264842649426504265142652426534265442655426564265742658426594266042661426624266342664426654266642667426684266942670426714267242673426744267542676426774267842679426804268142682426834268442685426864268742688426894269042691426924269342694426954269642697426984269942700427014270242703427044270542706427074270842709427104271142712427134271442715427164271742718427194272042721427224272342724427254272642727427284272942730427314273242733427344273542736427374273842739427404274142742427434274442745427464274742748427494275042751427524275342754427554275642757427584275942760427614276242763427644276542766427674276842769427704277142772427734277442775427764277742778427794278042781427824278342784427854278642787427884278942790427914279242793427944279542796427974279842799428004280142802428034280442805428064280742808428094281042811428124281342814428154281642817428184281942820428214282242823428244282542826428274282842829428304283142832428334283442835428364283742838428394284042841428424284342844428454284642847428484284942850428514285242853428544285542856428574285842859428604286142862428634286442865428664286742868428694287042871428724287342874428754287642877428784287942880428814288242883428844288542886428874288842889428904289142892428934289442895428964289742898428994290042901429024290342904429054290642907429084290942910429114291242913429144291542916429174291842919429204292142922429234292442925429264292742928429294293042931429324293342934429354293642937429384293942940429414294242943429444294542946429474294842949429504295142952429534295442955429564295742958429594296042961429624296342964429654296642967429684296942970429714297242973429744297542976429774297842979429804298142982429834298442985429864298742988429894299042991429924299342994429954299642997429984299943000430014300243003430044300543006430074300843009430104301143012430134301443015430164301743018430194302043021430224302343024430254302643027430284302943030430314303243033430344303543036430374303843039430404304143042430434304443045430464304743048430494305043051430524305343054430554305643057430584305943060430614306243063430644306543066430674306843069430704307143072430734307443075430764307743078430794308043081430824308343084430854308643087430884308943090430914309243093430944309543096430974309843099431004310143102431034310443105431064310743108431094311043111431124311343114431154311643117431184311943120431214312243123431244312543126431274312843129431304313143132431334313443135431364313743138431394314043141431424314343144431454314643147431484314943150431514315243153431544315543156431574315843159431604316143162431634316443165431664316743168431694317043171431724317343174431754317643177431784317943180431814318243183431844318543186431874318843189431904319143192431934319443195431964319743198431994320043201432024320343204432054320643207432084320943210432114321243213432144321543216432174321843219432204322143222432234322443225432264322743228432294323043231432324323343234432354323643237432384323943240432414324243243432444324543246432474324843249432504325143252432534325443255432564325743258432594326043261432624326343264432654326643267432684326943270432714327243273432744327543276432774327843279432804328143282432834328443285432864328743288432894329043291432924329343294432954329643297432984329943300433014330243303433044330543306433074330843309433104331143312433134331443315433164331743318433194332043321433224332343324433254332643327433284332943330433314333243333433344333543336433374333843339433404334143342433434334443345433464334743348433494335043351433524335343354433554335643357433584335943360433614336243363433644336543366433674336843369433704337143372433734337443375433764337743378433794338043381433824338343384433854338643387433884338943390433914339243393433944339543396433974339843399434004340143402434034340443405434064340743408434094341043411434124341343414434154341643417434184341943420434214342243423434244342543426434274342843429434304343143432434334343443435434364343743438434394344043441434424344343444434454344643447434484344943450434514345243453434544345543456434574345843459434604346143462434634346443465434664346743468434694347043471434724347343474434754347643477434784347943480434814348243483434844348543486434874348843489434904349143492434934349443495434964349743498434994350043501435024350343504435054350643507435084350943510435114351243513435144351543516435174351843519435204352143522435234352443525435264352743528435294353043531435324353343534435354353643537435384353943540435414354243543435444354543546435474354843549435504355143552435534355443555435564355743558435594356043561435624356343564435654356643567435684356943570435714357243573435744357543576435774357843579435804358143582435834358443585435864358743588435894359043591435924359343594435954359643597435984359943600436014360243603436044360543606436074360843609436104361143612436134361443615436164361743618436194362043621436224362343624436254362643627436284362943630436314363243633436344363543636436374363843639436404364143642436434364443645436464364743648436494365043651436524365343654436554365643657436584365943660436614366243663436644366543666436674366843669436704367143672436734367443675436764367743678436794368043681436824368343684436854368643687436884368943690436914369243693436944369543696436974369843699437004370143702437034370443705437064370743708437094371043711437124371343714437154371643717437184371943720437214372243723437244372543726437274372843729437304373143732437334373443735437364373743738437394374043741437424374343744437454374643747437484374943750437514375243753437544375543756437574375843759437604376143762437634376443765437664376743768437694377043771437724377343774437754377643777437784377943780437814378243783437844378543786437874378843789437904379143792437934379443795437964379743798437994380043801438024380343804438054380643807438084380943810438114381243813438144381543816438174381843819438204382143822438234382443825438264382743828438294383043831438324383343834438354383643837438384383943840438414384243843438444384543846438474384843849438504385143852438534385443855438564385743858438594386043861438624386343864438654386643867438684386943870438714387243873438744387543876438774387843879438804388143882438834388443885438864388743888438894389043891438924389343894438954389643897438984389943900439014390243903439044390543906439074390843909439104391143912439134391443915439164391743918439194392043921439224392343924439254392643927439284392943930439314393243933439344393543936439374393843939439404394143942439434394443945439464394743948439494395043951439524395343954439554395643957439584395943960439614396243963439644396543966439674396843969439704397143972439734397443975439764397743978439794398043981439824398343984439854398643987439884398943990439914399243993439944399543996439974399843999440004400144002440034400444005440064400744008440094401044011440124401344014440154401644017440184401944020440214402244023440244402544026440274402844029440304403144032440334403444035440364403744038440394404044041440424404344044440454404644047440484404944050440514405244053440544405544056440574405844059440604406144062440634406444065440664406744068440694407044071440724407344074440754407644077440784407944080440814408244083440844408544086440874408844089440904409144092440934409444095440964409744098440994410044101441024410344104441054410644107441084410944110441114411244113441144411544116441174411844119441204412144122441234412444125441264412744128441294413044131441324413344134441354413644137441384413944140441414414244143441444414544146441474414844149441504415144152441534415444155441564415744158441594416044161441624416344164441654416644167441684416944170441714417244173441744417544176441774417844179441804418144182441834418444185441864418744188441894419044191441924419344194441954419644197441984419944200442014420244203442044420544206442074420844209442104421144212442134421444215442164421744218442194422044221442224422344224442254422644227442284422944230442314423244233442344423544236442374423844239442404424144242442434424444245442464424744248442494425044251442524425344254442554425644257442584425944260442614426244263442644426544266442674426844269442704427144272442734427444275442764427744278442794428044281442824428344284442854428644287442884428944290442914429244293442944429544296442974429844299443004430144302443034430444305443064430744308443094431044311443124431344314443154431644317443184431944320443214432244323443244432544326443274432844329443304433144332443334433444335443364433744338443394434044341443424434344344443454434644347443484434944350443514435244353443544435544356443574435844359443604436144362443634436444365443664436744368443694437044371443724437344374443754437644377443784437944380443814438244383443844438544386443874438844389443904439144392443934439444395443964439744398443994440044401444024440344404444054440644407444084440944410444114441244413444144441544416444174441844419444204442144422444234442444425444264442744428444294443044431444324443344434444354443644437444384443944440444414444244443444444444544446444474444844449444504445144452444534445444455444564445744458444594446044461444624446344464444654446644467444684446944470444714447244473444744447544476444774447844479444804448144482444834448444485444864448744488444894449044491444924449344494444954449644497444984449944500445014450244503445044450544506445074450844509445104451144512445134451444515445164451744518445194452044521445224452344524445254452644527445284452944530445314453244533445344453544536445374453844539445404454144542445434454444545445464454744548445494455044551445524455344554445554455644557445584455944560445614456244563445644456544566445674456844569445704457144572445734457444575445764457744578445794458044581445824458344584445854458644587445884458944590445914459244593445944459544596445974459844599446004460144602446034460444605446064460744608446094461044611446124461344614446154461644617446184461944620446214462244623446244462544626446274462844629446304463144632446334463444635446364463744638446394464044641446424464344644446454464644647446484464944650446514465244653446544465544656446574465844659446604466144662446634466444665446664466744668446694467044671446724467344674446754467644677446784467944680446814468244683446844468544686446874468844689446904469144692446934469444695446964469744698446994470044701447024470344704447054470644707447084470944710447114471244713447144471544716447174471844719447204472144722447234472444725447264472744728447294473044731447324473344734447354473644737447384473944740447414474244743447444474544746447474474844749447504475144752447534475444755447564475744758447594476044761447624476344764447654476644767447684476944770447714477244773447744477544776447774477844779447804478144782447834478444785447864478744788447894479044791447924479344794447954479644797447984479944800448014480244803448044480544806448074480844809448104481144812448134481444815448164481744818448194482044821448224482344824448254482644827448284482944830448314483244833448344483544836448374483844839448404484144842448434484444845448464484744848448494485044851448524485344854448554485644857448584485944860448614486244863448644486544866448674486844869448704487144872448734487444875448764487744878448794488044881448824488344884448854488644887448884488944890448914489244893448944489544896448974489844899449004490144902449034490444905449064490744908449094491044911449124491344914449154491644917449184491944920449214492244923449244492544926449274492844929449304493144932449334493444935449364493744938449394494044941449424494344944449454494644947449484494944950449514495244953449544495544956449574495844959449604496144962449634496444965449664496744968449694497044971449724497344974449754497644977449784497944980449814498244983449844498544986449874498844989449904499144992449934499444995449964499744998449994500045001450024500345004450054500645007450084500945010450114501245013450144501545016450174501845019450204502145022450234502445025450264502745028450294503045031450324503345034450354503645037450384503945040450414504245043450444504545046450474504845049450504505145052450534505445055450564505745058450594506045061450624506345064450654506645067450684506945070450714507245073450744507545076450774507845079450804508145082450834508445085450864508745088450894509045091450924509345094450954509645097450984509945100451014510245103451044510545106451074510845109451104511145112451134511445115451164511745118451194512045121451224512345124451254512645127451284512945130451314513245133451344513545136451374513845139451404514145142451434514445145451464514745148451494515045151451524515345154451554515645157451584515945160451614516245163451644516545166451674516845169451704517145172451734517445175451764517745178451794518045181451824518345184451854518645187451884518945190451914519245193451944519545196451974519845199452004520145202452034520445205452064520745208452094521045211452124521345214452154521645217452184521945220452214522245223452244522545226452274522845229452304523145232452334523445235452364523745238452394524045241452424524345244452454524645247452484524945250452514525245253452544525545256452574525845259452604526145262452634526445265452664526745268452694527045271452724527345274452754527645277452784527945280452814528245283452844528545286452874528845289452904529145292452934529445295452964529745298452994530045301453024530345304453054530645307453084530945310453114531245313453144531545316453174531845319453204532145322453234532445325453264532745328453294533045331453324533345334453354533645337453384533945340453414534245343453444534545346453474534845349453504535145352453534535445355453564535745358453594536045361453624536345364453654536645367453684536945370453714537245373453744537545376453774537845379453804538145382453834538445385453864538745388453894539045391453924539345394453954539645397453984539945400454014540245403454044540545406454074540845409454104541145412454134541445415454164541745418454194542045421454224542345424454254542645427454284542945430454314543245433454344543545436454374543845439454404544145442454434544445445454464544745448454494545045451454524545345454454554545645457454584545945460454614546245463454644546545466454674546845469454704547145472454734547445475454764547745478454794548045481454824548345484454854548645487454884548945490454914549245493454944549545496454974549845499455004550145502455034550445505455064550745508455094551045511455124551345514455154551645517455184551945520455214552245523455244552545526455274552845529455304553145532455334553445535455364553745538455394554045541455424554345544455454554645547455484554945550455514555245553455544555545556455574555845559455604556145562455634556445565455664556745568455694557045571455724557345574455754557645577455784557945580455814558245583455844558545586455874558845589455904559145592455934559445595455964559745598455994560045601456024560345604456054560645607456084560945610456114561245613456144561545616456174561845619456204562145622456234562445625456264562745628456294563045631456324563345634456354563645637456384563945640456414564245643456444564545646456474564845649456504565145652456534565445655456564565745658456594566045661456624566345664456654566645667456684566945670456714567245673456744567545676456774567845679456804568145682456834568445685456864568745688456894569045691456924569345694456954569645697456984569945700457014570245703457044570545706457074570845709457104571145712457134571445715457164571745718457194572045721457224572345724457254572645727457284572945730457314573245733457344573545736457374573845739457404574145742457434574445745457464574745748457494575045751457524575345754457554575645757457584575945760457614576245763457644576545766457674576845769457704577145772457734577445775457764577745778457794578045781457824578345784457854578645787457884578945790457914579245793457944579545796457974579845799458004580145802458034580445805458064580745808458094581045811458124581345814458154581645817458184581945820458214582245823458244582545826458274582845829458304583145832458334583445835458364583745838458394584045841458424584345844458454584645847458484584945850458514585245853458544585545856458574585845859458604586145862458634586445865458664586745868458694587045871458724587345874458754587645877458784587945880458814588245883458844588545886458874588845889458904589145892458934589445895458964589745898458994590045901459024590345904459054590645907459084590945910459114591245913459144591545916459174591845919459204592145922459234592445925459264592745928459294593045931459324593345934459354593645937459384593945940459414594245943459444594545946459474594845949459504595145952459534595445955459564595745958459594596045961459624596345964459654596645967459684596945970459714597245973459744597545976459774597845979459804598145982459834598445985459864598745988459894599045991459924599345994459954599645997459984599946000460014600246003460044600546006460074600846009460104601146012460134601446015460164601746018460194602046021460224602346024460254602646027460284602946030460314603246033460344603546036460374603846039460404604146042460434604446045460464604746048460494605046051460524605346054460554605646057460584605946060460614606246063460644606546066460674606846069460704607146072460734607446075460764607746078460794608046081460824608346084460854608646087460884608946090460914609246093460944609546096460974609846099461004610146102461034610446105461064610746108461094611046111461124611346114461154611646117461184611946120461214612246123461244612546126461274612846129461304613146132461334613446135461364613746138461394614046141461424614346144461454614646147461484614946150461514615246153461544615546156461574615846159461604616146162461634616446165461664616746168461694617046171461724617346174461754617646177461784617946180461814618246183461844618546186461874618846189461904619146192461934619446195461964619746198461994620046201462024620346204462054620646207462084620946210462114621246213462144621546216462174621846219462204622146222462234622446225462264622746228462294623046231462324623346234462354623646237462384623946240462414624246243462444624546246462474624846249462504625146252462534625446255462564625746258462594626046261462624626346264462654626646267462684626946270462714627246273462744627546276462774627846279462804628146282462834628446285462864628746288462894629046291462924629346294462954629646297462984629946300463014630246303463044630546306463074630846309463104631146312463134631446315463164631746318463194632046321463224632346324463254632646327463284632946330463314633246333463344633546336463374633846339463404634146342463434634446345463464634746348463494635046351463524635346354463554635646357463584635946360463614636246363463644636546366463674636846369463704637146372463734637446375463764637746378463794638046381463824638346384463854638646387463884638946390463914639246393463944639546396463974639846399464004640146402464034640446405464064640746408464094641046411464124641346414464154641646417464184641946420464214642246423464244642546426464274642846429464304643146432464334643446435464364643746438464394644046441464424644346444464454644646447464484644946450464514645246453464544645546456464574645846459464604646146462464634646446465464664646746468464694647046471464724647346474464754647646477464784647946480464814648246483464844648546486464874648846489464904649146492464934649446495464964649746498464994650046501465024650346504465054650646507465084650946510465114651246513465144651546516465174651846519465204652146522465234652446525465264652746528465294653046531465324653346534465354653646537465384653946540465414654246543465444654546546465474654846549465504655146552465534655446555465564655746558465594656046561465624656346564465654656646567465684656946570465714657246573465744657546576465774657846579465804658146582465834658446585465864658746588465894659046591465924659346594465954659646597465984659946600466014660246603466044660546606466074660846609466104661146612466134661446615466164661746618466194662046621466224662346624466254662646627466284662946630466314663246633466344663546636466374663846639466404664146642466434664446645466464664746648466494665046651466524665346654466554665646657466584665946660466614666246663466644666546666466674666846669466704667146672466734667446675466764667746678466794668046681466824668346684466854668646687466884668946690466914669246693466944669546696466974669846699467004670146702467034670446705467064670746708467094671046711467124671346714467154671646717467184671946720467214672246723467244672546726467274672846729467304673146732467334673446735467364673746738467394674046741467424674346744467454674646747467484674946750467514675246753467544675546756467574675846759467604676146762467634676446765467664676746768467694677046771467724677346774467754677646777467784677946780467814678246783467844678546786467874678846789467904679146792467934679446795467964679746798467994680046801468024680346804468054680646807468084680946810468114681246813468144681546816468174681846819468204682146822468234682446825468264682746828468294683046831468324683346834468354683646837468384683946840468414684246843468444684546846468474684846849468504685146852468534685446855468564685746858468594686046861468624686346864468654686646867468684686946870468714687246873468744687546876468774687846879468804688146882468834688446885468864688746888468894689046891468924689346894468954689646897468984689946900469014690246903469044690546906469074690846909469104691146912469134691446915469164691746918469194692046921469224692346924469254692646927469284692946930469314693246933469344693546936469374693846939469404694146942469434694446945469464694746948469494695046951469524695346954469554695646957469584695946960469614696246963469644696546966469674696846969469704697146972469734697446975469764697746978469794698046981469824698346984469854698646987469884698946990469914699246993469944699546996469974699846999470004700147002470034700447005470064700747008470094701047011470124701347014470154701647017470184701947020470214702247023470244702547026470274702847029470304703147032470334703447035470364703747038470394704047041470424704347044470454704647047470484704947050470514705247053470544705547056470574705847059470604706147062470634706447065470664706747068470694707047071470724707347074470754707647077470784707947080470814708247083470844708547086470874708847089470904709147092470934709447095470964709747098470994710047101471024710347104471054710647107471084710947110471114711247113471144711547116471174711847119471204712147122471234712447125471264712747128471294713047131471324713347134471354713647137471384713947140471414714247143471444714547146471474714847149471504715147152471534715447155471564715747158471594716047161471624716347164471654716647167471684716947170471714717247173471744717547176471774717847179471804718147182471834718447185471864718747188471894719047191471924719347194471954719647197471984719947200472014720247203472044720547206472074720847209472104721147212472134721447215472164721747218472194722047221472224722347224472254722647227472284722947230472314723247233472344723547236472374723847239472404724147242472434724447245472464724747248472494725047251472524725347254472554725647257472584725947260472614726247263472644726547266472674726847269472704727147272472734727447275472764727747278472794728047281472824728347284472854728647287472884728947290472914729247293472944729547296472974729847299473004730147302473034730447305473064730747308473094731047311473124731347314473154731647317473184731947320473214732247323473244732547326473274732847329473304733147332473334733447335473364733747338473394734047341473424734347344473454734647347473484734947350473514735247353473544735547356473574735847359473604736147362473634736447365473664736747368473694737047371473724737347374473754737647377473784737947380473814738247383473844738547386473874738847389473904739147392473934739447395473964739747398473994740047401474024740347404474054740647407474084740947410474114741247413474144741547416474174741847419474204742147422474234742447425474264742747428474294743047431474324743347434474354743647437474384743947440474414744247443474444744547446474474744847449474504745147452474534745447455474564745747458474594746047461474624746347464474654746647467474684746947470474714747247473474744747547476474774747847479474804748147482474834748447485474864748747488474894749047491474924749347494474954749647497474984749947500475014750247503475044750547506475074750847509475104751147512475134751447515475164751747518475194752047521475224752347524475254752647527475284752947530475314753247533475344753547536475374753847539475404754147542475434754447545475464754747548475494755047551475524755347554475554755647557475584755947560475614756247563475644756547566475674756847569475704757147572475734757447575475764757747578475794758047581475824758347584475854758647587475884758947590475914759247593475944759547596475974759847599476004760147602476034760447605476064760747608476094761047611476124761347614476154761647617476184761947620476214762247623476244762547626476274762847629476304763147632476334763447635476364763747638476394764047641476424764347644476454764647647476484764947650476514765247653476544765547656476574765847659476604766147662476634766447665476664766747668476694767047671476724767347674476754767647677476784767947680476814768247683476844768547686476874768847689476904769147692476934769447695476964769747698476994770047701477024770347704477054770647707477084770947710477114771247713477144771547716477174771847719477204772147722477234772447725477264772747728477294773047731477324773347734477354773647737477384773947740477414774247743477444774547746477474774847749477504775147752477534775447755477564775747758477594776047761477624776347764477654776647767477684776947770477714777247773477744777547776477774777847779477804778147782477834778447785477864778747788477894779047791477924779347794477954779647797477984779947800478014780247803478044780547806478074780847809478104781147812478134781447815478164781747818478194782047821478224782347824478254782647827478284782947830478314783247833478344783547836478374783847839478404784147842478434784447845478464784747848478494785047851478524785347854478554785647857478584785947860478614786247863478644786547866478674786847869478704787147872478734787447875478764787747878478794788047881478824788347884478854788647887478884788947890478914789247893478944789547896478974789847899479004790147902479034790447905479064790747908479094791047911479124791347914479154791647917479184791947920479214792247923479244792547926479274792847929479304793147932479334793447935479364793747938479394794047941479424794347944479454794647947479484794947950479514795247953479544795547956479574795847959479604796147962479634796447965479664796747968479694797047971479724797347974479754797647977479784797947980479814798247983479844798547986479874798847989479904799147992479934799447995479964799747998479994800048001480024800348004480054800648007480084800948010480114801248013480144801548016480174801848019480204802148022480234802448025480264802748028480294803048031480324803348034480354803648037480384803948040480414804248043480444804548046480474804848049480504805148052480534805448055480564805748058480594806048061480624806348064480654806648067480684806948070480714807248073480744807548076480774807848079480804808148082480834808448085480864808748088480894809048091480924809348094480954809648097480984809948100481014810248103481044810548106481074810848109481104811148112481134811448115481164811748118481194812048121481224812348124481254812648127481284812948130481314813248133481344813548136481374813848139481404814148142481434814448145481464814748148481494815048151481524815348154481554815648157481584815948160481614816248163481644816548166481674816848169481704817148172481734817448175481764817748178481794818048181481824818348184481854818648187481884818948190481914819248193481944819548196481974819848199482004820148202482034820448205482064820748208482094821048211482124821348214482154821648217482184821948220482214822248223482244822548226482274822848229482304823148232482334823448235482364823748238482394824048241482424824348244482454824648247482484824948250482514825248253482544825548256482574825848259482604826148262482634826448265482664826748268482694827048271482724827348274482754827648277482784827948280482814828248283482844828548286482874828848289482904829148292482934829448295482964829748298482994830048301483024830348304483054830648307483084830948310483114831248313483144831548316483174831848319483204832148322483234832448325483264832748328483294833048331483324833348334483354833648337483384833948340483414834248343483444834548346483474834848349483504835148352483534835448355483564835748358483594836048361483624836348364483654836648367483684836948370483714837248373483744837548376483774837848379483804838148382483834838448385483864838748388483894839048391483924839348394483954839648397483984839948400484014840248403484044840548406484074840848409484104841148412484134841448415484164841748418484194842048421484224842348424484254842648427484284842948430484314843248433484344843548436484374843848439484404844148442484434844448445484464844748448484494845048451484524845348454484554845648457484584845948460484614846248463484644846548466484674846848469484704847148472484734847448475484764847748478484794848048481484824848348484484854848648487484884848948490484914849248493484944849548496484974849848499485004850148502485034850448505485064850748508485094851048511485124851348514485154851648517485184851948520485214852248523485244852548526485274852848529485304853148532485334853448535485364853748538485394854048541485424854348544485454854648547485484854948550485514855248553485544855548556485574855848559485604856148562485634856448565485664856748568485694857048571485724857348574485754857648577485784857948580485814858248583485844858548586485874858848589485904859148592485934859448595485964859748598485994860048601486024860348604486054860648607486084860948610486114861248613486144861548616486174861848619486204862148622486234862448625486264862748628486294863048631486324863348634486354863648637486384863948640486414864248643486444864548646486474864848649486504865148652486534865448655486564865748658486594866048661486624866348664486654866648667486684866948670486714867248673486744867548676486774867848679486804868148682486834868448685486864868748688486894869048691486924869348694486954869648697486984869948700487014870248703487044870548706487074870848709487104871148712487134871448715487164871748718487194872048721487224872348724487254872648727487284872948730487314873248733487344873548736487374873848739487404874148742487434874448745487464874748748487494875048751487524875348754487554875648757487584875948760487614876248763487644876548766487674876848769487704877148772487734877448775487764877748778487794878048781487824878348784487854878648787487884878948790487914879248793487944879548796487974879848799488004880148802488034880448805488064880748808488094881048811488124881348814488154881648817488184881948820488214882248823488244882548826488274882848829488304883148832488334883448835488364883748838488394884048841488424884348844488454884648847488484884948850488514885248853488544885548856488574885848859488604886148862488634886448865488664886748868488694887048871488724887348874488754887648877488784887948880488814888248883488844888548886488874888848889488904889148892488934889448895488964889748898488994890048901489024890348904489054890648907489084890948910489114891248913489144891548916489174891848919489204892148922489234892448925489264892748928489294893048931489324893348934489354893648937489384893948940489414894248943489444894548946489474894848949489504895148952489534895448955489564895748958489594896048961489624896348964489654896648967489684896948970489714897248973489744897548976489774897848979489804898148982489834898448985489864898748988489894899048991489924899348994489954899648997489984899949000490014900249003490044900549006490074900849009490104901149012490134901449015490164901749018490194902049021490224902349024490254902649027490284902949030490314903249033490344903549036490374903849039490404904149042490434904449045490464904749048490494905049051490524905349054490554905649057490584905949060490614906249063490644906549066490674906849069490704907149072490734907449075490764907749078490794908049081490824908349084490854908649087490884908949090490914909249093490944909549096490974909849099491004910149102491034910449105491064910749108491094911049111491124911349114491154911649117491184911949120491214912249123491244912549126491274912849129491304913149132491334913449135491364913749138491394914049141491424914349144491454914649147491484914949150491514915249153491544915549156491574915849159491604916149162491634916449165491664916749168491694917049171491724917349174491754917649177491784917949180491814918249183491844918549186491874918849189491904919149192491934919449195491964919749198491994920049201492024920349204492054920649207492084920949210492114921249213492144921549216492174921849219492204922149222492234922449225492264922749228492294923049231492324923349234492354923649237492384923949240492414924249243492444924549246492474924849249492504925149252492534925449255492564925749258492594926049261492624926349264492654926649267492684926949270492714927249273492744927549276492774927849279492804928149282492834928449285492864928749288492894929049291492924929349294492954929649297492984929949300493014930249303493044930549306493074930849309493104931149312493134931449315493164931749318493194932049321493224932349324493254932649327493284932949330493314933249333493344933549336493374933849339493404934149342493434934449345493464934749348493494935049351493524935349354493554935649357493584935949360493614936249363493644936549366493674936849369493704937149372493734937449375493764937749378493794938049381493824938349384493854938649387493884938949390493914939249393493944939549396493974939849399494004940149402494034940449405494064940749408494094941049411494124941349414494154941649417494184941949420494214942249423494244942549426494274942849429494304943149432494334943449435494364943749438494394944049441494424944349444494454944649447494484944949450494514945249453494544945549456494574945849459494604946149462494634946449465494664946749468494694947049471494724947349474494754947649477494784947949480494814948249483494844948549486494874948849489494904949149492494934949449495494964949749498494994950049501495024950349504495054950649507495084950949510495114951249513495144951549516495174951849519495204952149522495234952449525495264952749528495294953049531495324953349534495354953649537495384953949540495414954249543495444954549546495474954849549495504955149552495534955449555495564955749558495594956049561495624956349564495654956649567495684956949570495714957249573495744957549576495774957849579495804958149582495834958449585495864958749588495894959049591495924959349594495954959649597495984959949600496014960249603496044960549606496074960849609496104961149612496134961449615496164961749618496194962049621496224962349624496254962649627496284962949630496314963249633496344963549636496374963849639496404964149642496434964449645496464964749648496494965049651496524965349654496554965649657496584965949660496614966249663496644966549666496674966849669496704967149672496734967449675496764967749678496794968049681496824968349684496854968649687496884968949690496914969249693496944969549696496974969849699497004970149702497034970449705497064970749708497094971049711497124971349714497154971649717497184971949720497214972249723497244972549726497274972849729497304973149732497334973449735497364973749738497394974049741497424974349744497454974649747497484974949750497514975249753497544975549756497574975849759497604976149762497634976449765497664976749768497694977049771497724977349774497754977649777497784977949780497814978249783497844978549786497874978849789497904979149792497934979449795497964979749798497994980049801498024980349804498054980649807498084980949810498114981249813498144981549816498174981849819498204982149822498234982449825498264982749828498294983049831498324983349834498354983649837498384983949840498414984249843498444984549846498474984849849498504985149852498534985449855498564985749858498594986049861498624986349864498654986649867498684986949870498714987249873498744987549876498774987849879498804988149882498834988449885498864988749888498894989049891498924989349894498954989649897498984989949900499014990249903499044990549906499074990849909499104991149912499134991449915499164991749918499194992049921499224992349924499254992649927499284992949930499314993249933499344993549936499374993849939499404994149942499434994449945499464994749948499494995049951499524995349954499554995649957499584995949960499614996249963499644996549966499674996849969499704997149972499734997449975499764997749978499794998049981499824998349984499854998649987499884998949990499914999249993499944999549996499974999849999500005000150002500035000450005500065000750008500095001050011500125001350014500155001650017500185001950020500215002250023500245002550026500275002850029500305003150032500335003450035500365003750038500395004050041500425004350044500455004650047500485004950050500515005250053500545005550056500575005850059500605006150062500635006450065500665006750068500695007050071500725007350074500755007650077500785007950080500815008250083500845008550086500875008850089500905009150092500935009450095500965009750098500995010050101501025010350104501055010650107501085010950110501115011250113501145011550116501175011850119501205012150122501235012450125501265012750128501295013050131501325013350134501355013650137501385013950140501415014250143501445014550146501475014850149501505015150152501535015450155501565015750158501595016050161501625016350164501655016650167501685016950170501715017250173501745017550176501775017850179501805018150182501835018450185501865018750188501895019050191501925019350194501955019650197501985019950200502015020250203502045020550206502075020850209502105021150212502135021450215502165021750218502195022050221502225022350224502255022650227502285022950230502315023250233502345023550236502375023850239502405024150242502435024450245502465024750248502495025050251502525025350254502555025650257502585025950260502615026250263502645026550266502675026850269502705027150272502735027450275502765027750278502795028050281502825028350284502855028650287502885028950290502915029250293502945029550296502975029850299503005030150302503035030450305503065030750308503095031050311503125031350314503155031650317503185031950320503215032250323503245032550326503275032850329503305033150332503335033450335503365033750338503395034050341503425034350344503455034650347503485034950350503515035250353503545035550356503575035850359503605036150362503635036450365503665036750368503695037050371503725037350374503755037650377503785037950380503815038250383503845038550386503875038850389503905039150392503935039450395503965039750398503995040050401504025040350404504055040650407504085040950410504115041250413504145041550416504175041850419504205042150422504235042450425504265042750428504295043050431504325043350434504355043650437504385043950440504415044250443504445044550446504475044850449504505045150452504535045450455504565045750458504595046050461504625046350464504655046650467504685046950470504715047250473504745047550476504775047850479504805048150482504835048450485504865048750488504895049050491504925049350494504955049650497504985049950500505015050250503505045050550506505075050850509505105051150512505135051450515505165051750518505195052050521505225052350524505255052650527505285052950530505315053250533505345053550536505375053850539505405054150542505435054450545505465054750548505495055050551505525055350554505555055650557505585055950560505615056250563505645056550566505675056850569505705057150572505735057450575505765057750578505795058050581505825058350584505855058650587505885058950590505915059250593505945059550596505975059850599506005060150602506035060450605506065060750608506095061050611506125061350614506155061650617506185061950620506215062250623506245062550626506275062850629506305063150632506335063450635506365063750638506395064050641506425064350644506455064650647506485064950650506515065250653506545065550656506575065850659506605066150662506635066450665506665066750668506695067050671506725067350674506755067650677506785067950680506815068250683506845068550686506875068850689506905069150692506935069450695506965069750698506995070050701507025070350704507055070650707507085070950710507115071250713507145071550716507175071850719507205072150722507235072450725507265072750728507295073050731507325073350734507355073650737507385073950740507415074250743507445074550746507475074850749507505075150752507535075450755507565075750758507595076050761507625076350764507655076650767507685076950770507715077250773507745077550776507775077850779507805078150782507835078450785507865078750788507895079050791507925079350794507955079650797507985079950800508015080250803508045080550806508075080850809508105081150812508135081450815508165081750818508195082050821508225082350824508255082650827508285082950830508315083250833508345083550836508375083850839508405084150842508435084450845508465084750848508495085050851508525085350854508555085650857508585085950860508615086250863508645086550866508675086850869508705087150872508735087450875508765087750878508795088050881508825088350884508855088650887508885088950890508915089250893508945089550896508975089850899509005090150902509035090450905509065090750908509095091050911509125091350914509155091650917509185091950920509215092250923509245092550926509275092850929509305093150932509335093450935509365093750938509395094050941509425094350944509455094650947509485094950950509515095250953509545095550956509575095850959509605096150962509635096450965509665096750968509695097050971509725097350974509755097650977509785097950980509815098250983509845098550986509875098850989509905099150992509935099450995509965099750998509995100051001510025100351004510055100651007510085100951010510115101251013510145101551016510175101851019510205102151022510235102451025510265102751028510295103051031510325103351034510355103651037510385103951040510415104251043510445104551046510475104851049510505105151052510535105451055510565105751058510595106051061510625106351064510655106651067510685106951070510715107251073510745107551076510775107851079510805108151082510835108451085510865108751088510895109051091510925109351094510955109651097510985109951100511015110251103511045110551106511075110851109511105111151112511135111451115511165111751118511195112051121511225112351124511255112651127511285112951130511315113251133511345113551136511375113851139511405114151142511435114451145511465114751148511495115051151511525115351154511555115651157511585115951160511615116251163511645116551166511675116851169511705117151172511735117451175511765117751178511795118051181511825118351184511855118651187511885118951190511915119251193511945119551196511975119851199512005120151202512035120451205512065120751208512095121051211512125121351214512155121651217512185121951220512215122251223512245122551226512275122851229512305123151232512335123451235512365123751238512395124051241512425124351244512455124651247512485124951250512515125251253512545125551256512575125851259512605126151262512635126451265512665126751268512695127051271512725127351274512755127651277512785127951280512815128251283512845128551286512875128851289512905129151292512935129451295512965129751298512995130051301513025130351304513055130651307513085130951310513115131251313513145131551316513175131851319513205132151322513235132451325513265132751328513295133051331513325133351334513355133651337513385133951340513415134251343513445134551346513475134851349513505135151352513535135451355513565135751358513595136051361513625136351364513655136651367513685136951370513715137251373513745137551376513775137851379513805138151382513835138451385513865138751388513895139051391513925139351394513955139651397513985139951400514015140251403514045140551406514075140851409514105141151412514135141451415514165141751418514195142051421514225142351424514255142651427514285142951430514315143251433514345143551436514375143851439514405144151442514435144451445514465144751448514495145051451514525145351454514555145651457514585145951460514615146251463514645146551466514675146851469514705147151472514735147451475514765147751478514795148051481514825148351484514855148651487514885148951490514915149251493514945149551496514975149851499515005150151502515035150451505515065150751508515095151051511515125151351514515155151651517515185151951520515215152251523515245152551526515275152851529515305153151532515335153451535515365153751538515395154051541515425154351544515455154651547515485154951550515515155251553515545155551556515575155851559515605156151562515635156451565515665156751568515695157051571515725157351574515755157651577515785157951580515815158251583515845158551586515875158851589515905159151592515935159451595515965159751598515995160051601516025160351604516055160651607516085160951610516115161251613516145161551616516175161851619516205162151622516235162451625516265162751628516295163051631516325163351634516355163651637516385163951640516415164251643516445164551646516475164851649516505165151652516535165451655516565165751658516595166051661516625166351664516655166651667516685166951670516715167251673516745167551676516775167851679516805168151682516835168451685516865168751688516895169051691516925169351694516955169651697516985169951700517015170251703517045170551706517075170851709517105171151712517135171451715517165171751718517195172051721517225172351724517255172651727517285172951730517315173251733517345173551736517375173851739517405174151742517435174451745517465174751748517495175051751517525175351754517555175651757517585175951760517615176251763517645176551766517675176851769517705177151772517735177451775517765177751778517795178051781517825178351784517855178651787517885178951790517915179251793517945179551796517975179851799518005180151802518035180451805518065180751808518095181051811518125181351814518155181651817518185181951820518215182251823518245182551826518275182851829518305183151832518335183451835518365183751838518395184051841518425184351844518455184651847518485184951850518515185251853518545185551856518575185851859518605186151862518635186451865518665186751868518695187051871518725187351874518755187651877518785187951880518815188251883518845188551886518875188851889518905189151892518935189451895518965189751898518995190051901519025190351904519055190651907519085190951910519115191251913519145191551916519175191851919519205192151922519235192451925519265192751928519295193051931519325193351934519355193651937519385193951940519415194251943519445194551946519475194851949519505195151952519535195451955519565195751958519595196051961519625196351964519655196651967519685196951970519715197251973519745197551976519775197851979519805198151982519835198451985519865198751988519895199051991519925199351994519955199651997519985199952000520015200252003520045200552006520075200852009520105201152012520135201452015520165201752018520195202052021520225202352024520255202652027520285202952030520315203252033520345203552036520375203852039520405204152042520435204452045520465204752048520495205052051520525205352054520555205652057520585205952060520615206252063520645206552066520675206852069520705207152072520735207452075520765207752078520795208052081520825208352084520855208652087520885208952090520915209252093520945209552096520975209852099521005210152102521035210452105521065210752108521095211052111521125211352114521155211652117521185211952120521215212252123521245212552126521275212852129521305213152132521335213452135521365213752138521395214052141521425214352144521455214652147521485214952150521515215252153521545215552156521575215852159521605216152162521635216452165521665216752168521695217052171521725217352174521755217652177521785217952180521815218252183521845218552186521875218852189521905219152192521935219452195521965219752198521995220052201522025220352204522055220652207522085220952210522115221252213522145221552216522175221852219522205222152222522235222452225522265222752228522295223052231522325223352234522355223652237522385223952240522415224252243522445224552246522475224852249522505225152252522535225452255522565225752258522595226052261522625226352264522655226652267522685226952270522715227252273522745227552276522775227852279522805228152282522835228452285522865228752288522895229052291522925229352294522955229652297522985229952300523015230252303523045230552306523075230852309523105231152312523135231452315523165231752318523195232052321523225232352324523255232652327523285232952330523315233252333523345233552336523375233852339523405234152342523435234452345523465234752348523495235052351523525235352354523555235652357523585235952360523615236252363523645236552366523675236852369523705237152372523735237452375523765237752378523795238052381523825238352384523855238652387523885238952390523915239252393523945239552396523975239852399524005240152402524035240452405524065240752408524095241052411524125241352414524155241652417524185241952420524215242252423524245242552426524275242852429524305243152432524335243452435524365243752438524395244052441524425244352444524455244652447524485244952450524515245252453524545245552456524575245852459524605246152462524635246452465524665246752468524695247052471524725247352474524755247652477524785247952480524815248252483524845248552486524875248852489524905249152492524935249452495524965249752498524995250052501525025250352504525055250652507525085250952510525115251252513525145251552516525175251852519525205252152522525235252452525525265252752528525295253052531525325253352534525355253652537525385253952540525415254252543525445254552546525475254852549525505255152552525535255452555525565255752558525595256052561525625256352564525655256652567525685256952570525715257252573525745257552576525775257852579525805258152582525835258452585525865258752588525895259052591525925259352594525955259652597525985259952600526015260252603526045260552606526075260852609526105261152612526135261452615526165261752618526195262052621526225262352624526255262652627526285262952630526315263252633526345263552636526375263852639526405264152642526435264452645526465264752648526495265052651526525265352654526555265652657526585265952660526615266252663526645266552666526675266852669526705267152672526735267452675526765267752678526795268052681526825268352684526855268652687526885268952690526915269252693526945269552696526975269852699527005270152702527035270452705527065270752708527095271052711527125271352714527155271652717527185271952720527215272252723527245272552726527275272852729527305273152732527335273452735527365273752738527395274052741527425274352744527455274652747527485274952750527515275252753527545275552756527575275852759527605276152762527635276452765527665276752768527695277052771527725277352774527755277652777527785277952780527815278252783527845278552786527875278852789527905279152792527935279452795527965279752798527995280052801528025280352804528055280652807528085280952810528115281252813528145281552816528175281852819528205282152822528235282452825528265282752828528295283052831528325283352834528355283652837528385283952840528415284252843528445284552846528475284852849528505285152852528535285452855528565285752858528595286052861528625286352864528655286652867528685286952870528715287252873528745287552876528775287852879528805288152882528835288452885528865288752888528895289052891528925289352894528955289652897528985289952900529015290252903529045290552906529075290852909529105291152912529135291452915529165291752918529195292052921529225292352924529255292652927529285292952930529315293252933529345293552936529375293852939529405294152942529435294452945529465294752948529495295052951529525295352954529555295652957529585295952960529615296252963529645296552966529675296852969529705297152972529735297452975529765297752978529795298052981529825298352984529855298652987529885298952990529915299252993529945299552996529975299852999530005300153002530035300453005530065300753008530095301053011530125301353014530155301653017530185301953020530215302253023530245302553026530275302853029530305303153032530335303453035530365303753038530395304053041530425304353044530455304653047530485304953050530515305253053530545305553056530575305853059530605306153062530635306453065530665306753068530695307053071530725307353074530755307653077530785307953080530815308253083530845308553086530875308853089530905309153092530935309453095530965309753098530995310053101531025310353104531055310653107531085310953110531115311253113531145311553116531175311853119531205312153122531235312453125531265312753128531295313053131531325313353134531355313653137531385313953140531415314253143531445314553146531475314853149531505315153152531535315453155531565315753158531595316053161531625316353164531655316653167531685316953170531715317253173531745317553176531775317853179531805318153182531835318453185531865318753188531895319053191531925319353194531955319653197531985319953200532015320253203532045320553206532075320853209532105321153212532135321453215532165321753218532195322053221532225322353224532255322653227532285322953230532315323253233532345323553236532375323853239532405324153242532435324453245532465324753248532495325053251532525325353254532555325653257532585325953260532615326253263532645326553266532675326853269532705327153272532735327453275532765327753278532795328053281532825328353284532855328653287532885328953290532915329253293532945329553296532975329853299533005330153302533035330453305533065330753308533095331053311533125331353314533155331653317533185331953320533215332253323533245332553326533275332853329533305333153332533335333453335533365333753338533395334053341533425334353344533455334653347533485334953350533515335253353533545335553356533575335853359533605336153362533635336453365533665336753368533695337053371533725337353374533755337653377533785337953380533815338253383533845338553386533875338853389533905339153392533935339453395533965339753398533995340053401534025340353404534055340653407534085340953410534115341253413534145341553416534175341853419534205342153422534235342453425534265342753428534295343053431534325343353434534355343653437534385343953440534415344253443534445344553446534475344853449534505345153452534535345453455534565345753458534595346053461534625346353464534655346653467534685346953470534715347253473534745347553476534775347853479534805348153482534835348453485534865348753488534895349053491534925349353494534955349653497534985349953500535015350253503535045350553506535075350853509535105351153512535135351453515535165351753518535195352053521535225352353524535255352653527535285352953530535315353253533535345353553536535375353853539535405354153542535435354453545535465354753548535495355053551535525355353554535555355653557535585355953560535615356253563535645356553566535675356853569535705357153572535735357453575535765357753578535795358053581535825358353584535855358653587535885358953590535915359253593535945359553596535975359853599536005360153602536035360453605536065360753608536095361053611536125361353614536155361653617536185361953620536215362253623536245362553626536275362853629536305363153632536335363453635536365363753638536395364053641536425364353644536455364653647536485364953650536515365253653536545365553656536575365853659536605366153662536635366453665536665366753668536695367053671536725367353674536755367653677536785367953680536815368253683536845368553686536875368853689536905369153692536935369453695536965369753698536995370053701537025370353704537055370653707537085370953710537115371253713537145371553716537175371853719537205372153722537235372453725537265372753728537295373053731537325373353734537355373653737537385373953740537415374253743537445374553746537475374853749537505375153752537535375453755537565375753758537595376053761537625376353764537655376653767537685376953770537715377253773537745377553776537775377853779537805378153782537835378453785537865378753788537895379053791537925379353794537955379653797537985379953800538015380253803538045380553806538075380853809538105381153812538135381453815538165381753818538195382053821538225382353824538255382653827538285382953830538315383253833538345383553836538375383853839538405384153842538435384453845538465384753848538495385053851538525385353854538555385653857538585385953860538615386253863538645386553866538675386853869538705387153872538735387453875538765387753878538795388053881538825388353884538855388653887538885388953890538915389253893538945389553896538975389853899539005390153902539035390453905539065390753908539095391053911539125391353914539155391653917539185391953920539215392253923539245392553926539275392853929539305393153932539335393453935539365393753938539395394053941539425394353944539455394653947539485394953950539515395253953539545395553956539575395853959539605396153962539635396453965539665396753968539695397053971539725397353974539755397653977539785397953980539815398253983539845398553986539875398853989539905399153992539935399453995539965399753998539995400054001540025400354004540055400654007540085400954010540115401254013540145401554016540175401854019540205402154022540235402454025540265402754028540295403054031540325403354034540355403654037540385403954040540415404254043540445404554046540475404854049540505405154052540535405454055540565405754058540595406054061540625406354064540655406654067540685406954070540715407254073540745407554076540775407854079540805408154082540835408454085540865408754088540895409054091540925409354094540955409654097540985409954100541015410254103541045410554106541075410854109541105411154112541135411454115541165411754118541195412054121541225412354124541255412654127541285412954130541315413254133541345413554136541375413854139541405414154142541435414454145541465414754148541495415054151541525415354154541555415654157541585415954160541615416254163541645416554166541675416854169541705417154172541735417454175541765417754178541795418054181541825418354184541855418654187541885418954190541915419254193541945419554196541975419854199542005420154202542035420454205542065420754208542095421054211542125421354214542155421654217542185421954220542215422254223542245422554226542275422854229542305423154232542335423454235542365423754238542395424054241542425424354244542455424654247542485424954250542515425254253542545425554256542575425854259542605426154262542635426454265542665426754268542695427054271542725427354274542755427654277542785427954280542815428254283542845428554286542875428854289542905429154292542935429454295542965429754298542995430054301543025430354304543055430654307543085430954310543115431254313543145431554316543175431854319543205432154322543235432454325543265432754328543295433054331543325433354334543355433654337543385433954340543415434254343543445434554346543475434854349543505435154352543535435454355543565435754358543595436054361543625436354364543655436654367543685436954370543715437254373543745437554376543775437854379543805438154382543835438454385543865438754388543895439054391543925439354394543955439654397543985439954400544015440254403544045440554406544075440854409544105441154412544135441454415544165441754418544195442054421544225442354424544255442654427544285442954430544315443254433544345443554436544375443854439544405444154442544435444454445544465444754448544495445054451544525445354454544555445654457544585445954460544615446254463544645446554466544675446854469544705447154472544735447454475544765447754478544795448054481544825448354484544855448654487544885448954490544915449254493544945449554496544975449854499545005450154502545035450454505545065450754508545095451054511545125451354514545155451654517545185451954520545215452254523545245452554526545275452854529545305453154532545335453454535545365453754538545395454054541545425454354544545455454654547545485454954550545515455254553545545455554556545575455854559545605456154562545635456454565545665456754568545695457054571545725457354574545755457654577545785457954580545815458254583545845458554586545875458854589545905459154592545935459454595545965459754598545995460054601546025460354604546055460654607546085460954610546115461254613546145461554616546175461854619546205462154622546235462454625546265462754628546295463054631546325463354634546355463654637546385463954640546415464254643546445464554646546475464854649546505465154652546535465454655546565465754658546595466054661546625466354664546655466654667546685466954670546715467254673546745467554676546775467854679546805468154682546835468454685546865468754688546895469054691546925469354694546955469654697546985469954700547015470254703547045470554706547075470854709547105471154712547135471454715547165471754718547195472054721547225472354724547255472654727547285472954730547315473254733547345473554736547375473854739547405474154742547435474454745547465474754748547495475054751547525475354754547555475654757547585475954760547615476254763547645476554766547675476854769547705477154772547735477454775547765477754778547795478054781547825478354784547855478654787547885478954790547915479254793547945479554796547975479854799548005480154802548035480454805548065480754808548095481054811548125481354814548155481654817548185481954820548215482254823548245482554826548275482854829548305483154832548335483454835548365483754838548395484054841548425484354844548455484654847548485484954850548515485254853548545485554856548575485854859548605486154862548635486454865548665486754868548695487054871548725487354874548755487654877548785487954880548815488254883548845488554886548875488854889548905489154892548935489454895548965489754898548995490054901549025490354904549055490654907549085490954910549115491254913549145491554916549175491854919549205492154922549235492454925549265492754928549295493054931549325493354934549355493654937549385493954940549415494254943549445494554946549475494854949549505495154952549535495454955549565495754958549595496054961549625496354964549655496654967549685496954970549715497254973549745497554976549775497854979549805498154982549835498454985549865498754988549895499054991549925499354994549955499654997549985499955000550015500255003550045500555006550075500855009550105501155012550135501455015550165501755018550195502055021550225502355024550255502655027550285502955030550315503255033550345503555036550375503855039550405504155042550435504455045550465504755048550495505055051550525505355054550555505655057550585505955060550615506255063550645506555066550675506855069550705507155072550735507455075550765507755078550795508055081550825508355084550855508655087550885508955090550915509255093550945509555096550975509855099551005510155102551035510455105551065510755108551095511055111551125511355114551155511655117551185511955120551215512255123551245512555126551275512855129551305513155132551335513455135551365513755138551395514055141551425514355144551455514655147551485514955150551515515255153551545515555156551575515855159551605516155162551635516455165551665516755168551695517055171551725517355174551755517655177551785517955180551815518255183551845518555186551875518855189551905519155192551935519455195551965519755198551995520055201552025520355204552055520655207552085520955210552115521255213552145521555216552175521855219552205522155222552235522455225552265522755228552295523055231552325523355234552355523655237552385523955240552415524255243552445524555246552475524855249552505525155252552535525455255552565525755258552595526055261552625526355264552655526655267552685526955270552715527255273552745527555276552775527855279552805528155282552835528455285552865528755288552895529055291552925529355294552955529655297552985529955300553015530255303553045530555306553075530855309553105531155312553135531455315553165531755318553195532055321553225532355324553255532655327553285532955330553315533255333553345533555336553375533855339553405534155342553435534455345553465534755348553495535055351553525535355354553555535655357553585535955360553615536255363553645536555366553675536855369553705537155372553735537455375553765537755378553795538055381553825538355384553855538655387553885538955390553915539255393553945539555396553975539855399554005540155402554035540455405554065540755408554095541055411554125541355414554155541655417554185541955420554215542255423554245542555426554275542855429554305543155432554335543455435554365543755438554395544055441554425544355444554455544655447554485544955450554515545255453554545545555456554575545855459554605546155462554635546455465554665546755468554695547055471554725547355474554755547655477554785547955480554815548255483554845548555486554875548855489554905549155492554935549455495554965549755498554995550055501555025550355504555055550655507555085550955510555115551255513555145551555516555175551855519555205552155522555235552455525555265552755528555295553055531555325553355534555355553655537555385553955540555415554255543555445554555546555475554855549555505555155552555535555455555555565555755558555595556055561555625556355564555655556655567555685556955570555715557255573555745557555576555775557855579555805558155582555835558455585555865558755588555895559055591555925559355594555955559655597555985559955600556015560255603556045560555606556075560855609556105561155612556135561455615556165561755618556195562055621556225562355624556255562655627556285562955630556315563255633556345563555636556375563855639556405564155642556435564455645556465564755648556495565055651556525565355654556555565655657556585565955660556615566255663556645566555666556675566855669556705567155672556735567455675556765567755678556795568055681556825568355684556855568655687556885568955690556915569255693556945569555696556975569855699557005570155702557035570455705557065570755708557095571055711557125571355714557155571655717557185571955720557215572255723557245572555726557275572855729557305573155732557335573455735557365573755738557395574055741557425574355744557455574655747557485574955750557515575255753557545575555756557575575855759557605576155762557635576455765557665576755768557695577055771557725577355774557755577655777557785577955780557815578255783557845578555786557875578855789557905579155792557935579455795557965579755798557995580055801558025580355804558055580655807558085580955810558115581255813558145581555816558175581855819558205582155822558235582455825558265582755828558295583055831558325583355834558355583655837558385583955840558415584255843558445584555846558475584855849558505585155852558535585455855558565585755858558595586055861558625586355864558655586655867558685586955870558715587255873558745587555876558775587855879558805588155882558835588455885558865588755888558895589055891558925589355894558955589655897558985589955900559015590255903559045590555906559075590855909559105591155912559135591455915559165591755918559195592055921559225592355924559255592655927559285592955930559315593255933559345593555936559375593855939559405594155942559435594455945559465594755948559495595055951559525595355954559555595655957559585595955960559615596255963559645596555966559675596855969559705597155972559735597455975559765597755978559795598055981559825598355984559855598655987559885598955990559915599255993559945599555996559975599855999560005600156002560035600456005560065600756008560095601056011560125601356014560155601656017560185601956020560215602256023560245602556026560275602856029560305603156032560335603456035560365603756038560395604056041560425604356044560455604656047560485604956050560515605256053560545605556056560575605856059560605606156062560635606456065560665606756068560695607056071560725607356074560755607656077560785607956080560815608256083560845608556086560875608856089560905609156092560935609456095560965609756098560995610056101561025610356104561055610656107561085610956110561115611256113561145611556116561175611856119561205612156122561235612456125561265612756128561295613056131561325613356134561355613656137561385613956140561415614256143561445614556146561475614856149561505615156152561535615456155561565615756158561595616056161561625616356164561655616656167561685616956170561715617256173561745617556176561775617856179561805618156182561835618456185561865618756188561895619056191561925619356194561955619656197561985619956200562015620256203562045620556206562075620856209562105621156212562135621456215562165621756218562195622056221562225622356224562255622656227562285622956230562315623256233562345623556236562375623856239562405624156242562435624456245562465624756248562495625056251562525625356254562555625656257562585625956260562615626256263562645626556266562675626856269562705627156272562735627456275562765627756278562795628056281562825628356284562855628656287562885628956290562915629256293562945629556296562975629856299563005630156302563035630456305563065630756308563095631056311563125631356314563155631656317563185631956320563215632256323563245632556326563275632856329563305633156332563335633456335563365633756338563395634056341563425634356344563455634656347563485634956350563515635256353563545635556356563575635856359563605636156362563635636456365563665636756368563695637056371563725637356374563755637656377563785637956380563815638256383563845638556386563875638856389563905639156392563935639456395563965639756398563995640056401564025640356404564055640656407564085640956410564115641256413564145641556416564175641856419564205642156422564235642456425564265642756428564295643056431564325643356434564355643656437564385643956440564415644256443564445644556446564475644856449564505645156452564535645456455564565645756458564595646056461564625646356464564655646656467564685646956470564715647256473564745647556476564775647856479564805648156482564835648456485564865648756488564895649056491564925649356494564955649656497564985649956500565015650256503565045650556506565075650856509565105651156512565135651456515565165651756518565195652056521565225652356524565255652656527565285652956530565315653256533565345653556536565375653856539565405654156542565435654456545565465654756548565495655056551565525655356554565555655656557565585655956560565615656256563565645656556566565675656856569565705657156572565735657456575565765657756578565795658056581565825658356584565855658656587565885658956590565915659256593565945659556596565975659856599566005660156602566035660456605566065660756608566095661056611566125661356614566155661656617566185661956620566215662256623566245662556626566275662856629566305663156632566335663456635566365663756638566395664056641566425664356644566455664656647566485664956650566515665256653566545665556656566575665856659566605666156662566635666456665566665666756668566695667056671566725667356674566755667656677566785667956680566815668256683566845668556686566875668856689566905669156692566935669456695566965669756698566995670056701567025670356704567055670656707567085670956710567115671256713567145671556716567175671856719567205672156722567235672456725567265672756728567295673056731567325673356734567355673656737567385673956740567415674256743567445674556746567475674856749567505675156752567535675456755567565675756758567595676056761567625676356764567655676656767567685676956770567715677256773567745677556776567775677856779567805678156782567835678456785567865678756788567895679056791567925679356794567955679656797567985679956800568015680256803568045680556806568075680856809568105681156812568135681456815568165681756818568195682056821568225682356824568255682656827568285682956830568315683256833568345683556836568375683856839568405684156842568435684456845568465684756848568495685056851568525685356854568555685656857568585685956860568615686256863568645686556866568675686856869568705687156872568735687456875568765687756878568795688056881568825688356884568855688656887568885688956890568915689256893568945689556896568975689856899569005690156902569035690456905569065690756908569095691056911569125691356914569155691656917569185691956920569215692256923569245692556926569275692856929569305693156932569335693456935569365693756938569395694056941569425694356944569455694656947569485694956950569515695256953569545695556956569575695856959569605696156962569635696456965569665696756968569695697056971569725697356974569755697656977569785697956980569815698256983569845698556986569875698856989569905699156992569935699456995569965699756998569995700057001570025700357004570055700657007570085700957010570115701257013570145701557016570175701857019570205702157022570235702457025570265702757028570295703057031570325703357034570355703657037570385703957040570415704257043570445704557046570475704857049570505705157052570535705457055570565705757058570595706057061570625706357064570655706657067570685706957070570715707257073570745707557076570775707857079570805708157082570835708457085570865708757088570895709057091570925709357094570955709657097570985709957100571015710257103571045710557106571075710857109571105711157112571135711457115571165711757118571195712057121571225712357124571255712657127571285712957130571315713257133571345713557136571375713857139571405714157142571435714457145571465714757148571495715057151571525715357154571555715657157571585715957160571615716257163571645716557166571675716857169571705717157172571735717457175571765717757178571795718057181571825718357184571855718657187571885718957190571915719257193571945719557196571975719857199572005720157202572035720457205572065720757208572095721057211572125721357214572155721657217572185721957220572215722257223572245722557226572275722857229572305723157232572335723457235572365723757238572395724057241572425724357244572455724657247572485724957250572515725257253572545725557256572575725857259572605726157262572635726457265572665726757268572695727057271572725727357274572755727657277572785727957280572815728257283572845728557286572875728857289572905729157292572935729457295572965729757298572995730057301573025730357304573055730657307573085730957310573115731257313573145731557316573175731857319573205732157322573235732457325573265732757328573295733057331573325733357334573355733657337573385733957340573415734257343573445734557346573475734857349573505735157352573535735457355573565735757358573595736057361573625736357364573655736657367573685736957370573715737257373573745737557376573775737857379573805738157382573835738457385573865738757388573895739057391573925739357394573955739657397573985739957400574015740257403574045740557406574075740857409574105741157412574135741457415574165741757418574195742057421574225742357424574255742657427574285742957430574315743257433574345743557436574375743857439574405744157442574435744457445574465744757448574495745057451574525745357454574555745657457574585745957460574615746257463574645746557466574675746857469574705747157472574735747457475574765747757478574795748057481574825748357484574855748657487574885748957490574915749257493574945749557496574975749857499575005750157502575035750457505575065750757508575095751057511575125751357514575155751657517575185751957520575215752257523575245752557526575275752857529575305753157532575335753457535575365753757538575395754057541575425754357544575455754657547575485754957550575515755257553575545755557556575575755857559575605756157562575635756457565575665756757568575695757057571575725757357574575755757657577575785757957580575815758257583575845758557586575875758857589575905759157592575935759457595575965759757598575995760057601576025760357604576055760657607576085760957610576115761257613576145761557616576175761857619576205762157622576235762457625576265762757628576295763057631576325763357634576355763657637576385763957640576415764257643576445764557646576475764857649576505765157652576535765457655576565765757658576595766057661576625766357664576655766657667576685766957670576715767257673576745767557676576775767857679576805768157682576835768457685576865768757688576895769057691576925769357694576955769657697576985769957700577015770257703577045770557706577075770857709577105771157712577135771457715577165771757718577195772057721577225772357724577255772657727577285772957730577315773257733577345773557736577375773857739577405774157742577435774457745577465774757748577495775057751577525775357754577555775657757577585775957760577615776257763577645776557766577675776857769577705777157772577735777457775577765777757778577795778057781577825778357784577855778657787577885778957790577915779257793577945779557796577975779857799578005780157802578035780457805578065780757808578095781057811578125781357814578155781657817578185781957820578215782257823578245782557826578275782857829578305783157832578335783457835578365783757838578395784057841578425784357844578455784657847578485784957850578515785257853578545785557856578575785857859578605786157862578635786457865578665786757868578695787057871578725787357874578755787657877578785787957880578815788257883578845788557886578875788857889578905789157892578935789457895578965789757898578995790057901579025790357904579055790657907579085790957910579115791257913579145791557916579175791857919579205792157922579235792457925579265792757928579295793057931579325793357934579355793657937579385793957940579415794257943579445794557946579475794857949579505795157952579535795457955579565795757958579595796057961579625796357964579655796657967579685796957970579715797257973579745797557976579775797857979579805798157982579835798457985579865798757988579895799057991579925799357994579955799657997579985799958000580015800258003580045800558006580075800858009580105801158012580135801458015580165801758018580195802058021580225802358024580255802658027580285802958030580315803258033580345803558036580375803858039580405804158042580435804458045580465804758048580495805058051580525805358054580555805658057580585805958060580615806258063580645806558066580675806858069580705807158072580735807458075580765807758078580795808058081580825808358084580855808658087580885808958090580915809258093580945809558096580975809858099581005810158102581035810458105581065810758108581095811058111581125811358114581155811658117581185811958120581215812258123581245812558126581275812858129581305813158132581335813458135581365813758138581395814058141581425814358144581455814658147581485814958150581515815258153581545815558156581575815858159581605816158162581635816458165581665816758168581695817058171581725817358174581755817658177581785817958180581815818258183581845818558186581875818858189581905819158192581935819458195581965819758198581995820058201582025820358204582055820658207582085820958210582115821258213582145821558216582175821858219582205822158222582235822458225582265822758228582295823058231582325823358234582355823658237582385823958240582415824258243582445824558246582475824858249582505825158252582535825458255582565825758258582595826058261582625826358264582655826658267582685826958270582715827258273582745827558276582775827858279582805828158282582835828458285582865828758288582895829058291582925829358294582955829658297582985829958300583015830258303583045830558306583075830858309583105831158312583135831458315583165831758318583195832058321583225832358324583255832658327583285832958330583315833258333583345833558336583375833858339583405834158342583435834458345583465834758348583495835058351583525835358354583555835658357583585835958360583615836258363583645836558366583675836858369583705837158372583735837458375583765837758378583795838058381583825838358384583855838658387583885838958390583915839258393583945839558396583975839858399584005840158402584035840458405584065840758408584095841058411584125841358414584155841658417584185841958420584215842258423584245842558426584275842858429584305843158432584335843458435584365843758438584395844058441584425844358444584455844658447584485844958450584515845258453584545845558456584575845858459584605846158462584635846458465584665846758468584695847058471584725847358474584755847658477584785847958480584815848258483584845848558486584875848858489584905849158492584935849458495584965849758498584995850058501585025850358504585055850658507585085850958510585115851258513585145851558516585175851858519585205852158522585235852458525585265852758528585295853058531585325853358534585355853658537585385853958540585415854258543585445854558546585475854858549585505855158552585535855458555585565855758558585595856058561585625856358564585655856658567585685856958570585715857258573585745857558576585775857858579585805858158582585835858458585585865858758588585895859058591585925859358594585955859658597585985859958600586015860258603586045860558606586075860858609586105861158612586135861458615586165861758618586195862058621586225862358624586255862658627586285862958630586315863258633586345863558636586375863858639586405864158642586435864458645586465864758648586495865058651586525865358654586555865658657586585865958660586615866258663586645866558666586675866858669586705867158672586735867458675586765867758678586795868058681586825868358684586855868658687586885868958690586915869258693586945869558696586975869858699587005870158702587035870458705587065870758708587095871058711587125871358714587155871658717587185871958720587215872258723587245872558726587275872858729587305873158732587335873458735587365873758738587395874058741587425874358744587455874658747587485874958750587515875258753587545875558756587575875858759587605876158762587635876458765587665876758768587695877058771587725877358774587755877658777587785877958780587815878258783587845878558786587875878858789587905879158792587935879458795587965879758798587995880058801588025880358804588055880658807588085880958810588115881258813588145881558816588175881858819588205882158822588235882458825588265882758828588295883058831588325883358834588355883658837588385883958840588415884258843588445884558846588475884858849588505885158852588535885458855588565885758858588595886058861588625886358864588655886658867588685886958870588715887258873588745887558876588775887858879588805888158882588835888458885588865888758888588895889058891588925889358894588955889658897588985889958900589015890258903589045890558906589075890858909589105891158912589135891458915589165891758918589195892058921589225892358924589255892658927589285892958930589315893258933589345893558936589375893858939589405894158942589435894458945589465894758948589495895058951589525895358954589555895658957589585895958960589615896258963589645896558966589675896858969589705897158972589735897458975589765897758978589795898058981589825898358984589855898658987589885898958990589915899258993589945899558996589975899858999590005900159002590035900459005590065900759008590095901059011590125901359014590155901659017590185901959020590215902259023590245902559026590275902859029590305903159032590335903459035590365903759038590395904059041590425904359044590455904659047590485904959050590515905259053590545905559056590575905859059590605906159062590635906459065590665906759068590695907059071590725907359074590755907659077590785907959080590815908259083590845908559086590875908859089590905909159092590935909459095590965909759098590995910059101591025910359104591055910659107591085910959110591115911259113591145911559116591175911859119591205912159122591235912459125591265912759128591295913059131591325913359134591355913659137591385913959140591415914259143591445914559146591475914859149591505915159152591535915459155591565915759158591595916059161591625916359164591655916659167591685916959170591715917259173591745917559176591775917859179591805918159182591835918459185591865918759188591895919059191591925919359194591955919659197591985919959200592015920259203592045920559206592075920859209592105921159212592135921459215592165921759218592195922059221592225922359224592255922659227592285922959230592315923259233592345923559236592375923859239592405924159242592435924459245592465924759248592495925059251592525925359254592555925659257592585925959260592615926259263592645926559266592675926859269592705927159272592735927459275592765927759278592795928059281592825928359284592855928659287592885928959290592915929259293592945929559296592975929859299593005930159302593035930459305593065930759308593095931059311593125931359314593155931659317593185931959320593215932259323593245932559326593275932859329593305933159332593335933459335593365933759338593395934059341593425934359344593455934659347593485934959350593515935259353593545935559356593575935859359593605936159362593635936459365593665936759368593695937059371593725937359374593755937659377593785937959380593815938259383593845938559386593875938859389593905939159392593935939459395593965939759398593995940059401594025940359404594055940659407594085940959410594115941259413594145941559416594175941859419594205942159422594235942459425594265942759428594295943059431594325943359434594355943659437594385943959440594415944259443594445944559446594475944859449594505945159452594535945459455594565945759458594595946059461594625946359464594655946659467594685946959470594715947259473594745947559476594775947859479594805948159482594835948459485594865948759488594895949059491594925949359494594955949659497594985949959500595015950259503595045950559506595075950859509595105951159512595135951459515595165951759518595195952059521595225952359524595255952659527595285952959530595315953259533595345953559536595375953859539595405954159542595435954459545595465954759548595495955059551595525955359554595555955659557595585955959560595615956259563595645956559566595675956859569595705957159572595735957459575595765957759578595795958059581595825958359584595855958659587595885958959590595915959259593595945959559596595975959859599596005960159602596035960459605596065960759608596095961059611596125961359614596155961659617596185961959620596215962259623596245962559626596275962859629596305963159632596335963459635596365963759638596395964059641596425964359644596455964659647596485964959650596515965259653596545965559656596575965859659596605966159662596635966459665596665966759668596695967059671596725967359674596755967659677596785967959680596815968259683596845968559686596875968859689596905969159692596935969459695596965969759698596995970059701597025970359704597055970659707597085970959710597115971259713597145971559716597175971859719597205972159722597235972459725597265972759728597295973059731597325973359734597355973659737597385973959740597415974259743597445974559746597475974859749597505975159752597535975459755597565975759758597595976059761597625976359764597655976659767597685976959770597715977259773597745977559776597775977859779597805978159782597835978459785597865978759788597895979059791597925979359794597955979659797597985979959800598015980259803598045980559806598075980859809598105981159812598135981459815598165981759818598195982059821598225982359824598255982659827598285982959830598315983259833598345983559836598375983859839598405984159842598435984459845598465984759848598495985059851598525985359854598555985659857598585985959860598615986259863598645986559866598675986859869598705987159872598735987459875598765987759878598795988059881598825988359884598855988659887598885988959890598915989259893598945989559896598975989859899599005990159902599035990459905599065990759908599095991059911599125991359914599155991659917599185991959920599215992259923599245992559926599275992859929599305993159932599335993459935599365993759938599395994059941599425994359944599455994659947599485994959950599515995259953599545995559956599575995859959599605996159962599635996459965599665996759968599695997059971599725997359974599755997659977599785997959980599815998259983599845998559986599875998859989599905999159992599935999459995599965999759998599996000060001600026000360004600056000660007600086000960010600116001260013600146001560016600176001860019600206002160022600236002460025600266002760028600296003060031600326003360034600356003660037600386003960040600416004260043600446004560046600476004860049600506005160052600536005460055600566005760058600596006060061600626006360064600656006660067600686006960070600716007260073600746007560076600776007860079600806008160082600836008460085600866008760088600896009060091600926009360094600956009660097600986009960100601016010260103601046010560106601076010860109601106011160112601136011460115601166011760118601196012060121601226012360124601256012660127601286012960130601316013260133601346013560136601376013860139601406014160142601436014460145601466014760148601496015060151601526015360154601556015660157601586015960160601616016260163601646016560166601676016860169601706017160172601736017460175601766017760178601796018060181601826018360184601856018660187601886018960190601916019260193601946019560196601976019860199602006020160202602036020460205602066020760208602096021060211602126021360214602156021660217602186021960220602216022260223602246022560226602276022860229602306023160232602336023460235602366023760238602396024060241602426024360244602456024660247602486024960250602516025260253602546025560256602576025860259602606026160262602636026460265602666026760268602696027060271602726027360274602756027660277602786027960280602816028260283602846028560286602876028860289602906029160292602936029460295602966029760298602996030060301603026030360304603056030660307603086030960310603116031260313603146031560316603176031860319603206032160322603236032460325603266032760328603296033060331603326033360334603356033660337603386033960340603416034260343603446034560346603476034860349603506035160352603536035460355603566035760358603596036060361603626036360364603656036660367603686036960370603716037260373603746037560376603776037860379603806038160382603836038460385603866038760388603896039060391603926039360394603956039660397603986039960400604016040260403604046040560406604076040860409604106041160412604136041460415604166041760418604196042060421604226042360424604256042660427604286042960430604316043260433604346043560436604376043860439604406044160442604436044460445604466044760448604496045060451604526045360454604556045660457604586045960460604616046260463604646046560466604676046860469604706047160472604736047460475604766047760478604796048060481604826048360484604856048660487604886048960490604916049260493604946049560496604976049860499605006050160502605036050460505605066050760508605096051060511605126051360514605156051660517605186051960520605216052260523605246052560526605276052860529605306053160532605336053460535605366053760538605396054060541605426054360544605456054660547605486054960550605516055260553605546055560556605576055860559605606056160562605636056460565605666056760568605696057060571605726057360574605756057660577605786057960580605816058260583605846058560586605876058860589605906059160592605936059460595605966059760598605996060060601606026060360604606056060660607606086060960610606116061260613606146061560616606176061860619606206062160622606236062460625606266062760628606296063060631606326063360634606356063660637606386063960640606416064260643606446064560646606476064860649606506065160652606536065460655606566065760658606596066060661606626066360664606656066660667606686066960670606716067260673606746067560676606776067860679606806068160682606836068460685606866068760688606896069060691606926069360694606956069660697606986069960700607016070260703607046070560706607076070860709607106071160712607136071460715607166071760718607196072060721607226072360724607256072660727607286072960730607316073260733607346073560736607376073860739607406074160742607436074460745607466074760748607496075060751607526075360754607556075660757607586075960760607616076260763607646076560766607676076860769607706077160772607736077460775607766077760778607796078060781607826078360784607856078660787607886078960790607916079260793607946079560796607976079860799608006080160802608036080460805608066080760808608096081060811608126081360814608156081660817608186081960820608216082260823608246082560826608276082860829608306083160832608336083460835608366083760838608396084060841608426084360844608456084660847608486084960850608516085260853608546085560856608576085860859608606086160862608636086460865608666086760868608696087060871608726087360874608756087660877608786087960880608816088260883608846088560886608876088860889608906089160892608936089460895608966089760898608996090060901609026090360904609056090660907609086090960910609116091260913609146091560916609176091860919609206092160922609236092460925609266092760928609296093060931609326093360934609356093660937609386093960940609416094260943609446094560946609476094860949609506095160952609536095460955609566095760958609596096060961609626096360964609656096660967609686096960970609716097260973609746097560976609776097860979609806098160982609836098460985609866098760988609896099060991609926099360994609956099660997609986099961000610016100261003610046100561006610076100861009610106101161012610136101461015610166101761018610196102061021610226102361024610256102661027610286102961030610316103261033610346103561036610376103861039610406104161042610436104461045610466104761048610496105061051610526105361054610556105661057610586105961060610616106261063610646106561066610676106861069610706107161072610736107461075610766107761078610796108061081610826108361084610856108661087610886108961090610916109261093610946109561096610976109861099611006110161102611036110461105611066110761108611096111061111611126111361114611156111661117611186111961120611216112261123611246112561126611276112861129611306113161132611336113461135611366113761138611396114061141611426114361144611456114661147611486114961150611516115261153611546115561156611576115861159611606116161162611636116461165611666116761168611696117061171611726117361174611756117661177611786117961180611816118261183611846118561186611876118861189611906119161192611936119461195611966119761198611996120061201612026120361204612056120661207612086120961210612116121261213612146121561216612176121861219612206122161222612236122461225612266122761228612296123061231612326123361234612356123661237612386123961240612416124261243612446124561246612476124861249612506125161252612536125461255612566125761258612596126061261612626126361264612656126661267612686126961270612716127261273612746127561276612776127861279612806128161282612836128461285612866128761288612896129061291612926129361294612956129661297612986129961300613016130261303613046130561306613076130861309613106131161312613136131461315613166131761318613196132061321613226132361324613256132661327613286132961330613316133261333613346133561336613376133861339613406134161342613436134461345613466134761348613496135061351613526135361354613556135661357613586135961360613616136261363613646136561366613676136861369613706137161372613736137461375613766137761378613796138061381613826138361384613856138661387613886138961390613916139261393613946139561396613976139861399614006140161402614036140461405614066140761408614096141061411614126141361414614156141661417614186141961420614216142261423614246142561426614276142861429614306143161432614336143461435614366143761438614396144061441614426144361444614456144661447614486144961450614516145261453614546145561456614576145861459614606146161462614636146461465614666146761468614696147061471614726147361474614756147661477614786147961480614816148261483614846148561486614876148861489614906149161492614936149461495614966149761498614996150061501615026150361504615056150661507615086150961510615116151261513615146151561516615176151861519615206152161522615236152461525615266152761528615296153061531615326153361534615356153661537615386153961540615416154261543615446154561546615476154861549615506155161552615536155461555615566155761558615596156061561615626156361564615656156661567615686156961570615716157261573615746157561576615776157861579615806158161582615836158461585615866158761588615896159061591615926159361594615956159661597615986159961600616016160261603616046160561606616076160861609616106161161612616136161461615616166161761618616196162061621616226162361624616256162661627616286162961630616316163261633616346163561636616376163861639616406164161642616436164461645616466164761648616496165061651616526165361654616556165661657616586165961660616616166261663616646166561666616676166861669616706167161672616736167461675616766167761678616796168061681616826168361684616856168661687616886168961690616916169261693616946169561696616976169861699617006170161702617036170461705617066170761708617096171061711617126171361714617156171661717617186171961720617216172261723617246172561726617276172861729617306173161732617336173461735617366173761738617396174061741617426174361744617456174661747617486174961750617516175261753617546175561756617576175861759617606176161762617636176461765617666176761768617696177061771617726177361774617756177661777617786177961780617816178261783617846178561786617876178861789617906179161792617936179461795617966179761798617996180061801618026180361804618056180661807618086180961810618116181261813618146181561816618176181861819618206182161822618236182461825618266182761828618296183061831618326183361834618356183661837618386183961840618416184261843618446184561846618476184861849618506185161852618536185461855618566185761858618596186061861618626186361864618656186661867618686186961870618716187261873618746187561876618776187861879618806188161882618836188461885618866188761888618896189061891618926189361894618956189661897618986189961900619016190261903619046190561906619076190861909619106191161912619136191461915619166191761918619196192061921619226192361924619256192661927619286192961930619316193261933619346193561936619376193861939619406194161942619436194461945619466194761948619496195061951619526195361954619556195661957619586195961960619616196261963619646196561966619676196861969619706197161972619736197461975619766197761978619796198061981619826198361984619856198661987619886198961990619916199261993619946199561996619976199861999620006200162002620036200462005620066200762008620096201062011620126201362014620156201662017620186201962020620216202262023620246202562026620276202862029620306203162032620336203462035620366203762038620396204062041620426204362044620456204662047620486204962050620516205262053620546205562056620576205862059620606206162062620636206462065620666206762068620696207062071620726207362074620756207662077620786207962080620816208262083620846208562086620876208862089620906209162092620936209462095620966209762098620996210062101621026210362104621056210662107621086210962110621116211262113621146211562116621176211862119621206212162122621236212462125621266212762128621296213062131621326213362134621356213662137621386213962140621416214262143621446214562146621476214862149621506215162152621536215462155621566215762158621596216062161621626216362164621656216662167621686216962170621716217262173621746217562176621776217862179621806218162182621836218462185621866218762188621896219062191621926219362194621956219662197621986219962200622016220262203622046220562206622076220862209622106221162212622136221462215622166221762218622196222062221622226222362224622256222662227622286222962230622316223262233622346223562236622376223862239622406224162242622436224462245622466224762248622496225062251622526225362254622556225662257622586225962260622616226262263622646226562266622676226862269622706227162272622736227462275622766227762278622796228062281622826228362284622856228662287622886228962290622916229262293622946229562296622976229862299623006230162302623036230462305623066230762308623096231062311623126231362314623156231662317623186231962320623216232262323623246232562326623276232862329623306233162332623336233462335623366233762338623396234062341623426234362344623456234662347623486234962350623516235262353623546235562356623576235862359623606236162362623636236462365623666236762368623696237062371623726237362374623756237662377623786237962380623816238262383623846238562386623876238862389623906239162392623936239462395623966239762398623996240062401624026240362404624056240662407624086240962410624116241262413624146241562416624176241862419624206242162422624236242462425624266242762428624296243062431624326243362434624356243662437624386243962440624416244262443624446244562446624476244862449624506245162452624536245462455624566245762458624596246062461624626246362464624656246662467624686246962470624716247262473624746247562476624776247862479624806248162482624836248462485624866248762488624896249062491624926249362494624956249662497624986249962500625016250262503625046250562506625076250862509625106251162512625136251462515625166251762518625196252062521625226252362524625256252662527625286252962530625316253262533625346253562536625376253862539625406254162542625436254462545625466254762548625496255062551625526255362554625556255662557625586255962560625616256262563625646256562566625676256862569625706257162572625736257462575625766257762578625796258062581625826258362584625856258662587625886258962590625916259262593625946259562596625976259862599626006260162602626036260462605626066260762608626096261062611626126261362614626156261662617626186261962620626216262262623626246262562626626276262862629626306263162632626336263462635626366263762638626396264062641626426264362644626456264662647626486264962650626516265262653626546265562656626576265862659626606266162662626636266462665626666266762668626696267062671626726267362674626756267662677626786267962680626816268262683626846268562686626876268862689626906269162692626936269462695626966269762698626996270062701627026270362704627056270662707627086270962710627116271262713627146271562716627176271862719627206272162722627236272462725627266272762728627296273062731627326273362734627356273662737627386273962740627416274262743627446274562746627476274862749627506275162752627536275462755627566275762758627596276062761627626276362764627656276662767627686276962770627716277262773627746277562776627776277862779627806278162782627836278462785627866278762788627896279062791627926279362794627956279662797627986279962800628016280262803628046280562806628076280862809628106281162812628136281462815628166281762818628196282062821628226282362824628256282662827628286282962830628316283262833628346283562836628376283862839628406284162842628436284462845628466284762848628496285062851628526285362854628556285662857628586285962860628616286262863628646286562866628676286862869628706287162872628736287462875628766287762878628796288062881628826288362884628856288662887628886288962890628916289262893628946289562896628976289862899629006290162902629036290462905629066290762908629096291062911629126291362914629156291662917629186291962920629216292262923629246292562926629276292862929629306293162932629336293462935629366293762938629396294062941629426294362944629456294662947629486294962950629516295262953629546295562956629576295862959629606296162962629636296462965629666296762968629696297062971629726297362974629756297662977629786297962980629816298262983629846298562986629876298862989629906299162992629936299462995629966299762998629996300063001630026300363004630056300663007630086300963010630116301263013630146301563016630176301863019630206302163022630236302463025630266302763028630296303063031630326303363034630356303663037630386303963040630416304263043630446304563046630476304863049630506305163052630536305463055630566305763058630596306063061630626306363064630656306663067630686306963070630716307263073630746307563076630776307863079630806308163082630836308463085630866308763088630896309063091630926309363094630956309663097630986309963100631016310263103631046310563106631076310863109631106311163112631136311463115631166311763118631196312063121631226312363124631256312663127631286312963130631316313263133631346313563136631376313863139631406314163142631436314463145631466314763148631496315063151631526315363154631556315663157631586315963160631616316263163631646316563166631676316863169631706317163172631736317463175631766317763178631796318063181631826318363184631856318663187631886318963190631916319263193631946319563196631976319863199632006320163202632036320463205632066320763208632096321063211632126321363214632156321663217632186321963220632216322263223632246322563226632276322863229632306323163232632336323463235632366323763238632396324063241632426324363244632456324663247632486324963250632516325263253632546325563256632576325863259632606326163262632636326463265632666326763268632696327063271632726327363274632756327663277632786327963280632816328263283632846328563286632876328863289632906329163292632936329463295632966329763298632996330063301633026330363304633056330663307633086330963310633116331263313633146331563316633176331863319633206332163322633236332463325633266332763328633296333063331633326333363334633356333663337633386333963340633416334263343633446334563346633476334863349633506335163352633536335463355633566335763358633596336063361633626336363364633656336663367633686336963370633716337263373633746337563376633776337863379633806338163382633836338463385633866338763388633896339063391633926339363394633956339663397633986339963400634016340263403634046340563406634076340863409634106341163412634136341463415634166341763418634196342063421634226342363424634256342663427634286342963430634316343263433634346343563436634376343863439634406344163442634436344463445634466344763448634496345063451634526345363454634556345663457634586345963460634616346263463634646346563466634676346863469634706347163472634736347463475634766347763478634796348063481634826348363484634856348663487634886348963490634916349263493634946349563496634976349863499635006350163502635036350463505635066350763508635096351063511635126351363514635156351663517635186351963520635216352263523635246352563526635276352863529635306353163532635336353463535635366353763538635396354063541635426354363544635456354663547635486354963550635516355263553635546355563556635576355863559635606356163562635636356463565635666356763568635696357063571635726357363574635756357663577635786357963580635816358263583635846358563586635876358863589635906359163592635936359463595635966359763598635996360063601636026360363604636056360663607636086360963610636116361263613636146361563616636176361863619636206362163622636236362463625636266362763628636296363063631636326363363634636356363663637636386363963640636416364263643636446364563646636476364863649636506365163652636536365463655636566365763658636596366063661636626366363664636656366663667636686366963670636716367263673636746367563676636776367863679636806368163682636836368463685636866368763688636896369063691636926369363694636956369663697636986369963700637016370263703637046370563706637076370863709637106371163712637136371463715637166371763718637196372063721637226372363724637256372663727637286372963730637316373263733637346373563736637376373863739637406374163742637436374463745637466374763748637496375063751637526375363754637556375663757637586375963760637616376263763637646376563766637676376863769637706377163772637736377463775637766377763778637796378063781637826378363784637856378663787637886378963790637916379263793637946379563796637976379863799638006380163802638036380463805638066380763808638096381063811638126381363814638156381663817638186381963820638216382263823638246382563826638276382863829638306383163832638336383463835638366383763838638396384063841638426384363844638456384663847638486384963850638516385263853638546385563856638576385863859638606386163862638636386463865638666386763868638696387063871638726387363874638756387663877638786387963880638816388263883638846388563886638876388863889638906389163892638936389463895638966389763898638996390063901639026390363904639056390663907639086390963910639116391263913639146391563916639176391863919639206392163922639236392463925639266392763928639296393063931639326393363934639356393663937639386393963940639416394263943639446394563946639476394863949639506395163952639536395463955639566395763958639596396063961639626396363964639656396663967639686396963970639716397263973639746397563976639776397863979639806398163982639836398463985639866398763988639896399063991639926399363994639956399663997639986399964000640016400264003640046400564006640076400864009640106401164012640136401464015640166401764018640196402064021640226402364024640256402664027640286402964030640316403264033640346403564036640376403864039640406404164042640436404464045640466404764048640496405064051640526405364054640556405664057640586405964060640616406264063640646406564066640676406864069640706407164072640736407464075640766407764078640796408064081640826408364084640856408664087640886408964090640916409264093640946409564096640976409864099641006410164102641036410464105641066410764108641096411064111641126411364114641156411664117641186411964120641216412264123641246412564126641276412864129641306413164132641336413464135641366413764138641396414064141641426414364144641456414664147641486414964150641516415264153641546415564156641576415864159641606416164162641636416464165641666416764168641696417064171641726417364174641756417664177641786417964180641816418264183641846418564186641876418864189641906419164192641936419464195641966419764198641996420064201642026420364204642056420664207642086420964210642116421264213642146421564216642176421864219642206422164222642236422464225642266422764228642296423064231642326423364234642356423664237642386423964240642416424264243642446424564246642476424864249642506425164252642536425464255642566425764258642596426064261642626426364264642656426664267642686426964270642716427264273642746427564276642776427864279642806428164282642836428464285642866428764288642896429064291642926429364294642956429664297642986429964300643016430264303643046430564306643076430864309643106431164312643136431464315643166431764318643196432064321643226432364324643256432664327643286432964330643316433264333643346433564336643376433864339643406434164342643436434464345643466434764348643496435064351643526435364354643556435664357643586435964360643616436264363643646436564366643676436864369643706437164372643736437464375643766437764378643796438064381643826438364384643856438664387643886438964390643916439264393643946439564396643976439864399644006440164402644036440464405644066440764408644096441064411644126441364414644156441664417644186441964420644216442264423644246442564426644276442864429644306443164432644336443464435644366443764438644396444064441644426444364444644456444664447644486444964450644516445264453644546445564456644576445864459644606446164462644636446464465644666446764468644696447064471644726447364474644756447664477644786447964480644816448264483644846448564486644876448864489644906449164492644936449464495644966449764498644996450064501645026450364504645056450664507645086450964510645116451264513645146451564516645176451864519645206452164522645236452464525645266452764528645296453064531645326453364534645356453664537645386453964540645416454264543645446454564546645476454864549645506455164552645536455464555645566455764558645596456064561645626456364564645656456664567645686456964570645716457264573645746457564576645776457864579645806458164582645836458464585645866458764588645896459064591645926459364594645956459664597645986459964600646016460264603646046460564606646076460864609646106461164612646136461464615646166461764618646196462064621646226462364624646256462664627646286462964630646316463264633646346463564636646376463864639646406464164642646436464464645646466464764648646496465064651646526465364654646556465664657646586465964660646616466264663646646466564666646676466864669646706467164672646736467464675646766467764678646796468064681646826468364684646856468664687646886468964690646916469264693646946469564696646976469864699647006470164702647036470464705647066470764708647096471064711647126471364714647156471664717647186471964720647216472264723647246472564726647276472864729647306473164732647336473464735647366473764738647396474064741647426474364744647456474664747647486474964750647516475264753647546475564756647576475864759647606476164762647636476464765647666476764768647696477064771647726477364774647756477664777647786477964780647816478264783647846478564786647876478864789647906479164792647936479464795647966479764798647996480064801648026480364804648056480664807648086480964810648116481264813648146481564816648176481864819648206482164822648236482464825648266482764828648296483064831648326483364834648356483664837648386483964840648416484264843648446484564846648476484864849648506485164852648536485464855648566485764858648596486064861648626486364864648656486664867648686486964870648716487264873648746487564876648776487864879648806488164882648836488464885648866488764888648896489064891648926489364894648956489664897648986489964900649016490264903649046490564906649076490864909649106491164912649136491464915649166491764918649196492064921649226492364924649256492664927649286492964930649316493264933649346493564936649376493864939649406494164942649436494464945649466494764948649496495064951649526495364954649556495664957649586495964960649616496264963649646496564966649676496864969649706497164972649736497464975649766497764978649796498064981649826498364984649856498664987649886498964990649916499264993649946499564996649976499864999650006500165002650036500465005650066500765008650096501065011650126501365014650156501665017650186501965020650216502265023650246502565026650276502865029650306503165032650336503465035650366503765038650396504065041650426504365044650456504665047650486504965050650516505265053650546505565056650576505865059650606506165062650636506465065650666506765068650696507065071650726507365074650756507665077650786507965080650816508265083650846508565086650876508865089650906509165092650936509465095650966509765098650996510065101651026510365104651056510665107651086510965110651116511265113651146511565116651176511865119651206512165122651236512465125651266512765128651296513065131651326513365134651356513665137651386513965140651416514265143651446514565146651476514865149651506515165152651536515465155651566515765158651596516065161651626516365164651656516665167651686516965170651716517265173651746517565176651776517865179651806518165182651836518465185651866518765188651896519065191651926519365194651956519665197651986519965200652016520265203652046520565206652076520865209652106521165212652136521465215652166521765218652196522065221652226522365224652256522665227652286522965230652316523265233652346523565236652376523865239652406524165242652436524465245652466524765248652496525065251652526525365254652556525665257652586525965260652616526265263652646526565266652676526865269652706527165272652736527465275652766527765278652796528065281652826528365284652856528665287652886528965290652916529265293652946529565296652976529865299653006530165302653036530465305653066530765308653096531065311653126531365314653156531665317653186531965320653216532265323653246532565326653276532865329653306533165332653336533465335653366533765338653396534065341653426534365344653456534665347653486534965350653516535265353653546535565356653576535865359653606536165362653636536465365653666536765368653696537065371653726537365374653756537665377653786537965380653816538265383653846538565386653876538865389653906539165392653936539465395653966539765398653996540065401654026540365404654056540665407654086540965410654116541265413654146541565416654176541865419654206542165422654236542465425654266542765428654296543065431654326543365434654356543665437654386543965440654416544265443654446544565446654476544865449654506545165452654536545465455654566545765458654596546065461654626546365464654656546665467654686546965470654716547265473654746547565476654776547865479654806548165482654836548465485654866548765488654896549065491654926549365494654956549665497654986549965500655016550265503655046550565506655076550865509655106551165512655136551465515655166551765518655196552065521655226552365524655256552665527655286552965530655316553265533655346553565536655376553865539655406554165542655436554465545655466554765548655496555065551655526555365554655556555665557655586555965560655616556265563655646556565566655676556865569655706557165572655736557465575655766557765578655796558065581655826558365584655856558665587655886558965590655916559265593655946559565596655976559865599656006560165602656036560465605656066560765608656096561065611656126561365614656156561665617656186561965620656216562265623656246562565626656276562865629656306563165632656336563465635656366563765638656396564065641656426564365644656456564665647656486564965650656516565265653656546565565656656576565865659656606566165662656636566465665656666566765668656696567065671656726567365674656756567665677656786567965680656816568265683656846568565686656876568865689656906569165692656936569465695656966569765698656996570065701657026570365704657056570665707657086570965710657116571265713657146571565716657176571865719657206572165722657236572465725657266572765728657296573065731657326573365734657356573665737657386573965740657416574265743657446574565746657476574865749657506575165752657536575465755657566575765758657596576065761657626576365764657656576665767657686576965770657716577265773657746577565776657776577865779657806578165782657836578465785657866578765788657896579065791657926579365794657956579665797657986579965800658016580265803658046580565806658076580865809658106581165812658136581465815658166581765818658196582065821658226582365824658256582665827658286582965830658316583265833658346583565836658376583865839658406584165842658436584465845658466584765848658496585065851658526585365854658556585665857658586585965860658616586265863658646586565866658676586865869658706587165872658736587465875658766587765878658796588065881658826588365884658856588665887658886588965890658916589265893658946589565896658976589865899659006590165902659036590465905659066590765908659096591065911659126591365914659156591665917659186591965920659216592265923659246592565926659276592865929659306593165932659336593465935659366593765938659396594065941659426594365944659456594665947659486594965950659516595265953659546595565956659576595865959659606596165962659636596465965659666596765968659696597065971659726597365974659756597665977659786597965980659816598265983659846598565986659876598865989659906599165992659936599465995659966599765998659996600066001660026600366004660056600666007660086600966010660116601266013660146601566016660176601866019660206602166022660236602466025660266602766028660296603066031660326603366034660356603666037660386603966040660416604266043660446604566046660476604866049660506605166052660536605466055660566605766058660596606066061660626606366064660656606666067660686606966070660716607266073660746607566076660776607866079660806608166082660836608466085660866608766088660896609066091660926609366094660956609666097660986609966100661016610266103661046610566106661076610866109661106611166112661136611466115661166611766118661196612066121661226612366124661256612666127661286612966130661316613266133661346613566136661376613866139661406614166142661436614466145661466614766148661496615066151661526615366154661556615666157661586615966160661616616266163661646616566166661676616866169661706617166172661736617466175661766617766178661796618066181661826618366184661856618666187661886618966190661916619266193661946619566196661976619866199662006620166202662036620466205662066620766208662096621066211662126621366214662156621666217662186621966220662216622266223662246622566226662276622866229662306623166232662336623466235662366623766238662396624066241662426624366244662456624666247662486624966250662516625266253662546625566256662576625866259662606626166262662636626466265662666626766268662696627066271662726627366274662756627666277662786627966280662816628266283662846628566286662876628866289662906629166292662936629466295662966629766298662996630066301663026630366304663056630666307663086630966310663116631266313663146631566316663176631866319663206632166322663236632466325663266632766328663296633066331663326633366334663356633666337663386633966340663416634266343663446634566346663476634866349663506635166352663536635466355663566635766358663596636066361663626636366364663656636666367663686636966370663716637266373663746637566376663776637866379663806638166382663836638466385663866638766388663896639066391663926639366394663956639666397663986639966400664016640266403664046640566406664076640866409664106641166412664136641466415664166641766418664196642066421664226642366424664256642666427664286642966430664316643266433664346643566436664376643866439664406644166442664436644466445664466644766448664496645066451664526645366454664556645666457664586645966460664616646266463664646646566466664676646866469664706647166472664736647466475664766647766478664796648066481664826648366484664856648666487664886648966490664916649266493664946649566496664976649866499665006650166502665036650466505665066650766508665096651066511665126651366514665156651666517665186651966520665216652266523665246652566526665276652866529665306653166532665336653466535665366653766538665396654066541665426654366544665456654666547665486654966550665516655266553665546655566556665576655866559665606656166562665636656466565665666656766568665696657066571665726657366574665756657666577665786657966580665816658266583665846658566586665876658866589665906659166592665936659466595665966659766598665996660066601666026660366604666056660666607666086660966610666116661266613666146661566616666176661866619666206662166622666236662466625666266662766628666296663066631666326663366634666356663666637666386663966640666416664266643666446664566646666476664866649666506665166652666536665466655666566665766658666596666066661666626666366664666656666666667666686666966670666716667266673666746667566676666776667866679666806668166682666836668466685666866668766688666896669066691666926669366694666956669666697666986669966700667016670266703667046670566706667076670866709667106671166712667136671466715667166671766718667196672066721667226672366724667256672666727667286672966730667316673266733667346673566736667376673866739667406674166742667436674466745667466674766748667496675066751667526675366754667556675666757667586675966760667616676266763667646676566766667676676866769667706677166772667736677466775667766677766778667796678066781667826678366784667856678666787667886678966790667916679266793667946679566796667976679866799668006680166802668036680466805668066680766808668096681066811668126681366814668156681666817668186681966820668216682266823668246682566826668276682866829668306683166832668336683466835668366683766838668396684066841668426684366844668456684666847668486684966850668516685266853668546685566856668576685866859668606686166862668636686466865668666686766868668696687066871668726687366874668756687666877668786687966880668816688266883668846688566886668876688866889668906689166892668936689466895668966689766898668996690066901669026690366904669056690666907669086690966910669116691266913669146691566916669176691866919669206692166922669236692466925669266692766928669296693066931669326693366934669356693666937669386693966940669416694266943669446694566946669476694866949669506695166952669536695466955669566695766958669596696066961669626696366964669656696666967669686696966970669716697266973669746697566976669776697866979669806698166982669836698466985669866698766988669896699066991669926699366994669956699666997669986699967000670016700267003670046700567006670076700867009670106701167012670136701467015670166701767018670196702067021670226702367024670256702667027670286702967030670316703267033670346703567036670376703867039670406704167042670436704467045670466704767048670496705067051670526705367054670556705667057670586705967060670616706267063670646706567066670676706867069670706707167072670736707467075670766707767078670796708067081670826708367084670856708667087670886708967090670916709267093670946709567096670976709867099671006710167102671036710467105671066710767108671096711067111671126711367114671156711667117671186711967120671216712267123671246712567126671276712867129671306713167132671336713467135671366713767138671396714067141671426714367144671456714667147671486714967150671516715267153671546715567156671576715867159671606716167162671636716467165671666716767168671696717067171671726717367174671756717667177671786717967180671816718267183671846718567186671876718867189671906719167192671936719467195671966719767198671996720067201672026720367204672056720667207672086720967210672116721267213672146721567216672176721867219672206722167222672236722467225672266722767228672296723067231672326723367234672356723667237672386723967240672416724267243672446724567246672476724867249672506725167252672536725467255672566725767258672596726067261672626726367264672656726667267672686726967270672716727267273672746727567276672776727867279672806728167282672836728467285672866728767288672896729067291672926729367294672956729667297672986729967300673016730267303673046730567306673076730867309673106731167312673136731467315673166731767318673196732067321673226732367324673256732667327673286732967330673316733267333673346733567336673376733867339673406734167342673436734467345673466734767348673496735067351673526735367354673556735667357673586735967360673616736267363673646736567366673676736867369673706737167372673736737467375673766737767378673796738067381673826738367384673856738667387673886738967390673916739267393673946739567396673976739867399674006740167402674036740467405674066740767408674096741067411674126741367414674156741667417674186741967420674216742267423674246742567426674276742867429674306743167432674336743467435674366743767438674396744067441674426744367444674456744667447674486744967450674516745267453674546745567456674576745867459674606746167462674636746467465674666746767468674696747067471674726747367474674756747667477674786747967480674816748267483674846748567486674876748867489674906749167492674936749467495674966749767498674996750067501675026750367504675056750667507675086750967510675116751267513675146751567516675176751867519675206752167522675236752467525675266752767528675296753067531675326753367534675356753667537675386753967540675416754267543675446754567546675476754867549675506755167552675536755467555675566755767558675596756067561675626756367564675656756667567675686756967570675716757267573675746757567576675776757867579675806758167582675836758467585675866758767588675896759067591675926759367594675956759667597675986759967600676016760267603676046760567606676076760867609676106761167612676136761467615676166761767618676196762067621676226762367624676256762667627676286762967630676316763267633676346763567636676376763867639676406764167642676436764467645676466764767648676496765067651676526765367654676556765667657676586765967660676616766267663676646766567666676676766867669676706767167672676736767467675676766767767678676796768067681676826768367684676856768667687676886768967690676916769267693676946769567696676976769867699677006770167702677036770467705677066770767708677096771067711677126771367714677156771667717677186771967720677216772267723677246772567726677276772867729677306773167732677336773467735677366773767738677396774067741677426774367744677456774667747677486774967750677516775267753677546775567756677576775867759677606776167762677636776467765677666776767768677696777067771677726777367774677756777667777677786777967780677816778267783677846778567786677876778867789677906779167792677936779467795677966779767798677996780067801678026780367804678056780667807678086780967810678116781267813678146781567816678176781867819678206782167822678236782467825678266782767828678296783067831678326783367834678356783667837678386783967840678416784267843678446784567846678476784867849678506785167852678536785467855678566785767858678596786067861678626786367864678656786667867678686786967870678716787267873678746787567876678776787867879678806788167882678836788467885678866788767888678896789067891678926789367894678956789667897678986789967900679016790267903679046790567906679076790867909679106791167912679136791467915679166791767918679196792067921679226792367924679256792667927679286792967930679316793267933679346793567936679376793867939679406794167942679436794467945679466794767948679496795067951679526795367954679556795667957679586795967960679616796267963679646796567966679676796867969679706797167972679736797467975679766797767978679796798067981679826798367984679856798667987679886798967990679916799267993679946799567996679976799867999680006800168002680036800468005680066800768008680096801068011680126801368014680156801668017680186801968020680216802268023680246802568026680276802868029680306803168032680336803468035680366803768038680396804068041680426804368044680456804668047680486804968050680516805268053680546805568056680576805868059680606806168062680636806468065680666806768068680696807068071680726807368074680756807668077680786807968080680816808268083680846808568086680876808868089680906809168092680936809468095680966809768098680996810068101681026810368104681056810668107681086810968110681116811268113681146811568116681176811868119681206812168122681236812468125681266812768128681296813068131681326813368134681356813668137681386813968140681416814268143681446814568146681476814868149681506815168152681536815468155681566815768158681596816068161681626816368164681656816668167681686816968170681716817268173681746817568176681776817868179681806818168182681836818468185681866818768188681896819068191681926819368194681956819668197681986819968200682016820268203682046820568206682076820868209682106821168212682136821468215682166821768218682196822068221682226822368224682256822668227682286822968230682316823268233682346823568236682376823868239682406824168242682436824468245682466824768248682496825068251682526825368254682556825668257682586825968260682616826268263682646826568266682676826868269682706827168272682736827468275682766827768278682796828068281682826828368284682856828668287682886828968290682916829268293682946829568296682976829868299683006830168302683036830468305683066830768308683096831068311683126831368314683156831668317683186831968320683216832268323683246832568326683276832868329683306833168332683336833468335683366833768338683396834068341683426834368344683456834668347683486834968350683516835268353683546835568356683576835868359683606836168362683636836468365683666836768368683696837068371683726837368374683756837668377683786837968380683816838268383683846838568386683876838868389683906839168392683936839468395683966839768398683996840068401684026840368404684056840668407684086840968410684116841268413684146841568416684176841868419684206842168422684236842468425684266842768428684296843068431684326843368434684356843668437684386843968440684416844268443684446844568446684476844868449684506845168452684536845468455684566845768458684596846068461684626846368464684656846668467684686846968470684716847268473684746847568476684776847868479684806848168482684836848468485684866848768488684896849068491684926849368494684956849668497684986849968500685016850268503685046850568506685076850868509685106851168512685136851468515685166851768518685196852068521685226852368524685256852668527685286852968530685316853268533685346853568536685376853868539685406854168542685436854468545685466854768548685496855068551685526855368554685556855668557685586855968560685616856268563685646856568566685676856868569685706857168572685736857468575685766857768578685796858068581685826858368584685856858668587685886858968590685916859268593685946859568596685976859868599686006860168602686036860468605686066860768608686096861068611686126861368614686156861668617686186861968620686216862268623686246862568626686276862868629686306863168632686336863468635686366863768638686396864068641686426864368644686456864668647686486864968650686516865268653686546865568656686576865868659686606866168662686636866468665686666866768668686696867068671686726867368674686756867668677686786867968680686816868268683686846868568686686876868868689686906869168692686936869468695686966869768698686996870068701687026870368704687056870668707687086870968710687116871268713687146871568716687176871868719687206872168722687236872468725687266872768728687296873068731687326873368734687356873668737687386873968740687416874268743687446874568746687476874868749687506875168752687536875468755687566875768758687596876068761687626876368764687656876668767687686876968770687716877268773687746877568776687776877868779687806878168782687836878468785687866878768788687896879068791687926879368794687956879668797687986879968800688016880268803688046880568806688076880868809688106881168812688136881468815688166881768818688196882068821688226882368824688256882668827688286882968830688316883268833688346883568836688376883868839688406884168842688436884468845688466884768848688496885068851688526885368854688556885668857688586885968860688616886268863688646886568866688676886868869688706887168872688736887468875688766887768878688796888068881688826888368884688856888668887688886888968890688916889268893688946889568896688976889868899689006890168902689036890468905689066890768908689096891068911689126891368914689156891668917689186891968920689216892268923689246892568926689276892868929689306893168932689336893468935689366893768938689396894068941689426894368944689456894668947689486894968950689516895268953689546895568956689576895868959689606896168962689636896468965689666896768968689696897068971689726897368974689756897668977689786897968980689816898268983689846898568986689876898868989689906899168992689936899468995689966899768998689996900069001690026900369004690056900669007690086900969010690116901269013690146901569016690176901869019690206902169022690236902469025690266902769028690296903069031690326903369034690356903669037690386903969040690416904269043690446904569046690476904869049690506905169052690536905469055690566905769058690596906069061690626906369064690656906669067690686906969070690716907269073690746907569076690776907869079690806908169082690836908469085690866908769088690896909069091690926909369094690956909669097690986909969100691016910269103691046910569106691076910869109691106911169112691136911469115691166911769118691196912069121691226912369124691256912669127691286912969130691316913269133691346913569136691376913869139691406914169142691436914469145691466914769148691496915069151691526915369154691556915669157691586915969160691616916269163691646916569166691676916869169691706917169172691736917469175691766917769178691796918069181691826918369184691856918669187691886918969190691916919269193691946919569196691976919869199692006920169202692036920469205692066920769208692096921069211692126921369214692156921669217692186921969220692216922269223692246922569226692276922869229692306923169232692336923469235692366923769238692396924069241692426924369244692456924669247692486924969250692516925269253692546925569256692576925869259692606926169262692636926469265692666926769268692696927069271692726927369274692756927669277692786927969280692816928269283692846928569286692876928869289692906929169292692936929469295692966929769298692996930069301693026930369304693056930669307693086930969310693116931269313693146931569316693176931869319693206932169322693236932469325693266932769328693296933069331693326933369334693356933669337693386933969340693416934269343693446934569346693476934869349693506935169352693536935469355693566935769358693596936069361693626936369364693656936669367693686936969370693716937269373693746937569376693776937869379693806938169382693836938469385693866938769388693896939069391693926939369394693956939669397693986939969400694016940269403694046940569406694076940869409694106941169412694136941469415694166941769418694196942069421694226942369424694256942669427694286942969430694316943269433694346943569436694376943869439694406944169442694436944469445694466944769448694496945069451694526945369454694556945669457694586945969460694616946269463694646946569466694676946869469694706947169472694736947469475694766947769478694796948069481694826948369484694856948669487694886948969490694916949269493694946949569496694976949869499695006950169502695036950469505695066950769508695096951069511695126951369514695156951669517695186951969520695216952269523695246952569526695276952869529695306953169532695336953469535695366953769538695396954069541695426954369544695456954669547695486954969550695516955269553695546955569556695576955869559695606956169562695636956469565695666956769568695696957069571695726957369574695756957669577695786957969580695816958269583695846958569586695876958869589695906959169592695936959469595695966959769598695996960069601696026960369604696056960669607696086960969610696116961269613696146961569616696176961869619696206962169622696236962469625696266962769628696296963069631696326963369634696356963669637696386963969640696416964269643696446964569646696476964869649696506965169652696536965469655696566965769658696596966069661696626966369664696656966669667696686966969670696716967269673696746967569676696776967869679696806968169682696836968469685696866968769688696896969069691696926969369694696956969669697696986969969700697016970269703697046970569706697076970869709697106971169712697136971469715697166971769718697196972069721697226972369724697256972669727697286972969730697316973269733697346973569736697376973869739697406974169742697436974469745697466974769748697496975069751697526975369754697556975669757697586975969760697616976269763697646976569766697676976869769697706977169772697736977469775697766977769778697796978069781697826978369784697856978669787697886978969790697916979269793697946979569796697976979869799698006980169802698036980469805698066980769808698096981069811698126981369814698156981669817698186981969820698216982269823698246982569826698276982869829698306983169832698336983469835698366983769838698396984069841698426984369844698456984669847698486984969850698516985269853698546985569856698576985869859698606986169862698636986469865698666986769868698696987069871698726987369874698756987669877698786987969880698816988269883698846988569886698876988869889698906989169892698936989469895698966989769898698996990069901699026990369904699056990669907699086990969910699116991269913699146991569916699176991869919699206992169922699236992469925699266992769928699296993069931699326993369934699356993669937699386993969940699416994269943699446994569946699476994869949699506995169952699536995469955699566995769958699596996069961699626996369964699656996669967699686996969970699716997269973699746997569976699776997869979699806998169982699836998469985699866998769988699896999069991699926999369994699956999669997699986999970000700017000270003700047000570006700077000870009700107001170012700137001470015700167001770018700197002070021700227002370024700257002670027700287002970030700317003270033700347003570036700377003870039700407004170042700437004470045700467004770048700497005070051700527005370054700557005670057700587005970060700617006270063700647006570066700677006870069700707007170072700737007470075700767007770078700797008070081700827008370084700857008670087700887008970090700917009270093700947009570096700977009870099701007010170102701037010470105701067010770108701097011070111701127011370114701157011670117701187011970120701217012270123701247012570126701277012870129701307013170132701337013470135701367013770138701397014070141701427014370144701457014670147701487014970150701517015270153701547015570156701577015870159701607016170162701637016470165701667016770168701697017070171701727017370174701757017670177701787017970180701817018270183701847018570186701877018870189701907019170192701937019470195701967019770198701997020070201702027020370204702057020670207702087020970210702117021270213702147021570216702177021870219702207022170222702237022470225702267022770228702297023070231702327023370234702357023670237702387023970240702417024270243702447024570246702477024870249702507025170252702537025470255702567025770258702597026070261702627026370264702657026670267702687026970270702717027270273702747027570276702777027870279702807028170282702837028470285702867028770288702897029070291702927029370294702957029670297702987029970300703017030270303703047030570306703077030870309703107031170312703137031470315703167031770318703197032070321703227032370324703257032670327703287032970330703317033270333703347033570336703377033870339703407034170342703437034470345703467034770348703497035070351703527035370354703557035670357703587035970360703617036270363703647036570366703677036870369703707037170372703737037470375703767037770378703797038070381703827038370384703857038670387703887038970390703917039270393703947039570396703977039870399704007040170402704037040470405704067040770408704097041070411704127041370414704157041670417704187041970420704217042270423704247042570426704277042870429704307043170432704337043470435704367043770438704397044070441704427044370444704457044670447704487044970450704517045270453704547045570456704577045870459704607046170462704637046470465704667046770468704697047070471704727047370474704757047670477704787047970480704817048270483704847048570486704877048870489704907049170492704937049470495704967049770498704997050070501705027050370504705057050670507705087050970510705117051270513705147051570516705177051870519705207052170522705237052470525705267052770528705297053070531705327053370534705357053670537705387053970540705417054270543705447054570546705477054870549705507055170552705537055470555705567055770558705597056070561705627056370564705657056670567705687056970570705717057270573705747057570576705777057870579705807058170582705837058470585705867058770588705897059070591705927059370594705957059670597705987059970600706017060270603706047060570606706077060870609706107061170612706137061470615706167061770618706197062070621706227062370624706257062670627706287062970630706317063270633706347063570636706377063870639706407064170642706437064470645706467064770648706497065070651706527065370654706557065670657706587065970660706617066270663706647066570666706677066870669706707067170672706737067470675706767067770678706797068070681706827068370684706857068670687706887068970690706917069270693706947069570696706977069870699707007070170702707037070470705707067070770708707097071070711707127071370714707157071670717707187071970720707217072270723707247072570726707277072870729707307073170732707337073470735707367073770738707397074070741707427074370744707457074670747707487074970750707517075270753707547075570756707577075870759707607076170762707637076470765707667076770768707697077070771707727077370774707757077670777707787077970780707817078270783707847078570786707877078870789707907079170792707937079470795707967079770798707997080070801708027080370804708057080670807708087080970810708117081270813708147081570816708177081870819708207082170822708237082470825708267082770828708297083070831708327083370834708357083670837708387083970840708417084270843708447084570846708477084870849708507085170852708537085470855708567085770858708597086070861708627086370864708657086670867708687086970870708717087270873708747087570876708777087870879708807088170882708837088470885708867088770888708897089070891708927089370894708957089670897708987089970900709017090270903709047090570906709077090870909709107091170912709137091470915709167091770918709197092070921709227092370924709257092670927709287092970930709317093270933709347093570936709377093870939709407094170942709437094470945709467094770948709497095070951709527095370954709557095670957709587095970960709617096270963709647096570966709677096870969709707097170972709737097470975709767097770978709797098070981709827098370984709857098670987709887098970990709917099270993709947099570996709977099870999710007100171002710037100471005710067100771008710097101071011710127101371014710157101671017710187101971020710217102271023710247102571026710277102871029710307103171032710337103471035710367103771038710397104071041710427104371044710457104671047710487104971050710517105271053710547105571056710577105871059710607106171062710637106471065710667106771068710697107071071710727107371074710757107671077710787107971080710817108271083710847108571086710877108871089710907109171092710937109471095710967109771098710997110071101711027110371104711057110671107711087110971110711117111271113711147111571116711177111871119711207112171122711237112471125711267112771128711297113071131711327113371134711357113671137711387113971140711417114271143711447114571146711477114871149711507115171152711537115471155711567115771158711597116071161711627116371164711657116671167711687116971170711717117271173711747117571176711777117871179711807118171182711837118471185711867118771188711897119071191711927119371194711957119671197711987119971200712017120271203712047120571206712077120871209712107121171212712137121471215712167121771218712197122071221712227122371224712257122671227712287122971230712317123271233712347123571236712377123871239712407124171242712437124471245712467124771248712497125071251712527125371254712557125671257712587125971260712617126271263712647126571266712677126871269712707127171272712737127471275712767127771278712797128071281712827128371284712857128671287712887128971290712917129271293712947129571296712977129871299713007130171302713037130471305713067130771308713097131071311713127131371314713157131671317713187131971320713217132271323713247132571326713277132871329713307133171332713337133471335713367133771338713397134071341713427134371344713457134671347713487134971350713517135271353713547135571356713577135871359713607136171362713637136471365713667136771368713697137071371713727137371374713757137671377713787137971380713817138271383713847138571386713877138871389713907139171392713937139471395713967139771398713997140071401714027140371404714057140671407714087140971410714117141271413714147141571416714177141871419714207142171422714237142471425714267142771428714297143071431714327143371434714357143671437714387143971440714417144271443714447144571446714477144871449714507145171452714537145471455714567145771458714597146071461714627146371464714657146671467714687146971470714717147271473714747147571476714777147871479714807148171482714837148471485714867148771488714897149071491714927149371494714957149671497714987149971500715017150271503715047150571506715077150871509715107151171512715137151471515715167151771518715197152071521715227152371524715257152671527715287152971530715317153271533715347153571536715377153871539715407154171542715437154471545715467154771548715497155071551715527155371554715557155671557715587155971560715617156271563715647156571566715677156871569715707157171572715737157471575715767157771578715797158071581715827158371584715857158671587715887158971590715917159271593715947159571596715977159871599716007160171602716037160471605716067160771608716097161071611716127161371614716157161671617716187161971620716217162271623716247162571626716277162871629716307163171632716337163471635716367163771638716397164071641716427164371644716457164671647716487164971650716517165271653716547165571656716577165871659716607166171662716637166471665716667166771668716697167071671716727167371674716757167671677716787167971680716817168271683716847168571686716877168871689716907169171692716937169471695716967169771698716997170071701717027170371704717057170671707717087170971710717117171271713717147171571716717177171871719717207172171722717237172471725717267172771728717297173071731717327173371734717357173671737717387173971740717417174271743717447174571746717477174871749717507175171752717537175471755717567175771758717597176071761717627176371764717657176671767717687176971770717717177271773717747177571776717777177871779717807178171782717837178471785717867178771788717897179071791717927179371794717957179671797717987179971800718017180271803718047180571806718077180871809718107181171812718137181471815718167181771818718197182071821718227182371824718257182671827718287182971830718317183271833718347183571836718377183871839718407184171842718437184471845718467184771848718497185071851718527185371854718557185671857718587185971860718617186271863718647186571866718677186871869718707187171872718737187471875718767187771878718797188071881718827188371884718857188671887718887188971890718917189271893718947189571896718977189871899719007190171902719037190471905719067190771908719097191071911719127191371914719157191671917719187191971920719217192271923719247192571926719277192871929719307193171932719337193471935719367193771938719397194071941719427194371944719457194671947719487194971950719517195271953719547195571956719577195871959719607196171962719637196471965719667196771968719697197071971719727197371974719757197671977719787197971980719817198271983719847198571986719877198871989719907199171992719937199471995719967199771998719997200072001720027200372004720057200672007720087200972010720117201272013720147201572016720177201872019720207202172022720237202472025720267202772028720297203072031720327203372034720357203672037720387203972040720417204272043720447204572046720477204872049720507205172052720537205472055720567205772058720597206072061720627206372064720657206672067720687206972070720717207272073720747207572076720777207872079720807208172082720837208472085720867208772088720897209072091720927209372094720957209672097720987209972100721017210272103721047210572106721077210872109721107211172112721137211472115721167211772118721197212072121721227212372124721257212672127721287212972130721317213272133721347213572136721377213872139721407214172142721437214472145721467214772148721497215072151721527215372154721557215672157721587215972160721617216272163721647216572166721677216872169721707217172172721737217472175721767217772178721797218072181721827218372184721857218672187721887218972190721917219272193721947219572196721977219872199722007220172202722037220472205722067220772208722097221072211722127221372214722157221672217722187221972220722217222272223722247222572226722277222872229722307223172232722337223472235722367223772238722397224072241722427224372244722457224672247722487224972250722517225272253722547225572256722577225872259722607226172262722637226472265722667226772268722697227072271722727227372274722757227672277722787227972280722817228272283722847228572286722877228872289722907229172292722937229472295722967229772298722997230072301723027230372304723057230672307723087230972310723117231272313723147231572316723177231872319723207232172322723237232472325723267232772328723297233072331723327233372334723357233672337723387233972340723417234272343723447234572346723477234872349723507235172352723537235472355723567235772358723597236072361723627236372364723657236672367723687236972370723717237272373723747237572376723777237872379723807238172382723837238472385723867238772388723897239072391723927239372394723957239672397723987239972400724017240272403724047240572406724077240872409724107241172412724137241472415724167241772418724197242072421724227242372424724257242672427724287242972430724317243272433724347243572436724377243872439724407244172442724437244472445724467244772448724497245072451724527245372454724557245672457724587245972460724617246272463724647246572466724677246872469724707247172472724737247472475724767247772478724797248072481724827248372484724857248672487724887248972490724917249272493724947249572496724977249872499725007250172502725037250472505725067250772508725097251072511725127251372514725157251672517725187251972520725217252272523725247252572526725277252872529725307253172532725337253472535725367253772538725397254072541725427254372544725457254672547725487254972550725517255272553725547255572556725577255872559725607256172562725637256472565725667256772568725697257072571725727257372574725757257672577725787257972580725817258272583725847258572586725877258872589725907259172592725937259472595725967259772598725997260072601726027260372604726057260672607726087260972610726117261272613726147261572616726177261872619726207262172622726237262472625726267262772628726297263072631726327263372634726357263672637726387263972640726417264272643726447264572646726477264872649726507265172652726537265472655726567265772658726597266072661726627266372664726657266672667726687266972670726717267272673726747267572676726777267872679726807268172682726837268472685726867268772688726897269072691726927269372694726957269672697726987269972700727017270272703727047270572706727077270872709727107271172712727137271472715727167271772718727197272072721727227272372724727257272672727727287272972730727317273272733727347273572736727377273872739727407274172742727437274472745727467274772748727497275072751727527275372754727557275672757727587275972760727617276272763727647276572766727677276872769727707277172772727737277472775727767277772778727797278072781727827278372784727857278672787727887278972790727917279272793727947279572796727977279872799728007280172802728037280472805728067280772808728097281072811728127281372814728157281672817728187281972820728217282272823728247282572826728277282872829728307283172832728337283472835728367283772838728397284072841728427284372844728457284672847728487284972850728517285272853728547285572856728577285872859728607286172862728637286472865728667286772868728697287072871728727287372874728757287672877728787287972880728817288272883728847288572886728877288872889728907289172892728937289472895728967289772898728997290072901729027290372904729057290672907729087290972910729117291272913729147291572916729177291872919729207292172922729237292472925729267292772928729297293072931729327293372934729357293672937729387293972940729417294272943729447294572946729477294872949729507295172952729537295472955729567295772958729597296072961729627296372964729657296672967729687296972970729717297272973729747297572976729777297872979729807298172982729837298472985729867298772988729897299072991729927299372994729957299672997729987299973000730017300273003730047300573006730077300873009730107301173012730137301473015730167301773018730197302073021730227302373024730257302673027730287302973030730317303273033730347303573036730377303873039730407304173042730437304473045730467304773048730497305073051730527305373054730557305673057730587305973060730617306273063730647306573066730677306873069730707307173072730737307473075730767307773078730797308073081730827308373084730857308673087730887308973090730917309273093730947309573096730977309873099731007310173102731037310473105731067310773108731097311073111731127311373114731157311673117731187311973120731217312273123731247312573126731277312873129731307313173132731337313473135731367313773138731397314073141731427314373144731457314673147731487314973150731517315273153731547315573156731577315873159731607316173162731637316473165731667316773168731697317073171731727317373174731757317673177731787317973180731817318273183731847318573186731877318873189731907319173192731937319473195731967319773198731997320073201732027320373204732057320673207732087320973210732117321273213732147321573216732177321873219732207322173222732237322473225732267322773228732297323073231732327323373234732357323673237732387323973240732417324273243732447324573246732477324873249732507325173252732537325473255732567325773258732597326073261732627326373264732657326673267732687326973270732717327273273732747327573276732777327873279732807328173282732837328473285732867328773288732897329073291732927329373294732957329673297732987329973300733017330273303733047330573306733077330873309733107331173312733137331473315733167331773318733197332073321733227332373324733257332673327733287332973330733317333273333733347333573336733377333873339733407334173342733437334473345733467334773348733497335073351733527335373354733557335673357733587335973360733617336273363733647336573366733677336873369733707337173372733737337473375733767337773378733797338073381733827338373384733857338673387733887338973390733917339273393733947339573396733977339873399734007340173402734037340473405734067340773408734097341073411734127341373414734157341673417734187341973420734217342273423734247342573426734277342873429734307343173432734337343473435734367343773438734397344073441734427344373444734457344673447734487344973450734517345273453734547345573456734577345873459734607346173462734637346473465734667346773468734697347073471734727347373474734757347673477734787347973480734817348273483734847348573486734877348873489734907349173492734937349473495734967349773498734997350073501735027350373504735057350673507735087350973510735117351273513735147351573516735177351873519735207352173522735237352473525735267352773528735297353073531735327353373534735357353673537735387353973540735417354273543735447354573546735477354873549735507355173552735537355473555735567355773558735597356073561735627356373564735657356673567735687356973570735717357273573735747357573576735777357873579735807358173582735837358473585735867358773588735897359073591735927359373594735957359673597735987359973600736017360273603736047360573606736077360873609736107361173612736137361473615736167361773618736197362073621736227362373624736257362673627736287362973630736317363273633736347363573636736377363873639736407364173642736437364473645736467364773648736497365073651736527365373654736557365673657736587365973660736617366273663736647366573666736677366873669736707367173672736737367473675736767367773678736797368073681736827368373684736857368673687736887368973690736917369273693736947369573696736977369873699737007370173702737037370473705737067370773708737097371073711737127371373714737157371673717737187371973720737217372273723737247372573726737277372873729737307373173732737337373473735737367373773738737397374073741737427374373744737457374673747737487374973750737517375273753737547375573756737577375873759737607376173762737637376473765737667376773768737697377073771737727377373774737757377673777737787377973780737817378273783737847378573786737877378873789737907379173792737937379473795737967379773798737997380073801738027380373804738057380673807738087380973810738117381273813738147381573816738177381873819738207382173822738237382473825738267382773828738297383073831738327383373834738357383673837738387383973840738417384273843738447384573846738477384873849738507385173852738537385473855738567385773858738597386073861738627386373864738657386673867738687386973870738717387273873738747387573876738777387873879738807388173882738837388473885738867388773888738897389073891738927389373894738957389673897738987389973900739017390273903739047390573906739077390873909739107391173912739137391473915739167391773918739197392073921739227392373924739257392673927739287392973930739317393273933739347393573936739377393873939739407394173942739437394473945739467394773948739497395073951739527395373954739557395673957739587395973960739617396273963739647396573966739677396873969739707397173972739737397473975739767397773978739797398073981739827398373984739857398673987739887398973990739917399273993739947399573996739977399873999740007400174002740037400474005740067400774008740097401074011740127401374014740157401674017740187401974020740217402274023740247402574026740277402874029740307403174032740337403474035740367403774038740397404074041740427404374044740457404674047740487404974050740517405274053740547405574056740577405874059740607406174062740637406474065740667406774068740697407074071740727407374074740757407674077740787407974080740817408274083740847408574086740877408874089740907409174092740937409474095740967409774098740997410074101741027410374104741057410674107741087410974110741117411274113741147411574116741177411874119741207412174122741237412474125741267412774128741297413074131741327413374134741357413674137741387413974140741417414274143741447414574146741477414874149741507415174152741537415474155741567415774158741597416074161741627416374164741657416674167741687416974170741717417274173741747417574176741777417874179741807418174182741837418474185741867418774188741897419074191741927419374194741957419674197741987419974200742017420274203742047420574206742077420874209742107421174212742137421474215742167421774218742197422074221742227422374224742257422674227742287422974230742317423274233742347423574236742377423874239742407424174242742437424474245742467424774248742497425074251742527425374254742557425674257742587425974260742617426274263742647426574266742677426874269742707427174272742737427474275742767427774278742797428074281742827428374284742857428674287742887428974290742917429274293742947429574296742977429874299743007430174302743037430474305743067430774308743097431074311743127431374314743157431674317743187431974320743217432274323743247432574326743277432874329743307433174332743337433474335743367433774338743397434074341743427434374344743457434674347743487434974350743517435274353743547435574356743577435874359743607436174362743637436474365743667436774368743697437074371743727437374374743757437674377743787437974380743817438274383743847438574386743877438874389743907439174392743937439474395743967439774398743997440074401744027440374404744057440674407744087440974410744117441274413744147441574416744177441874419744207442174422744237442474425744267442774428744297443074431744327443374434744357443674437744387443974440744417444274443744447444574446744477444874449744507445174452744537445474455744567445774458744597446074461744627446374464744657446674467744687446974470744717447274473744747447574476744777447874479744807448174482744837448474485744867448774488744897449074491744927449374494744957449674497744987449974500745017450274503745047450574506745077450874509745107451174512745137451474515745167451774518745197452074521745227452374524745257452674527745287452974530745317453274533745347453574536745377453874539745407454174542745437454474545745467454774548745497455074551745527455374554745557455674557745587455974560745617456274563745647456574566745677456874569745707457174572745737457474575745767457774578745797458074581745827458374584745857458674587745887458974590745917459274593745947459574596745977459874599746007460174602746037460474605746067460774608746097461074611746127461374614746157461674617746187461974620746217462274623746247462574626746277462874629746307463174632746337463474635746367463774638746397464074641746427464374644746457464674647746487464974650746517465274653746547465574656746577465874659746607466174662746637466474665746667466774668746697467074671746727467374674746757467674677746787467974680746817468274683746847468574686746877468874689746907469174692746937469474695746967469774698746997470074701747027470374704747057470674707747087470974710747117471274713747147471574716747177471874719747207472174722747237472474725747267472774728747297473074731747327473374734747357473674737747387473974740747417474274743747447474574746747477474874749747507475174752747537475474755747567475774758747597476074761747627476374764747657476674767747687476974770747717477274773747747477574776747777477874779747807478174782747837478474785747867478774788747897479074791747927479374794747957479674797747987479974800748017480274803748047480574806748077480874809748107481174812748137481474815748167481774818748197482074821748227482374824748257482674827748287482974830748317483274833748347483574836748377483874839748407484174842748437484474845748467484774848748497485074851748527485374854748557485674857748587485974860748617486274863748647486574866748677486874869748707487174872748737487474875748767487774878748797488074881748827488374884748857488674887748887488974890748917489274893748947489574896748977489874899749007490174902749037490474905749067490774908749097491074911749127491374914749157491674917749187491974920749217492274923749247492574926749277492874929749307493174932749337493474935749367493774938749397494074941749427494374944749457494674947749487494974950749517495274953749547495574956749577495874959749607496174962749637496474965749667496774968749697497074971749727497374974749757497674977749787497974980749817498274983749847498574986749877498874989749907499174992749937499474995749967499774998749997500075001750027500375004750057500675007750087500975010750117501275013750147501575016750177501875019750207502175022750237502475025750267502775028750297503075031750327503375034750357503675037750387503975040750417504275043750447504575046750477504875049750507505175052750537505475055750567505775058750597506075061750627506375064750657506675067750687506975070750717507275073750747507575076750777507875079750807508175082750837508475085750867508775088750897509075091750927509375094750957509675097750987509975100751017510275103751047510575106751077510875109751107511175112751137511475115751167511775118751197512075121751227512375124751257512675127751287512975130751317513275133751347513575136751377513875139751407514175142751437514475145751467514775148751497515075151751527515375154751557515675157751587515975160751617516275163751647516575166751677516875169751707517175172751737517475175751767517775178751797518075181751827518375184751857518675187751887518975190751917519275193751947519575196751977519875199752007520175202752037520475205752067520775208752097521075211752127521375214752157521675217752187521975220752217522275223752247522575226752277522875229752307523175232752337523475235752367523775238752397524075241752427524375244752457524675247752487524975250752517525275253752547525575256752577525875259752607526175262752637526475265752667526775268752697527075271752727527375274752757527675277752787527975280752817528275283752847528575286752877528875289752907529175292752937529475295752967529775298752997530075301753027530375304753057530675307753087530975310753117531275313753147531575316753177531875319753207532175322753237532475325753267532775328753297533075331753327533375334753357533675337753387533975340753417534275343753447534575346753477534875349753507535175352753537535475355753567535775358753597536075361753627536375364753657536675367753687536975370753717537275373753747537575376753777537875379753807538175382753837538475385753867538775388753897539075391753927539375394753957539675397753987539975400754017540275403754047540575406754077540875409754107541175412754137541475415754167541775418754197542075421754227542375424754257542675427754287542975430754317543275433754347543575436754377543875439754407544175442754437544475445754467544775448754497545075451754527545375454754557545675457754587545975460754617546275463754647546575466754677546875469754707547175472754737547475475754767547775478754797548075481754827548375484754857548675487754887548975490754917549275493754947549575496754977549875499755007550175502755037550475505755067550775508755097551075511755127551375514755157551675517755187551975520755217552275523755247552575526755277552875529755307553175532755337553475535755367553775538755397554075541755427554375544755457554675547755487554975550755517555275553755547555575556755577555875559755607556175562755637556475565755667556775568755697557075571755727557375574755757557675577755787557975580755817558275583755847558575586755877558875589755907559175592755937559475595755967559775598755997560075601756027560375604756057560675607756087560975610756117561275613756147561575616756177561875619756207562175622756237562475625756267562775628756297563075631756327563375634756357563675637756387563975640756417564275643756447564575646756477564875649756507565175652756537565475655756567565775658756597566075661756627566375664756657566675667756687566975670756717567275673756747567575676756777567875679756807568175682756837568475685756867568775688756897569075691756927569375694756957569675697756987569975700757017570275703757047570575706757077570875709757107571175712757137571475715757167571775718757197572075721757227572375724757257572675727757287572975730757317573275733757347573575736757377573875739757407574175742757437574475745757467574775748757497575075751757527575375754757557575675757757587575975760757617576275763757647576575766757677576875769757707577175772757737577475775757767577775778757797578075781757827578375784757857578675787757887578975790757917579275793757947579575796757977579875799758007580175802758037580475805758067580775808758097581075811758127581375814758157581675817758187581975820758217582275823758247582575826758277582875829758307583175832758337583475835758367583775838758397584075841758427584375844758457584675847758487584975850758517585275853758547585575856758577585875859758607586175862758637586475865758667586775868758697587075871758727587375874758757587675877758787587975880758817588275883758847588575886758877588875889758907589175892758937589475895758967589775898758997590075901759027590375904759057590675907759087590975910759117591275913759147591575916759177591875919759207592175922759237592475925759267592775928759297593075931759327593375934759357593675937759387593975940759417594275943759447594575946759477594875949759507595175952759537595475955759567595775958759597596075961759627596375964759657596675967759687596975970759717597275973759747597575976759777597875979759807598175982759837598475985759867598775988759897599075991759927599375994759957599675997759987599976000760017600276003760047600576006760077600876009760107601176012760137601476015760167601776018760197602076021760227602376024760257602676027760287602976030760317603276033760347603576036760377603876039760407604176042760437604476045760467604776048760497605076051760527605376054760557605676057760587605976060760617606276063760647606576066760677606876069760707607176072760737607476075760767607776078760797608076081760827608376084760857608676087760887608976090760917609276093760947609576096760977609876099761007610176102761037610476105761067610776108761097611076111761127611376114761157611676117761187611976120761217612276123761247612576126761277612876129761307613176132761337613476135761367613776138761397614076141761427614376144761457614676147761487614976150761517615276153761547615576156761577615876159761607616176162761637616476165761667616776168761697617076171761727617376174761757617676177761787617976180761817618276183761847618576186761877618876189761907619176192761937619476195761967619776198761997620076201762027620376204762057620676207762087620976210762117621276213762147621576216762177621876219762207622176222762237622476225762267622776228762297623076231762327623376234762357623676237762387623976240762417624276243762447624576246762477624876249762507625176252762537625476255762567625776258762597626076261762627626376264762657626676267762687626976270762717627276273762747627576276762777627876279762807628176282762837628476285762867628776288762897629076291762927629376294762957629676297762987629976300763017630276303763047630576306763077630876309763107631176312763137631476315763167631776318763197632076321763227632376324763257632676327763287632976330763317633276333763347633576336763377633876339763407634176342763437634476345763467634776348763497635076351763527635376354763557635676357763587635976360763617636276363763647636576366763677636876369763707637176372763737637476375763767637776378763797638076381763827638376384763857638676387763887638976390763917639276393763947639576396763977639876399764007640176402764037640476405764067640776408764097641076411764127641376414764157641676417764187641976420764217642276423764247642576426764277642876429764307643176432764337643476435764367643776438764397644076441764427644376444764457644676447764487644976450764517645276453764547645576456764577645876459764607646176462764637646476465764667646776468764697647076471764727647376474764757647676477764787647976480764817648276483764847648576486764877648876489764907649176492764937649476495764967649776498764997650076501765027650376504765057650676507765087650976510765117651276513765147651576516765177651876519765207652176522765237652476525765267652776528765297653076531765327653376534765357653676537765387653976540765417654276543765447654576546765477654876549765507655176552765537655476555765567655776558765597656076561765627656376564765657656676567765687656976570765717657276573765747657576576765777657876579765807658176582765837658476585765867658776588765897659076591765927659376594765957659676597765987659976600766017660276603766047660576606766077660876609766107661176612766137661476615766167661776618766197662076621766227662376624766257662676627766287662976630766317663276633766347663576636766377663876639766407664176642766437664476645766467664776648766497665076651766527665376654766557665676657766587665976660766617666276663766647666576666766677666876669766707667176672766737667476675766767667776678766797668076681766827668376684766857668676687766887668976690766917669276693766947669576696766977669876699767007670176702767037670476705767067670776708767097671076711767127671376714767157671676717767187671976720767217672276723767247672576726767277672876729767307673176732767337673476735767367673776738767397674076741767427674376744767457674676747767487674976750767517675276753767547675576756767577675876759767607676176762767637676476765767667676776768767697677076771767727677376774767757677676777767787677976780767817678276783767847678576786767877678876789767907679176792767937679476795767967679776798767997680076801768027680376804768057680676807768087680976810768117681276813768147681576816768177681876819768207682176822768237682476825768267682776828768297683076831768327683376834768357683676837768387683976840768417684276843768447684576846768477684876849768507685176852768537685476855768567685776858768597686076861768627686376864768657686676867768687686976870768717687276873768747687576876768777687876879768807688176882768837688476885768867688776888768897689076891768927689376894768957689676897768987689976900769017690276903769047690576906769077690876909769107691176912769137691476915769167691776918769197692076921769227692376924769257692676927769287692976930769317693276933769347693576936769377693876939769407694176942769437694476945769467694776948769497695076951769527695376954769557695676957769587695976960769617696276963769647696576966769677696876969769707697176972769737697476975769767697776978769797698076981769827698376984769857698676987769887698976990769917699276993769947699576996769977699876999770007700177002770037700477005770067700777008770097701077011770127701377014770157701677017770187701977020770217702277023770247702577026770277702877029770307703177032770337703477035770367703777038770397704077041770427704377044770457704677047770487704977050770517705277053770547705577056770577705877059770607706177062770637706477065770667706777068770697707077071770727707377074770757707677077770787707977080770817708277083770847708577086770877708877089770907709177092770937709477095770967709777098770997710077101771027710377104771057710677107771087710977110771117711277113771147711577116771177711877119771207712177122771237712477125771267712777128771297713077131771327713377134771357713677137771387713977140771417714277143771447714577146771477714877149771507715177152771537715477155771567715777158771597716077161771627716377164771657716677167771687716977170771717717277173771747717577176771777717877179771807718177182771837718477185771867718777188771897719077191771927719377194771957719677197771987719977200772017720277203772047720577206772077720877209772107721177212772137721477215772167721777218772197722077221772227722377224772257722677227772287722977230772317723277233772347723577236772377723877239772407724177242772437724477245772467724777248772497725077251772527725377254772557725677257772587725977260772617726277263772647726577266772677726877269772707727177272772737727477275772767727777278772797728077281772827728377284772857728677287772887728977290772917729277293772947729577296772977729877299773007730177302773037730477305773067730777308773097731077311773127731377314773157731677317773187731977320773217732277323773247732577326773277732877329773307733177332773337733477335773367733777338773397734077341773427734377344773457734677347773487734977350773517735277353773547735577356773577735877359773607736177362773637736477365773667736777368773697737077371773727737377374773757737677377773787737977380773817738277383773847738577386773877738877389773907739177392773937739477395773967739777398773997740077401774027740377404774057740677407774087740977410774117741277413774147741577416774177741877419774207742177422774237742477425774267742777428774297743077431774327743377434774357743677437774387743977440774417744277443774447744577446774477744877449774507745177452774537745477455774567745777458774597746077461774627746377464774657746677467774687746977470774717747277473774747747577476774777747877479774807748177482774837748477485774867748777488774897749077491774927749377494774957749677497774987749977500775017750277503775047750577506775077750877509775107751177512775137751477515775167751777518775197752077521775227752377524775257752677527775287752977530775317753277533775347753577536775377753877539775407754177542775437754477545775467754777548775497755077551775527755377554775557755677557775587755977560775617756277563775647756577566775677756877569775707757177572775737757477575775767757777578775797758077581775827758377584775857758677587775887758977590775917759277593775947759577596775977759877599776007760177602776037760477605776067760777608776097761077611776127761377614776157761677617776187761977620776217762277623776247762577626776277762877629776307763177632776337763477635776367763777638776397764077641776427764377644776457764677647776487764977650776517765277653776547765577656776577765877659776607766177662776637766477665776667766777668776697767077671776727767377674776757767677677776787767977680776817768277683776847768577686776877768877689776907769177692776937769477695776967769777698776997770077701777027770377704777057770677707777087770977710777117771277713777147771577716777177771877719777207772177722777237772477725777267772777728777297773077731777327773377734777357773677737777387773977740777417774277743777447774577746777477774877749777507775177752777537775477755777567775777758777597776077761777627776377764777657776677767777687776977770777717777277773777747777577776777777777877779777807778177782777837778477785777867778777788777897779077791777927779377794777957779677797777987779977800778017780277803778047780577806778077780877809778107781177812778137781477815778167781777818778197782077821778227782377824778257782677827778287782977830778317783277833778347783577836778377783877839778407784177842778437784477845778467784777848778497785077851778527785377854778557785677857778587785977860778617786277863778647786577866778677786877869778707787177872778737787477875778767787777878778797788077881778827788377884778857788677887778887788977890778917789277893778947789577896778977789877899779007790177902779037790477905779067790777908779097791077911779127791377914779157791677917779187791977920779217792277923779247792577926779277792877929779307793177932779337793477935779367793777938779397794077941779427794377944779457794677947779487794977950779517795277953779547795577956779577795877959779607796177962779637796477965779667796777968779697797077971779727797377974779757797677977779787797977980779817798277983779847798577986779877798877989779907799177992779937799477995779967799777998779997800078001780027800378004780057800678007780087800978010780117801278013780147801578016780177801878019780207802178022780237802478025780267802778028780297803078031780327803378034780357803678037780387803978040780417804278043780447804578046780477804878049780507805178052780537805478055780567805778058780597806078061780627806378064780657806678067780687806978070780717807278073780747807578076780777807878079780807808178082780837808478085780867808778088780897809078091780927809378094780957809678097780987809978100781017810278103781047810578106781077810878109781107811178112781137811478115781167811778118781197812078121781227812378124781257812678127781287812978130781317813278133781347813578136781377813878139781407814178142781437814478145781467814778148781497815078151781527815378154781557815678157781587815978160781617816278163781647816578166781677816878169781707817178172781737817478175781767817778178781797818078181781827818378184781857818678187781887818978190781917819278193781947819578196781977819878199782007820178202782037820478205782067820778208782097821078211782127821378214782157821678217782187821978220782217822278223782247822578226782277822878229782307823178232782337823478235782367823778238782397824078241782427824378244782457824678247782487824978250782517825278253782547825578256782577825878259782607826178262782637826478265782667826778268782697827078271782727827378274782757827678277782787827978280782817828278283782847828578286782877828878289782907829178292782937829478295782967829778298782997830078301783027830378304783057830678307783087830978310783117831278313783147831578316783177831878319783207832178322783237832478325783267832778328783297833078331783327833378334783357833678337783387833978340783417834278343783447834578346783477834878349783507835178352783537835478355783567835778358783597836078361783627836378364783657836678367783687836978370783717837278373783747837578376783777837878379783807838178382783837838478385783867838778388783897839078391783927839378394783957839678397783987839978400784017840278403784047840578406784077840878409784107841178412784137841478415784167841778418784197842078421784227842378424784257842678427784287842978430784317843278433784347843578436784377843878439784407844178442784437844478445784467844778448784497845078451784527845378454784557845678457784587845978460784617846278463784647846578466784677846878469784707847178472784737847478475784767847778478784797848078481784827848378484784857848678487784887848978490784917849278493784947849578496784977849878499785007850178502785037850478505785067850778508785097851078511785127851378514785157851678517785187851978520785217852278523785247852578526785277852878529785307853178532785337853478535785367853778538785397854078541785427854378544785457854678547785487854978550785517855278553785547855578556785577855878559785607856178562785637856478565785667856778568785697857078571785727857378574785757857678577785787857978580785817858278583785847858578586785877858878589785907859178592785937859478595785967859778598785997860078601786027860378604786057860678607786087860978610786117861278613786147861578616786177861878619786207862178622786237862478625786267862778628786297863078631786327863378634786357863678637786387863978640786417864278643786447864578646786477864878649786507865178652786537865478655786567865778658786597866078661786627866378664786657866678667786687866978670786717867278673786747867578676786777867878679786807868178682786837868478685786867868778688786897869078691786927869378694786957869678697786987869978700787017870278703787047870578706787077870878709787107871178712787137871478715787167871778718787197872078721787227872378724787257872678727787287872978730787317873278733787347873578736787377873878739787407874178742787437874478745787467874778748787497875078751787527875378754787557875678757787587875978760787617876278763787647876578766787677876878769787707877178772787737877478775787767877778778787797878078781787827878378784787857878678787787887878978790787917879278793787947879578796787977879878799788007880178802788037880478805788067880778808788097881078811788127881378814788157881678817788187881978820788217882278823788247882578826788277882878829788307883178832788337883478835788367883778838788397884078841788427884378844788457884678847788487884978850788517885278853788547885578856788577885878859788607886178862788637886478865788667886778868788697887078871788727887378874788757887678877788787887978880788817888278883788847888578886788877888878889788907889178892788937889478895788967889778898788997890078901789027890378904789057890678907789087890978910789117891278913789147891578916789177891878919789207892178922789237892478925789267892778928789297893078931789327893378934789357893678937789387893978940789417894278943789447894578946789477894878949789507895178952789537895478955789567895778958789597896078961789627896378964789657896678967789687896978970789717897278973789747897578976789777897878979789807898178982789837898478985789867898778988789897899078991789927899378994789957899678997789987899979000790017900279003790047900579006790077900879009790107901179012790137901479015790167901779018790197902079021790227902379024790257902679027790287902979030790317903279033790347903579036790377903879039790407904179042790437904479045790467904779048790497905079051790527905379054790557905679057790587905979060790617906279063790647906579066790677906879069790707907179072790737907479075790767907779078790797908079081790827908379084790857908679087790887908979090790917909279093790947909579096790977909879099791007910179102791037910479105791067910779108791097911079111791127911379114791157911679117791187911979120791217912279123791247912579126791277912879129791307913179132791337913479135791367913779138791397914079141791427914379144791457914679147791487914979150791517915279153791547915579156791577915879159791607916179162791637916479165791667916779168791697917079171791727917379174791757917679177791787917979180791817918279183791847918579186791877918879189791907919179192791937919479195791967919779198791997920079201792027920379204792057920679207792087920979210792117921279213792147921579216792177921879219792207922179222792237922479225792267922779228792297923079231792327923379234792357923679237792387923979240792417924279243792447924579246792477924879249792507925179252792537925479255792567925779258792597926079261792627926379264792657926679267792687926979270792717927279273792747927579276792777927879279792807928179282792837928479285792867928779288792897929079291792927929379294792957929679297792987929979300793017930279303793047930579306793077930879309793107931179312793137931479315793167931779318793197932079321793227932379324793257932679327793287932979330793317933279333793347933579336793377933879339793407934179342793437934479345793467934779348793497935079351793527935379354793557935679357793587935979360793617936279363793647936579366793677936879369793707937179372793737937479375793767937779378793797938079381793827938379384793857938679387793887938979390793917939279393793947939579396793977939879399794007940179402794037940479405794067940779408794097941079411794127941379414794157941679417794187941979420794217942279423794247942579426794277942879429794307943179432794337943479435794367943779438794397944079441794427944379444794457944679447794487944979450794517945279453794547945579456794577945879459794607946179462794637946479465794667946779468794697947079471794727947379474794757947679477794787947979480794817948279483794847948579486794877948879489794907949179492794937949479495794967949779498794997950079501795027950379504795057950679507795087950979510795117951279513795147951579516795177951879519795207952179522795237952479525795267952779528795297953079531795327953379534795357953679537795387953979540795417954279543795447954579546795477954879549795507955179552795537955479555795567955779558795597956079561795627956379564795657956679567795687956979570795717957279573795747957579576795777957879579795807958179582795837958479585795867958779588795897959079591795927959379594795957959679597795987959979600796017960279603796047960579606796077960879609796107961179612796137961479615796167961779618796197962079621796227962379624796257962679627796287962979630796317963279633796347963579636796377963879639796407964179642796437964479645796467964779648796497965079651796527965379654796557965679657796587965979660796617966279663796647966579666796677966879669796707967179672796737967479675796767967779678796797968079681796827968379684796857968679687796887968979690796917969279693796947969579696796977969879699797007970179702797037970479705797067970779708797097971079711797127971379714797157971679717797187971979720797217972279723797247972579726797277972879729797307973179732797337973479735797367973779738797397974079741797427974379744797457974679747797487974979750797517975279753797547975579756797577975879759797607976179762797637976479765797667976779768797697977079771797727977379774797757977679777797787977979780797817978279783797847978579786797877978879789797907979179792797937979479795797967979779798797997980079801798027980379804798057980679807798087980979810798117981279813798147981579816798177981879819798207982179822798237982479825798267982779828798297983079831798327983379834798357983679837798387983979840798417984279843798447984579846798477984879849798507985179852798537985479855798567985779858798597986079861798627986379864798657986679867798687986979870798717987279873798747987579876798777987879879798807988179882798837988479885798867988779888798897989079891798927989379894798957989679897798987989979900799017990279903799047990579906799077990879909799107991179912799137991479915799167991779918799197992079921799227992379924799257992679927799287992979930799317993279933799347993579936799377993879939799407994179942799437994479945799467994779948799497995079951799527995379954799557995679957799587995979960799617996279963799647996579966799677996879969799707997179972799737997479975799767997779978799797998079981799827998379984799857998679987799887998979990799917999279993799947999579996799977999879999800008000180002800038000480005800068000780008800098001080011800128001380014800158001680017800188001980020800218002280023800248002580026800278002880029800308003180032800338003480035800368003780038800398004080041800428004380044800458004680047800488004980050800518005280053800548005580056800578005880059 |
- #if defined(QJS_BUILD_LIBC) && defined(__linux__) && !defined(_GNU_SOURCE)
- #define _GNU_SOURCE
- #endif
- /*
- * QuickJS C atomics definitions
- *
- * Copyright (c) 2023 Marcin Kolny
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #if (defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__)
- // Use GCC builtins for version < 4.9
- # if((__GNUC__ << 16) + __GNUC_MINOR__ < ((4) << 16) + 9)
- # define GCC_BUILTIN_ATOMICS
- # endif
- #endif
- #ifdef GCC_BUILTIN_ATOMICS
- #define atomic_fetch_add(obj, arg) \
- __atomic_fetch_add(obj, arg, __ATOMIC_SEQ_CST)
- #define atomic_compare_exchange_strong(obj, expected, desired) \
- __atomic_compare_exchange_n(obj, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
- #define atomic_exchange(obj, desired) \
- __atomic_exchange_n (obj, desired, __ATOMIC_SEQ_CST)
- #define atomic_load(obj) \
- __atomic_load_n(obj, __ATOMIC_SEQ_CST)
- #define atomic_store(obj, desired) \
- __atomic_store_n(obj, desired, __ATOMIC_SEQ_CST)
- #define atomic_fetch_or(obj, arg) \
- __atomic_fetch_or(obj, arg, __ATOMIC_SEQ_CST)
- #define atomic_fetch_xor(obj, arg) \
- __atomic_fetch_xor(obj, arg, __ATOMIC_SEQ_CST)
- #define atomic_fetch_and(obj, arg) \
- __atomic_fetch_and(obj, arg, __ATOMIC_SEQ_CST)
- #define atomic_fetch_sub(obj, arg) \
- __atomic_fetch_sub(obj, arg, __ATOMIC_SEQ_CST)
- #define _Atomic
- #else
- #include <stdatomic.h>
- #endif
- /*
- * C utilities
- *
- * Copyright (c) 2017 Fabrice Bellard
- * Copyright (c) 2018 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifndef CUTILS_H
- #define CUTILS_H
- #include <stdbool.h>
- #include <stdlib.h>
- #include <string.h>
- #include <inttypes.h>
- #include <math.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- #if defined(_MSC_VER)
- #include <winsock2.h>
- #include <malloc.h>
- #define alloca _alloca
- #define ssize_t ptrdiff_t
- #endif
- #if defined(__APPLE__)
- #include <malloc/malloc.h>
- #elif defined(__linux__) || defined(__ANDROID__) || defined(__CYGWIN__) || defined(__GLIBC__)
- #include <malloc.h>
- #elif defined(__FreeBSD__)
- #include <malloc_np.h>
- #elif defined(_WIN32)
- #include <windows.h>
- #endif
- #if !defined(_WIN32) && !defined(EMSCRIPTEN) && !defined(__wasi__)
- #include <errno.h>
- #include <pthread.h>
- #endif
- #if !defined(_WIN32)
- #include <limits.h>
- #include <unistd.h>
- #endif
- #if defined(_MSC_VER) && !defined(__clang__)
- # define likely(x) (x)
- # define unlikely(x) (x)
- # define force_inline __forceinline
- # define no_inline __declspec(noinline)
- # define __maybe_unused
- # define __attribute__(x)
- # define __attribute(x)
- #else
- # define likely(x) __builtin_expect(!!(x), 1)
- # define unlikely(x) __builtin_expect(!!(x), 0)
- # define force_inline inline __attribute__((always_inline))
- # define no_inline __attribute__((noinline))
- # define __maybe_unused __attribute__((unused))
- #endif
- #if defined(_MSC_VER) && !defined(__clang__)
- #include <math.h>
- #define INF INFINITY
- #define NEG_INF -INFINITY
- #else
- #define INF (1.0/0.0)
- #define NEG_INF (-1.0/0.0)
- #endif
- #ifndef offsetof
- #define offsetof(type, field) ((size_t) &((type *)0)->field)
- #endif
- #ifndef countof
- #define countof(x) (sizeof(x) / sizeof((x)[0]))
- #ifndef endof
- #define endof(x) ((x) + countof(x))
- #endif
- #endif
- #ifndef container_of
- /* return the pointer of type 'type *' containing 'ptr' as field 'member' */
- #define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
- #endif
- #if defined(_MSC_VER) || defined(__cplusplus)
- #define minimum_length(n) n
- #else
- #define minimum_length(n) static n
- #endif
- /* Borrowed from Folly */
- #ifndef JS_PRINTF_FORMAT
- #ifdef _MSC_VER
- #include <sal.h>
- #define JS_PRINTF_FORMAT _Printf_format_string_
- #define JS_PRINTF_FORMAT_ATTR(format_param, dots_param)
- #else
- #define JS_PRINTF_FORMAT
- #if !defined(__clang__) && defined(__GNUC__)
- #define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \
- __attribute__((format(gnu_printf, format_param, dots_param)))
- #else
- #define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \
- __attribute__((format(printf, format_param, dots_param)))
- #endif
- #endif
- #endif
- #if defined(PATH_MAX)
- # define JS__PATH_MAX PATH_MAX
- #elif defined(_WIN32)
- # define JS__PATH_MAX 32767
- #else
- # define JS__PATH_MAX 8192
- #endif
- void js__pstrcpy(char *buf, int buf_size, const char *str);
- char *js__pstrcat(char *buf, int buf_size, const char *s);
- int js__strstart(const char *str, const char *val, const char **ptr);
- int js__has_suffix(const char *str, const char *suffix);
- static inline uint8_t is_be(void) {
- union {
- uint16_t a;
- uint8_t b;
- } u = { 0x100 };
- return u.b;
- }
- static inline int max_int(int a, int b)
- {
- if (a > b)
- return a;
- else
- return b;
- }
- static inline int min_int(int a, int b)
- {
- if (a < b)
- return a;
- else
- return b;
- }
- static inline uint32_t max_uint32(uint32_t a, uint32_t b)
- {
- if (a > b)
- return a;
- else
- return b;
- }
- static inline uint32_t min_uint32(uint32_t a, uint32_t b)
- {
- if (a < b)
- return a;
- else
- return b;
- }
- static inline int64_t max_int64(int64_t a, int64_t b)
- {
- if (a > b)
- return a;
- else
- return b;
- }
- static inline int64_t min_int64(int64_t a, int64_t b)
- {
- if (a < b)
- return a;
- else
- return b;
- }
- /* WARNING: undefined if a = 0 */
- static inline int clz32(unsigned int a)
- {
- #if defined(_MSC_VER) && !defined(__clang__)
- unsigned long index;
- _BitScanReverse(&index, a);
- return 31 - index;
- #else
- return __builtin_clz(a);
- #endif
- }
- /* WARNING: undefined if a = 0 */
- static inline int clz64(uint64_t a)
- {
- #if defined(_MSC_VER) && !defined(__clang__)
- #if INTPTR_MAX == INT64_MAX
- unsigned long index;
- _BitScanReverse64(&index, a);
- return 63 - index;
- #else
- if (a >> 32)
- return clz32((unsigned)(a >> 32));
- else
- return clz32((unsigned)a) + 32;
- #endif
- #else
- return __builtin_clzll(a);
- #endif
- }
- /* WARNING: undefined if a = 0 */
- static inline int ctz32(unsigned int a)
- {
- #if defined(_MSC_VER) && !defined(__clang__)
- unsigned long index;
- _BitScanForward(&index, a);
- return index;
- #else
- return __builtin_ctz(a);
- #endif
- }
- /* WARNING: undefined if a = 0 */
- static inline int ctz64(uint64_t a)
- {
- #if defined(_MSC_VER) && !defined(__clang__)
- unsigned long index;
- _BitScanForward64(&index, a);
- return index;
- #else
- return __builtin_ctzll(a);
- #endif
- }
- static inline uint64_t get_u64(const uint8_t *tab)
- {
- uint64_t v;
- memcpy(&v, tab, sizeof(v));
- return v;
- }
- static inline int64_t get_i64(const uint8_t *tab)
- {
- int64_t v;
- memcpy(&v, tab, sizeof(v));
- return v;
- }
- static inline void put_u64(uint8_t *tab, uint64_t val)
- {
- memcpy(tab, &val, sizeof(val));
- }
- static inline uint32_t get_u32(const uint8_t *tab)
- {
- uint32_t v;
- memcpy(&v, tab, sizeof(v));
- return v;
- }
- static inline int32_t get_i32(const uint8_t *tab)
- {
- int32_t v;
- memcpy(&v, tab, sizeof(v));
- return v;
- }
- static inline void put_u32(uint8_t *tab, uint32_t val)
- {
- memcpy(tab, &val, sizeof(val));
- }
- static inline uint32_t get_u16(const uint8_t *tab)
- {
- uint16_t v;
- memcpy(&v, tab, sizeof(v));
- return v;
- }
- static inline int32_t get_i16(const uint8_t *tab)
- {
- int16_t v;
- memcpy(&v, tab, sizeof(v));
- return v;
- }
- static inline void put_u16(uint8_t *tab, uint16_t val)
- {
- memcpy(tab, &val, sizeof(val));
- }
- static inline uint32_t get_u8(const uint8_t *tab)
- {
- return *tab;
- }
- static inline int32_t get_i8(const uint8_t *tab)
- {
- return (int8_t)*tab;
- }
- static inline void put_u8(uint8_t *tab, uint8_t val)
- {
- *tab = val;
- }
- #ifndef bswap16
- static inline uint16_t bswap16(uint16_t x)
- {
- return (x >> 8) | (x << 8);
- }
- #endif
- #ifndef bswap32
- static inline uint32_t bswap32(uint32_t v)
- {
- return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
- ((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
- }
- #endif
- #ifndef bswap64
- static inline uint64_t bswap64(uint64_t v)
- {
- return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
- ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |
- ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |
- ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |
- ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |
- ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |
- ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
- ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
- }
- #endif
- static inline void inplace_bswap16(uint8_t *tab) {
- put_u16(tab, bswap16(get_u16(tab)));
- }
- static inline void inplace_bswap32(uint8_t *tab) {
- put_u32(tab, bswap32(get_u32(tab)));
- }
- static inline double fromfp16(uint16_t v) {
- double d, s;
- int e;
- if ((v & 0x7C00) == 0x7C00) {
- d = (v & 0x3FF) ? NAN : INFINITY;
- } else {
- d = (v & 0x3FF) / 1024.;
- e = (v & 0x7C00) >> 10;
- if (e == 0) {
- e = -14;
- } else {
- d += 1;
- e -= 15;
- }
- d = scalbn(d, e);
- }
- s = (v & 0x8000) ? -1.0 : 1.0;
- return d * s;
- }
- static inline uint16_t tofp16(double d) {
- uint16_t f, s;
- double t;
- int e;
- s = 0;
- if (copysign(1, d) < 0) { // preserve sign when |d| is negative zero
- d = -d;
- s = 0x8000;
- }
- if (isinf(d))
- return s | 0x7C00;
- if (isnan(d))
- return s | 0x7C01;
- if (d == 0)
- return s | 0;
- d = 2 * frexp(d, &e);
- e--;
- if (e > 15)
- return s | 0x7C00; // out of range, return +/-infinity
- if (e < -25) {
- d = 0;
- e = 0;
- } else if (e < -14) {
- d = scalbn(d, e + 14);
- e = 0;
- } else {
- d -= 1;
- e += 15;
- }
- d *= 1024.;
- f = (uint16_t)d;
- t = d - f;
- if (t < 0.5)
- goto done;
- if (t == 0.5)
- if ((f & 1) == 0)
- goto done;
- // adjust for rounding
- if (++f == 1024) {
- f = 0;
- if (++e == 31)
- return s | 0x7C00; // out of range, return +/-infinity
- }
- done:
- return s | (e << 10) | f;
- }
- static inline int isfp16nan(uint16_t v) {
- return (v & 0x7FFF) > 0x7C00;
- }
- static inline int isfp16zero(uint16_t v) {
- return (v & 0x7FFF) == 0;
- }
- /* XXX: should take an extra argument to pass slack information to the caller */
- typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);
- typedef struct DynBuf {
- uint8_t *buf;
- size_t size;
- size_t allocated_size;
- bool error; /* true if a memory allocation error occurred */
- DynBufReallocFunc *realloc_func;
- void *opaque; /* for realloc_func */
- } DynBuf;
- void dbuf_init(DynBuf *s);
- void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);
- int dbuf_realloc(DynBuf *s, size_t new_size);
- int dbuf_write(DynBuf *s, size_t offset, const void *data, size_t len);
- int dbuf_put(DynBuf *s, const void *data, size_t len);
- int dbuf_put_self(DynBuf *s, size_t offset, size_t len);
- int dbuf_putc(DynBuf *s, uint8_t c);
- int dbuf_putstr(DynBuf *s, const char *str);
- static inline int dbuf_put_u16(DynBuf *s, uint16_t val)
- {
- return dbuf_put(s, (uint8_t *)&val, 2);
- }
- static inline int dbuf_put_u32(DynBuf *s, uint32_t val)
- {
- return dbuf_put(s, (uint8_t *)&val, 4);
- }
- static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
- {
- return dbuf_put(s, (uint8_t *)&val, 8);
- }
- int JS_PRINTF_FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, JS_PRINTF_FORMAT const char *fmt, ...);
- void dbuf_free(DynBuf *s);
- static inline bool dbuf_error(DynBuf *s) {
- return s->error;
- }
- static inline void dbuf_set_error(DynBuf *s)
- {
- s->error = true;
- }
- /*---- UTF-8 and UTF-16 handling ----*/
- #define UTF8_CHAR_LEN_MAX 4
- enum {
- UTF8_PLAIN_ASCII = 0, // 7-bit ASCII plain text
- UTF8_NON_ASCII = 1, // has non ASCII code points (8-bit or more)
- UTF8_HAS_16BIT = 2, // has 16-bit code points
- UTF8_HAS_NON_BMP1 = 4, // has non-BMP1 code points, needs UTF-16 surrogate pairs
- UTF8_HAS_ERRORS = 8, // has encoding errors
- };
- int utf8_scan(const char *buf, size_t len, size_t *plen);
- size_t utf8_encode_len(uint32_t c);
- size_t utf8_encode(uint8_t buf[minimum_length(UTF8_CHAR_LEN_MAX)], uint32_t c);
- uint32_t utf8_decode_len(const uint8_t *p, size_t max_len, const uint8_t **pp);
- uint32_t utf8_decode(const uint8_t *p, const uint8_t **pp);
- size_t utf8_decode_buf8(uint8_t *dest, size_t dest_len, const char *src, size_t src_len);
- size_t utf8_decode_buf16(uint16_t *dest, size_t dest_len, const char *src, size_t src_len);
- size_t utf8_encode_buf8(char *dest, size_t dest_len, const uint8_t *src, size_t src_len);
- size_t utf8_encode_buf16(char *dest, size_t dest_len, const uint16_t *src, size_t src_len);
- static inline bool is_surrogate(uint32_t c)
- {
- return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF
- }
- static inline bool is_hi_surrogate(uint32_t c)
- {
- return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF
- }
- static inline bool is_lo_surrogate(uint32_t c)
- {
- return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF
- }
- static inline uint32_t get_hi_surrogate(uint32_t c)
- {
- return (c >> 10) - (0x10000 >> 10) + 0xD800;
- }
- static inline uint32_t get_lo_surrogate(uint32_t c)
- {
- return (c & 0x3FF) | 0xDC00;
- }
- static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo)
- {
- return 65536 + 1024 * (hi & 1023) + (lo & 1023);
- }
- static inline int from_hex(int c)
- {
- if (c >= '0' && c <= '9')
- return c - '0';
- else if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
- else if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- else
- return -1;
- }
- static inline uint8_t is_upper_ascii(uint8_t c) {
- return c >= 'A' && c <= 'Z';
- }
- static inline uint8_t to_upper_ascii(uint8_t c) {
- return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c;
- }
- void rqsort(void *base, size_t nmemb, size_t size,
- int (*cmp)(const void *, const void *, void *),
- void *arg);
- static inline uint64_t float64_as_uint64(double d)
- {
- union {
- double d;
- uint64_t u64;
- } u;
- u.d = d;
- return u.u64;
- }
- static inline double uint64_as_float64(uint64_t u64)
- {
- union {
- double d;
- uint64_t u64;
- } u;
- u.u64 = u64;
- return u.d;
- }
- int64_t js__gettimeofday_us(void);
- uint64_t js__hrtime_ns(void);
- static inline size_t js__malloc_usable_size(const void *ptr)
- {
- #if defined(__APPLE__)
- return malloc_size(ptr);
- #elif defined(_WIN32)
- return _msize((void *)ptr);
- #elif defined(__linux__) || defined(__ANDROID__) || defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__GLIBC__)
- return malloc_usable_size((void *)ptr);
- #else
- return 0;
- #endif
- }
- int js_exepath(char* buffer, size_t* size);
- /* Cross-platform threading APIs. */
- #if defined(EMSCRIPTEN) || defined(__wasi__)
- #define JS_HAVE_THREADS 0
- #else
- #define JS_HAVE_THREADS 1
- #if defined(_WIN32)
- #define JS_ONCE_INIT INIT_ONCE_STATIC_INIT
- typedef INIT_ONCE js_once_t;
- typedef CRITICAL_SECTION js_mutex_t;
- typedef CONDITION_VARIABLE js_cond_t;
- typedef HANDLE js_thread_t;
- #else
- #define JS_ONCE_INIT PTHREAD_ONCE_INIT
- typedef pthread_once_t js_once_t;
- typedef pthread_mutex_t js_mutex_t;
- typedef pthread_cond_t js_cond_t;
- typedef pthread_t js_thread_t;
- #endif
- void js_once(js_once_t *guard, void (*callback)(void));
- void js_mutex_init(js_mutex_t *mutex);
- void js_mutex_destroy(js_mutex_t *mutex);
- void js_mutex_lock(js_mutex_t *mutex);
- void js_mutex_unlock(js_mutex_t *mutex);
- void js_cond_init(js_cond_t *cond);
- void js_cond_destroy(js_cond_t *cond);
- void js_cond_signal(js_cond_t *cond);
- void js_cond_broadcast(js_cond_t *cond);
- void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex);
- int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout);
- enum {
- JS_THREAD_CREATE_DETACHED = 1,
- };
- // creates threads with 2 MB stacks (glibc default)
- int js_thread_create(js_thread_t *thrd, void (*start)(void *), void *arg,
- int flags);
- int js_thread_join(js_thread_t thrd);
- #endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */
- #ifdef __cplusplus
- } /* extern "C" { */
- #endif
- #endif /* CUTILS_H */
- /*
- * Tiny float64 printing and parsing library
- *
- * Copyright (c) 2024 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- //#define JS_DTOA_DUMP_STATS
- /* maximum number of digits for fixed and frac formats */
- #define JS_DTOA_MAX_DIGITS 101
- /* radix != 10 is only supported with flags = JS_DTOA_FORMAT_FREE */
- /* use as many digits as necessary */
- #define JS_DTOA_FORMAT_FREE (0 << 0)
- /* use n_digits significant digits (1 <= n_digits <= JS_DTOA_MAX_DIGITS) */
- #define JS_DTOA_FORMAT_FIXED (1 << 0)
- /* force fractional format: [-]dd.dd with n_digits fractional digits.
- 0 <= n_digits <= JS_DTOA_MAX_DIGITS */
- #define JS_DTOA_FORMAT_FRAC (2 << 0)
- #define JS_DTOA_FORMAT_MASK (3 << 0)
- /* select exponential notation either in fixed or free format */
- #define JS_DTOA_EXP_AUTO (0 << 2)
- #define JS_DTOA_EXP_ENABLED (1 << 2)
- #define JS_DTOA_EXP_DISABLED (2 << 2)
- #define JS_DTOA_EXP_MASK (3 << 2)
- #define JS_DTOA_MINUS_ZERO (1 << 4) /* show the minus sign for -0 */
- /* only accepts integers (no dot, no exponent) */
- #define JS_ATOD_INT_ONLY (1 << 0)
- /* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
- #define JS_ATOD_ACCEPT_BIN_OCT (1 << 1)
- /* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
- #define JS_ATOD_ACCEPT_LEGACY_OCTAL (1 << 2)
- /* accept _ between digits as a digit separator */
- #define JS_ATOD_ACCEPT_UNDERSCORES (1 << 3)
- typedef struct {
- uint64_t mem[37];
- } JSDTOATempMem;
- typedef struct {
- uint64_t mem[27];
- } JSATODTempMem;
- /* return a maximum bound of the string length */
- int js_dtoa_max_len(double d, int radix, int n_digits, int flags);
- /* return the string length */
- int js_dtoa(char *buf, double d, int radix, int n_digits, int flags,
- JSDTOATempMem *tmp_mem);
- double js_atod(const char *str, const char **pnext, int radix, int flags,
- JSATODTempMem *tmp_mem);
- #ifdef JS_DTOA_DUMP_STATS
- void js_dtoa_dump_stats(void);
- #endif
- /* additional exported functions */
- size_t u32toa(char *buf, uint32_t n);
- size_t i32toa(char *buf, int32_t n);
- size_t u64toa(char *buf, uint64_t n);
- size_t i64toa(char *buf, int64_t n);
- size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix);
- size_t i64toa_radix(char *buf, int64_t n, unsigned int radix);
- /*
- * Linux klist like system
- *
- * Copyright (c) 2016-2017 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifndef LIST_H
- #define LIST_H
- #ifndef NULL
- #include <stddef.h>
- #endif
- #ifdef __cplusplus
- extern "C" {
- #endif
- struct list_head {
- struct list_head *prev;
- struct list_head *next;
- };
- #define LIST_HEAD_INIT(el) { &(el), &(el) }
- /* return the pointer of type 'type *' containing 'el' as field 'member' */
- #define list_entry(el, type, member) container_of(el, type, member)
- static inline void init_list_head(struct list_head *head)
- {
- head->prev = head;
- head->next = head;
- }
- /* insert 'el' between 'prev' and 'next' */
- static inline void __list_add(struct list_head *el,
- struct list_head *prev, struct list_head *next)
- {
- prev->next = el;
- el->prev = prev;
- el->next = next;
- next->prev = el;
- }
- /* add 'el' at the head of the list 'head' (= after element head) */
- static inline void list_add(struct list_head *el, struct list_head *head)
- {
- __list_add(el, head, head->next);
- }
- /* add 'el' at the end of the list 'head' (= before element head) */
- static inline void list_add_tail(struct list_head *el, struct list_head *head)
- {
- __list_add(el, head->prev, head);
- }
- static inline void list_del(struct list_head *el)
- {
- struct list_head *prev, *next;
- prev = el->prev;
- next = el->next;
- prev->next = next;
- next->prev = prev;
- el->prev = NULL; /* fail safe */
- el->next = NULL; /* fail safe */
- }
- static inline int list_empty(struct list_head *el)
- {
- return el->next == el;
- }
- #define list_for_each(el, head) \
- for(el = (head)->next; el != (head); el = el->next)
- #define list_for_each_safe(el, el1, head) \
- for(el = (head)->next, el1 = el->next; el != (head); \
- el = el1, el1 = el->next)
- #define list_for_each_prev(el, head) \
- for(el = (head)->prev; el != (head); el = el->prev)
- #define list_for_each_prev_safe(el, el1, head) \
- for(el = (head)->prev, el1 = el->prev; el != (head); \
- el = el1, el1 = el->prev)
- #ifdef __cplusplus
- } /* extern "C" { */
- #endif
- #endif /* LIST_H */
- /*
- * Unicode utilities
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifndef LIBUNICODE_H
- #define LIBUNICODE_H
- #include <stdbool.h>
- #include <stddef.h>
- #include <inttypes.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- #define LRE_CC_RES_LEN_MAX 3
- typedef enum {
- UNICODE_NFC,
- UNICODE_NFD,
- UNICODE_NFKC,
- UNICODE_NFKD,
- } UnicodeNormalizationEnum;
- int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
- int lre_canonicalize(uint32_t c, bool is_unicode);
- bool lre_is_cased(uint32_t c);
- bool lre_is_case_ignorable(uint32_t c);
- /* char ranges */
- typedef struct {
- int len; /* in points, always even */
- int size;
- uint32_t *points; /* points sorted by increasing value */
- void *mem_opaque;
- void *(*realloc_func)(void *opaque, void *ptr, size_t size);
- } CharRange;
- typedef enum {
- CR_OP_UNION,
- CR_OP_INTER,
- CR_OP_XOR,
- } CharRangeOpEnum;
- void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
- void cr_free(CharRange *cr);
- int cr_realloc(CharRange *cr, int size);
- int cr_copy(CharRange *cr, const CharRange *cr1);
- static inline int cr_add_point(CharRange *cr, uint32_t v)
- {
- if (cr->len >= cr->size) {
- if (cr_realloc(cr, cr->len + 1))
- return -1;
- }
- cr->points[cr->len++] = v;
- return 0;
- }
- static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2)
- {
- if ((cr->len + 2) > cr->size) {
- if (cr_realloc(cr, cr->len + 2))
- return -1;
- }
- cr->points[cr->len++] = c1;
- cr->points[cr->len++] = c2;
- return 0;
- }
- int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len);
- static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2)
- {
- uint32_t b_pt[2];
- b_pt[0] = c1;
- b_pt[1] = c2 + 1;
- return cr_union1(cr, b_pt, 2);
- }
- int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
- const uint32_t *b_pt, int b_len, int op);
- int cr_invert(CharRange *cr);
- int cr_regexp_canonicalize(CharRange *cr, bool is_unicode);
- bool lre_is_id_start(uint32_t c);
- bool lre_is_id_continue(uint32_t c);
- bool lre_is_white_space(uint32_t c);
- int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
- UnicodeNormalizationEnum n_type,
- void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
- /* Unicode character range functions */
- int unicode_script(CharRange *cr,
- const char *script_name, bool is_ext);
- int unicode_general_category(CharRange *cr, const char *gc_name);
- int unicode_prop(CharRange *cr, const char *prop_name);
- #ifdef __cplusplus
- } /* extern "C" { */
- #endif
- #endif /* LIBUNICODE_H */
- /*
- * Regular Expression Engine
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifndef LIBREGEXP_H
- #define LIBREGEXP_H
- #include <stdbool.h>
- #include <stddef.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- #define LRE_FLAG_GLOBAL (1 << 0)
- #define LRE_FLAG_IGNORECASE (1 << 1)
- #define LRE_FLAG_MULTILINE (1 << 2)
- #define LRE_FLAG_DOTALL (1 << 3)
- #define LRE_FLAG_UNICODE (1 << 4)
- #define LRE_FLAG_STICKY (1 << 5)
- #define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */
- #define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */
- #define LRE_FLAG_UNICODE_SETS (1 << 8)
- #define LRE_RET_MEMORY_ERROR (-1)
- #define LRE_RET_TIMEOUT (-2)
- uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
- const char *buf, size_t buf_len, int re_flags,
- void *opaque);
- int lre_get_capture_count(const uint8_t *bc_buf);
- int lre_get_flags(const uint8_t *bc_buf);
- const char *lre_get_groupnames(const uint8_t *bc_buf);
- int lre_exec(uint8_t **capture,
- const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,
- int cbuf_type, void *opaque);
- int lre_parse_escape(const uint8_t **pp, int allow_utf16);
- bool lre_is_space(int c);
- void lre_byte_swap(uint8_t *buf, size_t len, bool is_byte_swapped);
- /* must be provided by the user */
- bool lre_check_stack_overflow(void *opaque, size_t alloca_size);
- /* must be provided by the user, return non zero if time out */
- int lre_check_timeout(void *opaque);
- void *lre_realloc(void *opaque, void *ptr, size_t size);
- /* JS identifier test */
- extern uint32_t const lre_id_start_table_ascii[4];
- extern uint32_t const lre_id_continue_table_ascii[4];
- static inline int lre_js_is_ident_first(int c)
- {
- if ((uint32_t)c < 128) {
- return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1;
- } else {
- return lre_is_id_start(c);
- }
- }
- static inline int lre_js_is_ident_next(int c)
- {
- if ((uint32_t)c < 128) {
- return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1;
- } else {
- /* ZWNJ and ZWJ are accepted in identifiers */
- return lre_is_id_continue(c) || c == 0x200C || c == 0x200D;
- }
- }
- #ifdef __cplusplus
- } /* extern "C" { */
- #endif
- #endif /* LIBREGEXP_H */
- /* Compressed unicode tables */
- /* Automatically generated file - do not edit */
- #include <stdint.h>
- static const uint32_t case_conv_table1[378] = {
- 0x00209a30, 0x00309a00, 0x005a8173, 0x00601730,
- 0x006c0730, 0x006f81b3, 0x00701700, 0x007c0700,
- 0x007f8100, 0x00803040, 0x009801c3, 0x00988190,
- 0x00990640, 0x009c9040, 0x00a481b4, 0x00a52e40,
- 0x00bc0130, 0x00bc8640, 0x00bf8170, 0x00c00100,
- 0x00c08130, 0x00c10440, 0x00c30130, 0x00c38240,
- 0x00c48230, 0x00c58240, 0x00c70130, 0x00c78130,
- 0x00c80130, 0x00c88240, 0x00c98130, 0x00ca0130,
- 0x00ca8100, 0x00cb0130, 0x00cb8130, 0x00cc0240,
- 0x00cd0100, 0x00cd8101, 0x00ce0130, 0x00ce8130,
- 0x00cf0100, 0x00cf8130, 0x00d00640, 0x00d30130,
- 0x00d38240, 0x00d48130, 0x00d60240, 0x00d70130,
- 0x00d78240, 0x00d88230, 0x00d98440, 0x00db8130,
- 0x00dc0240, 0x00de0240, 0x00df8100, 0x00e20350,
- 0x00e38350, 0x00e50350, 0x00e69040, 0x00ee8100,
- 0x00ef1240, 0x00f801b4, 0x00f88350, 0x00fa0240,
- 0x00fb0130, 0x00fb8130, 0x00fc2840, 0x01100130,
- 0x01111240, 0x011d0131, 0x011d8240, 0x011e8130,
- 0x011f0131, 0x011f8201, 0x01208240, 0x01218130,
- 0x01220130, 0x01228130, 0x01230a40, 0x01280101,
- 0x01288101, 0x01290101, 0x01298100, 0x012a0100,
- 0x012b0200, 0x012c8100, 0x012d8100, 0x012e0101,
- 0x01300100, 0x01308101, 0x01318100, 0x01320101,
- 0x01328101, 0x01330101, 0x01340100, 0x01348100,
- 0x01350101, 0x01358101, 0x01360101, 0x01378100,
- 0x01388101, 0x01390100, 0x013a8100, 0x013e8101,
- 0x01400100, 0x01410101, 0x01418100, 0x01438101,
- 0x01440100, 0x01448100, 0x01450200, 0x01460100,
- 0x01490100, 0x014e8101, 0x014f0101, 0x01a28173,
- 0x01b80440, 0x01bb0240, 0x01bd8300, 0x01bf8130,
- 0x01c30130, 0x01c40330, 0x01c60130, 0x01c70230,
- 0x01c801d0, 0x01c89130, 0x01d18930, 0x01d60100,
- 0x01d68300, 0x01d801d3, 0x01d89100, 0x01e10173,
- 0x01e18900, 0x01e60100, 0x01e68200, 0x01e78130,
- 0x01e80173, 0x01e88173, 0x01ea8173, 0x01eb0173,
- 0x01eb8100, 0x01ec1840, 0x01f80173, 0x01f88173,
- 0x01f90100, 0x01f98100, 0x01fa01a0, 0x01fa8173,
- 0x01fb8240, 0x01fc8130, 0x01fd0240, 0x01fe8330,
- 0x02001030, 0x02082030, 0x02182000, 0x02281000,
- 0x02302240, 0x02453640, 0x02600130, 0x02608e40,
- 0x02678100, 0x02686040, 0x0298a630, 0x02b0a600,
- 0x02c381b5, 0x08502631, 0x08638131, 0x08668131,
- 0x08682b00, 0x087e8300, 0x09d05011, 0x09f80610,
- 0x09fc0620, 0x0e400174, 0x0e408174, 0x0e410174,
- 0x0e418174, 0x0e420174, 0x0e428174, 0x0e430174,
- 0x0e438180, 0x0e440180, 0x0e448240, 0x0e482b30,
- 0x0e5e8330, 0x0ebc8101, 0x0ebe8101, 0x0ec70101,
- 0x0f007e40, 0x0f3f1840, 0x0f4b01b5, 0x0f4b81b6,
- 0x0f4c01b6, 0x0f4c81b6, 0x0f4d01b7, 0x0f4d8180,
- 0x0f4f0130, 0x0f506040, 0x0f800800, 0x0f840830,
- 0x0f880600, 0x0f8c0630, 0x0f900800, 0x0f940830,
- 0x0f980800, 0x0f9c0830, 0x0fa00600, 0x0fa40630,
- 0x0fa801b0, 0x0fa88100, 0x0fa901d3, 0x0fa98100,
- 0x0faa01d3, 0x0faa8100, 0x0fab01d3, 0x0fab8100,
- 0x0fac8130, 0x0fad8130, 0x0fae8130, 0x0faf8130,
- 0x0fb00800, 0x0fb40830, 0x0fb80200, 0x0fb90400,
- 0x0fbb0201, 0x0fbc0201, 0x0fbd0201, 0x0fbe0201,
- 0x0fc008b7, 0x0fc40867, 0x0fc808b8, 0x0fcc0868,
- 0x0fd008b8, 0x0fd40868, 0x0fd80200, 0x0fd901b9,
- 0x0fd981b1, 0x0fda01b9, 0x0fdb01b1, 0x0fdb81d7,
- 0x0fdc0230, 0x0fdd0230, 0x0fde0161, 0x0fdf0173,
- 0x0fe101b9, 0x0fe181b2, 0x0fe201ba, 0x0fe301b2,
- 0x0fe381d8, 0x0fe40430, 0x0fe60162, 0x0fe80201,
- 0x0fe901d0, 0x0fe981d0, 0x0feb01b0, 0x0feb81d0,
- 0x0fec0230, 0x0fed0230, 0x0ff00201, 0x0ff101d3,
- 0x0ff181d3, 0x0ff201ba, 0x0ff28101, 0x0ff301b0,
- 0x0ff381d3, 0x0ff40231, 0x0ff50230, 0x0ff60131,
- 0x0ff901ba, 0x0ff981b2, 0x0ffa01bb, 0x0ffb01b2,
- 0x0ffb81d9, 0x0ffc0230, 0x0ffd0230, 0x0ffe0162,
- 0x109301a0, 0x109501a0, 0x109581a0, 0x10990131,
- 0x10a70101, 0x10b01031, 0x10b81001, 0x10c18240,
- 0x125b1a31, 0x12681a01, 0x16003031, 0x16183001,
- 0x16300240, 0x16310130, 0x16318130, 0x16320130,
- 0x16328100, 0x16330100, 0x16338640, 0x16368130,
- 0x16370130, 0x16378130, 0x16380130, 0x16390240,
- 0x163a8240, 0x163f0230, 0x16406440, 0x16758440,
- 0x16790240, 0x16802600, 0x16938100, 0x16968100,
- 0x53202e40, 0x53401c40, 0x53910e40, 0x53993e40,
- 0x53bc8440, 0x53be8130, 0x53bf0a40, 0x53c58240,
- 0x53c68130, 0x53c80440, 0x53ca0101, 0x53cb1440,
- 0x53d50130, 0x53d58130, 0x53d60130, 0x53d68130,
- 0x53d70130, 0x53d80130, 0x53d88130, 0x53d90130,
- 0x53d98131, 0x53da1040, 0x53e20131, 0x53e28130,
- 0x53e30130, 0x53e38440, 0x53e58130, 0x53e60240,
- 0x53e80240, 0x53eb0640, 0x53ee0130, 0x53fa8240,
- 0x55a98101, 0x55b85020, 0x7d8001b2, 0x7d8081b2,
- 0x7d8101b2, 0x7d8181da, 0x7d8201da, 0x7d8281b3,
- 0x7d8301b3, 0x7d8981bb, 0x7d8a01bb, 0x7d8a81bb,
- 0x7d8b01bc, 0x7d8b81bb, 0x7f909a31, 0x7fa09a01,
- 0x82002831, 0x82142801, 0x82582431, 0x826c2401,
- 0x82b80b31, 0x82be0f31, 0x82c60731, 0x82ca0231,
- 0x82cb8b01, 0x82d18f01, 0x82d98701, 0x82dd8201,
- 0x86403331, 0x86603301, 0x86a81631, 0x86b81601,
- 0x8c502031, 0x8c602001, 0xb7202031, 0xb7302001,
- 0xf4802231, 0xf4912201,
- };
- static const uint8_t case_conv_table2[378] = {
- 0x01, 0x00, 0x9c, 0x06, 0x07, 0x4d, 0x03, 0x04,
- 0x10, 0x00, 0x8f, 0x0b, 0x00, 0x00, 0x11, 0x00,
- 0x08, 0x00, 0x53, 0x4b, 0x52, 0x00, 0x53, 0x00,
- 0x54, 0x00, 0x3b, 0x55, 0x56, 0x00, 0x58, 0x5a,
- 0x40, 0x5f, 0x5e, 0x00, 0x47, 0x52, 0x63, 0x65,
- 0x43, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00, 0x6c,
- 0x00, 0x6e, 0x00, 0x70, 0x00, 0x00, 0x41, 0x00,
- 0x00, 0x00, 0x00, 0x1a, 0x00, 0x93, 0x00, 0x00,
- 0x20, 0x36, 0x00, 0x28, 0x00, 0x24, 0x00, 0x24,
- 0x25, 0x2d, 0x00, 0x13, 0x6d, 0x6f, 0x00, 0x29,
- 0x27, 0x2a, 0x14, 0x16, 0x18, 0x1b, 0x1c, 0x41,
- 0x1e, 0x42, 0x1f, 0x4e, 0x3c, 0x40, 0x22, 0x21,
- 0x44, 0x21, 0x43, 0x26, 0x28, 0x27, 0x29, 0x23,
- 0x2b, 0x4b, 0x2d, 0x46, 0x2f, 0x4c, 0x31, 0x4d,
- 0x33, 0x47, 0x45, 0x99, 0x00, 0x00, 0x97, 0x91,
- 0x7f, 0x80, 0x85, 0x86, 0x12, 0x82, 0x84, 0x78,
- 0x79, 0x12, 0x7d, 0xa3, 0x7e, 0x7a, 0x7b, 0x8c,
- 0x92, 0x98, 0xa6, 0xa0, 0x87, 0x00, 0x9a, 0xa1,
- 0x95, 0x77, 0x33, 0x95, 0x00, 0x90, 0x00, 0x76,
- 0x9b, 0x9a, 0x99, 0x98, 0x00, 0x00, 0xa0, 0x00,
- 0x9e, 0x00, 0xa3, 0xa2, 0x15, 0x31, 0x32, 0x33,
- 0xb7, 0xb8, 0x55, 0xac, 0xab, 0x12, 0x14, 0x1e,
- 0x21, 0x22, 0x22, 0x2a, 0x34, 0x35, 0x00, 0xa8,
- 0xa9, 0x39, 0x22, 0x4c, 0x00, 0x00, 0x97, 0x01,
- 0x5a, 0xda, 0x1d, 0x36, 0x05, 0x00, 0xc7, 0xc6,
- 0xc9, 0xc8, 0xcb, 0xca, 0xcd, 0xcc, 0xcf, 0xce,
- 0xc4, 0xd8, 0x45, 0xd9, 0x42, 0xda, 0x46, 0xdb,
- 0xd1, 0xd3, 0xd5, 0xd7, 0xdd, 0xdc, 0xf1, 0xf9,
- 0x01, 0x11, 0x0a, 0x12, 0x80, 0x9f, 0x00, 0x21,
- 0x80, 0xa3, 0xf0, 0x00, 0xc0, 0x40, 0xc6, 0x60,
- 0xea, 0xde, 0xe6, 0x99, 0xc0, 0x00, 0x00, 0x06,
- 0x60, 0xdf, 0x29, 0x00, 0x15, 0x12, 0x06, 0x16,
- 0xfb, 0xe0, 0x09, 0x15, 0x12, 0x84, 0x0b, 0xc6,
- 0x16, 0x02, 0xe2, 0x06, 0xc0, 0x40, 0x00, 0x46,
- 0x60, 0xe1, 0xe3, 0x6d, 0x37, 0x38, 0x39, 0x18,
- 0x17, 0x1a, 0x19, 0x00, 0x1d, 0x1c, 0x1f, 0x1e,
- 0x00, 0x61, 0xba, 0x67, 0x45, 0x48, 0x00, 0x50,
- 0x64, 0x4f, 0x51, 0x00, 0x00, 0x49, 0x00, 0x00,
- 0x00, 0xa5, 0xa6, 0xa7, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xb9, 0x00, 0x00, 0x5c, 0x00, 0x4a, 0x00,
- 0x5d, 0x57, 0x59, 0x62, 0x60, 0x72, 0x6b, 0x71,
- 0x54, 0x00, 0x3e, 0x69, 0xbb, 0x00, 0x5b, 0x00,
- 0x00, 0x00, 0x25, 0x00, 0x48, 0xaa, 0x8a, 0x8b,
- 0x8c, 0xab, 0xac, 0x58, 0x58, 0xaf, 0x94, 0xb0,
- 0x6f, 0xb2, 0x63, 0x62, 0x65, 0x64, 0x67, 0x66,
- 0x6c, 0x6d, 0x6e, 0x6f, 0x68, 0x69, 0x6a, 0x6b,
- 0x71, 0x70, 0x73, 0x72, 0x75, 0x74, 0x77, 0x76,
- 0x79, 0x78,
- };
- static const uint16_t case_conv_ext[58] = {
- 0x0399, 0x0308, 0x0301, 0x03a5, 0x0313, 0x0300, 0x0342, 0x0391,
- 0x0397, 0x03a9, 0x0046, 0x0049, 0x004c, 0x0053, 0x0069, 0x0307,
- 0x02bc, 0x004e, 0x004a, 0x030c, 0x0535, 0x0552, 0x0048, 0x0331,
- 0x0054, 0x0057, 0x030a, 0x0059, 0x0041, 0x02be, 0x1f08, 0x1f80,
- 0x1f28, 0x1f90, 0x1f68, 0x1fa0, 0x1fba, 0x0386, 0x1fb3, 0x1fca,
- 0x0389, 0x1fc3, 0x03a1, 0x1ffa, 0x038f, 0x1ff3, 0x0544, 0x0546,
- 0x053b, 0x054e, 0x053d, 0x03b8, 0x0462, 0xa64a, 0x1e60, 0x03c9,
- 0x006b, 0x00e5,
- };
- static const uint8_t unicode_prop_Cased1_table[193] = {
- 0x40, 0xa9, 0x80, 0x8e, 0x80, 0xfc, 0x80, 0xd3,
- 0x80, 0x9b, 0x81, 0x8d, 0x02, 0x80, 0xe1, 0x80,
- 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01, 0x11, 0x03,
- 0x04, 0x08, 0x01, 0x08, 0x30, 0x08, 0x01, 0x15,
- 0x20, 0x00, 0x39, 0x99, 0x31, 0x9d, 0x84, 0x40,
- 0x94, 0x80, 0xd6, 0x82, 0xa6, 0x80, 0x41, 0x62,
- 0x80, 0xa6, 0x80, 0x4b, 0x72, 0x80, 0x4c, 0x02,
- 0xf8, 0x02, 0x80, 0x8f, 0x80, 0xb0, 0x40, 0xdb,
- 0x08, 0x80, 0x41, 0xd0, 0x80, 0x8c, 0x80, 0x8f,
- 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x14, 0x28,
- 0x10, 0x11, 0x02, 0x01, 0x18, 0x0b, 0x24, 0x4b,
- 0x26, 0x01, 0x01, 0x86, 0xe5, 0x80, 0x60, 0x79,
- 0xb6, 0x81, 0x40, 0x91, 0x81, 0xbd, 0x88, 0x94,
- 0x05, 0x80, 0x98, 0x80, 0xa2, 0x00, 0x80, 0x9b,
- 0x12, 0x82, 0x43, 0x34, 0xa2, 0x06, 0x80, 0x8d,
- 0x60, 0x5c, 0x15, 0x01, 0x10, 0xa9, 0x80, 0x88,
- 0x60, 0xcc, 0x44, 0xd4, 0x80, 0xc6, 0x01, 0x08,
- 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0,
- 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00,
- 0x16, 0x80, 0x41, 0x53, 0x81, 0x98, 0x80, 0x98,
- 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98,
- 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98,
- 0x07, 0x47, 0x33, 0x89, 0x80, 0x93, 0x2d, 0x41,
- 0x04, 0xbd, 0x50, 0xc1, 0x99, 0x85, 0x99, 0x85,
- 0x99,
- };
- static const uint8_t unicode_prop_Cased1_index[18] = {
- 0xb9, 0x02, 0x80, 0xa0, 0x1e, 0x40, 0x9e, 0xa6,
- 0x40, 0xbb, 0x07, 0x01, 0xdb, 0xd6, 0x01, 0x8a,
- 0xf1, 0x01,
- };
- static const uint8_t unicode_prop_Case_Ignorable_table[764] = {
- 0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80,
- 0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6,
- 0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40,
- 0xfa, 0x86, 0x40, 0xce, 0x04, 0x80, 0xb0, 0xac,
- 0x00, 0x01, 0x01, 0x00, 0xab, 0x80, 0x8a, 0x85,
- 0x89, 0x8a, 0x00, 0xa2, 0x80, 0x89, 0x94, 0x8f,
- 0x80, 0xe4, 0x38, 0x89, 0x03, 0xa0, 0x00, 0x80,
- 0x9d, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0x18, 0x08,
- 0x97, 0x97, 0xaa, 0x82, 0xab, 0x06, 0x0c, 0x88,
- 0xa8, 0xb9, 0xb6, 0x00, 0x03, 0x3b, 0x02, 0x86,
- 0x89, 0x81, 0x8c, 0x80, 0x8e, 0x80, 0xb9, 0x03,
- 0x1f, 0x80, 0x93, 0x81, 0x99, 0x01, 0x81, 0xb8,
- 0x03, 0x0b, 0x09, 0x12, 0x80, 0x9d, 0x0a, 0x80,
- 0x8a, 0x81, 0xb8, 0x03, 0x20, 0x0b, 0x80, 0x93,
- 0x81, 0x95, 0x28, 0x80, 0xb9, 0x01, 0x00, 0x1f,
- 0x06, 0x81, 0x8a, 0x81, 0x9d, 0x80, 0xbc, 0x80,
- 0x8b, 0x80, 0xb1, 0x02, 0x80, 0xb6, 0x00, 0x14,
- 0x10, 0x1e, 0x81, 0x8a, 0x81, 0x9c, 0x80, 0xb9,
- 0x01, 0x05, 0x04, 0x81, 0x93, 0x81, 0x9b, 0x81,
- 0xb8, 0x0b, 0x1f, 0x80, 0x93, 0x81, 0x9c, 0x80,
- 0xc7, 0x06, 0x10, 0x80, 0xd9, 0x01, 0x86, 0x8a,
- 0x88, 0xe1, 0x01, 0x88, 0x88, 0x00, 0x86, 0xc8,
- 0x81, 0x9a, 0x00, 0x00, 0x80, 0xb6, 0x8d, 0x04,
- 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, 0x80, 0xe5,
- 0x18, 0x28, 0x09, 0x81, 0x98, 0x0b, 0x82, 0x8f,
- 0x83, 0x8c, 0x01, 0x0d, 0x80, 0x8e, 0x80, 0xdd,
- 0x80, 0x42, 0x5f, 0x82, 0x43, 0xb1, 0x82, 0x9c,
- 0x81, 0x9d, 0x81, 0x9d, 0x81, 0xbf, 0x08, 0x37,
- 0x01, 0x8a, 0x10, 0x20, 0xac, 0x84, 0xb2, 0x80,
- 0xc0, 0x81, 0xa1, 0x80, 0xf5, 0x13, 0x81, 0x88,
- 0x05, 0x82, 0x40, 0xda, 0x09, 0x80, 0xb9, 0x00,
- 0x30, 0x00, 0x01, 0x3d, 0x89, 0x08, 0xa6, 0x07,
- 0x9e, 0xb0, 0x83, 0xaf, 0x00, 0x20, 0x04, 0x80,
- 0xa7, 0x88, 0x8b, 0x81, 0x9f, 0x19, 0x08, 0x82,
- 0xb7, 0x00, 0x0a, 0x00, 0x82, 0xb9, 0x39, 0x81,
- 0xbf, 0x85, 0xd1, 0x10, 0x8c, 0x06, 0x18, 0x28,
- 0x11, 0xb1, 0xbe, 0x8c, 0x80, 0xa1, 0xe4, 0x41,
- 0xbc, 0x00, 0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c,
- 0x82, 0x8c, 0x81, 0x8b, 0x27, 0x81, 0x89, 0x01,
- 0x01, 0x84, 0xb0, 0x20, 0x89, 0x00, 0x8c, 0x80,
- 0x8f, 0x8c, 0xb2, 0xa0, 0x4b, 0x8a, 0x81, 0xf0,
- 0x82, 0xfc, 0x80, 0x8e, 0x80, 0xdf, 0x9f, 0xae,
- 0x80, 0x41, 0xd4, 0x80, 0xa3, 0x1a, 0x24, 0x80,
- 0xdc, 0x85, 0xdc, 0x82, 0x60, 0x6f, 0x15, 0x80,
- 0x44, 0xe1, 0x85, 0x41, 0x0d, 0x80, 0xe1, 0x18,
- 0x89, 0x00, 0x9b, 0x83, 0xcf, 0x81, 0x8d, 0xa1,
- 0xcd, 0x80, 0x96, 0x82, 0xe6, 0x12, 0x0f, 0x02,
- 0x03, 0x80, 0x98, 0x0c, 0x80, 0x40, 0x96, 0x81,
- 0x99, 0x91, 0x8c, 0x80, 0xa5, 0x87, 0x98, 0x8a,
- 0xad, 0x82, 0xaf, 0x01, 0x19, 0x81, 0x90, 0x80,
- 0x94, 0x81, 0xc1, 0x29, 0x09, 0x81, 0x8b, 0x07,
- 0x80, 0xa2, 0x80, 0x8a, 0x80, 0xb2, 0x00, 0x11,
- 0x0c, 0x08, 0x80, 0x9a, 0x80, 0x8d, 0x0c, 0x08,
- 0x80, 0xe3, 0x84, 0x88, 0x82, 0xf8, 0x01, 0x03,
- 0x80, 0x60, 0x4f, 0x2f, 0x80, 0x40, 0x92, 0x90,
- 0x42, 0x3c, 0x8f, 0x10, 0x8b, 0x8f, 0xa1, 0x01,
- 0x80, 0x40, 0xa8, 0x06, 0x05, 0x80, 0x8a, 0x80,
- 0xa2, 0x00, 0x80, 0xae, 0x80, 0xac, 0x81, 0xc2,
- 0x80, 0x94, 0x82, 0x42, 0x00, 0x80, 0x40, 0xe1,
- 0x80, 0x40, 0x94, 0x84, 0x44, 0x04, 0x28, 0xa9,
- 0x80, 0x88, 0x42, 0x45, 0x10, 0x0c, 0x83, 0xa7,
- 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x83,
- 0xa5, 0x80, 0x99, 0x20, 0x80, 0x41, 0x3a, 0x81,
- 0xce, 0x83, 0xc5, 0x8a, 0xb0, 0x83, 0xfa, 0x80,
- 0xb5, 0x8e, 0xa8, 0x01, 0x81, 0x89, 0x82, 0xb0,
- 0x19, 0x09, 0x03, 0x80, 0x89, 0x80, 0xb1, 0x82,
- 0xa3, 0x20, 0x87, 0xbd, 0x80, 0x8b, 0x81, 0xb3,
- 0x88, 0x89, 0x19, 0x80, 0xde, 0x11, 0x00, 0x0d,
- 0x01, 0x80, 0x40, 0x9c, 0x02, 0x87, 0x94, 0x81,
- 0xb8, 0x0a, 0x80, 0xa4, 0x32, 0x84, 0xc5, 0x85,
- 0x8c, 0x00, 0x00, 0x80, 0x8d, 0x81, 0xd4, 0x39,
- 0x10, 0x80, 0x96, 0x80, 0xd3, 0x28, 0x03, 0x08,
- 0x81, 0x40, 0xed, 0x1d, 0x08, 0x81, 0x9a, 0x81,
- 0xd4, 0x39, 0x00, 0x81, 0xe9, 0x00, 0x01, 0x28,
- 0x80, 0xe4, 0x00, 0x01, 0x18, 0x84, 0x41, 0x02,
- 0x88, 0x01, 0x40, 0xff, 0x08, 0x03, 0x80, 0x40,
- 0x8f, 0x19, 0x0b, 0x80, 0x9f, 0x89, 0xa7, 0x29,
- 0x1f, 0x80, 0x88, 0x29, 0x82, 0xad, 0x8c, 0x01,
- 0x41, 0x95, 0x30, 0x28, 0x80, 0xd1, 0x95, 0x0e,
- 0x01, 0x01, 0xf9, 0x2a, 0x00, 0x08, 0x30, 0x80,
- 0xc7, 0x0a, 0x00, 0x80, 0x41, 0x5a, 0x81, 0x8a,
- 0x81, 0xb3, 0x24, 0x00, 0x80, 0x96, 0x80, 0x54,
- 0xd4, 0x90, 0x85, 0x8e, 0x60, 0x2c, 0xc7, 0x8b,
- 0x12, 0x49, 0xbf, 0x84, 0xba, 0x86, 0x88, 0x83,
- 0x41, 0xfb, 0x82, 0xa7, 0x81, 0x41, 0xe1, 0x80,
- 0xbe, 0x90, 0xbf, 0x08, 0x81, 0x60, 0x40, 0x0a,
- 0x18, 0x30, 0x81, 0x4c, 0x9d, 0x08, 0x83, 0x52,
- 0x5b, 0xad, 0x81, 0x96, 0x42, 0x1f, 0x82, 0x88,
- 0x8f, 0x0e, 0x9d, 0x83, 0x40, 0x93, 0x82, 0x47,
- 0xba, 0xb6, 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95,
- 0x20, 0x8e, 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01,
- 0x04, 0x84, 0xbd, 0xa0, 0x80, 0x40, 0x9f, 0x8d,
- 0x41, 0x6f, 0x80, 0xbc, 0x83, 0x41, 0xfa, 0x84,
- 0x40, 0xfd, 0x81, 0x42, 0xdf, 0x86, 0xec, 0x87,
- 0x4a, 0xae, 0x84, 0x6c, 0x0c, 0x00, 0x80, 0x9d,
- 0xdf, 0xff, 0x40, 0xef,
- };
- static const uint8_t unicode_prop_Case_Ignorable_index[72] = {
- 0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a,
- 0xa0, 0xc1, 0x0b, 0x00, 0x82, 0x0d, 0x00, 0x3f,
- 0x10, 0x80, 0xd4, 0x17, 0x40, 0xcf, 0x1a, 0x20,
- 0xf5, 0x1c, 0x00, 0x80, 0x20, 0x00, 0x16, 0xa0,
- 0x00, 0xc6, 0xa8, 0x00, 0xc2, 0xaa, 0x60, 0x56,
- 0xfe, 0x20, 0xb1, 0x07, 0x01, 0x02, 0x10, 0x01,
- 0x42, 0x12, 0x41, 0xc4, 0x14, 0x21, 0xe1, 0x19,
- 0x81, 0x48, 0x1d, 0x01, 0x44, 0x6b, 0x01, 0x83,
- 0xd1, 0x21, 0x3e, 0xe1, 0x01, 0xf0, 0x01, 0x0e,
- };
- static const uint8_t unicode_prop_ID_Start_table[1133] = {
- 0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03,
- 0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83,
- 0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20,
- 0x09, 0x18, 0x05, 0x00, 0x10, 0x00, 0x93, 0x80,
- 0xd2, 0x80, 0x40, 0x8a, 0x87, 0x40, 0xa5, 0x80,
- 0xa5, 0x08, 0x85, 0xa8, 0xc6, 0x9a, 0x1b, 0xac,
- 0xaa, 0xa2, 0x08, 0xe2, 0x00, 0x8e, 0x0e, 0x81,
- 0x89, 0x11, 0x80, 0x8f, 0x00, 0x9d, 0x9c, 0xd8,
- 0x8a, 0x80, 0x97, 0xa0, 0x88, 0x0b, 0x04, 0x95,
- 0x18, 0x88, 0x02, 0x80, 0x96, 0x98, 0x86, 0x8a,
- 0x84, 0x97, 0x05, 0x90, 0xa9, 0xb9, 0xb5, 0x10,
- 0x91, 0x06, 0x89, 0x8e, 0x8f, 0x1f, 0x09, 0x81,
- 0x95, 0x06, 0x00, 0x13, 0x10, 0x8f, 0x80, 0x8c,
- 0x08, 0x82, 0x8d, 0x81, 0x89, 0x07, 0x2b, 0x09,
- 0x95, 0x06, 0x01, 0x01, 0x01, 0x9e, 0x18, 0x80,
- 0x92, 0x82, 0x8f, 0x88, 0x02, 0x80, 0x95, 0x06,
- 0x01, 0x04, 0x10, 0x91, 0x80, 0x8e, 0x81, 0x96,
- 0x80, 0x8a, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04,
- 0x10, 0x9d, 0x08, 0x82, 0x8e, 0x80, 0x90, 0x00,
- 0x2a, 0x10, 0x1a, 0x08, 0x00, 0x0a, 0x0a, 0x12,
- 0x8b, 0x95, 0x80, 0xb3, 0x38, 0x10, 0x96, 0x80,
- 0x8f, 0x10, 0x99, 0x11, 0x01, 0x81, 0x9d, 0x03,
- 0x38, 0x10, 0x96, 0x80, 0x89, 0x04, 0x10, 0x9e,
- 0x08, 0x81, 0x8e, 0x81, 0x90, 0x88, 0x02, 0x80,
- 0xa8, 0x08, 0x8f, 0x04, 0x17, 0x82, 0x97, 0x2c,
- 0x91, 0x82, 0x97, 0x80, 0x88, 0x00, 0x0e, 0xb9,
- 0xaf, 0x01, 0x8b, 0x86, 0xb9, 0x08, 0x00, 0x20,
- 0x97, 0x00, 0x80, 0x89, 0x01, 0x88, 0x01, 0x20,
- 0x80, 0x94, 0x83, 0x9f, 0x80, 0xbe, 0x38, 0xa3,
- 0x9a, 0x84, 0xf2, 0xaa, 0x93, 0x80, 0x8f, 0x2b,
- 0x1a, 0x02, 0x0e, 0x13, 0x8c, 0x8b, 0x80, 0x90,
- 0xa5, 0x00, 0x20, 0x81, 0xaa, 0x80, 0x41, 0x4c,
- 0x03, 0x0e, 0x00, 0x03, 0x81, 0xa8, 0x03, 0x81,
- 0xa0, 0x03, 0x0e, 0x00, 0x03, 0x81, 0x8e, 0x80,
- 0xb8, 0x03, 0x81, 0xc2, 0xa4, 0x8f, 0x8f, 0xd5,
- 0x0d, 0x82, 0x42, 0x6b, 0x81, 0x90, 0x80, 0x99,
- 0x84, 0xca, 0x82, 0x8a, 0x86, 0x91, 0x8c, 0x92,
- 0x8d, 0x91, 0x8d, 0x8c, 0x02, 0x8e, 0xb3, 0xa2,
- 0x03, 0x80, 0xc2, 0xd8, 0x86, 0xa8, 0x00, 0x84,
- 0xc5, 0x89, 0x9e, 0xb0, 0x9d, 0x0c, 0x8a, 0xab,
- 0x83, 0x99, 0xb5, 0x96, 0x88, 0xb4, 0xd1, 0x80,
- 0xdc, 0xae, 0x90, 0x87, 0xb5, 0x9d, 0x8c, 0x81,
- 0x89, 0xab, 0x99, 0xa3, 0xa8, 0x82, 0x89, 0xa3,
- 0x81, 0x8a, 0x84, 0xaa, 0x0a, 0xa8, 0x18, 0x28,
- 0x0a, 0x04, 0x40, 0xbf, 0xbf, 0x41, 0x15, 0x0d,
- 0x81, 0xa5, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x80,
- 0x9e, 0x81, 0xb4, 0x06, 0x00, 0x12, 0x06, 0x13,
- 0x0d, 0x83, 0x8c, 0x22, 0x06, 0xf3, 0x80, 0x8c,
- 0x80, 0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00,
- 0x0d, 0x28, 0x00, 0x00, 0x80, 0x8f, 0x0b, 0x24,
- 0x18, 0x90, 0xa8, 0x4a, 0x76, 0x40, 0xe4, 0x2b,
- 0x11, 0x8b, 0xa5, 0x00, 0x20, 0x81, 0xb7, 0x30,
- 0x8f, 0x96, 0x88, 0x30, 0x30, 0x30, 0x30, 0x30,
- 0x30, 0x30, 0x86, 0x42, 0x25, 0x82, 0x98, 0x88,
- 0x34, 0x0c, 0x83, 0xd5, 0x1c, 0x80, 0xd9, 0x03,
- 0x84, 0xaa, 0x80, 0xdd, 0x90, 0x9f, 0xaf, 0x8f,
- 0x41, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x56, 0x8c,
- 0xc2, 0xad, 0x81, 0x41, 0x0c, 0x82, 0x8f, 0x89,
- 0x81, 0x93, 0xae, 0x8f, 0x9e, 0x81, 0xcf, 0xa6,
- 0x88, 0x81, 0xe6, 0x81, 0xc2, 0x09, 0x00, 0x07,
- 0x94, 0x8f, 0x02, 0x03, 0x80, 0x96, 0x9c, 0xb3,
- 0x8d, 0xb1, 0xbd, 0x2a, 0x00, 0x81, 0x8a, 0x9b,
- 0x89, 0x96, 0x98, 0x9c, 0x86, 0xae, 0x9b, 0x80,
- 0x8f, 0x20, 0x89, 0x89, 0x20, 0xa8, 0x96, 0x10,
- 0x87, 0x93, 0x96, 0x10, 0x82, 0xb1, 0x00, 0x11,
- 0x0c, 0x08, 0x00, 0x97, 0x11, 0x8a, 0x32, 0x8b,
- 0x29, 0x29, 0x85, 0x88, 0x30, 0x30, 0xaa, 0x80,
- 0x8d, 0x85, 0xf2, 0x9c, 0x60, 0x2b, 0xa3, 0x8b,
- 0x96, 0x83, 0xb0, 0x60, 0x21, 0x03, 0x41, 0x6d,
- 0x81, 0xe9, 0xa5, 0x86, 0x8b, 0x24, 0x00, 0x89,
- 0x80, 0x8c, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb,
- 0xa0, 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7,
- 0x8b, 0xf3, 0x20, 0x40, 0x86, 0xa3, 0x99, 0x85,
- 0x99, 0x8a, 0xd8, 0x15, 0x0d, 0x0d, 0x0a, 0xa2,
- 0x8b, 0x80, 0x99, 0x80, 0x92, 0x01, 0x80, 0x8e,
- 0x81, 0x8d, 0xa1, 0xfa, 0xc4, 0xb4, 0x41, 0x0a,
- 0x9c, 0x82, 0xb0, 0xae, 0x9f, 0x8c, 0x9d, 0x84,
- 0xa5, 0x89, 0x9d, 0x81, 0xa3, 0x1f, 0x04, 0xa9,
- 0x40, 0x9d, 0x91, 0xa3, 0x83, 0xa3, 0x83, 0xa7,
- 0x87, 0xb3, 0x8b, 0x8a, 0x80, 0x8e, 0x06, 0x01,
- 0x80, 0x8a, 0x80, 0x8e, 0x06, 0x01, 0x82, 0xb3,
- 0x8b, 0x41, 0x36, 0x88, 0x95, 0x89, 0x87, 0x97,
- 0x28, 0xa9, 0x80, 0x88, 0xc4, 0x29, 0x00, 0xab,
- 0x01, 0x10, 0x81, 0x96, 0x89, 0x96, 0x88, 0x9e,
- 0xc0, 0x92, 0x01, 0x89, 0x95, 0x89, 0x99, 0xc5,
- 0xb7, 0x29, 0xbf, 0x80, 0x8e, 0x18, 0x10, 0x9c,
- 0xa9, 0x9c, 0x82, 0x9c, 0xa2, 0x38, 0x9b, 0x9a,
- 0xb5, 0x89, 0x95, 0x89, 0x92, 0x8c, 0x91, 0xed,
- 0xc8, 0xb6, 0xb2, 0x8c, 0xb2, 0x8c, 0xa3, 0xa5,
- 0x9b, 0x88, 0x96, 0x40, 0xf9, 0xa9, 0x29, 0x8f,
- 0x82, 0xba, 0x9c, 0x89, 0x07, 0x95, 0xa9, 0x91,
- 0xad, 0x94, 0x9a, 0x96, 0x8b, 0xb4, 0xb8, 0x09,
- 0x80, 0x8c, 0xac, 0x9f, 0x98, 0x99, 0xa3, 0x9c,
- 0x01, 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d, 0x83,
- 0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 0x92,
- 0x81, 0xbe, 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89,
- 0x86, 0xae, 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01,
- 0x04, 0x10, 0x91, 0x80, 0x8b, 0x84, 0x9d, 0x89,
- 0x00, 0x08, 0x80, 0xa5, 0x00, 0x98, 0x00, 0x80,
- 0xab, 0xb4, 0x91, 0x83, 0x93, 0x82, 0x9d, 0xaf,
- 0x93, 0x08, 0x80, 0x40, 0xb7, 0xae, 0xa8, 0x83,
- 0xa3, 0xaf, 0x93, 0x80, 0xba, 0xaa, 0x8c, 0x80,
- 0xc6, 0x9a, 0xa4, 0x86, 0x40, 0xb8, 0xab, 0xf3,
- 0xbf, 0x9e, 0x39, 0x01, 0x38, 0x08, 0x97, 0x8e,
- 0x00, 0x80, 0xdd, 0x39, 0xa6, 0x8f, 0x00, 0x80,
- 0x9b, 0x80, 0x89, 0xa7, 0x30, 0x94, 0x80, 0x8a,
- 0xad, 0x92, 0x80, 0x91, 0xc8, 0x40, 0xc6, 0xa0,
- 0x9e, 0x88, 0x80, 0xa4, 0x90, 0x80, 0xb0, 0x9d,
- 0xef, 0x30, 0x08, 0xa5, 0x94, 0x80, 0x98, 0x28,
- 0x08, 0x9f, 0x8d, 0x80, 0x41, 0x46, 0x92, 0x8e,
- 0x00, 0x8c, 0x80, 0xa1, 0xfb, 0x80, 0xce, 0x43,
- 0x99, 0xe5, 0xee, 0x90, 0x40, 0xc3, 0x4a, 0x4b,
- 0xe0, 0x8e, 0x44, 0x2f, 0x90, 0x85, 0x98, 0x4f,
- 0x9a, 0x84, 0x42, 0x46, 0x5a, 0xb8, 0x9d, 0x46,
- 0xe1, 0x42, 0x38, 0x86, 0x9e, 0x90, 0xce, 0x90,
- 0x9d, 0x91, 0xaf, 0x8f, 0x83, 0x9e, 0x94, 0x84,
- 0x92, 0x41, 0xaf, 0xac, 0x40, 0xd2, 0xbf, 0xff,
- 0xca, 0x20, 0xc1, 0x8c, 0xbf, 0x08, 0x80, 0x9b,
- 0x57, 0xf7, 0x87, 0x44, 0xd5, 0xa8, 0x89, 0x60,
- 0x22, 0xe6, 0x18, 0x30, 0x08, 0x41, 0x22, 0x8e,
- 0x80, 0x9c, 0x11, 0x80, 0x8d, 0x1f, 0x41, 0x8b,
- 0x49, 0x03, 0xea, 0x84, 0x8c, 0x82, 0x88, 0x86,
- 0x89, 0x57, 0x65, 0xd4, 0x80, 0xc6, 0x01, 0x08,
- 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0,
- 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00,
- 0x16, 0x80, 0x41, 0x53, 0x81, 0x98, 0x80, 0x98,
- 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98,
- 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98,
- 0x07, 0x47, 0x33, 0x9e, 0x2d, 0x41, 0x04, 0xbd,
- 0x40, 0x91, 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41,
- 0x40, 0x9d, 0x91, 0xab, 0x41, 0xe3, 0x9b, 0x40,
- 0xe3, 0x9d, 0x08, 0x41, 0xee, 0x30, 0x18, 0x08,
- 0x8e, 0x80, 0x40, 0xc4, 0xba, 0xc3, 0x30, 0x44,
- 0xb3, 0x18, 0x9a, 0x01, 0x00, 0x08, 0x80, 0x89,
- 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x02,
- 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, 0x80, 0x89,
- 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, 0x51, 0x43,
- 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x39, 0x85, 0x40,
- 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x8e,
- 0x42, 0x6d, 0x49, 0xa1, 0x42, 0x1d, 0x45, 0xe1,
- 0x53, 0x4a, 0x84, 0x50, 0x5f,
- };
- static const uint8_t unicode_prop_ID_Start_index[108] = {
- 0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09,
- 0x20, 0xb1, 0x0a, 0x00, 0xba, 0x0b, 0x20, 0x3b,
- 0x0d, 0x20, 0xc7, 0x0e, 0x20, 0x49, 0x12, 0x00,
- 0x9b, 0x16, 0x00, 0xac, 0x19, 0x00, 0xc0, 0x1d,
- 0x80, 0x80, 0x20, 0x20, 0x70, 0x2d, 0x00, 0x00,
- 0x32, 0x00, 0xdd, 0xa7, 0x00, 0x4c, 0xaa, 0x20,
- 0xc7, 0xd7, 0x20, 0xfc, 0xfd, 0x20, 0x9d, 0x02,
- 0x21, 0x96, 0x05, 0x01, 0x9f, 0x08, 0x01, 0x49,
- 0x0c, 0x21, 0x76, 0x10, 0x21, 0xa9, 0x12, 0x01,
- 0xb0, 0x14, 0x01, 0x42, 0x19, 0x41, 0x90, 0x1c,
- 0x01, 0xf1, 0x2f, 0x21, 0x90, 0x6b, 0x21, 0x33,
- 0xb1, 0x21, 0x06, 0xd5, 0x01, 0xc3, 0xd7, 0x01,
- 0xff, 0xe7, 0x21, 0x63, 0xee, 0x01, 0x5e, 0xee,
- 0x42, 0xb0, 0x23, 0x03,
- };
- static const uint8_t unicode_prop_ID_Continue1_table[695] = {
- 0xaf, 0x89, 0xa4, 0x80, 0xd6, 0x80, 0x42, 0x47,
- 0xef, 0x96, 0x80, 0x40, 0xfa, 0x84, 0x41, 0x08,
- 0xac, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf,
- 0x9e, 0x28, 0xe4, 0x31, 0x29, 0x08, 0x19, 0x89,
- 0x96, 0x80, 0x9d, 0x9a, 0xda, 0x8a, 0x8e, 0x89,
- 0xa0, 0x88, 0x88, 0x80, 0x97, 0x18, 0x88, 0x02,
- 0x04, 0xaa, 0x82, 0xba, 0x88, 0xa9, 0x97, 0x80,
- 0xa0, 0xb5, 0x10, 0x91, 0x06, 0x89, 0x09, 0x89,
- 0x90, 0x82, 0xb7, 0x00, 0x31, 0x09, 0x82, 0x88,
- 0x80, 0x89, 0x09, 0x89, 0x8d, 0x01, 0x82, 0xb7,
- 0x00, 0x23, 0x09, 0x12, 0x80, 0x93, 0x8b, 0x10,
- 0x8a, 0x82, 0xb7, 0x00, 0x38, 0x10, 0x82, 0x93,
- 0x09, 0x89, 0x89, 0x28, 0x82, 0xb7, 0x00, 0x31,
- 0x09, 0x16, 0x82, 0x89, 0x09, 0x89, 0x91, 0x80,
- 0xba, 0x22, 0x10, 0x83, 0x88, 0x80, 0x8d, 0x89,
- 0x8f, 0x84, 0xb6, 0x00, 0x30, 0x10, 0x1e, 0x81,
- 0x8a, 0x09, 0x89, 0x90, 0x82, 0xb7, 0x00, 0x30,
- 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, 0x10, 0x8b,
- 0x83, 0xb6, 0x08, 0x30, 0x10, 0x83, 0x88, 0x80,
- 0x89, 0x09, 0x89, 0x90, 0x82, 0xc5, 0x03, 0x28,
- 0x00, 0x3d, 0x89, 0x09, 0xbc, 0x01, 0x86, 0x8b,
- 0x38, 0x89, 0xd6, 0x01, 0x88, 0x8a, 0x30, 0x89,
- 0xbd, 0x0d, 0x89, 0x8a, 0x00, 0x00, 0x03, 0x81,
- 0xb0, 0x93, 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88,
- 0x80, 0xe3, 0x93, 0x80, 0x89, 0x8b, 0x1b, 0x10,
- 0x11, 0x32, 0x83, 0x8c, 0x8b, 0x80, 0x8e, 0x42,
- 0xbe, 0x82, 0x88, 0x88, 0x43, 0x9f, 0x83, 0x9b,
- 0x82, 0x9c, 0x81, 0x9d, 0x81, 0xbf, 0x9f, 0x88,
- 0x01, 0x89, 0xa0, 0x10, 0x8a, 0x40, 0x8e, 0x80,
- 0xf5, 0x8b, 0x83, 0x8b, 0x89, 0x89, 0xff, 0x8a,
- 0xbb, 0x84, 0xb8, 0x89, 0x80, 0x9c, 0x81, 0x8a,
- 0x85, 0x89, 0x95, 0x8d, 0x80, 0x8f, 0xb0, 0x84,
- 0xae, 0x90, 0x8a, 0x89, 0x90, 0x88, 0x8b, 0x82,
- 0x9d, 0x8c, 0x81, 0x89, 0xab, 0x8d, 0xaf, 0x93,
- 0x87, 0x89, 0x85, 0x89, 0xf5, 0x10, 0x94, 0x18,
- 0x28, 0x0a, 0x40, 0xc5, 0xbf, 0x42, 0x0b, 0x81,
- 0xb0, 0x81, 0x92, 0x80, 0xfa, 0x8c, 0x18, 0x82,
- 0x8b, 0x4b, 0xfd, 0x82, 0x40, 0x8c, 0x80, 0xdf,
- 0x9f, 0x42, 0x29, 0x85, 0xe8, 0x81, 0xdf, 0x80,
- 0x60, 0x75, 0x23, 0x89, 0xc4, 0x03, 0x89, 0x9f,
- 0x81, 0xcf, 0x81, 0x41, 0x0f, 0x02, 0x03, 0x80,
- 0x96, 0x23, 0x80, 0xd2, 0x81, 0xb1, 0x91, 0x89,
- 0x89, 0x85, 0x91, 0x8c, 0x8a, 0x9b, 0x87, 0x98,
- 0x8c, 0xab, 0x83, 0xae, 0x8d, 0x8e, 0x89, 0x8a,
- 0x80, 0x89, 0x89, 0xae, 0x8d, 0x8b, 0x07, 0x09,
- 0x89, 0xa0, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x08,
- 0x80, 0xa8, 0x24, 0x81, 0x40, 0xeb, 0x38, 0x09,
- 0x89, 0x60, 0x4f, 0x23, 0x80, 0x42, 0xe0, 0x8f,
- 0x8f, 0x8f, 0x11, 0x97, 0x82, 0x40, 0xbf, 0x89,
- 0xa4, 0x80, 0xa4, 0x80, 0x42, 0x96, 0x80, 0x40,
- 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41, 0x24, 0x89,
- 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7, 0x13, 0x80,
- 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f, 0x89, 0x85,
- 0x89, 0x9e, 0x84, 0x41, 0x3c, 0x81, 0xce, 0x83,
- 0xc5, 0x8a, 0xb0, 0x83, 0xf9, 0x82, 0xb4, 0x8e,
- 0x9e, 0x8a, 0x09, 0x89, 0x83, 0xac, 0x8a, 0x30,
- 0xac, 0x89, 0x2a, 0xa3, 0x8d, 0x80, 0x89, 0x21,
- 0xab, 0x80, 0x8b, 0x82, 0xaf, 0x8d, 0x3b, 0x80,
- 0x8b, 0xd1, 0x8b, 0x28, 0x08, 0x40, 0x9c, 0x8b,
- 0x84, 0x89, 0x2b, 0xb6, 0x08, 0x31, 0x09, 0x82,
- 0x88, 0x80, 0x89, 0x09, 0x32, 0x84, 0xc2, 0x88,
- 0x00, 0x08, 0x03, 0x04, 0x00, 0x8d, 0x81, 0xd1,
- 0x91, 0x88, 0x89, 0x18, 0xd0, 0x93, 0x8b, 0x89,
- 0x40, 0xd4, 0x31, 0x88, 0x9a, 0x81, 0xd1, 0x90,
- 0x8e, 0x89, 0xd0, 0x8c, 0x87, 0x89, 0x85, 0x93,
- 0xb8, 0x8e, 0x83, 0x89, 0x40, 0xf1, 0x8e, 0x40,
- 0xa4, 0x89, 0xc5, 0x28, 0x09, 0x18, 0x00, 0x81,
- 0x8b, 0x89, 0xf6, 0x31, 0x32, 0x80, 0x9b, 0x89,
- 0xa7, 0x30, 0x1f, 0x80, 0x88, 0x8a, 0xad, 0x8f,
- 0x41, 0x55, 0x89, 0xb4, 0x38, 0x87, 0x8f, 0x89,
- 0xb7, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, 0x08,
- 0x30, 0x07, 0x89, 0xaf, 0x20, 0x08, 0x27, 0x89,
- 0x41, 0x48, 0x83, 0x88, 0x08, 0x80, 0xaf, 0x32,
- 0x84, 0x8c, 0x8a, 0x54, 0xe4, 0x05, 0x8e, 0x60,
- 0x2c, 0xc7, 0x9b, 0x49, 0x25, 0x89, 0xd5, 0x89,
- 0xa5, 0x84, 0xba, 0x86, 0x98, 0x89, 0x42, 0x15,
- 0x89, 0x41, 0xd4, 0x00, 0xb6, 0x33, 0xd0, 0x80,
- 0x8a, 0x81, 0x60, 0x4c, 0xaa, 0x81, 0x50, 0x50,
- 0x89, 0x42, 0x05, 0xad, 0x81, 0x96, 0x42, 0x1d,
- 0x22, 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x40, 0x93,
- 0x82, 0x45, 0x88, 0xb1, 0x41, 0xff, 0xb6, 0x83,
- 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, 0x45,
- 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3, 0x80,
- 0x40, 0x9f, 0x86, 0x88, 0x89, 0x41, 0x63, 0x80,
- 0xbc, 0x8d, 0x41, 0xf1, 0x8d, 0x40, 0xf3, 0x08,
- 0x89, 0x42, 0xd4, 0x86, 0xec, 0x34, 0x89, 0x52,
- 0x95, 0x89, 0x6c, 0x05, 0x05, 0x40, 0xef,
- };
- static const uint8_t unicode_prop_ID_Continue1_index[66] = {
- 0xfa, 0x06, 0x00, 0x70, 0x09, 0x00, 0xf0, 0x0a,
- 0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x60, 0xc7,
- 0x0f, 0x20, 0xea, 0x17, 0x40, 0x05, 0x1b, 0x00,
- 0x0e, 0x20, 0x00, 0xa0, 0xa6, 0x20, 0xe6, 0xa9,
- 0x20, 0x10, 0xfe, 0x00, 0x40, 0x0a, 0x01, 0xc3,
- 0x10, 0x01, 0x4e, 0x13, 0x01, 0x41, 0x16, 0x01,
- 0x0b, 0x1a, 0x01, 0xaa, 0x1d, 0x01, 0x7a, 0x6d,
- 0x21, 0x45, 0xd2, 0x21, 0xaf, 0xe2, 0x01, 0xf0,
- 0x01, 0x0e,
- };
- static const uint8_t unicode_prop_White_Space_table[22] = {
- 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x99, 0x80,
- 0x55, 0xde, 0x80, 0x49, 0x7e, 0x8a, 0x9c, 0x0c,
- 0x80, 0xae, 0x80, 0x4f, 0x9f, 0x80,
- };
- static const uint8_t unicode_prop_White_Space_index[3] = {
- 0x01, 0x30, 0x00,
- };
- static const uint8_t unicode_cc_table[916] = {
- 0xb2, 0xcf, 0xd4, 0x00, 0xe8, 0x03, 0xdc, 0x00,
- 0xe8, 0x00, 0xd8, 0x04, 0xdc, 0x01, 0xca, 0x03,
- 0xdc, 0x01, 0xca, 0x0a, 0xdc, 0x04, 0x01, 0x03,
- 0xdc, 0xc7, 0x00, 0xf0, 0xc0, 0x02, 0xdc, 0xc2,
- 0x01, 0xdc, 0x80, 0xc2, 0x03, 0xdc, 0xc0, 0x00,
- 0xe8, 0x01, 0xdc, 0xc0, 0x41, 0xe9, 0x00, 0xea,
- 0x41, 0xe9, 0x00, 0xea, 0x00, 0xe9, 0xcc, 0xb0,
- 0xe2, 0xc4, 0xb0, 0xd8, 0x00, 0xdc, 0xc3, 0x00,
- 0xdc, 0xc2, 0x00, 0xde, 0x00, 0xdc, 0xc5, 0x05,
- 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xde, 0x00,
- 0xe4, 0xc0, 0x49, 0x0a, 0x43, 0x13, 0x80, 0x00,
- 0x17, 0x80, 0x41, 0x18, 0x80, 0xc0, 0x00, 0xdc,
- 0x80, 0x00, 0x12, 0xb0, 0x17, 0xc7, 0x42, 0x1e,
- 0xaf, 0x47, 0x1b, 0xc1, 0x01, 0xdc, 0xc4, 0x00,
- 0xdc, 0xc1, 0x00, 0xdc, 0x8f, 0x00, 0x23, 0xb0,
- 0x34, 0xc6, 0x81, 0xc3, 0x00, 0xdc, 0xc0, 0x81,
- 0xc1, 0x80, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xa2,
- 0x00, 0x24, 0x9d, 0xc0, 0x00, 0xdc, 0xc1, 0x00,
- 0xdc, 0xc1, 0x02, 0xdc, 0xc0, 0x01, 0xdc, 0xc0,
- 0x00, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x00, 0xdc,
- 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xc1, 0xb0,
- 0x6f, 0xc6, 0x00, 0xdc, 0xc0, 0x88, 0x00, 0xdc,
- 0x97, 0xc3, 0x80, 0xc8, 0x80, 0xc2, 0x80, 0xc4,
- 0xaa, 0x02, 0xdc, 0xb0, 0x0a, 0xc1, 0x02, 0xdc,
- 0xc3, 0xa9, 0xc4, 0x04, 0xdc, 0xcd, 0x80, 0x00,
- 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xc2,
- 0x02, 0xdc, 0x42, 0x1b, 0xc2, 0x00, 0xdc, 0xc1,
- 0x01, 0xdc, 0xc4, 0xb0, 0x0b, 0x00, 0x07, 0x8f,
- 0x00, 0x09, 0x82, 0xc0, 0x00, 0xdc, 0xc1, 0xb0,
- 0x36, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xaf, 0xc0,
- 0xb0, 0x0c, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0,
- 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3d,
- 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x4e, 0x00,
- 0x09, 0xb0, 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09,
- 0x86, 0x00, 0x54, 0x00, 0x5b, 0xb0, 0x34, 0x00,
- 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3c, 0x01, 0x09,
- 0x8f, 0x00, 0x09, 0xb0, 0x4b, 0x00, 0x09, 0xb0,
- 0x3c, 0x01, 0x67, 0x00, 0x09, 0x8c, 0x03, 0x6b,
- 0xb0, 0x3b, 0x01, 0x76, 0x00, 0x09, 0x8c, 0x03,
- 0x7a, 0xb0, 0x1b, 0x01, 0xdc, 0x9a, 0x00, 0xdc,
- 0x80, 0x00, 0xdc, 0x80, 0x00, 0xd8, 0xb0, 0x06,
- 0x41, 0x81, 0x80, 0x00, 0x84, 0x84, 0x03, 0x82,
- 0x81, 0x00, 0x82, 0x80, 0xc1, 0x00, 0x09, 0x80,
- 0xc1, 0xb0, 0x0d, 0x00, 0xdc, 0xb0, 0x3f, 0x00,
- 0x07, 0x80, 0x01, 0x09, 0xb0, 0x21, 0x00, 0xdc,
- 0xb2, 0x9e, 0xc2, 0xb3, 0x83, 0x01, 0x09, 0x9d,
- 0x00, 0x09, 0xb0, 0x6c, 0x00, 0x09, 0x89, 0xc0,
- 0xb0, 0x9a, 0x00, 0xe4, 0xb0, 0x5e, 0x00, 0xde,
- 0xc0, 0x00, 0xdc, 0xb0, 0xaa, 0xc0, 0x00, 0xdc,
- 0xb0, 0x16, 0x00, 0x09, 0x93, 0xc7, 0x81, 0x00,
- 0xdc, 0xaf, 0xc4, 0x05, 0xdc, 0xc1, 0x00, 0xdc,
- 0x80, 0x01, 0xdc, 0xc1, 0x01, 0xdc, 0xc4, 0x00,
- 0xdc, 0xc3, 0xb0, 0x34, 0x00, 0x07, 0x8e, 0x00,
- 0x09, 0xa5, 0xc0, 0x00, 0xdc, 0xc6, 0xb0, 0x05,
- 0x01, 0x09, 0xb0, 0x09, 0x00, 0x07, 0x8a, 0x01,
- 0x09, 0xb0, 0x12, 0x00, 0x07, 0xb0, 0x67, 0xc2,
- 0x41, 0x00, 0x04, 0xdc, 0xc1, 0x03, 0xdc, 0xc0,
- 0x41, 0x00, 0x05, 0x01, 0x83, 0x00, 0xdc, 0x85,
- 0xc0, 0x82, 0xc1, 0xb0, 0x95, 0xc1, 0x00, 0xdc,
- 0xc6, 0x00, 0xdc, 0xc1, 0x00, 0xea, 0x00, 0xd6,
- 0x00, 0xdc, 0x00, 0xca, 0xe4, 0x00, 0xe8, 0x01,
- 0xe4, 0x00, 0xdc, 0x00, 0xda, 0xc0, 0x00, 0xe9,
- 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xb2, 0x9f, 0xc1,
- 0x01, 0x01, 0xc3, 0x02, 0x01, 0xc1, 0x83, 0xc0,
- 0x82, 0x01, 0x01, 0xc0, 0x00, 0xdc, 0xc0, 0x01,
- 0x01, 0x03, 0xdc, 0xc0, 0xb8, 0x03, 0xcd, 0xc2,
- 0xb0, 0x5c, 0x00, 0x09, 0xb0, 0x2f, 0xdf, 0xb1,
- 0xf9, 0x00, 0xda, 0x00, 0xe4, 0x00, 0xe8, 0x00,
- 0xde, 0x01, 0xe0, 0xb0, 0x38, 0x01, 0x08, 0xb8,
- 0x6d, 0xa3, 0xc0, 0x83, 0xc9, 0x9f, 0xc1, 0xb0,
- 0x1f, 0xc1, 0xb0, 0xe3, 0x00, 0x09, 0xa4, 0x00,
- 0x09, 0xb0, 0x66, 0x00, 0x09, 0x9a, 0xd1, 0xb0,
- 0x08, 0x02, 0xdc, 0xa4, 0x00, 0x09, 0xb0, 0x2e,
- 0x00, 0x07, 0x8b, 0x00, 0x09, 0xb0, 0xbe, 0xc0,
- 0x80, 0xc1, 0x00, 0xdc, 0x81, 0xc1, 0x84, 0xc1,
- 0x80, 0xc0, 0xb0, 0x03, 0x00, 0x09, 0xb0, 0xc5,
- 0x00, 0x09, 0xb8, 0x46, 0xff, 0x00, 0x1a, 0xb2,
- 0xd0, 0xc6, 0x06, 0xdc, 0xc1, 0xb3, 0x9c, 0x00,
- 0xdc, 0xb0, 0xb1, 0x00, 0xdc, 0xb0, 0x64, 0xc4,
- 0xb6, 0x61, 0x00, 0xdc, 0x80, 0xc0, 0xa7, 0xc0,
- 0x00, 0x01, 0x00, 0xdc, 0x83, 0x00, 0x09, 0xb0,
- 0x74, 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, 0xb0,
- 0x10, 0xc4, 0xb1, 0x0c, 0xc1, 0xb0, 0x1f, 0x02,
- 0xdc, 0xb0, 0x15, 0x01, 0xdc, 0xc2, 0x00, 0xdc,
- 0xc0, 0x03, 0xdc, 0xb0, 0x00, 0xc0, 0x00, 0xdc,
- 0xc0, 0x00, 0xdc, 0xb0, 0x8f, 0x00, 0x09, 0xa8,
- 0x00, 0x09, 0x8d, 0x00, 0x09, 0xb0, 0x08, 0x00,
- 0x09, 0x00, 0x07, 0xb0, 0x14, 0xc2, 0xaf, 0x01,
- 0x09, 0xb0, 0x0d, 0x00, 0x07, 0xb0, 0x1b, 0x00,
- 0x09, 0x88, 0x00, 0x07, 0xb0, 0x39, 0x00, 0x09,
- 0x00, 0x07, 0xb0, 0x81, 0x00, 0x07, 0x00, 0x09,
- 0xb0, 0x1f, 0x01, 0x07, 0x8f, 0x00, 0x09, 0x97,
- 0xc6, 0x82, 0xc4, 0xb0, 0x28, 0x02, 0x09, 0xb0,
- 0x40, 0x00, 0x09, 0x82, 0x00, 0x07, 0x96, 0xc0,
- 0xb0, 0x32, 0x00, 0x09, 0x00, 0x07, 0xb0, 0xca,
- 0x00, 0x09, 0x00, 0x07, 0xb0, 0x4d, 0x00, 0x09,
- 0xb0, 0x45, 0x00, 0x09, 0x00, 0x07, 0xb0, 0x42,
- 0x00, 0x09, 0xb0, 0xdc, 0x00, 0x09, 0x00, 0x07,
- 0xb0, 0xd1, 0x01, 0x09, 0x83, 0x00, 0x07, 0xb0,
- 0x6b, 0x00, 0x09, 0xb0, 0x22, 0x00, 0x09, 0x91,
- 0x00, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, 0x74,
- 0x00, 0x09, 0xb0, 0xd1, 0x00, 0x07, 0x80, 0x01,
- 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, 0x78, 0x01,
- 0x09, 0xb8, 0x39, 0xbb, 0x00, 0x09, 0xb8, 0x01,
- 0x8f, 0x04, 0x01, 0xb0, 0x0a, 0xc6, 0xb4, 0x88,
- 0x01, 0x06, 0xb8, 0x44, 0x7b, 0x00, 0x01, 0xb8,
- 0x0c, 0x95, 0x01, 0xd8, 0x02, 0x01, 0x82, 0x00,
- 0xe2, 0x04, 0xd8, 0x87, 0x07, 0xdc, 0x81, 0xc4,
- 0x01, 0xdc, 0x9d, 0xc3, 0xb0, 0x63, 0xc2, 0xb8,
- 0x05, 0x8a, 0xc6, 0x80, 0xd0, 0x81, 0xc6, 0x80,
- 0xc1, 0x80, 0xc4, 0xb0, 0x33, 0xc0, 0xb0, 0x6f,
- 0xc6, 0xb1, 0x46, 0xc0, 0xb0, 0x0c, 0xc3, 0xb1,
- 0xcb, 0x01, 0xe8, 0x00, 0xdc, 0xc0, 0xb0, 0xcd,
- 0xc0, 0x00, 0xdc, 0xb2, 0xaf, 0x06, 0xdc, 0xb0,
- 0x3c, 0xc5, 0x00, 0x07,
- };
- static const uint8_t unicode_cc_index[87] = {
- 0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05,
- 0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0x9c,
- 0x08, 0x00, 0x4d, 0x09, 0x00, 0x3c, 0x0b, 0x00,
- 0x3d, 0x0d, 0x00, 0x36, 0x0f, 0x00, 0x38, 0x10,
- 0x20, 0x3a, 0x19, 0x00, 0xcb, 0x1a, 0x20, 0xd3,
- 0x1c, 0x00, 0xcf, 0x1d, 0x00, 0xe2, 0x20, 0x00,
- 0x2e, 0x30, 0x20, 0x2b, 0xa9, 0x20, 0xed, 0xab,
- 0x00, 0x39, 0x0a, 0x01, 0x4c, 0x0f, 0x01, 0x35,
- 0x11, 0x21, 0x66, 0x13, 0x01, 0x40, 0x16, 0x01,
- 0x47, 0x1a, 0x01, 0xf0, 0x6a, 0x21, 0x8a, 0xd1,
- 0x01, 0xec, 0xe4, 0x21, 0x4b, 0xe9, 0x01,
- };
- static const uint32_t unicode_decomp_table1[709] = {
- 0x00280081, 0x002a0097, 0x002a8081, 0x002bc097,
- 0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097,
- 0x002e4115, 0x002f0199, 0x00302016, 0x00400842,
- 0x00448a42, 0x004a0442, 0x004c0096, 0x004c8117,
- 0x004d0242, 0x004e4342, 0x004fc12f, 0x0050c342,
- 0x005240bf, 0x00530342, 0x00550942, 0x005a0842,
- 0x005e0096, 0x005e4342, 0x005fc081, 0x00680142,
- 0x006bc142, 0x00710185, 0x0071c317, 0x00734844,
- 0x00778344, 0x00798342, 0x007b02be, 0x007c4197,
- 0x007d0142, 0x007e0444, 0x00800e42, 0x00878142,
- 0x00898744, 0x00ac0483, 0x00b60317, 0x00b80283,
- 0x00d00214, 0x00d10096, 0x00dd0080, 0x00de8097,
- 0x00df8080, 0x00e10097, 0x00e1413e, 0x00e1c080,
- 0x00e204be, 0x00ea83ae, 0x00f282ae, 0x00f401ad,
- 0x00f4c12e, 0x00f54103, 0x00fc0303, 0x00fe4081,
- 0x0100023e, 0x0101c0be, 0x010301be, 0x010640be,
- 0x010e40be, 0x0114023e, 0x0115c0be, 0x011701be,
- 0x011d8144, 0x01304144, 0x01340244, 0x01358144,
- 0x01368344, 0x01388344, 0x013a8644, 0x013e0144,
- 0x0161c085, 0x018882ae, 0x019d422f, 0x01b00184,
- 0x01b4c084, 0x024a4084, 0x024c4084, 0x024d0084,
- 0x0256042e, 0x0272c12e, 0x02770120, 0x0277c084,
- 0x028cc084, 0x028d8084, 0x029641ae, 0x02978084,
- 0x02d20084, 0x02d2c12e, 0x02d70120, 0x02e50084,
- 0x02f281ae, 0x03120084, 0x03300084, 0x0331c122,
- 0x0332812e, 0x035281ae, 0x03768084, 0x037701ae,
- 0x038cc085, 0x03acc085, 0x03b7012f, 0x03c30081,
- 0x03d0c084, 0x03d34084, 0x03d48084, 0x03d5c084,
- 0x03d70084, 0x03da4084, 0x03dcc084, 0x03dd412e,
- 0x03ddc085, 0x03de0084, 0x03de4085, 0x03e04084,
- 0x03e4c084, 0x03e74084, 0x03e88084, 0x03e9c084,
- 0x03eb0084, 0x03ee4084, 0x04098084, 0x043f0081,
- 0x06c18484, 0x06c48084, 0x06cec184, 0x06d00120,
- 0x06d0c084, 0x074b0383, 0x074cc41f, 0x074f1783,
- 0x075e0081, 0x0766d283, 0x07801d44, 0x078e8942,
- 0x07931844, 0x079f0d42, 0x07a58216, 0x07a68085,
- 0x07a6c0be, 0x07a80d44, 0x07aea044, 0x07c00122,
- 0x07c08344, 0x07c20122, 0x07c28344, 0x07c40122,
- 0x07c48244, 0x07c60122, 0x07c68244, 0x07c8113e,
- 0x07d08244, 0x07d20122, 0x07d28244, 0x07d40122,
- 0x07d48344, 0x07d64c3e, 0x07dc4080, 0x07dc80be,
- 0x07dcc080, 0x07dd00be, 0x07dd4080, 0x07dd80be,
- 0x07ddc080, 0x07de00be, 0x07de4080, 0x07de80be,
- 0x07dec080, 0x07df00be, 0x07df4080, 0x07e00820,
- 0x07e40820, 0x07e80820, 0x07ec05be, 0x07eec080,
- 0x07ef00be, 0x07ef4097, 0x07ef8080, 0x07efc117,
- 0x07f0443e, 0x07f24080, 0x07f280be, 0x07f2c080,
- 0x07f303be, 0x07f4c080, 0x07f582ae, 0x07f6c080,
- 0x07f7433e, 0x07f8c080, 0x07f903ae, 0x07fac080,
- 0x07fb013e, 0x07fb8102, 0x07fc83be, 0x07fe4080,
- 0x07fe80be, 0x07fec080, 0x07ff00be, 0x07ff4080,
- 0x07ff8097, 0x0800011e, 0x08008495, 0x08044081,
- 0x0805c097, 0x08090081, 0x08094097, 0x08098099,
- 0x080bc081, 0x080cc085, 0x080d00b1, 0x080d8085,
- 0x080dc0b1, 0x080f0197, 0x0811c197, 0x0815c0b3,
- 0x0817c081, 0x081c0595, 0x081ec081, 0x081f0215,
- 0x0820051f, 0x08228583, 0x08254415, 0x082a0097,
- 0x08400119, 0x08408081, 0x0840c0bf, 0x08414119,
- 0x0841c081, 0x084240bf, 0x0842852d, 0x08454081,
- 0x08458097, 0x08464295, 0x08480097, 0x08484099,
- 0x08488097, 0x08490081, 0x08498080, 0x084a0081,
- 0x084a8102, 0x084b0495, 0x084d421f, 0x084e4081,
- 0x084ec099, 0x084f0283, 0x08514295, 0x08540119,
- 0x0854809b, 0x0854c619, 0x0857c097, 0x08580081,
- 0x08584097, 0x08588099, 0x0858c097, 0x08590081,
- 0x08594097, 0x08598099, 0x0859c09b, 0x085a0097,
- 0x085a4081, 0x085a8097, 0x085ac099, 0x085b0295,
- 0x085c4097, 0x085c8099, 0x085cc097, 0x085d0081,
- 0x085d4097, 0x085d8099, 0x085dc09b, 0x085e0097,
- 0x085e4081, 0x085e8097, 0x085ec099, 0x085f0215,
- 0x08624099, 0x0866813e, 0x086b80be, 0x087341be,
- 0x088100be, 0x088240be, 0x088300be, 0x088901be,
- 0x088b0085, 0x088b40b1, 0x088bc085, 0x088c00b1,
- 0x089040be, 0x089100be, 0x0891c1be, 0x089801be,
- 0x089b42be, 0x089d0144, 0x089e0144, 0x08a00144,
- 0x08a10144, 0x08a20144, 0x08ab023e, 0x08b80244,
- 0x08ba8220, 0x08ca411e, 0x0918049f, 0x091a4523,
- 0x091cc097, 0x091d04a5, 0x091f452b, 0x0921c09b,
- 0x092204a1, 0x09244525, 0x0926c099, 0x09270d25,
- 0x092d8d1f, 0x09340d1f, 0x093a8081, 0x0a8300b3,
- 0x0a9d0099, 0x0a9d4097, 0x0a9d8099, 0x0ab700be,
- 0x0b1f0115, 0x0b5bc081, 0x0ba7c081, 0x0bbcc081,
- 0x0bc004ad, 0x0bc244ad, 0x0bc484ad, 0x0bc6f383,
- 0x0be0852d, 0x0be31d03, 0x0bf1882d, 0x0c000081,
- 0x0c0d8283, 0x0c130b84, 0x0c194284, 0x0c1c0122,
- 0x0c1cc122, 0x0c1d8122, 0x0c1e4122, 0x0c1f0122,
- 0x0c250084, 0x0c26c123, 0x0c278084, 0x0c27c085,
- 0x0c2b0b84, 0x0c314284, 0x0c340122, 0x0c34c122,
- 0x0c358122, 0x0c364122, 0x0c370122, 0x0c3d0084,
- 0x0c3dc220, 0x0c3f8084, 0x0c3fc085, 0x0c4c4a2d,
- 0x0c51451f, 0x0c53ca9f, 0x0c5915ad, 0x0c648703,
- 0x0c800741, 0x0c838089, 0x0c83c129, 0x0c8441a9,
- 0x0c850089, 0x0c854129, 0x0c85c2a9, 0x0c870089,
- 0x0c87408f, 0x0c87808d, 0x0c881241, 0x0c910203,
- 0x0c940099, 0x0c9444a3, 0x0c968323, 0x0c98072d,
- 0x0c9b84af, 0x0c9dc2a1, 0x0c9f00b5, 0x0c9f40b3,
- 0x0c9f8085, 0x0ca01883, 0x0cac4223, 0x0cad4523,
- 0x0cafc097, 0x0cb004a1, 0x0cb241a5, 0x0cb30097,
- 0x0cb34099, 0x0cb38097, 0x0cb3c099, 0x0cb417ad,
- 0x0cbfc085, 0x0cc001b3, 0x0cc0c0b1, 0x0cc100b3,
- 0x0cc14131, 0x0cc1c0b5, 0x0cc200b3, 0x0cc241b1,
- 0x0cc30133, 0x0cc38131, 0x0cc40085, 0x0cc440b1,
- 0x0cc48133, 0x0cc50085, 0x0cc540b5, 0x0cc580b7,
- 0x0cc5c0b5, 0x0cc600b1, 0x0cc64135, 0x0cc6c0b3,
- 0x0cc701b1, 0x0cc7c0b3, 0x0cc800b5, 0x0cc840b3,
- 0x0cc881b1, 0x0cc9422f, 0x0cca4131, 0x0ccac0b5,
- 0x0ccb00b1, 0x0ccb40b3, 0x0ccb80b5, 0x0ccbc0b1,
- 0x0ccc012f, 0x0ccc80b5, 0x0cccc0b3, 0x0ccd00b5,
- 0x0ccd40b1, 0x0ccd80b5, 0x0ccdc085, 0x0cce02b1,
- 0x0ccf40b3, 0x0ccf80b1, 0x0ccfc085, 0x0cd001b1,
- 0x0cd0c0b3, 0x0cd101b1, 0x0cd1c0b5, 0x0cd200b3,
- 0x0cd24085, 0x0cd280b5, 0x0cd2c085, 0x0cd30133,
- 0x0cd381b1, 0x0cd440b3, 0x0cd48085, 0x0cd4c0b1,
- 0x0cd500b3, 0x0cd54085, 0x0cd580b5, 0x0cd5c0b1,
- 0x0cd60521, 0x0cd88525, 0x0cdb02a5, 0x0cdc4099,
- 0x0cdc8117, 0x0cdd0099, 0x0cdd4197, 0x0cde0127,
- 0x0cde8285, 0x0cdfc089, 0x0ce0043f, 0x0ce20099,
- 0x0ce2409b, 0x0ce283bf, 0x0ce44219, 0x0ce54205,
- 0x0ce6433f, 0x0ce7c131, 0x0ce84085, 0x0ce881b1,
- 0x0ce94085, 0x0ce98107, 0x0cea0089, 0x0cea4097,
- 0x0cea8219, 0x0ceb809d, 0x0cebc08d, 0x0cec083f,
- 0x0cf00105, 0x0cf0809b, 0x0cf0c197, 0x0cf1809b,
- 0x0cf1c099, 0x0cf20517, 0x0cf48099, 0x0cf4c117,
- 0x0cf54119, 0x0cf5c097, 0x0cf6009b, 0x0cf64099,
- 0x0cf68217, 0x0cf78119, 0x0cf804a1, 0x0cfa4525,
- 0x0cfcc525, 0x0cff4125, 0x0cffc099, 0x29a70103,
- 0x29dc0081, 0x29fc8195, 0x29fe0103, 0x2ad70203,
- 0x2ada4081, 0x3e401482, 0x3e4a7f82, 0x3e6a3f82,
- 0x3e8aa102, 0x3e9b0110, 0x3e9c2f82, 0x3eb3c590,
- 0x3ec00197, 0x3ec0c119, 0x3ec1413f, 0x3ec4c2af,
- 0x3ec74184, 0x3ec804ad, 0x3eca4081, 0x3eca8304,
- 0x3ecc03a0, 0x3ece02a0, 0x3ecf8084, 0x3ed00120,
- 0x3ed0c120, 0x3ed184ae, 0x3ed3c085, 0x3ed4312d,
- 0x3ef4cbad, 0x3efa892f, 0x3eff022d, 0x3f002f2f,
- 0x3f1782a5, 0x3f18c0b1, 0x3f1907af, 0x3f1cffaf,
- 0x3f3c81a5, 0x3f3d64af, 0x3f542031, 0x3f649b31,
- 0x3f7c0131, 0x3f7c83b3, 0x3f7e40b1, 0x3f7e80bd,
- 0x3f7ec0bb, 0x3f7f00b3, 0x3f840503, 0x3f8c01ad,
- 0x3f8cc315, 0x3f8e462d, 0x3f91cc03, 0x3f97c695,
- 0x3f9c01af, 0x3f9d0085, 0x3f9d852f, 0x3fa03aad,
- 0x3fbd442f, 0x3fc06f1f, 0x3fd7c11f, 0x3fd85fad,
- 0x3fe80081, 0x3fe84f1f, 0x3ff0831f, 0x3ff2831f,
- 0x3ff4831f, 0x3ff6819f, 0x3ff80783, 0x41724092,
- 0x41790092, 0x41e04d83, 0x41e70f91, 0x44268192,
- 0x442ac092, 0x444b8112, 0x44d2c112, 0x44e0c192,
- 0x44e38092, 0x44e44092, 0x44f14212, 0x452ec212,
- 0x456e8112, 0x464e0092, 0x58484412, 0x5b5a0192,
- 0x73358d1f, 0x733c051f, 0x74578392, 0x746ec312,
- 0x75000d1f, 0x75068d1f, 0x750d0d1f, 0x7513839f,
- 0x7515891f, 0x751a0d1f, 0x75208d1f, 0x75271015,
- 0x752f439f, 0x7531459f, 0x75340d1f, 0x753a8d1f,
- 0x75410395, 0x7543441f, 0x7545839f, 0x75478d1f,
- 0x754e0795, 0x7552839f, 0x75548d1f, 0x755b0d1f,
- 0x75618d1f, 0x75680d1f, 0x756e8d1f, 0x75750d1f,
- 0x757b8d1f, 0x75820d1f, 0x75888d1f, 0x758f0d1f,
- 0x75958d1f, 0x759c0d1f, 0x75a28d1f, 0x75a90103,
- 0x75aa089f, 0x75ae4081, 0x75ae839f, 0x75b04081,
- 0x75b08c9f, 0x75b6c081, 0x75b7032d, 0x75b8889f,
- 0x75bcc081, 0x75bd039f, 0x75bec081, 0x75bf0c9f,
- 0x75c54081, 0x75c5832d, 0x75c7089f, 0x75cb4081,
- 0x75cb839f, 0x75cd4081, 0x75cd8c9f, 0x75d3c081,
- 0x75d4032d, 0x75d5889f, 0x75d9c081, 0x75da039f,
- 0x75dbc081, 0x75dc0c9f, 0x75e24081, 0x75e2832d,
- 0x75e4089f, 0x75e84081, 0x75e8839f, 0x75ea4081,
- 0x75ea8c9f, 0x75f0c081, 0x75f1042d, 0x75f3851f,
- 0x75f6051f, 0x75f8851f, 0x75fb051f, 0x75fd851f,
- 0x780c049f, 0x780e419f, 0x780f059f, 0x7811c203,
- 0x7812d0ad, 0x781b0103, 0x7b80022d, 0x7b814dad,
- 0x7b884203, 0x7b89c081, 0x7b8a452d, 0x7b8d0403,
- 0x7b908081, 0x7b91dc03, 0x7ba0052d, 0x7ba2c8ad,
- 0x7ba84483, 0x7baac8ad, 0x7c400097, 0x7c404521,
- 0x7c440d25, 0x7c4a8087, 0x7c4ac115, 0x7c4b4117,
- 0x7c4c0d1f, 0x7c528217, 0x7c538099, 0x7c53c097,
- 0x7c5a8197, 0x7c640097, 0x7c80012f, 0x7c808081,
- 0x7c841603, 0x7c9004c1, 0x7c940103, 0x7efc051f,
- 0xbe0001ac, 0xbe00d110, 0xbe0947ac, 0xbe0d3910,
- 0xbe29872c, 0xbe2d022c, 0xbe2e3790, 0xbe49ff90,
- 0xbe69bc10,
- };
- static const uint16_t unicode_decomp_table2[709] = {
- 0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008,
- 0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3,
- 0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8,
- 0x0108, 0x010a, 0x0073, 0x0110, 0x0112, 0x0114, 0x0120, 0x012c,
- 0x0144, 0x014d, 0x0153, 0x0162, 0x0168, 0x016a, 0x0176, 0x0192,
- 0x0194, 0x01a9, 0x01bb, 0x01c7, 0x01d1, 0x01d5, 0x02b9, 0x01d7,
- 0x003b, 0x01d9, 0x01db, 0x00b7, 0x01e1, 0x01fc, 0x020c, 0x0218,
- 0x021d, 0x0223, 0x0227, 0x03a3, 0x0233, 0x023f, 0x0242, 0x024b,
- 0x024e, 0x0251, 0x025d, 0x0260, 0x0269, 0x026c, 0x026f, 0x0275,
- 0x0278, 0x0281, 0x028a, 0x029c, 0x029f, 0x02a3, 0x02af, 0x02b9,
- 0x02c5, 0x02c9, 0x02cd, 0x02d1, 0x02d5, 0x02e7, 0x02ed, 0x02f1,
- 0x02f5, 0x02f9, 0x02fd, 0x0305, 0x0309, 0x030d, 0x0313, 0x0317,
- 0x031b, 0x0323, 0x0327, 0x032b, 0x032f, 0x0335, 0x033d, 0x0341,
- 0x0349, 0x034d, 0x0351, 0x0f0b, 0x0357, 0x035b, 0x035f, 0x0363,
- 0x0367, 0x036b, 0x036f, 0x0373, 0x0379, 0x037d, 0x0381, 0x0385,
- 0x0389, 0x038d, 0x0391, 0x0395, 0x0399, 0x039d, 0x03a1, 0x10dc,
- 0x03a5, 0x03c9, 0x03cd, 0x03d9, 0x03dd, 0x03e1, 0x03ef, 0x03f1,
- 0x043d, 0x044f, 0x0499, 0x04f0, 0x0502, 0x054a, 0x0564, 0x056c,
- 0x0570, 0x0573, 0x059a, 0x05fa, 0x05fe, 0x0607, 0x060b, 0x0614,
- 0x0618, 0x061e, 0x0622, 0x0628, 0x068e, 0x0694, 0x0698, 0x069e,
- 0x06a2, 0x06ab, 0x03ac, 0x06f3, 0x03ad, 0x06f6, 0x03ae, 0x06f9,
- 0x03af, 0x06fc, 0x03cc, 0x06ff, 0x03cd, 0x0702, 0x03ce, 0x0705,
- 0x0709, 0x070d, 0x0711, 0x0386, 0x0732, 0x0735, 0x03b9, 0x0737,
- 0x073b, 0x0388, 0x0753, 0x0389, 0x0756, 0x0390, 0x076b, 0x038a,
- 0x0777, 0x03b0, 0x0789, 0x038e, 0x0799, 0x079f, 0x07a3, 0x038c,
- 0x07b8, 0x038f, 0x07bb, 0x00b4, 0x07be, 0x07c0, 0x07c2, 0x2010,
- 0x07cb, 0x002e, 0x07cd, 0x07cf, 0x0020, 0x07d2, 0x07d6, 0x07db,
- 0x07df, 0x07e4, 0x07ea, 0x07f0, 0x0020, 0x07f6, 0x2212, 0x0801,
- 0x0805, 0x0807, 0x081d, 0x0825, 0x0827, 0x0043, 0x082d, 0x0830,
- 0x0190, 0x0836, 0x0839, 0x004e, 0x0845, 0x0847, 0x084c, 0x084e,
- 0x0851, 0x005a, 0x03a9, 0x005a, 0x0853, 0x0857, 0x0860, 0x0069,
- 0x0862, 0x0865, 0x086f, 0x0874, 0x087a, 0x087e, 0x08a2, 0x0049,
- 0x08a4, 0x08a6, 0x08a9, 0x0056, 0x08ab, 0x08ad, 0x08b0, 0x08b4,
- 0x0058, 0x08b6, 0x08b8, 0x08bb, 0x08c0, 0x08c2, 0x08c5, 0x0076,
- 0x08c7, 0x08c9, 0x08cc, 0x08d0, 0x0078, 0x08d2, 0x08d4, 0x08d7,
- 0x08db, 0x08de, 0x08e4, 0x08e7, 0x08f0, 0x08f3, 0x08f6, 0x08f9,
- 0x0902, 0x0906, 0x090b, 0x090f, 0x0914, 0x0917, 0x091a, 0x0923,
- 0x092c, 0x093b, 0x093e, 0x0941, 0x0944, 0x0947, 0x094a, 0x0956,
- 0x095c, 0x0960, 0x0962, 0x0964, 0x0968, 0x096a, 0x0970, 0x0978,
- 0x097c, 0x0980, 0x0986, 0x0989, 0x098f, 0x0991, 0x0030, 0x0993,
- 0x0999, 0x099c, 0x099e, 0x09a1, 0x09a4, 0x2d61, 0x6bcd, 0x9f9f,
- 0x09a6, 0x09b1, 0x09bc, 0x09c7, 0x0a95, 0x0aa1, 0x0b15, 0x0020,
- 0x0b27, 0x0b31, 0x0b8d, 0x0ba1, 0x0ba5, 0x0ba9, 0x0bad, 0x0bb1,
- 0x0bb5, 0x0bb9, 0x0bbd, 0x0bc1, 0x0bc5, 0x0c21, 0x0c35, 0x0c39,
- 0x0c3d, 0x0c41, 0x0c45, 0x0c49, 0x0c4d, 0x0c51, 0x0c55, 0x0c59,
- 0x0c6f, 0x0c71, 0x0c73, 0x0ca0, 0x0cbc, 0x0cdc, 0x0ce4, 0x0cec,
- 0x0cf4, 0x0cfc, 0x0d04, 0x0d0c, 0x0d14, 0x0d22, 0x0d2e, 0x0d7a,
- 0x0d82, 0x0d85, 0x0d89, 0x0d8d, 0x0d9d, 0x0db1, 0x0db5, 0x0dbc,
- 0x0dc2, 0x0dc6, 0x0e28, 0x0e2c, 0x0e30, 0x0e32, 0x0e36, 0x0e3c,
- 0x0e3e, 0x0e41, 0x0e43, 0x0e46, 0x0e77, 0x0e7b, 0x0e89, 0x0e8e,
- 0x0e94, 0x0e9c, 0x0ea3, 0x0ea9, 0x0eb4, 0x0ebe, 0x0ec6, 0x0eca,
- 0x0ecf, 0x0ed9, 0x0edd, 0x0ee4, 0x0eec, 0x0ef3, 0x0ef8, 0x0f04,
- 0x0f0a, 0x0f15, 0x0f1b, 0x0f22, 0x0f28, 0x0f33, 0x0f3d, 0x0f45,
- 0x0f4c, 0x0f51, 0x0f57, 0x0f5e, 0x0f63, 0x0f69, 0x0f70, 0x0f76,
- 0x0f7d, 0x0f82, 0x0f89, 0x0f8d, 0x0f9e, 0x0fa4, 0x0fa9, 0x0fad,
- 0x0fb8, 0x0fbe, 0x0fc9, 0x0fd0, 0x0fd6, 0x0fda, 0x0fe1, 0x0fe5,
- 0x0fef, 0x0ffa, 0x1000, 0x1004, 0x1009, 0x100f, 0x1013, 0x101a,
- 0x101f, 0x1023, 0x1029, 0x102f, 0x1032, 0x1036, 0x1039, 0x103f,
- 0x1045, 0x1059, 0x1061, 0x1079, 0x107c, 0x1080, 0x1095, 0x10a1,
- 0x10b1, 0x10c3, 0x10cb, 0x10cf, 0x10da, 0x10de, 0x10ea, 0x10f2,
- 0x10f4, 0x1100, 0x1105, 0x1111, 0x1141, 0x1149, 0x114d, 0x1153,
- 0x1157, 0x115a, 0x116e, 0x1171, 0x1175, 0x117b, 0x117d, 0x1181,
- 0x1184, 0x118c, 0x1192, 0x1196, 0x119c, 0x11a2, 0x11a8, 0x11ab,
- 0xa76f, 0x11af, 0x11b2, 0x11b6, 0x028d, 0x11be, 0x1210, 0x130e,
- 0x140c, 0x1490, 0x1495, 0x1553, 0x156c, 0x1572, 0x1578, 0x157e,
- 0x158a, 0x1596, 0x002b, 0x15a1, 0x15b9, 0x15bd, 0x15c1, 0x15c5,
- 0x15c9, 0x15cd, 0x15e1, 0x15e5, 0x1649, 0x1662, 0x1688, 0x168e,
- 0x174c, 0x1752, 0x1757, 0x1777, 0x1877, 0x187d, 0x1911, 0x19d3,
- 0x1a77, 0x1a7f, 0x1a9d, 0x1aa2, 0x1ab6, 0x1ac0, 0x1ac6, 0x1ada,
- 0x1adf, 0x1ae5, 0x1af3, 0x1b23, 0x1b30, 0x1b38, 0x1b3c, 0x1b52,
- 0x1bc9, 0x1bdb, 0x1bdd, 0x1bdf, 0x3164, 0x1c20, 0x1c22, 0x1c24,
- 0x1c26, 0x1c28, 0x1c2a, 0x1c48, 0x1c4d, 0x1c52, 0x1c88, 0x1cce,
- 0x1cdc, 0x1ce1, 0x1cea, 0x1cf3, 0x1d01, 0x1d06, 0x1d0b, 0x1d1d,
- 0x1d2f, 0x1d38, 0x1d3d, 0x1d61, 0x1d6f, 0x1d71, 0x1d73, 0x1d93,
- 0x1dae, 0x1db0, 0x1db2, 0x1db4, 0x1db6, 0x1db8, 0x1dba, 0x1dbc,
- 0x1ddc, 0x1dde, 0x1de0, 0x1de2, 0x1de4, 0x1deb, 0x1ded, 0x1def,
- 0x1df1, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a, 0x1e0c,
- 0x1e0e, 0x1e10, 0x1e12, 0x1e14, 0x1e16, 0x1e18, 0x1e1a, 0x1e1c,
- 0x1e20, 0x03f4, 0x1e22, 0x2207, 0x1e24, 0x2202, 0x1e26, 0x1e2e,
- 0x03f4, 0x1e30, 0x2207, 0x1e32, 0x2202, 0x1e34, 0x1e3c, 0x03f4,
- 0x1e3e, 0x2207, 0x1e40, 0x2202, 0x1e42, 0x1e4a, 0x03f4, 0x1e4c,
- 0x2207, 0x1e4e, 0x2202, 0x1e50, 0x1e58, 0x03f4, 0x1e5a, 0x2207,
- 0x1e5c, 0x2202, 0x1e5e, 0x1e68, 0x1e6a, 0x1e6c, 0x1e6e, 0x1e70,
- 0x1e72, 0x1e74, 0x1e76, 0x1e78, 0x1e80, 0x1ea3, 0x1ea7, 0x1ead,
- 0x1eca, 0x062d, 0x1ed2, 0x1ede, 0x062c, 0x1eee, 0x1f5e, 0x1f6a,
- 0x1f7d, 0x1f8f, 0x1fa2, 0x1fa4, 0x1fa8, 0x1fae, 0x1fb4, 0x1fb6,
- 0x1fba, 0x1fbc, 0x1fc4, 0x1fc7, 0x1fc9, 0x1fcf, 0x1fd1, 0x30b5,
- 0x1fd7, 0x202f, 0x2045, 0x2049, 0x204b, 0x2050, 0x209d, 0x20ae,
- 0x21af, 0x21bf, 0x21c5, 0x22bf, 0x23dd,
- };
- static const uint8_t unicode_decomp_data[9451] = {
- 0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81,
- 0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31,
- 0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41,
- 0x81, 0x41, 0x82, 0x41, 0x83, 0x41, 0x88, 0x41,
- 0x8a, 0x00, 0x00, 0x43, 0xa7, 0x45, 0x80, 0x45,
- 0x81, 0x45, 0x82, 0x45, 0x88, 0x49, 0x80, 0x49,
- 0x81, 0x49, 0x82, 0x49, 0x88, 0x00, 0x00, 0x4e,
- 0x83, 0x4f, 0x80, 0x4f, 0x81, 0x4f, 0x82, 0x4f,
- 0x83, 0x4f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x55,
- 0x80, 0x55, 0x81, 0x55, 0x82, 0x55, 0x88, 0x59,
- 0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x80, 0x61,
- 0x81, 0x61, 0x82, 0x61, 0x83, 0x61, 0x88, 0x61,
- 0x8a, 0x00, 0x00, 0x63, 0xa7, 0x65, 0x80, 0x65,
- 0x81, 0x65, 0x82, 0x65, 0x88, 0x69, 0x80, 0x69,
- 0x81, 0x69, 0x82, 0x69, 0x88, 0x00, 0x00, 0x6e,
- 0x83, 0x6f, 0x80, 0x6f, 0x81, 0x6f, 0x82, 0x6f,
- 0x83, 0x6f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x75,
- 0x80, 0x75, 0x81, 0x75, 0x82, 0x75, 0x88, 0x79,
- 0x81, 0x00, 0x00, 0x79, 0x88, 0x41, 0x84, 0x41,
- 0x86, 0x41, 0xa8, 0x43, 0x81, 0x43, 0x82, 0x43,
- 0x87, 0x43, 0x8c, 0x44, 0x8c, 0x45, 0x84, 0x45,
- 0x86, 0x45, 0x87, 0x45, 0xa8, 0x45, 0x8c, 0x47,
- 0x82, 0x47, 0x86, 0x47, 0x87, 0x47, 0xa7, 0x48,
- 0x82, 0x49, 0x83, 0x49, 0x84, 0x49, 0x86, 0x49,
- 0xa8, 0x49, 0x87, 0x49, 0x4a, 0x69, 0x6a, 0x4a,
- 0x82, 0x4b, 0xa7, 0x4c, 0x81, 0x4c, 0xa7, 0x4c,
- 0x8c, 0x4c, 0x00, 0x00, 0x6b, 0x20, 0x6b, 0x4e,
- 0x81, 0x4e, 0xa7, 0x4e, 0x8c, 0xbc, 0x02, 0x6e,
- 0x4f, 0x84, 0x4f, 0x86, 0x4f, 0x8b, 0x52, 0x81,
- 0x52, 0xa7, 0x52, 0x8c, 0x53, 0x81, 0x53, 0x82,
- 0x53, 0xa7, 0x53, 0x8c, 0x54, 0xa7, 0x54, 0x8c,
- 0x55, 0x83, 0x55, 0x84, 0x55, 0x86, 0x55, 0x8a,
- 0x55, 0x8b, 0x55, 0xa8, 0x57, 0x82, 0x59, 0x82,
- 0x59, 0x88, 0x5a, 0x81, 0x5a, 0x87, 0x5a, 0x8c,
- 0x4f, 0x9b, 0x55, 0x9b, 0x44, 0x00, 0x7d, 0x01,
- 0x44, 0x00, 0x7e, 0x01, 0x64, 0x00, 0x7e, 0x01,
- 0x4c, 0x4a, 0x4c, 0x6a, 0x6c, 0x6a, 0x4e, 0x4a,
- 0x4e, 0x6a, 0x6e, 0x6a, 0x41, 0x00, 0x8c, 0x49,
- 0x00, 0x8c, 0x4f, 0x00, 0x8c, 0x55, 0x00, 0x8c,
- 0xdc, 0x00, 0x84, 0xdc, 0x00, 0x81, 0xdc, 0x00,
- 0x8c, 0xdc, 0x00, 0x80, 0xc4, 0x00, 0x84, 0x26,
- 0x02, 0x84, 0xc6, 0x00, 0x84, 0x47, 0x8c, 0x4b,
- 0x8c, 0x4f, 0xa8, 0xea, 0x01, 0x84, 0xeb, 0x01,
- 0x84, 0xb7, 0x01, 0x8c, 0x92, 0x02, 0x8c, 0x6a,
- 0x00, 0x8c, 0x44, 0x5a, 0x44, 0x7a, 0x64, 0x7a,
- 0x47, 0x81, 0x4e, 0x00, 0x80, 0xc5, 0x00, 0x81,
- 0xc6, 0x00, 0x81, 0xd8, 0x00, 0x81, 0x41, 0x8f,
- 0x41, 0x91, 0x45, 0x8f, 0x45, 0x91, 0x49, 0x8f,
- 0x49, 0x91, 0x4f, 0x8f, 0x4f, 0x91, 0x52, 0x8f,
- 0x52, 0x91, 0x55, 0x8f, 0x55, 0x91, 0x53, 0xa6,
- 0x54, 0xa6, 0x48, 0x8c, 0x41, 0x00, 0x87, 0x45,
- 0x00, 0xa7, 0xd6, 0x00, 0x84, 0xd5, 0x00, 0x84,
- 0x4f, 0x00, 0x87, 0x2e, 0x02, 0x84, 0x59, 0x00,
- 0x84, 0x68, 0x00, 0x66, 0x02, 0x6a, 0x00, 0x72,
- 0x00, 0x79, 0x02, 0x7b, 0x02, 0x81, 0x02, 0x77,
- 0x00, 0x79, 0x00, 0x20, 0x86, 0x20, 0x87, 0x20,
- 0x8a, 0x20, 0xa8, 0x20, 0x83, 0x20, 0x8b, 0x63,
- 0x02, 0x6c, 0x00, 0x73, 0x00, 0x78, 0x00, 0x95,
- 0x02, 0x80, 0x81, 0x00, 0x93, 0x88, 0x81, 0x20,
- 0xc5, 0x20, 0x81, 0xa8, 0x00, 0x81, 0x91, 0x03,
- 0x81, 0x95, 0x03, 0x81, 0x97, 0x03, 0x81, 0x99,
- 0x03, 0x81, 0x00, 0x00, 0x00, 0x9f, 0x03, 0x81,
- 0x00, 0x00, 0x00, 0xa5, 0x03, 0x81, 0xa9, 0x03,
- 0x81, 0xca, 0x03, 0x81, 0x01, 0x03, 0x98, 0x07,
- 0xa4, 0x07, 0xb0, 0x00, 0xb4, 0x00, 0xb6, 0x00,
- 0xb8, 0x00, 0xca, 0x00, 0x01, 0x03, 0xb8, 0x07,
- 0xc4, 0x07, 0xbe, 0x00, 0xc4, 0x00, 0xc8, 0x00,
- 0xa5, 0x03, 0x0d, 0x13, 0x00, 0x01, 0x03, 0xd1,
- 0x00, 0xd1, 0x07, 0xc6, 0x03, 0xc0, 0x03, 0xba,
- 0x03, 0xc1, 0x03, 0xc2, 0x03, 0x00, 0x00, 0x98,
- 0x03, 0xb5, 0x03, 0x15, 0x04, 0x80, 0x15, 0x04,
- 0x88, 0x00, 0x00, 0x00, 0x13, 0x04, 0x81, 0x06,
- 0x04, 0x88, 0x1a, 0x04, 0x81, 0x18, 0x04, 0x80,
- 0x23, 0x04, 0x86, 0x18, 0x04, 0x86, 0x38, 0x04,
- 0x86, 0x35, 0x04, 0x80, 0x35, 0x04, 0x88, 0x00,
- 0x00, 0x00, 0x33, 0x04, 0x81, 0x56, 0x04, 0x88,
- 0x3a, 0x04, 0x81, 0x38, 0x04, 0x80, 0x43, 0x04,
- 0x86, 0x74, 0x04, 0x8f, 0x16, 0x04, 0x86, 0x10,
- 0x04, 0x86, 0x10, 0x04, 0x88, 0x15, 0x04, 0x86,
- 0xd8, 0x04, 0x88, 0x16, 0x04, 0x88, 0x17, 0x04,
- 0x88, 0x18, 0x04, 0x84, 0x18, 0x04, 0x88, 0x1e,
- 0x04, 0x88, 0xe8, 0x04, 0x88, 0x2d, 0x04, 0x88,
- 0x23, 0x04, 0x84, 0x23, 0x04, 0x88, 0x23, 0x04,
- 0x8b, 0x27, 0x04, 0x88, 0x2b, 0x04, 0x88, 0x65,
- 0x05, 0x82, 0x05, 0x27, 0x06, 0x00, 0x2c, 0x00,
- 0x2d, 0x21, 0x2d, 0x00, 0x2e, 0x23, 0x2d, 0x27,
- 0x06, 0x00, 0x4d, 0x21, 0x4d, 0xa0, 0x4d, 0x23,
- 0x4d, 0xd5, 0x06, 0x54, 0x06, 0x00, 0x00, 0x00,
- 0x00, 0xc1, 0x06, 0x54, 0x06, 0xd2, 0x06, 0x54,
- 0x06, 0x28, 0x09, 0x3c, 0x09, 0x30, 0x09, 0x3c,
- 0x09, 0x33, 0x09, 0x3c, 0x09, 0x15, 0x09, 0x00,
- 0x27, 0x01, 0x27, 0x02, 0x27, 0x07, 0x27, 0x0c,
- 0x27, 0x0d, 0x27, 0x16, 0x27, 0x1a, 0x27, 0xbe,
- 0x09, 0x09, 0x00, 0x09, 0x19, 0xa1, 0x09, 0xbc,
- 0x09, 0xaf, 0x09, 0xbc, 0x09, 0x32, 0x0a, 0x3c,
- 0x0a, 0x38, 0x0a, 0x3c, 0x0a, 0x16, 0x0a, 0x00,
- 0x26, 0x01, 0x26, 0x06, 0x26, 0x2b, 0x0a, 0x3c,
- 0x0a, 0x47, 0x0b, 0x56, 0x0b, 0x3e, 0x0b, 0x09,
- 0x00, 0x09, 0x19, 0x21, 0x0b, 0x3c, 0x0b, 0x92,
- 0x0b, 0xd7, 0x0b, 0xbe, 0x0b, 0x08, 0x00, 0x09,
- 0x00, 0x08, 0x19, 0x46, 0x0c, 0x56, 0x0c, 0xbf,
- 0x0c, 0xd5, 0x0c, 0xc6, 0x0c, 0xd5, 0x0c, 0xc2,
- 0x0c, 0x04, 0x00, 0x08, 0x13, 0x3e, 0x0d, 0x08,
- 0x00, 0x09, 0x00, 0x08, 0x19, 0xd9, 0x0d, 0xca,
- 0x0d, 0xca, 0x0d, 0x0f, 0x05, 0x12, 0x00, 0x0f,
- 0x15, 0x4d, 0x0e, 0x32, 0x0e, 0xcd, 0x0e, 0xb2,
- 0x0e, 0x99, 0x0e, 0x12, 0x00, 0x12, 0x08, 0x42,
- 0x0f, 0xb7, 0x0f, 0x4c, 0x0f, 0xb7, 0x0f, 0x51,
- 0x0f, 0xb7, 0x0f, 0x56, 0x0f, 0xb7, 0x0f, 0x5b,
- 0x0f, 0xb7, 0x0f, 0x40, 0x0f, 0xb5, 0x0f, 0x71,
- 0x0f, 0x72, 0x0f, 0x71, 0x0f, 0x00, 0x03, 0x41,
- 0x0f, 0xb2, 0x0f, 0x81, 0x0f, 0xb3, 0x0f, 0x80,
- 0x0f, 0xb3, 0x0f, 0x81, 0x0f, 0x71, 0x0f, 0x80,
- 0x0f, 0x92, 0x0f, 0xb7, 0x0f, 0x9c, 0x0f, 0xb7,
- 0x0f, 0xa1, 0x0f, 0xb7, 0x0f, 0xa6, 0x0f, 0xb7,
- 0x0f, 0xab, 0x0f, 0xb7, 0x0f, 0x90, 0x0f, 0xb5,
- 0x0f, 0x25, 0x10, 0x2e, 0x10, 0x05, 0x1b, 0x35,
- 0x1b, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1b, 0x35,
- 0x1b, 0x00, 0x00, 0x00, 0x00, 0x09, 0x1b, 0x35,
- 0x1b, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0x35,
- 0x1b, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x1b, 0x35,
- 0x1b, 0x11, 0x1b, 0x35, 0x1b, 0x3a, 0x1b, 0x35,
- 0x1b, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1b, 0x35,
- 0x1b, 0x3e, 0x1b, 0x35, 0x1b, 0x42, 0x1b, 0x35,
- 0x1b, 0x41, 0x00, 0xc6, 0x00, 0x42, 0x00, 0x00,
- 0x00, 0x44, 0x00, 0x45, 0x00, 0x8e, 0x01, 0x47,
- 0x00, 0x4f, 0x00, 0x22, 0x02, 0x50, 0x00, 0x52,
- 0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x61,
- 0x00, 0x50, 0x02, 0x51, 0x02, 0x02, 0x1d, 0x62,
- 0x00, 0x64, 0x00, 0x65, 0x00, 0x59, 0x02, 0x5b,
- 0x02, 0x5c, 0x02, 0x67, 0x00, 0x00, 0x00, 0x6b,
- 0x00, 0x6d, 0x00, 0x4b, 0x01, 0x6f, 0x00, 0x54,
- 0x02, 0x16, 0x1d, 0x17, 0x1d, 0x70, 0x00, 0x74,
- 0x00, 0x75, 0x00, 0x1d, 0x1d, 0x6f, 0x02, 0x76,
- 0x00, 0x25, 0x1d, 0xb2, 0x03, 0xb3, 0x03, 0xb4,
- 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x69, 0x00, 0x72,
- 0x00, 0x75, 0x00, 0x76, 0x00, 0xb2, 0x03, 0xb3,
- 0x03, 0xc1, 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x52,
- 0x02, 0x63, 0x00, 0x55, 0x02, 0xf0, 0x00, 0x5c,
- 0x02, 0x66, 0x00, 0x5f, 0x02, 0x61, 0x02, 0x65,
- 0x02, 0x68, 0x02, 0x69, 0x02, 0x6a, 0x02, 0x7b,
- 0x1d, 0x9d, 0x02, 0x6d, 0x02, 0x85, 0x1d, 0x9f,
- 0x02, 0x71, 0x02, 0x70, 0x02, 0x72, 0x02, 0x73,
- 0x02, 0x74, 0x02, 0x75, 0x02, 0x78, 0x02, 0x82,
- 0x02, 0x83, 0x02, 0xab, 0x01, 0x89, 0x02, 0x8a,
- 0x02, 0x1c, 0x1d, 0x8b, 0x02, 0x8c, 0x02, 0x7a,
- 0x00, 0x90, 0x02, 0x91, 0x02, 0x92, 0x02, 0xb8,
- 0x03, 0x41, 0x00, 0xa5, 0x42, 0x00, 0x87, 0x42,
- 0x00, 0xa3, 0x42, 0x00, 0xb1, 0xc7, 0x00, 0x81,
- 0x44, 0x00, 0x87, 0x44, 0x00, 0xa3, 0x44, 0x00,
- 0xb1, 0x44, 0x00, 0xa7, 0x44, 0x00, 0xad, 0x12,
- 0x01, 0x80, 0x12, 0x01, 0x81, 0x45, 0x00, 0xad,
- 0x45, 0x00, 0xb0, 0x28, 0x02, 0x86, 0x46, 0x00,
- 0x87, 0x47, 0x00, 0x84, 0x48, 0x00, 0x87, 0x48,
- 0x00, 0xa3, 0x48, 0x00, 0x88, 0x48, 0x00, 0xa7,
- 0x48, 0x00, 0xae, 0x49, 0x00, 0xb0, 0xcf, 0x00,
- 0x81, 0x4b, 0x00, 0x81, 0x4b, 0x00, 0xa3, 0x4b,
- 0x00, 0xb1, 0x4c, 0x00, 0xa3, 0x36, 0x1e, 0x84,
- 0x4c, 0xb1, 0x4c, 0xad, 0x4d, 0x81, 0x4d, 0x87,
- 0x4d, 0xa3, 0x4e, 0x87, 0x4e, 0xa3, 0x4e, 0xb1,
- 0x4e, 0xad, 0xd5, 0x00, 0x81, 0xd5, 0x00, 0x88,
- 0x4c, 0x01, 0x80, 0x4c, 0x01, 0x81, 0x50, 0x00,
- 0x81, 0x50, 0x00, 0x87, 0x52, 0x00, 0x87, 0x52,
- 0x00, 0xa3, 0x5a, 0x1e, 0x84, 0x52, 0x00, 0xb1,
- 0x53, 0x00, 0x87, 0x53, 0x00, 0xa3, 0x5a, 0x01,
- 0x87, 0x60, 0x01, 0x87, 0x62, 0x1e, 0x87, 0x54,
- 0x00, 0x87, 0x54, 0x00, 0xa3, 0x54, 0x00, 0xb1,
- 0x54, 0x00, 0xad, 0x55, 0x00, 0xa4, 0x55, 0x00,
- 0xb0, 0x55, 0x00, 0xad, 0x68, 0x01, 0x81, 0x6a,
- 0x01, 0x88, 0x56, 0x83, 0x56, 0xa3, 0x57, 0x80,
- 0x57, 0x81, 0x57, 0x88, 0x57, 0x87, 0x57, 0xa3,
- 0x58, 0x87, 0x58, 0x88, 0x59, 0x87, 0x5a, 0x82,
- 0x5a, 0xa3, 0x5a, 0xb1, 0x68, 0xb1, 0x74, 0x88,
- 0x77, 0x8a, 0x79, 0x8a, 0x61, 0x00, 0xbe, 0x02,
- 0x7f, 0x01, 0x87, 0x41, 0x00, 0xa3, 0x41, 0x00,
- 0x89, 0xc2, 0x00, 0x81, 0xc2, 0x00, 0x80, 0xc2,
- 0x00, 0x89, 0xc2, 0x00, 0x83, 0xa0, 0x1e, 0x82,
- 0x02, 0x01, 0x81, 0x02, 0x01, 0x80, 0x02, 0x01,
- 0x89, 0x02, 0x01, 0x83, 0xa0, 0x1e, 0x86, 0x45,
- 0x00, 0xa3, 0x45, 0x00, 0x89, 0x45, 0x00, 0x83,
- 0xca, 0x00, 0x81, 0xca, 0x00, 0x80, 0xca, 0x00,
- 0x89, 0xca, 0x00, 0x83, 0xb8, 0x1e, 0x82, 0x49,
- 0x00, 0x89, 0x49, 0x00, 0xa3, 0x4f, 0x00, 0xa3,
- 0x4f, 0x00, 0x89, 0xd4, 0x00, 0x81, 0xd4, 0x00,
- 0x80, 0xd4, 0x00, 0x89, 0xd4, 0x00, 0x83, 0xcc,
- 0x1e, 0x82, 0xa0, 0x01, 0x81, 0xa0, 0x01, 0x80,
- 0xa0, 0x01, 0x89, 0xa0, 0x01, 0x83, 0xa0, 0x01,
- 0xa3, 0x55, 0x00, 0xa3, 0x55, 0x00, 0x89, 0xaf,
- 0x01, 0x81, 0xaf, 0x01, 0x80, 0xaf, 0x01, 0x89,
- 0xaf, 0x01, 0x83, 0xaf, 0x01, 0xa3, 0x59, 0x00,
- 0x80, 0x59, 0x00, 0xa3, 0x59, 0x00, 0x89, 0x59,
- 0x00, 0x83, 0xb1, 0x03, 0x13, 0x03, 0x00, 0x1f,
- 0x80, 0x00, 0x1f, 0x81, 0x00, 0x1f, 0xc2, 0x91,
- 0x03, 0x13, 0x03, 0x08, 0x1f, 0x80, 0x08, 0x1f,
- 0x81, 0x08, 0x1f, 0xc2, 0xb5, 0x03, 0x13, 0x03,
- 0x10, 0x1f, 0x80, 0x10, 0x1f, 0x81, 0x95, 0x03,
- 0x13, 0x03, 0x18, 0x1f, 0x80, 0x18, 0x1f, 0x81,
- 0xb7, 0x03, 0x93, 0xb7, 0x03, 0x94, 0x20, 0x1f,
- 0x80, 0x21, 0x1f, 0x80, 0x20, 0x1f, 0x81, 0x21,
- 0x1f, 0x81, 0x20, 0x1f, 0xc2, 0x21, 0x1f, 0xc2,
- 0x97, 0x03, 0x93, 0x97, 0x03, 0x94, 0x28, 0x1f,
- 0x80, 0x29, 0x1f, 0x80, 0x28, 0x1f, 0x81, 0x29,
- 0x1f, 0x81, 0x28, 0x1f, 0xc2, 0x29, 0x1f, 0xc2,
- 0xb9, 0x03, 0x93, 0xb9, 0x03, 0x94, 0x30, 0x1f,
- 0x80, 0x31, 0x1f, 0x80, 0x30, 0x1f, 0x81, 0x31,
- 0x1f, 0x81, 0x30, 0x1f, 0xc2, 0x31, 0x1f, 0xc2,
- 0x99, 0x03, 0x93, 0x99, 0x03, 0x94, 0x38, 0x1f,
- 0x80, 0x39, 0x1f, 0x80, 0x38, 0x1f, 0x81, 0x39,
- 0x1f, 0x81, 0x38, 0x1f, 0xc2, 0x39, 0x1f, 0xc2,
- 0xbf, 0x03, 0x93, 0xbf, 0x03, 0x94, 0x40, 0x1f,
- 0x80, 0x40, 0x1f, 0x81, 0x9f, 0x03, 0x13, 0x03,
- 0x48, 0x1f, 0x80, 0x48, 0x1f, 0x81, 0xc5, 0x03,
- 0x13, 0x03, 0x50, 0x1f, 0x80, 0x50, 0x1f, 0x81,
- 0x50, 0x1f, 0xc2, 0xa5, 0x03, 0x94, 0x00, 0x00,
- 0x00, 0x59, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x59,
- 0x1f, 0x81, 0x00, 0x00, 0x00, 0x59, 0x1f, 0xc2,
- 0xc9, 0x03, 0x93, 0xc9, 0x03, 0x94, 0x60, 0x1f,
- 0x80, 0x61, 0x1f, 0x80, 0x60, 0x1f, 0x81, 0x61,
- 0x1f, 0x81, 0x60, 0x1f, 0xc2, 0x61, 0x1f, 0xc2,
- 0xa9, 0x03, 0x93, 0xa9, 0x03, 0x94, 0x68, 0x1f,
- 0x80, 0x69, 0x1f, 0x80, 0x68, 0x1f, 0x81, 0x69,
- 0x1f, 0x81, 0x68, 0x1f, 0xc2, 0x69, 0x1f, 0xc2,
- 0xb1, 0x03, 0x80, 0xb5, 0x03, 0x80, 0xb7, 0x03,
- 0x80, 0xb9, 0x03, 0x80, 0xbf, 0x03, 0x80, 0xc5,
- 0x03, 0x80, 0xc9, 0x03, 0x80, 0x00, 0x1f, 0x45,
- 0x03, 0x20, 0x1f, 0x45, 0x03, 0x60, 0x1f, 0x45,
- 0x03, 0xb1, 0x03, 0x86, 0xb1, 0x03, 0x84, 0x70,
- 0x1f, 0xc5, 0xb1, 0x03, 0xc5, 0xac, 0x03, 0xc5,
- 0x00, 0x00, 0x00, 0xb1, 0x03, 0xc2, 0xb6, 0x1f,
- 0xc5, 0x91, 0x03, 0x86, 0x91, 0x03, 0x84, 0x91,
- 0x03, 0x80, 0x91, 0x03, 0xc5, 0x20, 0x93, 0x20,
- 0x93, 0x20, 0xc2, 0xa8, 0x00, 0xc2, 0x74, 0x1f,
- 0xc5, 0xb7, 0x03, 0xc5, 0xae, 0x03, 0xc5, 0x00,
- 0x00, 0x00, 0xb7, 0x03, 0xc2, 0xc6, 0x1f, 0xc5,
- 0x95, 0x03, 0x80, 0x97, 0x03, 0x80, 0x97, 0x03,
- 0xc5, 0xbf, 0x1f, 0x80, 0xbf, 0x1f, 0x81, 0xbf,
- 0x1f, 0xc2, 0xb9, 0x03, 0x86, 0xb9, 0x03, 0x84,
- 0xca, 0x03, 0x80, 0x00, 0x03, 0xb9, 0x42, 0xca,
- 0x42, 0x99, 0x06, 0x99, 0x04, 0x99, 0x00, 0xfe,
- 0x1f, 0x80, 0xfe, 0x1f, 0x81, 0xfe, 0x1f, 0xc2,
- 0xc5, 0x03, 0x86, 0xc5, 0x03, 0x84, 0xcb, 0x03,
- 0x80, 0x00, 0x03, 0xc1, 0x13, 0xc1, 0x14, 0xc5,
- 0x42, 0xcb, 0x42, 0xa5, 0x06, 0xa5, 0x04, 0xa5,
- 0x00, 0xa1, 0x03, 0x94, 0xa8, 0x00, 0x80, 0x85,
- 0x03, 0x60, 0x00, 0x7c, 0x1f, 0xc5, 0xc9, 0x03,
- 0xc5, 0xce, 0x03, 0xc5, 0x00, 0x00, 0x00, 0xc9,
- 0x03, 0xc2, 0xf6, 0x1f, 0xc5, 0x9f, 0x03, 0x80,
- 0xa9, 0x03, 0x80, 0xa9, 0x03, 0xc5, 0x20, 0x94,
- 0x02, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0xb3, 0x2e, 0x2e, 0x2e,
- 0x2e, 0x2e, 0x32, 0x20, 0x32, 0x20, 0x32, 0x20,
- 0x00, 0x00, 0x00, 0x35, 0x20, 0x35, 0x20, 0x35,
- 0x20, 0x00, 0x00, 0x00, 0x21, 0x21, 0x00, 0x00,
- 0x20, 0x85, 0x3f, 0x3f, 0x3f, 0x21, 0x21, 0x3f,
- 0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x30, 0x69,
- 0x00, 0x00, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
- 0x2b, 0x3d, 0x28, 0x29, 0x6e, 0x30, 0x00, 0x2b,
- 0x00, 0x12, 0x22, 0x3d, 0x00, 0x28, 0x00, 0x29,
- 0x00, 0x00, 0x00, 0x61, 0x00, 0x65, 0x00, 0x6f,
- 0x00, 0x78, 0x00, 0x59, 0x02, 0x68, 0x6b, 0x6c,
- 0x6d, 0x6e, 0x70, 0x73, 0x74, 0x52, 0x73, 0x61,
- 0x2f, 0x63, 0x61, 0x2f, 0x73, 0xb0, 0x00, 0x43,
- 0x63, 0x2f, 0x6f, 0x63, 0x2f, 0x75, 0xb0, 0x00,
- 0x46, 0x48, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20,
- 0xdf, 0x01, 0x01, 0x04, 0x24, 0x4e, 0x6f, 0x50,
- 0x51, 0x52, 0x52, 0x52, 0x53, 0x4d, 0x54, 0x45,
- 0x4c, 0x54, 0x4d, 0x4b, 0x00, 0xc5, 0x00, 0x42,
- 0x43, 0x00, 0x65, 0x45, 0x46, 0x00, 0x4d, 0x6f,
- 0xd0, 0x05, 0x46, 0x41, 0x58, 0xc0, 0x03, 0xb3,
- 0x03, 0x93, 0x03, 0xa0, 0x03, 0x11, 0x22, 0x44,
- 0x64, 0x65, 0x69, 0x6a, 0x31, 0xd0, 0x37, 0x31,
- 0xd0, 0x39, 0x31, 0xd0, 0x31, 0x30, 0x31, 0xd0,
- 0x33, 0x32, 0xd0, 0x33, 0x31, 0xd0, 0x35, 0x32,
- 0xd0, 0x35, 0x33, 0xd0, 0x35, 0x34, 0xd0, 0x35,
- 0x31, 0xd0, 0x36, 0x35, 0xd0, 0x36, 0x31, 0xd0,
- 0x38, 0x33, 0xd0, 0x38, 0x35, 0xd0, 0x38, 0x37,
- 0xd0, 0x38, 0x31, 0xd0, 0x49, 0x49, 0x49, 0x49,
- 0x49, 0x49, 0x56, 0x56, 0x49, 0x56, 0x49, 0x49,
- 0x56, 0x49, 0x49, 0x49, 0x49, 0x58, 0x58, 0x49,
- 0x58, 0x49, 0x49, 0x4c, 0x43, 0x44, 0x4d, 0x69,
- 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x76, 0x76,
- 0x69, 0x76, 0x69, 0x69, 0x76, 0x69, 0x69, 0x69,
- 0x69, 0x78, 0x78, 0x69, 0x78, 0x69, 0x69, 0x6c,
- 0x63, 0x64, 0x6d, 0x30, 0xd0, 0x33, 0x90, 0x21,
- 0xb8, 0x92, 0x21, 0xb8, 0x94, 0x21, 0xb8, 0xd0,
- 0x21, 0xb8, 0xd4, 0x21, 0xb8, 0xd2, 0x21, 0xb8,
- 0x03, 0x22, 0xb8, 0x08, 0x22, 0xb8, 0x0b, 0x22,
- 0xb8, 0x23, 0x22, 0xb8, 0x00, 0x00, 0x00, 0x25,
- 0x22, 0xb8, 0x2b, 0x22, 0x2b, 0x22, 0x2b, 0x22,
- 0x00, 0x00, 0x00, 0x2e, 0x22, 0x2e, 0x22, 0x2e,
- 0x22, 0x00, 0x00, 0x00, 0x3c, 0x22, 0xb8, 0x43,
- 0x22, 0xb8, 0x45, 0x22, 0xb8, 0x00, 0x00, 0x00,
- 0x48, 0x22, 0xb8, 0x3d, 0x00, 0xb8, 0x00, 0x00,
- 0x00, 0x61, 0x22, 0xb8, 0x4d, 0x22, 0xb8, 0x3c,
- 0x00, 0xb8, 0x3e, 0x00, 0xb8, 0x64, 0x22, 0xb8,
- 0x65, 0x22, 0xb8, 0x72, 0x22, 0xb8, 0x76, 0x22,
- 0xb8, 0x7a, 0x22, 0xb8, 0x82, 0x22, 0xb8, 0x86,
- 0x22, 0xb8, 0xa2, 0x22, 0xb8, 0xa8, 0x22, 0xb8,
- 0xa9, 0x22, 0xb8, 0xab, 0x22, 0xb8, 0x7c, 0x22,
- 0xb8, 0x91, 0x22, 0xb8, 0xb2, 0x22, 0x38, 0x03,
- 0x08, 0x30, 0x31, 0x00, 0x31, 0x00, 0x30, 0x00,
- 0x32, 0x30, 0x28, 0x00, 0x31, 0x00, 0x29, 0x00,
- 0x28, 0x00, 0x31, 0x00, 0x30, 0x00, 0x29, 0x00,
- 0x28, 0x32, 0x30, 0x29, 0x31, 0x00, 0x2e, 0x00,
- 0x31, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x32, 0x30,
- 0x2e, 0x28, 0x00, 0x61, 0x00, 0x29, 0x00, 0x41,
- 0x00, 0x61, 0x00, 0x2b, 0x22, 0x00, 0x00, 0x00,
- 0x00, 0x3a, 0x3a, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
- 0x3d, 0xdd, 0x2a, 0xb8, 0x6a, 0x56, 0x00, 0x4e,
- 0x00, 0x28, 0x36, 0x3f, 0x59, 0x85, 0x8c, 0xa0,
- 0xba, 0x3f, 0x51, 0x00, 0x26, 0x2c, 0x43, 0x57,
- 0x6c, 0xa1, 0xb6, 0xc1, 0x9b, 0x52, 0x00, 0x5e,
- 0x7a, 0x7f, 0x9d, 0xa6, 0xc1, 0xce, 0xe7, 0xb6,
- 0x53, 0xc8, 0x53, 0xe3, 0x53, 0xd7, 0x56, 0x1f,
- 0x57, 0xeb, 0x58, 0x02, 0x59, 0x0a, 0x59, 0x15,
- 0x59, 0x27, 0x59, 0x73, 0x59, 0x50, 0x5b, 0x80,
- 0x5b, 0xf8, 0x5b, 0x0f, 0x5c, 0x22, 0x5c, 0x38,
- 0x5c, 0x6e, 0x5c, 0x71, 0x5c, 0xdb, 0x5d, 0xe5,
- 0x5d, 0xf1, 0x5d, 0xfe, 0x5d, 0x72, 0x5e, 0x7a,
- 0x5e, 0x7f, 0x5e, 0xf4, 0x5e, 0xfe, 0x5e, 0x0b,
- 0x5f, 0x13, 0x5f, 0x50, 0x5f, 0x61, 0x5f, 0x73,
- 0x5f, 0xc3, 0x5f, 0x08, 0x62, 0x36, 0x62, 0x4b,
- 0x62, 0x2f, 0x65, 0x34, 0x65, 0x87, 0x65, 0x97,
- 0x65, 0xa4, 0x65, 0xb9, 0x65, 0xe0, 0x65, 0xe5,
- 0x65, 0xf0, 0x66, 0x08, 0x67, 0x28, 0x67, 0x20,
- 0x6b, 0x62, 0x6b, 0x79, 0x6b, 0xb3, 0x6b, 0xcb,
- 0x6b, 0xd4, 0x6b, 0xdb, 0x6b, 0x0f, 0x6c, 0x14,
- 0x6c, 0x34, 0x6c, 0x6b, 0x70, 0x2a, 0x72, 0x36,
- 0x72, 0x3b, 0x72, 0x3f, 0x72, 0x47, 0x72, 0x59,
- 0x72, 0x5b, 0x72, 0xac, 0x72, 0x84, 0x73, 0x89,
- 0x73, 0xdc, 0x74, 0xe6, 0x74, 0x18, 0x75, 0x1f,
- 0x75, 0x28, 0x75, 0x30, 0x75, 0x8b, 0x75, 0x92,
- 0x75, 0x76, 0x76, 0x7d, 0x76, 0xae, 0x76, 0xbf,
- 0x76, 0xee, 0x76, 0xdb, 0x77, 0xe2, 0x77, 0xf3,
- 0x77, 0x3a, 0x79, 0xb8, 0x79, 0xbe, 0x79, 0x74,
- 0x7a, 0xcb, 0x7a, 0xf9, 0x7a, 0x73, 0x7c, 0xf8,
- 0x7c, 0x36, 0x7f, 0x51, 0x7f, 0x8a, 0x7f, 0xbd,
- 0x7f, 0x01, 0x80, 0x0c, 0x80, 0x12, 0x80, 0x33,
- 0x80, 0x7f, 0x80, 0x89, 0x80, 0xe3, 0x81, 0x00,
- 0x07, 0x10, 0x19, 0x29, 0x38, 0x3c, 0x8b, 0x8f,
- 0x95, 0x4d, 0x86, 0x6b, 0x86, 0x40, 0x88, 0x4c,
- 0x88, 0x63, 0x88, 0x7e, 0x89, 0x8b, 0x89, 0xd2,
- 0x89, 0x00, 0x8a, 0x37, 0x8c, 0x46, 0x8c, 0x55,
- 0x8c, 0x78, 0x8c, 0x9d, 0x8c, 0x64, 0x8d, 0x70,
- 0x8d, 0xb3, 0x8d, 0xab, 0x8e, 0xca, 0x8e, 0x9b,
- 0x8f, 0xb0, 0x8f, 0xb5, 0x8f, 0x91, 0x90, 0x49,
- 0x91, 0xc6, 0x91, 0xcc, 0x91, 0xd1, 0x91, 0x77,
- 0x95, 0x80, 0x95, 0x1c, 0x96, 0xb6, 0x96, 0xb9,
- 0x96, 0xe8, 0x96, 0x51, 0x97, 0x5e, 0x97, 0x62,
- 0x97, 0x69, 0x97, 0xcb, 0x97, 0xed, 0x97, 0xf3,
- 0x97, 0x01, 0x98, 0xa8, 0x98, 0xdb, 0x98, 0xdf,
- 0x98, 0x96, 0x99, 0x99, 0x99, 0xac, 0x99, 0xa8,
- 0x9a, 0xd8, 0x9a, 0xdf, 0x9a, 0x25, 0x9b, 0x2f,
- 0x9b, 0x32, 0x9b, 0x3c, 0x9b, 0x5a, 0x9b, 0xe5,
- 0x9c, 0x75, 0x9e, 0x7f, 0x9e, 0xa5, 0x9e, 0x00,
- 0x16, 0x1e, 0x28, 0x2c, 0x54, 0x58, 0x69, 0x6e,
- 0x7b, 0x96, 0xa5, 0xad, 0xe8, 0xf7, 0xfb, 0x12,
- 0x30, 0x00, 0x00, 0x41, 0x53, 0x44, 0x53, 0x45,
- 0x53, 0x4b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x4d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x4f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x51, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x53, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x55, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x57, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x59, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x5b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x5d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x5f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x61, 0x30, 0x99, 0x30, 0x64, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0x66, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0x68, 0x30, 0x99,
- 0x30, 0x6f, 0x30, 0x99, 0x30, 0x72, 0x30, 0x99,
- 0x30, 0x75, 0x30, 0x99, 0x30, 0x78, 0x30, 0x99,
- 0x30, 0x7b, 0x30, 0x99, 0x30, 0x46, 0x30, 0x99,
- 0x30, 0x20, 0x00, 0x99, 0x30, 0x9d, 0x30, 0x99,
- 0x30, 0x88, 0x30, 0x8a, 0x30, 0xab, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0xad, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x30, 0x99,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x30, 0x99,
- 0x30, 0xc4, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0xc6, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0xc8, 0x30, 0x99, 0x30, 0xcf, 0x30, 0x99,
- 0x30, 0xd2, 0x30, 0x99, 0x30, 0xd5, 0x30, 0x99,
- 0x30, 0xd8, 0x30, 0x99, 0x30, 0xdb, 0x30, 0x99,
- 0x30, 0xa6, 0x30, 0x99, 0x30, 0xef, 0x30, 0x99,
- 0x30, 0xfd, 0x30, 0x99, 0x30, 0xb3, 0x30, 0xc8,
- 0x30, 0x00, 0x11, 0x00, 0x01, 0xaa, 0x02, 0xac,
- 0xad, 0x03, 0x04, 0x05, 0xb0, 0xb1, 0xb2, 0xb3,
- 0xb4, 0xb5, 0x1a, 0x06, 0x07, 0x08, 0x21, 0x09,
- 0x11, 0x61, 0x11, 0x14, 0x11, 0x4c, 0x00, 0x01,
- 0xb3, 0xb4, 0xb8, 0xba, 0xbf, 0xc3, 0xc5, 0x08,
- 0xc9, 0xcb, 0x09, 0x0a, 0x0c, 0x0e, 0x0f, 0x13,
- 0x15, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x22,
- 0x2c, 0x33, 0x38, 0xdd, 0xde, 0x43, 0x44, 0x45,
- 0x70, 0x71, 0x74, 0x7d, 0x7e, 0x80, 0x8a, 0x8d,
- 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56,
- 0x0a, 0x4e, 0x2d, 0x4e, 0x0b, 0x4e, 0x32, 0x75,
- 0x59, 0x4e, 0x19, 0x4e, 0x01, 0x4e, 0x29, 0x59,
- 0x30, 0x57, 0xba, 0x4e, 0x28, 0x00, 0x29, 0x00,
- 0x00, 0x11, 0x02, 0x11, 0x03, 0x11, 0x05, 0x11,
- 0x06, 0x11, 0x07, 0x11, 0x09, 0x11, 0x0b, 0x11,
- 0x0c, 0x11, 0x0e, 0x11, 0x0f, 0x11, 0x10, 0x11,
- 0x11, 0x11, 0x12, 0x11, 0x28, 0x00, 0x00, 0x11,
- 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x02, 0x11,
- 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x05, 0x11,
- 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x09, 0x11,
- 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11,
- 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0e, 0x11,
- 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0c, 0x11,
- 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11,
- 0x69, 0x11, 0x0c, 0x11, 0x65, 0x11, 0xab, 0x11,
- 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, 0x69, 0x11,
- 0x12, 0x11, 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00,
- 0x29, 0x00, 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e,
- 0xdb, 0x56, 0x94, 0x4e, 0x6d, 0x51, 0x03, 0x4e,
- 0x6b, 0x51, 0x5d, 0x4e, 0x41, 0x53, 0x08, 0x67,
- 0x6b, 0x70, 0x34, 0x6c, 0x28, 0x67, 0xd1, 0x91,
- 0x1f, 0x57, 0xe5, 0x65, 0x2a, 0x68, 0x09, 0x67,
- 0x3e, 0x79, 0x0d, 0x54, 0x79, 0x72, 0xa1, 0x8c,
- 0x5d, 0x79, 0xb4, 0x52, 0xe3, 0x4e, 0x7c, 0x54,
- 0x66, 0x5b, 0xe3, 0x76, 0x01, 0x4f, 0xc7, 0x8c,
- 0x54, 0x53, 0x6d, 0x79, 0x11, 0x4f, 0xea, 0x81,
- 0xf3, 0x81, 0x4f, 0x55, 0x7c, 0x5e, 0x87, 0x65,
- 0x8f, 0x7b, 0x50, 0x54, 0x45, 0x32, 0x00, 0x31,
- 0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x11, 0x00,
- 0x02, 0x03, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x0c,
- 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x00, 0x11, 0x00,
- 0x61, 0x02, 0x61, 0x03, 0x61, 0x05, 0x61, 0x06,
- 0x61, 0x07, 0x61, 0x09, 0x61, 0x0b, 0x61, 0x0c,
- 0x61, 0x0e, 0x11, 0x61, 0x11, 0x00, 0x11, 0x0e,
- 0x61, 0xb7, 0x00, 0x69, 0x0b, 0x11, 0x01, 0x63,
- 0x00, 0x69, 0x0b, 0x11, 0x6e, 0x11, 0x00, 0x4e,
- 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, 0x94, 0x4e,
- 0x6d, 0x51, 0x03, 0x4e, 0x6b, 0x51, 0x5d, 0x4e,
- 0x41, 0x53, 0x08, 0x67, 0x6b, 0x70, 0x34, 0x6c,
- 0x28, 0x67, 0xd1, 0x91, 0x1f, 0x57, 0xe5, 0x65,
- 0x2a, 0x68, 0x09, 0x67, 0x3e, 0x79, 0x0d, 0x54,
- 0x79, 0x72, 0xa1, 0x8c, 0x5d, 0x79, 0xb4, 0x52,
- 0xd8, 0x79, 0x37, 0x75, 0x73, 0x59, 0x69, 0x90,
- 0x2a, 0x51, 0x70, 0x53, 0xe8, 0x6c, 0x05, 0x98,
- 0x11, 0x4f, 0x99, 0x51, 0x63, 0x6b, 0x0a, 0x4e,
- 0x2d, 0x4e, 0x0b, 0x4e, 0xe6, 0x5d, 0xf3, 0x53,
- 0x3b, 0x53, 0x97, 0x5b, 0x66, 0x5b, 0xe3, 0x76,
- 0x01, 0x4f, 0xc7, 0x8c, 0x54, 0x53, 0x1c, 0x59,
- 0x33, 0x00, 0x36, 0x00, 0x34, 0x00, 0x30, 0x00,
- 0x35, 0x30, 0x31, 0x00, 0x08, 0x67, 0x31, 0x00,
- 0x30, 0x00, 0x08, 0x67, 0x48, 0x67, 0x65, 0x72,
- 0x67, 0x65, 0x56, 0x4c, 0x54, 0x44, 0xa2, 0x30,
- 0x00, 0x02, 0x04, 0x06, 0x08, 0x09, 0x0b, 0x0d,
- 0x0f, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d,
- 0x1f, 0x22, 0x24, 0x26, 0x28, 0x29, 0x2a, 0x2b,
- 0x2c, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3d,
- 0x3e, 0x3f, 0x40, 0x42, 0x44, 0x46, 0x47, 0x48,
- 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0xe4,
- 0x4e, 0x8c, 0x54, 0xa1, 0x30, 0x01, 0x30, 0x5b,
- 0x27, 0x01, 0x4a, 0x34, 0x00, 0x01, 0x52, 0x39,
- 0x01, 0xa2, 0x30, 0x00, 0x5a, 0x49, 0xa4, 0x30,
- 0x00, 0x27, 0x4f, 0x0c, 0xa4, 0x30, 0x00, 0x4f,
- 0x1d, 0x02, 0x05, 0x4f, 0xa8, 0x30, 0x00, 0x11,
- 0x07, 0x54, 0x21, 0xa8, 0x30, 0x00, 0x54, 0x03,
- 0x54, 0xa4, 0x30, 0x06, 0x4f, 0x15, 0x06, 0x58,
- 0x3c, 0x07, 0x00, 0x46, 0xab, 0x30, 0x00, 0x3e,
- 0x18, 0x1d, 0x00, 0x42, 0x3f, 0x51, 0xac, 0x30,
- 0x00, 0x41, 0x47, 0x00, 0x47, 0x32, 0xae, 0x30,
- 0xac, 0x30, 0xae, 0x30, 0x00, 0x1d, 0x4e, 0xad,
- 0x30, 0x00, 0x38, 0x3d, 0x4f, 0x01, 0x3e, 0x13,
- 0x4f, 0xad, 0x30, 0xed, 0x30, 0xad, 0x30, 0x00,
- 0x40, 0x03, 0x3c, 0x33, 0xad, 0x30, 0x00, 0x40,
- 0x34, 0x4f, 0x1b, 0x3e, 0xad, 0x30, 0x00, 0x40,
- 0x42, 0x16, 0x1b, 0xb0, 0x30, 0x00, 0x39, 0x30,
- 0xa4, 0x30, 0x0c, 0x45, 0x3c, 0x24, 0x4f, 0x0b,
- 0x47, 0x18, 0x00, 0x49, 0xaf, 0x30, 0x00, 0x3e,
- 0x4d, 0x1e, 0xb1, 0x30, 0x00, 0x4b, 0x08, 0x02,
- 0x3a, 0x19, 0x02, 0x4b, 0x2c, 0xa4, 0x30, 0x11,
- 0x00, 0x0b, 0x47, 0xb5, 0x30, 0x00, 0x3e, 0x0c,
- 0x47, 0x2b, 0xb0, 0x30, 0x07, 0x3a, 0x43, 0x00,
- 0xb9, 0x30, 0x02, 0x3a, 0x08, 0x02, 0x3a, 0x0f,
- 0x07, 0x43, 0x00, 0xb7, 0x30, 0x10, 0x00, 0x12,
- 0x34, 0x11, 0x3c, 0x13, 0x17, 0xa4, 0x30, 0x2a,
- 0x1f, 0x24, 0x2b, 0x00, 0x20, 0xbb, 0x30, 0x16,
- 0x41, 0x00, 0x38, 0x0d, 0xc4, 0x30, 0x0d, 0x38,
- 0x00, 0xd0, 0x30, 0x00, 0x2c, 0x1c, 0x1b, 0xa2,
- 0x30, 0x32, 0x00, 0x17, 0x26, 0x49, 0xaf, 0x30,
- 0x25, 0x00, 0x3c, 0xb3, 0x30, 0x21, 0x00, 0x20,
- 0x38, 0xa1, 0x30, 0x34, 0x00, 0x48, 0x22, 0x28,
- 0xa3, 0x30, 0x32, 0x00, 0x59, 0x25, 0xa7, 0x30,
- 0x2f, 0x1c, 0x10, 0x00, 0x44, 0xd5, 0x30, 0x00,
- 0x14, 0x1e, 0xaf, 0x30, 0x29, 0x00, 0x10, 0x4d,
- 0x3c, 0xda, 0x30, 0xbd, 0x30, 0xb8, 0x30, 0x22,
- 0x13, 0x1a, 0x20, 0x33, 0x0c, 0x22, 0x3b, 0x01,
- 0x22, 0x44, 0x00, 0x21, 0x44, 0x07, 0xa4, 0x30,
- 0x39, 0x00, 0x4f, 0x24, 0xc8, 0x30, 0x14, 0x23,
- 0x00, 0xdb, 0x30, 0xf3, 0x30, 0xc9, 0x30, 0x14,
- 0x2a, 0x00, 0x12, 0x33, 0x22, 0x12, 0x33, 0x2a,
- 0xa4, 0x30, 0x3a, 0x00, 0x0b, 0x49, 0xa4, 0x30,
- 0x3a, 0x00, 0x47, 0x3a, 0x1f, 0x2b, 0x3a, 0x47,
- 0x0b, 0xb7, 0x30, 0x27, 0x3c, 0x00, 0x30, 0x3c,
- 0xaf, 0x30, 0x30, 0x00, 0x3e, 0x44, 0xdf, 0x30,
- 0xea, 0x30, 0xd0, 0x30, 0x0f, 0x1a, 0x00, 0x2c,
- 0x1b, 0xe1, 0x30, 0xac, 0x30, 0xac, 0x30, 0x35,
- 0x00, 0x1c, 0x47, 0x35, 0x50, 0x1c, 0x3f, 0xa2,
- 0x30, 0x42, 0x5a, 0x27, 0x42, 0x5a, 0x49, 0x44,
- 0x00, 0x51, 0xc3, 0x30, 0x27, 0x00, 0x05, 0x28,
- 0xea, 0x30, 0xe9, 0x30, 0xd4, 0x30, 0x17, 0x00,
- 0x28, 0xd6, 0x30, 0x15, 0x26, 0x00, 0x15, 0xec,
- 0x30, 0xe0, 0x30, 0xb2, 0x30, 0x3a, 0x41, 0x16,
- 0x00, 0x41, 0xc3, 0x30, 0x2c, 0x00, 0x05, 0x30,
- 0x00, 0xb9, 0x70, 0x31, 0x00, 0x30, 0x00, 0xb9,
- 0x70, 0x32, 0x00, 0x30, 0x00, 0xb9, 0x70, 0x68,
- 0x50, 0x61, 0x64, 0x61, 0x41, 0x55, 0x62, 0x61,
- 0x72, 0x6f, 0x56, 0x70, 0x63, 0x64, 0x6d, 0x64,
- 0x00, 0x6d, 0x00, 0xb2, 0x00, 0x49, 0x00, 0x55,
- 0x00, 0x73, 0x5e, 0x10, 0x62, 0x2d, 0x66, 0x8c,
- 0x54, 0x27, 0x59, 0x63, 0x6b, 0x0e, 0x66, 0xbb,
- 0x6c, 0x2a, 0x68, 0x0f, 0x5f, 0x1a, 0x4f, 0x3e,
- 0x79, 0x70, 0x00, 0x41, 0x6e, 0x00, 0x41, 0xbc,
- 0x03, 0x41, 0x6d, 0x00, 0x41, 0x6b, 0x00, 0x41,
- 0x4b, 0x00, 0x42, 0x4d, 0x00, 0x42, 0x47, 0x00,
- 0x42, 0x63, 0x61, 0x6c, 0x6b, 0x63, 0x61, 0x6c,
- 0x70, 0x00, 0x46, 0x6e, 0x00, 0x46, 0xbc, 0x03,
- 0x46, 0xbc, 0x03, 0x67, 0x6d, 0x00, 0x67, 0x6b,
- 0x00, 0x67, 0x48, 0x00, 0x7a, 0x6b, 0x48, 0x7a,
- 0x4d, 0x48, 0x7a, 0x47, 0x48, 0x7a, 0x54, 0x48,
- 0x7a, 0xbc, 0x03, 0x13, 0x21, 0x6d, 0x00, 0x13,
- 0x21, 0x64, 0x00, 0x13, 0x21, 0x6b, 0x00, 0x13,
- 0x21, 0x66, 0x00, 0x6d, 0x6e, 0x00, 0x6d, 0xbc,
- 0x03, 0x6d, 0x6d, 0x00, 0x6d, 0x63, 0x00, 0x6d,
- 0x6b, 0x00, 0x6d, 0x63, 0x00, 0x0a, 0x0a, 0x4f,
- 0x00, 0x0a, 0x4f, 0x6d, 0x00, 0xb2, 0x00, 0x63,
- 0x00, 0x08, 0x0a, 0x4f, 0x0a, 0x0a, 0x50, 0x00,
- 0x0a, 0x50, 0x6d, 0x00, 0xb3, 0x00, 0x6b, 0x00,
- 0x6d, 0x00, 0xb3, 0x00, 0x6d, 0x00, 0x15, 0x22,
- 0x73, 0x00, 0x6d, 0x00, 0x15, 0x22, 0x73, 0x00,
- 0xb2, 0x00, 0x50, 0x61, 0x6b, 0x50, 0x61, 0x4d,
- 0x50, 0x61, 0x47, 0x50, 0x61, 0x72, 0x61, 0x64,
- 0x72, 0x61, 0x64, 0xd1, 0x73, 0x72, 0x00, 0x61,
- 0x00, 0x64, 0x00, 0x15, 0x22, 0x73, 0x00, 0xb2,
- 0x00, 0x70, 0x00, 0x73, 0x6e, 0x00, 0x73, 0xbc,
- 0x03, 0x73, 0x6d, 0x00, 0x73, 0x70, 0x00, 0x56,
- 0x6e, 0x00, 0x56, 0xbc, 0x03, 0x56, 0x6d, 0x00,
- 0x56, 0x6b, 0x00, 0x56, 0x4d, 0x00, 0x56, 0x70,
- 0x00, 0x57, 0x6e, 0x00, 0x57, 0xbc, 0x03, 0x57,
- 0x6d, 0x00, 0x57, 0x6b, 0x00, 0x57, 0x4d, 0x00,
- 0x57, 0x6b, 0x00, 0xa9, 0x03, 0x4d, 0x00, 0xa9,
- 0x03, 0x61, 0x2e, 0x6d, 0x2e, 0x42, 0x71, 0x63,
- 0x63, 0x63, 0x64, 0x43, 0xd1, 0x6b, 0x67, 0x43,
- 0x6f, 0x2e, 0x64, 0x42, 0x47, 0x79, 0x68, 0x61,
- 0x48, 0x50, 0x69, 0x6e, 0x4b, 0x4b, 0x4b, 0x4d,
- 0x6b, 0x74, 0x6c, 0x6d, 0x6c, 0x6e, 0x6c, 0x6f,
- 0x67, 0x6c, 0x78, 0x6d, 0x62, 0x6d, 0x69, 0x6c,
- 0x6d, 0x6f, 0x6c, 0x50, 0x48, 0x70, 0x2e, 0x6d,
- 0x2e, 0x50, 0x50, 0x4d, 0x50, 0x52, 0x73, 0x72,
- 0x53, 0x76, 0x57, 0x62, 0x56, 0xd1, 0x6d, 0x41,
- 0xd1, 0x6d, 0x31, 0x00, 0xe5, 0x65, 0x31, 0x00,
- 0x30, 0x00, 0xe5, 0x65, 0x32, 0x00, 0x30, 0x00,
- 0xe5, 0x65, 0x33, 0x00, 0x30, 0x00, 0xe5, 0x65,
- 0x67, 0x61, 0x6c, 0x4a, 0x04, 0x4c, 0x04, 0x43,
- 0x46, 0x51, 0x26, 0x01, 0x53, 0x01, 0x27, 0xa7,
- 0x37, 0xab, 0x6b, 0x02, 0x52, 0xab, 0x48, 0x8c,
- 0xf4, 0x66, 0xca, 0x8e, 0xc8, 0x8c, 0xd1, 0x6e,
- 0x32, 0x4e, 0xe5, 0x53, 0x9c, 0x9f, 0x9c, 0x9f,
- 0x51, 0x59, 0xd1, 0x91, 0x87, 0x55, 0x48, 0x59,
- 0xf6, 0x61, 0x69, 0x76, 0x85, 0x7f, 0x3f, 0x86,
- 0xba, 0x87, 0xf8, 0x88, 0x8f, 0x90, 0x02, 0x6a,
- 0x1b, 0x6d, 0xd9, 0x70, 0xde, 0x73, 0x3d, 0x84,
- 0x6a, 0x91, 0xf1, 0x99, 0x82, 0x4e, 0x75, 0x53,
- 0x04, 0x6b, 0x1b, 0x72, 0x2d, 0x86, 0x1e, 0x9e,
- 0x50, 0x5d, 0xeb, 0x6f, 0xcd, 0x85, 0x64, 0x89,
- 0xc9, 0x62, 0xd8, 0x81, 0x1f, 0x88, 0xca, 0x5e,
- 0x17, 0x67, 0x6a, 0x6d, 0xfc, 0x72, 0xce, 0x90,
- 0x86, 0x4f, 0xb7, 0x51, 0xde, 0x52, 0xc4, 0x64,
- 0xd3, 0x6a, 0x10, 0x72, 0xe7, 0x76, 0x01, 0x80,
- 0x06, 0x86, 0x5c, 0x86, 0xef, 0x8d, 0x32, 0x97,
- 0x6f, 0x9b, 0xfa, 0x9d, 0x8c, 0x78, 0x7f, 0x79,
- 0xa0, 0x7d, 0xc9, 0x83, 0x04, 0x93, 0x7f, 0x9e,
- 0xd6, 0x8a, 0xdf, 0x58, 0x04, 0x5f, 0x60, 0x7c,
- 0x7e, 0x80, 0x62, 0x72, 0xca, 0x78, 0xc2, 0x8c,
- 0xf7, 0x96, 0xd8, 0x58, 0x62, 0x5c, 0x13, 0x6a,
- 0xda, 0x6d, 0x0f, 0x6f, 0x2f, 0x7d, 0x37, 0x7e,
- 0x4b, 0x96, 0xd2, 0x52, 0x8b, 0x80, 0xdc, 0x51,
- 0xcc, 0x51, 0x1c, 0x7a, 0xbe, 0x7d, 0xf1, 0x83,
- 0x75, 0x96, 0x80, 0x8b, 0xcf, 0x62, 0x02, 0x6a,
- 0xfe, 0x8a, 0x39, 0x4e, 0xe7, 0x5b, 0x12, 0x60,
- 0x87, 0x73, 0x70, 0x75, 0x17, 0x53, 0xfb, 0x78,
- 0xbf, 0x4f, 0xa9, 0x5f, 0x0d, 0x4e, 0xcc, 0x6c,
- 0x78, 0x65, 0x22, 0x7d, 0xc3, 0x53, 0x5e, 0x58,
- 0x01, 0x77, 0x49, 0x84, 0xaa, 0x8a, 0xba, 0x6b,
- 0xb0, 0x8f, 0x88, 0x6c, 0xfe, 0x62, 0xe5, 0x82,
- 0xa0, 0x63, 0x65, 0x75, 0xae, 0x4e, 0x69, 0x51,
- 0xc9, 0x51, 0x81, 0x68, 0xe7, 0x7c, 0x6f, 0x82,
- 0xd2, 0x8a, 0xcf, 0x91, 0xf5, 0x52, 0x42, 0x54,
- 0x73, 0x59, 0xec, 0x5e, 0xc5, 0x65, 0xfe, 0x6f,
- 0x2a, 0x79, 0xad, 0x95, 0x6a, 0x9a, 0x97, 0x9e,
- 0xce, 0x9e, 0x9b, 0x52, 0xc6, 0x66, 0x77, 0x6b,
- 0x62, 0x8f, 0x74, 0x5e, 0x90, 0x61, 0x00, 0x62,
- 0x9a, 0x64, 0x23, 0x6f, 0x49, 0x71, 0x89, 0x74,
- 0xca, 0x79, 0xf4, 0x7d, 0x6f, 0x80, 0x26, 0x8f,
- 0xee, 0x84, 0x23, 0x90, 0x4a, 0x93, 0x17, 0x52,
- 0xa3, 0x52, 0xbd, 0x54, 0xc8, 0x70, 0xc2, 0x88,
- 0xaa, 0x8a, 0xc9, 0x5e, 0xf5, 0x5f, 0x7b, 0x63,
- 0xae, 0x6b, 0x3e, 0x7c, 0x75, 0x73, 0xe4, 0x4e,
- 0xf9, 0x56, 0xe7, 0x5b, 0xba, 0x5d, 0x1c, 0x60,
- 0xb2, 0x73, 0x69, 0x74, 0x9a, 0x7f, 0x46, 0x80,
- 0x34, 0x92, 0xf6, 0x96, 0x48, 0x97, 0x18, 0x98,
- 0x8b, 0x4f, 0xae, 0x79, 0xb4, 0x91, 0xb8, 0x96,
- 0xe1, 0x60, 0x86, 0x4e, 0xda, 0x50, 0xee, 0x5b,
- 0x3f, 0x5c, 0x99, 0x65, 0x02, 0x6a, 0xce, 0x71,
- 0x42, 0x76, 0xfc, 0x84, 0x7c, 0x90, 0x8d, 0x9f,
- 0x88, 0x66, 0x2e, 0x96, 0x89, 0x52, 0x7b, 0x67,
- 0xf3, 0x67, 0x41, 0x6d, 0x9c, 0x6e, 0x09, 0x74,
- 0x59, 0x75, 0x6b, 0x78, 0x10, 0x7d, 0x5e, 0x98,
- 0x6d, 0x51, 0x2e, 0x62, 0x78, 0x96, 0x2b, 0x50,
- 0x19, 0x5d, 0xea, 0x6d, 0x2a, 0x8f, 0x8b, 0x5f,
- 0x44, 0x61, 0x17, 0x68, 0x87, 0x73, 0x86, 0x96,
- 0x29, 0x52, 0x0f, 0x54, 0x65, 0x5c, 0x13, 0x66,
- 0x4e, 0x67, 0xa8, 0x68, 0xe5, 0x6c, 0x06, 0x74,
- 0xe2, 0x75, 0x79, 0x7f, 0xcf, 0x88, 0xe1, 0x88,
- 0xcc, 0x91, 0xe2, 0x96, 0x3f, 0x53, 0xba, 0x6e,
- 0x1d, 0x54, 0xd0, 0x71, 0x98, 0x74, 0xfa, 0x85,
- 0xa3, 0x96, 0x57, 0x9c, 0x9f, 0x9e, 0x97, 0x67,
- 0xcb, 0x6d, 0xe8, 0x81, 0xcb, 0x7a, 0x20, 0x7b,
- 0x92, 0x7c, 0xc0, 0x72, 0x99, 0x70, 0x58, 0x8b,
- 0xc0, 0x4e, 0x36, 0x83, 0x3a, 0x52, 0x07, 0x52,
- 0xa6, 0x5e, 0xd3, 0x62, 0xd6, 0x7c, 0x85, 0x5b,
- 0x1e, 0x6d, 0xb4, 0x66, 0x3b, 0x8f, 0x4c, 0x88,
- 0x4d, 0x96, 0x8b, 0x89, 0xd3, 0x5e, 0x40, 0x51,
- 0xc0, 0x55, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x58,
- 0x00, 0x00, 0x74, 0x66, 0x00, 0x00, 0x00, 0x00,
- 0xde, 0x51, 0x2a, 0x73, 0xca, 0x76, 0x3c, 0x79,
- 0x5e, 0x79, 0x65, 0x79, 0x8f, 0x79, 0x56, 0x97,
- 0xbe, 0x7c, 0xbd, 0x7f, 0x00, 0x00, 0x12, 0x86,
- 0x00, 0x00, 0xf8, 0x8a, 0x00, 0x00, 0x00, 0x00,
- 0x38, 0x90, 0xfd, 0x90, 0xef, 0x98, 0xfc, 0x98,
- 0x28, 0x99, 0xb4, 0x9d, 0xde, 0x90, 0xb7, 0x96,
- 0xae, 0x4f, 0xe7, 0x50, 0x4d, 0x51, 0xc9, 0x52,
- 0xe4, 0x52, 0x51, 0x53, 0x9d, 0x55, 0x06, 0x56,
- 0x68, 0x56, 0x40, 0x58, 0xa8, 0x58, 0x64, 0x5c,
- 0x6e, 0x5c, 0x94, 0x60, 0x68, 0x61, 0x8e, 0x61,
- 0xf2, 0x61, 0x4f, 0x65, 0xe2, 0x65, 0x91, 0x66,
- 0x85, 0x68, 0x77, 0x6d, 0x1a, 0x6e, 0x22, 0x6f,
- 0x6e, 0x71, 0x2b, 0x72, 0x22, 0x74, 0x91, 0x78,
- 0x3e, 0x79, 0x49, 0x79, 0x48, 0x79, 0x50, 0x79,
- 0x56, 0x79, 0x5d, 0x79, 0x8d, 0x79, 0x8e, 0x79,
- 0x40, 0x7a, 0x81, 0x7a, 0xc0, 0x7b, 0xf4, 0x7d,
- 0x09, 0x7e, 0x41, 0x7e, 0x72, 0x7f, 0x05, 0x80,
- 0xed, 0x81, 0x79, 0x82, 0x79, 0x82, 0x57, 0x84,
- 0x10, 0x89, 0x96, 0x89, 0x01, 0x8b, 0x39, 0x8b,
- 0xd3, 0x8c, 0x08, 0x8d, 0xb6, 0x8f, 0x38, 0x90,
- 0xe3, 0x96, 0xff, 0x97, 0x3b, 0x98, 0x75, 0x60,
- 0xee, 0x42, 0x18, 0x82, 0x02, 0x26, 0x4e, 0xb5,
- 0x51, 0x68, 0x51, 0x80, 0x4f, 0x45, 0x51, 0x80,
- 0x51, 0xc7, 0x52, 0xfa, 0x52, 0x9d, 0x55, 0x55,
- 0x55, 0x99, 0x55, 0xe2, 0x55, 0x5a, 0x58, 0xb3,
- 0x58, 0x44, 0x59, 0x54, 0x59, 0x62, 0x5a, 0x28,
- 0x5b, 0xd2, 0x5e, 0xd9, 0x5e, 0x69, 0x5f, 0xad,
- 0x5f, 0xd8, 0x60, 0x4e, 0x61, 0x08, 0x61, 0x8e,
- 0x61, 0x60, 0x61, 0xf2, 0x61, 0x34, 0x62, 0xc4,
- 0x63, 0x1c, 0x64, 0x52, 0x64, 0x56, 0x65, 0x74,
- 0x66, 0x17, 0x67, 0x1b, 0x67, 0x56, 0x67, 0x79,
- 0x6b, 0xba, 0x6b, 0x41, 0x6d, 0xdb, 0x6e, 0xcb,
- 0x6e, 0x22, 0x6f, 0x1e, 0x70, 0x6e, 0x71, 0xa7,
- 0x77, 0x35, 0x72, 0xaf, 0x72, 0x2a, 0x73, 0x71,
- 0x74, 0x06, 0x75, 0x3b, 0x75, 0x1d, 0x76, 0x1f,
- 0x76, 0xca, 0x76, 0xdb, 0x76, 0xf4, 0x76, 0x4a,
- 0x77, 0x40, 0x77, 0xcc, 0x78, 0xb1, 0x7a, 0xc0,
- 0x7b, 0x7b, 0x7c, 0x5b, 0x7d, 0xf4, 0x7d, 0x3e,
- 0x7f, 0x05, 0x80, 0x52, 0x83, 0xef, 0x83, 0x79,
- 0x87, 0x41, 0x89, 0x86, 0x89, 0x96, 0x89, 0xbf,
- 0x8a, 0xf8, 0x8a, 0xcb, 0x8a, 0x01, 0x8b, 0xfe,
- 0x8a, 0xed, 0x8a, 0x39, 0x8b, 0x8a, 0x8b, 0x08,
- 0x8d, 0x38, 0x8f, 0x72, 0x90, 0x99, 0x91, 0x76,
- 0x92, 0x7c, 0x96, 0xe3, 0x96, 0x56, 0x97, 0xdb,
- 0x97, 0xff, 0x97, 0x0b, 0x98, 0x3b, 0x98, 0x12,
- 0x9b, 0x9c, 0x9f, 0x4a, 0x28, 0x44, 0x28, 0xd5,
- 0x33, 0x9d, 0x3b, 0x18, 0x40, 0x39, 0x40, 0x49,
- 0x52, 0xd0, 0x5c, 0xd3, 0x7e, 0x43, 0x9f, 0x8e,
- 0x9f, 0x2a, 0xa0, 0x02, 0x66, 0x66, 0x66, 0x69,
- 0x66, 0x6c, 0x66, 0x66, 0x69, 0x66, 0x66, 0x6c,
- 0x7f, 0x01, 0x74, 0x73, 0x00, 0x74, 0x65, 0x05,
- 0x0f, 0x11, 0x0f, 0x00, 0x0f, 0x06, 0x19, 0x11,
- 0x0f, 0x08, 0xd9, 0x05, 0xb4, 0x05, 0x00, 0x00,
- 0x00, 0x00, 0xf2, 0x05, 0xb7, 0x05, 0xd0, 0x05,
- 0x12, 0x00, 0x03, 0x04, 0x0b, 0x0c, 0x0d, 0x18,
- 0x1a, 0xe9, 0x05, 0xc1, 0x05, 0xe9, 0x05, 0xc2,
- 0x05, 0x49, 0xfb, 0xc1, 0x05, 0x49, 0xfb, 0xc2,
- 0x05, 0xd0, 0x05, 0xb7, 0x05, 0xd0, 0x05, 0xb8,
- 0x05, 0xd0, 0x05, 0xbc, 0x05, 0xd8, 0x05, 0xbc,
- 0x05, 0xde, 0x05, 0xbc, 0x05, 0xe0, 0x05, 0xbc,
- 0x05, 0xe3, 0x05, 0xbc, 0x05, 0xb9, 0x05, 0x2d,
- 0x03, 0x2e, 0x03, 0x2f, 0x03, 0x30, 0x03, 0x31,
- 0x03, 0x1c, 0x00, 0x18, 0x06, 0x22, 0x06, 0x2b,
- 0x06, 0xd0, 0x05, 0xdc, 0x05, 0x71, 0x06, 0x00,
- 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0d, 0x0d, 0x0d,
- 0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x09, 0x09, 0x09,
- 0x09, 0x0e, 0x0e, 0x0e, 0x0e, 0x08, 0x08, 0x08,
- 0x08, 0x33, 0x33, 0x33, 0x33, 0x35, 0x35, 0x35,
- 0x35, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12,
- 0x12, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16,
- 0x16, 0x1c, 0x1c, 0x1b, 0x1b, 0x1d, 0x1d, 0x17,
- 0x17, 0x27, 0x27, 0x20, 0x20, 0x38, 0x38, 0x38,
- 0x38, 0x3e, 0x3e, 0x3e, 0x3e, 0x42, 0x42, 0x42,
- 0x42, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x4a,
- 0x4a, 0x4a, 0x4a, 0x4f, 0x4f, 0x50, 0x50, 0x50,
- 0x50, 0x4d, 0x4d, 0x4d, 0x4d, 0x61, 0x61, 0x62,
- 0x62, 0x49, 0x06, 0x64, 0x64, 0x64, 0x64, 0x7e,
- 0x7e, 0x7d, 0x7d, 0x7f, 0x7f, 0x2e, 0x82, 0x82,
- 0x7c, 0x7c, 0x80, 0x80, 0x87, 0x87, 0x87, 0x87,
- 0x00, 0x00, 0x26, 0x06, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0xaf, 0x00, 0xaf, 0x00, 0x22, 0x00, 0x22,
- 0x00, 0xa1, 0x00, 0xa1, 0x00, 0xa0, 0x00, 0xa0,
- 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xaa, 0x00, 0xaa,
- 0x00, 0xaa, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23,
- 0xcc, 0x06, 0x00, 0x00, 0x00, 0x00, 0x26, 0x06,
- 0x00, 0x06, 0x00, 0x07, 0x00, 0x1f, 0x00, 0x23,
- 0x00, 0x24, 0x02, 0x06, 0x02, 0x07, 0x02, 0x08,
- 0x02, 0x1f, 0x02, 0x23, 0x02, 0x24, 0x04, 0x06,
- 0x04, 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, 0x23,
- 0x04, 0x24, 0x05, 0x06, 0x05, 0x1f, 0x05, 0x23,
- 0x05, 0x24, 0x06, 0x07, 0x06, 0x1f, 0x07, 0x06,
- 0x07, 0x1f, 0x08, 0x06, 0x08, 0x07, 0x08, 0x1f,
- 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x08, 0x0d, 0x1f,
- 0x0f, 0x07, 0x0f, 0x1f, 0x10, 0x06, 0x10, 0x07,
- 0x10, 0x08, 0x10, 0x1f, 0x11, 0x07, 0x11, 0x1f,
- 0x12, 0x1f, 0x13, 0x06, 0x13, 0x1f, 0x14, 0x06,
- 0x14, 0x1f, 0x1b, 0x06, 0x1b, 0x07, 0x1b, 0x08,
- 0x1b, 0x1f, 0x1b, 0x23, 0x1b, 0x24, 0x1c, 0x07,
- 0x1c, 0x1f, 0x1c, 0x23, 0x1c, 0x24, 0x1d, 0x01,
- 0x1d, 0x06, 0x1d, 0x07, 0x1d, 0x08, 0x1d, 0x1e,
- 0x1d, 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, 0x06,
- 0x1e, 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, 0x23,
- 0x1e, 0x24, 0x1f, 0x06, 0x1f, 0x07, 0x1f, 0x08,
- 0x1f, 0x1f, 0x1f, 0x23, 0x1f, 0x24, 0x20, 0x06,
- 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, 0x20, 0x23,
- 0x20, 0x24, 0x21, 0x06, 0x21, 0x1f, 0x21, 0x23,
- 0x21, 0x24, 0x24, 0x06, 0x24, 0x07, 0x24, 0x08,
- 0x24, 0x1f, 0x24, 0x23, 0x24, 0x24, 0x0a, 0x4a,
- 0x0b, 0x4a, 0x23, 0x4a, 0x20, 0x00, 0x4c, 0x06,
- 0x51, 0x06, 0x51, 0x06, 0xff, 0x00, 0x1f, 0x26,
- 0x06, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x1f, 0x00,
- 0x20, 0x00, 0x23, 0x00, 0x24, 0x02, 0x0b, 0x02,
- 0x0c, 0x02, 0x1f, 0x02, 0x20, 0x02, 0x23, 0x02,
- 0x24, 0x04, 0x0b, 0x04, 0x0c, 0x04, 0x1f, 0x26,
- 0x06, 0x04, 0x20, 0x04, 0x23, 0x04, 0x24, 0x05,
- 0x0b, 0x05, 0x0c, 0x05, 0x1f, 0x05, 0x20, 0x05,
- 0x23, 0x05, 0x24, 0x1b, 0x23, 0x1b, 0x24, 0x1c,
- 0x23, 0x1c, 0x24, 0x1d, 0x01, 0x1d, 0x1e, 0x1d,
- 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, 0x1f, 0x1e,
- 0x23, 0x1e, 0x24, 0x1f, 0x01, 0x1f, 0x1f, 0x20,
- 0x0b, 0x20, 0x0c, 0x20, 0x1f, 0x20, 0x20, 0x20,
- 0x23, 0x20, 0x24, 0x23, 0x4a, 0x24, 0x0b, 0x24,
- 0x0c, 0x24, 0x1f, 0x24, 0x20, 0x24, 0x23, 0x24,
- 0x24, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00,
- 0x1f, 0x00, 0x21, 0x02, 0x06, 0x02, 0x07, 0x02,
- 0x08, 0x02, 0x1f, 0x02, 0x21, 0x04, 0x06, 0x04,
- 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, 0x21, 0x05,
- 0x1f, 0x06, 0x07, 0x06, 0x1f, 0x07, 0x06, 0x07,
- 0x1f, 0x08, 0x06, 0x08, 0x1f, 0x0d, 0x06, 0x0d,
- 0x07, 0x0d, 0x08, 0x0d, 0x1f, 0x0f, 0x07, 0x0f,
- 0x08, 0x0f, 0x1f, 0x10, 0x06, 0x10, 0x07, 0x10,
- 0x08, 0x10, 0x1f, 0x11, 0x07, 0x12, 0x1f, 0x13,
- 0x06, 0x13, 0x1f, 0x14, 0x06, 0x14, 0x1f, 0x1b,
- 0x06, 0x1b, 0x07, 0x1b, 0x08, 0x1b, 0x1f, 0x1c,
- 0x07, 0x1c, 0x1f, 0x1d, 0x06, 0x1d, 0x07, 0x1d,
- 0x08, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x06, 0x1e,
- 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, 0x21, 0x1f,
- 0x06, 0x1f, 0x07, 0x1f, 0x08, 0x1f, 0x1f, 0x20,
- 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, 0x20,
- 0x21, 0x21, 0x06, 0x21, 0x1f, 0x21, 0x4a, 0x24,
- 0x06, 0x24, 0x07, 0x24, 0x08, 0x24, 0x1f, 0x24,
- 0x21, 0x00, 0x1f, 0x00, 0x21, 0x02, 0x1f, 0x02,
- 0x21, 0x04, 0x1f, 0x04, 0x21, 0x05, 0x1f, 0x05,
- 0x21, 0x0d, 0x1f, 0x0d, 0x21, 0x0e, 0x1f, 0x0e,
- 0x21, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x1f, 0x20,
- 0x1f, 0x20, 0x21, 0x24, 0x1f, 0x24, 0x21, 0x40,
- 0x06, 0x4e, 0x06, 0x51, 0x06, 0x27, 0x06, 0x10,
- 0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23, 0x13,
- 0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23, 0x0d,
- 0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23, 0x05,
- 0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23, 0x0e,
- 0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23, 0x0d,
- 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0d,
- 0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a, 0x10,
- 0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23, 0x13,
- 0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23, 0x0d,
- 0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23, 0x05,
- 0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23, 0x0e,
- 0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23, 0x0d,
- 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0d,
- 0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a, 0x0d,
- 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0c,
- 0x20, 0x0d, 0x20, 0x10, 0x1e, 0x0c, 0x05, 0x0c,
- 0x06, 0x0c, 0x07, 0x0d, 0x05, 0x0d, 0x06, 0x0d,
- 0x07, 0x10, 0x1e, 0x11, 0x1e, 0x00, 0x24, 0x00,
- 0x24, 0x2a, 0x06, 0x00, 0x02, 0x1b, 0x00, 0x03,
- 0x02, 0x00, 0x03, 0x02, 0x00, 0x03, 0x1b, 0x00,
- 0x04, 0x1b, 0x00, 0x1b, 0x02, 0x00, 0x1b, 0x03,
- 0x00, 0x1b, 0x04, 0x02, 0x1b, 0x03, 0x02, 0x1b,
- 0x03, 0x03, 0x1b, 0x20, 0x03, 0x1b, 0x1f, 0x09,
- 0x03, 0x02, 0x09, 0x02, 0x03, 0x09, 0x02, 0x1f,
- 0x09, 0x1b, 0x03, 0x09, 0x1b, 0x03, 0x09, 0x1b,
- 0x02, 0x09, 0x1b, 0x1b, 0x09, 0x1b, 0x1b, 0x0b,
- 0x03, 0x03, 0x0b, 0x03, 0x03, 0x0b, 0x1b, 0x1b,
- 0x0a, 0x03, 0x1b, 0x0a, 0x03, 0x1b, 0x0a, 0x02,
- 0x20, 0x0a, 0x1b, 0x04, 0x0a, 0x1b, 0x04, 0x0a,
- 0x1b, 0x1b, 0x0a, 0x1b, 0x1b, 0x0c, 0x03, 0x1f,
- 0x0c, 0x04, 0x1b, 0x0c, 0x04, 0x1b, 0x0d, 0x1b,
- 0x03, 0x0d, 0x1b, 0x03, 0x0d, 0x1b, 0x1b, 0x0d,
- 0x1b, 0x20, 0x0f, 0x02, 0x1b, 0x0f, 0x1b, 0x1b,
- 0x0f, 0x1b, 0x1b, 0x0f, 0x1b, 0x1f, 0x10, 0x1b,
- 0x1b, 0x10, 0x1b, 0x20, 0x10, 0x1b, 0x1f, 0x17,
- 0x04, 0x1b, 0x17, 0x04, 0x1b, 0x18, 0x1b, 0x03,
- 0x18, 0x1b, 0x1b, 0x1a, 0x03, 0x1b, 0x1a, 0x03,
- 0x20, 0x1a, 0x03, 0x1f, 0x1a, 0x02, 0x02, 0x1a,
- 0x02, 0x02, 0x1a, 0x04, 0x1b, 0x1a, 0x04, 0x1b,
- 0x1a, 0x1b, 0x03, 0x1a, 0x1b, 0x03, 0x1b, 0x03,
- 0x02, 0x1b, 0x03, 0x1b, 0x1b, 0x03, 0x20, 0x1b,
- 0x02, 0x03, 0x1b, 0x02, 0x1b, 0x1b, 0x04, 0x02,
- 0x1b, 0x04, 0x1b, 0x28, 0x06, 0x1d, 0x04, 0x06,
- 0x1f, 0x1d, 0x04, 0x1f, 0x1d, 0x1d, 0x1e, 0x05,
- 0x1d, 0x1e, 0x05, 0x21, 0x1e, 0x04, 0x1d, 0x1e,
- 0x04, 0x1d, 0x1e, 0x04, 0x21, 0x1e, 0x1d, 0x22,
- 0x1e, 0x1d, 0x21, 0x22, 0x1d, 0x1d, 0x22, 0x1d,
- 0x1d, 0x00, 0x06, 0x22, 0x02, 0x04, 0x22, 0x02,
- 0x04, 0x21, 0x02, 0x06, 0x22, 0x02, 0x06, 0x21,
- 0x02, 0x1d, 0x22, 0x02, 0x1d, 0x21, 0x04, 0x1d,
- 0x22, 0x04, 0x05, 0x21, 0x04, 0x1d, 0x21, 0x0b,
- 0x06, 0x21, 0x0d, 0x05, 0x22, 0x0c, 0x05, 0x22,
- 0x0e, 0x05, 0x22, 0x1c, 0x04, 0x22, 0x1c, 0x1d,
- 0x22, 0x22, 0x05, 0x22, 0x22, 0x04, 0x22, 0x22,
- 0x1d, 0x22, 0x1d, 0x1d, 0x22, 0x1a, 0x1d, 0x22,
- 0x1e, 0x05, 0x22, 0x1a, 0x1d, 0x05, 0x1c, 0x05,
- 0x1d, 0x11, 0x1d, 0x22, 0x1b, 0x1d, 0x22, 0x1e,
- 0x04, 0x05, 0x1d, 0x06, 0x22, 0x1c, 0x04, 0x1d,
- 0x1b, 0x1d, 0x1d, 0x1c, 0x04, 0x1d, 0x1e, 0x04,
- 0x05, 0x04, 0x05, 0x22, 0x05, 0x04, 0x22, 0x1d,
- 0x04, 0x22, 0x19, 0x1d, 0x22, 0x00, 0x05, 0x22,
- 0x1b, 0x1d, 0x1d, 0x11, 0x04, 0x1d, 0x0d, 0x1d,
- 0x1d, 0x0b, 0x06, 0x22, 0x1e, 0x04, 0x22, 0x35,
- 0x06, 0x00, 0x0f, 0x9d, 0x0d, 0x0f, 0x9d, 0x27,
- 0x06, 0x00, 0x1d, 0x1d, 0x20, 0x00, 0x1c, 0x01,
- 0x0a, 0x1e, 0x06, 0x1e, 0x08, 0x0e, 0x1d, 0x12,
- 0x1e, 0x0a, 0x0c, 0x21, 0x1d, 0x12, 0x1d, 0x23,
- 0x20, 0x21, 0x0c, 0x1d, 0x1e, 0x35, 0x06, 0x00,
- 0x0f, 0x14, 0x27, 0x06, 0x0e, 0x1d, 0x22, 0xff,
- 0x00, 0x1d, 0x1d, 0x20, 0xff, 0x12, 0x1d, 0x23,
- 0x20, 0xff, 0x21, 0x0c, 0x1d, 0x1e, 0x27, 0x06,
- 0x05, 0x1d, 0xff, 0x05, 0x1d, 0x00, 0x1d, 0x20,
- 0x27, 0x06, 0x0a, 0xa5, 0x00, 0x1d, 0x2c, 0x00,
- 0x01, 0x30, 0x02, 0x30, 0x3a, 0x00, 0x3b, 0x00,
- 0x21, 0x00, 0x3f, 0x00, 0x16, 0x30, 0x17, 0x30,
- 0x26, 0x20, 0x13, 0x20, 0x12, 0x01, 0x00, 0x5f,
- 0x5f, 0x28, 0x29, 0x7b, 0x7d, 0x08, 0x30, 0x0c,
- 0x0d, 0x08, 0x09, 0x02, 0x03, 0x00, 0x01, 0x04,
- 0x05, 0x06, 0x07, 0x5b, 0x00, 0x5d, 0x00, 0x3e,
- 0x20, 0x3e, 0x20, 0x3e, 0x20, 0x3e, 0x20, 0x5f,
- 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x2c, 0x00, 0x01,
- 0x30, 0x2e, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x3a,
- 0x00, 0x3f, 0x00, 0x21, 0x00, 0x14, 0x20, 0x28,
- 0x00, 0x29, 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x14,
- 0x30, 0x15, 0x30, 0x23, 0x26, 0x2a, 0x2b, 0x2d,
- 0x3c, 0x3e, 0x3d, 0x00, 0x5c, 0x24, 0x25, 0x40,
- 0x40, 0x06, 0xff, 0x0b, 0x00, 0x0b, 0xff, 0x0c,
- 0x20, 0x00, 0x4d, 0x06, 0x40, 0x06, 0xff, 0x0e,
- 0x00, 0x0e, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0x10,
- 0x00, 0x10, 0xff, 0x11, 0x00, 0x11, 0xff, 0x12,
- 0x00, 0x12, 0x21, 0x06, 0x00, 0x01, 0x01, 0x02,
- 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x05,
- 0x05, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08,
- 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a,
- 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c,
- 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f,
- 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x12,
- 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14,
- 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16,
- 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18,
- 0x18, 0x19, 0x19, 0x19, 0x19, 0x20, 0x20, 0x20,
- 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22,
- 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24,
- 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26,
- 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x29,
- 0x29, 0x22, 0x06, 0x22, 0x00, 0x22, 0x00, 0x22,
- 0x01, 0x22, 0x01, 0x22, 0x03, 0x22, 0x03, 0x22,
- 0x05, 0x22, 0x05, 0x21, 0x00, 0x85, 0x29, 0x01,
- 0x30, 0x01, 0x0b, 0x0c, 0x00, 0xfa, 0xf1, 0xa0,
- 0xa2, 0xa4, 0xa6, 0xa8, 0xe2, 0xe4, 0xe6, 0xc2,
- 0xfb, 0xa1, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac,
- 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc,
- 0xbe, 0xc0, 0xc3, 0xc5, 0xc7, 0xc9, 0xca, 0xcb,
- 0xcc, 0xcd, 0xce, 0xd1, 0xd4, 0xd7, 0xda, 0xdd,
- 0xde, 0xdf, 0xe0, 0xe1, 0xe3, 0xe5, 0xe7, 0xe8,
- 0xe9, 0xea, 0xeb, 0xec, 0xee, 0xf2, 0x98, 0x99,
- 0x31, 0x31, 0x4f, 0x31, 0x55, 0x31, 0x5b, 0x31,
- 0x61, 0x31, 0xa2, 0x00, 0xa3, 0x00, 0xac, 0x00,
- 0xaf, 0x00, 0xa6, 0x00, 0xa5, 0x00, 0xa9, 0x20,
- 0x00, 0x00, 0x02, 0x25, 0x90, 0x21, 0x91, 0x21,
- 0x92, 0x21, 0x93, 0x21, 0xa0, 0x25, 0xcb, 0x25,
- 0xd2, 0x05, 0x07, 0x03, 0x01, 0xda, 0x05, 0x07,
- 0x03, 0x01, 0xd0, 0x02, 0xd1, 0x02, 0xe6, 0x00,
- 0x99, 0x02, 0x53, 0x02, 0x00, 0x00, 0xa3, 0x02,
- 0x66, 0xab, 0xa5, 0x02, 0xa4, 0x02, 0x56, 0x02,
- 0x57, 0x02, 0x91, 0x1d, 0x58, 0x02, 0x5e, 0x02,
- 0xa9, 0x02, 0x64, 0x02, 0x62, 0x02, 0x60, 0x02,
- 0x9b, 0x02, 0x27, 0x01, 0x9c, 0x02, 0x67, 0x02,
- 0x84, 0x02, 0xaa, 0x02, 0xab, 0x02, 0x6c, 0x02,
- 0x04, 0xdf, 0x8e, 0xa7, 0x6e, 0x02, 0x05, 0xdf,
- 0x8e, 0x02, 0x06, 0xdf, 0xf8, 0x00, 0x76, 0x02,
- 0x77, 0x02, 0x71, 0x00, 0x7a, 0x02, 0x08, 0xdf,
- 0x7d, 0x02, 0x7e, 0x02, 0x80, 0x02, 0xa8, 0x02,
- 0xa6, 0x02, 0x67, 0xab, 0xa7, 0x02, 0x88, 0x02,
- 0x71, 0x2c, 0x00, 0x00, 0x8f, 0x02, 0xa1, 0x02,
- 0xa2, 0x02, 0x98, 0x02, 0xc0, 0x01, 0xc1, 0x01,
- 0xc2, 0x01, 0x0a, 0xdf, 0x1e, 0xdf, 0x41, 0x04,
- 0x40, 0x00, 0x00, 0x00, 0x00, 0x14, 0x99, 0x10,
- 0xba, 0x10, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x10,
- 0xba, 0x10, 0x05, 0x05, 0xa5, 0x10, 0xba, 0x10,
- 0x05, 0x31, 0x11, 0x27, 0x11, 0x32, 0x11, 0x27,
- 0x11, 0x55, 0x47, 0x13, 0x3e, 0x13, 0x47, 0x13,
- 0x57, 0x13, 0x55, 0x82, 0x13, 0xc9, 0x13, 0x00,
- 0x00, 0x00, 0x00, 0x84, 0x13, 0xbb, 0x13, 0x05,
- 0x05, 0x8b, 0x13, 0xc2, 0x13, 0x05, 0x90, 0x13,
- 0xc9, 0x13, 0x05, 0xc2, 0x13, 0xc2, 0x13, 0x00,
- 0x00, 0x00, 0x00, 0xc2, 0x13, 0xb8, 0x13, 0xc2,
- 0x13, 0xc9, 0x13, 0x05, 0x55, 0xb9, 0x14, 0xba,
- 0x14, 0xb9, 0x14, 0xb0, 0x14, 0x00, 0x00, 0x00,
- 0x00, 0xb9, 0x14, 0xbd, 0x14, 0x55, 0x50, 0xb8,
- 0x15, 0xaf, 0x15, 0xb9, 0x15, 0xaf, 0x15, 0x55,
- 0x35, 0x19, 0x30, 0x19, 0x05, 0x1e, 0x61, 0x1e,
- 0x61, 0x1e, 0x61, 0x29, 0x61, 0x1e, 0x61, 0x1f,
- 0x61, 0x29, 0x61, 0x1f, 0x61, 0x1e, 0x61, 0x20,
- 0x61, 0x21, 0x61, 0x1f, 0x61, 0x22, 0x61, 0x1f,
- 0x61, 0x21, 0x61, 0x20, 0x61, 0x55, 0x55, 0x55,
- 0x55, 0x67, 0x6d, 0x67, 0x6d, 0x63, 0x6d, 0x67,
- 0x6d, 0x69, 0x6d, 0x67, 0x6d, 0x55, 0x05, 0x41,
- 0x00, 0x30, 0x00, 0x57, 0xd1, 0x65, 0xd1, 0x58,
- 0xd1, 0x65, 0xd1, 0x5f, 0xd1, 0x6e, 0xd1, 0x5f,
- 0xd1, 0x6f, 0xd1, 0x5f, 0xd1, 0x70, 0xd1, 0x5f,
- 0xd1, 0x71, 0xd1, 0x5f, 0xd1, 0x72, 0xd1, 0x55,
- 0x55, 0x55, 0x05, 0xb9, 0xd1, 0x65, 0xd1, 0xba,
- 0xd1, 0x65, 0xd1, 0xbb, 0xd1, 0x6e, 0xd1, 0xbc,
- 0xd1, 0x6e, 0xd1, 0xbb, 0xd1, 0x6f, 0xd1, 0xbc,
- 0xd1, 0x6f, 0xd1, 0x55, 0x55, 0x55, 0x41, 0x00,
- 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x69, 0x00,
- 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x43, 0x44,
- 0x00, 0x00, 0x47, 0x00, 0x00, 0x4a, 0x4b, 0x00,
- 0x00, 0x4e, 0x4f, 0x50, 0x51, 0x00, 0x53, 0x54,
- 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62,
- 0x63, 0x64, 0x00, 0x66, 0x68, 0x00, 0x70, 0x00,
- 0x41, 0x00, 0x61, 0x00, 0x41, 0x42, 0x00, 0x44,
- 0x45, 0x46, 0x47, 0x4a, 0x00, 0x53, 0x00, 0x61,
- 0x00, 0x41, 0x42, 0x00, 0x44, 0x45, 0x46, 0x47,
- 0x00, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x00, 0x4f,
- 0x53, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00,
- 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00,
- 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00,
- 0x41, 0x00, 0x61, 0x00, 0x31, 0x01, 0x37, 0x02,
- 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03,
- 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03,
- 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00,
- 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03,
- 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04,
- 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03,
- 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05,
- 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03,
- 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x0b, 0x0c,
- 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00,
- 0x30, 0x00, 0x30, 0x04, 0x3a, 0x04, 0x3e, 0x04,
- 0x4b, 0x04, 0x4d, 0x04, 0x4e, 0x04, 0x89, 0xa6,
- 0x30, 0x04, 0xa9, 0x26, 0x28, 0xb9, 0x7f, 0x9f,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x0a, 0x0b, 0x0e, 0x0f, 0x11, 0x13, 0x14,
- 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x61, 0x26,
- 0x25, 0x2f, 0x7b, 0x51, 0xa6, 0xb1, 0x04, 0x27,
- 0x06, 0x00, 0x01, 0x05, 0x08, 0x2a, 0x06, 0x1e,
- 0x08, 0x03, 0x0d, 0x20, 0x19, 0x1a, 0x1b, 0x1c,
- 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00,
- 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x44, 0x90,
- 0x77, 0x45, 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00,
- 0x47, 0x06, 0x33, 0x06, 0x17, 0x10, 0x11, 0x12,
- 0x13, 0x00, 0x06, 0x0e, 0x02, 0x0f, 0x34, 0x06,
- 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, 0x00, 0x00,
- 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x2d, 0x06,
- 0x00, 0x00, 0x4a, 0x06, 0x00, 0x00, 0x44, 0x06,
- 0x00, 0x00, 0x46, 0x06, 0x33, 0x06, 0x39, 0x06,
- 0x00, 0x00, 0x35, 0x06, 0x42, 0x06, 0x00, 0x00,
- 0x34, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x06,
- 0x00, 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06,
- 0x00, 0x00, 0xba, 0x06, 0x00, 0x00, 0x6f, 0x06,
- 0x00, 0x00, 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00,
- 0x47, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x06,
- 0x37, 0x06, 0x4a, 0x06, 0x43, 0x06, 0x00, 0x00,
- 0x45, 0x06, 0x46, 0x06, 0x33, 0x06, 0x39, 0x06,
- 0x41, 0x06, 0x35, 0x06, 0x42, 0x06, 0x00, 0x00,
- 0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06,
- 0x00, 0x00, 0x36, 0x06, 0x38, 0x06, 0x3a, 0x06,
- 0x6e, 0x06, 0x00, 0x00, 0xa1, 0x06, 0x27, 0x06,
- 0x00, 0x01, 0x05, 0x08, 0x20, 0x21, 0x0b, 0x06,
- 0x10, 0x23, 0x2a, 0x06, 0x1a, 0x1b, 0x1c, 0x09,
- 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01,
- 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x28, 0x06, 0x2c,
- 0x06, 0x2f, 0x06, 0x00, 0x00, 0x48, 0x06, 0x32,
- 0x06, 0x2d, 0x06, 0x37, 0x06, 0x4a, 0x06, 0x2a,
- 0x06, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, 0x17, 0x0b,
- 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, 0x06, 0x0c,
- 0x0e, 0x10, 0x30, 0x2e, 0x30, 0x00, 0x2c, 0x00,
- 0x28, 0x00, 0x41, 0x00, 0x29, 0x00, 0x14, 0x30,
- 0x53, 0x00, 0x15, 0x30, 0x43, 0x52, 0x43, 0x44,
- 0x57, 0x5a, 0x41, 0x00, 0x48, 0x56, 0x4d, 0x56,
- 0x53, 0x44, 0x53, 0x53, 0x50, 0x50, 0x56, 0x57,
- 0x43, 0x4d, 0x43, 0x4d, 0x44, 0x4d, 0x52, 0x44,
- 0x4a, 0x4b, 0x30, 0x30, 0x00, 0x68, 0x68, 0x4b,
- 0x62, 0x57, 0x5b, 0xcc, 0x53, 0xc7, 0x30, 0x8c,
- 0x4e, 0x1a, 0x59, 0xe3, 0x89, 0x29, 0x59, 0xa4,
- 0x4e, 0x20, 0x66, 0x21, 0x71, 0x99, 0x65, 0x4d,
- 0x52, 0x8c, 0x5f, 0x8d, 0x51, 0xb0, 0x65, 0x1d,
- 0x52, 0x42, 0x7d, 0x1f, 0x75, 0xa9, 0x8c, 0xf0,
- 0x58, 0x39, 0x54, 0x14, 0x6f, 0x95, 0x62, 0x55,
- 0x63, 0x00, 0x4e, 0x09, 0x4e, 0x4a, 0x90, 0xe6,
- 0x5d, 0x2d, 0x4e, 0xf3, 0x53, 0x07, 0x63, 0x70,
- 0x8d, 0x53, 0x62, 0x81, 0x79, 0x7a, 0x7a, 0x08,
- 0x54, 0x80, 0x6e, 0x09, 0x67, 0x08, 0x67, 0x33,
- 0x75, 0x72, 0x52, 0xb6, 0x55, 0x4d, 0x91, 0x14,
- 0x30, 0x15, 0x30, 0x2c, 0x67, 0x09, 0x4e, 0x8c,
- 0x4e, 0x89, 0x5b, 0xb9, 0x70, 0x53, 0x62, 0xd7,
- 0x76, 0xdd, 0x52, 0x57, 0x65, 0x97, 0x5f, 0xef,
- 0x53, 0x30, 0x00, 0x38, 0x4e, 0x05, 0x00, 0x09,
- 0x22, 0x01, 0x60, 0x4f, 0xae, 0x4f, 0xbb, 0x4f,
- 0x02, 0x50, 0x7a, 0x50, 0x99, 0x50, 0xe7, 0x50,
- 0xcf, 0x50, 0x9e, 0x34, 0x3a, 0x06, 0x4d, 0x51,
- 0x54, 0x51, 0x64, 0x51, 0x77, 0x51, 0x1c, 0x05,
- 0xb9, 0x34, 0x67, 0x51, 0x8d, 0x51, 0x4b, 0x05,
- 0x97, 0x51, 0xa4, 0x51, 0xcc, 0x4e, 0xac, 0x51,
- 0xb5, 0x51, 0xdf, 0x91, 0xf5, 0x51, 0x03, 0x52,
- 0xdf, 0x34, 0x3b, 0x52, 0x46, 0x52, 0x72, 0x52,
- 0x77, 0x52, 0x15, 0x35, 0x02, 0x00, 0x20, 0x80,
- 0x80, 0x00, 0x08, 0x00, 0x00, 0xc7, 0x52, 0x00,
- 0x02, 0x1d, 0x33, 0x3e, 0x3f, 0x50, 0x82, 0x8a,
- 0x93, 0xac, 0xb6, 0xb8, 0xb8, 0xb8, 0x2c, 0x0a,
- 0x70, 0x70, 0xca, 0x53, 0xdf, 0x53, 0x63, 0x0b,
- 0xeb, 0x53, 0xf1, 0x53, 0x06, 0x54, 0x9e, 0x54,
- 0x38, 0x54, 0x48, 0x54, 0x68, 0x54, 0xa2, 0x54,
- 0xf6, 0x54, 0x10, 0x55, 0x53, 0x55, 0x63, 0x55,
- 0x84, 0x55, 0x84, 0x55, 0x99, 0x55, 0xab, 0x55,
- 0xb3, 0x55, 0xc2, 0x55, 0x16, 0x57, 0x06, 0x56,
- 0x17, 0x57, 0x51, 0x56, 0x74, 0x56, 0x07, 0x52,
- 0xee, 0x58, 0xce, 0x57, 0xf4, 0x57, 0x0d, 0x58,
- 0x8b, 0x57, 0x32, 0x58, 0x31, 0x58, 0xac, 0x58,
- 0xe4, 0x14, 0xf2, 0x58, 0xf7, 0x58, 0x06, 0x59,
- 0x1a, 0x59, 0x22, 0x59, 0x62, 0x59, 0xa8, 0x16,
- 0xea, 0x16, 0xec, 0x59, 0x1b, 0x5a, 0x27, 0x5a,
- 0xd8, 0x59, 0x66, 0x5a, 0xee, 0x36, 0xfc, 0x36,
- 0x08, 0x5b, 0x3e, 0x5b, 0x3e, 0x5b, 0xc8, 0x19,
- 0xc3, 0x5b, 0xd8, 0x5b, 0xe7, 0x5b, 0xf3, 0x5b,
- 0x18, 0x1b, 0xff, 0x5b, 0x06, 0x5c, 0x53, 0x5f,
- 0x22, 0x5c, 0x81, 0x37, 0x60, 0x5c, 0x6e, 0x5c,
- 0xc0, 0x5c, 0x8d, 0x5c, 0xe4, 0x1d, 0x43, 0x5d,
- 0xe6, 0x1d, 0x6e, 0x5d, 0x6b, 0x5d, 0x7c, 0x5d,
- 0xe1, 0x5d, 0xe2, 0x5d, 0x2f, 0x38, 0xfd, 0x5d,
- 0x28, 0x5e, 0x3d, 0x5e, 0x69, 0x5e, 0x62, 0x38,
- 0x83, 0x21, 0x7c, 0x38, 0xb0, 0x5e, 0xb3, 0x5e,
- 0xb6, 0x5e, 0xca, 0x5e, 0x92, 0xa3, 0xfe, 0x5e,
- 0x31, 0x23, 0x31, 0x23, 0x01, 0x82, 0x22, 0x5f,
- 0x22, 0x5f, 0xc7, 0x38, 0xb8, 0x32, 0xda, 0x61,
- 0x62, 0x5f, 0x6b, 0x5f, 0xe3, 0x38, 0x9a, 0x5f,
- 0xcd, 0x5f, 0xd7, 0x5f, 0xf9, 0x5f, 0x81, 0x60,
- 0x3a, 0x39, 0x1c, 0x39, 0x94, 0x60, 0xd4, 0x26,
- 0xc7, 0x60, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00,
- 0x02, 0x08, 0x00, 0x80, 0x08, 0x00, 0x00, 0x08,
- 0x80, 0x28, 0x80, 0x02, 0x00, 0x00, 0x02, 0x48,
- 0x61, 0x00, 0x04, 0x06, 0x04, 0x32, 0x46, 0x6a,
- 0x5c, 0x67, 0x96, 0xaa, 0xae, 0xc8, 0xd3, 0x5d,
- 0x62, 0x00, 0x54, 0x77, 0xf3, 0x0c, 0x2b, 0x3d,
- 0x63, 0xfc, 0x62, 0x68, 0x63, 0x83, 0x63, 0xe4,
- 0x63, 0xf1, 0x2b, 0x22, 0x64, 0xc5, 0x63, 0xa9,
- 0x63, 0x2e, 0x3a, 0x69, 0x64, 0x7e, 0x64, 0x9d,
- 0x64, 0x77, 0x64, 0x6c, 0x3a, 0x4f, 0x65, 0x6c,
- 0x65, 0x0a, 0x30, 0xe3, 0x65, 0xf8, 0x66, 0x49,
- 0x66, 0x19, 0x3b, 0x91, 0x66, 0x08, 0x3b, 0xe4,
- 0x3a, 0x92, 0x51, 0x95, 0x51, 0x00, 0x67, 0x9c,
- 0x66, 0xad, 0x80, 0xd9, 0x43, 0x17, 0x67, 0x1b,
- 0x67, 0x21, 0x67, 0x5e, 0x67, 0x53, 0x67, 0xc3,
- 0x33, 0x49, 0x3b, 0xfa, 0x67, 0x85, 0x67, 0x52,
- 0x68, 0x85, 0x68, 0x6d, 0x34, 0x8e, 0x68, 0x1f,
- 0x68, 0x14, 0x69, 0x9d, 0x3b, 0x42, 0x69, 0xa3,
- 0x69, 0xea, 0x69, 0xa8, 0x6a, 0xa3, 0x36, 0xdb,
- 0x6a, 0x18, 0x3c, 0x21, 0x6b, 0xa7, 0x38, 0x54,
- 0x6b, 0x4e, 0x3c, 0x72, 0x6b, 0x9f, 0x6b, 0xba,
- 0x6b, 0xbb, 0x6b, 0x8d, 0x3a, 0x0b, 0x1d, 0xfa,
- 0x3a, 0x4e, 0x6c, 0xbc, 0x3c, 0xbf, 0x6c, 0xcd,
- 0x6c, 0x67, 0x6c, 0x16, 0x6d, 0x3e, 0x6d, 0x77,
- 0x6d, 0x41, 0x6d, 0x69, 0x6d, 0x78, 0x6d, 0x85,
- 0x6d, 0x1e, 0x3d, 0x34, 0x6d, 0x2f, 0x6e, 0x6e,
- 0x6e, 0x33, 0x3d, 0xcb, 0x6e, 0xc7, 0x6e, 0xd1,
- 0x3e, 0xf9, 0x6d, 0x6e, 0x6f, 0x5e, 0x3f, 0x8e,
- 0x3f, 0xc6, 0x6f, 0x39, 0x70, 0x1e, 0x70, 0x1b,
- 0x70, 0x96, 0x3d, 0x4a, 0x70, 0x7d, 0x70, 0x77,
- 0x70, 0xad, 0x70, 0x25, 0x05, 0x45, 0x71, 0x63,
- 0x42, 0x9c, 0x71, 0xab, 0x43, 0x28, 0x72, 0x35,
- 0x72, 0x50, 0x72, 0x08, 0x46, 0x80, 0x72, 0x95,
- 0x72, 0x35, 0x47, 0x02, 0x20, 0x00, 0x00, 0x20,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00,
- 0x02, 0x02, 0x80, 0x8a, 0x00, 0x00, 0x20, 0x00,
- 0x08, 0x0a, 0x00, 0x80, 0x88, 0x80, 0x20, 0x14,
- 0x48, 0x7a, 0x73, 0x8b, 0x73, 0xac, 0x3e, 0xa5,
- 0x73, 0xb8, 0x3e, 0xb8, 0x3e, 0x47, 0x74, 0x5c,
- 0x74, 0x71, 0x74, 0x85, 0x74, 0xca, 0x74, 0x1b,
- 0x3f, 0x24, 0x75, 0x36, 0x4c, 0x3e, 0x75, 0x92,
- 0x4c, 0x70, 0x75, 0x9f, 0x21, 0x10, 0x76, 0xa1,
- 0x4f, 0xb8, 0x4f, 0x44, 0x50, 0xfc, 0x3f, 0x08,
- 0x40, 0xf4, 0x76, 0xf3, 0x50, 0xf2, 0x50, 0x19,
- 0x51, 0x33, 0x51, 0x1e, 0x77, 0x1f, 0x77, 0x1f,
- 0x77, 0x4a, 0x77, 0x39, 0x40, 0x8b, 0x77, 0x46,
- 0x40, 0x96, 0x40, 0x1d, 0x54, 0x4e, 0x78, 0x8c,
- 0x78, 0xcc, 0x78, 0xe3, 0x40, 0x26, 0x56, 0x56,
- 0x79, 0x9a, 0x56, 0xc5, 0x56, 0x8f, 0x79, 0xeb,
- 0x79, 0x2f, 0x41, 0x40, 0x7a, 0x4a, 0x7a, 0x4f,
- 0x7a, 0x7c, 0x59, 0xa7, 0x5a, 0xa7, 0x5a, 0xee,
- 0x7a, 0x02, 0x42, 0xab, 0x5b, 0xc6, 0x7b, 0xc9,
- 0x7b, 0x27, 0x42, 0x80, 0x5c, 0xd2, 0x7c, 0xa0,
- 0x42, 0xe8, 0x7c, 0xe3, 0x7c, 0x00, 0x7d, 0x86,
- 0x5f, 0x63, 0x7d, 0x01, 0x43, 0xc7, 0x7d, 0x02,
- 0x7e, 0x45, 0x7e, 0x34, 0x43, 0x28, 0x62, 0x47,
- 0x62, 0x59, 0x43, 0xd9, 0x62, 0x7a, 0x7f, 0x3e,
- 0x63, 0x95, 0x7f, 0xfa, 0x7f, 0x05, 0x80, 0xda,
- 0x64, 0x23, 0x65, 0x60, 0x80, 0xa8, 0x65, 0x70,
- 0x80, 0x5f, 0x33, 0xd5, 0x43, 0xb2, 0x80, 0x03,
- 0x81, 0x0b, 0x44, 0x3e, 0x81, 0xb5, 0x5a, 0xa7,
- 0x67, 0xb5, 0x67, 0x93, 0x33, 0x9c, 0x33, 0x01,
- 0x82, 0x04, 0x82, 0x9e, 0x8f, 0x6b, 0x44, 0x91,
- 0x82, 0x8b, 0x82, 0x9d, 0x82, 0xb3, 0x52, 0xb1,
- 0x82, 0xb3, 0x82, 0xbd, 0x82, 0xe6, 0x82, 0x3c,
- 0x6b, 0xe5, 0x82, 0x1d, 0x83, 0x63, 0x83, 0xad,
- 0x83, 0x23, 0x83, 0xbd, 0x83, 0xe7, 0x83, 0x57,
- 0x84, 0x53, 0x83, 0xca, 0x83, 0xcc, 0x83, 0xdc,
- 0x83, 0x36, 0x6c, 0x6b, 0x6d, 0x02, 0x00, 0x00,
- 0x20, 0x22, 0x2a, 0xa0, 0x0a, 0x00, 0x20, 0x80,
- 0x28, 0x00, 0xa8, 0x20, 0x20, 0x00, 0x02, 0x80,
- 0x22, 0x02, 0x8a, 0x08, 0x00, 0xaa, 0x00, 0x00,
- 0x00, 0x02, 0x00, 0x00, 0x28, 0xd5, 0x6c, 0x2b,
- 0x45, 0xf1, 0x84, 0xf3, 0x84, 0x16, 0x85, 0xca,
- 0x73, 0x64, 0x85, 0x2c, 0x6f, 0x5d, 0x45, 0x61,
- 0x45, 0xb1, 0x6f, 0xd2, 0x70, 0x6b, 0x45, 0x50,
- 0x86, 0x5c, 0x86, 0x67, 0x86, 0x69, 0x86, 0xa9,
- 0x86, 0x88, 0x86, 0x0e, 0x87, 0xe2, 0x86, 0x79,
- 0x87, 0x28, 0x87, 0x6b, 0x87, 0x86, 0x87, 0xd7,
- 0x45, 0xe1, 0x87, 0x01, 0x88, 0xf9, 0x45, 0x60,
- 0x88, 0x63, 0x88, 0x67, 0x76, 0xd7, 0x88, 0xde,
- 0x88, 0x35, 0x46, 0xfa, 0x88, 0xbb, 0x34, 0xae,
- 0x78, 0x66, 0x79, 0xbe, 0x46, 0xc7, 0x46, 0xa0,
- 0x8a, 0xed, 0x8a, 0x8a, 0x8b, 0x55, 0x8c, 0xa8,
- 0x7c, 0xab, 0x8c, 0xc1, 0x8c, 0x1b, 0x8d, 0x77,
- 0x8d, 0x2f, 0x7f, 0x04, 0x08, 0xcb, 0x8d, 0xbc,
- 0x8d, 0xf0, 0x8d, 0xde, 0x08, 0xd4, 0x8e, 0x38,
- 0x8f, 0xd2, 0x85, 0xed, 0x85, 0x94, 0x90, 0xf1,
- 0x90, 0x11, 0x91, 0x2e, 0x87, 0x1b, 0x91, 0x38,
- 0x92, 0xd7, 0x92, 0xd8, 0x92, 0x7c, 0x92, 0xf9,
- 0x93, 0x15, 0x94, 0xfa, 0x8b, 0x8b, 0x95, 0x95,
- 0x49, 0xb7, 0x95, 0x77, 0x8d, 0xe6, 0x49, 0xc3,
- 0x96, 0xb2, 0x5d, 0x23, 0x97, 0x45, 0x91, 0x1a,
- 0x92, 0x6e, 0x4a, 0x76, 0x4a, 0xe0, 0x97, 0x0a,
- 0x94, 0xb2, 0x4a, 0x96, 0x94, 0x0b, 0x98, 0x0b,
- 0x98, 0x29, 0x98, 0xb6, 0x95, 0xe2, 0x98, 0x33,
- 0x4b, 0x29, 0x99, 0xa7, 0x99, 0xc2, 0x99, 0xfe,
- 0x99, 0xce, 0x4b, 0x30, 0x9b, 0x12, 0x9b, 0x40,
- 0x9c, 0xfd, 0x9c, 0xce, 0x4c, 0xed, 0x4c, 0x67,
- 0x9d, 0xce, 0xa0, 0xf8, 0x4c, 0x05, 0xa1, 0x0e,
- 0xa2, 0x91, 0xa2, 0xbb, 0x9e, 0x56, 0x4d, 0xf9,
- 0x9e, 0xfe, 0x9e, 0x05, 0x9f, 0x0f, 0x9f, 0x16,
- 0x9f, 0x3b, 0x9f, 0x00, 0xa6, 0x02, 0x88, 0xa0,
- 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x28, 0x00,
- 0x08, 0xa0, 0x80, 0xa0, 0x80, 0x00, 0x80, 0x80,
- 0x00, 0x0a, 0x88, 0x80, 0x00, 0x80, 0x00, 0x20,
- 0x2a, 0x00, 0x80,
- };
- static const uint16_t unicode_comp_table[965] = {
- 0x4a01, 0x49c0, 0x4a02, 0x0280, 0x0281, 0x0282, 0x0283, 0x02c0,
- 0x02c2, 0x0a00, 0x0284, 0x2442, 0x0285, 0x07c0, 0x0980, 0x0982,
- 0x2440, 0x2280, 0x02c4, 0x2282, 0x2284, 0x2286, 0x02c6, 0x02c8,
- 0x02ca, 0x02cc, 0x0287, 0x228a, 0x02ce, 0x228c, 0x2290, 0x2292,
- 0x228e, 0x0288, 0x0289, 0x028a, 0x2482, 0x0300, 0x0302, 0x0304,
- 0x028b, 0x2480, 0x0308, 0x0984, 0x0986, 0x2458, 0x0a02, 0x0306,
- 0x2298, 0x229a, 0x229e, 0x0900, 0x030a, 0x22a0, 0x030c, 0x030e,
- 0x0840, 0x0310, 0x0312, 0x22a2, 0x22a6, 0x09c0, 0x22a4, 0x22a8,
- 0x22aa, 0x028c, 0x028d, 0x028e, 0x0340, 0x0342, 0x0344, 0x0380,
- 0x028f, 0x248e, 0x07c2, 0x0988, 0x098a, 0x2490, 0x0346, 0x22ac,
- 0x0400, 0x22b0, 0x0842, 0x22b2, 0x0402, 0x22b4, 0x0440, 0x0444,
- 0x22b6, 0x0442, 0x22c2, 0x22c0, 0x22c4, 0x22c6, 0x22c8, 0x0940,
- 0x04c0, 0x0291, 0x22ca, 0x04c4, 0x22cc, 0x04c2, 0x22d0, 0x22ce,
- 0x0292, 0x0293, 0x0294, 0x0295, 0x0540, 0x0542, 0x0a08, 0x0296,
- 0x2494, 0x0544, 0x07c4, 0x098c, 0x098e, 0x06c0, 0x2492, 0x0844,
- 0x2308, 0x230a, 0x0580, 0x230c, 0x0584, 0x0990, 0x0992, 0x230e,
- 0x0582, 0x2312, 0x0586, 0x0588, 0x2314, 0x058c, 0x2316, 0x0998,
- 0x058a, 0x231e, 0x0590, 0x2320, 0x099a, 0x058e, 0x2324, 0x2322,
- 0x0299, 0x029a, 0x029b, 0x05c0, 0x05c2, 0x05c4, 0x029c, 0x24ac,
- 0x05c6, 0x05c8, 0x07c6, 0x0994, 0x0996, 0x0700, 0x24aa, 0x2326,
- 0x05ca, 0x232a, 0x2328, 0x2340, 0x2342, 0x2344, 0x2346, 0x05cc,
- 0x234a, 0x2348, 0x234c, 0x234e, 0x2350, 0x24b8, 0x029d, 0x05ce,
- 0x24be, 0x0a0c, 0x2352, 0x0600, 0x24bc, 0x24ba, 0x0640, 0x2354,
- 0x0642, 0x0644, 0x2356, 0x2358, 0x02a0, 0x02a1, 0x02a2, 0x02a3,
- 0x02c1, 0x02c3, 0x0a01, 0x02a4, 0x2443, 0x02a5, 0x07c1, 0x0981,
- 0x0983, 0x2441, 0x2281, 0x02c5, 0x2283, 0x2285, 0x2287, 0x02c7,
- 0x02c9, 0x02cb, 0x02cd, 0x02a7, 0x228b, 0x02cf, 0x228d, 0x2291,
- 0x2293, 0x228f, 0x02a8, 0x02a9, 0x02aa, 0x2483, 0x0301, 0x0303,
- 0x0305, 0x02ab, 0x2481, 0x0309, 0x0985, 0x0987, 0x2459, 0x0a03,
- 0x0307, 0x2299, 0x229b, 0x229f, 0x0901, 0x030b, 0x22a1, 0x030d,
- 0x030f, 0x0841, 0x0311, 0x0313, 0x22a3, 0x22a7, 0x09c1, 0x22a5,
- 0x22a9, 0x22ab, 0x2380, 0x02ac, 0x02ad, 0x02ae, 0x0341, 0x0343,
- 0x0345, 0x02af, 0x248f, 0x07c3, 0x0989, 0x098b, 0x2491, 0x0347,
- 0x22ad, 0x0401, 0x0884, 0x22b1, 0x0843, 0x22b3, 0x0403, 0x22b5,
- 0x0441, 0x0445, 0x22b7, 0x0443, 0x22c3, 0x22c1, 0x22c5, 0x22c7,
- 0x22c9, 0x0941, 0x04c1, 0x02b1, 0x22cb, 0x04c5, 0x22cd, 0x04c3,
- 0x22d1, 0x22cf, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x0541, 0x0543,
- 0x0a09, 0x02b6, 0x2495, 0x0545, 0x07c5, 0x098d, 0x098f, 0x06c1,
- 0x2493, 0x0845, 0x2309, 0x230b, 0x0581, 0x230d, 0x0585, 0x0991,
- 0x0993, 0x230f, 0x0583, 0x2313, 0x0587, 0x0589, 0x2315, 0x058d,
- 0x2317, 0x0999, 0x058b, 0x231f, 0x2381, 0x0591, 0x2321, 0x099b,
- 0x058f, 0x2325, 0x2323, 0x02b9, 0x02ba, 0x02bb, 0x05c1, 0x05c3,
- 0x05c5, 0x02bc, 0x24ad, 0x05c7, 0x05c9, 0x07c7, 0x0995, 0x0997,
- 0x0701, 0x24ab, 0x2327, 0x05cb, 0x232b, 0x2329, 0x2341, 0x2343,
- 0x2345, 0x2347, 0x05cd, 0x234b, 0x2349, 0x2382, 0x234d, 0x234f,
- 0x2351, 0x24b9, 0x02bd, 0x05cf, 0x24bf, 0x0a0d, 0x2353, 0x02bf,
- 0x24bd, 0x2383, 0x24bb, 0x0641, 0x2355, 0x0643, 0x0645, 0x2357,
- 0x2359, 0x3101, 0x0c80, 0x2e00, 0x2446, 0x2444, 0x244a, 0x2448,
- 0x0800, 0x0942, 0x0944, 0x0804, 0x2288, 0x2486, 0x2484, 0x248a,
- 0x2488, 0x22ae, 0x2498, 0x2496, 0x249c, 0x249a, 0x2300, 0x0a06,
- 0x2302, 0x0a04, 0x0946, 0x07ce, 0x07ca, 0x07c8, 0x07cc, 0x2447,
- 0x2445, 0x244b, 0x2449, 0x0801, 0x0943, 0x0945, 0x0805, 0x2289,
- 0x2487, 0x2485, 0x248b, 0x2489, 0x22af, 0x2499, 0x2497, 0x249d,
- 0x249b, 0x2301, 0x0a07, 0x2303, 0x0a05, 0x0947, 0x07cf, 0x07cb,
- 0x07c9, 0x07cd, 0x2450, 0x244e, 0x2454, 0x2452, 0x2451, 0x244f,
- 0x2455, 0x2453, 0x2294, 0x2296, 0x2295, 0x2297, 0x2304, 0x2306,
- 0x2305, 0x2307, 0x2318, 0x2319, 0x231a, 0x231b, 0x232c, 0x232d,
- 0x232e, 0x232f, 0x2400, 0x24a2, 0x24a0, 0x24a6, 0x24a4, 0x24a8,
- 0x24a3, 0x24a1, 0x24a7, 0x24a5, 0x24a9, 0x24b0, 0x24ae, 0x24b4,
- 0x24b2, 0x24b6, 0x24b1, 0x24af, 0x24b5, 0x24b3, 0x24b7, 0x0882,
- 0x0880, 0x0881, 0x0802, 0x0803, 0x229c, 0x229d, 0x0a0a, 0x0a0b,
- 0x0883, 0x0b40, 0x2c8a, 0x0c81, 0x2c89, 0x2c88, 0x2540, 0x2541,
- 0x2d00, 0x2e07, 0x0d00, 0x2640, 0x2641, 0x2e80, 0x0d01, 0x26c8,
- 0x26c9, 0x2f00, 0x2f84, 0x0d02, 0x2f83, 0x2f82, 0x0d40, 0x26d8,
- 0x26d9, 0x3186, 0x0d04, 0x2740, 0x2741, 0x3100, 0x3086, 0x0d06,
- 0x3085, 0x3084, 0x0d41, 0x2840, 0x3200, 0x0d07, 0x284f, 0x2850,
- 0x3280, 0x2c84, 0x2e03, 0x2857, 0x0d42, 0x2c81, 0x2c80, 0x24c0,
- 0x24c1, 0x2c86, 0x2c83, 0x28c0, 0x0d43, 0x25c0, 0x25c1, 0x2940,
- 0x0d44, 0x26c0, 0x26c1, 0x2e05, 0x2e02, 0x29c0, 0x0d45, 0x2f05,
- 0x2f04, 0x0d80, 0x26d0, 0x26d1, 0x2f80, 0x2a40, 0x0d82, 0x26e0,
- 0x26e1, 0x3080, 0x3081, 0x2ac0, 0x0d83, 0x3004, 0x3003, 0x0d81,
- 0x27c0, 0x27c1, 0x3082, 0x2b40, 0x0d84, 0x2847, 0x2848, 0x3184,
- 0x3181, 0x2f06, 0x0d08, 0x2f81, 0x3005, 0x0d46, 0x3083, 0x3182,
- 0x0e00, 0x0e01, 0x0f40, 0x1180, 0x1182, 0x0f03, 0x0f00, 0x11c0,
- 0x0f01, 0x1140, 0x1202, 0x1204, 0x0f81, 0x1240, 0x0fc0, 0x1242,
- 0x0f80, 0x1244, 0x1284, 0x0f82, 0x1286, 0x1288, 0x128a, 0x12c0,
- 0x1282, 0x1181, 0x1183, 0x1043, 0x1040, 0x11c1, 0x1041, 0x1141,
- 0x1203, 0x1205, 0x10c1, 0x1241, 0x1000, 0x1243, 0x10c0, 0x1245,
- 0x1285, 0x10c2, 0x1287, 0x1289, 0x128b, 0x12c1, 0x1283, 0x1080,
- 0x1100, 0x1101, 0x1200, 0x1201, 0x1280, 0x1281, 0x1340, 0x1341,
- 0x1343, 0x1342, 0x1344, 0x13c2, 0x1400, 0x13c0, 0x1440, 0x1480,
- 0x14c0, 0x1540, 0x1541, 0x1740, 0x1700, 0x1741, 0x17c0, 0x1800,
- 0x1802, 0x1801, 0x1840, 0x1880, 0x1900, 0x18c0, 0x18c1, 0x1901,
- 0x1940, 0x1942, 0x1941, 0x1980, 0x19c0, 0x19c2, 0x19c1, 0x1c80,
- 0x1cc0, 0x1dc0, 0x1f80, 0x2000, 0x2002, 0x2004, 0x2006, 0x2008,
- 0x2040, 0x2080, 0x2082, 0x20c0, 0x20c1, 0x2100, 0x22b8, 0x22b9,
- 0x2310, 0x2311, 0x231c, 0x231d, 0x244c, 0x2456, 0x244d, 0x2457,
- 0x248c, 0x248d, 0x249e, 0x249f, 0x2500, 0x2502, 0x2504, 0x2bc0,
- 0x2501, 0x2503, 0x2505, 0x2bc1, 0x2bc2, 0x2bc3, 0x2bc4, 0x2bc5,
- 0x2bc6, 0x2bc7, 0x2580, 0x2582, 0x2584, 0x2bc8, 0x2581, 0x2583,
- 0x2585, 0x2bc9, 0x2bca, 0x2bcb, 0x2bcc, 0x2bcd, 0x2bce, 0x2bcf,
- 0x2600, 0x2602, 0x2601, 0x2603, 0x2680, 0x2682, 0x2681, 0x2683,
- 0x26c2, 0x26c4, 0x26c6, 0x2c00, 0x26c3, 0x26c5, 0x26c7, 0x2c01,
- 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x26ca, 0x26cc,
- 0x26ce, 0x2c08, 0x26cb, 0x26cd, 0x26cf, 0x2c09, 0x2c0a, 0x2c0b,
- 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x26d2, 0x26d4, 0x26d6, 0x26d3,
- 0x26d5, 0x26d7, 0x26da, 0x26dc, 0x26de, 0x26db, 0x26dd, 0x26df,
- 0x2700, 0x2702, 0x2701, 0x2703, 0x2780, 0x2782, 0x2781, 0x2783,
- 0x2800, 0x2802, 0x2804, 0x2801, 0x2803, 0x2805, 0x2842, 0x2844,
- 0x2846, 0x2849, 0x284b, 0x284d, 0x2c40, 0x284a, 0x284c, 0x284e,
- 0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47, 0x2851,
- 0x2853, 0x2855, 0x2c48, 0x2852, 0x2854, 0x2856, 0x2c49, 0x2c4a,
- 0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f, 0x2c82, 0x2e01, 0x3180,
- 0x2c87, 0x2f01, 0x2f02, 0x2f03, 0x2e06, 0x3185, 0x3000, 0x3001,
- 0x3002, 0x4640, 0x4641, 0x4680, 0x46c0, 0x46c2, 0x46c1, 0x4700,
- 0x4740, 0x4780, 0x47c0, 0x47c2, 0x4900, 0x4940, 0x4980, 0x4982,
- 0x4a00, 0x49c2, 0x4a03, 0x4a04, 0x4a40, 0x4a41, 0x4a80, 0x4a81,
- 0x4ac0, 0x4ac1, 0x4bc0, 0x4bc1, 0x4b00, 0x4b01, 0x4b40, 0x4b41,
- 0x4bc2, 0x4bc3, 0x4b80, 0x4b81, 0x4b82, 0x4b83, 0x4c00, 0x4c01,
- 0x4c02, 0x4c03, 0x5600, 0x5440, 0x5442, 0x5444, 0x5446, 0x5448,
- 0x544a, 0x544c, 0x544e, 0x5450, 0x5452, 0x5454, 0x5456, 0x5480,
- 0x5482, 0x5484, 0x54c0, 0x54c1, 0x5500, 0x5501, 0x5540, 0x5541,
- 0x5580, 0x5581, 0x55c0, 0x55c1, 0x5680, 0x58c0, 0x5700, 0x5702,
- 0x5704, 0x5706, 0x5708, 0x570a, 0x570c, 0x570e, 0x5710, 0x5712,
- 0x5714, 0x5716, 0x5740, 0x5742, 0x5744, 0x5780, 0x5781, 0x57c0,
- 0x57c1, 0x5800, 0x5801, 0x5840, 0x5841, 0x5880, 0x5881, 0x5900,
- 0x5901, 0x5902, 0x5903, 0x5940, 0x8ec0, 0x8f00, 0x8fc0, 0x8fc2,
- 0x9000, 0x9040, 0x9041, 0x9080, 0x9081, 0x90c0, 0x90c2, 0x9100,
- 0x9140, 0x9182, 0x9180, 0x9183, 0x91c1, 0x91c0, 0x91c3, 0x9200,
- 0x9201, 0x9240, 0x9280, 0x9282, 0x9284, 0x9281, 0x9285, 0x9287,
- 0x9286, 0x9283, 0x92c1, 0x92c0, 0x92c2,
- };
- typedef enum {
- UNICODE_GC_Cn,
- UNICODE_GC_Lu,
- UNICODE_GC_Ll,
- UNICODE_GC_Lt,
- UNICODE_GC_Lm,
- UNICODE_GC_Lo,
- UNICODE_GC_Mn,
- UNICODE_GC_Mc,
- UNICODE_GC_Me,
- UNICODE_GC_Nd,
- UNICODE_GC_Nl,
- UNICODE_GC_No,
- UNICODE_GC_Sm,
- UNICODE_GC_Sc,
- UNICODE_GC_Sk,
- UNICODE_GC_So,
- UNICODE_GC_Pc,
- UNICODE_GC_Pd,
- UNICODE_GC_Ps,
- UNICODE_GC_Pe,
- UNICODE_GC_Pi,
- UNICODE_GC_Pf,
- UNICODE_GC_Po,
- UNICODE_GC_Zs,
- UNICODE_GC_Zl,
- UNICODE_GC_Zp,
- UNICODE_GC_Cc,
- UNICODE_GC_Cf,
- UNICODE_GC_Cs,
- UNICODE_GC_Co,
- UNICODE_GC_LC,
- UNICODE_GC_L,
- UNICODE_GC_M,
- UNICODE_GC_N,
- UNICODE_GC_S,
- UNICODE_GC_P,
- UNICODE_GC_Z,
- UNICODE_GC_C,
- UNICODE_GC_COUNT,
- } UnicodeGCEnum;
- static const char unicode_gc_name_table[] =
- "Cn,Unassigned" "\0"
- "Lu,Uppercase_Letter" "\0"
- "Ll,Lowercase_Letter" "\0"
- "Lt,Titlecase_Letter" "\0"
- "Lm,Modifier_Letter" "\0"
- "Lo,Other_Letter" "\0"
- "Mn,Nonspacing_Mark" "\0"
- "Mc,Spacing_Mark" "\0"
- "Me,Enclosing_Mark" "\0"
- "Nd,Decimal_Number,digit" "\0"
- "Nl,Letter_Number" "\0"
- "No,Other_Number" "\0"
- "Sm,Math_Symbol" "\0"
- "Sc,Currency_Symbol" "\0"
- "Sk,Modifier_Symbol" "\0"
- "So,Other_Symbol" "\0"
- "Pc,Connector_Punctuation" "\0"
- "Pd,Dash_Punctuation" "\0"
- "Ps,Open_Punctuation" "\0"
- "Pe,Close_Punctuation" "\0"
- "Pi,Initial_Punctuation" "\0"
- "Pf,Final_Punctuation" "\0"
- "Po,Other_Punctuation" "\0"
- "Zs,Space_Separator" "\0"
- "Zl,Line_Separator" "\0"
- "Zp,Paragraph_Separator" "\0"
- "Cc,Control,cntrl" "\0"
- "Cf,Format" "\0"
- "Cs,Surrogate" "\0"
- "Co,Private_Use" "\0"
- "LC,Cased_Letter" "\0"
- "L,Letter" "\0"
- "M,Mark,Combining_Mark" "\0"
- "N,Number" "\0"
- "S,Symbol" "\0"
- "P,Punctuation,punct" "\0"
- "Z,Separator" "\0"
- "C,Other" "\0"
- ;
- static const uint8_t unicode_gc_table[4070] = {
- 0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13,
- 0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36,
- 0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e,
- 0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c,
- 0xfa, 0x19, 0x17, 0x16, 0x6d, 0x0f, 0x16, 0x0e,
- 0x0f, 0x05, 0x14, 0x0c, 0x1b, 0x0f, 0x0e, 0x0f,
- 0x0c, 0x2b, 0x0e, 0x02, 0x36, 0x0e, 0x0b, 0x05,
- 0x15, 0x4b, 0x16, 0xe1, 0x0f, 0x0c, 0xc1, 0xe2,
- 0x10, 0x0c, 0xe2, 0x00, 0xff, 0x30, 0x02, 0xff,
- 0x08, 0x02, 0xff, 0x27, 0xbf, 0x22, 0x21, 0x02,
- 0x5f, 0x5f, 0x21, 0x22, 0x61, 0x02, 0x21, 0x02,
- 0x41, 0x42, 0x21, 0x02, 0x21, 0x02, 0x9f, 0x7f,
- 0x02, 0x5f, 0x5f, 0x21, 0x02, 0x5f, 0x3f, 0x02,
- 0x05, 0x3f, 0x22, 0x65, 0x01, 0x03, 0x02, 0x01,
- 0x03, 0x02, 0x01, 0x03, 0x02, 0xff, 0x08, 0x02,
- 0xff, 0x0a, 0x02, 0x01, 0x03, 0x02, 0x5f, 0x21,
- 0x02, 0xff, 0x32, 0xa2, 0x21, 0x02, 0x21, 0x22,
- 0x5f, 0x41, 0x02, 0xff, 0x00, 0xe2, 0x3c, 0x05,
- 0xe2, 0x13, 0xe4, 0x0a, 0x6e, 0xe4, 0x04, 0xee,
- 0x06, 0x84, 0xce, 0x04, 0x0e, 0x04, 0xee, 0x09,
- 0xe6, 0x68, 0x7f, 0x04, 0x0e, 0x3f, 0x20, 0x04,
- 0x42, 0x16, 0x01, 0x60, 0x2e, 0x01, 0x16, 0x41,
- 0x00, 0x01, 0x00, 0x21, 0x02, 0xe1, 0x09, 0x00,
- 0xe1, 0x01, 0xe2, 0x1b, 0x3f, 0x02, 0x41, 0x42,
- 0xff, 0x10, 0x62, 0x3f, 0x0c, 0x5f, 0x3f, 0x02,
- 0xe1, 0x2b, 0xe2, 0x28, 0xff, 0x1a, 0x0f, 0x86,
- 0x28, 0xff, 0x2f, 0xff, 0x06, 0x02, 0xff, 0x58,
- 0x00, 0xe1, 0x1e, 0x20, 0x04, 0xb6, 0xe2, 0x21,
- 0x16, 0x11, 0x20, 0x2f, 0x0d, 0x00, 0xe6, 0x25,
- 0x11, 0x06, 0x16, 0x26, 0x16, 0x26, 0x16, 0x06,
- 0xe0, 0x00, 0xe5, 0x13, 0x60, 0x65, 0x36, 0xe0,
- 0x03, 0xbb, 0x4c, 0x36, 0x0d, 0x36, 0x2f, 0xe6,
- 0x03, 0x16, 0x1b, 0x56, 0xe5, 0x18, 0x04, 0xe5,
- 0x02, 0xe6, 0x0d, 0xe9, 0x02, 0x76, 0x25, 0x06,
- 0xe5, 0x5b, 0x16, 0x05, 0xc6, 0x1b, 0x0f, 0xa6,
- 0x24, 0x26, 0x0f, 0x66, 0x25, 0xe9, 0x02, 0x45,
- 0x2f, 0x05, 0xf6, 0x06, 0x00, 0x1b, 0x05, 0x06,
- 0xe5, 0x16, 0xe6, 0x13, 0x20, 0xe5, 0x51, 0xe6,
- 0x03, 0x05, 0xe0, 0x06, 0xe9, 0x02, 0xe5, 0x19,
- 0xe6, 0x01, 0x24, 0x0f, 0x56, 0x04, 0x20, 0x06,
- 0x2d, 0xe5, 0x0e, 0x66, 0x04, 0xe6, 0x01, 0x04,
- 0x46, 0x04, 0x86, 0x20, 0xf6, 0x07, 0x00, 0xe5,
- 0x11, 0x46, 0x20, 0x16, 0x00, 0xe5, 0x03, 0x80,
- 0xe5, 0x10, 0x0e, 0xa5, 0x00, 0x3b, 0x80, 0xe6,
- 0x01, 0xe5, 0x21, 0x04, 0xe6, 0x10, 0x1b, 0xe6,
- 0x18, 0x07, 0xe5, 0x2e, 0x06, 0x07, 0x06, 0x05,
- 0x47, 0xe6, 0x00, 0x67, 0x06, 0x27, 0x05, 0xc6,
- 0xe5, 0x02, 0x26, 0x36, 0xe9, 0x02, 0x16, 0x04,
- 0xe5, 0x07, 0x06, 0x27, 0x00, 0xe5, 0x00, 0x20,
- 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x05,
- 0x40, 0x65, 0x20, 0x06, 0x05, 0x47, 0x66, 0x20,
- 0x27, 0x20, 0x27, 0x06, 0x05, 0xe0, 0x00, 0x07,
- 0x60, 0x25, 0x00, 0x45, 0x26, 0x20, 0xe9, 0x02,
- 0x25, 0x2d, 0xab, 0x0f, 0x0d, 0x05, 0x16, 0x06,
- 0x20, 0x26, 0x07, 0x00, 0xa5, 0x60, 0x25, 0x20,
- 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x25,
- 0x00, 0x25, 0x20, 0x06, 0x00, 0x47, 0x26, 0x60,
- 0x26, 0x20, 0x46, 0x40, 0x06, 0xc0, 0x65, 0x00,
- 0x05, 0xc0, 0xe9, 0x02, 0x26, 0x45, 0x06, 0x16,
- 0xe0, 0x02, 0x26, 0x07, 0x00, 0xe5, 0x01, 0x00,
- 0x45, 0x00, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25,
- 0x00, 0x85, 0x20, 0x06, 0x05, 0x47, 0x86, 0x00,
- 0x26, 0x07, 0x00, 0x27, 0x06, 0x20, 0x05, 0xe0,
- 0x07, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x16, 0x0d,
- 0xc0, 0x05, 0xa6, 0x00, 0x06, 0x27, 0x00, 0xe5,
- 0x00, 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5,
- 0x00, 0x25, 0x00, 0x85, 0x20, 0x06, 0x05, 0x07,
- 0x06, 0x07, 0x66, 0x20, 0x27, 0x20, 0x27, 0x06,
- 0xc0, 0x26, 0x07, 0x60, 0x25, 0x00, 0x45, 0x26,
- 0x20, 0xe9, 0x02, 0x0f, 0x05, 0xab, 0xe0, 0x02,
- 0x06, 0x05, 0x00, 0xa5, 0x40, 0x45, 0x00, 0x65,
- 0x40, 0x25, 0x00, 0x05, 0x00, 0x25, 0x40, 0x25,
- 0x40, 0x45, 0x40, 0xe5, 0x04, 0x60, 0x27, 0x06,
- 0x27, 0x40, 0x47, 0x00, 0x47, 0x06, 0x20, 0x05,
- 0xa0, 0x07, 0xe0, 0x06, 0xe9, 0x02, 0x4b, 0xaf,
- 0x0d, 0x0f, 0x80, 0x06, 0x47, 0x06, 0xe5, 0x00,
- 0x00, 0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x08,
- 0x20, 0x06, 0x05, 0x46, 0x67, 0x00, 0x46, 0x00,
- 0x66, 0xc0, 0x26, 0x00, 0x45, 0x20, 0x05, 0x20,
- 0x25, 0x26, 0x20, 0xe9, 0x02, 0xc0, 0x16, 0xcb,
- 0x0f, 0x05, 0x06, 0x27, 0x16, 0xe5, 0x00, 0x00,
- 0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x02, 0x00,
- 0x85, 0x20, 0x06, 0x05, 0x07, 0x06, 0x87, 0x00,
- 0x06, 0x27, 0x00, 0x27, 0x26, 0xc0, 0x27, 0xa0,
- 0x25, 0x00, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x00,
- 0x25, 0x07, 0xe0, 0x04, 0x26, 0x27, 0xe5, 0x01,
- 0x00, 0x45, 0x00, 0xe5, 0x21, 0x26, 0x05, 0x47,
- 0x66, 0x00, 0x47, 0x00, 0x47, 0x06, 0x05, 0x0f,
- 0x60, 0x45, 0x07, 0xcb, 0x45, 0x26, 0x20, 0xe9,
- 0x02, 0xeb, 0x01, 0x0f, 0xa5, 0x00, 0x06, 0x27,
- 0x00, 0xe5, 0x0a, 0x40, 0xe5, 0x10, 0x00, 0xe5,
- 0x01, 0x00, 0x05, 0x20, 0xc5, 0x40, 0x06, 0x60,
- 0x47, 0x46, 0x00, 0x06, 0x00, 0xe7, 0x00, 0xa0,
- 0xe9, 0x02, 0x20, 0x27, 0x16, 0xe0, 0x04, 0xe5,
- 0x28, 0x06, 0x25, 0xc6, 0x60, 0x0d, 0xa5, 0x04,
- 0xe6, 0x00, 0x16, 0xe9, 0x02, 0x36, 0xe0, 0x1d,
- 0x25, 0x00, 0x05, 0x00, 0x85, 0x00, 0xe5, 0x10,
- 0x00, 0x05, 0x00, 0xe5, 0x02, 0x06, 0x25, 0xe6,
- 0x01, 0x05, 0x20, 0x85, 0x00, 0x04, 0x00, 0xc6,
- 0x00, 0xe9, 0x02, 0x20, 0x65, 0xe0, 0x18, 0x05,
- 0x4f, 0xf6, 0x07, 0x0f, 0x16, 0x4f, 0x26, 0xaf,
- 0xe9, 0x02, 0xeb, 0x02, 0x0f, 0x06, 0x0f, 0x06,
- 0x0f, 0x06, 0x12, 0x13, 0x12, 0x13, 0x27, 0xe5,
- 0x00, 0x00, 0xe5, 0x1c, 0x60, 0xe6, 0x06, 0x07,
- 0x86, 0x16, 0x26, 0x85, 0xe6, 0x03, 0x00, 0xe6,
- 0x1c, 0x00, 0xef, 0x00, 0x06, 0xaf, 0x00, 0x2f,
- 0x96, 0x6f, 0x36, 0xe0, 0x1d, 0xe5, 0x23, 0x27,
- 0x66, 0x07, 0xa6, 0x07, 0x26, 0x27, 0x26, 0x05,
- 0xe9, 0x02, 0xb6, 0xa5, 0x27, 0x26, 0x65, 0x46,
- 0x05, 0x47, 0x25, 0xc7, 0x45, 0x66, 0xe5, 0x05,
- 0x06, 0x27, 0x26, 0xa7, 0x06, 0x05, 0x07, 0xe9,
- 0x02, 0x47, 0x06, 0x2f, 0xe1, 0x1e, 0x00, 0x01,
- 0x80, 0x01, 0x20, 0xe2, 0x23, 0x16, 0x04, 0x42,
- 0xe5, 0x80, 0xc1, 0x00, 0x65, 0x20, 0xc5, 0x00,
- 0x05, 0x00, 0x65, 0x20, 0xe5, 0x21, 0x00, 0x65,
- 0x20, 0xe5, 0x19, 0x00, 0x65, 0x20, 0xc5, 0x00,
- 0x05, 0x00, 0x65, 0x20, 0xe5, 0x07, 0x00, 0xe5,
- 0x31, 0x00, 0x65, 0x20, 0xe5, 0x3b, 0x20, 0x46,
- 0xf6, 0x01, 0xeb, 0x0c, 0x40, 0xe5, 0x08, 0xef,
- 0x02, 0xa0, 0xe1, 0x4e, 0x20, 0xa2, 0x20, 0x11,
- 0xe5, 0x81, 0xe4, 0x0f, 0x16, 0xe5, 0x09, 0x17,
- 0xe5, 0x12, 0x12, 0x13, 0x40, 0xe5, 0x43, 0x56,
- 0x4a, 0xe5, 0x00, 0xc0, 0xe5, 0x0a, 0x46, 0x07,
- 0xe0, 0x01, 0xe5, 0x0b, 0x26, 0x07, 0x36, 0xe0,
- 0x01, 0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5, 0x05,
- 0x00, 0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5, 0x2c,
- 0x26, 0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27, 0xe6,
- 0x03, 0x56, 0x04, 0x56, 0x0d, 0x05, 0x06, 0x20,
- 0xe9, 0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6, 0x11,
- 0x76, 0x46, 0x1b, 0x06, 0xe9, 0x02, 0xa0, 0xe5,
- 0x1b, 0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26, 0xe5,
- 0x1a, 0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0, 0x02,
- 0xe5, 0x17, 0x00, 0x46, 0x67, 0x26, 0x47, 0x60,
- 0x27, 0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40, 0x36,
- 0xe9, 0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0, 0x03,
- 0xe5, 0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9, 0x02,
- 0x0b, 0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26, 0x27,
- 0x06, 0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06, 0x07,
- 0xc6, 0x00, 0x06, 0x07, 0x06, 0x27, 0xe6, 0x00,
- 0xa7, 0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02, 0xa0,
- 0xe9, 0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, 0xe6,
- 0x06, 0x08, 0xe6, 0x08, 0xe0, 0x29, 0x66, 0x07,
- 0xe5, 0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87,
- 0x06, 0x27, 0xe5, 0x00, 0x00, 0x36, 0xe9, 0x02,
- 0xd6, 0xef, 0x02, 0xe6, 0x01, 0xef, 0x01, 0x56,
- 0x26, 0x07, 0xe5, 0x16, 0x07, 0x66, 0x27, 0x26,
- 0x07, 0x46, 0x25, 0xe9, 0x02, 0xe5, 0x24, 0x06,
- 0x07, 0x26, 0x47, 0x06, 0x07, 0x46, 0x27, 0xe0,
- 0x00, 0x76, 0xe5, 0x1c, 0xe7, 0x00, 0xe6, 0x00,
- 0x27, 0x26, 0x40, 0x96, 0xe9, 0x02, 0x40, 0x45,
- 0xe9, 0x02, 0xe5, 0x16, 0xa4, 0x36, 0xe2, 0x01,
- 0x3f, 0x80, 0xe1, 0x23, 0x20, 0x41, 0xf6, 0x00,
- 0xe0, 0x00, 0x46, 0x16, 0xe6, 0x05, 0x07, 0xc6,
- 0x65, 0x06, 0xa5, 0x06, 0x25, 0x07, 0x26, 0x05,
- 0x80, 0xe2, 0x24, 0xe4, 0x37, 0xe2, 0x05, 0x04,
- 0xe2, 0x1a, 0xe4, 0x1d, 0xe6, 0x38, 0xff, 0x80,
- 0x0e, 0xe2, 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1,
- 0x00, 0xa2, 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1,
- 0x00, 0xe2, 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1,
- 0x20, 0xe2, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06,
- 0x20, 0xe2, 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3,
- 0x00, 0xe2, 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22,
- 0x61, 0x03, 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22,
- 0x61, 0x03, 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00,
- 0x4e, 0xe2, 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00,
- 0x22, 0x61, 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b,
- 0xb1, 0x36, 0x14, 0x15, 0x12, 0x34, 0x15, 0x12,
- 0x14, 0xf6, 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6,
- 0x01, 0x14, 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12,
- 0x13, 0xf6, 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02,
- 0x17, 0x9b, 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20,
- 0xab, 0x4c, 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c,
- 0x12, 0x13, 0x00, 0xe4, 0x05, 0x40, 0xed, 0x19,
- 0xe0, 0x07, 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6,
- 0x04, 0xe0, 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f,
- 0x02, 0x41, 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f,
- 0x0c, 0x81, 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01,
- 0x0f, 0x61, 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02,
- 0x2f, 0x22, 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c,
- 0x2f, 0x02, 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f,
- 0x6a, 0x0b, 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f,
- 0x0c, 0x2f, 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef,
- 0x17, 0x2c, 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17,
- 0xec, 0x80, 0x84, 0xef, 0x00, 0x12, 0x13, 0x12,
- 0x13, 0xef, 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef,
- 0x49, 0x0c, 0xef, 0x16, 0xec, 0x11, 0xef, 0x20,
- 0xac, 0xef, 0x40, 0xe0, 0x0e, 0xef, 0x03, 0xe0,
- 0x0d, 0xeb, 0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef,
- 0x80, 0x2f, 0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e,
- 0xec, 0x00, 0xef, 0x67, 0x0c, 0xef, 0x80, 0x70,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0xeb, 0x16,
- 0xef, 0x24, 0x8c, 0x12, 0x13, 0xec, 0x17, 0x12,
- 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
- 0x13, 0xec, 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0xec, 0x37,
- 0x12, 0x13, 0x12, 0x13, 0xec, 0x18, 0x12, 0x13,
- 0xec, 0x80, 0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f,
- 0xac, 0xef, 0x1f, 0x20, 0xef, 0x18, 0x00, 0xef,
- 0x61, 0xe1, 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22,
- 0xdf, 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24,
- 0x41, 0x02, 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46,
- 0x3f, 0x80, 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00,
- 0x02, 0x80, 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04,
- 0x16, 0xe0, 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01,
- 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00,
- 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00,
- 0xe6, 0x18, 0x36, 0x14, 0x15, 0x14, 0x15, 0x56,
- 0x14, 0x15, 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11,
- 0x36, 0x11, 0x16, 0x14, 0x15, 0x36, 0x14, 0x15,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
- 0x96, 0x04, 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16,
- 0x12, 0xf6, 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12,
- 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a,
- 0xef, 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef,
- 0x80, 0x4e, 0xe0, 0x12, 0xef, 0x08, 0x17, 0x56,
- 0x0f, 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, 0x13,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, 0x12,
- 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x11,
- 0x12, 0x33, 0x0f, 0xea, 0x01, 0x66, 0x27, 0x11,
- 0x84, 0x2f, 0x4a, 0x04, 0x05, 0x16, 0x2f, 0x00,
- 0xe5, 0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05, 0x11,
- 0xe5, 0x52, 0x16, 0x44, 0x05, 0x80, 0xe5, 0x23,
- 0x00, 0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef, 0x02,
- 0xe5, 0x18, 0xef, 0x1e, 0xe0, 0x01, 0x0f, 0xe5,
- 0x08, 0xef, 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16,
- 0xeb, 0x00, 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb,
- 0x02, 0xef, 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8,
- 0xe5, 0x99, 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11,
- 0x8d, 0x04, 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f,
- 0xe0, 0x01, 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80,
- 0x84, 0x04, 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25,
- 0xe0, 0x0c, 0xff, 0x26, 0x05, 0x06, 0x48, 0x16,
- 0xe6, 0x02, 0x16, 0x04, 0xff, 0x14, 0x24, 0x26,
- 0xe5, 0x3e, 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00,
- 0xee, 0x0f, 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22,
- 0xff, 0x36, 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02,
- 0x04, 0x2e, 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d,
- 0x61, 0x02, 0x81, 0x02, 0xff, 0x07, 0x41, 0x02,
- 0x5f, 0x3f, 0x20, 0x3f, 0x00, 0x02, 0x00, 0x02,
- 0xdf, 0xe0, 0x0d, 0x44, 0x3f, 0x05, 0x24, 0x02,
- 0xc5, 0x06, 0x45, 0x06, 0x65, 0x06, 0xe5, 0x0f,
- 0x27, 0x26, 0x07, 0x6f, 0x06, 0x40, 0xab, 0x2f,
- 0x0d, 0x0f, 0xa0, 0xe5, 0x2c, 0x76, 0xe0, 0x00,
- 0x27, 0xe5, 0x2a, 0xe7, 0x08, 0x26, 0xe0, 0x00,
- 0x36, 0xe9, 0x02, 0xa0, 0xe6, 0x0a, 0xa5, 0x56,
- 0x05, 0x16, 0x25, 0x06, 0xe9, 0x02, 0xe5, 0x14,
- 0xe6, 0x00, 0x36, 0xe5, 0x0f, 0xe6, 0x03, 0x27,
- 0xe0, 0x03, 0x16, 0xe5, 0x15, 0x40, 0x46, 0x07,
- 0xe5, 0x27, 0x06, 0x27, 0x66, 0x27, 0x26, 0x47,
- 0xf6, 0x05, 0x00, 0x04, 0xe9, 0x02, 0x60, 0x36,
- 0x85, 0x06, 0x04, 0xe5, 0x01, 0xe9, 0x02, 0x85,
- 0x00, 0xe5, 0x21, 0xa6, 0x27, 0x26, 0x27, 0x26,
- 0xe0, 0x01, 0x45, 0x06, 0xe5, 0x00, 0x06, 0x07,
- 0x20, 0xe9, 0x02, 0x20, 0x76, 0xe5, 0x08, 0x04,
- 0xa5, 0x4f, 0x05, 0x07, 0x06, 0x07, 0xe5, 0x2a,
- 0x06, 0x05, 0x46, 0x25, 0x26, 0x85, 0x26, 0x05,
- 0x06, 0x05, 0xe0, 0x10, 0x25, 0x04, 0x36, 0xe5,
- 0x03, 0x07, 0x26, 0x27, 0x36, 0x05, 0x24, 0x07,
- 0x06, 0xe0, 0x02, 0xa5, 0x20, 0xa5, 0x20, 0xa5,
- 0xe0, 0x01, 0xc5, 0x00, 0xc5, 0x00, 0xe2, 0x23,
- 0x0e, 0x64, 0xe2, 0x01, 0x04, 0x2e, 0x60, 0xe2,
- 0x48, 0xe5, 0x1b, 0x27, 0x06, 0x27, 0x06, 0x27,
- 0x16, 0x07, 0x06, 0x20, 0xe9, 0x02, 0xa0, 0xe5,
- 0xab, 0x1c, 0xe0, 0x04, 0xe5, 0x0f, 0x60, 0xe5,
- 0x29, 0x60, 0xfc, 0x87, 0x78, 0xfd, 0x98, 0x78,
- 0xe5, 0x80, 0xe6, 0x20, 0xe5, 0x62, 0xe0, 0x1e,
- 0xc2, 0xe0, 0x04, 0x82, 0x80, 0x05, 0x06, 0xe5,
- 0x02, 0x0c, 0xe5, 0x05, 0x00, 0x85, 0x00, 0x05,
- 0x00, 0x25, 0x00, 0x25, 0x00, 0xe5, 0x64, 0xee,
- 0x09, 0xe0, 0x08, 0xe5, 0x80, 0xe3, 0x13, 0x12,
- 0xef, 0x08, 0xe5, 0x38, 0x20, 0xe5, 0x2e, 0xc0,
- 0x0f, 0xe0, 0x18, 0xe5, 0x04, 0x0d, 0x4f, 0xe6,
- 0x08, 0xd6, 0x12, 0x13, 0x16, 0xa0, 0xe6, 0x08,
- 0x16, 0x31, 0x30, 0x12, 0x13, 0x12, 0x13, 0x12,
- 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
- 0x13, 0x12, 0x13, 0x36, 0x12, 0x13, 0x76, 0x50,
- 0x56, 0x00, 0x76, 0x11, 0x12, 0x13, 0x12, 0x13,
- 0x12, 0x13, 0x56, 0x0c, 0x11, 0x4c, 0x00, 0x16,
- 0x0d, 0x36, 0x60, 0x85, 0x00, 0xe5, 0x7f, 0x20,
- 0x1b, 0x00, 0x56, 0x0d, 0x56, 0x12, 0x13, 0x16,
- 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36, 0x4c,
- 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e, 0x10,
- 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c, 0x12,
- 0x13, 0x16, 0x12, 0x13, 0x36, 0xe5, 0x02, 0x04,
- 0xe5, 0x25, 0x24, 0xe5, 0x17, 0x40, 0xa5, 0x20,
- 0xa5, 0x20, 0xa5, 0x20, 0x45, 0x40, 0x2d, 0x0c,
- 0x0e, 0x0f, 0x2d, 0x00, 0x0f, 0x6c, 0x2f, 0xe0,
- 0x02, 0x5b, 0x2f, 0x20, 0xe5, 0x04, 0x00, 0xe5,
- 0x12, 0x00, 0xe5, 0x0b, 0x00, 0x25, 0x00, 0xe5,
- 0x07, 0x20, 0xe5, 0x06, 0xe0, 0x1a, 0xe5, 0x73,
- 0x80, 0x56, 0x60, 0xeb, 0x25, 0x40, 0xef, 0x01,
- 0xea, 0x2d, 0x6b, 0xef, 0x09, 0x2b, 0x4f, 0x00,
- 0xef, 0x05, 0x40, 0x0f, 0xe0, 0x27, 0xef, 0x25,
- 0x06, 0xe0, 0x7a, 0xe5, 0x15, 0x40, 0xe5, 0x29,
- 0xe0, 0x07, 0x06, 0xeb, 0x13, 0x60, 0xe5, 0x18,
- 0x6b, 0xe0, 0x01, 0xe5, 0x0c, 0x0a, 0xe5, 0x00,
- 0x0a, 0x80, 0xe5, 0x1e, 0x86, 0x80, 0xe5, 0x16,
- 0x00, 0x16, 0xe5, 0x1c, 0x60, 0xe5, 0x00, 0x16,
- 0x8a, 0xe0, 0x22, 0xe1, 0x20, 0xe2, 0x20, 0xe5,
- 0x46, 0x20, 0xe9, 0x02, 0xa0, 0xe1, 0x1c, 0x60,
- 0xe2, 0x1c, 0x60, 0xe5, 0x20, 0xe0, 0x00, 0xe5,
- 0x2c, 0xe0, 0x03, 0x16, 0xe1, 0x03, 0x00, 0xe1,
- 0x07, 0x00, 0xc1, 0x00, 0x21, 0x00, 0xe2, 0x03,
- 0x00, 0xe2, 0x07, 0x00, 0xc2, 0x00, 0x22, 0x40,
- 0xe5, 0x2c, 0xe0, 0x04, 0xe5, 0x80, 0xaf, 0xe0,
- 0x01, 0xe5, 0x0e, 0xe0, 0x02, 0xe5, 0x00, 0xe0,
- 0x10, 0xa4, 0x00, 0xe4, 0x22, 0x00, 0xe4, 0x01,
- 0xe0, 0x3d, 0xa5, 0x20, 0x05, 0x00, 0xe5, 0x24,
- 0x00, 0x25, 0x40, 0x05, 0x20, 0xe5, 0x0f, 0x00,
- 0x16, 0xeb, 0x00, 0xe5, 0x0f, 0x2f, 0xcb, 0xe5,
- 0x17, 0xe0, 0x00, 0xeb, 0x01, 0xe0, 0x28, 0xe5,
- 0x0b, 0x00, 0x25, 0x80, 0x8b, 0xe5, 0x0e, 0xab,
- 0x40, 0x16, 0xe5, 0x12, 0x80, 0x16, 0xe0, 0x38,
- 0xe5, 0x30, 0x60, 0x2b, 0x25, 0xeb, 0x08, 0x20,
- 0xeb, 0x26, 0x05, 0x46, 0x00, 0x26, 0x80, 0x66,
- 0x65, 0x00, 0x45, 0x00, 0xe5, 0x15, 0x20, 0x46,
- 0x60, 0x06, 0xeb, 0x01, 0xc0, 0xf6, 0x01, 0xc0,
- 0xe5, 0x15, 0x2b, 0x16, 0xe5, 0x15, 0x4b, 0xe0,
- 0x18, 0xe5, 0x00, 0x0f, 0xe5, 0x14, 0x26, 0x60,
- 0x8b, 0xd6, 0xe0, 0x01, 0xe5, 0x2e, 0x40, 0xd6,
- 0xe5, 0x0e, 0x20, 0xeb, 0x00, 0xe5, 0x0b, 0x80,
- 0xeb, 0x00, 0xe5, 0x0a, 0xc0, 0x76, 0xe0, 0x04,
- 0xcb, 0xe0, 0x48, 0xe5, 0x41, 0xe0, 0x2f, 0xe1,
- 0x2b, 0xe0, 0x05, 0xe2, 0x2b, 0xc0, 0xab, 0xe5,
- 0x1c, 0x66, 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xe9,
- 0x02, 0x65, 0x04, 0x05, 0xe1, 0x0e, 0x40, 0x86,
- 0x11, 0x04, 0xe2, 0x0e, 0xe0, 0x00, 0x2c, 0xe0,
- 0x80, 0x48, 0xeb, 0x17, 0x00, 0xe5, 0x22, 0x00,
- 0x26, 0x11, 0x20, 0x25, 0xe0, 0x08, 0x45, 0xe0,
- 0x2f, 0x66, 0xe5, 0x15, 0xeb, 0x02, 0x05, 0xe0,
- 0x00, 0xe5, 0x0e, 0xe6, 0x03, 0x6b, 0x96, 0xe0,
- 0x0e, 0xe5, 0x0a, 0x66, 0x76, 0xe0, 0x1e, 0xe5,
- 0x0d, 0xcb, 0xe0, 0x0c, 0xe5, 0x0f, 0xe0, 0x01,
- 0x07, 0x06, 0x07, 0xe5, 0x2d, 0xe6, 0x07, 0xd6,
- 0x60, 0xeb, 0x0c, 0xe9, 0x02, 0x06, 0x25, 0x26,
- 0x05, 0xe0, 0x01, 0x46, 0x07, 0xe5, 0x25, 0x47,
- 0x66, 0x27, 0x26, 0x36, 0x1b, 0x76, 0x06, 0xe0,
- 0x02, 0x1b, 0x20, 0xe5, 0x11, 0xc0, 0xe9, 0x02,
- 0xa0, 0x46, 0xe5, 0x1c, 0x86, 0x07, 0xe6, 0x00,
- 0x00, 0xe9, 0x02, 0x76, 0x05, 0x27, 0x05, 0xe0,
- 0x00, 0xe5, 0x1b, 0x06, 0x36, 0x05, 0xe0, 0x01,
- 0x26, 0x07, 0xe5, 0x28, 0x47, 0xe6, 0x01, 0x27,
- 0x65, 0x76, 0x66, 0x16, 0x07, 0x06, 0xe9, 0x02,
- 0x05, 0x16, 0x05, 0x56, 0x00, 0xeb, 0x0c, 0xe0,
- 0x03, 0xe5, 0x0a, 0x00, 0xe5, 0x11, 0x47, 0x46,
- 0x27, 0x06, 0x07, 0x26, 0xb6, 0x06, 0x25, 0x06,
- 0xe0, 0x36, 0xc5, 0x00, 0x05, 0x00, 0x65, 0x00,
- 0xe5, 0x07, 0x00, 0xe5, 0x02, 0x16, 0xa0, 0xe5,
- 0x27, 0x06, 0x47, 0xe6, 0x00, 0x80, 0xe9, 0x02,
- 0xa0, 0x26, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25,
- 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00,
- 0x85, 0x00, 0x26, 0x05, 0x27, 0x06, 0x67, 0x20,
- 0x27, 0x20, 0x47, 0x20, 0x05, 0xa0, 0x07, 0x80,
- 0x85, 0x27, 0x20, 0xc6, 0x40, 0x86, 0xe0, 0x03,
- 0xe5, 0x02, 0x00, 0x05, 0x20, 0x05, 0x00, 0xe5,
- 0x1e, 0x00, 0x05, 0x47, 0xa6, 0x00, 0x07, 0x20,
- 0x07, 0x00, 0x67, 0x00, 0x27, 0x06, 0x07, 0x06,
- 0x05, 0x06, 0x05, 0x36, 0x00, 0x36, 0xe0, 0x00,
- 0x26, 0xe0, 0x15, 0xe5, 0x2d, 0x47, 0xe6, 0x00,
- 0x27, 0x46, 0x07, 0x06, 0x65, 0x96, 0xe9, 0x02,
- 0x36, 0x00, 0x16, 0x06, 0x45, 0xe0, 0x16, 0xe5,
- 0x28, 0x47, 0xa6, 0x07, 0x06, 0x67, 0x26, 0x07,
- 0x26, 0x25, 0x16, 0x05, 0xe0, 0x00, 0xe9, 0x02,
- 0xe0, 0x80, 0x1e, 0xe5, 0x27, 0x47, 0x66, 0x20,
- 0x67, 0x26, 0x07, 0x26, 0xf6, 0x0f, 0x65, 0x26,
- 0xe0, 0x1a, 0xe5, 0x28, 0x47, 0xe6, 0x00, 0x27,
- 0x06, 0x07, 0x26, 0x56, 0x05, 0xe0, 0x03, 0xe9,
- 0x02, 0xa0, 0xf6, 0x05, 0xe0, 0x0b, 0xe5, 0x23,
- 0x06, 0x07, 0x06, 0x27, 0xa6, 0x07, 0x06, 0x05,
- 0x16, 0xa0, 0xe9, 0x02, 0xa0, 0xe9, 0x0c, 0xe0,
- 0x14, 0xe5, 0x13, 0x20, 0x06, 0x07, 0x06, 0x27,
- 0x66, 0x07, 0x86, 0x60, 0xe9, 0x02, 0x2b, 0x56,
- 0x0f, 0xc5, 0xe0, 0x80, 0x31, 0xe5, 0x24, 0x47,
- 0xe6, 0x01, 0x07, 0x26, 0x16, 0xe0, 0x5c, 0xe1,
- 0x18, 0xe2, 0x18, 0xe9, 0x02, 0xeb, 0x01, 0xe0,
- 0x04, 0xe5, 0x00, 0x20, 0x05, 0x20, 0xe5, 0x00,
- 0x00, 0x25, 0x00, 0xe5, 0x10, 0xa7, 0x00, 0x27,
- 0x20, 0x26, 0x07, 0x06, 0x05, 0x07, 0x05, 0x07,
- 0x06, 0x56, 0xe0, 0x01, 0xe9, 0x02, 0xe0, 0x3e,
- 0xe5, 0x00, 0x20, 0xe5, 0x1f, 0x47, 0x66, 0x20,
- 0x26, 0x67, 0x06, 0x05, 0x16, 0x05, 0x07, 0xe0,
- 0x13, 0x05, 0xe6, 0x02, 0xe5, 0x20, 0xa6, 0x07,
- 0x05, 0x66, 0xf6, 0x00, 0x06, 0xe0, 0x00, 0x05,
- 0xa6, 0x27, 0x46, 0xe5, 0x26, 0xe6, 0x05, 0x07,
- 0x26, 0x56, 0x05, 0x96, 0xe0, 0x05, 0xe5, 0x41,
- 0xc0, 0xf6, 0x02, 0xe0, 0x80, 0x2e, 0xe5, 0x19,
- 0x16, 0xe0, 0x06, 0xe9, 0x02, 0xa0, 0xe5, 0x01,
- 0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, 0xa6, 0x07,
- 0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, 0x02, 0xeb,
- 0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, 0xe6, 0x0e,
- 0x00, 0x07, 0xc6, 0x07, 0x26, 0x07, 0x26, 0xe0,
- 0x41, 0xc5, 0x00, 0x25, 0x00, 0xe5, 0x1e, 0xa6,
- 0x40, 0x06, 0x00, 0x26, 0x00, 0xc6, 0x05, 0x06,
- 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xa5, 0x00, 0x25,
- 0x00, 0xe5, 0x18, 0x87, 0x00, 0x26, 0x00, 0x27,
- 0x06, 0x07, 0x06, 0x05, 0xc0, 0xe9, 0x02, 0xe0,
- 0x80, 0xae, 0xe5, 0x0b, 0x26, 0x27, 0x36, 0xc0,
- 0x26, 0x05, 0x07, 0xe5, 0x05, 0x00, 0xe5, 0x1a,
- 0x27, 0x86, 0x40, 0x27, 0x06, 0x07, 0x06, 0xf6,
- 0x05, 0xe9, 0x02, 0x06, 0xe0, 0x4d, 0x05, 0xe0,
- 0x07, 0xeb, 0x0d, 0xef, 0x00, 0x6d, 0xef, 0x09,
- 0xe0, 0x05, 0x16, 0xe5, 0x83, 0x12, 0xe0, 0x5e,
- 0xea, 0x67, 0x00, 0x96, 0xe0, 0x03, 0xe5, 0x80,
- 0x3c, 0xe0, 0x89, 0xc4, 0xe5, 0x59, 0x36, 0xe0,
- 0x05, 0xe5, 0x83, 0xa8, 0xfb, 0x08, 0x06, 0xa5,
- 0xe6, 0x07, 0xe0, 0x02, 0xe5, 0x8f, 0x13, 0x80,
- 0xe5, 0x81, 0xbf, 0xe0, 0x9a, 0x31, 0xe5, 0x16,
- 0xe6, 0x04, 0x47, 0x46, 0xe9, 0x02, 0xe0, 0x86,
- 0x3e, 0xe5, 0x81, 0xb1, 0xc0, 0xe5, 0x17, 0x00,
- 0xe9, 0x02, 0x60, 0x36, 0xe5, 0x47, 0x00, 0xe9,
- 0x02, 0xa0, 0xe5, 0x16, 0x20, 0x86, 0x16, 0xe0,
- 0x02, 0xe5, 0x28, 0xc6, 0x96, 0x6f, 0x64, 0x16,
- 0x0f, 0xe0, 0x02, 0xe9, 0x02, 0x00, 0xcb, 0x00,
- 0xe5, 0x0d, 0x80, 0xe5, 0x0b, 0xe0, 0x81, 0x28,
- 0x44, 0xe5, 0x20, 0x24, 0x56, 0xe9, 0x02, 0xe0,
- 0x80, 0x3e, 0xe1, 0x18, 0xe2, 0x18, 0xeb, 0x0f,
- 0x76, 0xe0, 0x5d, 0xe5, 0x43, 0x60, 0x06, 0x05,
- 0xe7, 0x2f, 0xc0, 0x66, 0xe4, 0x05, 0xe0, 0x38,
- 0x24, 0x16, 0x04, 0x06, 0xe0, 0x03, 0x27, 0xe0,
- 0x06, 0xe5, 0x97, 0x70, 0xe0, 0x00, 0xe5, 0x84,
- 0x4e, 0xe0, 0x21, 0xe5, 0x02, 0xe0, 0xa2, 0x5f,
- 0x64, 0x00, 0xc4, 0x00, 0x24, 0x00, 0xe5, 0x80,
- 0x9b, 0xe0, 0x07, 0x05, 0xe0, 0x15, 0x45, 0x20,
- 0x05, 0xe0, 0x06, 0x65, 0xe0, 0x00, 0xe5, 0x81,
- 0x04, 0xe0, 0x88, 0x7c, 0xe5, 0x63, 0x80, 0xe5,
- 0x05, 0x40, 0xe5, 0x01, 0xc0, 0xe5, 0x02, 0x20,
- 0x0f, 0x26, 0x16, 0x7b, 0xe0, 0x8e, 0xd4, 0xef,
- 0x80, 0x68, 0xe9, 0x02, 0xa0, 0xef, 0x81, 0x2c,
- 0xe0, 0x44, 0xe6, 0x26, 0x20, 0xe6, 0x0f, 0xe0,
- 0x01, 0xef, 0x6c, 0xe0, 0x34, 0xef, 0x80, 0x6e,
- 0xe0, 0x02, 0xef, 0x1f, 0x20, 0xef, 0x34, 0x27,
- 0x46, 0x4f, 0xa7, 0xfb, 0x00, 0xe6, 0x00, 0x2f,
- 0xc6, 0xef, 0x16, 0x66, 0xef, 0x35, 0xe0, 0x0d,
- 0xef, 0x3a, 0x46, 0x0f, 0xe0, 0x72, 0xeb, 0x0c,
- 0xe0, 0x04, 0xeb, 0x0c, 0xe0, 0x04, 0xef, 0x4f,
- 0xe0, 0x01, 0xeb, 0x11, 0xe0, 0x7f, 0xe1, 0x12,
- 0xe2, 0x12, 0xe1, 0x12, 0xc2, 0x00, 0xe2, 0x0a,
- 0xe1, 0x12, 0xe2, 0x12, 0x01, 0x00, 0x21, 0x20,
- 0x01, 0x20, 0x21, 0x20, 0x61, 0x00, 0xe1, 0x00,
- 0x62, 0x00, 0x02, 0x00, 0xc2, 0x00, 0xe2, 0x03,
- 0xe1, 0x12, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x20,
- 0xe1, 0x00, 0x00, 0xc1, 0x00, 0xe2, 0x12, 0x21,
- 0x00, 0x61, 0x00, 0x81, 0x00, 0x01, 0x40, 0xc1,
- 0x00, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1,
- 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1,
- 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1,
- 0x12, 0xe2, 0x14, 0x20, 0xe1, 0x11, 0x0c, 0xe2,
- 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11,
- 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c,
- 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2,
- 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0x3f,
- 0x20, 0xe9, 0x2a, 0xef, 0x81, 0x78, 0xe6, 0x2f,
- 0x6f, 0xe6, 0x2a, 0xef, 0x00, 0x06, 0xef, 0x06,
- 0x06, 0x2f, 0x96, 0xe0, 0x07, 0x86, 0x00, 0xe6,
- 0x07, 0xe0, 0x83, 0xc8, 0xe2, 0x02, 0x05, 0xe2,
- 0x0c, 0xa0, 0xa2, 0xe0, 0x80, 0x4d, 0xc6, 0x00,
- 0xe6, 0x09, 0x20, 0xc6, 0x00, 0x26, 0x00, 0x86,
- 0x80, 0xe4, 0x36, 0xe0, 0x19, 0x06, 0xe0, 0x68,
- 0xe5, 0x25, 0x40, 0xc6, 0xc4, 0x20, 0xe9, 0x02,
- 0x60, 0x05, 0x0f, 0xe0, 0x80, 0xb8, 0xe5, 0x16,
- 0x06, 0xe0, 0x09, 0xe5, 0x24, 0x66, 0xe9, 0x02,
- 0x80, 0x0d, 0xe0, 0x81, 0x48, 0xe5, 0x13, 0x04,
- 0x66, 0xe9, 0x02, 0xe0, 0x80, 0x4e, 0xe5, 0x16,
- 0x26, 0x05, 0xe9, 0x02, 0x60, 0x16, 0xe0, 0x81,
- 0x58, 0xc5, 0x00, 0x65, 0x00, 0x25, 0x00, 0xe5,
- 0x07, 0x00, 0xe5, 0x80, 0x3d, 0x20, 0xeb, 0x01,
- 0xc6, 0xe0, 0x21, 0xe1, 0x1a, 0xe2, 0x1a, 0xc6,
- 0x04, 0x60, 0xe9, 0x02, 0x60, 0x36, 0xe0, 0x82,
- 0x89, 0xeb, 0x33, 0x0f, 0x4b, 0x0d, 0x6b, 0xe0,
- 0x44, 0xeb, 0x25, 0x0f, 0xeb, 0x07, 0xe0, 0x80,
- 0x3a, 0x65, 0x00, 0xe5, 0x13, 0x00, 0x25, 0x00,
- 0x05, 0x20, 0x05, 0x00, 0xe5, 0x02, 0x00, 0x65,
- 0x00, 0x05, 0x00, 0x05, 0xa0, 0x05, 0x60, 0x05,
- 0x00, 0x05, 0x00, 0x05, 0x00, 0x45, 0x00, 0x25,
- 0x00, 0x05, 0x20, 0x05, 0x00, 0x05, 0x00, 0x05,
- 0x00, 0x05, 0x00, 0x05, 0x00, 0x25, 0x00, 0x05,
- 0x20, 0x65, 0x00, 0xc5, 0x00, 0x65, 0x00, 0x65,
- 0x00, 0x05, 0x00, 0xe5, 0x02, 0x00, 0xe5, 0x09,
- 0x80, 0x45, 0x00, 0x85, 0x00, 0xe5, 0x09, 0xe0,
- 0x2c, 0x2c, 0xe0, 0x80, 0x86, 0xef, 0x24, 0x60,
- 0xef, 0x5c, 0xe0, 0x04, 0xef, 0x07, 0x20, 0xef,
- 0x07, 0x00, 0xef, 0x07, 0x00, 0xef, 0x1d, 0xe0,
- 0x02, 0xeb, 0x05, 0xef, 0x80, 0x19, 0xe0, 0x30,
- 0xef, 0x15, 0xe0, 0x05, 0xef, 0x24, 0x60, 0xef,
- 0x01, 0xc0, 0x2f, 0xe0, 0x06, 0xaf, 0xe0, 0x80,
- 0x12, 0xef, 0x80, 0x73, 0x8e, 0xef, 0x82, 0x50,
- 0x60, 0xef, 0x09, 0x40, 0xef, 0x05, 0x40, 0xef,
- 0x6f, 0x60, 0xef, 0x57, 0xa0, 0xef, 0x04, 0x60,
- 0x0f, 0xe0, 0x07, 0xef, 0x04, 0x60, 0xef, 0x30,
- 0xe0, 0x00, 0xef, 0x02, 0xa0, 0xef, 0x20, 0xe0,
- 0x00, 0xef, 0x16, 0x20, 0xef, 0x04, 0x60, 0x2f,
- 0xe0, 0x36, 0xef, 0x80, 0xcc, 0xe0, 0x04, 0xef,
- 0x06, 0x20, 0xef, 0x05, 0x40, 0xef, 0x02, 0x80,
- 0xef, 0x30, 0xc0, 0xef, 0x07, 0x20, 0xef, 0x03,
- 0xa0, 0xef, 0x01, 0xc0, 0xef, 0x80, 0x0b, 0x00,
- 0xef, 0x54, 0xe9, 0x02, 0xe0, 0x83, 0x7e, 0xe5,
- 0xc0, 0x66, 0x58, 0xe0, 0x18, 0xe5, 0x8f, 0xb2,
- 0xa0, 0xe5, 0x80, 0x56, 0x20, 0xe5, 0x95, 0xfa,
- 0xe0, 0x06, 0xe5, 0x9c, 0xa9, 0xe0, 0x07, 0xe5,
- 0x81, 0xe6, 0xe0, 0x89, 0x1a, 0xe5, 0x81, 0x96,
- 0xe0, 0x85, 0x5a, 0xe5, 0x92, 0xc3, 0x80, 0xe5,
- 0x8f, 0xd8, 0xe0, 0xca, 0x9b, 0xc9, 0x1b, 0xe0,
- 0x16, 0xfb, 0x58, 0xe0, 0x78, 0xe6, 0x80, 0x68,
- 0xe0, 0xc0, 0xbd, 0x88, 0xfd, 0xc0, 0xbf, 0x76,
- 0x20, 0xfd, 0xc0, 0xbf, 0x76, 0x20,
- };
- typedef enum {
- UNICODE_SCRIPT_Unknown,
- UNICODE_SCRIPT_Adlam,
- UNICODE_SCRIPT_Ahom,
- UNICODE_SCRIPT_Anatolian_Hieroglyphs,
- UNICODE_SCRIPT_Arabic,
- UNICODE_SCRIPT_Armenian,
- UNICODE_SCRIPT_Avestan,
- UNICODE_SCRIPT_Balinese,
- UNICODE_SCRIPT_Bamum,
- UNICODE_SCRIPT_Bassa_Vah,
- UNICODE_SCRIPT_Batak,
- UNICODE_SCRIPT_Bengali,
- UNICODE_SCRIPT_Bhaiksuki,
- UNICODE_SCRIPT_Bopomofo,
- UNICODE_SCRIPT_Brahmi,
- UNICODE_SCRIPT_Braille,
- UNICODE_SCRIPT_Buginese,
- UNICODE_SCRIPT_Buhid,
- UNICODE_SCRIPT_Canadian_Aboriginal,
- UNICODE_SCRIPT_Carian,
- UNICODE_SCRIPT_Caucasian_Albanian,
- UNICODE_SCRIPT_Chakma,
- UNICODE_SCRIPT_Cham,
- UNICODE_SCRIPT_Cherokee,
- UNICODE_SCRIPT_Chorasmian,
- UNICODE_SCRIPT_Common,
- UNICODE_SCRIPT_Coptic,
- UNICODE_SCRIPT_Cuneiform,
- UNICODE_SCRIPT_Cypriot,
- UNICODE_SCRIPT_Cyrillic,
- UNICODE_SCRIPT_Cypro_Minoan,
- UNICODE_SCRIPT_Deseret,
- UNICODE_SCRIPT_Devanagari,
- UNICODE_SCRIPT_Dives_Akuru,
- UNICODE_SCRIPT_Dogra,
- UNICODE_SCRIPT_Duployan,
- UNICODE_SCRIPT_Egyptian_Hieroglyphs,
- UNICODE_SCRIPT_Elbasan,
- UNICODE_SCRIPT_Elymaic,
- UNICODE_SCRIPT_Ethiopic,
- UNICODE_SCRIPT_Georgian,
- UNICODE_SCRIPT_Glagolitic,
- UNICODE_SCRIPT_Gothic,
- UNICODE_SCRIPT_Garay,
- UNICODE_SCRIPT_Grantha,
- UNICODE_SCRIPT_Greek,
- UNICODE_SCRIPT_Gujarati,
- UNICODE_SCRIPT_Gunjala_Gondi,
- UNICODE_SCRIPT_Gurmukhi,
- UNICODE_SCRIPT_Gurung_Khema,
- UNICODE_SCRIPT_Han,
- UNICODE_SCRIPT_Hangul,
- UNICODE_SCRIPT_Hanifi_Rohingya,
- UNICODE_SCRIPT_Hanunoo,
- UNICODE_SCRIPT_Hatran,
- UNICODE_SCRIPT_Hebrew,
- UNICODE_SCRIPT_Hiragana,
- UNICODE_SCRIPT_Imperial_Aramaic,
- UNICODE_SCRIPT_Inherited,
- UNICODE_SCRIPT_Inscriptional_Pahlavi,
- UNICODE_SCRIPT_Inscriptional_Parthian,
- UNICODE_SCRIPT_Javanese,
- UNICODE_SCRIPT_Kaithi,
- UNICODE_SCRIPT_Kannada,
- UNICODE_SCRIPT_Katakana,
- UNICODE_SCRIPT_Kawi,
- UNICODE_SCRIPT_Kayah_Li,
- UNICODE_SCRIPT_Kharoshthi,
- UNICODE_SCRIPT_Khmer,
- UNICODE_SCRIPT_Khojki,
- UNICODE_SCRIPT_Khitan_Small_Script,
- UNICODE_SCRIPT_Khudawadi,
- UNICODE_SCRIPT_Kirat_Rai,
- UNICODE_SCRIPT_Lao,
- UNICODE_SCRIPT_Latin,
- UNICODE_SCRIPT_Lepcha,
- UNICODE_SCRIPT_Limbu,
- UNICODE_SCRIPT_Linear_A,
- UNICODE_SCRIPT_Linear_B,
- UNICODE_SCRIPT_Lisu,
- UNICODE_SCRIPT_Lycian,
- UNICODE_SCRIPT_Lydian,
- UNICODE_SCRIPT_Makasar,
- UNICODE_SCRIPT_Mahajani,
- UNICODE_SCRIPT_Malayalam,
- UNICODE_SCRIPT_Mandaic,
- UNICODE_SCRIPT_Manichaean,
- UNICODE_SCRIPT_Marchen,
- UNICODE_SCRIPT_Masaram_Gondi,
- UNICODE_SCRIPT_Medefaidrin,
- UNICODE_SCRIPT_Meetei_Mayek,
- UNICODE_SCRIPT_Mende_Kikakui,
- UNICODE_SCRIPT_Meroitic_Cursive,
- UNICODE_SCRIPT_Meroitic_Hieroglyphs,
- UNICODE_SCRIPT_Miao,
- UNICODE_SCRIPT_Modi,
- UNICODE_SCRIPT_Mongolian,
- UNICODE_SCRIPT_Mro,
- UNICODE_SCRIPT_Multani,
- UNICODE_SCRIPT_Myanmar,
- UNICODE_SCRIPT_Nabataean,
- UNICODE_SCRIPT_Nag_Mundari,
- UNICODE_SCRIPT_Nandinagari,
- UNICODE_SCRIPT_New_Tai_Lue,
- UNICODE_SCRIPT_Newa,
- UNICODE_SCRIPT_Nko,
- UNICODE_SCRIPT_Nushu,
- UNICODE_SCRIPT_Nyiakeng_Puachue_Hmong,
- UNICODE_SCRIPT_Ogham,
- UNICODE_SCRIPT_Ol_Chiki,
- UNICODE_SCRIPT_Ol_Onal,
- UNICODE_SCRIPT_Old_Hungarian,
- UNICODE_SCRIPT_Old_Italic,
- UNICODE_SCRIPT_Old_North_Arabian,
- UNICODE_SCRIPT_Old_Permic,
- UNICODE_SCRIPT_Old_Persian,
- UNICODE_SCRIPT_Old_Sogdian,
- UNICODE_SCRIPT_Old_South_Arabian,
- UNICODE_SCRIPT_Old_Turkic,
- UNICODE_SCRIPT_Old_Uyghur,
- UNICODE_SCRIPT_Oriya,
- UNICODE_SCRIPT_Osage,
- UNICODE_SCRIPT_Osmanya,
- UNICODE_SCRIPT_Pahawh_Hmong,
- UNICODE_SCRIPT_Palmyrene,
- UNICODE_SCRIPT_Pau_Cin_Hau,
- UNICODE_SCRIPT_Phags_Pa,
- UNICODE_SCRIPT_Phoenician,
- UNICODE_SCRIPT_Psalter_Pahlavi,
- UNICODE_SCRIPT_Rejang,
- UNICODE_SCRIPT_Runic,
- UNICODE_SCRIPT_Samaritan,
- UNICODE_SCRIPT_Saurashtra,
- UNICODE_SCRIPT_Sharada,
- UNICODE_SCRIPT_Shavian,
- UNICODE_SCRIPT_Siddham,
- UNICODE_SCRIPT_SignWriting,
- UNICODE_SCRIPT_Sinhala,
- UNICODE_SCRIPT_Sogdian,
- UNICODE_SCRIPT_Sora_Sompeng,
- UNICODE_SCRIPT_Soyombo,
- UNICODE_SCRIPT_Sundanese,
- UNICODE_SCRIPT_Sunuwar,
- UNICODE_SCRIPT_Syloti_Nagri,
- UNICODE_SCRIPT_Syriac,
- UNICODE_SCRIPT_Tagalog,
- UNICODE_SCRIPT_Tagbanwa,
- UNICODE_SCRIPT_Tai_Le,
- UNICODE_SCRIPT_Tai_Tham,
- UNICODE_SCRIPT_Tai_Viet,
- UNICODE_SCRIPT_Takri,
- UNICODE_SCRIPT_Tamil,
- UNICODE_SCRIPT_Tangut,
- UNICODE_SCRIPT_Telugu,
- UNICODE_SCRIPT_Thaana,
- UNICODE_SCRIPT_Thai,
- UNICODE_SCRIPT_Tibetan,
- UNICODE_SCRIPT_Tifinagh,
- UNICODE_SCRIPT_Tirhuta,
- UNICODE_SCRIPT_Tangsa,
- UNICODE_SCRIPT_Todhri,
- UNICODE_SCRIPT_Toto,
- UNICODE_SCRIPT_Tulu_Tigalari,
- UNICODE_SCRIPT_Ugaritic,
- UNICODE_SCRIPT_Vai,
- UNICODE_SCRIPT_Vithkuqi,
- UNICODE_SCRIPT_Wancho,
- UNICODE_SCRIPT_Warang_Citi,
- UNICODE_SCRIPT_Yezidi,
- UNICODE_SCRIPT_Yi,
- UNICODE_SCRIPT_Zanabazar_Square,
- UNICODE_SCRIPT_COUNT,
- } UnicodeScriptEnum;
- static const char unicode_script_name_table[] =
- "Adlam,Adlm" "\0"
- "Ahom,Ahom" "\0"
- "Anatolian_Hieroglyphs,Hluw" "\0"
- "Arabic,Arab" "\0"
- "Armenian,Armn" "\0"
- "Avestan,Avst" "\0"
- "Balinese,Bali" "\0"
- "Bamum,Bamu" "\0"
- "Bassa_Vah,Bass" "\0"
- "Batak,Batk" "\0"
- "Bengali,Beng" "\0"
- "Bhaiksuki,Bhks" "\0"
- "Bopomofo,Bopo" "\0"
- "Brahmi,Brah" "\0"
- "Braille,Brai" "\0"
- "Buginese,Bugi" "\0"
- "Buhid,Buhd" "\0"
- "Canadian_Aboriginal,Cans" "\0"
- "Carian,Cari" "\0"
- "Caucasian_Albanian,Aghb" "\0"
- "Chakma,Cakm" "\0"
- "Cham,Cham" "\0"
- "Cherokee,Cher" "\0"
- "Chorasmian,Chrs" "\0"
- "Common,Zyyy" "\0"
- "Coptic,Copt,Qaac" "\0"
- "Cuneiform,Xsux" "\0"
- "Cypriot,Cprt" "\0"
- "Cyrillic,Cyrl" "\0"
- "Cypro_Minoan,Cpmn" "\0"
- "Deseret,Dsrt" "\0"
- "Devanagari,Deva" "\0"
- "Dives_Akuru,Diak" "\0"
- "Dogra,Dogr" "\0"
- "Duployan,Dupl" "\0"
- "Egyptian_Hieroglyphs,Egyp" "\0"
- "Elbasan,Elba" "\0"
- "Elymaic,Elym" "\0"
- "Ethiopic,Ethi" "\0"
- "Georgian,Geor" "\0"
- "Glagolitic,Glag" "\0"
- "Gothic,Goth" "\0"
- "Garay,Gara" "\0"
- "Grantha,Gran" "\0"
- "Greek,Grek" "\0"
- "Gujarati,Gujr" "\0"
- "Gunjala_Gondi,Gong" "\0"
- "Gurmukhi,Guru" "\0"
- "Gurung_Khema,Gukh" "\0"
- "Han,Hani" "\0"
- "Hangul,Hang" "\0"
- "Hanifi_Rohingya,Rohg" "\0"
- "Hanunoo,Hano" "\0"
- "Hatran,Hatr" "\0"
- "Hebrew,Hebr" "\0"
- "Hiragana,Hira" "\0"
- "Imperial_Aramaic,Armi" "\0"
- "Inherited,Zinh,Qaai" "\0"
- "Inscriptional_Pahlavi,Phli" "\0"
- "Inscriptional_Parthian,Prti" "\0"
- "Javanese,Java" "\0"
- "Kaithi,Kthi" "\0"
- "Kannada,Knda" "\0"
- "Katakana,Kana" "\0"
- "Kawi,Kawi" "\0"
- "Kayah_Li,Kali" "\0"
- "Kharoshthi,Khar" "\0"
- "Khmer,Khmr" "\0"
- "Khojki,Khoj" "\0"
- "Khitan_Small_Script,Kits" "\0"
- "Khudawadi,Sind" "\0"
- "Kirat_Rai,Krai" "\0"
- "Lao,Laoo" "\0"
- "Latin,Latn" "\0"
- "Lepcha,Lepc" "\0"
- "Limbu,Limb" "\0"
- "Linear_A,Lina" "\0"
- "Linear_B,Linb" "\0"
- "Lisu,Lisu" "\0"
- "Lycian,Lyci" "\0"
- "Lydian,Lydi" "\0"
- "Makasar,Maka" "\0"
- "Mahajani,Mahj" "\0"
- "Malayalam,Mlym" "\0"
- "Mandaic,Mand" "\0"
- "Manichaean,Mani" "\0"
- "Marchen,Marc" "\0"
- "Masaram_Gondi,Gonm" "\0"
- "Medefaidrin,Medf" "\0"
- "Meetei_Mayek,Mtei" "\0"
- "Mende_Kikakui,Mend" "\0"
- "Meroitic_Cursive,Merc" "\0"
- "Meroitic_Hieroglyphs,Mero" "\0"
- "Miao,Plrd" "\0"
- "Modi,Modi" "\0"
- "Mongolian,Mong" "\0"
- "Mro,Mroo" "\0"
- "Multani,Mult" "\0"
- "Myanmar,Mymr" "\0"
- "Nabataean,Nbat" "\0"
- "Nag_Mundari,Nagm" "\0"
- "Nandinagari,Nand" "\0"
- "New_Tai_Lue,Talu" "\0"
- "Newa,Newa" "\0"
- "Nko,Nkoo" "\0"
- "Nushu,Nshu" "\0"
- "Nyiakeng_Puachue_Hmong,Hmnp" "\0"
- "Ogham,Ogam" "\0"
- "Ol_Chiki,Olck" "\0"
- "Ol_Onal,Onao" "\0"
- "Old_Hungarian,Hung" "\0"
- "Old_Italic,Ital" "\0"
- "Old_North_Arabian,Narb" "\0"
- "Old_Permic,Perm" "\0"
- "Old_Persian,Xpeo" "\0"
- "Old_Sogdian,Sogo" "\0"
- "Old_South_Arabian,Sarb" "\0"
- "Old_Turkic,Orkh" "\0"
- "Old_Uyghur,Ougr" "\0"
- "Oriya,Orya" "\0"
- "Osage,Osge" "\0"
- "Osmanya,Osma" "\0"
- "Pahawh_Hmong,Hmng" "\0"
- "Palmyrene,Palm" "\0"
- "Pau_Cin_Hau,Pauc" "\0"
- "Phags_Pa,Phag" "\0"
- "Phoenician,Phnx" "\0"
- "Psalter_Pahlavi,Phlp" "\0"
- "Rejang,Rjng" "\0"
- "Runic,Runr" "\0"
- "Samaritan,Samr" "\0"
- "Saurashtra,Saur" "\0"
- "Sharada,Shrd" "\0"
- "Shavian,Shaw" "\0"
- "Siddham,Sidd" "\0"
- "SignWriting,Sgnw" "\0"
- "Sinhala,Sinh" "\0"
- "Sogdian,Sogd" "\0"
- "Sora_Sompeng,Sora" "\0"
- "Soyombo,Soyo" "\0"
- "Sundanese,Sund" "\0"
- "Sunuwar,Sunu" "\0"
- "Syloti_Nagri,Sylo" "\0"
- "Syriac,Syrc" "\0"
- "Tagalog,Tglg" "\0"
- "Tagbanwa,Tagb" "\0"
- "Tai_Le,Tale" "\0"
- "Tai_Tham,Lana" "\0"
- "Tai_Viet,Tavt" "\0"
- "Takri,Takr" "\0"
- "Tamil,Taml" "\0"
- "Tangut,Tang" "\0"
- "Telugu,Telu" "\0"
- "Thaana,Thaa" "\0"
- "Thai,Thai" "\0"
- "Tibetan,Tibt" "\0"
- "Tifinagh,Tfng" "\0"
- "Tirhuta,Tirh" "\0"
- "Tangsa,Tnsa" "\0"
- "Todhri,Todr" "\0"
- "Toto,Toto" "\0"
- "Tulu_Tigalari,Tutg" "\0"
- "Ugaritic,Ugar" "\0"
- "Vai,Vaii" "\0"
- "Vithkuqi,Vith" "\0"
- "Wancho,Wcho" "\0"
- "Warang_Citi,Wara" "\0"
- "Yezidi,Yezi" "\0"
- "Yi,Yiii" "\0"
- "Zanabazar_Square,Zanb" "\0"
- ;
- static const uint8_t unicode_script_table[2803] = {
- 0xc0, 0x19, 0x99, 0x4a, 0x85, 0x19, 0x99, 0x4a,
- 0xae, 0x19, 0x80, 0x4a, 0x8e, 0x19, 0x80, 0x4a,
- 0x84, 0x19, 0x96, 0x4a, 0x80, 0x19, 0x9e, 0x4a,
- 0x80, 0x19, 0xe1, 0x60, 0x4a, 0xa6, 0x19, 0x84,
- 0x4a, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0,
- 0x0f, 0x3a, 0x83, 0x2d, 0x80, 0x19, 0x82, 0x2d,
- 0x01, 0x83, 0x2d, 0x80, 0x19, 0x80, 0x2d, 0x03,
- 0x80, 0x2d, 0x80, 0x19, 0x80, 0x2d, 0x80, 0x19,
- 0x82, 0x2d, 0x00, 0x80, 0x2d, 0x00, 0x93, 0x2d,
- 0x00, 0xbe, 0x2d, 0x8d, 0x1a, 0x8f, 0x2d, 0xe0,
- 0x24, 0x1d, 0x81, 0x3a, 0xe0, 0x48, 0x1d, 0x00,
- 0xa5, 0x05, 0x01, 0xb1, 0x05, 0x01, 0x82, 0x05,
- 0x00, 0xb6, 0x37, 0x07, 0x9a, 0x37, 0x03, 0x85,
- 0x37, 0x0a, 0x84, 0x04, 0x80, 0x19, 0x85, 0x04,
- 0x80, 0x19, 0x8d, 0x04, 0x80, 0x19, 0x82, 0x04,
- 0x80, 0x19, 0x9f, 0x04, 0x80, 0x19, 0x89, 0x04,
- 0x8a, 0x3a, 0x99, 0x04, 0x80, 0x3a, 0xe0, 0x0b,
- 0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x90, 0x00,
- 0xbb, 0x90, 0x01, 0x82, 0x90, 0xaf, 0x04, 0xb1,
- 0x9a, 0x0d, 0xba, 0x69, 0x01, 0x82, 0x69, 0xad,
- 0x83, 0x01, 0x8e, 0x83, 0x00, 0x9b, 0x55, 0x01,
- 0x80, 0x55, 0x00, 0x8a, 0x90, 0x04, 0x9e, 0x04,
- 0x00, 0x81, 0x04, 0x04, 0xca, 0x04, 0x80, 0x19,
- 0x9c, 0x04, 0xd0, 0x20, 0x83, 0x3a, 0x8e, 0x20,
- 0x81, 0x19, 0x99, 0x20, 0x83, 0x0b, 0x00, 0x87,
- 0x0b, 0x01, 0x81, 0x0b, 0x01, 0x95, 0x0b, 0x00,
- 0x86, 0x0b, 0x00, 0x80, 0x0b, 0x02, 0x83, 0x0b,
- 0x01, 0x88, 0x0b, 0x01, 0x81, 0x0b, 0x01, 0x83,
- 0x0b, 0x07, 0x80, 0x0b, 0x03, 0x81, 0x0b, 0x00,
- 0x84, 0x0b, 0x01, 0x98, 0x0b, 0x01, 0x82, 0x30,
- 0x00, 0x85, 0x30, 0x03, 0x81, 0x30, 0x01, 0x95,
- 0x30, 0x00, 0x86, 0x30, 0x00, 0x81, 0x30, 0x00,
- 0x81, 0x30, 0x00, 0x81, 0x30, 0x01, 0x80, 0x30,
- 0x00, 0x84, 0x30, 0x03, 0x81, 0x30, 0x01, 0x82,
- 0x30, 0x02, 0x80, 0x30, 0x06, 0x83, 0x30, 0x00,
- 0x80, 0x30, 0x06, 0x90, 0x30, 0x09, 0x82, 0x2e,
- 0x00, 0x88, 0x2e, 0x00, 0x82, 0x2e, 0x00, 0x95,
- 0x2e, 0x00, 0x86, 0x2e, 0x00, 0x81, 0x2e, 0x00,
- 0x84, 0x2e, 0x01, 0x89, 0x2e, 0x00, 0x82, 0x2e,
- 0x00, 0x82, 0x2e, 0x01, 0x80, 0x2e, 0x0e, 0x83,
- 0x2e, 0x01, 0x8b, 0x2e, 0x06, 0x86, 0x2e, 0x00,
- 0x82, 0x78, 0x00, 0x87, 0x78, 0x01, 0x81, 0x78,
- 0x01, 0x95, 0x78, 0x00, 0x86, 0x78, 0x00, 0x81,
- 0x78, 0x00, 0x84, 0x78, 0x01, 0x88, 0x78, 0x01,
- 0x81, 0x78, 0x01, 0x82, 0x78, 0x06, 0x82, 0x78,
- 0x03, 0x81, 0x78, 0x00, 0x84, 0x78, 0x01, 0x91,
- 0x78, 0x09, 0x81, 0x97, 0x00, 0x85, 0x97, 0x02,
- 0x82, 0x97, 0x00, 0x83, 0x97, 0x02, 0x81, 0x97,
- 0x00, 0x80, 0x97, 0x00, 0x81, 0x97, 0x02, 0x81,
- 0x97, 0x02, 0x82, 0x97, 0x02, 0x8b, 0x97, 0x03,
- 0x84, 0x97, 0x02, 0x82, 0x97, 0x00, 0x83, 0x97,
- 0x01, 0x80, 0x97, 0x05, 0x80, 0x97, 0x0d, 0x94,
- 0x97, 0x04, 0x8c, 0x99, 0x00, 0x82, 0x99, 0x00,
- 0x96, 0x99, 0x00, 0x8f, 0x99, 0x01, 0x88, 0x99,
- 0x00, 0x82, 0x99, 0x00, 0x83, 0x99, 0x06, 0x81,
- 0x99, 0x00, 0x82, 0x99, 0x01, 0x80, 0x99, 0x01,
- 0x83, 0x99, 0x01, 0x89, 0x99, 0x06, 0x88, 0x99,
- 0x8c, 0x3f, 0x00, 0x82, 0x3f, 0x00, 0x96, 0x3f,
- 0x00, 0x89, 0x3f, 0x00, 0x84, 0x3f, 0x01, 0x88,
- 0x3f, 0x00, 0x82, 0x3f, 0x00, 0x83, 0x3f, 0x06,
- 0x81, 0x3f, 0x05, 0x81, 0x3f, 0x00, 0x83, 0x3f,
- 0x01, 0x89, 0x3f, 0x00, 0x82, 0x3f, 0x0b, 0x8c,
- 0x54, 0x00, 0x82, 0x54, 0x00, 0xb2, 0x54, 0x00,
- 0x82, 0x54, 0x00, 0x85, 0x54, 0x03, 0x8f, 0x54,
- 0x01, 0x99, 0x54, 0x00, 0x82, 0x89, 0x00, 0x91,
- 0x89, 0x02, 0x97, 0x89, 0x00, 0x88, 0x89, 0x00,
- 0x80, 0x89, 0x01, 0x86, 0x89, 0x02, 0x80, 0x89,
- 0x03, 0x85, 0x89, 0x00, 0x80, 0x89, 0x00, 0x87,
- 0x89, 0x05, 0x89, 0x89, 0x01, 0x82, 0x89, 0x0b,
- 0xb9, 0x9b, 0x03, 0x80, 0x19, 0x9b, 0x9b, 0x24,
- 0x81, 0x49, 0x00, 0x80, 0x49, 0x00, 0x84, 0x49,
- 0x00, 0x97, 0x49, 0x00, 0x80, 0x49, 0x00, 0x96,
- 0x49, 0x01, 0x84, 0x49, 0x00, 0x80, 0x49, 0x00,
- 0x86, 0x49, 0x00, 0x89, 0x49, 0x01, 0x83, 0x49,
- 0x1f, 0xc7, 0x9c, 0x00, 0xa3, 0x9c, 0x03, 0xa6,
- 0x9c, 0x00, 0xa3, 0x9c, 0x00, 0x8e, 0x9c, 0x00,
- 0x86, 0x9c, 0x83, 0x19, 0x81, 0x9c, 0x24, 0xe0,
- 0x3f, 0x63, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04,
- 0x80, 0x28, 0x01, 0xaa, 0x28, 0x80, 0x19, 0x83,
- 0x28, 0xe0, 0x9f, 0x33, 0xc8, 0x27, 0x00, 0x83,
- 0x27, 0x01, 0x86, 0x27, 0x00, 0x80, 0x27, 0x00,
- 0x83, 0x27, 0x01, 0xa8, 0x27, 0x00, 0x83, 0x27,
- 0x01, 0xa0, 0x27, 0x00, 0x83, 0x27, 0x01, 0x86,
- 0x27, 0x00, 0x80, 0x27, 0x00, 0x83, 0x27, 0x01,
- 0x8e, 0x27, 0x00, 0xb8, 0x27, 0x00, 0x83, 0x27,
- 0x01, 0xc2, 0x27, 0x01, 0x9f, 0x27, 0x02, 0x99,
- 0x27, 0x05, 0xd5, 0x17, 0x01, 0x85, 0x17, 0x01,
- 0xe2, 0x1f, 0x12, 0x9c, 0x6c, 0x02, 0xca, 0x82,
- 0x82, 0x19, 0x8a, 0x82, 0x06, 0x95, 0x91, 0x08,
- 0x80, 0x91, 0x94, 0x35, 0x81, 0x19, 0x08, 0x93,
- 0x11, 0x0b, 0x8c, 0x92, 0x00, 0x82, 0x92, 0x00,
- 0x81, 0x92, 0x0b, 0xdd, 0x44, 0x01, 0x89, 0x44,
- 0x05, 0x89, 0x44, 0x05, 0x81, 0x60, 0x81, 0x19,
- 0x80, 0x60, 0x80, 0x19, 0x93, 0x60, 0x05, 0xd8,
- 0x60, 0x06, 0xaa, 0x60, 0x04, 0xc5, 0x12, 0x09,
- 0x9e, 0x4c, 0x00, 0x8b, 0x4c, 0x03, 0x8b, 0x4c,
- 0x03, 0x80, 0x4c, 0x02, 0x8b, 0x4c, 0x9d, 0x93,
- 0x01, 0x84, 0x93, 0x0a, 0xab, 0x67, 0x03, 0x99,
- 0x67, 0x05, 0x8a, 0x67, 0x02, 0x81, 0x67, 0x9f,
- 0x44, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x94,
- 0x00, 0x9c, 0x94, 0x01, 0x8a, 0x94, 0x05, 0x89,
- 0x94, 0x05, 0x8d, 0x94, 0x01, 0x9e, 0x3a, 0x30,
- 0xcc, 0x07, 0x00, 0xb1, 0x07, 0xbf, 0x8d, 0xb3,
- 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x4b, 0x02, 0x8e,
- 0x4b, 0x02, 0x82, 0x4b, 0xaf, 0x6d, 0x8a, 0x1d,
- 0x04, 0xaa, 0x28, 0x01, 0x82, 0x28, 0x87, 0x8d,
- 0x07, 0x82, 0x3a, 0x80, 0x19, 0x8c, 0x3a, 0x80,
- 0x19, 0x86, 0x3a, 0x83, 0x19, 0x80, 0x3a, 0x85,
- 0x19, 0x80, 0x3a, 0x82, 0x19, 0x81, 0x3a, 0x80,
- 0x19, 0x04, 0xa5, 0x4a, 0x84, 0x2d, 0x80, 0x1d,
- 0xb0, 0x4a, 0x84, 0x2d, 0x83, 0x4a, 0x84, 0x2d,
- 0x8c, 0x4a, 0x80, 0x1d, 0xc5, 0x4a, 0x80, 0x2d,
- 0xbf, 0x3a, 0xe0, 0x9f, 0x4a, 0x95, 0x2d, 0x01,
- 0x85, 0x2d, 0x01, 0xa5, 0x2d, 0x01, 0x85, 0x2d,
- 0x01, 0x87, 0x2d, 0x00, 0x80, 0x2d, 0x00, 0x80,
- 0x2d, 0x00, 0x80, 0x2d, 0x00, 0x9e, 0x2d, 0x01,
- 0xb4, 0x2d, 0x00, 0x8e, 0x2d, 0x00, 0x8d, 0x2d,
- 0x01, 0x85, 0x2d, 0x00, 0x92, 0x2d, 0x01, 0x82,
- 0x2d, 0x00, 0x88, 0x2d, 0x00, 0x8b, 0x19, 0x81,
- 0x3a, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80, 0x4a,
- 0x01, 0x8a, 0x19, 0x80, 0x4a, 0x8e, 0x19, 0x00,
- 0x8c, 0x4a, 0x02, 0xa0, 0x19, 0x0e, 0xa0, 0x3a,
- 0x0e, 0xa5, 0x19, 0x80, 0x2d, 0x82, 0x19, 0x81,
- 0x4a, 0x85, 0x19, 0x80, 0x4a, 0x9a, 0x19, 0x80,
- 0x4a, 0x90, 0x19, 0xa8, 0x4a, 0x82, 0x19, 0x03,
- 0xe2, 0x39, 0x19, 0x15, 0x8a, 0x19, 0x14, 0xe3,
- 0x3f, 0x19, 0xe0, 0x9f, 0x0f, 0xe2, 0x13, 0x19,
- 0x01, 0x9f, 0x19, 0x00, 0xe0, 0x08, 0x19, 0xdf,
- 0x29, 0x9f, 0x4a, 0xe0, 0x13, 0x1a, 0x04, 0x86,
- 0x1a, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04, 0x80,
- 0x28, 0x01, 0xb7, 0x9d, 0x06, 0x81, 0x9d, 0x0d,
- 0x80, 0x9d, 0x96, 0x27, 0x08, 0x86, 0x27, 0x00,
- 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27,
- 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86,
- 0x27, 0x00, 0x86, 0x27, 0x00, 0x9f, 0x1d, 0xdd,
- 0x19, 0x21, 0x99, 0x32, 0x00, 0xd8, 0x32, 0x0b,
- 0xe0, 0x75, 0x32, 0x19, 0x94, 0x19, 0x80, 0x32,
- 0x80, 0x19, 0x80, 0x32, 0x98, 0x19, 0x88, 0x32,
- 0x83, 0x3a, 0x81, 0x33, 0x87, 0x19, 0x83, 0x32,
- 0x83, 0x19, 0x00, 0xd5, 0x38, 0x01, 0x81, 0x3a,
- 0x81, 0x19, 0x82, 0x38, 0x80, 0x19, 0xd9, 0x40,
- 0x81, 0x19, 0x82, 0x40, 0x04, 0xaa, 0x0d, 0x00,
- 0xdd, 0x33, 0x00, 0x8f, 0x19, 0x9f, 0x0d, 0xa5,
- 0x19, 0x08, 0x80, 0x19, 0x8f, 0x40, 0x9e, 0x33,
- 0x00, 0xbf, 0x19, 0x9e, 0x33, 0xd0, 0x19, 0xae,
- 0x40, 0x80, 0x19, 0xd7, 0x40, 0xe0, 0x47, 0x19,
- 0xf0, 0x09, 0x5f, 0x32, 0xbf, 0x19, 0xf0, 0x41,
- 0x9f, 0x32, 0xe4, 0x2c, 0xa9, 0x02, 0xb6, 0xa9,
- 0x08, 0xaf, 0x4f, 0xe0, 0xcb, 0xa4, 0x13, 0xdf,
- 0x1d, 0xd7, 0x08, 0x07, 0xa1, 0x19, 0xe0, 0x05,
- 0x4a, 0x82, 0x19, 0xc2, 0x4a, 0x01, 0x81, 0x4a,
- 0x00, 0x80, 0x4a, 0x00, 0x87, 0x4a, 0x14, 0x8d,
- 0x4a, 0xac, 0x8f, 0x02, 0x89, 0x19, 0x05, 0xb7,
- 0x7e, 0x07, 0xc5, 0x84, 0x07, 0x8b, 0x84, 0x05,
- 0x9f, 0x20, 0xad, 0x42, 0x80, 0x19, 0x80, 0x42,
- 0xa3, 0x81, 0x0a, 0x80, 0x81, 0x9c, 0x33, 0x02,
- 0xcd, 0x3d, 0x00, 0x80, 0x19, 0x89, 0x3d, 0x03,
- 0x81, 0x3d, 0x9e, 0x63, 0x00, 0xb6, 0x16, 0x08,
- 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01, 0x83, 0x16,
- 0x9f, 0x63, 0xc2, 0x95, 0x17, 0x84, 0x95, 0x96,
- 0x5a, 0x09, 0x85, 0x27, 0x01, 0x85, 0x27, 0x01,
- 0x85, 0x27, 0x08, 0x86, 0x27, 0x00, 0x86, 0x27,
- 0x00, 0xaa, 0x4a, 0x80, 0x19, 0x88, 0x4a, 0x80,
- 0x2d, 0x83, 0x4a, 0x81, 0x19, 0x03, 0xcf, 0x17,
- 0xad, 0x5a, 0x01, 0x89, 0x5a, 0x05, 0xf0, 0x1b,
- 0x43, 0x33, 0x0b, 0x96, 0x33, 0x03, 0xb0, 0x33,
- 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x32, 0x01, 0xe0,
- 0x09, 0x32, 0x25, 0x86, 0x4a, 0x0b, 0x84, 0x05,
- 0x04, 0x99, 0x37, 0x00, 0x84, 0x37, 0x00, 0x80,
- 0x37, 0x00, 0x81, 0x37, 0x00, 0x81, 0x37, 0x00,
- 0x89, 0x37, 0xe0, 0x12, 0x04, 0x0f, 0xe1, 0x0a,
- 0x04, 0x81, 0x19, 0xcf, 0x04, 0x01, 0xb5, 0x04,
- 0x06, 0x80, 0x04, 0x1f, 0x8f, 0x04, 0x8f, 0x3a,
- 0x89, 0x19, 0x05, 0x8d, 0x3a, 0x81, 0x1d, 0xa2,
- 0x19, 0x00, 0x92, 0x19, 0x00, 0x83, 0x19, 0x03,
- 0x84, 0x04, 0x00, 0xe0, 0x26, 0x04, 0x01, 0x80,
- 0x19, 0x00, 0x9f, 0x19, 0x99, 0x4a, 0x85, 0x19,
- 0x99, 0x4a, 0x8a, 0x19, 0x89, 0x40, 0x80, 0x19,
- 0xac, 0x40, 0x81, 0x19, 0x9e, 0x33, 0x02, 0x85,
- 0x33, 0x01, 0x85, 0x33, 0x01, 0x85, 0x33, 0x01,
- 0x82, 0x33, 0x02, 0x86, 0x19, 0x00, 0x86, 0x19,
- 0x09, 0x84, 0x19, 0x01, 0x8b, 0x4e, 0x00, 0x99,
- 0x4e, 0x00, 0x92, 0x4e, 0x00, 0x81, 0x4e, 0x00,
- 0x8e, 0x4e, 0x01, 0x8d, 0x4e, 0x21, 0xe0, 0x1a,
- 0x4e, 0x04, 0x82, 0x19, 0x03, 0xac, 0x19, 0x02,
- 0x88, 0x19, 0xce, 0x2d, 0x00, 0x8c, 0x19, 0x02,
- 0x80, 0x2d, 0x2e, 0xac, 0x19, 0x80, 0x3a, 0x60,
- 0x21, 0x9c, 0x50, 0x02, 0xb0, 0x13, 0x0e, 0x80,
- 0x3a, 0x9a, 0x19, 0x03, 0xa3, 0x70, 0x08, 0x82,
- 0x70, 0x9a, 0x2a, 0x04, 0xaa, 0x72, 0x04, 0x9d,
- 0xa3, 0x00, 0x80, 0xa3, 0xa3, 0x73, 0x03, 0x8d,
- 0x73, 0x29, 0xcf, 0x1f, 0xaf, 0x86, 0x9d, 0x7a,
- 0x01, 0x89, 0x7a, 0x05, 0xa3, 0x79, 0x03, 0xa3,
- 0x79, 0x03, 0xa7, 0x25, 0x07, 0xb3, 0x14, 0x0a,
- 0x80, 0x14, 0x8a, 0xa5, 0x00, 0x8e, 0xa5, 0x00,
- 0x86, 0xa5, 0x00, 0x81, 0xa5, 0x00, 0x8a, 0xa5,
- 0x00, 0x8e, 0xa5, 0x00, 0x86, 0xa5, 0x00, 0x81,
- 0xa5, 0x02, 0xb3, 0xa0, 0x0b, 0xe0, 0xd6, 0x4d,
- 0x08, 0x95, 0x4d, 0x09, 0x87, 0x4d, 0x17, 0x85,
- 0x4a, 0x00, 0xa9, 0x4a, 0x00, 0x88, 0x4a, 0x44,
- 0x85, 0x1c, 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c,
- 0x00, 0x81, 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80,
- 0x1c, 0x95, 0x39, 0x00, 0x88, 0x39, 0x9f, 0x7c,
- 0x9e, 0x64, 0x07, 0x88, 0x64, 0x2f, 0x92, 0x36,
- 0x00, 0x81, 0x36, 0x04, 0x84, 0x36, 0x9b, 0x7f,
- 0x02, 0x80, 0x7f, 0x99, 0x51, 0x04, 0x80, 0x51,
- 0x3f, 0x9f, 0x5d, 0x97, 0x5c, 0x03, 0x93, 0x5c,
- 0x01, 0xad, 0x5c, 0x83, 0x43, 0x00, 0x81, 0x43,
- 0x04, 0x87, 0x43, 0x00, 0x82, 0x43, 0x00, 0x9c,
- 0x43, 0x01, 0x82, 0x43, 0x03, 0x89, 0x43, 0x06,
- 0x88, 0x43, 0x06, 0x9f, 0x75, 0x9f, 0x71, 0x1f,
- 0xa6, 0x56, 0x03, 0x8b, 0x56, 0x08, 0xb5, 0x06,
- 0x02, 0x86, 0x06, 0x95, 0x3c, 0x01, 0x87, 0x3c,
- 0x92, 0x3b, 0x04, 0x87, 0x3b, 0x91, 0x80, 0x06,
- 0x83, 0x80, 0x0b, 0x86, 0x80, 0x4f, 0xc8, 0x76,
- 0x36, 0xb2, 0x6f, 0x0c, 0xb2, 0x6f, 0x06, 0x85,
- 0x6f, 0xa7, 0x34, 0x07, 0x89, 0x34, 0x05, 0xa5,
- 0x2b, 0x02, 0x9c, 0x2b, 0x07, 0x81, 0x2b, 0x60,
- 0x6f, 0x9e, 0x04, 0x00, 0xa9, 0xa8, 0x00, 0x82,
- 0xa8, 0x01, 0x81, 0xa8, 0x0f, 0x82, 0x04, 0x36,
- 0x83, 0x04, 0xa7, 0x74, 0x07, 0xa9, 0x8a, 0x15,
- 0x99, 0x77, 0x25, 0x9b, 0x18, 0x13, 0x96, 0x26,
- 0x08, 0xcd, 0x0e, 0x03, 0xa3, 0x0e, 0x08, 0x80,
- 0x0e, 0xc2, 0x3e, 0x09, 0x80, 0x3e, 0x01, 0x98,
- 0x8b, 0x06, 0x89, 0x8b, 0x05, 0xb4, 0x15, 0x00,
- 0x91, 0x15, 0x07, 0xa6, 0x53, 0x08, 0xdf, 0x85,
- 0x00, 0x93, 0x89, 0x0a, 0x91, 0x45, 0x00, 0xae,
- 0x45, 0x3d, 0x86, 0x62, 0x00, 0x80, 0x62, 0x00,
- 0x83, 0x62, 0x00, 0x8e, 0x62, 0x00, 0x8a, 0x62,
- 0x05, 0xba, 0x47, 0x04, 0x89, 0x47, 0x05, 0x83,
- 0x2c, 0x00, 0x87, 0x2c, 0x01, 0x81, 0x2c, 0x01,
- 0x95, 0x2c, 0x00, 0x86, 0x2c, 0x00, 0x81, 0x2c,
- 0x00, 0x84, 0x2c, 0x00, 0x80, 0x3a, 0x88, 0x2c,
- 0x01, 0x81, 0x2c, 0x01, 0x82, 0x2c, 0x01, 0x80,
- 0x2c, 0x05, 0x80, 0x2c, 0x04, 0x86, 0x2c, 0x01,
- 0x86, 0x2c, 0x02, 0x84, 0x2c, 0x0a, 0x89, 0xa2,
- 0x00, 0x80, 0xa2, 0x01, 0x80, 0xa2, 0x00, 0xa5,
- 0xa2, 0x00, 0x89, 0xa2, 0x00, 0x80, 0xa2, 0x01,
- 0x80, 0xa2, 0x00, 0x83, 0xa2, 0x00, 0x89, 0xa2,
- 0x00, 0x81, 0xa2, 0x07, 0x81, 0xa2, 0x1c, 0xdb,
- 0x68, 0x00, 0x84, 0x68, 0x1d, 0xc7, 0x9e, 0x07,
- 0x89, 0x9e, 0x60, 0x45, 0xb5, 0x87, 0x01, 0xa5,
- 0x87, 0x21, 0xc4, 0x5f, 0x0a, 0x89, 0x5f, 0x05,
- 0x8c, 0x60, 0x12, 0xb9, 0x96, 0x05, 0x89, 0x96,
- 0x05, 0x93, 0x63, 0x1b, 0x9a, 0x02, 0x01, 0x8e,
- 0x02, 0x03, 0x96, 0x02, 0x60, 0x58, 0xbb, 0x22,
- 0x60, 0x03, 0xd2, 0xa7, 0x0b, 0x80, 0xa7, 0x86,
- 0x21, 0x01, 0x80, 0x21, 0x01, 0x87, 0x21, 0x00,
- 0x81, 0x21, 0x00, 0x9d, 0x21, 0x00, 0x81, 0x21,
- 0x01, 0x8b, 0x21, 0x08, 0x89, 0x21, 0x45, 0x87,
- 0x66, 0x01, 0xad, 0x66, 0x01, 0x8a, 0x66, 0x1a,
- 0xc7, 0xaa, 0x07, 0xd2, 0x8c, 0x0c, 0x8f, 0x12,
- 0xb8, 0x7d, 0x06, 0x89, 0x20, 0x60, 0x55, 0xa1,
- 0x8e, 0x0d, 0x89, 0x8e, 0x05, 0x88, 0x0c, 0x00,
- 0xac, 0x0c, 0x00, 0x8d, 0x0c, 0x09, 0x9c, 0x0c,
- 0x02, 0x9f, 0x57, 0x01, 0x95, 0x57, 0x00, 0x8d,
- 0x57, 0x48, 0x86, 0x58, 0x00, 0x81, 0x58, 0x00,
- 0xab, 0x58, 0x02, 0x80, 0x58, 0x00, 0x81, 0x58,
- 0x00, 0x88, 0x58, 0x07, 0x89, 0x58, 0x05, 0x85,
- 0x2f, 0x00, 0x81, 0x2f, 0x00, 0xa4, 0x2f, 0x00,
- 0x81, 0x2f, 0x00, 0x85, 0x2f, 0x06, 0x89, 0x2f,
- 0x60, 0xd5, 0x98, 0x52, 0x06, 0x90, 0x41, 0x00,
- 0xa8, 0x41, 0x02, 0x9c, 0x41, 0x54, 0x80, 0x4f,
- 0x0e, 0xb1, 0x97, 0x0c, 0x80, 0x97, 0xe3, 0x39,
- 0x1b, 0x60, 0x05, 0xe0, 0x0e, 0x1b, 0x00, 0x84,
- 0x1b, 0x0a, 0xe0, 0x63, 0x1b, 0x69, 0xeb, 0xe0,
- 0x02, 0x1e, 0x0c, 0xe3, 0xf5, 0x24, 0x09, 0xef,
- 0x3a, 0x24, 0x04, 0xe1, 0xe6, 0x03, 0x70, 0x0a,
- 0x58, 0xb9, 0x31, 0x66, 0x65, 0xe1, 0xd8, 0x08,
- 0x06, 0x9e, 0x61, 0x00, 0x89, 0x61, 0x03, 0x81,
- 0x61, 0xce, 0x9f, 0x00, 0x89, 0x9f, 0x05, 0x9d,
- 0x09, 0x01, 0x85, 0x09, 0x09, 0xc5, 0x7b, 0x09,
- 0x89, 0x7b, 0x00, 0x86, 0x7b, 0x00, 0x94, 0x7b,
- 0x04, 0x92, 0x7b, 0x61, 0x4f, 0xb9, 0x48, 0x60,
- 0x65, 0xda, 0x59, 0x60, 0x04, 0xca, 0x5e, 0x03,
- 0xb8, 0x5e, 0x06, 0x90, 0x5e, 0x3f, 0x80, 0x98,
- 0x80, 0x6a, 0x81, 0x32, 0x80, 0x46, 0x0a, 0x81,
- 0x32, 0x0d, 0xf0, 0x07, 0x97, 0x98, 0x07, 0xe2,
- 0x9f, 0x98, 0xe1, 0x75, 0x46, 0x28, 0x80, 0x46,
- 0x88, 0x98, 0x70, 0x12, 0x86, 0x83, 0x40, 0x00,
- 0x86, 0x40, 0x00, 0x81, 0x40, 0x00, 0x80, 0x40,
- 0xe0, 0xbe, 0x38, 0x82, 0x40, 0x0e, 0x80, 0x38,
- 0x1c, 0x82, 0x38, 0x01, 0x80, 0x40, 0x0d, 0x83,
- 0x40, 0x07, 0xe1, 0x2b, 0x6a, 0x68, 0xa3, 0xe0,
- 0x0a, 0x23, 0x04, 0x8c, 0x23, 0x02, 0x88, 0x23,
- 0x06, 0x89, 0x23, 0x01, 0x83, 0x23, 0x83, 0x19,
- 0x6e, 0xfb, 0xe0, 0x99, 0x19, 0x05, 0xe1, 0x53,
- 0x19, 0x4b, 0xad, 0x3a, 0x01, 0x96, 0x3a, 0x08,
- 0xe0, 0x13, 0x19, 0x3b, 0xe0, 0x95, 0x19, 0x09,
- 0xa6, 0x19, 0x01, 0xbd, 0x19, 0x82, 0x3a, 0x90,
- 0x19, 0x87, 0x3a, 0x81, 0x19, 0x86, 0x3a, 0x9d,
- 0x19, 0x83, 0x3a, 0xbc, 0x19, 0x14, 0xc5, 0x2d,
- 0x60, 0x19, 0x93, 0x19, 0x0b, 0x93, 0x19, 0x0b,
- 0xd6, 0x19, 0x08, 0x98, 0x19, 0x60, 0x26, 0xd4,
- 0x19, 0x00, 0xc6, 0x19, 0x00, 0x81, 0x19, 0x01,
- 0x80, 0x19, 0x01, 0x81, 0x19, 0x01, 0x83, 0x19,
- 0x00, 0x8b, 0x19, 0x00, 0x80, 0x19, 0x00, 0x86,
- 0x19, 0x00, 0xc0, 0x19, 0x00, 0x83, 0x19, 0x01,
- 0x87, 0x19, 0x00, 0x86, 0x19, 0x00, 0x9b, 0x19,
- 0x00, 0x83, 0x19, 0x00, 0x84, 0x19, 0x00, 0x80,
- 0x19, 0x02, 0x86, 0x19, 0x00, 0xe0, 0xf3, 0x19,
- 0x01, 0xe0, 0xc3, 0x19, 0x01, 0xb1, 0x19, 0xe2,
- 0x2b, 0x88, 0x0e, 0x84, 0x88, 0x00, 0x8e, 0x88,
- 0x63, 0xef, 0x9e, 0x4a, 0x05, 0x85, 0x4a, 0x60,
- 0x74, 0x86, 0x29, 0x00, 0x90, 0x29, 0x01, 0x86,
- 0x29, 0x00, 0x81, 0x29, 0x00, 0x84, 0x29, 0x04,
- 0xbd, 0x1d, 0x20, 0x80, 0x1d, 0x60, 0x0f, 0xac,
- 0x6b, 0x02, 0x8d, 0x6b, 0x01, 0x89, 0x6b, 0x03,
- 0x81, 0x6b, 0x60, 0xdf, 0x9e, 0xa1, 0x10, 0xb9,
- 0xa6, 0x04, 0x80, 0xa6, 0x61, 0x6f, 0xa9, 0x65,
- 0x60, 0x75, 0xaa, 0x6e, 0x03, 0x80, 0x6e, 0x61,
- 0x7f, 0x86, 0x27, 0x00, 0x83, 0x27, 0x00, 0x81,
- 0x27, 0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x5b,
- 0x01, 0x8f, 0x5b, 0x28, 0xcb, 0x01, 0x03, 0x89,
- 0x01, 0x03, 0x81, 0x01, 0x62, 0xb0, 0xc3, 0x19,
- 0x4b, 0xbc, 0x19, 0x60, 0x61, 0x83, 0x04, 0x00,
- 0x9a, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04,
- 0x01, 0x80, 0x04, 0x00, 0x89, 0x04, 0x00, 0x83,
- 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x05,
- 0x80, 0x04, 0x03, 0x80, 0x04, 0x00, 0x80, 0x04,
- 0x00, 0x80, 0x04, 0x00, 0x82, 0x04, 0x00, 0x81,
- 0x04, 0x00, 0x80, 0x04, 0x01, 0x80, 0x04, 0x00,
- 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04,
- 0x00, 0x80, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80,
- 0x04, 0x01, 0x83, 0x04, 0x00, 0x86, 0x04, 0x00,
- 0x83, 0x04, 0x00, 0x83, 0x04, 0x00, 0x80, 0x04,
- 0x00, 0x89, 0x04, 0x00, 0x90, 0x04, 0x04, 0x82,
- 0x04, 0x00, 0x84, 0x04, 0x00, 0x90, 0x04, 0x33,
- 0x81, 0x04, 0x60, 0xad, 0xab, 0x19, 0x03, 0xe0,
- 0x03, 0x19, 0x0b, 0x8e, 0x19, 0x01, 0x8e, 0x19,
- 0x00, 0x8e, 0x19, 0x00, 0xa4, 0x19, 0x09, 0xe0,
- 0x4d, 0x19, 0x37, 0x99, 0x19, 0x80, 0x38, 0x81,
- 0x19, 0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06,
- 0x81, 0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3,
- 0x77, 0x19, 0x03, 0x90, 0x19, 0x02, 0x8c, 0x19,
- 0x02, 0xe0, 0x16, 0x19, 0x03, 0xde, 0x19, 0x05,
- 0x8b, 0x19, 0x03, 0x80, 0x19, 0x0e, 0x8b, 0x19,
- 0x03, 0xb7, 0x19, 0x07, 0x89, 0x19, 0x05, 0xa7,
- 0x19, 0x07, 0x9d, 0x19, 0x01, 0x8b, 0x19, 0x03,
- 0x81, 0x19, 0x3d, 0xe0, 0xf3, 0x19, 0x0b, 0x8d,
- 0x19, 0x01, 0x8c, 0x19, 0x02, 0x89, 0x19, 0x04,
- 0xb7, 0x19, 0x06, 0x8e, 0x19, 0x01, 0x8a, 0x19,
- 0x05, 0x88, 0x19, 0x06, 0xe0, 0x32, 0x19, 0x00,
- 0xe0, 0x05, 0x19, 0x63, 0xa5, 0xf0, 0x96, 0x7f,
- 0x32, 0x1f, 0xef, 0xd9, 0x32, 0x05, 0xe0, 0x7d,
- 0x32, 0x01, 0xf0, 0x06, 0x21, 0x32, 0x0d, 0xf0,
- 0x0c, 0xd0, 0x32, 0x0e, 0xe2, 0x0d, 0x32, 0x69,
- 0x41, 0xe1, 0xbd, 0x32, 0x65, 0x81, 0xf0, 0x02,
- 0xea, 0x32, 0x04, 0xef, 0xff, 0x32, 0x7a, 0xcb,
- 0xf0, 0x80, 0x19, 0x1d, 0xdf, 0x19, 0x60, 0x1f,
- 0xe0, 0x8f, 0x3a,
- };
- static const uint8_t unicode_script_ext_table[1253] = {
- 0x80, 0x36, 0x00, 0x00, 0x10, 0x06, 0x13, 0x1a,
- 0x23, 0x25, 0x28, 0x29, 0x2f, 0x2a, 0x2d, 0x32,
- 0x4a, 0x51, 0x53, 0x72, 0x86, 0x81, 0x83, 0x00,
- 0x00, 0x07, 0x0b, 0x1d, 0x20, 0x4a, 0x4f, 0x9b,
- 0xa1, 0x09, 0x00, 0x00, 0x02, 0x0d, 0x4a, 0x00,
- 0x00, 0x02, 0x02, 0x0d, 0x4a, 0x00, 0x00, 0x00,
- 0x02, 0x4a, 0x4f, 0x08, 0x00, 0x00, 0x02, 0x4a,
- 0x9b, 0x00, 0x00, 0x00, 0x02, 0x0d, 0x4a, 0x25,
- 0x00, 0x00, 0x08, 0x17, 0x1a, 0x1d, 0x2d, 0x4a,
- 0x72, 0x8e, 0x93, 0x00, 0x08, 0x17, 0x1d, 0x2d,
- 0x4a, 0x79, 0x8e, 0x93, 0xa0, 0x00, 0x04, 0x17,
- 0x1d, 0x4a, 0x9d, 0x00, 0x05, 0x29, 0x4a, 0x8e,
- 0x90, 0x9b, 0x00, 0x0b, 0x14, 0x17, 0x1a, 0x1d,
- 0x2a, 0x2d, 0x4a, 0x79, 0x90, 0x9d, 0xa0, 0x00,
- 0x06, 0x1a, 0x25, 0x29, 0x2a, 0x40, 0x4a, 0x00,
- 0x04, 0x1d, 0x2d, 0x4a, 0x72, 0x00, 0x09, 0x1a,
- 0x23, 0x37, 0x4a, 0x72, 0x90, 0x93, 0x9d, 0xa0,
- 0x00, 0x0a, 0x05, 0x1d, 0x23, 0x2a, 0x2d, 0x37,
- 0x4a, 0x72, 0x90, 0x93, 0x00, 0x02, 0x4a, 0x9d,
- 0x00, 0x03, 0x23, 0x4a, 0x90, 0x00, 0x04, 0x17,
- 0x1d, 0x4a, 0x79, 0x00, 0x03, 0x17, 0x4a, 0x93,
- 0x00, 0x02, 0x4a, 0x8e, 0x00, 0x02, 0x27, 0x4a,
- 0x00, 0x00, 0x00, 0x02, 0x4a, 0x8e, 0x00, 0x03,
- 0x1d, 0x4a, 0xa0, 0x00, 0x00, 0x00, 0x04, 0x2d,
- 0x4a, 0x72, 0xa0, 0x0b, 0x00, 0x00, 0x02, 0x4a,
- 0x90, 0x01, 0x00, 0x00, 0x05, 0x17, 0x23, 0x40,
- 0x4a, 0x90, 0x00, 0x04, 0x17, 0x23, 0x4a, 0x90,
- 0x00, 0x02, 0x4a, 0x90, 0x06, 0x00, 0x00, 0x03,
- 0x4a, 0x8e, 0x90, 0x00, 0x02, 0x4a, 0x90, 0x00,
- 0x00, 0x00, 0x03, 0x17, 0x4a, 0x90, 0x00, 0x06,
- 0x14, 0x17, 0x2a, 0x4a, 0x8e, 0x9b, 0x0f, 0x00,
- 0x00, 0x01, 0x2d, 0x01, 0x00, 0x00, 0x01, 0x2d,
- 0x11, 0x00, 0x00, 0x02, 0x4a, 0x79, 0x04, 0x00,
- 0x00, 0x03, 0x14, 0x4a, 0xa0, 0x03, 0x00, 0x0c,
- 0x01, 0x4a, 0x03, 0x00, 0x01, 0x02, 0x1a, 0x2d,
- 0x80, 0x8c, 0x00, 0x00, 0x02, 0x1d, 0x72, 0x00,
- 0x02, 0x1d, 0x29, 0x01, 0x02, 0x1d, 0x4a, 0x00,
- 0x02, 0x1d, 0x29, 0x80, 0x80, 0x00, 0x00, 0x03,
- 0x05, 0x28, 0x29, 0x80, 0x01, 0x00, 0x00, 0x07,
- 0x04, 0x2b, 0x69, 0x34, 0x90, 0x9a, 0xa8, 0x0d,
- 0x00, 0x00, 0x07, 0x04, 0x2b, 0x69, 0x34, 0x90,
- 0x9a, 0xa8, 0x00, 0x03, 0x04, 0x90, 0x9a, 0x01,
- 0x00, 0x00, 0x08, 0x01, 0x04, 0x2b, 0x69, 0x34,
- 0x90, 0x9a, 0xa8, 0x1f, 0x00, 0x00, 0x09, 0x01,
- 0x04, 0x55, 0x56, 0x77, 0x80, 0x34, 0x8a, 0x90,
- 0x09, 0x00, 0x0a, 0x02, 0x04, 0x90, 0x09, 0x00,
- 0x09, 0x03, 0x04, 0x9a, 0xa8, 0x05, 0x00, 0x00,
- 0x02, 0x04, 0x90, 0x62, 0x00, 0x00, 0x02, 0x04,
- 0x34, 0x81, 0xfb, 0x00, 0x00, 0x0d, 0x0b, 0x20,
- 0x2c, 0x2e, 0x30, 0x3f, 0x4a, 0x54, 0x78, 0x85,
- 0x97, 0x99, 0x9e, 0x00, 0x0c, 0x0b, 0x20, 0x2c,
- 0x2e, 0x30, 0x3f, 0x4a, 0x54, 0x78, 0x97, 0x99,
- 0x9e, 0x10, 0x00, 0x00, 0x15, 0x0b, 0x20, 0x22,
- 0x2f, 0x58, 0x2c, 0x2e, 0x30, 0x3f, 0x53, 0x54,
- 0x66, 0x6e, 0x78, 0x47, 0x89, 0x8f, 0x96, 0x97,
- 0x99, 0x9e, 0x00, 0x17, 0x0b, 0x20, 0x22, 0x2f,
- 0x58, 0x2c, 0x2e, 0x31, 0x30, 0x3f, 0x4c, 0x53,
- 0x54, 0x66, 0x6e, 0x78, 0x47, 0x89, 0x8f, 0x96,
- 0x97, 0x99, 0x9e, 0x09, 0x04, 0x20, 0x22, 0x3e,
- 0x53, 0x75, 0x00, 0x09, 0x03, 0x0b, 0x15, 0x8f,
- 0x75, 0x00, 0x09, 0x02, 0x30, 0x62, 0x75, 0x00,
- 0x09, 0x02, 0x2e, 0x45, 0x80, 0x75, 0x00, 0x0d,
- 0x02, 0x2c, 0x97, 0x80, 0x71, 0x00, 0x09, 0x03,
- 0x3f, 0x66, 0xa2, 0x82, 0xcf, 0x00, 0x09, 0x03,
- 0x15, 0x63, 0x93, 0x80, 0x30, 0x00, 0x00, 0x03,
- 0x28, 0x29, 0x4a, 0x85, 0x6e, 0x00, 0x02, 0x01,
- 0x82, 0x46, 0x00, 0x01, 0x04, 0x11, 0x35, 0x92,
- 0x91, 0x80, 0x4a, 0x00, 0x01, 0x02, 0x60, 0x7e,
- 0x00, 0x00, 0x00, 0x02, 0x60, 0x7e, 0x84, 0x49,
- 0x00, 0x00, 0x04, 0x0b, 0x20, 0x2c, 0x3f, 0x00,
- 0x01, 0x20, 0x00, 0x04, 0x0b, 0x20, 0x2c, 0x3f,
- 0x00, 0x03, 0x20, 0x2c, 0x3f, 0x00, 0x01, 0x20,
- 0x01, 0x02, 0x0b, 0x20, 0x00, 0x02, 0x20, 0x85,
- 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02, 0x20, 0x85,
- 0x00, 0x06, 0x20, 0x3f, 0x54, 0x78, 0x97, 0x99,
- 0x00, 0x01, 0x20, 0x01, 0x02, 0x20, 0x85, 0x01,
- 0x01, 0x20, 0x00, 0x02, 0x20, 0x85, 0x00, 0x02,
- 0x0b, 0x20, 0x06, 0x01, 0x20, 0x00, 0x02, 0x20,
- 0x66, 0x00, 0x02, 0x0b, 0x20, 0x01, 0x01, 0x20,
- 0x00, 0x02, 0x0b, 0x20, 0x03, 0x01, 0x20, 0x00,
- 0x0b, 0x0b, 0x20, 0x2c, 0x3f, 0x54, 0x66, 0x78,
- 0x89, 0x99, 0x9e, 0xa2, 0x00, 0x02, 0x20, 0x2c,
- 0x00, 0x04, 0x20, 0x2c, 0x3f, 0xa2, 0x01, 0x02,
- 0x0b, 0x20, 0x00, 0x01, 0x0b, 0x01, 0x02, 0x20,
- 0x2c, 0x00, 0x01, 0x66, 0x80, 0x44, 0x00, 0x01,
- 0x01, 0x2d, 0x35, 0x00, 0x00, 0x03, 0x1d, 0x4a,
- 0x90, 0x00, 0x00, 0x00, 0x01, 0x90, 0x81, 0xb3,
- 0x00, 0x00, 0x03, 0x4a, 0x60, 0x7e, 0x1e, 0x00,
- 0x00, 0x02, 0x01, 0x04, 0x09, 0x00, 0x00, 0x06,
- 0x13, 0x28, 0x29, 0x6f, 0x50, 0x76, 0x01, 0x00,
- 0x00, 0x04, 0x13, 0x2d, 0x6f, 0x5d, 0x80, 0x11,
- 0x00, 0x00, 0x03, 0x20, 0x2c, 0x4a, 0x8c, 0xa5,
- 0x00, 0x00, 0x02, 0x1a, 0x4a, 0x17, 0x00, 0x00,
- 0x02, 0x06, 0x76, 0x00, 0x07, 0x06, 0x13, 0x28,
- 0x6f, 0x3e, 0x51, 0x83, 0x09, 0x00, 0x00, 0x01,
- 0x23, 0x03, 0x00, 0x00, 0x03, 0x01, 0x04, 0x6f,
- 0x00, 0x00, 0x00, 0x02, 0x1d, 0x29, 0x81, 0x2b,
- 0x00, 0x0f, 0x02, 0x32, 0x98, 0x00, 0x00, 0x00,
- 0x07, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x60, 0xa9,
- 0x00, 0x08, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x60,
- 0x7e, 0xa9, 0x00, 0x05, 0x0d, 0x33, 0x32, 0x38,
- 0x40, 0x01, 0x00, 0x00, 0x01, 0x32, 0x00, 0x00,
- 0x01, 0x08, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x60,
- 0x9c, 0xa9, 0x01, 0x09, 0x0d, 0x33, 0x32, 0x38,
- 0x40, 0x4f, 0x60, 0x9c, 0xa9, 0x05, 0x06, 0x0d,
- 0x33, 0x32, 0x38, 0x40, 0xa9, 0x00, 0x00, 0x00,
- 0x05, 0x0d, 0x33, 0x32, 0x38, 0x40, 0x07, 0x06,
- 0x0d, 0x33, 0x32, 0x38, 0x40, 0xa9, 0x03, 0x05,
- 0x0d, 0x33, 0x32, 0x38, 0x40, 0x09, 0x00, 0x03,
- 0x02, 0x0d, 0x32, 0x01, 0x00, 0x00, 0x05, 0x0d,
- 0x33, 0x32, 0x38, 0x40, 0x04, 0x02, 0x38, 0x40,
- 0x00, 0x00, 0x00, 0x05, 0x0d, 0x33, 0x32, 0x38,
- 0x40, 0x03, 0x00, 0x01, 0x03, 0x32, 0x38, 0x40,
- 0x01, 0x01, 0x32, 0x58, 0x00, 0x03, 0x02, 0x38,
- 0x40, 0x02, 0x00, 0x00, 0x02, 0x38, 0x40, 0x59,
- 0x00, 0x00, 0x06, 0x0d, 0x33, 0x32, 0x38, 0x40,
- 0xa9, 0x00, 0x02, 0x38, 0x40, 0x80, 0x12, 0x00,
- 0x0f, 0x01, 0x32, 0x1f, 0x00, 0x25, 0x01, 0x32,
- 0x08, 0x00, 0x00, 0x02, 0x32, 0x98, 0x2f, 0x00,
- 0x27, 0x01, 0x32, 0x37, 0x00, 0x30, 0x01, 0x32,
- 0x0e, 0x00, 0x0b, 0x01, 0x32, 0x32, 0x00, 0x00,
- 0x01, 0x32, 0x57, 0x00, 0x18, 0x01, 0x32, 0x09,
- 0x00, 0x04, 0x01, 0x32, 0x5f, 0x00, 0x1e, 0x01,
- 0x32, 0xc0, 0x31, 0xef, 0x00, 0x00, 0x02, 0x1d,
- 0x29, 0x80, 0x0f, 0x00, 0x07, 0x02, 0x32, 0x4a,
- 0x80, 0xa7, 0x00, 0x02, 0x10, 0x20, 0x22, 0x2e,
- 0x30, 0x45, 0x3f, 0x3e, 0x53, 0x54, 0x5f, 0x66,
- 0x85, 0x47, 0x96, 0x9e, 0xa2, 0x02, 0x0f, 0x20,
- 0x22, 0x2e, 0x30, 0x45, 0x3f, 0x3e, 0x53, 0x5f,
- 0x66, 0x85, 0x47, 0x96, 0x9e, 0xa2, 0x01, 0x0b,
- 0x20, 0x22, 0x2e, 0x30, 0x45, 0x3e, 0x53, 0x5f,
- 0x47, 0x96, 0x9e, 0x00, 0x0c, 0x20, 0x22, 0x2e,
- 0x30, 0x45, 0x3e, 0x53, 0x5f, 0x85, 0x47, 0x96,
- 0x9e, 0x00, 0x0b, 0x20, 0x22, 0x2e, 0x30, 0x45,
- 0x3e, 0x53, 0x5f, 0x47, 0x96, 0x9e, 0x80, 0x36,
- 0x00, 0x00, 0x03, 0x0b, 0x20, 0xa2, 0x00, 0x00,
- 0x00, 0x02, 0x20, 0x97, 0x39, 0x00, 0x00, 0x03,
- 0x42, 0x4a, 0x63, 0x80, 0x1f, 0x00, 0x00, 0x02,
- 0x10, 0x3d, 0xc0, 0x12, 0xed, 0x00, 0x01, 0x02,
- 0x04, 0x69, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04,
- 0x9a, 0x09, 0x00, 0x00, 0x02, 0x04, 0x9a, 0x46,
- 0x00, 0x01, 0x05, 0x0d, 0x33, 0x32, 0x38, 0x40,
- 0x80, 0x99, 0x00, 0x04, 0x06, 0x0d, 0x33, 0x32,
- 0x38, 0x40, 0xa9, 0x09, 0x00, 0x00, 0x02, 0x38,
- 0x40, 0x2c, 0x00, 0x01, 0x02, 0x38, 0x40, 0x80,
- 0xdf, 0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4e, 0x00,
- 0x02, 0x1c, 0x4e, 0x03, 0x00, 0x2c, 0x03, 0x1c,
- 0x4d, 0x4e, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4e,
- 0x81, 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a, 0x87,
- 0x75, 0x00, 0x00, 0x02, 0x56, 0x77, 0x87, 0x8d,
- 0x00, 0x00, 0x02, 0x2c, 0x97, 0x00, 0x00, 0x00,
- 0x02, 0x2c, 0x97, 0x36, 0x00, 0x01, 0x02, 0x2c,
- 0x97, 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2c, 0x97,
- 0x00, 0x00, 0x00, 0x02, 0x2c, 0x97, 0xc0, 0x5c,
- 0x4b, 0x00, 0x03, 0x01, 0x23, 0x96, 0x3b, 0x00,
- 0x11, 0x01, 0x32, 0x9e, 0x5d, 0x00, 0x01, 0x01,
- 0x32, 0xce, 0xcd, 0x2d, 0x00,
- };
- static const uint8_t unicode_prop_Hyphen_table[28] = {
- 0xac, 0x80, 0xfe, 0x80, 0x44, 0xdb, 0x80, 0x52,
- 0x7a, 0x80, 0x48, 0x08, 0x81, 0x4e, 0x04, 0x80,
- 0x42, 0xe2, 0x80, 0x60, 0xcd, 0x66, 0x80, 0x40,
- 0xa8, 0x80, 0xd6, 0x80,
- };
- static const uint8_t unicode_prop_Other_Math_table[200] = {
- 0xdd, 0x80, 0x43, 0x70, 0x11, 0x80, 0x99, 0x09,
- 0x81, 0x5c, 0x1f, 0x80, 0x9a, 0x82, 0x8a, 0x80,
- 0x9f, 0x83, 0x97, 0x81, 0x8d, 0x81, 0xc0, 0x8c,
- 0x18, 0x11, 0x1c, 0x91, 0x03, 0x01, 0x89, 0x00,
- 0x14, 0x28, 0x11, 0x09, 0x02, 0x05, 0x13, 0x24,
- 0xca, 0x21, 0x18, 0x08, 0x08, 0x00, 0x21, 0x0b,
- 0x0b, 0x91, 0x09, 0x00, 0x06, 0x00, 0x29, 0x41,
- 0x21, 0x83, 0x40, 0xa7, 0x08, 0x80, 0x97, 0x80,
- 0x90, 0x80, 0x41, 0xbc, 0x81, 0x8b, 0x88, 0x24,
- 0x21, 0x09, 0x14, 0x8d, 0x00, 0x01, 0x85, 0x97,
- 0x81, 0xb8, 0x00, 0x80, 0x9c, 0x83, 0x88, 0x81,
- 0x41, 0x55, 0x81, 0x9e, 0x89, 0x41, 0x92, 0x95,
- 0xbe, 0x83, 0x9f, 0x81, 0x60, 0xd4, 0x62, 0x00,
- 0x03, 0x80, 0x40, 0xd2, 0x00, 0x80, 0x60, 0xd4,
- 0xc0, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b,
- 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f,
- 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80,
- 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e,
- 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e,
- 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x81,
- 0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01, 0x00, 0x08,
- 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00,
- 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00,
- 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90,
- };
- static const uint8_t unicode_prop_Other_Alphabetic_table[443] = {
- 0x43, 0x44, 0x80, 0x9c, 0x8c, 0x42, 0x3f, 0x8d,
- 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c,
- 0x06, 0x8f, 0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80,
- 0xa2, 0x80, 0x9d, 0x8f, 0xe5, 0x8a, 0xe4, 0x0a,
- 0x88, 0x02, 0x03, 0xe9, 0x80, 0xbb, 0x8b, 0x16,
- 0x85, 0x93, 0xb5, 0x09, 0x8e, 0x01, 0x22, 0x89,
- 0x81, 0x9c, 0x82, 0xb9, 0x31, 0x09, 0x81, 0x89,
- 0x80, 0x89, 0x81, 0x9c, 0x82, 0xb9, 0x23, 0x09,
- 0x0b, 0x80, 0x9d, 0x0a, 0x80, 0x8a, 0x82, 0xb9,
- 0x38, 0x10, 0x81, 0x94, 0x81, 0x95, 0x13, 0x82,
- 0xb9, 0x31, 0x09, 0x81, 0x88, 0x81, 0x89, 0x81,
- 0x9d, 0x80, 0xba, 0x22, 0x10, 0x82, 0x89, 0x80,
- 0xa7, 0x84, 0xb8, 0x30, 0x10, 0x17, 0x81, 0x8a,
- 0x81, 0x9c, 0x82, 0xb9, 0x30, 0x10, 0x17, 0x81,
- 0x8a, 0x81, 0x8e, 0x80, 0x8b, 0x83, 0xb9, 0x30,
- 0x10, 0x82, 0x89, 0x80, 0x89, 0x81, 0x9c, 0x82,
- 0xca, 0x28, 0x00, 0x87, 0x91, 0x81, 0xbc, 0x01,
- 0x86, 0x91, 0x80, 0xe2, 0x01, 0x28, 0x81, 0x8f,
- 0x80, 0x40, 0xa2, 0x92, 0x88, 0x8a, 0x80, 0xa3,
- 0xed, 0x8b, 0x00, 0x0b, 0x96, 0x1b, 0x10, 0x11,
- 0x32, 0x83, 0x8c, 0x8b, 0x00, 0x89, 0x83, 0x46,
- 0x73, 0x81, 0x9d, 0x81, 0x9d, 0x81, 0x9d, 0x81,
- 0xc1, 0x92, 0x40, 0xbb, 0x81, 0xa1, 0x80, 0xf5,
- 0x8b, 0x83, 0x88, 0x40, 0xdd, 0x84, 0xb8, 0x89,
- 0x81, 0x93, 0xc9, 0x81, 0x8a, 0x82, 0xb0, 0x84,
- 0xaf, 0x8e, 0xbb, 0x82, 0x9d, 0x88, 0x09, 0xb8,
- 0x8a, 0xb1, 0x92, 0x41, 0x9b, 0xa1, 0x46, 0xc0,
- 0xb3, 0x48, 0xf5, 0x9f, 0x60, 0x78, 0x73, 0x87,
- 0xa1, 0x81, 0x41, 0x61, 0x07, 0x80, 0x96, 0x84,
- 0xd7, 0x81, 0xb1, 0x8f, 0x00, 0xb8, 0x80, 0xa5,
- 0x84, 0x9b, 0x8b, 0xac, 0x83, 0xaf, 0x8b, 0xa4,
- 0x80, 0xc2, 0x8d, 0x8b, 0x07, 0x81, 0xac, 0x82,
- 0xb1, 0x00, 0x11, 0x0c, 0x80, 0xab, 0x24, 0x80,
- 0x40, 0xec, 0x87, 0x60, 0x4f, 0x32, 0x80, 0x48,
- 0x56, 0x84, 0x46, 0x85, 0x10, 0x0c, 0x83, 0x43,
- 0x13, 0x83, 0xc0, 0x80, 0x41, 0x40, 0x81, 0xce,
- 0x80, 0x41, 0x02, 0x82, 0xb4, 0x8d, 0xac, 0x81,
- 0x8a, 0x82, 0xac, 0x88, 0x88, 0x80, 0xbc, 0x82,
- 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, 0x8c,
- 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x08, 0x40,
- 0x9c, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09, 0x81,
- 0x89, 0x80, 0x89, 0x81, 0xd3, 0x88, 0x00, 0x08,
- 0x03, 0x01, 0xe6, 0x8c, 0x02, 0xe9, 0x91, 0x40,
- 0xec, 0x31, 0x86, 0x9c, 0x81, 0xd1, 0x8e, 0x00,
- 0xe9, 0x8a, 0xe6, 0x8d, 0x41, 0x00, 0x8c, 0x40,
- 0xf6, 0x28, 0x09, 0x0a, 0x00, 0x80, 0x40, 0x8d,
- 0x31, 0x2b, 0x80, 0x9b, 0x89, 0xa9, 0x20, 0x83,
- 0x91, 0x8a, 0xad, 0x8d, 0x41, 0x96, 0x38, 0x86,
- 0xd2, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, 0x08,
- 0x10, 0x02, 0x80, 0xc1, 0x20, 0x08, 0x83, 0x41,
- 0x5b, 0x83, 0x88, 0x08, 0x80, 0xaf, 0x32, 0x82,
- 0x60, 0x41, 0xdc, 0x90, 0x4e, 0x1f, 0x00, 0xb6,
- 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, 0x80, 0x60,
- 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3,
- 0x80, 0x48, 0xb6, 0x80, 0x47, 0xe7, 0x99, 0x85,
- 0x99, 0x85, 0x99,
- };
- static const uint8_t unicode_prop_Other_Lowercase_table[69] = {
- 0x40, 0xa9, 0x80, 0x8e, 0x80, 0x41, 0xf4, 0x88,
- 0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x4d,
- 0x80, 0x80, 0x4c, 0x2e, 0xbe, 0x8c, 0x80, 0xa1,
- 0xa4, 0x42, 0xb0, 0x80, 0x8c, 0x80, 0x8f, 0x8c,
- 0x40, 0xd2, 0x8f, 0x43, 0x4f, 0x99, 0x47, 0x91,
- 0x81, 0x60, 0x7a, 0x1d, 0x81, 0x40, 0xd1, 0x80,
- 0x40, 0x80, 0x12, 0x81, 0x43, 0x61, 0x83, 0x88,
- 0x80, 0x60, 0x5c, 0x15, 0x01, 0x10, 0xa9, 0x80,
- 0x88, 0x60, 0xd8, 0x74, 0xbd,
- };
- static const uint8_t unicode_prop_Other_Uppercase_table[15] = {
- 0x60, 0x21, 0x5f, 0x8f, 0x43, 0x45, 0x99, 0x61,
- 0xcc, 0x5f, 0x99, 0x85, 0x99, 0x85, 0x99,
- };
- static const uint8_t unicode_prop_Other_Grapheme_Extend_table[112] = {
- 0x49, 0xbd, 0x80, 0x97, 0x80, 0x41, 0x65, 0x80,
- 0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 0xe7,
- 0x00, 0x03, 0x08, 0x81, 0x88, 0x81, 0xe6, 0x80,
- 0x97, 0x80, 0xf6, 0x80, 0x8e, 0x80, 0x49, 0x34,
- 0x80, 0x9d, 0x80, 0x43, 0xff, 0x04, 0x00, 0x04,
- 0x81, 0xe4, 0x80, 0xc6, 0x81, 0x44, 0x17, 0x80,
- 0x50, 0x20, 0x81, 0x60, 0x79, 0x22, 0x80, 0xeb,
- 0x80, 0x60, 0x55, 0xdc, 0x81, 0x52, 0x1f, 0x80,
- 0xf3, 0x80, 0x41, 0x07, 0x80, 0x8d, 0x80, 0x88,
- 0x80, 0xdf, 0x80, 0x88, 0x01, 0x00, 0x14, 0x80,
- 0x40, 0xdf, 0x80, 0x8b, 0x80, 0x40, 0xf0, 0x80,
- 0x41, 0x05, 0x80, 0x42, 0x78, 0x80, 0x8b, 0x80,
- 0x46, 0x02, 0x80, 0x60, 0x50, 0xad, 0x81, 0x60,
- 0x61, 0x72, 0x0d, 0x85, 0x6c, 0x2e, 0xac, 0xdf,
- };
- static const uint8_t unicode_prop_Other_Default_Ignorable_Code_Point_table[32] = {
- 0x43, 0x4e, 0x80, 0x4e, 0x0e, 0x81, 0x46, 0x52,
- 0x81, 0x48, 0xae, 0x80, 0x50, 0xfd, 0x80, 0x60,
- 0xce, 0x3a, 0x80, 0xce, 0x88, 0x6d, 0x00, 0x06,
- 0x00, 0x9d, 0xdf, 0xff, 0x40, 0xef, 0x4e, 0x0f,
- };
- static const uint8_t unicode_prop_Other_ID_Start_table[11] = {
- 0x58, 0x84, 0x81, 0x48, 0x90, 0x80, 0x94, 0x80,
- 0x4f, 0x6b, 0x81,
- };
- static const uint8_t unicode_prop_Other_ID_Continue_table[22] = {
- 0x40, 0xb6, 0x80, 0x42, 0xce, 0x80, 0x4f, 0xe0,
- 0x88, 0x46, 0x67, 0x80, 0x46, 0x30, 0x81, 0x50,
- 0xec, 0x80, 0x60, 0xce, 0x68, 0x80,
- };
- static const uint8_t unicode_prop_Prepended_Concatenation_Mark_table[19] = {
- 0x45, 0xff, 0x85, 0x40, 0xd6, 0x80, 0xb0, 0x80,
- 0x41, 0x7f, 0x81, 0xcf, 0x80, 0x61, 0x07, 0xd9,
- 0x80, 0x8e, 0x80,
- };
- static const uint8_t unicode_prop_XID_Start1_table[31] = {
- 0x43, 0x79, 0x80, 0x4a, 0xb7, 0x80, 0xfe, 0x80,
- 0x60, 0x21, 0xe6, 0x81, 0x60, 0xcb, 0xc0, 0x85,
- 0x41, 0x95, 0x81, 0xf3, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x80, 0x41, 0x1e, 0x81,
- };
- static const uint8_t unicode_prop_XID_Continue1_table[23] = {
- 0x43, 0x79, 0x80, 0x60, 0x2d, 0x1f, 0x81, 0x60,
- 0xcb, 0xc0, 0x85, 0x41, 0x95, 0x81, 0xf3, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
- };
- static const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = {
- 0x41, 0xc3, 0x08, 0x08, 0x81, 0xa4, 0x81, 0x4e,
- 0xdc, 0xaa, 0x0a, 0x4e, 0x87, 0x3f, 0x3f, 0x87,
- 0x8b, 0x80, 0x8e, 0x80, 0xae, 0x80,
- };
- static const uint8_t unicode_prop_Changes_When_Casefolded1_table[29] = {
- 0x41, 0xef, 0x80, 0x41, 0x9e, 0x80, 0x9e, 0x80,
- 0x5a, 0xe4, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00,
- 0x80, 0xde, 0x06, 0x06, 0x80, 0x8a, 0x09, 0x81,
- 0x89, 0x10, 0x81, 0x8d, 0x80,
- };
- static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[450] = {
- 0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12,
- 0x10, 0x82, 0xf3, 0x80, 0x8b, 0x80, 0x40, 0x84,
- 0x01, 0x01, 0x80, 0xa2, 0x01, 0x80, 0x40, 0xbb,
- 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08, 0x81, 0x89,
- 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08, 0x07, 0x80,
- 0x9e, 0x80, 0xa0, 0x82, 0x9c, 0x80, 0x42, 0x28,
- 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87, 0xfb, 0x08,
- 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11, 0x80, 0x40,
- 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe, 0x80, 0xa7,
- 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88, 0x03, 0x03,
- 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00, 0x26, 0x80,
- 0x90, 0x80, 0x88, 0x03, 0x03, 0x03, 0x80, 0x8b,
- 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81, 0x46, 0x52,
- 0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10, 0x8a, 0x80,
- 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1, 0xa4, 0x40,
- 0xd5, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, 0x80,
- 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
- 0xb7, 0x05, 0x00, 0x13, 0x05, 0x11, 0x02, 0x0c,
- 0x11, 0x00, 0x00, 0x0c, 0x15, 0x05, 0x08, 0x8f,
- 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b, 0x00,
- 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a, 0x80,
- 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a, 0x01,
- 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06, 0x05,
- 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80, 0x40,
- 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41, 0x34,
- 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6, 0x82,
- 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0, 0x80,
- 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40, 0xd5,
- 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09, 0x80,
- 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf, 0x9e,
- 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f, 0x60,
- 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40, 0x80,
- 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, 0x60,
- 0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, 0x89,
- 0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, 0xc2,
- 0x00, 0x97, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb,
- 0xa0, 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7,
- 0x8c, 0x82, 0x99, 0x95, 0x94, 0x81, 0x8b, 0x80,
- 0x92, 0x03, 0x1a, 0x00, 0x80, 0x40, 0x86, 0x08,
- 0x80, 0x9f, 0x99, 0x40, 0x83, 0x15, 0x0d, 0x0d,
- 0x0a, 0x16, 0x06, 0x80, 0x88, 0x47, 0x87, 0x20,
- 0xa9, 0x80, 0x88, 0x60, 0xb4, 0xe4, 0x83, 0x50,
- 0x31, 0xa3, 0x44, 0x63, 0x86, 0x8d, 0x87, 0xbf,
- 0x85, 0x42, 0x3e, 0xd4, 0x80, 0xc6, 0x01, 0x08,
- 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0,
- 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00,
- 0x16, 0x80, 0x41, 0x53, 0x81, 0x41, 0x23, 0x81,
- 0xb1, 0x48, 0x2f, 0xbd, 0x4d, 0x91, 0x18, 0x9a,
- 0x01, 0x00, 0x08, 0x80, 0x89, 0x03, 0x00, 0x00,
- 0x28, 0x18, 0x00, 0x00, 0x02, 0x01, 0x00, 0x08,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x06,
- 0x03, 0x03, 0x00, 0x80, 0x89, 0x80, 0x90, 0x22,
- 0x04, 0x80, 0x90, 0x42, 0x43, 0x8a, 0x84, 0x9e,
- 0x80, 0x9f, 0x99, 0x82, 0xa2, 0x80, 0xee, 0x82,
- 0x8c, 0xab, 0x83, 0x88, 0x31, 0x49, 0x9d, 0x89,
- 0x60, 0xfc, 0x05, 0x42, 0x1d, 0x6b, 0x05, 0xe1,
- 0x4f, 0xff,
- };
- static const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = {
- 0xaf, 0x89, 0x35, 0x99, 0x85,
- };
- static const uint8_t unicode_prop_Bidi_Control_table[10] = {
- 0x46, 0x1b, 0x80, 0x59, 0xf0, 0x81, 0x99, 0x84,
- 0xb6, 0x83,
- };
- static const uint8_t unicode_prop_Dash_table[58] = {
- 0xac, 0x80, 0x45, 0x5b, 0x80, 0xb2, 0x80, 0x4e,
- 0x40, 0x80, 0x44, 0x04, 0x80, 0x48, 0x08, 0x85,
- 0xbc, 0x80, 0xa6, 0x80, 0x8e, 0x80, 0x41, 0x85,
- 0x80, 0x4c, 0x03, 0x01, 0x80, 0x9e, 0x0b, 0x80,
- 0x9b, 0x80, 0x41, 0xbd, 0x80, 0x92, 0x80, 0xee,
- 0x80, 0x60, 0xcd, 0x8f, 0x81, 0xa4, 0x80, 0x89,
- 0x80, 0x40, 0xa8, 0x80, 0x4e, 0x5f, 0x80, 0x41,
- 0x3d, 0x80,
- };
- static const uint8_t unicode_prop_Deprecated_table[23] = {
- 0x41, 0x48, 0x80, 0x45, 0x28, 0x80, 0x49, 0x02,
- 0x00, 0x80, 0x48, 0x28, 0x81, 0x48, 0xc4, 0x85,
- 0x42, 0xb8, 0x81, 0x6d, 0xdc, 0xd5, 0x80,
- };
- static const uint8_t unicode_prop_Diacritic_table[438] = {
- 0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81,
- 0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b,
- 0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0,
- 0x80, 0xb6, 0x90, 0x80, 0x9a, 0x00, 0x01, 0x00,
- 0x40, 0x85, 0x3b, 0x81, 0x40, 0x85, 0x0b, 0x0a,
- 0x82, 0xc2, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0xa1,
- 0x81, 0xfd, 0x87, 0xa8, 0x89, 0x8f, 0x9b, 0xbc,
- 0x80, 0x8f, 0x02, 0x83, 0x9b, 0x80, 0xc9, 0x80,
- 0x8f, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, 0x80,
- 0x8f, 0x80, 0xae, 0x82, 0xbb, 0x80, 0x8f, 0x06,
- 0x80, 0xf6, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed,
- 0x80, 0x8f, 0x80, 0xec, 0x81, 0x8f, 0x80, 0xfb,
- 0x80, 0xee, 0x80, 0x8b, 0x28, 0x80, 0xea, 0x80,
- 0x8c, 0x84, 0xca, 0x81, 0x9a, 0x00, 0x00, 0x03,
- 0x81, 0xc1, 0x10, 0x81, 0xbd, 0x80, 0xef, 0x00,
- 0x81, 0xa7, 0x0b, 0x84, 0x98, 0x30, 0x80, 0x89,
- 0x81, 0x42, 0xc0, 0x82, 0x43, 0xb3, 0x81, 0x9d,
- 0x80, 0x40, 0x93, 0x8a, 0x88, 0x80, 0x41, 0x5a,
- 0x82, 0x41, 0x23, 0x80, 0x93, 0x39, 0x80, 0xaf,
- 0x8e, 0x81, 0x8a, 0xe7, 0x80, 0x8e, 0x80, 0xa5,
- 0x88, 0xb5, 0x81, 0xb9, 0x80, 0x8a, 0x81, 0xc1,
- 0x81, 0xbf, 0x85, 0xd1, 0x98, 0x18, 0x28, 0x0a,
- 0xb1, 0xbe, 0xd8, 0x8b, 0xa4, 0x8a, 0x41, 0xbc,
- 0x00, 0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c, 0x82,
- 0x8c, 0x81, 0x4c, 0xef, 0x82, 0x41, 0x3c, 0x80,
- 0x41, 0xf9, 0x85, 0xe8, 0x83, 0xde, 0x80, 0x60,
- 0x75, 0x71, 0x80, 0x8b, 0x08, 0x80, 0x9b, 0x81,
- 0xd1, 0x81, 0x8d, 0xa1, 0xe5, 0x82, 0xec, 0x81,
- 0x8b, 0x80, 0xa4, 0x80, 0x40, 0x96, 0x80, 0x9a,
- 0x91, 0xb8, 0x83, 0xa3, 0x80, 0xde, 0x80, 0x8b,
- 0x80, 0xa3, 0x80, 0x40, 0x94, 0x82, 0xc0, 0x83,
- 0xb2, 0x80, 0xe3, 0x84, 0x88, 0x82, 0xff, 0x81,
- 0x60, 0x4f, 0x2f, 0x80, 0x43, 0x00, 0x8f, 0x41,
- 0x0d, 0x00, 0x80, 0xae, 0x80, 0xac, 0x81, 0xc2,
- 0x80, 0x42, 0xfb, 0x80, 0x44, 0x9e, 0x28, 0xa9,
- 0x80, 0x88, 0x42, 0x7c, 0x13, 0x80, 0x40, 0xa4,
- 0x81, 0x42, 0x3a, 0x85, 0xa5, 0x80, 0x99, 0x84,
- 0x41, 0x8e, 0x82, 0xc5, 0x8a, 0xb0, 0x83, 0x40,
- 0xbf, 0x80, 0xa8, 0x80, 0xc7, 0x81, 0xf7, 0x81,
- 0xbd, 0x80, 0xcb, 0x80, 0x88, 0x82, 0xe7, 0x81,
- 0x40, 0xb1, 0x81, 0xcf, 0x81, 0x8f, 0x80, 0x97,
- 0x32, 0x84, 0xd8, 0x10, 0x81, 0x8c, 0x81, 0xde,
- 0x02, 0x80, 0xfa, 0x81, 0x40, 0xfa, 0x81, 0xfd,
- 0x80, 0xf5, 0x81, 0xf2, 0x80, 0x41, 0x0c, 0x81,
- 0x41, 0x01, 0x0b, 0x80, 0x40, 0x9b, 0x80, 0xd2,
- 0x80, 0x91, 0x80, 0xd0, 0x80, 0x41, 0xa4, 0x80,
- 0x41, 0x01, 0x00, 0x81, 0xd0, 0x80, 0x41, 0xa8,
- 0x81, 0x96, 0x80, 0x54, 0xeb, 0x8e, 0x60, 0x2c,
- 0xd8, 0x80, 0x49, 0xbf, 0x84, 0xba, 0x86, 0x42,
- 0x33, 0x81, 0x42, 0x21, 0x90, 0xcf, 0x81, 0x60,
- 0x3f, 0xfd, 0x18, 0x30, 0x81, 0x5f, 0x00, 0xad,
- 0x81, 0x96, 0x42, 0x1f, 0x12, 0x2f, 0x39, 0x86,
- 0x9d, 0x83, 0x4e, 0x81, 0xbd, 0x40, 0xc1, 0x86,
- 0x41, 0x76, 0x80, 0xbc, 0x83, 0x42, 0xfd, 0x81,
- 0x42, 0xdf, 0x86, 0xec, 0x10, 0x82,
- };
- static const uint8_t unicode_prop_Extender_table[111] = {
- 0x40, 0xb6, 0x80, 0x42, 0x17, 0x81, 0x43, 0x6d,
- 0x80, 0x41, 0xb8, 0x80, 0x42, 0x75, 0x80, 0x40,
- 0x88, 0x80, 0xd8, 0x80, 0x42, 0xef, 0x80, 0xfe,
- 0x80, 0x49, 0x42, 0x80, 0xb7, 0x80, 0x42, 0x62,
- 0x80, 0x41, 0x8d, 0x80, 0xc3, 0x80, 0x53, 0x88,
- 0x80, 0xaa, 0x84, 0xe6, 0x81, 0xdc, 0x82, 0x60,
- 0x6f, 0x15, 0x80, 0x45, 0xf5, 0x80, 0x43, 0xc1,
- 0x80, 0x95, 0x80, 0x40, 0x88, 0x80, 0xeb, 0x80,
- 0x94, 0x81, 0x60, 0x54, 0x7a, 0x80, 0x48, 0x0f,
- 0x81, 0x45, 0xca, 0x80, 0x9a, 0x03, 0x80, 0x44,
- 0xc6, 0x80, 0x41, 0x24, 0x80, 0xf3, 0x81, 0x41,
- 0xf1, 0x82, 0x44, 0xce, 0x80, 0x60, 0x50, 0xa8,
- 0x81, 0x44, 0x9b, 0x08, 0x80, 0x60, 0x71, 0x57,
- 0x81, 0x44, 0xb0, 0x80, 0x43, 0x53, 0x82,
- };
- static const uint8_t unicode_prop_Hex_Digit_table[12] = {
- 0xaf, 0x89, 0x35, 0x99, 0x85, 0x60, 0xfe, 0xa8,
- 0x89, 0x35, 0x99, 0x85,
- };
- static const uint8_t unicode_prop_IDS_Unary_Operator_table[4] = {
- 0x60, 0x2f, 0xfd, 0x81,
- };
- static const uint8_t unicode_prop_IDS_Binary_Operator_table[8] = {
- 0x60, 0x2f, 0xef, 0x09, 0x89, 0x41, 0xf0, 0x80,
- };
- static const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = {
- 0x60, 0x2f, 0xf1, 0x81,
- };
- static const uint8_t unicode_prop_Ideographic_table[72] = {
- 0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82,
- 0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xff,
- 0x60, 0x58, 0xff, 0x41, 0x6d, 0x81, 0xe9, 0x60,
- 0x75, 0x09, 0x80, 0x9a, 0x57, 0xf7, 0x87, 0x44,
- 0xd5, 0xa8, 0x89, 0x60, 0x24, 0x66, 0x41, 0x8b,
- 0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdf, 0x9f, 0x50,
- 0x39, 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d,
- 0x5d, 0x30, 0x8e, 0x42, 0x6d, 0x49, 0xa1, 0x42,
- 0x1d, 0x45, 0xe1, 0x53, 0x4a, 0x84, 0x50, 0x5f,
- };
- static const uint8_t unicode_prop_Join_Control_table[4] = {
- 0x60, 0x20, 0x0b, 0x81,
- };
- static const uint8_t unicode_prop_Logical_Order_Exception_table[15] = {
- 0x4e, 0x3f, 0x84, 0xfa, 0x84, 0x4a, 0xef, 0x11,
- 0x80, 0x60, 0x90, 0xf9, 0x09, 0x00, 0x81,
- };
- static const uint8_t unicode_prop_Modifier_Combining_Mark_table[16] = {
- 0x46, 0x53, 0x09, 0x80, 0x40, 0x82, 0x05, 0x02,
- 0x81, 0x41, 0xe0, 0x08, 0x12, 0x80, 0x9e, 0x80,
- };
- static const uint8_t unicode_prop_Noncharacter_Code_Point_table[71] = {
- 0x60, 0xfd, 0xcf, 0x9f, 0x42, 0x0d, 0x81, 0x60,
- 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
- 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
- 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
- 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
- 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
- 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
- 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
- 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81,
- };
- static const uint8_t unicode_prop_Pattern_Syntax_table[58] = {
- 0xa0, 0x8e, 0x89, 0x86, 0x99, 0x18, 0x80, 0x99,
- 0x83, 0xa1, 0x30, 0x00, 0x08, 0x00, 0x0b, 0x03,
- 0x02, 0x80, 0x96, 0x80, 0x9e, 0x80, 0x5f, 0x17,
- 0x97, 0x87, 0x8e, 0x81, 0x92, 0x80, 0x89, 0x41,
- 0x30, 0x42, 0xcf, 0x40, 0x9f, 0x42, 0x75, 0x9d,
- 0x44, 0x6b, 0x41, 0xff, 0xff, 0x41, 0x80, 0x13,
- 0x98, 0x8e, 0x80, 0x60, 0xcd, 0x0c, 0x81, 0x41,
- 0x04, 0x81,
- };
- static const uint8_t unicode_prop_Pattern_White_Space_table[11] = {
- 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x5f, 0x87,
- 0x81, 0x97, 0x81,
- };
- static const uint8_t unicode_prop_Quotation_Mark_table[31] = {
- 0xa1, 0x03, 0x80, 0x40, 0x82, 0x80, 0x8e, 0x80,
- 0x5f, 0x5b, 0x87, 0x98, 0x81, 0x4e, 0x06, 0x80,
- 0x41, 0xc8, 0x83, 0x8c, 0x82, 0x60, 0xce, 0x20,
- 0x83, 0x40, 0xbc, 0x03, 0x80, 0xd9, 0x81,
- };
- static const uint8_t unicode_prop_Radical_table[9] = {
- 0x60, 0x2e, 0x7f, 0x99, 0x80, 0xd8, 0x8b, 0x40,
- 0xd5,
- };
- static const uint8_t unicode_prop_Regional_Indicator_table[4] = {
- 0x61, 0xf1, 0xe5, 0x99,
- };
- static const uint8_t unicode_prop_Sentence_Terminal_table[213] = {
- 0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48,
- 0x80, 0x40, 0x92, 0x82, 0x40, 0xb3, 0x80, 0xaa,
- 0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81,
- 0x41, 0x24, 0x81, 0x46, 0xe3, 0x81, 0x43, 0x15,
- 0x03, 0x81, 0x43, 0x04, 0x80, 0x40, 0xc5, 0x81,
- 0x40, 0x9c, 0x81, 0xac, 0x04, 0x80, 0x41, 0x39,
- 0x81, 0x41, 0x61, 0x83, 0x40, 0xa1, 0x81, 0x89,
- 0x09, 0x81, 0x9c, 0x82, 0x40, 0xba, 0x81, 0xc0,
- 0x81, 0x43, 0xa3, 0x80, 0x96, 0x81, 0x88, 0x82,
- 0x4c, 0xae, 0x82, 0x41, 0x31, 0x80, 0x8c, 0x80,
- 0x95, 0x81, 0x41, 0xac, 0x80, 0x60, 0x74, 0xfb,
- 0x80, 0x41, 0x0d, 0x81, 0x40, 0xe2, 0x02, 0x80,
- 0x41, 0x7d, 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40,
- 0x97, 0x81, 0x40, 0x92, 0x82, 0x40, 0x8f, 0x81,
- 0x40, 0xf8, 0x80, 0x60, 0x52, 0x25, 0x01, 0x81,
- 0xba, 0x02, 0x81, 0x40, 0xa8, 0x80, 0x8b, 0x80,
- 0x8f, 0x80, 0xc0, 0x80, 0x4a, 0xf3, 0x81, 0x44,
- 0xfc, 0x84, 0xab, 0x83, 0x40, 0xbc, 0x81, 0xf4,
- 0x83, 0xfe, 0x82, 0x40, 0x80, 0x0d, 0x80, 0x8f,
- 0x81, 0xd7, 0x08, 0x81, 0xeb, 0x80, 0x41, 0x29,
- 0x81, 0xf4, 0x81, 0x41, 0x74, 0x0c, 0x8e, 0xe8,
- 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, 0x00, 0x80,
- 0x40, 0xfa, 0x81, 0xd6, 0x81, 0x41, 0xa3, 0x81,
- 0x42, 0xb3, 0x81, 0xc9, 0x81, 0x60, 0x4b, 0x28,
- 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, 0x8a, 0x80,
- 0x42, 0x28, 0x81, 0x41, 0x27, 0x80, 0x60, 0x4e,
- 0x05, 0x80, 0x5d, 0xe7, 0x80,
- };
- static const uint8_t unicode_prop_Soft_Dotted_table[79] = {
- 0xe8, 0x81, 0x40, 0xc3, 0x80, 0x41, 0x18, 0x80,
- 0x9d, 0x80, 0xb3, 0x80, 0x93, 0x80, 0x41, 0x3f,
- 0x80, 0xe1, 0x00, 0x80, 0x59, 0x08, 0x80, 0xb2,
- 0x80, 0x8c, 0x02, 0x80, 0x40, 0x83, 0x80, 0x40,
- 0x9c, 0x80, 0x41, 0xa4, 0x80, 0x40, 0xd5, 0x81,
- 0x4b, 0x31, 0x80, 0x61, 0xa7, 0xa4, 0x81, 0xb1,
- 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1,
- 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1,
- 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0x48,
- 0x85, 0x80, 0x41, 0x30, 0x81, 0x99, 0x80,
- };
- static const uint8_t unicode_prop_Terminal_Punctuation_table[264] = {
- 0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80,
- 0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8,
- 0x80, 0xc7, 0x80, 0x8d, 0x00, 0x82, 0x40, 0xb3,
- 0x80, 0xaa, 0x8a, 0x00, 0x40, 0xea, 0x81, 0xb5,
- 0x28, 0x87, 0x9e, 0x80, 0x41, 0x04, 0x81, 0x44,
- 0xf3, 0x81, 0x40, 0xab, 0x03, 0x85, 0x41, 0x36,
- 0x81, 0x43, 0x14, 0x87, 0x43, 0x04, 0x80, 0xfb,
- 0x82, 0xc6, 0x81, 0x40, 0x9c, 0x12, 0x80, 0xa6,
- 0x19, 0x81, 0x41, 0x39, 0x81, 0x41, 0x61, 0x83,
- 0x40, 0xa1, 0x81, 0x89, 0x08, 0x82, 0x9c, 0x82,
- 0x40, 0xba, 0x84, 0xbd, 0x81, 0x43, 0xa3, 0x80,
- 0x96, 0x81, 0x88, 0x82, 0x4c, 0xae, 0x82, 0x41,
- 0x31, 0x80, 0x8c, 0x03, 0x80, 0x89, 0x00, 0x0a,
- 0x81, 0x41, 0xab, 0x81, 0x60, 0x74, 0xfa, 0x81,
- 0x41, 0x0c, 0x82, 0x40, 0xe2, 0x84, 0x41, 0x7d,
- 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x96, 0x82,
- 0x40, 0x92, 0x82, 0xfe, 0x80, 0x8f, 0x81, 0x40,
- 0xf8, 0x80, 0x60, 0x52, 0x25, 0x01, 0x81, 0xb8,
- 0x10, 0x83, 0x40, 0xa8, 0x80, 0x89, 0x00, 0x80,
- 0x8a, 0x0a, 0x80, 0xc0, 0x01, 0x80, 0x44, 0x39,
- 0x80, 0xaf, 0x80, 0x44, 0x85, 0x80, 0x40, 0xc6,
- 0x80, 0x41, 0x35, 0x81, 0x40, 0x97, 0x85, 0xc3,
- 0x85, 0xd8, 0x83, 0x43, 0xb7, 0x84, 0xab, 0x83,
- 0x40, 0xbc, 0x86, 0xef, 0x83, 0xfe, 0x82, 0x40,
- 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x84, 0xeb,
- 0x80, 0x41, 0x29, 0x81, 0xf4, 0x82, 0x8b, 0x81,
- 0x41, 0x65, 0x1a, 0x8e, 0xe8, 0x81, 0x40, 0xf8,
- 0x82, 0x42, 0x04, 0x00, 0x80, 0x40, 0xfa, 0x81,
- 0xd6, 0x0b, 0x81, 0x41, 0x9d, 0x82, 0xac, 0x80,
- 0x42, 0x84, 0x81, 0xc9, 0x81, 0x45, 0x2a, 0x84,
- 0x60, 0x45, 0xf8, 0x81, 0x40, 0x84, 0x80, 0xc0,
- 0x82, 0x89, 0x80, 0x42, 0x28, 0x81, 0x41, 0x26,
- 0x81, 0x60, 0x4e, 0x05, 0x80, 0x5d, 0xe6, 0x83,
- };
- static const uint8_t unicode_prop_Unified_Ideograph_table[48] = {
- 0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51,
- 0xff, 0x60, 0x5a, 0x0d, 0x08, 0x00, 0x81, 0x89,
- 0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60,
- 0xa6, 0xdf, 0x9f, 0x50, 0x39, 0x85, 0x40, 0xdd,
- 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x8e, 0x42,
- 0x6d, 0x51, 0xa1, 0x53, 0x4a, 0x84, 0x50, 0x5f,
- };
- static const uint8_t unicode_prop_Variation_Selector_table[13] = {
- 0x58, 0x0a, 0x10, 0x80, 0x60, 0xe5, 0xef, 0x8f,
- 0x6d, 0x02, 0xef, 0x40, 0xef,
- };
- static const uint8_t unicode_prop_Bidi_Mirrored_table[173] = {
- 0xa7, 0x81, 0x91, 0x00, 0x80, 0x9b, 0x00, 0x80,
- 0x9c, 0x00, 0x80, 0xac, 0x80, 0x8e, 0x80, 0x4e,
- 0x7d, 0x83, 0x47, 0x5c, 0x81, 0x49, 0x9b, 0x81,
- 0x89, 0x81, 0xb5, 0x81, 0x8d, 0x81, 0x40, 0xb0,
- 0x80, 0x40, 0xbf, 0x1a, 0x2a, 0x02, 0x0a, 0x18,
- 0x18, 0x00, 0x03, 0x88, 0x20, 0x80, 0x91, 0x23,
- 0x88, 0x08, 0x00, 0x38, 0x9f, 0x0b, 0x20, 0x88,
- 0x09, 0x92, 0x21, 0x88, 0x21, 0x0b, 0x97, 0x81,
- 0x8f, 0x3b, 0x93, 0x0e, 0x81, 0x44, 0x3c, 0x8d,
- 0xc9, 0x01, 0x18, 0x08, 0x14, 0x1c, 0x12, 0x8d,
- 0x41, 0x92, 0x95, 0x0d, 0x80, 0x8d, 0x38, 0x35,
- 0x10, 0x1c, 0x01, 0x0c, 0x18, 0x02, 0x09, 0x89,
- 0x29, 0x81, 0x8b, 0x92, 0x03, 0x08, 0x00, 0x08,
- 0x03, 0x21, 0x2a, 0x97, 0x81, 0x8a, 0x0b, 0x18,
- 0x09, 0x0b, 0xaa, 0x0f, 0x80, 0xa7, 0x20, 0x00,
- 0x14, 0x22, 0x18, 0x14, 0x00, 0x40, 0xff, 0x80,
- 0x42, 0x02, 0x1a, 0x08, 0x81, 0x8d, 0x09, 0x89,
- 0xaa, 0x87, 0x41, 0xaa, 0x89, 0x0f, 0x60, 0xce,
- 0x3c, 0x2c, 0x81, 0x40, 0xa1, 0x81, 0x91, 0x00,
- 0x80, 0x9b, 0x00, 0x80, 0x9c, 0x00, 0x00, 0x08,
- 0x81, 0x60, 0xd7, 0x76, 0x80, 0xb8, 0x80, 0xb8,
- 0x80, 0xb8, 0x80, 0xb8, 0x80,
- };
- static const uint8_t unicode_prop_Emoji_table[238] = {
- 0xa2, 0x05, 0x04, 0x89, 0xee, 0x03, 0x80, 0x5f,
- 0x8c, 0x80, 0x8b, 0x80, 0x40, 0xd7, 0x80, 0x95,
- 0x80, 0xd9, 0x85, 0x8e, 0x81, 0x41, 0x6e, 0x81,
- 0x8b, 0x80, 0x40, 0xa5, 0x80, 0x98, 0x8a, 0x1a,
- 0x40, 0xc6, 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80,
- 0x88, 0x80, 0xb9, 0x18, 0x84, 0x88, 0x01, 0x01,
- 0x09, 0x03, 0x01, 0x00, 0x09, 0x02, 0x02, 0x0f,
- 0x14, 0x00, 0x04, 0x8b, 0x8a, 0x09, 0x00, 0x08,
- 0x80, 0x91, 0x01, 0x81, 0x91, 0x28, 0x00, 0x0a,
- 0x0c, 0x01, 0x0b, 0x81, 0x8a, 0x0c, 0x09, 0x04,
- 0x08, 0x00, 0x81, 0x93, 0x0c, 0x28, 0x19, 0x03,
- 0x01, 0x01, 0x28, 0x01, 0x00, 0x00, 0x05, 0x02,
- 0x05, 0x80, 0x89, 0x81, 0x8e, 0x01, 0x03, 0x00,
- 0x03, 0x10, 0x80, 0x8a, 0x81, 0xaf, 0x82, 0x88,
- 0x80, 0x8d, 0x80, 0x8d, 0x80, 0x41, 0x73, 0x81,
- 0x41, 0xce, 0x82, 0x92, 0x81, 0xb2, 0x03, 0x80,
- 0x44, 0xd9, 0x80, 0x8b, 0x80, 0x42, 0x58, 0x00,
- 0x80, 0x61, 0xbd, 0x69, 0x80, 0x40, 0xc9, 0x80,
- 0x40, 0x9f, 0x81, 0x8b, 0x81, 0x8d, 0x01, 0x89,
- 0xca, 0x99, 0x01, 0x96, 0x80, 0x93, 0x01, 0x88,
- 0x94, 0x81, 0x40, 0xad, 0xa1, 0x81, 0xef, 0x09,
- 0x02, 0x81, 0xd2, 0x0a, 0x80, 0x41, 0x06, 0x80,
- 0xbe, 0x8a, 0x28, 0x97, 0x31, 0x0f, 0x8b, 0x01,
- 0x19, 0x03, 0x81, 0x8c, 0x09, 0x07, 0x81, 0x88,
- 0x04, 0x82, 0x8b, 0x17, 0x11, 0x00, 0x03, 0x05,
- 0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0a, 0x83,
- 0x89, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2,
- 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89, 0x80,
- 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x89, 0x84, 0xb7,
- 0x86, 0x8e, 0x81, 0x8a, 0x85, 0x88,
- };
- static const uint8_t unicode_prop_Emoji_Component_table[28] = {
- 0xa2, 0x05, 0x04, 0x89, 0x5f, 0xd2, 0x80, 0x40,
- 0xd4, 0x80, 0x60, 0xdd, 0x2a, 0x80, 0x60, 0xf3,
- 0xd5, 0x99, 0x41, 0xfa, 0x84, 0x45, 0xaf, 0x83,
- 0x6c, 0x06, 0x6b, 0xdf,
- };
- static const uint8_t unicode_prop_Emoji_Modifier_table[4] = {
- 0x61, 0xf3, 0xfa, 0x84,
- };
- static const uint8_t unicode_prop_Emoji_Modifier_Base_table[71] = {
- 0x60, 0x26, 0x1c, 0x80, 0x40, 0xda, 0x80, 0x8f,
- 0x83, 0x61, 0xcc, 0x76, 0x80, 0xbb, 0x11, 0x01,
- 0x82, 0xf4, 0x09, 0x8a, 0x94, 0x92, 0x10, 0x1a,
- 0x02, 0x30, 0x00, 0x97, 0x80, 0x40, 0xc8, 0x0b,
- 0x80, 0x94, 0x03, 0x81, 0x40, 0xad, 0x12, 0x84,
- 0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, 0x8a, 0x80,
- 0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, 0x88, 0x89,
- 0x0a, 0xb7, 0x80, 0xbc, 0x08, 0x08, 0x80, 0x90,
- 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x88,
- };
- static const uint8_t unicode_prop_Emoji_Presentation_table[144] = {
- 0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01,
- 0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b,
- 0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90,
- 0x0c, 0x0f, 0x04, 0x80, 0x94, 0x06, 0x08, 0x03,
- 0x01, 0x06, 0x03, 0x81, 0x9b, 0x80, 0xa2, 0x00,
- 0x03, 0x10, 0x80, 0xbc, 0x82, 0x97, 0x80, 0x8d,
- 0x80, 0x43, 0x5a, 0x81, 0xb2, 0x03, 0x80, 0x61,
- 0xc4, 0xad, 0x80, 0x40, 0xc9, 0x80, 0x40, 0xbd,
- 0x01, 0x89, 0xca, 0x99, 0x00, 0x97, 0x80, 0x93,
- 0x01, 0x20, 0x82, 0x94, 0x81, 0x40, 0xad, 0xa0,
- 0x8b, 0x88, 0x80, 0xc5, 0x80, 0x95, 0x8b, 0xaa,
- 0x1c, 0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80,
- 0x40, 0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91,
- 0x80, 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf,
- 0xc5, 0x28, 0x12, 0x0a, 0x1b, 0x8a, 0x0e, 0x88,
- 0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80,
- 0x89, 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x89,
- 0x84, 0xb7, 0x86, 0x8e, 0x81, 0x8a, 0x85, 0x88,
- };
- static const uint8_t unicode_prop_Extended_Pictographic_table[156] = {
- 0x40, 0xa8, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b,
- 0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85,
- 0x8e, 0x81, 0x41, 0x6e, 0x81, 0x8b, 0x80, 0xde,
- 0x80, 0xc5, 0x80, 0x98, 0x8a, 0x1a, 0x40, 0xc6,
- 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80, 0x88, 0x80,
- 0xb9, 0x18, 0x28, 0x8b, 0x80, 0xf1, 0x89, 0xf5,
- 0x81, 0x8a, 0x00, 0x00, 0x28, 0x10, 0x28, 0x89,
- 0x81, 0x8e, 0x01, 0x03, 0x00, 0x03, 0x10, 0x80,
- 0x8a, 0x84, 0xac, 0x82, 0x88, 0x80, 0x8d, 0x80,
- 0x8d, 0x80, 0x41, 0x73, 0x81, 0x41, 0xce, 0x82,
- 0x92, 0x81, 0xb2, 0x03, 0x80, 0x44, 0xd9, 0x80,
- 0x8b, 0x80, 0x42, 0x58, 0x00, 0x80, 0x61, 0xbd,
- 0x65, 0x40, 0xff, 0x8c, 0x82, 0x9e, 0x80, 0xbb,
- 0x85, 0x8b, 0x81, 0x8d, 0x01, 0x89, 0x91, 0xb8,
- 0x9a, 0x8e, 0x89, 0x80, 0x93, 0x01, 0x88, 0x03,
- 0x88, 0x41, 0xb1, 0x84, 0x41, 0x3d, 0x87, 0x41,
- 0x09, 0xaf, 0xff, 0xf3, 0x8b, 0xd4, 0xaa, 0x8b,
- 0x83, 0xb7, 0x87, 0x89, 0x85, 0xa7, 0x87, 0x9d,
- 0xd1, 0x8b, 0xae, 0x80, 0x89, 0x80, 0x41, 0xb8,
- 0x40, 0xff, 0x43, 0xfd,
- };
- static const uint8_t unicode_prop_Default_Ignorable_Code_Point_table[51] = {
- 0x40, 0xac, 0x80, 0x42, 0xa0, 0x80, 0x42, 0xcb,
- 0x80, 0x4b, 0x41, 0x81, 0x46, 0x52, 0x81, 0xd4,
- 0x84, 0x47, 0xfa, 0x84, 0x99, 0x84, 0xb0, 0x8f,
- 0x50, 0xf3, 0x80, 0x60, 0xcc, 0x9a, 0x8f, 0x40,
- 0xee, 0x80, 0x40, 0x9f, 0x80, 0xce, 0x88, 0x60,
- 0xbc, 0xa6, 0x83, 0x54, 0xce, 0x87, 0x6c, 0x2e,
- 0x84, 0x4f, 0xff,
- };
- typedef enum {
- UNICODE_PROP_Hyphen,
- UNICODE_PROP_Other_Math,
- UNICODE_PROP_Other_Alphabetic,
- UNICODE_PROP_Other_Lowercase,
- UNICODE_PROP_Other_Uppercase,
- UNICODE_PROP_Other_Grapheme_Extend,
- UNICODE_PROP_Other_Default_Ignorable_Code_Point,
- UNICODE_PROP_Other_ID_Start,
- UNICODE_PROP_Other_ID_Continue,
- UNICODE_PROP_Prepended_Concatenation_Mark,
- UNICODE_PROP_ID_Continue1,
- UNICODE_PROP_XID_Start1,
- UNICODE_PROP_XID_Continue1,
- UNICODE_PROP_Changes_When_Titlecased1,
- UNICODE_PROP_Changes_When_Casefolded1,
- UNICODE_PROP_Changes_When_NFKC_Casefolded1,
- UNICODE_PROP_ASCII_Hex_Digit,
- UNICODE_PROP_Bidi_Control,
- UNICODE_PROP_Dash,
- UNICODE_PROP_Deprecated,
- UNICODE_PROP_Diacritic,
- UNICODE_PROP_Extender,
- UNICODE_PROP_Hex_Digit,
- UNICODE_PROP_IDS_Unary_Operator,
- UNICODE_PROP_IDS_Binary_Operator,
- UNICODE_PROP_IDS_Trinary_Operator,
- UNICODE_PROP_Ideographic,
- UNICODE_PROP_Join_Control,
- UNICODE_PROP_Logical_Order_Exception,
- UNICODE_PROP_Modifier_Combining_Mark,
- UNICODE_PROP_Noncharacter_Code_Point,
- UNICODE_PROP_Pattern_Syntax,
- UNICODE_PROP_Pattern_White_Space,
- UNICODE_PROP_Quotation_Mark,
- UNICODE_PROP_Radical,
- UNICODE_PROP_Regional_Indicator,
- UNICODE_PROP_Sentence_Terminal,
- UNICODE_PROP_Soft_Dotted,
- UNICODE_PROP_Terminal_Punctuation,
- UNICODE_PROP_Unified_Ideograph,
- UNICODE_PROP_Variation_Selector,
- UNICODE_PROP_White_Space,
- UNICODE_PROP_Bidi_Mirrored,
- UNICODE_PROP_Emoji,
- UNICODE_PROP_Emoji_Component,
- UNICODE_PROP_Emoji_Modifier,
- UNICODE_PROP_Emoji_Modifier_Base,
- UNICODE_PROP_Emoji_Presentation,
- UNICODE_PROP_Extended_Pictographic,
- UNICODE_PROP_Default_Ignorable_Code_Point,
- UNICODE_PROP_ID_Start,
- UNICODE_PROP_Case_Ignorable,
- UNICODE_PROP_ASCII,
- UNICODE_PROP_Alphabetic,
- UNICODE_PROP_Any,
- UNICODE_PROP_Assigned,
- UNICODE_PROP_Cased,
- UNICODE_PROP_Changes_When_Casefolded,
- UNICODE_PROP_Changes_When_Casemapped,
- UNICODE_PROP_Changes_When_Lowercased,
- UNICODE_PROP_Changes_When_NFKC_Casefolded,
- UNICODE_PROP_Changes_When_Titlecased,
- UNICODE_PROP_Changes_When_Uppercased,
- UNICODE_PROP_Grapheme_Base,
- UNICODE_PROP_Grapheme_Extend,
- UNICODE_PROP_ID_Continue,
- UNICODE_PROP_ID_Compat_Math_Start,
- UNICODE_PROP_ID_Compat_Math_Continue,
- UNICODE_PROP_Lowercase,
- UNICODE_PROP_Math,
- UNICODE_PROP_Uppercase,
- UNICODE_PROP_XID_Continue,
- UNICODE_PROP_XID_Start,
- UNICODE_PROP_Cased1,
- UNICODE_PROP_InCB,
- UNICODE_PROP_COUNT,
- } UnicodePropertyEnum;
- static const char unicode_prop_name_table[] =
- "ASCII_Hex_Digit,AHex" "\0"
- "Bidi_Control,Bidi_C" "\0"
- "Dash" "\0"
- "Deprecated,Dep" "\0"
- "Diacritic,Dia" "\0"
- "Extender,Ext" "\0"
- "Hex_Digit,Hex" "\0"
- "IDS_Unary_Operator,IDSU" "\0"
- "IDS_Binary_Operator,IDSB" "\0"
- "IDS_Trinary_Operator,IDST" "\0"
- "Ideographic,Ideo" "\0"
- "Join_Control,Join_C" "\0"
- "Logical_Order_Exception,LOE" "\0"
- "Modifier_Combining_Mark,MCM" "\0"
- "Noncharacter_Code_Point,NChar" "\0"
- "Pattern_Syntax,Pat_Syn" "\0"
- "Pattern_White_Space,Pat_WS" "\0"
- "Quotation_Mark,QMark" "\0"
- "Radical" "\0"
- "Regional_Indicator,RI" "\0"
- "Sentence_Terminal,STerm" "\0"
- "Soft_Dotted,SD" "\0"
- "Terminal_Punctuation,Term" "\0"
- "Unified_Ideograph,UIdeo" "\0"
- "Variation_Selector,VS" "\0"
- "White_Space,space" "\0"
- "Bidi_Mirrored,Bidi_M" "\0"
- "Emoji" "\0"
- "Emoji_Component,EComp" "\0"
- "Emoji_Modifier,EMod" "\0"
- "Emoji_Modifier_Base,EBase" "\0"
- "Emoji_Presentation,EPres" "\0"
- "Extended_Pictographic,ExtPict" "\0"
- "Default_Ignorable_Code_Point,DI" "\0"
- "ID_Start,IDS" "\0"
- "Case_Ignorable,CI" "\0"
- "ASCII" "\0"
- "Alphabetic,Alpha" "\0"
- "Any" "\0"
- "Assigned" "\0"
- "Cased" "\0"
- "Changes_When_Casefolded,CWCF" "\0"
- "Changes_When_Casemapped,CWCM" "\0"
- "Changes_When_Lowercased,CWL" "\0"
- "Changes_When_NFKC_Casefolded,CWKCF" "\0"
- "Changes_When_Titlecased,CWT" "\0"
- "Changes_When_Uppercased,CWU" "\0"
- "Grapheme_Base,Gr_Base" "\0"
- "Grapheme_Extend,Gr_Ext" "\0"
- "ID_Continue,IDC" "\0"
- "ID_Compat_Math_Start" "\0"
- "ID_Compat_Math_Continue" "\0"
- "Lowercase,Lower" "\0"
- "Math" "\0"
- "Uppercase,Upper" "\0"
- "XID_Continue,XIDC" "\0"
- "XID_Start,XIDS" "\0"
- ;
- static const uint8_t * const unicode_prop_table[] = {
- unicode_prop_Hyphen_table,
- unicode_prop_Other_Math_table,
- unicode_prop_Other_Alphabetic_table,
- unicode_prop_Other_Lowercase_table,
- unicode_prop_Other_Uppercase_table,
- unicode_prop_Other_Grapheme_Extend_table,
- unicode_prop_Other_Default_Ignorable_Code_Point_table,
- unicode_prop_Other_ID_Start_table,
- unicode_prop_Other_ID_Continue_table,
- unicode_prop_Prepended_Concatenation_Mark_table,
- unicode_prop_ID_Continue1_table,
- unicode_prop_XID_Start1_table,
- unicode_prop_XID_Continue1_table,
- unicode_prop_Changes_When_Titlecased1_table,
- unicode_prop_Changes_When_Casefolded1_table,
- unicode_prop_Changes_When_NFKC_Casefolded1_table,
- unicode_prop_ASCII_Hex_Digit_table,
- unicode_prop_Bidi_Control_table,
- unicode_prop_Dash_table,
- unicode_prop_Deprecated_table,
- unicode_prop_Diacritic_table,
- unicode_prop_Extender_table,
- unicode_prop_Hex_Digit_table,
- unicode_prop_IDS_Unary_Operator_table,
- unicode_prop_IDS_Binary_Operator_table,
- unicode_prop_IDS_Trinary_Operator_table,
- unicode_prop_Ideographic_table,
- unicode_prop_Join_Control_table,
- unicode_prop_Logical_Order_Exception_table,
- unicode_prop_Modifier_Combining_Mark_table,
- unicode_prop_Noncharacter_Code_Point_table,
- unicode_prop_Pattern_Syntax_table,
- unicode_prop_Pattern_White_Space_table,
- unicode_prop_Quotation_Mark_table,
- unicode_prop_Radical_table,
- unicode_prop_Regional_Indicator_table,
- unicode_prop_Sentence_Terminal_table,
- unicode_prop_Soft_Dotted_table,
- unicode_prop_Terminal_Punctuation_table,
- unicode_prop_Unified_Ideograph_table,
- unicode_prop_Variation_Selector_table,
- unicode_prop_White_Space_table,
- unicode_prop_Bidi_Mirrored_table,
- unicode_prop_Emoji_table,
- unicode_prop_Emoji_Component_table,
- unicode_prop_Emoji_Modifier_table,
- unicode_prop_Emoji_Modifier_Base_table,
- unicode_prop_Emoji_Presentation_table,
- unicode_prop_Extended_Pictographic_table,
- unicode_prop_Default_Ignorable_Code_Point_table,
- unicode_prop_ID_Start_table,
- unicode_prop_Case_Ignorable_table,
- };
- static const uint16_t unicode_prop_len_table[] = {
- countof(unicode_prop_Hyphen_table),
- countof(unicode_prop_Other_Math_table),
- countof(unicode_prop_Other_Alphabetic_table),
- countof(unicode_prop_Other_Lowercase_table),
- countof(unicode_prop_Other_Uppercase_table),
- countof(unicode_prop_Other_Grapheme_Extend_table),
- countof(unicode_prop_Other_Default_Ignorable_Code_Point_table),
- countof(unicode_prop_Other_ID_Start_table),
- countof(unicode_prop_Other_ID_Continue_table),
- countof(unicode_prop_Prepended_Concatenation_Mark_table),
- countof(unicode_prop_ID_Continue1_table),
- countof(unicode_prop_XID_Start1_table),
- countof(unicode_prop_XID_Continue1_table),
- countof(unicode_prop_Changes_When_Titlecased1_table),
- countof(unicode_prop_Changes_When_Casefolded1_table),
- countof(unicode_prop_Changes_When_NFKC_Casefolded1_table),
- countof(unicode_prop_ASCII_Hex_Digit_table),
- countof(unicode_prop_Bidi_Control_table),
- countof(unicode_prop_Dash_table),
- countof(unicode_prop_Deprecated_table),
- countof(unicode_prop_Diacritic_table),
- countof(unicode_prop_Extender_table),
- countof(unicode_prop_Hex_Digit_table),
- countof(unicode_prop_IDS_Unary_Operator_table),
- countof(unicode_prop_IDS_Binary_Operator_table),
- countof(unicode_prop_IDS_Trinary_Operator_table),
- countof(unicode_prop_Ideographic_table),
- countof(unicode_prop_Join_Control_table),
- countof(unicode_prop_Logical_Order_Exception_table),
- countof(unicode_prop_Modifier_Combining_Mark_table),
- countof(unicode_prop_Noncharacter_Code_Point_table),
- countof(unicode_prop_Pattern_Syntax_table),
- countof(unicode_prop_Pattern_White_Space_table),
- countof(unicode_prop_Quotation_Mark_table),
- countof(unicode_prop_Radical_table),
- countof(unicode_prop_Regional_Indicator_table),
- countof(unicode_prop_Sentence_Terminal_table),
- countof(unicode_prop_Soft_Dotted_table),
- countof(unicode_prop_Terminal_Punctuation_table),
- countof(unicode_prop_Unified_Ideograph_table),
- countof(unicode_prop_Variation_Selector_table),
- countof(unicode_prop_White_Space_table),
- countof(unicode_prop_Bidi_Mirrored_table),
- countof(unicode_prop_Emoji_table),
- countof(unicode_prop_Emoji_Component_table),
- countof(unicode_prop_Emoji_Modifier_table),
- countof(unicode_prop_Emoji_Modifier_Base_table),
- countof(unicode_prop_Emoji_Presentation_table),
- countof(unicode_prop_Extended_Pictographic_table),
- countof(unicode_prop_Default_Ignorable_Code_Point_table),
- countof(unicode_prop_ID_Start_table),
- countof(unicode_prop_Case_Ignorable_table),
- };
- /*
- * QuickJS Javascript Engine
- *
- * Copyright (c) 2017-2024 Fabrice Bellard
- * Copyright (c) 2017-2024 Charlie Gordon
- * Copyright (c) 2023-2025 Ben Noordhuis
- * Copyright (c) 2023-2025 Saúl Ibarra Corretgé
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifndef QUICKJS_H
- #define QUICKJS_H
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <string.h>
- #include <math.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- #define QUICKJS_NG 1
- #if defined(__GNUC__) || defined(__clang__)
- #define js_force_inline inline __attribute__((always_inline))
- #define JS_EXTERN __attribute__((visibility("default")))
- #else
- #define js_force_inline inline
- #define JS_EXTERN /* nothing */
- #endif
- /* Borrowed from Folly */
- #ifndef JS_PRINTF_FORMAT
- #ifdef _MSC_VER
- #include <sal.h>
- #define JS_PRINTF_FORMAT _Printf_format_string_
- #define JS_PRINTF_FORMAT_ATTR(format_param, dots_param)
- #else
- #define JS_PRINTF_FORMAT
- #if !defined(__clang__) && defined(__GNUC__)
- #define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \
- __attribute__((format(gnu_printf, format_param, dots_param)))
- #else
- #define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \
- __attribute__((format(printf, format_param, dots_param)))
- #endif
- #endif
- #endif
- typedef struct JSRuntime JSRuntime;
- typedef struct JSContext JSContext;
- typedef struct JSObject JSObject;
- typedef struct JSClass JSClass;
- typedef uint32_t JSClassID;
- typedef uint32_t JSAtom;
- /* Unless documented otherwise, C string pointers (`char *` or `const char *`)
- are assumed to verify these constraints:
- - unless a length is passed separately, the string has a null terminator
- - string contents is either pure ASCII or is UTF-8 encoded.
- */
- /* Overridable purely for testing purposes; don't touch. */
- #ifndef JS_NAN_BOXING
- #if INTPTR_MAX < INT64_MAX
- #define JS_NAN_BOXING 1 /* Use NAN boxing for 32bit builds. */
- #endif
- #endif
- enum {
- /* all tags with a reference count are negative */
- JS_TAG_FIRST = -9, /* first negative tag */
- JS_TAG_BIG_INT = -9,
- JS_TAG_SYMBOL = -8,
- JS_TAG_STRING = -7,
- JS_TAG_MODULE = -3, /* used internally */
- JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */
- JS_TAG_OBJECT = -1,
- JS_TAG_INT = 0,
- JS_TAG_BOOL = 1,
- JS_TAG_NULL = 2,
- JS_TAG_UNDEFINED = 3,
- JS_TAG_UNINITIALIZED = 4,
- JS_TAG_CATCH_OFFSET = 5,
- JS_TAG_EXCEPTION = 6,
- JS_TAG_SHORT_BIG_INT = 7,
- JS_TAG_FLOAT64 = 8,
- /* any larger tag is FLOAT64 if JS_NAN_BOXING */
- };
- #if !defined(JS_CHECK_JSVALUE)
- #define JSValueConst JSValue
- #endif
- // JS_CHECK_JSVALUE build mode does not produce working code but is here to
- // help catch reference counting bugs at compile time, by making it harder
- // to mix up JSValue and JSValueConst
- //
- // rules:
- //
- // - a function with a JSValue parameter takes ownership;
- // caller must *not* call JS_FreeValue
- //
- // - a function with a JSValueConst parameter does not take ownership;
- // caller *must* call JS_FreeValue
- //
- // - a function returning a JSValue transfers ownership to caller;
- // caller *must* call JS_FreeValue
- //
- // - a function returning a JSValueConst does *not* transfer ownership;
- // caller must *not* call JS_FreeValue
- #if defined(JS_CHECK_JSVALUE)
- typedef struct JSValue *JSValue;
- typedef const struct JSValue *JSValueConst;
- #define JS_MKVAL(tag, val) ((JSValue)((tag) | (intptr_t)(val) << 4))
- #define JS_MKPTR(tag, ptr) ((JSValue)((tag) | (intptr_t)(ptr)))
- #define JS_VALUE_GET_NORM_TAG(v) ((int)((intptr_t)(v) & 15))
- #define JS_VALUE_GET_TAG(v) ((int)((intptr_t)(v) & 15))
- #define JS_VALUE_GET_SHORT_BIG_INT(v) JS_VALUE_GET_INT(v)
- #define JS_VALUE_GET_PTR(v) ((void *)((intptr_t)(v) & ~15))
- #define JS_VALUE_GET_INT(v) ((int)((intptr_t)(v) >> 4))
- #define JS_VALUE_GET_BOOL(v) ((int)((intptr_t)(v) >> 4))
- #define JS_VALUE_GET_FLOAT64(v) ((double)((intptr_t)(v) >> 4))
- #define JS_TAG_IS_FLOAT64(tag) ((int)(tag) == JS_TAG_FLOAT64)
- #define JS_NAN JS_MKVAL(JS_TAG_FLOAT64, 0)
- static inline JSValue __JS_NewFloat64(double d)
- {
- return JS_MKVAL(JS_TAG_FLOAT64, (int)d);
- }
- static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int32_t d)
- {
- (void)&ctx;
- return JS_MKVAL(JS_TAG_SHORT_BIG_INT, d);
- }
- static inline bool JS_VALUE_IS_NAN(JSValue v)
- {
- (void)&v;
- return false;
- }
- #elif defined(JS_NAN_BOXING) && JS_NAN_BOXING
- typedef uint64_t JSValue;
- #define JS_VALUE_GET_TAG(v) (int)((v) >> 32)
- #define JS_VALUE_GET_INT(v) (int)(v)
- #define JS_VALUE_GET_BOOL(v) (int)(v)
- #define JS_VALUE_GET_SHORT_BIG_INT(v) (int)(v)
- #define JS_VALUE_GET_PTR(v) (void *)(intptr_t)(v)
- #define JS_MKVAL(tag, val) (((uint64_t)(tag) << 32) | (uint32_t)(val))
- #define JS_MKPTR(tag, ptr) (((uint64_t)(tag) << 32) | (uintptr_t)(ptr))
- #define JS_FLOAT64_TAG_ADDEND (0x7ff80000 - JS_TAG_FIRST + 1) /* quiet NaN encoding */
- static inline double JS_VALUE_GET_FLOAT64(JSValue v)
- {
- union {
- JSValue v;
- double d;
- } u;
- u.v = v;
- u.v += (uint64_t)JS_FLOAT64_TAG_ADDEND << 32;
- return u.d;
- }
- #define JS_NAN (0x7ff8000000000000 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32))
- static inline JSValue __JS_NewFloat64(double d)
- {
- union {
- double d;
- uint64_t u64;
- } u;
- JSValue v;
- u.d = d;
- /* normalize NaN */
- if ((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000)
- v = JS_NAN;
- else
- v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32);
- return v;
- }
- static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int32_t d)
- {
- (void)&ctx;
- return JS_MKVAL(JS_TAG_SHORT_BIG_INT, d);
- }
- #define JS_TAG_IS_FLOAT64(tag) ((unsigned)((tag) - JS_TAG_FIRST) >= (JS_TAG_FLOAT64 - JS_TAG_FIRST))
- /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */
- static inline int JS_VALUE_GET_NORM_TAG(JSValue v)
- {
- uint32_t tag;
- tag = JS_VALUE_GET_TAG(v);
- if (JS_TAG_IS_FLOAT64(tag))
- return JS_TAG_FLOAT64;
- else
- return tag;
- }
- static inline bool JS_VALUE_IS_NAN(JSValue v)
- {
- uint32_t tag;
- tag = JS_VALUE_GET_TAG(v);
- return tag == (JS_NAN >> 32);
- }
- #else /* !JS_NAN_BOXING */
- typedef union JSValueUnion {
- int32_t int32;
- double float64;
- void *ptr;
- int32_t short_big_int;
- } JSValueUnion;
- typedef struct JSValue {
- JSValueUnion u;
- int64_t tag;
- } JSValue;
- #define JS_VALUE_GET_TAG(v) ((int32_t)(v).tag)
- /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */
- #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v)
- #define JS_VALUE_GET_INT(v) ((v).u.int32)
- #define JS_VALUE_GET_BOOL(v) ((v).u.int32)
- #define JS_VALUE_GET_FLOAT64(v) ((v).u.float64)
- #define JS_VALUE_GET_SHORT_BIG_INT(v) ((v).u.short_big_int)
- #define JS_VALUE_GET_PTR(v) ((v).u.ptr)
- /* msvc doesn't understand designated initializers without /std:c++20 */
- #ifdef __cplusplus
- static inline JSValue JS_MKPTR(int64_t tag, void *ptr)
- {
- JSValue v;
- v.u.ptr = ptr;
- v.tag = tag;
- return v;
- }
- static inline JSValue JS_MKVAL(int64_t tag, int32_t int32)
- {
- JSValue v;
- v.u.int32 = int32;
- v.tag = tag;
- return v;
- }
- static inline JSValue JS_MKNAN(void)
- {
- JSValue v;
- v.u.float64 = NAN;
- v.tag = JS_TAG_FLOAT64;
- return v;
- }
- /* provide as macros for consistency and backward compat reasons */
- #define JS_MKPTR(tag, ptr) JS_MKPTR(tag, ptr)
- #define JS_MKVAL(tag, val) JS_MKVAL(tag, val)
- #define JS_NAN JS_MKNAN() /* alas, not a constant expression */
- #else
- #define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag }
- #define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag }
- #define JS_NAN (JSValue){ (JSValueUnion){ .float64 = NAN }, JS_TAG_FLOAT64 }
- #endif
- #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64)
- static inline JSValue __JS_NewFloat64(double d)
- {
- JSValue v;
- v.tag = JS_TAG_FLOAT64;
- v.u.float64 = d;
- return v;
- }
- static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int64_t d)
- {
- (void)&ctx;
- JSValue v;
- v.tag = JS_TAG_SHORT_BIG_INT;
- v.u.short_big_int = d;
- return v;
- }
- static inline bool JS_VALUE_IS_NAN(JSValue v)
- {
- union {
- double d;
- uint64_t u64;
- } u;
- if (v.tag != JS_TAG_FLOAT64)
- return 0;
- u.d = v.u.float64;
- return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000;
- }
- #endif /* !JS_NAN_BOXING */
- #define JS_VALUE_IS_BOTH_INT(v1, v2) ((JS_VALUE_GET_TAG(v1) | JS_VALUE_GET_TAG(v2)) == 0)
- #define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2)))
- #define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v))
- #define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST)
- /* special values */
- #define JS_NULL JS_MKVAL(JS_TAG_NULL, 0)
- #define JS_UNDEFINED JS_MKVAL(JS_TAG_UNDEFINED, 0)
- #define JS_FALSE JS_MKVAL(JS_TAG_BOOL, 0)
- #define JS_TRUE JS_MKVAL(JS_TAG_BOOL, 1)
- #define JS_EXCEPTION JS_MKVAL(JS_TAG_EXCEPTION, 0)
- #define JS_UNINITIALIZED JS_MKVAL(JS_TAG_UNINITIALIZED, 0)
- /* flags for object properties */
- #define JS_PROP_CONFIGURABLE (1 << 0)
- #define JS_PROP_WRITABLE (1 << 1)
- #define JS_PROP_ENUMERABLE (1 << 2)
- #define JS_PROP_C_W_E (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)
- #define JS_PROP_LENGTH (1 << 3) /* used internally in Arrays */
- #define JS_PROP_TMASK (3 << 4) /* mask for NORMAL, GETSET, VARREF, AUTOINIT */
- #define JS_PROP_NORMAL (0 << 4)
- #define JS_PROP_GETSET (1 << 4)
- #define JS_PROP_VARREF (2 << 4) /* used internally */
- #define JS_PROP_AUTOINIT (3 << 4) /* used internally */
- /* flags for JS_DefineProperty */
- #define JS_PROP_HAS_SHIFT 8
- #define JS_PROP_HAS_CONFIGURABLE (1 << 8)
- #define JS_PROP_HAS_WRITABLE (1 << 9)
- #define JS_PROP_HAS_ENUMERABLE (1 << 10)
- #define JS_PROP_HAS_GET (1 << 11)
- #define JS_PROP_HAS_SET (1 << 12)
- #define JS_PROP_HAS_VALUE (1 << 13)
- /* throw an exception if false would be returned
- (JS_DefineProperty/JS_SetProperty) */
- #define JS_PROP_THROW (1 << 14)
- /* throw an exception if false would be returned in strict mode
- (JS_SetProperty) */
- #define JS_PROP_THROW_STRICT (1 << 15)
- #define JS_PROP_NO_ADD (1 << 16) /* internal use */
- #define JS_PROP_NO_EXOTIC (1 << 17) /* internal use */
- #define JS_PROP_DEFINE_PROPERTY (1 << 18) /* internal use */
- #define JS_PROP_REFLECT_DEFINE_PROPERTY (1 << 19) /* internal use */
- #ifndef JS_DEFAULT_STACK_SIZE
- #define JS_DEFAULT_STACK_SIZE (1024 * 1024)
- #endif
- /* JS_Eval() flags */
- #define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */
- #define JS_EVAL_TYPE_MODULE (1 << 0) /* module code */
- #define JS_EVAL_TYPE_DIRECT (2 << 0) /* direct call (internal use) */
- #define JS_EVAL_TYPE_INDIRECT (3 << 0) /* indirect call (internal use) */
- #define JS_EVAL_TYPE_MASK (3 << 0)
- #define JS_EVAL_FLAG_STRICT (1 << 3) /* force 'strict' mode */
- #define JS_EVAL_FLAG_UNUSED (1 << 4) /* unused */
- /* compile but do not run. The result is an object with a
- JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed
- with JS_EvalFunction(). */
- #define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5)
- /* don't include the stack frames before this eval in the Error() backtraces */
- #define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6)
- /* allow top-level await in normal script. JS_Eval() returns a
- promise. Only allowed with JS_EVAL_TYPE_GLOBAL */
- #define JS_EVAL_FLAG_ASYNC (1 << 7)
- typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
- typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);
- typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValueConst *func_data);
- typedef struct JSMallocFunctions {
- void *(*js_calloc)(void *opaque, size_t count, size_t size);
- void *(*js_malloc)(void *opaque, size_t size);
- void (*js_free)(void *opaque, void *ptr);
- void *(*js_realloc)(void *opaque, void *ptr, size_t size);
- size_t (*js_malloc_usable_size)(const void *ptr);
- } JSMallocFunctions;
- // Debug trace system: the debug output will be produced to the dump stream (currently
- // stdout) if dumps are enabled and JS_SetDumpFlags is invoked with the corresponding
- // bit set.
- #define JS_DUMP_BYTECODE_FINAL 0x01 /* dump pass 3 final byte code */
- #define JS_DUMP_BYTECODE_PASS2 0x02 /* dump pass 2 code */
- #define JS_DUMP_BYTECODE_PASS1 0x04 /* dump pass 1 code */
- #define JS_DUMP_BYTECODE_HEX 0x10 /* dump bytecode in hex */
- #define JS_DUMP_BYTECODE_PC2LINE 0x20 /* dump line number table */
- #define JS_DUMP_BYTECODE_STACK 0x40 /* dump compute_stack_size */
- #define JS_DUMP_BYTECODE_STEP 0x80 /* dump executed bytecode */
- #define JS_DUMP_READ_OBJECT 0x100 /* dump the marshalled objects at load time */
- #define JS_DUMP_FREE 0x200 /* dump every object free */
- #define JS_DUMP_GC 0x400 /* dump the occurrence of the automatic GC */
- #define JS_DUMP_GC_FREE 0x800 /* dump objects freed by the GC */
- #define JS_DUMP_MODULE_RESOLVE 0x1000 /* dump module resolution steps */
- #define JS_DUMP_PROMISE 0x2000 /* dump promise steps */
- #define JS_DUMP_LEAKS 0x4000 /* dump leaked objects and strings in JS_FreeRuntime */
- #define JS_DUMP_ATOM_LEAKS 0x8000 /* dump leaked atoms in JS_FreeRuntime */
- #define JS_DUMP_MEM 0x10000 /* dump memory usage in JS_FreeRuntime */
- #define JS_DUMP_OBJECTS 0x20000 /* dump objects in JS_FreeRuntime */
- #define JS_DUMP_ATOMS 0x40000 /* dump atoms in JS_FreeRuntime */
- #define JS_DUMP_SHAPES 0x80000 /* dump shapes in JS_FreeRuntime */
- // Finalizers run in LIFO order at the very end of JS_FreeRuntime.
- // Intended for cleanup of associated resources; the runtime itself
- // is no longer usable.
- typedef void JSRuntimeFinalizer(JSRuntime *rt, void *arg);
- typedef struct JSGCObjectHeader JSGCObjectHeader;
- JS_EXTERN JSRuntime *JS_NewRuntime(void);
- /* info lifetime must exceed that of rt */
- JS_EXTERN void JS_SetRuntimeInfo(JSRuntime *rt, const char *info);
- /* use 0 to disable memory limit */
- JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit);
- JS_EXTERN void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags);
- JS_EXTERN uint64_t JS_GetDumpFlags(JSRuntime *rt);
- JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt);
- JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);
- /* use 0 to disable maximum stack size check */
- JS_EXTERN void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size);
- /* should be called when changing thread to update the stack top value
- used to check stack overflow. */
- JS_EXTERN void JS_UpdateStackTop(JSRuntime *rt);
- JS_EXTERN JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque);
- JS_EXTERN void JS_FreeRuntime(JSRuntime *rt);
- JS_EXTERN void *JS_GetRuntimeOpaque(JSRuntime *rt);
- JS_EXTERN void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque);
- JS_EXTERN int JS_AddRuntimeFinalizer(JSRuntime *rt,
- JSRuntimeFinalizer *finalizer, void *arg);
- typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp);
- JS_EXTERN void JS_MarkValue(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- JS_EXTERN void JS_RunGC(JSRuntime *rt);
- JS_EXTERN bool JS_IsLiveObject(JSRuntime *rt, JSValueConst obj);
- JS_EXTERN JSContext *JS_NewContext(JSRuntime *rt);
- JS_EXTERN void JS_FreeContext(JSContext *s);
- JS_EXTERN JSContext *JS_DupContext(JSContext *ctx);
- JS_EXTERN void *JS_GetContextOpaque(JSContext *ctx);
- JS_EXTERN void JS_SetContextOpaque(JSContext *ctx, void *opaque);
- JS_EXTERN JSRuntime *JS_GetRuntime(JSContext *ctx);
- JS_EXTERN void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj);
- JS_EXTERN JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id);
- JS_EXTERN JSValue JS_GetFunctionProto(JSContext *ctx);
- /* the following functions are used to select the intrinsic object to
- save memory */
- JS_EXTERN JSContext *JS_NewContextRaw(JSRuntime *rt);
- JS_EXTERN void JS_AddIntrinsicBaseObjects(JSContext *ctx);
- JS_EXTERN void JS_AddIntrinsicDate(JSContext *ctx);
- JS_EXTERN void JS_AddIntrinsicEval(JSContext *ctx);
- JS_EXTERN void JS_AddIntrinsicRegExpCompiler(JSContext *ctx);
- JS_EXTERN void JS_AddIntrinsicRegExp(JSContext *ctx);
- JS_EXTERN void JS_AddIntrinsicJSON(JSContext *ctx);
- JS_EXTERN void JS_AddIntrinsicProxy(JSContext *ctx);
- JS_EXTERN void JS_AddIntrinsicMapSet(JSContext *ctx);
- JS_EXTERN void JS_AddIntrinsicTypedArrays(JSContext *ctx);
- JS_EXTERN void JS_AddIntrinsicPromise(JSContext *ctx);
- JS_EXTERN void JS_AddIntrinsicBigInt(JSContext *ctx);
- JS_EXTERN void JS_AddIntrinsicWeakRef(JSContext *ctx);
- JS_EXTERN void JS_AddPerformance(JSContext *ctx);
- JS_EXTERN void JS_AddIntrinsicDOMException(JSContext *ctx);
- /* for equality comparisons and sameness */
- JS_EXTERN int JS_IsEqual(JSContext *ctx, JSValueConst op1, JSValueConst op2);
- JS_EXTERN bool JS_IsStrictEqual(JSContext *ctx, JSValueConst op1, JSValueConst op2);
- JS_EXTERN bool JS_IsSameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2);
- /* Similar to same-value equality, but +0 and -0 are considered equal. */
- JS_EXTERN bool JS_IsSameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
- /* Only used for running 262 tests. TODO(saghul) add build time flag. */
- JS_EXTERN JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv);
- JS_EXTERN void *js_calloc_rt(JSRuntime *rt, size_t count, size_t size);
- JS_EXTERN void *js_malloc_rt(JSRuntime *rt, size_t size);
- JS_EXTERN void js_free_rt(JSRuntime *rt, void *ptr);
- JS_EXTERN void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size);
- JS_EXTERN size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr);
- JS_EXTERN void *js_mallocz_rt(JSRuntime *rt, size_t size);
- JS_EXTERN void *js_calloc(JSContext *ctx, size_t count, size_t size);
- JS_EXTERN void *js_malloc(JSContext *ctx, size_t size);
- JS_EXTERN void js_free(JSContext *ctx, void *ptr);
- JS_EXTERN void *js_realloc(JSContext *ctx, void *ptr, size_t size);
- JS_EXTERN size_t js_malloc_usable_size(JSContext *ctx, const void *ptr);
- JS_EXTERN void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack);
- JS_EXTERN void *js_mallocz(JSContext *ctx, size_t size);
- JS_EXTERN char *js_strdup(JSContext *ctx, const char *str);
- JS_EXTERN char *js_strndup(JSContext *ctx, const char *s, size_t n);
- typedef struct JSMemoryUsage {
- int64_t malloc_size, malloc_limit, memory_used_size;
- int64_t malloc_count;
- int64_t memory_used_count;
- int64_t atom_count, atom_size;
- int64_t str_count, str_size;
- int64_t obj_count, obj_size;
- int64_t prop_count, prop_size;
- int64_t shape_count, shape_size;
- int64_t js_func_count, js_func_size, js_func_code_size;
- int64_t js_func_pc2line_count, js_func_pc2line_size;
- int64_t c_func_count, array_count;
- int64_t fast_array_count, fast_array_elements;
- int64_t binary_object_count, binary_object_size;
- } JSMemoryUsage;
- JS_EXTERN void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s);
- JS_EXTERN void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt);
- /* atom support */
- #define JS_ATOM_NULL 0
- JS_EXTERN JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len);
- JS_EXTERN JSAtom JS_NewAtom(JSContext *ctx, const char *str);
- JS_EXTERN JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n);
- JS_EXTERN JSAtom JS_DupAtom(JSContext *ctx, JSAtom v);
- JS_EXTERN void JS_FreeAtom(JSContext *ctx, JSAtom v);
- JS_EXTERN void JS_FreeAtomRT(JSRuntime *rt, JSAtom v);
- JS_EXTERN JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom);
- JS_EXTERN JSValue JS_AtomToString(JSContext *ctx, JSAtom atom);
- JS_EXTERN const char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom);
- static inline const char *JS_AtomToCString(JSContext *ctx, JSAtom atom)
- {
- return JS_AtomToCStringLen(ctx, NULL, atom);
- }
- JS_EXTERN JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val);
- /* object class support */
- typedef struct JSPropertyEnum {
- bool is_enumerable;
- JSAtom atom;
- } JSPropertyEnum;
- typedef struct JSPropertyDescriptor {
- int flags;
- JSValue value;
- JSValue getter;
- JSValue setter;
- } JSPropertyDescriptor;
- typedef struct JSClassExoticMethods {
- /* Return -1 if exception (can only happen in case of Proxy object),
- false if the property does not exists, true if it exists. If 1 is
- returned, the property descriptor 'desc' is filled if != NULL. */
- int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc,
- JSValueConst obj, JSAtom prop);
- /* '*ptab' should hold the '*plen' property keys. Return 0 if OK,
- -1 if exception. The 'is_enumerable' field is ignored.
- */
- int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab,
- uint32_t *plen, JSValueConst obj);
- /* return < 0 if exception, or true/false */
- int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop);
- /* return < 0 if exception or true/false */
- int (*define_own_property)(JSContext *ctx, JSValueConst this_obj,
- JSAtom prop, JSValueConst val,
- JSValueConst getter, JSValueConst setter,
- int flags);
- /* The following methods can be emulated with the previous ones,
- so they are usually not needed */
- /* return < 0 if exception or true/false */
- int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom);
- JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom,
- JSValueConst receiver);
- /* return < 0 if exception or true/false */
- int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom,
- JSValueConst value, JSValueConst receiver, int flags);
- } JSClassExoticMethods;
- typedef void JSClassFinalizer(JSRuntime *rt, JSValueConst val);
- typedef void JSClassGCMark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- #define JS_CALL_FLAG_CONSTRUCTOR (1 << 0)
- typedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_val, int argc,
- JSValueConst *argv, int flags);
- typedef struct JSClassDef {
- const char *class_name; /* pure ASCII only! */
- JSClassFinalizer *finalizer;
- JSClassGCMark *gc_mark;
- /* if call != NULL, the object is a function. If (flags &
- JS_CALL_FLAG_CONSTRUCTOR) != 0, the function is called as a
- constructor. In this case, 'this_val' is new.target. A
- constructor call only happens if the object constructor bit is
- set (see JS_SetConstructorBit()). */
- JSClassCall *call;
- /* XXX: suppress this indirection ? It is here only to save memory
- because only a few classes need these methods */
- JSClassExoticMethods *exotic;
- } JSClassDef;
- #define JS_EVAL_OPTIONS_VERSION 1
- typedef struct JSEvalOptions {
- int version;
- int eval_flags;
- const char *filename;
- int line_num;
- // can add new fields in ABI-compatible manner by incrementing JS_EVAL_OPTIONS_VERSION
- } JSEvalOptions;
- #define JS_INVALID_CLASS_ID 0
- JS_EXTERN JSClassID JS_NewClassID(JSRuntime *rt, JSClassID *pclass_id);
- /* Returns the class ID if `v` is an object, otherwise returns JS_INVALID_CLASS_ID. */
- JS_EXTERN JSClassID JS_GetClassID(JSValueConst v);
- JS_EXTERN int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def);
- JS_EXTERN bool JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id);
- /* value handling */
- static js_force_inline JSValue JS_NewBool(JSContext *ctx, bool val)
- {
- (void)&ctx;
- return JS_MKVAL(JS_TAG_BOOL, (val != 0));
- }
- static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val)
- {
- (void)&ctx;
- return JS_MKVAL(JS_TAG_INT, val);
- }
- static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double val)
- {
- (void)&ctx;
- return __JS_NewFloat64(val);
- }
- static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val)
- {
- (void)&ctx;
- return JS_MKVAL(JS_TAG_CATCH_OFFSET, val);
- }
- static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val)
- {
- JSValue v;
- if (val >= INT32_MIN && val <= INT32_MAX) {
- v = JS_NewInt32(ctx, (int32_t)val);
- } else {
- v = JS_NewFloat64(ctx, (double)val);
- }
- return v;
- }
- static js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
- {
- JSValue v;
- if (val <= INT32_MAX) {
- v = JS_NewInt32(ctx, (int32_t)val);
- } else {
- v = JS_NewFloat64(ctx, (double)val);
- }
- return v;
- }
- JS_EXTERN JSValue JS_NewNumber(JSContext *ctx, double d);
- JS_EXTERN JSValue JS_NewBigInt64(JSContext *ctx, int64_t v);
- JS_EXTERN JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v);
- static inline bool JS_IsNumber(JSValueConst v)
- {
- int tag = JS_VALUE_GET_TAG(v);
- return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag);
- }
- static inline bool JS_IsBigInt(JSValueConst v)
- {
- int tag = JS_VALUE_GET_TAG(v);
- return tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT;
- }
- static inline bool JS_IsBool(JSValueConst v)
- {
- return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL;
- }
- static inline bool JS_IsNull(JSValueConst v)
- {
- return JS_VALUE_GET_TAG(v) == JS_TAG_NULL;
- }
- static inline bool JS_IsUndefined(JSValueConst v)
- {
- return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED;
- }
- static inline bool JS_IsException(JSValueConst v)
- {
- return JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION;
- }
- static inline bool JS_IsUninitialized(JSValueConst v)
- {
- return JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED;
- }
- static inline bool JS_IsString(JSValueConst v)
- {
- return JS_VALUE_GET_TAG(v) == JS_TAG_STRING;
- }
- static inline bool JS_IsSymbol(JSValueConst v)
- {
- return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL;
- }
- static inline bool JS_IsObject(JSValueConst v)
- {
- return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT;
- }
- static inline bool JS_IsModule(JSValueConst v)
- {
- return JS_VALUE_GET_TAG(v) == JS_TAG_MODULE;
- }
- JS_EXTERN JSValue JS_Throw(JSContext *ctx, JSValue obj);
- JS_EXTERN JSValue JS_GetException(JSContext *ctx);
- JS_EXTERN bool JS_HasException(JSContext *ctx);
- JS_EXTERN bool JS_IsError(JSValueConst val);
- JS_EXTERN bool JS_IsUncatchableError(JSValueConst val);
- JS_EXTERN void JS_SetUncatchableError(JSContext *ctx, JSValueConst val);
- JS_EXTERN void JS_ClearUncatchableError(JSContext *ctx, JSValueConst val);
- // Shorthand for:
- // JSValue exc = JS_GetException(ctx);
- // JS_ClearUncatchableError(ctx, exc);
- // JS_Throw(ctx, exc);
- JS_EXTERN void JS_ResetUncatchableError(JSContext *ctx);
- JS_EXTERN JSValue JS_NewError(JSContext *ctx);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_NewInternalError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_NewPlainError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_NewRangeError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_NewReferenceError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_NewSyntaxError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_NewTypeError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowInternalError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowPlainError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowRangeError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowReferenceError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowSyntaxError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowTypeError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_PRINTF_FORMAT_ATTR(3, 4) JS_ThrowDOMException(JSContext *ctx, const char *name, JS_PRINTF_FORMAT const char *fmt, ...);
- JS_EXTERN JSValue JS_ThrowOutOfMemory(JSContext *ctx);
- JS_EXTERN void JS_FreeValue(JSContext *ctx, JSValue v);
- JS_EXTERN void JS_FreeValueRT(JSRuntime *rt, JSValue v);
- JS_EXTERN JSValue JS_DupValue(JSContext *ctx, JSValueConst v);
- JS_EXTERN JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v);
- JS_EXTERN int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */
- static inline JSValue JS_ToBoolean(JSContext *ctx, JSValueConst val)
- {
- return JS_NewBool(ctx, JS_ToBool(ctx, val));
- }
- JS_EXTERN JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);
- JS_EXTERN int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val);
- static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)
- {
- return JS_ToInt32(ctx, (int32_t*)pres, val);
- }
- JS_EXTERN int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val);
- JS_EXTERN int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val);
- JS_EXTERN int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val);
- /* return an exception if 'val' is a Number */
- JS_EXTERN int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val);
- JS_EXTERN int JS_ToBigUint64(JSContext *ctx, uint64_t *pres, JSValueConst val);
- /* same as JS_ToInt64() but allow BigInt */
- JS_EXTERN int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val);
- JS_EXTERN JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1);
- static inline JSValue JS_NewString(JSContext *ctx, const char *str) {
- return JS_NewStringLen(ctx, str, strlen(str));
- }
- // makes a copy of the input; does not check if the input is valid UTF-16,
- // that is the responsibility of the caller
- JS_EXTERN JSValue JS_NewTwoByteString(JSContext *ctx, const uint16_t *buf,
- size_t len);
- JS_EXTERN JSValue JS_NewAtomString(JSContext *ctx, const char *str);
- JS_EXTERN JSValue JS_ToString(JSContext *ctx, JSValueConst val);
- JS_EXTERN JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val);
- JS_EXTERN const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, bool cesu8);
- static inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValueConst val1)
- {
- return JS_ToCStringLen2(ctx, plen, val1, 0);
- }
- static inline const char *JS_ToCString(JSContext *ctx, JSValueConst val1)
- {
- return JS_ToCStringLen2(ctx, NULL, val1, 0);
- }
- JS_EXTERN void JS_FreeCString(JSContext *ctx, const char *ptr);
- JS_EXTERN JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto,
- JSClassID class_id);
- JS_EXTERN JSValue JS_NewObjectClass(JSContext *ctx, JSClassID class_id);
- JS_EXTERN JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto);
- JS_EXTERN JSValue JS_NewObject(JSContext *ctx);
- // takes ownership of the values
- JS_EXTERN JSValue JS_NewObjectFrom(JSContext *ctx, int count,
- const JSAtom *props,
- const JSValue *values);
- // takes ownership of the values
- JS_EXTERN JSValue JS_NewObjectFromStr(JSContext *ctx, int count,
- const char **props,
- const JSValue *values);
- JS_EXTERN JSValue JS_ToObject(JSContext *ctx, JSValueConst val);
- JS_EXTERN JSValue JS_ToObjectString(JSContext *ctx, JSValueConst val);
- JS_EXTERN bool JS_IsFunction(JSContext* ctx, JSValueConst val);
- JS_EXTERN bool JS_IsConstructor(JSContext* ctx, JSValueConst val);
- JS_EXTERN bool JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, bool val);
- JS_EXTERN bool JS_IsRegExp(JSValueConst val);
- JS_EXTERN bool JS_IsMap(JSValueConst val);
- JS_EXTERN bool JS_IsSet(JSValueConst val);
- JS_EXTERN bool JS_IsWeakRef(JSValueConst val);
- JS_EXTERN bool JS_IsWeakSet(JSValueConst val);
- JS_EXTERN bool JS_IsWeakMap(JSValueConst val);
- JS_EXTERN bool JS_IsDataView(JSValueConst val);
- JS_EXTERN JSValue JS_NewArray(JSContext *ctx);
- // takes ownership of the values
- JS_EXTERN JSValue JS_NewArrayFrom(JSContext *ctx, int count,
- const JSValue *values);
- // reader beware: JS_IsArray used to "punch" through proxies and check
- // if the target object is an array but it no longer does; use JS_IsProxy
- // and JS_GetProxyTarget instead, and remember that the target itself can
- // also be a proxy, ad infinitum
- JS_EXTERN bool JS_IsArray(JSValueConst val);
- JS_EXTERN bool JS_IsProxy(JSValueConst val);
- JS_EXTERN JSValue JS_GetProxyTarget(JSContext *ctx, JSValueConst proxy);
- JS_EXTERN JSValue JS_GetProxyHandler(JSContext *ctx, JSValueConst proxy);
- JS_EXTERN JSValue JS_NewDate(JSContext *ctx, double epoch_ms);
- JS_EXTERN bool JS_IsDate(JSValueConst v);
- JS_EXTERN JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop);
- JS_EXTERN JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
- uint32_t idx);
- JS_EXTERN JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst this_obj,
- int64_t idx);
- JS_EXTERN JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
- const char *prop);
- JS_EXTERN int JS_SetProperty(JSContext *ctx, JSValueConst this_obj,
- JSAtom prop, JSValue val);
- JS_EXTERN int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
- uint32_t idx, JSValue val);
- JS_EXTERN int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj,
- int64_t idx, JSValue val);
- JS_EXTERN int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
- const char *prop, JSValue val);
- JS_EXTERN int JS_HasProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop);
- JS_EXTERN int JS_IsExtensible(JSContext *ctx, JSValueConst obj);
- JS_EXTERN int JS_PreventExtensions(JSContext *ctx, JSValueConst obj);
- JS_EXTERN int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags);
- JS_EXTERN int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val);
- JS_EXTERN JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val);
- JS_EXTERN int JS_GetLength(JSContext *ctx, JSValueConst obj, int64_t *pres);
- JS_EXTERN int JS_SetLength(JSContext *ctx, JSValueConst obj, int64_t len);
- JS_EXTERN int JS_SealObject(JSContext *ctx, JSValueConst obj);
- JS_EXTERN int JS_FreezeObject(JSContext *ctx, JSValueConst obj);
- #define JS_GPN_STRING_MASK (1 << 0)
- #define JS_GPN_SYMBOL_MASK (1 << 1)
- #define JS_GPN_PRIVATE_MASK (1 << 2)
- /* only include the enumerable properties */
- #define JS_GPN_ENUM_ONLY (1 << 4)
- /* set theJSPropertyEnum.is_enumerable field */
- #define JS_GPN_SET_ENUM (1 << 5)
- JS_EXTERN int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
- uint32_t *plen, JSValueConst obj,
- int flags);
- JS_EXTERN int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
- JSValueConst obj, JSAtom prop);
- JS_EXTERN void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab,
- uint32_t len);
- JS_EXTERN JSValue JS_Call(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_obj, int argc, JSValueConst *argv);
- JS_EXTERN JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,
- int argc, JSValueConst *argv);
- JS_EXTERN JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,
- int argc, JSValueConst *argv);
- JS_EXTERN JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
- JSValueConst new_target,
- int argc, JSValueConst *argv);
- /* Try to detect if the input is a module. Returns true if parsing the input
- * as a module produces no syntax errors. It's a naive approach that is not
- * wholly infallible: non-strict classic scripts may _parse_ okay as a module
- * but not _execute_ as one (different runtime semantics.) Use with caution.
- * |input| can be either ASCII or UTF-8 encoded source code.
- * Returns false if QuickJS was built with -DQJS_DISABLE_PARSER.
- */
- JS_EXTERN bool JS_DetectModule(const char *input, size_t input_len);
- /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
- JS_EXTERN JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
- const char *filename, int eval_flags);
- JS_EXTERN JSValue JS_Eval2(JSContext *ctx, const char *input, size_t input_len,
- JSEvalOptions *options);
- JS_EXTERN JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
- const char *filename, int eval_flags);
- JS_EXTERN JSValue JS_EvalThis2(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
- JSEvalOptions *options);
- JS_EXTERN JSValue JS_GetGlobalObject(JSContext *ctx);
- JS_EXTERN int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj);
- JS_EXTERN int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
- JSAtom prop, JSValueConst val,
- JSValueConst getter, JSValueConst setter,
- int flags);
- JS_EXTERN int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj,
- JSAtom prop, JSValue val, int flags);
- JS_EXTERN int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj,
- uint32_t idx, JSValue val, int flags);
- JS_EXTERN int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
- const char *prop, JSValue val, int flags);
- JS_EXTERN int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
- JSAtom prop, JSValue getter, JSValue setter,
- int flags);
- /* Only supported for custom classes, returns 0 on success < 0 otherwise. */
- JS_EXTERN int JS_SetOpaque(JSValueConst obj, void *opaque);
- JS_EXTERN void *JS_GetOpaque(JSValueConst obj, JSClassID class_id);
- JS_EXTERN void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id);
- JS_EXTERN void *JS_GetAnyOpaque(JSValueConst obj, JSClassID *class_id);
- /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
- JS_EXTERN JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
- const char *filename);
- JS_EXTERN JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
- JSValueConst replacer, JSValueConst space0);
- typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr);
- JS_EXTERN JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
- JSFreeArrayBufferDataFunc *free_func, void *opaque,
- bool is_shared);
- JS_EXTERN JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len);
- JS_EXTERN void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj);
- JS_EXTERN uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj);
- JS_EXTERN bool JS_IsArrayBuffer(JSValueConst obj);
- JS_EXTERN uint8_t *JS_GetUint8Array(JSContext *ctx, size_t *psize, JSValueConst obj);
- typedef enum JSTypedArrayEnum {
- JS_TYPED_ARRAY_UINT8C = 0,
- JS_TYPED_ARRAY_INT8,
- JS_TYPED_ARRAY_UINT8,
- JS_TYPED_ARRAY_INT16,
- JS_TYPED_ARRAY_UINT16,
- JS_TYPED_ARRAY_INT32,
- JS_TYPED_ARRAY_UINT32,
- JS_TYPED_ARRAY_BIG_INT64,
- JS_TYPED_ARRAY_BIG_UINT64,
- JS_TYPED_ARRAY_FLOAT16,
- JS_TYPED_ARRAY_FLOAT32,
- JS_TYPED_ARRAY_FLOAT64,
- } JSTypedArrayEnum;
- JS_EXTERN JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,
- JSTypedArrayEnum array_type);
- JS_EXTERN JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
- size_t *pbyte_offset,
- size_t *pbyte_length,
- size_t *pbytes_per_element);
- JS_EXTERN JSValue JS_NewUint8Array(JSContext *ctx, uint8_t *buf, size_t len,
- JSFreeArrayBufferDataFunc *free_func, void *opaque,
- bool is_shared);
- /* returns -1 if not a typed array otherwise return a JSTypedArrayEnum value */
- JS_EXTERN int JS_GetTypedArrayType(JSValueConst obj);
- JS_EXTERN JSValue JS_NewUint8ArrayCopy(JSContext *ctx, const uint8_t *buf, size_t len);
- typedef struct {
- void *(*sab_alloc)(void *opaque, size_t size);
- void (*sab_free)(void *opaque, void *ptr);
- void (*sab_dup)(void *opaque, void *ptr);
- void *sab_opaque;
- } JSSharedArrayBufferFunctions;
- JS_EXTERN void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, const JSSharedArrayBufferFunctions *sf);
- typedef enum JSPromiseStateEnum {
- JS_PROMISE_PENDING,
- JS_PROMISE_FULFILLED,
- JS_PROMISE_REJECTED,
- } JSPromiseStateEnum;
- JS_EXTERN JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
- JS_EXTERN JSPromiseStateEnum JS_PromiseState(JSContext *ctx,
- JSValueConst promise);
- JS_EXTERN JSValue JS_PromiseResult(JSContext *ctx, JSValueConst promise);
- JS_EXTERN bool JS_IsPromise(JSValueConst val);
- JS_EXTERN JSValue JS_NewSymbol(JSContext *ctx, const char *description, bool is_global);
- typedef enum JSPromiseHookType {
- JS_PROMISE_HOOK_INIT, // emitted when a new promise is created
- JS_PROMISE_HOOK_BEFORE, // runs right before promise.then is invoked
- JS_PROMISE_HOOK_AFTER, // runs right after promise.then is invoked
- JS_PROMISE_HOOK_RESOLVE, // not emitted for rejected promises
- } JSPromiseHookType;
- // parent_promise is only passed in when type == JS_PROMISE_HOOK_INIT and
- // is then either a promise object or JS_UNDEFINED if the new promise does
- // not have a parent promise; only promises created with promise.then have
- // a parent promise
- typedef void JSPromiseHook(JSContext *ctx, JSPromiseHookType type,
- JSValueConst promise, JSValueConst parent_promise,
- void *opaque);
- JS_EXTERN void JS_SetPromiseHook(JSRuntime *rt, JSPromiseHook promise_hook,
- void *opaque);
- /* is_handled = true means that the rejection is handled */
- typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise,
- JSValueConst reason,
- bool is_handled, void *opaque);
- JS_EXTERN void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque);
- /* return != 0 if the JS code needs to be interrupted */
- typedef int JSInterruptHandler(JSRuntime *rt, void *opaque);
- JS_EXTERN void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque);
- /* if can_block is true, Atomics.wait() can be used */
- JS_EXTERN void JS_SetCanBlock(JSRuntime *rt, bool can_block);
- /* set the [IsHTMLDDA] internal slot */
- JS_EXTERN void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj);
- typedef struct JSModuleDef JSModuleDef;
- /* return the module specifier (allocated with js_malloc()) or NULL if
- exception */
- typedef char *JSModuleNormalizeFunc(JSContext *ctx,
- const char *module_base_name,
- const char *module_name, void *opaque);
- typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx,
- const char *module_name, void *opaque);
- /* module_normalize = NULL is allowed and invokes the default module
- filename normalizer */
- JS_EXTERN void JS_SetModuleLoaderFunc(JSRuntime *rt,
- JSModuleNormalizeFunc *module_normalize,
- JSModuleLoaderFunc *module_loader, void *opaque);
- /* return the import.meta object of a module */
- JS_EXTERN JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m);
- JS_EXTERN JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m);
- JS_EXTERN JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m);
- /* JS Job support */
- typedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValueConst *argv);
- JS_EXTERN int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func,
- int argc, JSValueConst *argv);
- JS_EXTERN bool JS_IsJobPending(JSRuntime *rt);
- JS_EXTERN int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx);
- /* Structure to retrieve (de)serialized SharedArrayBuffer objects. */
- typedef struct JSSABTab {
- uint8_t **tab;
- size_t len;
- } JSSABTab;
- /* Object Writer/Reader (currently only used to handle precompiled code) */
- #define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
- #define JS_WRITE_OBJ_BSWAP (0) /* byte swapped output (obsolete, handled transparently) */
- #define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
- #define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to encode arbitrary object graph */
- #define JS_WRITE_OBJ_STRIP_SOURCE (1 << 4) /* do not write source code information */
- #define JS_WRITE_OBJ_STRIP_DEBUG (1 << 5) /* do not write debug information */
- JS_EXTERN uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, int flags);
- JS_EXTERN uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
- int flags, JSSABTab *psab_tab);
- #define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */
- #define JS_READ_OBJ_ROM_DATA (0) /* avoid duplicating 'buf' data (obsolete, broken by ICs) */
- #define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
- #define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */
- JS_EXTERN JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, int flags);
- JS_EXTERN JSValue JS_ReadObject2(JSContext *ctx, const uint8_t *buf, size_t buf_len,
- int flags, JSSABTab *psab_tab);
- /* instantiate and evaluate a bytecode function. Only used when
- reading a script or module with JS_ReadObject() */
- JS_EXTERN JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj);
- /* load the dependencies of the module 'obj'. Useful when JS_ReadObject()
- returns a module. */
- JS_EXTERN int JS_ResolveModule(JSContext *ctx, JSValueConst obj);
- /* only exported for os.Worker() */
- JS_EXTERN JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);
- /* only exported for os.Worker() */
- JS_EXTERN JSValue JS_LoadModule(JSContext *ctx, const char *basename,
- const char *filename);
- /* C function definition */
- typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
- JS_CFUNC_generic,
- JS_CFUNC_generic_magic,
- JS_CFUNC_constructor,
- JS_CFUNC_constructor_magic,
- JS_CFUNC_constructor_or_func,
- JS_CFUNC_constructor_or_func_magic,
- JS_CFUNC_f_f,
- JS_CFUNC_f_f_f,
- JS_CFUNC_getter,
- JS_CFUNC_setter,
- JS_CFUNC_getter_magic,
- JS_CFUNC_setter_magic,
- JS_CFUNC_iterator_next,
- } JSCFunctionEnum;
- typedef union JSCFunctionType {
- JSCFunction *generic;
- JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);
- JSCFunction *constructor;
- JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic);
- JSCFunction *constructor_or_func;
- double (*f_f)(double);
- double (*f_f_f)(double, double);
- JSValue (*getter)(JSContext *ctx, JSValueConst this_val);
- JSValue (*setter)(JSContext *ctx, JSValueConst this_val, JSValueConst val);
- JSValue (*getter_magic)(JSContext *ctx, JSValueConst this_val, int magic);
- JSValue (*setter_magic)(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic);
- JSValue (*iterator_next)(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int *pdone, int magic);
- } JSCFunctionType;
- JS_EXTERN JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
- const char *name,
- int length, JSCFunctionEnum cproto, int magic);
- JS_EXTERN JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
- const char *name,
- int length, JSCFunctionEnum cproto, int magic,
- JSValueConst proto_val);
- JS_EXTERN JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
- int length, int magic, int data_len,
- JSValueConst *data);
- JS_EXTERN JSValue JS_NewCFunctionData2(JSContext *ctx, JSCFunctionData *func,
- const char *name,
- int length, int magic, int data_len,
- JSValueConst *data);
- static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func,
- const char *name, int length)
- {
- return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0);
- }
- static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func,
- const char *name, int length,
- JSCFunctionEnum cproto, int magic)
- {
- /* Used to squelch a -Wcast-function-type warning. */
- JSCFunctionType ft;
- ft.generic_magic = func;
- return JS_NewCFunction2(ctx, ft.generic, name, length, cproto, magic);
- }
- JS_EXTERN void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
- JSValueConst proto);
- /* C property definition */
- typedef struct JSCFunctionListEntry {
- const char *name; /* pure ASCII or UTF-8 encoded */
- uint8_t prop_flags;
- uint8_t def_type;
- int16_t magic;
- union {
- struct {
- uint8_t length; /* XXX: should move outside union */
- uint8_t cproto; /* XXX: should move outside union */
- JSCFunctionType cfunc;
- } func;
- struct {
- JSCFunctionType get;
- JSCFunctionType set;
- } getset;
- struct {
- const char *name;
- int base;
- } alias;
- struct {
- const struct JSCFunctionListEntry *tab;
- int len;
- } prop_list;
- const char *str; /* pure ASCII or UTF-8 encoded */
- int32_t i32;
- int64_t i64;
- uint64_t u64;
- double f64;
- } u;
- } JSCFunctionListEntry;
- #define JS_DEF_CFUNC 0
- #define JS_DEF_CGETSET 1
- #define JS_DEF_CGETSET_MAGIC 2
- #define JS_DEF_PROP_STRING 3
- #define JS_DEF_PROP_INT32 4
- #define JS_DEF_PROP_INT64 5
- #define JS_DEF_PROP_DOUBLE 6
- #define JS_DEF_PROP_UNDEFINED 7
- #define JS_DEF_OBJECT 8
- #define JS_DEF_ALIAS 9
- /* Note: c++ does not like nested designators */
- #define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
- #define JS_CFUNC_DEF2(name, length, func1, prop_flags) { name, prop_flags, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
- #define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } }
- #define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } }
- #define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } }
- #define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } }
- #define JS_CGETSET_DEF2(name, fgetter, fsetter, prop_flags) { name, prop_flags, JS_DEF_CGETSET, 0, { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } }
- #define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } }
- #define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, { .str = cstr } }
- #define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, { .i32 = val } }
- #define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, { .i64 = val } }
- #define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, { .f64 = val } }
- #define JS_PROP_U2D_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, { .u64 = val } }
- #define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, { .i32 = 0 } }
- #define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, { .prop_list = { tab, len } } }
- #define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, { .alias = { from, -1 } } }
- #define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, { .alias = { from, base } } }
- JS_EXTERN int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
- const JSCFunctionListEntry *tab,
- int len);
- /* C module definition */
- typedef int JSModuleInitFunc(JSContext *ctx, JSModuleDef *m);
- JS_EXTERN JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
- JSModuleInitFunc *func);
- /* can only be called before the module is instantiated */
- JS_EXTERN int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *name_str);
- JS_EXTERN int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
- const JSCFunctionListEntry *tab, int len);
- /* can only be called after the module is instantiated */
- JS_EXTERN int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
- JSValue val);
- JS_EXTERN int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
- const JSCFunctionListEntry *tab, int len);
- /* Version */
- #define QJS_VERSION_MAJOR 0
- #define QJS_VERSION_MINOR 11
- #define QJS_VERSION_PATCH 0
- #define QJS_VERSION_SUFFIX ""
- JS_EXTERN const char* JS_GetVersion(void);
- /* Integration point for quickjs-libc.c, not for public use. */
- JS_EXTERN uintptr_t js_std_cmd(int cmd, ...);
- #undef JS_EXTERN
- #undef js_force_inline
- #ifdef __cplusplus
- } /* extern "C" { */
- #endif
- #endif /* QUICKJS_H */
- /*
- * QuickJS Javascript Engine
- *
- * Copyright (c) 2017-2025 Fabrice Bellard
- * Copyright (c) 2017-2025 Charlie Gordon
- * Copyright (c) 2023-2025 Ben Noordhuis
- * Copyright (c) 2023-2025 Saúl Ibarra Corretgé
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <inttypes.h>
- #include <string.h>
- #include <assert.h>
- #if !defined(_MSC_VER)
- #include <sys/time.h>
- #if defined(_WIN32)
- #include <timezoneapi.h>
- #endif
- #endif
- #if defined(_WIN32)
- #include <intrin.h>
- #endif
- #include <time.h>
- #include <fenv.h>
- #include <math.h>
- #if defined(EMSCRIPTEN) || defined(_MSC_VER)
- #define DIRECT_DISPATCH 0
- #else
- #define DIRECT_DISPATCH 1
- #endif
- #if defined(__APPLE__)
- #define MALLOC_OVERHEAD 0
- #else
- #define MALLOC_OVERHEAD 8
- #endif
- #if defined(__NEWLIB__)
- #define NO_TM_GMTOFF
- #endif
- // atomic_store etc. are completely busted in recent versions of tcc;
- // somehow the compiler forgets to load |ptr| into %rdi when calling
- // the __atomic_*() helpers in its lib/stdatomic.c and lib/atomic.S
- #if !defined(__TINYC__) && !defined(EMSCRIPTEN) && !defined(__wasi__) && !__STDC_NO_ATOMICS__
- #define CONFIG_ATOMICS
- #endif
- #ifndef __GNUC__
- #define __extension__
- #endif
- #ifndef NDEBUG
- #define ENABLE_DUMPS
- #endif
- //#define FORCE_GC_AT_MALLOC /* test the GC by forcing it before each object allocation */
- #define check_dump_flag(rt, flag) ((rt->dump_flags & (flag +0)) == (flag +0))
- #define STRINGIFY_(x) #x
- #define STRINGIFY(x) STRINGIFY_(x)
- #define QJS_VERSION_STRING \
- STRINGIFY(QJS_VERSION_MAJOR) "." STRINGIFY(QJS_VERSION_MINOR) "." STRINGIFY(QJS_VERSION_PATCH) QJS_VERSION_SUFFIX
- const char* JS_GetVersion(void) {
- return QJS_VERSION_STRING;
- }
- #undef STRINFIGY_
- #undef STRINGIFY
- static inline JSValueConst *vc(JSValue *vals)
- {
- return (JSValueConst *)vals;
- }
- static inline JSValue unsafe_unconst(JSValueConst v)
- {
- #ifdef JS_CHECK_JSVALUE
- return (JSValue)v;
- #else
- return v;
- #endif
- }
- static inline JSValueConst safe_const(JSValue v)
- {
- #ifdef JS_CHECK_JSVALUE
- return (JSValueConst)v;
- #else
- return v;
- #endif
- }
- enum {
- /* classid tag */ /* union usage | properties */
- JS_CLASS_OBJECT = 1, /* must be first */
- JS_CLASS_ARRAY, /* u.array | length */
- JS_CLASS_ERROR,
- JS_CLASS_NUMBER, /* u.object_data */
- JS_CLASS_STRING, /* u.object_data */
- JS_CLASS_BOOLEAN, /* u.object_data */
- JS_CLASS_SYMBOL, /* u.object_data */
- JS_CLASS_ARGUMENTS, /* u.array | length */
- JS_CLASS_MAPPED_ARGUMENTS, /* | length */
- JS_CLASS_DATE, /* u.object_data */
- JS_CLASS_MODULE_NS,
- JS_CLASS_C_FUNCTION, /* u.cfunc */
- JS_CLASS_BYTECODE_FUNCTION, /* u.func */
- JS_CLASS_BOUND_FUNCTION, /* u.bound_function */
- JS_CLASS_C_FUNCTION_DATA, /* u.c_function_data_record */
- JS_CLASS_GENERATOR_FUNCTION, /* u.func */
- JS_CLASS_FOR_IN_ITERATOR, /* u.for_in_iterator */
- JS_CLASS_REGEXP, /* u.regexp */
- JS_CLASS_ARRAY_BUFFER, /* u.array_buffer */
- JS_CLASS_SHARED_ARRAY_BUFFER, /* u.array_buffer */
- JS_CLASS_UINT8C_ARRAY, /* u.array (typed_array) */
- JS_CLASS_INT8_ARRAY, /* u.array (typed_array) */
- JS_CLASS_UINT8_ARRAY, /* u.array (typed_array) */
- JS_CLASS_INT16_ARRAY, /* u.array (typed_array) */
- JS_CLASS_UINT16_ARRAY, /* u.array (typed_array) */
- JS_CLASS_INT32_ARRAY, /* u.array (typed_array) */
- JS_CLASS_UINT32_ARRAY, /* u.array (typed_array) */
- JS_CLASS_BIG_INT64_ARRAY, /* u.array (typed_array) */
- JS_CLASS_BIG_UINT64_ARRAY, /* u.array (typed_array) */
- JS_CLASS_FLOAT16_ARRAY, /* u.array (typed_array) */
- JS_CLASS_FLOAT32_ARRAY, /* u.array (typed_array) */
- JS_CLASS_FLOAT64_ARRAY, /* u.array (typed_array) */
- JS_CLASS_DATAVIEW, /* u.typed_array */
- JS_CLASS_BIG_INT, /* u.object_data */
- JS_CLASS_MAP, /* u.map_state */
- JS_CLASS_SET, /* u.map_state */
- JS_CLASS_WEAKMAP, /* u.map_state */
- JS_CLASS_WEAKSET, /* u.map_state */
- JS_CLASS_ITERATOR,
- JS_CLASS_ITERATOR_CONCAT, /* u.iterator_concat_data */
- JS_CLASS_ITERATOR_HELPER, /* u.iterator_helper_data */
- JS_CLASS_ITERATOR_WRAP, /* u.iterator_wrap_data */
- JS_CLASS_MAP_ITERATOR, /* u.map_iterator_data */
- JS_CLASS_SET_ITERATOR, /* u.map_iterator_data */
- JS_CLASS_ARRAY_ITERATOR, /* u.array_iterator_data */
- JS_CLASS_STRING_ITERATOR, /* u.array_iterator_data */
- JS_CLASS_REGEXP_STRING_ITERATOR, /* u.regexp_string_iterator_data */
- JS_CLASS_GENERATOR, /* u.generator_data */
- JS_CLASS_PROXY, /* u.proxy_data */
- JS_CLASS_PROMISE, /* u.promise_data */
- JS_CLASS_PROMISE_RESOLVE_FUNCTION, /* u.promise_function_data */
- JS_CLASS_PROMISE_REJECT_FUNCTION, /* u.promise_function_data */
- JS_CLASS_ASYNC_FUNCTION, /* u.func */
- JS_CLASS_ASYNC_FUNCTION_RESOLVE, /* u.async_function_data */
- JS_CLASS_ASYNC_FUNCTION_REJECT, /* u.async_function_data */
- JS_CLASS_ASYNC_FROM_SYNC_ITERATOR, /* u.async_from_sync_iterator_data */
- JS_CLASS_ASYNC_GENERATOR_FUNCTION, /* u.func */
- JS_CLASS_ASYNC_GENERATOR, /* u.async_generator_data */
- JS_CLASS_WEAK_REF,
- JS_CLASS_FINALIZATION_REGISTRY,
- JS_CLASS_DOM_EXCEPTION,
- JS_CLASS_CALL_SITE,
- JS_CLASS_INIT_COUNT, /* last entry for predefined classes */
- };
- /* number of typed array types */
- #define JS_TYPED_ARRAY_COUNT (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1)
- static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT];
- #define typed_array_size_log2(classid) (typed_array_size_log2[(classid)- JS_CLASS_UINT8C_ARRAY])
- typedef enum JSErrorEnum {
- JS_EVAL_ERROR,
- JS_RANGE_ERROR,
- JS_REFERENCE_ERROR,
- JS_SYNTAX_ERROR,
- JS_TYPE_ERROR,
- JS_URI_ERROR,
- JS_INTERNAL_ERROR,
- JS_AGGREGATE_ERROR,
- JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */
- JS_PLAIN_ERROR = JS_NATIVE_ERROR_COUNT
- } JSErrorEnum;
- #define JS_MAX_LOCAL_VARS 65535
- #define JS_STACK_SIZE_MAX 65534
- #define JS_STRING_LEN_MAX ((1 << 30) - 1)
- // 1,024 bytes is about the cutoff point where it starts getting
- // more profitable to ref slice than to copy
- #define JS_STRING_SLICE_LEN_MAX 1024 // in bytes
- #define __exception __attribute__((warn_unused_result))
- typedef struct JSShape JSShape;
- typedef struct JSString JSString;
- typedef struct JSString JSAtomStruct;
- #define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v))
- typedef enum {
- JS_GC_PHASE_NONE,
- JS_GC_PHASE_DECREF,
- JS_GC_PHASE_REMOVE_CYCLES,
- } JSGCPhaseEnum;
- typedef struct JSMallocState {
- size_t malloc_count;
- size_t malloc_size;
- size_t malloc_limit;
- void *opaque; /* user opaque */
- } JSMallocState;
- typedef struct JSRuntimeFinalizerState {
- struct JSRuntimeFinalizerState *next;
- JSRuntimeFinalizer *finalizer;
- void *arg;
- } JSRuntimeFinalizerState;
- typedef struct JSValueLink {
- struct JSValueLink *next;
- JSValueConst value;
- } JSValueLink;
- struct JSRuntime {
- JSMallocFunctions mf;
- JSMallocState malloc_state;
- const char *rt_info;
- int atom_hash_size; /* power of two */
- int atom_count;
- int atom_size;
- int atom_count_resize; /* resize hash table at this count */
- uint32_t *atom_hash;
- JSAtomStruct **atom_array;
- int atom_free_index; /* 0 = none */
- JSClassID js_class_id_alloc; /* counter for user defined classes */
- int class_count; /* size of class_array */
- JSClass *class_array;
- struct list_head context_list; /* list of JSContext.link */
- /* list of JSGCObjectHeader.link. List of allocated GC objects (used
- by the garbage collector) */
- struct list_head gc_obj_list;
- /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */
- struct list_head gc_zero_ref_count_list;
- struct list_head tmp_obj_list; /* used during GC */
- JSGCPhaseEnum gc_phase : 8;
- size_t malloc_gc_threshold;
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- struct list_head string_list; /* list of JSString.link */
- #endif
- /* stack limitation */
- uintptr_t stack_size; /* in bytes, 0 if no limit */
- uintptr_t stack_top;
- uintptr_t stack_limit; /* lower stack limit */
- JSValue current_exception;
- /* true if inside an out of memory error, to avoid recursing */
- bool in_out_of_memory;
- /* true if inside build_backtrace, to avoid recursing */
- bool in_build_stack_trace;
- /* true if inside JS_FreeRuntime */
- bool in_free;
- struct JSStackFrame *current_stack_frame;
- JSInterruptHandler *interrupt_handler;
- void *interrupt_opaque;
- JSPromiseHook *promise_hook;
- void *promise_hook_opaque;
- // for smuggling the parent promise from js_promise_then
- // to js_promise_constructor
- JSValueLink *parent_promise;
- JSHostPromiseRejectionTracker *host_promise_rejection_tracker;
- void *host_promise_rejection_tracker_opaque;
- struct list_head job_list; /* list of JSJobEntry.link */
- JSModuleNormalizeFunc *module_normalize_func;
- JSModuleLoaderFunc *module_loader_func;
- void *module_loader_opaque;
- /* timestamp for internal use in module evaluation */
- int64_t module_async_evaluation_next_timestamp;
- /* used to allocate, free and clone SharedArrayBuffers */
- JSSharedArrayBufferFunctions sab_funcs;
- bool can_block; /* true if Atomics.wait can block */
- uint32_t dump_flags : 24;
- /* Shape hash table */
- int shape_hash_bits;
- int shape_hash_size;
- int shape_hash_count; /* number of hashed shapes */
- JSShape **shape_hash;
- void *user_opaque;
- void *libc_opaque;
- JSRuntimeFinalizerState *finalizers;
- };
- struct JSClass {
- uint32_t class_id; /* 0 means free entry */
- JSAtom class_name;
- JSClassFinalizer *finalizer;
- JSClassGCMark *gc_mark;
- JSClassCall *call;
- /* pointers for exotic behavior, can be NULL if none are present */
- const JSClassExoticMethods *exotic;
- };
- typedef struct JSStackFrame {
- struct JSStackFrame *prev_frame; /* NULL if first stack frame */
- JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
- JSValue *arg_buf; /* arguments */
- JSValue *var_buf; /* variables */
- struct list_head var_ref_list; /* list of JSVarRef.link */
- uint8_t *cur_pc; /* only used in bytecode functions : PC of the
- instruction after the call */
- uint32_t arg_count : 31;
- uint32_t is_strict_mode : 1;
- /* only used in generators. Current stack pointer value. NULL if
- the function is running. */
- JSValue *cur_sp;
- } JSStackFrame;
- typedef enum {
- JS_GC_OBJ_TYPE_JS_OBJECT,
- JS_GC_OBJ_TYPE_FUNCTION_BYTECODE,
- JS_GC_OBJ_TYPE_SHAPE,
- JS_GC_OBJ_TYPE_VAR_REF,
- JS_GC_OBJ_TYPE_ASYNC_FUNCTION,
- JS_GC_OBJ_TYPE_JS_CONTEXT,
- } JSGCObjectTypeEnum;
- /* header for GC objects. GC objects are C data structures with a
- reference count that can reference other GC objects. JS Objects are
- a particular type of GC object. */
- struct JSGCObjectHeader {
- int ref_count; /* must come first, 32-bit */
- JSGCObjectTypeEnum gc_obj_type : 4;
- uint8_t mark : 4; /* used by the GC */
- uint8_t dummy1; /* not used by the GC */
- uint16_t dummy2; /* not used by the GC */
- struct list_head link;
- };
- typedef struct JSVarRef {
- union {
- JSGCObjectHeader header; /* must come first */
- struct {
- int __gc_ref_count; /* corresponds to header.ref_count */
- uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
- uint8_t is_detached;
- };
- };
- JSValue *pvalue; /* pointer to the value, either on the stack or
- to 'value' */
- JSValue value; /* used when the variable is no longer on the stack */
- } JSVarRef;
- typedef struct JSRefCountHeader {
- int ref_count;
- } JSRefCountHeader;
- /* bigint */
- typedef int32_t js_slimb_t;
- typedef uint32_t js_limb_t;
- typedef int64_t js_sdlimb_t;
- typedef uint64_t js_dlimb_t;
- #define JS_LIMB_DIGITS 9
- /* Must match the size of short_big_int in JSValueUnion */
- #define JS_LIMB_BITS 32
- #define JS_SHORT_BIG_INT_BITS JS_LIMB_BITS
- #define JS_BIGINT_MAX_SIZE ((1024 * 1024) / JS_LIMB_BITS) /* in limbs */
- #define JS_SHORT_BIG_INT_MIN INT32_MIN
- #define JS_SHORT_BIG_INT_MAX INT32_MAX
- typedef struct JSBigInt {
- JSRefCountHeader header; /* must come first, 32-bit */
- uint32_t len; /* number of limbs, >= 1 */
- js_limb_t tab[]; /* two's complement representation, always
- normalized so that 'len' is the minimum
- possible length >= 1 */
- } JSBigInt;
- /* this bigint structure can hold a 64 bit integer */
- typedef struct {
- js_limb_t big_int_buf[sizeof(JSBigInt) / sizeof(js_limb_t)]; /* for JSBigInt */
- /* must come just after */
- js_limb_t tab[(64 + JS_LIMB_BITS - 1) / JS_LIMB_BITS];
- } JSBigIntBuf;
- typedef enum {
- JS_AUTOINIT_ID_PROTOTYPE,
- JS_AUTOINIT_ID_MODULE_NS,
- JS_AUTOINIT_ID_PROP,
- JS_AUTOINIT_ID_BYTECODE,
- } JSAutoInitIDEnum;
- enum {
- JS_BUILTIN_ARRAY_FROMASYNC = 1,
- };
- /* must be large enough to have a negligible runtime cost and small
- enough to call the interrupt callback often. */
- #define JS_INTERRUPT_COUNTER_INIT 10000
- struct JSContext {
- JSGCObjectHeader header; /* must come first */
- JSRuntime *rt;
- struct list_head link;
- uint16_t binary_object_count;
- int binary_object_size;
- JSShape *array_shape; /* initial shape for Array objects */
- JSValue *class_proto;
- JSValue function_proto;
- JSValue function_ctor;
- JSValue array_ctor;
- JSValue regexp_ctor;
- JSValue promise_ctor;
- JSValue native_error_proto[JS_NATIVE_ERROR_COUNT];
- JSValue error_ctor;
- JSValue error_back_trace;
- JSValue error_prepare_stack;
- JSValue error_stack_trace_limit;
- JSValue iterator_ctor;
- JSValue iterator_ctor_getset;
- JSValue iterator_proto;
- JSValue async_iterator_proto;
- JSValue array_proto_values;
- JSValue throw_type_error;
- JSValue eval_obj;
- JSValue global_obj; /* global object */
- JSValue global_var_obj; /* contains the global let/const definitions */
- double time_origin;
- uint64_t random_state;
- /* when the counter reaches zero, JSRutime.interrupt_handler is called */
- int interrupt_counter;
- struct list_head loaded_modules; /* list of JSModuleDef.link */
- /* if NULL, RegExp compilation is not supported */
- JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern,
- JSValueConst flags);
- /* if NULL, eval is not supported */
- JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
- const char *filename, int line, int flags, int scope_idx);
- void *user_opaque;
- };
- typedef union JSFloat64Union {
- double d;
- uint64_t u64;
- uint32_t u32[2];
- } JSFloat64Union;
- typedef enum {
- JS_WEAK_REF_KIND_MAP,
- JS_WEAK_REF_KIND_WEAK_REF,
- JS_WEAK_REF_KIND_FINALIZATION_REGISTRY_ENTRY,
- } JSWeakRefKindEnum;
- typedef struct JSWeakRefRecord {
- JSWeakRefKindEnum kind;
- struct JSWeakRefRecord *next_weak_ref;
- union {
- struct JSMapRecord *map_record;
- struct JSWeakRefData *weak_ref_data;
- struct JSFinRecEntry *fin_rec_entry;
- } u;
- } JSWeakRefRecord;
- typedef struct JSMapRecord {
- int ref_count; /* used during enumeration to avoid freeing the record */
- bool empty; /* true if the record is deleted */
- struct JSMapState *map;
- struct list_head link;
- struct list_head hash_link;
- JSValue key;
- JSValue value;
- } JSMapRecord;
- typedef struct JSMapState {
- bool is_weak; /* true if WeakSet/WeakMap */
- struct list_head records; /* list of JSMapRecord.link */
- uint32_t record_count;
- struct list_head *hash_table;
- uint32_t hash_size; /* must be a power of two */
- uint32_t record_count_threshold; /* count at which a hash table
- resize is needed */
- } JSMapState;
- enum
- {
- JS_TO_STRING_IS_PROPERTY_KEY = 1 << 0,
- JS_TO_STRING_NO_SIDE_EFFECTS = 1 << 1,
- };
- enum {
- JS_ATOM_TYPE_STRING = 1,
- JS_ATOM_TYPE_GLOBAL_SYMBOL,
- JS_ATOM_TYPE_SYMBOL,
- JS_ATOM_TYPE_PRIVATE,
- };
- enum {
- JS_ATOM_HASH_SYMBOL,
- JS_ATOM_HASH_PRIVATE,
- };
- typedef enum {
- JS_ATOM_KIND_STRING,
- JS_ATOM_KIND_SYMBOL,
- JS_ATOM_KIND_PRIVATE,
- } JSAtomKindEnum;
- typedef enum {
- JS_STRING_KIND_NORMAL,
- JS_STRING_KIND_SLICE,
- } JSStringKind;
- #define JS_ATOM_HASH_MASK ((1 << 29) - 1)
- struct JSString {
- JSRefCountHeader header; /* must come first, 32-bit */
- uint32_t len : 31;
- uint8_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */
- /* for JS_ATOM_TYPE_SYMBOL: hash = 0, atom_type = 3,
- for JS_ATOM_TYPE_PRIVATE: hash = 1, atom_type = 3
- XXX: could change encoding to have one more bit in hash */
- uint32_t hash : 29;
- uint8_t kind : 1;
- uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */
- uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */
- JSWeakRefRecord *first_weak_ref;
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- struct list_head link; /* string list */
- #endif
- };
- typedef struct JSStringSlice {
- JSString *parent;
- uint32_t start; // in bytes, not characters
- } JSStringSlice;
- static inline void *strv(JSString *p)
- {
- JSStringSlice *slice;
- switch (p->kind) {
- case JS_STRING_KIND_NORMAL:
- return (void *)&p[1];
- case JS_STRING_KIND_SLICE:
- slice = (void *)&p[1];
- return (char *)&slice->parent[1] + slice->start;
- }
- abort();
- return NULL;
- }
- static inline uint8_t *str8(JSString *p)
- {
- return strv(p);
- }
- static inline uint16_t *str16(JSString *p)
- {
- return strv(p);
- }
- typedef struct JSClosureVar {
- uint8_t is_local : 1;
- uint8_t is_arg : 1;
- uint8_t is_const : 1;
- uint8_t is_lexical : 1;
- uint8_t var_kind : 4; /* see JSVarKindEnum */
- /* 8 bits available */
- uint16_t var_idx; /* is_local = true: index to a normal variable of the
- parent function. otherwise: index to a closure
- variable of the parent function */
- JSAtom var_name;
- } JSClosureVar;
- #define ARG_SCOPE_INDEX 1
- #define ARG_SCOPE_END (-2)
- typedef struct JSVarScope {
- int parent; /* index into fd->scopes of the enclosing scope */
- int first; /* index into fd->vars of the last variable in this scope */
- } JSVarScope;
- typedef enum {
- /* XXX: add more variable kinds here instead of using bit fields */
- JS_VAR_NORMAL,
- JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */
- JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator
- function declaration */
- JS_VAR_CATCH,
- JS_VAR_FUNCTION_NAME, /* function expression name */
- JS_VAR_PRIVATE_FIELD,
- JS_VAR_PRIVATE_METHOD,
- JS_VAR_PRIVATE_GETTER,
- JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */
- JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */
- } JSVarKindEnum;
- /* XXX: could use a different structure in bytecode functions to save
- memory */
- typedef struct JSVarDef {
- JSAtom var_name;
- /* index into fd->scopes of this variable lexical scope */
- int scope_level;
- /* during compilation:
- - if scope_level = 0: scope in which the variable is defined
- - if scope_level != 0: index into fd->vars of the next
- variable in the same or enclosing lexical scope
- in a bytecode function:
- index into fd->vars of the next
- variable in the same or enclosing lexical scope
- */
- int scope_next;
- uint8_t is_const : 1;
- uint8_t is_lexical : 1;
- uint8_t is_captured : 1;
- uint8_t is_static_private : 1; /* only used during private class field parsing */
- uint8_t var_kind : 4; /* see JSVarKindEnum */
- /* only used during compilation: function pool index for lexical
- variables with var_kind =
- JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of
- the definition of the 'var' variables (they have scope_level =
- 0) */
- int func_pool_idx : 24; /* only used during compilation : index in
- the constant pool for hoisted function
- definition */
- } JSVarDef;
- /* for the encoding of the pc2line table */
- #define PC2LINE_BASE (-1)
- #define PC2LINE_RANGE 5
- #define PC2LINE_OP_FIRST 1
- #define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE)
- typedef enum JSFunctionKindEnum {
- JS_FUNC_NORMAL = 0,
- JS_FUNC_GENERATOR = (1 << 0),
- JS_FUNC_ASYNC = (1 << 1),
- JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC),
- } JSFunctionKindEnum;
- typedef struct JSFunctionBytecode {
- JSGCObjectHeader header; /* must come first */
- uint8_t is_strict_mode : 1;
- uint8_t has_prototype : 1; /* true if a prototype field is necessary */
- uint8_t has_simple_parameter_list : 1;
- uint8_t is_derived_class_constructor : 1;
- /* true if home_object needs to be initialized */
- uint8_t need_home_object : 1;
- uint8_t func_kind : 2;
- uint8_t new_target_allowed : 1;
- uint8_t super_call_allowed : 1;
- uint8_t super_allowed : 1;
- uint8_t arguments_allowed : 1;
- uint8_t backtrace_barrier : 1; /* stop backtrace on this function */
- /* XXX: 5 bits available */
- uint8_t *byte_code_buf; /* (self pointer) */
- int byte_code_len;
- JSAtom func_name;
- JSVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */
- JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */
- uint16_t arg_count;
- uint16_t var_count;
- uint16_t defined_arg_count; /* for length function property */
- uint16_t stack_size; /* maximum stack size */
- JSContext *realm; /* function realm */
- JSValue *cpool; /* constant pool (self pointer) */
- int cpool_count;
- int closure_var_count;
- JSAtom filename;
- int line_num;
- int col_num;
- int source_len;
- int pc2line_len;
- uint8_t *pc2line_buf;
- char *source;
- } JSFunctionBytecode;
- typedef struct JSBoundFunction {
- JSValue func_obj;
- JSValue this_val;
- int argc;
- JSValue argv[];
- } JSBoundFunction;
- typedef enum JSIteratorKindEnum {
- JS_ITERATOR_KIND_KEY,
- JS_ITERATOR_KIND_VALUE,
- JS_ITERATOR_KIND_KEY_AND_VALUE,
- } JSIteratorKindEnum;
- typedef enum JSIteratorHelperKindEnum {
- JS_ITERATOR_HELPER_KIND_DROP,
- JS_ITERATOR_HELPER_KIND_EVERY,
- JS_ITERATOR_HELPER_KIND_FILTER,
- JS_ITERATOR_HELPER_KIND_FIND,
- JS_ITERATOR_HELPER_KIND_FLAT_MAP,
- JS_ITERATOR_HELPER_KIND_FOR_EACH,
- JS_ITERATOR_HELPER_KIND_MAP,
- JS_ITERATOR_HELPER_KIND_SOME,
- JS_ITERATOR_HELPER_KIND_TAKE,
- } JSIteratorHelperKindEnum;
- typedef struct JSForInIterator {
- JSValue obj;
- bool is_array;
- uint32_t array_length;
- uint32_t idx;
- } JSForInIterator;
- typedef struct JSRegExp {
- JSString *pattern;
- JSString *bytecode; /* also contains the flags */
- } JSRegExp;
- typedef struct JSProxyData {
- JSValue target;
- JSValue handler;
- uint8_t is_func;
- uint8_t is_revoked;
- } JSProxyData;
- typedef struct JSArrayBuffer {
- int byte_length; /* 0 if detached */
- int max_byte_length; /* -1 if not resizable; >= byte_length otherwise */
- uint8_t detached;
- uint8_t shared; /* if shared, the array buffer cannot be detached */
- uint8_t *data; /* NULL if detached */
- struct list_head array_list;
- void *opaque;
- JSFreeArrayBufferDataFunc *free_func;
- } JSArrayBuffer;
- typedef struct JSTypedArray {
- struct list_head link; /* link to arraybuffer */
- JSObject *obj; /* back pointer to the TypedArray/DataView object */
- JSObject *buffer; /* based array buffer */
- uint32_t offset; /* byte offset in the array buffer */
- uint32_t length; /* byte length in the array buffer */
- bool track_rab; /* auto-track length of backing array buffer */
- } JSTypedArray;
- typedef struct JSAsyncFunctionState {
- JSValue this_val; /* 'this' generator argument */
- int argc; /* number of function arguments */
- bool throw_flag; /* used to throw an exception in JS_CallInternal() */
- JSStackFrame frame;
- } JSAsyncFunctionState;
- /* XXX: could use an object instead to avoid the
- JS_TAG_ASYNC_FUNCTION tag for the GC */
- typedef struct JSAsyncFunctionData {
- JSGCObjectHeader header; /* must come first */
- JSValue resolving_funcs[2];
- bool is_active; /* true if the async function state is valid */
- JSAsyncFunctionState func_state;
- } JSAsyncFunctionData;
- typedef struct JSReqModuleEntry {
- JSAtom module_name;
- JSModuleDef *module; /* used using resolution */
- } JSReqModuleEntry;
- typedef enum JSExportTypeEnum {
- JS_EXPORT_TYPE_LOCAL,
- JS_EXPORT_TYPE_INDIRECT,
- } JSExportTypeEnum;
- typedef struct JSExportEntry {
- union {
- struct {
- int var_idx; /* closure variable index */
- JSVarRef *var_ref; /* if != NULL, reference to the variable */
- } local; /* for local export */
- int req_module_idx; /* module for indirect export */
- } u;
- JSExportTypeEnum export_type;
- JSAtom local_name; /* '*' if export ns from. not used for local
- export after compilation */
- JSAtom export_name; /* exported variable name */
- } JSExportEntry;
- typedef struct JSStarExportEntry {
- int req_module_idx; /* in req_module_entries */
- } JSStarExportEntry;
- typedef struct JSImportEntry {
- int var_idx; /* closure variable index */
- JSAtom import_name;
- int req_module_idx; /* in req_module_entries */
- } JSImportEntry;
- typedef enum {
- JS_MODULE_STATUS_UNLINKED,
- JS_MODULE_STATUS_LINKING,
- JS_MODULE_STATUS_LINKED,
- JS_MODULE_STATUS_EVALUATING,
- JS_MODULE_STATUS_EVALUATING_ASYNC,
- JS_MODULE_STATUS_EVALUATED,
- } JSModuleStatus;
- struct JSModuleDef {
- JSRefCountHeader header; /* must come first, 32-bit */
- JSAtom module_name;
- struct list_head link;
- JSReqModuleEntry *req_module_entries;
- int req_module_entries_count;
- int req_module_entries_size;
- JSExportEntry *export_entries;
- int export_entries_count;
- int export_entries_size;
- JSStarExportEntry *star_export_entries;
- int star_export_entries_count;
- int star_export_entries_size;
- JSImportEntry *import_entries;
- int import_entries_count;
- int import_entries_size;
- JSValue module_ns;
- JSValue func_obj; /* only used for JS modules */
- JSModuleInitFunc *init_func; /* only used for C modules */
- bool has_tla; /* true if func_obj contains await */
- bool resolved;
- bool func_created;
- JSModuleStatus status : 8;
- /* temp use during js_module_link() & js_module_evaluate() */
- int dfs_index, dfs_ancestor_index;
- JSModuleDef *stack_prev;
- /* temp use during js_module_evaluate() */
- JSModuleDef **async_parent_modules;
- int async_parent_modules_count;
- int async_parent_modules_size;
- int pending_async_dependencies;
- bool async_evaluation;
- int64_t async_evaluation_timestamp;
- JSModuleDef *cycle_root;
- JSValue promise; /* corresponds to spec field: capability */
- JSValue resolving_funcs[2]; /* corresponds to spec field: capability */
- /* true if evaluation yielded an exception. It is saved in
- eval_exception */
- bool eval_has_exception;
- JSValue eval_exception;
- JSValue meta_obj; /* for import.meta */
- };
- typedef struct JSJobEntry {
- struct list_head link;
- JSContext *ctx;
- JSJobFunc *job_func;
- int argc;
- JSValue argv[];
- } JSJobEntry;
- typedef struct JSProperty {
- union {
- JSValue value; /* JS_PROP_NORMAL */
- struct { /* JS_PROP_GETSET */
- JSObject *getter; /* NULL if undefined */
- JSObject *setter; /* NULL if undefined */
- } getset;
- JSVarRef *var_ref; /* JS_PROP_VARREF */
- struct { /* JS_PROP_AUTOINIT */
- /* in order to use only 2 pointers, we compress the realm
- and the init function pointer */
- uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x)
- in the 2 low bits */
- void *opaque;
- } init;
- } u;
- } JSProperty;
- #define JS_PROP_INITIAL_SIZE 2
- #define JS_PROP_INITIAL_HASH_SIZE 4 /* must be a power of two */
- #define JS_ARRAY_INITIAL_SIZE 2
- typedef struct JSShapeProperty {
- uint32_t hash_next : 26; /* 0 if last in list */
- uint32_t flags : 6; /* JS_PROP_XXX */
- JSAtom atom; /* JS_ATOM_NULL = free property entry */
- } JSShapeProperty;
- struct JSShape {
- /* hash table of size hash_mask + 1 before the start of the
- structure (see prop_hash_end()). */
- JSGCObjectHeader header;
- /* true if the shape is inserted in the shape hash table. If not,
- JSShape.hash is not valid */
- uint8_t is_hashed;
- /* If true, the shape may have small array index properties 'n' with 0
- <= n <= 2^31-1. If false, the shape is guaranteed not to have
- small array index properties */
- uint8_t has_small_array_index;
- uint32_t hash; /* current hash value */
- uint32_t prop_hash_mask;
- int prop_size; /* allocated properties */
- int prop_count; /* include deleted properties */
- int deleted_prop_count;
- JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */
- JSObject *proto;
- JSShapeProperty prop[]; /* prop_size elements */
- };
- struct JSObject {
- union {
- JSGCObjectHeader header;
- struct {
- int __gc_ref_count; /* corresponds to header.ref_count */
- uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
- uint8_t extensible : 1;
- uint8_t free_mark : 1; /* only used when freeing objects with cycles */
- uint8_t is_exotic : 1; /* true if object has exotic property handlers */
- uint8_t fast_array : 1; /* true if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */
- uint8_t is_constructor : 1; /* true if object is a constructor function */
- uint8_t is_uncatchable_error : 1; /* if true, error is not catchable */
- uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
- uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */
- uint16_t class_id; /* see JS_CLASS_x */
- };
- };
- /* byte offsets: 16/24 */
- JSShape *shape; /* prototype and property names + flag */
- JSProperty *prop; /* array of properties */
- /* byte offsets: 24/40 */
- JSWeakRefRecord *first_weak_ref;
- /* byte offsets: 28/48 */
- union {
- void *opaque;
- struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */
- struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */
- struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */
- struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */
- struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */
- struct JSMapState *map_state; /* JS_CLASS_MAP..JS_CLASS_WEAKSET */
- struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */
- struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */
- struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */
- struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */
- struct JSIteratorConcatData *iterator_concat_data; /* JS_CLASS_ITERATOR_CONCAT */
- struct JSIteratorHelperData *iterator_helper_data; /* JS_CLASS_ITERATOR_HELPER */
- struct JSIteratorWrapData *iterator_wrap_data; /* JS_CLASS_ITERATOR_WRAP */
- struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */
- struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */
- struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */
- struct JSAsyncFunctionData *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */
- struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
- struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */
- struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */
- /* also used by JS_CLASS_GENERATOR_FUNCTION, JS_CLASS_ASYNC_FUNCTION and JS_CLASS_ASYNC_GENERATOR_FUNCTION */
- struct JSFunctionBytecode *function_bytecode;
- JSVarRef **var_refs;
- JSObject *home_object; /* for 'super' access */
- } func;
- struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */
- JSContext *realm;
- JSCFunctionType c_function;
- uint8_t length;
- uint8_t cproto;
- int16_t magic;
- } cfunc;
- /* array part for fast arrays and typed arrays */
- struct { /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
- union {
- uint32_t size; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
- struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
- } u1;
- union {
- JSValue *values; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
- void *ptr; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
- int8_t *int8_ptr; /* JS_CLASS_INT8_ARRAY */
- uint8_t *uint8_ptr; /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */
- int16_t *int16_ptr; /* JS_CLASS_INT16_ARRAY */
- uint16_t *uint16_ptr; /* JS_CLASS_UINT16_ARRAY */
- int32_t *int32_ptr; /* JS_CLASS_INT32_ARRAY */
- uint32_t *uint32_ptr; /* JS_CLASS_UINT32_ARRAY */
- int64_t *int64_ptr; /* JS_CLASS_INT64_ARRAY */
- uint64_t *uint64_ptr; /* JS_CLASS_UINT64_ARRAY */
- uint16_t *fp16_ptr; /* JS_CLASS_FLOAT16_ARRAY */
- float *float_ptr; /* JS_CLASS_FLOAT32_ARRAY */
- double *double_ptr; /* JS_CLASS_FLOAT64_ARRAY */
- } u;
- uint32_t count; /* <= 2^31-1. 0 for a detached typed array */
- } array; /* 12/20 bytes */
- JSRegExp regexp; /* JS_CLASS_REGEXP: 8/16 bytes */
- JSValue object_data; /* for JS_SetObjectData(): 8/16/16 bytes */
- } u;
- /* byte sizes: 40/48/72 */
- };
- typedef struct JSCallSiteData {
- JSValue filename;
- JSValue func;
- JSValue func_name;
- bool native;
- int line_num;
- int col_num;
- } JSCallSiteData;
- enum {
- __JS_ATOM_NULL = JS_ATOM_NULL,
- #define DEF(name, str) JS_ATOM_ ## name,
- /*
- * QuickJS atom definitions
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- * Copyright (c) 2017-2018 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifdef DEF
- /* Note: first atoms are considered as keywords in the parser */
- DEF(null, "null") /* must be first */
- DEF(false, "false")
- DEF(true, "true")
- DEF(if, "if")
- DEF(else, "else")
- DEF(return, "return")
- DEF(var, "var")
- DEF(this, "this")
- DEF(delete, "delete")
- DEF(void, "void")
- DEF(typeof, "typeof")
- DEF(new, "new")
- DEF(in, "in")
- DEF(instanceof, "instanceof")
- DEF(do, "do")
- DEF(while, "while")
- DEF(for, "for")
- DEF(break, "break")
- DEF(continue, "continue")
- DEF(switch, "switch")
- DEF(case, "case")
- DEF(default, "default")
- DEF(throw, "throw")
- DEF(try, "try")
- DEF(catch, "catch")
- DEF(finally, "finally")
- DEF(function, "function")
- DEF(debugger, "debugger")
- DEF(with, "with")
- /* FutureReservedWord */
- DEF(class, "class")
- DEF(const, "const")
- DEF(enum, "enum")
- DEF(export, "export")
- DEF(extends, "extends")
- DEF(import, "import")
- DEF(super, "super")
- /* FutureReservedWords when parsing strict mode code */
- DEF(implements, "implements")
- DEF(interface, "interface")
- DEF(let, "let")
- DEF(package, "package")
- DEF(private, "private")
- DEF(protected, "protected")
- DEF(public, "public")
- DEF(static, "static")
- DEF(yield, "yield")
- DEF(await, "await")
- /* empty string */
- DEF(empty_string, "")
- /* identifiers */
- DEF(keys, "keys")
- DEF(size, "size")
- DEF(length, "length")
- DEF(message, "message")
- DEF(cause, "cause")
- DEF(errors, "errors")
- DEF(stack, "stack")
- DEF(name, "name")
- DEF(toString, "toString")
- DEF(toLocaleString, "toLocaleString")
- DEF(valueOf, "valueOf")
- DEF(eval, "eval")
- DEF(prototype, "prototype")
- DEF(constructor, "constructor")
- DEF(configurable, "configurable")
- DEF(writable, "writable")
- DEF(enumerable, "enumerable")
- DEF(value, "value")
- DEF(get, "get")
- DEF(set, "set")
- DEF(of, "of")
- DEF(__proto__, "__proto__")
- DEF(undefined, "undefined")
- DEF(number, "number")
- DEF(boolean, "boolean")
- DEF(string, "string")
- DEF(object, "object")
- DEF(symbol, "symbol")
- DEF(integer, "integer")
- DEF(unknown, "unknown")
- DEF(arguments, "arguments")
- DEF(callee, "callee")
- DEF(caller, "caller")
- DEF(_eval_, "<eval>")
- DEF(_ret_, "<ret>")
- DEF(_var_, "<var>")
- DEF(_arg_var_, "<arg_var>")
- DEF(_with_, "<with>")
- DEF(lastIndex, "lastIndex")
- DEF(target, "target")
- DEF(index, "index")
- DEF(input, "input")
- DEF(defineProperties, "defineProperties")
- DEF(apply, "apply")
- DEF(join, "join")
- DEF(concat, "concat")
- DEF(split, "split")
- DEF(construct, "construct")
- DEF(getPrototypeOf, "getPrototypeOf")
- DEF(setPrototypeOf, "setPrototypeOf")
- DEF(isExtensible, "isExtensible")
- DEF(preventExtensions, "preventExtensions")
- DEF(has, "has")
- DEF(deleteProperty, "deleteProperty")
- DEF(defineProperty, "defineProperty")
- DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor")
- DEF(ownKeys, "ownKeys")
- DEF(add, "add")
- DEF(done, "done")
- DEF(next, "next")
- DEF(values, "values")
- DEF(source, "source")
- DEF(flags, "flags")
- DEF(global, "global")
- DEF(unicode, "unicode")
- DEF(raw, "raw")
- DEF(new_target, "new.target")
- DEF(this_active_func, "this.active_func")
- DEF(home_object, "<home_object>")
- DEF(computed_field, "<computed_field>")
- DEF(static_computed_field, "<static_computed_field>") /* must come after computed_fields */
- DEF(class_fields_init, "<class_fields_init>")
- DEF(brand, "<brand>")
- DEF(hash_constructor, "#constructor")
- DEF(as, "as")
- DEF(from, "from")
- DEF(fromAsync, "fromAsync")
- DEF(meta, "meta")
- DEF(_default_, "*default*")
- DEF(_star_, "*")
- DEF(Module, "Module")
- DEF(then, "then")
- DEF(resolve, "resolve")
- DEF(reject, "reject")
- DEF(promise, "promise")
- DEF(proxy, "proxy")
- DEF(revoke, "revoke")
- DEF(async, "async")
- DEF(exec, "exec")
- DEF(groups, "groups")
- DEF(indices, "indices")
- DEF(status, "status")
- DEF(reason, "reason")
- DEF(globalThis, "globalThis")
- DEF(bigint, "bigint")
- DEF(not_equal, "not-equal")
- DEF(timed_out, "timed-out")
- DEF(ok, "ok")
- DEF(toJSON, "toJSON")
- DEF(maxByteLength, "maxByteLength")
- /* class names */
- DEF(Object, "Object")
- DEF(Array, "Array")
- DEF(Error, "Error")
- DEF(Number, "Number")
- DEF(String, "String")
- DEF(Boolean, "Boolean")
- DEF(Symbol, "Symbol")
- DEF(Arguments, "Arguments")
- DEF(Math, "Math")
- DEF(JSON, "JSON")
- DEF(Date, "Date")
- DEF(Function, "Function")
- DEF(GeneratorFunction, "GeneratorFunction")
- DEF(ForInIterator, "ForInIterator")
- DEF(RegExp, "RegExp")
- DEF(ArrayBuffer, "ArrayBuffer")
- DEF(SharedArrayBuffer, "SharedArrayBuffer")
- /* must keep same order as class IDs for typed arrays */
- DEF(Uint8ClampedArray, "Uint8ClampedArray")
- DEF(Int8Array, "Int8Array")
- DEF(Uint8Array, "Uint8Array")
- DEF(Int16Array, "Int16Array")
- DEF(Uint16Array, "Uint16Array")
- DEF(Int32Array, "Int32Array")
- DEF(Uint32Array, "Uint32Array")
- DEF(BigInt64Array, "BigInt64Array")
- DEF(BigUint64Array, "BigUint64Array")
- DEF(Float16Array, "Float16Array")
- DEF(Float32Array, "Float32Array")
- DEF(Float64Array, "Float64Array")
- DEF(DataView, "DataView")
- DEF(BigInt, "BigInt")
- DEF(WeakRef, "WeakRef")
- DEF(FinalizationRegistry, "FinalizationRegistry")
- DEF(Map, "Map")
- DEF(Set, "Set") /* Map + 1 */
- DEF(WeakMap, "WeakMap") /* Map + 2 */
- DEF(WeakSet, "WeakSet") /* Map + 3 */
- DEF(Iterator, "Iterator")
- DEF(IteratorConcat, "Iterator Concat")
- DEF(IteratorHelper, "Iterator Helper")
- DEF(IteratorWrap, "Iterator Wrap")
- DEF(Map_Iterator, "Map Iterator")
- DEF(Set_Iterator, "Set Iterator")
- DEF(Array_Iterator, "Array Iterator")
- DEF(String_Iterator, "String Iterator")
- DEF(RegExp_String_Iterator, "RegExp String Iterator")
- DEF(Generator, "Generator")
- DEF(Proxy, "Proxy")
- DEF(Promise, "Promise")
- DEF(PromiseResolveFunction, "PromiseResolveFunction")
- DEF(PromiseRejectFunction, "PromiseRejectFunction")
- DEF(AsyncFunction, "AsyncFunction")
- DEF(AsyncFunctionResolve, "AsyncFunctionResolve")
- DEF(AsyncFunctionReject, "AsyncFunctionReject")
- DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction")
- DEF(AsyncGenerator, "AsyncGenerator")
- DEF(EvalError, "EvalError")
- DEF(RangeError, "RangeError")
- DEF(ReferenceError, "ReferenceError")
- DEF(SyntaxError, "SyntaxError")
- DEF(TypeError, "TypeError")
- DEF(URIError, "URIError")
- DEF(InternalError, "InternalError")
- DEF(DOMException, "DOMException")
- DEF(CallSite, "CallSite")
- /* private symbols */
- DEF(Private_brand, "<brand>")
- /* symbols */
- DEF(Symbol_toPrimitive, "Symbol.toPrimitive")
- DEF(Symbol_iterator, "Symbol.iterator")
- DEF(Symbol_match, "Symbol.match")
- DEF(Symbol_matchAll, "Symbol.matchAll")
- DEF(Symbol_replace, "Symbol.replace")
- DEF(Symbol_search, "Symbol.search")
- DEF(Symbol_split, "Symbol.split")
- DEF(Symbol_toStringTag, "Symbol.toStringTag")
- DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable")
- DEF(Symbol_hasInstance, "Symbol.hasInstance")
- DEF(Symbol_species, "Symbol.species")
- DEF(Symbol_unscopables, "Symbol.unscopables")
- DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
- #endif /* DEF */
- #undef DEF
- JS_ATOM_END,
- };
- #define JS_ATOM_LAST_KEYWORD JS_ATOM_super
- #define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield
- static const char js_atom_init[] =
- #define DEF(name, str) str "\0"
- /*
- * QuickJS atom definitions
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- * Copyright (c) 2017-2018 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifdef DEF
- /* Note: first atoms are considered as keywords in the parser */
- DEF(null, "null") /* must be first */
- DEF(false, "false")
- DEF(true, "true")
- DEF(if, "if")
- DEF(else, "else")
- DEF(return, "return")
- DEF(var, "var")
- DEF(this, "this")
- DEF(delete, "delete")
- DEF(void, "void")
- DEF(typeof, "typeof")
- DEF(new, "new")
- DEF(in, "in")
- DEF(instanceof, "instanceof")
- DEF(do, "do")
- DEF(while, "while")
- DEF(for, "for")
- DEF(break, "break")
- DEF(continue, "continue")
- DEF(switch, "switch")
- DEF(case, "case")
- DEF(default, "default")
- DEF(throw, "throw")
- DEF(try, "try")
- DEF(catch, "catch")
- DEF(finally, "finally")
- DEF(function, "function")
- DEF(debugger, "debugger")
- DEF(with, "with")
- /* FutureReservedWord */
- DEF(class, "class")
- DEF(const, "const")
- DEF(enum, "enum")
- DEF(export, "export")
- DEF(extends, "extends")
- DEF(import, "import")
- DEF(super, "super")
- /* FutureReservedWords when parsing strict mode code */
- DEF(implements, "implements")
- DEF(interface, "interface")
- DEF(let, "let")
- DEF(package, "package")
- DEF(private, "private")
- DEF(protected, "protected")
- DEF(public, "public")
- DEF(static, "static")
- DEF(yield, "yield")
- DEF(await, "await")
- /* empty string */
- DEF(empty_string, "")
- /* identifiers */
- DEF(keys, "keys")
- DEF(size, "size")
- DEF(length, "length")
- DEF(message, "message")
- DEF(cause, "cause")
- DEF(errors, "errors")
- DEF(stack, "stack")
- DEF(name, "name")
- DEF(toString, "toString")
- DEF(toLocaleString, "toLocaleString")
- DEF(valueOf, "valueOf")
- DEF(eval, "eval")
- DEF(prototype, "prototype")
- DEF(constructor, "constructor")
- DEF(configurable, "configurable")
- DEF(writable, "writable")
- DEF(enumerable, "enumerable")
- DEF(value, "value")
- DEF(get, "get")
- DEF(set, "set")
- DEF(of, "of")
- DEF(__proto__, "__proto__")
- DEF(undefined, "undefined")
- DEF(number, "number")
- DEF(boolean, "boolean")
- DEF(string, "string")
- DEF(object, "object")
- DEF(symbol, "symbol")
- DEF(integer, "integer")
- DEF(unknown, "unknown")
- DEF(arguments, "arguments")
- DEF(callee, "callee")
- DEF(caller, "caller")
- DEF(_eval_, "<eval>")
- DEF(_ret_, "<ret>")
- DEF(_var_, "<var>")
- DEF(_arg_var_, "<arg_var>")
- DEF(_with_, "<with>")
- DEF(lastIndex, "lastIndex")
- DEF(target, "target")
- DEF(index, "index")
- DEF(input, "input")
- DEF(defineProperties, "defineProperties")
- DEF(apply, "apply")
- DEF(join, "join")
- DEF(concat, "concat")
- DEF(split, "split")
- DEF(construct, "construct")
- DEF(getPrototypeOf, "getPrototypeOf")
- DEF(setPrototypeOf, "setPrototypeOf")
- DEF(isExtensible, "isExtensible")
- DEF(preventExtensions, "preventExtensions")
- DEF(has, "has")
- DEF(deleteProperty, "deleteProperty")
- DEF(defineProperty, "defineProperty")
- DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor")
- DEF(ownKeys, "ownKeys")
- DEF(add, "add")
- DEF(done, "done")
- DEF(next, "next")
- DEF(values, "values")
- DEF(source, "source")
- DEF(flags, "flags")
- DEF(global, "global")
- DEF(unicode, "unicode")
- DEF(raw, "raw")
- DEF(new_target, "new.target")
- DEF(this_active_func, "this.active_func")
- DEF(home_object, "<home_object>")
- DEF(computed_field, "<computed_field>")
- DEF(static_computed_field, "<static_computed_field>") /* must come after computed_fields */
- DEF(class_fields_init, "<class_fields_init>")
- DEF(brand, "<brand>")
- DEF(hash_constructor, "#constructor")
- DEF(as, "as")
- DEF(from, "from")
- DEF(fromAsync, "fromAsync")
- DEF(meta, "meta")
- DEF(_default_, "*default*")
- DEF(_star_, "*")
- DEF(Module, "Module")
- DEF(then, "then")
- DEF(resolve, "resolve")
- DEF(reject, "reject")
- DEF(promise, "promise")
- DEF(proxy, "proxy")
- DEF(revoke, "revoke")
- DEF(async, "async")
- DEF(exec, "exec")
- DEF(groups, "groups")
- DEF(indices, "indices")
- DEF(status, "status")
- DEF(reason, "reason")
- DEF(globalThis, "globalThis")
- DEF(bigint, "bigint")
- DEF(not_equal, "not-equal")
- DEF(timed_out, "timed-out")
- DEF(ok, "ok")
- DEF(toJSON, "toJSON")
- DEF(maxByteLength, "maxByteLength")
- /* class names */
- DEF(Object, "Object")
- DEF(Array, "Array")
- DEF(Error, "Error")
- DEF(Number, "Number")
- DEF(String, "String")
- DEF(Boolean, "Boolean")
- DEF(Symbol, "Symbol")
- DEF(Arguments, "Arguments")
- DEF(Math, "Math")
- DEF(JSON, "JSON")
- DEF(Date, "Date")
- DEF(Function, "Function")
- DEF(GeneratorFunction, "GeneratorFunction")
- DEF(ForInIterator, "ForInIterator")
- DEF(RegExp, "RegExp")
- DEF(ArrayBuffer, "ArrayBuffer")
- DEF(SharedArrayBuffer, "SharedArrayBuffer")
- /* must keep same order as class IDs for typed arrays */
- DEF(Uint8ClampedArray, "Uint8ClampedArray")
- DEF(Int8Array, "Int8Array")
- DEF(Uint8Array, "Uint8Array")
- DEF(Int16Array, "Int16Array")
- DEF(Uint16Array, "Uint16Array")
- DEF(Int32Array, "Int32Array")
- DEF(Uint32Array, "Uint32Array")
- DEF(BigInt64Array, "BigInt64Array")
- DEF(BigUint64Array, "BigUint64Array")
- DEF(Float16Array, "Float16Array")
- DEF(Float32Array, "Float32Array")
- DEF(Float64Array, "Float64Array")
- DEF(DataView, "DataView")
- DEF(BigInt, "BigInt")
- DEF(WeakRef, "WeakRef")
- DEF(FinalizationRegistry, "FinalizationRegistry")
- DEF(Map, "Map")
- DEF(Set, "Set") /* Map + 1 */
- DEF(WeakMap, "WeakMap") /* Map + 2 */
- DEF(WeakSet, "WeakSet") /* Map + 3 */
- DEF(Iterator, "Iterator")
- DEF(IteratorConcat, "Iterator Concat")
- DEF(IteratorHelper, "Iterator Helper")
- DEF(IteratorWrap, "Iterator Wrap")
- DEF(Map_Iterator, "Map Iterator")
- DEF(Set_Iterator, "Set Iterator")
- DEF(Array_Iterator, "Array Iterator")
- DEF(String_Iterator, "String Iterator")
- DEF(RegExp_String_Iterator, "RegExp String Iterator")
- DEF(Generator, "Generator")
- DEF(Proxy, "Proxy")
- DEF(Promise, "Promise")
- DEF(PromiseResolveFunction, "PromiseResolveFunction")
- DEF(PromiseRejectFunction, "PromiseRejectFunction")
- DEF(AsyncFunction, "AsyncFunction")
- DEF(AsyncFunctionResolve, "AsyncFunctionResolve")
- DEF(AsyncFunctionReject, "AsyncFunctionReject")
- DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction")
- DEF(AsyncGenerator, "AsyncGenerator")
- DEF(EvalError, "EvalError")
- DEF(RangeError, "RangeError")
- DEF(ReferenceError, "ReferenceError")
- DEF(SyntaxError, "SyntaxError")
- DEF(TypeError, "TypeError")
- DEF(URIError, "URIError")
- DEF(InternalError, "InternalError")
- DEF(DOMException, "DOMException")
- DEF(CallSite, "CallSite")
- /* private symbols */
- DEF(Private_brand, "<brand>")
- /* symbols */
- DEF(Symbol_toPrimitive, "Symbol.toPrimitive")
- DEF(Symbol_iterator, "Symbol.iterator")
- DEF(Symbol_match, "Symbol.match")
- DEF(Symbol_matchAll, "Symbol.matchAll")
- DEF(Symbol_replace, "Symbol.replace")
- DEF(Symbol_search, "Symbol.search")
- DEF(Symbol_split, "Symbol.split")
- DEF(Symbol_toStringTag, "Symbol.toStringTag")
- DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable")
- DEF(Symbol_hasInstance, "Symbol.hasInstance")
- DEF(Symbol_species, "Symbol.species")
- DEF(Symbol_unscopables, "Symbol.unscopables")
- DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
- #endif /* DEF */
- #undef DEF
- ;
- typedef enum OPCodeFormat {
- #define FMT(f) OP_FMT_ ## f,
- #define DEF(id, size, n_pop, n_push, f)
- /*
- * QuickJS opcode definitions
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- * Copyright (c) 2017-2018 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifdef FMT
- FMT(none)
- FMT(none_int)
- FMT(none_loc)
- FMT(none_arg)
- FMT(none_var_ref)
- FMT(u8)
- FMT(i8)
- FMT(loc8)
- FMT(const8)
- FMT(label8)
- FMT(u16)
- FMT(i16)
- FMT(label16)
- FMT(npop)
- FMT(npopx)
- FMT(npop_u16)
- FMT(loc)
- FMT(arg)
- FMT(var_ref)
- FMT(u32)
- FMT(u32x2)
- FMT(i32)
- FMT(const)
- FMT(label)
- FMT(atom)
- FMT(atom_u8)
- FMT(atom_u16)
- FMT(atom_label_u8)
- FMT(atom_label_u16)
- FMT(label_u16)
- #undef FMT
- #endif /* FMT */
- #ifdef DEF
- #ifndef def
- #define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f)
- #endif
- DEF(invalid, 1, 0, 0, none) /* never emitted */
- /* push values */
- DEF( push_i32, 5, 0, 1, i32)
- DEF( push_const, 5, 0, 1, const)
- DEF( fclosure, 5, 0, 1, const) /* must follow push_const */
- DEF(push_atom_value, 5, 0, 1, atom)
- DEF( private_symbol, 5, 0, 1, atom)
- DEF( undefined, 1, 0, 1, none)
- DEF( null, 1, 0, 1, none)
- DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */
- DEF( push_false, 1, 0, 1, none)
- DEF( push_true, 1, 0, 1, none)
- DEF( object, 1, 0, 1, none)
- DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */
- DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */
- DEF( drop, 1, 1, 0, none) /* a -> */
- DEF( nip, 1, 2, 1, none) /* a b -> b */
- DEF( nip1, 1, 3, 2, none) /* a b c -> b c */
- DEF( dup, 1, 1, 2, none) /* a -> a a */
- DEF( dup1, 1, 2, 3, none) /* a b -> a a b */
- DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */
- DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */
- DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */
- DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */
- DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */
- DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */
- DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */
- DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */
- DEF( swap, 1, 2, 2, none) /* a b -> b a */
- DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */
- DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */
- DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */
- DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */
- DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */
- DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */
- DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */
- DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */
- DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */
- DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */
- DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */
- DEF( apply, 3, 3, 1, u16)
- DEF( return, 1, 1, 0, none)
- DEF( return_undef, 1, 0, 0, none)
- DEF(check_ctor_return, 1, 1, 2, none)
- DEF( check_ctor, 1, 0, 0, none)
- DEF( init_ctor, 1, 0, 1, none)
- DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */
- DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */
- DEF( return_async, 1, 1, 0, none)
- DEF( throw, 1, 1, 0, none)
- DEF( throw_error, 6, 0, 0, atom_u8)
- DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
- DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
- DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
- bytecode string */
- DEF( get_super, 1, 1, 1, none)
- DEF( import, 1, 1, 1, none) /* dynamic module import */
- DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */
- DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */
- DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */
- DEF( put_var, 5, 1, 0, atom) /* must come after get_var */
- DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */
- DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */
- DEF( get_ref_value, 1, 2, 3, none)
- DEF( put_ref_value, 1, 3, 0, none)
- DEF( define_var, 6, 0, 0, atom_u8)
- DEF(check_define_var, 6, 0, 0, atom_u8)
- DEF( define_func, 6, 1, 0, atom_u8)
- // order matters, see IC counterparts
- DEF( get_field, 5, 1, 1, atom)
- DEF( get_field2, 5, 1, 2, atom)
- DEF( put_field, 5, 2, 0, atom)
- DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */
- DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */
- DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */
- DEF( get_array_el, 1, 2, 1, none)
- DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */
- DEF( put_array_el, 1, 3, 0, none)
- DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */
- DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */
- DEF( define_field, 5, 2, 1, atom)
- DEF( set_name, 5, 1, 1, atom)
- DEF(set_name_computed, 1, 2, 2, none)
- DEF( set_proto, 1, 2, 1, none)
- DEF(set_home_object, 1, 2, 2, none)
- DEF(define_array_el, 1, 3, 2, none)
- DEF( append, 1, 3, 2, none) /* append enumerated object, update length */
- DEF(copy_data_properties, 2, 3, 3, u8)
- DEF( define_method, 6, 2, 1, atom_u8)
- DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */
- DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */
- DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */
- DEF( get_loc, 3, 0, 1, loc)
- DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */
- DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */
- DEF( get_arg, 3, 0, 1, arg)
- DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */
- DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */
- DEF( get_var_ref, 3, 0, 1, var_ref)
- DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */
- DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */
- DEF(set_loc_uninitialized, 3, 0, 0, loc)
- DEF( get_loc_check, 3, 0, 1, loc)
- DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */
- DEF( put_loc_check_init, 3, 1, 0, loc)
- DEF(get_var_ref_check, 3, 0, 1, var_ref)
- DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */
- DEF(put_var_ref_check_init, 3, 1, 0, var_ref)
- DEF( close_loc, 3, 0, 0, loc)
- DEF( if_false, 5, 1, 0, label)
- DEF( if_true, 5, 1, 0, label) /* must come after if_false */
- DEF( goto, 5, 0, 0, label) /* must come after if_true */
- DEF( catch, 5, 0, 1, label)
- DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */
- DEF( ret, 1, 1, 0, none) /* used to return from the finally block */
- DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */
- DEF( to_object, 1, 1, 1, none)
- //DEF( to_string, 1, 1, 1, none)
- DEF( to_propkey, 1, 1, 1, none)
- DEF( to_propkey2, 1, 2, 2, none)
- DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF(with_get_ref_undef, 10, 1, 0, atom_label_u8)
- DEF( make_loc_ref, 7, 0, 2, atom_u16)
- DEF( make_arg_ref, 7, 0, 2, atom_u16)
- DEF(make_var_ref_ref, 7, 0, 2, atom_u16)
- DEF( make_var_ref, 5, 0, 2, atom)
- DEF( for_in_start, 1, 1, 1, none)
- DEF( for_of_start, 1, 1, 3, none)
- DEF(for_await_of_start, 1, 1, 3, none)
- DEF( for_in_next, 1, 1, 3, none)
- DEF( for_of_next, 2, 3, 5, u8)
- DEF(iterator_check_object, 1, 1, 1, none)
- DEF(iterator_get_value_done, 1, 1, 2, none)
- DEF( iterator_close, 1, 3, 0, none)
- DEF( iterator_next, 1, 4, 4, none)
- DEF( iterator_call, 2, 4, 5, u8)
- DEF( initial_yield, 1, 0, 0, none)
- DEF( yield, 1, 1, 2, none)
- DEF( yield_star, 1, 1, 2, none)
- DEF(async_yield_star, 1, 1, 2, none)
- DEF( await, 1, 1, 1, none)
- /* arithmetic/logic operations */
- DEF( neg, 1, 1, 1, none)
- DEF( plus, 1, 1, 1, none)
- DEF( dec, 1, 1, 1, none)
- DEF( inc, 1, 1, 1, none)
- DEF( post_dec, 1, 1, 2, none)
- DEF( post_inc, 1, 1, 2, none)
- DEF( dec_loc, 2, 0, 0, loc8)
- DEF( inc_loc, 2, 0, 0, loc8)
- DEF( add_loc, 2, 1, 0, loc8)
- DEF( not, 1, 1, 1, none)
- DEF( lnot, 1, 1, 1, none)
- DEF( typeof, 1, 1, 1, none)
- DEF( delete, 1, 2, 1, none)
- DEF( delete_var, 5, 0, 1, atom)
- /* warning: order matters (see js_parse_assign_expr) */
- DEF( mul, 1, 2, 1, none)
- DEF( div, 1, 2, 1, none)
- DEF( mod, 1, 2, 1, none)
- DEF( add, 1, 2, 1, none)
- DEF( sub, 1, 2, 1, none)
- DEF( shl, 1, 2, 1, none)
- DEF( sar, 1, 2, 1, none)
- DEF( shr, 1, 2, 1, none)
- DEF( and, 1, 2, 1, none)
- DEF( xor, 1, 2, 1, none)
- DEF( or, 1, 2, 1, none)
- DEF( pow, 1, 2, 1, none)
- DEF( lt, 1, 2, 1, none)
- DEF( lte, 1, 2, 1, none)
- DEF( gt, 1, 2, 1, none)
- DEF( gte, 1, 2, 1, none)
- DEF( instanceof, 1, 2, 1, none)
- DEF( in, 1, 2, 1, none)
- DEF( eq, 1, 2, 1, none)
- DEF( neq, 1, 2, 1, none)
- DEF( strict_eq, 1, 2, 1, none)
- DEF( strict_neq, 1, 2, 1, none)
- DEF(is_undefined_or_null, 1, 1, 1, none)
- DEF( private_in, 1, 2, 1, none)
- DEF(push_bigint_i32, 5, 0, 1, i32)
- /* must be the last non short and non temporary opcode */
- DEF( nop, 1, 0, 0, none)
- /* temporary opcodes: never emitted in the final bytecode */
- def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
- def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
- def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */
- def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
- def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
- def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
- def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */
- def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */
- def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
- def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
- def( source_loc, 9, 0, 0, u32x2) /* emitted in phase 1, removed in phase 3 */
- DEF( push_minus1, 1, 0, 1, none_int)
- DEF( push_0, 1, 0, 1, none_int)
- DEF( push_1, 1, 0, 1, none_int)
- DEF( push_2, 1, 0, 1, none_int)
- DEF( push_3, 1, 0, 1, none_int)
- DEF( push_4, 1, 0, 1, none_int)
- DEF( push_5, 1, 0, 1, none_int)
- DEF( push_6, 1, 0, 1, none_int)
- DEF( push_7, 1, 0, 1, none_int)
- DEF( push_i8, 2, 0, 1, i8)
- DEF( push_i16, 3, 0, 1, i16)
- DEF( push_const8, 2, 0, 1, const8)
- DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */
- DEF(push_empty_string, 1, 0, 1, none)
- DEF( get_loc8, 2, 0, 1, loc8)
- DEF( put_loc8, 2, 1, 0, loc8)
- DEF( set_loc8, 2, 1, 1, loc8)
- DEF( get_loc0_loc1, 1, 0, 2, none_loc)
- DEF( get_loc0, 1, 0, 1, none_loc)
- DEF( get_loc1, 1, 0, 1, none_loc)
- DEF( get_loc2, 1, 0, 1, none_loc)
- DEF( get_loc3, 1, 0, 1, none_loc)
- DEF( put_loc0, 1, 1, 0, none_loc)
- DEF( put_loc1, 1, 1, 0, none_loc)
- DEF( put_loc2, 1, 1, 0, none_loc)
- DEF( put_loc3, 1, 1, 0, none_loc)
- DEF( set_loc0, 1, 1, 1, none_loc)
- DEF( set_loc1, 1, 1, 1, none_loc)
- DEF( set_loc2, 1, 1, 1, none_loc)
- DEF( set_loc3, 1, 1, 1, none_loc)
- DEF( get_arg0, 1, 0, 1, none_arg)
- DEF( get_arg1, 1, 0, 1, none_arg)
- DEF( get_arg2, 1, 0, 1, none_arg)
- DEF( get_arg3, 1, 0, 1, none_arg)
- DEF( put_arg0, 1, 1, 0, none_arg)
- DEF( put_arg1, 1, 1, 0, none_arg)
- DEF( put_arg2, 1, 1, 0, none_arg)
- DEF( put_arg3, 1, 1, 0, none_arg)
- DEF( set_arg0, 1, 1, 1, none_arg)
- DEF( set_arg1, 1, 1, 1, none_arg)
- DEF( set_arg2, 1, 1, 1, none_arg)
- DEF( set_arg3, 1, 1, 1, none_arg)
- DEF( get_var_ref0, 1, 0, 1, none_var_ref)
- DEF( get_var_ref1, 1, 0, 1, none_var_ref)
- DEF( get_var_ref2, 1, 0, 1, none_var_ref)
- DEF( get_var_ref3, 1, 0, 1, none_var_ref)
- DEF( put_var_ref0, 1, 1, 0, none_var_ref)
- DEF( put_var_ref1, 1, 1, 0, none_var_ref)
- DEF( put_var_ref2, 1, 1, 0, none_var_ref)
- DEF( put_var_ref3, 1, 1, 0, none_var_ref)
- DEF( set_var_ref0, 1, 1, 1, none_var_ref)
- DEF( set_var_ref1, 1, 1, 1, none_var_ref)
- DEF( set_var_ref2, 1, 1, 1, none_var_ref)
- DEF( set_var_ref3, 1, 1, 1, none_var_ref)
- DEF( get_length, 1, 1, 1, none)
- DEF( if_false8, 2, 1, 0, label8)
- DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */
- DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */
- DEF( goto16, 3, 0, 0, label16)
- DEF( call0, 1, 1, 1, npopx)
- DEF( call1, 1, 1, 1, npopx)
- DEF( call2, 1, 1, 1, npopx)
- DEF( call3, 1, 1, 1, npopx)
- DEF( is_undefined, 1, 1, 1, none)
- DEF( is_null, 1, 1, 1, none)
- DEF(typeof_is_undefined, 1, 1, 1, none)
- DEF( typeof_is_function, 1, 1, 1, none)
- #undef DEF
- #undef def
- #endif /* DEF */
- #undef DEF
- #undef FMT
- } OPCodeFormat;
- typedef enum OPCodeEnum {
- #define FMT(f)
- #define DEF(id, size, n_pop, n_push, f) OP_ ## id,
- #define def(id, size, n_pop, n_push, f)
- /*
- * QuickJS opcode definitions
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- * Copyright (c) 2017-2018 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifdef FMT
- FMT(none)
- FMT(none_int)
- FMT(none_loc)
- FMT(none_arg)
- FMT(none_var_ref)
- FMT(u8)
- FMT(i8)
- FMT(loc8)
- FMT(const8)
- FMT(label8)
- FMT(u16)
- FMT(i16)
- FMT(label16)
- FMT(npop)
- FMT(npopx)
- FMT(npop_u16)
- FMT(loc)
- FMT(arg)
- FMT(var_ref)
- FMT(u32)
- FMT(u32x2)
- FMT(i32)
- FMT(const)
- FMT(label)
- FMT(atom)
- FMT(atom_u8)
- FMT(atom_u16)
- FMT(atom_label_u8)
- FMT(atom_label_u16)
- FMT(label_u16)
- #undef FMT
- #endif /* FMT */
- #ifdef DEF
- #ifndef def
- #define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f)
- #endif
- DEF(invalid, 1, 0, 0, none) /* never emitted */
- /* push values */
- DEF( push_i32, 5, 0, 1, i32)
- DEF( push_const, 5, 0, 1, const)
- DEF( fclosure, 5, 0, 1, const) /* must follow push_const */
- DEF(push_atom_value, 5, 0, 1, atom)
- DEF( private_symbol, 5, 0, 1, atom)
- DEF( undefined, 1, 0, 1, none)
- DEF( null, 1, 0, 1, none)
- DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */
- DEF( push_false, 1, 0, 1, none)
- DEF( push_true, 1, 0, 1, none)
- DEF( object, 1, 0, 1, none)
- DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */
- DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */
- DEF( drop, 1, 1, 0, none) /* a -> */
- DEF( nip, 1, 2, 1, none) /* a b -> b */
- DEF( nip1, 1, 3, 2, none) /* a b c -> b c */
- DEF( dup, 1, 1, 2, none) /* a -> a a */
- DEF( dup1, 1, 2, 3, none) /* a b -> a a b */
- DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */
- DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */
- DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */
- DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */
- DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */
- DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */
- DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */
- DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */
- DEF( swap, 1, 2, 2, none) /* a b -> b a */
- DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */
- DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */
- DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */
- DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */
- DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */
- DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */
- DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */
- DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */
- DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */
- DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */
- DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */
- DEF( apply, 3, 3, 1, u16)
- DEF( return, 1, 1, 0, none)
- DEF( return_undef, 1, 0, 0, none)
- DEF(check_ctor_return, 1, 1, 2, none)
- DEF( check_ctor, 1, 0, 0, none)
- DEF( init_ctor, 1, 0, 1, none)
- DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */
- DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */
- DEF( return_async, 1, 1, 0, none)
- DEF( throw, 1, 1, 0, none)
- DEF( throw_error, 6, 0, 0, atom_u8)
- DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
- DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
- DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
- bytecode string */
- DEF( get_super, 1, 1, 1, none)
- DEF( import, 1, 1, 1, none) /* dynamic module import */
- DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */
- DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */
- DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */
- DEF( put_var, 5, 1, 0, atom) /* must come after get_var */
- DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */
- DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */
- DEF( get_ref_value, 1, 2, 3, none)
- DEF( put_ref_value, 1, 3, 0, none)
- DEF( define_var, 6, 0, 0, atom_u8)
- DEF(check_define_var, 6, 0, 0, atom_u8)
- DEF( define_func, 6, 1, 0, atom_u8)
- // order matters, see IC counterparts
- DEF( get_field, 5, 1, 1, atom)
- DEF( get_field2, 5, 1, 2, atom)
- DEF( put_field, 5, 2, 0, atom)
- DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */
- DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */
- DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */
- DEF( get_array_el, 1, 2, 1, none)
- DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */
- DEF( put_array_el, 1, 3, 0, none)
- DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */
- DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */
- DEF( define_field, 5, 2, 1, atom)
- DEF( set_name, 5, 1, 1, atom)
- DEF(set_name_computed, 1, 2, 2, none)
- DEF( set_proto, 1, 2, 1, none)
- DEF(set_home_object, 1, 2, 2, none)
- DEF(define_array_el, 1, 3, 2, none)
- DEF( append, 1, 3, 2, none) /* append enumerated object, update length */
- DEF(copy_data_properties, 2, 3, 3, u8)
- DEF( define_method, 6, 2, 1, atom_u8)
- DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */
- DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */
- DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */
- DEF( get_loc, 3, 0, 1, loc)
- DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */
- DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */
- DEF( get_arg, 3, 0, 1, arg)
- DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */
- DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */
- DEF( get_var_ref, 3, 0, 1, var_ref)
- DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */
- DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */
- DEF(set_loc_uninitialized, 3, 0, 0, loc)
- DEF( get_loc_check, 3, 0, 1, loc)
- DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */
- DEF( put_loc_check_init, 3, 1, 0, loc)
- DEF(get_var_ref_check, 3, 0, 1, var_ref)
- DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */
- DEF(put_var_ref_check_init, 3, 1, 0, var_ref)
- DEF( close_loc, 3, 0, 0, loc)
- DEF( if_false, 5, 1, 0, label)
- DEF( if_true, 5, 1, 0, label) /* must come after if_false */
- DEF( goto, 5, 0, 0, label) /* must come after if_true */
- DEF( catch, 5, 0, 1, label)
- DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */
- DEF( ret, 1, 1, 0, none) /* used to return from the finally block */
- DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */
- DEF( to_object, 1, 1, 1, none)
- //DEF( to_string, 1, 1, 1, none)
- DEF( to_propkey, 1, 1, 1, none)
- DEF( to_propkey2, 1, 2, 2, none)
- DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF(with_get_ref_undef, 10, 1, 0, atom_label_u8)
- DEF( make_loc_ref, 7, 0, 2, atom_u16)
- DEF( make_arg_ref, 7, 0, 2, atom_u16)
- DEF(make_var_ref_ref, 7, 0, 2, atom_u16)
- DEF( make_var_ref, 5, 0, 2, atom)
- DEF( for_in_start, 1, 1, 1, none)
- DEF( for_of_start, 1, 1, 3, none)
- DEF(for_await_of_start, 1, 1, 3, none)
- DEF( for_in_next, 1, 1, 3, none)
- DEF( for_of_next, 2, 3, 5, u8)
- DEF(iterator_check_object, 1, 1, 1, none)
- DEF(iterator_get_value_done, 1, 1, 2, none)
- DEF( iterator_close, 1, 3, 0, none)
- DEF( iterator_next, 1, 4, 4, none)
- DEF( iterator_call, 2, 4, 5, u8)
- DEF( initial_yield, 1, 0, 0, none)
- DEF( yield, 1, 1, 2, none)
- DEF( yield_star, 1, 1, 2, none)
- DEF(async_yield_star, 1, 1, 2, none)
- DEF( await, 1, 1, 1, none)
- /* arithmetic/logic operations */
- DEF( neg, 1, 1, 1, none)
- DEF( plus, 1, 1, 1, none)
- DEF( dec, 1, 1, 1, none)
- DEF( inc, 1, 1, 1, none)
- DEF( post_dec, 1, 1, 2, none)
- DEF( post_inc, 1, 1, 2, none)
- DEF( dec_loc, 2, 0, 0, loc8)
- DEF( inc_loc, 2, 0, 0, loc8)
- DEF( add_loc, 2, 1, 0, loc8)
- DEF( not, 1, 1, 1, none)
- DEF( lnot, 1, 1, 1, none)
- DEF( typeof, 1, 1, 1, none)
- DEF( delete, 1, 2, 1, none)
- DEF( delete_var, 5, 0, 1, atom)
- /* warning: order matters (see js_parse_assign_expr) */
- DEF( mul, 1, 2, 1, none)
- DEF( div, 1, 2, 1, none)
- DEF( mod, 1, 2, 1, none)
- DEF( add, 1, 2, 1, none)
- DEF( sub, 1, 2, 1, none)
- DEF( shl, 1, 2, 1, none)
- DEF( sar, 1, 2, 1, none)
- DEF( shr, 1, 2, 1, none)
- DEF( and, 1, 2, 1, none)
- DEF( xor, 1, 2, 1, none)
- DEF( or, 1, 2, 1, none)
- DEF( pow, 1, 2, 1, none)
- DEF( lt, 1, 2, 1, none)
- DEF( lte, 1, 2, 1, none)
- DEF( gt, 1, 2, 1, none)
- DEF( gte, 1, 2, 1, none)
- DEF( instanceof, 1, 2, 1, none)
- DEF( in, 1, 2, 1, none)
- DEF( eq, 1, 2, 1, none)
- DEF( neq, 1, 2, 1, none)
- DEF( strict_eq, 1, 2, 1, none)
- DEF( strict_neq, 1, 2, 1, none)
- DEF(is_undefined_or_null, 1, 1, 1, none)
- DEF( private_in, 1, 2, 1, none)
- DEF(push_bigint_i32, 5, 0, 1, i32)
- /* must be the last non short and non temporary opcode */
- DEF( nop, 1, 0, 0, none)
- /* temporary opcodes: never emitted in the final bytecode */
- def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
- def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
- def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */
- def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
- def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
- def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
- def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */
- def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */
- def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
- def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
- def( source_loc, 9, 0, 0, u32x2) /* emitted in phase 1, removed in phase 3 */
- DEF( push_minus1, 1, 0, 1, none_int)
- DEF( push_0, 1, 0, 1, none_int)
- DEF( push_1, 1, 0, 1, none_int)
- DEF( push_2, 1, 0, 1, none_int)
- DEF( push_3, 1, 0, 1, none_int)
- DEF( push_4, 1, 0, 1, none_int)
- DEF( push_5, 1, 0, 1, none_int)
- DEF( push_6, 1, 0, 1, none_int)
- DEF( push_7, 1, 0, 1, none_int)
- DEF( push_i8, 2, 0, 1, i8)
- DEF( push_i16, 3, 0, 1, i16)
- DEF( push_const8, 2, 0, 1, const8)
- DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */
- DEF(push_empty_string, 1, 0, 1, none)
- DEF( get_loc8, 2, 0, 1, loc8)
- DEF( put_loc8, 2, 1, 0, loc8)
- DEF( set_loc8, 2, 1, 1, loc8)
- DEF( get_loc0_loc1, 1, 0, 2, none_loc)
- DEF( get_loc0, 1, 0, 1, none_loc)
- DEF( get_loc1, 1, 0, 1, none_loc)
- DEF( get_loc2, 1, 0, 1, none_loc)
- DEF( get_loc3, 1, 0, 1, none_loc)
- DEF( put_loc0, 1, 1, 0, none_loc)
- DEF( put_loc1, 1, 1, 0, none_loc)
- DEF( put_loc2, 1, 1, 0, none_loc)
- DEF( put_loc3, 1, 1, 0, none_loc)
- DEF( set_loc0, 1, 1, 1, none_loc)
- DEF( set_loc1, 1, 1, 1, none_loc)
- DEF( set_loc2, 1, 1, 1, none_loc)
- DEF( set_loc3, 1, 1, 1, none_loc)
- DEF( get_arg0, 1, 0, 1, none_arg)
- DEF( get_arg1, 1, 0, 1, none_arg)
- DEF( get_arg2, 1, 0, 1, none_arg)
- DEF( get_arg3, 1, 0, 1, none_arg)
- DEF( put_arg0, 1, 1, 0, none_arg)
- DEF( put_arg1, 1, 1, 0, none_arg)
- DEF( put_arg2, 1, 1, 0, none_arg)
- DEF( put_arg3, 1, 1, 0, none_arg)
- DEF( set_arg0, 1, 1, 1, none_arg)
- DEF( set_arg1, 1, 1, 1, none_arg)
- DEF( set_arg2, 1, 1, 1, none_arg)
- DEF( set_arg3, 1, 1, 1, none_arg)
- DEF( get_var_ref0, 1, 0, 1, none_var_ref)
- DEF( get_var_ref1, 1, 0, 1, none_var_ref)
- DEF( get_var_ref2, 1, 0, 1, none_var_ref)
- DEF( get_var_ref3, 1, 0, 1, none_var_ref)
- DEF( put_var_ref0, 1, 1, 0, none_var_ref)
- DEF( put_var_ref1, 1, 1, 0, none_var_ref)
- DEF( put_var_ref2, 1, 1, 0, none_var_ref)
- DEF( put_var_ref3, 1, 1, 0, none_var_ref)
- DEF( set_var_ref0, 1, 1, 1, none_var_ref)
- DEF( set_var_ref1, 1, 1, 1, none_var_ref)
- DEF( set_var_ref2, 1, 1, 1, none_var_ref)
- DEF( set_var_ref3, 1, 1, 1, none_var_ref)
- DEF( get_length, 1, 1, 1, none)
- DEF( if_false8, 2, 1, 0, label8)
- DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */
- DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */
- DEF( goto16, 3, 0, 0, label16)
- DEF( call0, 1, 1, 1, npopx)
- DEF( call1, 1, 1, 1, npopx)
- DEF( call2, 1, 1, 1, npopx)
- DEF( call3, 1, 1, 1, npopx)
- DEF( is_undefined, 1, 1, 1, none)
- DEF( is_null, 1, 1, 1, none)
- DEF(typeof_is_undefined, 1, 1, 1, none)
- DEF( typeof_is_function, 1, 1, 1, none)
- #undef DEF
- #undef def
- #endif /* DEF */
- #undef def
- #undef DEF
- #undef FMT
- OP_COUNT, /* excluding temporary opcodes */
- /* temporary opcodes : overlap with the short opcodes */
- OP_TEMP_START = OP_nop + 1,
- OP___dummy = OP_TEMP_START - 1,
- #define FMT(f)
- #define DEF(id, size, n_pop, n_push, f)
- #define def(id, size, n_pop, n_push, f) OP_ ## id,
- /*
- * QuickJS opcode definitions
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- * Copyright (c) 2017-2018 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifdef FMT
- FMT(none)
- FMT(none_int)
- FMT(none_loc)
- FMT(none_arg)
- FMT(none_var_ref)
- FMT(u8)
- FMT(i8)
- FMT(loc8)
- FMT(const8)
- FMT(label8)
- FMT(u16)
- FMT(i16)
- FMT(label16)
- FMT(npop)
- FMT(npopx)
- FMT(npop_u16)
- FMT(loc)
- FMT(arg)
- FMT(var_ref)
- FMT(u32)
- FMT(u32x2)
- FMT(i32)
- FMT(const)
- FMT(label)
- FMT(atom)
- FMT(atom_u8)
- FMT(atom_u16)
- FMT(atom_label_u8)
- FMT(atom_label_u16)
- FMT(label_u16)
- #undef FMT
- #endif /* FMT */
- #ifdef DEF
- #ifndef def
- #define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f)
- #endif
- DEF(invalid, 1, 0, 0, none) /* never emitted */
- /* push values */
- DEF( push_i32, 5, 0, 1, i32)
- DEF( push_const, 5, 0, 1, const)
- DEF( fclosure, 5, 0, 1, const) /* must follow push_const */
- DEF(push_atom_value, 5, 0, 1, atom)
- DEF( private_symbol, 5, 0, 1, atom)
- DEF( undefined, 1, 0, 1, none)
- DEF( null, 1, 0, 1, none)
- DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */
- DEF( push_false, 1, 0, 1, none)
- DEF( push_true, 1, 0, 1, none)
- DEF( object, 1, 0, 1, none)
- DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */
- DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */
- DEF( drop, 1, 1, 0, none) /* a -> */
- DEF( nip, 1, 2, 1, none) /* a b -> b */
- DEF( nip1, 1, 3, 2, none) /* a b c -> b c */
- DEF( dup, 1, 1, 2, none) /* a -> a a */
- DEF( dup1, 1, 2, 3, none) /* a b -> a a b */
- DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */
- DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */
- DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */
- DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */
- DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */
- DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */
- DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */
- DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */
- DEF( swap, 1, 2, 2, none) /* a b -> b a */
- DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */
- DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */
- DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */
- DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */
- DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */
- DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */
- DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */
- DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */
- DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */
- DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */
- DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */
- DEF( apply, 3, 3, 1, u16)
- DEF( return, 1, 1, 0, none)
- DEF( return_undef, 1, 0, 0, none)
- DEF(check_ctor_return, 1, 1, 2, none)
- DEF( check_ctor, 1, 0, 0, none)
- DEF( init_ctor, 1, 0, 1, none)
- DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */
- DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */
- DEF( return_async, 1, 1, 0, none)
- DEF( throw, 1, 1, 0, none)
- DEF( throw_error, 6, 0, 0, atom_u8)
- DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
- DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
- DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
- bytecode string */
- DEF( get_super, 1, 1, 1, none)
- DEF( import, 1, 1, 1, none) /* dynamic module import */
- DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */
- DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */
- DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */
- DEF( put_var, 5, 1, 0, atom) /* must come after get_var */
- DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */
- DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */
- DEF( get_ref_value, 1, 2, 3, none)
- DEF( put_ref_value, 1, 3, 0, none)
- DEF( define_var, 6, 0, 0, atom_u8)
- DEF(check_define_var, 6, 0, 0, atom_u8)
- DEF( define_func, 6, 1, 0, atom_u8)
- // order matters, see IC counterparts
- DEF( get_field, 5, 1, 1, atom)
- DEF( get_field2, 5, 1, 2, atom)
- DEF( put_field, 5, 2, 0, atom)
- DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */
- DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */
- DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */
- DEF( get_array_el, 1, 2, 1, none)
- DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */
- DEF( put_array_el, 1, 3, 0, none)
- DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */
- DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */
- DEF( define_field, 5, 2, 1, atom)
- DEF( set_name, 5, 1, 1, atom)
- DEF(set_name_computed, 1, 2, 2, none)
- DEF( set_proto, 1, 2, 1, none)
- DEF(set_home_object, 1, 2, 2, none)
- DEF(define_array_el, 1, 3, 2, none)
- DEF( append, 1, 3, 2, none) /* append enumerated object, update length */
- DEF(copy_data_properties, 2, 3, 3, u8)
- DEF( define_method, 6, 2, 1, atom_u8)
- DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */
- DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */
- DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */
- DEF( get_loc, 3, 0, 1, loc)
- DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */
- DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */
- DEF( get_arg, 3, 0, 1, arg)
- DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */
- DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */
- DEF( get_var_ref, 3, 0, 1, var_ref)
- DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */
- DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */
- DEF(set_loc_uninitialized, 3, 0, 0, loc)
- DEF( get_loc_check, 3, 0, 1, loc)
- DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */
- DEF( put_loc_check_init, 3, 1, 0, loc)
- DEF(get_var_ref_check, 3, 0, 1, var_ref)
- DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */
- DEF(put_var_ref_check_init, 3, 1, 0, var_ref)
- DEF( close_loc, 3, 0, 0, loc)
- DEF( if_false, 5, 1, 0, label)
- DEF( if_true, 5, 1, 0, label) /* must come after if_false */
- DEF( goto, 5, 0, 0, label) /* must come after if_true */
- DEF( catch, 5, 0, 1, label)
- DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */
- DEF( ret, 1, 1, 0, none) /* used to return from the finally block */
- DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */
- DEF( to_object, 1, 1, 1, none)
- //DEF( to_string, 1, 1, 1, none)
- DEF( to_propkey, 1, 1, 1, none)
- DEF( to_propkey2, 1, 2, 2, none)
- DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF(with_get_ref_undef, 10, 1, 0, atom_label_u8)
- DEF( make_loc_ref, 7, 0, 2, atom_u16)
- DEF( make_arg_ref, 7, 0, 2, atom_u16)
- DEF(make_var_ref_ref, 7, 0, 2, atom_u16)
- DEF( make_var_ref, 5, 0, 2, atom)
- DEF( for_in_start, 1, 1, 1, none)
- DEF( for_of_start, 1, 1, 3, none)
- DEF(for_await_of_start, 1, 1, 3, none)
- DEF( for_in_next, 1, 1, 3, none)
- DEF( for_of_next, 2, 3, 5, u8)
- DEF(iterator_check_object, 1, 1, 1, none)
- DEF(iterator_get_value_done, 1, 1, 2, none)
- DEF( iterator_close, 1, 3, 0, none)
- DEF( iterator_next, 1, 4, 4, none)
- DEF( iterator_call, 2, 4, 5, u8)
- DEF( initial_yield, 1, 0, 0, none)
- DEF( yield, 1, 1, 2, none)
- DEF( yield_star, 1, 1, 2, none)
- DEF(async_yield_star, 1, 1, 2, none)
- DEF( await, 1, 1, 1, none)
- /* arithmetic/logic operations */
- DEF( neg, 1, 1, 1, none)
- DEF( plus, 1, 1, 1, none)
- DEF( dec, 1, 1, 1, none)
- DEF( inc, 1, 1, 1, none)
- DEF( post_dec, 1, 1, 2, none)
- DEF( post_inc, 1, 1, 2, none)
- DEF( dec_loc, 2, 0, 0, loc8)
- DEF( inc_loc, 2, 0, 0, loc8)
- DEF( add_loc, 2, 1, 0, loc8)
- DEF( not, 1, 1, 1, none)
- DEF( lnot, 1, 1, 1, none)
- DEF( typeof, 1, 1, 1, none)
- DEF( delete, 1, 2, 1, none)
- DEF( delete_var, 5, 0, 1, atom)
- /* warning: order matters (see js_parse_assign_expr) */
- DEF( mul, 1, 2, 1, none)
- DEF( div, 1, 2, 1, none)
- DEF( mod, 1, 2, 1, none)
- DEF( add, 1, 2, 1, none)
- DEF( sub, 1, 2, 1, none)
- DEF( shl, 1, 2, 1, none)
- DEF( sar, 1, 2, 1, none)
- DEF( shr, 1, 2, 1, none)
- DEF( and, 1, 2, 1, none)
- DEF( xor, 1, 2, 1, none)
- DEF( or, 1, 2, 1, none)
- DEF( pow, 1, 2, 1, none)
- DEF( lt, 1, 2, 1, none)
- DEF( lte, 1, 2, 1, none)
- DEF( gt, 1, 2, 1, none)
- DEF( gte, 1, 2, 1, none)
- DEF( instanceof, 1, 2, 1, none)
- DEF( in, 1, 2, 1, none)
- DEF( eq, 1, 2, 1, none)
- DEF( neq, 1, 2, 1, none)
- DEF( strict_eq, 1, 2, 1, none)
- DEF( strict_neq, 1, 2, 1, none)
- DEF(is_undefined_or_null, 1, 1, 1, none)
- DEF( private_in, 1, 2, 1, none)
- DEF(push_bigint_i32, 5, 0, 1, i32)
- /* must be the last non short and non temporary opcode */
- DEF( nop, 1, 0, 0, none)
- /* temporary opcodes: never emitted in the final bytecode */
- def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
- def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
- def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */
- def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
- def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
- def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
- def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */
- def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */
- def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
- def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
- def( source_loc, 9, 0, 0, u32x2) /* emitted in phase 1, removed in phase 3 */
- DEF( push_minus1, 1, 0, 1, none_int)
- DEF( push_0, 1, 0, 1, none_int)
- DEF( push_1, 1, 0, 1, none_int)
- DEF( push_2, 1, 0, 1, none_int)
- DEF( push_3, 1, 0, 1, none_int)
- DEF( push_4, 1, 0, 1, none_int)
- DEF( push_5, 1, 0, 1, none_int)
- DEF( push_6, 1, 0, 1, none_int)
- DEF( push_7, 1, 0, 1, none_int)
- DEF( push_i8, 2, 0, 1, i8)
- DEF( push_i16, 3, 0, 1, i16)
- DEF( push_const8, 2, 0, 1, const8)
- DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */
- DEF(push_empty_string, 1, 0, 1, none)
- DEF( get_loc8, 2, 0, 1, loc8)
- DEF( put_loc8, 2, 1, 0, loc8)
- DEF( set_loc8, 2, 1, 1, loc8)
- DEF( get_loc0_loc1, 1, 0, 2, none_loc)
- DEF( get_loc0, 1, 0, 1, none_loc)
- DEF( get_loc1, 1, 0, 1, none_loc)
- DEF( get_loc2, 1, 0, 1, none_loc)
- DEF( get_loc3, 1, 0, 1, none_loc)
- DEF( put_loc0, 1, 1, 0, none_loc)
- DEF( put_loc1, 1, 1, 0, none_loc)
- DEF( put_loc2, 1, 1, 0, none_loc)
- DEF( put_loc3, 1, 1, 0, none_loc)
- DEF( set_loc0, 1, 1, 1, none_loc)
- DEF( set_loc1, 1, 1, 1, none_loc)
- DEF( set_loc2, 1, 1, 1, none_loc)
- DEF( set_loc3, 1, 1, 1, none_loc)
- DEF( get_arg0, 1, 0, 1, none_arg)
- DEF( get_arg1, 1, 0, 1, none_arg)
- DEF( get_arg2, 1, 0, 1, none_arg)
- DEF( get_arg3, 1, 0, 1, none_arg)
- DEF( put_arg0, 1, 1, 0, none_arg)
- DEF( put_arg1, 1, 1, 0, none_arg)
- DEF( put_arg2, 1, 1, 0, none_arg)
- DEF( put_arg3, 1, 1, 0, none_arg)
- DEF( set_arg0, 1, 1, 1, none_arg)
- DEF( set_arg1, 1, 1, 1, none_arg)
- DEF( set_arg2, 1, 1, 1, none_arg)
- DEF( set_arg3, 1, 1, 1, none_arg)
- DEF( get_var_ref0, 1, 0, 1, none_var_ref)
- DEF( get_var_ref1, 1, 0, 1, none_var_ref)
- DEF( get_var_ref2, 1, 0, 1, none_var_ref)
- DEF( get_var_ref3, 1, 0, 1, none_var_ref)
- DEF( put_var_ref0, 1, 1, 0, none_var_ref)
- DEF( put_var_ref1, 1, 1, 0, none_var_ref)
- DEF( put_var_ref2, 1, 1, 0, none_var_ref)
- DEF( put_var_ref3, 1, 1, 0, none_var_ref)
- DEF( set_var_ref0, 1, 1, 1, none_var_ref)
- DEF( set_var_ref1, 1, 1, 1, none_var_ref)
- DEF( set_var_ref2, 1, 1, 1, none_var_ref)
- DEF( set_var_ref3, 1, 1, 1, none_var_ref)
- DEF( get_length, 1, 1, 1, none)
- DEF( if_false8, 2, 1, 0, label8)
- DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */
- DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */
- DEF( goto16, 3, 0, 0, label16)
- DEF( call0, 1, 1, 1, npopx)
- DEF( call1, 1, 1, 1, npopx)
- DEF( call2, 1, 1, 1, npopx)
- DEF( call3, 1, 1, 1, npopx)
- DEF( is_undefined, 1, 1, 1, none)
- DEF( is_null, 1, 1, 1, none)
- DEF(typeof_is_undefined, 1, 1, 1, none)
- DEF( typeof_is_function, 1, 1, 1, none)
- #undef DEF
- #undef def
- #endif /* DEF */
- #undef def
- #undef DEF
- #undef FMT
- OP_TEMP_END,
- } OPCodeEnum;
- static int JS_InitAtoms(JSRuntime *rt);
- static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
- int atom_type);
- static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p);
- static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b);
- static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_obj,
- int argc, JSValueConst *argv, int flags);
- static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_obj,
- int argc, JSValueConst *argv, int flags);
- static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_obj, JSValueConst new_target,
- int argc, JSValueConst *argv, int flags);
- static JSValue JS_CallConstructorInternal(JSContext *ctx,
- JSValueConst func_obj,
- JSValueConst new_target,
- int argc, JSValueConst *argv, int flags);
- static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
- int argc, JSValueConst *argv);
- static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
- int argc, JSValueConst *argv);
- static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
- JSValue val, bool is_array_ctor);
- static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
- JSValueConst val, int flags, int scope_idx);
- static __maybe_unused void JS_DumpString(JSRuntime *rt, JSString *p);
- static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
- static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
- static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
- static __maybe_unused void JS_DumpValue(JSRuntime *rt, JSValueConst val);
- static __maybe_unused void JS_DumpAtoms(JSRuntime *rt);
- static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
- static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic);
- static void js_array_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_array_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_object_data_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_c_function_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_bytecode_function_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_bound_function_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_regexp_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_array_buffer_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_typed_array_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_proxy_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_map_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_map_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_map_iterator_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_array_iterator_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_iterator_concat_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_iterator_concat_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_iterator_helper_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_iterator_helper_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_iterator_wrap_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_iterator_wrap_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_regexp_string_iterator_finalizer(JSRuntime *rt,
- JSValueConst val);
- static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_generator_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_generator_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_promise_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_promise_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- #define HINT_STRING 0
- #define HINT_NUMBER 1
- #define HINT_NONE 2
- #define HINT_FORCE_ORDINARY (1 << 4) // don't try Symbol.toPrimitive
- static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint);
- static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
- static int JS_ToBoolFree(JSContext *ctx, JSValue val);
- static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
- static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val);
- static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val);
- static JSValue JS_ToPropertyKeyInternal(JSContext *ctx, JSValueConst val,
- int flags);
- static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len);
- static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
- JSValueConst flags);
- static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
- JSValue pattern, JSValue bc);
- static void gc_decref(JSRuntime *rt);
- static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
- const JSClassDef *class_def, JSAtom name);
- static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int unshift);
- static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv);
- static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv, int magic);
- static JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic);
- typedef enum JSStrictEqModeEnum {
- JS_EQ_STRICT,
- JS_EQ_SAME_VALUE,
- JS_EQ_SAME_VALUE_ZERO,
- } JSStrictEqModeEnum;
- static bool js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
- JSStrictEqModeEnum eq_mode);
- static bool js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2);
- static bool js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2);
- static bool js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
- static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val);
- static JSProperty *add_property(JSContext *ctx,
- JSObject *p, JSAtom prop, int prop_flags);
- static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
- static JSValue JS_ThrowStackOverflow(JSContext *ctx);
- static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
- static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj);
- static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
- JSValueConst proto_val, bool throw_flag);
- static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj);
- static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj);
- static int js_proxy_isArray(JSContext *ctx, JSValueConst obj);
- static int JS_CreateProperty(JSContext *ctx, JSObject *p,
- JSAtom prop, JSValueConst val,
- JSValueConst getter, JSValueConst setter,
- int flags);
- static int js_string_memcmp(JSString *p1, JSString *p2, int len);
- static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref);
- static bool is_valid_weakref_target(JSValueConst val);
- static void insert_weakref_record(JSValueConst target,
- struct JSWeakRefRecord *wr);
- static JSValue js_array_buffer_constructor3(JSContext *ctx,
- JSValueConst new_target,
- uint64_t len, uint64_t *max_len,
- JSClassID class_id,
- uint8_t *buf,
- JSFreeArrayBufferDataFunc *free_func,
- void *opaque, bool alloc_flag);
- static void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr);
- static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj);
- static bool array_buffer_is_resizable(const JSArrayBuffer *abuf);
- static JSValue js_typed_array_constructor(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv,
- int classid);
- static JSValue js_typed_array_constructor_ta(JSContext *ctx,
- JSValueConst new_target,
- JSValueConst src_obj,
- int classid, uint32_t len);
- static bool is_typed_array(JSClassID class_id);
- static bool typed_array_is_oob(JSObject *p);
- static uint32_t typed_array_length(JSObject *p);
- static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx);
- static JSValue JS_ThrowTypeErrorArrayBufferOOB(JSContext *ctx);
- static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,
- bool is_arg);
- static JSValue js_call_generator_function(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_obj,
- int argc, JSValueConst *argv,
- int flags);
- static void js_async_function_resolve_finalizer(JSRuntime *rt,
- JSValueConst val);
- static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
- const char *filename, int line, int flags, int scope_idx);
- static void js_free_module_def(JSContext *ctx, JSModuleDef *m);
- static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
- JS_MarkFunc *mark_func);
- static JSValue js_import_meta(JSContext *ctx);
- static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier);
- static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
- static JSValue js_new_promise_capability(JSContext *ctx,
- JSValue *resolving_funcs,
- JSValueConst ctor);
- static __exception int perform_promise_then(JSContext *ctx,
- JSValueConst promise,
- JSValueConst *resolve_reject,
- JSValueConst *cap_resolving_funcs);
- static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic);
- static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv);
- static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
- int argc, JSValueConst *argv);
- static bool js_string_eq(JSString *p1, JSString *p2);
- static int js_string_compare(JSString *p1, JSString *p2);
- static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
- JSValue prop, JSValue val, int flags);
- static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val);
- static bool JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val);
- static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val);
- static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
- JSObject *p, JSAtom prop);
- static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc);
- static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
- JS_MarkFunc *mark_func);
- static void JS_AddIntrinsicBasicObjects(JSContext *ctx);
- static void js_free_shape(JSRuntime *rt, JSShape *sh);
- static void js_free_shape_null(JSRuntime *rt, JSShape *sh);
- static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
- JSShapeProperty **pprs);
- static int init_shape_hash(JSRuntime *rt);
- static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
- JSValueConst obj);
- static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
- JSValueConst obj);
- static __exception int js_set_length64(JSContext *ctx, JSValueConst obj,
- int64_t len);
- static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len);
- static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
- JSValueConst array_arg);
- static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab);
- static bool js_get_fast_array(JSContext *ctx, JSValue obj,
- JSValue **arrpp, uint32_t *countp);
- static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len);
- static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
- JSValue sync_iter);
- static void js_c_function_data_finalizer(JSRuntime *rt, JSValueConst val);
- static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static JSValue js_call_c_function_data(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_val,
- int argc, JSValueConst *argv, int flags);
- static JSAtom js_symbol_to_atom(JSContext *ctx, JSValueConst val);
- static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
- JSGCObjectTypeEnum type);
- static void remove_gc_object(JSGCObjectHeader *h);
- static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s);
- static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
- static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
- void *opaque);
- static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
- JSAtom atom, void *opaque);
- static void js_set_uncatchable_error(JSContext *ctx, JSValueConst val,
- bool flag);
- static JSValue js_new_callsite(JSContext *ctx, JSCallSiteData *csd);
- static void js_new_callsite_data(JSContext *ctx, JSCallSiteData *csd, JSStackFrame *sf);
- static void js_new_callsite_data2(JSContext *ctx, JSCallSiteData *csd, const char *filename, int line_num, int col_num);
- static void _JS_AddIntrinsicCallSite(JSContext *ctx);
- static void JS_SetOpaqueInternal(JSValueConst obj, void *opaque);
- static const JSClassExoticMethods js_arguments_exotic_methods;
- static const JSClassExoticMethods js_string_exotic_methods;
- static const JSClassExoticMethods js_proxy_exotic_methods;
- static const JSClassExoticMethods js_module_ns_exotic_methods;
- static inline bool double_is_int32(double d)
- {
- uint64_t u, e;
- JSFloat64Union t;
- t.d = d;
- u = t.u64;
- e = ((u >> 52) & 0x7FF) - 1023;
- if (e > 30) {
- // accept 0, INT32_MIN, reject too large, too small, nan, inf, -0
- return !u || (u == 0xc1e0000000000000);
- } else {
- // shift out sign, exponent and whole part bits
- // value is fractional if remaining low bits are non-zero
- return !(u << 12 << e);
- }
- }
- static JSValue js_float64(double d)
- {
- return __JS_NewFloat64(d);
- }
- static int compare_u32(uint32_t a, uint32_t b)
- {
- return -(a < b) + (b < a); // -1, 0 or 1
- }
- static JSValue js_int32(int32_t v)
- {
- return JS_MKVAL(JS_TAG_INT, v);
- }
- static JSValue js_uint32(uint32_t v)
- {
- if (v <= INT32_MAX)
- return js_int32(v);
- else
- return js_float64(v);
- }
- static JSValue js_int64(int64_t v)
- {
- if (v >= INT32_MIN && v <= INT32_MAX)
- return js_int32(v);
- else
- return js_float64(v);
- }
- static JSValue js_number(double d)
- {
- if (double_is_int32(d))
- return js_int32((int32_t)d);
- else
- return js_float64(d);
- }
- JSValue JS_NewNumber(JSContext *ctx, double d)
- {
- return js_number(d);
- }
- static JSValue js_bool(bool v)
- {
- return JS_MKVAL(JS_TAG_BOOL, (v != 0));
- }
- static JSValue js_dup(JSValueConst v)
- {
- if (JS_VALUE_HAS_REF_COUNT(v)) {
- JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
- p->ref_count++;
- }
- return unsafe_unconst(v);
- }
- JSValue JS_DupValue(JSContext *ctx, JSValueConst v)
- {
- return js_dup(v);
- }
- JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)
- {
- return js_dup(v);
- }
- static void js_trigger_gc(JSRuntime *rt, size_t size)
- {
- bool force_gc;
- #ifdef FORCE_GC_AT_MALLOC
- force_gc = true;
- #else
- force_gc = ((rt->malloc_state.malloc_size + size) >
- rt->malloc_gc_threshold);
- #endif
- if (force_gc) {
- #ifdef ENABLE_DUMPS // JS_DUMP_GC
- if (check_dump_flag(rt, JS_DUMP_GC)) {
- printf("GC: size=%zd\n", rt->malloc_state.malloc_size);
- }
- #endif
- JS_RunGC(rt);
- rt->malloc_gc_threshold = rt->malloc_state.malloc_size +
- (rt->malloc_state.malloc_size >> 1);
- }
- }
- static size_t js_malloc_usable_size_unknown(const void *ptr)
- {
- return 0;
- }
- void *js_calloc_rt(JSRuntime *rt, size_t count, size_t size)
- {
- void *ptr;
- JSMallocState *s;
- /* Do not allocate zero bytes: behavior is platform dependent */
- assert(count != 0 && size != 0);
- if (size > 0)
- if (unlikely(count != (count * size) / size))
- return NULL;
- s = &rt->malloc_state;
- /* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
- if (unlikely(s->malloc_size + (count * size) > s->malloc_limit - 1))
- return NULL;
- ptr = rt->mf.js_calloc(s->opaque, count, size);
- if (!ptr)
- return NULL;
- s->malloc_count++;
- s->malloc_size += rt->mf.js_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
- return ptr;
- }
- void *js_malloc_rt(JSRuntime *rt, size_t size)
- {
- void *ptr;
- JSMallocState *s;
- /* Do not allocate zero bytes: behavior is platform dependent */
- assert(size != 0);
- s = &rt->malloc_state;
- /* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
- if (unlikely(s->malloc_size + size > s->malloc_limit - 1))
- return NULL;
- ptr = rt->mf.js_malloc(s->opaque, size);
- if (!ptr)
- return NULL;
- s->malloc_count++;
- s->malloc_size += rt->mf.js_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
- return ptr;
- }
- void js_free_rt(JSRuntime *rt, void *ptr)
- {
- JSMallocState *s;
- if (!ptr)
- return;
- s = &rt->malloc_state;
- s->malloc_count--;
- s->malloc_size -= rt->mf.js_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
- rt->mf.js_free(s->opaque, ptr);
- }
- void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size)
- {
- size_t old_size;
- JSMallocState *s;
- if (!ptr) {
- if (size == 0)
- return NULL;
- return js_malloc_rt(rt, size);
- }
- if (unlikely(size == 0)) {
- js_free_rt(rt, ptr);
- return NULL;
- }
- old_size = rt->mf.js_malloc_usable_size(ptr);
- s = &rt->malloc_state;
- /* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
- if (s->malloc_size + size - old_size > s->malloc_limit - 1)
- return NULL;
- ptr = rt->mf.js_realloc(s->opaque, ptr, size);
- if (!ptr)
- return NULL;
- s->malloc_size += rt->mf.js_malloc_usable_size(ptr) - old_size;
- return ptr;
- }
- size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr)
- {
- return rt->mf.js_malloc_usable_size(ptr);
- }
- /**
- * This used to be implemented as malloc + memset, but using calloc
- * yields better performance in initial, bursty allocations, something useful
- * for QuickJS.
- *
- * More information: https://github.com/quickjs-ng/quickjs/pull/519
- */
- void *js_mallocz_rt(JSRuntime *rt, size_t size)
- {
- return js_calloc_rt(rt, 1, size);
- }
- /* Throw out of memory in case of error */
- void *js_calloc(JSContext *ctx, size_t count, size_t size)
- {
- void *ptr;
- ptr = js_calloc_rt(ctx->rt, count, size);
- if (unlikely(!ptr)) {
- JS_ThrowOutOfMemory(ctx);
- return NULL;
- }
- return ptr;
- }
- /* Throw out of memory in case of error */
- void *js_malloc(JSContext *ctx, size_t size)
- {
- void *ptr;
- ptr = js_malloc_rt(ctx->rt, size);
- if (unlikely(!ptr)) {
- JS_ThrowOutOfMemory(ctx);
- return NULL;
- }
- return ptr;
- }
- /* Throw out of memory in case of error */
- void *js_mallocz(JSContext *ctx, size_t size)
- {
- void *ptr;
- ptr = js_mallocz_rt(ctx->rt, size);
- if (unlikely(!ptr)) {
- JS_ThrowOutOfMemory(ctx);
- return NULL;
- }
- return ptr;
- }
- void js_free(JSContext *ctx, void *ptr)
- {
- js_free_rt(ctx->rt, ptr);
- }
- /* Throw out of memory in case of error */
- void *js_realloc(JSContext *ctx, void *ptr, size_t size)
- {
- void *ret;
- ret = js_realloc_rt(ctx->rt, ptr, size);
- if (unlikely(!ret && size != 0)) {
- JS_ThrowOutOfMemory(ctx);
- return NULL;
- }
- return ret;
- }
- /* store extra allocated size in *pslack if successful */
- void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack)
- {
- void *ret;
- ret = js_realloc_rt(ctx->rt, ptr, size);
- if (unlikely(!ret && size != 0)) {
- JS_ThrowOutOfMemory(ctx);
- return NULL;
- }
- if (pslack) {
- size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret);
- *pslack = (new_size > size) ? new_size - size : 0;
- }
- return ret;
- }
- size_t js_malloc_usable_size(JSContext *ctx, const void *ptr)
- {
- return js_malloc_usable_size_rt(ctx->rt, ptr);
- }
- /* Throw out of memory exception in case of error */
- char *js_strndup(JSContext *ctx, const char *s, size_t n)
- {
- char *ptr;
- ptr = js_malloc(ctx, n + 1);
- if (ptr) {
- memcpy(ptr, s, n);
- ptr[n] = '\0';
- }
- return ptr;
- }
- char *js_strdup(JSContext *ctx, const char *str)
- {
- return js_strndup(ctx, str, strlen(str));
- }
- static no_inline int js_realloc_array(JSContext *ctx, void **parray,
- int elem_size, int *psize, int req_size)
- {
- int new_size;
- size_t slack;
- void *new_array;
- /* XXX: potential arithmetic overflow */
- new_size = max_int(req_size, *psize * 3 / 2);
- new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack);
- if (!new_array)
- return -1;
- new_size += slack / elem_size;
- *psize = new_size;
- *parray = new_array;
- return 0;
- }
- /* resize the array and update its size if req_size > *psize */
- static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size,
- int *psize, int req_size)
- {
- if (unlikely(req_size > *psize))
- return js_realloc_array(ctx, parray, elem_size, psize, req_size);
- else
- return 0;
- }
- static void *js_dbuf_realloc(void *ctx, void *ptr, size_t size)
- {
- return js_realloc(ctx, ptr, size);
- }
- static inline void js_dbuf_init(JSContext *ctx, DynBuf *s)
- {
- dbuf_init2(s, ctx, js_dbuf_realloc);
- }
- static inline int is_digit(int c) {
- return c >= '0' && c <= '9';
- }
- static inline int string_get(JSString *p, int idx) {
- return p->is_wide_char ? str16(p)[idx] : str8(p)[idx];
- }
- typedef struct JSClassShortDef {
- JSAtom class_name;
- JSClassFinalizer *finalizer;
- JSClassGCMark *gc_mark;
- } JSClassShortDef;
- static JSClassShortDef const js_std_class_def[] = {
- { JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_OBJECT */
- { JS_ATOM_Array, js_array_finalizer, js_array_mark }, /* JS_CLASS_ARRAY */
- { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */
- { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */
- { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */
- { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */
- { JS_ATOM_Symbol, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_SYMBOL */
- { JS_ATOM_Arguments, js_array_finalizer, js_array_mark }, /* JS_CLASS_ARGUMENTS */
- { JS_ATOM_Arguments, NULL, NULL }, /* JS_CLASS_MAPPED_ARGUMENTS */
- { JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_DATE */
- { JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_MODULE_NS */
- { JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */
- { JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */
- { JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */
- { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */
- { JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_GENERATOR_FUNCTION */
- { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark }, /* JS_CLASS_FOR_IN_ITERATOR */
- { JS_ATOM_RegExp, js_regexp_finalizer, NULL }, /* JS_CLASS_REGEXP */
- { JS_ATOM_ArrayBuffer, js_array_buffer_finalizer, NULL }, /* JS_CLASS_ARRAY_BUFFER */
- { JS_ATOM_SharedArrayBuffer, js_array_buffer_finalizer, NULL }, /* JS_CLASS_SHARED_ARRAY_BUFFER */
- { JS_ATOM_Uint8ClampedArray, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8C_ARRAY */
- { JS_ATOM_Int8Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT8_ARRAY */
- { JS_ATOM_Uint8Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8_ARRAY */
- { JS_ATOM_Int16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT16_ARRAY */
- { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT16_ARRAY */
- { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT32_ARRAY */
- { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT32_ARRAY */
- { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_INT64_ARRAY */
- { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_UINT64_ARRAY */
- { JS_ATOM_Float16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT16_ARRAY */
- { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT32_ARRAY */
- { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT64_ARRAY */
- { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_DATAVIEW */
- { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_INT */
- { JS_ATOM_Map, js_map_finalizer, js_map_mark }, /* JS_CLASS_MAP */
- { JS_ATOM_Set, js_map_finalizer, js_map_mark }, /* JS_CLASS_SET */
- { JS_ATOM_WeakMap, js_map_finalizer, NULL }, /* JS_CLASS_WEAKMAP */
- { JS_ATOM_WeakSet, js_map_finalizer, NULL }, /* JS_CLASS_WEAKSET */
- { JS_ATOM_Iterator, NULL, NULL }, /* JS_CLASS_ITERATOR */
- { JS_ATOM_IteratorConcat, js_iterator_concat_finalizer, js_iterator_concat_mark }, /* JS_CLASS_ITERATOR_CONCAT */
- { JS_ATOM_IteratorHelper, js_iterator_helper_finalizer, js_iterator_helper_mark }, /* JS_CLASS_ITERATOR_HELPER */
- { JS_ATOM_IteratorWrap, js_iterator_wrap_finalizer, js_iterator_wrap_mark }, /* JS_CLASS_ITERATOR_WRAP */
- { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */
- { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */
- { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */
- { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */
- { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */
- { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */
- };
- static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,
- int start, int count)
- {
- JSClassDef cm_s, *cm = &cm_s;
- int i, class_id;
- for(i = 0; i < count; i++) {
- class_id = i + start;
- memset(cm, 0, sizeof(*cm));
- cm->finalizer = tab[i].finalizer;
- cm->gc_mark = tab[i].gc_mark;
- if (JS_NewClass1(rt, class_id, cm, tab[i].class_name) < 0)
- return -1;
- }
- return 0;
- }
- /* Uses code from LLVM project. */
- static inline uintptr_t js_get_stack_pointer(void)
- {
- #if defined(__clang__) || defined(__GNUC__)
- return (uintptr_t)__builtin_frame_address(0);
- #elif defined(_MSC_VER)
- return (uintptr_t)_AddressOfReturnAddress();
- #else
- char CharOnStack = 0;
- // The volatile store here is intended to escape the local variable, to
- // prevent the compiler from optimizing CharOnStack into anything other
- // than a char on the stack.
- //
- // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19.
- char *volatile Ptr = &CharOnStack;
- return (uintptr_t) Ptr;
- #endif
- }
- static inline bool js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
- {
- uintptr_t sp;
- sp = js_get_stack_pointer() - alloca_size;
- return unlikely(sp < rt->stack_limit);
- }
- JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
- {
- JSRuntime *rt;
- JSMallocState ms;
- memset(&ms, 0, sizeof(ms));
- ms.opaque = opaque;
- ms.malloc_limit = 0;
- rt = mf->js_calloc(opaque, 1, sizeof(JSRuntime));
- if (!rt)
- return NULL;
- rt->mf = *mf;
- if (!rt->mf.js_malloc_usable_size) {
- /* use dummy function if none provided */
- rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown;
- }
- /* Inline what js_malloc_rt does since we cannot use it here. */
- ms.malloc_count++;
- ms.malloc_size += rt->mf.js_malloc_usable_size(rt) + MALLOC_OVERHEAD;
- rt->malloc_state = ms;
- rt->malloc_gc_threshold = 256 * 1024;
- init_list_head(&rt->context_list);
- init_list_head(&rt->gc_obj_list);
- init_list_head(&rt->gc_zero_ref_count_list);
- rt->gc_phase = JS_GC_PHASE_NONE;
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- init_list_head(&rt->string_list);
- #endif
- init_list_head(&rt->job_list);
- if (JS_InitAtoms(rt))
- goto fail;
- /* create the object, array and function classes */
- if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT,
- countof(js_std_class_def)) < 0)
- goto fail;
- rt->class_array[JS_CLASS_ARGUMENTS].exotic = &js_arguments_exotic_methods;
- rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods;
- rt->class_array[JS_CLASS_MODULE_NS].exotic = &js_module_ns_exotic_methods;
- rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function;
- rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_call_c_function_data;
- rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function;
- rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_call_generator_function;
- if (init_shape_hash(rt))
- goto fail;
- rt->js_class_id_alloc = JS_CLASS_INIT_COUNT;
- rt->stack_size = JS_DEFAULT_STACK_SIZE;
- #ifdef __wasi__
- rt->stack_size = 0;
- #endif
- JS_UpdateStackTop(rt);
- rt->current_exception = JS_UNINITIALIZED;
- return rt;
- fail:
- JS_FreeRuntime(rt);
- return NULL;
- }
- void *JS_GetRuntimeOpaque(JSRuntime *rt)
- {
- return rt->user_opaque;
- }
- void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)
- {
- rt->user_opaque = opaque;
- }
- int JS_AddRuntimeFinalizer(JSRuntime *rt, JSRuntimeFinalizer *finalizer,
- void *arg)
- {
- JSRuntimeFinalizerState *fs = js_malloc_rt(rt, sizeof(*fs));
- if (!fs)
- return -1;
- fs->next = rt->finalizers;
- fs->finalizer = finalizer;
- fs->arg = arg;
- rt->finalizers = fs;
- return 0;
- }
- static void *js_def_calloc(void *opaque, size_t count, size_t size)
- {
- return calloc(count, size);
- }
- static void *js_def_malloc(void *opaque, size_t size)
- {
- return malloc(size);
- }
- static void js_def_free(void *opaque, void *ptr)
- {
- free(ptr);
- }
- static void *js_def_realloc(void *opaque, void *ptr, size_t size)
- {
- return realloc(ptr, size);
- }
- static const JSMallocFunctions def_malloc_funcs = {
- js_def_calloc,
- js_def_malloc,
- js_def_free,
- js_def_realloc,
- js__malloc_usable_size
- };
- JSRuntime *JS_NewRuntime(void)
- {
- return JS_NewRuntime2(&def_malloc_funcs, NULL);
- }
- void JS_SetMemoryLimit(JSRuntime *rt, size_t limit)
- {
- rt->malloc_state.malloc_limit = limit;
- }
- void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags)
- {
- #ifdef ENABLE_DUMPS
- rt->dump_flags = flags;
- #endif
- }
- uint64_t JS_GetDumpFlags(JSRuntime *rt)
- {
- #ifdef ENABLE_DUMPS
- return rt->dump_flags;
- #else
- return 0;
- #endif
- }
- size_t JS_GetGCThreshold(JSRuntime *rt) {
- return rt->malloc_gc_threshold;
- }
- /* use -1 to disable automatic GC */
- void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold)
- {
- rt->malloc_gc_threshold = gc_threshold;
- }
- #define malloc(s) malloc_is_forbidden(s)
- #define free(p) free_is_forbidden(p)
- #define realloc(p,s) realloc_is_forbidden(p,s)
- void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque)
- {
- rt->interrupt_handler = cb;
- rt->interrupt_opaque = opaque;
- }
- void JS_SetCanBlock(JSRuntime *rt, bool can_block)
- {
- rt->can_block = can_block;
- }
- void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
- const JSSharedArrayBufferFunctions *sf)
- {
- rt->sab_funcs = *sf;
- }
- /* return 0 if OK, < 0 if exception */
- int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = ctx->rt;
- JSJobEntry *e;
- int i;
- assert(!rt->in_free);
- e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue));
- if (!e)
- return -1;
- e->ctx = ctx;
- e->job_func = job_func;
- e->argc = argc;
- for(i = 0; i < argc; i++) {
- e->argv[i] = js_dup(argv[i]);
- }
- list_add_tail(&e->link, &rt->job_list);
- return 0;
- }
- bool JS_IsJobPending(JSRuntime *rt)
- {
- return !list_empty(&rt->job_list);
- }
- /* return < 0 if exception, 0 if no job pending, 1 if a job was
- executed successfully. the context of the job is stored in '*pctx' */
- int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx)
- {
- JSContext *ctx;
- JSJobEntry *e;
- JSValue res;
- int i, ret;
- if (list_empty(&rt->job_list)) {
- *pctx = NULL;
- return 0;
- }
- /* get the first pending job and execute it */
- e = list_entry(rt->job_list.next, JSJobEntry, link);
- list_del(&e->link);
- ctx = e->ctx;
- res = e->job_func(e->ctx, e->argc, vc(e->argv));
- for(i = 0; i < e->argc; i++)
- JS_FreeValue(ctx, e->argv[i]);
- if (JS_IsException(res))
- ret = -1;
- else
- ret = 1;
- JS_FreeValue(ctx, res);
- js_free(ctx, e);
- *pctx = ctx;
- return ret;
- }
- static inline uint32_t atom_get_free(const JSAtomStruct *p)
- {
- return (uintptr_t)p >> 1;
- }
- static inline bool atom_is_free(const JSAtomStruct *p)
- {
- return (uintptr_t)p & 1;
- }
- static inline JSAtomStruct *atom_set_free(uint32_t v)
- {
- return (JSAtomStruct *)(((uintptr_t)v << 1) | 1);
- }
- /* Note: the string contents are uninitialized */
- static JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char)
- {
- JSString *str;
- str = js_malloc_rt(rt, sizeof(JSString) + (max_len << is_wide_char) + 1 - is_wide_char);
- if (unlikely(!str))
- return NULL;
- str->header.ref_count = 1;
- str->is_wide_char = is_wide_char;
- str->len = max_len;
- str->kind = JS_STRING_KIND_NORMAL;
- str->atom_type = 0;
- str->hash = 0; /* optional but costless */
- str->hash_next = 0; /* optional */
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- list_add_tail(&str->link, &rt->string_list);
- #endif
- return str;
- }
- static JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char)
- {
- JSString *p;
- p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char);
- if (unlikely(!p)) {
- JS_ThrowOutOfMemory(ctx);
- return NULL;
- }
- return p;
- }
- static inline void js_free_string0(JSRuntime *rt, JSString *str);
- /* same as JS_FreeValueRT() but faster */
- static inline void js_free_string(JSRuntime *rt, JSString *str)
- {
- if (--str->header.ref_count <= 0)
- js_free_string0(rt, str);
- }
- static inline void js_free_string0(JSRuntime *rt, JSString *str)
- {
- if (str->atom_type) {
- JS_FreeAtomStruct(rt, str);
- } else {
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- list_del(&str->link);
- #endif
- if (str->kind == JS_STRING_KIND_SLICE) {
- JSStringSlice *slice = (void *)&str[1];
- js_free_string(rt, slice->parent); // safe, recurses only 1 level
- }
- js_free_rt(rt, str);
- }
- }
- void JS_SetRuntimeInfo(JSRuntime *rt, const char *s)
- {
- if (rt)
- rt->rt_info = s;
- }
- void JS_FreeRuntime(JSRuntime *rt)
- {
- struct list_head *el, *el1;
- int i;
- rt->in_free = true;
- JS_FreeValueRT(rt, rt->current_exception);
- list_for_each_safe(el, el1, &rt->job_list) {
- JSJobEntry *e = list_entry(el, JSJobEntry, link);
- for(i = 0; i < e->argc; i++)
- JS_FreeValueRT(rt, e->argv[i]);
- js_free_rt(rt, e);
- }
- init_list_head(&rt->job_list);
- JS_RunGC(rt);
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- /* leaking objects */
- if (check_dump_flag(rt, JS_DUMP_LEAKS)) {
- bool header_done;
- JSGCObjectHeader *p;
- int count;
- /* remove the internal refcounts to display only the object
- referenced externally */
- list_for_each(el, &rt->gc_obj_list) {
- p = list_entry(el, JSGCObjectHeader, link);
- p->mark = 0;
- }
- gc_decref(rt);
- header_done = false;
- list_for_each(el, &rt->gc_obj_list) {
- p = list_entry(el, JSGCObjectHeader, link);
- if (p->ref_count != 0) {
- if (!header_done) {
- printf("Object leaks:\n");
- JS_DumpObjectHeader(rt);
- header_done = true;
- }
- JS_DumpGCObject(rt, p);
- }
- }
- count = 0;
- list_for_each(el, &rt->gc_obj_list) {
- p = list_entry(el, JSGCObjectHeader, link);
- if (p->ref_count == 0) {
- count++;
- }
- }
- if (count != 0)
- printf("Secondary object leaks: %d\n", count);
- }
- #endif
- assert(list_empty(&rt->gc_obj_list));
- /* free the classes */
- for(i = 0; i < rt->class_count; i++) {
- JSClass *cl = &rt->class_array[i];
- if (cl->class_id != 0) {
- JS_FreeAtomRT(rt, cl->class_name);
- }
- }
- js_free_rt(rt, rt->class_array);
- #ifdef ENABLE_DUMPS // JS_DUMP_ATOM_LEAKS
- /* only the atoms defined in JS_InitAtoms() should be left */
- if (check_dump_flag(rt, JS_DUMP_ATOM_LEAKS)) {
- bool header_done = false;
- for(i = 0; i < rt->atom_size; i++) {
- JSAtomStruct *p = rt->atom_array[i];
- if (!atom_is_free(p) /* && p->str*/) {
- if (i >= JS_ATOM_END || p->header.ref_count != 1) {
- if (!header_done) {
- header_done = true;
- if (rt->rt_info) {
- printf("%s:1: atom leakage:", rt->rt_info);
- } else {
- printf("Atom leaks:\n"
- " %6s %6s %s\n",
- "ID", "REFCNT", "NAME");
- }
- }
- if (rt->rt_info) {
- printf(" ");
- } else {
- printf(" %6u %6u ", i, p->header.ref_count);
- }
- switch (p->atom_type) {
- case JS_ATOM_TYPE_STRING:
- JS_DumpString(rt, p);
- break;
- case JS_ATOM_TYPE_GLOBAL_SYMBOL:
- printf("Symbol.for(");
- JS_DumpString(rt, p);
- printf(")");
- break;
- case JS_ATOM_TYPE_SYMBOL:
- if (p->hash == JS_ATOM_HASH_SYMBOL) {
- printf("Symbol(");
- JS_DumpString(rt, p);
- printf(")");
- } else {
- printf("Private(");
- JS_DumpString(rt, p);
- printf(")");
- }
- break;
- }
- if (rt->rt_info) {
- printf(":%u", p->header.ref_count);
- } else {
- printf("\n");
- }
- }
- }
- }
- if (rt->rt_info && header_done)
- printf("\n");
- }
- #endif
- /* free the atoms */
- for(i = 0; i < rt->atom_size; i++) {
- JSAtomStruct *p = rt->atom_array[i];
- if (!atom_is_free(p)) {
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- list_del(&p->link);
- #endif
- js_free_rt(rt, p);
- }
- }
- js_free_rt(rt, rt->atom_array);
- js_free_rt(rt, rt->atom_hash);
- js_free_rt(rt, rt->shape_hash);
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- if (check_dump_flag(rt, JS_DUMP_LEAKS) && !list_empty(&rt->string_list)) {
- if (rt->rt_info) {
- printf("%s:1: string leakage:", rt->rt_info);
- } else {
- printf("String leaks:\n"
- " %6s %s\n",
- "REFCNT", "VALUE");
- }
- list_for_each_safe(el, el1, &rt->string_list) {
- JSString *str = list_entry(el, JSString, link);
- if (rt->rt_info) {
- printf(" ");
- } else {
- printf(" %6u ", str->header.ref_count);
- }
- JS_DumpString(rt, str);
- if (rt->rt_info) {
- printf(":%u", str->header.ref_count);
- } else {
- printf("\n");
- }
- list_del(&str->link);
- js_free_rt(rt, str);
- }
- if (rt->rt_info)
- printf("\n");
- }
- #endif
- while (rt->finalizers) {
- JSRuntimeFinalizerState *fs = rt->finalizers;
- rt->finalizers = fs->next;
- fs->finalizer(rt, fs->arg);
- js_free_rt(rt, fs);
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- if (check_dump_flag(rt, JS_DUMP_LEAKS)) {
- JSMallocState *s = &rt->malloc_state;
- if (s->malloc_count > 1) {
- if (rt->rt_info)
- printf("%s:1: ", rt->rt_info);
- printf("Memory leak: %zd bytes lost in %zd block%s\n",
- s->malloc_size - sizeof(JSRuntime),
- s->malloc_count - 1, &"s"[s->malloc_count == 2]);
- }
- }
- #endif
- {
- JSMallocState *ms = &rt->malloc_state;
- rt->mf.js_free(ms->opaque, rt);
- }
- }
- JSContext *JS_NewContextRaw(JSRuntime *rt)
- {
- JSContext *ctx;
- int i;
- ctx = js_mallocz_rt(rt, sizeof(JSContext));
- if (!ctx)
- return NULL;
- ctx->header.ref_count = 1;
- add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT);
- ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) *
- rt->class_count);
- if (!ctx->class_proto) {
- js_free_rt(rt, ctx);
- return NULL;
- }
- ctx->rt = rt;
- list_add_tail(&ctx->link, &rt->context_list);
- for(i = 0; i < rt->class_count; i++)
- ctx->class_proto[i] = JS_NULL;
- ctx->array_ctor = JS_NULL;
- ctx->iterator_ctor = JS_NULL;
- ctx->iterator_ctor_getset = JS_NULL;
- ctx->regexp_ctor = JS_NULL;
- ctx->promise_ctor = JS_NULL;
- ctx->error_ctor = JS_NULL;
- ctx->error_back_trace = JS_UNDEFINED;
- ctx->error_prepare_stack = JS_UNDEFINED;
- ctx->error_stack_trace_limit = js_int32(10);
- init_list_head(&ctx->loaded_modules);
- JS_AddIntrinsicBasicObjects(ctx);
- return ctx;
- }
- JSContext *JS_NewContext(JSRuntime *rt)
- {
- JSContext *ctx;
- ctx = JS_NewContextRaw(rt);
- if (!ctx)
- return NULL;
- JS_AddIntrinsicBaseObjects(ctx);
- JS_AddIntrinsicDate(ctx);
- JS_AddIntrinsicEval(ctx);
- JS_AddIntrinsicRegExp(ctx);
- JS_AddIntrinsicJSON(ctx);
- JS_AddIntrinsicProxy(ctx);
- JS_AddIntrinsicMapSet(ctx);
- JS_AddIntrinsicTypedArrays(ctx);
- JS_AddIntrinsicPromise(ctx);
- JS_AddIntrinsicBigInt(ctx);
- JS_AddIntrinsicWeakRef(ctx);
- JS_AddIntrinsicDOMException(ctx);
- JS_AddPerformance(ctx);
- return ctx;
- }
- void *JS_GetContextOpaque(JSContext *ctx)
- {
- return ctx->user_opaque;
- }
- void JS_SetContextOpaque(JSContext *ctx, void *opaque)
- {
- ctx->user_opaque = opaque;
- }
- /* set the new value and free the old value after (freeing the value
- can reallocate the object data) */
- static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val)
- {
- JSValue old_val;
- old_val = *pval;
- *pval = new_val;
- JS_FreeValue(ctx, old_val);
- }
- void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj)
- {
- assert(class_id < ctx->rt->class_count);
- set_value(ctx, &ctx->class_proto[class_id], obj);
- }
- JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id)
- {
- assert(class_id < ctx->rt->class_count);
- return js_dup(ctx->class_proto[class_id]);
- }
- JSValue JS_GetFunctionProto(JSContext *ctx)
- {
- return js_dup(ctx->function_proto);
- }
- typedef enum JSFreeModuleEnum {
- JS_FREE_MODULE_ALL,
- JS_FREE_MODULE_NOT_RESOLVED,
- } JSFreeModuleEnum;
- /* XXX: would be more efficient with separate module lists */
- static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)
- {
- struct list_head *el, *el1;
- list_for_each_safe(el, el1, &ctx->loaded_modules) {
- JSModuleDef *m = list_entry(el, JSModuleDef, link);
- if (flag == JS_FREE_MODULE_ALL ||
- (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) {
- js_free_module_def(ctx, m);
- }
- }
- }
- JSContext *JS_DupContext(JSContext *ctx)
- {
- ctx->header.ref_count++;
- return ctx;
- }
- /* used by the GC */
- static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
- JS_MarkFunc *mark_func)
- {
- int i;
- struct list_head *el;
- /* modules are not seen by the GC, so we directly mark the objects
- referenced by each module */
- list_for_each(el, &ctx->loaded_modules) {
- JSModuleDef *m = list_entry(el, JSModuleDef, link);
- js_mark_module_def(rt, m, mark_func);
- }
- JS_MarkValue(rt, ctx->global_obj, mark_func);
- JS_MarkValue(rt, ctx->global_var_obj, mark_func);
- JS_MarkValue(rt, ctx->throw_type_error, mark_func);
- JS_MarkValue(rt, ctx->eval_obj, mark_func);
- JS_MarkValue(rt, ctx->array_proto_values, mark_func);
- for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
- JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
- }
- JS_MarkValue(rt, ctx->error_ctor, mark_func);
- JS_MarkValue(rt, ctx->error_back_trace, mark_func);
- JS_MarkValue(rt, ctx->error_prepare_stack, mark_func);
- JS_MarkValue(rt, ctx->error_stack_trace_limit, mark_func);
- for(i = 0; i < rt->class_count; i++) {
- JS_MarkValue(rt, ctx->class_proto[i], mark_func);
- }
- JS_MarkValue(rt, ctx->iterator_ctor, mark_func);
- JS_MarkValue(rt, ctx->iterator_ctor_getset, mark_func);
- JS_MarkValue(rt, ctx->async_iterator_proto, mark_func);
- JS_MarkValue(rt, ctx->promise_ctor, mark_func);
- JS_MarkValue(rt, ctx->array_ctor, mark_func);
- JS_MarkValue(rt, ctx->regexp_ctor, mark_func);
- JS_MarkValue(rt, ctx->function_ctor, mark_func);
- JS_MarkValue(rt, ctx->function_proto, mark_func);
- if (ctx->array_shape)
- mark_func(rt, &ctx->array_shape->header);
- }
- void JS_FreeContext(JSContext *ctx)
- {
- JSRuntime *rt = ctx->rt;
- int i;
- if (--ctx->header.ref_count > 0)
- return;
- assert(ctx->header.ref_count == 0);
- #ifdef ENABLE_DUMPS // JS_DUMP_ATOMS
- if (check_dump_flag(rt, JS_DUMP_ATOMS))
- JS_DumpAtoms(ctx->rt);
- #endif
- #ifdef ENABLE_DUMPS // JS_DUMP_SHAPES
- if (check_dump_flag(rt, JS_DUMP_SHAPES))
- JS_DumpShapes(ctx->rt);
- #endif
- #ifdef ENABLE_DUMPS // JS_DUMP_OBJECTS
- if (check_dump_flag(rt, JS_DUMP_OBJECTS)) {
- struct list_head *el;
- JSGCObjectHeader *p;
- printf("JSObjects: {\n");
- JS_DumpObjectHeader(ctx->rt);
- list_for_each(el, &rt->gc_obj_list) {
- p = list_entry(el, JSGCObjectHeader, link);
- JS_DumpGCObject(rt, p);
- }
- printf("}\n");
- }
- #endif
- #ifdef ENABLE_DUMPS // JS_DUMP_MEM
- if (check_dump_flag(rt, JS_DUMP_MEM)) {
- JSMemoryUsage stats;
- JS_ComputeMemoryUsage(rt, &stats);
- JS_DumpMemoryUsage(stdout, &stats, rt);
- }
- #endif
- js_free_modules(ctx, JS_FREE_MODULE_ALL);
- JS_FreeValue(ctx, ctx->global_obj);
- JS_FreeValue(ctx, ctx->global_var_obj);
- JS_FreeValue(ctx, ctx->throw_type_error);
- JS_FreeValue(ctx, ctx->eval_obj);
- JS_FreeValue(ctx, ctx->array_proto_values);
- for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
- JS_FreeValue(ctx, ctx->native_error_proto[i]);
- }
- JS_FreeValue(ctx, ctx->error_ctor);
- JS_FreeValue(ctx, ctx->error_back_trace);
- JS_FreeValue(ctx, ctx->error_prepare_stack);
- JS_FreeValue(ctx, ctx->error_stack_trace_limit);
- for(i = 0; i < rt->class_count; i++) {
- JS_FreeValue(ctx, ctx->class_proto[i]);
- }
- js_free_rt(rt, ctx->class_proto);
- JS_FreeValue(ctx, ctx->iterator_ctor);
- JS_FreeValue(ctx, ctx->iterator_ctor_getset);
- JS_FreeValue(ctx, ctx->async_iterator_proto);
- JS_FreeValue(ctx, ctx->promise_ctor);
- JS_FreeValue(ctx, ctx->array_ctor);
- JS_FreeValue(ctx, ctx->regexp_ctor);
- JS_FreeValue(ctx, ctx->function_ctor);
- JS_FreeValue(ctx, ctx->function_proto);
- js_free_shape_null(ctx->rt, ctx->array_shape);
- list_del(&ctx->link);
- remove_gc_object(&ctx->header);
- js_free_rt(ctx->rt, ctx);
- }
- JSRuntime *JS_GetRuntime(JSContext *ctx)
- {
- return ctx->rt;
- }
- static void update_stack_limit(JSRuntime *rt)
- {
- #if defined(__wasi__)
- rt->stack_limit = 0; /* no limit */
- #else
- if (rt->stack_size == 0) {
- rt->stack_limit = 0; /* no limit */
- } else {
- rt->stack_limit = rt->stack_top - rt->stack_size;
- }
- #endif
- }
- void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size)
- {
- rt->stack_size = stack_size;
- update_stack_limit(rt);
- }
- void JS_UpdateStackTop(JSRuntime *rt)
- {
- rt->stack_top = js_get_stack_pointer();
- update_stack_limit(rt);
- }
- static inline bool is_strict_mode(JSContext *ctx)
- {
- JSStackFrame *sf = ctx->rt->current_stack_frame;
- return sf && sf->is_strict_mode;
- }
- /* JSAtom support */
- #define JS_ATOM_TAG_INT (1U << 31)
- #define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1)
- #define JS_ATOM_MAX ((1U << 30) - 1)
- /* return the max count from the hash size */
- #define JS_ATOM_COUNT_RESIZE(n) ((n) * 2)
- static inline bool __JS_AtomIsConst(JSAtom v)
- {
- return (int32_t)v < JS_ATOM_END;
- }
- static inline bool __JS_AtomIsTaggedInt(JSAtom v)
- {
- return (v & JS_ATOM_TAG_INT) != 0;
- }
- static inline JSAtom __JS_AtomFromUInt32(uint32_t v)
- {
- return v | JS_ATOM_TAG_INT;
- }
- static inline uint32_t __JS_AtomToUInt32(JSAtom atom)
- {
- return atom & ~JS_ATOM_TAG_INT;
- }
- static inline int is_num(int c)
- {
- return c >= '0' && c <= '9';
- }
- /* return true if the string is a number n with 0 <= n <= 2^32-1 */
- static inline bool is_num_string(uint32_t *pval, JSString *p)
- {
- uint32_t n;
- uint64_t n64;
- int c, i, len;
- len = p->len;
- if (len == 0 || len > 10)
- return false;
- c = string_get(p, 0);
- if (is_num(c)) {
- if (c == '0') {
- if (len != 1)
- return false;
- n = 0;
- } else {
- n = c - '0';
- for(i = 1; i < len; i++) {
- c = string_get(p, i);
- if (!is_num(c))
- return false;
- n64 = (uint64_t)n * 10 + (c - '0');
- if ((n64 >> 32) != 0)
- return false;
- n = n64;
- }
- }
- *pval = n;
- return true;
- } else {
- return false;
- }
- }
- /* XXX: could use faster version ? */
- static inline uint32_t hash_string8(const uint8_t *str, size_t len, uint32_t h)
- {
- size_t i;
- for(i = 0; i < len; i++)
- h = h * 263 + str[i];
- return h;
- }
- static inline uint32_t hash_string16(const uint16_t *str,
- size_t len, uint32_t h)
- {
- size_t i;
- for(i = 0; i < len; i++)
- h = h * 263 + str[i];
- return h;
- }
- static uint32_t hash_string(JSString *str, uint32_t h)
- {
- if (str->is_wide_char)
- h = hash_string16(str16(str), str->len, h);
- else
- h = hash_string8(str8(str), str->len, h);
- return h;
- }
- static __maybe_unused void JS_DumpString(JSRuntime *rt, JSString *p)
- {
- int i, c, sep;
- if (p == NULL) {
- printf("<null>");
- return;
- }
- if (p->header.ref_count != 1)
- printf("%d", p->header.ref_count);
- if (p->is_wide_char)
- putchar('L');
- sep = '\"';
- putchar(sep);
- for(i = 0; i < p->len; i++) {
- c = string_get(p, i);
- if (c == sep || c == '\\') {
- putchar('\\');
- putchar(c);
- } else if (c >= ' ' && c <= 126) {
- putchar(c);
- } else if (c == '\n') {
- putchar('\\');
- putchar('n');
- } else {
- printf("\\u%04x", c);
- }
- }
- putchar(sep);
- }
- static __maybe_unused void JS_DumpAtoms(JSRuntime *rt)
- {
- JSAtomStruct *p;
- int h, i;
- /* This only dumps hashed atoms, not JS_ATOM_TYPE_SYMBOL atoms */
- printf("JSAtom count=%d size=%d hash_size=%d:\n",
- rt->atom_count, rt->atom_size, rt->atom_hash_size);
- printf("JSAtom hash table: {\n");
- for(i = 0; i < rt->atom_hash_size; i++) {
- h = rt->atom_hash[i];
- if (h) {
- printf(" %d:", i);
- while (h) {
- p = rt->atom_array[h];
- printf(" ");
- JS_DumpString(rt, p);
- h = p->hash_next;
- }
- printf("\n");
- }
- }
- printf("}\n");
- printf("JSAtom table: {\n");
- for(i = 0; i < rt->atom_size; i++) {
- p = rt->atom_array[i];
- if (!atom_is_free(p)) {
- printf(" %d: { %d %08x ", i, p->atom_type, p->hash);
- if (!(p->len == 0 && p->is_wide_char != 0))
- JS_DumpString(rt, p);
- printf(" %d }\n", p->hash_next);
- }
- }
- printf("}\n");
- }
- static int JS_ResizeAtomHash(JSRuntime *rt, int new_hash_size)
- {
- JSAtomStruct *p;
- uint32_t new_hash_mask, h, i, hash_next1, j, *new_hash;
- assert((new_hash_size & (new_hash_size - 1)) == 0); /* power of two */
- new_hash_mask = new_hash_size - 1;
- new_hash = js_mallocz_rt(rt, sizeof(rt->atom_hash[0]) * new_hash_size);
- if (!new_hash)
- return -1;
- for(i = 0; i < rt->atom_hash_size; i++) {
- h = rt->atom_hash[i];
- while (h != 0) {
- p = rt->atom_array[h];
- hash_next1 = p->hash_next;
- /* add in new hash table */
- j = p->hash & new_hash_mask;
- p->hash_next = new_hash[j];
- new_hash[j] = h;
- h = hash_next1;
- }
- }
- js_free_rt(rt, rt->atom_hash);
- rt->atom_hash = new_hash;
- rt->atom_hash_size = new_hash_size;
- rt->atom_count_resize = JS_ATOM_COUNT_RESIZE(new_hash_size);
- // JS_DumpAtoms(rt);
- return 0;
- }
- static int JS_InitAtoms(JSRuntime *rt)
- {
- int i, len, atom_type;
- const char *p;
- rt->atom_hash_size = 0;
- rt->atom_hash = NULL;
- rt->atom_count = 0;
- rt->atom_size = 0;
- rt->atom_free_index = 0;
- if (JS_ResizeAtomHash(rt, 256)) /* there are at least 195 predefined atoms */
- return -1;
- p = js_atom_init;
- for(i = 1; i < JS_ATOM_END; i++) {
- if (i == JS_ATOM_Private_brand)
- atom_type = JS_ATOM_TYPE_PRIVATE;
- else if (i >= JS_ATOM_Symbol_toPrimitive)
- atom_type = JS_ATOM_TYPE_SYMBOL;
- else
- atom_type = JS_ATOM_TYPE_STRING;
- len = strlen(p);
- if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL)
- return -1;
- p = p + len + 1;
- }
- return 0;
- }
- static JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v)
- {
- JSAtomStruct *p;
- if (!__JS_AtomIsConst(v)) {
- p = rt->atom_array[v];
- p->header.ref_count++;
- }
- return v;
- }
- JSAtom JS_DupAtom(JSContext *ctx, JSAtom v)
- {
- JSRuntime *rt;
- JSAtomStruct *p;
- if (!__JS_AtomIsConst(v)) {
- rt = ctx->rt;
- p = rt->atom_array[v];
- p->header.ref_count++;
- }
- return v;
- }
- static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v)
- {
- JSRuntime *rt;
- JSAtomStruct *p;
- rt = ctx->rt;
- if (__JS_AtomIsTaggedInt(v))
- return JS_ATOM_KIND_STRING;
- p = rt->atom_array[v];
- switch(p->atom_type) {
- case JS_ATOM_TYPE_STRING:
- return JS_ATOM_KIND_STRING;
- case JS_ATOM_TYPE_GLOBAL_SYMBOL:
- return JS_ATOM_KIND_SYMBOL;
- case JS_ATOM_TYPE_SYMBOL:
- switch(p->hash) {
- case JS_ATOM_HASH_SYMBOL:
- return JS_ATOM_KIND_SYMBOL;
- case JS_ATOM_HASH_PRIVATE:
- return JS_ATOM_KIND_PRIVATE;
- default:
- abort();
- }
- default:
- abort();
- }
- return (JSAtomKindEnum){-1}; // pacify compiler
- }
- static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p)
- {
- uint32_t i = p->hash_next; /* atom_index */
- if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
- JSAtomStruct *p1;
- i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)];
- p1 = rt->atom_array[i];
- while (p1 != p) {
- assert(i != 0);
- i = p1->hash_next;
- p1 = rt->atom_array[i];
- }
- }
- return i;
- }
- /* string case (internal). Return JS_ATOM_NULL if error. 'str' is
- freed. */
- static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
- {
- uint32_t h, h1, i;
- JSAtomStruct *p;
- int len;
- if (atom_type < JS_ATOM_TYPE_SYMBOL) {
- /* str is not NULL */
- if (str->atom_type == atom_type) {
- /* str is the atom, return its index */
- i = js_get_atom_index(rt, str);
- /* reduce string refcount and increase atom's unless constant */
- if (__JS_AtomIsConst(i))
- str->header.ref_count--;
- return i;
- }
- /* try and locate an already registered atom */
- len = str->len;
- h = hash_string(str, atom_type);
- h &= JS_ATOM_HASH_MASK;
- h1 = h & (rt->atom_hash_size - 1);
- i = rt->atom_hash[h1];
- while (i != 0) {
- p = rt->atom_array[i];
- if (p->hash == h &&
- p->atom_type == atom_type &&
- p->len == len &&
- js_string_memcmp(p, str, len) == 0) {
- if (!__JS_AtomIsConst(i))
- p->header.ref_count++;
- goto done;
- }
- i = p->hash_next;
- }
- } else {
- h1 = 0; /* avoid warning */
- if (atom_type == JS_ATOM_TYPE_SYMBOL) {
- h = JS_ATOM_HASH_SYMBOL;
- } else {
- h = JS_ATOM_HASH_PRIVATE;
- atom_type = JS_ATOM_TYPE_SYMBOL;
- }
- }
- if (rt->atom_free_index == 0) {
- /* allow new atom entries */
- uint32_t new_size, start;
- JSAtomStruct **new_array;
- /* alloc new with size progression 3/2:
- 4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599 2398 3597 5395 8092
- preallocating space for predefined atoms (at least 195).
- */
- new_size = max_int(211, rt->atom_size * 3 / 2);
- if (new_size > JS_ATOM_MAX)
- goto fail;
- /* XXX: should use realloc2 to use slack space */
- new_array = js_realloc_rt(rt, rt->atom_array, sizeof(*new_array) * new_size);
- if (!new_array)
- goto fail;
- /* Note: the atom 0 is not used */
- start = rt->atom_size;
- if (start == 0) {
- /* JS_ATOM_NULL entry */
- p = js_mallocz_rt(rt, sizeof(JSAtomStruct));
- if (!p) {
- js_free_rt(rt, new_array);
- goto fail;
- }
- p->header.ref_count = 1; /* not refcounted */
- p->atom_type = JS_ATOM_TYPE_SYMBOL;
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- list_add_tail(&p->link, &rt->string_list);
- #endif
- new_array[0] = p;
- rt->atom_count++;
- start = 1;
- }
- rt->atom_size = new_size;
- rt->atom_array = new_array;
- rt->atom_free_index = start;
- for(i = start; i < new_size; i++) {
- uint32_t next;
- if (i == (new_size - 1))
- next = 0;
- else
- next = i + 1;
- rt->atom_array[i] = atom_set_free(next);
- }
- }
- if (str) {
- if (str->atom_type == 0) {
- p = str;
- p->atom_type = atom_type;
- } else {
- p = js_malloc_rt(rt, sizeof(JSString) +
- (str->len << str->is_wide_char) +
- 1 - str->is_wide_char);
- if (unlikely(!p))
- goto fail;
- p->header.ref_count = 1;
- p->is_wide_char = str->is_wide_char;
- p->len = str->len;
- p->kind = JS_STRING_KIND_NORMAL;
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- list_add_tail(&p->link, &rt->string_list);
- #endif
- memcpy(str8(p), str8(str), (str->len << str->is_wide_char) +
- 1 - str->is_wide_char);
- js_free_string(rt, str);
- }
- } else {
- p = js_malloc_rt(rt, sizeof(JSAtomStruct)); /* empty wide string */
- if (!p)
- return JS_ATOM_NULL;
- p->header.ref_count = 1;
- p->is_wide_char = 1; /* Hack to represent NULL as a JSString */
- p->len = 0;
- p->kind = JS_STRING_KIND_NORMAL;
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- list_add_tail(&p->link, &rt->string_list);
- #endif
- }
- /* use an already free entry */
- i = rt->atom_free_index;
- rt->atom_free_index = atom_get_free(rt->atom_array[i]);
- rt->atom_array[i] = p;
- p->hash = h;
- p->hash_next = i; /* atom_index */
- p->atom_type = atom_type;
- p->first_weak_ref = NULL;
- rt->atom_count++;
- if (atom_type != JS_ATOM_TYPE_SYMBOL) {
- p->hash_next = rt->atom_hash[h1];
- rt->atom_hash[h1] = i;
- if (unlikely(rt->atom_count >= rt->atom_count_resize))
- JS_ResizeAtomHash(rt, rt->atom_hash_size * 2);
- }
- // JS_DumpAtoms(rt);
- return i;
- fail:
- i = JS_ATOM_NULL;
- done:
- if (str)
- js_free_string(rt, str);
- return i;
- }
- // XXX: `str` must be pure ASCII. No UTF-8 encoded strings
- // XXX: `str` must not be the string representation of a small integer
- static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
- int atom_type)
- {
- JSString *p;
- p = js_alloc_string_rt(rt, len, 0);
- if (!p)
- return JS_ATOM_NULL;
- memcpy(str8(p), str, len);
- str8(p)[len] = '\0';
- return __JS_NewAtom(rt, p, atom_type);
- }
- // XXX: `str` must be raw 8-bit contents. No UTF-8 encoded strings
- static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
- int atom_type)
- {
- uint32_t h, h1, i;
- JSAtomStruct *p;
- h = hash_string8((const uint8_t *)str, len, JS_ATOM_TYPE_STRING);
- h &= JS_ATOM_HASH_MASK;
- h1 = h & (rt->atom_hash_size - 1);
- i = rt->atom_hash[h1];
- while (i != 0) {
- p = rt->atom_array[i];
- if (p->hash == h &&
- p->atom_type == JS_ATOM_TYPE_STRING &&
- p->len == len &&
- p->is_wide_char == 0 &&
- memcmp(str8(p), str, len) == 0) {
- if (!__JS_AtomIsConst(i))
- p->header.ref_count++;
- return i;
- }
- i = p->hash_next;
- }
- return JS_ATOM_NULL;
- }
- static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p)
- {
- uint32_t i = p->hash_next; /* atom_index */
- if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
- JSAtomStruct *p0, *p1;
- uint32_t h0;
- h0 = p->hash & (rt->atom_hash_size - 1);
- i = rt->atom_hash[h0];
- p1 = rt->atom_array[i];
- if (p1 == p) {
- rt->atom_hash[h0] = p1->hash_next;
- } else {
- for(;;) {
- assert(i != 0);
- p0 = p1;
- i = p1->hash_next;
- p1 = rt->atom_array[i];
- if (p1 == p) {
- p0->hash_next = p1->hash_next;
- break;
- }
- }
- }
- }
- /* insert in free atom list */
- rt->atom_array[i] = atom_set_free(rt->atom_free_index);
- rt->atom_free_index = i;
- if (unlikely(p->first_weak_ref)) {
- reset_weak_ref(rt, &p->first_weak_ref);
- }
- /* free the string structure */
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- list_del(&p->link);
- #endif
- js_free_rt(rt, p);
- rt->atom_count--;
- assert(rt->atom_count >= 0);
- }
- static void __JS_FreeAtom(JSRuntime *rt, uint32_t i)
- {
- JSAtomStruct *p;
- p = rt->atom_array[i];
- if (--p->header.ref_count > 0)
- return;
- JS_FreeAtomStruct(rt, p);
- }
- /* Warning: 'p' is freed */
- static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p)
- {
- JSRuntime *rt = ctx->rt;
- uint32_t n;
- if (is_num_string(&n, p)) {
- if (n <= JS_ATOM_MAX_INT) {
- js_free_string(rt, p);
- return __JS_AtomFromUInt32(n);
- }
- }
- /* XXX: should generate an exception */
- return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING);
- }
- /* `str` may be pure ASCII or UTF-8 encoded */
- JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)
- {
- JSValue val;
- if (len == 0 || !is_digit(*str)) {
- // TODO(chqrlie): this does not work if `str` has UTF-8 encoded contents
- // bug example: `({ "\u00c3\u00a9": 1 }).\u00e9` evaluates to `1`.
- JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
- if (atom)
- return atom;
- }
- val = JS_NewStringLen(ctx, str, len);
- if (JS_IsException(val))
- return JS_ATOM_NULL;
- return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val));
- }
- /* `str` may be pure ASCII or UTF-8 encoded */
- JSAtom JS_NewAtom(JSContext *ctx, const char *str)
- {
- return JS_NewAtomLen(ctx, str, strlen(str));
- }
- JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
- {
- if (n <= JS_ATOM_MAX_INT) {
- return __JS_AtomFromUInt32(n);
- } else {
- char buf[16];
- size_t len = u32toa(buf, n);
- JSValue val = js_new_string8_len(ctx, buf, len);
- if (JS_IsException(val))
- return JS_ATOM_NULL;
- return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
- JS_ATOM_TYPE_STRING);
- }
- }
- static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)
- {
- if ((uint64_t)n <= JS_ATOM_MAX_INT) {
- return __JS_AtomFromUInt32((uint32_t)n);
- } else {
- char buf[24];
- size_t len = i64toa(buf, n);
- JSValue val = js_new_string8_len(ctx, buf, len);
- if (JS_IsException(val))
- return JS_ATOM_NULL;
- return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
- JS_ATOM_TYPE_STRING);
- }
- }
- /* 'p' is freed */
- static JSValue JS_NewSymbolInternal(JSContext *ctx, JSString *p, int atom_type)
- {
- JSRuntime *rt = ctx->rt;
- JSAtom atom;
- atom = __JS_NewAtom(rt, p, atom_type);
- if (atom == JS_ATOM_NULL)
- return JS_ThrowOutOfMemory(ctx);
- return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]);
- }
- /* descr must be a non-numeric string atom */
- static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
- int atom_type)
- {
- JSRuntime *rt = ctx->rt;
- JSString *p;
- assert(!__JS_AtomIsTaggedInt(descr));
- assert(descr < rt->atom_size);
- p = rt->atom_array[descr];
- js_dup(JS_MKPTR(JS_TAG_STRING, p));
- return JS_NewSymbolInternal(ctx, p, atom_type);
- }
- /* `description` may be pure ASCII or UTF-8 encoded */
- JSValue JS_NewSymbol(JSContext *ctx, const char *description, bool is_global)
- {
- JSAtom atom = JS_NewAtom(ctx, description);
- if (atom == JS_ATOM_NULL)
- return JS_EXCEPTION;
- return JS_NewSymbolFromAtom(ctx, atom, is_global ? JS_ATOM_TYPE_GLOBAL_SYMBOL : JS_ATOM_TYPE_SYMBOL);
- }
- #define ATOM_GET_STR_BUF_SIZE 64
- static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
- JSAtom atom)
- {
- if (__JS_AtomIsTaggedInt(atom)) {
- snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom));
- } else if (atom == JS_ATOM_NULL) {
- snprintf(buf, buf_size, "<null>");
- } else if (atom >= rt->atom_size) {
- assert(atom < rt->atom_size);
- snprintf(buf, buf_size, "<invalid %x>", atom);
- } else {
- JSAtomStruct *p = rt->atom_array[atom];
- *buf = '\0';
- if (atom_is_free(p)) {
- snprintf(buf, buf_size, "<free %x>", atom);
- } else if (p != NULL) {
- JSString *str = p;
- if (str->is_wide_char) {
- /* encode surrogates correctly */
- utf8_encode_buf16(buf, buf_size, str16(str), str->len);
- } else {
- utf8_encode_buf8(buf, buf_size, str8(str), str->len);
- }
- }
- }
- return buf;
- }
- static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom)
- {
- return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom);
- }
- static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, bool force_string)
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
- if (__JS_AtomIsTaggedInt(atom)) {
- size_t len = u32toa(buf, __JS_AtomToUInt32(atom));
- return js_new_string8_len(ctx, buf, len);
- } else {
- JSRuntime *rt = ctx->rt;
- JSAtomStruct *p;
- assert(atom < rt->atom_size);
- p = rt->atom_array[atom];
- if (p->atom_type == JS_ATOM_TYPE_STRING) {
- goto ret_string;
- } else if (force_string) {
- if (p->len == 0 && p->is_wide_char != 0) {
- /* no description string */
- p = rt->atom_array[JS_ATOM_empty_string];
- }
- ret_string:
- return js_dup(JS_MKPTR(JS_TAG_STRING, p));
- } else {
- return js_dup(JS_MKPTR(JS_TAG_SYMBOL, p));
- }
- }
- }
- JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom)
- {
- return __JS_AtomToValue(ctx, atom, false);
- }
- JSValue JS_AtomToString(JSContext *ctx, JSAtom atom)
- {
- return __JS_AtomToValue(ctx, atom, true);
- }
- /* return true if the atom is an array index (i.e. 0 <= index <=
- 2^32-2 and return its value */
- static bool JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom)
- {
- if (__JS_AtomIsTaggedInt(atom)) {
- *pval = __JS_AtomToUInt32(atom);
- return true;
- } else {
- JSRuntime *rt = ctx->rt;
- JSAtomStruct *p;
- uint32_t val;
- assert(atom < rt->atom_size);
- p = rt->atom_array[atom];
- if (p->atom_type == JS_ATOM_TYPE_STRING &&
- is_num_string(&val, p) && val != -1) {
- *pval = val;
- return true;
- } else {
- *pval = 0;
- return false;
- }
- }
- }
- /* This test must be fast if atom is not a numeric index (e.g. a
- method name). Return JS_UNDEFINED if not a numeric
- index. JS_EXCEPTION can also be returned. */
- static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
- {
- JSRuntime *rt = ctx->rt;
- JSAtomStruct *p1;
- JSString *p;
- int c, len, ret;
- JSValue num, str;
- if (__JS_AtomIsTaggedInt(atom))
- return js_int32(__JS_AtomToUInt32(atom));
- assert(atom < rt->atom_size);
- p1 = rt->atom_array[atom];
- if (p1->atom_type != JS_ATOM_TYPE_STRING)
- return JS_UNDEFINED;
- p = p1;
- len = p->len;
- if (p->is_wide_char) {
- const uint16_t *r = str16(p), *r_end = str16(p) + len;
- if (r >= r_end)
- return JS_UNDEFINED;
- c = *r;
- if (c == '-') {
- if (r >= r_end)
- return JS_UNDEFINED;
- r++;
- c = *r;
- /* -0 case is specific */
- if (c == '0' && len == 2)
- goto minus_zero;
- }
- /* XXX: should test NaN, but the tests do not check it */
- if (!is_num(c)) {
- /* XXX: String should be normalized, therefore 8-bit only */
- const uint16_t nfinity16[7] = { 'n', 'f', 'i', 'n', 'i', 't', 'y' };
- if (!(c =='I' && (r_end - r) == 8 &&
- !memcmp(r + 1, nfinity16, sizeof(nfinity16))))
- return JS_UNDEFINED;
- }
- } else {
- const uint8_t *r = str8(p), *r_end = str8(p) + len;
- if (r >= r_end)
- return JS_UNDEFINED;
- c = *r;
- if (c == '-') {
- if (r >= r_end)
- return JS_UNDEFINED;
- r++;
- c = *r;
- /* -0 case is specific */
- if (c == '0' && len == 2) {
- minus_zero:
- return js_float64(-0.0);
- }
- }
- if (!is_num(c)) {
- if (!(c =='I' && (r_end - r) == 8 &&
- !memcmp(r + 1, "nfinity", 7)))
- return JS_UNDEFINED;
- }
- }
- /* this is ECMA CanonicalNumericIndexString primitive */
- num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p));
- if (JS_IsException(num))
- return num;
- str = JS_ToString(ctx, num);
- if (JS_IsException(str)) {
- JS_FreeValue(ctx, num);
- return str;
- }
- ret = js_string_eq(p, JS_VALUE_GET_STRING(str));
- JS_FreeValue(ctx, str);
- if (ret) {
- return num;
- } else {
- JS_FreeValue(ctx, num);
- return JS_UNDEFINED;
- }
- }
- /* return -1 if exception or true/false */
- static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom)
- {
- JSValue num;
- num = JS_AtomIsNumericIndex1(ctx, atom);
- if (likely(JS_IsUndefined(num)))
- return false;
- if (JS_IsException(num))
- return -1;
- JS_FreeValue(ctx, num);
- return true;
- }
- void JS_FreeAtom(JSContext *ctx, JSAtom v)
- {
- if (!__JS_AtomIsConst(v))
- __JS_FreeAtom(ctx->rt, v);
- }
- void JS_FreeAtomRT(JSRuntime *rt, JSAtom v)
- {
- if (!__JS_AtomIsConst(v))
- __JS_FreeAtom(rt, v);
- }
- /* return true if 'v' is a symbol with a string description */
- static bool JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
- {
- JSRuntime *rt;
- JSAtomStruct *p;
- rt = ctx->rt;
- if (__JS_AtomIsTaggedInt(v))
- return false;
- p = rt->atom_array[v];
- return (((p->atom_type == JS_ATOM_TYPE_SYMBOL &&
- p->hash == JS_ATOM_HASH_SYMBOL) ||
- p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) &&
- !(p->len == 0 && p->is_wide_char != 0));
- }
- static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
- const char *p;
- int i;
- /* XXX: should handle embedded null characters */
- /* XXX: should move encoding code to JS_AtomGetStr */
- p = JS_AtomGetStr(ctx, buf, sizeof(buf), atom);
- for (i = 0; p[i]; i++) {
- int c = (unsigned char)p[i];
- if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
- (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0)))
- break;
- }
- if (i > 0 && p[i] == '\0') {
- printf("%s", p);
- } else {
- putchar('"');
- printf("%.*s", i, p);
- for (; p[i]; i++) {
- int c = (unsigned char)p[i];
- if (c == '\"' || c == '\\') {
- putchar('\\');
- putchar(c);
- } else if (c >= ' ' && c <= 126) {
- putchar(c);
- } else if (c == '\n') {
- putchar('\\');
- putchar('n');
- } else {
- printf("\\u%04x", c);
- }
- }
- putchar('\"');
- }
- }
- /* free with JS_FreeCString() */
- const char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom)
- {
- JSValue str;
- const char *cstr;
- str = JS_AtomToString(ctx, atom);
- if (JS_IsException(str)) {
- if (plen)
- *plen = 0;
- return NULL;
- }
- cstr = JS_ToCStringLen(ctx, plen, str);
- JS_FreeValue(ctx, str);
- return cstr;
- }
- #ifndef QJS_DISABLE_PARSER
- /* return a string atom containing name concatenated with str1 */
- /* `str1` may be pure ASCII or UTF-8 encoded */
- // TODO(chqrlie): use string concatenation instead of UTF-8 conversion
- static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1)
- {
- JSValue str;
- JSAtom atom;
- const char *cstr;
- char *cstr2;
- size_t len, len1;
- str = JS_AtomToString(ctx, name);
- if (JS_IsException(str))
- return JS_ATOM_NULL;
- cstr = JS_ToCStringLen(ctx, &len, str);
- if (!cstr)
- goto fail;
- len1 = strlen(str1);
- cstr2 = js_malloc(ctx, len + len1 + 1);
- if (!cstr2)
- goto fail;
- memcpy(cstr2, cstr, len);
- memcpy(cstr2 + len, str1, len1);
- cstr2[len + len1] = '\0';
- atom = JS_NewAtomLen(ctx, cstr2, len + len1);
- js_free(ctx, cstr2);
- JS_FreeCString(ctx, cstr);
- JS_FreeValue(ctx, str);
- return atom;
- fail:
- JS_FreeCString(ctx, cstr);
- JS_FreeValue(ctx, str);
- return JS_ATOM_NULL;
- }
- static JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n)
- {
- char buf[16];
- size_t len;
- len = u32toa(buf, n);
- buf[len] = '\0';
- return js_atom_concat_str(ctx, name, buf);
- }
- #endif // QJS_DISABLE_PARSER
- static inline bool JS_IsEmptyString(JSValueConst v)
- {
- return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0;
- }
- /* JSClass support */
- /* a new class ID is allocated if *pclass_id == 0, otherwise *pclass_id is left unchanged */
- JSClassID JS_NewClassID(JSRuntime *rt, JSClassID *pclass_id)
- {
- JSClassID class_id = *pclass_id;
- if (class_id == 0) {
- class_id = rt->js_class_id_alloc++;
- *pclass_id = class_id;
- }
- return class_id;
- }
- JSClassID JS_GetClassID(JSValueConst v)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
- return JS_INVALID_CLASS_ID;
- p = JS_VALUE_GET_OBJ(v);
- return p->class_id;
- }
- bool JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id)
- {
- return (class_id < rt->class_count &&
- rt->class_array[class_id].class_id != 0);
- }
- /* create a new object internal class. Return -1 if error, 0 if
- OK. The finalizer can be NULL if none is needed. */
- static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
- const JSClassDef *class_def, JSAtom name)
- {
- int new_size, i;
- JSClass *cl, *new_class_array;
- struct list_head *el;
- if (class_id >= (1 << 16))
- return -1;
- if (class_id < rt->class_count &&
- rt->class_array[class_id].class_id != 0)
- return -1;
- if (class_id >= rt->class_count) {
- new_size = max_int(JS_CLASS_INIT_COUNT,
- max_int(class_id + 1, rt->class_count * 3 / 2));
- /* reallocate the context class prototype array, if any */
- list_for_each(el, &rt->context_list) {
- JSContext *ctx = list_entry(el, JSContext, link);
- JSValue *new_tab;
- new_tab = js_realloc_rt(rt, ctx->class_proto,
- sizeof(ctx->class_proto[0]) * new_size);
- if (!new_tab)
- return -1;
- for(i = rt->class_count; i < new_size; i++)
- new_tab[i] = JS_NULL;
- ctx->class_proto = new_tab;
- }
- /* reallocate the class array */
- new_class_array = js_realloc_rt(rt, rt->class_array,
- sizeof(JSClass) * new_size);
- if (!new_class_array)
- return -1;
- memset(new_class_array + rt->class_count, 0,
- (new_size - rt->class_count) * sizeof(JSClass));
- rt->class_array = new_class_array;
- rt->class_count = new_size;
- }
- cl = &rt->class_array[class_id];
- cl->class_id = class_id;
- cl->class_name = JS_DupAtomRT(rt, name);
- cl->finalizer = class_def->finalizer;
- cl->gc_mark = class_def->gc_mark;
- cl->call = class_def->call;
- cl->exotic = class_def->exotic;
- return 0;
- }
- int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def)
- {
- int ret, len;
- JSAtom name;
- // XXX: class_def->class_name must be raw 8-bit contents. No UTF-8 encoded strings
- len = strlen(class_def->class_name);
- name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
- if (name == JS_ATOM_NULL) {
- name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
- if (name == JS_ATOM_NULL)
- return -1;
- }
- ret = JS_NewClass1(rt, class_id, class_def, name);
- JS_FreeAtomRT(rt, name);
- return ret;
- }
- static inline JSValue js_empty_string(JSRuntime *rt)
- {
- JSAtomStruct *p = rt->atom_array[JS_ATOM_empty_string];
- return js_dup(JS_MKPTR(JS_TAG_STRING, p));
- }
- // XXX: `buf` contains raw 8-bit data, no UTF-8 decoding is performed
- // XXX: no special case for len == 0
- static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len)
- {
- JSString *str;
- str = js_alloc_string(ctx, len, 0);
- if (!str)
- return JS_EXCEPTION;
- memcpy(str8(str), buf, len);
- str8(str)[len] = '\0';
- return JS_MKPTR(JS_TAG_STRING, str);
- }
- // XXX: `buf` contains raw 8-bit data, no UTF-8 decoding is performed
- // XXX: no special case for the empty string
- static inline JSValue js_new_string8(JSContext *ctx, const char *str)
- {
- return js_new_string8_len(ctx, str, strlen(str));
- }
- static JSValue js_new_string16_len(JSContext *ctx, const uint16_t *buf, int len)
- {
- JSString *str;
- str = js_alloc_string(ctx, len, 1);
- if (!str)
- return JS_EXCEPTION;
- memcpy(str16(str), buf, len * 2);
- return JS_MKPTR(JS_TAG_STRING, str);
- }
- static JSValue js_new_string_char(JSContext *ctx, uint16_t c)
- {
- if (c < 0x100) {
- char ch8 = c;
- return js_new_string8_len(ctx, &ch8, 1);
- } else {
- uint16_t ch16 = c;
- return js_new_string16_len(ctx, &ch16, 1);
- }
- }
- static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end)
- {
- JSStringSlice *slice;
- JSString *q;
- int len;
- len = end - start;
- if (start == 0 && end == p->len) {
- return js_dup(JS_MKPTR(JS_TAG_STRING, p));
- }
- if (len <= 0) {
- return js_empty_string(ctx->rt);
- }
- if (len > (JS_STRING_SLICE_LEN_MAX >> p->is_wide_char)) {
- if (p->kind == JS_STRING_KIND_SLICE) {
- slice = (void *)&p[1];
- p = slice->parent;
- start += slice->start >> p->is_wide_char; // bytes -> chars
- }
- // allocate as 16 bit wide string to avoid wastage;
- // js_alloc_string allocates 1 byte extra for 8 bit strings;
- q = js_alloc_string(ctx, sizeof(*slice)/2, /*is_wide_char*/true);
- if (!q)
- return JS_EXCEPTION;
- q->is_wide_char = p->is_wide_char;
- q->kind = JS_STRING_KIND_SLICE;
- q->len = len;
- slice = (void *)&q[1];
- slice->parent = p;
- slice->start = start << p->is_wide_char; // chars -> bytes
- p->header.ref_count++;
- return JS_MKPTR(JS_TAG_STRING, q);
- }
- if (p->is_wide_char) {
- JSString *str;
- int i;
- uint16_t c = 0;
- for (i = start; i < end; i++) {
- c |= str16(p)[i];
- }
- if (c > 0xFF)
- return js_new_string16_len(ctx, str16(p) + start, len);
- str = js_alloc_string(ctx, len, 0);
- if (!str)
- return JS_EXCEPTION;
- for (i = 0; i < len; i++) {
- str8(str)[i] = str16(p)[start + i];
- }
- str8(str)[len] = '\0';
- return JS_MKPTR(JS_TAG_STRING, str);
- } else {
- return js_new_string8_len(ctx, (const char *)(str8(p) + start), len);
- }
- }
- typedef struct StringBuffer {
- JSContext *ctx;
- JSString *str;
- int len;
- int size;
- int is_wide_char;
- int error_status;
- } StringBuffer;
- /* It is valid to call string_buffer_end() and all string_buffer functions even
- if string_buffer_init() or another string_buffer function returns an error.
- If the error_status is set, string_buffer_end() returns JS_EXCEPTION.
- */
- static int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size,
- int is_wide)
- {
- s->ctx = ctx;
- s->size = size;
- s->len = 0;
- s->is_wide_char = is_wide;
- s->error_status = 0;
- s->str = js_alloc_string(ctx, size, is_wide);
- if (unlikely(!s->str)) {
- s->size = 0;
- return s->error_status = -1;
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- /* the StringBuffer may reallocate the JSString, only link it at the end */
- list_del(&s->str->link);
- #endif
- return 0;
- }
- static inline int string_buffer_init(JSContext *ctx, StringBuffer *s, int size)
- {
- return string_buffer_init2(ctx, s, size, 0);
- }
- static void string_buffer_free(StringBuffer *s)
- {
- js_free(s->ctx, s->str);
- s->str = NULL;
- }
- static int string_buffer_set_error(StringBuffer *s)
- {
- js_free(s->ctx, s->str);
- s->str = NULL;
- s->size = 0;
- s->len = 0;
- return s->error_status = -1;
- }
- static no_inline int string_buffer_widen(StringBuffer *s, int size)
- {
- JSString *str;
- size_t slack;
- int i;
- if (s->error_status)
- return -1;
- str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack);
- if (!str)
- return string_buffer_set_error(s);
- size += slack >> 1;
- for(i = s->len; i-- > 0;) {
- str16(str)[i] = str8(str)[i];
- }
- s->is_wide_char = 1;
- s->size = size;
- s->str = str;
- return 0;
- }
- static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c)
- {
- JSString *new_str;
- int new_size;
- size_t new_size_bytes, slack;
- if (s->error_status)
- return -1;
- if (new_len > JS_STRING_LEN_MAX) {
- JS_ThrowRangeError(s->ctx, "invalid string length");
- return string_buffer_set_error(s);
- }
- new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX);
- if (!s->is_wide_char && c >= 0x100) {
- return string_buffer_widen(s, new_size);
- }
- new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char;
- new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack);
- if (!new_str)
- return string_buffer_set_error(s);
- new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX);
- s->size = new_size;
- s->str = new_str;
- return 0;
- }
- static no_inline int string_buffer_putc_slow(StringBuffer *s, uint32_t c)
- {
- if (unlikely(s->len >= s->size)) {
- if (string_buffer_realloc(s, s->len + 1, c))
- return -1;
- }
- if (s->is_wide_char) {
- str16(s->str)[s->len++] = c;
- } else if (c < 0x100) {
- str8(s->str)[s->len++] = c;
- } else {
- if (string_buffer_widen(s, s->size))
- return -1;
- str16(s->str)[s->len++] = c;
- }
- return 0;
- }
- /* 0 <= c <= 0xff */
- static int string_buffer_putc8(StringBuffer *s, uint32_t c)
- {
- if (unlikely(s->len >= s->size)) {
- if (string_buffer_realloc(s, s->len + 1, c))
- return -1;
- }
- if (s->is_wide_char) {
- str16(s->str)[s->len++] = c;
- } else {
- str8(s->str)[s->len++] = c;
- }
- return 0;
- }
- /* 0 <= c <= 0xffff */
- static int string_buffer_putc16(StringBuffer *s, uint32_t c)
- {
- if (likely(s->len < s->size)) {
- if (s->is_wide_char) {
- str16(s->str)[s->len++] = c;
- return 0;
- } else if (c < 0x100) {
- str8(s->str)[s->len++] = c;
- return 0;
- }
- }
- return string_buffer_putc_slow(s, c);
- }
- /* 0 <= c <= 0x10ffff */
- static int string_buffer_putc(StringBuffer *s, uint32_t c)
- {
- if (unlikely(c >= 0x10000)) {
- /* surrogate pair */
- if (string_buffer_putc16(s, get_hi_surrogate(c)))
- return -1;
- c = get_lo_surrogate(c);
- }
- return string_buffer_putc16(s, c);
- }
- static int string_getc(JSString *p, int *pidx)
- {
- int idx, c, c1;
- idx = *pidx;
- if (p->is_wide_char) {
- c = str16(p)[idx++];
- if (is_hi_surrogate(c) && idx < p->len) {
- c1 = str16(p)[idx];
- if (is_lo_surrogate(c1)) {
- c = from_surrogate(c, c1);
- idx++;
- }
- }
- } else {
- c = str8(p)[idx++];
- }
- *pidx = idx;
- return c;
- }
- static int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len)
- {
- int i;
- if (s->len + len > s->size) {
- if (string_buffer_realloc(s, s->len + len, 0))
- return -1;
- }
- if (s->is_wide_char) {
- for (i = 0; i < len; i++) {
- str16(s->str)[s->len + i] = p[i];
- }
- s->len += len;
- } else {
- memcpy(&str8(s->str)[s->len], p, len);
- s->len += len;
- }
- return 0;
- }
- static int string_buffer_write16(StringBuffer *s, const uint16_t *p, int len)
- {
- int c = 0, i;
- for (i = 0; i < len; i++) {
- c |= p[i];
- }
- if (s->len + len > s->size) {
- if (string_buffer_realloc(s, s->len + len, c))
- return -1;
- } else if (!s->is_wide_char && c >= 0x100) {
- if (string_buffer_widen(s, s->size))
- return -1;
- }
- if (s->is_wide_char) {
- memcpy(&str16(s->str)[s->len], p, len << 1);
- s->len += len;
- } else {
- for (i = 0; i < len; i++) {
- str8(s->str)[s->len + i] = p[i];
- }
- s->len += len;
- }
- return 0;
- }
- /* appending an ASCII string */
- static int string_buffer_puts8(StringBuffer *s, const char *str)
- {
- return string_buffer_write8(s, (const uint8_t *)str, strlen(str));
- }
- static int string_buffer_concat(StringBuffer *s, JSString *p,
- uint32_t from, uint32_t to)
- {
- if (to <= from)
- return 0;
- if (p->is_wide_char)
- return string_buffer_write16(s, str16(p) + from, to - from);
- else
- return string_buffer_write8(s, str8(p) + from, to - from);
- }
- static int string_buffer_concat_value(StringBuffer *s, JSValueConst v)
- {
- JSString *p;
- JSValue v1;
- int res;
- if (s->error_status) {
- /* prevent exception overload */
- return -1;
- }
- if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
- v1 = JS_ToString(s->ctx, v);
- if (JS_IsException(v1))
- return string_buffer_set_error(s);
- p = JS_VALUE_GET_STRING(v1);
- res = string_buffer_concat(s, p, 0, p->len);
- JS_FreeValue(s->ctx, v1);
- return res;
- }
- p = JS_VALUE_GET_STRING(v);
- return string_buffer_concat(s, p, 0, p->len);
- }
- static int string_buffer_concat_value_free(StringBuffer *s, JSValue v)
- {
- JSString *p;
- int res;
- if (s->error_status) {
- /* prevent exception overload */
- JS_FreeValue(s->ctx, v);
- return -1;
- }
- if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
- v = JS_ToStringFree(s->ctx, v);
- if (JS_IsException(v))
- return string_buffer_set_error(s);
- }
- p = JS_VALUE_GET_STRING(v);
- res = string_buffer_concat(s, p, 0, p->len);
- JS_FreeValue(s->ctx, v);
- return res;
- }
- static int string_buffer_fill(StringBuffer *s, int c, int count)
- {
- /* XXX: optimize */
- if (s->len + count > s->size) {
- if (string_buffer_realloc(s, s->len + count, c))
- return -1;
- }
- while (count-- > 0) {
- if (string_buffer_putc16(s, c))
- return -1;
- }
- return 0;
- }
- static JSValue string_buffer_end(StringBuffer *s)
- {
- JSString *str;
- str = s->str;
- if (s->error_status)
- return JS_EXCEPTION;
- if (s->len == 0) {
- js_free(s->ctx, str);
- s->str = NULL;
- return js_empty_string(s->ctx->rt);
- }
- if (s->len < s->size) {
- /* smaller size so js_realloc should not fail, but OK if it does */
- /* XXX: should add some slack to avoid unnecessary calls */
- /* XXX: might need to use malloc+free to ensure smaller size */
- str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) +
- (s->len << s->is_wide_char) + 1 - s->is_wide_char);
- if (str == NULL)
- str = s->str;
- s->str = str;
- }
- if (!s->is_wide_char)
- str8(str)[s->len] = 0;
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- list_add_tail(&str->link, &s->ctx->rt->string_list);
- #endif
- str->is_wide_char = s->is_wide_char;
- str->len = s->len;
- s->str = NULL;
- return JS_MKPTR(JS_TAG_STRING, str);
- }
- /* create a string from a UTF-8 buffer */
- JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
- {
- JSString *str;
- size_t len;
- int kind;
- if (buf_len <= 0) {
- return js_empty_string(ctx->rt);
- }
- /* Compute string kind and length: 7-bit, 8-bit, 16-bit, 16-bit UTF-16 */
- kind = utf8_scan(buf, buf_len, &len);
- if (len > JS_STRING_LEN_MAX)
- return JS_ThrowRangeError(ctx, "invalid string length");
- switch (kind) {
- case UTF8_PLAIN_ASCII:
- str = js_alloc_string(ctx, len, 0);
- if (!str)
- return JS_EXCEPTION;
- memcpy(str8(str), buf, len);
- str8(str)[len] = '\0';
- break;
- case UTF8_NON_ASCII:
- /* buf contains non-ASCII code-points, but limited to 8-bit values */
- str = js_alloc_string(ctx, len, 0);
- if (!str)
- return JS_EXCEPTION;
- utf8_decode_buf8(str8(str), len + 1, buf, buf_len);
- break;
- default:
- // This causes a potential problem in JS_ThrowError if message is invalid
- //if (kind & UTF8_HAS_ERRORS)
- // return JS_ThrowRangeError(ctx, "invalid UTF-8 sequence");
- str = js_alloc_string(ctx, len, 1);
- if (!str)
- return JS_EXCEPTION;
- utf8_decode_buf16(str16(str), len, buf, buf_len);
- break;
- }
- return JS_MKPTR(JS_TAG_STRING, str);
- }
- JSValue JS_NewTwoByteString(JSContext *ctx, const uint16_t *buf, size_t len)
- {
- JSString *str;
- if (!len)
- return js_empty_string(ctx->rt);
- str = js_alloc_string(ctx, len, 1);
- if (!str)
- return JS_EXCEPTION;
- memcpy(str16(str), buf, len * sizeof(*buf));
- return JS_MKPTR(JS_TAG_STRING, str);
- }
- static JSValue JS_ConcatString3(JSContext *ctx, const char *str1,
- JSValue str2, const char *str3)
- {
- StringBuffer b_s, *b = &b_s;
- int len1, len3;
- JSString *p;
- if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) {
- str2 = JS_ToStringFree(ctx, str2);
- if (JS_IsException(str2))
- goto fail;
- }
- p = JS_VALUE_GET_STRING(str2);
- len1 = strlen(str1);
- len3 = strlen(str3);
- if (string_buffer_init2(ctx, b, len1 + p->len + len3, p->is_wide_char))
- goto fail;
- string_buffer_write8(b, (const uint8_t *)str1, len1);
- string_buffer_concat(b, p, 0, p->len);
- string_buffer_write8(b, (const uint8_t *)str3, len3);
- JS_FreeValue(ctx, str2);
- return string_buffer_end(b);
- fail:
- JS_FreeValue(ctx, str2);
- return JS_EXCEPTION;
- }
- /* `str` may be pure ASCII or UTF-8 encoded */
- JSValue JS_NewAtomString(JSContext *ctx, const char *str)
- {
- JSAtom atom = JS_NewAtom(ctx, str);
- if (atom == JS_ATOM_NULL)
- return JS_EXCEPTION;
- JSValue val = JS_AtomToString(ctx, atom);
- JS_FreeAtom(ctx, atom);
- return val;
- }
- /* return (NULL, 0) if exception. */
- /* return pointer into a JSString with a live ref_count */
- /* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */
- const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1,
- bool cesu8)
- {
- JSValue val;
- JSString *str, *str_new;
- int pos, len, c, c1;
- JSObject *p;
- uint8_t *q;
- if (JS_VALUE_GET_TAG(val1) == JS_TAG_STRING) {
- val = js_dup(val1);
- goto go;
- }
- val = JS_ToString(ctx, val1);
- if (!JS_IsException(val))
- goto go;
- // Stringification can fail when there is an exception pending,
- // e.g. a stack overflow InternalError. Special-case exception
- // objects to make debugging easier, look up the .message property
- // and stringify that.
- if (JS_VALUE_GET_TAG(val1) != JS_TAG_OBJECT)
- goto fail;
- p = JS_VALUE_GET_OBJ(val1);
- if (p->class_id != JS_CLASS_ERROR)
- goto fail;
- val = JS_GetProperty(ctx, val1, JS_ATOM_message);
- if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) {
- JS_FreeValue(ctx, val);
- goto fail;
- }
- go:
- str = JS_VALUE_GET_STRING(val);
- len = str->len;
- if (!str->is_wide_char) {
- const uint8_t *src = str8(str);
- int count;
- /* count the number of non-ASCII characters */
- /* Scanning the whole string is required for ASCII strings,
- and computing the number of non-ASCII bytes is less expensive
- than testing each byte, hence this method is faster for ASCII
- strings, which is the most common case.
- */
- count = 0;
- for (pos = 0; pos < len; pos++) {
- count += src[pos] >> 7;
- }
- if (count == 0 && str->kind == JS_STRING_KIND_NORMAL) {
- if (plen)
- *plen = len;
- return (const char *)src;
- }
- str_new = js_alloc_string(ctx, len + count, 0);
- if (!str_new)
- goto fail;
- q = str8(str_new);
- for (pos = 0; pos < len; pos++) {
- c = src[pos];
- if (c < 0x80) {
- *q++ = c;
- } else {
- *q++ = (c >> 6) | 0xc0;
- *q++ = (c & 0x3f) | 0x80;
- }
- }
- } else {
- const uint16_t *src = str16(str);
- /* Allocate 3 bytes per 16 bit code point. Surrogate pairs may
- produce 4 bytes but use 2 code points.
- */
- str_new = js_alloc_string(ctx, len * 3, 0);
- if (!str_new)
- goto fail;
- q = str8(str_new);
- pos = 0;
- while (pos < len) {
- c = src[pos++];
- if (c < 0x80) {
- *q++ = c;
- } else {
- if (is_hi_surrogate(c)) {
- if (pos < len && !cesu8) {
- c1 = src[pos];
- if (is_lo_surrogate(c1)) {
- pos++;
- c = from_surrogate(c, c1);
- } else {
- /* Keep unmatched surrogate code points */
- /* c = 0xfffd; */ /* error */
- }
- } else {
- /* Keep unmatched surrogate code points */
- /* c = 0xfffd; */ /* error */
- }
- }
- q += utf8_encode(q, c);
- }
- }
- }
- *q = '\0';
- str_new->len = q - str8(str_new);
- JS_FreeValue(ctx, val);
- if (plen)
- *plen = str_new->len;
- return (const char *)str8(str_new);
- fail:
- if (plen)
- *plen = 0;
- return NULL;
- }
- void JS_FreeCString(JSContext *ctx, const char *ptr)
- {
- if (!ptr)
- return;
- /* purposely removing constness */
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, (JSString *)ptr - 1));
- }
- static int memcmp16_8(const uint16_t *src1, const uint8_t *src2, int len)
- {
- int c, i;
- for(i = 0; i < len; i++) {
- c = src1[i] - src2[i];
- if (c != 0)
- return c;
- }
- return 0;
- }
- static int memcmp16(const uint16_t *src1, const uint16_t *src2, int len)
- {
- int c, i;
- for(i = 0; i < len; i++) {
- c = src1[i] - src2[i];
- if (c != 0)
- return c;
- }
- return 0;
- }
- static int js_string_memcmp(JSString *p1, JSString *p2, int len)
- {
- int res;
- if (likely(!p1->is_wide_char)) {
- if (likely(!p2->is_wide_char))
- res = memcmp(str8(p1), str8(p2), len);
- else
- res = -memcmp16_8(str16(p2), str8(p1), len);
- } else {
- if (!p2->is_wide_char)
- res = memcmp16_8(str16(p1), str8(p2), len);
- else
- res = memcmp16(str16(p1), str16(p2), len);
- }
- return res;
- }
- static bool js_string_eq(JSString *p1, JSString *p2) {
- if (p1->len != p2->len)
- return false;
- return js_string_memcmp(p1, p2, p1->len) == 0;
- }
- /* return < 0, 0 or > 0 */
- static int js_string_compare(JSString *p1, JSString *p2)
- {
- int res, len;
- len = min_int(p1->len, p2->len);
- res = js_string_memcmp(p1, p2, len);
- if (res == 0)
- res = compare_u32(p1->len, p2->len);
- return res;
- }
- static void copy_str16(uint16_t *dst, JSString *p, int offset, int len)
- {
- if (p->is_wide_char) {
- memcpy(dst, str16(p) + offset, len * 2);
- } else {
- const uint8_t *src1 = str8(p) + offset;
- int i;
- for(i = 0; i < len; i++)
- dst[i] = src1[i];
- }
- }
- static JSValue JS_ConcatString1(JSContext *ctx, JSString *p1, JSString *p2)
- {
- JSString *p;
- uint32_t len;
- int is_wide_char;
- len = p1->len + p2->len;
- if (len > JS_STRING_LEN_MAX)
- return JS_ThrowRangeError(ctx, "invalid string length");
- is_wide_char = p1->is_wide_char | p2->is_wide_char;
- p = js_alloc_string(ctx, len, is_wide_char);
- if (!p)
- return JS_EXCEPTION;
- if (!is_wide_char) {
- memcpy(str8(p), str8(p1), p1->len);
- memcpy(str8(p) + p1->len, str8(p2), p2->len);
- str8(p)[len] = '\0';
- } else {
- copy_str16(str16(p), p1, 0, p1->len);
- copy_str16(str16(p) + p1->len, p2, 0, p2->len);
- }
- return JS_MKPTR(JS_TAG_STRING, p);
- }
- /* op1 and op2 are converted to strings. For convience, op1 or op2 =
- JS_EXCEPTION are accepted and return JS_EXCEPTION. */
- static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2)
- {
- JSValue ret;
- JSString *p1, *p2;
- if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING)) {
- op1 = JS_ToStringFree(ctx, op1);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- return JS_EXCEPTION;
- }
- }
- if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING)) {
- op2 = JS_ToStringFree(ctx, op2);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- return JS_EXCEPTION;
- }
- }
- p1 = JS_VALUE_GET_STRING(op1);
- p2 = JS_VALUE_GET_STRING(op2);
- /* XXX: could also check if p1 is empty */
- if (p2->len == 0) {
- goto ret_op1;
- }
- if (p1->header.ref_count == 1 && p1->is_wide_char == p2->is_wide_char
- && js_malloc_usable_size(ctx, p1) >= sizeof(*p1) + ((p1->len + p2->len) << p2->is_wide_char) + 1 - p1->is_wide_char) {
- /* Concatenate in place in available space at the end of p1 */
- if (p1->is_wide_char) {
- memcpy(str16(p1) + p1->len, str16(p2), p2->len << 1);
- p1->len += p2->len;
- } else {
- memcpy(str8(p1) + p1->len, str8(p2), p2->len);
- p1->len += p2->len;
- str8(p1)[p1->len] = '\0';
- }
- ret_op1:
- JS_FreeValue(ctx, op2);
- return op1;
- }
- ret = JS_ConcatString1(ctx, p1, p2);
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- return ret;
- }
- /* Shape support */
- static inline size_t get_shape_size(size_t hash_size, size_t prop_size)
- {
- return hash_size * sizeof(uint32_t) + sizeof(JSShape) +
- prop_size * sizeof(JSShapeProperty);
- }
- static inline JSShape *get_shape_from_alloc(void *sh_alloc, size_t hash_size)
- {
- return (JSShape *)(void *)((uint32_t *)sh_alloc + hash_size);
- }
- static inline uint32_t *prop_hash_end(JSShape *sh)
- {
- return (uint32_t *)sh;
- }
- static inline void *get_alloc_from_shape(JSShape *sh)
- {
- return prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1);
- }
- static inline JSShapeProperty *get_shape_prop(JSShape *sh)
- {
- return sh->prop;
- }
- static int init_shape_hash(JSRuntime *rt)
- {
- rt->shape_hash_bits = 6; /* 64 shapes */
- rt->shape_hash_size = 1 << rt->shape_hash_bits;
- rt->shape_hash_count = 0;
- rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
- rt->shape_hash_size);
- if (!rt->shape_hash)
- return -1;
- return 0;
- }
- /* same magic hash multiplier as the Linux kernel */
- static uint32_t shape_hash(uint32_t h, uint32_t val)
- {
- return (h + val) * 0x9e370001;
- }
- /* truncate the shape hash to 'hash_bits' bits */
- static uint32_t get_shape_hash(uint32_t h, int hash_bits)
- {
- return h >> (32 - hash_bits);
- }
- static uint32_t shape_initial_hash(JSObject *proto)
- {
- uint32_t h;
- h = shape_hash(1, (uintptr_t)proto);
- if (sizeof(proto) > 4)
- h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32);
- return h;
- }
- static int resize_shape_hash(JSRuntime *rt, int new_shape_hash_bits)
- {
- int new_shape_hash_size, i;
- uint32_t h;
- JSShape **new_shape_hash, *sh, *sh_next;
- new_shape_hash_size = 1 << new_shape_hash_bits;
- new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
- new_shape_hash_size);
- if (!new_shape_hash)
- return -1;
- for(i = 0; i < rt->shape_hash_size; i++) {
- for(sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) {
- sh_next = sh->shape_hash_next;
- h = get_shape_hash(sh->hash, new_shape_hash_bits);
- sh->shape_hash_next = new_shape_hash[h];
- new_shape_hash[h] = sh;
- }
- }
- js_free_rt(rt, rt->shape_hash);
- rt->shape_hash_bits = new_shape_hash_bits;
- rt->shape_hash_size = new_shape_hash_size;
- rt->shape_hash = new_shape_hash;
- return 0;
- }
- static void js_shape_hash_link(JSRuntime *rt, JSShape *sh)
- {
- uint32_t h;
- h = get_shape_hash(sh->hash, rt->shape_hash_bits);
- sh->shape_hash_next = rt->shape_hash[h];
- rt->shape_hash[h] = sh;
- rt->shape_hash_count++;
- }
- static void js_shape_hash_unlink(JSRuntime *rt, JSShape *sh)
- {
- uint32_t h;
- JSShape **psh;
- h = get_shape_hash(sh->hash, rt->shape_hash_bits);
- psh = &rt->shape_hash[h];
- while (*psh != sh)
- psh = &(*psh)->shape_hash_next;
- *psh = sh->shape_hash_next;
- rt->shape_hash_count--;
- }
- /* create a new empty shape with prototype 'proto' */
- static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto,
- int hash_size, int prop_size)
- {
- JSRuntime *rt = ctx->rt;
- void *sh_alloc;
- JSShape *sh;
- /* resize the shape hash table if necessary */
- if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) {
- resize_shape_hash(rt, rt->shape_hash_bits + 1);
- }
- sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size));
- if (!sh_alloc)
- return NULL;
- sh = get_shape_from_alloc(sh_alloc, hash_size);
- sh->header.ref_count = 1;
- add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
- if (proto)
- js_dup(JS_MKPTR(JS_TAG_OBJECT, proto));
- sh->proto = proto;
- memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) *
- hash_size);
- sh->prop_hash_mask = hash_size - 1;
- sh->prop_size = prop_size;
- sh->prop_count = 0;
- sh->deleted_prop_count = 0;
- /* insert in the hash table */
- sh->hash = shape_initial_hash(proto);
- sh->is_hashed = true;
- sh->has_small_array_index = false;
- js_shape_hash_link(ctx->rt, sh);
- return sh;
- }
- static JSShape *js_new_shape(JSContext *ctx, JSObject *proto)
- {
- return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE,
- JS_PROP_INITIAL_SIZE);
- }
- /* The shape is cloned. The new shape is not inserted in the shape
- hash table */
- static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1)
- {
- JSShape *sh;
- void *sh_alloc, *sh_alloc1;
- size_t size;
- JSShapeProperty *pr;
- uint32_t i, hash_size;
- hash_size = sh1->prop_hash_mask + 1;
- size = get_shape_size(hash_size, sh1->prop_size);
- sh_alloc = js_malloc(ctx, size);
- if (!sh_alloc)
- return NULL;
- sh_alloc1 = get_alloc_from_shape(sh1);
- memcpy(sh_alloc, sh_alloc1, size);
- sh = get_shape_from_alloc(sh_alloc, hash_size);
- sh->header.ref_count = 1;
- add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
- sh->is_hashed = false;
- if (sh->proto) {
- js_dup(JS_MKPTR(JS_TAG_OBJECT, sh->proto));
- }
- for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
- JS_DupAtom(ctx, pr->atom);
- }
- return sh;
- }
- static JSShape *js_dup_shape(JSShape *sh)
- {
- sh->header.ref_count++;
- return sh;
- }
- static void js_free_shape0(JSRuntime *rt, JSShape *sh)
- {
- uint32_t i;
- JSShapeProperty *pr;
- assert(sh->header.ref_count == 0);
- if (sh->is_hashed)
- js_shape_hash_unlink(rt, sh);
- if (sh->proto != NULL) {
- JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
- }
- pr = get_shape_prop(sh);
- for(i = 0; i < sh->prop_count; i++) {
- JS_FreeAtomRT(rt, pr->atom);
- pr++;
- }
- remove_gc_object(&sh->header);
- js_free_rt(rt, get_alloc_from_shape(sh));
- }
- static void js_free_shape(JSRuntime *rt, JSShape *sh)
- {
- if (unlikely(--sh->header.ref_count <= 0)) {
- js_free_shape0(rt, sh);
- }
- }
- static void js_free_shape_null(JSRuntime *rt, JSShape *sh)
- {
- if (sh)
- js_free_shape(rt, sh);
- }
- /* make space to hold at least 'count' properties */
- static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
- JSObject *p, uint32_t count)
- {
- JSShape *sh;
- uint32_t new_size, new_hash_size, new_hash_mask, i;
- JSShapeProperty *pr;
- void *sh_alloc;
- intptr_t h;
- sh = *psh;
- new_size = max_int(count, sh->prop_size * 3 / 2);
- /* Reallocate prop array first to avoid crash or size inconsistency
- in case of memory allocation failure */
- if (p) {
- JSProperty *new_prop;
- new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
- if (unlikely(!new_prop))
- return -1;
- p->prop = new_prop;
- }
- new_hash_size = sh->prop_hash_mask + 1;
- while (new_hash_size < new_size)
- new_hash_size = 2 * new_hash_size;
- if (new_hash_size != (sh->prop_hash_mask + 1)) {
- JSShape *old_sh;
- /* resize the hash table and the properties */
- old_sh = sh;
- sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
- if (!sh_alloc)
- return -1;
- sh = get_shape_from_alloc(sh_alloc, new_hash_size);
- list_del(&old_sh->header.link);
- /* copy all the fields and the properties */
- memcpy(sh, old_sh,
- sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count);
- list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
- new_hash_mask = new_hash_size - 1;
- sh->prop_hash_mask = new_hash_mask;
- memset(prop_hash_end(sh) - new_hash_size, 0,
- sizeof(prop_hash_end(sh)[0]) * new_hash_size);
- for(i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) {
- if (pr->atom != JS_ATOM_NULL) {
- h = ((uintptr_t)pr->atom & new_hash_mask);
- pr->hash_next = prop_hash_end(sh)[-h - 1];
- prop_hash_end(sh)[-h - 1] = i + 1;
- }
- }
- js_free(ctx, get_alloc_from_shape(old_sh));
- } else {
- /* only resize the properties */
- list_del(&sh->header.link);
- sh_alloc = js_realloc(ctx, get_alloc_from_shape(sh),
- get_shape_size(new_hash_size, new_size));
- if (unlikely(!sh_alloc)) {
- /* insert again in the GC list */
- list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
- return -1;
- }
- sh = get_shape_from_alloc(sh_alloc, new_hash_size);
- list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
- }
- *psh = sh;
- sh->prop_size = new_size;
- return 0;
- }
- /* remove the deleted properties. */
- static int compact_properties(JSContext *ctx, JSObject *p)
- {
- JSShape *sh, *old_sh;
- void *sh_alloc;
- intptr_t h;
- uint32_t new_hash_size, i, j, new_hash_mask, new_size;
- JSShapeProperty *old_pr, *pr;
- JSProperty *prop, *new_prop;
- sh = p->shape;
- assert(!sh->is_hashed);
- new_size = max_int(JS_PROP_INITIAL_SIZE,
- sh->prop_count - sh->deleted_prop_count);
- assert(new_size <= sh->prop_size);
- new_hash_size = sh->prop_hash_mask + 1;
- while ((new_hash_size / 2) >= new_size)
- new_hash_size = new_hash_size / 2;
- new_hash_mask = new_hash_size - 1;
- /* resize the hash table and the properties */
- old_sh = sh;
- sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
- if (!sh_alloc)
- return -1;
- sh = get_shape_from_alloc(sh_alloc, new_hash_size);
- list_del(&old_sh->header.link);
- memcpy(sh, old_sh, sizeof(JSShape));
- list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
- memset(prop_hash_end(sh) - new_hash_size, 0,
- sizeof(prop_hash_end(sh)[0]) * new_hash_size);
- j = 0;
- old_pr = old_sh->prop;
- pr = sh->prop;
- prop = p->prop;
- for(i = 0; i < sh->prop_count; i++) {
- if (old_pr->atom != JS_ATOM_NULL) {
- pr->atom = old_pr->atom;
- pr->flags = old_pr->flags;
- h = ((uintptr_t)old_pr->atom & new_hash_mask);
- pr->hash_next = prop_hash_end(sh)[-h - 1];
- prop_hash_end(sh)[-h - 1] = j + 1;
- prop[j] = prop[i];
- j++;
- pr++;
- }
- old_pr++;
- }
- assert(j == (sh->prop_count - sh->deleted_prop_count));
- sh->prop_hash_mask = new_hash_mask;
- sh->prop_size = new_size;
- sh->deleted_prop_count = 0;
- sh->prop_count = j;
- p->shape = sh;
- js_free(ctx, get_alloc_from_shape(old_sh));
- /* reduce the size of the object properties */
- new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
- if (new_prop)
- p->prop = new_prop;
- return 0;
- }
- static int add_shape_property(JSContext *ctx, JSShape **psh,
- JSObject *p, JSAtom atom, int prop_flags)
- {
- JSRuntime *rt = ctx->rt;
- JSShape *sh = *psh;
- JSShapeProperty *pr, *prop;
- uint32_t hash_mask, new_shape_hash = 0;
- intptr_t h;
- /* update the shape hash */
- if (sh->is_hashed) {
- js_shape_hash_unlink(rt, sh);
- new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags);
- }
- if (unlikely(sh->prop_count >= sh->prop_size)) {
- if (resize_properties(ctx, psh, p, sh->prop_count + 1)) {
- /* in case of error, reinsert in the hash table.
- sh is still valid if resize_properties() failed */
- if (sh->is_hashed)
- js_shape_hash_link(rt, sh);
- return -1;
- }
- sh = *psh;
- }
- if (sh->is_hashed) {
- sh->hash = new_shape_hash;
- js_shape_hash_link(rt, sh);
- }
- /* Initialize the new shape property.
- The object property at p->prop[sh->prop_count] is uninitialized */
- prop = get_shape_prop(sh);
- pr = &prop[sh->prop_count++];
- pr->atom = JS_DupAtom(ctx, atom);
- pr->flags = prop_flags;
- sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom);
- /* add in hash table */
- hash_mask = sh->prop_hash_mask;
- h = atom & hash_mask;
- pr->hash_next = prop_hash_end(sh)[-h - 1];
- prop_hash_end(sh)[-h - 1] = sh->prop_count;
- return 0;
- }
- /* find a hashed empty shape matching the prototype. Return NULL if
- not found */
- static JSShape *find_hashed_shape_proto(JSRuntime *rt, JSObject *proto)
- {
- JSShape *sh1;
- uint32_t h, h1;
- h = shape_initial_hash(proto);
- h1 = get_shape_hash(h, rt->shape_hash_bits);
- for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
- if (sh1->hash == h &&
- sh1->proto == proto &&
- sh1->prop_count == 0) {
- return sh1;
- }
- }
- return NULL;
- }
- /* find a hashed shape matching sh + (prop, prop_flags). Return NULL if
- not found */
- static JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh,
- JSAtom atom, int prop_flags)
- {
- JSShape *sh1;
- uint32_t h, h1, i, n;
- h = sh->hash;
- h = shape_hash(h, atom);
- h = shape_hash(h, prop_flags);
- h1 = get_shape_hash(h, rt->shape_hash_bits);
- for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
- /* we test the hash first so that the rest is done only if the
- shapes really match */
- if (sh1->hash == h &&
- sh1->proto == sh->proto &&
- sh1->prop_count == ((n = sh->prop_count) + 1)) {
- for(i = 0; i < n; i++) {
- if (unlikely(sh1->prop[i].atom != sh->prop[i].atom) ||
- unlikely(sh1->prop[i].flags != sh->prop[i].flags))
- goto next;
- }
- if (unlikely(sh1->prop[n].atom != atom) ||
- unlikely(sh1->prop[n].flags != prop_flags))
- goto next;
- return sh1;
- }
- next: ;
- }
- return NULL;
- }
- static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
- {
- char atom_buf[ATOM_GET_STR_BUF_SIZE];
- int j;
- /* XXX: should output readable class prototype */
- printf("%5d %3d%c %14p %5d %5d", i,
- sh->header.ref_count, " *"[sh->is_hashed],
- (void *)sh->proto, sh->prop_size, sh->prop_count);
- for(j = 0; j < sh->prop_count; j++) {
- printf(" %s", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf),
- sh->prop[j].atom));
- }
- printf("\n");
- }
- static __maybe_unused void JS_DumpShapes(JSRuntime *rt)
- {
- int i;
- JSShape *sh;
- struct list_head *el;
- JSObject *p;
- JSGCObjectHeader *gp;
- printf("JSShapes: {\n");
- printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS");
- for(i = 0; i < rt->shape_hash_size; i++) {
- for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
- JS_DumpShape(rt, i, sh);
- assert(sh->is_hashed);
- }
- }
- /* dump non-hashed shapes */
- list_for_each(el, &rt->gc_obj_list) {
- gp = list_entry(el, JSGCObjectHeader, link);
- if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
- p = (JSObject *)gp;
- if (!p->shape->is_hashed) {
- JS_DumpShape(rt, -1, p->shape);
- }
- }
- }
- printf("}\n");
- }
- static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID class_id)
- {
- JSObject *p;
- js_trigger_gc(ctx->rt, sizeof(JSObject));
- p = js_malloc(ctx, sizeof(JSObject));
- if (unlikely(!p))
- goto fail;
- p->class_id = class_id;
- p->extensible = true;
- p->free_mark = 0;
- p->is_exotic = 0;
- p->fast_array = 0;
- p->is_constructor = 0;
- p->is_uncatchable_error = 0;
- p->tmp_mark = 0;
- p->is_HTMLDDA = 0;
- p->first_weak_ref = NULL;
- p->u.opaque = NULL;
- p->shape = sh;
- p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size);
- if (unlikely(!p->prop)) {
- js_free(ctx, p);
- fail:
- js_free_shape(ctx->rt, sh);
- return JS_EXCEPTION;
- }
- switch(class_id) {
- case JS_CLASS_OBJECT:
- break;
- case JS_CLASS_ARRAY:
- {
- JSProperty *pr;
- p->is_exotic = 1;
- p->fast_array = 1;
- p->u.array.u.values = NULL;
- p->u.array.count = 0;
- p->u.array.u1.size = 0;
- /* the length property is always the first one */
- if (likely(sh == ctx->array_shape)) {
- pr = &p->prop[0];
- } else {
- /* only used for the first array */
- /* cannot fail */
- pr = add_property(ctx, p, JS_ATOM_length,
- JS_PROP_WRITABLE | JS_PROP_LENGTH);
- }
- pr->u.value = js_int32(0);
- }
- break;
- case JS_CLASS_C_FUNCTION:
- p->prop[0].u.value = JS_UNDEFINED;
- break;
- case JS_CLASS_ARGUMENTS:
- case JS_CLASS_UINT8C_ARRAY:
- case JS_CLASS_INT8_ARRAY:
- case JS_CLASS_UINT8_ARRAY:
- case JS_CLASS_INT16_ARRAY:
- case JS_CLASS_UINT16_ARRAY:
- case JS_CLASS_INT32_ARRAY:
- case JS_CLASS_UINT32_ARRAY:
- case JS_CLASS_BIG_INT64_ARRAY:
- case JS_CLASS_BIG_UINT64_ARRAY:
- case JS_CLASS_FLOAT16_ARRAY:
- case JS_CLASS_FLOAT32_ARRAY:
- case JS_CLASS_FLOAT64_ARRAY:
- p->is_exotic = 1;
- p->fast_array = 1;
- p->u.array.u.ptr = NULL;
- p->u.array.count = 0;
- break;
- case JS_CLASS_DATAVIEW:
- p->u.array.u.ptr = NULL;
- p->u.array.count = 0;
- break;
- case JS_CLASS_NUMBER:
- case JS_CLASS_STRING:
- case JS_CLASS_BOOLEAN:
- case JS_CLASS_SYMBOL:
- case JS_CLASS_DATE:
- case JS_CLASS_BIG_INT:
- p->u.object_data = JS_UNDEFINED;
- goto set_exotic;
- case JS_CLASS_REGEXP:
- p->u.regexp.pattern = NULL;
- p->u.regexp.bytecode = NULL;
- goto set_exotic;
- default:
- set_exotic:
- if (ctx->rt->class_array[class_id].exotic) {
- p->is_exotic = 1;
- }
- break;
- }
- p->header.ref_count = 1;
- add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT);
- return JS_MKPTR(JS_TAG_OBJECT, p);
- }
- static JSObject *get_proto_obj(JSValueConst proto_val)
- {
- if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT)
- return NULL;
- else
- return JS_VALUE_GET_OBJ(proto_val);
- }
- /* WARNING: proto must be an object or JS_NULL */
- JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val,
- JSClassID class_id)
- {
- JSShape *sh;
- JSObject *proto;
- proto = get_proto_obj(proto_val);
- sh = find_hashed_shape_proto(ctx->rt, proto);
- if (likely(sh)) {
- sh = js_dup_shape(sh);
- } else {
- sh = js_new_shape(ctx, proto);
- if (!sh)
- return JS_EXCEPTION;
- }
- return JS_NewObjectFromShape(ctx, sh, class_id);
- }
- static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
- p = JS_VALUE_GET_OBJ(obj);
- switch(p->class_id) {
- case JS_CLASS_NUMBER:
- case JS_CLASS_STRING:
- case JS_CLASS_BOOLEAN:
- case JS_CLASS_SYMBOL:
- case JS_CLASS_DATE:
- case JS_CLASS_BIG_INT:
- JS_FreeValue(ctx, p->u.object_data);
- p->u.object_data = val;
- return 0;
- }
- }
- JS_FreeValue(ctx, val);
- if (!JS_IsException(obj))
- JS_ThrowTypeError(ctx, "invalid object type");
- return -1;
- }
- JSValue JS_NewObjectClass(JSContext *ctx, JSClassID class_id)
- {
- return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id);
- }
- JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto)
- {
- return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT);
- }
- JSValue JS_NewObjectFrom(JSContext *ctx, int count, const JSAtom *props,
- const JSValue *values)
- {
- JSShapeProperty *pr;
- uint32_t *hash;
- JSRuntime *rt;
- JSObject *p;
- JSShape *sh;
- JSValue obj;
- JSAtom atom;
- intptr_t h;
- int i;
- rt = ctx->rt;
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- if (count > 0) {
- p = JS_VALUE_GET_OBJ(obj);
- sh = p->shape;
- assert(sh->is_hashed);
- assert(sh->header.ref_count == 1);
- js_shape_hash_unlink(rt, sh);
- if (resize_properties(ctx, &sh, p, count)) {
- js_shape_hash_link(rt, sh);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- p->shape = sh;
- for (i = 0; i < count; i++) {
- atom = props[i];
- pr = &sh->prop[i];
- sh->hash = shape_hash(shape_hash(sh->hash, atom), JS_PROP_C_W_E);
- sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom);
- h = atom & sh->prop_hash_mask;
- hash = &prop_hash_end(sh)[-h - 1];
- pr->hash_next = *hash;
- *hash = i + 1;
- pr->atom = JS_DupAtom(ctx, atom);
- pr->flags = JS_PROP_C_W_E;
- p->prop[i].u.value = values[i];
- }
- js_shape_hash_link(rt, sh);
- sh->prop_count = count;
- }
- return obj;
- }
- JSValue JS_NewObjectFromStr(JSContext *ctx, int count, const char **props,
- const JSValue *values)
- {
- JSAtom atoms_s[16], *atoms = atoms_s;
- JSValue ret;
- int i;
- i = 0;
- ret = JS_EXCEPTION;
- if (count < 1)
- goto out;
- if (count > (int)countof(atoms_s)) {
- atoms = js_malloc(ctx, count * sizeof(*atoms));
- if (!atoms)
- return JS_EXCEPTION;
- }
- for (i = 0; i < count; i++) {
- atoms[i] = JS_NewAtom(ctx, props[i]);
- if (atoms[i] == JS_ATOM_NULL)
- goto out;
- }
- ret = JS_NewObjectFrom(ctx, count, atoms, values);
- out:
- while (i-- > 0)
- JS_FreeAtom(ctx, atoms[i]);
- if (atoms != atoms_s)
- js_free(ctx, atoms);
- return ret;
- }
- JSValue JS_NewArray(JSContext *ctx)
- {
- return JS_NewObjectFromShape(ctx, js_dup_shape(ctx->array_shape),
- JS_CLASS_ARRAY);
- }
- // note: takes ownership of |values|, unlike js_create_array
- JSValue JS_NewArrayFrom(JSContext *ctx, int count, const JSValue *values)
- {
- JSObject *p;
- JSValue obj;
- int i;
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj))
- goto exception;
- if (count > 0) {
- p = JS_VALUE_GET_OBJ(obj);
- if (expand_fast_array(ctx, p, count)) {
- JS_FreeValue(ctx, obj);
- goto exception;
- }
- p->u.array.count = count;
- p->prop[0].u.value = js_int32(count);
- memcpy(p->u.array.u.values, values, count * sizeof(*values));
- }
- return obj;
- exception:
- for (i = 0; i < count; i++)
- JS_FreeValue(ctx, values[i]);
- return JS_EXCEPTION;
- }
- JSValue JS_NewObject(JSContext *ctx)
- {
- /* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */
- return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT);
- }
- static void js_function_set_properties(JSContext *ctx, JSValue func_obj,
- JSAtom name, int len)
- {
- /* ES6 feature non compatible with ES5.1: length is configurable */
- JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, js_int32(len),
- JS_PROP_CONFIGURABLE);
- JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name,
- JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE);
- }
- static bool js_class_has_bytecode(JSClassID class_id)
- {
- return (class_id == JS_CLASS_BYTECODE_FUNCTION ||
- class_id == JS_CLASS_GENERATOR_FUNCTION ||
- class_id == JS_CLASS_ASYNC_FUNCTION ||
- class_id == JS_CLASS_ASYNC_GENERATOR_FUNCTION);
- }
- /* return NULL without exception if not a function or no bytecode */
- static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return NULL;
- p = JS_VALUE_GET_OBJ(val);
- if (!js_class_has_bytecode(p->class_id))
- return NULL;
- return p->u.func.function_bytecode;
- }
- static void js_method_set_home_object(JSContext *ctx, JSValue func_obj,
- JSValue home_obj)
- {
- JSObject *p, *p1;
- JSFunctionBytecode *b;
- if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
- return;
- p = JS_VALUE_GET_OBJ(func_obj);
- if (!js_class_has_bytecode(p->class_id))
- return;
- b = p->u.func.function_bytecode;
- if (b->need_home_object) {
- p1 = p->u.func.home_object;
- if (p1) {
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
- }
- if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT)
- p1 = JS_VALUE_GET_OBJ(js_dup(home_obj));
- else
- p1 = NULL;
- p->u.func.home_object = p1;
- }
- }
- static JSValue js_get_function_name(JSContext *ctx, JSAtom name)
- {
- JSValue name_str;
- name_str = JS_AtomToString(ctx, name);
- if (JS_AtomSymbolHasDescription(ctx, name)) {
- name_str = JS_ConcatString3(ctx, "[", name_str, "]");
- }
- return name_str;
- }
- /* Modify the name of a method according to the atom and
- 'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and
- JS_PROP_HAS_SET. Also set the home object of the method.
- Return < 0 if exception. */
- static int js_method_set_properties(JSContext *ctx, JSValue func_obj,
- JSAtom name, int flags, JSValue home_obj)
- {
- JSValue name_str;
- name_str = js_get_function_name(ctx, name);
- if (flags & JS_PROP_HAS_GET) {
- name_str = JS_ConcatString3(ctx, "get ", name_str, "");
- } else if (flags & JS_PROP_HAS_SET) {
- name_str = JS_ConcatString3(ctx, "set ", name_str, "");
- }
- if (JS_IsException(name_str))
- return -1;
- if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name_str,
- JS_PROP_CONFIGURABLE) < 0)
- return -1;
- js_method_set_home_object(ctx, func_obj, home_obj);
- return 0;
- }
- /* Note: at least 'length' arguments will be readable in 'argv' */
- /* `name` may be NULL, pure ASCII or UTF-8 encoded */
- JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
- const char *name,
- int length, JSCFunctionEnum cproto, int magic,
- JSValueConst proto_val)
- {
- JSValue func_obj;
- JSObject *p;
- JSAtom name_atom;
- func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION);
- if (JS_IsException(func_obj))
- return func_obj;
- p = JS_VALUE_GET_OBJ(func_obj);
- p->u.cfunc.realm = JS_DupContext(ctx);
- p->u.cfunc.c_function.generic = func;
- p->u.cfunc.length = length;
- p->u.cfunc.cproto = cproto;
- p->u.cfunc.magic = magic;
- p->is_constructor = (cproto == JS_CFUNC_constructor ||
- cproto == JS_CFUNC_constructor_magic ||
- cproto == JS_CFUNC_constructor_or_func ||
- cproto == JS_CFUNC_constructor_or_func_magic);
- name_atom = JS_ATOM_empty_string;
- if (name && *name) {
- name_atom = JS_NewAtom(ctx, name);
- if (name_atom == JS_ATOM_NULL) {
- JS_FreeValue(ctx, func_obj);
- return JS_EXCEPTION;
- }
- }
- js_function_set_properties(ctx, func_obj, name_atom, length);
- JS_FreeAtom(ctx, name_atom);
- return func_obj;
- }
- /* Note: at least 'length' arguments will be readable in 'argv' */
- JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
- const char *name,
- int length, JSCFunctionEnum cproto, int magic)
- {
- return JS_NewCFunction3(ctx, func, name, length, cproto, magic,
- ctx->function_proto);
- }
- typedef struct JSCFunctionDataRecord {
- JSCFunctionData *func;
- uint8_t length;
- uint8_t data_len;
- uint16_t magic;
- JSValue data[];
- } JSCFunctionDataRecord;
- static void js_c_function_data_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
- int i;
- if (s) {
- for(i = 0; i < s->data_len; i++) {
- JS_FreeValueRT(rt, s->data[i]);
- }
- js_free_rt(rt, s);
- }
- }
- static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
- int i;
- if (s) {
- for(i = 0; i < s->data_len; i++) {
- JS_MarkValue(rt, s->data[i], mark_func);
- }
- }
- }
- static JSValue js_call_c_function_data(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_val,
- int argc, JSValueConst *argv, int flags)
- {
- JSRuntime *rt = ctx->rt;
- JSStackFrame sf_s, *sf = &sf_s, *prev_sf;
- JSCFunctionDataRecord *s;
- JSValueConst *arg_buf;
- JSValue ret;
- size_t stack_size;
- int arg_count;
- int i;
- s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA);
- if (!s)
- return JS_EXCEPTION; // can't really happen
- arg_buf = argv;
- arg_count = s->length;
- if (unlikely(argc < arg_count)) {
- stack_size = arg_count * sizeof(arg_buf[0]);
- if (js_check_stack_overflow(rt, stack_size))
- return JS_ThrowStackOverflow(ctx);
- arg_buf = alloca(stack_size);
- for(i = 0; i < argc; i++)
- arg_buf[i] = argv[i];
- for(i = argc; i < arg_count; i++)
- arg_buf[i] = JS_UNDEFINED;
- }
- prev_sf = rt->current_stack_frame;
- sf->prev_frame = prev_sf;
- rt->current_stack_frame = sf;
- // TODO(bnoordhuis) switch realms like js_call_c_function does
- sf->is_strict_mode = false;
- sf->cur_func = unsafe_unconst(func_obj);
- sf->arg_count = argc;
- ret = s->func(ctx, this_val, argc, arg_buf, s->magic, vc(s->data));
- rt->current_stack_frame = sf->prev_frame;
- return ret;
- }
- JSValue JS_NewCFunctionData2(JSContext *ctx, JSCFunctionData *func,
- const char *name,
- int length, int magic, int data_len,
- JSValueConst *data)
- {
- JSCFunctionDataRecord *s;
- JSAtom name_atom;
- JSValue func_obj;
- int i;
- func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
- JS_CLASS_C_FUNCTION_DATA);
- if (JS_IsException(func_obj))
- return func_obj;
- s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue));
- if (!s) {
- JS_FreeValue(ctx, func_obj);
- return JS_EXCEPTION;
- }
- s->func = func;
- s->length = length;
- s->data_len = data_len;
- s->magic = magic;
- for(i = 0; i < data_len; i++)
- s->data[i] = js_dup(data[i]);
- JS_SetOpaqueInternal(func_obj, s);
- name_atom = JS_ATOM_empty_string;
- if (name && *name) {
- name_atom = JS_NewAtom(ctx, name);
- if (name_atom == JS_ATOM_NULL) {
- JS_FreeValue(ctx, func_obj);
- return JS_EXCEPTION;
- }
- }
- js_function_set_properties(ctx, func_obj, name_atom, length);
- JS_FreeAtom(ctx, name_atom);
- return func_obj;
- }
- JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
- int length, int magic, int data_len,
- JSValueConst *data)
- {
- return JS_NewCFunctionData2(ctx, func, NULL, length, magic, data_len, data);
- }
- static JSContext *js_autoinit_get_realm(JSProperty *pr)
- {
- return (JSContext *)(pr->u.init.realm_and_id & ~3);
- }
- static JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr)
- {
- return pr->u.init.realm_and_id & 3;
- }
- static void js_autoinit_free(JSRuntime *rt, JSProperty *pr)
- {
- JS_FreeContext(js_autoinit_get_realm(pr));
- }
- static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr,
- JS_MarkFunc *mark_func)
- {
- mark_func(rt, &js_autoinit_get_realm(pr)->header);
- }
- static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)
- {
- if (unlikely(prop_flags & JS_PROP_TMASK)) {
- if ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
- if (pr->u.getset.getter)
- JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
- if (pr->u.getset.setter)
- JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
- } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
- free_var_ref(rt, pr->u.var_ref);
- } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- js_autoinit_free(rt, pr);
- }
- } else {
- JS_FreeValueRT(rt, pr->u.value);
- }
- }
- static force_inline JSShapeProperty *find_own_property1(JSObject *p,
- JSAtom atom)
- {
- JSShape *sh;
- JSShapeProperty *pr, *prop;
- intptr_t h;
- sh = p->shape;
- h = (uintptr_t)atom & sh->prop_hash_mask;
- h = prop_hash_end(sh)[-h - 1];
- prop = get_shape_prop(sh);
- while (h) {
- pr = &prop[h - 1];
- if (likely(pr->atom == atom)) {
- return pr;
- }
- h = pr->hash_next;
- }
- return NULL;
- }
- static force_inline JSShapeProperty *find_own_property(JSProperty **ppr,
- JSObject *p,
- JSAtom atom)
- {
- JSShape *sh;
- JSShapeProperty *pr, *prop;
- intptr_t h;
- sh = p->shape;
- h = (uintptr_t)atom & sh->prop_hash_mask;
- h = prop_hash_end(sh)[-h - 1];
- prop = get_shape_prop(sh);
- while (h) {
- pr = &prop[h - 1];
- if (likely(pr->atom == atom)) {
- *ppr = &p->prop[h - 1];
- /* the compiler should be able to assume that pr != NULL here */
- return pr;
- }
- h = pr->hash_next;
- }
- *ppr = NULL;
- return NULL;
- }
- static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)
- {
- if (var_ref) {
- assert(var_ref->header.ref_count > 0);
- if (--var_ref->header.ref_count == 0) {
- if (var_ref->is_detached) {
- JS_FreeValueRT(rt, var_ref->value);
- remove_gc_object(&var_ref->header);
- } else {
- list_del(&var_ref->header.link); /* still on the stack */
- }
- js_free_rt(rt, var_ref);
- }
- }
- }
- static void js_array_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- int i;
- for(i = 0; i < p->u.array.count; i++) {
- JS_FreeValueRT(rt, p->u.array.u.values[i]);
- }
- js_free_rt(rt, p->u.array.u.values);
- }
- static void js_array_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- int i;
- for(i = 0; i < p->u.array.count; i++) {
- JS_MarkValue(rt, p->u.array.u.values[i], mark_func);
- }
- }
- static void js_object_data_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JS_FreeValueRT(rt, p->u.object_data);
- p->u.object_data = JS_UNDEFINED;
- }
- static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JS_MarkValue(rt, p->u.object_data, mark_func);
- }
- static void js_c_function_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- if (p->u.cfunc.realm)
- JS_FreeContext(p->u.cfunc.realm);
- }
- static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- if (p->u.cfunc.realm)
- mark_func(rt, &p->u.cfunc.realm->header);
- }
- static void js_bytecode_function_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p1, *p = JS_VALUE_GET_OBJ(val);
- JSFunctionBytecode *b;
- JSVarRef **var_refs;
- int i;
- p1 = p->u.func.home_object;
- if (p1) {
- JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, p1));
- }
- b = p->u.func.function_bytecode;
- if (b) {
- var_refs = p->u.func.var_refs;
- if (var_refs) {
- for(i = 0; i < b->closure_var_count; i++)
- free_var_ref(rt, var_refs[i]);
- js_free_rt(rt, var_refs);
- }
- JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b));
- }
- }
- static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSVarRef **var_refs = p->u.func.var_refs;
- JSFunctionBytecode *b = p->u.func.function_bytecode;
- int i;
- if (p->u.func.home_object) {
- JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object),
- mark_func);
- }
- if (b) {
- if (var_refs) {
- for(i = 0; i < b->closure_var_count; i++) {
- JSVarRef *var_ref = var_refs[i];
- if (var_ref && var_ref->is_detached) {
- mark_func(rt, &var_ref->header);
- }
- }
- }
- /* must mark the function bytecode because template objects may be
- part of a cycle */
- JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func);
- }
- }
- static void js_bound_function_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSBoundFunction *bf = p->u.bound_function;
- int i;
- JS_FreeValueRT(rt, bf->func_obj);
- JS_FreeValueRT(rt, bf->this_val);
- for(i = 0; i < bf->argc; i++) {
- JS_FreeValueRT(rt, bf->argv[i]);
- }
- js_free_rt(rt, bf);
- }
- static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSBoundFunction *bf = p->u.bound_function;
- int i;
- JS_MarkValue(rt, bf->func_obj, mark_func);
- JS_MarkValue(rt, bf->this_val, mark_func);
- for(i = 0; i < bf->argc; i++)
- JS_MarkValue(rt, bf->argv[i], mark_func);
- }
- static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSForInIterator *it = p->u.for_in_iterator;
- JS_FreeValueRT(rt, it->obj);
- js_free_rt(rt, it);
- }
- static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSForInIterator *it = p->u.for_in_iterator;
- JS_MarkValue(rt, it->obj, mark_func);
- }
- static void free_object(JSRuntime *rt, JSObject *p)
- {
- int i;
- JSClassFinalizer *finalizer;
- JSShape *sh;
- JSShapeProperty *pr;
- p->free_mark = 1; /* used to tell the object is invalid when
- freeing cycles */
- /* free all the fields */
- sh = p->shape;
- pr = get_shape_prop(sh);
- for(i = 0; i < sh->prop_count; i++) {
- free_property(rt, &p->prop[i], pr->flags);
- pr++;
- }
- js_free_rt(rt, p->prop);
- /* as an optimization we destroy the shape immediately without
- putting it in gc_zero_ref_count_list */
- js_free_shape(rt, sh);
- /* fail safe */
- p->shape = NULL;
- p->prop = NULL;
- if (unlikely(p->first_weak_ref)) {
- reset_weak_ref(rt, &p->first_weak_ref);
- }
- finalizer = rt->class_array[p->class_id].finalizer;
- if (finalizer)
- (*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p));
- /* fail safe */
- p->class_id = 0;
- p->u.opaque = NULL;
- p->u.func.var_refs = NULL;
- p->u.func.home_object = NULL;
- remove_gc_object(&p->header);
- if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && p->header.ref_count != 0) {
- list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list);
- } else {
- js_free_rt(rt, p);
- }
- }
- static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)
- {
- switch(gp->gc_obj_type) {
- case JS_GC_OBJ_TYPE_JS_OBJECT:
- free_object(rt, (JSObject *)gp);
- break;
- case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
- free_function_bytecode(rt, (JSFunctionBytecode *)gp);
- break;
- default:
- abort();
- }
- }
- static void free_zero_refcount(JSRuntime *rt)
- {
- struct list_head *el;
- JSGCObjectHeader *p;
- rt->gc_phase = JS_GC_PHASE_DECREF;
- for(;;) {
- el = rt->gc_zero_ref_count_list.next;
- if (el == &rt->gc_zero_ref_count_list)
- break;
- p = list_entry(el, JSGCObjectHeader, link);
- assert(p->ref_count == 0);
- free_gc_object(rt, p);
- }
- rt->gc_phase = JS_GC_PHASE_NONE;
- }
- /* called with the ref_count of 'v' reaches zero. */
- static void js_free_value_rt(JSRuntime *rt, JSValue v)
- {
- uint32_t tag = JS_VALUE_GET_TAG(v);
- #ifdef ENABLE_DUMPS // JS_DUMP_FREE
- if (check_dump_flag(rt, JS_DUMP_FREE)) {
- /* Prevent invalid object access during GC */
- if ((rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES)
- || (tag != JS_TAG_OBJECT && tag != JS_TAG_FUNCTION_BYTECODE)) {
- printf("Freeing ");
- if (tag == JS_TAG_OBJECT) {
- JS_DumpObject(rt, JS_VALUE_GET_OBJ(v));
- } else {
- JS_DumpValue(rt, v);
- printf("\n");
- }
- }
- }
- #endif
- switch(tag) {
- case JS_TAG_STRING:
- js_free_string0(rt, JS_VALUE_GET_STRING(v));
- break;
- case JS_TAG_OBJECT:
- case JS_TAG_FUNCTION_BYTECODE:
- {
- JSGCObjectHeader *p = JS_VALUE_GET_PTR(v);
- if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
- list_del(&p->link);
- list_add(&p->link, &rt->gc_zero_ref_count_list);
- if (rt->gc_phase == JS_GC_PHASE_NONE) {
- free_zero_refcount(rt);
- }
- }
- }
- break;
- case JS_TAG_MODULE:
- abort(); /* never freed here */
- break;
- case JS_TAG_BIG_INT:
- {
- JSBigInt *p = JS_VALUE_GET_PTR(v);
- js_free_rt(rt, p);
- }
- break;
- case JS_TAG_SYMBOL:
- {
- JSAtomStruct *p = JS_VALUE_GET_PTR(v);
- JS_FreeAtomStruct(rt, p);
- }
- break;
- default:
- printf("js_free_value_rt: unknown tag=%d\n", tag);
- abort();
- }
- }
- void JS_FreeValueRT(JSRuntime *rt, JSValue v)
- {
- if (JS_VALUE_HAS_REF_COUNT(v)) {
- JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
- if (--p->ref_count <= 0) {
- js_free_value_rt(rt, v);
- }
- }
- }
- void JS_FreeValue(JSContext *ctx, JSValue v)
- {
- JS_FreeValueRT(ctx->rt, v);
- }
- /* garbage collection */
- static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
- JSGCObjectTypeEnum type)
- {
- h->mark = 0;
- h->gc_obj_type = type;
- list_add_tail(&h->link, &rt->gc_obj_list);
- }
- static void remove_gc_object(JSGCObjectHeader *h)
- {
- list_del(&h->link);
- }
- void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
- {
- if (JS_VALUE_HAS_REF_COUNT(val)) {
- switch(JS_VALUE_GET_TAG(val)) {
- case JS_TAG_OBJECT:
- case JS_TAG_FUNCTION_BYTECODE:
- mark_func(rt, JS_VALUE_GET_PTR(val));
- break;
- default:
- break;
- }
- }
- }
- static void mark_weak_map_value(JSRuntime *rt, JSWeakRefRecord *first_weak_ref, JS_MarkFunc *mark_func) {
- JSWeakRefRecord *wr;
- JSMapRecord *mr;
- JSMapState *s;
- for (wr = first_weak_ref; wr != NULL; wr = wr->next_weak_ref) {
- if (wr->kind == JS_WEAK_REF_KIND_MAP) {
- mr = wr->u.map_record;
- s = mr->map;
- assert(s->is_weak);
- assert(!mr->empty); /* no iterator on WeakMap/WeakSet */
- JS_MarkValue(rt, mr->value, mark_func);
- }
- }
- }
- static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
- JS_MarkFunc *mark_func)
- {
- switch(gp->gc_obj_type) {
- case JS_GC_OBJ_TYPE_JS_OBJECT:
- {
- JSObject *p = (JSObject *)gp;
- JSShapeProperty *prs;
- JSShape *sh;
- int i;
- sh = p->shape;
- mark_func(rt, &sh->header);
- /* mark all the fields */
- prs = get_shape_prop(sh);
- for(i = 0; i < sh->prop_count; i++) {
- JSProperty *pr = &p->prop[i];
- if (prs->atom != JS_ATOM_NULL) {
- if (prs->flags & JS_PROP_TMASK) {
- if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
- if (pr->u.getset.getter)
- mark_func(rt, &pr->u.getset.getter->header);
- if (pr->u.getset.setter)
- mark_func(rt, &pr->u.getset.setter->header);
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
- if (pr->u.var_ref->is_detached) {
- /* Note: the tag does not matter
- provided it is a GC object */
- mark_func(rt, &pr->u.var_ref->header);
- }
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- js_autoinit_mark(rt, pr, mark_func);
- }
- } else {
- JS_MarkValue(rt, pr->u.value, mark_func);
- }
- }
- prs++;
- }
- if (unlikely(p->first_weak_ref)) {
- mark_weak_map_value(rt, p->first_weak_ref, mark_func);
- }
- if (p->class_id != JS_CLASS_OBJECT) {
- JSClassGCMark *gc_mark;
- gc_mark = rt->class_array[p->class_id].gc_mark;
- if (gc_mark)
- gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func);
- }
- }
- break;
- case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
- /* the template objects can be part of a cycle */
- {
- JSFunctionBytecode *b = (JSFunctionBytecode *)gp;
- int i;
- for(i = 0; i < b->cpool_count; i++) {
- JS_MarkValue(rt, b->cpool[i], mark_func);
- }
- if (b->realm)
- mark_func(rt, &b->realm->header);
- }
- break;
- case JS_GC_OBJ_TYPE_VAR_REF:
- {
- JSVarRef *var_ref = (JSVarRef *)gp;
- /* only detached variable referenced are taken into account */
- assert(var_ref->is_detached);
- JS_MarkValue(rt, *var_ref->pvalue, mark_func);
- }
- break;
- case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
- {
- JSAsyncFunctionData *s = (JSAsyncFunctionData *)gp;
- if (s->is_active)
- async_func_mark(rt, &s->func_state, mark_func);
- JS_MarkValue(rt, s->resolving_funcs[0], mark_func);
- JS_MarkValue(rt, s->resolving_funcs[1], mark_func);
- }
- break;
- case JS_GC_OBJ_TYPE_SHAPE:
- {
- JSShape *sh = (JSShape *)gp;
- if (sh->proto != NULL) {
- mark_func(rt, &sh->proto->header);
- }
- }
- break;
- case JS_GC_OBJ_TYPE_JS_CONTEXT:
- {
- JSContext *ctx = (JSContext *)gp;
- JS_MarkContext(rt, ctx, mark_func);
- }
- break;
- default:
- abort();
- }
- }
- static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p)
- {
- assert(p->ref_count > 0);
- p->ref_count--;
- if (p->ref_count == 0 && p->mark == 1) {
- list_del(&p->link);
- list_add_tail(&p->link, &rt->tmp_obj_list);
- }
- }
- static void gc_decref(JSRuntime *rt)
- {
- struct list_head *el, *el1;
- JSGCObjectHeader *p;
- init_list_head(&rt->tmp_obj_list);
- /* decrement the refcount of all the children of all the GC
- objects and move the GC objects with zero refcount to
- tmp_obj_list */
- list_for_each_safe(el, el1, &rt->gc_obj_list) {
- p = list_entry(el, JSGCObjectHeader, link);
- assert(p->mark == 0);
- mark_children(rt, p, gc_decref_child);
- p->mark = 1;
- if (p->ref_count == 0) {
- list_del(&p->link);
- list_add_tail(&p->link, &rt->tmp_obj_list);
- }
- }
- }
- static void gc_scan_incref_child(JSRuntime *rt, JSGCObjectHeader *p)
- {
- p->ref_count++;
- if (p->ref_count == 1) {
- /* ref_count was 0: remove from tmp_obj_list and add at the
- end of gc_obj_list */
- list_del(&p->link);
- list_add_tail(&p->link, &rt->gc_obj_list);
- p->mark = 0; /* reset the mark for the next GC call */
- }
- }
- static void gc_scan_incref_child2(JSRuntime *rt, JSGCObjectHeader *p)
- {
- p->ref_count++;
- }
- static void gc_scan(JSRuntime *rt)
- {
- struct list_head *el;
- JSGCObjectHeader *p;
- /* keep the objects with a refcount > 0 and their children. */
- list_for_each(el, &rt->gc_obj_list) {
- p = list_entry(el, JSGCObjectHeader, link);
- assert(p->ref_count > 0);
- p->mark = 0; /* reset the mark for the next GC call */
- mark_children(rt, p, gc_scan_incref_child);
- }
- /* restore the refcount of the objects to be deleted. */
- list_for_each(el, &rt->tmp_obj_list) {
- p = list_entry(el, JSGCObjectHeader, link);
- mark_children(rt, p, gc_scan_incref_child2);
- }
- }
- static void gc_free_cycles(JSRuntime *rt)
- {
- struct list_head *el, *el1;
- JSGCObjectHeader *p;
- #ifdef ENABLE_DUMPS // JS_DUMP_GC_FREE
- bool header_done = false;
- #endif
- rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES;
- for(;;) {
- el = rt->tmp_obj_list.next;
- if (el == &rt->tmp_obj_list)
- break;
- p = list_entry(el, JSGCObjectHeader, link);
- /* Only need to free the GC object associated with JS
- values. The rest will be automatically removed because they
- must be referenced by them. */
- switch(p->gc_obj_type) {
- case JS_GC_OBJ_TYPE_JS_OBJECT:
- case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
- #ifdef ENABLE_DUMPS // JS_DUMP_GC_FREE
- if (check_dump_flag(rt, JS_DUMP_GC_FREE)) {
- if (!header_done) {
- printf("Freeing cycles:\n");
- JS_DumpObjectHeader(rt);
- header_done = true;
- }
- JS_DumpGCObject(rt, p);
- }
- #endif
- free_gc_object(rt, p);
- break;
- default:
- list_del(&p->link);
- list_add_tail(&p->link, &rt->gc_zero_ref_count_list);
- break;
- }
- }
- rt->gc_phase = JS_GC_PHASE_NONE;
- list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) {
- p = list_entry(el, JSGCObjectHeader, link);
- assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT ||
- p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
- js_free_rt(rt, p);
- }
- init_list_head(&rt->gc_zero_ref_count_list);
- }
- void JS_RunGC(JSRuntime *rt)
- {
- /* decrement the reference of the children of each object. mark =
- 1 after this pass. */
- gc_decref(rt);
- /* keep the GC objects with a non zero refcount and their childs */
- gc_scan(rt);
- /* free the GC objects in a cycle */
- gc_free_cycles(rt);
- }
- /* Return false if not an object or if the object has already been
- freed (zombie objects are visible in finalizers when freeing
- cycles). */
- bool JS_IsLiveObject(JSRuntime *rt, JSValueConst obj)
- {
- JSObject *p;
- if (!JS_IsObject(obj))
- return false;
- p = JS_VALUE_GET_OBJ(obj);
- return !p->free_mark;
- }
- /* Compute memory used by various object types */
- /* XXX: poor man's approach to handling multiply referenced objects */
- typedef struct JSMemoryUsage_helper {
- double memory_used_count;
- double str_count;
- double str_size;
- int64_t js_func_count;
- double js_func_size;
- int64_t js_func_code_size;
- int64_t js_func_pc2line_count;
- int64_t js_func_pc2line_size;
- } JSMemoryUsage_helper;
- static void compute_value_size(JSValue val, JSMemoryUsage_helper *hp);
- static void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp)
- {
- if (!str->atom_type) { /* atoms are handled separately */
- double s_ref_count = str->header.ref_count;
- hp->str_count += 1 / s_ref_count;
- hp->str_size += ((sizeof(*str) + (str->len << str->is_wide_char) +
- 1 - str->is_wide_char) / s_ref_count);
- }
- }
- static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *hp)
- {
- int memory_used_count, js_func_size, i;
- memory_used_count = 0;
- js_func_size = sizeof(*b);
- if (b->vardefs) {
- js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs);
- }
- if (b->cpool) {
- js_func_size += b->cpool_count * sizeof(*b->cpool);
- for (i = 0; i < b->cpool_count; i++) {
- JSValue val = b->cpool[i];
- compute_value_size(val, hp);
- }
- }
- if (b->closure_var) {
- js_func_size += b->closure_var_count * sizeof(*b->closure_var);
- }
- if (b->byte_code_buf) {
- hp->js_func_code_size += b->byte_code_len;
- }
- memory_used_count++;
- js_func_size += b->source_len + 1;
- if (b->pc2line_len) {
- memory_used_count++;
- hp->js_func_pc2line_count += 1;
- hp->js_func_pc2line_size += b->pc2line_len;
- }
- hp->js_func_size += js_func_size;
- hp->js_func_count += 1;
- hp->memory_used_count += memory_used_count;
- }
- static void compute_value_size(JSValue val, JSMemoryUsage_helper *hp)
- {
- switch(JS_VALUE_GET_TAG(val)) {
- case JS_TAG_STRING:
- compute_jsstring_size(JS_VALUE_GET_STRING(val), hp);
- break;
- case JS_TAG_BIG_INT:
- /* should track JSBigInt usage */
- break;
- }
- }
- void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
- {
- struct list_head *el, *el1;
- int i;
- JSMemoryUsage_helper mem = { 0 }, *hp = &mem;
- memset(s, 0, sizeof(*s));
- s->malloc_count = rt->malloc_state.malloc_count;
- s->malloc_size = rt->malloc_state.malloc_size;
- s->malloc_limit = rt->malloc_state.malloc_limit;
- s->memory_used_count = 2; /* rt + rt->class_array */
- s->memory_used_size = sizeof(JSRuntime) + sizeof(JSClass) * rt->class_count;
- list_for_each(el, &rt->context_list) {
- JSContext *ctx = list_entry(el, JSContext, link);
- JSShape *sh = ctx->array_shape;
- s->memory_used_count += 2; /* ctx + ctx->class_proto */
- s->memory_used_size += sizeof(JSContext) +
- sizeof(JSValue) * rt->class_count;
- s->binary_object_count += ctx->binary_object_count;
- s->binary_object_size += ctx->binary_object_size;
- /* the hashed shapes are counted separately */
- if (sh && !sh->is_hashed) {
- int hash_size = sh->prop_hash_mask + 1;
- s->shape_count++;
- s->shape_size += get_shape_size(hash_size, sh->prop_size);
- }
- list_for_each(el1, &ctx->loaded_modules) {
- JSModuleDef *m = list_entry(el1, JSModuleDef, link);
- s->memory_used_count += 1;
- s->memory_used_size += sizeof(*m);
- if (m->req_module_entries) {
- s->memory_used_count += 1;
- s->memory_used_size += m->req_module_entries_count * sizeof(*m->req_module_entries);
- }
- if (m->export_entries) {
- s->memory_used_count += 1;
- s->memory_used_size += m->export_entries_count * sizeof(*m->export_entries);
- for (i = 0; i < m->export_entries_count; i++) {
- JSExportEntry *me = &m->export_entries[i];
- if (me->export_type == JS_EXPORT_TYPE_LOCAL && me->u.local.var_ref) {
- /* potential multiple count */
- s->memory_used_count += 1;
- compute_value_size(me->u.local.var_ref->value, hp);
- }
- }
- }
- if (m->star_export_entries) {
- s->memory_used_count += 1;
- s->memory_used_size += m->star_export_entries_count * sizeof(*m->star_export_entries);
- }
- if (m->import_entries) {
- s->memory_used_count += 1;
- s->memory_used_size += m->import_entries_count * sizeof(*m->import_entries);
- }
- compute_value_size(m->module_ns, hp);
- compute_value_size(m->func_obj, hp);
- }
- }
- list_for_each(el, &rt->gc_obj_list) {
- JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
- JSObject *p;
- JSShape *sh;
- JSShapeProperty *prs;
- /* XXX: could count the other GC object types too */
- if (gp->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) {
- compute_bytecode_size((JSFunctionBytecode *)gp, hp);
- continue;
- } else if (gp->gc_obj_type != JS_GC_OBJ_TYPE_JS_OBJECT) {
- continue;
- }
- p = (JSObject *)gp;
- sh = p->shape;
- s->obj_count++;
- if (p->prop) {
- s->memory_used_count++;
- s->prop_size += sh->prop_size * sizeof(*p->prop);
- s->prop_count += sh->prop_count;
- prs = get_shape_prop(sh);
- for(i = 0; i < sh->prop_count; i++) {
- JSProperty *pr = &p->prop[i];
- if (prs->atom != JS_ATOM_NULL && !(prs->flags & JS_PROP_TMASK)) {
- compute_value_size(pr->u.value, hp);
- }
- prs++;
- }
- }
- /* the hashed shapes are counted separately */
- if (!sh->is_hashed) {
- int hash_size = sh->prop_hash_mask + 1;
- s->shape_count++;
- s->shape_size += get_shape_size(hash_size, sh->prop_size);
- }
- switch(p->class_id) {
- case JS_CLASS_ARRAY: /* u.array | length */
- case JS_CLASS_ARGUMENTS: /* u.array | length */
- s->array_count++;
- if (p->fast_array) {
- s->fast_array_count++;
- if (p->u.array.u.values) {
- s->memory_used_count++;
- s->memory_used_size += p->u.array.count *
- sizeof(*p->u.array.u.values);
- s->fast_array_elements += p->u.array.count;
- for (i = 0; i < p->u.array.count; i++) {
- compute_value_size(p->u.array.u.values[i], hp);
- }
- }
- }
- break;
- case JS_CLASS_NUMBER: /* u.object_data */
- case JS_CLASS_STRING: /* u.object_data */
- case JS_CLASS_BOOLEAN: /* u.object_data */
- case JS_CLASS_SYMBOL: /* u.object_data */
- case JS_CLASS_DATE: /* u.object_data */
- case JS_CLASS_BIG_INT: /* u.object_data */
- compute_value_size(p->u.object_data, hp);
- break;
- case JS_CLASS_C_FUNCTION: /* u.cfunc */
- s->c_func_count++;
- break;
- case JS_CLASS_BYTECODE_FUNCTION: /* u.func */
- {
- JSFunctionBytecode *b = p->u.func.function_bytecode;
- JSVarRef **var_refs = p->u.func.var_refs;
- /* home_object: object will be accounted for in list scan */
- if (var_refs) {
- s->memory_used_count++;
- s->js_func_size += b->closure_var_count * sizeof(*var_refs);
- for (i = 0; i < b->closure_var_count; i++) {
- if (var_refs[i]) {
- double ref_count = var_refs[i]->header.ref_count;
- s->memory_used_count += 1 / ref_count;
- s->js_func_size += sizeof(*var_refs[i]) / ref_count;
- /* handle non object closed values */
- if (var_refs[i]->pvalue == &var_refs[i]->value) {
- /* potential multiple count */
- compute_value_size(var_refs[i]->value, hp);
- }
- }
- }
- }
- }
- break;
- case JS_CLASS_BOUND_FUNCTION: /* u.bound_function */
- {
- JSBoundFunction *bf = p->u.bound_function;
- /* func_obj and this_val are objects */
- for (i = 0; i < bf->argc; i++) {
- compute_value_size(bf->argv[i], hp);
- }
- s->memory_used_count += 1;
- s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv);
- }
- break;
- case JS_CLASS_C_FUNCTION_DATA: /* u.c_function_data_record */
- {
- JSCFunctionDataRecord *fd = p->u.c_function_data_record;
- if (fd) {
- for (i = 0; i < fd->data_len; i++) {
- compute_value_size(fd->data[i], hp);
- }
- s->memory_used_count += 1;
- s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data);
- }
- }
- break;
- case JS_CLASS_REGEXP: /* u.regexp */
- compute_jsstring_size(p->u.regexp.pattern, hp);
- compute_jsstring_size(p->u.regexp.bytecode, hp);
- break;
- case JS_CLASS_FOR_IN_ITERATOR: /* u.for_in_iterator */
- {
- JSForInIterator *it = p->u.for_in_iterator;
- if (it) {
- compute_value_size(it->obj, hp);
- s->memory_used_count += 1;
- s->memory_used_size += sizeof(*it);
- }
- }
- break;
- case JS_CLASS_ARRAY_BUFFER: /* u.array_buffer */
- case JS_CLASS_SHARED_ARRAY_BUFFER: /* u.array_buffer */
- {
- JSArrayBuffer *abuf = p->u.array_buffer;
- if (abuf) {
- s->memory_used_count += 1;
- s->memory_used_size += sizeof(*abuf);
- if (abuf->data) {
- s->memory_used_count += 1;
- s->memory_used_size += abuf->byte_length;
- }
- }
- }
- break;
- case JS_CLASS_GENERATOR: /* u.generator_data */
- case JS_CLASS_UINT8C_ARRAY: /* u.typed_array / u.array */
- case JS_CLASS_INT8_ARRAY: /* u.typed_array / u.array */
- case JS_CLASS_UINT8_ARRAY: /* u.typed_array / u.array */
- case JS_CLASS_INT16_ARRAY: /* u.typed_array / u.array */
- case JS_CLASS_UINT16_ARRAY: /* u.typed_array / u.array */
- case JS_CLASS_INT32_ARRAY: /* u.typed_array / u.array */
- case JS_CLASS_UINT32_ARRAY: /* u.typed_array / u.array */
- case JS_CLASS_BIG_INT64_ARRAY: /* u.typed_array / u.array */
- case JS_CLASS_BIG_UINT64_ARRAY: /* u.typed_array / u.array */
- case JS_CLASS_FLOAT16_ARRAY: /* u.typed_array / u.array */
- case JS_CLASS_FLOAT32_ARRAY: /* u.typed_array / u.array */
- case JS_CLASS_FLOAT64_ARRAY: /* u.typed_array / u.array */
- case JS_CLASS_DATAVIEW: /* u.typed_array */
- case JS_CLASS_MAP: /* u.map_state */
- case JS_CLASS_SET: /* u.map_state */
- case JS_CLASS_WEAKMAP: /* u.map_state */
- case JS_CLASS_WEAKSET: /* u.map_state */
- case JS_CLASS_MAP_ITERATOR: /* u.map_iterator_data */
- case JS_CLASS_SET_ITERATOR: /* u.map_iterator_data */
- case JS_CLASS_ARRAY_ITERATOR: /* u.array_iterator_data */
- case JS_CLASS_STRING_ITERATOR: /* u.array_iterator_data */
- case JS_CLASS_PROXY: /* u.proxy_data */
- case JS_CLASS_PROMISE: /* u.promise_data */
- case JS_CLASS_PROMISE_RESOLVE_FUNCTION: /* u.promise_function_data */
- case JS_CLASS_PROMISE_REJECT_FUNCTION: /* u.promise_function_data */
- case JS_CLASS_ASYNC_FUNCTION_RESOLVE: /* u.async_function_data */
- case JS_CLASS_ASYNC_FUNCTION_REJECT: /* u.async_function_data */
- case JS_CLASS_ASYNC_FROM_SYNC_ITERATOR: /* u.async_from_sync_iterator_data */
- case JS_CLASS_ASYNC_GENERATOR: /* u.async_generator_data */
- /* TODO */
- default:
- /* XXX: class definition should have an opaque block size */
- if (p->u.opaque) {
- s->memory_used_count += 1;
- }
- break;
- }
- }
- s->obj_size += s->obj_count * sizeof(JSObject);
- /* hashed shapes */
- s->memory_used_count++; /* rt->shape_hash */
- s->memory_used_size += sizeof(rt->shape_hash[0]) * rt->shape_hash_size;
- for(i = 0; i < rt->shape_hash_size; i++) {
- JSShape *sh;
- for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
- int hash_size = sh->prop_hash_mask + 1;
- s->shape_count++;
- s->shape_size += get_shape_size(hash_size, sh->prop_size);
- }
- }
- /* atoms */
- s->memory_used_count += 2; /* rt->atom_array, rt->atom_hash */
- s->atom_count = rt->atom_count;
- s->atom_size = sizeof(rt->atom_array[0]) * rt->atom_size +
- sizeof(rt->atom_hash[0]) * rt->atom_hash_size;
- for(i = 0; i < rt->atom_size; i++) {
- JSAtomStruct *p = rt->atom_array[i];
- if (!atom_is_free(p)) {
- s->atom_size += (sizeof(*p) + (p->len << p->is_wide_char) +
- 1 - p->is_wide_char);
- }
- }
- s->str_count = round(mem.str_count);
- s->str_size = round(mem.str_size);
- s->js_func_count = mem.js_func_count;
- s->js_func_size = round(mem.js_func_size);
- s->js_func_code_size = mem.js_func_code_size;
- s->js_func_pc2line_count = mem.js_func_pc2line_count;
- s->js_func_pc2line_size = mem.js_func_pc2line_size;
- s->memory_used_count += round(mem.memory_used_count) +
- s->atom_count + s->str_count +
- s->obj_count + s->shape_count +
- s->js_func_count + s->js_func_pc2line_count;
- s->memory_used_size += s->atom_size + s->str_size +
- s->obj_size + s->prop_size + s->shape_size +
- s->js_func_size + s->js_func_code_size + s->js_func_pc2line_size;
- }
- void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
- {
- fprintf(fp, "QuickJS-ng memory usage -- %s version, %d-bit, %s Endian, malloc limit: %"PRId64"\n\n",
- JS_GetVersion(), (int)sizeof(void *) * 8, is_be() ? "Big" : "Little", s->malloc_limit);
- if (rt) {
- static const struct {
- const char *name;
- size_t size;
- } object_types[] = {
- { "JSRuntime", sizeof(JSRuntime) },
- { "JSContext", sizeof(JSContext) },
- { "JSObject", sizeof(JSObject) },
- { "JSString", sizeof(JSString) },
- { "JSFunctionBytecode", sizeof(JSFunctionBytecode) },
- };
- int i, usage_size_ok = 0;
- for(i = 0; i < countof(object_types); i++) {
- unsigned int size = object_types[i].size;
- void *p = js_malloc_rt(rt, size);
- if (p) {
- unsigned int size1 = js_malloc_usable_size_rt(rt, p);
- if (size1 >= size) {
- usage_size_ok = 1;
- fprintf(fp, " %3u + %-2u %s\n",
- size, size1 - size, object_types[i].name);
- }
- js_free_rt(rt, p);
- }
- }
- if (!usage_size_ok) {
- fprintf(fp, " malloc_usable_size unavailable\n");
- }
- {
- int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 };
- int class_id;
- struct list_head *el;
- list_for_each(el, &rt->gc_obj_list) {
- JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
- JSObject *p;
- if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
- p = (JSObject *)gp;
- obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++;
- }
- }
- fprintf(fp, "\n" "JSObject classes\n");
- if (obj_classes[0])
- fprintf(fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none");
- for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {
- if (obj_classes[class_id] && class_id < rt->class_count) {
- char buf[ATOM_GET_STR_BUF_SIZE];
- fprintf(fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id,
- JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name));
- }
- }
- if (obj_classes[JS_CLASS_INIT_COUNT])
- fprintf(fp, " %5d %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other");
- }
- fprintf(fp, "\n");
- }
- fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE");
- if (s->malloc_count) {
- fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per block)\n",
- "memory allocated", s->malloc_count, s->malloc_size,
- (double)s->malloc_size / s->malloc_count);
- fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%d overhead, %0.1f average slack)\n",
- "memory used", s->memory_used_count, s->memory_used_size,
- MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) /
- s->memory_used_count));
- }
- if (s->atom_count) {
- fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per atom)\n",
- "atoms", s->atom_count, s->atom_size,
- (double)s->atom_size / s->atom_count);
- }
- if (s->str_count) {
- fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per string)\n",
- "strings", s->str_count, s->str_size,
- (double)s->str_size / s->str_count);
- }
- if (s->obj_count) {
- fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n",
- "objects", s->obj_count, s->obj_size,
- (double)s->obj_size / s->obj_count);
- fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n",
- " properties", s->prop_count, s->prop_size,
- (double)s->prop_count / s->obj_count);
- fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per shape)\n",
- " shapes", s->shape_count, s->shape_size,
- (double)s->shape_size / s->shape_count);
- }
- if (s->js_func_count) {
- fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
- "bytecode functions", s->js_func_count, s->js_func_size);
- fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n",
- " bytecode", s->js_func_count, s->js_func_code_size,
- (double)s->js_func_code_size / s->js_func_count);
- if (s->js_func_pc2line_count) {
- fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n",
- " pc2line", s->js_func_pc2line_count,
- s->js_func_pc2line_size,
- (double)s->js_func_pc2line_size / s->js_func_pc2line_count);
- }
- }
- if (s->c_func_count) {
- fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count);
- }
- if (s->array_count) {
- fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count);
- if (s->fast_array_count) {
- fprintf(fp, "%-20s %8"PRId64"\n", " fast arrays", s->fast_array_count);
- fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per fast array)\n",
- " elements", s->fast_array_elements,
- s->fast_array_elements * (int)sizeof(JSValue),
- (double)s->fast_array_elements / s->fast_array_count);
- }
- }
- if (s->binary_object_count) {
- fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
- "binary objects", s->binary_object_count, s->binary_object_size);
- }
- }
- JSValue JS_GetGlobalObject(JSContext *ctx)
- {
- return js_dup(ctx->global_obj);
- }
- /* WARNING: obj is freed */
- JSValue JS_Throw(JSContext *ctx, JSValue obj)
- {
- JSRuntime *rt = ctx->rt;
- JS_FreeValue(ctx, rt->current_exception);
- rt->current_exception = obj;
- return JS_EXCEPTION;
- }
- /* return the pending exception (cannot be called twice). */
- JSValue JS_GetException(JSContext *ctx)
- {
- JSValue val;
- JSRuntime *rt = ctx->rt;
- val = rt->current_exception;
- rt->current_exception = JS_UNINITIALIZED;
- return val;
- }
- bool JS_HasException(JSContext *ctx)
- {
- return !JS_IsUninitialized(ctx->rt->current_exception);
- }
- static void dbuf_put_leb128(DynBuf *s, uint32_t v)
- {
- uint32_t a;
- for(;;) {
- a = v & 0x7f;
- v >>= 7;
- if (v != 0) {
- dbuf_putc(s, a | 0x80);
- } else {
- dbuf_putc(s, a);
- break;
- }
- }
- }
- static void dbuf_put_sleb128(DynBuf *s, int32_t v1)
- {
- uint32_t v = v1;
- dbuf_put_leb128(s, (2 * v) ^ -(v >> 31));
- }
- static int get_leb128(uint32_t *pval, const uint8_t *buf,
- const uint8_t *buf_end)
- {
- const uint8_t *ptr = buf;
- uint32_t v, a, i;
- v = 0;
- for(i = 0; i < 5; i++) {
- if (unlikely(ptr >= buf_end))
- break;
- a = *ptr++;
- v |= (a & 0x7f) << (i * 7);
- if (!(a & 0x80)) {
- *pval = v;
- return ptr - buf;
- }
- }
- *pval = 0;
- return -1;
- }
- static int get_sleb128(int32_t *pval, const uint8_t *buf,
- const uint8_t *buf_end)
- {
- int ret;
- uint32_t val;
- ret = get_leb128(&val, buf, buf_end);
- if (ret < 0) {
- *pval = 0;
- return -1;
- }
- *pval = (val >> 1) ^ -(val & 1);
- return ret;
- }
- static int find_line_num(JSContext *ctx, JSFunctionBytecode *b,
- uint32_t pc_value, int *col)
- {
- const uint8_t *p_end, *p;
- int new_line_num, new_col_num, line_num, col_num, pc, v, ret;
- unsigned int op;
- *col = 1;
- p = b->pc2line_buf;
- if (!p)
- goto fail;
- p_end = p + b->pc2line_len;
- pc = 0;
- line_num = b->line_num;
- col_num = b->col_num;
- while (p < p_end) {
- op = *p++;
- if (op == 0) {
- uint32_t val;
- ret = get_leb128(&val, p, p_end);
- if (ret < 0)
- goto fail;
- pc += val;
- p += ret;
- ret = get_sleb128(&v, p, p_end);
- if (ret < 0)
- goto fail;
- p += ret;
- new_line_num = line_num + v;
- } else {
- op -= PC2LINE_OP_FIRST;
- pc += (op / PC2LINE_RANGE);
- new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE;
- }
- ret = get_sleb128(&v, p, p_end);
- if (ret < 0)
- goto fail;
- p += ret;
- new_col_num = col_num + v;
- if (pc_value < pc)
- break;
- line_num = new_line_num;
- col_num = new_col_num;
- }
- *col = col_num;
- return line_num;
- fail:
- /* should never happen */
- return b->line_num;
- }
- /* in order to avoid executing arbitrary code during the stack trace
- generation, we only look at simple 'name' properties containing a
- string. */
- static const char *get_func_name(JSContext *ctx, JSValueConst func)
- {
- JSProperty *pr;
- JSShapeProperty *prs;
- JSValue val;
- if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)
- return NULL;
- prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name);
- if (!prs)
- return NULL;
- if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
- return NULL;
- val = pr->u.value;
- if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
- return NULL;
- return JS_ToCString(ctx, val);
- }
- /* Note: it is important that no exception is returned by this function */
- static bool can_add_backtrace(JSValueConst obj)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- return false;
- p = JS_VALUE_GET_OBJ(obj);
- if (p->class_id != JS_CLASS_ERROR && p->class_id != JS_CLASS_DOM_EXCEPTION)
- return false;
- if (find_own_property1(p, JS_ATOM_stack))
- return false;
- return true;
- }
- #define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
- /* only taken into account if filename is provided */
- #define JS_BACKTRACE_FLAG_SINGLE_LEVEL (1 << 1)
- #define JS_BACKTRACE_FLAG_FILTER_FUNC (1 << 2)
- /* if filename != NULL, an additional level is added with the filename
- and line number information (used for parse error). */
- static void build_backtrace(JSContext *ctx, JSValueConst error_val,
- JSValueConst filter_func, const char *filename,
- int line_num, int col_num, int backtrace_flags)
- {
- JSStackFrame *sf, *sf_start;
- JSValue stack, prepare, saved_exception;
- DynBuf dbuf;
- const char *func_name_str;
- const char *str1;
- JSObject *p;
- JSFunctionBytecode *b;
- bool backtrace_barrier, has_prepare, has_filter_func;
- JSRuntime *rt;
- JSCallSiteData csd[64];
- uint32_t i;
- double d;
- int stack_trace_limit;
- rt = ctx->rt;
- if (rt->in_build_stack_trace)
- return;
- rt->in_build_stack_trace = true;
- // Save exception because conversion to double may fail.
- saved_exception = JS_GetException(ctx);
- // Extract stack trace limit.
- // Ignore error since it sets d to NAN anyway.
- // coverity[check_return]
- JS_ToFloat64(ctx, &d, ctx->error_stack_trace_limit);
- if (isnan(d) || d < 0.0)
- stack_trace_limit = 0;
- else if (d > INT32_MAX)
- stack_trace_limit = INT32_MAX;
- else
- stack_trace_limit = fabs(d);
- // Restore current exception.
- JS_Throw(ctx, saved_exception);
- saved_exception = JS_UNINITIALIZED;
- stack_trace_limit = min_int(stack_trace_limit, countof(csd));
- stack_trace_limit = max_int(stack_trace_limit, 0);
- has_prepare = false;
- has_filter_func = backtrace_flags & JS_BACKTRACE_FLAG_FILTER_FUNC;
- i = 0;
- if (!JS_IsNull(ctx->error_ctor)) {
- prepare = js_dup(ctx->error_prepare_stack);
- has_prepare = JS_IsFunction(ctx, prepare);
- }
- if (has_prepare) {
- saved_exception = JS_GetException(ctx);
- if (stack_trace_limit == 0)
- goto done;
- if (filename)
- js_new_callsite_data2(ctx, &csd[i++], filename, line_num, col_num);
- } else {
- js_dbuf_init(ctx, &dbuf);
- if (stack_trace_limit == 0)
- goto done;
- if (filename) {
- i++;
- dbuf_printf(&dbuf, " at %s", filename);
- if (line_num != -1)
- dbuf_printf(&dbuf, ":%d:%d", line_num, col_num);
- dbuf_putc(&dbuf, '\n');
- }
- }
- if (filename && (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL))
- goto done;
- sf_start = rt->current_stack_frame;
- /* Find the frame we want to start from. Note that when a filter is used the filter
- function will be the first, but we also specify we want to skip the first one. */
- if (has_filter_func) {
- for (sf = sf_start; sf != NULL && i < stack_trace_limit; sf = sf->prev_frame) {
- if (js_same_value(ctx, sf->cur_func, filter_func)) {
- sf_start = sf;
- break;
- }
- }
- }
- for (sf = sf_start; sf != NULL && i < stack_trace_limit; sf = sf->prev_frame) {
- if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
- backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
- continue;
- }
- p = JS_VALUE_GET_OBJ(sf->cur_func);
- b = NULL;
- backtrace_barrier = false;
- if (js_class_has_bytecode(p->class_id)) {
- b = p->u.func.function_bytecode;
- backtrace_barrier = b->backtrace_barrier;
- }
- if (has_prepare) {
- js_new_callsite_data(ctx, &csd[i], sf);
- } else {
- /* func_name_str is UTF-8 encoded if needed */
- func_name_str = get_func_name(ctx, sf->cur_func);
- if (!func_name_str || func_name_str[0] == '\0')
- str1 = "<anonymous>";
- else
- str1 = func_name_str;
- dbuf_printf(&dbuf, " at %s", str1);
- JS_FreeCString(ctx, func_name_str);
- if (b && sf->cur_pc) {
- const char *atom_str;
- int line_num1, col_num1;
- uint32_t pc;
- pc = sf->cur_pc - b->byte_code_buf - 1;
- line_num1 = find_line_num(ctx, b, pc, &col_num1);
- atom_str = b->filename ? JS_AtomToCString(ctx, b->filename) : NULL;
- dbuf_printf(&dbuf, " (%s", atom_str ? atom_str : "<null>");
- JS_FreeCString(ctx, atom_str);
- if (line_num1 != -1)
- dbuf_printf(&dbuf, ":%d:%d", line_num1, col_num1);
- dbuf_putc(&dbuf, ')');
- } else if (b) {
- // FIXME(bnoordhuis) Missing `sf->cur_pc = pc` in bytecode
- // handler in JS_CallInternal. Almost never user observable
- // except with intercepting JS proxies that throw exceptions.
- dbuf_printf(&dbuf, " (missing)");
- } else {
- dbuf_printf(&dbuf, " (native)");
- }
- dbuf_putc(&dbuf, '\n');
- }
- i++;
- /* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */
- if (backtrace_barrier)
- break;
- }
- done:
- if (has_prepare) {
- int j = 0, k;
- stack = JS_NewArray(ctx);
- if (JS_IsException(stack)) {
- stack = JS_NULL;
- } else {
- for (; j < i; j++) {
- JSValue v = js_new_callsite(ctx, &csd[j]);
- if (JS_IsException(v))
- break;
- if (JS_DefinePropertyValueUint32(ctx, stack, j, v, JS_PROP_C_W_E) < 0) {
- JS_FreeValue(ctx, v);
- break;
- }
- }
- }
- // Clear the csd's we didn't use in case of error.
- for (k = j; k < i; k++) {
- JS_FreeValue(ctx, csd[k].filename);
- JS_FreeValue(ctx, csd[k].func);
- JS_FreeValue(ctx, csd[k].func_name);
- }
- JSValueConst args[] = {
- error_val,
- stack,
- };
- JSValue stack2 = JS_Call(ctx, prepare, ctx->error_ctor, countof(args), args);
- JS_FreeValue(ctx, stack);
- if (JS_IsException(stack2))
- stack = JS_NULL;
- else
- stack = stack2;
- JS_FreeValue(ctx, prepare);
- JS_Throw(ctx, saved_exception);
- } else {
- if (dbuf_error(&dbuf))
- stack = JS_NULL;
- else
- stack = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size);
- dbuf_free(&dbuf);
- }
- if (JS_IsUndefined(ctx->error_back_trace))
- ctx->error_back_trace = js_dup(stack);
- if (has_filter_func || can_add_backtrace(error_val)) {
- JS_DefinePropertyValue(ctx, error_val, JS_ATOM_stack, stack,
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- } else {
- JS_FreeValue(ctx, stack);
- }
- rt->in_build_stack_trace = false;
- }
- JSValue JS_NewError(JSContext *ctx)
- {
- JSValue obj = JS_NewObjectClass(ctx, JS_CLASS_ERROR);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0, 0);
- return obj;
- }
- static JSValue JS_MakeError2(JSContext *ctx, JSErrorEnum error_num,
- bool add_backtrace, const char *message)
- {
- JSValue obj, msg;
- if (error_num == JS_PLAIN_ERROR) {
- obj = JS_NewObjectClass(ctx, JS_CLASS_ERROR);
- } else {
- obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num],
- JS_CLASS_ERROR);
- }
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- msg = JS_NewString(ctx, message);
- if (JS_IsException(msg))
- msg = JS_NewString(ctx, "Invalid error message");
- if (!JS_IsException(msg)) {
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg,
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- }
- if (add_backtrace)
- build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0, 0);
- return obj;
- }
- static JSValue JS_PRINTF_FORMAT_ATTR(4, 0)
- JS_MakeError(JSContext *ctx, JSErrorEnum error_num, bool add_backtrace,
- JS_PRINTF_FORMAT const char *fmt, va_list ap)
- {
- char buf[256];
- vsnprintf(buf, sizeof(buf), fmt, ap);
- return JS_MakeError2(ctx, error_num, add_backtrace, buf);
- }
- /* fmt and arguments may be pure ASCII or UTF-8 encoded contents */
- static JSValue JS_PRINTF_FORMAT_ATTR(4, 0)
- JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num, bool add_backtrace,
- JS_PRINTF_FORMAT const char *fmt, va_list ap)
- {
- JSValue obj;
- obj = JS_MakeError(ctx, error_num, add_backtrace, fmt, ap);
- if (unlikely(JS_IsException(obj))) {
- /* out of memory: throw JS_NULL to avoid recursing */
- obj = JS_NULL;
- }
- return JS_Throw(ctx, obj);
- }
- static JSValue JS_PRINTF_FORMAT_ATTR(3, 0)
- JS_ThrowError(JSContext *ctx, JSErrorEnum error_num,
- JS_PRINTF_FORMAT const char *fmt, va_list ap)
- {
- JSRuntime *rt = ctx->rt;
- JSStackFrame *sf;
- bool add_backtrace;
- /* the backtrace is added later if called from a bytecode function */
- sf = rt->current_stack_frame;
- add_backtrace = !rt->in_out_of_memory &&
- (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));
- return JS_ThrowError2(ctx, error_num, add_backtrace, fmt, ap);
- }
- #define JS_ERROR_MAP(X) \
- X(Internal, INTERNAL) \
- X(Plain, PLAIN) \
- X(Range, RANGE) \
- X(Reference, REFERENCE) \
- X(Syntax, SYNTAX) \
- X(Type, TYPE) \
- #define X(lc, uc) \
- JSValue JS_PRINTF_FORMAT_ATTR(2, 3) \
- JS_New##lc##Error(JSContext *ctx, \
- JS_PRINTF_FORMAT const char *fmt, ...) \
- { \
- JSValue val; \
- va_list ap; \
- \
- va_start(ap, fmt); \
- val = JS_MakeError(ctx, JS_##uc##_ERROR, \
- /*add_backtrace*/true, fmt, ap); \
- va_end(ap); \
- return val; \
- } \
- JSValue JS_PRINTF_FORMAT_ATTR(2, 3) \
- JS_Throw##lc##Error(JSContext *ctx, \
- JS_PRINTF_FORMAT const char *fmt, ...) \
- { \
- JSValue val; \
- va_list ap; \
- \
- va_start(ap, fmt); \
- val = JS_ThrowError(ctx, JS_##uc##_ERROR, fmt, ap); \
- va_end(ap); \
- return val; \
- } \
- JS_ERROR_MAP(X)
- #undef X
- #undef JS_ERROR_MAP
- static int JS_PRINTF_FORMAT_ATTR(3, 4) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, JS_PRINTF_FORMAT const char *fmt, ...)
- {
- va_list ap;
- if ((flags & JS_PROP_THROW) ||
- ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
- va_start(ap, fmt);
- JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
- va_end(ap);
- return -1;
- } else {
- return false;
- }
- }
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wformat-nonliteral"
- #endif // __GNUC__
- static JSValue JS_ThrowTypeErrorAtom(JSContext *ctx, const char *fmt, JSAtom atom)
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
- JS_AtomGetStr(ctx, buf, sizeof(buf), atom);
- return JS_ThrowTypeError(ctx, fmt, buf);
- }
- static JSValue JS_ThrowSyntaxErrorAtom(JSContext *ctx, const char *fmt, JSAtom atom)
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
- JS_AtomGetStr(ctx, buf, sizeof(buf), atom);
- return JS_ThrowSyntaxError(ctx, fmt, buf);
- }
- #ifdef __GNUC__
- #pragma GCC diagnostic pop // ignored "-Wformat-nonliteral"
- #endif // __GNUC__
- static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
- {
- if ((flags & JS_PROP_THROW) ||
- ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
- JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom);
- return -1;
- } else {
- return false;
- }
- }
- JSValue JS_ThrowOutOfMemory(JSContext *ctx)
- {
- JSRuntime *rt = ctx->rt;
- if (!rt->in_out_of_memory) {
- rt->in_out_of_memory = true;
- JS_ThrowInternalError(ctx, "out of memory");
- rt->in_out_of_memory = false;
- }
- return JS_EXCEPTION;
- }
- static JSValue JS_ThrowStackOverflow(JSContext *ctx)
- {
- return JS_ThrowRangeError(ctx, "Maximum call stack size exceeded");
- }
- static JSValue JS_ThrowTypeErrorNotAConstructor(JSContext *ctx,
- JSValueConst func_obj)
- {
- JSObject *p;
- JSAtom name;
- if (JS_TAG_OBJECT != JS_VALUE_GET_TAG(func_obj))
- goto fini;
- p = JS_VALUE_GET_OBJ(func_obj);
- if (!js_class_has_bytecode(p->class_id))
- goto fini;
- name = p->u.func.function_bytecode->func_name;
- if (name == JS_ATOM_NULL)
- goto fini;
- return JS_ThrowTypeErrorAtom(ctx, "%s is not a constructor", name);
- fini:
- return JS_ThrowTypeError(ctx, "not a constructor");
- }
- static JSValue JS_ThrowTypeErrorNotAFunction(JSContext *ctx)
- {
- return JS_ThrowTypeError(ctx, "not a function");
- }
- static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx)
- {
- return JS_ThrowTypeError(ctx, "not an object");
- }
- static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx)
- {
- return JS_ThrowTypeError(ctx, "not a symbol");
- }
- static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name)
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
- return JS_ThrowReferenceError(ctx, "%s is not defined",
- JS_AtomGetStr(ctx, buf, sizeof(buf), name));
- }
- static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name)
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
- return JS_ThrowReferenceError(ctx, "%s is not initialized",
- name == JS_ATOM_NULL ? "lexical variable" :
- JS_AtomGetStr(ctx, buf, sizeof(buf), name));
- }
- static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx,
- JSFunctionBytecode *b,
- int idx, bool is_ref)
- {
- JSAtom atom = JS_ATOM_NULL;
- if (is_ref) {
- atom = b->closure_var[idx].var_name;
- } else {
- /* not present if the function is stripped and contains no eval() */
- if (b->vardefs)
- atom = b->vardefs[b->arg_count + idx].var_name;
- }
- return JS_ThrowReferenceErrorUninitialized(ctx, atom);
- }
- static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
- {
- JSRuntime *rt = ctx->rt;
- JSAtom name;
- name = rt->class_array[class_id].class_name;
- return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
- }
- static void JS_ThrowInterrupted(JSContext *ctx)
- {
- JS_ThrowInternalError(ctx, "interrupted");
- JS_SetUncatchableError(ctx, ctx->rt->current_exception);
- }
- static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
- {
- JSRuntime *rt = ctx->rt;
- ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
- if (rt->interrupt_handler) {
- if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
- JS_ThrowInterrupted(ctx);
- return -1;
- }
- }
- return 0;
- }
- static inline __exception int js_poll_interrupts(JSContext *ctx)
- {
- if (unlikely(--ctx->interrupt_counter <= 0)) {
- return __js_poll_interrupts(ctx);
- } else {
- return 0;
- }
- }
- /* return -1 (exception) or true/false */
- static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj,
- JSValueConst proto_val, bool throw_flag)
- {
- JSObject *proto, *p, *p1;
- JSShape *sh;
- if (throw_flag) {
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL ||
- JS_VALUE_GET_TAG(obj) == JS_TAG_UNDEFINED)
- goto not_obj;
- } else {
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- goto not_obj;
- }
- p = JS_VALUE_GET_OBJ(obj);
- if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) {
- if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) {
- not_obj:
- JS_ThrowTypeErrorNotAnObject(ctx);
- return -1;
- }
- proto = NULL;
- } else {
- proto = JS_VALUE_GET_OBJ(proto_val);
- }
- if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- return true;
- if (unlikely(p->class_id == JS_CLASS_PROXY))
- return js_proxy_setPrototypeOf(ctx, obj, proto_val, throw_flag);
- sh = p->shape;
- if (sh->proto == proto)
- return true;
- if (p == JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_OBJECT])) {
- if (throw_flag) {
- JS_ThrowTypeError(ctx, "'Immutable prototype object \'Object.prototype\' cannot have their prototype set'");
- return -1;
- }
- return false;
- }
- if (!p->extensible) {
- if (throw_flag) {
- JS_ThrowTypeError(ctx, "object is not extensible");
- return -1;
- } else {
- return false;
- }
- }
- if (proto) {
- /* check if there is a cycle */
- p1 = proto;
- do {
- if (p1 == p) {
- if (throw_flag) {
- JS_ThrowTypeError(ctx, "circular prototype chain");
- return -1;
- } else {
- return false;
- }
- }
- /* Note: for Proxy objects, proto is NULL */
- p1 = p1->shape->proto;
- } while (p1 != NULL);
- js_dup(proto_val);
- }
- if (js_shape_prepare_update(ctx, p, NULL))
- return -1;
- sh = p->shape;
- if (sh->proto)
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
- sh->proto = proto;
- return true;
- }
- /* return -1 (exception) or true/false */
- int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val)
- {
- return JS_SetPrototypeInternal(ctx, obj, proto_val, true);
- }
- /* Only works for primitive types, otherwise return JS_NULL. */
- static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)
- {
- JSValue ret;
- switch(JS_VALUE_GET_NORM_TAG(val)) {
- case JS_TAG_SHORT_BIG_INT:
- case JS_TAG_BIG_INT:
- ret = ctx->class_proto[JS_CLASS_BIG_INT];
- break;
- case JS_TAG_INT:
- case JS_TAG_FLOAT64:
- ret = ctx->class_proto[JS_CLASS_NUMBER];
- break;
- case JS_TAG_BOOL:
- ret = ctx->class_proto[JS_CLASS_BOOLEAN];
- break;
- case JS_TAG_STRING:
- ret = ctx->class_proto[JS_CLASS_STRING];
- break;
- case JS_TAG_SYMBOL:
- ret = ctx->class_proto[JS_CLASS_SYMBOL];
- break;
- case JS_TAG_OBJECT:
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- default:
- ret = JS_NULL;
- break;
- }
- return ret;
- }
- /* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */
- JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj)
- {
- JSValue val;
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
- JSObject *p;
- p = JS_VALUE_GET_OBJ(obj);
- if (unlikely(p->class_id == JS_CLASS_PROXY)) {
- val = js_proxy_getPrototypeOf(ctx, obj);
- } else {
- p = p->shape->proto;
- if (!p)
- val = JS_NULL;
- else
- val = js_dup(JS_MKPTR(JS_TAG_OBJECT, p));
- }
- } else {
- val = js_dup(JS_GetPrototypePrimitive(ctx, obj));
- }
- return val;
- }
- static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj)
- {
- JSValue obj1;
- obj1 = JS_GetPrototype(ctx, obj);
- JS_FreeValue(ctx, obj);
- return obj1;
- }
- int JS_GetLength(JSContext *ctx, JSValueConst obj, int64_t *pres) {
- return js_get_length64(ctx, pres, obj);
- }
- int JS_SetLength(JSContext *ctx, JSValueConst obj, int64_t len) {
- return js_set_length64(ctx, obj, len);
- }
- /* return true, false or (-1) in case of exception */
- static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val,
- JSValueConst obj)
- {
- JSValue obj_proto;
- JSObject *proto;
- const JSObject *p, *proto1;
- int ret;
- if (!JS_IsFunction(ctx, obj))
- return false;
- p = JS_VALUE_GET_OBJ(obj);
- if (p->class_id == JS_CLASS_BOUND_FUNCTION) {
- JSBoundFunction *s = p->u.bound_function;
- return JS_IsInstanceOf(ctx, val, s->func_obj);
- }
- /* Only explicitly boxed values are instances of constructors */
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return false;
- obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype);
- if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) {
- if (!JS_IsException(obj_proto))
- JS_ThrowTypeError(ctx, "operand 'prototype' property is not an object");
- ret = -1;
- goto done;
- }
- proto = JS_VALUE_GET_OBJ(obj_proto);
- p = JS_VALUE_GET_OBJ(val);
- for(;;) {
- proto1 = p->shape->proto;
- if (!proto1) {
- /* slow case if proxy in the prototype chain */
- if (unlikely(p->class_id == JS_CLASS_PROXY)) {
- JSValue obj1;
- obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p));
- for(;;) {
- obj1 = JS_GetPrototypeFree(ctx, obj1);
- if (JS_IsException(obj1)) {
- ret = -1;
- break;
- }
- if (JS_IsNull(obj1)) {
- ret = false;
- break;
- }
- if (proto == JS_VALUE_GET_OBJ(obj1)) {
- JS_FreeValue(ctx, obj1);
- ret = true;
- break;
- }
- /* must check for timeout to avoid infinite loop */
- if (js_poll_interrupts(ctx)) {
- JS_FreeValue(ctx, obj1);
- ret = -1;
- break;
- }
- }
- } else {
- ret = false;
- }
- break;
- }
- p = proto1;
- if (proto == p) {
- ret = true;
- break;
- }
- }
- done:
- JS_FreeValue(ctx, obj_proto);
- return ret;
- }
- /* return true, false or (-1) in case of exception */
- int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj)
- {
- JSValue method;
- if (!JS_IsObject(obj))
- goto fail;
- method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance);
- if (JS_IsException(method))
- return -1;
- if (!JS_IsNull(method) && !JS_IsUndefined(method)) {
- JSValue ret;
- ret = JS_CallFree(ctx, method, obj, 1, &val);
- return JS_ToBoolFree(ctx, ret);
- }
- /* legacy case */
- if (!JS_IsFunction(ctx, obj)) {
- fail:
- JS_ThrowTypeError(ctx, "invalid 'instanceof' right operand");
- return -1;
- }
- return JS_OrdinaryIsInstanceOf(ctx, val, obj);
- }
- /* File generated automatically by the QuickJS-ng compiler. */
- #include <inttypes.h>
- const uint32_t qjsc_builtin_array_fromasync_size = 826;
- const uint8_t qjsc_builtin_array_fromasync[826] = {
- 0x15, 0x0d, 0x01, 0x1a, 0x61, 0x73, 0x79, 0x6e,
- 0x63, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f,
- 0x72, 0x01, 0x10, 0x69, 0x74, 0x65, 0x72, 0x61,
- 0x74, 0x6f, 0x72, 0x01, 0x12, 0x61, 0x72, 0x72,
- 0x61, 0x79, 0x4c, 0x69, 0x6b, 0x65, 0x01, 0x0a,
- 0x6d, 0x61, 0x70, 0x46, 0x6e, 0x01, 0x0e, 0x74,
- 0x68, 0x69, 0x73, 0x41, 0x72, 0x67, 0x01, 0x0c,
- 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x01, 0x02,
- 0x69, 0x01, 0x1a, 0x69, 0x73, 0x43, 0x6f, 0x6e,
- 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, 0x72,
- 0x01, 0x08, 0x73, 0x79, 0x6e, 0x63, 0x01, 0x0c,
- 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x01, 0x08,
- 0x69, 0x74, 0x65, 0x72, 0x01, 0x1c, 0x6e, 0x6f,
- 0x74, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x01, 0x08, 0x63, 0x61,
- 0x6c, 0x6c, 0x0c, 0x00, 0x02, 0x00, 0xa2, 0x01,
- 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0x01,
- 0xa4, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x43, 0x02,
- 0x01, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x01,
- 0x03, 0x05, 0xaa, 0x02, 0x00, 0x01, 0x40, 0xa0,
- 0x03, 0x00, 0x01, 0x40, 0xc6, 0x03, 0x00, 0x01,
- 0x40, 0xcc, 0x01, 0x00, 0x01, 0x40, 0xc8, 0x03,
- 0x00, 0x01, 0x40, 0x0c, 0x60, 0x02, 0x01, 0xf8,
- 0x01, 0x03, 0x0e, 0x01, 0x06, 0x05, 0x00, 0x86,
- 0x04, 0x11, 0xca, 0x03, 0x00, 0x01, 0x00, 0xcc,
- 0x03, 0x00, 0x01, 0x00, 0xce, 0x03, 0x00, 0x01,
- 0x00, 0xca, 0x03, 0x01, 0xff, 0xff, 0xff, 0xff,
- 0x0f, 0x20, 0xcc, 0x03, 0x01, 0x01, 0x20, 0xce,
- 0x03, 0x01, 0x02, 0x20, 0xd0, 0x03, 0x02, 0x00,
- 0x20, 0xd2, 0x03, 0x02, 0x04, 0x20, 0xd4, 0x03,
- 0x02, 0x05, 0x20, 0xd6, 0x03, 0x02, 0x06, 0x20,
- 0xd8, 0x03, 0x02, 0x07, 0x20, 0x64, 0x06, 0x08,
- 0x20, 0x82, 0x01, 0x07, 0x09, 0x20, 0xda, 0x03,
- 0x0a, 0x08, 0x30, 0x82, 0x01, 0x0d, 0x0b, 0x20,
- 0xd4, 0x01, 0x0d, 0x0c, 0x20, 0x10, 0x00, 0x01,
- 0x00, 0xa0, 0x03, 0x01, 0x03, 0xc6, 0x03, 0x02,
- 0x03, 0xc8, 0x03, 0x04, 0x03, 0xaa, 0x02, 0x00,
- 0x03, 0xcc, 0x01, 0x03, 0x03, 0x08, 0xc4, 0x0d,
- 0x62, 0x02, 0x00, 0x62, 0x01, 0x00, 0x62, 0x00,
- 0x00, 0xd3, 0xcb, 0xd4, 0x11, 0xf4, 0xec, 0x08,
- 0x0e, 0x39, 0x46, 0x00, 0x00, 0x00, 0xdc, 0xcc,
- 0xd5, 0x11, 0xf4, 0xec, 0x08, 0x0e, 0x39, 0x46,
- 0x00, 0x00, 0x00, 0xdd, 0xcd, 0x62, 0x07, 0x00,
- 0x62, 0x06, 0x00, 0x62, 0x05, 0x00, 0x62, 0x04,
- 0x00, 0x62, 0x03, 0x00, 0xd4, 0x39, 0x46, 0x00,
- 0x00, 0x00, 0xb0, 0xec, 0x16, 0xd4, 0x98, 0x04,
- 0x1b, 0x00, 0x00, 0x00, 0xb0, 0xec, 0x0c, 0xdf,
- 0x11, 0x04, 0xee, 0x00, 0x00, 0x00, 0x21, 0x01,
- 0x00, 0x30, 0x06, 0xce, 0xb6, 0xc4, 0x04, 0xc3,
- 0x0d, 0xf7, 0xc4, 0x05, 0x09, 0xc4, 0x06, 0xd3,
- 0xe0, 0x48, 0xc4, 0x07, 0x63, 0x07, 0x00, 0x07,
- 0xad, 0xec, 0x0f, 0x0a, 0x11, 0x64, 0x06, 0x00,
- 0x0e, 0xd3, 0xe1, 0x48, 0x11, 0x64, 0x07, 0x00,
- 0x0e, 0x63, 0x07, 0x00, 0x07, 0xad, 0x6a, 0xa6,
- 0x00, 0x00, 0x00, 0x62, 0x08, 0x00, 0x06, 0x11,
- 0xf4, 0xed, 0x0c, 0x71, 0x43, 0x32, 0x00, 0x00,
- 0x00, 0xc4, 0x08, 0x0e, 0xee, 0x05, 0x0e, 0xd3,
- 0xee, 0xf2, 0x63, 0x08, 0x00, 0x8e, 0x11, 0xed,
- 0x03, 0x0e, 0xb6, 0x11, 0x64, 0x08, 0x00, 0x0e,
- 0x63, 0x05, 0x00, 0xec, 0x0c, 0xc3, 0x0d, 0x11,
- 0x63, 0x08, 0x00, 0x21, 0x01, 0x00, 0xee, 0x06,
- 0xe2, 0x63, 0x08, 0x00, 0xf1, 0x11, 0x64, 0x03,
- 0x00, 0x0e, 0x63, 0x04, 0x00, 0x63, 0x08, 0x00,
- 0xa7, 0x6a, 0x2a, 0x01, 0x00, 0x00, 0x62, 0x09,
- 0x00, 0xd3, 0x63, 0x04, 0x00, 0x48, 0xc4, 0x09,
- 0x63, 0x06, 0x00, 0xec, 0x0a, 0x63, 0x09, 0x00,
- 0x8c, 0x11, 0x64, 0x09, 0x00, 0x0e, 0xd4, 0xec,
- 0x17, 0xd4, 0x43, 0xef, 0x00, 0x00, 0x00, 0xd5,
- 0x63, 0x09, 0x00, 0x63, 0x04, 0x00, 0x24, 0x03,
- 0x00, 0x8c, 0x11, 0x64, 0x09, 0x00, 0x0e, 0x5f,
- 0x04, 0x00, 0x63, 0x03, 0x00, 0x63, 0x04, 0x00,
- 0x92, 0x64, 0x04, 0x00, 0x0b, 0x63, 0x09, 0x00,
- 0x4d, 0x41, 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3e,
- 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3f, 0x00, 0x00,
- 0x00, 0xf3, 0x0e, 0xee, 0x9e, 0x62, 0x0a, 0x00,
- 0x63, 0x07, 0x00, 0x43, 0xef, 0x00, 0x00, 0x00,
- 0xd3, 0x24, 0x01, 0x00, 0xc4, 0x0a, 0x63, 0x05,
- 0x00, 0xec, 0x09, 0xc3, 0x0d, 0x11, 0x21, 0x00,
- 0x00, 0xee, 0x03, 0xe2, 0xf0, 0x11, 0x64, 0x03,
- 0x00, 0x0e, 0x6d, 0x8c, 0x00, 0x00, 0x00, 0x62,
- 0x0c, 0x00, 0x62, 0x0b, 0x00, 0x06, 0x11, 0xf4,
- 0xed, 0x13, 0x71, 0x43, 0x41, 0x00, 0x00, 0x00,
- 0xc4, 0x0b, 0x43, 0x6a, 0x00, 0x00, 0x00, 0xc4,
- 0x0c, 0x0e, 0xee, 0x10, 0x0e, 0x63, 0x0a, 0x00,
- 0x43, 0x6b, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00,
- 0x8c, 0xee, 0xe0, 0x63, 0x0c, 0x00, 0xed, 0x4e,
- 0x63, 0x06, 0x00, 0xec, 0x0a, 0x63, 0x0b, 0x00,
- 0x8c, 0x11, 0x64, 0x0b, 0x00, 0x0e, 0xd4, 0xec,
- 0x17, 0xd4, 0x43, 0xef, 0x00, 0x00, 0x00, 0xd5,
- 0x63, 0x0b, 0x00, 0x63, 0x04, 0x00, 0x24, 0x03,
- 0x00, 0x8c, 0x11, 0x64, 0x0b, 0x00, 0x0e, 0x5f,
- 0x04, 0x00, 0x63, 0x03, 0x00, 0x63, 0x04, 0x00,
- 0x92, 0x64, 0x04, 0x00, 0x0b, 0x63, 0x0b, 0x00,
- 0x4d, 0x41, 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3e,
- 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3f, 0x00, 0x00,
- 0x00, 0xf3, 0x0e, 0xee, 0x83, 0x0e, 0x06, 0x6e,
- 0x0d, 0x00, 0x00, 0x00, 0x0e, 0xee, 0x1e, 0x6e,
- 0x05, 0x00, 0x00, 0x00, 0x30, 0x63, 0x0a, 0x00,
- 0x42, 0x06, 0x00, 0x00, 0x00, 0xec, 0x0d, 0x63,
- 0x0a, 0x00, 0x43, 0x06, 0x00, 0x00, 0x00, 0x24,
- 0x00, 0x00, 0x0e, 0x6f, 0x63, 0x03, 0x00, 0x63,
- 0x04, 0x00, 0x44, 0x32, 0x00, 0x00, 0x00, 0x63,
- 0x03, 0x00, 0x2f, 0xc1, 0x00, 0x28, 0xc1, 0x00,
- 0xcf, 0x28,
- };
- static JSValue js_bytecode_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
- void *opaque)
- {
- switch ((uintptr_t)opaque) {
- default:
- abort();
- case JS_BUILTIN_ARRAY_FROMASYNC:
- {
- JSValue obj = JS_ReadObject(ctx, qjsc_builtin_array_fromasync,
- sizeof(qjsc_builtin_array_fromasync),
- JS_READ_OBJ_BYTECODE);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- JSValue fun = JS_EvalFunction(ctx, obj);
- if (JS_IsException(fun))
- return JS_EXCEPTION;
- assert(JS_IsFunction(ctx, fun));
- JSValue args[] = {
- JS_NewCFunction(ctx, js_array_constructor, "Array", 0),
- JS_NewCFunctionMagic(ctx, js_error_constructor, "TypeError", 1,
- JS_CFUNC_constructor_or_func_magic,
- JS_TYPE_ERROR),
- JS_AtomToValue(ctx, JS_ATOM_Symbol_asyncIterator),
- JS_NewCFunctionMagic(ctx, js_object_defineProperty,
- "Object.defineProperty", 3,
- JS_CFUNC_generic_magic, 0),
- JS_AtomToValue(ctx, JS_ATOM_Symbol_iterator),
- };
- JSValue result = JS_Call(ctx, fun, JS_UNDEFINED,
- countof(args), vc(args));
- for (size_t i = 0; i < countof(args); i++)
- JS_FreeValue(ctx, args[i]);
- JS_FreeValue(ctx, fun);
- if (JS_SetPrototypeInternal(ctx, result, ctx->function_proto,
- /*throw_flag*/true) < 0) {
- JS_FreeValue(ctx, result);
- return JS_EXCEPTION;
- }
- return result;
- }
- }
- return JS_UNDEFINED;
- }
- /* return the value associated to the autoinit property or an exception */
- typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
- static JSAutoInitFunc *const js_autoinit_func_table[] = {
- js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */
- js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */
- JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */
- js_bytecode_autoinit, /* JS_AUTOINIT_ID_BYTECODE */
- };
- /* warning: 'prs' is reallocated after it */
- static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
- JSProperty *pr, JSShapeProperty *prs)
- {
- JSValue val;
- JSContext *realm;
- JSAutoInitFunc *func;
- if (js_shape_prepare_update(ctx, p, &prs))
- return -1;
- realm = js_autoinit_get_realm(pr);
- func = js_autoinit_func_table[js_autoinit_get_id(pr)];
- /* 'func' shall not modify the object properties 'pr' */
- val = func(realm, p, prop, pr->u.init.opaque);
- js_autoinit_free(ctx->rt, pr);
- prs->flags &= ~JS_PROP_TMASK;
- pr->u.value = JS_UNDEFINED;
- if (JS_IsException(val))
- return -1;
- pr->u.value = val;
- return 0;
- }
- static JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
- JSAtom prop, JSValueConst this_obj,
- bool throw_ref_error)
- {
- JSObject *p;
- JSProperty *pr;
- JSShapeProperty *prs;
- uint32_t tag;
- tag = JS_VALUE_GET_TAG(obj);
- if (unlikely(tag != JS_TAG_OBJECT)) {
- switch(tag) {
- case JS_TAG_NULL:
- return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop);
- case JS_TAG_UNDEFINED:
- return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop);
- case JS_TAG_EXCEPTION:
- return JS_EXCEPTION;
- case JS_TAG_STRING:
- {
- JSString *p1 = JS_VALUE_GET_STRING(obj);
- if (__JS_AtomIsTaggedInt(prop)) {
- uint32_t idx, ch;
- idx = __JS_AtomToUInt32(prop);
- if (idx < p1->len) {
- ch = string_get(p1, idx);
- return js_new_string_char(ctx, ch);
- }
- } else if (prop == JS_ATOM_length) {
- return js_int32(p1->len);
- }
- }
- break;
- default:
- break;
- }
- /* cannot raise an exception */
- p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
- if (!p)
- return JS_UNDEFINED;
- } else {
- p = JS_VALUE_GET_OBJ(obj);
- }
- for(;;) {
- prs = find_own_property(&pr, p, prop);
- if (prs) {
- /* found */
- if (unlikely(prs->flags & JS_PROP_TMASK)) {
- if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
- if (unlikely(!pr->u.getset.getter)) {
- return JS_UNDEFINED;
- } else {
- JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter);
- /* Note: the field could be removed in the getter */
- func = js_dup(func);
- return JS_CallFree(ctx, func, this_obj, 0, NULL);
- }
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
- JSValue val = *pr->u.var_ref->pvalue;
- if (unlikely(JS_IsUninitialized(val)))
- return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
- return js_dup(val);
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* Instantiate property and retry */
- if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
- return JS_EXCEPTION;
- continue;
- }
- } else {
- return js_dup(pr->u.value);
- }
- }
- if (unlikely(p->is_exotic)) {
- /* exotic behaviors */
- if (p->fast_array) {
- if (__JS_AtomIsTaggedInt(prop)) {
- uint32_t idx = __JS_AtomToUInt32(prop);
- if (idx < p->u.array.count) {
- /* we avoid duplicating the code */
- return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
- } else if (is_typed_array(p->class_id)) {
- return JS_UNDEFINED;
- }
- } else if (is_typed_array(p->class_id)) {
- int ret;
- ret = JS_AtomIsNumericIndex(ctx, prop);
- if (ret != 0) {
- if (ret < 0)
- return JS_EXCEPTION;
- return JS_UNDEFINED;
- }
- }
- } else {
- const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
- if (em) {
- if (em->get_property) {
- JSValue obj1, retval;
- /* XXX: should pass throw_ref_error */
- /* Note: if 'p' is a prototype, it can be
- freed in the called function */
- obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p));
- retval = em->get_property(ctx, obj1, prop, this_obj);
- JS_FreeValue(ctx, obj1);
- return retval;
- }
- if (em->get_own_property) {
- JSPropertyDescriptor desc;
- int ret;
- JSValue obj1;
- /* Note: if 'p' is a prototype, it can be
- freed in the called function */
- obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p));
- ret = em->get_own_property(ctx, &desc, obj1, prop);
- JS_FreeValue(ctx, obj1);
- if (ret < 0)
- return JS_EXCEPTION;
- if (ret) {
- if (desc.flags & JS_PROP_GETSET) {
- JS_FreeValue(ctx, desc.setter);
- return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL);
- } else {
- return desc.value;
- }
- }
- }
- }
- }
- }
- p = p->shape->proto;
- if (!p)
- break;
- }
- if (unlikely(throw_ref_error)) {
- return JS_ThrowReferenceErrorNotDefined(ctx, prop);
- } else {
- return JS_UNDEFINED;
- }
- }
- JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop)
- {
- return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, false);
- }
- static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom)
- {
- return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist",
- atom);
- }
- /* Private fields can be added even on non extensible objects or
- Proxies */
- static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj,
- JSValue name, JSValue val)
- {
- JSObject *p;
- JSShapeProperty *prs;
- JSProperty *pr;
- JSAtom prop;
- if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
- JS_ThrowTypeErrorNotAnObject(ctx);
- goto fail;
- }
- /* safety check */
- if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
- JS_ThrowTypeErrorNotASymbol(ctx);
- goto fail;
- }
- prop = js_symbol_to_atom(ctx, name);
- p = JS_VALUE_GET_OBJ(obj);
- prs = find_own_property(&pr, p, prop);
- if (prs) {
- JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists",
- prop);
- goto fail;
- }
- pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
- if (unlikely(!pr)) {
- fail:
- JS_FreeValue(ctx, val);
- return -1;
- }
- pr->u.value = val;
- return 0;
- }
- static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj,
- JSValueConst name)
- {
- JSObject *p;
- JSShapeProperty *prs;
- JSProperty *pr;
- JSAtom prop;
- if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- /* safety check */
- if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL))
- return JS_ThrowTypeErrorNotASymbol(ctx);
- prop = js_symbol_to_atom(ctx, name);
- p = JS_VALUE_GET_OBJ(obj);
- prs = find_own_property(&pr, p, prop);
- if (!prs) {
- JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
- return JS_EXCEPTION;
- }
- return js_dup(pr->u.value);
- }
- static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,
- JSValueConst name, JSValue val)
- {
- JSObject *p;
- JSShapeProperty *prs;
- JSProperty *pr;
- JSAtom prop;
- if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
- JS_ThrowTypeErrorNotAnObject(ctx);
- goto fail;
- }
- /* safety check */
- if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
- JS_ThrowTypeErrorNotASymbol(ctx);
- goto fail;
- }
- prop = js_symbol_to_atom(ctx, name);
- p = JS_VALUE_GET_OBJ(obj);
- prs = find_own_property(&pr, p, prop);
- if (!prs) {
- JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
- fail:
- JS_FreeValue(ctx, val);
- return -1;
- }
- set_value(ctx, &pr->u.value, val);
- return 0;
- }
- /* add a private brand field to 'home_obj' if not already present and
- if obj is != null add a private brand to it */
- static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
- {
- JSObject *p, *p1;
- JSShapeProperty *prs;
- JSProperty *pr;
- JSValue brand;
- JSAtom brand_atom;
- if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) {
- JS_ThrowTypeErrorNotAnObject(ctx);
- return -1;
- }
- p = JS_VALUE_GET_OBJ(home_obj);
- prs = find_own_property(&pr, p, JS_ATOM_Private_brand);
- if (!prs) {
- /* if the brand is not present, add it */
- brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE);
- if (JS_IsException(brand))
- return -1;
- pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E);
- if (!pr) {
- JS_FreeValue(ctx, brand);
- return -1;
- }
- pr->u.value = js_dup(brand);
- } else {
- brand = js_dup(pr->u.value);
- }
- brand_atom = js_symbol_to_atom(ctx, brand);
- if (JS_IsObject(obj)) {
- p1 = JS_VALUE_GET_OBJ(obj);
- prs = find_own_property(&pr, p1, brand_atom);
- if (unlikely(prs)) {
- JS_FreeAtom(ctx, brand_atom);
- JS_ThrowTypeError(ctx, "private method is already present");
- return -1;
- }
- pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E);
- JS_FreeAtom(ctx, brand_atom);
- if (!pr)
- return -1;
- pr->u.value = JS_UNDEFINED;
- } else {
- JS_FreeAtom(ctx, brand_atom);
- }
- return 0;
- }
- /* return a boolean telling if the brand of the home object of 'func'
- is present on 'obj' or -1 in case of exception */
- static int JS_CheckBrand(JSContext *ctx, JSValue obj, JSValue func)
- {
- JSObject *p, *p1, *home_obj;
- JSShapeProperty *prs;
- JSProperty *pr;
- JSValue brand;
- /* get the home object of 'func' */
- if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT))
- goto not_obj;
- p1 = JS_VALUE_GET_OBJ(func);
- if (!js_class_has_bytecode(p1->class_id))
- goto not_obj;
- home_obj = p1->u.func.home_object;
- if (!home_obj)
- goto not_obj;
- prs = find_own_property(&pr, home_obj, JS_ATOM_Private_brand);
- if (!prs) {
- JS_ThrowTypeError(ctx, "expecting <brand> private field");
- return -1;
- }
- brand = pr->u.value;
- /* safety check */
- if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL))
- goto not_obj;
- /* get the brand array of 'obj' */
- if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
- not_obj:
- JS_ThrowTypeErrorNotAnObject(ctx);
- return -1;
- }
- p = JS_VALUE_GET_OBJ(obj);
- prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, brand));
- return (prs != NULL);
- }
- static uint32_t js_string_obj_get_length(JSContext *ctx, JSValueConst obj)
- {
- JSObject *p;
- JSString *p1;
- uint32_t len = 0;
- /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
- p = JS_VALUE_GET_OBJ(obj);
- if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
- p1 = JS_VALUE_GET_STRING(p->u.object_data);
- len = p1->len;
- }
- return len;
- }
- static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
- {
- JSContext *ctx = opaque;
- JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom;
- JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom;
- uint32_t v1, v2;
- bool atom1_is_integer, atom2_is_integer;
- atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1);
- atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2);
- assert(atom1_is_integer && atom2_is_integer);
- if (v1 < v2)
- return -1;
- else if (v1 == v2)
- return 0;
- else
- return 1;
- }
- static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
- {
- uint32_t i;
- if (tab) {
- for(i = 0; i < len; i++)
- JS_FreeAtom(ctx, tab[i].atom);
- js_free(ctx, tab);
- }
- }
- /* return < 0 in case if exception, 0 if OK. ptab and its atoms must
- be freed by the user. */
- static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
- JSPropertyEnum **ptab,
- uint32_t *plen,
- JSObject *p, int flags)
- {
- int i, j;
- JSShape *sh;
- JSShapeProperty *prs;
- JSPropertyEnum *tab_atom, *tab_exotic;
- JSAtom atom;
- uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count;
- uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count;
- bool is_enumerable, num_sorted;
- uint32_t num_key;
- JSAtomKindEnum kind;
- /* clear pointer for consistency in case of failure */
- *ptab = NULL;
- *plen = 0;
- /* compute the number of returned properties */
- num_keys_count = 0;
- str_keys_count = 0;
- sym_keys_count = 0;
- exotic_keys_count = 0;
- exotic_count = 0;
- tab_exotic = NULL;
- sh = p->shape;
- for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
- atom = prs->atom;
- if (atom != JS_ATOM_NULL) {
- is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
- kind = JS_AtomGetKind(ctx, atom);
- if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
- ((flags >> kind) & 1) != 0) {
- /* need to raise an exception in case of the module
- name space (implicit GetOwnProperty) */
- if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) &&
- (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) {
- JSVarRef *var_ref = p->prop[i].u.var_ref;
- if (unlikely(JS_IsUninitialized(*var_ref->pvalue))) {
- JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
- return -1;
- }
- }
- if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
- num_keys_count++;
- } else if (kind == JS_ATOM_KIND_STRING) {
- str_keys_count++;
- } else {
- sym_keys_count++;
- }
- }
- }
- }
- if (p->is_exotic) {
- if (p->fast_array) {
- if (flags & JS_GPN_STRING_MASK) {
- num_keys_count += p->u.array.count;
- }
- } else if (p->class_id == JS_CLASS_STRING) {
- if (flags & JS_GPN_STRING_MASK) {
- num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
- }
- } else {
- const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
- if (em && em->get_own_property_names) {
- if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count,
- JS_MKPTR(JS_TAG_OBJECT, p)))
- return -1;
- for(i = 0; i < exotic_count; i++) {
- atom = tab_exotic[i].atom;
- kind = JS_AtomGetKind(ctx, atom);
- if (((flags >> kind) & 1) != 0) {
- is_enumerable = false;
- if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) {
- JSPropertyDescriptor desc;
- int res;
- /* set the "is_enumerable" field if necessary */
- res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
- if (res < 0) {
- js_free_prop_enum(ctx, tab_exotic, exotic_count);
- return -1;
- }
- if (res) {
- is_enumerable =
- ((desc.flags & JS_PROP_ENUMERABLE) != 0);
- js_free_desc(ctx, &desc);
- }
- tab_exotic[i].is_enumerable = is_enumerable;
- }
- if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) {
- exotic_keys_count++;
- }
- }
- }
- }
- }
- }
- /* fill them */
- atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_keys_count;
- /* avoid allocating 0 bytes */
- tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
- if (!tab_atom) {
- js_free_prop_enum(ctx, tab_exotic, exotic_count);
- return -1;
- }
- num_index = 0;
- str_index = num_keys_count;
- sym_index = str_index + str_keys_count;
- num_sorted = true;
- sh = p->shape;
- for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
- atom = prs->atom;
- if (atom != JS_ATOM_NULL) {
- is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
- kind = JS_AtomGetKind(ctx, atom);
- if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
- ((flags >> kind) & 1) != 0) {
- if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
- j = num_index++;
- num_sorted = false;
- } else if (kind == JS_ATOM_KIND_STRING) {
- j = str_index++;
- } else {
- j = sym_index++;
- }
- tab_atom[j].atom = JS_DupAtom(ctx, atom);
- tab_atom[j].is_enumerable = is_enumerable;
- }
- }
- }
- if (p->is_exotic) {
- int len;
- if (p->fast_array) {
- if (flags & JS_GPN_STRING_MASK) {
- len = p->u.array.count;
- goto add_array_keys;
- }
- } else if (p->class_id == JS_CLASS_STRING) {
- if (flags & JS_GPN_STRING_MASK) {
- len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
- add_array_keys:
- for(i = 0; i < len; i++) {
- tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
- if (tab_atom[num_index].atom == JS_ATOM_NULL) {
- js_free_prop_enum(ctx, tab_atom, num_index);
- return -1;
- }
- tab_atom[num_index].is_enumerable = true;
- num_index++;
- }
- }
- } else {
- /* Note: exotic keys are not reordered and comes after the object own properties. */
- for(i = 0; i < exotic_count; i++) {
- atom = tab_exotic[i].atom;
- is_enumerable = tab_exotic[i].is_enumerable;
- kind = JS_AtomGetKind(ctx, atom);
- if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
- ((flags >> kind) & 1) != 0) {
- tab_atom[sym_index].atom = atom;
- tab_atom[sym_index].is_enumerable = is_enumerable;
- sym_index++;
- } else {
- JS_FreeAtom(ctx, atom);
- }
- }
- js_free(ctx, tab_exotic);
- }
- }
- assert(num_index == num_keys_count);
- assert(str_index == num_keys_count + str_keys_count);
- assert(sym_index == atom_count);
- if (num_keys_count != 0 && !num_sorted) {
- rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp,
- ctx);
- }
- *ptab = tab_atom;
- *plen = atom_count;
- return 0;
- }
- int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
- uint32_t *plen, JSValueConst obj, int flags)
- {
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
- JS_ThrowTypeErrorNotAnObject(ctx);
- return -1;
- }
- return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
- JS_VALUE_GET_OBJ(obj), flags);
- }
- /* Return -1 if exception,
- false if the property does not exist, true if it exists. If true is
- returned, the property descriptor 'desc' is filled present. */
- static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
- JSObject *p, JSAtom prop)
- {
- JSShapeProperty *prs;
- JSProperty *pr;
- retry:
- prs = find_own_property(&pr, p, prop);
- if (prs) {
- if (desc) {
- desc->flags = prs->flags & JS_PROP_C_W_E;
- desc->getter = JS_UNDEFINED;
- desc->setter = JS_UNDEFINED;
- desc->value = JS_UNDEFINED;
- if (unlikely(prs->flags & JS_PROP_TMASK)) {
- if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
- desc->flags |= JS_PROP_GETSET;
- if (pr->u.getset.getter)
- desc->getter = js_dup(JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
- if (pr->u.getset.setter)
- desc->setter = js_dup(JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
- JSValue val = *pr->u.var_ref->pvalue;
- if (unlikely(JS_IsUninitialized(val))) {
- JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
- return -1;
- }
- desc->value = js_dup(val);
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* Instantiate property and retry */
- if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
- return -1;
- goto retry;
- }
- } else {
- desc->value = js_dup(pr->u.value);
- }
- } else {
- /* for consistency, send the exception even if desc is NULL */
- if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) {
- if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) {
- JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
- return -1;
- }
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* nothing to do: delay instantiation until actual value and/or attributes are read */
- }
- }
- return true;
- }
- if (p->is_exotic) {
- if (p->fast_array) {
- /* specific case for fast arrays */
- if (__JS_AtomIsTaggedInt(prop)) {
- uint32_t idx;
- idx = __JS_AtomToUInt32(prop);
- if (idx < p->u.array.count) {
- if (desc) {
- desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE |
- JS_PROP_CONFIGURABLE;
- desc->getter = JS_UNDEFINED;
- desc->setter = JS_UNDEFINED;
- desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
- }
- return true;
- }
- }
- } else {
- const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
- if (em && em->get_own_property) {
- return em->get_own_property(ctx, desc,
- JS_MKPTR(JS_TAG_OBJECT, p), prop);
- }
- }
- }
- return false;
- }
- int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
- JSValueConst obj, JSAtom prop)
- {
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
- JS_ThrowTypeErrorNotAnObject(ctx);
- return -1;
- }
- return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop);
- }
- void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab,
- uint32_t len)
- {
- js_free_prop_enum(ctx, tab, len);
- }
- /* return -1 if exception (Proxy object only) or true/false */
- int JS_IsExtensible(JSContext *ctx, JSValueConst obj)
- {
- JSObject *p;
- if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
- return false;
- p = JS_VALUE_GET_OBJ(obj);
- if (unlikely(p->class_id == JS_CLASS_PROXY))
- return js_proxy_isExtensible(ctx, obj);
- else
- return p->extensible;
- }
- /* return -1 if exception (Proxy object only) or true/false */
- int JS_PreventExtensions(JSContext *ctx, JSValueConst obj)
- {
- JSObject *p;
- if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
- return false;
- p = JS_VALUE_GET_OBJ(obj);
- if (unlikely(p->class_id == JS_CLASS_PROXY))
- return js_proxy_preventExtensions(ctx, obj);
- p->extensible = false;
- return true;
- }
- /* return -1 if exception otherwise true or false */
- int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop)
- {
- JSObject *p;
- int ret;
- JSValue obj1;
- if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
- return false;
- p = JS_VALUE_GET_OBJ(obj);
- for(;;) {
- if (p->is_exotic) {
- const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
- if (em && em->has_property) {
- /* has_property can free the prototype */
- obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p));
- ret = em->has_property(ctx, obj1, prop);
- JS_FreeValue(ctx, obj1);
- return ret;
- }
- }
- /* JS_GetOwnPropertyInternal can free the prototype */
- js_dup(JS_MKPTR(JS_TAG_OBJECT, p));
- ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop);
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
- if (ret != 0)
- return ret;
- if (is_typed_array(p->class_id)) {
- ret = JS_AtomIsNumericIndex(ctx, prop);
- if (ret != 0) {
- if (ret < 0)
- return -1;
- return false;
- }
- }
- p = p->shape->proto;
- if (!p)
- break;
- }
- return false;
- }
- /* val must be a symbol */
- static JSAtom js_symbol_to_atom(JSContext *ctx, JSValueConst val)
- {
- JSAtomStruct *p = JS_VALUE_GET_PTR(val);
- return js_get_atom_index(ctx->rt, p);
- }
- /* return JS_ATOM_NULL in case of exception */
- static JSAtom JS_ValueToAtomInternal(JSContext *ctx, JSValueConst val,
- int flags)
- {
- JSAtom atom;
- uint32_t tag;
- tag = JS_VALUE_GET_TAG(val);
- if (tag == JS_TAG_INT &&
- (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) {
- /* fast path for integer values */
- atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val));
- } else if (tag == JS_TAG_SYMBOL) {
- JSAtomStruct *p = JS_VALUE_GET_PTR(val);
- atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));
- } else {
- JSValue str;
- str = JS_ToPropertyKeyInternal(ctx, val, flags);
- if (JS_IsException(str))
- return JS_ATOM_NULL;
- if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) {
- atom = js_symbol_to_atom(ctx, str);
- } else {
- atom = JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(str));
- }
- }
- return atom;
- }
- JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
- {
- return JS_ValueToAtomInternal(ctx, val, /*flags*/0);
- }
- static bool js_get_fast_array_element(JSContext *ctx, JSObject *p,
- uint32_t idx, JSValue *pval)
- {
- switch(p->class_id) {
- case JS_CLASS_ARRAY:
- case JS_CLASS_ARGUMENTS:
- if (unlikely(idx >= p->u.array.count)) return false;
- *pval = js_dup(p->u.array.u.values[idx]);
- return true;
- case JS_CLASS_INT8_ARRAY:
- if (unlikely(idx >= p->u.array.count)) return false;
- *pval = js_int32(p->u.array.u.int8_ptr[idx]);
- return true;
- case JS_CLASS_UINT8C_ARRAY:
- case JS_CLASS_UINT8_ARRAY:
- if (unlikely(idx >= p->u.array.count)) return false;
- *pval = js_int32(p->u.array.u.uint8_ptr[idx]);
- return true;
- case JS_CLASS_INT16_ARRAY:
- if (unlikely(idx >= p->u.array.count)) return false;
- *pval = js_int32(p->u.array.u.int16_ptr[idx]);
- return true;
- case JS_CLASS_UINT16_ARRAY:
- if (unlikely(idx >= p->u.array.count)) return false;
- *pval = js_int32(p->u.array.u.uint16_ptr[idx]);
- return true;
- case JS_CLASS_INT32_ARRAY:
- if (unlikely(idx >= p->u.array.count)) return false;
- *pval = js_int32(p->u.array.u.int32_ptr[idx]);
- return true;
- case JS_CLASS_UINT32_ARRAY:
- if (unlikely(idx >= p->u.array.count)) return false;
- *pval = js_uint32(p->u.array.u.uint32_ptr[idx]);
- return true;
- case JS_CLASS_BIG_INT64_ARRAY:
- if (unlikely(idx >= p->u.array.count)) return false;
- *pval = JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
- return true;
- case JS_CLASS_BIG_UINT64_ARRAY:
- if (unlikely(idx >= p->u.array.count)) return false;
- *pval = JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
- return true;
- case JS_CLASS_FLOAT16_ARRAY:
- if (unlikely(idx >= p->u.array.count)) return false;
- *pval = js_float64(fromfp16(p->u.array.u.fp16_ptr[idx]));
- return true;
- case JS_CLASS_FLOAT32_ARRAY:
- if (unlikely(idx >= p->u.array.count)) return false;
- *pval = js_float64(p->u.array.u.float_ptr[idx]);
- return true;
- case JS_CLASS_FLOAT64_ARRAY:
- if (unlikely(idx >= p->u.array.count)) return false;
- *pval = js_float64(p->u.array.u.double_ptr[idx]);
- return true;
- default:
- return false;
- }
- }
- static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
- JSValue prop)
- {
- JSAtom atom;
- JSValue ret;
- uint32_t tag;
- tag = JS_VALUE_GET_TAG(this_obj);
- if (likely(tag == JS_TAG_OBJECT)) {
- if (JS_VALUE_GET_TAG(prop) == JS_TAG_INT) {
- JSObject *p = JS_VALUE_GET_OBJ(this_obj);
- uint32_t idx = JS_VALUE_GET_INT(prop);
- JSValue val;
- /* fast path for array and typed array access */
- if (js_get_fast_array_element(ctx, p, idx, &val))
- return val;
- }
- } else if (unlikely(tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)) {
- // per spec: not allowed to call ToPropertyKey before ToObject
- // so we must ensure to not invoke JS anything that's observable
- // from JS code
- atom = JS_ValueToAtomInternal(ctx, prop, JS_TO_STRING_NO_SIDE_EFFECTS);
- JS_FreeValue(ctx, prop);
- if (unlikely(atom == JS_ATOM_NULL))
- return JS_EXCEPTION;
- if (tag == JS_TAG_NULL) {
- JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", atom);
- } else {
- JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", atom);
- }
- JS_FreeAtom(ctx, atom);
- return JS_EXCEPTION;
- }
- atom = JS_ValueToAtom(ctx, prop);
- JS_FreeValue(ctx, prop);
- if (unlikely(atom == JS_ATOM_NULL))
- return JS_EXCEPTION;
- ret = JS_GetProperty(ctx, this_obj, atom);
- JS_FreeAtom(ctx, atom);
- return ret;
- }
- JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
- uint32_t idx)
- {
- return JS_GetPropertyInt64(ctx, this_obj, idx);
- }
- /* Check if an object has a generalized numeric property. Return value:
- -1 for exception, *pval set to JS_EXCEPTION
- true if property exists, stored into *pval,
- false if property does not exist. *pval set to JS_UNDEFINED.
- */
- static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, JSValue *pval)
- {
- JSValue val;
- JSAtom prop;
- int present;
- if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT &&
- (uint64_t)idx <= INT32_MAX)) {
- /* fast path for array and typed array access */
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- if (js_get_fast_array_element(ctx, p, idx, pval))
- return true;
- }
- val = JS_EXCEPTION;
- present = -1;
- prop = JS_NewAtomInt64(ctx, idx);
- if (likely(prop != JS_ATOM_NULL)) {
- present = JS_HasProperty(ctx, obj, prop);
- if (present > 0) {
- val = JS_GetProperty(ctx, obj, prop);
- if (unlikely(JS_IsException(val)))
- present = -1;
- } else if (present == false) {
- val = JS_UNDEFINED;
- }
- JS_FreeAtom(ctx, prop);
- }
- *pval = val;
- return present;
- }
- JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx)
- {
- JSAtom prop;
- JSValue val;
- if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT &&
- (uint64_t)idx <= INT32_MAX)) {
- /* fast path for array and typed array access */
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- if (js_get_fast_array_element(ctx, p, idx, &val))
- return val;
- }
- prop = JS_NewAtomInt64(ctx, idx);
- if (prop == JS_ATOM_NULL)
- return JS_EXCEPTION;
- val = JS_GetProperty(ctx, obj, prop);
- JS_FreeAtom(ctx, prop);
- return val;
- }
- /* `prop` may be pure ASCII or UTF-8 encoded */
- JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
- const char *prop)
- {
- JSAtom atom;
- JSValue ret;
- atom = JS_NewAtom(ctx, prop);
- if (atom == JS_ATOM_NULL)
- return JS_EXCEPTION;
- ret = JS_GetProperty(ctx, this_obj, atom);
- JS_FreeAtom(ctx, atom);
- return ret;
- }
- /* Note: the property value is not initialized. Return NULL if memory
- error. */
- static JSProperty *add_property(JSContext *ctx,
- JSObject *p, JSAtom prop, int prop_flags)
- {
- JSShape *sh, *new_sh;
- sh = p->shape;
- if (sh->is_hashed) {
- /* try to find an existing shape */
- new_sh = find_hashed_shape_prop(ctx->rt, sh, prop, prop_flags);
- if (new_sh) {
- /* matching shape found: use it */
- /* the property array may need to be resized */
- if (new_sh->prop_size != sh->prop_size) {
- JSProperty *new_prop;
- new_prop = js_realloc(ctx, p->prop, sizeof(p->prop[0]) *
- new_sh->prop_size);
- if (!new_prop)
- return NULL;
- p->prop = new_prop;
- }
- p->shape = js_dup_shape(new_sh);
- js_free_shape(ctx->rt, sh);
- return &p->prop[new_sh->prop_count - 1];
- } else if (sh->header.ref_count != 1) {
- /* if the shape is shared, clone it */
- new_sh = js_clone_shape(ctx, sh);
- if (!new_sh)
- return NULL;
- /* hash the cloned shape */
- new_sh->is_hashed = true;
- js_shape_hash_link(ctx->rt, new_sh);
- js_free_shape(ctx->rt, p->shape);
- p->shape = new_sh;
- }
- }
- assert(p->shape->header.ref_count == 1);
- if (add_shape_property(ctx, &p->shape, p, prop, prop_flags))
- return NULL;
- return &p->prop[p->shape->prop_count - 1];
- }
- /* can be called on Array or Arguments objects. return < 0 if
- memory alloc error. */
- static no_inline __exception int convert_fast_array_to_array(JSContext *ctx,
- JSObject *p)
- {
- JSProperty *pr;
- JSShape *sh;
- JSValue *tab;
- uint32_t i, len, new_count;
- if (js_shape_prepare_update(ctx, p, NULL))
- return -1;
- len = p->u.array.count;
- /* resize the properties once to simplify the error handling */
- sh = p->shape;
- new_count = sh->prop_count + len;
- if (new_count > sh->prop_size) {
- if (resize_properties(ctx, &p->shape, p, new_count))
- return -1;
- }
- tab = p->u.array.u.values;
- for(i = 0; i < len; i++) {
- /* add_property cannot fail here but
- __JS_AtomFromUInt32(i) fails for i > INT32_MAX */
- pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E);
- pr->u.value = *tab++;
- }
- js_free(ctx, p->u.array.u.values);
- p->u.array.count = 0;
- p->u.array.u.values = NULL; /* fail safe */
- p->u.array.u1.size = 0;
- p->fast_array = 0;
- return 0;
- }
- static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom)
- {
- JSShape *sh;
- JSShapeProperty *pr, *lpr, *prop;
- JSProperty *pr1;
- uint32_t lpr_idx;
- intptr_t h, h1;
- redo:
- sh = p->shape;
- h1 = atom & sh->prop_hash_mask;
- h = prop_hash_end(sh)[-h1 - 1];
- prop = get_shape_prop(sh);
- lpr = NULL;
- lpr_idx = 0; /* prevent warning */
- while (h != 0) {
- pr = &prop[h - 1];
- if (likely(pr->atom == atom)) {
- /* found ! */
- if (!(pr->flags & JS_PROP_CONFIGURABLE))
- return false;
- /* realloc the shape if needed */
- if (lpr)
- lpr_idx = lpr - get_shape_prop(sh);
- if (js_shape_prepare_update(ctx, p, &pr))
- return -1;
- sh = p->shape;
- /* remove property */
- if (lpr) {
- lpr = get_shape_prop(sh) + lpr_idx;
- lpr->hash_next = pr->hash_next;
- } else {
- prop_hash_end(sh)[-h1 - 1] = pr->hash_next;
- }
- sh->deleted_prop_count++;
- /* free the entry */
- pr1 = &p->prop[h - 1];
- free_property(ctx->rt, pr1, pr->flags);
- JS_FreeAtom(ctx, pr->atom);
- /* put default values */
- pr->flags = 0;
- pr->atom = JS_ATOM_NULL;
- pr1->u.value = JS_UNDEFINED;
- /* compact the properties if too many deleted properties */
- if (sh->deleted_prop_count >= 8 &&
- sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) {
- compact_properties(ctx, p);
- }
- return true;
- }
- lpr = pr;
- h = pr->hash_next;
- }
- if (p->is_exotic) {
- if (p->fast_array) {
- uint32_t idx;
- if (JS_AtomIsArrayIndex(ctx, &idx, atom) &&
- idx < p->u.array.count) {
- if (p->class_id == JS_CLASS_ARRAY ||
- p->class_id == JS_CLASS_ARGUMENTS) {
- /* Special case deleting the last element of a fast Array */
- if (idx == p->u.array.count - 1) {
- JS_FreeValue(ctx, p->u.array.u.values[idx]);
- p->u.array.count = idx;
- return true;
- }
- if (convert_fast_array_to_array(ctx, p))
- return -1;
- goto redo;
- } else {
- return false;
- }
- }
- } else {
- const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
- if (em && em->delete_property) {
- return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom);
- }
- }
- }
- /* not found */
- return true;
- }
- static int call_setter(JSContext *ctx, JSObject *setter,
- JSValueConst this_obj, JSValue val, int flags)
- {
- JSValue ret, func;
- if (likely(setter)) {
- func = JS_MKPTR(JS_TAG_OBJECT, setter);
- /* Note: the field could be removed in the setter */
- func = js_dup(func);
- ret = JS_CallFree(ctx, func, this_obj, 1, vc(&val));
- JS_FreeValue(ctx, val);
- if (JS_IsException(ret))
- return -1;
- JS_FreeValue(ctx, ret);
- return true;
- } else {
- JS_FreeValue(ctx, val);
- if ((flags & JS_PROP_THROW) ||
- ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
- JS_ThrowTypeError(ctx, "no setter for property");
- return -1;
- }
- return false;
- }
- }
- /* set the array length and remove the array elements if necessary. */
- static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
- int flags)
- {
- uint32_t len, idx, cur_len;
- int i, ret;
- /* Note: this call can reallocate the properties of 'p' */
- ret = JS_ToArrayLengthFree(ctx, &len, val, false);
- if (ret)
- return -1;
- /* JS_ToArrayLengthFree() must be done before the read-only test */
- if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE)))
- return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
- if (likely(p->fast_array)) {
- uint32_t old_len = p->u.array.count;
- if (len < old_len) {
- for(i = len; i < old_len; i++) {
- JS_FreeValue(ctx, p->u.array.u.values[i]);
- }
- p->u.array.count = len;
- }
- p->prop[0].u.value = js_uint32(len);
- } else {
- /* Note: length is always a uint32 because the object is an
- array */
- JS_ToUint32(ctx, &cur_len, p->prop[0].u.value);
- if (len < cur_len) {
- uint32_t d;
- JSShape *sh;
- JSShapeProperty *pr;
- d = cur_len - len;
- sh = p->shape;
- if (d <= sh->prop_count) {
- JSAtom atom;
- /* faster to iterate */
- while (cur_len > len) {
- atom = JS_NewAtomUInt32(ctx, cur_len - 1);
- ret = delete_property(ctx, p, atom);
- JS_FreeAtom(ctx, atom);
- if (unlikely(!ret)) {
- /* unlikely case: property is not
- configurable */
- break;
- }
- cur_len--;
- }
- } else {
- /* faster to iterate thru all the properties. Need two
- passes in case one of the property is not
- configurable */
- cur_len = len;
- for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
- i++, pr++) {
- if (pr->atom != JS_ATOM_NULL &&
- JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
- if (idx >= cur_len &&
- !(pr->flags & JS_PROP_CONFIGURABLE)) {
- cur_len = idx + 1;
- }
- }
- }
- for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
- i++, pr++) {
- if (pr->atom != JS_ATOM_NULL &&
- JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
- if (idx >= cur_len) {
- /* remove the property */
- delete_property(ctx, p, pr->atom);
- /* WARNING: the shape may have been modified */
- sh = p->shape;
- pr = get_shape_prop(sh) + i;
- }
- }
- }
- }
- } else {
- cur_len = len;
- }
- set_value(ctx, &p->prop[0].u.value, js_uint32(cur_len));
- if (unlikely(cur_len > len)) {
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable");
- }
- }
- return true;
- }
- /* return -1 if exception */
- static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len)
- {
- uint32_t new_size;
- size_t slack;
- JSValue *new_array_prop;
- /* XXX: potential arithmetic overflow */
- new_size = max_int(new_len, p->u.array.u1.size * 3 / 2);
- new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack);
- if (!new_array_prop)
- return -1;
- new_size += slack / sizeof(*new_array_prop);
- p->u.array.u.values = new_array_prop;
- p->u.array.u1.size = new_size;
- return 0;
- }
- /* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array =
- true and p->extensible = true */
- static int add_fast_array_element(JSContext *ctx, JSObject *p,
- JSValue val, int flags)
- {
- uint32_t new_len, array_len;
- /* extend the array by one */
- /* XXX: convert to slow array if new_len > 2^31-1 elements */
- new_len = p->u.array.count + 1;
- /* update the length if necessary. We assume that if the length is
- not an integer, then if it >= 2^31. */
- if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) {
- array_len = JS_VALUE_GET_INT(p->prop[0].u.value);
- if (new_len > array_len) {
- if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) {
- JS_FreeValue(ctx, val);
- return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
- }
- p->prop[0].u.value = js_int32(new_len);
- }
- }
- if (unlikely(new_len > p->u.array.u1.size)) {
- if (expand_fast_array(ctx, p, new_len)) {
- JS_FreeValue(ctx, val);
- return -1;
- }
- }
- p->u.array.u.values[new_len - 1] = val;
- p->u.array.count = new_len;
- return true;
- }
- static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
- {
- JS_FreeValue(ctx, desc->getter);
- JS_FreeValue(ctx, desc->setter);
- JS_FreeValue(ctx, desc->value);
- }
- /* return -1 in case of exception or true or false. Warning: 'val' is
- freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD,
- JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set,
- the new property is not added and an error is raised.
- 'obj' must be an object when obj != this_obj.
- */
- static int JS_SetPropertyInternal2(JSContext *ctx, JSValueConst obj, JSAtom prop,
- JSValue val, JSValueConst this_obj, int flags)
- {
- JSObject *p, *p1;
- JSShapeProperty *prs;
- JSProperty *pr;
- JSPropertyDescriptor desc;
- int ret;
- switch(JS_VALUE_GET_TAG(this_obj)) {
- case JS_TAG_NULL:
- JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop);
- goto fail;
- case JS_TAG_UNDEFINED:
- JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop);
- goto fail;
- case JS_TAG_OBJECT:
- p = JS_VALUE_GET_OBJ(this_obj);
- p1 = JS_VALUE_GET_OBJ(obj);
- if (p == p1)
- break;
- goto retry2;
- default:
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- obj = JS_GetPrototypePrimitive(ctx, obj);
- p = NULL;
- p1 = JS_VALUE_GET_OBJ(obj);
- goto prototype_lookup;
- }
- retry:
- prs = find_own_property(&pr, p1, prop);
- if (prs) {
- if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE |
- JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {
- /* fast case */
- set_value(ctx, &pr->u.value, val);
- return true;
- } else if (prs->flags & JS_PROP_LENGTH) {
- assert(p->class_id == JS_CLASS_ARRAY);
- assert(prop == JS_ATOM_length);
- return set_array_length(ctx, p, val, flags);
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
- return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
- /* JS_PROP_WRITABLE is always true for variable
- references, but they are write protected in module name
- spaces. */
- if (p->class_id == JS_CLASS_MODULE_NS)
- goto read_only_prop;
- set_value(ctx, pr->u.var_ref->pvalue, val);
- return true;
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* Instantiate property and retry (potentially useless) */
- if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
- goto fail;
- goto retry;
- } else {
- goto read_only_prop;
- }
- }
- for(;;) {
- if (p1->is_exotic) {
- if (p1->fast_array) {
- if (__JS_AtomIsTaggedInt(prop)) {
- uint32_t idx = __JS_AtomToUInt32(prop);
- if (idx < p1->u.array.count) {
- if (unlikely(p == p1))
- return JS_SetPropertyValue(ctx, this_obj, js_int32(idx), val, flags);
- else
- break;
- } else if (is_typed_array(p1->class_id)) {
- goto typed_array_oob;
- }
- } else if (is_typed_array(p1->class_id)) {
- ret = JS_AtomIsNumericIndex(ctx, prop);
- if (ret != 0) {
- if (ret < 0)
- goto fail;
- typed_array_oob:
- // per spec: evaluate value for side effects
- if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY ||
- p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
- int64_t v;
- if (JS_ToBigInt64Free(ctx, &v, val))
- return -1;
- } else {
- val = JS_ToNumberFree(ctx, val);
- JS_FreeValue(ctx, val);
- if (JS_IsException(val))
- return -1;
- }
- return true;
- }
- }
- } else {
- const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic;
- if (em) {
- JSValue obj1;
- if (em->set_property) {
- /* set_property can free the prototype */
- obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p1));
- ret = em->set_property(ctx, obj1, prop,
- val, this_obj, flags);
- JS_FreeValue(ctx, obj1);
- JS_FreeValue(ctx, val);
- return ret;
- }
- if (em->get_own_property) {
- /* get_own_property can free the prototype */
- obj1 = js_dup(JS_MKPTR(JS_TAG_OBJECT, p1));
- ret = em->get_own_property(ctx, &desc,
- obj1, prop);
- JS_FreeValue(ctx, obj1);
- if (ret < 0)
- goto fail;
- if (ret) {
- if (desc.flags & JS_PROP_GETSET) {
- JSObject *setter;
- if (JS_IsUndefined(desc.setter))
- setter = NULL;
- else
- setter = JS_VALUE_GET_OBJ(desc.setter);
- ret = call_setter(ctx, setter, this_obj, val, flags);
- JS_FreeValue(ctx, desc.getter);
- JS_FreeValue(ctx, desc.setter);
- return ret;
- } else {
- JS_FreeValue(ctx, desc.value);
- if (!(desc.flags & JS_PROP_WRITABLE))
- goto read_only_prop;
- if (likely(p == p1)) {
- ret = JS_DefineProperty(ctx, this_obj, prop, val,
- JS_UNDEFINED, JS_UNDEFINED,
- JS_PROP_HAS_VALUE);
- JS_FreeValue(ctx, val);
- return ret;
- } else {
- break;
- }
- }
- }
- }
- }
- }
- }
- p1 = p1->shape->proto;
- prototype_lookup:
- if (!p1)
- break;
- retry2:
- prs = find_own_property(&pr, p1, prop);
- if (prs) {
- if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
- return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* Instantiate property and retry (potentially useless) */
- if (JS_AutoInitProperty(ctx, p1, prop, pr, prs))
- return -1;
- goto retry2;
- } else if (!(prs->flags & JS_PROP_WRITABLE)) {
- goto read_only_prop;
- } else {
- break;
- }
- }
- }
- if (unlikely(flags & JS_PROP_NO_ADD)) {
- JS_ThrowReferenceErrorNotDefined(ctx, prop);
- goto fail;
- }
- if (unlikely(!p)) {
- ret = JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object");
- goto done;
- }
- if (unlikely(!p->extensible)) {
- ret = JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
- goto done;
- }
- if (p == JS_VALUE_GET_OBJ(obj)) {
- if (p->is_exotic) {
- if (p->class_id == JS_CLASS_ARRAY && p->fast_array &&
- __JS_AtomIsTaggedInt(prop)) {
- uint32_t idx = __JS_AtomToUInt32(prop);
- if (idx == p->u.array.count) {
- /* fast case */
- return add_fast_array_element(ctx, p, val, flags);
- }
- }
- goto generic_create_prop;
- } else {
- pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
- if (!pr)
- goto fail;
- pr->u.value = val;
- return true;
- }
- }
- // TODO(bnoordhuis) return JSProperty slot and update in place
- // when plain property (not is_exotic/setter/etc.) to avoid
- // calling find_own_property() thrice?
- ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
- if (ret < 0)
- goto fail;
- if (ret) {
- JS_FreeValue(ctx, desc.value);
- if (desc.flags & JS_PROP_GETSET) {
- JS_FreeValue(ctx, desc.getter);
- JS_FreeValue(ctx, desc.setter);
- ret = JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden");
- goto done;
- } else if (!(desc.flags & JS_PROP_WRITABLE) ||
- p->class_id == JS_CLASS_MODULE_NS) {
- read_only_prop:
- ret = JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
- goto done;
- }
- ret = JS_DefineProperty(ctx, this_obj, prop, val,
- JS_UNDEFINED, JS_UNDEFINED,
- JS_PROP_HAS_VALUE);
- } else {
- generic_create_prop:
- ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
- flags |
- JS_PROP_HAS_VALUE |
- JS_PROP_HAS_ENUMERABLE |
- JS_PROP_HAS_WRITABLE |
- JS_PROP_HAS_CONFIGURABLE |
- JS_PROP_C_W_E);
- }
- done:
- JS_FreeValue(ctx, val);
- return ret;
- fail:
- JS_FreeValue(ctx, val);
- return -1;
- }
- static int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop,
- JSValue val, int flags)
- {
- return JS_SetPropertyInternal2(ctx, obj, prop, val, obj, flags);
- }
- int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val)
- {
- return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW);
- }
- /* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */
- static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
- JSValue prop, JSValue val, int flags)
- {
- if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
- JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
- JSObject *p;
- uint32_t idx;
- double d;
- int32_t v;
- /* fast path for array access */
- p = JS_VALUE_GET_OBJ(this_obj);
- idx = JS_VALUE_GET_INT(prop);
- switch(p->class_id) {
- case JS_CLASS_ARRAY:
- if (unlikely(idx >= (uint32_t)p->u.array.count)) {
- JSObject *p1;
- JSShape *sh1;
- /* fast path to add an element to the array */
- if (idx != (uint32_t)p->u.array.count ||
- !p->fast_array || !p->extensible)
- goto slow_path;
- /* check if prototype chain has a numeric property */
- p1 = p->shape->proto;
- while (p1 != NULL) {
- sh1 = p1->shape;
- if (p1->class_id == JS_CLASS_ARRAY) {
- if (unlikely(!p1->fast_array))
- goto slow_path;
- } else if (p1->class_id == JS_CLASS_OBJECT) {
- if (unlikely(sh1->has_small_array_index))
- goto slow_path;
- } else {
- goto slow_path;
- }
- p1 = sh1->proto;
- }
- /* add element */
- return add_fast_array_element(ctx, p, val, flags);
- }
- set_value(ctx, &p->u.array.u.values[idx], val);
- break;
- case JS_CLASS_ARGUMENTS:
- if (unlikely(idx >= (uint32_t)p->u.array.count))
- goto slow_path;
- set_value(ctx, &p->u.array.u.values[idx], val);
- break;
- case JS_CLASS_UINT8C_ARRAY:
- if (JS_ToUint8ClampFree(ctx, &v, val))
- goto ta_cvt_fail;
- /* Note: the conversion can detach the typed array, so the
- array bound check must be done after */
- if (unlikely(idx >= (uint32_t)p->u.array.count))
- goto ta_out_of_bound;
- p->u.array.u.uint8_ptr[idx] = v;
- break;
- case JS_CLASS_INT8_ARRAY:
- case JS_CLASS_UINT8_ARRAY:
- if (JS_ToInt32Free(ctx, &v, val))
- goto ta_cvt_fail;
- if (unlikely(idx >= (uint32_t)p->u.array.count))
- goto ta_out_of_bound;
- p->u.array.u.uint8_ptr[idx] = v;
- break;
- case JS_CLASS_INT16_ARRAY:
- case JS_CLASS_UINT16_ARRAY:
- if (JS_ToInt32Free(ctx, &v, val))
- goto ta_cvt_fail;
- if (unlikely(idx >= (uint32_t)p->u.array.count))
- goto ta_out_of_bound;
- p->u.array.u.uint16_ptr[idx] = v;
- break;
- case JS_CLASS_INT32_ARRAY:
- case JS_CLASS_UINT32_ARRAY:
- if (JS_ToInt32Free(ctx, &v, val))
- goto ta_cvt_fail;
- if (unlikely(idx >= (uint32_t)p->u.array.count))
- goto ta_out_of_bound;
- p->u.array.u.uint32_ptr[idx] = v;
- break;
- case JS_CLASS_BIG_INT64_ARRAY:
- case JS_CLASS_BIG_UINT64_ARRAY:
- /* XXX: need specific conversion function */
- {
- int64_t v;
- if (JS_ToBigInt64Free(ctx, &v, val))
- goto ta_cvt_fail;
- if (unlikely(idx >= (uint32_t)p->u.array.count))
- goto ta_out_of_bound;
- p->u.array.u.uint64_ptr[idx] = v;
- }
- break;
- case JS_CLASS_FLOAT16_ARRAY:
- if (JS_ToFloat64Free(ctx, &d, val))
- goto ta_cvt_fail;
- if (unlikely(idx >= (uint32_t)p->u.array.count))
- goto ta_out_of_bound;
- p->u.array.u.fp16_ptr[idx] = tofp16(d);
- break;
- case JS_CLASS_FLOAT32_ARRAY:
- if (JS_ToFloat64Free(ctx, &d, val))
- goto ta_cvt_fail;
- if (unlikely(idx >= (uint32_t)p->u.array.count))
- goto ta_out_of_bound;
- p->u.array.u.float_ptr[idx] = d;
- break;
- case JS_CLASS_FLOAT64_ARRAY:
- if (JS_ToFloat64Free(ctx, &d, val)) {
- ta_cvt_fail:
- if (flags & JS_PROP_REFLECT_DEFINE_PROPERTY) {
- JS_FreeValue(ctx, JS_GetException(ctx));
- return false;
- }
- return -1;
- }
- if (unlikely(idx >= (uint32_t)p->u.array.count)) {
- ta_out_of_bound:
- if (typed_array_is_oob(p))
- if (flags & JS_PROP_DEFINE_PROPERTY)
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
- return true; // per spec: no OOB exception
- }
- p->u.array.u.double_ptr[idx] = d;
- break;
- default:
- goto slow_path;
- }
- return true;
- } else {
- JSAtom atom;
- int ret;
- slow_path:
- atom = JS_ValueToAtom(ctx, prop);
- JS_FreeValue(ctx, prop);
- if (unlikely(atom == JS_ATOM_NULL)) {
- JS_FreeValue(ctx, val);
- return -1;
- }
- ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags);
- JS_FreeAtom(ctx, atom);
- return ret;
- }
- }
- int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
- uint32_t idx, JSValue val)
- {
- return JS_SetPropertyValue(ctx, this_obj, js_uint32(idx), val,
- JS_PROP_THROW);
- }
- int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj,
- int64_t idx, JSValue val)
- {
- JSAtom prop;
- int res;
- if ((uint64_t)idx <= INT32_MAX) {
- /* fast path for fast arrays */
- return JS_SetPropertyValue(ctx, this_obj, js_int32(idx), val,
- JS_PROP_THROW);
- }
- prop = JS_NewAtomInt64(ctx, idx);
- if (prop == JS_ATOM_NULL) {
- JS_FreeValue(ctx, val);
- return -1;
- }
- res = JS_SetProperty(ctx, this_obj, prop, val);
- JS_FreeAtom(ctx, prop);
- return res;
- }
- /* `prop` may be pure ASCII or UTF-8 encoded */
- int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
- const char *prop, JSValue val)
- {
- JSAtom atom;
- int ret;
- atom = JS_NewAtom(ctx, prop);
- if (atom == JS_ATOM_NULL) {
- JS_FreeValue(ctx, val);
- return -1;
- }
- ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW);
- JS_FreeAtom(ctx, atom);
- return ret;
- }
- /* compute the property flags. For each flag: (JS_PROP_HAS_x forces
- it, otherwise def_flags is used)
- Note: makes assumption about the bit pattern of the flags
- */
- static int get_prop_flags(int flags, int def_flags)
- {
- int mask;
- mask = (flags >> JS_PROP_HAS_SHIFT) & JS_PROP_C_W_E;
- return (flags & mask) | (def_flags & ~mask);
- }
- static int JS_CreateProperty(JSContext *ctx, JSObject *p,
- JSAtom prop, JSValueConst val,
- JSValueConst getter, JSValueConst setter,
- int flags)
- {
- JSProperty *pr;
- int ret, prop_flags;
- /* add a new property or modify an existing exotic one */
- if (p->is_exotic) {
- if (p->class_id == JS_CLASS_ARRAY) {
- uint32_t idx, len;
- if (p->fast_array) {
- if (__JS_AtomIsTaggedInt(prop)) {
- idx = __JS_AtomToUInt32(prop);
- if (idx == p->u.array.count) {
- if (!p->extensible)
- goto not_extensible;
- if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET))
- goto convert_to_array;
- prop_flags = get_prop_flags(flags, 0);
- if (prop_flags != JS_PROP_C_W_E)
- goto convert_to_array;
- return add_fast_array_element(ctx, p,
- js_dup(val), flags);
- } else {
- goto convert_to_array;
- }
- } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
- /* convert the fast array to normal array */
- convert_to_array:
- if (convert_fast_array_to_array(ctx, p))
- return -1;
- goto generic_array;
- }
- } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
- JSProperty *plen;
- JSShapeProperty *pslen;
- generic_array:
- /* update the length field */
- plen = &p->prop[0];
- JS_ToUint32(ctx, &len, plen->u.value);
- if ((idx + 1) > len) {
- pslen = get_shape_prop(p->shape);
- if (unlikely(!(pslen->flags & JS_PROP_WRITABLE)))
- return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
- /* XXX: should update the length after defining
- the property */
- len = idx + 1;
- set_value(ctx, &plen->u.value, js_uint32(len));
- }
- }
- } else if (is_typed_array(p->class_id)) {
- ret = JS_AtomIsNumericIndex(ctx, prop);
- if (ret != 0) {
- if (ret < 0)
- return -1;
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "cannot create numeric index in typed array");
- }
- } else if (!(flags & JS_PROP_NO_EXOTIC)) {
- const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
- if (em) {
- if (em->define_own_property) {
- return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p),
- prop, val, getter, setter, flags);
- }
- ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
- if (ret < 0)
- return -1;
- if (!ret)
- goto not_extensible;
- }
- }
- }
- if (!p->extensible) {
- not_extensible:
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
- }
- if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
- prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
- JS_PROP_GETSET;
- } else {
- prop_flags = flags & JS_PROP_C_W_E;
- }
- pr = add_property(ctx, p, prop, prop_flags);
- if (unlikely(!pr))
- return -1;
- if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
- pr->u.getset.getter = NULL;
- if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) {
- pr->u.getset.getter =
- JS_VALUE_GET_OBJ(js_dup(getter));
- }
- pr->u.getset.setter = NULL;
- if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) {
- pr->u.getset.setter =
- JS_VALUE_GET_OBJ(js_dup(setter));
- }
- } else {
- if (flags & JS_PROP_HAS_VALUE) {
- pr->u.value = js_dup(val);
- } else {
- pr->u.value = JS_UNDEFINED;
- }
- }
- return true;
- }
- /* return false if not OK */
- static bool check_define_prop_flags(int prop_flags, int flags)
- {
- bool has_accessor, is_getset;
- if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
- if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) ==
- (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) {
- return false;
- }
- if ((flags & JS_PROP_HAS_ENUMERABLE) &&
- (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE))
- return false;
- }
- if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
- JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
- if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
- has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0);
- is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET);
- if (has_accessor != is_getset)
- return false;
- if (!has_accessor && !is_getset && !(prop_flags & JS_PROP_WRITABLE)) {
- /* not writable: cannot set the writable bit */
- if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
- (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE))
- return false;
- }
- }
- }
- return true;
- }
- /* ensure that the shape can be safely modified */
- static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
- JSShapeProperty **pprs)
- {
- JSShape *sh;
- uint32_t idx = 0; /* prevent warning */
- sh = p->shape;
- if (sh->is_hashed) {
- if (sh->header.ref_count != 1) {
- if (pprs)
- idx = *pprs - get_shape_prop(sh);
- /* clone the shape (the resulting one is no longer hashed) */
- sh = js_clone_shape(ctx, sh);
- if (!sh)
- return -1;
- js_free_shape(ctx->rt, p->shape);
- p->shape = sh;
- if (pprs)
- *pprs = get_shape_prop(sh) + idx;
- } else {
- js_shape_hash_unlink(ctx->rt, sh);
- sh->is_hashed = false;
- }
- }
- return 0;
- }
- static int js_update_property_flags(JSContext *ctx, JSObject *p,
- JSShapeProperty **pprs, int flags)
- {
- if (flags != (*pprs)->flags) {
- if (js_shape_prepare_update(ctx, p, pprs))
- return -1;
- (*pprs)->flags = flags;
- }
- return 0;
- }
- /* allowed flags:
- JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE
- JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE,
- JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE,
- JS_PROP_THROW, JS_PROP_NO_EXOTIC.
- If JS_PROP_THROW is set, return an exception instead of false.
- if JS_PROP_NO_EXOTIC is set, do not call the exotic
- define_own_property callback.
- return -1 (exception), false or true.
- */
- int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
- JSAtom prop, JSValueConst val,
- JSValueConst getter, JSValueConst setter, int flags)
- {
- JSObject *p;
- JSShapeProperty *prs;
- JSProperty *pr;
- int mask, res;
- if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) {
- JS_ThrowTypeErrorNotAnObject(ctx);
- return -1;
- }
- p = JS_VALUE_GET_OBJ(this_obj);
- redo_prop_update:
- prs = find_own_property(&pr, p, prop);
- if (prs) {
- /* the range of the Array length property is always tested before */
- if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) {
- uint32_t array_length;
- if (JS_ToArrayLengthFree(ctx, &array_length,
- js_dup(val), false)) {
- return -1;
- }
- /* this code relies on the fact that Uint32 are never allocated */
- val = js_uint32(array_length);
- /* prs may have been modified */
- prs = find_own_property(&pr, p, prop);
- assert(prs != NULL);
- }
- /* property already exists */
- if (!check_define_prop_flags(prs->flags, flags)) {
- not_configurable:
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
- }
- if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* Instantiate property and retry */
- if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
- return -1;
- goto redo_prop_update;
- }
- if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
- JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
- if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
- JSObject *new_getter, *new_setter;
- if (JS_IsFunction(ctx, getter)) {
- new_getter = JS_VALUE_GET_OBJ(getter);
- } else {
- new_getter = NULL;
- }
- if (JS_IsFunction(ctx, setter)) {
- new_setter = JS_VALUE_GET_OBJ(setter);
- } else {
- new_setter = NULL;
- }
- if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) {
- if (js_shape_prepare_update(ctx, p, &prs))
- return -1;
- /* convert to getset */
- if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
- free_var_ref(ctx->rt, pr->u.var_ref);
- } else {
- JS_FreeValue(ctx, pr->u.value);
- }
- prs->flags = (prs->flags &
- (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
- JS_PROP_GETSET;
- pr->u.getset.getter = NULL;
- pr->u.getset.setter = NULL;
- } else {
- if (!(prs->flags & JS_PROP_CONFIGURABLE)) {
- if ((flags & JS_PROP_HAS_GET) &&
- new_getter != pr->u.getset.getter) {
- goto not_configurable;
- }
- if ((flags & JS_PROP_HAS_SET) &&
- new_setter != pr->u.getset.setter) {
- goto not_configurable;
- }
- }
- }
- if (flags & JS_PROP_HAS_GET) {
- if (pr->u.getset.getter)
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
- if (new_getter)
- js_dup(getter);
- pr->u.getset.getter = new_getter;
- }
- if (flags & JS_PROP_HAS_SET) {
- if (pr->u.getset.setter)
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
- if (new_setter)
- js_dup(setter);
- pr->u.getset.setter = new_setter;
- }
- } else {
- if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
- /* convert to data descriptor */
- if (js_shape_prepare_update(ctx, p, &prs))
- return -1;
- if (pr->u.getset.getter)
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
- if (pr->u.getset.setter)
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
- prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
- pr->u.value = JS_UNDEFINED;
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
- /* Note: JS_PROP_VARREF is always writable */
- } else {
- if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
- (flags & JS_PROP_HAS_VALUE)) {
- if (!js_same_value(ctx, val, pr->u.value)) {
- goto not_configurable;
- } else {
- return true;
- }
- }
- }
- if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
- if (flags & JS_PROP_HAS_VALUE) {
- if (p->class_id == JS_CLASS_MODULE_NS) {
- /* JS_PROP_WRITABLE is always true for variable
- references, but they are write protected in module name
- spaces. */
- if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue))
- goto not_configurable;
- }
- /* update the reference */
- set_value(ctx, pr->u.var_ref->pvalue, js_dup(val));
- }
- /* if writable is set to false, no longer a
- reference (for mapped arguments) */
- if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
- JSValue val1;
- if (js_shape_prepare_update(ctx, p, &prs))
- return -1;
- val1 = js_dup(*pr->u.var_ref->pvalue);
- free_var_ref(ctx->rt, pr->u.var_ref);
- pr->u.value = val1;
- prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
- }
- } else if (prs->flags & JS_PROP_LENGTH) {
- if (flags & JS_PROP_HAS_VALUE) {
- /* Note: no JS code is executable because
- 'val' is guaranted to be a Uint32 */
- res = set_array_length(ctx, p, js_dup(val), flags);
- } else {
- res = true;
- }
- /* still need to reset the writable flag if
- needed. The JS_PROP_LENGTH is kept because the
- Uint32 test is still done if the length
- property is read-only. */
- if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
- JS_PROP_HAS_WRITABLE) {
- prs = get_shape_prop(p->shape);
- if (js_update_property_flags(ctx, p, &prs,
- prs->flags & ~JS_PROP_WRITABLE))
- return -1;
- }
- return res;
- } else {
- if (flags & JS_PROP_HAS_VALUE) {
- JS_FreeValue(ctx, pr->u.value);
- pr->u.value = js_dup(val);
- }
- if (flags & JS_PROP_HAS_WRITABLE) {
- if (js_update_property_flags(ctx, p, &prs,
- (prs->flags & ~JS_PROP_WRITABLE) |
- (flags & JS_PROP_WRITABLE)))
- return -1;
- }
- }
- }
- }
- mask = 0;
- if (flags & JS_PROP_HAS_CONFIGURABLE)
- mask |= JS_PROP_CONFIGURABLE;
- if (flags & JS_PROP_HAS_ENUMERABLE)
- mask |= JS_PROP_ENUMERABLE;
- if (js_update_property_flags(ctx, p, &prs,
- (prs->flags & ~mask) | (flags & mask)))
- return -1;
- return true;
- }
- /* handle modification of fast array elements */
- if (p->fast_array) {
- uint32_t idx;
- uint32_t prop_flags;
- if (p->class_id == JS_CLASS_ARRAY) {
- if (__JS_AtomIsTaggedInt(prop)) {
- idx = __JS_AtomToUInt32(prop);
- if (idx < p->u.array.count) {
- prop_flags = get_prop_flags(flags, JS_PROP_C_W_E);
- if (prop_flags != JS_PROP_C_W_E)
- goto convert_to_slow_array;
- if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
- convert_to_slow_array:
- if (convert_fast_array_to_array(ctx, p))
- return -1;
- else
- goto redo_prop_update;
- }
- if (flags & JS_PROP_HAS_VALUE) {
- set_value(ctx, &p->u.array.u.values[idx], js_dup(val));
- }
- return true;
- }
- }
- } else if (is_typed_array(p->class_id)) {
- JSValue num;
- int ret;
- if (!__JS_AtomIsTaggedInt(prop)) {
- /* slow path with to handle all numeric indexes */
- num = JS_AtomIsNumericIndex1(ctx, prop);
- if (JS_IsUndefined(num))
- goto typed_array_done;
- if (JS_IsException(num))
- return -1;
- ret = JS_NumberIsInteger(ctx, num);
- if (ret < 0) {
- JS_FreeValue(ctx, num);
- return -1;
- }
- if (!ret) {
- JS_FreeValue(ctx, num);
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "non integer index in typed array");
- }
- ret = JS_NumberIsNegativeOrMinusZero(ctx, num);
- JS_FreeValue(ctx, num);
- if (ret) {
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array");
- }
- if (!__JS_AtomIsTaggedInt(prop))
- goto typed_array_oob;
- }
- idx = __JS_AtomToUInt32(prop);
- /* if the typed array is detached, p->u.array.count = 0 */
- if (idx >= p->u.array.count) {
- typed_array_oob:
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array");
- }
- prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) ||
- prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) {
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags");
- }
- if (flags & JS_PROP_HAS_VALUE) {
- return JS_SetPropertyValue(ctx, this_obj, js_int32(idx), js_dup(val), flags);
- }
- return true;
- typed_array_done: ;
- }
- }
- return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags);
- }
- static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj,
- JSAtom prop, JSAutoInitIDEnum id,
- void *opaque, int flags)
- {
- JSObject *p;
- JSProperty *pr;
- if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT)
- return false;
- p = JS_VALUE_GET_OBJ(this_obj);
- if (find_own_property(&pr, p, prop)) {
- /* property already exists */
- abort();
- return false;
- }
- /* Specialized CreateProperty */
- pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT);
- if (unlikely(!pr))
- return -1;
- pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx);
- assert((pr->u.init.realm_and_id & 3) == 0);
- assert(id <= 3);
- pr->u.init.realm_and_id |= id;
- pr->u.init.opaque = opaque;
- return true;
- }
- /* shortcut to add or redefine a new property value */
- int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj,
- JSAtom prop, JSValue val, int flags)
- {
- int ret;
- ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED,
- flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE);
- JS_FreeValue(ctx, val);
- return ret;
- }
- int JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj,
- JSValue prop, JSValue val, int flags)
- {
- JSAtom atom;
- int ret;
- atom = JS_ValueToAtom(ctx, prop);
- JS_FreeValue(ctx, prop);
- if (unlikely(atom == JS_ATOM_NULL)) {
- JS_FreeValue(ctx, val);
- return -1;
- }
- ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
- JS_FreeAtom(ctx, atom);
- return ret;
- }
- int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj,
- uint32_t idx, JSValue val, int flags)
- {
- return JS_DefinePropertyValueValue(ctx, this_obj, js_uint32(idx),
- val, flags);
- }
- int JS_DefinePropertyValueInt64(JSContext *ctx, JSValueConst this_obj,
- int64_t idx, JSValue val, int flags)
- {
- return JS_DefinePropertyValueValue(ctx, this_obj, js_int64(idx),
- val, flags);
- }
- /* `prop` may be pure ASCII or UTF-8 encoded */
- int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
- const char *prop, JSValue val, int flags)
- {
- JSAtom atom;
- int ret;
- atom = JS_NewAtom(ctx, prop);
- if (atom == JS_ATOM_NULL) {
- JS_FreeValue(ctx, val);
- return -1;
- }
- ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
- JS_FreeAtom(ctx, atom);
- return ret;
- }
- /* shortcut to add getter & setter */
- int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
- JSAtom prop, JSValue getter, JSValue setter,
- int flags)
- {
- int ret;
- ret = JS_DefineProperty(ctx, this_obj, prop, JS_UNDEFINED, getter, setter,
- flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET |
- JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE);
- JS_FreeValue(ctx, getter);
- JS_FreeValue(ctx, setter);
- return ret;
- }
- static int JS_CreateDataPropertyUint32(JSContext *ctx, JSValueConst this_obj,
- int64_t idx, JSValue val, int flags)
- {
- return JS_DefinePropertyValueValue(ctx, this_obj, js_int64(idx),
- val, flags | JS_PROP_CONFIGURABLE |
- JS_PROP_ENUMERABLE | JS_PROP_WRITABLE);
- }
- /* return true if 'obj' has a non empty 'name' string */
- static bool js_object_has_name(JSContext *ctx, JSValue obj)
- {
- JSProperty *pr;
- JSShapeProperty *prs;
- JSValue val;
- JSString *p;
- prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name);
- if (!prs)
- return false;
- if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
- return true;
- val = pr->u.value;
- if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
- return true;
- p = JS_VALUE_GET_STRING(val);
- return (p->len != 0);
- }
- static int JS_DefineObjectName(JSContext *ctx, JSValue obj,
- JSAtom name, int flags)
- {
- if (name != JS_ATOM_NULL
- && JS_IsObject(obj)
- && !js_object_has_name(ctx, obj)
- && JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, JS_AtomToString(ctx, name), flags) < 0) {
- return -1;
- }
- return 0;
- }
- static int JS_DefineObjectNameComputed(JSContext *ctx, JSValue obj,
- JSValue str, int flags)
- {
- if (JS_IsObject(obj) &&
- !js_object_has_name(ctx, obj)) {
- JSAtom prop;
- JSValue name_str;
- prop = JS_ValueToAtom(ctx, str);
- if (prop == JS_ATOM_NULL)
- return -1;
- name_str = js_get_function_name(ctx, prop);
- JS_FreeAtom(ctx, prop);
- if (JS_IsException(name_str))
- return -1;
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name_str, flags) < 0)
- return -1;
- }
- return 0;
- }
- #define DEFINE_GLOBAL_LEX_VAR (1 << 7)
- #define DEFINE_GLOBAL_FUNC_VAR (1 << 6)
- static JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop)
- {
- return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
- }
- /* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */
- /* XXX: could support exotic global object. */
- static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags)
- {
- JSObject *p;
- JSShapeProperty *prs;
- p = JS_VALUE_GET_OBJ(ctx->global_obj);
- prs = find_own_property1(p, prop);
- /* XXX: should handle JS_PROP_AUTOINIT */
- if (flags & DEFINE_GLOBAL_LEX_VAR) {
- if (prs && !(prs->flags & JS_PROP_CONFIGURABLE))
- goto fail_redeclaration;
- } else {
- if (!prs && !p->extensible)
- goto define_error;
- if (flags & DEFINE_GLOBAL_FUNC_VAR) {
- if (prs) {
- if (!(prs->flags & JS_PROP_CONFIGURABLE) &&
- ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET ||
- ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) !=
- (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) {
- define_error:
- JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'",
- prop);
- return -1;
- }
- }
- }
- }
- /* check if there already is a lexical declaration */
- p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
- prs = find_own_property1(p, prop);
- if (prs) {
- fail_redeclaration:
- JS_ThrowSyntaxErrorVarRedeclaration(ctx, prop);
- return -1;
- }
- return 0;
- }
- /* def_flags is (0, DEFINE_GLOBAL_LEX_VAR) |
- JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE */
- /* XXX: could support exotic global object. */
- static int JS_DefineGlobalVar(JSContext *ctx, JSAtom prop, int def_flags)
- {
- JSObject *p;
- JSShapeProperty *prs;
- JSProperty *pr;
- JSValue val;
- int flags;
- if (def_flags & DEFINE_GLOBAL_LEX_VAR) {
- p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
- flags = JS_PROP_ENUMERABLE | (def_flags & JS_PROP_WRITABLE) |
- JS_PROP_CONFIGURABLE;
- val = JS_UNINITIALIZED;
- } else {
- p = JS_VALUE_GET_OBJ(ctx->global_obj);
- flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
- (def_flags & JS_PROP_CONFIGURABLE);
- val = JS_UNDEFINED;
- }
- prs = find_own_property1(p, prop);
- if (prs)
- return 0;
- if (!p->extensible)
- return 0;
- pr = add_property(ctx, p, prop, flags);
- if (unlikely(!pr))
- return -1;
- pr->u.value = val;
- return 0;
- }
- /* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */
- /* XXX: could support exotic global object. */
- static int JS_DefineGlobalFunction(JSContext *ctx, JSAtom prop,
- JSValue func, int def_flags)
- {
- JSObject *p;
- JSShapeProperty *prs;
- int flags;
- p = JS_VALUE_GET_OBJ(ctx->global_obj);
- prs = find_own_property1(p, prop);
- flags = JS_PROP_HAS_VALUE | JS_PROP_THROW;
- if (!prs || (prs->flags & JS_PROP_CONFIGURABLE)) {
- flags |= JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | def_flags |
- JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE;
- }
- if (JS_DefineProperty(ctx, ctx->global_obj, prop, func,
- JS_UNDEFINED, JS_UNDEFINED, flags) < 0)
- return -1;
- return 0;
- }
- static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop,
- bool throw_ref_error)
- {
- JSObject *p;
- JSShapeProperty *prs;
- JSProperty *pr;
- /* no exotic behavior is possible in global_var_obj */
- p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
- prs = find_own_property(&pr, p, prop);
- if (prs) {
- /* XXX: should handle JS_PROP_TMASK properties */
- if (unlikely(JS_IsUninitialized(pr->u.value)))
- return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
- return js_dup(pr->u.value);
- }
- return JS_GetPropertyInternal(ctx, ctx->global_obj, prop,
- ctx->global_obj, throw_ref_error);
- }
- /* construct a reference to a global variable */
- static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp)
- {
- JSObject *p;
- JSShapeProperty *prs;
- JSProperty *pr;
- /* no exotic behavior is possible in global_var_obj */
- p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
- prs = find_own_property(&pr, p, prop);
- if (prs) {
- /* XXX: should handle JS_PROP_AUTOINIT properties? */
- /* XXX: conformance: do these tests in
- OP_put_var_ref/OP_get_var_ref ? */
- if (unlikely(JS_IsUninitialized(pr->u.value))) {
- JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
- return -1;
- }
- if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
- return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
- }
- sp[0] = js_dup(ctx->global_var_obj);
- } else {
- int ret;
- ret = JS_HasProperty(ctx, ctx->global_obj, prop);
- if (ret < 0)
- return -1;
- if (ret) {
- sp[0] = js_dup(ctx->global_obj);
- } else {
- sp[0] = JS_UNDEFINED;
- }
- }
- sp[1] = JS_AtomToValue(ctx, prop);
- return 0;
- }
- /* use for strict variable access: test if the variable exists */
- static int JS_CheckGlobalVar(JSContext *ctx, JSAtom prop)
- {
- JSObject *p;
- JSShapeProperty *prs;
- int ret;
- /* no exotic behavior is possible in global_var_obj */
- p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
- prs = find_own_property1(p, prop);
- if (prs) {
- ret = true;
- } else {
- ret = JS_HasProperty(ctx, ctx->global_obj, prop);
- if (ret < 0)
- return -1;
- }
- return ret;
- }
- /* flag = 0: normal variable write
- flag = 1: initialize lexical variable
- flag = 2: normal variable write, strict check was done before
- */
- static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val,
- int flag)
- {
- JSObject *p;
- JSShapeProperty *prs;
- JSProperty *pr;
- int flags;
- /* no exotic behavior is possible in global_var_obj */
- p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
- prs = find_own_property(&pr, p, prop);
- if (prs) {
- /* XXX: should handle JS_PROP_AUTOINIT properties? */
- if (flag != 1) {
- if (unlikely(JS_IsUninitialized(pr->u.value))) {
- JS_FreeValue(ctx, val);
- JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
- return -1;
- }
- if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
- JS_FreeValue(ctx, val);
- return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
- }
- }
- set_value(ctx, &pr->u.value, val);
- return 0;
- }
- flags = JS_PROP_THROW_STRICT;
- if (is_strict_mode(ctx))
- flags |= JS_PROP_NO_ADD;
- return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags);
- }
- /* return -1, false or true */
- static int JS_DeleteGlobalVar(JSContext *ctx, JSAtom prop)
- {
- JSObject *p;
- JSShapeProperty *prs;
- JSProperty *pr;
- int ret;
- /* 9.1.1.4.7 DeleteBinding ( N ) */
- p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
- prs = find_own_property(&pr, p, prop);
- if (prs)
- return false; /* lexical variables cannot be deleted */
- ret = JS_HasProperty(ctx, ctx->global_obj, prop);
- if (ret < 0)
- return -1;
- if (ret) {
- return JS_DeleteProperty(ctx, ctx->global_obj, prop, 0);
- } else {
- return true;
- }
- }
- /* return -1, false or true. return false if not configurable or
- invalid object. return -1 in case of exception.
- flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */
- int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags)
- {
- JSValue obj1;
- JSObject *p;
- int res;
- obj1 = JS_ToObject(ctx, obj);
- if (JS_IsException(obj1))
- return -1;
- p = JS_VALUE_GET_OBJ(obj1);
- res = delete_property(ctx, p, prop);
- JS_FreeValue(ctx, obj1);
- if (res != false)
- return res;
- if ((flags & JS_PROP_THROW) ||
- ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
- JS_ThrowTypeError(ctx, "could not delete property");
- return -1;
- }
- return false;
- }
- int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int flags)
- {
- JSAtom prop;
- int res;
- if ((uint64_t)idx <= JS_ATOM_MAX_INT) {
- /* fast path for fast arrays */
- return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags);
- }
- prop = JS_NewAtomInt64(ctx, idx);
- if (prop == JS_ATOM_NULL)
- return -1;
- res = JS_DeleteProperty(ctx, obj, prop, flags);
- JS_FreeAtom(ctx, prop);
- return res;
- }
- bool JS_IsFunction(JSContext *ctx, JSValueConst val)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return false;
- p = JS_VALUE_GET_OBJ(val);
- switch(p->class_id) {
- case JS_CLASS_BYTECODE_FUNCTION:
- return true;
- case JS_CLASS_PROXY:
- return p->u.proxy_data->is_func;
- default:
- return (ctx->rt->class_array[p->class_id].call != NULL);
- }
- }
- static bool JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func,
- int magic)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return false;
- p = JS_VALUE_GET_OBJ(val);
- if (p->class_id == JS_CLASS_C_FUNCTION)
- return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic);
- else
- return false;
- }
- bool JS_IsConstructor(JSContext *ctx, JSValueConst val)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return false;
- p = JS_VALUE_GET_OBJ(val);
- return p->is_constructor;
- }
- bool JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, bool val)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
- return false;
- p = JS_VALUE_GET_OBJ(func_obj);
- p->is_constructor = val;
- return true;
- }
- bool JS_IsRegExp(JSValueConst val)
- {
- return JS_CLASS_REGEXP == JS_GetClassID(val);
- }
- bool JS_IsMap(JSValueConst val)
- {
- return JS_CLASS_MAP == JS_GetClassID(val);
- }
- bool JS_IsSet(JSValueConst val)
- {
- return JS_CLASS_SET == JS_GetClassID(val);
- }
- bool JS_IsWeakRef(JSValueConst val)
- {
- return JS_CLASS_WEAK_REF == JS_GetClassID(val);
- }
- bool JS_IsWeakSet(JSValueConst val)
- {
- return JS_CLASS_WEAKSET == JS_GetClassID(val);
- }
- bool JS_IsWeakMap(JSValueConst val)
- {
- return JS_CLASS_WEAKMAP == JS_GetClassID(val);
- }
- bool JS_IsDataView(JSValueConst val)
- {
- return JS_CLASS_DATAVIEW == JS_GetClassID(val);
- }
- bool JS_IsError(JSValueConst val)
- {
- return JS_CLASS_ERROR == JS_GetClassID(val);
- }
- /* used to avoid catching interrupt exceptions */
- bool JS_IsUncatchableError(JSValueConst val)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return false;
- p = JS_VALUE_GET_OBJ(val);
- return p->class_id == JS_CLASS_ERROR && p->is_uncatchable_error;
- }
- static void js_set_uncatchable_error(JSContext *ctx, JSValueConst val, bool flag)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return;
- p = JS_VALUE_GET_OBJ(val);
- if (p->class_id == JS_CLASS_ERROR)
- p->is_uncatchable_error = flag;
- }
- void JS_SetUncatchableError(JSContext *ctx, JSValueConst val)
- {
- js_set_uncatchable_error(ctx, val, true);
- }
- void JS_ClearUncatchableError(JSContext *ctx, JSValueConst val)
- {
- js_set_uncatchable_error(ctx, val, false);
- }
- void JS_ResetUncatchableError(JSContext *ctx)
- {
- js_set_uncatchable_error(ctx, ctx->rt->current_exception, false);
- }
- int JS_SetOpaque(JSValueConst obj, void *opaque)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
- p = JS_VALUE_GET_OBJ(obj);
- // User code can't set the opaque of internal objects.
- if (p->class_id >= JS_CLASS_INIT_COUNT) {
- p->u.opaque = opaque;
- return 0;
- }
- }
- return -1;
- }
- /* |obj| must be a JSObject of an internal class. */
- static void JS_SetOpaqueInternal(JSValueConst obj, void *opaque)
- {
- JSObject *p;
- assert(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT);
- p = JS_VALUE_GET_OBJ(obj);
- assert(p->class_id < JS_CLASS_INIT_COUNT);
- p->u.opaque = opaque;
- }
- /* return NULL if not an object of class class_id */
- void *JS_GetOpaque(JSValueConst obj, JSClassID class_id)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- return NULL;
- p = JS_VALUE_GET_OBJ(obj);
- if (p->class_id != class_id)
- return NULL;
- return p->u.opaque;
- }
- void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id)
- {
- void *p = JS_GetOpaque(obj, class_id);
- if (unlikely(!p)) {
- JS_ThrowTypeErrorInvalidClass(ctx, class_id);
- }
- return p;
- }
- void *JS_GetAnyOpaque(JSValueConst obj, JSClassID *class_id)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
- *class_id = 0;
- return NULL;
- }
- p = JS_VALUE_GET_OBJ(obj);
- *class_id = p->class_id;
- return p->u.opaque;
- }
- static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
- {
- int i;
- bool force_ordinary;
- JSAtom method_name;
- JSValue method, ret;
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return val;
- force_ordinary = hint & HINT_FORCE_ORDINARY;
- hint &= ~HINT_FORCE_ORDINARY;
- if (!force_ordinary) {
- method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive);
- if (JS_IsException(method))
- goto exception;
- /* ECMA says *If exoticToPrim is not undefined* but tests in
- test262 use null as a non callable converter */
- if (!JS_IsUndefined(method) && !JS_IsNull(method)) {
- JSAtom atom;
- JSValue arg;
- switch(hint) {
- case HINT_STRING:
- atom = JS_ATOM_string;
- break;
- case HINT_NUMBER:
- atom = JS_ATOM_number;
- break;
- default:
- case HINT_NONE:
- atom = JS_ATOM_default;
- break;
- }
- arg = JS_AtomToString(ctx, atom);
- ret = JS_CallFree(ctx, method, val, 1, vc(&arg));
- JS_FreeValue(ctx, arg);
- if (JS_IsException(ret))
- goto exception;
- JS_FreeValue(ctx, val);
- if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT)
- return ret;
- JS_FreeValue(ctx, ret);
- return JS_ThrowTypeError(ctx, "toPrimitive");
- }
- }
- if (hint != HINT_STRING)
- hint = HINT_NUMBER;
- for(i = 0; i < 2; i++) {
- if ((i ^ hint) == 0) {
- method_name = JS_ATOM_toString;
- } else {
- method_name = JS_ATOM_valueOf;
- }
- method = JS_GetProperty(ctx, val, method_name);
- if (JS_IsException(method))
- goto exception;
- if (JS_IsFunction(ctx, method)) {
- ret = JS_CallFree(ctx, method, val, 0, NULL);
- if (JS_IsException(ret))
- goto exception;
- if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
- JS_FreeValue(ctx, val);
- return ret;
- }
- JS_FreeValue(ctx, ret);
- } else {
- JS_FreeValue(ctx, method);
- }
- }
- JS_ThrowTypeError(ctx, "toPrimitive");
- exception:
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- static JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint)
- {
- return JS_ToPrimitiveFree(ctx, js_dup(val), hint);
- }
- void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- return;
- p = JS_VALUE_GET_OBJ(obj);
- p->is_HTMLDDA = true;
- }
- static inline bool JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- return false;
- p = JS_VALUE_GET_OBJ(obj);
- return p->is_HTMLDDA;
- }
- static int JS_ToBoolFree(JSContext *ctx, JSValue val)
- {
- uint32_t tag = JS_VALUE_GET_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- return JS_VALUE_GET_INT(val) != 0;
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- return JS_VALUE_GET_INT(val);
- case JS_TAG_EXCEPTION:
- return -1;
- case JS_TAG_STRING:
- {
- bool ret = JS_VALUE_GET_STRING(val)->len != 0;
- JS_FreeValue(ctx, val);
- return ret;
- }
- case JS_TAG_SHORT_BIG_INT:
- return JS_VALUE_GET_SHORT_BIG_INT(val) != 0;
- case JS_TAG_BIG_INT:
- {
- JSBigInt *p = JS_VALUE_GET_PTR(val);
- bool ret;
- int i;
- /* fail safe: we assume it is not necessarily
- normalized. Beginning from the MSB ensures that the
- test is fast. */
- ret = false;
- for(i = p->len - 1; i >= 0; i--) {
- if (p->tab[i] != 0) {
- ret = true;
- break;
- }
- }
- JS_FreeValue(ctx, val);
- return ret;
- }
- case JS_TAG_OBJECT:
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- bool ret = !p->is_HTMLDDA;
- JS_FreeValue(ctx, val);
- return ret;
- }
- break;
- default:
- if (JS_TAG_IS_FLOAT64(tag)) {
- double d = JS_VALUE_GET_FLOAT64(val);
- return !isnan(d) && d != 0;
- } else {
- JS_FreeValue(ctx, val);
- return true;
- }
- }
- }
- int JS_ToBool(JSContext *ctx, JSValueConst val)
- {
- return JS_ToBoolFree(ctx, js_dup(val));
- }
- /* pc points to pure ASCII or UTF-8, null terminated contents */
- static int skip_spaces(const char *pc)
- {
- const uint8_t *p, *p_next, *p_start;
- uint32_t c;
- p = p_start = (const uint8_t *)pc;
- for (;;) {
- c = *p++;
- if (c < 0x80) {
- if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20)))
- break;
- } else {
- c = utf8_decode(p - 1, &p_next);
- /* no need to test for invalid UTF-8, 0xFFFD is not a space */
- if (!lre_is_space(c))
- break;
- p = p_next;
- }
- }
- return p - 1 - p_start;
- }
- static inline int js_to_digit(int c)
- {
- if (c >= '0' && c <= '9')
- return c - '0';
- else if (c >= 'A' && c <= 'Z')
- return c - 'A' + 10;
- else if (c >= 'a' && c <= 'z')
- return c - 'a' + 10;
- else
- return 36;
- }
- /* bigint support */
- #define ADDC(res, carry_out, op1, op2, carry_in) \
- do { \
- js_limb_t __v, __a, __k, __k1; \
- __v = (op1); \
- __a = __v + (op2); \
- __k1 = __a < __v; \
- __k = (carry_in); \
- __a = __a + __k; \
- carry_out = (__a < __k) | __k1; \
- res = __a; \
- } while (0)
- /* a != 0 */
- static inline js_limb_t js_limb_clz(js_limb_t a)
- {
- if (!a)
- return JS_LIMB_BITS;
- return clz32(a);
- }
- static js_limb_t js_mp_add(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2,
- js_limb_t n, js_limb_t carry)
- {
- int i;
- for(i = 0;i < n; i++) {
- ADDC(res[i], carry, op1[i], op2[i], carry);
- }
- return carry;
- }
- static js_limb_t js_mp_sub(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2,
- int n, js_limb_t carry)
- {
- int i;
- js_limb_t k, a, v, k1;
- k = carry;
- for(i=0;i<n;i++) {
- v = op1[i];
- a = v - op2[i];
- k1 = a > v;
- v = a - k;
- k = (v > a) | k1;
- res[i] = v;
- }
- return k;
- }
- /* compute 0 - op2. carry = 0 or 1. */
- static js_limb_t js_mp_neg(js_limb_t *res, const js_limb_t *op2, int n)
- {
- int i;
- js_limb_t v, carry;
- carry = 1;
- for(i=0;i<n;i++) {
- v = ~op2[i] + carry;
- carry = v < carry;
- res[i] = v;
- }
- return carry;
- }
- /* tabr[] = taba[] * b + l. Return the high carry */
- static js_limb_t js_mp_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
- js_limb_t b, js_limb_t l)
- {
- js_limb_t i;
- js_dlimb_t t;
- for(i = 0; i < n; i++) {
- t = (js_dlimb_t)taba[i] * (js_dlimb_t)b + l;
- tabr[i] = t;
- l = t >> JS_LIMB_BITS;
- }
- return l;
- }
- static js_limb_t js_mp_div1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
- js_limb_t b, js_limb_t r)
- {
- js_slimb_t i;
- js_dlimb_t a1;
- for(i = n - 1; i >= 0; i--) {
- a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i];
- tabr[i] = a1 / b;
- r = a1 % b;
- }
- return r;
- }
- /* tabr[] += taba[] * b, return the high word. */
- static js_limb_t js_mp_add_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
- js_limb_t b)
- {
- js_limb_t i, l;
- js_dlimb_t t;
- l = 0;
- for(i = 0; i < n; i++) {
- t = (js_dlimb_t)taba[i] * (js_dlimb_t)b + l + tabr[i];
- tabr[i] = t;
- l = t >> JS_LIMB_BITS;
- }
- return l;
- }
- /* size of the result : op1_size + op2_size. */
- static void js_mp_mul_basecase(js_limb_t *result,
- const js_limb_t *op1, js_limb_t op1_size,
- const js_limb_t *op2, js_limb_t op2_size)
- {
- int i;
- js_limb_t r;
- result[op1_size] = js_mp_mul1(result, op1, op1_size, op2[0], 0);
- for(i=1;i<op2_size;i++) {
- r = js_mp_add_mul1(result + i, op1, op1_size, op2[i]);
- result[i + op1_size] = r;
- }
- }
- /* tabr[] -= taba[] * b. Return the value to substract to the high
- word. */
- static js_limb_t js_mp_sub_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
- js_limb_t b)
- {
- js_limb_t i, l;
- js_dlimb_t t;
- l = 0;
- for(i = 0; i < n; i++) {
- t = tabr[i] - (js_dlimb_t)taba[i] * (js_dlimb_t)b - l;
- tabr[i] = t;
- l = -(t >> JS_LIMB_BITS);
- }
- return l;
- }
- /* WARNING: d must be >= 2^(JS_LIMB_BITS-1) */
- static inline js_limb_t js_udiv1norm_init(js_limb_t d)
- {
- js_limb_t a0, a1;
- a1 = -d - 1;
- a0 = -1;
- return (((js_dlimb_t)a1 << JS_LIMB_BITS) | a0) / d;
- }
- /* return the quotient and the remainder in '*pr'of 'a1*2^JS_LIMB_BITS+a0
- / d' with 0 <= a1 < d. */
- static inline js_limb_t js_udiv1norm(js_limb_t *pr, js_limb_t a1, js_limb_t a0,
- js_limb_t d, js_limb_t d_inv)
- {
- js_limb_t n1m, n_adj, q, r, ah;
- js_dlimb_t a;
- n1m = ((js_slimb_t)a0 >> (JS_LIMB_BITS - 1));
- n_adj = a0 + (n1m & d);
- a = (js_dlimb_t)d_inv * (a1 - n1m) + n_adj;
- q = (a >> JS_LIMB_BITS) + a1;
- /* compute a - q * r and update q so that the remainder is\
- between 0 and d - 1 */
- a = ((js_dlimb_t)a1 << JS_LIMB_BITS) | a0;
- a = a - (js_dlimb_t)q * d - d;
- ah = a >> JS_LIMB_BITS;
- q += 1 + ah;
- r = (js_limb_t)a + (ah & d);
- *pr = r;
- return q;
- }
- #define UDIV1NORM_THRESHOLD 3
- /* b must be >= 1 << (JS_LIMB_BITS - 1) */
- static js_limb_t js_mp_div1norm(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
- js_limb_t b, js_limb_t r)
- {
- js_slimb_t i;
- if (n >= UDIV1NORM_THRESHOLD) {
- js_limb_t b_inv;
- b_inv = js_udiv1norm_init(b);
- for(i = n - 1; i >= 0; i--) {
- tabr[i] = js_udiv1norm(&r, r, taba[i], b, b_inv);
- }
- } else {
- js_dlimb_t a1;
- for(i = n - 1; i >= 0; i--) {
- a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i];
- tabr[i] = a1 / b;
- r = a1 % b;
- }
- }
- return r;
- }
- /* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb
- - 1] must be >= 1 << (JS_LIMB_BITS - 1). na - nb must be >= 0. 'taba'
- is modified and contains the remainder (nb limbs). tabq[0..na-nb]
- contains the quotient with tabq[na - nb] <= 1. */
- static void js_mp_divnorm(js_limb_t *tabq, js_limb_t *taba, js_limb_t na,
- const js_limb_t *tabb, js_limb_t nb)
- {
- js_limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r;
- int i, j;
- b1 = tabb[nb - 1];
- if (nb == 1) {
- taba[0] = js_mp_div1norm(tabq, taba, na, b1, 0);
- return;
- }
- n = na - nb;
- if (n >= UDIV1NORM_THRESHOLD)
- b1_inv = js_udiv1norm_init(b1);
- else
- b1_inv = 0;
- /* first iteration: the quotient is only 0 or 1 */
- q = 1;
- for(j = nb - 1; j >= 0; j--) {
- if (taba[n + j] != tabb[j]) {
- if (taba[n + j] < tabb[j])
- q = 0;
- break;
- }
- }
- tabq[n] = q;
- if (q) {
- js_mp_sub(taba + n, taba + n, tabb, nb, 0);
- }
- for(i = n - 1; i >= 0; i--) {
- if (unlikely(taba[i + nb] >= b1)) {
- q = -1;
- } else if (b1_inv) {
- q = js_udiv1norm(&dummy_r, taba[i + nb], taba[i + nb - 1], b1, b1_inv);
- } else {
- js_dlimb_t al;
- al = ((js_dlimb_t)taba[i + nb] << JS_LIMB_BITS) | taba[i + nb - 1];
- q = al / b1;
- r = al % b1;
- }
- r = js_mp_sub_mul1(taba + i, tabb, nb, q);
- v = taba[i + nb];
- a = v - r;
- c = (a > v);
- taba[i + nb] = a;
- if (c != 0) {
- /* negative result */
- for(;;) {
- q--;
- c = js_mp_add(taba + i, taba + i, tabb, nb, 0);
- /* propagate carry and test if positive result */
- if (c != 0) {
- if (++taba[i + nb] == 0) {
- break;
- }
- }
- }
- }
- tabq[i] = q;
- }
- }
- /* 1 <= shift <= JS_LIMB_BITS - 1 */
- static js_limb_t js_mp_shl(js_limb_t *tabr, const js_limb_t *taba, int n,
- int shift)
- {
- int i;
- js_limb_t l, v;
- l = 0;
- for(i = 0; i < n; i++) {
- v = taba[i];
- tabr[i] = (v << shift) | l;
- l = v >> (JS_LIMB_BITS - shift);
- }
- return l;
- }
- /* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift).
- 1 <= shift <= LIMB_BITS - 1 */
- static js_limb_t js_mp_shr(js_limb_t *tab_r, const js_limb_t *tab, int n,
- int shift, js_limb_t high)
- {
- int i;
- js_limb_t l, a;
- l = high;
- for(i = n - 1; i >= 0; i--) {
- a = tab[i];
- tab_r[i] = (a >> shift) | (l << (JS_LIMB_BITS - shift));
- l = a;
- }
- return l & (((js_limb_t)1 << shift) - 1);
- }
- static JSBigInt *js_bigint_new(JSContext *ctx, int len)
- {
- JSBigInt *r;
- if (len > JS_BIGINT_MAX_SIZE) {
- JS_ThrowRangeError(ctx, "BigInt is too large to allocate");
- return NULL;
- }
- r = js_malloc(ctx, sizeof(JSBigInt) + len * sizeof(js_limb_t));
- if (!r)
- return NULL;
- r->header.ref_count = 1;
- r->len = len;
- return r;
- }
- static JSBigInt *js_bigint_set_si(JSBigIntBuf *buf, js_slimb_t a)
- {
- JSBigInt *r = (JSBigInt *)buf->big_int_buf;
- r->header.ref_count = 0; /* fail safe */
- r->len = 1;
- r->tab[0] = a;
- return r;
- }
- static JSBigInt *js_bigint_set_si64(JSBigIntBuf *buf, int64_t a)
- {
- JSBigInt *r = (JSBigInt *)buf->big_int_buf;
- r->header.ref_count = 0; /* fail safe */
- if (a >= INT32_MIN && a <= INT32_MAX) {
- r->len = 1;
- r->tab[0] = a;
- } else {
- r->len = 2;
- r->tab[0] = a;
- r->tab[1] = a >> JS_LIMB_BITS;
- }
- return r;
- }
- /* val must be a short big int */
- static JSBigInt *js_bigint_set_short(JSBigIntBuf *buf, JSValueConst val)
- {
- return js_bigint_set_si(buf, JS_VALUE_GET_SHORT_BIG_INT(val));
- }
- static __maybe_unused void js_bigint_dump1(JSContext *ctx, const char *str,
- const js_limb_t *tab, int len)
- {
- int i;
- printf("%s: ", str);
- for(i = len - 1; i >= 0; i--) {
- printf(" %08x", tab[i]);
- }
- printf("\n");
- }
- static __maybe_unused void js_bigint_dump(JSContext *ctx, const char *str,
- const JSBigInt *p)
- {
- js_bigint_dump1(ctx, str, p->tab, p->len);
- }
- static JSBigInt *js_bigint_new_si(JSContext *ctx, js_slimb_t a)
- {
- JSBigInt *r;
- r = js_bigint_new(ctx, 1);
- if (!r)
- return NULL;
- r->tab[0] = a;
- return r;
- }
- static JSBigInt *js_bigint_new_si64(JSContext *ctx, int64_t a)
- {
- if (a >= INT32_MIN && a <= INT32_MAX) {
- return js_bigint_new_si(ctx, a);
- } else {
- JSBigInt *r;
- r = js_bigint_new(ctx, 2);
- if (!r)
- return NULL;
- r->tab[0] = a;
- r->tab[1] = a >> 32;
- return r;
- }
- }
- static JSBigInt *js_bigint_new_ui64(JSContext *ctx, uint64_t a)
- {
- if (a <= INT64_MAX) {
- return js_bigint_new_si64(ctx, a);
- } else {
- JSBigInt *r;
- r = js_bigint_new(ctx, (65 + JS_LIMB_BITS - 1) / JS_LIMB_BITS);
- if (!r)
- return NULL;
- r->tab[0] = a;
- r->tab[1] = a >> 32;
- r->tab[2] = 0;
- return r;
- }
- }
- static JSBigInt *js_bigint_new_di(JSContext *ctx, js_sdlimb_t a)
- {
- JSBigInt *r;
- if (a == (js_slimb_t)a) {
- r = js_bigint_new(ctx, 1);
- if (!r)
- return NULL;
- r->tab[0] = a;
- } else {
- r = js_bigint_new(ctx, 2);
- if (!r)
- return NULL;
- r->tab[0] = a;
- r->tab[1] = a >> JS_LIMB_BITS;
- }
- return r;
- }
- /* Remove redundant high order limbs. Warning: 'a' may be
- reallocated. Can never fail.
- */
- static JSBigInt *js_bigint_normalize1(JSContext *ctx, JSBigInt *a, int l)
- {
- js_limb_t v;
- assert(a->header.ref_count == 1);
- while (l > 1) {
- v = a->tab[l - 1];
- if ((v != 0 && v != -1) ||
- (v & 1) != (a->tab[l - 2] >> (JS_LIMB_BITS - 1))) {
- break;
- }
- l--;
- }
- if (l != a->len) {
- JSBigInt *a1;
- /* realloc to reduce the size */
- a->len = l;
- a1 = js_realloc(ctx, a, sizeof(JSBigInt) + l * sizeof(js_limb_t));
- if (a1)
- a = a1;
- }
- return a;
- }
- static JSBigInt *js_bigint_normalize(JSContext *ctx, JSBigInt *a)
- {
- return js_bigint_normalize1(ctx, a, a->len);
- }
- /* return 0 or 1 depending on the sign */
- static inline int js_bigint_sign(const JSBigInt *a)
- {
- return a->tab[a->len - 1] >> (JS_LIMB_BITS - 1);
- }
- static js_slimb_t js_bigint_get_si_sat(const JSBigInt *a)
- {
- if (a->len == 1) {
- return a->tab[0];
- } else {
- if (js_bigint_sign(a))
- return INT32_MIN;
- else
- return INT32_MAX;
- }
- }
- /* add the op1 limb */
- static JSBigInt *js_bigint_extend(JSContext *ctx, JSBigInt *r,
- js_limb_t op1)
- {
- int n2 = r->len;
- if ((op1 != 0 && op1 != -1) ||
- (op1 & 1) != r->tab[n2 - 1] >> (JS_LIMB_BITS - 1)) {
- JSBigInt *r1;
- r1 = js_realloc(ctx, r,
- sizeof(JSBigInt) + (n2 + 1) * sizeof(js_limb_t));
- if (!r1) {
- js_free(ctx, r);
- return NULL;
- }
- r = r1;
- r->len = n2 + 1;
- r->tab[n2] = op1;
- } else {
- /* otherwise still need to normalize the result */
- r = js_bigint_normalize(ctx, r);
- }
- return r;
- }
- /* return NULL in case of error. Compute a + b (b_neg = 0) or a - b
- (b_neg = 1) */
- /* XXX: optimize */
- static JSBigInt *js_bigint_add(JSContext *ctx, const JSBigInt *a,
- const JSBigInt *b, int b_neg)
- {
- JSBigInt *r;
- int n1, n2, i;
- js_limb_t carry, op1, op2, a_sign, b_sign;
- n2 = max_int(a->len, b->len);
- n1 = min_int(a->len, b->len);
- r = js_bigint_new(ctx, n2);
- if (!r)
- return NULL;
- /* XXX: optimize */
- /* common part */
- carry = b_neg;
- for(i = 0; i < n1; i++) {
- op1 = a->tab[i];
- op2 = b->tab[i] ^ (-b_neg);
- ADDC(r->tab[i], carry, op1, op2, carry);
- }
- a_sign = -js_bigint_sign(a);
- b_sign = (-js_bigint_sign(b)) ^ (-b_neg);
- /* part with sign extension of one operand */
- if (a->len > b->len) {
- for(i = n1; i < n2; i++) {
- op1 = a->tab[i];
- ADDC(r->tab[i], carry, op1, b_sign, carry);
- }
- } else if (a->len < b->len) {
- for(i = n1; i < n2; i++) {
- op2 = b->tab[i] ^ (-b_neg);
- ADDC(r->tab[i], carry, a_sign, op2, carry);
- }
- }
- /* part with sign extension for both operands. Extend the result
- if necessary */
- return js_bigint_extend(ctx, r, a_sign + b_sign + carry);
- }
- /* XXX: optimize */
- static JSBigInt *js_bigint_neg(JSContext *ctx, const JSBigInt *a)
- {
- JSBigIntBuf buf;
- JSBigInt *b;
- b = js_bigint_set_si(&buf, 0);
- return js_bigint_add(ctx, b, a, 1);
- }
- static JSBigInt *js_bigint_mul(JSContext *ctx, const JSBigInt *a,
- const JSBigInt *b)
- {
- JSBigInt *r;
- r = js_bigint_new(ctx, a->len + b->len);
- if (!r)
- return NULL;
- js_mp_mul_basecase(r->tab, a->tab, a->len, b->tab, b->len);
- /* correct the result if negative operands (no overflow is
- possible) */
- if (js_bigint_sign(a))
- js_mp_sub(r->tab + a->len, r->tab + a->len, b->tab, b->len, 0);
- if (js_bigint_sign(b))
- js_mp_sub(r->tab + b->len, r->tab + b->len, a->tab, a->len, 0);
- return js_bigint_normalize(ctx, r);
- }
- /* return the division or the remainder. 'b' must be != 0. return NULL
- in case of exception (division by zero or memory error) */
- static JSBigInt *js_bigint_divrem(JSContext *ctx, const JSBigInt *a,
- const JSBigInt *b, bool is_rem)
- {
- JSBigInt *r, *q;
- js_limb_t *tabb, h;
- int na, nb, a_sign, b_sign, shift;
- if (b->len == 1 && b->tab[0] == 0) {
- JS_ThrowRangeError(ctx, "BigInt division by zero");
- return NULL;
- }
- a_sign = js_bigint_sign(a);
- b_sign = js_bigint_sign(b);
- na = a->len;
- nb = b->len;
- r = js_bigint_new(ctx, na + 2);
- if (!r)
- return NULL;
- if (a_sign) {
- js_mp_neg(r->tab, a->tab, na);
- } else {
- memcpy(r->tab, a->tab, na * sizeof(a->tab[0]));
- }
- /* normalize */
- while (na > 1 && r->tab[na - 1] == 0)
- na--;
- tabb = js_malloc(ctx, nb * sizeof(tabb[0]));
- if (!tabb) {
- js_free(ctx, r);
- return NULL;
- }
- if (b_sign) {
- js_mp_neg(tabb, b->tab, nb);
- } else {
- memcpy(tabb, b->tab, nb * sizeof(tabb[0]));
- }
- /* normalize */
- while (nb > 1 && tabb[nb - 1] == 0)
- nb--;
- /* trivial case if 'a' is small */
- if (na < nb) {
- js_free(ctx, r);
- js_free(ctx, tabb);
- if (is_rem) {
- /* r = a */
- r = js_bigint_new(ctx, a->len);
- if (!r)
- return NULL;
- memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0]));
- return r;
- } else {
- /* q = 0 */
- return js_bigint_new_si(ctx, 0);
- }
- }
- /* normalize 'b' */
- shift = js_limb_clz(tabb[nb - 1]);
- if (shift != 0) {
- js_mp_shl(tabb, tabb, nb, shift);
- h = js_mp_shl(r->tab, r->tab, na, shift);
- if (h != 0)
- r->tab[na++] = h;
- }
- q = js_bigint_new(ctx, na - nb + 2); /* one more limb for the sign */
- if (!q) {
- js_free(ctx, r);
- js_free(ctx, tabb);
- return NULL;
- }
- // js_bigint_dump1(ctx, "a", r->tab, na);
- // js_bigint_dump1(ctx, "b", tabb, nb);
- js_mp_divnorm(q->tab, r->tab, na, tabb, nb);
- js_free(ctx, tabb);
- if (is_rem) {
- js_free(ctx, q);
- if (shift != 0)
- js_mp_shr(r->tab, r->tab, nb, shift, 0);
- r->tab[nb++] = 0;
- if (a_sign)
- js_mp_neg(r->tab, r->tab, nb);
- r = js_bigint_normalize1(ctx, r, nb);
- return r;
- } else {
- js_free(ctx, r);
- q->tab[na - nb + 1] = 0;
- if (a_sign ^ b_sign) {
- js_mp_neg(q->tab, q->tab, q->len);
- }
- q = js_bigint_normalize(ctx, q);
- return q;
- }
- }
- /* and, or, xor */
- static JSBigInt *js_bigint_logic(JSContext *ctx, const JSBigInt *a,
- const JSBigInt *b, OPCodeEnum op)
- {
- JSBigInt *r;
- js_limb_t b_sign;
- int a_len, b_len, i;
- if (a->len < b->len) {
- const JSBigInt *tmp;
- tmp = a;
- a = b;
- b = tmp;
- }
- /* a_len >= b_len */
- a_len = a->len;
- b_len = b->len;
- b_sign = -js_bigint_sign(b);
- r = js_bigint_new(ctx, a_len);
- if (!r)
- return NULL;
- switch(op) {
- case OP_or:
- for(i = 0; i < b_len; i++) {
- r->tab[i] = a->tab[i] | b->tab[i];
- }
- for(i = b_len; i < a_len; i++) {
- r->tab[i] = a->tab[i] | b_sign;
- }
- break;
- case OP_and:
- for(i = 0; i < b_len; i++) {
- r->tab[i] = a->tab[i] & b->tab[i];
- }
- for(i = b_len; i < a_len; i++) {
- r->tab[i] = a->tab[i] & b_sign;
- }
- break;
- case OP_xor:
- for(i = 0; i < b_len; i++) {
- r->tab[i] = a->tab[i] ^ b->tab[i];
- }
- for(i = b_len; i < a_len; i++) {
- r->tab[i] = a->tab[i] ^ b_sign;
- }
- break;
- default:
- abort();
- }
- return js_bigint_normalize(ctx, r);
- }
- static JSBigInt *js_bigint_not(JSContext *ctx, const JSBigInt *a)
- {
- JSBigInt *r;
- int i;
- r = js_bigint_new(ctx, a->len);
- if (!r)
- return NULL;
- for(i = 0; i < a->len; i++) {
- r->tab[i] = ~a->tab[i];
- }
- /* no normalization is needed */
- return r;
- }
- static JSBigInt *js_bigint_shl(JSContext *ctx, const JSBigInt *a,
- unsigned int shift1)
- {
- int d, i, shift;
- JSBigInt *r;
- js_limb_t l;
- if (a->len == 1 && a->tab[0] == 0)
- return js_bigint_new_si(ctx, 0); /* zero case */
- d = shift1 / JS_LIMB_BITS;
- shift = shift1 % JS_LIMB_BITS;
- r = js_bigint_new(ctx, a->len + d);
- if (!r)
- return NULL;
- for(i = 0; i < d; i++)
- r->tab[i] = 0;
- if (shift == 0) {
- for(i = 0; i < a->len; i++) {
- r->tab[i + d] = a->tab[i];
- }
- } else {
- l = js_mp_shl(r->tab + d, a->tab, a->len, shift);
- if (js_bigint_sign(a))
- l |= (js_limb_t)(-1) << shift;
- r = js_bigint_extend(ctx, r, l);
- }
- return r;
- }
- static JSBigInt *js_bigint_shr(JSContext *ctx, const JSBigInt *a,
- unsigned int shift1)
- {
- int d, i, shift, a_sign, n1;
- JSBigInt *r;
- d = shift1 / JS_LIMB_BITS;
- shift = shift1 % JS_LIMB_BITS;
- a_sign = js_bigint_sign(a);
- if (d >= a->len)
- return js_bigint_new_si(ctx, -a_sign);
- n1 = a->len - d;
- r = js_bigint_new(ctx, n1);
- if (!r)
- return NULL;
- if (shift == 0) {
- for(i = 0; i < n1; i++) {
- r->tab[i] = a->tab[i + d];
- }
- /* no normalization is needed */
- } else {
- js_mp_shr(r->tab, a->tab + d, n1, shift, -a_sign);
- r = js_bigint_normalize(ctx, r);
- }
- return r;
- }
- static JSBigInt *js_bigint_pow(JSContext *ctx, const JSBigInt *a, JSBigInt *b)
- {
- uint32_t e;
- int n_bits, i;
- JSBigInt *r, *r1;
- /* b must be >= 0 */
- if (js_bigint_sign(b)) {
- JS_ThrowRangeError(ctx, "BigInt negative exponent");
- return NULL;
- }
- if (b->len == 1 && b->tab[0] == 0) {
- /* a^0 = 1 */
- return js_bigint_new_si(ctx, 1);
- } else if (a->len == 1) {
- js_limb_t v;
- bool is_neg;
- v = a->tab[0];
- if (v <= 1)
- return js_bigint_new_si(ctx, v);
- else if (v == -1)
- return js_bigint_new_si(ctx, 1 - 2 * (b->tab[0] & 1));
- is_neg = (js_slimb_t)v < 0;
- if (is_neg)
- v = -v;
- if ((v & (v - 1)) == 0) {
- uint64_t e1;
- int n;
- /* v = 2^n */
- n = JS_LIMB_BITS - 1 - js_limb_clz(v);
- if (b->len > 1)
- goto overflow;
- if (b->tab[0] > INT32_MAX)
- goto overflow;
- e = b->tab[0];
- e1 = (uint64_t)e * n;
- if (e1 > JS_BIGINT_MAX_SIZE * JS_LIMB_BITS)
- goto overflow;
- e = e1;
- if (is_neg)
- is_neg = b->tab[0] & 1;
- r = js_bigint_new(ctx,
- (e + JS_LIMB_BITS + 1 - is_neg) / JS_LIMB_BITS);
- if (!r)
- return NULL;
- memset(r->tab, 0, sizeof(r->tab[0]) * r->len);
- r->tab[e / JS_LIMB_BITS] =
- (js_limb_t)(1 - 2 * is_neg) << (e % JS_LIMB_BITS);
- return r;
- }
- }
- if (b->len > 1)
- goto overflow;
- if (b->tab[0] > INT32_MAX)
- goto overflow;
- e = b->tab[0];
- n_bits = 32 - clz32(e);
- r = js_bigint_new(ctx, a->len);
- if (!r)
- return NULL;
- memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0]));
- for(i = n_bits - 2; i >= 0; i--) {
- r1 = js_bigint_mul(ctx, r, r);
- if (!r1)
- return NULL;
- js_free(ctx, r);
- r = r1;
- if ((e >> i) & 1) {
- r1 = js_bigint_mul(ctx, r, a);
- if (!r1)
- return NULL;
- js_free(ctx, r);
- r = r1;
- }
- }
- return r;
- overflow:
- JS_ThrowRangeError(ctx, "BigInt is too large");
- return NULL;
- }
- /* return (mant, exp) so that abs(a) ~ mant*2^(exp - (limb_bits -
- 1). a must be != 0. */
- static uint64_t js_bigint_get_mant_exp(JSContext *ctx,
- int *pexp, const JSBigInt *a)
- {
- js_limb_t t[4 - JS_LIMB_BITS / 32], carry, v, low_bits;
- int n1, n2, sgn, shift, i, j, e;
- uint64_t a1, a0;
- n2 = 4 - JS_LIMB_BITS / 32;
- n1 = a->len - n2;
- sgn = js_bigint_sign(a);
- /* low_bits != 0 if there are a non zero low bit in abs(a) */
- low_bits = 0;
- carry = sgn;
- for(i = 0; i < n1; i++) {
- v = (a->tab[i] ^ (-sgn)) + carry;
- carry = v < carry;
- low_bits |= v;
- }
- /* get the n2 high limbs of abs(a) */
- for(j = 0; j < n2; j++) {
- i = j + n1;
- if (i < 0) {
- v = 0;
- } else {
- v = (a->tab[i] ^ (-sgn)) + carry;
- carry = v < carry;
- }
- t[j] = v;
- }
- a1 = ((uint64_t)t[2] << 32) | t[1];
- a0 = (uint64_t)t[0] << 32;
- a0 |= (low_bits != 0);
- /* normalize */
- {
- shift = clz64(a1);
- if (shift != 0) {
- a1 = (a1 << shift) | (a0 >> (64 - shift));
- a0 <<= shift;
- }
- }
- a1 |= (a0 != 0); /* keep the bits for the final rounding */
- /* compute the exponent */
- e = a->len * JS_LIMB_BITS - shift - 1;
- *pexp = e;
- return a1;
- }
- /* shift left with round to nearest, ties to even. n >= 1 */
- static uint64_t shr_rndn(uint64_t a, int n)
- {
- uint64_t addend = ((a >> n) & 1) + ((1 << (n - 1)) - 1);
- return (a + addend) >> n;
- }
- /* convert to float64 with round to nearest, ties to even. Return
- +/-infinity if too large. */
- static double js_bigint_to_float64(JSContext *ctx, const JSBigInt *a)
- {
- int sgn, e;
- uint64_t mant;
- if (a->len == 1) {
- /* fast case, including zero */
- return (double)(js_slimb_t)a->tab[0];
- }
- sgn = js_bigint_sign(a);
- mant = js_bigint_get_mant_exp(ctx, &e, a);
- if (e > 1023) {
- /* overflow: return infinity */
- mant = 0;
- e = 1024;
- } else {
- mant = (mant >> 1) | (mant & 1); /* avoid overflow in rounding */
- mant = shr_rndn(mant, 10);
- /* rounding can cause an overflow */
- if (mant >= ((uint64_t)1 << 53)) {
- mant >>= 1;
- e++;
- }
- mant &= (((uint64_t)1 << 52) - 1);
- }
- return uint64_as_float64(((uint64_t)sgn << 63) |
- ((uint64_t)(e + 1023) << 52) |
- mant);
- }
- /* return (1, NULL) if not an integer, (2, NULL) if NaN or Infinity,
- (0, n) if an integer, (0, NULL) in case of memory error */
- static JSBigInt *js_bigint_from_float64(JSContext *ctx, int *pres, double a1)
- {
- uint64_t a = float64_as_uint64(a1);
- int sgn, e, shift;
- uint64_t mant;
- JSBigIntBuf buf;
- JSBigInt *r;
- sgn = a >> 63;
- e = (a >> 52) & ((1 << 11) - 1);
- mant = a & (((uint64_t)1 << 52) - 1);
- if (e == 2047) {
- /* NaN, Infinity */
- *pres = 2;
- return NULL;
- }
- if (e == 0 && mant == 0) {
- /* zero */
- *pres = 0;
- return js_bigint_new_si(ctx, 0);
- }
- e -= 1023;
- /* 0 < a < 1 : not an integer */
- if (e < 0)
- goto not_an_integer;
- mant |= (uint64_t)1 << 52;
- if (e < 52) {
- shift = 52 - e;
- /* check that there is no fractional part */
- if (mant & (((uint64_t)1 << shift) - 1)) {
- not_an_integer:
- *pres = 1;
- return NULL;
- }
- mant >>= shift;
- e = 0;
- } else {
- e -= 52;
- }
- if (sgn)
- mant = -mant;
- /* the integer is mant*2^e */
- r = js_bigint_set_si64(&buf, (int64_t)mant);
- *pres = 0;
- return js_bigint_shl(ctx, r, e);
- }
- /* return -1, 0, 1 or (2) (unordered) */
- static int js_bigint_float64_cmp(JSContext *ctx, const JSBigInt *a,
- double b)
- {
- int b_sign, a_sign, e, f;
- uint64_t mant, b1, a_mant;
- b1 = float64_as_uint64(b);
- b_sign = b1 >> 63;
- e = (b1 >> 52) & ((1 << 11) - 1);
- mant = b1 & (((uint64_t)1 << 52) - 1);
- a_sign = js_bigint_sign(a);
- if (e == 2047) {
- if (mant != 0) {
- /* NaN */
- return 2;
- } else {
- /* +/- infinity */
- return 2 * b_sign - 1;
- }
- } else if (e == 0 && mant == 0) {
- /* b = +/-0 */
- if (a->len == 1 && a->tab[0] == 0)
- return 0;
- else
- return 1 - 2 * a_sign;
- } else if (a->len == 1 && a->tab[0] == 0) {
- /* a = 0, b != 0 */
- return 2 * b_sign - 1;
- } else if (a_sign != b_sign) {
- return 1 - 2 * a_sign;
- } else {
- e -= 1023;
- /* Note: handling denormals is not necessary because we
- compare to integers hence f >= 0 */
- /* compute f so that 2^f <= abs(a) < 2^(f+1) */
- a_mant = js_bigint_get_mant_exp(ctx, &f, a);
- if (f != e) {
- if (f < e)
- return -1;
- else
- return 1;
- } else {
- mant = (mant | ((uint64_t)1 << 52)) << 11; /* align to a_mant */
- if (a_mant < mant)
- return 2 * a_sign - 1;
- else if (a_mant > mant)
- return 1 - 2 * a_sign;
- else
- return 0;
- }
- }
- }
- /* return -1, 0 or 1 */
- static int js_bigint_cmp(JSContext *ctx, const JSBigInt *a,
- const JSBigInt *b)
- {
- int a_sign, b_sign, res, i;
- a_sign = js_bigint_sign(a);
- b_sign = js_bigint_sign(b);
- if (a_sign != b_sign) {
- res = 1 - 2 * a_sign;
- } else {
- /* we assume the numbers are normalized */
- if (a->len != b->len) {
- if (a->len < b->len)
- res = 2 * a_sign - 1;
- else
- res = 1 - 2 * a_sign;
- } else {
- res = 0;
- for(i = a->len -1; i >= 0; i--) {
- if (a->tab[i] != b->tab[i]) {
- if (a->tab[i] < b->tab[i])
- res = -1;
- else
- res = 1;
- break;
- }
- }
- }
- }
- return res;
- }
- /* contains 10^i */
- static const js_limb_t js_pow_dec[JS_LIMB_DIGITS + 1] = {
- 1U,
- 10U,
- 100U,
- 1000U,
- 10000U,
- 100000U,
- 1000000U,
- 10000000U,
- 100000000U,
- 1000000000U,
- };
- /* syntax: [-]digits in base radix. Return NULL if memory error. radix
- = 10, 2, 8 or 16. */
- static JSBigInt *js_bigint_from_string(JSContext *ctx,
- const char *str, int radix)
- {
- const char *p = str;
- size_t n_digits1;
- int is_neg, n_digits, n_limbs, len, log2_radix, n_bits, i;
- JSBigInt *r;
- js_limb_t v, c, h;
- is_neg = 0;
- if (*p == '-') {
- is_neg = 1;
- p++;
- }
- while (*p == '0')
- p++;
- n_digits1 = strlen(p);
- /* the real check for overflox is done js_bigint_new(). Here
- we just avoid integer overflow */
- if (n_digits1 > JS_BIGINT_MAX_SIZE * JS_LIMB_BITS) {
- JS_ThrowRangeError(ctx, "BigInt is too large to allocate");
- return NULL;
- }
- n_digits = n_digits1;
- log2_radix = 32 - clz32(radix - 1); /* ceil(log2(radix)) */
- /* compute the maximum number of limbs */
- if (radix == 10) {
- n_bits = (n_digits * 27 + 7) / 8; /* >= ceil(n_digits * log2(10)) */
- } else {
- n_bits = n_digits * log2_radix;
- }
- /* we add one extra bit for the sign */
- n_limbs = max_int(1, n_bits / JS_LIMB_BITS + 1);
- r = js_bigint_new(ctx, n_limbs);
- if (!r)
- return NULL;
- if (radix == 10) {
- int digits_per_limb = JS_LIMB_DIGITS;
- len = 1;
- r->tab[0] = 0;
- for(;;) {
- /* XXX: slow */
- v = 0;
- for(i = 0; i < digits_per_limb; i++) {
- c = js_to_digit(*p);
- if (c >= radix)
- break;
- p++;
- v = v * 10 + c;
- }
- if (i == 0)
- break;
- if (len == 1 && r->tab[0] == 0) {
- r->tab[0] = v;
- } else {
- h = js_mp_mul1(r->tab, r->tab, len, js_pow_dec[i], v);
- if (h != 0) {
- r->tab[len++] = h;
- }
- }
- }
- /* add one extra limb to have the correct sign*/
- if ((r->tab[len - 1] >> (JS_LIMB_BITS - 1)) != 0)
- r->tab[len++] = 0;
- r->len = len;
- } else {
- unsigned int bit_pos, shift, pos;
- /* power of two base: no multiplication is needed */
- r->len = n_limbs;
- memset(r->tab, 0, sizeof(r->tab[0]) * n_limbs);
- for(i = 0; i < n_digits; i++) {
- c = js_to_digit(p[n_digits - 1 - i]);
- assert(c < radix);
- bit_pos = i * log2_radix;
- shift = bit_pos & (JS_LIMB_BITS - 1);
- pos = bit_pos / JS_LIMB_BITS;
- r->tab[pos] |= c << shift;
- /* if log2_radix does not divide JS_LIMB_BITS, needed an
- additional op */
- if (shift + log2_radix > JS_LIMB_BITS) {
- r->tab[pos + 1] |= c >> (JS_LIMB_BITS - shift);
- }
- }
- }
- r = js_bigint_normalize(ctx, r);
- /* XXX: could do it in place */
- if (is_neg) {
- JSBigInt *r1;
- r1 = js_bigint_neg(ctx, r);
- js_free(ctx, r);
- r = r1;
- }
- return r;
- }
- /* 2 <= base <= 36 */
- static char const digits[36] = {
- '0','1','2','3','4','5','6','7','8','9',
- 'a','b','c','d','e','f','g','h','i','j',
- 'k','l','m','n','o','p','q','r','s','t',
- 'u','v','w','x','y','z'
- };
- /* special version going backwards */
- /* XXX: use dtoa.c */
- static char *js_u64toa(char *q, int64_t n, unsigned int base)
- {
- int digit;
- if (base == 10) {
- /* division by known base uses multiplication */
- do {
- digit = (uint64_t)n % 10;
- n = (uint64_t)n / 10;
- *--q = '0' + digit;
- } while (n != 0);
- } else {
- do {
- digit = (uint64_t)n % base;
- n = (uint64_t)n / base;
- *--q = digits[digit];
- } while (n != 0);
- }
- return q;
- }
- /* len >= 1. 2 <= radix <= 36 */
- static char *js_limb_to_a(char *q, js_limb_t n, unsigned int radix, int len)
- {
- int digit, i;
- if (radix == 10) {
- /* specific case with constant divisor */
- /* XXX: optimize */
- for(i = 0; i < len; i++) {
- digit = (js_limb_t)n % 10;
- n = (js_limb_t)n / 10;
- *--q = digit + '0';
- }
- } else {
- for(i = 0; i < len; i++) {
- digit = (js_limb_t)n % radix;
- n = (js_limb_t)n / radix;
- *--q = digits[digit];
- }
- }
- return q;
- }
- #define JS_RADIX_MAX 36
- static const uint8_t js_digits_per_limb_table[JS_RADIX_MAX - 1] = {
- 32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- };
- static const js_limb_t js_radix_base_table[JS_RADIX_MAX - 1] = {
- 0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395,
- 0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91,
- 0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021,
- 0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571,
- 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d,
- 0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51,
- 0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899,
- 0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1,
- 0x5c13d840, 0x6d91b519, 0x81bf1000,
- };
- static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
- {
- if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {
- char buf[66];
- int len;
- len = i64toa_radix(buf, JS_VALUE_GET_SHORT_BIG_INT(val), radix);
- return js_new_string8_len(ctx, buf, len);
- } else {
- JSBigInt *r, *tmp = NULL;
- char *buf, *q, *buf_end;
- int is_neg, n_bits, log2_radix, n_digits;
- bool is_binary_radix;
- JSValue res;
- assert(JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT);
- r = JS_VALUE_GET_PTR(val);
- if (r->len == 1 && r->tab[0] == 0) {
- /* '0' case */
- return js_new_string8_len(ctx, "0", 1);
- }
- is_binary_radix = ((radix & (radix - 1)) == 0);
- is_neg = js_bigint_sign(r);
- if (is_neg) {
- tmp = js_bigint_neg(ctx, r);
- if (!tmp)
- return JS_EXCEPTION;
- r = tmp;
- } else if (!is_binary_radix) {
- /* need to modify 'r' */
- tmp = js_bigint_new(ctx, r->len);
- if (!tmp)
- return JS_EXCEPTION;
- memcpy(tmp->tab, r->tab, r->len * sizeof(r->tab[0]));
- r = tmp;
- }
- log2_radix = 31 - clz32(radix); /* floor(log2(radix)) */
- n_bits = r->len * JS_LIMB_BITS - js_limb_clz(r->tab[r->len - 1]);
- /* n_digits is exact only if radix is a power of
- two. Otherwise it is >= the exact number of digits */
- n_digits = (n_bits + log2_radix - 1) / log2_radix;
- /* XXX: could directly build the JSString */
- buf = js_malloc(ctx, n_digits + is_neg + 1);
- if (!buf) {
- js_free(ctx, tmp);
- return JS_EXCEPTION;
- }
- q = buf + n_digits + is_neg + 1;
- *--q = '\0';
- buf_end = q;
- if (!is_binary_radix) {
- int len;
- js_limb_t radix_base, v;
- radix_base = js_radix_base_table[radix - 2];
- len = r->len;
- for(;;) {
- /* remove leading zero limbs */
- while (len > 1 && r->tab[len - 1] == 0)
- len--;
- if (len == 1 && r->tab[0] < radix_base) {
- v = r->tab[0];
- if (v != 0) {
- q = js_u64toa(q, v, radix);
- }
- break;
- } else {
- v = js_mp_div1(r->tab, r->tab, len, radix_base, 0);
- q = js_limb_to_a(q, v, radix, js_digits_per_limb_table[radix - 2]);
- }
- }
- } else {
- int i, shift;
- unsigned int bit_pos, pos, c;
- /* radix is a power of two */
- for(i = 0; i < n_digits; i++) {
- bit_pos = i * log2_radix;
- pos = bit_pos / JS_LIMB_BITS;
- shift = bit_pos % JS_LIMB_BITS;
- c = r->tab[pos] >> shift;
- if ((shift + log2_radix) > JS_LIMB_BITS &&
- (pos + 1) < r->len) {
- c |= r->tab[pos + 1] << (JS_LIMB_BITS - shift);
- }
- c &= (radix - 1);
- *--q = digits[c];
- }
- }
- if (is_neg)
- *--q = '-';
- js_free(ctx, tmp);
- res = js_new_string8_len(ctx, q, buf_end - q);
- js_free(ctx, buf);
- return res;
- }
- }
- /* if possible transform a BigInt to short big and free it, otherwise
- return a normal bigint */
- static JSValue JS_CompactBigInt(JSContext *ctx, JSBigInt *p)
- {
- JSValue res;
- if (p->len == 1) {
- res = __JS_NewShortBigInt(ctx, (js_slimb_t)p->tab[0]);
- js_free(ctx, p);
- return res;
- } else {
- return JS_MKPTR(JS_TAG_BIG_INT, p);
- }
- }
- #define ATOD_INT_ONLY (1 << 0)
- /* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
- #define ATOD_ACCEPT_BIN_OCT (1 << 2)
- /* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
- #define ATOD_ACCEPT_LEGACY_OCTAL (1 << 4)
- /* accept _ between digits as a digit separator */
- #define ATOD_ACCEPT_UNDERSCORES (1 << 5)
- /* allow a suffix to override the type */
- #define ATOD_ACCEPT_SUFFIX (1 << 6)
- /* default type */
- #define ATOD_TYPE_MASK (3 << 7)
- #define ATOD_TYPE_FLOAT64 (0 << 7)
- #define ATOD_TYPE_BIG_INT (1 << 7)
- /* accept -0x1 */
- #define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)
- /* return an exception in case of memory error. Return JS_NAN if
- invalid syntax */
- /* XXX: directly use js_atod() */
- static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
- int radix, int flags)
- {
- const char *p, *p_start;
- int sep, is_neg;
- bool is_float, has_legacy_octal;
- int atod_type = flags & ATOD_TYPE_MASK;
- char buf1[64], *buf;
- int i, j, len;
- bool buf_allocated = false;
- JSValue val;
- JSATODTempMem atod_mem;
- /* optional separator between digits */
- sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
- has_legacy_octal = false;
- p = str;
- p_start = p;
- is_neg = 0;
- if (p[0] == '+') {
- p++;
- p_start++;
- if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
- goto no_radix_prefix;
- } else if (p[0] == '-') {
- p++;
- p_start++;
- is_neg = 1;
- if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
- goto no_radix_prefix;
- }
- if (p[0] == '0') {
- if ((p[1] == 'x' || p[1] == 'X') &&
- (radix == 0 || radix == 16)) {
- p += 2;
- radix = 16;
- } else if ((p[1] == 'o' || p[1] == 'O') &&
- radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
- p += 2;
- radix = 8;
- } else if ((p[1] == 'b' || p[1] == 'B') &&
- radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
- p += 2;
- radix = 2;
- } else if ((p[1] >= '0' && p[1] <= '9') &&
- radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) {
- int i;
- has_legacy_octal = true;
- sep = 256;
- for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)
- continue;
- if (p[i] == '8' || p[i] == '9')
- goto no_prefix;
- p += 1;
- radix = 8;
- } else {
- goto no_prefix;
- }
- /* there must be a digit after the prefix */
- if (js_to_digit((uint8_t)*p) >= radix)
- goto fail;
- no_prefix: ;
- } else {
- no_radix_prefix:
- if (!(flags & ATOD_INT_ONLY) &&
- (atod_type == ATOD_TYPE_FLOAT64) &&
- js__strstart(p, "Infinity", &p)) {
- double d = INF;
- if (is_neg)
- d = -d;
- val = js_float64(d);
- goto done;
- }
- }
- if (radix == 0)
- radix = 10;
- is_float = false;
- p_start = p;
- while (js_to_digit((uint8_t)*p) < radix
- || (*p == sep && (radix != 10 ||
- p != p_start + 1 || p[-1] != '0') &&
- js_to_digit((uint8_t)p[1]) < radix)) {
- p++;
- }
- if (!(flags & ATOD_INT_ONLY) && radix == 10) {
- if (*p == '.' && (p > p_start || js_to_digit((uint8_t)p[1]) < radix)) {
- is_float = true;
- p++;
- if (*p == sep)
- goto fail;
- while (js_to_digit((uint8_t)*p) < radix ||
- (*p == sep && js_to_digit((uint8_t)p[1]) < radix))
- p++;
- }
- if (p > p_start && (*p == 'e' || *p == 'E')) {
- const char *p1 = p + 1;
- is_float = true;
- if (*p1 == '+') {
- p1++;
- } else if (*p1 == '-') {
- p1++;
- }
- if (is_digit((uint8_t)*p1)) {
- p = p1 + 1;
- while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))
- p++;
- }
- }
- }
- if (p == p_start)
- goto fail;
- buf = buf1;
- buf_allocated = false;
- len = p - p_start;
- if (unlikely((len + 2) > sizeof(buf1))) {
- buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */
- if (!buf)
- goto mem_error;
- buf_allocated = true;
- }
- /* remove the separators and the radix prefixes */
- j = 0;
- if (is_neg)
- buf[j++] = '-';
- for (i = 0; i < len; i++) {
- if (p_start[i] != '_')
- buf[j++] = p_start[i];
- }
- buf[j] = '\0';
- if (flags & ATOD_ACCEPT_SUFFIX) {
- if (*p == 'n') {
- p++;
- atod_type = ATOD_TYPE_BIG_INT;
- }
- }
- switch(atod_type) {
- case ATOD_TYPE_FLOAT64:
- {
- double d;
- d = js_atod(buf, NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY,
- &atod_mem);
- /* return int or float64 */
- val = js_number(d);
- }
- break;
- case ATOD_TYPE_BIG_INT:
- {
- JSBigInt *r;
- if (has_legacy_octal || is_float)
- goto fail;
- r = js_bigint_from_string(ctx, buf, radix);
- if (!r) {
- val = JS_EXCEPTION;
- goto done;
- }
- val = JS_CompactBigInt(ctx, r);
- }
- break;
- default:
- abort();
- }
- done:
- if (buf_allocated)
- js_free_rt(ctx->rt, buf);
- if (pp)
- *pp = p;
- return val;
- fail:
- val = JS_NAN;
- goto done;
- mem_error:
- val = JS_ThrowOutOfMemory(ctx);
- goto done;
- }
- typedef enum JSToNumberHintEnum {
- TON_FLAG_NUMBER,
- TON_FLAG_NUMERIC,
- } JSToNumberHintEnum;
- static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
- JSToNumberHintEnum flag)
- {
- uint32_t tag;
- JSValue ret;
- redo:
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_BIG_INT:
- case JS_TAG_SHORT_BIG_INT:
- if (flag != TON_FLAG_NUMERIC) {
- JS_FreeValue(ctx, val);
- return JS_ThrowTypeError(ctx, "cannot convert BigInt to number");
- }
- ret = val;
- break;
- case JS_TAG_FLOAT64:
- case JS_TAG_INT:
- case JS_TAG_EXCEPTION:
- ret = val;
- break;
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- ret = js_int32(JS_VALUE_GET_INT(val));
- break;
- case JS_TAG_UNDEFINED:
- ret = JS_NAN;
- break;
- case JS_TAG_OBJECT:
- val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
- if (JS_IsException(val))
- return JS_EXCEPTION;
- goto redo;
- case JS_TAG_STRING:
- {
- const char *str;
- const char *p;
- size_t len;
- str = JS_ToCStringLen(ctx, &len, val);
- JS_FreeValue(ctx, val);
- if (!str)
- return JS_EXCEPTION;
- p = str;
- p += skip_spaces(p);
- if ((p - str) == len) {
- ret = JS_NewInt32(ctx, 0);
- } else {
- int flags = ATOD_ACCEPT_BIN_OCT;
- ret = js_atof(ctx, p, &p, 0, flags);
- if (!JS_IsException(ret)) {
- p += skip_spaces(p);
- if ((p - str) != len) {
- JS_FreeValue(ctx, ret);
- ret = JS_NAN;
- }
- }
- }
- JS_FreeCString(ctx, str);
- }
- break;
- case JS_TAG_SYMBOL:
- JS_FreeValue(ctx, val);
- return JS_ThrowTypeError(ctx, "cannot convert symbol to number");
- default:
- JS_FreeValue(ctx, val);
- ret = JS_NAN;
- break;
- }
- return ret;
- }
- static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val)
- {
- return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
- }
- static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
- {
- return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
- }
- static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
- {
- return JS_ToNumericFree(ctx, js_dup(val));
- }
- static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
- JSValue val)
- {
- double d;
- uint32_t tag;
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val))
- goto fail;
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- d = JS_VALUE_GET_INT(val);
- break;
- case JS_TAG_FLOAT64:
- d = JS_VALUE_GET_FLOAT64(val);
- break;
- default:
- abort();
- }
- *pres = d;
- return 0;
- fail:
- *pres = NAN;
- return -1;
- }
- static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val)
- {
- uint32_t tag;
- tag = JS_VALUE_GET_TAG(val);
- if (tag <= JS_TAG_NULL) {
- *pres = JS_VALUE_GET_INT(val);
- return 0;
- } else if (JS_TAG_IS_FLOAT64(tag)) {
- *pres = JS_VALUE_GET_FLOAT64(val);
- return 0;
- } else {
- return __JS_ToFloat64Free(ctx, pres, val);
- }
- }
- int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val)
- {
- return JS_ToFloat64Free(ctx, pres, js_dup(val));
- }
- JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
- {
- return JS_ToNumberFree(ctx, js_dup(val));
- }
- /* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
- static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
- {
- uint32_t tag;
- JSValue ret;
- redo:
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- ret = js_int32(JS_VALUE_GET_INT(val));
- break;
- case JS_TAG_FLOAT64:
- {
- double d = JS_VALUE_GET_FLOAT64(val);
- if (isnan(d)) {
- ret = js_int32(0);
- } else {
- /* convert -0 to +0 */
- d = trunc(d) + 0.0;
- ret = js_number(d);
- }
- }
- break;
- default:
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val))
- return val;
- goto redo;
- }
- return ret;
- }
- /* Note: the integer value is satured to 32 bits */
- static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val)
- {
- uint32_t tag;
- int ret;
- redo:
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- ret = JS_VALUE_GET_INT(val);
- break;
- case JS_TAG_EXCEPTION:
- *pres = 0;
- return -1;
- case JS_TAG_FLOAT64:
- {
- double d = JS_VALUE_GET_FLOAT64(val);
- if (isnan(d)) {
- ret = 0;
- } else {
- if (d < INT32_MIN)
- ret = INT32_MIN;
- else if (d > INT32_MAX)
- ret = INT32_MAX;
- else
- ret = (int)d;
- }
- }
- break;
- default:
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val)) {
- *pres = 0;
- return -1;
- }
- goto redo;
- }
- *pres = ret;
- return 0;
- }
- static int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val)
- {
- return JS_ToInt32SatFree(ctx, pres, js_dup(val));
- }
- static int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val,
- int min, int max, int min_offset)
- {
- int res = JS_ToInt32SatFree(ctx, pres, js_dup(val));
- if (res == 0) {
- if (*pres < min) {
- *pres += min_offset;
- if (*pres < min)
- *pres = min;
- } else {
- if (*pres > max)
- *pres = max;
- }
- }
- return res;
- }
- static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)
- {
- uint32_t tag;
- redo:
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- *pres = JS_VALUE_GET_INT(val);
- return 0;
- case JS_TAG_EXCEPTION:
- *pres = 0;
- return -1;
- case JS_TAG_FLOAT64:
- {
- double d = JS_VALUE_GET_FLOAT64(val);
- if (isnan(d)) {
- *pres = 0;
- } else {
- if (d < INT64_MIN)
- *pres = INT64_MIN;
- else if (d >= 0x1p63)
- *pres = INT64_MAX;
- else
- *pres = (int64_t)d;
- }
- }
- return 0;
- default:
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val)) {
- *pres = 0;
- return -1;
- }
- goto redo;
- }
- }
- int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val)
- {
- return JS_ToInt64SatFree(ctx, pres, js_dup(val));
- }
- int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val,
- int64_t min, int64_t max, int64_t neg_offset)
- {
- int res = JS_ToInt64SatFree(ctx, pres, js_dup(val));
- if (res == 0) {
- if (*pres < 0)
- *pres += neg_offset;
- if (*pres < min)
- *pres = min;
- else if (*pres > max)
- *pres = max;
- }
- return res;
- }
- /* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0)
- in case of exception */
- static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
- {
- uint32_t tag;
- int64_t ret;
- redo:
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- ret = JS_VALUE_GET_INT(val);
- break;
- case JS_TAG_FLOAT64:
- {
- JSFloat64Union u;
- double d;
- int e;
- d = JS_VALUE_GET_FLOAT64(val);
- u.d = d;
- /* we avoid doing fmod(x, 2^64) */
- e = (u.u64 >> 52) & 0x7ff;
- if (likely(e <= (1023 + 62))) {
- /* fast case */
- ret = (int64_t)d;
- } else if (e <= (1023 + 62 + 53)) {
- uint64_t v;
- /* remainder modulo 2^64 */
- v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
- ret = v << ((e - 1023) - 52);
- /* take the sign into account */
- if (u.u64 >> 63)
- if (ret != INT64_MIN)
- ret = -ret;
- } else {
- ret = 0; /* also handles NaN and +inf */
- }
- }
- break;
- default:
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val)) {
- *pres = 0;
- return -1;
- }
- goto redo;
- }
- *pres = ret;
- return 0;
- }
- int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
- {
- return JS_ToInt64Free(ctx, pres, js_dup(val));
- }
- int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val)
- {
- if (JS_IsBigInt(val))
- return JS_ToBigInt64(ctx, pres, val);
- else
- return JS_ToInt64(ctx, pres, val);
- }
- /* return (<0, 0) in case of exception */
- static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
- {
- uint32_t tag;
- int32_t ret;
- redo:
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- ret = JS_VALUE_GET_INT(val);
- break;
- case JS_TAG_FLOAT64:
- {
- JSFloat64Union u;
- double d;
- int e;
- d = JS_VALUE_GET_FLOAT64(val);
- u.d = d;
- /* we avoid doing fmod(x, 2^32) */
- e = (u.u64 >> 52) & 0x7ff;
- if (likely(e <= (1023 + 30))) {
- /* fast case */
- ret = (int32_t)d;
- } else if (e <= (1023 + 30 + 53)) {
- uint64_t v;
- /* remainder modulo 2^32 */
- v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
- v = v << ((e - 1023) - 52 + 32);
- ret = v >> 32;
- /* take the sign into account */
- if (u.u64 >> 63)
- if (ret != INT32_MIN)
- ret = -ret;
- } else {
- ret = 0; /* also handles NaN and +inf */
- }
- }
- break;
- default:
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val)) {
- *pres = 0;
- return -1;
- }
- goto redo;
- }
- *pres = ret;
- return 0;
- }
- int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val)
- {
- return JS_ToInt32Free(ctx, pres, js_dup(val));
- }
- static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val)
- {
- return JS_ToInt32Free(ctx, (int32_t *)pres, val);
- }
- static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
- {
- uint32_t tag;
- int res;
- redo:
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- res = JS_VALUE_GET_INT(val);
- res = max_int(0, min_int(255, res));
- break;
- case JS_TAG_FLOAT64:
- {
- double d = JS_VALUE_GET_FLOAT64(val);
- if (isnan(d)) {
- res = 0;
- } else {
- if (d < 0)
- res = 0;
- else if (d > 255)
- res = 255;
- else
- res = lrint(d);
- }
- }
- break;
- default:
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val)) {
- *pres = 0;
- return -1;
- }
- goto redo;
- }
- *pres = res;
- return 0;
- }
- static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
- JSValue val, bool is_array_ctor)
- {
- uint32_t tag, len;
- tag = JS_VALUE_GET_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- {
- int v;
- v = JS_VALUE_GET_INT(val);
- if (v < 0)
- goto fail;
- len = v;
- }
- break;
- default:
- if (JS_TAG_IS_FLOAT64(tag)) {
- double d;
- d = JS_VALUE_GET_FLOAT64(val);
- if (!(d >= 0 && d <= UINT32_MAX))
- goto fail;
- len = (uint32_t)d;
- if (len != d)
- goto fail;
- } else {
- uint32_t len1;
- if (is_array_ctor) {
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val))
- return -1;
- /* cannot recurse because val is a number */
- if (JS_ToArrayLengthFree(ctx, &len, val, true))
- return -1;
- } else {
- /* legacy behavior: must do the conversion twice and compare */
- if (JS_ToUint32(ctx, &len, val)) {
- JS_FreeValue(ctx, val);
- return -1;
- }
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val))
- return -1;
- /* cannot recurse because val is a number */
- if (JS_ToArrayLengthFree(ctx, &len1, val, false))
- return -1;
- if (len1 != len) {
- fail:
- JS_ThrowRangeError(ctx, "invalid array length");
- return -1;
- }
- }
- }
- break;
- }
- *plen = len;
- return 0;
- }
- #define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
- static bool is_safe_integer(double d)
- {
- return isfinite(d) && floor(d) == d &&
- fabs(d) <= (double)MAX_SAFE_INTEGER;
- }
- int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
- {
- int64_t v;
- if (JS_ToInt64Sat(ctx, &v, val))
- return -1;
- if (v < 0 || v > MAX_SAFE_INTEGER) {
- JS_ThrowRangeError(ctx, "invalid array index");
- *plen = 0;
- return -1;
- }
- *plen = v;
- return 0;
- }
- /* convert a value to a length between 0 and MAX_SAFE_INTEGER.
- return -1 for exception */
- static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
- JSValue val)
- {
- int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);
- JS_FreeValue(ctx, val);
- return res;
- }
- /* Note: can return an exception */
- static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)
- {
- double d;
- if (!JS_IsNumber(val))
- return false;
- if (unlikely(JS_ToFloat64(ctx, &d, val)))
- return -1;
- return isfinite(d) && floor(d) == d;
- }
- static bool JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val)
- {
- uint32_t tag;
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- {
- int v;
- v = JS_VALUE_GET_INT(val);
- return (v < 0);
- }
- case JS_TAG_FLOAT64:
- {
- JSFloat64Union u;
- u.d = JS_VALUE_GET_FLOAT64(val);
- return (u.u64 >> 63);
- }
- case JS_TAG_SHORT_BIG_INT:
- return (JS_VALUE_GET_SHORT_BIG_INT(val) < 0);
- case JS_TAG_BIG_INT:
- {
- JSBigInt *p = JS_VALUE_GET_PTR(val);
- return js_bigint_sign(p);
- }
- default:
- return false;
- }
- }
- static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)
- {
- return js_bigint_to_string1(ctx, val, 10);
- }
- /*---- floating point number to string conversions ----*/
- static JSValue js_dtoa2(JSContext *ctx,
- double d, int radix, int n_digits, int flags)
- {
- char static_buf[128], *buf, *tmp_buf;
- int len, len_max;
- JSValue res;
- JSDTOATempMem dtoa_mem;
- len_max = js_dtoa_max_len(d, radix, n_digits, flags);
- /* longer buffer may be used if radix != 10 */
- if (len_max > sizeof(static_buf) - 1) {
- tmp_buf = js_malloc(ctx, len_max + 1);
- if (!tmp_buf)
- return JS_EXCEPTION;
- buf = tmp_buf;
- } else {
- tmp_buf = NULL;
- buf = static_buf;
- }
- len = js_dtoa(buf, d, radix, n_digits, flags, &dtoa_mem);
- res = js_new_string8_len(ctx, buf, len);
- js_free(ctx, tmp_buf);
- return res;
- }
- static JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val,
- int flags)
- {
- uint32_t tag;
- char buf[32];
- size_t len;
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_STRING:
- return js_dup(val);
- case JS_TAG_INT:
- len = i32toa(buf, JS_VALUE_GET_INT(val));
- return js_new_string8_len(ctx, buf, len);
- case JS_TAG_BOOL:
- return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
- JS_ATOM_true : JS_ATOM_false);
- case JS_TAG_NULL:
- return JS_AtomToString(ctx, JS_ATOM_null);
- case JS_TAG_UNDEFINED:
- return JS_AtomToString(ctx, JS_ATOM_undefined);
- case JS_TAG_EXCEPTION:
- return JS_EXCEPTION;
- case JS_TAG_OBJECT:
- if (flags & JS_TO_STRING_NO_SIDE_EFFECTS) {
- return js_new_string8(ctx, "{}");
- } else {
- JSValue val1, ret;
- val1 = JS_ToPrimitive(ctx, val, HINT_STRING);
- if (JS_IsException(val1))
- return val1;
- ret = JS_ToStringInternal(ctx, val1, flags);
- JS_FreeValue(ctx, val1);
- return ret;
- }
- break;
- case JS_TAG_FUNCTION_BYTECODE:
- return js_new_string8(ctx, "[function bytecode]");
- case JS_TAG_SYMBOL:
- if (flags & JS_TO_STRING_IS_PROPERTY_KEY) {
- return js_dup(val);
- } else {
- return JS_ThrowTypeError(ctx, "cannot convert symbol to string");
- }
- case JS_TAG_FLOAT64:
- return js_dtoa2(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0,
- JS_DTOA_FORMAT_FREE);
- case JS_TAG_SHORT_BIG_INT:
- case JS_TAG_BIG_INT:
- return js_bigint_to_string(ctx, val);
- case JS_TAG_UNINITIALIZED:
- return js_new_string8(ctx, "[uninitialized]");
- default:
- return js_new_string8(ctx, "[unsupported type]");
- }
- }
- JSValue JS_ToString(JSContext *ctx, JSValueConst val)
- {
- return JS_ToStringInternal(ctx, val, /*flags*/0);
- }
- static JSValue JS_ToStringFree(JSContext *ctx, JSValue val)
- {
- JSValue ret;
- ret = JS_ToString(ctx, val);
- JS_FreeValue(ctx, val);
- return ret;
- }
- static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val)
- {
- if (JS_IsUndefined(val) || JS_IsNull(val))
- return JS_ToStringFree(ctx, val);
- return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL);
- }
- static JSValue JS_ToPropertyKeyInternal(JSContext *ctx, JSValueConst val,
- int flags)
- {
- return JS_ToStringInternal(ctx, val, flags | JS_TO_STRING_IS_PROPERTY_KEY);
- }
- JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val)
- {
- return JS_ToPropertyKeyInternal(ctx, val, /*flags*/0);
- }
- static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val)
- {
- uint32_t tag = JS_VALUE_GET_TAG(val);
- if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
- return JS_ThrowTypeError(ctx, "null or undefined are forbidden");
- return JS_ToString(ctx, val);
- }
- static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
- {
- JSValue val;
- JSString *p;
- int i;
- uint32_t c;
- StringBuffer b_s, *b = &b_s;
- char buf[16];
- val = JS_ToStringCheckObject(ctx, val1);
- if (JS_IsException(val))
- return val;
- p = JS_VALUE_GET_STRING(val);
- if (string_buffer_init(ctx, b, p->len + 2))
- goto fail;
- if (string_buffer_putc8(b, '\"'))
- goto fail;
- for(i = 0; i < p->len; ) {
- c = string_getc(p, &i);
- switch(c) {
- case '\t':
- c = 't';
- goto quote;
- case '\r':
- c = 'r';
- goto quote;
- case '\n':
- c = 'n';
- goto quote;
- case '\b':
- c = 'b';
- goto quote;
- case '\f':
- c = 'f';
- goto quote;
- case '\"':
- case '\\':
- quote:
- if (string_buffer_putc8(b, '\\'))
- goto fail;
- if (string_buffer_putc8(b, c))
- goto fail;
- break;
- default:
- if (c < 32 || is_surrogate(c)) {
- snprintf(buf, sizeof(buf), "\\u%04x", c);
- if (string_buffer_write8(b, (uint8_t*)buf, 6))
- goto fail;
- } else {
- if (string_buffer_putc(b, c))
- goto fail;
- }
- break;
- }
- }
- if (string_buffer_putc8(b, '\"'))
- goto fail;
- JS_FreeValue(ctx, val);
- return string_buffer_end(b);
- fail:
- JS_FreeValue(ctx, val);
- string_buffer_free(b);
- return JS_EXCEPTION;
- }
- static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
- {
- printf("%14s %4s %4s %14s %10s %s\n",
- "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
- }
- /* for debug only: dump an object without side effect */
- static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
- {
- uint32_t i;
- char atom_buf[ATOM_GET_STR_BUF_SIZE];
- JSShape *sh;
- JSShapeProperty *prs;
- JSProperty *pr;
- bool is_first = true;
- /* XXX: should encode atoms with special characters */
- sh = p->shape; /* the shape can be NULL while freeing an object */
- printf("%14p %4d ",
- (void *)p,
- p->header.ref_count);
- if (sh) {
- printf("%3d%c %14p ",
- sh->header.ref_count,
- " *"[sh->is_hashed],
- (void *)sh->proto);
- } else {
- printf("%3s %14s ", "-", "-");
- }
- printf("%10s ",
- JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), rt->class_array[p->class_id].class_name));
- if (p->is_exotic && p->fast_array) {
- printf("[ ");
- for(i = 0; i < p->u.array.count; i++) {
- if (i != 0)
- printf(", ");
- switch (p->class_id) {
- case JS_CLASS_ARRAY:
- case JS_CLASS_ARGUMENTS:
- JS_DumpValue(rt, p->u.array.u.values[i]);
- break;
- case JS_CLASS_UINT8C_ARRAY:
- case JS_CLASS_INT8_ARRAY:
- case JS_CLASS_UINT8_ARRAY:
- case JS_CLASS_INT16_ARRAY:
- case JS_CLASS_UINT16_ARRAY:
- case JS_CLASS_INT32_ARRAY:
- case JS_CLASS_UINT32_ARRAY:
- case JS_CLASS_BIG_INT64_ARRAY:
- case JS_CLASS_BIG_UINT64_ARRAY:
- case JS_CLASS_FLOAT16_ARRAY:
- case JS_CLASS_FLOAT32_ARRAY:
- case JS_CLASS_FLOAT64_ARRAY:
- {
- int size = 1 << typed_array_size_log2(p->class_id);
- const uint8_t *b = p->u.array.u.uint8_ptr + i * size;
- while (size-- > 0)
- printf("%02X", *b++);
- }
- break;
- }
- }
- printf(" ] ");
- }
- if (sh) {
- printf("{ ");
- for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
- if (prs->atom != JS_ATOM_NULL) {
- pr = &p->prop[i];
- if (!is_first)
- printf(", ");
- printf("%s: ",
- JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), prs->atom));
- if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
- printf("[getset %p %p]", (void *)pr->u.getset.getter,
- (void *)pr->u.getset.setter);
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
- printf("[varref %p]", (void *)pr->u.var_ref);
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- printf("[autoinit %p %d %p]",
- (void *)js_autoinit_get_realm(pr),
- js_autoinit_get_id(pr),
- (void *)pr->u.init.opaque);
- } else {
- JS_DumpValue(rt, pr->u.value);
- }
- is_first = false;
- }
- }
- printf(" }");
- }
- if (js_class_has_bytecode(p->class_id)) {
- JSFunctionBytecode *b = p->u.func.function_bytecode;
- JSVarRef **var_refs;
- if (b->closure_var_count) {
- var_refs = p->u.func.var_refs;
- printf(" Closure:");
- for(i = 0; i < b->closure_var_count; i++) {
- printf(" ");
- JS_DumpValue(rt, var_refs[i]->value);
- }
- if (p->u.func.home_object) {
- printf(" HomeObject: ");
- JS_DumpValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
- }
- }
- }
- printf("\n");
- }
- static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
- {
- if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
- JS_DumpObject(rt, (JSObject *)p);
- } else {
- printf("%14p %4d ",
- (void *)p,
- p->ref_count);
- switch(p->gc_obj_type) {
- case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
- printf("[function bytecode]");
- break;
- case JS_GC_OBJ_TYPE_SHAPE:
- printf("[shape]");
- break;
- case JS_GC_OBJ_TYPE_VAR_REF:
- printf("[var_ref]");
- break;
- case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
- printf("[async_function]");
- break;
- case JS_GC_OBJ_TYPE_JS_CONTEXT:
- printf("[js_context]");
- break;
- default:
- printf("[unknown %d]", p->gc_obj_type);
- break;
- }
- printf("\n");
- }
- }
- static __maybe_unused void JS_DumpValue(JSRuntime *rt, JSValueConst val)
- {
- uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
- const char *str;
- switch(tag) {
- case JS_TAG_INT:
- printf("%d", JS_VALUE_GET_INT(val));
- break;
- case JS_TAG_BOOL:
- if (JS_VALUE_GET_BOOL(val))
- str = "true";
- else
- str = "false";
- goto print_str;
- case JS_TAG_NULL:
- str = "null";
- goto print_str;
- case JS_TAG_EXCEPTION:
- str = "exception";
- goto print_str;
- case JS_TAG_UNINITIALIZED:
- str = "uninitialized";
- goto print_str;
- case JS_TAG_UNDEFINED:
- str = "undefined";
- print_str:
- printf("%s", str);
- break;
- case JS_TAG_FLOAT64:
- printf("%.14g", JS_VALUE_GET_FLOAT64(val));
- break;
- case JS_TAG_SHORT_BIG_INT:
- printf("%" PRId64 "n", (int64_t)JS_VALUE_GET_SHORT_BIG_INT(val));
- break;
- case JS_TAG_BIG_INT:
- {
- JSBigInt *p = JS_VALUE_GET_PTR(val);
- int sgn, i;
- /* In order to avoid allocations we just dump the limbs */
- sgn = js_bigint_sign(p);
- if (sgn)
- printf("BigInt.asIntN(%d,", p->len * JS_LIMB_BITS);
- printf("0x");
- for(i = p->len - 1; i >= 0; i--) {
- if (i != p->len - 1)
- printf("_");
- printf("%08x", p->tab[i]);
- }
- printf("n");
- if (sgn)
- printf(")");
- }
- break;
- case JS_TAG_STRING:
- {
- JSString *p;
- p = JS_VALUE_GET_STRING(val);
- JS_DumpString(rt, p);
- }
- break;
- case JS_TAG_FUNCTION_BYTECODE:
- {
- JSFunctionBytecode *b = JS_VALUE_GET_PTR(val);
- char buf[ATOM_GET_STR_BUF_SIZE];
- if (b->func_name) {
- printf("[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
- } else {
- printf("[bytecode (anonymous)]");
- }
- }
- break;
- case JS_TAG_OBJECT:
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSAtom atom = rt->class_array[p->class_id].class_name;
- char atom_buf[ATOM_GET_STR_BUF_SIZE];
- printf("[%s %p]",
- JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), atom), (void *)p);
- }
- break;
- case JS_TAG_SYMBOL:
- {
- JSAtomStruct *p = JS_VALUE_GET_PTR(val);
- char atom_buf[ATOM_GET_STR_BUF_SIZE];
- printf("Symbol(%s)",
- JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), js_get_atom_index(rt, p)));
- }
- break;
- case JS_TAG_MODULE:
- printf("[module]");
- break;
- default:
- printf("[unknown tag %d]", tag);
- break;
- }
- }
- bool JS_IsArray(JSValueConst val)
- {
- if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- return p->class_id == JS_CLASS_ARRAY;
- }
- return false;
- }
- /* return -1 if exception (proxy case) or true/false */
- static int js_is_array(JSContext *ctx, JSValueConst val)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
- p = JS_VALUE_GET_OBJ(val);
- if (unlikely(p->class_id == JS_CLASS_PROXY))
- return js_proxy_isArray(ctx, val);
- else
- return p->class_id == JS_CLASS_ARRAY;
- } else {
- return false;
- }
- }
- static double js_math_pow(double a, double b)
- {
- if (unlikely(!isfinite(b)) && fabs(a) == 1) {
- /* not compatible with IEEE 754 */
- return NAN;
- } else {
- return pow(a, b);
- }
- }
- JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
- {
- if (v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX) {
- return __JS_NewShortBigInt(ctx, v);
- } else {
- JSBigInt *p;
- p = js_bigint_new_si64(ctx, v);
- if (!p)
- return JS_EXCEPTION;
- return JS_MKPTR(JS_TAG_BIG_INT, p);
- }
- }
- JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
- {
- if (v <= JS_SHORT_BIG_INT_MAX) {
- return __JS_NewShortBigInt(ctx, v);
- } else {
- JSBigInt *p;
- p = js_bigint_new_ui64(ctx, v);
- if (!p)
- return JS_EXCEPTION;
- return JS_MKPTR(JS_TAG_BIG_INT, p);
- }
- }
- /* return NaN if bad bigint literal */
- static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
- {
- const char *str, *p;
- size_t len;
- int flags;
- str = JS_ToCStringLen(ctx, &len, val);
- JS_FreeValue(ctx, val);
- if (!str)
- return JS_EXCEPTION;
- p = str;
- p += skip_spaces(p);
- if ((p - str) == len) {
- val = JS_NewBigInt64(ctx, 0);
- } else {
- flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
- val = js_atof(ctx, p, &p, 0, flags);
- p += skip_spaces(p);
- if (!JS_IsException(val)) {
- if ((p - str) != len) {
- JS_FreeValue(ctx, val);
- val = JS_NAN;
- }
- }
- }
- JS_FreeCString(ctx, str);
- return val;
- }
- static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val)
- {
- val = JS_StringToBigInt(ctx, val);
- if (JS_VALUE_IS_NAN(val))
- return JS_ThrowSyntaxError(ctx, "invalid BigInt literal");
- return val;
- }
- /* JS Numbers are not allowed */
- static JSValue JS_ToBigIntFree(JSContext *ctx, JSValue val)
- {
- uint32_t tag;
- redo:
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_SHORT_BIG_INT:
- case JS_TAG_BIG_INT:
- break;
- case JS_TAG_INT:
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- case JS_TAG_FLOAT64:
- goto fail;
- case JS_TAG_BOOL:
- val = __JS_NewShortBigInt(ctx, JS_VALUE_GET_INT(val));
- break;
- case JS_TAG_STRING:
- val = JS_StringToBigIntErr(ctx, val);
- if (JS_IsException(val))
- return val;
- goto redo;
- case JS_TAG_OBJECT:
- val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
- if (JS_IsException(val))
- return val;
- goto redo;
- default:
- fail:
- JS_FreeValue(ctx, val);
- return JS_ThrowTypeError(ctx, "cannot convert to bigint");
- }
- return val;
- }
- static JSValue JS_ToBigInt(JSContext *ctx, JSValueConst val)
- {
- return JS_ToBigIntFree(ctx, js_dup(val));
- }
- /* XXX: merge with JS_ToInt64Free with a specific flag */
- static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
- {
- uint64_t res;
- val = JS_ToBigIntFree(ctx, val);
- if (JS_IsException(val)) {
- *pres = 0;
- return -1;
- }
- if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {
- res = JS_VALUE_GET_SHORT_BIG_INT(val);
- } else {
- JSBigInt *p = JS_VALUE_GET_PTR(val);
- /* return the value mod 2^64 */
- res = p->tab[0];
- if (p->len >= 2)
- res |= (uint64_t)p->tab[1] << 32;
- JS_FreeValue(ctx, val);
- }
- *pres = res;
- return 0;
- }
- int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
- {
- return JS_ToBigInt64Free(ctx, pres, js_dup(val));
- }
- int JS_ToBigUint64(JSContext *ctx, uint64_t *pres, JSValueConst val)
- {
- return JS_ToBigInt64Free(ctx, (int64_t *)pres, js_dup(val));
- }
- static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
- JSValue *sp,
- OPCodeEnum op)
- {
- JSValue op1;
- int v;
- uint32_t tag;
- JSBigIntBuf buf1;
- JSBigInt *p1;
- op1 = sp[-1];
- /* fast path for float64 */
- if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
- goto handle_float64;
- op1 = JS_ToNumericFree(ctx, op1);
- if (JS_IsException(op1))
- goto exception;
- tag = JS_VALUE_GET_TAG(op1);
- switch(tag) {
- case JS_TAG_INT:
- {
- int64_t v64;
- v64 = JS_VALUE_GET_INT(op1);
- switch(op) {
- case OP_inc:
- case OP_dec:
- v = 2 * (op - OP_dec) - 1;
- v64 += v;
- break;
- case OP_plus:
- break;
- case OP_neg:
- if (v64 == 0) {
- sp[-1] = js_float64(-0.0);
- return 0;
- } else {
- v64 = -v64;
- }
- break;
- default:
- abort();
- }
- sp[-1] = js_int64(v64);
- }
- break;
- case JS_TAG_SHORT_BIG_INT:
- {
- int64_t v;
- v = JS_VALUE_GET_SHORT_BIG_INT(op1);
- switch(op) {
- case OP_plus:
- JS_ThrowTypeError(ctx, "bigint argument with unary +");
- goto exception;
- case OP_inc:
- if (v == JS_SHORT_BIG_INT_MAX)
- goto bigint_slow_case;
- sp[-1] = __JS_NewShortBigInt(ctx, v + 1);
- break;
- case OP_dec:
- if (v == JS_SHORT_BIG_INT_MIN)
- goto bigint_slow_case;
- sp[-1] = __JS_NewShortBigInt(ctx, v - 1);
- break;
- case OP_neg:
- v = JS_VALUE_GET_SHORT_BIG_INT(op1);
- if (v == JS_SHORT_BIG_INT_MIN) {
- bigint_slow_case:
- p1 = js_bigint_set_short(&buf1, op1);
- goto bigint_slow_case1;
- }
- sp[-1] = __JS_NewShortBigInt(ctx, -v);
- break;
- default:
- abort();
- }
- }
- break;
- case JS_TAG_BIG_INT:
- {
- JSBigInt *r;
- p1 = JS_VALUE_GET_PTR(op1);
- bigint_slow_case1:
- switch(op) {
- case OP_plus:
- JS_ThrowTypeError(ctx, "bigint argument with unary +");
- JS_FreeValue(ctx, op1);
- goto exception;
- case OP_inc:
- case OP_dec:
- {
- JSBigIntBuf buf2;
- JSBigInt *p2;
- p2 = js_bigint_set_si(&buf2, 2 * (op - OP_dec) - 1);
- r = js_bigint_add(ctx, p1, p2, 0);
- }
- break;
- case OP_neg:
- r = js_bigint_neg(ctx, p1);
- break;
- case OP_not:
- r = js_bigint_not(ctx, p1);
- break;
- default:
- abort();
- }
- JS_FreeValue(ctx, op1);
- if (!r)
- goto exception;
- sp[-1] = JS_CompactBigInt(ctx, r);
- }
- break;
- default:
- handle_float64:
- {
- double d;
- d = JS_VALUE_GET_FLOAT64(op1);
- switch(op) {
- case OP_inc:
- case OP_dec:
- v = 2 * (op - OP_dec) - 1;
- d += v;
- break;
- case OP_plus:
- break;
- case OP_neg:
- d = -d;
- break;
- default:
- abort();
- }
- sp[-1] = js_float64(d);
- }
- break;
- }
- return 0;
- exception:
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- static __exception int js_post_inc_slow(JSContext *ctx,
- JSValue *sp, OPCodeEnum op)
- {
- JSValue op1;
- /* XXX: allow custom operators */
- op1 = sp[-1];
- op1 = JS_ToNumericFree(ctx, op1);
- if (JS_IsException(op1)) {
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- sp[-1] = op1;
- sp[0] = js_dup(op1);
- return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec);
- }
- static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
- {
- JSValue op1;
- op1 = sp[-1];
- op1 = JS_ToNumericFree(ctx, op1);
- if (JS_IsException(op1))
- goto exception;
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) {
- sp[-1] = __JS_NewShortBigInt(ctx, ~JS_VALUE_GET_SHORT_BIG_INT(op1));
- } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
- JSBigInt *r;
- r = js_bigint_not(ctx, JS_VALUE_GET_PTR(op1));
- JS_FreeValue(ctx, op1);
- if (!r)
- goto exception;
- sp[-1] = JS_CompactBigInt(ctx, r);
- } else {
- int32_t v1;
- if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
- goto exception;
- sp[-1] = js_int32(~v1);
- }
- return 0;
- exception:
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
- OPCodeEnum op)
- {
- JSValue op1, op2;
- uint32_t tag1, tag2;
- double d1, d2;
- op1 = sp[-2];
- op2 = sp[-1];
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- /* fast path for float operations */
- if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
- d1 = JS_VALUE_GET_FLOAT64(op1);
- d2 = JS_VALUE_GET_FLOAT64(op2);
- goto handle_float64;
- }
- /* fast path for short big int operations */
- if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {
- js_slimb_t v1, v2;
- js_sdlimb_t v;
- v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
- v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
- switch(op) {
- case OP_sub:
- v = (js_sdlimb_t)v1 - (js_sdlimb_t)v2;
- break;
- case OP_mul:
- v = (js_sdlimb_t)v1 * (js_sdlimb_t)v2;
- break;
- case OP_div:
- if (v2 == 0 ||
- ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) &&
- v2 == -1)) {
- goto slow_big_int;
- }
- sp[-2] = __JS_NewShortBigInt(ctx, v1 / v2);
- return 0;
- case OP_mod:
- if (v2 == 0 ||
- ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) &&
- v2 == -1)) {
- goto slow_big_int;
- }
- sp[-2] = __JS_NewShortBigInt(ctx, v1 % v2);
- return 0;
- case OP_pow:
- goto slow_big_int;
- default:
- abort();
- }
- if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) {
- sp[-2] = __JS_NewShortBigInt(ctx, v);
- } else {
- JSBigInt *r = js_bigint_new_di(ctx, v);
- if (!r)
- goto exception;
- sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);
- }
- return 0;
- }
- op1 = JS_ToNumericFree(ctx, op1);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- op2 = JS_ToNumericFree(ctx, op2);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- goto exception;
- }
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
- int32_t v1, v2;
- int64_t v;
- v1 = JS_VALUE_GET_INT(op1);
- v2 = JS_VALUE_GET_INT(op2);
- switch(op) {
- case OP_sub:
- v = (int64_t)v1 - (int64_t)v2;
- break;
- case OP_mul:
- v = (int64_t)v1 * (int64_t)v2;
- if (v == 0 && (v1 | v2) < 0) {
- sp[-2] = js_float64(-0.0);
- return 0;
- }
- break;
- case OP_div:
- sp[-2] = js_number((double)v1 / (double)v2);
- return 0;
- case OP_mod:
- if (v1 < 0 || v2 <= 0) {
- sp[-2] = js_number(fmod(v1, v2));
- return 0;
- } else {
- v = (int64_t)v1 % (int64_t)v2;
- }
- break;
- case OP_pow:
- sp[-2] = js_number(js_math_pow(v1, v2));
- return 0;
- default:
- abort();
- }
- sp[-2] = js_int64(v);
- } else if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_BIG_INT) &&
- (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_BIG_INT)) {
- JSBigInt *p1, *p2, *r;
- JSBigIntBuf buf1, buf2;
- slow_big_int:
- /* bigint result */
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
- p1 = js_bigint_set_short(&buf1, op1);
- else
- p1 = JS_VALUE_GET_PTR(op1);
- if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
- p2 = js_bigint_set_short(&buf2, op2);
- else
- p2 = JS_VALUE_GET_PTR(op2);
- switch(op) {
- case OP_add:
- r = js_bigint_add(ctx, p1, p2, 0);
- break;
- case OP_sub:
- r = js_bigint_add(ctx, p1, p2, 1);
- break;
- case OP_mul:
- r = js_bigint_mul(ctx, p1, p2);
- break;
- case OP_div:
- r = js_bigint_divrem(ctx, p1, p2, false);
- break;
- case OP_mod:
- r = js_bigint_divrem(ctx, p1, p2, true);
- break;
- case OP_pow:
- r = js_bigint_pow(ctx, p1, p2);
- break;
- default:
- abort();
- }
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- if (!r)
- goto exception;
- sp[-2] = JS_CompactBigInt(ctx, r);
- } else {
- double dr;
- /* float64 result */
- if (JS_ToFloat64Free(ctx, &d1, op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- if (JS_ToFloat64Free(ctx, &d2, op2))
- goto exception;
- handle_float64:
- switch(op) {
- case OP_sub:
- dr = d1 - d2;
- break;
- case OP_mul:
- dr = d1 * d2;
- break;
- case OP_div:
- dr = d1 / d2;
- break;
- case OP_mod:
- dr = fmod(d1, d2);
- break;
- case OP_pow:
- dr = js_math_pow(d1, d2);
- break;
- default:
- abort();
- }
- sp[-2] = js_float64(dr);
- }
- return 0;
- exception:
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
- {
- JSValue op1, op2;
- uint32_t tag1, tag2;
- op1 = sp[-2];
- op2 = sp[-1];
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- /* fast path for float64 */
- if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
- double d1, d2;
- d1 = JS_VALUE_GET_FLOAT64(op1);
- d2 = JS_VALUE_GET_FLOAT64(op2);
- sp[-2] = js_float64(d1 + d2);
- return 0;
- }
- /* fast path for short bigint */
- if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {
- js_slimb_t v1, v2;
- js_sdlimb_t v;
- v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
- v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
- v = (js_sdlimb_t)v1 + (js_sdlimb_t)v2;
- if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) {
- sp[-2] = __JS_NewShortBigInt(ctx, v);
- } else {
- JSBigInt *r = js_bigint_new_di(ctx, v);
- if (!r)
- goto exception;
- sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);
- }
- return 0;
- }
- if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
- op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- goto exception;
- }
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- }
- if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
- sp[-2] = JS_ConcatString(ctx, op1, op2);
- if (JS_IsException(sp[-2]))
- goto exception;
- return 0;
- }
- op1 = JS_ToNumericFree(ctx, op1);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- op2 = JS_ToNumericFree(ctx, op2);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- goto exception;
- }
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
- int32_t v1, v2;
- int64_t v;
- v1 = JS_VALUE_GET_INT(op1);
- v2 = JS_VALUE_GET_INT(op2);
- v = (int64_t)v1 + (int64_t)v2;
- sp[-2] = js_int64(v);
- } else if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
- (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) {
- JSBigInt *p1, *p2, *r;
- JSBigIntBuf buf1, buf2;
- /* bigint result */
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
- p1 = js_bigint_set_short(&buf1, op1);
- else
- p1 = JS_VALUE_GET_PTR(op1);
- if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
- p2 = js_bigint_set_short(&buf2, op2);
- else
- p2 = JS_VALUE_GET_PTR(op2);
- r = js_bigint_add(ctx, p1, p2, 0);
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- if (!r)
- goto exception;
- sp[-2] = JS_CompactBigInt(ctx, r);
- } else {
- double d1, d2;
- /* float64 result */
- if (JS_ToFloat64Free(ctx, &d1, op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- if (JS_ToFloat64Free(ctx, &d2, op2))
- goto exception;
- sp[-2] = js_float64(d1 + d2);
- }
- return 0;
- exception:
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
- JSValue *sp,
- OPCodeEnum op)
- {
- JSValue op1, op2;
- uint32_t tag1, tag2;
- uint32_t v1, v2, r;
- op1 = sp[-2];
- op2 = sp[-1];
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {
- js_slimb_t v1, v2, v;
- js_sdlimb_t vd;
- v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
- v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
- /* bigint fast path */
- switch(op) {
- case OP_and:
- v = v1 & v2;
- break;
- case OP_or:
- v = v1 | v2;
- break;
- case OP_xor:
- v = v1 ^ v2;
- break;
- case OP_sar:
- if (v2 > (JS_LIMB_BITS - 1)) {
- goto slow_big_int;
- } else if (v2 < 0) {
- if (v2 < -(JS_LIMB_BITS - 1))
- goto slow_big_int;
- v2 = -v2;
- goto bigint_shl;
- }
- bigint_sar:
- v = v1 >> v2;
- break;
- case OP_shl:
- if (v2 > (JS_LIMB_BITS - 1)) {
- goto slow_big_int;
- } else if (v2 < 0) {
- if (v2 < -(JS_LIMB_BITS - 1))
- goto slow_big_int;
- v2 = -v2;
- goto bigint_sar;
- }
- bigint_shl:
- vd = (js_dlimb_t)v1 << v2;
- if (likely(vd >= JS_SHORT_BIG_INT_MIN &&
- vd <= JS_SHORT_BIG_INT_MAX)) {
- v = vd;
- } else {
- JSBigInt *r = js_bigint_new_di(ctx, vd);
- if (!r)
- goto exception;
- sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);
- return 0;
- }
- break;
- default:
- abort();
- }
- sp[-2] = __JS_NewShortBigInt(ctx, v);
- return 0;
- }
- op1 = JS_ToNumericFree(ctx, op1);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- op2 = JS_ToNumericFree(ctx, op2);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- goto exception;
- }
- tag1 = JS_VALUE_GET_TAG(op1);
- tag2 = JS_VALUE_GET_TAG(op2);
- if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
- (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) {
- JSBigInt *p1, *p2, *r;
- JSBigIntBuf buf1, buf2;
- slow_big_int:
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
- p1 = js_bigint_set_short(&buf1, op1);
- else
- p1 = JS_VALUE_GET_PTR(op1);
- if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
- p2 = js_bigint_set_short(&buf2, op2);
- else
- p2 = JS_VALUE_GET_PTR(op2);
- switch(op) {
- case OP_and:
- case OP_or:
- case OP_xor:
- r = js_bigint_logic(ctx, p1, p2, op);
- break;
- case OP_shl:
- case OP_sar:
- {
- js_slimb_t shift;
- shift = js_bigint_get_si_sat(p2);
- if (shift > INT32_MAX)
- shift = INT32_MAX;
- else if (shift < -INT32_MAX)
- shift = -INT32_MAX;
- if (op == OP_sar)
- shift = -shift;
- if (shift >= 0)
- r = js_bigint_shl(ctx, p1, shift);
- else
- r = js_bigint_shr(ctx, p1, -shift);
- }
- break;
- default:
- abort();
- }
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- if (!r)
- goto exception;
- sp[-2] = JS_CompactBigInt(ctx, r);
- } else {
- if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
- goto exception;
- switch(op) {
- case OP_shl:
- r = v1 << (v2 & 0x1f);
- break;
- case OP_sar:
- r = (int)v1 >> (v2 & 0x1f);
- break;
- case OP_and:
- r = v1 & v2;
- break;
- case OP_or:
- r = v1 | v2;
- break;
- case OP_xor:
- r = v1 ^ v2;
- break;
- default:
- abort();
- }
- sp[-2] = js_int32(r);
- }
- return 0;
- exception:
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- /* op1 must be a bigint or int. */
- static JSBigInt *JS_ToBigIntBuf(JSContext *ctx, JSBigIntBuf *buf1,
- JSValue op1)
- {
- JSBigInt *p1;
- switch(JS_VALUE_GET_TAG(op1)) {
- case JS_TAG_INT:
- p1 = js_bigint_set_si(buf1, JS_VALUE_GET_INT(op1));
- break;
- case JS_TAG_SHORT_BIG_INT:
- p1 = js_bigint_set_short(buf1, op1);
- break;
- case JS_TAG_BIG_INT:
- p1 = JS_VALUE_GET_PTR(op1);
- break;
- default:
- abort();
- }
- return p1;
- }
- /* op1 and op2 must be numeric types and at least one must be a
- bigint. No exception is generated. */
- static int js_compare_bigint(JSContext *ctx, OPCodeEnum op,
- JSValue op1, JSValue op2)
- {
- int res, val, tag1, tag2;
- JSBigIntBuf buf1, buf2;
- JSBigInt *p1, *p2;
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_INT) &&
- (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_INT)) {
- /* fast path */
- js_slimb_t v1, v2;
- if (tag1 == JS_TAG_INT)
- v1 = JS_VALUE_GET_INT(op1);
- else
- v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
- if (tag2 == JS_TAG_INT)
- v2 = JS_VALUE_GET_INT(op2);
- else
- v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
- val = (v1 > v2) - (v1 < v2);
- } else {
- if (tag1 == JS_TAG_FLOAT64) {
- p2 = JS_ToBigIntBuf(ctx, &buf2, op2);
- val = js_bigint_float64_cmp(ctx, p2, JS_VALUE_GET_FLOAT64(op1));
- if (val == 2)
- goto unordered;
- val = -val;
- } else if (tag2 == JS_TAG_FLOAT64) {
- p1 = JS_ToBigIntBuf(ctx, &buf1, op1);
- val = js_bigint_float64_cmp(ctx, p1, JS_VALUE_GET_FLOAT64(op2));
- if (val == 2) {
- unordered:
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- return false;
- }
- } else {
- p1 = JS_ToBigIntBuf(ctx, &buf1, op1);
- p2 = JS_ToBigIntBuf(ctx, &buf2, op2);
- val = js_bigint_cmp(ctx, p1, p2);
- }
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- }
- switch(op) {
- case OP_lt:
- res = val < 0;
- break;
- case OP_lte:
- res = val <= 0;
- break;
- case OP_gt:
- res = val > 0;
- break;
- case OP_gte:
- res = val >= 0;
- break;
- case OP_eq:
- res = val == 0;
- break;
- default:
- abort();
- }
- return res;
- }
- static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
- OPCodeEnum op)
- {
- JSValue op1, op2;
- int res;
- uint32_t tag1, tag2;
- op1 = sp[-2];
- op2 = sp[-1];
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- goto exception;
- }
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
- JSString *p1, *p2;
- p1 = JS_VALUE_GET_STRING(op1);
- p2 = JS_VALUE_GET_STRING(op2);
- res = js_string_compare(p1, p2);
- switch(op) {
- case OP_lt:
- res = (res < 0);
- break;
- case OP_lte:
- res = (res <= 0);
- break;
- case OP_gt:
- res = (res > 0);
- break;
- default:
- case OP_gte:
- res = (res >= 0);
- break;
- }
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) &&
- (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) {
- /* fast path for float64/int */
- goto float64_compare;
- } else {
- if ((((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
- tag2 == JS_TAG_STRING) ||
- ((tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) &&
- tag1 == JS_TAG_STRING))) {
- if (tag1 == JS_TAG_STRING) {
- op1 = JS_StringToBigInt(ctx, op1);
- if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT &&
- JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT)
- goto invalid_bigint_string;
- }
- if (tag2 == JS_TAG_STRING) {
- op2 = JS_StringToBigInt(ctx, op2);
- if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT &&
- JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT) {
- invalid_bigint_string:
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- res = false;
- goto done;
- }
- }
- } else {
- op1 = JS_ToNumericFree(ctx, op1);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- op2 = JS_ToNumericFree(ctx, op2);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- goto exception;
- }
- }
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT ||
- tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) {
- res = js_compare_bigint(ctx, op, op1, op2);
- } else {
- double d1, d2;
- float64_compare:
- /* can use floating point comparison */
- if (tag1 == JS_TAG_FLOAT64) {
- d1 = JS_VALUE_GET_FLOAT64(op1);
- } else {
- d1 = JS_VALUE_GET_INT(op1);
- }
- if (tag2 == JS_TAG_FLOAT64) {
- d2 = JS_VALUE_GET_FLOAT64(op2);
- } else {
- d2 = JS_VALUE_GET_INT(op2);
- }
- switch(op) {
- case OP_lt:
- res = (d1 < d2); /* if NaN return false */
- break;
- case OP_lte:
- res = (d1 <= d2); /* if NaN return false */
- break;
- case OP_gt:
- res = (d1 > d2); /* if NaN return false */
- break;
- default:
- case OP_gte:
- res = (d1 >= d2); /* if NaN return false */
- break;
- }
- }
- }
- done:
- sp[-2] = js_bool(res);
- return 0;
- exception:
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- static bool tag_is_number(uint32_t tag)
- {
- return (tag == JS_TAG_INT ||
- tag == JS_TAG_FLOAT64 ||
- tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT);
- }
- static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
- bool is_neq)
- {
- JSValue op1, op2;
- int res;
- uint32_t tag1, tag2;
- op1 = sp[-2];
- op2 = sp[-1];
- redo:
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- if (tag_is_number(tag1) && tag_is_number(tag2)) {
- if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
- res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
- } else if ((tag1 == JS_TAG_FLOAT64 &&
- (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) ||
- (tag2 == JS_TAG_FLOAT64 &&
- (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) {
- double d1, d2;
- if (tag1 == JS_TAG_FLOAT64) {
- d1 = JS_VALUE_GET_FLOAT64(op1);
- } else {
- d1 = JS_VALUE_GET_INT(op1);
- }
- if (tag2 == JS_TAG_FLOAT64) {
- d2 = JS_VALUE_GET_FLOAT64(op2);
- } else {
- d2 = JS_VALUE_GET_INT(op2);
- }
- res = (d1 == d2);
- } else {
- res = js_compare_bigint(ctx, OP_eq, op1, op2);
- if (res < 0)
- goto exception;
- }
- } else if (tag1 == tag2) {
- res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
- } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
- (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
- res = true;
- } else if ((tag1 == JS_TAG_STRING && tag_is_number(tag2)) ||
- (tag2 == JS_TAG_STRING && tag_is_number(tag1))) {
- if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT ||
- tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) {
- if (tag1 == JS_TAG_STRING) {
- op1 = JS_StringToBigInt(ctx, op1);
- if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT &&
- JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT)
- goto invalid_bigint_string;
- }
- if (tag2 == JS_TAG_STRING) {
- op2 = JS_StringToBigInt(ctx, op2);
- if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT &&
- JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT ) {
- invalid_bigint_string:
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- res = false;
- goto done;
- }
- }
- } else {
- op1 = JS_ToNumericFree(ctx, op1);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- op2 = JS_ToNumericFree(ctx, op2);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- goto exception;
- }
- }
- res = js_strict_eq(ctx, op1, op2);
- } else if (tag1 == JS_TAG_BOOL) {
- op1 = js_int32(JS_VALUE_GET_INT(op1));
- goto redo;
- } else if (tag2 == JS_TAG_BOOL) {
- op2 = js_int32(JS_VALUE_GET_INT(op2));
- goto redo;
- } else if ((tag1 == JS_TAG_OBJECT &&
- (tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) ||
- (tag2 == JS_TAG_OBJECT &&
- (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) {
- op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- goto exception;
- }
- goto redo;
- } else {
- /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
- if ((JS_IsHTMLDDA(ctx, op1) &&
- (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
- (JS_IsHTMLDDA(ctx, op2) &&
- (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
- res = true;
- } else {
- res = false;
- }
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- }
- done:
- sp[-2] = js_bool(res ^ is_neq);
- return 0;
- exception:
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
- {
- JSValue op1, op2;
- uint32_t v1, v2, r;
- op1 = sp[-2];
- op2 = sp[-1];
- op1 = JS_ToNumericFree(ctx, op1);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- op2 = JS_ToNumericFree(ctx, op2);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- goto exception;
- }
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
- JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT ||
- JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT ||
- JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) {
- JS_ThrowTypeError(ctx, "BigInt operands are forbidden for >>>");
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- /* cannot give an exception */
- JS_ToUint32Free(ctx, &v1, op1);
- JS_ToUint32Free(ctx, &v2, op2);
- r = v1 >> (v2 & 0x1f);
- sp[-2] = js_uint32(r);
- return 0;
- exception:
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- static bool js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
- JSStrictEqModeEnum eq_mode)
- {
- bool res;
- int tag1, tag2;
- double d1, d2;
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- switch(tag1) {
- case JS_TAG_BOOL:
- if (tag1 != tag2) {
- res = false;
- } else {
- res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
- goto done_no_free;
- }
- break;
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- res = (tag1 == tag2);
- break;
- case JS_TAG_STRING:
- {
- JSString *p1, *p2;
- if (tag1 != tag2) {
- res = false;
- } else {
- p1 = JS_VALUE_GET_STRING(op1);
- p2 = JS_VALUE_GET_STRING(op2);
- res = js_string_eq(p1, p2);
- }
- }
- break;
- case JS_TAG_SYMBOL:
- {
- JSAtomStruct *p1, *p2;
- if (tag1 != tag2) {
- res = false;
- } else {
- p1 = JS_VALUE_GET_PTR(op1);
- p2 = JS_VALUE_GET_PTR(op2);
- res = (p1 == p2);
- }
- }
- break;
- case JS_TAG_OBJECT:
- if (tag1 != tag2)
- res = false;
- else
- res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2);
- break;
- case JS_TAG_INT:
- d1 = JS_VALUE_GET_INT(op1);
- if (tag2 == JS_TAG_INT) {
- d2 = JS_VALUE_GET_INT(op2);
- goto number_test;
- } else if (tag2 == JS_TAG_FLOAT64) {
- d2 = JS_VALUE_GET_FLOAT64(op2);
- goto number_test;
- } else {
- res = false;
- }
- break;
- case JS_TAG_FLOAT64:
- d1 = JS_VALUE_GET_FLOAT64(op1);
- if (tag2 == JS_TAG_FLOAT64) {
- d2 = JS_VALUE_GET_FLOAT64(op2);
- } else if (tag2 == JS_TAG_INT) {
- d2 = JS_VALUE_GET_INT(op2);
- } else {
- res = false;
- break;
- }
- number_test:
- if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
- JSFloat64Union u1, u2;
- /* NaN is not always normalized, so this test is necessary */
- if (isnan(d1) || isnan(d2)) {
- res = isnan(d1) == isnan(d2);
- } else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) {
- res = (d1 == d2); /* +0 == -0 */
- } else {
- u1.d = d1;
- u2.d = d2;
- res = (u1.u64 == u2.u64); /* +0 != -0 */
- }
- } else {
- res = (d1 == d2); /* if NaN return false and +0 == -0 */
- }
- goto done_no_free;
- case JS_TAG_SHORT_BIG_INT:
- case JS_TAG_BIG_INT:
- {
- JSBigIntBuf buf1, buf2;
- JSBigInt *p1, *p2;
- if (tag2 != JS_TAG_SHORT_BIG_INT &&
- tag2 != JS_TAG_BIG_INT) {
- res = false;
- break;
- }
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
- p1 = js_bigint_set_short(&buf1, op1);
- else
- p1 = JS_VALUE_GET_PTR(op1);
- if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
- p2 = js_bigint_set_short(&buf2, op2);
- else
- p2 = JS_VALUE_GET_PTR(op2);
- res = (js_bigint_cmp(ctx, p1, p2) == 0);
- }
- break;
- default:
- res = false;
- break;
- }
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- done_no_free:
- return res;
- }
- static bool js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2)
- {
- return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
- }
- static bool js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)
- {
- return js_strict_eq2(ctx, js_dup(op1), js_dup(op2), JS_EQ_SAME_VALUE);
- }
- static bool js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
- {
- return js_strict_eq2(ctx, js_dup(op1), js_dup(op2), JS_EQ_SAME_VALUE_ZERO);
- }
- static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp,
- bool is_neq)
- {
- bool res;
- res = js_strict_eq(ctx, sp[-2], sp[-1]);
- sp[-2] = js_bool(res ^ is_neq);
- return 0;
- }
- static __exception int js_operator_in(JSContext *ctx, JSValue *sp)
- {
- JSValue op1, op2;
- JSAtom atom;
- int ret;
- op1 = sp[-2];
- op2 = sp[-1];
- if (JS_VALUE_GET_TAG(op2) != JS_TAG_OBJECT) {
- JS_ThrowTypeError(ctx, "invalid 'in' operand");
- return -1;
- }
- atom = JS_ValueToAtom(ctx, op1);
- if (unlikely(atom == JS_ATOM_NULL))
- return -1;
- ret = JS_HasProperty(ctx, op2, atom);
- JS_FreeAtom(ctx, atom);
- if (ret < 0)
- return -1;
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- sp[-2] = js_bool(ret);
- return 0;
- }
- static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp)
- {
- JSValue op1, op2;
- int ret;
- op1 = sp[-2]; /* object */
- op2 = sp[-1]; /* field name or method function */
- if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) {
- JS_ThrowTypeError(ctx, "invalid 'in' operand");
- return -1;
- }
- if (JS_IsObject(op2)) {
- /* method: use the brand */
- ret = JS_CheckBrand(ctx, op1, op2);
- if (ret < 0)
- return -1;
- } else {
- JSAtom atom;
- JSObject *p;
- JSShapeProperty *prs;
- JSProperty *pr;
- /* field */
- atom = JS_ValueToAtom(ctx, op2);
- if (unlikely(atom == JS_ATOM_NULL))
- return -1;
- p = JS_VALUE_GET_OBJ(op1);
- prs = find_own_property(&pr, p, atom);
- JS_FreeAtom(ctx, atom);
- ret = (prs != NULL);
- }
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- sp[-2] = js_bool(ret);
- return 0;
- }
- static __exception int js_has_unscopable(JSContext *ctx, JSValue obj,
- JSAtom atom)
- {
- JSValue arr, val;
- int ret;
- arr = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_unscopables);
- if (JS_IsException(arr))
- return -1;
- ret = 0;
- if (JS_IsObject(arr)) {
- val = JS_GetProperty(ctx, arr, atom);
- ret = JS_ToBoolFree(ctx, val);
- }
- JS_FreeValue(ctx, arr);
- return ret;
- }
- static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp)
- {
- JSValue op1, op2;
- int ret;
- op1 = sp[-2];
- op2 = sp[-1];
- ret = JS_IsInstanceOf(ctx, op1, op2);
- if (ret < 0)
- return ret;
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- sp[-2] = js_bool(ret);
- return 0;
- }
- static __exception int js_operator_typeof(JSContext *ctx, JSValue op1)
- {
- JSAtom atom;
- uint32_t tag;
- tag = JS_VALUE_GET_NORM_TAG(op1);
- switch(tag) {
- case JS_TAG_SHORT_BIG_INT:
- case JS_TAG_BIG_INT:
- atom = JS_ATOM_bigint;
- break;
- case JS_TAG_INT:
- case JS_TAG_FLOAT64:
- atom = JS_ATOM_number;
- break;
- case JS_TAG_UNDEFINED:
- atom = JS_ATOM_undefined;
- break;
- case JS_TAG_BOOL:
- atom = JS_ATOM_boolean;
- break;
- case JS_TAG_STRING:
- atom = JS_ATOM_string;
- break;
- case JS_TAG_OBJECT:
- {
- JSObject *p;
- p = JS_VALUE_GET_OBJ(op1);
- if (unlikely(p->is_HTMLDDA))
- atom = JS_ATOM_undefined;
- else if (JS_IsFunction(ctx, op1))
- atom = JS_ATOM_function;
- else
- goto obj_type;
- }
- break;
- case JS_TAG_NULL:
- obj_type:
- atom = JS_ATOM_object;
- break;
- case JS_TAG_SYMBOL:
- atom = JS_ATOM_symbol;
- break;
- default:
- atom = JS_ATOM_unknown;
- break;
- }
- return atom;
- }
- static __exception int js_operator_delete(JSContext *ctx, JSValue *sp)
- {
- JSValue op1, op2;
- JSAtom atom;
- int ret;
- op1 = sp[-2];
- op2 = sp[-1];
- atom = JS_ValueToAtom(ctx, op2);
- if (unlikely(atom == JS_ATOM_NULL))
- return -1;
- ret = JS_DeleteProperty(ctx, op1, atom, JS_PROP_THROW_STRICT);
- JS_FreeAtom(ctx, atom);
- if (unlikely(ret < 0))
- return -1;
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- sp[-2] = js_bool(ret);
- return 0;
- }
- static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
- if (!b || b->is_strict_mode || !b->has_prototype) {
- return JS_ThrowTypeError(ctx, "invalid property access");
- }
- return JS_UNDEFINED;
- }
- static JSValue js_function_proto_fileName(JSContext *ctx,
- JSValueConst this_val)
- {
- JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
- if (b) {
- return JS_AtomToString(ctx, b->filename);
- }
- return JS_UNDEFINED;
- }
- static JSValue js_function_proto_int32(JSContext *ctx,
- JSValueConst this_val,
- int magic)
- {
- JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
- if (b) {
- int *field = (int *) ((char *)b + magic);
- return js_int32(*field);
- }
- return JS_UNDEFINED;
- }
- static int js_arguments_define_own_property(JSContext *ctx,
- JSValueConst this_obj,
- JSAtom prop, JSValueConst val,
- JSValueConst getter,
- JSValueConst setter, int flags)
- {
- JSObject *p;
- uint32_t idx;
- p = JS_VALUE_GET_OBJ(this_obj);
- /* convert to normal array when redefining an existing numeric field */
- if (p->fast_array && JS_AtomIsArrayIndex(ctx, &idx, prop) &&
- idx < p->u.array.count) {
- if (convert_fast_array_to_array(ctx, p))
- return -1;
- }
- /* run the default define own property */
- return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
- flags | JS_PROP_NO_EXOTIC);
- }
- static const JSClassExoticMethods js_arguments_exotic_methods = {
- .define_own_property = js_arguments_define_own_property,
- };
- static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv)
- {
- JSValue val, *tab;
- JSProperty *pr;
- JSObject *p;
- int i;
- val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
- JS_CLASS_ARGUMENTS);
- if (JS_IsException(val))
- return val;
- p = JS_VALUE_GET_OBJ(val);
- /* add the length field (cannot fail) */
- pr = add_property(ctx, p, JS_ATOM_length,
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- if (!pr) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- pr->u.value = js_int32(argc);
- /* initialize the fast array part */
- tab = NULL;
- if (argc > 0) {
- tab = js_malloc(ctx, sizeof(tab[0]) * argc);
- if (!tab) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- for(i = 0; i < argc; i++) {
- tab[i] = js_dup(argv[i]);
- }
- }
- p->u.array.u.values = tab;
- p->u.array.count = argc;
- JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator,
- js_dup(ctx->array_proto_values),
- JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
- /* add callee property to throw a TypeError in strict mode */
- JS_DefineProperty(ctx, val, JS_ATOM_callee, JS_UNDEFINED,
- ctx->throw_type_error, ctx->throw_type_error,
- JS_PROP_HAS_GET | JS_PROP_HAS_SET);
- return val;
- }
- #define GLOBAL_VAR_OFFSET 0x40000000
- #define ARGUMENT_VAR_OFFSET 0x20000000
- /* legacy arguments object: add references to the function arguments */
- static JSValue js_build_mapped_arguments(JSContext *ctx, int argc,
- JSValueConst *argv,
- JSStackFrame *sf, int arg_count)
- {
- JSValue val;
- JSProperty *pr;
- JSObject *p;
- int i;
- val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
- JS_CLASS_MAPPED_ARGUMENTS);
- if (JS_IsException(val))
- return val;
- p = JS_VALUE_GET_OBJ(val);
- /* add the length field (cannot fail) */
- pr = add_property(ctx, p, JS_ATOM_length,
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- if (!pr)
- goto fail;
- pr->u.value = js_int32(argc);
- for(i = 0; i < arg_count; i++) {
- JSVarRef *var_ref;
- var_ref = get_var_ref(ctx, sf, i, true);
- if (!var_ref)
- goto fail;
- pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);
- if (!pr) {
- free_var_ref(ctx->rt, var_ref);
- goto fail;
- }
- pr->u.var_ref = var_ref;
- }
- /* the arguments not mapped to the arguments of the function can
- be normal properties */
- for(i = arg_count; i < argc; i++) {
- if (JS_DefinePropertyValueUint32(ctx, val, i,
- js_dup(argv[i]),
- JS_PROP_C_W_E) < 0)
- goto fail;
- }
- JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator,
- js_dup(ctx->array_proto_values),
- JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
- /* callee returns this function in non strict mode */
- JS_DefinePropertyValue(ctx, val, JS_ATOM_callee,
- js_dup(ctx->rt->current_stack_frame->cur_func),
- JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
- return val;
- fail:
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
- {
- JSObject *p;
- JSPropertyEnum *tab_atom;
- int i;
- JSValue enum_obj, obj1;
- JSForInIterator *it;
- uint32_t tag, tab_atom_count;
- tag = JS_VALUE_GET_TAG(obj);
- if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL && tag != JS_TAG_UNDEFINED) {
- obj = JS_ToObjectFree(ctx, obj);
- }
- it = js_malloc(ctx, sizeof(*it));
- if (!it) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR);
- if (JS_IsException(enum_obj)) {
- js_free(ctx, it);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- it->is_array = false;
- it->obj = obj;
- it->idx = 0;
- p = JS_VALUE_GET_OBJ(enum_obj);
- p->u.for_in_iterator = it;
- if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
- return enum_obj;
- /* fast path: assume no enumerable properties in the prototype chain */
- obj1 = js_dup(obj);
- for(;;) {
- obj1 = JS_GetPrototypeFree(ctx, obj1);
- if (JS_IsNull(obj1))
- break;
- if (JS_IsException(obj1))
- goto fail;
- if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
- JS_VALUE_GET_OBJ(obj1),
- JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
- JS_FreeValue(ctx, obj1);
- goto fail;
- }
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
- if (tab_atom_count != 0) {
- JS_FreeValue(ctx, obj1);
- goto slow_path;
- }
- /* must check for timeout to avoid infinite loop */
- if (js_poll_interrupts(ctx)) {
- JS_FreeValue(ctx, obj1);
- goto fail;
- }
- }
- p = JS_VALUE_GET_OBJ(obj);
- if (p->fast_array) {
- JSShape *sh;
- JSShapeProperty *prs;
- /* check that there are no enumerable normal fields */
- sh = p->shape;
- for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
- if (prs->flags & JS_PROP_ENUMERABLE)
- goto normal_case;
- }
- /* for fast arrays, we only store the number of elements */
- it->is_array = true;
- it->array_length = p->u.array.count;
- } else {
- normal_case:
- if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
- JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY))
- goto fail;
- for(i = 0; i < tab_atom_count; i++) {
- JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0);
- }
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
- }
- return enum_obj;
- slow_path:
- /* non enumerable properties hide the enumerables ones in the
- prototype chain */
- obj1 = js_dup(obj);
- for(;;) {
- if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
- JS_VALUE_GET_OBJ(obj1),
- JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
- JS_FreeValue(ctx, obj1);
- goto fail;
- }
- for(i = 0; i < tab_atom_count; i++) {
- JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL,
- (tab_atom[i].is_enumerable ?
- JS_PROP_ENUMERABLE : 0));
- }
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
- obj1 = JS_GetPrototypeFree(ctx, obj1);
- if (JS_IsNull(obj1))
- break;
- if (JS_IsException(obj1))
- goto fail;
- /* must check for timeout to avoid infinite loop */
- if (js_poll_interrupts(ctx)) {
- JS_FreeValue(ctx, obj1);
- goto fail;
- }
- }
- return enum_obj;
- fail:
- JS_FreeValue(ctx, enum_obj);
- return JS_EXCEPTION;
- }
- /* obj -> enum_obj */
- static __exception int js_for_in_start(JSContext *ctx, JSValue *sp)
- {
- sp[-1] = build_for_in_iterator(ctx, sp[-1]);
- if (JS_IsException(sp[-1]))
- return -1;
- return 0;
- }
- /* enum_obj -> enum_obj value done */
- static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
- {
- JSValue enum_obj;
- JSObject *p;
- JSAtom prop;
- JSForInIterator *it;
- int ret;
- enum_obj = sp[-1];
- /* fail safe */
- if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT)
- goto done;
- p = JS_VALUE_GET_OBJ(enum_obj);
- if (p->class_id != JS_CLASS_FOR_IN_ITERATOR)
- goto done;
- it = p->u.for_in_iterator;
- for(;;) {
- if (it->is_array) {
- if (it->idx >= it->array_length)
- goto done;
- prop = __JS_AtomFromUInt32(it->idx);
- it->idx++;
- } else {
- JSShape *sh = p->shape;
- JSShapeProperty *prs;
- if (it->idx >= sh->prop_count)
- goto done;
- prs = get_shape_prop(sh) + it->idx;
- prop = prs->atom;
- it->idx++;
- if (prop == JS_ATOM_NULL || !(prs->flags & JS_PROP_ENUMERABLE))
- continue;
- }
- // check if the property was deleted unless we're dealing with a proxy
- JSValue obj = it->obj;
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- if (p->class_id == JS_CLASS_PROXY)
- break;
- }
- ret = JS_HasProperty(ctx, obj, prop);
- if (ret < 0)
- return ret;
- if (ret)
- break;
- }
- /* return the property */
- sp[0] = JS_AtomToValue(ctx, prop);
- sp[1] = JS_FALSE;
- return 0;
- done:
- /* return the end */
- sp[0] = JS_UNDEFINED;
- sp[1] = JS_TRUE;
- return 0;
- }
- static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj,
- JSValueConst method)
- {
- JSValue enum_obj;
- enum_obj = JS_Call(ctx, method, obj, 0, NULL);
- if (JS_IsException(enum_obj))
- return enum_obj;
- if (!JS_IsObject(enum_obj)) {
- JS_FreeValue(ctx, enum_obj);
- return JS_ThrowTypeErrorNotAnObject(ctx);
- }
- return enum_obj;
- }
- static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, bool is_async)
- {
- JSValue method, ret, sync_iter;
- if (is_async) {
- method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator);
- if (JS_IsException(method))
- return method;
- if (JS_IsUndefined(method) || JS_IsNull(method)) {
- method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
- if (JS_IsException(method))
- return method;
- sync_iter = JS_GetIterator2(ctx, obj, method);
- JS_FreeValue(ctx, method);
- if (JS_IsException(sync_iter))
- return sync_iter;
- ret = JS_CreateAsyncFromSyncIterator(ctx, sync_iter);
- JS_FreeValue(ctx, sync_iter);
- return ret;
- }
- } else {
- method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
- if (JS_IsException(method))
- return method;
- }
- if (!JS_IsFunction(ctx, method)) {
- JS_FreeValue(ctx, method);
- return JS_ThrowTypeError(ctx, "value is not iterable");
- }
- ret = JS_GetIterator2(ctx, obj, method);
- JS_FreeValue(ctx, method);
- return ret;
- }
- /* return *pdone = 2 if the iterator object is not parsed */
- static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj,
- JSValueConst method,
- int argc, JSValueConst *argv, int *pdone)
- {
- JSValue obj;
- /* fast path for the built-in iterators (avoid creating the
- intermediate result object) */
- if (JS_IsObject(method)) {
- JSObject *p = JS_VALUE_GET_OBJ(method);
- if (p->class_id == JS_CLASS_C_FUNCTION &&
- p->u.cfunc.cproto == JS_CFUNC_iterator_next) {
- JSCFunctionType func;
- JSValueConst args[1];
- /* in case the function expects one argument */
- if (argc == 0) {
- args[0] = JS_UNDEFINED;
- argv = args;
- }
- func = p->u.cfunc.c_function;
- return func.iterator_next(ctx, enum_obj, argc, argv,
- pdone, p->u.cfunc.magic);
- }
- }
- obj = JS_Call(ctx, method, enum_obj, argc, argv);
- if (JS_IsException(obj))
- goto fail;
- if (!JS_IsObject(obj)) {
- JS_FreeValue(ctx, obj);
- JS_ThrowTypeError(ctx, "iterator must return an object");
- goto fail;
- }
- *pdone = 2;
- return obj;
- fail:
- *pdone = false;
- return JS_EXCEPTION;
- }
- static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj,
- JSValueConst method,
- int argc, JSValueConst *argv, int *pdone)
- {
- JSValue obj, value, done_val;
- int done;
- obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done);
- if (JS_IsException(obj))
- goto fail;
- if (likely(done == 0)) {
- *pdone = false;
- return obj;
- } else if (done != 2) {
- JS_FreeValue(ctx, obj);
- *pdone = true;
- return JS_UNDEFINED;
- } else {
- done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
- if (JS_IsException(done_val))
- goto fail;
- *pdone = JS_ToBoolFree(ctx, done_val);
- value = JS_UNDEFINED;
- if (!*pdone) {
- value = JS_GetProperty(ctx, obj, JS_ATOM_value);
- }
- JS_FreeValue(ctx, obj);
- return value;
- }
- fail:
- JS_FreeValue(ctx, obj);
- *pdone = false;
- return JS_EXCEPTION;
- }
- /* return < 0 in case of exception */
- static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
- bool is_exception_pending)
- {
- JSValue method, ret, ex_obj;
- int res;
- if (is_exception_pending) {
- ex_obj = ctx->rt->current_exception;
- ctx->rt->current_exception = JS_UNINITIALIZED;
- res = -1;
- } else {
- ex_obj = JS_UNDEFINED;
- res = 0;
- }
- method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return);
- if (JS_IsException(method)) {
- res = -1;
- goto done;
- }
- if (JS_IsUndefined(method) || JS_IsNull(method)) {
- goto done;
- }
- ret = JS_CallFree(ctx, method, enum_obj, 0, NULL);
- if (!is_exception_pending) {
- if (JS_IsException(ret)) {
- res = -1;
- } else if (!JS_IsObject(ret)) {
- JS_ThrowTypeErrorNotAnObject(ctx);
- res = -1;
- }
- }
- JS_FreeValue(ctx, ret);
- done:
- if (is_exception_pending) {
- JS_Throw(ctx, ex_obj);
- }
- return res;
- }
- /* obj -> enum_rec (3 slots) */
- static __exception int js_for_of_start(JSContext *ctx, JSValue *sp,
- bool is_async)
- {
- JSValue op1, obj, method;
- op1 = sp[-1];
- obj = JS_GetIterator(ctx, op1, is_async);
- if (JS_IsException(obj))
- return -1;
- JS_FreeValue(ctx, op1);
- sp[-1] = obj;
- method = JS_GetProperty(ctx, obj, JS_ATOM_next);
- if (JS_IsException(method))
- return -1;
- sp[0] = method;
- return 0;
- }
- /* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset'
- objs. If 'done' is true or in case of exception, 'enum_rec' is set
- to undefined. If 'done' is true, 'value' is always set to
- undefined. */
- static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
- {
- JSValue value = JS_UNDEFINED;
- int done = 1;
- if (likely(!JS_IsUndefined(sp[offset]))) {
- value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done);
- if (JS_IsException(value))
- done = -1;
- if (done) {
- /* value is JS_UNDEFINED or JS_EXCEPTION */
- /* replace the iteration object with undefined */
- JS_FreeValue(ctx, sp[offset]);
- sp[offset] = JS_UNDEFINED;
- if (done < 0) {
- return -1;
- } else {
- JS_FreeValue(ctx, value);
- value = JS_UNDEFINED;
- }
- }
- }
- sp[0] = value;
- sp[1] = js_bool(done);
- return 0;
- }
- static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValue obj,
- int *pdone)
- {
- JSValue done_val, value;
- int done;
- done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
- if (JS_IsException(done_val))
- goto fail;
- done = JS_ToBoolFree(ctx, done_val);
- value = JS_GetProperty(ctx, obj, JS_ATOM_value);
- if (JS_IsException(value))
- goto fail;
- *pdone = done;
- return value;
- fail:
- *pdone = false;
- return JS_EXCEPTION;
- }
- static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
- {
- JSValue obj, value;
- int done;
- obj = sp[-1];
- if (!JS_IsObject(obj)) {
- JS_ThrowTypeError(ctx, "iterator must return an object");
- return -1;
- }
- value = JS_IteratorGetCompleteValue(ctx, obj, &done);
- if (JS_IsException(value))
- return -1;
- JS_FreeValue(ctx, obj);
- sp[-1] = value;
- sp[0] = js_bool(done);
- return 0;
- }
- static JSValue js_create_iterator_result(JSContext *ctx,
- JSValue val,
- bool done)
- {
- JSValue obj;
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj)) {
- JS_FreeValue(ctx, val);
- return obj;
- }
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value,
- val, JS_PROP_C_W_E) < 0) {
- goto fail;
- }
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done,
- js_bool(done), JS_PROP_C_W_E) < 0) {
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- return obj;
- }
- static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int *pdone, int magic);
- static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic);
- static bool js_is_fast_array(JSContext *ctx, JSValue obj)
- {
- /* Try and handle fast arrays explicitly */
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
- return true;
- }
- }
- return false;
- }
- /* Access an Array's internal JSValue array if available */
- static bool js_get_fast_array(JSContext *ctx, JSValue obj,
- JSValue **arrpp, uint32_t *countp)
- {
- /* Try and handle fast arrays explicitly */
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
- *countp = p->u.array.count;
- *arrpp = p->u.array.u.values;
- return true;
- }
- }
- return false;
- }
- static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp)
- {
- JSValue iterator, enumobj, method, value;
- int is_array_iterator;
- JSValue *arrp;
- uint32_t i, count32, pos;
- if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) {
- JS_ThrowInternalError(ctx, "invalid index for append");
- return -1;
- }
- pos = JS_VALUE_GET_INT(sp[-2]);
- /* XXX: further optimisations:
- - use ctx->array_proto_values?
- - check if array_iterator_prototype next method is built-in and
- avoid constructing actual iterator object?
- - build this into js_for_of_start and use in all `for (x of o)` loops
- */
- iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator);
- if (JS_IsException(iterator))
- return -1;
- /* Used to squelch a -Wcast-function-type warning. */
- JSCFunctionType ft = { .generic_magic = js_create_array_iterator };
- is_array_iterator = JS_IsCFunction(ctx, iterator,
- ft.generic,
- JS_ITERATOR_KIND_VALUE);
- JS_FreeValue(ctx, iterator);
- enumobj = JS_GetIterator(ctx, sp[-1], false);
- if (JS_IsException(enumobj))
- return -1;
- method = JS_GetProperty(ctx, enumobj, JS_ATOM_next);
- if (JS_IsException(method)) {
- JS_FreeValue(ctx, enumobj);
- return -1;
- }
- /* Used to squelch a -Wcast-function-type warning. */
- JSCFunctionType ft2 = { .iterator_next = js_array_iterator_next };
- if (is_array_iterator
- && JS_IsCFunction(ctx, method, ft2.generic, 0)
- && js_get_fast_array(ctx, sp[-1], &arrp, &count32)) {
- uint32_t len;
- if (js_get_length32(ctx, &len, sp[-1]))
- goto exception;
- /* if len > count32, the elements >= count32 might be read in
- the prototypes and might have side effects */
- if (len != count32)
- goto general_case;
- /* Handle fast arrays explicitly */
- for (i = 0; i < count32; i++) {
- if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++,
- js_dup(arrp[i]), JS_PROP_C_W_E) < 0)
- goto exception;
- }
- } else {
- general_case:
- for (;;) {
- int done;
- value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done);
- if (JS_IsException(value))
- goto exception;
- if (done) {
- /* value is JS_UNDEFINED */
- break;
- }
- if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0)
- goto exception;
- }
- }
- /* Note: could raise an error if too many elements */
- sp[-2] = js_int32(pos);
- JS_FreeValue(ctx, enumobj);
- JS_FreeValue(ctx, method);
- return 0;
- exception:
- JS_IteratorClose(ctx, enumobj, true);
- JS_FreeValue(ctx, enumobj);
- JS_FreeValue(ctx, method);
- return -1;
- }
- static __exception int JS_CopyDataProperties(JSContext *ctx,
- JSValue target,
- JSValue source,
- JSValue excluded,
- bool setprop)
- {
- JSPropertyEnum *tab_atom;
- JSValue val;
- uint32_t i, tab_atom_count;
- JSObject *p;
- JSObject *pexcl = NULL;
- int ret, gpn_flags;
- JSPropertyDescriptor desc;
- bool is_enumerable;
- if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT)
- return 0;
- if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT)
- pexcl = JS_VALUE_GET_OBJ(excluded);
- p = JS_VALUE_GET_OBJ(source);
- gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY;
- if (p->is_exotic) {
- const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
- /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it
- introduces a visible change */
- if (em && em->get_own_property_names) {
- gpn_flags &= ~JS_GPN_ENUM_ONLY;
- }
- }
- if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
- gpn_flags))
- return -1;
- for (i = 0; i < tab_atom_count; i++) {
- if (pexcl) {
- ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom);
- if (ret) {
- if (ret < 0)
- goto exception;
- continue;
- }
- }
- if (!(gpn_flags & JS_GPN_ENUM_ONLY)) {
- /* test if the property is enumerable */
- ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom);
- if (ret < 0)
- goto exception;
- if (!ret)
- continue;
- is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0;
- js_free_desc(ctx, &desc);
- if (!is_enumerable)
- continue;
- }
- val = JS_GetProperty(ctx, source, tab_atom[i].atom);
- if (JS_IsException(val))
- goto exception;
- if (setprop)
- ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val);
- else
- ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val,
- JS_PROP_C_W_E);
- if (ret < 0)
- goto exception;
- }
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
- return 0;
- exception:
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
- return -1;
- }
- /* only valid inside C functions */
- static JSValueConst JS_GetActiveFunction(JSContext *ctx)
- {
- return ctx->rt->current_stack_frame->cur_func;
- }
- static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
- int var_idx, bool is_arg)
- {
- JSVarRef *var_ref;
- struct list_head *el;
- JSValue *pvalue;
- if (is_arg)
- pvalue = &sf->arg_buf[var_idx];
- else
- pvalue = &sf->var_buf[var_idx];
- list_for_each(el, &sf->var_ref_list) {
- var_ref = list_entry(el, JSVarRef, header.link);
- if (var_ref->pvalue == pvalue) {
- var_ref->header.ref_count++;
- return var_ref;
- }
- }
- /* create a new one */
- var_ref = js_malloc(ctx, sizeof(JSVarRef));
- if (!var_ref)
- return NULL;
- var_ref->header.ref_count = 1;
- var_ref->is_detached = false;
- list_add_tail(&var_ref->header.link, &sf->var_ref_list);
- var_ref->pvalue = pvalue;
- var_ref->value = JS_UNDEFINED;
- return var_ref;
- }
- static JSValue js_closure2(JSContext *ctx, JSValue func_obj,
- JSFunctionBytecode *b,
- JSVarRef **cur_var_refs,
- JSStackFrame *sf)
- {
- JSObject *p;
- JSVarRef **var_refs;
- int i;
- p = JS_VALUE_GET_OBJ(func_obj);
- p->u.func.function_bytecode = b;
- p->u.func.home_object = NULL;
- p->u.func.var_refs = NULL;
- if (b->closure_var_count) {
- var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
- if (!var_refs)
- goto fail;
- p->u.func.var_refs = var_refs;
- for(i = 0; i < b->closure_var_count; i++) {
- JSClosureVar *cv = &b->closure_var[i];
- JSVarRef *var_ref;
- if (cv->is_local) {
- /* reuse the existing variable reference if it already exists */
- var_ref = get_var_ref(ctx, sf, cv->var_idx, cv->is_arg);
- if (!var_ref)
- goto fail;
- } else {
- var_ref = cur_var_refs[cv->var_idx];
- var_ref->header.ref_count++;
- }
- var_refs[i] = var_ref;
- }
- }
- return func_obj;
- fail:
- /* bfunc is freed when func_obj is freed */
- JS_FreeValue(ctx, func_obj);
- return JS_EXCEPTION;
- }
- static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque)
- {
- JSValue obj, this_val;
- int ret;
- this_val = JS_MKPTR(JS_TAG_OBJECT, p);
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor,
- js_dup(this_val),
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- if (ret < 0) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- return obj;
- }
- static const uint16_t func_kind_to_class_id[] = {
- [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION,
- [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION,
- [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION,
- [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION,
- };
- static JSValue js_closure(JSContext *ctx, JSValue bfunc,
- JSVarRef **cur_var_refs,
- JSStackFrame *sf)
- {
- JSFunctionBytecode *b;
- JSValue func_obj;
- JSAtom name_atom;
- b = JS_VALUE_GET_PTR(bfunc);
- func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]);
- if (JS_IsException(func_obj)) {
- JS_FreeValue(ctx, bfunc);
- return JS_EXCEPTION;
- }
- func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf);
- if (JS_IsException(func_obj)) {
- /* bfunc has been freed */
- goto fail;
- }
- name_atom = b->func_name;
- if (name_atom == JS_ATOM_NULL)
- name_atom = JS_ATOM_empty_string;
- js_function_set_properties(ctx, func_obj, name_atom,
- b->defined_arg_count);
- if (b->func_kind & JS_FUNC_GENERATOR) {
- JSValue proto;
- int proto_class_id;
- /* generators have a prototype field which is used as
- prototype for the generator object */
- if (b->func_kind == JS_FUNC_ASYNC_GENERATOR)
- proto_class_id = JS_CLASS_ASYNC_GENERATOR;
- else
- proto_class_id = JS_CLASS_GENERATOR;
- proto = JS_NewObjectProto(ctx, ctx->class_proto[proto_class_id]);
- if (JS_IsException(proto))
- goto fail;
- JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto,
- JS_PROP_WRITABLE);
- } else if (b->has_prototype) {
- /* add the 'prototype' property: delay instantiation to avoid
- creating cycles for every javascript function. The prototype
- object is created on the fly when first accessed */
- JS_SetConstructorBit(ctx, func_obj, true);
- JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype,
- JS_AUTOINIT_ID_PROTOTYPE, NULL,
- JS_PROP_WRITABLE);
- }
- return func_obj;
- fail:
- /* bfunc is freed when func_obj is freed */
- JS_FreeValue(ctx, func_obj);
- return JS_EXCEPTION;
- }
- #define JS_DEFINE_CLASS_HAS_HERITAGE (1 << 0)
- static int js_op_define_class(JSContext *ctx, JSValue *sp,
- JSAtom class_name, int class_flags,
- JSVarRef **cur_var_refs,
- JSStackFrame *sf, bool is_computed_name)
- {
- JSValue bfunc, parent_class, proto = JS_UNDEFINED;
- JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED;
- JSFunctionBytecode *b;
- parent_class = sp[-2];
- bfunc = sp[-1];
- if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) {
- if (JS_IsNull(parent_class)) {
- parent_proto = JS_NULL;
- parent_class = js_dup(ctx->function_proto);
- } else {
- if (!JS_IsConstructor(ctx, parent_class)) {
- JS_ThrowTypeError(ctx, "parent class must be constructor");
- goto fail;
- }
- parent_proto = JS_GetProperty(ctx, parent_class, JS_ATOM_prototype);
- if (JS_IsException(parent_proto))
- goto fail;
- if (!JS_IsNull(parent_proto) && !JS_IsObject(parent_proto)) {
- JS_ThrowTypeError(ctx, "parent prototype must be an object or null");
- goto fail;
- }
- }
- } else {
- /* parent_class is JS_UNDEFINED in this case */
- parent_proto = js_dup(ctx->class_proto[JS_CLASS_OBJECT]);
- parent_class = js_dup(ctx->function_proto);
- }
- proto = JS_NewObjectProto(ctx, parent_proto);
- if (JS_IsException(proto))
- goto fail;
- b = JS_VALUE_GET_PTR(bfunc);
- assert(b->func_kind == JS_FUNC_NORMAL);
- ctor = JS_NewObjectProtoClass(ctx, parent_class,
- JS_CLASS_BYTECODE_FUNCTION);
- if (JS_IsException(ctor))
- goto fail;
- ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf);
- bfunc = JS_UNDEFINED;
- if (JS_IsException(ctor))
- goto fail;
- js_method_set_home_object(ctx, ctor, proto);
- JS_SetConstructorBit(ctx, ctor, true);
- JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length,
- js_int32(b->defined_arg_count),
- JS_PROP_CONFIGURABLE);
- if (is_computed_name) {
- if (JS_DefineObjectNameComputed(ctx, ctor, sp[-3],
- JS_PROP_CONFIGURABLE) < 0)
- goto fail;
- } else {
- if (JS_DefineObjectName(ctx, ctor, class_name, JS_PROP_CONFIGURABLE) < 0)
- goto fail;
- }
- /* the constructor property must be first. It can be overriden by
- computed property names */
- if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
- js_dup(ctor),
- JS_PROP_CONFIGURABLE |
- JS_PROP_WRITABLE | JS_PROP_THROW) < 0)
- goto fail;
- /* set the prototype property */
- if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype,
- js_dup(proto), JS_PROP_THROW) < 0)
- goto fail;
- JS_FreeValue(ctx, parent_proto);
- JS_FreeValue(ctx, parent_class);
- sp[-2] = ctor;
- sp[-1] = proto;
- return 0;
- fail:
- JS_FreeValue(ctx, parent_class);
- JS_FreeValue(ctx, parent_proto);
- JS_FreeValue(ctx, bfunc);
- JS_FreeValue(ctx, proto);
- JS_FreeValue(ctx, ctor);
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- static void close_var_refs(JSRuntime *rt, JSStackFrame *sf)
- {
- struct list_head *el, *el1;
- JSVarRef *var_ref;
- list_for_each_safe(el, el1, &sf->var_ref_list) {
- var_ref = list_entry(el, JSVarRef, header.link);
- var_ref->value = js_dup(*var_ref->pvalue);
- var_ref->pvalue = &var_ref->value;
- /* the reference is no longer to a local variable */
- var_ref->is_detached = true;
- add_gc_object(rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
- }
- }
- static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int var_idx)
- {
- JSValue *pvalue;
- struct list_head *el, *el1;
- JSVarRef *var_ref;
- pvalue = &sf->var_buf[var_idx];
- list_for_each_safe(el, el1, &sf->var_ref_list) {
- var_ref = list_entry(el, JSVarRef, header.link);
- if (var_ref->pvalue == pvalue) {
- var_ref->value = js_dup(*var_ref->pvalue);
- var_ref->pvalue = &var_ref->value;
- list_del(&var_ref->header.link);
- /* the reference is no longer to a local variable */
- var_ref->is_detached = true;
- add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
- }
- }
- }
- #define JS_CALL_FLAG_COPY_ARGV (1 << 1)
- #define JS_CALL_FLAG_GENERATOR (1 << 2)
- static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_obj,
- int argc, JSValueConst *argv, int flags)
- {
- JSRuntime *rt = ctx->rt;
- JSCFunctionType func;
- JSObject *p;
- JSStackFrame sf_s, *sf = &sf_s, *prev_sf;
- JSValue ret_val;
- JSValueConst *arg_buf;
- int arg_count, i;
- JSCFunctionEnum cproto;
- p = JS_VALUE_GET_OBJ(func_obj);
- cproto = p->u.cfunc.cproto;
- arg_count = p->u.cfunc.length;
- /* better to always check stack overflow */
- if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count))
- return JS_ThrowStackOverflow(ctx);
- prev_sf = rt->current_stack_frame;
- sf->prev_frame = prev_sf;
- rt->current_stack_frame = sf;
- ctx = p->u.cfunc.realm; /* change the current realm */
- sf->is_strict_mode = false;
- sf->cur_func = unsafe_unconst(func_obj);
- sf->arg_count = argc;
- arg_buf = argv;
- if (unlikely(argc < arg_count)) {
- /* ensure that at least argc_count arguments are readable */
- arg_buf = alloca(sizeof(arg_buf[0]) * arg_count);
- for(i = 0; i < argc; i++)
- arg_buf[i] = argv[i];
- for(i = argc; i < arg_count; i++)
- arg_buf[i] = JS_UNDEFINED;
- sf->arg_count = arg_count;
- }
- sf->arg_buf = (JSValue *)arg_buf;
- func = p->u.cfunc.c_function;
- switch(cproto) {
- case JS_CFUNC_constructor:
- case JS_CFUNC_constructor_or_func:
- if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
- if (cproto == JS_CFUNC_constructor) {
- not_a_constructor:
- ret_val = JS_ThrowTypeError(ctx, "must be called with new");
- break;
- } else {
- this_obj = JS_UNDEFINED;
- }
- }
- /* here this_obj is new_target */
- /* fall thru */
- case JS_CFUNC_generic:
- ret_val = func.generic(ctx, this_obj, argc, arg_buf);
- break;
- case JS_CFUNC_constructor_magic:
- case JS_CFUNC_constructor_or_func_magic:
- if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
- if (cproto == JS_CFUNC_constructor_magic) {
- goto not_a_constructor;
- } else {
- this_obj = JS_UNDEFINED;
- }
- }
- /* fall thru */
- case JS_CFUNC_generic_magic:
- ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf,
- p->u.cfunc.magic);
- break;
- case JS_CFUNC_getter:
- ret_val = func.getter(ctx, this_obj);
- break;
- case JS_CFUNC_setter:
- ret_val = func.setter(ctx, this_obj, arg_buf[0]);
- break;
- case JS_CFUNC_getter_magic:
- ret_val = func.getter_magic(ctx, this_obj, p->u.cfunc.magic);
- break;
- case JS_CFUNC_setter_magic:
- ret_val = func.setter_magic(ctx, this_obj, arg_buf[0], p->u.cfunc.magic);
- break;
- case JS_CFUNC_f_f:
- {
- double d1;
- if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
- ret_val = JS_EXCEPTION;
- break;
- }
- ret_val = js_number(func.f_f(d1));
- }
- break;
- case JS_CFUNC_f_f_f:
- {
- double d1, d2;
- if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
- ret_val = JS_EXCEPTION;
- break;
- }
- if (unlikely(JS_ToFloat64(ctx, &d2, arg_buf[1]))) {
- ret_val = JS_EXCEPTION;
- break;
- }
- ret_val = js_number(func.f_f_f(d1, d2));
- }
- break;
- case JS_CFUNC_iterator_next:
- {
- int done;
- ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf,
- &done, p->u.cfunc.magic);
- if (!JS_IsException(ret_val) && done != 2) {
- ret_val = js_create_iterator_result(ctx, ret_val, done);
- }
- }
- break;
- default:
- abort();
- }
- rt->current_stack_frame = sf->prev_frame;
- return ret_val;
- }
- static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_obj,
- int argc, JSValueConst *argv, int flags)
- {
- JSObject *p;
- JSBoundFunction *bf;
- JSValueConst *arg_buf, new_target;
- int arg_count, i;
- p = JS_VALUE_GET_OBJ(func_obj);
- bf = p->u.bound_function;
- arg_count = bf->argc + argc;
- if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count))
- return JS_ThrowStackOverflow(ctx);
- arg_buf = alloca(sizeof(JSValue) * arg_count);
- for(i = 0; i < bf->argc; i++) {
- arg_buf[i] = bf->argv[i];
- }
- for(i = 0; i < argc; i++) {
- arg_buf[bf->argc + i] = argv[i];
- }
- if (flags & JS_CALL_FLAG_CONSTRUCTOR) {
- new_target = this_obj;
- if (js_same_value(ctx, func_obj, new_target))
- new_target = bf->func_obj;
- return JS_CallConstructor2(ctx, bf->func_obj, new_target,
- arg_count, arg_buf);
- } else {
- return JS_Call(ctx, bf->func_obj, bf->this_val,
- arg_count, arg_buf);
- }
- }
- /* argument of OP_special_object */
- typedef enum {
- OP_SPECIAL_OBJECT_ARGUMENTS,
- OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS,
- OP_SPECIAL_OBJECT_THIS_FUNC,
- OP_SPECIAL_OBJECT_NEW_TARGET,
- OP_SPECIAL_OBJECT_HOME_OBJECT,
- OP_SPECIAL_OBJECT_VAR_OBJECT,
- OP_SPECIAL_OBJECT_IMPORT_META,
- OP_SPECIAL_OBJECT_NULL_PROTO,
- } OPSpecialObjectEnum;
- #define FUNC_RET_AWAIT 0
- #define FUNC_RET_YIELD 1
- #define FUNC_RET_YIELD_STAR 2
- #ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_*
- static void dump_single_byte_code(JSContext *ctx, const uint8_t *pc,
- JSFunctionBytecode *b, int start_pos);
- static void print_func_name(JSFunctionBytecode *b);
- #endif
- static bool needs_backtrace(JSValue exc)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(exc) != JS_TAG_OBJECT)
- return false;
- p = JS_VALUE_GET_OBJ(exc);
- if (p->class_id != JS_CLASS_ERROR)
- return false;
- return !find_own_property1(p, JS_ATOM_stack);
- }
- /* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
- static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- JSValueConst this_obj, JSValueConst new_target,
- int argc, JSValueConst *argv, int flags)
- {
- JSRuntime *rt = caller_ctx->rt;
- JSContext *ctx;
- JSObject *p;
- JSFunctionBytecode *b;
- JSStackFrame sf_s, *sf = &sf_s;
- uint8_t *pc;
- int opcode, arg_allocated_size, i;
- JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval;
- JSVarRef **var_refs;
- size_t alloca_size;
- #ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_STEP
- #define DUMP_BYTECODE_OR_DONT(pc) \
- if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_STEP)) dump_single_byte_code(ctx, pc, b, 0);
- #else
- #define DUMP_BYTECODE_OR_DONT(pc)
- #endif
- #if !DIRECT_DISPATCH
- #define SWITCH(pc) DUMP_BYTECODE_OR_DONT(pc) switch (opcode = *pc++)
- #define CASE(op) case op
- #define DEFAULT default
- #define BREAK break
- #else
- __extension__ static const void * const dispatch_table[256] = {
- #define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id,
- #define def(id, size, n_pop, n_push, f)
- /*
- * QuickJS opcode definitions
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- * Copyright (c) 2017-2018 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifdef FMT
- FMT(none)
- FMT(none_int)
- FMT(none_loc)
- FMT(none_arg)
- FMT(none_var_ref)
- FMT(u8)
- FMT(i8)
- FMT(loc8)
- FMT(const8)
- FMT(label8)
- FMT(u16)
- FMT(i16)
- FMT(label16)
- FMT(npop)
- FMT(npopx)
- FMT(npop_u16)
- FMT(loc)
- FMT(arg)
- FMT(var_ref)
- FMT(u32)
- FMT(u32x2)
- FMT(i32)
- FMT(const)
- FMT(label)
- FMT(atom)
- FMT(atom_u8)
- FMT(atom_u16)
- FMT(atom_label_u8)
- FMT(atom_label_u16)
- FMT(label_u16)
- #undef FMT
- #endif /* FMT */
- #ifdef DEF
- #ifndef def
- #define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f)
- #endif
- DEF(invalid, 1, 0, 0, none) /* never emitted */
- /* push values */
- DEF( push_i32, 5, 0, 1, i32)
- DEF( push_const, 5, 0, 1, const)
- DEF( fclosure, 5, 0, 1, const) /* must follow push_const */
- DEF(push_atom_value, 5, 0, 1, atom)
- DEF( private_symbol, 5, 0, 1, atom)
- DEF( undefined, 1, 0, 1, none)
- DEF( null, 1, 0, 1, none)
- DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */
- DEF( push_false, 1, 0, 1, none)
- DEF( push_true, 1, 0, 1, none)
- DEF( object, 1, 0, 1, none)
- DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */
- DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */
- DEF( drop, 1, 1, 0, none) /* a -> */
- DEF( nip, 1, 2, 1, none) /* a b -> b */
- DEF( nip1, 1, 3, 2, none) /* a b c -> b c */
- DEF( dup, 1, 1, 2, none) /* a -> a a */
- DEF( dup1, 1, 2, 3, none) /* a b -> a a b */
- DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */
- DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */
- DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */
- DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */
- DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */
- DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */
- DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */
- DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */
- DEF( swap, 1, 2, 2, none) /* a b -> b a */
- DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */
- DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */
- DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */
- DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */
- DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */
- DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */
- DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */
- DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */
- DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */
- DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */
- DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */
- DEF( apply, 3, 3, 1, u16)
- DEF( return, 1, 1, 0, none)
- DEF( return_undef, 1, 0, 0, none)
- DEF(check_ctor_return, 1, 1, 2, none)
- DEF( check_ctor, 1, 0, 0, none)
- DEF( init_ctor, 1, 0, 1, none)
- DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */
- DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */
- DEF( return_async, 1, 1, 0, none)
- DEF( throw, 1, 1, 0, none)
- DEF( throw_error, 6, 0, 0, atom_u8)
- DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
- DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
- DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
- bytecode string */
- DEF( get_super, 1, 1, 1, none)
- DEF( import, 1, 1, 1, none) /* dynamic module import */
- DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */
- DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */
- DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */
- DEF( put_var, 5, 1, 0, atom) /* must come after get_var */
- DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */
- DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */
- DEF( get_ref_value, 1, 2, 3, none)
- DEF( put_ref_value, 1, 3, 0, none)
- DEF( define_var, 6, 0, 0, atom_u8)
- DEF(check_define_var, 6, 0, 0, atom_u8)
- DEF( define_func, 6, 1, 0, atom_u8)
- // order matters, see IC counterparts
- DEF( get_field, 5, 1, 1, atom)
- DEF( get_field2, 5, 1, 2, atom)
- DEF( put_field, 5, 2, 0, atom)
- DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */
- DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */
- DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */
- DEF( get_array_el, 1, 2, 1, none)
- DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */
- DEF( put_array_el, 1, 3, 0, none)
- DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */
- DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */
- DEF( define_field, 5, 2, 1, atom)
- DEF( set_name, 5, 1, 1, atom)
- DEF(set_name_computed, 1, 2, 2, none)
- DEF( set_proto, 1, 2, 1, none)
- DEF(set_home_object, 1, 2, 2, none)
- DEF(define_array_el, 1, 3, 2, none)
- DEF( append, 1, 3, 2, none) /* append enumerated object, update length */
- DEF(copy_data_properties, 2, 3, 3, u8)
- DEF( define_method, 6, 2, 1, atom_u8)
- DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */
- DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */
- DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */
- DEF( get_loc, 3, 0, 1, loc)
- DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */
- DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */
- DEF( get_arg, 3, 0, 1, arg)
- DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */
- DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */
- DEF( get_var_ref, 3, 0, 1, var_ref)
- DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */
- DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */
- DEF(set_loc_uninitialized, 3, 0, 0, loc)
- DEF( get_loc_check, 3, 0, 1, loc)
- DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */
- DEF( put_loc_check_init, 3, 1, 0, loc)
- DEF(get_var_ref_check, 3, 0, 1, var_ref)
- DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */
- DEF(put_var_ref_check_init, 3, 1, 0, var_ref)
- DEF( close_loc, 3, 0, 0, loc)
- DEF( if_false, 5, 1, 0, label)
- DEF( if_true, 5, 1, 0, label) /* must come after if_false */
- DEF( goto, 5, 0, 0, label) /* must come after if_true */
- DEF( catch, 5, 0, 1, label)
- DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */
- DEF( ret, 1, 1, 0, none) /* used to return from the finally block */
- DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */
- DEF( to_object, 1, 1, 1, none)
- //DEF( to_string, 1, 1, 1, none)
- DEF( to_propkey, 1, 1, 1, none)
- DEF( to_propkey2, 1, 2, 2, none)
- DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF(with_get_ref_undef, 10, 1, 0, atom_label_u8)
- DEF( make_loc_ref, 7, 0, 2, atom_u16)
- DEF( make_arg_ref, 7, 0, 2, atom_u16)
- DEF(make_var_ref_ref, 7, 0, 2, atom_u16)
- DEF( make_var_ref, 5, 0, 2, atom)
- DEF( for_in_start, 1, 1, 1, none)
- DEF( for_of_start, 1, 1, 3, none)
- DEF(for_await_of_start, 1, 1, 3, none)
- DEF( for_in_next, 1, 1, 3, none)
- DEF( for_of_next, 2, 3, 5, u8)
- DEF(iterator_check_object, 1, 1, 1, none)
- DEF(iterator_get_value_done, 1, 1, 2, none)
- DEF( iterator_close, 1, 3, 0, none)
- DEF( iterator_next, 1, 4, 4, none)
- DEF( iterator_call, 2, 4, 5, u8)
- DEF( initial_yield, 1, 0, 0, none)
- DEF( yield, 1, 1, 2, none)
- DEF( yield_star, 1, 1, 2, none)
- DEF(async_yield_star, 1, 1, 2, none)
- DEF( await, 1, 1, 1, none)
- /* arithmetic/logic operations */
- DEF( neg, 1, 1, 1, none)
- DEF( plus, 1, 1, 1, none)
- DEF( dec, 1, 1, 1, none)
- DEF( inc, 1, 1, 1, none)
- DEF( post_dec, 1, 1, 2, none)
- DEF( post_inc, 1, 1, 2, none)
- DEF( dec_loc, 2, 0, 0, loc8)
- DEF( inc_loc, 2, 0, 0, loc8)
- DEF( add_loc, 2, 1, 0, loc8)
- DEF( not, 1, 1, 1, none)
- DEF( lnot, 1, 1, 1, none)
- DEF( typeof, 1, 1, 1, none)
- DEF( delete, 1, 2, 1, none)
- DEF( delete_var, 5, 0, 1, atom)
- /* warning: order matters (see js_parse_assign_expr) */
- DEF( mul, 1, 2, 1, none)
- DEF( div, 1, 2, 1, none)
- DEF( mod, 1, 2, 1, none)
- DEF( add, 1, 2, 1, none)
- DEF( sub, 1, 2, 1, none)
- DEF( shl, 1, 2, 1, none)
- DEF( sar, 1, 2, 1, none)
- DEF( shr, 1, 2, 1, none)
- DEF( and, 1, 2, 1, none)
- DEF( xor, 1, 2, 1, none)
- DEF( or, 1, 2, 1, none)
- DEF( pow, 1, 2, 1, none)
- DEF( lt, 1, 2, 1, none)
- DEF( lte, 1, 2, 1, none)
- DEF( gt, 1, 2, 1, none)
- DEF( gte, 1, 2, 1, none)
- DEF( instanceof, 1, 2, 1, none)
- DEF( in, 1, 2, 1, none)
- DEF( eq, 1, 2, 1, none)
- DEF( neq, 1, 2, 1, none)
- DEF( strict_eq, 1, 2, 1, none)
- DEF( strict_neq, 1, 2, 1, none)
- DEF(is_undefined_or_null, 1, 1, 1, none)
- DEF( private_in, 1, 2, 1, none)
- DEF(push_bigint_i32, 5, 0, 1, i32)
- /* must be the last non short and non temporary opcode */
- DEF( nop, 1, 0, 0, none)
- /* temporary opcodes: never emitted in the final bytecode */
- def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
- def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
- def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */
- def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
- def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
- def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
- def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */
- def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */
- def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
- def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
- def( source_loc, 9, 0, 0, u32x2) /* emitted in phase 1, removed in phase 3 */
- DEF( push_minus1, 1, 0, 1, none_int)
- DEF( push_0, 1, 0, 1, none_int)
- DEF( push_1, 1, 0, 1, none_int)
- DEF( push_2, 1, 0, 1, none_int)
- DEF( push_3, 1, 0, 1, none_int)
- DEF( push_4, 1, 0, 1, none_int)
- DEF( push_5, 1, 0, 1, none_int)
- DEF( push_6, 1, 0, 1, none_int)
- DEF( push_7, 1, 0, 1, none_int)
- DEF( push_i8, 2, 0, 1, i8)
- DEF( push_i16, 3, 0, 1, i16)
- DEF( push_const8, 2, 0, 1, const8)
- DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */
- DEF(push_empty_string, 1, 0, 1, none)
- DEF( get_loc8, 2, 0, 1, loc8)
- DEF( put_loc8, 2, 1, 0, loc8)
- DEF( set_loc8, 2, 1, 1, loc8)
- DEF( get_loc0_loc1, 1, 0, 2, none_loc)
- DEF( get_loc0, 1, 0, 1, none_loc)
- DEF( get_loc1, 1, 0, 1, none_loc)
- DEF( get_loc2, 1, 0, 1, none_loc)
- DEF( get_loc3, 1, 0, 1, none_loc)
- DEF( put_loc0, 1, 1, 0, none_loc)
- DEF( put_loc1, 1, 1, 0, none_loc)
- DEF( put_loc2, 1, 1, 0, none_loc)
- DEF( put_loc3, 1, 1, 0, none_loc)
- DEF( set_loc0, 1, 1, 1, none_loc)
- DEF( set_loc1, 1, 1, 1, none_loc)
- DEF( set_loc2, 1, 1, 1, none_loc)
- DEF( set_loc3, 1, 1, 1, none_loc)
- DEF( get_arg0, 1, 0, 1, none_arg)
- DEF( get_arg1, 1, 0, 1, none_arg)
- DEF( get_arg2, 1, 0, 1, none_arg)
- DEF( get_arg3, 1, 0, 1, none_arg)
- DEF( put_arg0, 1, 1, 0, none_arg)
- DEF( put_arg1, 1, 1, 0, none_arg)
- DEF( put_arg2, 1, 1, 0, none_arg)
- DEF( put_arg3, 1, 1, 0, none_arg)
- DEF( set_arg0, 1, 1, 1, none_arg)
- DEF( set_arg1, 1, 1, 1, none_arg)
- DEF( set_arg2, 1, 1, 1, none_arg)
- DEF( set_arg3, 1, 1, 1, none_arg)
- DEF( get_var_ref0, 1, 0, 1, none_var_ref)
- DEF( get_var_ref1, 1, 0, 1, none_var_ref)
- DEF( get_var_ref2, 1, 0, 1, none_var_ref)
- DEF( get_var_ref3, 1, 0, 1, none_var_ref)
- DEF( put_var_ref0, 1, 1, 0, none_var_ref)
- DEF( put_var_ref1, 1, 1, 0, none_var_ref)
- DEF( put_var_ref2, 1, 1, 0, none_var_ref)
- DEF( put_var_ref3, 1, 1, 0, none_var_ref)
- DEF( set_var_ref0, 1, 1, 1, none_var_ref)
- DEF( set_var_ref1, 1, 1, 1, none_var_ref)
- DEF( set_var_ref2, 1, 1, 1, none_var_ref)
- DEF( set_var_ref3, 1, 1, 1, none_var_ref)
- DEF( get_length, 1, 1, 1, none)
- DEF( if_false8, 2, 1, 0, label8)
- DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */
- DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */
- DEF( goto16, 3, 0, 0, label16)
- DEF( call0, 1, 1, 1, npopx)
- DEF( call1, 1, 1, 1, npopx)
- DEF( call2, 1, 1, 1, npopx)
- DEF( call3, 1, 1, 1, npopx)
- DEF( is_undefined, 1, 1, 1, none)
- DEF( is_null, 1, 1, 1, none)
- DEF(typeof_is_undefined, 1, 1, 1, none)
- DEF( typeof_is_function, 1, 1, 1, none)
- #undef DEF
- #undef def
- #endif /* DEF */
- [ OP_COUNT ... 255 ] = &&case_default
- };
- #define SWITCH(pc) DUMP_BYTECODE_OR_DONT(pc) __extension__ ({ goto *dispatch_table[opcode = *pc++]; });
- #define CASE(op) case_ ## op
- #define DEFAULT case_default
- #define BREAK SWITCH(pc)
- #endif
- if (js_poll_interrupts(caller_ctx))
- return JS_EXCEPTION;
- if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) {
- if (flags & JS_CALL_FLAG_GENERATOR) {
- JSAsyncFunctionState *s = JS_VALUE_GET_PTR(func_obj);
- /* func_obj get contains a pointer to JSFuncAsyncState */
- /* the stack frame is already allocated */
- sf = &s->frame;
- p = JS_VALUE_GET_OBJ(sf->cur_func);
- b = p->u.func.function_bytecode;
- ctx = b->realm;
- var_refs = p->u.func.var_refs;
- local_buf = arg_buf = sf->arg_buf;
- var_buf = sf->var_buf;
- stack_buf = sf->var_buf + b->var_count;
- sp = sf->cur_sp;
- sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */
- pc = sf->cur_pc;
- sf->prev_frame = rt->current_stack_frame;
- rt->current_stack_frame = sf;
- if (s->throw_flag)
- goto exception;
- else
- goto restart;
- } else {
- goto not_a_function;
- }
- }
- p = JS_VALUE_GET_OBJ(func_obj);
- if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
- JSClassCall *call_func;
- call_func = rt->class_array[p->class_id].call;
- if (!call_func) {
- not_a_function:
- return JS_ThrowTypeErrorNotAFunction(caller_ctx);
- }
- return call_func(caller_ctx, func_obj, this_obj, argc,
- argv, flags);
- }
- b = p->u.func.function_bytecode;
- if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) {
- arg_allocated_size = b->arg_count;
- } else {
- arg_allocated_size = 0;
- }
- alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count +
- b->stack_size);
- if (js_check_stack_overflow(rt, alloca_size))
- return JS_ThrowStackOverflow(caller_ctx);
- sf->is_strict_mode = b->is_strict_mode;
- arg_buf = (JSValue *)argv;
- sf->arg_count = argc;
- sf->cur_func = unsafe_unconst(func_obj);
- init_list_head(&sf->var_ref_list);
- var_refs = p->u.func.var_refs;
- local_buf = alloca(alloca_size);
- if (unlikely(arg_allocated_size)) {
- int n = min_int(argc, b->arg_count);
- arg_buf = local_buf;
- for(i = 0; i < n; i++)
- arg_buf[i] = js_dup(argv[i]);
- for(; i < b->arg_count; i++)
- arg_buf[i] = JS_UNDEFINED;
- sf->arg_count = b->arg_count;
- }
- var_buf = local_buf + arg_allocated_size;
- sf->var_buf = var_buf;
- sf->arg_buf = arg_buf;
- for(i = 0; i < b->var_count; i++)
- var_buf[i] = JS_UNDEFINED;
- stack_buf = var_buf + b->var_count;
- sp = stack_buf;
- pc = b->byte_code_buf;
- /* sf->cur_pc must we set to pc before any recursive calls to JS_CallInternal. */
- sf->cur_pc = NULL;
- sf->prev_frame = rt->current_stack_frame;
- rt->current_stack_frame = sf;
- ctx = b->realm; /* set the current realm */
- #ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_STEP
- if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_STEP))
- print_func_name(b);
- #endif
- restart:
- for(;;) {
- int call_argc;
- JSValue *call_argv;
- SWITCH(pc) {
- CASE(OP_push_i32):
- *sp++ = js_int32(get_u32(pc));
- pc += 4;
- BREAK;
- CASE(OP_push_bigint_i32):
- *sp++ = __JS_NewShortBigInt(ctx, (int)get_u32(pc));
- pc += 4;
- BREAK;
- CASE(OP_push_const):
- *sp++ = js_dup(b->cpool[get_u32(pc)]);
- pc += 4;
- BREAK;
- CASE(OP_push_minus1):
- CASE(OP_push_0):
- CASE(OP_push_1):
- CASE(OP_push_2):
- CASE(OP_push_3):
- CASE(OP_push_4):
- CASE(OP_push_5):
- CASE(OP_push_6):
- CASE(OP_push_7):
- *sp++ = js_int32(opcode - OP_push_0);
- BREAK;
- CASE(OP_push_i8):
- *sp++ = js_int32(get_i8(pc));
- pc += 1;
- BREAK;
- CASE(OP_push_i16):
- *sp++ = js_int32(get_i16(pc));
- pc += 2;
- BREAK;
- CASE(OP_push_const8):
- *sp++ = js_dup(b->cpool[*pc++]);
- BREAK;
- CASE(OP_fclosure8):
- *sp++ = js_closure(ctx, js_dup(b->cpool[*pc++]), var_refs, sf);
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
- BREAK;
- CASE(OP_push_empty_string):
- *sp++ = js_empty_string(rt);
- BREAK;
- CASE(OP_get_length):
- {
- JSValue val;
- sf->cur_pc = pc;
- val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length);
- if (unlikely(JS_IsException(val)))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = val;
- }
- BREAK;
- CASE(OP_push_atom_value):
- *sp++ = JS_AtomToValue(ctx, get_u32(pc));
- pc += 4;
- BREAK;
- CASE(OP_undefined):
- *sp++ = JS_UNDEFINED;
- BREAK;
- CASE(OP_null):
- *sp++ = JS_NULL;
- BREAK;
- CASE(OP_push_this):
- /* OP_push_this is only called at the start of a function */
- {
- JSValue val;
- if (!b->is_strict_mode) {
- uint32_t tag = JS_VALUE_GET_TAG(this_obj);
- if (likely(tag == JS_TAG_OBJECT))
- goto normal_this;
- if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) {
- val = js_dup(ctx->global_obj);
- } else {
- val = JS_ToObject(ctx, this_obj);
- if (JS_IsException(val))
- goto exception;
- }
- } else {
- normal_this:
- val = js_dup(this_obj);
- }
- *sp++ = val;
- }
- BREAK;
- CASE(OP_push_false):
- *sp++ = JS_FALSE;
- BREAK;
- CASE(OP_push_true):
- *sp++ = JS_TRUE;
- BREAK;
- CASE(OP_object):
- *sp++ = JS_NewObject(ctx);
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
- BREAK;
- CASE(OP_special_object):
- {
- int arg = *pc++;
- switch(arg) {
- case OP_SPECIAL_OBJECT_ARGUMENTS:
- *sp++ = js_build_arguments(ctx, argc, argv);
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
- break;
- case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS:
- *sp++ = js_build_mapped_arguments(ctx, argc, argv,
- sf, min_int(argc, b->arg_count));
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
- break;
- case OP_SPECIAL_OBJECT_THIS_FUNC:
- *sp++ = js_dup(sf->cur_func);
- break;
- case OP_SPECIAL_OBJECT_NEW_TARGET:
- *sp++ = js_dup(new_target);
- break;
- case OP_SPECIAL_OBJECT_HOME_OBJECT:
- {
- JSObject *p1;
- p1 = p->u.func.home_object;
- if (unlikely(!p1))
- *sp++ = JS_UNDEFINED;
- else
- *sp++ = js_dup(JS_MKPTR(JS_TAG_OBJECT, p1));
- }
- break;
- case OP_SPECIAL_OBJECT_VAR_OBJECT:
- *sp++ = JS_NewObjectProto(ctx, JS_NULL);
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
- break;
- case OP_SPECIAL_OBJECT_IMPORT_META:
- *sp++ = js_import_meta(ctx);
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
- break;
- case OP_SPECIAL_OBJECT_NULL_PROTO:
- *sp++ = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_OBJECT);
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
- break;
- default:
- abort();
- }
- }
- BREAK;
- CASE(OP_rest):
- {
- int i, n, first = get_u16(pc);
- pc += 2;
- i = min_int(first, argc);
- n = argc - i;
- *sp++ = js_create_array(ctx, n, &argv[i]);
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
- }
- BREAK;
- CASE(OP_drop):
- JS_FreeValue(ctx, sp[-1]);
- sp--;
- BREAK;
- CASE(OP_nip):
- JS_FreeValue(ctx, sp[-2]);
- sp[-2] = sp[-1];
- sp--;
- BREAK;
- CASE(OP_nip1): /* a b c -> b c */
- JS_FreeValue(ctx, sp[-3]);
- sp[-3] = sp[-2];
- sp[-2] = sp[-1];
- sp--;
- BREAK;
- CASE(OP_dup):
- sp[0] = js_dup(sp[-1]);
- sp++;
- BREAK;
- CASE(OP_dup2): /* a b -> a b a b */
- sp[0] = js_dup(sp[-2]);
- sp[1] = js_dup(sp[-1]);
- sp += 2;
- BREAK;
- CASE(OP_dup3): /* a b c -> a b c a b c */
- sp[0] = js_dup(sp[-3]);
- sp[1] = js_dup(sp[-2]);
- sp[2] = js_dup(sp[-1]);
- sp += 3;
- BREAK;
- CASE(OP_dup1): /* a b -> a a b */
- sp[0] = sp[-1];
- sp[-1] = js_dup(sp[-2]);
- sp++;
- BREAK;
- CASE(OP_insert2): /* obj a -> a obj a (dup_x1) */
- sp[0] = sp[-1];
- sp[-1] = sp[-2];
- sp[-2] = js_dup(sp[0]);
- sp++;
- BREAK;
- CASE(OP_insert3): /* obj prop a -> a obj prop a (dup_x2) */
- sp[0] = sp[-1];
- sp[-1] = sp[-2];
- sp[-2] = sp[-3];
- sp[-3] = js_dup(sp[0]);
- sp++;
- BREAK;
- CASE(OP_insert4): /* this obj prop a -> a this obj prop a */
- sp[0] = sp[-1];
- sp[-1] = sp[-2];
- sp[-2] = sp[-3];
- sp[-3] = sp[-4];
- sp[-4] = js_dup(sp[0]);
- sp++;
- BREAK;
- CASE(OP_perm3): /* obj a b -> a obj b (213) */
- {
- JSValue tmp;
- tmp = sp[-2];
- sp[-2] = sp[-3];
- sp[-3] = tmp;
- }
- BREAK;
- CASE(OP_rot3l): /* x a b -> a b x (231) */
- {
- JSValue tmp;
- tmp = sp[-3];
- sp[-3] = sp[-2];
- sp[-2] = sp[-1];
- sp[-1] = tmp;
- }
- BREAK;
- CASE(OP_rot4l): /* x a b c -> a b c x */
- {
- JSValue tmp;
- tmp = sp[-4];
- sp[-4] = sp[-3];
- sp[-3] = sp[-2];
- sp[-2] = sp[-1];
- sp[-1] = tmp;
- }
- BREAK;
- CASE(OP_rot5l): /* x a b c d -> a b c d x */
- {
- JSValue tmp;
- tmp = sp[-5];
- sp[-5] = sp[-4];
- sp[-4] = sp[-3];
- sp[-3] = sp[-2];
- sp[-2] = sp[-1];
- sp[-1] = tmp;
- }
- BREAK;
- CASE(OP_rot3r): /* a b x -> x a b (312) */
- {
- JSValue tmp;
- tmp = sp[-1];
- sp[-1] = sp[-2];
- sp[-2] = sp[-3];
- sp[-3] = tmp;
- }
- BREAK;
- CASE(OP_perm4): /* obj prop a b -> a obj prop b */
- {
- JSValue tmp;
- tmp = sp[-2];
- sp[-2] = sp[-3];
- sp[-3] = sp[-4];
- sp[-4] = tmp;
- }
- BREAK;
- CASE(OP_perm5): /* this obj prop a b -> a this obj prop b */
- {
- JSValue tmp;
- tmp = sp[-2];
- sp[-2] = sp[-3];
- sp[-3] = sp[-4];
- sp[-4] = sp[-5];
- sp[-5] = tmp;
- }
- BREAK;
- CASE(OP_swap): /* a b -> b a */
- {
- JSValue tmp;
- tmp = sp[-2];
- sp[-2] = sp[-1];
- sp[-1] = tmp;
- }
- BREAK;
- CASE(OP_swap2): /* a b c d -> c d a b */
- {
- JSValue tmp1, tmp2;
- tmp1 = sp[-4];
- tmp2 = sp[-3];
- sp[-4] = sp[-2];
- sp[-3] = sp[-1];
- sp[-2] = tmp1;
- sp[-1] = tmp2;
- }
- BREAK;
- CASE(OP_fclosure):
- {
- JSValue bfunc = js_dup(b->cpool[get_u32(pc)]);
- pc += 4;
- *sp++ = js_closure(ctx, bfunc, var_refs, sf);
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
- }
- BREAK;
- CASE(OP_call0):
- CASE(OP_call1):
- CASE(OP_call2):
- CASE(OP_call3):
- call_argc = opcode - OP_call0;
- goto has_call_argc;
- CASE(OP_call):
- CASE(OP_tail_call):
- {
- call_argc = get_u16(pc);
- pc += 2;
- goto has_call_argc;
- has_call_argc:
- call_argv = sp - call_argc;
- sf->cur_pc = pc;
- ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
- JS_UNDEFINED, call_argc,
- vc(call_argv), 0);
- if (unlikely(JS_IsException(ret_val)))
- goto exception;
- if (opcode == OP_tail_call)
- goto done;
- for(i = -1; i < call_argc; i++)
- JS_FreeValue(ctx, call_argv[i]);
- sp -= call_argc + 1;
- *sp++ = ret_val;
- }
- BREAK;
- CASE(OP_call_constructor):
- {
- call_argc = get_u16(pc);
- pc += 2;
- call_argv = sp - call_argc;
- sf->cur_pc = pc;
- ret_val = JS_CallConstructorInternal(ctx, call_argv[-2],
- call_argv[-1], call_argc,
- vc(call_argv), 0);
- if (unlikely(JS_IsException(ret_val)))
- goto exception;
- for(i = -2; i < call_argc; i++)
- JS_FreeValue(ctx, call_argv[i]);
- sp -= call_argc + 2;
- *sp++ = ret_val;
- }
- BREAK;
- CASE(OP_call_method):
- CASE(OP_tail_call_method):
- {
- call_argc = get_u16(pc);
- pc += 2;
- call_argv = sp - call_argc;
- sf->cur_pc = pc;
- ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2],
- JS_UNDEFINED, call_argc,
- vc(call_argv), 0);
- if (unlikely(JS_IsException(ret_val)))
- goto exception;
- if (opcode == OP_tail_call_method)
- goto done;
- for(i = -2; i < call_argc; i++)
- JS_FreeValue(ctx, call_argv[i]);
- sp -= call_argc + 2;
- *sp++ = ret_val;
- }
- BREAK;
- CASE(OP_array_from):
- {
- call_argc = get_u16(pc);
- pc += 2;
- call_argv = sp - call_argc;
- ret_val = JS_NewArrayFrom(ctx, call_argc, call_argv);
- sp -= call_argc;
- if (unlikely(JS_IsException(ret_val)))
- goto exception;
- *sp++ = ret_val;
- }
- BREAK;
- CASE(OP_apply):
- {
- int magic;
- magic = get_u16(pc);
- pc += 2;
- sf->cur_pc = pc;
- ret_val = js_function_apply(ctx, sp[-3], 2, vc(&sp[-2]), magic);
- if (unlikely(JS_IsException(ret_val)))
- goto exception;
- JS_FreeValue(ctx, sp[-3]);
- JS_FreeValue(ctx, sp[-2]);
- JS_FreeValue(ctx, sp[-1]);
- sp -= 3;
- *sp++ = ret_val;
- }
- BREAK;
- CASE(OP_return):
- ret_val = *--sp;
- goto done;
- CASE(OP_return_undef):
- ret_val = JS_UNDEFINED;
- goto done;
- CASE(OP_check_ctor_return):
- /* return true if 'this' should be returned */
- if (!JS_IsObject(sp[-1])) {
- if (!JS_IsUndefined(sp[-1])) {
- JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined");
- goto exception;
- }
- sp[0] = JS_TRUE;
- } else {
- sp[0] = JS_FALSE;
- }
- sp++;
- BREAK;
- CASE(OP_check_ctor):
- if (JS_IsUndefined(new_target)) {
- non_ctor_call:
- JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'");
- goto exception;
- }
- BREAK;
- CASE(OP_init_ctor):
- {
- JSValue super, ret;
- sf->cur_pc = pc;
- if (JS_IsUndefined(new_target))
- goto non_ctor_call;
- super = JS_GetPrototype(ctx, func_obj);
- if (JS_IsException(super))
- goto exception;
- ret = JS_CallConstructor2(ctx, super, new_target, argc, argv);
- JS_FreeValue(ctx, super);
- if (JS_IsException(ret))
- goto exception;
- *sp++ = ret;
- }
- BREAK;
- CASE(OP_check_brand):
- {
- int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]);
- if (ret < 0)
- goto exception;
- if (!ret) {
- JS_ThrowTypeError(ctx, "invalid brand on object");
- goto exception;
- }
- }
- BREAK;
- CASE(OP_add_brand):
- if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0)
- goto exception;
- JS_FreeValue(ctx, sp[-2]);
- JS_FreeValue(ctx, sp[-1]);
- sp -= 2;
- BREAK;
- CASE(OP_throw):
- JS_Throw(ctx, *--sp);
- goto exception;
- CASE(OP_throw_error):
- #define JS_THROW_VAR_RO 0
- #define JS_THROW_VAR_REDECL 1
- #define JS_THROW_VAR_UNINITIALIZED 2
- #define JS_THROW_ERROR_DELETE_SUPER 3
- #define JS_THROW_ERROR_ITERATOR_THROW 4
- {
- JSAtom atom;
- int type;
- atom = get_u32(pc);
- type = pc[4];
- pc += 5;
- if (type == JS_THROW_VAR_RO)
- JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom);
- else
- if (type == JS_THROW_VAR_REDECL)
- JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom);
- else
- if (type == JS_THROW_VAR_UNINITIALIZED)
- JS_ThrowReferenceErrorUninitialized(ctx, atom);
- else
- if (type == JS_THROW_ERROR_DELETE_SUPER)
- JS_ThrowReferenceError(ctx, "unsupported reference to 'super'");
- else
- if (type == JS_THROW_ERROR_ITERATOR_THROW)
- JS_ThrowTypeError(ctx, "iterator does not have a throw method");
- else
- JS_ThrowInternalError(ctx, "invalid throw var type %d", type);
- }
- goto exception;
- CASE(OP_eval):
- {
- JSValue obj;
- int scope_idx;
- call_argc = get_u16(pc);
- scope_idx = get_u16(pc + 2) - 1;
- pc += 4;
- call_argv = sp - call_argc;
- sf->cur_pc = pc;
- if (js_same_value(ctx, call_argv[-1], ctx->eval_obj)) {
- if (call_argc >= 1)
- obj = call_argv[0];
- else
- obj = JS_UNDEFINED;
- ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
- JS_EVAL_TYPE_DIRECT, scope_idx);
- } else {
- ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
- JS_UNDEFINED, call_argc,
- vc(call_argv), 0);
- }
- if (unlikely(JS_IsException(ret_val)))
- goto exception;
- for(i = -1; i < call_argc; i++)
- JS_FreeValue(ctx, call_argv[i]);
- sp -= call_argc + 1;
- *sp++ = ret_val;
- }
- BREAK;
- /* could merge with OP_apply */
- CASE(OP_apply_eval):
- {
- int scope_idx;
- uint32_t len;
- JSValue *tab;
- JSValue obj;
- scope_idx = get_u16(pc) - 1;
- pc += 2;
- sf->cur_pc = pc;
- tab = build_arg_list(ctx, &len, sp[-1]);
- if (!tab)
- goto exception;
- if (js_same_value(ctx, sp[-2], ctx->eval_obj)) {
- if (len >= 1)
- obj = tab[0];
- else
- obj = JS_UNDEFINED;
- ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
- JS_EVAL_TYPE_DIRECT, scope_idx);
- } else {
- ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len, vc(tab));
- }
- free_arg_list(ctx, tab, len);
- if (unlikely(JS_IsException(ret_val)))
- goto exception;
- JS_FreeValue(ctx, sp[-2]);
- JS_FreeValue(ctx, sp[-1]);
- sp -= 2;
- *sp++ = ret_val;
- }
- BREAK;
- CASE(OP_regexp):
- {
- sp[-2] = js_regexp_constructor_internal(ctx, JS_UNDEFINED,
- sp[-2], sp[-1]);
- sp--;
- }
- BREAK;
- CASE(OP_get_super):
- {
- JSValue proto;
- proto = JS_GetPrototype(ctx, sp[-1]);
- if (JS_IsException(proto))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = proto;
- }
- BREAK;
- CASE(OP_import):
- {
- JSValue val;
- sf->cur_pc = pc;
- val = js_dynamic_import(ctx, sp[-1]);
- if (JS_IsException(val))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = val;
- }
- BREAK;
- CASE(OP_check_var):
- {
- int ret;
- JSAtom atom;
- atom = get_u32(pc);
- pc += 4;
- ret = JS_CheckGlobalVar(ctx, atom);
- if (ret < 0)
- goto exception;
- *sp++ = js_bool(ret);
- }
- BREAK;
- CASE(OP_get_var_undef):
- CASE(OP_get_var):
- {
- JSValue val;
- JSAtom atom;
- atom = get_u32(pc);
- pc += 4;
- sf->cur_pc = pc;
- val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef);
- if (unlikely(JS_IsException(val)))
- goto exception;
- *sp++ = val;
- }
- BREAK;
- CASE(OP_put_var):
- CASE(OP_put_var_init):
- {
- int ret;
- JSAtom atom;
- atom = get_u32(pc);
- pc += 4;
- sf->cur_pc = pc;
- ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var);
- sp--;
- if (unlikely(ret < 0))
- goto exception;
- }
- BREAK;
- CASE(OP_put_var_strict):
- {
- int ret;
- JSAtom atom;
- atom = get_u32(pc);
- pc += 4;
- sf->cur_pc = pc;
- /* sp[-2] is JS_TRUE or JS_FALSE */
- if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) {
- JS_ThrowReferenceErrorNotDefined(ctx, atom);
- goto exception;
- }
- ret = JS_SetGlobalVar(ctx, atom, sp[-1], 2);
- sp -= 2;
- if (unlikely(ret < 0))
- goto exception;
- }
- BREAK;
- CASE(OP_check_define_var):
- {
- JSAtom atom;
- int flags;
- atom = get_u32(pc);
- flags = pc[4];
- pc += 5;
- if (JS_CheckDefineGlobalVar(ctx, atom, flags))
- goto exception;
- }
- BREAK;
- CASE(OP_define_var):
- {
- JSAtom atom;
- int flags;
- atom = get_u32(pc);
- flags = pc[4];
- pc += 5;
- if (JS_DefineGlobalVar(ctx, atom, flags))
- goto exception;
- }
- BREAK;
- CASE(OP_define_func):
- {
- JSAtom atom;
- int flags;
- atom = get_u32(pc);
- flags = pc[4];
- pc += 5;
- if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp--;
- }
- BREAK;
- CASE(OP_get_loc):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- sp[0] = js_dup(var_buf[idx]);
- sp++;
- }
- BREAK;
- CASE(OP_put_loc):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- set_value(ctx, &var_buf[idx], sp[-1]);
- sp--;
- }
- BREAK;
- CASE(OP_set_loc):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- set_value(ctx, &var_buf[idx], js_dup(sp[-1]));
- }
- BREAK;
- CASE(OP_get_arg):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- sp[0] = js_dup(arg_buf[idx]);
- sp++;
- }
- BREAK;
- CASE(OP_put_arg):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- set_value(ctx, &arg_buf[idx], sp[-1]);
- sp--;
- }
- BREAK;
- CASE(OP_set_arg):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- set_value(ctx, &arg_buf[idx], js_dup(sp[-1]));
- }
- BREAK;
- CASE(OP_get_loc8): *sp++ = js_dup(var_buf[*pc++]); BREAK;
- CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK;
- CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], js_dup(sp[-1])); BREAK;
- // Observation: get_loc0 and get_loc1 are individually very
- // frequent opcodes _and_ they are very often paired together,
- // making them ideal candidates for opcode fusion.
- CASE(OP_get_loc0_loc1):
- *sp++ = js_dup(var_buf[0]);
- *sp++ = js_dup(var_buf[1]);
- BREAK;
- CASE(OP_get_loc0): *sp++ = js_dup(var_buf[0]); BREAK;
- CASE(OP_get_loc1): *sp++ = js_dup(var_buf[1]); BREAK;
- CASE(OP_get_loc2): *sp++ = js_dup(var_buf[2]); BREAK;
- CASE(OP_get_loc3): *sp++ = js_dup(var_buf[3]); BREAK;
- CASE(OP_put_loc0): set_value(ctx, &var_buf[0], *--sp); BREAK;
- CASE(OP_put_loc1): set_value(ctx, &var_buf[1], *--sp); BREAK;
- CASE(OP_put_loc2): set_value(ctx, &var_buf[2], *--sp); BREAK;
- CASE(OP_put_loc3): set_value(ctx, &var_buf[3], *--sp); BREAK;
- CASE(OP_set_loc0): set_value(ctx, &var_buf[0], js_dup(sp[-1])); BREAK;
- CASE(OP_set_loc1): set_value(ctx, &var_buf[1], js_dup(sp[-1])); BREAK;
- CASE(OP_set_loc2): set_value(ctx, &var_buf[2], js_dup(sp[-1])); BREAK;
- CASE(OP_set_loc3): set_value(ctx, &var_buf[3], js_dup(sp[-1])); BREAK;
- CASE(OP_get_arg0): *sp++ = js_dup(arg_buf[0]); BREAK;
- CASE(OP_get_arg1): *sp++ = js_dup(arg_buf[1]); BREAK;
- CASE(OP_get_arg2): *sp++ = js_dup(arg_buf[2]); BREAK;
- CASE(OP_get_arg3): *sp++ = js_dup(arg_buf[3]); BREAK;
- CASE(OP_put_arg0): set_value(ctx, &arg_buf[0], *--sp); BREAK;
- CASE(OP_put_arg1): set_value(ctx, &arg_buf[1], *--sp); BREAK;
- CASE(OP_put_arg2): set_value(ctx, &arg_buf[2], *--sp); BREAK;
- CASE(OP_put_arg3): set_value(ctx, &arg_buf[3], *--sp); BREAK;
- CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], js_dup(sp[-1])); BREAK;
- CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], js_dup(sp[-1])); BREAK;
- CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], js_dup(sp[-1])); BREAK;
- CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], js_dup(sp[-1])); BREAK;
- CASE(OP_get_var_ref0): *sp++ = js_dup(*var_refs[0]->pvalue); BREAK;
- CASE(OP_get_var_ref1): *sp++ = js_dup(*var_refs[1]->pvalue); BREAK;
- CASE(OP_get_var_ref2): *sp++ = js_dup(*var_refs[2]->pvalue); BREAK;
- CASE(OP_get_var_ref3): *sp++ = js_dup(*var_refs[3]->pvalue); BREAK;
- CASE(OP_put_var_ref0): set_value(ctx, var_refs[0]->pvalue, *--sp); BREAK;
- CASE(OP_put_var_ref1): set_value(ctx, var_refs[1]->pvalue, *--sp); BREAK;
- CASE(OP_put_var_ref2): set_value(ctx, var_refs[2]->pvalue, *--sp); BREAK;
- CASE(OP_put_var_ref3): set_value(ctx, var_refs[3]->pvalue, *--sp); BREAK;
- CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, js_dup(sp[-1])); BREAK;
- CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, js_dup(sp[-1])); BREAK;
- CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, js_dup(sp[-1])); BREAK;
- CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, js_dup(sp[-1])); BREAK;
- CASE(OP_get_var_ref):
- {
- int idx;
- JSValue val;
- idx = get_u16(pc);
- pc += 2;
- val = *var_refs[idx]->pvalue;
- sp[0] = js_dup(val);
- sp++;
- }
- BREAK;
- CASE(OP_put_var_ref):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
- sp--;
- }
- BREAK;
- CASE(OP_set_var_ref):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- set_value(ctx, var_refs[idx]->pvalue, js_dup(sp[-1]));
- }
- BREAK;
- CASE(OP_get_var_ref_check):
- {
- int idx;
- JSValue val;
- idx = get_u16(pc);
- pc += 2;
- val = *var_refs[idx]->pvalue;
- if (unlikely(JS_IsUninitialized(val))) {
- JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, true);
- goto exception;
- }
- sp[0] = js_dup(val);
- sp++;
- }
- BREAK;
- CASE(OP_put_var_ref_check):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) {
- JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, true);
- goto exception;
- }
- set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
- sp--;
- }
- BREAK;
- CASE(OP_put_var_ref_check_init):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) {
- JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, true);
- goto exception;
- }
- set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
- sp--;
- }
- BREAK;
- CASE(OP_set_loc_uninitialized):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- set_value(ctx, &var_buf[idx], JS_UNINITIALIZED);
- }
- BREAK;
- CASE(OP_get_loc_check):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
- JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx,
- false);
- goto exception;
- }
- sp[0] = js_dup(var_buf[idx]);
- sp++;
- }
- BREAK;
- CASE(OP_put_loc_check):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
- JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx,
- false);
- goto exception;
- }
- set_value(ctx, &var_buf[idx], sp[-1]);
- sp--;
- }
- BREAK;
- CASE(OP_put_loc_check_init):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- if (unlikely(!JS_IsUninitialized(var_buf[idx]))) {
- JS_ThrowReferenceError(caller_ctx,
- "'this' can be initialized only once");
- goto exception;
- }
- set_value(ctx, &var_buf[idx], sp[-1]);
- sp--;
- }
- BREAK;
- CASE(OP_close_loc):
- {
- int idx;
- idx = get_u16(pc);
- pc += 2;
- close_lexical_var(ctx, sf, idx);
- }
- BREAK;
- CASE(OP_make_loc_ref):
- CASE(OP_make_arg_ref):
- CASE(OP_make_var_ref_ref):
- {
- JSVarRef *var_ref;
- JSProperty *pr;
- JSAtom atom;
- int idx;
- atom = get_u32(pc);
- idx = get_u16(pc + 4);
- pc += 6;
- *sp++ = JS_NewObjectProto(ctx, JS_NULL);
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
- if (opcode == OP_make_var_ref_ref) {
- var_ref = var_refs[idx];
- var_ref->header.ref_count++;
- } else {
- var_ref = get_var_ref(ctx, sf, idx, opcode == OP_make_arg_ref);
- if (!var_ref)
- goto exception;
- }
- pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom,
- JS_PROP_WRITABLE | JS_PROP_VARREF);
- if (!pr) {
- free_var_ref(rt, var_ref);
- goto exception;
- }
- pr->u.var_ref = var_ref;
- *sp++ = JS_AtomToValue(ctx, atom);
- }
- BREAK;
- CASE(OP_make_var_ref):
- {
- JSAtom atom;
- atom = get_u32(pc);
- pc += 4;
- if (JS_GetGlobalVarRef(ctx, atom, sp))
- goto exception;
- sp += 2;
- }
- BREAK;
- CASE(OP_goto):
- pc += (int32_t)get_u32(pc);
- if (unlikely(js_poll_interrupts(ctx)))
- goto exception;
- BREAK;
- CASE(OP_goto16):
- pc += (int16_t)get_u16(pc);
- if (unlikely(js_poll_interrupts(ctx)))
- goto exception;
- BREAK;
- CASE(OP_goto8):
- pc += (int8_t)pc[0];
- if (unlikely(js_poll_interrupts(ctx)))
- goto exception;
- BREAK;
- CASE(OP_if_true):
- {
- int res;
- JSValue op1;
- op1 = sp[-1];
- pc += 4;
- if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
- res = JS_VALUE_GET_INT(op1);
- } else {
- res = JS_ToBoolFree(ctx, op1);
- }
- sp--;
- if (res) {
- pc += (int32_t)get_u32(pc - 4) - 4;
- }
- if (unlikely(js_poll_interrupts(ctx)))
- goto exception;
- }
- BREAK;
- CASE(OP_if_false):
- {
- int res;
- JSValue op1;
- op1 = sp[-1];
- pc += 4;
- if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
- res = JS_VALUE_GET_INT(op1);
- } else {
- res = JS_ToBoolFree(ctx, op1);
- }
- sp--;
- if (!res) {
- pc += (int32_t)get_u32(pc - 4) - 4;
- }
- if (unlikely(js_poll_interrupts(ctx)))
- goto exception;
- }
- BREAK;
- CASE(OP_if_true8):
- {
- int res;
- JSValue op1;
- op1 = sp[-1];
- pc += 1;
- if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
- res = JS_VALUE_GET_INT(op1);
- } else {
- res = JS_ToBoolFree(ctx, op1);
- }
- sp--;
- if (res) {
- pc += (int8_t)pc[-1] - 1;
- }
- if (unlikely(js_poll_interrupts(ctx)))
- goto exception;
- }
- BREAK;
- CASE(OP_if_false8):
- {
- int res;
- JSValue op1;
- op1 = sp[-1];
- pc += 1;
- if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
- res = JS_VALUE_GET_INT(op1);
- } else {
- res = JS_ToBoolFree(ctx, op1);
- }
- sp--;
- if (!res) {
- pc += (int8_t)pc[-1] - 1;
- }
- if (unlikely(js_poll_interrupts(ctx)))
- goto exception;
- }
- BREAK;
- CASE(OP_catch):
- {
- int32_t diff;
- diff = get_u32(pc);
- sp[0] = JS_NewCatchOffset(ctx, pc + diff - b->byte_code_buf);
- sp++;
- pc += 4;
- }
- BREAK;
- CASE(OP_gosub):
- {
- int32_t diff;
- diff = get_u32(pc);
- /* XXX: should have a different tag to avoid security flaw */
- sp[0] = js_int32(pc + 4 - b->byte_code_buf);
- sp++;
- pc += diff;
- }
- BREAK;
- CASE(OP_ret):
- {
- JSValue op1;
- uint32_t pos;
- op1 = sp[-1];
- if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_INT))
- goto ret_fail;
- pos = JS_VALUE_GET_INT(op1);
- if (unlikely(pos >= b->byte_code_len)) {
- ret_fail:
- JS_ThrowInternalError(ctx, "invalid ret value");
- goto exception;
- }
- sp--;
- pc = b->byte_code_buf + pos;
- }
- BREAK;
- CASE(OP_for_in_start):
- sf->cur_pc = pc;
- if (js_for_in_start(ctx, sp))
- goto exception;
- BREAK;
- CASE(OP_for_in_next):
- sf->cur_pc = pc;
- if (js_for_in_next(ctx, sp))
- goto exception;
- sp += 2;
- BREAK;
- CASE(OP_for_of_start):
- sf->cur_pc = pc;
- if (js_for_of_start(ctx, sp, false))
- goto exception;
- sp += 1;
- *sp++ = JS_NewCatchOffset(ctx, 0);
- BREAK;
- CASE(OP_for_of_next):
- {
- int offset = -3 - pc[0];
- pc += 1;
- sf->cur_pc = pc;
- if (js_for_of_next(ctx, sp, offset))
- goto exception;
- sp += 2;
- }
- BREAK;
- CASE(OP_for_await_of_start):
- sf->cur_pc = pc;
- if (js_for_of_start(ctx, sp, true))
- goto exception;
- sp += 1;
- *sp++ = JS_NewCatchOffset(ctx, 0);
- BREAK;
- CASE(OP_iterator_get_value_done):
- sf->cur_pc = pc;
- if (js_iterator_get_value_done(ctx, sp))
- goto exception;
- sp += 1;
- BREAK;
- CASE(OP_iterator_check_object):
- if (unlikely(!JS_IsObject(sp[-1]))) {
- JS_ThrowTypeError(ctx, "iterator must return an object");
- goto exception;
- }
- BREAK;
- CASE(OP_iterator_close):
- /* iter_obj next catch_offset -> */
- sp--; /* drop the catch offset to avoid getting caught by exception */
- JS_FreeValue(ctx, sp[-1]); /* drop the next method */
- sp--;
- if (!JS_IsUndefined(sp[-1])) {
- sf->cur_pc = pc;
- if (JS_IteratorClose(ctx, sp[-1], false))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- }
- sp--;
- BREAK;
- CASE(OP_nip_catch):
- {
- JSValue ret_val;
- /* catch_offset ... ret_val -> ret_eval */
- ret_val = *--sp;
- while (sp > stack_buf &&
- JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) {
- JS_FreeValue(ctx, *--sp);
- }
- if (unlikely(sp == stack_buf)) {
- JS_ThrowInternalError(ctx, "nip_catch");
- JS_FreeValue(ctx, ret_val);
- goto exception;
- }
- sp[-1] = ret_val;
- }
- BREAK;
- CASE(OP_iterator_next):
- /* stack: iter_obj next catch_offset val */
- {
- JSValue ret;
- sf->cur_pc = pc;
- ret = JS_Call(ctx, sp[-3], sp[-4], 1, vc(sp - 1));
- if (JS_IsException(ret))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = ret;
- }
- BREAK;
- CASE(OP_iterator_call):
- /* stack: iter_obj next catch_offset val */
- {
- JSValue method, ret;
- bool ret_flag;
- int flags;
- flags = *pc++;
- sf->cur_pc = pc;
- method = JS_GetProperty(ctx, sp[-4], (flags & 1) ?
- JS_ATOM_throw : JS_ATOM_return);
- if (JS_IsException(method))
- goto exception;
- if (JS_IsUndefined(method) || JS_IsNull(method)) {
- ret_flag = true;
- } else {
- if (flags & 2) {
- /* no argument */
- ret = JS_CallFree(ctx, method, sp[-4],
- 0, NULL);
- } else {
- ret = JS_CallFree(ctx, method, sp[-4],
- 1, vc(sp - 1));
- }
- if (JS_IsException(ret))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = ret;
- ret_flag = false;
- }
- sp[0] = js_bool(ret_flag);
- sp += 1;
- }
- BREAK;
- CASE(OP_lnot):
- {
- int res;
- JSValue op1;
- op1 = sp[-1];
- if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
- res = JS_VALUE_GET_INT(op1) != 0;
- } else {
- res = JS_ToBoolFree(ctx, op1);
- }
- sp[-1] = js_bool(!res);
- }
- BREAK;
- CASE(OP_get_field):
- {
- JSValue val;
- JSAtom atom;
- atom = get_u32(pc);
- pc += 4;
- sf->cur_pc = pc;
- val = JS_GetPropertyInternal(ctx, sp[-1], atom, sp[-1], false);
- if (unlikely(JS_IsException(val)))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = val;
- }
- BREAK;
- CASE(OP_get_field2):
- {
- JSValue val;
- JSAtom atom;
- atom = get_u32(pc);
- pc += 4;
- sf->cur_pc = pc;
- val = JS_GetPropertyInternal(ctx, sp[-1], atom, sp[-1], false);
- if (unlikely(JS_IsException(val)))
- goto exception;
- *sp++ = val;
- }
- BREAK;
- CASE(OP_put_field):
- {
- int ret;
- JSAtom atom;
- atom = get_u32(pc);
- pc += 4;
- sf->cur_pc = pc;
- ret = JS_SetPropertyInternal2(ctx,
- sp[-2], atom,
- sp[-1], sp[-2],
- JS_PROP_THROW_STRICT);
- JS_FreeValue(ctx, sp[-2]);
- sp -= 2;
- if (unlikely(ret < 0))
- goto exception;
- }
- BREAK;
- CASE(OP_private_symbol):
- {
- JSAtom atom;
- JSValue val;
- atom = get_u32(pc);
- pc += 4;
- val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE);
- if (JS_IsException(val))
- goto exception;
- *sp++ = val;
- }
- BREAK;
- CASE(OP_get_private_field):
- {
- JSValue val;
- sf->cur_pc = pc;
- val = JS_GetPrivateField(ctx, sp[-2], sp[-1]);
- JS_FreeValue(ctx, sp[-1]);
- JS_FreeValue(ctx, sp[-2]);
- sp[-2] = val;
- sp--;
- if (unlikely(JS_IsException(val)))
- goto exception;
- }
- BREAK;
- CASE(OP_put_private_field):
- {
- int ret;
- sf->cur_pc = pc;
- ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]);
- JS_FreeValue(ctx, sp[-3]);
- JS_FreeValue(ctx, sp[-1]);
- sp -= 3;
- if (unlikely(ret < 0))
- goto exception;
- }
- BREAK;
- CASE(OP_define_private_field):
- {
- int ret;
- ret = JS_DefinePrivateField(ctx, sp[-3], sp[-2], sp[-1]);
- JS_FreeValue(ctx, sp[-2]);
- sp -= 2;
- if (unlikely(ret < 0))
- goto exception;
- }
- BREAK;
- CASE(OP_define_field):
- {
- int ret;
- JSAtom atom;
- atom = get_u32(pc);
- pc += 4;
- ret = JS_DefinePropertyValue(ctx, sp[-2], atom, sp[-1],
- JS_PROP_C_W_E | JS_PROP_THROW);
- sp--;
- if (unlikely(ret < 0))
- goto exception;
- }
- BREAK;
- CASE(OP_set_name):
- {
- int ret;
- JSAtom atom;
- atom = get_u32(pc);
- pc += 4;
- ret = JS_DefineObjectName(ctx, sp[-1], atom, JS_PROP_CONFIGURABLE);
- if (unlikely(ret < 0))
- goto exception;
- }
- BREAK;
- CASE(OP_set_name_computed):
- {
- int ret;
- ret = JS_DefineObjectNameComputed(ctx, sp[-1], sp[-2], JS_PROP_CONFIGURABLE);
- if (unlikely(ret < 0))
- goto exception;
- }
- BREAK;
- CASE(OP_set_proto):
- {
- JSValue proto;
- proto = sp[-1];
- if (JS_IsObject(proto) || JS_IsNull(proto)) {
- if (JS_SetPrototypeInternal(ctx, sp[-2], proto, true) < 0)
- goto exception;
- }
- JS_FreeValue(ctx, proto);
- sp--;
- }
- BREAK;
- CASE(OP_set_home_object):
- js_method_set_home_object(ctx, sp[-1], sp[-2]);
- BREAK;
- CASE(OP_define_method):
- CASE(OP_define_method_computed):
- {
- JSValue getter, setter, value;
- JSValue obj;
- JSAtom atom;
- int flags, ret, op_flags;
- bool is_computed;
- #define OP_DEFINE_METHOD_METHOD 0
- #define OP_DEFINE_METHOD_GETTER 1
- #define OP_DEFINE_METHOD_SETTER 2
- #define OP_DEFINE_METHOD_ENUMERABLE 4
- is_computed = (opcode == OP_define_method_computed);
- if (is_computed) {
- atom = JS_ValueToAtom(ctx, sp[-2]);
- if (unlikely(atom == JS_ATOM_NULL))
- goto exception;
- opcode += OP_define_method - OP_define_method_computed;
- } else {
- atom = get_u32(pc);
- pc += 4;
- }
- op_flags = *pc++;
- obj = sp[-2 - is_computed];
- flags = JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE |
- JS_PROP_HAS_ENUMERABLE | JS_PROP_THROW;
- if (op_flags & OP_DEFINE_METHOD_ENUMERABLE)
- flags |= JS_PROP_ENUMERABLE;
- op_flags &= 3;
- value = JS_UNDEFINED;
- getter = JS_UNDEFINED;
- setter = JS_UNDEFINED;
- if (op_flags == OP_DEFINE_METHOD_METHOD) {
- value = sp[-1];
- flags |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE;
- } else if (op_flags == OP_DEFINE_METHOD_GETTER) {
- getter = sp[-1];
- flags |= JS_PROP_HAS_GET;
- } else {
- setter = sp[-1];
- flags |= JS_PROP_HAS_SET;
- }
- ret = js_method_set_properties(ctx, sp[-1], atom, flags, obj);
- if (ret >= 0) {
- ret = JS_DefineProperty(ctx, obj, atom, value,
- getter, setter, flags);
- }
- JS_FreeValue(ctx, sp[-1]);
- if (is_computed) {
- JS_FreeAtom(ctx, atom);
- JS_FreeValue(ctx, sp[-2]);
- }
- sp -= 1 + is_computed;
- if (unlikely(ret < 0))
- goto exception;
- }
- BREAK;
- CASE(OP_define_class):
- CASE(OP_define_class_computed):
- {
- int class_flags;
- JSAtom atom;
- atom = get_u32(pc);
- class_flags = pc[4];
- pc += 5;
- if (js_op_define_class(ctx, sp, atom, class_flags,
- var_refs, sf,
- (opcode == OP_define_class_computed)) < 0)
- goto exception;
- }
- BREAK;
- CASE(OP_get_array_el):
- {
- JSValue val;
- sf->cur_pc = pc;
- val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
- JS_FreeValue(ctx, sp[-2]);
- sp[-2] = val;
- sp--;
- if (unlikely(JS_IsException(val)))
- goto exception;
- }
- BREAK;
- CASE(OP_get_array_el2):
- {
- JSValue val;
- sf->cur_pc = pc;
- val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
- sp[-1] = val;
- if (unlikely(JS_IsException(val)))
- goto exception;
- }
- BREAK;
- CASE(OP_get_ref_value):
- {
- JSValue val;
- sf->cur_pc = pc;
- if (unlikely(JS_IsUndefined(sp[-2]))) {
- JSAtom atom = JS_ValueToAtom(ctx, sp[-1]);
- if (atom != JS_ATOM_NULL) {
- JS_ThrowReferenceErrorNotDefined(ctx, atom);
- JS_FreeAtom(ctx, atom);
- }
- goto exception;
- }
- val = JS_GetPropertyValue(ctx, sp[-2],
- js_dup(sp[-1]));
- if (unlikely(JS_IsException(val)))
- goto exception;
- sp[0] = val;
- sp++;
- }
- BREAK;
- CASE(OP_get_super_value):
- {
- JSValue val;
- JSAtom atom;
- sf->cur_pc = pc;
- atom = JS_ValueToAtom(ctx, sp[-1]);
- if (unlikely(atom == JS_ATOM_NULL))
- goto exception;
- val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], false);
- JS_FreeAtom(ctx, atom);
- if (unlikely(JS_IsException(val)))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- JS_FreeValue(ctx, sp[-2]);
- JS_FreeValue(ctx, sp[-3]);
- sp[-3] = val;
- sp -= 2;
- }
- BREAK;
- CASE(OP_put_array_el):
- {
- int ret;
- sf->cur_pc = pc;
- ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
- JS_FreeValue(ctx, sp[-3]);
- sp -= 3;
- if (unlikely(ret < 0))
- goto exception;
- }
- BREAK;
- CASE(OP_put_ref_value):
- {
- int ret, flags;
- sf->cur_pc = pc;
- flags = JS_PROP_THROW_STRICT;
- if (unlikely(JS_IsUndefined(sp[-3]))) {
- if (is_strict_mode(ctx)) {
- JSAtom atom = JS_ValueToAtom(ctx, sp[-2]);
- if (atom != JS_ATOM_NULL) {
- JS_ThrowReferenceErrorNotDefined(ctx, atom);
- JS_FreeAtom(ctx, atom);
- }
- goto exception;
- } else {
- sp[-3] = js_dup(ctx->global_obj);
- }
- } else {
- if (is_strict_mode(ctx))
- flags |= JS_PROP_NO_ADD;
- }
- ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], flags);
- JS_FreeValue(ctx, sp[-3]);
- sp -= 3;
- if (unlikely(ret < 0))
- goto exception;
- }
- BREAK;
- CASE(OP_put_super_value):
- {
- int ret;
- JSAtom atom;
- sf->cur_pc = pc;
- if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) {
- JS_ThrowTypeErrorNotAnObject(ctx);
- goto exception;
- }
- atom = JS_ValueToAtom(ctx, sp[-2]);
- if (unlikely(atom == JS_ATOM_NULL))
- goto exception;
- ret = JS_SetPropertyInternal2(ctx,
- sp[-3], atom,
- sp[-1], sp[-4],
- JS_PROP_THROW_STRICT);
- JS_FreeAtom(ctx, atom);
- JS_FreeValue(ctx, sp[-4]);
- JS_FreeValue(ctx, sp[-3]);
- JS_FreeValue(ctx, sp[-2]);
- sp -= 4;
- if (ret < 0)
- goto exception;
- }
- BREAK;
- CASE(OP_define_array_el):
- {
- int ret;
- ret = JS_DefinePropertyValueValue(ctx, sp[-3], js_dup(sp[-2]), sp[-1],
- JS_PROP_C_W_E | JS_PROP_THROW);
- sp -= 1;
- if (unlikely(ret < 0))
- goto exception;
- }
- BREAK;
- CASE(OP_append): /* array pos enumobj -- array pos */
- {
- sf->cur_pc = pc;
- if (js_append_enumerate(ctx, sp))
- goto exception;
- JS_FreeValue(ctx, *--sp);
- }
- BREAK;
- CASE(OP_copy_data_properties): /* target source excludeList */
- {
- /* stack offsets (-1 based):
- 2 bits for target,
- 3 bits for source,
- 2 bits for exclusionList */
- int mask;
- mask = *pc++;
- sf->cur_pc = pc;
- if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)],
- sp[-1 - ((mask >> 2) & 7)],
- sp[-1 - ((mask >> 5) & 7)], 0))
- goto exception;
- }
- BREAK;
- CASE(OP_add):
- {
- JSValue op1, op2;
- op1 = sp[-2];
- op2 = sp[-1];
- if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
- int64_t r;
- r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2);
- if (unlikely((int)r != r))
- goto add_slow;
- sp[-2] = js_int32(r);
- sp--;
- } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
- sp[-2] = js_float64(JS_VALUE_GET_FLOAT64(op1) +
- JS_VALUE_GET_FLOAT64(op2));
- sp--;
- } else {
- add_slow:
- sf->cur_pc = pc;
- if (js_add_slow(ctx, sp))
- goto exception;
- sp--;
- }
- }
- BREAK;
- CASE(OP_add_loc):
- {
- JSValue *pv;
- int idx;
- idx = *pc;
- pc += 1;
- pv = &var_buf[idx];
- if (likely(JS_VALUE_IS_BOTH_INT(*pv, sp[-1]))) {
- int64_t r;
- r = (int64_t)JS_VALUE_GET_INT(*pv) +
- JS_VALUE_GET_INT(sp[-1]);
- if (unlikely((int)r != r))
- goto add_loc_slow;
- *pv = js_int32(r);
- sp--;
- } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) {
- JSValue op1;
- op1 = sp[-1];
- sp--;
- sf->cur_pc = pc;
- op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
- if (JS_IsException(op1))
- goto exception;
- op1 = JS_ConcatString(ctx, js_dup(*pv), op1);
- if (JS_IsException(op1))
- goto exception;
- set_value(ctx, pv, op1);
- } else {
- JSValue ops[2];
- add_loc_slow:
- /* In case of exception, js_add_slow frees ops[0]
- and ops[1], so we must duplicate *pv */
- sf->cur_pc = pc;
- ops[0] = js_dup(*pv);
- ops[1] = sp[-1];
- sp--;
- if (js_add_slow(ctx, ops + 2))
- goto exception;
- set_value(ctx, pv, ops[0]);
- }
- }
- BREAK;
- CASE(OP_sub):
- {
- JSValue op1, op2;
- op1 = sp[-2];
- op2 = sp[-1];
- if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
- int64_t r;
- r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2);
- if (unlikely((int)r != r))
- goto binary_arith_slow;
- sp[-2] = js_int32(r);
- sp--;
- } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
- sp[-2] = js_float64(JS_VALUE_GET_FLOAT64(op1) -
- JS_VALUE_GET_FLOAT64(op2));
- sp--;
- } else {
- goto binary_arith_slow;
- }
- }
- BREAK;
- CASE(OP_mul):
- {
- JSValue op1, op2;
- double d;
- op1 = sp[-2];
- op2 = sp[-1];
- if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
- int32_t v1, v2;
- int64_t r;
- v1 = JS_VALUE_GET_INT(op1);
- v2 = JS_VALUE_GET_INT(op2);
- r = (int64_t)v1 * v2;
- if (unlikely((int)r != r)) {
- d = (double)r;
- goto mul_fp_res;
- }
- /* need to test zero case for -0 result */
- if (unlikely(r == 0 && (v1 | v2) < 0)) {
- d = -0.0;
- goto mul_fp_res;
- }
- sp[-2] = js_int32(r);
- sp--;
- } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
- d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);
- mul_fp_res:
- sp[-2] = js_float64(d);
- sp--;
- } else {
- goto binary_arith_slow;
- }
- }
- BREAK;
- CASE(OP_div):
- {
- JSValue op1, op2;
- op1 = sp[-2];
- op2 = sp[-1];
- if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
- int v1, v2;
- v1 = JS_VALUE_GET_INT(op1);
- v2 = JS_VALUE_GET_INT(op2);
- sp[-2] = js_number((double)v1 / (double)v2);
- sp--;
- } else {
- goto binary_arith_slow;
- }
- }
- BREAK;
- CASE(OP_mod):
- {
- JSValue op1, op2;
- op1 = sp[-2];
- op2 = sp[-1];
- if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
- int v1, v2, r;
- v1 = JS_VALUE_GET_INT(op1);
- v2 = JS_VALUE_GET_INT(op2);
- /* We must avoid v2 = 0, v1 = INT32_MIN and v2 =
- -1 and the cases where the result is -0. */
- if (unlikely(v1 < 0 || v2 <= 0))
- goto binary_arith_slow;
- r = v1 % v2;
- sp[-2] = js_int32(r);
- sp--;
- } else {
- goto binary_arith_slow;
- }
- }
- BREAK;
- CASE(OP_pow):
- binary_arith_slow:
- sf->cur_pc = pc;
- if (js_binary_arith_slow(ctx, sp, opcode))
- goto exception;
- sp--;
- BREAK;
- CASE(OP_plus):
- {
- JSValue op1;
- uint32_t tag;
- op1 = sp[-1];
- tag = JS_VALUE_GET_TAG(op1);
- if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) {
- } else {
- sf->cur_pc = pc;
- if (js_unary_arith_slow(ctx, sp, opcode))
- goto exception;
- }
- }
- BREAK;
- CASE(OP_neg):
- {
- JSValue op1;
- uint32_t tag;
- int val;
- double d;
- op1 = sp[-1];
- tag = JS_VALUE_GET_TAG(op1);
- if (tag == JS_TAG_INT) {
- val = JS_VALUE_GET_INT(op1);
- /* Note: -0 cannot be expressed as integer */
- if (unlikely(val == 0)) {
- d = -0.0;
- goto neg_fp_res;
- }
- if (unlikely(val == INT32_MIN)) {
- d = -(double)val;
- goto neg_fp_res;
- }
- sp[-1] = js_int32(-val);
- } else if (JS_TAG_IS_FLOAT64(tag)) {
- d = -JS_VALUE_GET_FLOAT64(op1);
- neg_fp_res:
- sp[-1] = js_float64(d);
- } else {
- sf->cur_pc = pc;
- if (js_unary_arith_slow(ctx, sp, opcode))
- goto exception;
- }
- }
- BREAK;
- CASE(OP_inc):
- {
- JSValue op1;
- int val;
- op1 = sp[-1];
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
- val = JS_VALUE_GET_INT(op1);
- if (unlikely(val == INT32_MAX))
- goto inc_slow;
- sp[-1] = js_int32(val + 1);
- } else {
- inc_slow:
- sf->cur_pc = pc;
- if (js_unary_arith_slow(ctx, sp, opcode))
- goto exception;
- }
- }
- BREAK;
- CASE(OP_dec):
- {
- JSValue op1;
- int val;
- op1 = sp[-1];
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
- val = JS_VALUE_GET_INT(op1);
- if (unlikely(val == INT32_MIN))
- goto dec_slow;
- sp[-1] = js_int32(val - 1);
- } else {
- dec_slow:
- sf->cur_pc = pc;
- if (js_unary_arith_slow(ctx, sp, opcode))
- goto exception;
- }
- }
- BREAK;
- CASE(OP_post_inc):
- CASE(OP_post_dec):
- sf->cur_pc = pc;
- if (js_post_inc_slow(ctx, sp, opcode))
- goto exception;
- sp++;
- BREAK;
- CASE(OP_inc_loc):
- {
- JSValue op1;
- int val;
- int idx;
- idx = *pc;
- pc += 1;
- op1 = var_buf[idx];
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
- val = JS_VALUE_GET_INT(op1);
- if (unlikely(val == INT32_MAX))
- goto inc_loc_slow;
- var_buf[idx] = js_int32(val + 1);
- } else {
- inc_loc_slow:
- sf->cur_pc = pc;
- /* must duplicate otherwise the variable value may
- be destroyed before JS code accesses it */
- op1 = js_dup(op1);
- if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc))
- goto exception;
- set_value(ctx, &var_buf[idx], op1);
- }
- }
- BREAK;
- CASE(OP_dec_loc):
- {
- JSValue op1;
- int val;
- int idx;
- idx = *pc;
- pc += 1;
- op1 = var_buf[idx];
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
- val = JS_VALUE_GET_INT(op1);
- if (unlikely(val == INT32_MIN))
- goto dec_loc_slow;
- var_buf[idx] = js_int32(val - 1);
- } else {
- dec_loc_slow:
- sf->cur_pc = pc;
- /* must duplicate otherwise the variable value may
- be destroyed before JS code accesses it */
- op1 = js_dup(op1);
- if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec))
- goto exception;
- set_value(ctx, &var_buf[idx], op1);
- }
- }
- BREAK;
- CASE(OP_not):
- {
- JSValue op1;
- op1 = sp[-1];
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
- sp[-1] = js_int32(~JS_VALUE_GET_INT(op1));
- } else {
- sf->cur_pc = pc;
- if (js_not_slow(ctx, sp))
- goto exception;
- }
- }
- BREAK;
- CASE(OP_shl):
- {
- JSValue op1, op2;
- op1 = sp[-2];
- op2 = sp[-1];
- if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
- uint32_t v1, v2;
- v1 = JS_VALUE_GET_INT(op1);
- v2 = JS_VALUE_GET_INT(op2) & 0x1f;
- sp[-2] = js_int32(v1 << v2);
- sp--;
- } else {
- sf->cur_pc = pc;
- if (js_binary_logic_slow(ctx, sp, opcode))
- goto exception;
- sp--;
- }
- }
- BREAK;
- CASE(OP_shr):
- {
- JSValue op1, op2;
- op1 = sp[-2];
- op2 = sp[-1];
- if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
- uint32_t v2;
- v2 = JS_VALUE_GET_INT(op2);
- v2 &= 0x1f;
- sp[-2] = js_uint32((uint32_t)JS_VALUE_GET_INT(op1) >> v2);
- sp--;
- } else {
- sf->cur_pc = pc;
- if (js_shr_slow(ctx, sp))
- goto exception;
- sp--;
- }
- }
- BREAK;
- CASE(OP_sar):
- {
- JSValue op1, op2;
- op1 = sp[-2];
- op2 = sp[-1];
- if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
- uint32_t v2;
- v2 = JS_VALUE_GET_INT(op2);
- if (unlikely(v2 > 0x1f)) {
- v2 &= 0x1f;
- }
- sp[-2] = js_int32((int)JS_VALUE_GET_INT(op1) >> v2);
- sp--;
- } else {
- sf->cur_pc = pc;
- if (js_binary_logic_slow(ctx, sp, opcode))
- goto exception;
- sp--;
- }
- }
- BREAK;
- CASE(OP_and):
- {
- JSValue op1, op2;
- op1 = sp[-2];
- op2 = sp[-1];
- if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
- sp[-2] = js_int32(JS_VALUE_GET_INT(op1) & JS_VALUE_GET_INT(op2));
- sp--;
- } else {
- sf->cur_pc = pc;
- if (js_binary_logic_slow(ctx, sp, opcode))
- goto exception;
- sp--;
- }
- }
- BREAK;
- CASE(OP_or):
- {
- JSValue op1, op2;
- op1 = sp[-2];
- op2 = sp[-1];
- if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
- sp[-2] = js_int32(JS_VALUE_GET_INT(op1) | JS_VALUE_GET_INT(op2));
- sp--;
- } else {
- sf->cur_pc = pc;
- if (js_binary_logic_slow(ctx, sp, opcode))
- goto exception;
- sp--;
- }
- }
- BREAK;
- CASE(OP_xor):
- {
- JSValue op1, op2;
- op1 = sp[-2];
- op2 = sp[-1];
- if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
- sp[-2] = js_int32(JS_VALUE_GET_INT(op1) ^ JS_VALUE_GET_INT(op2));
- sp--;
- } else {
- sf->cur_pc = pc;
- if (js_binary_logic_slow(ctx, sp, opcode))
- goto exception;
- sp--;
- }
- }
- BREAK;
- #define OP_CMP(opcode, binary_op, slow_call) \
- CASE(opcode): \
- { \
- JSValue op1, op2; \
- op1 = sp[-2]; \
- op2 = sp[-1]; \
- if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) { \
- sp[-2] = js_bool(JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \
- sp--; \
- } else { \
- sf->cur_pc = pc; \
- if (slow_call) \
- goto exception; \
- sp--; \
- } \
- } \
- BREAK
- OP_CMP(OP_lt, <, js_relational_slow(ctx, sp, opcode));
- OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode));
- OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode));
- OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode));
- OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0));
- OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1));
- OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0));
- OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1));
- CASE(OP_in):
- sf->cur_pc = pc;
- if (js_operator_in(ctx, sp))
- goto exception;
- sp--;
- BREAK;
- CASE(OP_private_in):
- if (js_operator_private_in(ctx, sp))
- goto exception;
- sp--;
- BREAK;
- CASE(OP_instanceof):
- sf->cur_pc = pc;
- if (js_operator_instanceof(ctx, sp))
- goto exception;
- sp--;
- BREAK;
- CASE(OP_typeof):
- {
- JSValue op1;
- JSAtom atom;
- op1 = sp[-1];
- atom = js_operator_typeof(ctx, op1);
- JS_FreeValue(ctx, op1);
- sp[-1] = JS_AtomToString(ctx, atom);
- }
- BREAK;
- CASE(OP_delete):
- sf->cur_pc = pc;
- if (js_operator_delete(ctx, sp))
- goto exception;
- sp--;
- BREAK;
- CASE(OP_delete_var):
- {
- JSAtom atom;
- int ret;
- atom = get_u32(pc);
- pc += 4;
- sf->cur_pc = pc;
- ret = JS_DeleteGlobalVar(ctx, atom);
- if (unlikely(ret < 0))
- goto exception;
- *sp++ = js_bool(ret);
- }
- BREAK;
- CASE(OP_to_object):
- if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) {
- sf->cur_pc = pc;
- ret_val = JS_ToObject(ctx, sp[-1]);
- if (JS_IsException(ret_val))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = ret_val;
- }
- BREAK;
- CASE(OP_to_propkey):
- switch (JS_VALUE_GET_TAG(sp[-1])) {
- case JS_TAG_INT:
- case JS_TAG_STRING:
- case JS_TAG_SYMBOL:
- break;
- default:
- sf->cur_pc = pc;
- ret_val = JS_ToPropertyKey(ctx, sp[-1]);
- if (JS_IsException(ret_val))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = ret_val;
- break;
- }
- BREAK;
- CASE(OP_to_propkey2):
- /* must be tested first */
- if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
- JS_ThrowTypeError(ctx, "value has no property");
- goto exception;
- }
- switch (JS_VALUE_GET_TAG(sp[-1])) {
- case JS_TAG_INT:
- case JS_TAG_STRING:
- case JS_TAG_SYMBOL:
- break;
- default:
- sf->cur_pc = pc;
- ret_val = JS_ToPropertyKey(ctx, sp[-1]);
- if (JS_IsException(ret_val))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = ret_val;
- break;
- }
- BREAK;
- CASE(OP_with_get_var):
- CASE(OP_with_put_var):
- CASE(OP_with_delete_var):
- CASE(OP_with_make_ref):
- CASE(OP_with_get_ref):
- CASE(OP_with_get_ref_undef):
- {
- JSAtom atom;
- int32_t diff;
- JSValue obj, val;
- int ret, is_with;
- atom = get_u32(pc);
- diff = get_u32(pc + 4);
- is_with = pc[8];
- pc += 9;
- sf->cur_pc = pc;
- obj = sp[-1];
- ret = JS_HasProperty(ctx, obj, atom);
- if (unlikely(ret < 0))
- goto exception;
- if (ret) {
- if (is_with) {
- ret = js_has_unscopable(ctx, obj, atom);
- if (unlikely(ret < 0))
- goto exception;
- if (ret)
- goto no_with;
- }
- switch (opcode) {
- case OP_with_get_var:
- val = JS_GetProperty(ctx, obj, atom);
- if (unlikely(JS_IsException(val)))
- goto exception;
- set_value(ctx, &sp[-1], val);
- break;
- case OP_with_put_var:
- /* XXX: check if strict mode */
- ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2],
- JS_PROP_THROW_STRICT);
- JS_FreeValue(ctx, sp[-1]);
- sp -= 2;
- if (unlikely(ret < 0))
- goto exception;
- break;
- case OP_with_delete_var:
- ret = JS_DeleteProperty(ctx, obj, atom, 0);
- if (unlikely(ret < 0))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = js_bool(ret);
- break;
- case OP_with_make_ref:
- /* produce a pair object/propname on the stack */
- *sp++ = JS_AtomToValue(ctx, atom);
- break;
- case OP_with_get_ref:
- /* produce a pair object/method on the stack */
- val = JS_GetProperty(ctx, obj, atom);
- if (unlikely(JS_IsException(val)))
- goto exception;
- *sp++ = val;
- break;
- case OP_with_get_ref_undef:
- /* produce a pair undefined/function on the stack */
- val = JS_GetProperty(ctx, obj, atom);
- if (unlikely(JS_IsException(val)))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = JS_UNDEFINED;
- *sp++ = val;
- break;
- }
- pc += diff - 5;
- } else {
- no_with:
- /* if not jumping, drop the object argument */
- JS_FreeValue(ctx, sp[-1]);
- sp--;
- }
- }
- BREAK;
- CASE(OP_await):
- ret_val = js_int32(FUNC_RET_AWAIT);
- goto done_generator;
- CASE(OP_yield):
- ret_val = js_int32(FUNC_RET_YIELD);
- goto done_generator;
- CASE(OP_yield_star):
- CASE(OP_async_yield_star):
- ret_val = js_int32(FUNC_RET_YIELD_STAR);
- goto done_generator;
- CASE(OP_return_async):
- CASE(OP_initial_yield):
- ret_val = JS_UNDEFINED;
- goto done_generator;
- CASE(OP_nop):
- BREAK;
- CASE(OP_is_undefined_or_null):
- if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED ||
- JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
- goto set_true;
- } else {
- goto free_and_set_false;
- }
- CASE(OP_is_undefined):
- if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) {
- goto set_true;
- } else {
- goto free_and_set_false;
- }
- CASE(OP_is_null):
- if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
- goto set_true;
- } else {
- goto free_and_set_false;
- }
- /* XXX: could merge to a single opcode */
- CASE(OP_typeof_is_undefined):
- /* different from OP_is_undefined because of isHTMLDDA */
- if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) {
- goto free_and_set_true;
- } else {
- goto free_and_set_false;
- }
- CASE(OP_typeof_is_function):
- if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) {
- goto free_and_set_true;
- } else {
- goto free_and_set_false;
- }
- free_and_set_true:
- JS_FreeValue(ctx, sp[-1]);
- set_true:
- sp[-1] = JS_TRUE;
- BREAK;
- free_and_set_false:
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = JS_FALSE;
- BREAK;
- CASE(OP_invalid):
- DEFAULT:
- JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x",
- (int)(pc - b->byte_code_buf - 1), opcode);
- goto exception;
- }
- }
- exception:
- if (needs_backtrace(rt->current_exception)
- || JS_IsUndefined(ctx->error_back_trace)) {
- sf->cur_pc = pc;
- build_backtrace(ctx, rt->current_exception, JS_UNDEFINED,
- NULL, 0, 0, 0);
- }
- if (!JS_IsUncatchableError(rt->current_exception)) {
- while (sp > stack_buf) {
- JSValue val = *--sp;
- JS_FreeValue(ctx, val);
- if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) {
- int pos = JS_VALUE_GET_INT(val);
- if (pos == 0) {
- /* enumerator: close it with a throw */
- JS_FreeValue(ctx, sp[-1]); /* drop the next method */
- sp--;
- JS_IteratorClose(ctx, sp[-1], true);
- } else {
- *sp++ = rt->current_exception;
- rt->current_exception = JS_UNINITIALIZED;
- JS_FreeValueRT(rt, ctx->error_back_trace);
- ctx->error_back_trace = JS_UNDEFINED;
- pc = b->byte_code_buf + pos;
- goto restart;
- }
- }
- }
- }
- ret_val = JS_EXCEPTION;
- /* the local variables are freed by the caller in the generator
- case. Hence the label 'done' should never be reached in a
- generator function. */
- if (b->func_kind != JS_FUNC_NORMAL) {
- done_generator:
- sf->cur_pc = pc;
- sf->cur_sp = sp;
- } else {
- done:
- if (unlikely(!list_empty(&sf->var_ref_list))) {
- /* variable references reference the stack: must close them */
- close_var_refs(rt, sf);
- }
- /* free the local variables and stack */
- for(pval = local_buf; pval < sp; pval++) {
- JS_FreeValue(ctx, *pval);
- }
- }
- rt->current_stack_frame = sf->prev_frame;
- return ret_val;
- }
- JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,
- int argc, JSValueConst *argv)
- {
- return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
- argc, argv, JS_CALL_FLAG_COPY_ARGV);
- }
- static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
- int argc, JSValueConst *argv)
- {
- JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
- argc, argv, JS_CALL_FLAG_COPY_ARGV);
- JS_FreeValue(ctx, func_obj);
- return res;
- }
- /* warning: the refcount of the context is not incremented. Return
- NULL in case of exception (case of revoked proxy only) */
- static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj)
- {
- JSObject *p;
- JSContext *realm;
- if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
- return ctx;
- p = JS_VALUE_GET_OBJ(func_obj);
- switch(p->class_id) {
- case JS_CLASS_C_FUNCTION:
- realm = p->u.cfunc.realm;
- break;
- case JS_CLASS_BYTECODE_FUNCTION:
- case JS_CLASS_GENERATOR_FUNCTION:
- case JS_CLASS_ASYNC_FUNCTION:
- case JS_CLASS_ASYNC_GENERATOR_FUNCTION:
- {
- JSFunctionBytecode *b;
- b = p->u.func.function_bytecode;
- realm = b->realm;
- }
- break;
- case JS_CLASS_PROXY:
- {
- JSProxyData *s = p->u.opaque;
- if (!s)
- return ctx;
- if (s->is_revoked) {
- JS_ThrowTypeErrorRevokedProxy(ctx);
- return NULL;
- } else {
- realm = JS_GetFunctionRealm(ctx, s->target);
- }
- }
- break;
- case JS_CLASS_BOUND_FUNCTION:
- {
- JSBoundFunction *bf = p->u.bound_function;
- realm = JS_GetFunctionRealm(ctx, bf->func_obj);
- }
- break;
- default:
- realm = ctx;
- break;
- }
- return realm;
- }
- static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,
- int class_id)
- {
- JSValue proto, obj;
- JSContext *realm;
- if (JS_IsUndefined(ctor)) {
- proto = js_dup(ctx->class_proto[class_id]);
- } else {
- proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
- if (JS_IsException(proto))
- return proto;
- if (!JS_IsObject(proto)) {
- JS_FreeValue(ctx, proto);
- realm = JS_GetFunctionRealm(ctx, ctor);
- if (!realm)
- return JS_EXCEPTION;
- proto = js_dup(realm->class_proto[class_id]);
- }
- }
- obj = JS_NewObjectProtoClass(ctx, proto, class_id);
- JS_FreeValue(ctx, proto);
- return obj;
- }
- /* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
- static JSValue JS_CallConstructorInternal(JSContext *ctx,
- JSValueConst func_obj,
- JSValueConst new_target,
- int argc, JSValueConst *argv,
- int flags)
- {
- JSObject *p;
- JSFunctionBytecode *b;
- if (js_poll_interrupts(ctx))
- return JS_EXCEPTION;
- flags |= JS_CALL_FLAG_CONSTRUCTOR;
- if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT))
- goto not_a_function;
- p = JS_VALUE_GET_OBJ(func_obj);
- if (unlikely(!p->is_constructor))
- return JS_ThrowTypeErrorNotAConstructor(ctx, func_obj);
- if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
- JSClassCall *call_func;
- call_func = ctx->rt->class_array[p->class_id].call;
- if (!call_func) {
- not_a_function:
- return JS_ThrowTypeErrorNotAFunction(ctx);
- }
- return call_func(ctx, func_obj, new_target, argc,
- argv, flags);
- }
- b = p->u.func.function_bytecode;
- if (b->is_derived_class_constructor) {
- return JS_CallInternal(ctx, func_obj, JS_UNDEFINED, new_target, argc, argv, flags);
- } else {
- JSValue obj, ret;
- /* legacy constructor behavior */
- obj = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- ret = JS_CallInternal(ctx, func_obj, obj, new_target, argc, argv, flags);
- if (JS_VALUE_GET_TAG(ret) == JS_TAG_OBJECT ||
- JS_IsException(ret)) {
- JS_FreeValue(ctx, obj);
- return ret;
- } else {
- JS_FreeValue(ctx, ret);
- return obj;
- }
- }
- }
- JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
- JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- return JS_CallConstructorInternal(ctx, func_obj, new_target,
- argc, argv,
- JS_CALL_FLAG_COPY_ARGV);
- }
- JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,
- int argc, JSValueConst *argv)
- {
- return JS_CallConstructorInternal(ctx, func_obj, func_obj,
- argc, argv,
- JS_CALL_FLAG_COPY_ARGV);
- }
- JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,
- int argc, JSValueConst *argv)
- {
- JSValue func_obj;
- func_obj = JS_GetProperty(ctx, this_val, atom);
- if (JS_IsException(func_obj))
- return func_obj;
- return JS_CallFree(ctx, func_obj, this_val, argc, argv);
- }
- static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
- int argc, JSValueConst *argv)
- {
- JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv);
- JS_FreeValue(ctx, this_val);
- return res;
- }
- /* JSAsyncFunctionState (used by generator and async functions) */
- static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
- JSValueConst func_obj,
- JSValueConst this_obj,
- int argc, JSValueConst *argv)
- {
- JSObject *p;
- JSFunctionBytecode *b;
- JSStackFrame *sf;
- int local_count, i, arg_buf_len, n;
- sf = &s->frame;
- init_list_head(&sf->var_ref_list);
- p = JS_VALUE_GET_OBJ(func_obj);
- b = p->u.func.function_bytecode;
- sf->is_strict_mode = b->is_strict_mode;
- sf->cur_pc = b->byte_code_buf;
- arg_buf_len = max_int(b->arg_count, argc);
- local_count = arg_buf_len + b->var_count + b->stack_size;
- sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1));
- if (!sf->arg_buf)
- return -1;
- sf->cur_func = js_dup(func_obj);
- s->this_val = js_dup(this_obj);
- s->argc = argc;
- sf->arg_count = arg_buf_len;
- sf->var_buf = sf->arg_buf + arg_buf_len;
- sf->cur_sp = sf->var_buf + b->var_count;
- for(i = 0; i < argc; i++)
- sf->arg_buf[i] = js_dup(argv[i]);
- n = arg_buf_len + b->var_count;
- for(i = argc; i < n; i++)
- sf->arg_buf[i] = JS_UNDEFINED;
- return 0;
- }
- static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
- JS_MarkFunc *mark_func)
- {
- JSStackFrame *sf;
- JSValue *sp;
- sf = &s->frame;
- JS_MarkValue(rt, sf->cur_func, mark_func);
- JS_MarkValue(rt, s->this_val, mark_func);
- if (sf->cur_sp) {
- /* if the function is running, cur_sp is not known so we
- cannot mark the stack. Marking the variables is not needed
- because a running function cannot be part of a removable
- cycle */
- for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)
- JS_MarkValue(rt, *sp, mark_func);
- }
- }
- static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
- {
- JSStackFrame *sf;
- JSValue *sp;
- sf = &s->frame;
- /* close the closure variables. */
- close_var_refs(rt, sf);
- if (sf->arg_buf) {
- /* cannot free the function if it is running */
- assert(sf->cur_sp != NULL);
- for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) {
- JS_FreeValueRT(rt, *sp);
- }
- js_free_rt(rt, sf->arg_buf);
- }
- JS_FreeValueRT(rt, sf->cur_func);
- JS_FreeValueRT(rt, s->this_val);
- }
- static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
- {
- JSValue func_obj;
- if (js_check_stack_overflow(ctx->rt, 0))
- return JS_ThrowStackOverflow(ctx);
- /* the tag does not matter provided it is not an object */
- func_obj = JS_MKPTR(JS_TAG_INT, s);
- return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
- s->argc, vc(s->frame.arg_buf),
- JS_CALL_FLAG_GENERATOR);
- }
- /* Generators */
- typedef enum JSGeneratorStateEnum {
- JS_GENERATOR_STATE_SUSPENDED_START,
- JS_GENERATOR_STATE_SUSPENDED_YIELD,
- JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
- JS_GENERATOR_STATE_EXECUTING,
- JS_GENERATOR_STATE_COMPLETED,
- } JSGeneratorStateEnum;
- typedef struct JSGeneratorData {
- JSGeneratorStateEnum state;
- JSAsyncFunctionState func_state;
- } JSGeneratorData;
- static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s)
- {
- if (s->state == JS_GENERATOR_STATE_COMPLETED)
- return;
- async_func_free(rt, &s->func_state);
- s->state = JS_GENERATOR_STATE_COMPLETED;
- }
- static void js_generator_finalizer(JSRuntime *rt, JSValueConst obj)
- {
- JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR);
- if (s) {
- free_generator_stack_rt(rt, s);
- js_free_rt(rt, s);
- }
- }
- static void free_generator_stack(JSContext *ctx, JSGeneratorData *s)
- {
- free_generator_stack_rt(ctx->rt, s);
- }
- static void js_generator_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSGeneratorData *s = p->u.generator_data;
- if (!s || s->state == JS_GENERATOR_STATE_COMPLETED)
- return;
- async_func_mark(rt, &s->func_state, mark_func);
- }
- /* XXX: use enum */
- #define GEN_MAGIC_NEXT 0
- #define GEN_MAGIC_RETURN 1
- #define GEN_MAGIC_THROW 2
- static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int *pdone, int magic)
- {
- JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR);
- JSStackFrame *sf;
- JSValue ret, func_ret;
- *pdone = true;
- if (!s)
- return JS_ThrowTypeError(ctx, "not a generator");
- sf = &s->func_state.frame;
- switch(s->state) {
- default:
- case JS_GENERATOR_STATE_SUSPENDED_START:
- if (magic == GEN_MAGIC_NEXT) {
- goto exec_no_arg;
- } else {
- free_generator_stack(ctx, s);
- goto done;
- }
- break;
- case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
- case JS_GENERATOR_STATE_SUSPENDED_YIELD:
- /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
- ret = js_dup(argv[0]);
- if (magic == GEN_MAGIC_THROW &&
- s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
- JS_Throw(ctx, ret);
- s->func_state.throw_flag = true;
- } else {
- sf->cur_sp[-1] = ret;
- sf->cur_sp[0] = js_int32(magic);
- sf->cur_sp++;
- exec_no_arg:
- s->func_state.throw_flag = false;
- }
- s->state = JS_GENERATOR_STATE_EXECUTING;
- func_ret = async_func_resume(ctx, &s->func_state);
- s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD;
- if (JS_IsException(func_ret)) {
- /* finalize the execution in case of exception */
- free_generator_stack(ctx, s);
- return func_ret;
- }
- if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
- /* get the returned yield value at the top of the stack */
- ret = sf->cur_sp[-1];
- sf->cur_sp[-1] = JS_UNDEFINED;
- if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {
- s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
- /* return (value, done) object */
- *pdone = 2;
- } else {
- *pdone = false;
- }
- } else {
- /* end of iterator */
- ret = sf->cur_sp[-1];
- sf->cur_sp[-1] = JS_UNDEFINED;
- JS_FreeValue(ctx, func_ret);
- free_generator_stack(ctx, s);
- }
- break;
- case JS_GENERATOR_STATE_COMPLETED:
- done:
- /* execution is finished */
- switch(magic) {
- default:
- case GEN_MAGIC_NEXT:
- ret = JS_UNDEFINED;
- break;
- case GEN_MAGIC_RETURN:
- ret = js_dup(argv[0]);
- break;
- case GEN_MAGIC_THROW:
- ret = JS_Throw(ctx, js_dup(argv[0]));
- break;
- }
- break;
- case JS_GENERATOR_STATE_EXECUTING:
- ret = JS_ThrowTypeError(ctx, "cannot invoke a running generator");
- break;
- }
- return ret;
- }
- static JSValue js_call_generator_function(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_obj,
- int argc, JSValueConst *argv,
- int flags)
- {
- JSValue obj, func_ret;
- JSGeneratorData *s;
- s = js_mallocz(ctx, sizeof(*s));
- if (!s)
- return JS_EXCEPTION;
- s->state = JS_GENERATOR_STATE_SUSPENDED_START;
- if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
- s->state = JS_GENERATOR_STATE_COMPLETED;
- goto fail;
- }
- /* execute the function up to 'OP_initial_yield' */
- func_ret = async_func_resume(ctx, &s->func_state);
- if (JS_IsException(func_ret))
- goto fail;
- JS_FreeValue(ctx, func_ret);
- obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR);
- if (JS_IsException(obj))
- goto fail;
- JS_SetOpaqueInternal(obj, s);
- return obj;
- fail:
- free_generator_stack_rt(ctx->rt, s);
- js_free(ctx, s);
- return JS_EXCEPTION;
- }
- /* AsyncFunction */
- static void js_async_function_terminate(JSRuntime *rt, JSAsyncFunctionData *s)
- {
- if (s->is_active) {
- async_func_free(rt, &s->func_state);
- s->is_active = false;
- }
- }
- static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s)
- {
- js_async_function_terminate(rt, s);
- JS_FreeValueRT(rt, s->resolving_funcs[0]);
- JS_FreeValueRT(rt, s->resolving_funcs[1]);
- remove_gc_object(&s->header);
- js_free_rt(rt, s);
- }
- static void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s)
- {
- if (--s->header.ref_count == 0) {
- js_async_function_free0(rt, s);
- }
- }
- static void js_async_function_resolve_finalizer(JSRuntime *rt,
- JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSAsyncFunctionData *s = p->u.async_function_data;
- if (s) {
- js_async_function_free(rt, s);
- }
- }
- static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSAsyncFunctionData *s = p->u.async_function_data;
- if (s) {
- mark_func(rt, &s->header);
- }
- }
- static int js_async_function_resolve_create(JSContext *ctx,
- JSAsyncFunctionData *s,
- JSValue *resolving_funcs)
- {
- int i;
- JSObject *p;
- for(i = 0; i < 2; i++) {
- resolving_funcs[i] =
- JS_NewObjectProtoClass(ctx, ctx->function_proto,
- JS_CLASS_ASYNC_FUNCTION_RESOLVE + i);
- if (JS_IsException(resolving_funcs[i])) {
- if (i == 1)
- JS_FreeValue(ctx, resolving_funcs[0]);
- return -1;
- }
- p = JS_VALUE_GET_OBJ(resolving_funcs[i]);
- s->header.ref_count++;
- p->u.async_function_data = s;
- }
- return 0;
- }
- static bool js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s)
- {
- bool is_success = true;
- JSValue func_ret, ret2;
- func_ret = async_func_resume(ctx, &s->func_state);
- if (JS_IsException(func_ret)) {
- fail:
- if (unlikely(JS_IsUncatchableError(ctx->rt->current_exception))) {
- is_success = false;
- } else {
- JSValue error = JS_GetException(ctx);
- ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,
- 1, vc(&error));
- JS_FreeValue(ctx, error);
- resolved:
- if (unlikely(JS_IsException(ret2))) {
- if (JS_IsUncatchableError(ctx->rt->current_exception)) {
- is_success = false;
- } else {
- abort(); /* BUG */
- }
- }
- JS_FreeValue(ctx, ret2);
- }
- js_async_function_terminate(ctx->rt, s);
- } else {
- JSValue value;
- value = s->func_state.frame.cur_sp[-1];
- s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
- if (JS_IsUndefined(func_ret)) {
- /* function returned */
- ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
- 1, vc(&value));
- JS_FreeValue(ctx, value);
- goto resolved;
- } else {
- JSValue promise, resolving_funcs[2], resolving_funcs1[2];
- int i, res;
- /* await */
- JS_FreeValue(ctx, func_ret); /* not used */
- promise = js_promise_resolve(ctx, ctx->promise_ctor,
- 1, vc(&value), 0);
- JS_FreeValue(ctx, value);
- if (JS_IsException(promise))
- goto fail;
- if (js_async_function_resolve_create(ctx, s, resolving_funcs)) {
- JS_FreeValue(ctx, promise);
- goto fail;
- }
- /* Note: no need to create 'thrownawayCapability' as in
- the spec */
- for(i = 0; i < 2; i++)
- resolving_funcs1[i] = JS_UNDEFINED;
- res = perform_promise_then(ctx, promise,
- vc(resolving_funcs),
- vc(resolving_funcs1));
- JS_FreeValue(ctx, promise);
- for(i = 0; i < 2; i++)
- JS_FreeValue(ctx, resolving_funcs[i]);
- if (res)
- goto fail;
- }
- }
- return is_success;
- }
- static JSValue js_async_function_resolve_call(JSContext *ctx,
- JSValueConst func_obj,
- JSValueConst this_obj,
- int argc, JSValueConst *argv,
- int flags)
- {
- JSObject *p = JS_VALUE_GET_OBJ(func_obj);
- JSAsyncFunctionData *s = p->u.async_function_data;
- bool is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE;
- JSValueConst arg;
- if (argc > 0)
- arg = argv[0];
- else
- arg = JS_UNDEFINED;
- s->func_state.throw_flag = is_reject;
- if (is_reject) {
- JS_Throw(ctx, js_dup(arg));
- } else {
- /* return value of await */
- s->func_state.frame.cur_sp[-1] = js_dup(arg);
- }
- if (!js_async_function_resume(ctx, s))
- return JS_EXCEPTION;
- return JS_UNDEFINED;
- }
- static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_obj,
- int argc, JSValueConst *argv, int flags)
- {
- JSValue promise;
- JSAsyncFunctionData *s;
- s = js_mallocz(ctx, sizeof(*s));
- if (!s)
- return JS_EXCEPTION;
- s->header.ref_count = 1;
- add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
- s->is_active = false;
- s->resolving_funcs[0] = JS_UNDEFINED;
- s->resolving_funcs[1] = JS_UNDEFINED;
- promise = JS_NewPromiseCapability(ctx, s->resolving_funcs);
- if (JS_IsException(promise))
- goto fail;
- if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
- fail:
- JS_FreeValue(ctx, promise);
- js_async_function_free(ctx->rt, s);
- return JS_EXCEPTION;
- }
- s->is_active = true;
- if (!js_async_function_resume(ctx, s))
- goto fail;
- js_async_function_free(ctx->rt, s);
- return promise;
- }
- /* AsyncGenerator */
- typedef enum JSAsyncGeneratorStateEnum {
- JS_ASYNC_GENERATOR_STATE_SUSPENDED_START,
- JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD,
- JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
- JS_ASYNC_GENERATOR_STATE_EXECUTING,
- JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN,
- JS_ASYNC_GENERATOR_STATE_COMPLETED,
- } JSAsyncGeneratorStateEnum;
- typedef struct JSAsyncGeneratorRequest {
- struct list_head link;
- /* completion */
- int completion_type; /* GEN_MAGIC_x */
- JSValue result;
- /* promise capability */
- JSValue promise;
- JSValue resolving_funcs[2];
- } JSAsyncGeneratorRequest;
- typedef struct JSAsyncGeneratorData {
- JSObject *generator; /* back pointer to the object (const) */
- JSAsyncGeneratorStateEnum state;
- JSAsyncFunctionState func_state;
- struct list_head queue; /* list of JSAsyncGeneratorRequest.link */
- } JSAsyncGeneratorData;
- static void js_async_generator_free(JSRuntime *rt,
- JSAsyncGeneratorData *s)
- {
- struct list_head *el, *el1;
- JSAsyncGeneratorRequest *req;
- list_for_each_safe(el, el1, &s->queue) {
- req = list_entry(el, JSAsyncGeneratorRequest, link);
- JS_FreeValueRT(rt, req->result);
- JS_FreeValueRT(rt, req->promise);
- JS_FreeValueRT(rt, req->resolving_funcs[0]);
- JS_FreeValueRT(rt, req->resolving_funcs[1]);
- js_free_rt(rt, req);
- }
- if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
- s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
- async_func_free(rt, &s->func_state);
- }
- js_free_rt(rt, s);
- }
- static void js_async_generator_finalizer(JSRuntime *rt, JSValueConst obj)
- {
- JSAsyncGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_ASYNC_GENERATOR);
- if (s) {
- js_async_generator_free(rt, s);
- }
- }
- static void js_async_generator_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR);
- struct list_head *el;
- JSAsyncGeneratorRequest *req;
- if (s) {
- list_for_each(el, &s->queue) {
- req = list_entry(el, JSAsyncGeneratorRequest, link);
- JS_MarkValue(rt, req->result, mark_func);
- JS_MarkValue(rt, req->promise, mark_func);
- JS_MarkValue(rt, req->resolving_funcs[0], mark_func);
- JS_MarkValue(rt, req->resolving_funcs[1], mark_func);
- }
- if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
- s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
- async_func_mark(rt, &s->func_state, mark_func);
- }
- }
- }
- static JSValue js_async_generator_resolve_function(JSContext *ctx,
- JSValueConst this_obj,
- int argc, JSValueConst *argv,
- int magic, JSValueConst *func_data);
- static int js_async_generator_resolve_function_create(JSContext *ctx,
- JSValue generator,
- JSValue *resolving_funcs,
- bool is_resume_next)
- {
- int i;
- JSValue func;
- for(i = 0; i < 2; i++) {
- func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1,
- i + is_resume_next * 2, 1, vc(&generator));
- if (JS_IsException(func)) {
- if (i == 1)
- JS_FreeValue(ctx, resolving_funcs[0]);
- return -1;
- }
- resolving_funcs[i] = func;
- }
- return 0;
- }
- static int js_async_generator_await(JSContext *ctx,
- JSAsyncGeneratorData *s,
- JSValue value)
- {
- JSValue promise, resolving_funcs[2], resolving_funcs1[2];
- int i, res;
- promise = js_promise_resolve(ctx, ctx->promise_ctor,
- 1, vc(&value), 0);
- if (JS_IsException(promise))
- goto fail;
- if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator),
- resolving_funcs, false)) {
- JS_FreeValue(ctx, promise);
- goto fail;
- }
- /* Note: no need to create 'thrownawayCapability' as in
- the spec */
- for(i = 0; i < 2; i++)
- resolving_funcs1[i] = JS_UNDEFINED;
- res = perform_promise_then(ctx, promise,
- vc(resolving_funcs),
- vc(resolving_funcs1));
- JS_FreeValue(ctx, promise);
- for(i = 0; i < 2; i++)
- JS_FreeValue(ctx, resolving_funcs[i]);
- if (res)
- goto fail;
- return 0;
- fail:
- return -1;
- }
- static void js_async_generator_resolve_or_reject(JSContext *ctx,
- JSAsyncGeneratorData *s,
- JSValueConst result,
- int is_reject)
- {
- JSAsyncGeneratorRequest *next;
- JSValue ret;
- next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
- list_del(&next->link);
- ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1,
- &result);
- JS_FreeValue(ctx, ret);
- JS_FreeValue(ctx, next->result);
- JS_FreeValue(ctx, next->promise);
- JS_FreeValue(ctx, next->resolving_funcs[0]);
- JS_FreeValue(ctx, next->resolving_funcs[1]);
- js_free(ctx, next);
- }
- static void js_async_generator_resolve(JSContext *ctx,
- JSAsyncGeneratorData *s,
- JSValueConst value,
- bool done)
- {
- JSValue result;
- result = js_create_iterator_result(ctx, js_dup(value), done);
- /* XXX: better exception handling ? */
- js_async_generator_resolve_or_reject(ctx, s, result, 0);
- JS_FreeValue(ctx, result);
- }
- static void js_async_generator_reject(JSContext *ctx,
- JSAsyncGeneratorData *s,
- JSValueConst exception)
- {
- js_async_generator_resolve_or_reject(ctx, s, exception, 1);
- }
- static void js_async_generator_complete(JSContext *ctx,
- JSAsyncGeneratorData *s)
- {
- if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) {
- s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
- async_func_free(ctx->rt, &s->func_state);
- }
- }
- static int js_async_generator_completed_return(JSContext *ctx,
- JSAsyncGeneratorData *s,
- JSValue value)
- {
- JSValue promise, resolving_funcs[2], resolving_funcs1[2];
- int res;
- // Can fail looking up JS_ATOM_constructor when is_reject==0.
- promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, vc(&value),
- /*is_reject*/0);
- // A poisoned .constructor property is observable and the resulting
- // exception should be delivered to the catch handler.
- if (JS_IsException(promise)) {
- JSValue err = JS_GetException(ctx);
- promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, vc(&err),
- /*is_reject*/1);
- JS_FreeValue(ctx, err);
- if (JS_IsException(promise))
- return -1;
- }
- if (js_async_generator_resolve_function_create(ctx,
- JS_MKPTR(JS_TAG_OBJECT, s->generator),
- resolving_funcs1,
- true)) {
- JS_FreeValue(ctx, promise);
- return -1;
- }
- resolving_funcs[0] = JS_UNDEFINED;
- resolving_funcs[1] = JS_UNDEFINED;
- res = perform_promise_then(ctx, promise,
- vc(resolving_funcs1),
- vc(resolving_funcs));
- JS_FreeValue(ctx, resolving_funcs1[0]);
- JS_FreeValue(ctx, resolving_funcs1[1]);
- JS_FreeValue(ctx, promise);
- return res;
- }
- static void js_async_generator_resume_next(JSContext *ctx,
- JSAsyncGeneratorData *s)
- {
- JSAsyncGeneratorRequest *next;
- JSValue func_ret, value;
- for(;;) {
- if (list_empty(&s->queue))
- break;
- next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
- switch(s->state) {
- case JS_ASYNC_GENERATOR_STATE_EXECUTING:
- /* only happens when restarting execution after await() */
- goto resume_exec;
- case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN:
- goto done;
- case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START:
- if (next->completion_type == GEN_MAGIC_NEXT) {
- goto exec_no_arg;
- } else {
- js_async_generator_complete(ctx, s);
- }
- break;
- case JS_ASYNC_GENERATOR_STATE_COMPLETED:
- if (next->completion_type == GEN_MAGIC_NEXT) {
- js_async_generator_resolve(ctx, s, JS_UNDEFINED, true);
- } else if (next->completion_type == GEN_MAGIC_RETURN) {
- s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN;
- js_async_generator_completed_return(ctx, s, next->result);
- } else {
- js_async_generator_reject(ctx, s, next->result);
- }
- goto done;
- case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD:
- case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
- value = js_dup(next->result);
- if (next->completion_type == GEN_MAGIC_THROW &&
- s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) {
- JS_Throw(ctx, value);
- s->func_state.throw_flag = true;
- } else {
- /* 'yield' returns a value. 'yield *' also returns a value
- in case the 'throw' method is called */
- s->func_state.frame.cur_sp[-1] = value;
- s->func_state.frame.cur_sp[0] =
- js_int32(next->completion_type);
- s->func_state.frame.cur_sp++;
- exec_no_arg:
- s->func_state.throw_flag = false;
- }
- s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING;
- resume_exec:
- func_ret = async_func_resume(ctx, &s->func_state);
- if (JS_IsException(func_ret)) {
- value = JS_GetException(ctx);
- js_async_generator_complete(ctx, s);
- js_async_generator_reject(ctx, s, value);
- JS_FreeValue(ctx, value);
- } else if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
- int func_ret_code, ret;
- value = s->func_state.frame.cur_sp[-1];
- s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
- func_ret_code = JS_VALUE_GET_INT(func_ret);
- switch(func_ret_code) {
- case FUNC_RET_YIELD:
- case FUNC_RET_YIELD_STAR:
- if (func_ret_code == FUNC_RET_YIELD_STAR)
- s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
- else
- s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD;
- js_async_generator_resolve(ctx, s, value, false);
- JS_FreeValue(ctx, value);
- break;
- case FUNC_RET_AWAIT:
- ret = js_async_generator_await(ctx, s, value);
- JS_FreeValue(ctx, value);
- if (ret < 0) {
- /* exception: throw it */
- s->func_state.throw_flag = true;
- goto resume_exec;
- }
- goto done;
- default:
- abort();
- }
- } else {
- assert(JS_IsUndefined(func_ret));
- /* end of function */
- value = s->func_state.frame.cur_sp[-1];
- s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
- js_async_generator_complete(ctx, s);
- js_async_generator_resolve(ctx, s, value, true);
- JS_FreeValue(ctx, value);
- }
- break;
- default:
- abort();
- }
- }
- done: ;
- }
- static JSValue js_async_generator_resolve_function(JSContext *ctx,
- JSValueConst this_obj,
- int argc, JSValueConst *argv,
- int magic, JSValueConst *func_data)
- {
- bool is_reject = magic & 1;
- JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR);
- JSValueConst arg = argv[0];
- /* XXX: what if s == NULL */
- if (magic >= 2) {
- /* resume next case in AWAITING_RETURN state */
- assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN ||
- s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED);
- s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
- if (is_reject) {
- js_async_generator_reject(ctx, s, arg);
- } else {
- js_async_generator_resolve(ctx, s, arg, true);
- }
- } else {
- /* restart function execution after await() */
- assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING);
- s->func_state.throw_flag = is_reject;
- if (is_reject) {
- JS_Throw(ctx, js_dup(arg));
- } else {
- /* return value of await */
- s->func_state.frame.cur_sp[-1] = js_dup(arg);
- }
- js_async_generator_resume_next(ctx, s);
- }
- return JS_UNDEFINED;
- }
- /* magic = GEN_MAGIC_x */
- static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int magic)
- {
- JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR);
- JSValue promise, resolving_funcs[2];
- JSAsyncGeneratorRequest *req;
- promise = JS_NewPromiseCapability(ctx, resolving_funcs);
- if (JS_IsException(promise))
- return JS_EXCEPTION;
- if (!s) {
- JSValue err, res2;
- JS_ThrowTypeError(ctx, "not an AsyncGenerator object");
- err = JS_GetException(ctx);
- res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
- 1, vc(&err));
- JS_FreeValue(ctx, err);
- JS_FreeValue(ctx, res2);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- return promise;
- }
- req = js_mallocz(ctx, sizeof(*req));
- if (!req)
- goto fail;
- req->completion_type = magic;
- req->result = js_dup(argv[0]);
- req->promise = js_dup(promise);
- req->resolving_funcs[0] = resolving_funcs[0];
- req->resolving_funcs[1] = resolving_funcs[1];
- list_add_tail(&req->link, &s->queue);
- if (s->state != JS_ASYNC_GENERATOR_STATE_EXECUTING) {
- js_async_generator_resume_next(ctx, s);
- }
- return promise;
- fail:
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- JS_FreeValue(ctx, promise);
- return JS_EXCEPTION;
- }
- static JSValue js_async_generator_function_call(JSContext *ctx,
- JSValueConst func_obj,
- JSValueConst this_obj,
- int argc, JSValueConst *argv,
- int flags)
- {
- JSValue obj, func_ret;
- JSAsyncGeneratorData *s;
- s = js_mallocz(ctx, sizeof(*s));
- if (!s)
- return JS_EXCEPTION;
- s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START;
- init_list_head(&s->queue);
- if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
- s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
- goto fail;
- }
- /* execute the function up to 'OP_initial_yield' (no yield nor
- await are possible) */
- func_ret = async_func_resume(ctx, &s->func_state);
- if (JS_IsException(func_ret))
- goto fail;
- JS_FreeValue(ctx, func_ret);
- obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_ASYNC_GENERATOR);
- if (JS_IsException(obj))
- goto fail;
- s->generator = JS_VALUE_GET_OBJ(obj);
- JS_SetOpaqueInternal(obj, s);
- return obj;
- fail:
- js_async_generator_free(ctx->rt, s);
- return JS_EXCEPTION;
- }
- /* JS parser */
- enum {
- TOK_NUMBER = -128,
- TOK_STRING,
- TOK_TEMPLATE,
- TOK_IDENT,
- TOK_REGEXP,
- /* warning: order matters (see js_parse_assign_expr) */
- TOK_MUL_ASSIGN,
- TOK_DIV_ASSIGN,
- TOK_MOD_ASSIGN,
- TOK_PLUS_ASSIGN,
- TOK_MINUS_ASSIGN,
- TOK_SHL_ASSIGN,
- TOK_SAR_ASSIGN,
- TOK_SHR_ASSIGN,
- TOK_AND_ASSIGN,
- TOK_XOR_ASSIGN,
- TOK_OR_ASSIGN,
- TOK_POW_ASSIGN,
- TOK_LAND_ASSIGN,
- TOK_LOR_ASSIGN,
- TOK_DOUBLE_QUESTION_MARK_ASSIGN,
- TOK_DEC,
- TOK_INC,
- TOK_SHL,
- TOK_SAR,
- TOK_SHR,
- TOK_LT,
- TOK_LTE,
- TOK_GT,
- TOK_GTE,
- TOK_EQ,
- TOK_STRICT_EQ,
- TOK_NEQ,
- TOK_STRICT_NEQ,
- TOK_LAND,
- TOK_LOR,
- TOK_POW,
- TOK_ARROW,
- TOK_ELLIPSIS,
- TOK_DOUBLE_QUESTION_MARK,
- TOK_QUESTION_MARK_DOT,
- TOK_ERROR,
- TOK_PRIVATE_NAME,
- TOK_EOF,
- /* keywords: WARNING: same order as atoms */
- TOK_NULL, /* must be first */
- TOK_FALSE,
- TOK_TRUE,
- TOK_IF,
- TOK_ELSE,
- TOK_RETURN,
- TOK_VAR,
- TOK_THIS,
- TOK_DELETE,
- TOK_VOID,
- TOK_TYPEOF,
- TOK_NEW,
- TOK_IN,
- TOK_INSTANCEOF,
- TOK_DO,
- TOK_WHILE,
- TOK_FOR,
- TOK_BREAK,
- TOK_CONTINUE,
- TOK_SWITCH,
- TOK_CASE,
- TOK_DEFAULT,
- TOK_THROW,
- TOK_TRY,
- TOK_CATCH,
- TOK_FINALLY,
- TOK_FUNCTION,
- TOK_DEBUGGER,
- TOK_WITH,
- /* FutureReservedWord */
- TOK_CLASS,
- TOK_CONST,
- TOK_ENUM,
- TOK_EXPORT,
- TOK_EXTENDS,
- TOK_IMPORT,
- TOK_SUPER,
- /* FutureReservedWords when parsing strict mode code */
- TOK_IMPLEMENTS,
- TOK_INTERFACE,
- TOK_LET,
- TOK_PACKAGE,
- TOK_PRIVATE,
- TOK_PROTECTED,
- TOK_PUBLIC,
- TOK_STATIC,
- TOK_YIELD,
- TOK_AWAIT, /* must be last */
- TOK_OF, /* only used for js_parse_skip_parens_token() */
- };
- #define TOK_FIRST_KEYWORD TOK_NULL
- #define TOK_LAST_KEYWORD TOK_AWAIT
- /* unicode code points */
- #define CP_NBSP 0x00a0
- #define CP_BOM 0xfeff
- #define CP_LS 0x2028
- #define CP_PS 0x2029
- typedef struct BlockEnv {
- struct BlockEnv *prev;
- JSAtom label_name; /* JS_ATOM_NULL if none */
- int label_break; /* -1 if none */
- int label_cont; /* -1 if none */
- int drop_count; /* number of stack elements to drop */
- int label_finally; /* -1 if none */
- int scope_level;
- uint8_t has_iterator : 1;
- uint8_t is_regular_stmt : 1; // i.e. not a loop statement
- } BlockEnv;
- typedef struct JSGlobalVar {
- int cpool_idx; /* if >= 0, index in the constant pool for hoisted
- function defintion*/
- uint8_t force_init : 1; /* force initialization to undefined */
- uint8_t is_lexical : 1; /* global let/const definition */
- uint8_t is_const : 1; /* const definition */
- int scope_level; /* scope of definition */
- JSAtom var_name; /* variable name */
- } JSGlobalVar;
- typedef struct RelocEntry {
- struct RelocEntry *next;
- uint32_t addr; /* address to patch */
- int size; /* address size: 1, 2 or 4 bytes */
- } RelocEntry;
- typedef struct JumpSlot {
- int op;
- int size;
- int pos;
- int label;
- } JumpSlot;
- typedef struct LabelSlot {
- int ref_count;
- int pos; /* phase 1 address, -1 means not resolved yet */
- int pos2; /* phase 2 address, -1 means not resolved yet */
- int addr; /* phase 3 address, -1 means not resolved yet */
- RelocEntry *first_reloc;
- } LabelSlot;
- typedef struct SourceLocSlot {
- uint32_t pc;
- int line_num;
- int col_num;
- } SourceLocSlot;
- typedef enum JSParseFunctionEnum {
- JS_PARSE_FUNC_STATEMENT,
- JS_PARSE_FUNC_VAR,
- JS_PARSE_FUNC_EXPR,
- JS_PARSE_FUNC_ARROW,
- JS_PARSE_FUNC_GETTER,
- JS_PARSE_FUNC_SETTER,
- JS_PARSE_FUNC_METHOD,
- JS_PARSE_FUNC_CLASS_STATIC_INIT,
- JS_PARSE_FUNC_CLASS_CONSTRUCTOR,
- JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR,
- } JSParseFunctionEnum;
- typedef enum JSParseExportEnum {
- JS_PARSE_EXPORT_NONE,
- JS_PARSE_EXPORT_NAMED,
- JS_PARSE_EXPORT_DEFAULT,
- } JSParseExportEnum;
- typedef struct JSFunctionDef {
- JSContext *ctx;
- struct JSFunctionDef *parent;
- int parent_cpool_idx; /* index in the constant pool of the parent
- or -1 if none */
- int parent_scope_level; /* scope level in parent at point of definition */
- struct list_head child_list; /* list of JSFunctionDef.link */
- struct list_head link;
- bool is_eval; /* true if eval code */
- int eval_type; /* only valid if is_eval = true */
- bool is_global_var; /* true if variables are not defined locally:
- eval global, eval module or non strict eval */
- bool is_func_expr; /* true if function expression */
- bool has_home_object; /* true if the home object is available */
- bool has_prototype; /* true if a prototype field is necessary */
- bool has_simple_parameter_list;
- bool has_parameter_expressions; /* if true, an argument scope is created */
- bool has_use_strict; /* to reject directive in special cases */
- bool has_eval_call; /* true if the function contains a call to eval() */
- bool has_arguments_binding; /* true if the 'arguments' binding is
- available in the function */
- bool has_this_binding; /* true if the 'this' and new.target binding are
- available in the function */
- bool new_target_allowed; /* true if the 'new.target' does not
- throw a syntax error */
- bool super_call_allowed; /* true if super() is allowed */
- bool super_allowed; /* true if super. or super[] is allowed */
- bool arguments_allowed; /* true if the 'arguments' identifier is allowed */
- bool is_derived_class_constructor;
- bool in_function_body;
- bool backtrace_barrier;
- JSFunctionKindEnum func_kind : 8;
- JSParseFunctionEnum func_type : 7;
- uint8_t is_strict_mode : 1;
- JSAtom func_name; /* JS_ATOM_NULL if no name */
- JSVarDef *vars;
- uint32_t *vars_htab; // indexes into vars[]
- int var_size; /* allocated size for vars[] */
- int var_count;
- JSVarDef *args;
- int arg_size; /* allocated size for args[] */
- int arg_count; /* number of arguments */
- int defined_arg_count;
- int var_object_idx; /* -1 if none */
- int arg_var_object_idx; /* -1 if none (var object for the argument scope) */
- int arguments_var_idx; /* -1 if none */
- int arguments_arg_idx; /* argument variable definition in argument scope,
- -1 if none */
- int func_var_idx; /* variable containing the current function (-1
- if none, only used if is_func_expr is true) */
- int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */
- int this_var_idx; /* variable containg the 'this' value, -1 if none */
- int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */
- int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */
- int home_object_var_idx;
- bool need_home_object;
- int scope_level; /* index into fd->scopes if the current lexical scope */
- int scope_first; /* index into vd->vars of first lexically scoped variable */
- int scope_size; /* allocated size of fd->scopes array */
- int scope_count; /* number of entries used in the fd->scopes array */
- JSVarScope *scopes;
- JSVarScope def_scope_array[4];
- int body_scope; /* scope of the body of the function or eval */
- int global_var_count;
- int global_var_size;
- JSGlobalVar *global_vars;
- DynBuf byte_code;
- int last_opcode_pos; /* -1 if no last opcode */
- bool use_short_opcodes; /* true if short opcodes are used in byte_code */
- LabelSlot *label_slots;
- int label_size; /* allocated size for label_slots[] */
- int label_count;
- BlockEnv *top_break; /* break/continue label stack */
- /* constant pool (strings, functions, numbers) */
- JSValue *cpool;
- int cpool_count;
- int cpool_size;
- /* list of variables in the closure */
- int closure_var_count;
- int closure_var_size;
- JSClosureVar *closure_var;
- JumpSlot *jump_slots;
- int jump_size;
- int jump_count;
- SourceLocSlot *source_loc_slots;
- int source_loc_size;
- int source_loc_count;
- int line_number_last;
- int line_number_last_pc;
- int col_number_last;
- /* pc2line table */
- JSAtom filename;
- int line_num;
- int col_num;
- DynBuf pc2line;
- char *source; /* raw source, utf-8 encoded */
- int source_len;
- JSModuleDef *module; /* != NULL when parsing a module */
- bool has_await; /* true if await is used (used in module eval) */
- } JSFunctionDef;
- typedef struct JSToken {
- int val;
- int line_num; /* line number of token start */
- int col_num; /* column number of token start */
- const uint8_t *ptr;
- union {
- struct {
- JSValue str;
- int sep;
- } str;
- struct {
- JSValue val;
- } num;
- struct {
- JSAtom atom;
- bool has_escape;
- bool is_reserved;
- } ident;
- struct {
- JSValue body;
- JSValue flags;
- } regexp;
- } u;
- } JSToken;
- typedef struct JSParseState {
- JSContext *ctx;
- int last_line_num; /* line number of last token */
- int last_col_num; /* column number of last token */
- int line_num; /* line number of current offset */
- int col_num; /* column number of current offset */
- const char *filename;
- JSToken token;
- bool got_lf; /* true if got line feed before the current token */
- const uint8_t *last_ptr;
- const uint8_t *buf_start;
- const uint8_t *buf_ptr;
- const uint8_t *buf_end;
- const uint8_t *eol; // most recently seen end-of-line character
- const uint8_t *mark; // first token character, invariant: eol < mark
- /* current function code */
- JSFunctionDef *cur_func;
- bool is_module; /* parsing a module */
- bool allow_html_comments;
- } JSParseState;
- typedef struct JSOpCode {
- #ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_*
- const char *name;
- #endif
- uint8_t size; /* in bytes */
- /* the opcodes remove n_pop items from the top of the stack, then
- pushes n_push items */
- uint8_t n_pop;
- uint8_t n_push;
- uint8_t fmt;
- } JSOpCode;
- static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = {
- #define FMT(f)
- #ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_*
- #define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f },
- #else
- #define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f },
- #endif
- /*
- * QuickJS opcode definitions
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- * Copyright (c) 2017-2018 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifdef FMT
- FMT(none)
- FMT(none_int)
- FMT(none_loc)
- FMT(none_arg)
- FMT(none_var_ref)
- FMT(u8)
- FMT(i8)
- FMT(loc8)
- FMT(const8)
- FMT(label8)
- FMT(u16)
- FMT(i16)
- FMT(label16)
- FMT(npop)
- FMT(npopx)
- FMT(npop_u16)
- FMT(loc)
- FMT(arg)
- FMT(var_ref)
- FMT(u32)
- FMT(u32x2)
- FMT(i32)
- FMT(const)
- FMT(label)
- FMT(atom)
- FMT(atom_u8)
- FMT(atom_u16)
- FMT(atom_label_u8)
- FMT(atom_label_u16)
- FMT(label_u16)
- #undef FMT
- #endif /* FMT */
- #ifdef DEF
- #ifndef def
- #define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f)
- #endif
- DEF(invalid, 1, 0, 0, none) /* never emitted */
- /* push values */
- DEF( push_i32, 5, 0, 1, i32)
- DEF( push_const, 5, 0, 1, const)
- DEF( fclosure, 5, 0, 1, const) /* must follow push_const */
- DEF(push_atom_value, 5, 0, 1, atom)
- DEF( private_symbol, 5, 0, 1, atom)
- DEF( undefined, 1, 0, 1, none)
- DEF( null, 1, 0, 1, none)
- DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */
- DEF( push_false, 1, 0, 1, none)
- DEF( push_true, 1, 0, 1, none)
- DEF( object, 1, 0, 1, none)
- DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */
- DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */
- DEF( drop, 1, 1, 0, none) /* a -> */
- DEF( nip, 1, 2, 1, none) /* a b -> b */
- DEF( nip1, 1, 3, 2, none) /* a b c -> b c */
- DEF( dup, 1, 1, 2, none) /* a -> a a */
- DEF( dup1, 1, 2, 3, none) /* a b -> a a b */
- DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */
- DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */
- DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */
- DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */
- DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */
- DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */
- DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */
- DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */
- DEF( swap, 1, 2, 2, none) /* a b -> b a */
- DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */
- DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */
- DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */
- DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */
- DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */
- DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */
- DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */
- DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */
- DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */
- DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */
- DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */
- DEF( apply, 3, 3, 1, u16)
- DEF( return, 1, 1, 0, none)
- DEF( return_undef, 1, 0, 0, none)
- DEF(check_ctor_return, 1, 1, 2, none)
- DEF( check_ctor, 1, 0, 0, none)
- DEF( init_ctor, 1, 0, 1, none)
- DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */
- DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */
- DEF( return_async, 1, 1, 0, none)
- DEF( throw, 1, 1, 0, none)
- DEF( throw_error, 6, 0, 0, atom_u8)
- DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
- DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
- DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
- bytecode string */
- DEF( get_super, 1, 1, 1, none)
- DEF( import, 1, 1, 1, none) /* dynamic module import */
- DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */
- DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */
- DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */
- DEF( put_var, 5, 1, 0, atom) /* must come after get_var */
- DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */
- DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */
- DEF( get_ref_value, 1, 2, 3, none)
- DEF( put_ref_value, 1, 3, 0, none)
- DEF( define_var, 6, 0, 0, atom_u8)
- DEF(check_define_var, 6, 0, 0, atom_u8)
- DEF( define_func, 6, 1, 0, atom_u8)
- // order matters, see IC counterparts
- DEF( get_field, 5, 1, 1, atom)
- DEF( get_field2, 5, 1, 2, atom)
- DEF( put_field, 5, 2, 0, atom)
- DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */
- DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */
- DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */
- DEF( get_array_el, 1, 2, 1, none)
- DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */
- DEF( put_array_el, 1, 3, 0, none)
- DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */
- DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */
- DEF( define_field, 5, 2, 1, atom)
- DEF( set_name, 5, 1, 1, atom)
- DEF(set_name_computed, 1, 2, 2, none)
- DEF( set_proto, 1, 2, 1, none)
- DEF(set_home_object, 1, 2, 2, none)
- DEF(define_array_el, 1, 3, 2, none)
- DEF( append, 1, 3, 2, none) /* append enumerated object, update length */
- DEF(copy_data_properties, 2, 3, 3, u8)
- DEF( define_method, 6, 2, 1, atom_u8)
- DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */
- DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */
- DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */
- DEF( get_loc, 3, 0, 1, loc)
- DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */
- DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */
- DEF( get_arg, 3, 0, 1, arg)
- DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */
- DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */
- DEF( get_var_ref, 3, 0, 1, var_ref)
- DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */
- DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */
- DEF(set_loc_uninitialized, 3, 0, 0, loc)
- DEF( get_loc_check, 3, 0, 1, loc)
- DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */
- DEF( put_loc_check_init, 3, 1, 0, loc)
- DEF(get_var_ref_check, 3, 0, 1, var_ref)
- DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */
- DEF(put_var_ref_check_init, 3, 1, 0, var_ref)
- DEF( close_loc, 3, 0, 0, loc)
- DEF( if_false, 5, 1, 0, label)
- DEF( if_true, 5, 1, 0, label) /* must come after if_false */
- DEF( goto, 5, 0, 0, label) /* must come after if_true */
- DEF( catch, 5, 0, 1, label)
- DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */
- DEF( ret, 1, 1, 0, none) /* used to return from the finally block */
- DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */
- DEF( to_object, 1, 1, 1, none)
- //DEF( to_string, 1, 1, 1, none)
- DEF( to_propkey, 1, 1, 1, none)
- DEF( to_propkey2, 1, 2, 2, none)
- DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
- DEF(with_get_ref_undef, 10, 1, 0, atom_label_u8)
- DEF( make_loc_ref, 7, 0, 2, atom_u16)
- DEF( make_arg_ref, 7, 0, 2, atom_u16)
- DEF(make_var_ref_ref, 7, 0, 2, atom_u16)
- DEF( make_var_ref, 5, 0, 2, atom)
- DEF( for_in_start, 1, 1, 1, none)
- DEF( for_of_start, 1, 1, 3, none)
- DEF(for_await_of_start, 1, 1, 3, none)
- DEF( for_in_next, 1, 1, 3, none)
- DEF( for_of_next, 2, 3, 5, u8)
- DEF(iterator_check_object, 1, 1, 1, none)
- DEF(iterator_get_value_done, 1, 1, 2, none)
- DEF( iterator_close, 1, 3, 0, none)
- DEF( iterator_next, 1, 4, 4, none)
- DEF( iterator_call, 2, 4, 5, u8)
- DEF( initial_yield, 1, 0, 0, none)
- DEF( yield, 1, 1, 2, none)
- DEF( yield_star, 1, 1, 2, none)
- DEF(async_yield_star, 1, 1, 2, none)
- DEF( await, 1, 1, 1, none)
- /* arithmetic/logic operations */
- DEF( neg, 1, 1, 1, none)
- DEF( plus, 1, 1, 1, none)
- DEF( dec, 1, 1, 1, none)
- DEF( inc, 1, 1, 1, none)
- DEF( post_dec, 1, 1, 2, none)
- DEF( post_inc, 1, 1, 2, none)
- DEF( dec_loc, 2, 0, 0, loc8)
- DEF( inc_loc, 2, 0, 0, loc8)
- DEF( add_loc, 2, 1, 0, loc8)
- DEF( not, 1, 1, 1, none)
- DEF( lnot, 1, 1, 1, none)
- DEF( typeof, 1, 1, 1, none)
- DEF( delete, 1, 2, 1, none)
- DEF( delete_var, 5, 0, 1, atom)
- /* warning: order matters (see js_parse_assign_expr) */
- DEF( mul, 1, 2, 1, none)
- DEF( div, 1, 2, 1, none)
- DEF( mod, 1, 2, 1, none)
- DEF( add, 1, 2, 1, none)
- DEF( sub, 1, 2, 1, none)
- DEF( shl, 1, 2, 1, none)
- DEF( sar, 1, 2, 1, none)
- DEF( shr, 1, 2, 1, none)
- DEF( and, 1, 2, 1, none)
- DEF( xor, 1, 2, 1, none)
- DEF( or, 1, 2, 1, none)
- DEF( pow, 1, 2, 1, none)
- DEF( lt, 1, 2, 1, none)
- DEF( lte, 1, 2, 1, none)
- DEF( gt, 1, 2, 1, none)
- DEF( gte, 1, 2, 1, none)
- DEF( instanceof, 1, 2, 1, none)
- DEF( in, 1, 2, 1, none)
- DEF( eq, 1, 2, 1, none)
- DEF( neq, 1, 2, 1, none)
- DEF( strict_eq, 1, 2, 1, none)
- DEF( strict_neq, 1, 2, 1, none)
- DEF(is_undefined_or_null, 1, 1, 1, none)
- DEF( private_in, 1, 2, 1, none)
- DEF(push_bigint_i32, 5, 0, 1, i32)
- /* must be the last non short and non temporary opcode */
- DEF( nop, 1, 0, 0, none)
- /* temporary opcodes: never emitted in the final bytecode */
- def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
- def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
- def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */
- def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */
- def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
- def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
- def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
- def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
- def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */
- def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */
- def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
- def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
- def( source_loc, 9, 0, 0, u32x2) /* emitted in phase 1, removed in phase 3 */
- DEF( push_minus1, 1, 0, 1, none_int)
- DEF( push_0, 1, 0, 1, none_int)
- DEF( push_1, 1, 0, 1, none_int)
- DEF( push_2, 1, 0, 1, none_int)
- DEF( push_3, 1, 0, 1, none_int)
- DEF( push_4, 1, 0, 1, none_int)
- DEF( push_5, 1, 0, 1, none_int)
- DEF( push_6, 1, 0, 1, none_int)
- DEF( push_7, 1, 0, 1, none_int)
- DEF( push_i8, 2, 0, 1, i8)
- DEF( push_i16, 3, 0, 1, i16)
- DEF( push_const8, 2, 0, 1, const8)
- DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */
- DEF(push_empty_string, 1, 0, 1, none)
- DEF( get_loc8, 2, 0, 1, loc8)
- DEF( put_loc8, 2, 1, 0, loc8)
- DEF( set_loc8, 2, 1, 1, loc8)
- DEF( get_loc0_loc1, 1, 0, 2, none_loc)
- DEF( get_loc0, 1, 0, 1, none_loc)
- DEF( get_loc1, 1, 0, 1, none_loc)
- DEF( get_loc2, 1, 0, 1, none_loc)
- DEF( get_loc3, 1, 0, 1, none_loc)
- DEF( put_loc0, 1, 1, 0, none_loc)
- DEF( put_loc1, 1, 1, 0, none_loc)
- DEF( put_loc2, 1, 1, 0, none_loc)
- DEF( put_loc3, 1, 1, 0, none_loc)
- DEF( set_loc0, 1, 1, 1, none_loc)
- DEF( set_loc1, 1, 1, 1, none_loc)
- DEF( set_loc2, 1, 1, 1, none_loc)
- DEF( set_loc3, 1, 1, 1, none_loc)
- DEF( get_arg0, 1, 0, 1, none_arg)
- DEF( get_arg1, 1, 0, 1, none_arg)
- DEF( get_arg2, 1, 0, 1, none_arg)
- DEF( get_arg3, 1, 0, 1, none_arg)
- DEF( put_arg0, 1, 1, 0, none_arg)
- DEF( put_arg1, 1, 1, 0, none_arg)
- DEF( put_arg2, 1, 1, 0, none_arg)
- DEF( put_arg3, 1, 1, 0, none_arg)
- DEF( set_arg0, 1, 1, 1, none_arg)
- DEF( set_arg1, 1, 1, 1, none_arg)
- DEF( set_arg2, 1, 1, 1, none_arg)
- DEF( set_arg3, 1, 1, 1, none_arg)
- DEF( get_var_ref0, 1, 0, 1, none_var_ref)
- DEF( get_var_ref1, 1, 0, 1, none_var_ref)
- DEF( get_var_ref2, 1, 0, 1, none_var_ref)
- DEF( get_var_ref3, 1, 0, 1, none_var_ref)
- DEF( put_var_ref0, 1, 1, 0, none_var_ref)
- DEF( put_var_ref1, 1, 1, 0, none_var_ref)
- DEF( put_var_ref2, 1, 1, 0, none_var_ref)
- DEF( put_var_ref3, 1, 1, 0, none_var_ref)
- DEF( set_var_ref0, 1, 1, 1, none_var_ref)
- DEF( set_var_ref1, 1, 1, 1, none_var_ref)
- DEF( set_var_ref2, 1, 1, 1, none_var_ref)
- DEF( set_var_ref3, 1, 1, 1, none_var_ref)
- DEF( get_length, 1, 1, 1, none)
- DEF( if_false8, 2, 1, 0, label8)
- DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */
- DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */
- DEF( goto16, 3, 0, 0, label16)
- DEF( call0, 1, 1, 1, npopx)
- DEF( call1, 1, 1, 1, npopx)
- DEF( call2, 1, 1, 1, npopx)
- DEF( call3, 1, 1, 1, npopx)
- DEF( is_undefined, 1, 1, 1, none)
- DEF( is_null, 1, 1, 1, none)
- DEF(typeof_is_undefined, 1, 1, 1, none)
- DEF( typeof_is_function, 1, 1, 1, none)
- #undef DEF
- #undef def
- #endif /* DEF */
- #undef DEF
- #undef FMT
- };
- /* After the final compilation pass, short opcodes are used. Their
- opcodes overlap with the temporary opcodes which cannot appear in
- the final bytecode. Their description is after the temporary
- opcodes in opcode_info[]. */
- #define short_opcode_info(op) \
- opcode_info[(op) >= OP_TEMP_START ? \
- (op) + (OP_TEMP_END - OP_TEMP_START) : (op)]
- static void free_token(JSParseState *s, JSToken *token)
- {
- switch(token->val) {
- case TOK_NUMBER:
- JS_FreeValue(s->ctx, token->u.num.val);
- break;
- case TOK_STRING:
- case TOK_TEMPLATE:
- JS_FreeValue(s->ctx, token->u.str.str);
- break;
- case TOK_REGEXP:
- JS_FreeValue(s->ctx, token->u.regexp.body);
- JS_FreeValue(s->ctx, token->u.regexp.flags);
- break;
- case TOK_IDENT:
- case TOK_PRIVATE_NAME:
- JS_FreeAtom(s->ctx, token->u.ident.atom);
- break;
- default:
- if (token->val >= TOK_FIRST_KEYWORD &&
- token->val <= TOK_LAST_KEYWORD) {
- JS_FreeAtom(s->ctx, token->u.ident.atom);
- }
- break;
- }
- }
- static void __attribute((unused)) dump_token(JSParseState *s,
- const JSToken *token)
- {
- printf("%d:%d ", token->line_num, token->col_num);
- switch(token->val) {
- case TOK_NUMBER:
- {
- double d;
- JS_ToFloat64(s->ctx, &d, token->u.num.val); /* no exception possible */
- printf("number: %.14g\n", d);
- }
- break;
- case TOK_IDENT:
- dump_atom:
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
- printf("ident: '%s'\n",
- JS_AtomGetStr(s->ctx, buf, sizeof(buf), token->u.ident.atom));
- }
- break;
- case TOK_STRING:
- {
- const char *str;
- /* XXX: quote the string */
- str = JS_ToCString(s->ctx, token->u.str.str);
- printf("string: '%s'\n", str);
- JS_FreeCString(s->ctx, str);
- }
- break;
- case TOK_TEMPLATE:
- {
- const char *str;
- str = JS_ToCString(s->ctx, token->u.str.str);
- printf("template: `%s`\n", str);
- JS_FreeCString(s->ctx, str);
- }
- break;
- case TOK_REGEXP:
- {
- const char *str, *str2;
- str = JS_ToCString(s->ctx, token->u.regexp.body);
- str2 = JS_ToCString(s->ctx, token->u.regexp.flags);
- printf("regexp: '%s' '%s'\n", str, str2);
- JS_FreeCString(s->ctx, str);
- JS_FreeCString(s->ctx, str2);
- }
- break;
- case TOK_EOF:
- printf("eof\n");
- break;
- default:
- if (s->token.val >= TOK_NULL && s->token.val <= TOK_LAST_KEYWORD) {
- goto dump_atom;
- } else if (s->token.val >= 256) {
- printf("token: %d\n", token->val);
- } else {
- printf("token: '%c'\n", token->val);
- }
- break;
- }
- }
- int JS_PRINTF_FORMAT_ATTR(2, 3) js_parse_error(JSParseState *s, JS_PRINTF_FORMAT const char *fmt, ...)
- {
- JSContext *ctx = s->ctx;
- va_list ap;
- int backtrace_flags;
- va_start(ap, fmt);
- JS_ThrowError2(ctx, JS_SYNTAX_ERROR, false, fmt, ap);
- va_end(ap);
- backtrace_flags = 0;
- if (s->cur_func && s->cur_func->backtrace_barrier)
- backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
- build_backtrace(ctx, ctx->rt->current_exception, JS_UNDEFINED, s->filename,
- s->line_num, s->col_num, backtrace_flags);
- return -1;
- }
- #ifndef QJS_DISABLE_PARSER
- static __exception int next_token(JSParseState *s);
- static int js_parse_expect(JSParseState *s, int tok)
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
- if (s->token.val == tok)
- return next_token(s);
- switch(s->token.val) {
- case TOK_EOF:
- return js_parse_error(s, "Unexpected end of input");
- case TOK_NUMBER:
- return js_parse_error(s, "Unexpected number");
- case TOK_STRING:
- return js_parse_error(s, "Unexpected string");
- case TOK_TEMPLATE:
- return js_parse_error(s, "Unexpected string template");
- case TOK_REGEXP:
- return js_parse_error(s, "Unexpected regexp");
- case TOK_IDENT:
- return js_parse_error(s, "Unexpected identifier '%s'",
- JS_AtomGetStr(s->ctx, buf, sizeof(buf),
- s->token.u.ident.atom));
- case TOK_ERROR:
- return js_parse_error(s, "Invalid or unexpected token");
- default:
- return js_parse_error(s, "Unexpected token '%.*s'",
- (int)(s->buf_ptr - s->token.ptr),
- (const char *)s->token.ptr);
- }
- }
- static int js_parse_expect_semi(JSParseState *s)
- {
- if (s->token.val != ';') {
- /* automatic insertion of ';' */
- if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) {
- return 0;
- }
- return js_parse_error(s, "expecting '%c'", ';');
- }
- return next_token(s);
- }
- static int js_parse_error_reserved_identifier(JSParseState *s)
- {
- char buf1[ATOM_GET_STR_BUF_SIZE];
- return js_parse_error(s, "'%s' is a reserved identifier",
- JS_AtomGetStr(s->ctx, buf1, sizeof(buf1),
- s->token.u.ident.atom));
- }
- static __exception int js_parse_template_part(JSParseState *s,
- const uint8_t *p)
- {
- const uint8_t *p_next;
- uint32_t c;
- StringBuffer b_s, *b = &b_s;
- JSValue str;
- /* p points to the first byte of the template part */
- if (string_buffer_init(s->ctx, b, 32))
- goto fail;
- for(;;) {
- if (p >= s->buf_end)
- goto unexpected_eof;
- c = *p++;
- if (c == '`') {
- /* template end part */
- break;
- }
- if (c == '$' && *p == '{') {
- /* template start or middle part */
- p++;
- break;
- }
- if (c == '\\') {
- if (string_buffer_putc8(b, c))
- goto fail;
- if (p >= s->buf_end)
- goto unexpected_eof;
- c = *p++;
- }
- /* newline sequences are normalized as single '\n' bytes */
- if (c == '\r') {
- if (*p == '\n')
- p++;
- c = '\n';
- }
- if (c == '\n') {
- s->line_num++;
- s->eol = &p[-1];
- s->mark = p;
- } else if (c >= 0x80) {
- c = utf8_decode(p - 1, &p_next);
- if (p_next == p) {
- js_parse_error(s, "invalid UTF-8 sequence");
- goto fail;
- }
- p = p_next;
- }
- if (string_buffer_putc(b, c))
- goto fail;
- }
- str = string_buffer_end(b);
- if (JS_IsException(str))
- return -1;
- s->token.val = TOK_TEMPLATE;
- s->token.u.str.sep = c;
- s->token.u.str.str = str;
- s->buf_ptr = p;
- return 0;
- unexpected_eof:
- js_parse_error(s, "unexpected end of string");
- fail:
- string_buffer_free(b);
- return -1;
- }
- static __exception int js_parse_string(JSParseState *s, int sep,
- bool do_throw, const uint8_t *p,
- JSToken *token, const uint8_t **pp)
- {
- const uint8_t *p_next;
- int ret;
- uint32_t c;
- StringBuffer b_s, *b = &b_s;
- JSValue str;
- /* string */
- if (string_buffer_init(s->ctx, b, 32))
- goto fail;
- for(;;) {
- if (p >= s->buf_end)
- goto invalid_char;
- c = *p;
- if (c < 0x20) {
- if (sep == '`') {
- if (c == '\r') {
- if (p[1] == '\n')
- p++;
- c = '\n';
- }
- /* do not update s->line_num */
- } else if (c == '\n' || c == '\r')
- goto invalid_char;
- }
- p++;
- if (c == sep)
- break;
- if (c == '$' && *p == '{' && sep == '`') {
- /* template start or middle part */
- p++;
- break;
- }
- if (c == '\\') {
- c = *p;
- switch(c) {
- case '\0':
- if (p >= s->buf_end) {
- if (sep != '`')
- goto invalid_char;
- if (do_throw)
- js_parse_error(s, "Unexpected end of input");
- goto fail;
- }
- p++;
- break;
- case '\'':
- case '\"':
- case '\\':
- p++;
- break;
- case '\r': /* accept DOS and MAC newline sequences */
- if (p[1] == '\n') {
- p++;
- }
- /* fall thru */
- case '\n':
- /* ignore escaped newline sequence */
- p++;
- if (sep != '`') {
- s->line_num++;
- s->eol = &p[-1];
- s->mark = p;
- }
- continue;
- default:
- if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) {
- /* accept isolated \0 */
- p++;
- c = '\0';
- } else
- if ((c >= '0' && c <= '9')
- && (s->cur_func->is_strict_mode || sep == '`')) {
- if (do_throw) {
- js_parse_error(s, "%s are not allowed in %s",
- (c >= '8') ? "\\8 and \\9" : "Octal escape sequences",
- (sep == '`') ? "template strings" : "strict mode");
- }
- goto fail;
- } else if (c >= 0x80) {
- c = utf8_decode(p, &p_next);
- if (p_next == p + 1) {
- goto invalid_utf8;
- }
- p = p_next;
- /* LS or PS are skipped */
- if (c == CP_LS || c == CP_PS)
- continue;
- } else {
- ret = lre_parse_escape(&p, true);
- if (ret == -1) {
- if (do_throw) {
- js_parse_error(s, "Invalid %s escape sequence",
- c == 'u' ? "Unicode" : "hexadecimal");
- }
- goto fail;
- } else if (ret < 0) {
- /* ignore the '\' (could output a warning) */
- p++;
- } else {
- c = ret;
- }
- }
- break;
- }
- } else if (c >= 0x80) {
- c = utf8_decode(p - 1, &p_next);
- if (p_next == p)
- goto invalid_utf8;
- p = p_next;
- }
- if (string_buffer_putc(b, c))
- goto fail;
- }
- str = string_buffer_end(b);
- if (JS_IsException(str))
- return -1;
- token->val = TOK_STRING;
- token->u.str.sep = c;
- token->u.str.str = str;
- *pp = p;
- return 0;
- invalid_utf8:
- if (do_throw)
- js_parse_error(s, "invalid UTF-8 sequence");
- goto fail;
- invalid_char:
- if (do_throw)
- js_parse_error(s, "unexpected end of string");
- fail:
- string_buffer_free(b);
- return -1;
- }
- static inline bool token_is_pseudo_keyword(JSParseState *s, JSAtom atom) {
- return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom &&
- !s->token.u.ident.has_escape;
- }
- static __exception int js_parse_regexp(JSParseState *s)
- {
- const uint8_t *p, *p_next;
- bool in_class;
- StringBuffer b_s, *b = &b_s;
- StringBuffer b2_s, *b2 = &b2_s;
- uint32_t c;
- JSValue body_str, flags_str;
- p = s->buf_ptr;
- p++;
- in_class = false;
- if (string_buffer_init(s->ctx, b, 32))
- return -1;
- if (string_buffer_init(s->ctx, b2, 1))
- goto fail;
- for(;;) {
- if (p >= s->buf_end) {
- eof_error:
- js_parse_error(s, "unexpected end of regexp");
- goto fail;
- }
- c = *p++;
- if (c == '\n' || c == '\r') {
- goto eol_error;
- } else if (c == '/') {
- if (!in_class)
- break;
- } else if (c == '[') {
- in_class = true;
- } else if (c == ']') {
- /* XXX: incorrect as the first character in a class */
- in_class = false;
- } else if (c == '\\') {
- if (string_buffer_putc8(b, c))
- goto fail;
- c = *p++;
- if (c == '\n' || c == '\r')
- goto eol_error;
- else if (c == '\0' && p >= s->buf_end)
- goto eof_error;
- else if (c >= 0x80) {
- c = utf8_decode(p - 1, &p_next);
- if (p_next == p) {
- goto invalid_utf8;
- }
- p = p_next;
- if (c == CP_LS || c == CP_PS)
- goto eol_error;
- }
- } else if (c >= 0x80) {
- c = utf8_decode(p - 1, &p_next);
- if (p_next == p) {
- invalid_utf8:
- js_parse_error(s, "invalid UTF-8 sequence");
- goto fail;
- }
- p = p_next;
- /* LS or PS are considered as line terminator */
- if (c == CP_LS || c == CP_PS) {
- eol_error:
- js_parse_error(s, "unexpected line terminator in regexp");
- goto fail;
- }
- }
- if (string_buffer_putc(b, c))
- goto fail;
- }
- /* flags */
- for(;;) {
- c = utf8_decode(p, &p_next);
- /* no need to test for invalid UTF-8, 0xFFFD is not ident_next */
- if (!lre_js_is_ident_next(c))
- break;
- if (string_buffer_putc(b2, c))
- goto fail;
- p = p_next;
- }
- body_str = string_buffer_end(b);
- flags_str = string_buffer_end(b2);
- if (JS_IsException(body_str) ||
- JS_IsException(flags_str)) {
- JS_FreeValue(s->ctx, body_str);
- JS_FreeValue(s->ctx, flags_str);
- return -1;
- }
- s->token.val = TOK_REGEXP;
- s->token.u.regexp.body = body_str;
- s->token.u.regexp.flags = flags_str;
- s->buf_ptr = p;
- return 0;
- fail:
- string_buffer_free(b);
- string_buffer_free(b2);
- return -1;
- }
- #endif // QJS_DISABLE_PARSER
- static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
- char *static_buf)
- {
- char *buf, *new_buf;
- size_t size, new_size;
- buf = *pbuf;
- size = *psize;
- if (size >= (SIZE_MAX / 3) * 2)
- new_size = SIZE_MAX;
- else
- new_size = size + (size >> 1);
- if (buf == static_buf) {
- new_buf = js_malloc(ctx, new_size);
- if (!new_buf)
- return -1;
- memcpy(new_buf, buf, size);
- } else {
- new_buf = js_realloc(ctx, buf, new_size);
- if (!new_buf)
- return -1;
- }
- *pbuf = new_buf;
- *psize = new_size;
- return 0;
- }
- #ifndef QJS_DISABLE_PARSER
- /* convert a TOK_IDENT to a keyword when needed */
- static void update_token_ident(JSParseState *s)
- {
- if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
- (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
- s->cur_func->is_strict_mode) ||
- (s->token.u.ident.atom == JS_ATOM_yield &&
- ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||
- (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
- !s->cur_func->in_function_body && s->cur_func->parent &&
- (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
- (s->token.u.ident.atom == JS_ATOM_await &&
- (s->is_module ||
- (s->cur_func->func_kind & JS_FUNC_ASYNC) ||
- s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT ||
- (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
- !s->cur_func->in_function_body && s->cur_func->parent &&
- ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) ||
- s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) {
- if (s->token.u.ident.has_escape) {
- s->token.u.ident.is_reserved = true;
- s->token.val = TOK_IDENT;
- } else {
- /* The keywords atoms are pre allocated */
- s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD;
- }
- }
- }
- /* if the current token is an identifier or keyword, reparse it
- according to the current function type */
- static void reparse_ident_token(JSParseState *s)
- {
- if (s->token.val == TOK_IDENT ||
- (s->token.val >= TOK_FIRST_KEYWORD &&
- s->token.val <= TOK_LAST_KEYWORD)) {
- s->token.val = TOK_IDENT;
- s->token.u.ident.is_reserved = false;
- update_token_ident(s);
- }
- }
- /* 'c' is the first character. Return JS_ATOM_NULL in case of error */
- static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
- bool *pident_has_escape, int c, bool is_private)
- {
- const uint8_t *p, *p_next;
- char ident_buf[128], *buf;
- size_t ident_size, ident_pos;
- JSAtom atom = JS_ATOM_NULL;
- p = *pp;
- buf = ident_buf;
- ident_size = sizeof(ident_buf);
- ident_pos = 0;
- if (is_private)
- buf[ident_pos++] = '#';
- for(;;) {
- if (c < 0x80) {
- buf[ident_pos++] = c;
- } else {
- ident_pos += utf8_encode((uint8_t*)buf + ident_pos, c);
- }
- c = *p;
- p_next = p + 1;
- if (c == '\\' && *p_next == 'u') {
- c = lre_parse_escape(&p_next, true);
- *pident_has_escape = true;
- } else if (c >= 0x80) {
- c = utf8_decode(p, &p_next);
- /* no need to test for invalid UTF-8, 0xFFFD is not ident_next */
- }
- if (!lre_js_is_ident_next(c))
- break;
- p = p_next;
- if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
- if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf))
- goto done;
- }
- }
- /* buf is pure ASCII or UTF-8 encoded */
- atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
- done:
- if (unlikely(buf != ident_buf))
- js_free(s->ctx, buf);
- *pp = p;
- return atom;
- }
- static __exception int next_token(JSParseState *s)
- {
- const uint8_t *p, *p_next;
- int c;
- bool ident_has_escape;
- JSAtom atom;
- if (js_check_stack_overflow(s->ctx->rt, 1000)) {
- JS_ThrowStackOverflow(s->ctx);
- return -1;
- }
- free_token(s, &s->token);
- p = s->last_ptr = s->buf_ptr;
- s->got_lf = false;
- s->last_line_num = s->token.line_num;
- s->last_col_num = s->token.col_num;
- redo:
- s->token.line_num = s->line_num;
- s->token.col_num = s->col_num;
- s->token.ptr = p;
- c = *p;
- switch(c) {
- case 0:
- if (p >= s->buf_end) {
- s->token.val = TOK_EOF;
- } else {
- goto def_token;
- }
- break;
- case '`':
- if (js_parse_template_part(s, p + 1))
- goto fail;
- p = s->buf_ptr;
- break;
- case '\'':
- case '\"':
- if (js_parse_string(s, c, true, p + 1, &s->token, &p))
- goto fail;
- break;
- case '\r': /* accept DOS and MAC newline sequences */
- if (p[1] == '\n') {
- p++;
- }
- /* fall thru */
- case '\n':
- p++;
- line_terminator:
- s->eol = &p[-1];
- s->mark = p;
- s->got_lf = true;
- s->line_num++;
- goto redo;
- case '\f':
- case '\v':
- case ' ':
- case '\t':
- s->mark = ++p;
- goto redo;
- case '/':
- if (p[1] == '*') {
- /* comment */
- p += 2;
- for(;;) {
- if (*p == '\0' && p >= s->buf_end) {
- js_parse_error(s, "unexpected end of comment");
- goto fail;
- }
- if (p[0] == '*' && p[1] == '/') {
- p += 2;
- break;
- }
- if (*p == '\n') {
- s->line_num++;
- s->got_lf = true; /* considered as LF for ASI */
- s->eol = p++;
- s->mark = p;
- } else if (*p == '\r') {
- s->got_lf = true; /* considered as LF for ASI */
- p++;
- } else if (*p >= 0x80) {
- c = utf8_decode(p, &p);
- /* ignore invalid UTF-8 in comments */
- if (c == CP_LS || c == CP_PS) {
- s->got_lf = true; /* considered as LF for ASI */
- }
- } else {
- p++;
- }
- }
- s->mark = p;
- goto redo;
- } else if (p[1] == '/') {
- /* line comment */
- p += 2;
- skip_line_comment:
- for(;;) {
- if (*p == '\0' && p >= s->buf_end)
- break;
- if (*p == '\r' || *p == '\n')
- break;
- if (*p >= 0x80) {
- c = utf8_decode(p, &p);
- /* ignore invalid UTF-8 in comments */
- /* LS or PS are considered as line terminator */
- if (c == CP_LS || c == CP_PS) {
- break;
- }
- } else {
- p++;
- }
- }
- s->mark = p;
- goto redo;
- } else if (p[1] == '=') {
- p += 2;
- s->token.val = TOK_DIV_ASSIGN;
- } else {
- p++;
- s->token.val = c;
- }
- break;
- case '\\':
- if (p[1] == 'u') {
- const uint8_t *p1 = p + 1;
- int c1 = lre_parse_escape(&p1, true);
- if (c1 >= 0 && lre_js_is_ident_first(c1)) {
- c = c1;
- p = p1;
- ident_has_escape = true;
- goto has_ident;
- } else {
- /* XXX: syntax error? */
- }
- }
- goto def_token;
- case 'a': case 'b': case 'c': case 'd':
- case 'e': case 'f': case 'g': case 'h':
- case 'i': case 'j': case 'k': case 'l':
- case 'm': case 'n': case 'o': case 'p':
- case 'q': case 'r': case 's': case 't':
- case 'u': case 'v': case 'w': case 'x':
- case 'y': case 'z':
- case 'A': case 'B': case 'C': case 'D':
- case 'E': case 'F': case 'G': case 'H':
- case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'P':
- case 'Q': case 'R': case 'S': case 'T':
- case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- case '_':
- case '$':
- /* identifier */
- s->mark = p;
- p++;
- ident_has_escape = false;
- has_ident:
- atom = parse_ident(s, &p, &ident_has_escape, c, false);
- if (atom == JS_ATOM_NULL)
- goto fail;
- s->token.u.ident.atom = atom;
- s->token.u.ident.has_escape = ident_has_escape;
- s->token.u.ident.is_reserved = false;
- s->token.val = TOK_IDENT;
- update_token_ident(s);
- break;
- case '#':
- /* private name */
- {
- p++;
- c = *p;
- p_next = p + 1;
- if (c == '\\' && *p_next == 'u') {
- c = lre_parse_escape(&p_next, true);
- } else if (c >= 0x80) {
- c = utf8_decode(p, &p_next);
- if (p_next == p + 1)
- goto invalid_utf8;
- }
- if (!lre_js_is_ident_first(c)) {
- js_parse_error(s, "invalid first character of private name");
- goto fail;
- }
- p = p_next;
- ident_has_escape = false; /* not used */
- atom = parse_ident(s, &p, &ident_has_escape, c, true);
- if (atom == JS_ATOM_NULL)
- goto fail;
- s->token.u.ident.atom = atom;
- s->token.val = TOK_PRIVATE_NAME;
- }
- break;
- case '.':
- if (p[1] == '.' && p[2] == '.') {
- p += 3;
- s->token.val = TOK_ELLIPSIS;
- break;
- }
- if (p[1] >= '0' && p[1] <= '9') {
- goto parse_number;
- } else {
- goto def_token;
- }
- break;
- case '0':
- /* in strict mode, octal literals are not accepted */
- if (is_digit(p[1]) && (s->cur_func->is_strict_mode)) {
- js_parse_error(s, "Octal literals are not allowed in strict mode");
- goto fail;
- }
- goto parse_number;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8':
- case '9':
- /* number */
- parse_number:
- {
- JSValue ret;
- const uint8_t *p1;
- int flags;
- flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
- ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_SUFFIX;
- ret = js_atof(s->ctx, (const char *)p, (const char **)&p, 0,
- flags);
- if (JS_IsException(ret))
- goto fail;
- /* reject `10instanceof Number` */
- if (JS_VALUE_IS_NAN(ret) ||
- lre_js_is_ident_next(utf8_decode(p, &p1))) {
- JS_FreeValue(s->ctx, ret);
- js_parse_error(s, "invalid number literal");
- goto fail;
- }
- s->token.val = TOK_NUMBER;
- s->token.u.num.val = ret;
- }
- break;
- case '*':
- if (p[1] == '=') {
- p += 2;
- s->token.val = TOK_MUL_ASSIGN;
- } else if (p[1] == '*') {
- if (p[2] == '=') {
- p += 3;
- s->token.val = TOK_POW_ASSIGN;
- } else {
- p += 2;
- s->token.val = TOK_POW;
- }
- } else {
- goto def_token;
- }
- break;
- case '%':
- if (p[1] == '=') {
- p += 2;
- s->token.val = TOK_MOD_ASSIGN;
- } else {
- goto def_token;
- }
- break;
- case '+':
- if (p[1] == '=') {
- p += 2;
- s->token.val = TOK_PLUS_ASSIGN;
- } else if (p[1] == '+') {
- p += 2;
- s->token.val = TOK_INC;
- } else {
- goto def_token;
- }
- break;
- case '-':
- if (p[1] == '=') {
- p += 2;
- s->token.val = TOK_MINUS_ASSIGN;
- } else if (p[1] == '-') {
- if (s->allow_html_comments && p[2] == '>' &&
- (s->got_lf || s->last_ptr == s->buf_start)) {
- /* Annex B: `-->` at beginning of line is an html comment end.
- It extends to the end of the line.
- */
- goto skip_line_comment;
- }
- p += 2;
- s->token.val = TOK_DEC;
- } else {
- goto def_token;
- }
- break;
- case '<':
- if (p[1] == '=') {
- p += 2;
- s->token.val = TOK_LTE;
- } else if (p[1] == '<') {
- if (p[2] == '=') {
- p += 3;
- s->token.val = TOK_SHL_ASSIGN;
- } else {
- p += 2;
- s->token.val = TOK_SHL;
- }
- } else if (s->allow_html_comments &&
- p[1] == '!' && p[2] == '-' && p[3] == '-') {
- /* Annex B: handle `<!--` single line html comments */
- goto skip_line_comment;
- } else {
- goto def_token;
- }
- break;
- case '>':
- if (p[1] == '=') {
- p += 2;
- s->token.val = TOK_GTE;
- } else if (p[1] == '>') {
- if (p[2] == '>') {
- if (p[3] == '=') {
- p += 4;
- s->token.val = TOK_SHR_ASSIGN;
- } else {
- p += 3;
- s->token.val = TOK_SHR;
- }
- } else if (p[2] == '=') {
- p += 3;
- s->token.val = TOK_SAR_ASSIGN;
- } else {
- p += 2;
- s->token.val = TOK_SAR;
- }
- } else {
- goto def_token;
- }
- break;
- case '=':
- if (p[1] == '=') {
- if (p[2] == '=') {
- p += 3;
- s->token.val = TOK_STRICT_EQ;
- } else {
- p += 2;
- s->token.val = TOK_EQ;
- }
- } else if (p[1] == '>') {
- p += 2;
- s->token.val = TOK_ARROW;
- } else {
- goto def_token;
- }
- break;
- case '!':
- if (p[1] == '=') {
- if (p[2] == '=') {
- p += 3;
- s->token.val = TOK_STRICT_NEQ;
- } else {
- p += 2;
- s->token.val = TOK_NEQ;
- }
- } else {
- goto def_token;
- }
- break;
- case '&':
- if (p[1] == '=') {
- p += 2;
- s->token.val = TOK_AND_ASSIGN;
- } else if (p[1] == '&') {
- if (p[2] == '=') {
- p += 3;
- s->token.val = TOK_LAND_ASSIGN;
- } else {
- p += 2;
- s->token.val = TOK_LAND;
- }
- } else {
- goto def_token;
- }
- break;
- case '^':
- if (p[1] == '=') {
- p += 2;
- s->token.val = TOK_XOR_ASSIGN;
- } else {
- goto def_token;
- }
- break;
- case '|':
- if (p[1] == '=') {
- p += 2;
- s->token.val = TOK_OR_ASSIGN;
- } else if (p[1] == '|') {
- if (p[2] == '=') {
- p += 3;
- s->token.val = TOK_LOR_ASSIGN;
- } else {
- p += 2;
- s->token.val = TOK_LOR;
- }
- } else {
- goto def_token;
- }
- break;
- case '?':
- if (p[1] == '?') {
- if (p[2] == '=') {
- p += 3;
- s->token.val = TOK_DOUBLE_QUESTION_MARK_ASSIGN;
- } else {
- p += 2;
- s->token.val = TOK_DOUBLE_QUESTION_MARK;
- }
- } else if (p[1] == '.' && !(p[2] >= '0' && p[2] <= '9')) {
- p += 2;
- s->token.val = TOK_QUESTION_MARK_DOT;
- } else {
- goto def_token;
- }
- break;
- default:
- if (c >= 0x80) { /* non-ASCII code-point */
- c = utf8_decode(p, &p_next);
- if (p_next == p + 1)
- goto invalid_utf8;
- p = p_next;
- switch(c) {
- case CP_PS:
- case CP_LS:
- /* XXX: should avoid incrementing line_number, but
- needed to handle HTML comments */
- goto line_terminator;
- default:
- if (lre_is_space(c)) {
- s->mark = p;
- goto redo;
- } else if (lre_js_is_ident_first(c)) {
- ident_has_escape = false;
- goto has_ident;
- } else {
- js_parse_error(s, "unexpected character");
- goto fail;
- }
- }
- }
- def_token:
- s->token.val = c;
- p++;
- break;
- }
- s->token.col_num = max_int(1, s->mark - s->eol);
- s->buf_ptr = p;
- // dump_token(s, &s->token);
- return 0;
- invalid_utf8:
- js_parse_error(s, "invalid UTF-8 sequence");
- fail:
- s->token.val = TOK_ERROR;
- return -1;
- }
- #endif // QJS_DISABLE_PARSER
- static int json_parse_error(JSParseState *s, const uint8_t *curp, const char *msg)
- {
- const uint8_t *p, *line_start;
- int position = curp - s->buf_start;
- int line = 1;
- for (line_start = p = s->buf_start; p < curp; p++) {
- /* column count does not account for TABs nor wide characters */
- if (*p == '\r' || *p == '\n') {
- p += 1 + (p[0] == '\r' && p[1] == '\n');
- line++;
- line_start = p;
- }
- }
- return js_parse_error(s, "%s in JSON at position %d (line %d column %d)",
- msg, position, line, (int)(p - line_start) + 1);
- }
- static int json_parse_string(JSParseState *s, const uint8_t **pp)
- {
- const uint8_t *p, *p_next;
- int i;
- uint32_t c;
- StringBuffer b_s, *b = &b_s;
- if (string_buffer_init(s->ctx, b, 32))
- goto fail;
- p = *pp;
- for(;;) {
- if (p >= s->buf_end) {
- goto end_of_input;
- }
- c = *p++;
- if (c == '"')
- break;
- if (c < 0x20) {
- json_parse_error(s, p - 1, "Bad control character in string literal");
- goto fail;
- }
- if (c == '\\') {
- c = *p++;
- switch(c) {
- case 'b': c = '\b'; break;
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case '\"': break;
- case '\\': break;
- case '/': break; /* for v8 compatibility */
- case 'u':
- c = 0;
- for(i = 0; i < 4; i++) {
- int h = from_hex(*p++);
- if (h < 0) {
- json_parse_error(s, p - 1, "Bad Unicode escape");
- goto fail;
- }
- c = (c << 4) | h;
- }
- break;
- default:
- if (p > s->buf_end)
- goto end_of_input;
- json_parse_error(s, p - 1, "Bad escaped character");
- goto fail;
- }
- } else
- if (c >= 0x80) {
- c = utf8_decode(p - 1, &p_next);
- if (p_next == p) {
- json_parse_error(s, p - 1, "Bad UTF-8 sequence");
- goto fail;
- }
- p = p_next;
- }
- if (string_buffer_putc(b, c))
- goto fail;
- }
- s->token.val = TOK_STRING;
- s->token.u.str.sep = '"';
- s->token.u.str.str = string_buffer_end(b);
- *pp = p;
- return 0;
- end_of_input:
- js_parse_error(s, "Unexpected end of JSON input");
- fail:
- string_buffer_free(b);
- return -1;
- }
- static int json_parse_number(JSParseState *s, const uint8_t **pp)
- {
- const uint8_t *p = *pp;
- const uint8_t *p_start = p;
- if (*p == '+' || *p == '-')
- p++;
- if (!is_digit(*p))
- return js_parse_error(s, "Unexpected token '%c'", *p_start);
- if (p[0] == '0' && is_digit(p[1]))
- return json_parse_error(s, p, "Unexpected number");
- while (is_digit(*p))
- p++;
- if (*p == '.') {
- p++;
- if (!is_digit(*p))
- return json_parse_error(s, p, "Unterminated fractional number");
- while (is_digit(*p))
- p++;
- }
- if (*p == 'e' || *p == 'E') {
- p++;
- if (*p == '+' || *p == '-')
- p++;
- if (!is_digit(*p))
- return json_parse_error(s, p, "Exponent part is missing a number");
- while (is_digit(*p))
- p++;
- }
- s->token.val = TOK_NUMBER;
- s->token.u.num.val = js_float64(strtod((const char *)p_start, NULL));
- *pp = p;
- return 0;
- }
- /* 'c' is the first character. Return JS_ATOM_NULL in case of error */
- static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
- {
- const uint8_t *p;
- char ident_buf[128], *buf;
- size_t ident_size, ident_pos;
- JSAtom atom;
- p = *pp;
- buf = ident_buf;
- ident_size = sizeof(ident_buf);
- ident_pos = 0;
- for(;;) {
- buf[ident_pos++] = c;
- c = *p;
- if (c >= 128 ||
- !((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1))
- break;
- p++;
- if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
- if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
- atom = JS_ATOM_NULL;
- goto done;
- }
- }
- }
- /* buf contains pure ASCII */
- atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
- done:
- if (unlikely(buf != ident_buf))
- js_free(s->ctx, buf);
- *pp = p;
- return atom;
- }
- static __exception int json_next_token(JSParseState *s)
- {
- const uint8_t *p, *p_next;
- int c;
- JSAtom atom;
- if (js_check_stack_overflow(s->ctx->rt, 1000)) {
- JS_ThrowStackOverflow(s->ctx);
- return -1;
- }
- free_token(s, &s->token);
- p = s->last_ptr = s->buf_ptr;
- s->last_line_num = s->token.line_num;
- s->last_col_num = s->token.col_num;
- redo:
- s->token.line_num = s->line_num;
- s->token.col_num = s->col_num;
- s->token.ptr = p;
- c = *p;
- switch(c) {
- case 0:
- if (p >= s->buf_end) {
- s->token.val = TOK_EOF;
- } else {
- goto def_token;
- }
- break;
- case '\'':
- /* JSON does not accept single quoted strings */
- goto def_token;
- case '\"':
- p++;
- if (json_parse_string(s, &p))
- goto fail;
- break;
- case '\r': /* accept DOS and MAC newline sequences */
- if (p[1] == '\n') {
- p++;
- }
- /* fall thru */
- case '\n':
- s->line_num++;
- s->eol = p++;
- s->mark = p;
- goto redo;
- case '\f':
- case '\v':
- /* JSONWhitespace does not match <VT>, nor <FF> */
- goto def_token;
- case ' ':
- case '\t':
- p++;
- s->mark = p;
- goto redo;
- case '/':
- /* JSON does not accept comments */
- goto def_token;
- case 'a': case 'b': case 'c': case 'd':
- case 'e': case 'f': case 'g': case 'h':
- case 'i': case 'j': case 'k': case 'l':
- case 'm': case 'n': case 'o': case 'p':
- case 'q': case 'r': case 's': case 't':
- case 'u': case 'v': case 'w': case 'x':
- case 'y': case 'z':
- case 'A': case 'B': case 'C': case 'D':
- case 'E': case 'F': case 'G': case 'H':
- case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'P':
- case 'Q': case 'R': case 'S': case 'T':
- case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- case '_':
- case '$':
- /* identifier : only pure ascii characters are accepted */
- p++;
- atom = json_parse_ident(s, &p, c);
- if (atom == JS_ATOM_NULL)
- goto fail;
- s->token.u.ident.atom = atom;
- s->token.u.ident.has_escape = false;
- s->token.u.ident.is_reserved = false;
- s->token.val = TOK_IDENT;
- break;
- case '-':
- if (!is_digit(p[1])) {
- json_parse_error(s, p, "No number after minus sign");
- goto fail;
- }
- goto parse_number;
- case '0':
- if (is_digit(p[1])) {
- json_parse_error(s, p, "Unexpected number");
- goto fail;
- }
- goto parse_number;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8':
- case '9':
- /* number */
- parse_number:
- if (json_parse_number(s, &p))
- goto fail;
- break;
- default:
- if (c >= 0x80) {
- c = utf8_decode(p, &p_next);
- if (p_next == p + 1) {
- js_parse_error(s, "Unexpected token '\\x%02x' in JSON", *p);
- } else {
- if (c > 0xFFFF) {
- c = get_hi_surrogate(c);
- }
- js_parse_error(s, "Unexpected token '\\u%04x' in JSON", c);
- }
- goto fail;
- }
- def_token:
- s->token.val = c;
- p++;
- break;
- }
- s->token.col_num = s->mark - s->eol;
- s->buf_ptr = p;
- // dump_token(s, &s->token);
- return 0;
- fail:
- s->token.val = TOK_ERROR;
- return -1;
- }
- #ifndef QJS_DISABLE_PARSER
- /* only used for ':' and '=>', 'let' or 'function' look-ahead. *pp is
- only set if TOK_IMPORT is returned */
- /* XXX: handle all unicode cases */
- static int simple_next_token(const uint8_t **pp, bool no_line_terminator)
- {
- const uint8_t *p;
- uint32_t c;
- /* skip spaces and comments */
- p = *pp;
- for (;;) {
- switch(c = *p++) {
- case '\r':
- case '\n':
- if (no_line_terminator)
- return '\n';
- continue;
- case ' ':
- case '\t':
- case '\v':
- case '\f':
- continue;
- case '/':
- if (*p == '/') {
- if (no_line_terminator)
- return '\n';
- while (*p && *p != '\r' && *p != '\n')
- p++;
- continue;
- }
- if (*p == '*') {
- while (*++p) {
- if ((*p == '\r' || *p == '\n') && no_line_terminator)
- return '\n';
- if (*p == '*' && p[1] == '/') {
- p += 2;
- break;
- }
- }
- continue;
- }
- break;
- case '=':
- if (*p == '>')
- return TOK_ARROW;
- break;
- default:
- if (lre_js_is_ident_first(c)) {
- if (c == 'i') {
- if (p[0] == 'n' && !lre_js_is_ident_next(p[1])) {
- return TOK_IN;
- }
- if (p[0] == 'm' && p[1] == 'p' && p[2] == 'o' &&
- p[3] == 'r' && p[4] == 't' &&
- !lre_js_is_ident_next(p[5])) {
- *pp = p + 5;
- return TOK_IMPORT;
- }
- } else if (c == 'o' && *p == 'f' && !lre_js_is_ident_next(p[1])) {
- return TOK_OF;
- } else if (c == 'e' &&
- p[0] == 'x' && p[1] == 'p' && p[2] == 'o' &&
- p[3] == 'r' && p[4] == 't' &&
- !lre_js_is_ident_next(p[5])) {
- *pp = p + 5;
- return TOK_EXPORT;
- } else if (c == 'f' && p[0] == 'u' && p[1] == 'n' &&
- p[2] == 'c' && p[3] == 't' && p[4] == 'i' &&
- p[5] == 'o' && p[6] == 'n' && !lre_js_is_ident_next(p[7])) {
- return TOK_FUNCTION;
- } else if (c == 'a' && p[0] == 'w' && p[1] == 'a' &&
- p[2] == 'i' && p[3] == 't' && !lre_js_is_ident_next(p[4])) {
- return TOK_AWAIT;
- }
- return TOK_IDENT;
- }
- break;
- }
- return c;
- }
- }
- static int peek_token(JSParseState *s, bool no_line_terminator)
- {
- const uint8_t *p = s->buf_ptr;
- return simple_next_token(&p, no_line_terminator);
- }
- static void skip_shebang(const uint8_t **pp, const uint8_t *buf_end)
- {
- const uint8_t *p = *pp;
- int c;
- if (p[0] == '#' && p[1] == '!') {
- p += 2;
- while (p < buf_end) {
- if (*p == '\n' || *p == '\r') {
- break;
- } else if (*p >= 0x80) {
- c = utf8_decode(p, &p);
- /* purposely ignore UTF-8 encoding errors in this comment line */
- if (c == CP_LS || c == CP_PS)
- break;
- } else {
- p++;
- }
- }
- *pp = p;
- }
- }
- static inline int get_prev_opcode(JSFunctionDef *fd) {
- if (fd->last_opcode_pos < 0 || dbuf_error(&fd->byte_code))
- return OP_invalid;
- else
- return fd->byte_code.buf[fd->last_opcode_pos];
- }
- static bool js_is_live_code(JSParseState *s) {
- switch (get_prev_opcode(s->cur_func)) {
- case OP_tail_call:
- case OP_tail_call_method:
- case OP_return:
- case OP_return_undef:
- case OP_return_async:
- case OP_throw:
- case OP_throw_error:
- case OP_goto:
- case OP_goto8:
- case OP_goto16:
- case OP_ret:
- return false;
- default:
- return true;
- }
- }
- static void emit_u8(JSParseState *s, uint8_t val)
- {
- dbuf_putc(&s->cur_func->byte_code, val);
- }
- static void emit_u16(JSParseState *s, uint16_t val)
- {
- dbuf_put_u16(&s->cur_func->byte_code, val);
- }
- static void emit_u32(JSParseState *s, uint32_t val)
- {
- dbuf_put_u32(&s->cur_func->byte_code, val);
- }
- static void emit_source_loc(JSParseState *s)
- {
- JSFunctionDef *fd = s->cur_func;
- DynBuf *bc = &fd->byte_code;
- dbuf_putc(bc, OP_source_loc);
- dbuf_put_u32(bc, s->token.line_num);
- dbuf_put_u32(bc, s->token.col_num);
- }
- static void emit_op(JSParseState *s, uint8_t val)
- {
- JSFunctionDef *fd = s->cur_func;
- DynBuf *bc = &fd->byte_code;
- fd->last_opcode_pos = bc->size;
- dbuf_putc(bc, val);
- }
- static void emit_atom(JSParseState *s, JSAtom name)
- {
- DynBuf *bc = &s->cur_func->byte_code;
- if (dbuf_realloc(bc, bc->size + 4))
- return; /* not enough memory : don't duplicate the atom */
- put_u32(bc->buf + bc->size, JS_DupAtom(s->ctx, name));
- bc->size += 4;
- }
- static int update_label(JSFunctionDef *s, int label, int delta)
- {
- LabelSlot *ls;
- assert(label >= 0 && label < s->label_count);
- ls = &s->label_slots[label];
- ls->ref_count += delta;
- assert(ls->ref_count >= 0);
- return ls->ref_count;
- }
- static int new_label_fd(JSFunctionDef *fd)
- {
- int label;
- LabelSlot *ls;
- if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
- sizeof(fd->label_slots[0]),
- &fd->label_size, fd->label_count + 1))
- return -1;
- label = fd->label_count++;
- ls = &fd->label_slots[label];
- ls->ref_count = 0;
- ls->pos = -1;
- ls->pos2 = -1;
- ls->addr = -1;
- ls->first_reloc = NULL;
- return label;
- }
- static int new_label(JSParseState *s)
- {
- int label;
- label = new_label_fd(s->cur_func);
- if (unlikely(label < 0)) {
- dbuf_set_error(&s->cur_func->byte_code);
- }
- return label;
- }
- /* don't update the last opcode and don't emit line number info */
- static void emit_label_raw(JSParseState *s, int label)
- {
- emit_u8(s, OP_label);
- emit_u32(s, label);
- s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
- }
- /* return the label ID offset */
- static int emit_label(JSParseState *s, int label)
- {
- if (label >= 0) {
- emit_op(s, OP_label);
- emit_u32(s, label);
- s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
- return s->cur_func->byte_code.size - 4;
- } else {
- return -1;
- }
- }
- /* return label or -1 if dead code */
- static int emit_goto(JSParseState *s, int opcode, int label)
- {
- if (js_is_live_code(s)) {
- if (label < 0) {
- label = new_label(s);
- if (label < 0)
- return -1;
- }
- emit_op(s, opcode);
- emit_u32(s, label);
- s->cur_func->label_slots[label].ref_count++;
- return label;
- }
- return -1;
- }
- /* return the constant pool index. 'val' is not duplicated. */
- static int cpool_add(JSParseState *s, JSValue val)
- {
- JSFunctionDef *fd = s->cur_func;
- if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]),
- &fd->cpool_size, fd->cpool_count + 1))
- return -1;
- fd->cpool[fd->cpool_count++] = val;
- return fd->cpool_count - 1;
- }
- static __exception int emit_push_const(JSParseState *s, JSValue val,
- bool as_atom)
- {
- int idx;
- if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING && as_atom) {
- JSAtom atom;
- /* warning: JS_NewAtomStr frees the string value */
- js_dup(val);
- atom = JS_NewAtomStr(s->ctx, JS_VALUE_GET_STRING(val));
- if (atom != JS_ATOM_NULL && !__JS_AtomIsTaggedInt(atom)) {
- emit_op(s, OP_push_atom_value);
- emit_u32(s, atom);
- return 0;
- }
- }
- idx = cpool_add(s, js_dup(val));
- if (idx < 0)
- return -1;
- emit_op(s, OP_push_const);
- emit_u32(s, idx);
- return 0;
- }
- // perl hash; variation of k&r hash with a different magic multiplier
- // and a final shuffle to improve distribution of the low-order bits
- static uint32_t hash_bytes(uint32_t h, const void *b, size_t n)
- {
- const char *p;
- for (p = b; p < (char *)b + n; p++)
- h = 33*h + *p;
- h += h >> 5;
- return h;
- }
- static uint32_t hash_atom(JSAtom atom)
- {
- return hash_bytes(0, &atom, sizeof(atom));
- }
- // caveat emptor: the table size must be a power of two in order for
- // masking to work, and the load factor constant must be an odd number (5)
- //
- // f(n)=n+n/t is used to estimate the load factor but changing t to an
- // even number introduces gaps in the output of f, sometimes "jumping"
- // over the next power of two; it's at powers of two when the hash table
- // must be resized
- static int update_var_htab(JSContext *ctx, JSFunctionDef *fd)
- {
- uint32_t i, j, k, m, *p;
- if (fd->var_count < 27) // 27 + 27/5 == 32
- return 0;
- k = fd->var_count - 1;
- m = fd->var_count + fd->var_count/5;
- if (m & (m - 1)) // unless power of two
- goto insert;
- m *= 2;
- p = js_realloc(ctx, fd->vars_htab, m * sizeof(*fd->vars_htab));
- if (!p)
- return -1;
- for (i = 0; i < m; i++)
- p[i] = UINT32_MAX;
- fd->vars_htab = p;
- k = 0;
- m--;
- insert:
- m = UINT32_MAX >> clz32(m);
- do {
- i = hash_atom(fd->vars[k].var_name);
- j = 1;
- for (;;) {
- p = &fd->vars_htab[i & m];
- if (*p == UINT32_MAX)
- break;
- i += j;
- j += 1; // quadratic probing
- }
- *p = k++;
- } while (k < (uint32_t)fd->var_count);
- return 0;
- }
- static int find_var_htab(JSFunctionDef *fd, JSAtom var_name)
- {
- uint32_t i, j, m, *p;
- i = hash_atom(var_name);
- j = 1;
- m = fd->var_count + fd->var_count/5;
- m = UINT32_MAX >> clz32(m);
- for (;;) {
- p = &fd->vars_htab[i & m];
- if (*p == UINT32_MAX)
- return -1;
- if (fd->vars[*p].var_name == var_name)
- return *p;
- i += j;
- j += 1; // quadratic probing
- }
- return -1; // pacify compiler
- }
- /* return the variable index or -1 if not found,
- add ARGUMENT_VAR_OFFSET for argument variables */
- static int find_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
- {
- int i;
- for(i = fd->arg_count; i-- > 0;) {
- if (fd->args[i].var_name == name)
- return i | ARGUMENT_VAR_OFFSET;
- }
- return -1;
- }
- static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
- {
- JSVarDef *vd;
- int i;
- if (fd->vars_htab) {
- i = find_var_htab(fd, name);
- if (i == -1)
- goto not_found;
- vd = &fd->vars[i];
- if (fd->vars[i].scope_level == 0)
- return i;
- }
- for(i = fd->var_count; i-- > 0;) {
- vd = &fd->vars[i];
- if (vd->var_name == name)
- if (vd->scope_level == 0)
- return i;
- }
- not_found:
- return find_arg(ctx, fd, name);
- }
- /* find a variable declaration in a given scope */
- static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd,
- JSAtom name, int scope_level)
- {
- int scope_idx;
- for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0;
- scope_idx = fd->vars[scope_idx].scope_next) {
- if (fd->vars[scope_idx].scope_level != scope_level)
- break;
- if (fd->vars[scope_idx].var_name == name)
- return scope_idx;
- }
- return -1;
- }
- /* return true if scope == parent_scope or if scope is a child of
- parent_scope */
- static bool is_child_scope(JSContext *ctx, JSFunctionDef *fd,
- int scope, int parent_scope)
- {
- while (scope >= 0) {
- if (scope == parent_scope)
- return true;
- scope = fd->scopes[scope].parent;
- }
- return false;
- }
- /* find a 'var' declaration in the same scope or a child scope */
- static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,
- JSAtom name, int scope_level)
- {
- int i;
- for(i = 0; i < fd->var_count; i++) {
- JSVarDef *vd = &fd->vars[i];
- if (vd->var_name == name && vd->scope_level == 0) {
- if (is_child_scope(ctx, fd, vd->scope_next,
- scope_level))
- return i;
- }
- }
- return -1;
- }
- static JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name)
- {
- int i;
- for(i = 0; i < fd->global_var_count; i++) {
- JSGlobalVar *hf = &fd->global_vars[i];
- if (hf->var_name == name)
- return hf;
- }
- return NULL;
- }
- static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name)
- {
- JSGlobalVar *hf = find_global_var(fd, name);
- if (hf && hf->is_lexical)
- return hf;
- else
- return NULL;
- }
- static int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
- int scope_idx, bool check_catch_var)
- {
- while (scope_idx >= 0) {
- JSVarDef *vd = &fd->vars[scope_idx];
- if (vd->var_name == name &&
- (vd->is_lexical || (vd->var_kind == JS_VAR_CATCH &&
- check_catch_var)))
- return scope_idx;
- scope_idx = vd->scope_next;
- }
- if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) {
- if (find_lexical_global_var(fd, name))
- return GLOBAL_VAR_OFFSET;
- }
- return -1;
- }
- static int push_scope(JSParseState *s) {
- if (s->cur_func) {
- JSFunctionDef *fd = s->cur_func;
- int scope = fd->scope_count;
- /* XXX: should check for scope overflow */
- if ((fd->scope_count + 1) > fd->scope_size) {
- int new_size;
- size_t slack;
- JSVarScope *new_buf;
- /* XXX: potential arithmetic overflow */
- new_size = max_int(fd->scope_count + 1, fd->scope_size * 3 / 2);
- if (fd->scopes == fd->def_scope_array) {
- new_buf = js_realloc2(s->ctx, NULL, new_size * sizeof(*fd->scopes), &slack);
- if (!new_buf)
- return -1;
- memcpy(new_buf, fd->scopes, fd->scope_count * sizeof(*fd->scopes));
- } else {
- new_buf = js_realloc2(s->ctx, fd->scopes, new_size * sizeof(*fd->scopes), &slack);
- if (!new_buf)
- return -1;
- }
- new_size += slack / sizeof(*new_buf);
- fd->scopes = new_buf;
- fd->scope_size = new_size;
- }
- fd->scope_count++;
- fd->scopes[scope].parent = fd->scope_level;
- fd->scopes[scope].first = fd->scope_first;
- emit_op(s, OP_enter_scope);
- emit_u16(s, scope);
- return fd->scope_level = scope;
- }
- return 0;
- }
- static int get_first_lexical_var(JSFunctionDef *fd, int scope)
- {
- while (scope >= 0) {
- int scope_idx = fd->scopes[scope].first;
- if (scope_idx >= 0)
- return scope_idx;
- scope = fd->scopes[scope].parent;
- }
- return -1;
- }
- static void pop_scope(JSParseState *s) {
- if (s->cur_func) {
- /* disable scoped variables */
- JSFunctionDef *fd = s->cur_func;
- int scope = fd->scope_level;
- emit_op(s, OP_leave_scope);
- emit_u16(s, scope);
- fd->scope_level = fd->scopes[scope].parent;
- fd->scope_first = get_first_lexical_var(fd, fd->scope_level);
- }
- }
- static void close_scopes(JSParseState *s, int scope, int scope_stop)
- {
- while (scope > scope_stop) {
- emit_op(s, OP_leave_scope);
- emit_u16(s, scope);
- scope = s->cur_func->scopes[scope].parent;
- }
- }
- /* return the variable index or -1 if error */
- static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
- {
- JSVarDef *vd;
- /* the local variable indexes are currently stored on 16 bits */
- if (fd->var_count >= JS_MAX_LOCAL_VARS) {
- // XXX: add_var() should take JSParseState *s and use js_parse_error
- JS_ThrowSyntaxError(ctx, "too many variables declared (only %d allowed)",
- JS_MAX_LOCAL_VARS - 1);
- return -1;
- }
- if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]),
- &fd->var_size, fd->var_count + 1))
- return -1;
- vd = &fd->vars[fd->var_count++];
- memset(vd, 0, sizeof(*vd));
- vd->var_name = JS_DupAtom(ctx, name);
- vd->func_pool_idx = -1;
- if (update_var_htab(ctx, fd))
- return -1;
- return fd->var_count - 1;
- }
- static int add_scope_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
- JSVarKindEnum var_kind)
- {
- int idx = add_var(ctx, fd, name);
- if (idx >= 0) {
- JSVarDef *vd = &fd->vars[idx];
- vd->var_kind = var_kind;
- vd->scope_level = fd->scope_level;
- vd->scope_next = fd->scope_first;
- fd->scopes[fd->scope_level].first = idx;
- fd->scope_first = idx;
- }
- return idx;
- }
- static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
- {
- int idx = fd->func_var_idx;
- if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {
- fd->func_var_idx = idx;
- fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME;
- if (fd->is_strict_mode)
- fd->vars[idx].is_const = true;
- }
- return idx;
- }
- static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd)
- {
- int idx = fd->arguments_var_idx;
- if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) {
- fd->arguments_var_idx = idx;
- }
- return idx;
- }
- /* add an argument definition in the argument scope. Only needed when
- "eval()" may be called in the argument scope. Return 0 if OK. */
- static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd)
- {
- int idx;
- if (fd->arguments_arg_idx < 0) {
- idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX);
- if (idx < 0) {
- /* XXX: the scope links are not fully updated. May be an
- issue if there are child scopes of the argument
- scope */
- idx = add_var(ctx, fd, JS_ATOM_arguments);
- if (idx < 0)
- return -1;
- fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first;
- fd->scopes[ARG_SCOPE_INDEX].first = idx;
- fd->vars[idx].scope_level = ARG_SCOPE_INDEX;
- fd->vars[idx].is_lexical = true;
- fd->arguments_arg_idx = idx;
- }
- }
- return 0;
- }
- static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
- {
- JSVarDef *vd;
- /* the local variable indexes are currently stored on 16 bits */
- if (fd->arg_count >= JS_MAX_LOCAL_VARS) {
- // XXX: add_arg() should take JSParseState *s and use js_parse_error
- JS_ThrowSyntaxError(ctx, "too many parameters in function definition (only %d allowed)",
- JS_MAX_LOCAL_VARS - 1);
- return -1;
- }
- if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]),
- &fd->arg_size, fd->arg_count + 1))
- return -1;
- vd = &fd->args[fd->arg_count++];
- memset(vd, 0, sizeof(*vd));
- vd->var_name = JS_DupAtom(ctx, name);
- vd->func_pool_idx = -1;
- return fd->arg_count - 1;
- }
- /* add a global variable definition */
- static JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s,
- JSAtom name)
- {
- JSGlobalVar *hf;
- if (js_resize_array(ctx, (void **)&s->global_vars,
- sizeof(s->global_vars[0]),
- &s->global_var_size, s->global_var_count + 1))
- return NULL;
- hf = &s->global_vars[s->global_var_count++];
- hf->cpool_idx = -1;
- hf->force_init = false;
- hf->is_lexical = false;
- hf->is_const = false;
- hf->scope_level = s->scope_level;
- hf->var_name = JS_DupAtom(ctx, name);
- return hf;
- }
- typedef enum {
- JS_VAR_DEF_WITH,
- JS_VAR_DEF_LET,
- JS_VAR_DEF_CONST,
- JS_VAR_DEF_FUNCTION_DECL, /* function declaration */
- JS_VAR_DEF_NEW_FUNCTION_DECL, /* async/generator function declaration */
- JS_VAR_DEF_CATCH,
- JS_VAR_DEF_VAR,
- } JSVarDefEnum;
- static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
- JSVarDefEnum var_def_type)
- {
- JSContext *ctx = s->ctx;
- JSVarDef *vd;
- int idx;
- switch (var_def_type) {
- case JS_VAR_DEF_WITH:
- idx = add_scope_var(ctx, fd, name, JS_VAR_NORMAL);
- break;
- case JS_VAR_DEF_LET:
- case JS_VAR_DEF_CONST:
- case JS_VAR_DEF_FUNCTION_DECL:
- case JS_VAR_DEF_NEW_FUNCTION_DECL:
- idx = find_lexical_decl(ctx, fd, name, fd->scope_first, true);
- if (idx >= 0) {
- if (idx < GLOBAL_VAR_OFFSET) {
- if (fd->vars[idx].scope_level == fd->scope_level) {
- /* same scope: in non strict mode, functions
- can be redefined (annex B.3.3.4). */
- if (!(!fd->is_strict_mode &&
- var_def_type == JS_VAR_DEF_FUNCTION_DECL &&
- fd->vars[idx].var_kind == JS_VAR_FUNCTION_DECL)) {
- goto redef_lex_error;
- }
- } else if (fd->vars[idx].var_kind == JS_VAR_CATCH && (fd->vars[idx].scope_level + 2) == fd->scope_level) {
- goto redef_lex_error;
- }
- } else {
- if (fd->scope_level == fd->body_scope) {
- redef_lex_error:
- /* redefining a scoped var in the same scope: error */
- return js_parse_error(s, "invalid redefinition of lexical identifier");
- }
- }
- }
- if (var_def_type != JS_VAR_DEF_FUNCTION_DECL &&
- var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL &&
- fd->scope_level == fd->body_scope &&
- find_arg(ctx, fd, name) >= 0) {
- /* lexical variable redefines a parameter name */
- return js_parse_error(s, "invalid redefinition of parameter name");
- }
- if (find_var_in_child_scope(ctx, fd, name, fd->scope_level) >= 0) {
- return js_parse_error(s, "invalid redefinition of a variable");
- }
- if (fd->is_global_var) {
- JSGlobalVar *hf;
- hf = find_global_var(fd, name);
- if (hf && is_child_scope(ctx, fd, hf->scope_level,
- fd->scope_level)) {
- return js_parse_error(s, "invalid redefinition of global identifier");
- }
- }
- if (fd->is_eval &&
- (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
- fd->eval_type == JS_EVAL_TYPE_MODULE) &&
- fd->scope_level == fd->body_scope) {
- JSGlobalVar *hf;
- hf = add_global_var(s->ctx, fd, name);
- if (!hf)
- return -1;
- hf->is_lexical = true;
- hf->is_const = (var_def_type == JS_VAR_DEF_CONST);
- idx = GLOBAL_VAR_OFFSET;
- } else {
- JSVarKindEnum var_kind;
- if (var_def_type == JS_VAR_DEF_FUNCTION_DECL)
- var_kind = JS_VAR_FUNCTION_DECL;
- else if (var_def_type == JS_VAR_DEF_NEW_FUNCTION_DECL)
- var_kind = JS_VAR_NEW_FUNCTION_DECL;
- else
- var_kind = JS_VAR_NORMAL;
- idx = add_scope_var(ctx, fd, name, var_kind);
- if (idx >= 0) {
- vd = &fd->vars[idx];
- vd->is_lexical = 1;
- vd->is_const = (var_def_type == JS_VAR_DEF_CONST);
- }
- }
- break;
- case JS_VAR_DEF_CATCH:
- idx = add_scope_var(ctx, fd, name, JS_VAR_CATCH);
- break;
- case JS_VAR_DEF_VAR:
- if (find_lexical_decl(ctx, fd, name, fd->scope_first,
- false) >= 0) {
- invalid_lexical_redefinition:
- /* error to redefine a var that inside a lexical scope */
- return js_parse_error(s, "invalid redefinition of lexical identifier");
- }
- if (fd->is_global_var) {
- JSGlobalVar *hf;
- hf = find_global_var(fd, name);
- if (hf && hf->is_lexical && hf->scope_level == fd->scope_level &&
- fd->eval_type == JS_EVAL_TYPE_MODULE) {
- goto invalid_lexical_redefinition;
- }
- hf = add_global_var(s->ctx, fd, name);
- if (!hf)
- return -1;
- idx = GLOBAL_VAR_OFFSET;
- } else {
- /* if the variable already exists, don't add it again */
- idx = find_var(ctx, fd, name);
- if (idx >= 0)
- break;
- idx = add_var(ctx, fd, name);
- if (idx >= 0) {
- if (name == JS_ATOM_arguments && fd->has_arguments_binding)
- fd->arguments_var_idx = idx;
- fd->vars[idx].scope_next = fd->scope_level;
- }
- }
- break;
- default:
- abort();
- }
- return idx;
- }
- /* add a private field variable in the current scope */
- static int add_private_class_field(JSParseState *s, JSFunctionDef *fd,
- JSAtom name, JSVarKindEnum var_kind, bool is_static)
- {
- JSContext *ctx = s->ctx;
- JSVarDef *vd;
- int idx;
- idx = add_scope_var(ctx, fd, name, var_kind);
- if (idx < 0)
- return idx;
- vd = &fd->vars[idx];
- vd->is_lexical = 1;
- vd->is_const = 1;
- vd->is_static_private = is_static;
- return idx;
- }
- static __exception int js_parse_expr(JSParseState *s);
- static __exception int js_parse_function_decl(JSParseState *s,
- JSParseFunctionEnum func_type,
- JSFunctionKindEnum func_kind,
- JSAtom func_name, const uint8_t *ptr,
- int start_line, int start_col);
- static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s);
- static __exception int js_parse_function_decl2(JSParseState *s,
- JSParseFunctionEnum func_type,
- JSFunctionKindEnum func_kind,
- JSAtom func_name,
- const uint8_t *ptr,
- int function_line_num,
- int function_col_num,
- JSParseExportEnum export_flag,
- JSFunctionDef **pfd);
- static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
- static __exception int js_parse_assign_expr(JSParseState *s);
- static __exception int js_parse_unary(JSParseState *s, int parse_flags);
- static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
- JSAtom label_name,
- int label_break, int label_cont,
- int drop_count);
- static void pop_break_entry(JSFunctionDef *fd);
- static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
- JSAtom local_name, JSAtom export_name,
- JSExportTypeEnum export_type);
- /* Note: all the fields are already sealed except length */
- static int seal_template_obj(JSContext *ctx, JSValue obj)
- {
- JSObject *p;
- JSShapeProperty *prs;
- p = JS_VALUE_GET_OBJ(obj);
- prs = find_own_property1(p, JS_ATOM_length);
- if (prs) {
- if (js_update_property_flags(ctx, p, &prs,
- prs->flags & ~(JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)))
- return -1;
- }
- p->extensible = false;
- return 0;
- }
- static __exception int js_parse_template(JSParseState *s, int call, int *argc)
- {
- JSContext *ctx = s->ctx;
- JSValue raw_array, template_object;
- JSToken cooked;
- int depth, ret;
- raw_array = JS_UNDEFINED; /* avoid warning */
- template_object = JS_UNDEFINED; /* avoid warning */
- if (call) {
- /* Create a template object: an array of cooked strings */
- /* Create an array of raw strings and store it to the raw property */
- template_object = JS_NewArray(ctx);
- if (JS_IsException(template_object))
- return -1;
- // pool_idx = s->cur_func->cpool_count;
- ret = emit_push_const(s, template_object, 0);
- JS_FreeValue(ctx, template_object);
- if (ret)
- return -1;
- raw_array = JS_NewArray(ctx);
- if (JS_IsException(raw_array))
- return -1;
- if (JS_DefinePropertyValue(ctx, template_object, JS_ATOM_raw,
- raw_array, JS_PROP_THROW) < 0) {
- return -1;
- }
- }
- depth = 0;
- while (s->token.val == TOK_TEMPLATE) {
- const uint8_t *p = s->token.ptr + 1;
- cooked = s->token;
- if (call) {
- if (JS_DefinePropertyValueUint32(ctx, raw_array, depth,
- js_dup(s->token.u.str.str),
- JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
- return -1;
- }
- /* re-parse the string with escape sequences but do not throw a
- syntax error if it contains invalid sequences
- */
- if (js_parse_string(s, '`', false, p, &cooked, &p)) {
- cooked.u.str.str = JS_UNDEFINED;
- }
- if (JS_DefinePropertyValueUint32(ctx, template_object, depth,
- cooked.u.str.str,
- JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
- return -1;
- }
- } else {
- JSString *str;
- /* re-parse the string with escape sequences and throw a
- syntax error if it contains invalid sequences
- */
- JS_FreeValue(ctx, s->token.u.str.str);
- s->token.u.str.str = JS_UNDEFINED;
- if (js_parse_string(s, '`', true, p, &cooked, &p))
- return -1;
- str = JS_VALUE_GET_STRING(cooked.u.str.str);
- if (str->len != 0 || depth == 0) {
- ret = emit_push_const(s, cooked.u.str.str, 1);
- JS_FreeValue(s->ctx, cooked.u.str.str);
- if (ret)
- return -1;
- if (depth == 0) {
- if (s->token.u.str.sep == '`')
- goto done1;
- emit_op(s, OP_get_field2);
- emit_atom(s, JS_ATOM_concat);
- }
- depth++;
- } else {
- JS_FreeValue(s->ctx, cooked.u.str.str);
- }
- }
- if (s->token.u.str.sep == '`')
- goto done;
- if (next_token(s))
- return -1;
- if (js_parse_expr(s))
- return -1;
- depth++;
- if (s->token.val != '}') {
- return js_parse_error(s, "expected '}' after template expression");
- }
- /* XXX: should convert to string at this stage? */
- free_token(s, &s->token);
- /* Resume TOK_TEMPLATE parsing (s->token.line_num and
- * s->token.ptr are OK) */
- s->got_lf = false;
- s->last_line_num = s->token.line_num;
- s->last_col_num = s->token.col_num;
- if (js_parse_template_part(s, s->buf_ptr))
- return -1;
- }
- return js_parse_expect(s, TOK_TEMPLATE);
- done:
- if (call) {
- /* Seal the objects */
- seal_template_obj(ctx, raw_array);
- seal_template_obj(ctx, template_object);
- *argc = depth + 1;
- } else {
- emit_op(s, OP_call_method);
- emit_u16(s, depth - 1);
- }
- done1:
- return next_token(s);
- }
- #define PROP_TYPE_IDENT 0
- #define PROP_TYPE_VAR 1
- #define PROP_TYPE_GET 2
- #define PROP_TYPE_SET 3
- #define PROP_TYPE_STAR 4
- #define PROP_TYPE_ASYNC 5
- #define PROP_TYPE_ASYNC_STAR 6
- #define PROP_TYPE_PRIVATE (1 << 4)
- static bool token_is_ident(int tok)
- {
- /* Accept keywords and reserved words as property names */
- return (tok == TOK_IDENT ||
- (tok >= TOK_FIRST_KEYWORD &&
- tok <= TOK_LAST_KEYWORD));
- }
- /* if the property is an expression, name = JS_ATOM_NULL */
- static int __exception js_parse_property_name(JSParseState *s,
- JSAtom *pname,
- bool allow_method, bool allow_var,
- bool allow_private)
- {
- int is_private = 0;
- bool is_non_reserved_ident;
- JSAtom name;
- int prop_type;
- prop_type = PROP_TYPE_IDENT;
- if (allow_method) {
- if (token_is_pseudo_keyword(s, JS_ATOM_get)
- || token_is_pseudo_keyword(s, JS_ATOM_set)) {
- /* get x(), set x() */
- name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
- if (next_token(s))
- goto fail1;
- if (s->token.val == ':' || s->token.val == ',' ||
- s->token.val == '}' || s->token.val == '(' ||
- s->token.val == '=' || s->token.val == ';') {
- is_non_reserved_ident = true;
- goto ident_found;
- }
- prop_type = PROP_TYPE_GET + (name == JS_ATOM_set);
- JS_FreeAtom(s->ctx, name);
- } else if (s->token.val == '*') {
- if (next_token(s))
- goto fail;
- prop_type = PROP_TYPE_STAR;
- } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
- peek_token(s, true) != '\n') {
- name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
- if (next_token(s))
- goto fail1;
- if (s->token.val == ':' || s->token.val == ',' ||
- s->token.val == '}' || s->token.val == '(' ||
- s->token.val == '=' || s->token.val == ';') {
- is_non_reserved_ident = true;
- goto ident_found;
- }
- JS_FreeAtom(s->ctx, name);
- if (s->token.val == '*') {
- if (next_token(s))
- goto fail;
- prop_type = PROP_TYPE_ASYNC_STAR;
- } else {
- prop_type = PROP_TYPE_ASYNC;
- }
- }
- }
- if (token_is_ident(s->token.val)) {
- /* variable can only be a non-reserved identifier */
- is_non_reserved_ident =
- (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved);
- /* keywords and reserved words have a valid atom */
- name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
- if (next_token(s))
- goto fail1;
- ident_found:
- if (is_non_reserved_ident &&
- prop_type == PROP_TYPE_IDENT && allow_var) {
- if (!(s->token.val == ':' ||
- (s->token.val == '(' && allow_method))) {
- prop_type = PROP_TYPE_VAR;
- }
- }
- } else if (s->token.val == TOK_STRING) {
- name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
- if (name == JS_ATOM_NULL)
- goto fail;
- if (next_token(s))
- goto fail1;
- } else if (s->token.val == TOK_NUMBER) {
- JSValue val;
- val = s->token.u.num.val;
- name = JS_ValueToAtom(s->ctx, val);
- if (name == JS_ATOM_NULL)
- goto fail;
- if (next_token(s))
- goto fail1;
- } else if (s->token.val == '[') {
- if (next_token(s))
- goto fail;
- if (js_parse_expr(s))
- goto fail;
- if (js_parse_expect(s, ']'))
- goto fail;
- name = JS_ATOM_NULL;
- } else if (s->token.val == TOK_PRIVATE_NAME && allow_private) {
- name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
- if (next_token(s))
- goto fail1;
- is_private = PROP_TYPE_PRIVATE;
- } else {
- goto invalid_prop;
- }
- if (prop_type != PROP_TYPE_IDENT && prop_type != PROP_TYPE_VAR &&
- s->token.val != '(') {
- JS_FreeAtom(s->ctx, name);
- invalid_prop:
- js_parse_error(s, "invalid property name");
- goto fail;
- }
- *pname = name;
- return prop_type | is_private;
- fail1:
- JS_FreeAtom(s->ctx, name);
- fail:
- *pname = JS_ATOM_NULL;
- return -1;
- }
- typedef struct JSParsePos {
- int last_line_num;
- int last_col_num;
- int line_num;
- int col_num;
- bool got_lf;
- const uint8_t *ptr;
- const uint8_t *eol;
- const uint8_t *mark;
- } JSParsePos;
- static int js_parse_get_pos(JSParseState *s, JSParsePos *sp)
- {
- sp->last_line_num = s->last_line_num;
- sp->last_col_num = s->last_col_num;
- sp->line_num = s->token.line_num;
- sp->col_num = s->token.col_num;
- sp->ptr = s->token.ptr;
- sp->eol = s->eol;
- sp->mark = s->mark;
- sp->got_lf = s->got_lf;
- return 0;
- }
- static __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)
- {
- s->token.line_num = sp->last_line_num;
- s->token.col_num = sp->last_col_num;
- s->line_num = sp->line_num;
- s->col_num = sp->col_num;
- s->buf_ptr = sp->ptr;
- s->eol = sp->eol;
- s->mark = sp->mark;
- s->got_lf = sp->got_lf;
- return next_token(s);
- }
- /* return true if a regexp literal is allowed after this token */
- static bool is_regexp_allowed(int tok)
- {
- switch (tok) {
- case TOK_NUMBER:
- case TOK_STRING:
- case TOK_REGEXP:
- case TOK_DEC:
- case TOK_INC:
- case TOK_NULL:
- case TOK_FALSE:
- case TOK_TRUE:
- case TOK_THIS:
- case ')':
- case ']':
- case '}': /* XXX: regexp may occur after */
- case TOK_IDENT:
- return false;
- default:
- return true;
- }
- }
- #define SKIP_HAS_SEMI (1 << 0)
- #define SKIP_HAS_ELLIPSIS (1 << 1)
- #define SKIP_HAS_ASSIGNMENT (1 << 2)
- /* XXX: improve speed with early bailout */
- /* XXX: no longer works if regexps are present. Could use previous
- regexp parsing heuristics to handle most cases */
- static int js_parse_skip_parens_token(JSParseState *s, int *pbits, bool no_line_terminator)
- {
- char state[256];
- size_t level = 0;
- JSParsePos pos;
- int last_tok, tok = TOK_EOF;
- int c, tok_len, bits = 0;
- /* protect from underflow */
- state[level++] = 0;
- js_parse_get_pos(s, &pos);
- last_tok = 0;
- for (;;) {
- switch(s->token.val) {
- case '(':
- case '[':
- case '{':
- if (level >= sizeof(state))
- goto done;
- state[level++] = s->token.val;
- break;
- case ')':
- if (state[--level] != '(')
- goto done;
- break;
- case ']':
- if (state[--level] != '[')
- goto done;
- break;
- case '}':
- c = state[--level];
- if (c == '`') {
- /* continue the parsing of the template */
- free_token(s, &s->token);
- /* Resume TOK_TEMPLATE parsing (s->token.line_num and
- * s->token.ptr are OK) */
- s->got_lf = false;
- s->last_line_num = s->token.line_num;
- s->last_col_num = s->token.col_num;
- if (js_parse_template_part(s, s->buf_ptr))
- goto done;
- goto handle_template;
- } else if (c != '{') {
- goto done;
- }
- break;
- case TOK_TEMPLATE:
- handle_template:
- if (s->token.u.str.sep != '`') {
- /* '${' inside the template : closing '}' and continue
- parsing the template */
- if (level >= sizeof(state))
- goto done;
- state[level++] = '`';
- }
- break;
- case TOK_EOF:
- goto done;
- case ';':
- if (level == 2) {
- bits |= SKIP_HAS_SEMI;
- }
- break;
- case TOK_ELLIPSIS:
- if (level == 2) {
- bits |= SKIP_HAS_ELLIPSIS;
- }
- break;
- case '=':
- bits |= SKIP_HAS_ASSIGNMENT;
- break;
- case TOK_DIV_ASSIGN:
- tok_len = 2;
- goto parse_regexp;
- case '/':
- tok_len = 1;
- parse_regexp:
- if (is_regexp_allowed(last_tok)) {
- s->buf_ptr -= tok_len;
- if (js_parse_regexp(s)) {
- /* XXX: should clear the exception */
- goto done;
- }
- }
- break;
- }
- /* last_tok is only used to recognize regexps */
- if (s->token.val == TOK_IDENT &&
- (token_is_pseudo_keyword(s, JS_ATOM_of) ||
- token_is_pseudo_keyword(s, JS_ATOM_yield))) {
- last_tok = TOK_OF;
- } else {
- last_tok = s->token.val;
- }
- if (next_token(s)) {
- /* XXX: should clear the exception generated by next_token() */
- break;
- }
- if (level <= 1) {
- tok = s->token.val;
- if (token_is_pseudo_keyword(s, JS_ATOM_of))
- tok = TOK_OF;
- if (no_line_terminator && s->last_line_num != s->token.line_num)
- tok = '\n';
- break;
- }
- }
- done:
- if (pbits) {
- *pbits = bits;
- }
- if (js_parse_seek_token(s, &pos))
- return -1;
- return tok;
- }
- static void set_object_name(JSParseState *s, JSAtom name)
- {
- JSFunctionDef *fd = s->cur_func;
- int opcode;
- opcode = get_prev_opcode(fd);
- if (opcode == OP_set_name) {
- /* XXX: should free atom after OP_set_name? */
- fd->byte_code.size = fd->last_opcode_pos;
- fd->last_opcode_pos = -1;
- emit_op(s, OP_set_name);
- emit_atom(s, name);
- } else if (opcode == OP_set_class_name) {
- int define_class_pos;
- JSAtom atom;
- define_class_pos = fd->last_opcode_pos + 1 -
- get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
- assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
- /* for consistency we free the previous atom which is
- JS_ATOM_empty_string */
- atom = get_u32(fd->byte_code.buf + define_class_pos + 1);
- JS_FreeAtom(s->ctx, atom);
- put_u32(fd->byte_code.buf + define_class_pos + 1,
- JS_DupAtom(s->ctx, name));
- fd->last_opcode_pos = -1;
- }
- }
- static void set_object_name_computed(JSParseState *s)
- {
- JSFunctionDef *fd = s->cur_func;
- int opcode;
- opcode = get_prev_opcode(fd);
- if (opcode == OP_set_name) {
- /* XXX: should free atom after OP_set_name? */
- fd->byte_code.size = fd->last_opcode_pos;
- fd->last_opcode_pos = -1;
- emit_op(s, OP_set_name_computed);
- } else if (opcode == OP_set_class_name) {
- int define_class_pos;
- define_class_pos = fd->last_opcode_pos + 1 -
- get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
- assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
- fd->byte_code.buf[define_class_pos] = OP_define_class_computed;
- fd->last_opcode_pos = -1;
- }
- }
- static __exception int js_parse_object_literal(JSParseState *s)
- {
- JSAtom name = JS_ATOM_NULL;
- const uint8_t *start_ptr;
- int start_line, start_col, prop_type;
- bool has_proto;
- if (next_token(s))
- goto fail;
- /* XXX: add an initial length that will be patched back */
- emit_op(s, OP_object);
- has_proto = false;
- while (s->token.val != '}') {
- /* specific case for getter/setter */
- start_ptr = s->token.ptr;
- start_line = s->token.line_num;
- start_col = s->token.col_num;
- if (s->token.val == TOK_ELLIPSIS) {
- if (next_token(s))
- return -1;
- if (js_parse_assign_expr(s))
- return -1;
- emit_op(s, OP_null); /* dummy excludeList */
- emit_op(s, OP_copy_data_properties);
- emit_u8(s, 2 | (1 << 2) | (0 << 5));
- emit_op(s, OP_drop); /* pop excludeList */
- emit_op(s, OP_drop); /* pop src object */
- goto next;
- }
- prop_type = js_parse_property_name(s, &name, true, true, false);
- if (prop_type < 0)
- goto fail;
- if (prop_type == PROP_TYPE_VAR) {
- /* shortcut for x: x */
- emit_op(s, OP_scope_get_var);
- emit_atom(s, name);
- emit_u16(s, s->cur_func->scope_level);
- emit_op(s, OP_define_field);
- emit_atom(s, name);
- } else if (s->token.val == '(') {
- bool is_getset = (prop_type == PROP_TYPE_GET ||
- prop_type == PROP_TYPE_SET);
- JSParseFunctionEnum func_type;
- JSFunctionKindEnum func_kind;
- int op_flags;
- func_kind = JS_FUNC_NORMAL;
- if (is_getset) {
- func_type = JS_PARSE_FUNC_GETTER + prop_type - PROP_TYPE_GET;
- } else {
- func_type = JS_PARSE_FUNC_METHOD;
- if (prop_type == PROP_TYPE_STAR)
- func_kind = JS_FUNC_GENERATOR;
- else if (prop_type == PROP_TYPE_ASYNC)
- func_kind = JS_FUNC_ASYNC;
- else if (prop_type == PROP_TYPE_ASYNC_STAR)
- func_kind = JS_FUNC_ASYNC_GENERATOR;
- }
- if (js_parse_function_decl(s, func_type, func_kind, JS_ATOM_NULL,
- start_ptr, start_line, start_col))
- goto fail;
- if (name == JS_ATOM_NULL) {
- emit_op(s, OP_define_method_computed);
- } else {
- emit_op(s, OP_define_method);
- emit_atom(s, name);
- }
- if (is_getset) {
- op_flags = OP_DEFINE_METHOD_GETTER +
- prop_type - PROP_TYPE_GET;
- } else {
- op_flags = OP_DEFINE_METHOD_METHOD;
- }
- emit_u8(s, op_flags | OP_DEFINE_METHOD_ENUMERABLE);
- } else {
- if (js_parse_expect(s, ':'))
- goto fail;
- if (js_parse_assign_expr(s))
- goto fail;
- if (name == JS_ATOM_NULL) {
- set_object_name_computed(s);
- emit_op(s, OP_define_array_el);
- emit_op(s, OP_drop);
- } else if (name == JS_ATOM___proto__) {
- if (has_proto) {
- js_parse_error(s, "duplicate __proto__ property name");
- goto fail;
- }
- emit_op(s, OP_set_proto);
- has_proto = true;
- } else {
- set_object_name(s, name);
- emit_op(s, OP_define_field);
- emit_atom(s, name);
- }
- }
- JS_FreeAtom(s->ctx, name);
- next:
- name = JS_ATOM_NULL;
- if (s->token.val != ',')
- break;
- if (next_token(s))
- goto fail;
- }
- if (js_parse_expect(s, '}'))
- goto fail;
- return 0;
- fail:
- JS_FreeAtom(s->ctx, name);
- return -1;
- }
- /* allow the 'in' binary operator */
- #define PF_IN_ACCEPTED (1 << 0)
- /* allow function calls parsing in js_parse_postfix_expr() */
- #define PF_POSTFIX_CALL (1 << 1)
- /* allow the exponentiation operator in js_parse_unary() */
- #define PF_POW_ALLOWED (1 << 2)
- /* forbid the exponentiation operator in js_parse_unary() */
- #define PF_POW_FORBIDDEN (1 << 3)
- static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
- static __exception int js_parse_left_hand_side_expr(JSParseState *s)
- {
- return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
- }
- /* find field in the current scope */
- static int find_private_class_field(JSContext *ctx, JSFunctionDef *fd,
- JSAtom name, int scope_level)
- {
- int idx;
- idx = fd->scopes[scope_level].first;
- while (idx != -1) {
- if (fd->vars[idx].scope_level != scope_level)
- break;
- if (fd->vars[idx].var_name == name)
- return idx;
- idx = fd->vars[idx].scope_next;
- }
- return -1;
- }
- /* initialize the class fields, called by the constructor. Note:
- super() can be called in an arrow function, so <this> and
- <class_fields_init> can be variable references */
- static void emit_class_field_init(JSParseState *s)
- {
- int label_next;
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_class_fields_init);
- emit_u16(s, s->cur_func->scope_level);
- /* no need to call the class field initializer if not defined */
- emit_op(s, OP_dup);
- label_next = emit_goto(s, OP_if_false, -1);
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_this);
- emit_u16(s, 0);
- emit_op(s, OP_swap);
- emit_op(s, OP_call_method);
- emit_u16(s, 0);
- emit_label(s, label_next);
- emit_op(s, OP_drop);
- }
- /* build a private setter function name from the private getter name */
- static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name)
- {
- return js_atom_concat_str(ctx, name, "<set>");
- }
- typedef struct {
- JSFunctionDef *fields_init_fd;
- int computed_fields_count;
- bool need_brand;
- int brand_push_pos;
- bool is_static;
- } ClassFieldsDef;
- static __exception int emit_class_init_start(JSParseState *s,
- ClassFieldsDef *cf)
- {
- int label_add_brand;
- cf->fields_init_fd = js_parse_function_class_fields_init(s);
- if (!cf->fields_init_fd)
- return -1;
- s->cur_func = cf->fields_init_fd;
- if (!cf->is_static) {
- /* add the brand to the newly created instance */
- /* XXX: would be better to add the code only if needed, maybe in a
- later pass */
- emit_op(s, OP_push_false); /* will be patched later */
- cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos;
- label_add_brand = emit_goto(s, OP_if_false, -1);
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_this);
- emit_u16(s, 0);
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_home_object);
- emit_u16(s, 0);
- emit_op(s, OP_add_brand);
- emit_label(s, label_add_brand);
- }
- s->cur_func = s->cur_func->parent;
- return 0;
- }
- static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf)
- {
- int cpool_idx;
- s->cur_func = cf->fields_init_fd;
- emit_op(s, OP_return_undef);
- s->cur_func = s->cur_func->parent;
- cpool_idx = cpool_add(s, JS_NULL);
- cf->fields_init_fd->parent_cpool_idx = cpool_idx;
- emit_op(s, OP_fclosure);
- emit_u32(s, cpool_idx);
- emit_op(s, OP_set_home_object);
- }
- static void emit_return(JSParseState *s, bool hasval);
- static JSFunctionDef *js_new_function_def(JSContext *ctx,
- JSFunctionDef *parent,
- bool is_eval,
- bool is_func_expr,
- const char *filename,
- int line_num,
- int col_num);
- static __exception int js_parse_class_default_ctor(JSParseState *s,
- bool has_super,
- JSFunctionDef **pfd)
- {
- JSParseFunctionEnum func_type;
- JSFunctionDef *fd = s->cur_func;
- fd = js_new_function_def(s->ctx, fd, false, false, s->filename,
- s->token.line_num, s->token.col_num);
- if (!fd)
- return -1;
- s->cur_func = fd;
- fd->has_home_object = true;
- fd->super_allowed = true;
- fd->has_prototype = false;
- fd->has_this_binding = true;
- fd->new_target_allowed = true;
- push_scope(s); /* enter body scope */
- fd->body_scope = fd->scope_level;
- if (has_super) {
- fd->is_derived_class_constructor = true;
- fd->super_call_allowed = true;
- fd->arguments_allowed = true;
- fd->has_arguments_binding = true;
- func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
- emit_op(s, OP_init_ctor);
- // TODO(bnoordhuis) roll into OP_init_ctor
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, JS_ATOM_this);
- emit_u16(s, 0);
- emit_class_field_init(s);
- } else {
- func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
- /* error if not invoked as a constructor */
- emit_op(s, OP_check_ctor);
- emit_class_field_init(s);
- }
- fd->func_kind = JS_FUNC_NORMAL;
- fd->func_type = func_type;
- emit_return(s, false);
- s->cur_func = fd->parent;
- if (pfd)
- *pfd = fd;
- int idx;
- /* the real object will be set at the end of the compilation */
- idx = cpool_add(s, JS_NULL);
- fd->parent_cpool_idx = idx;
- return 0;
- }
- static __exception int js_parse_class(JSParseState *s, bool is_class_expr,
- JSParseExportEnum export_flag)
- {
- JSContext *ctx = s->ctx;
- JSFunctionDef *fd = s->cur_func;
- JSAtom name = JS_ATOM_NULL, class_name = JS_ATOM_NULL, class_name1;
- JSAtom class_var_name = JS_ATOM_NULL;
- JSFunctionDef *method_fd, *ctor_fd;
- int class_name_var_idx, prop_type, ctor_cpool_offset;
- int class_flags = 0, i, define_class_offset;
- bool is_static, is_private, is_strict_mode;
- const uint8_t *class_start_ptr = s->token.ptr;
- const uint8_t *start_ptr;
- ClassFieldsDef class_fields[2];
- /* classes are parsed and executed in strict mode */
- is_strict_mode = fd->is_strict_mode;
- fd->is_strict_mode = true;
- if (next_token(s))
- goto fail;
- if (s->token.val == TOK_IDENT) {
- if (s->token.u.ident.is_reserved) {
- js_parse_error_reserved_identifier(s);
- goto fail;
- }
- class_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- if (next_token(s))
- goto fail;
- } else if (!is_class_expr && export_flag != JS_PARSE_EXPORT_DEFAULT) {
- js_parse_error(s, "class statement requires a name");
- goto fail;
- }
- if (!is_class_expr) {
- if (class_name == JS_ATOM_NULL)
- class_var_name = JS_ATOM__default_; /* export default */
- else
- class_var_name = class_name;
- class_var_name = JS_DupAtom(ctx, class_var_name);
- }
- push_scope(s);
- if (s->token.val == TOK_EXTENDS) {
- class_flags = JS_DEFINE_CLASS_HAS_HERITAGE;
- if (next_token(s))
- goto fail;
- if (js_parse_left_hand_side_expr(s))
- goto fail;
- } else {
- emit_op(s, OP_undefined);
- }
- /* add a 'const' definition for the class name */
- if (class_name != JS_ATOM_NULL) {
- class_name_var_idx = define_var(s, fd, class_name, JS_VAR_DEF_CONST);
- if (class_name_var_idx < 0)
- goto fail;
- }
- if (js_parse_expect(s, '{'))
- goto fail;
- /* this scope contains the private fields */
- push_scope(s);
- emit_op(s, OP_push_const);
- ctor_cpool_offset = fd->byte_code.size;
- emit_u32(s, 0); /* will be patched at the end of the class parsing */
- if (class_name == JS_ATOM_NULL) {
- if (class_var_name != JS_ATOM_NULL)
- class_name1 = JS_ATOM_default;
- else
- class_name1 = JS_ATOM_empty_string;
- } else {
- class_name1 = class_name;
- }
- emit_op(s, OP_define_class);
- emit_atom(s, class_name1);
- emit_u8(s, class_flags);
- define_class_offset = fd->last_opcode_pos;
- for(i = 0; i < 2; i++) {
- ClassFieldsDef *cf = &class_fields[i];
- cf->fields_init_fd = NULL;
- cf->computed_fields_count = 0;
- cf->need_brand = false;
- cf->is_static = i;
- }
- ctor_fd = NULL;
- while (s->token.val != '}') {
- if (s->token.val == ';') {
- if (next_token(s))
- goto fail;
- continue;
- }
- is_static = false;
- if (s->token.val == TOK_STATIC) {
- int next = peek_token(s, true);
- if (!(next == ';' || next == '}' || next == '(' || next == '='))
- is_static = true;
- }
- prop_type = -1;
- if (is_static) {
- if (next_token(s))
- goto fail;
- if (s->token.val == '{') {
- ClassFieldsDef *cf = &class_fields[is_static];
- if (!cf->fields_init_fd)
- if (emit_class_init_start(s, cf))
- goto fail;
- s->cur_func = cf->fields_init_fd;
- // stack is now: <empty>
- JSFunctionDef *init;
- if (js_parse_function_decl2(s, JS_PARSE_FUNC_CLASS_STATIC_INIT,
- JS_FUNC_NORMAL, JS_ATOM_NULL,
- s->token.ptr,
- s->token.line_num,
- s->token.col_num,
- JS_PARSE_EXPORT_NONE, &init) < 0) {
- goto fail;
- }
- // stack is now: fclosure
- push_scope(s);
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_this);
- emit_u16(s, 0);
- // stack is now: fclosure this
- if (class_name != JS_ATOM_NULL) {
- // TODO(bnoordhuis) pass as argument to init method?
- emit_op(s, OP_dup);
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, class_name);
- emit_u16(s, s->cur_func->scope_level);
- }
- emit_op(s, OP_swap);
- // stack is now: this fclosure
- emit_op(s, OP_call_method);
- emit_u16(s, 0);
- // stack is now: returnvalue
- emit_op(s, OP_drop);
- // stack is now: <empty>
- pop_scope(s);
- s->cur_func = s->cur_func->parent;
- continue;
- }
- /* allow "static" field name */
- if (s->token.val == ';' || s->token.val == '=') {
- is_static = false;
- name = JS_DupAtom(ctx, JS_ATOM_static);
- prop_type = PROP_TYPE_IDENT;
- }
- }
- if (is_static)
- emit_op(s, OP_swap);
- start_ptr = s->token.ptr;
- if (prop_type < 0) {
- prop_type = js_parse_property_name(s, &name, true, false, true);
- if (prop_type < 0)
- goto fail;
- }
- is_private = prop_type & PROP_TYPE_PRIVATE;
- prop_type &= ~PROP_TYPE_PRIVATE;
- if ((name == JS_ATOM_constructor && !is_static &&
- prop_type != PROP_TYPE_IDENT) ||
- (name == JS_ATOM_prototype && is_static) ||
- name == JS_ATOM_hash_constructor) {
- js_parse_error(s, "invalid method name");
- goto fail;
- }
- if (prop_type == PROP_TYPE_GET || prop_type == PROP_TYPE_SET) {
- bool is_set = prop_type - PROP_TYPE_GET;
- JSFunctionDef *method_fd;
- if (is_private) {
- int idx, var_kind, is_static1;
- idx = find_private_class_field(ctx, fd, name, fd->scope_level);
- if (idx >= 0) {
- var_kind = fd->vars[idx].var_kind;
- is_static1 = fd->vars[idx].is_static_private;
- if (var_kind == JS_VAR_PRIVATE_FIELD ||
- var_kind == JS_VAR_PRIVATE_METHOD ||
- var_kind == JS_VAR_PRIVATE_GETTER_SETTER ||
- var_kind == (JS_VAR_PRIVATE_GETTER + is_set) ||
- (var_kind == (JS_VAR_PRIVATE_GETTER + 1 - is_set) &&
- is_static != is_static1)) {
- goto private_field_already_defined;
- }
- fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER;
- } else {
- if (add_private_class_field(s, fd, name,
- JS_VAR_PRIVATE_GETTER + is_set, is_static) < 0)
- goto fail;
- }
- class_fields[is_static].need_brand = true;
- }
- if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set,
- JS_FUNC_NORMAL, JS_ATOM_NULL,
- start_ptr,
- s->token.line_num,
- s->token.col_num,
- JS_PARSE_EXPORT_NONE, &method_fd))
- goto fail;
- if (is_private) {
- method_fd->need_home_object = true; /* needed for brand check */
- emit_op(s, OP_set_home_object);
- /* XXX: missing function name */
- emit_op(s, OP_scope_put_var_init);
- if (is_set) {
- JSAtom setter_name;
- int ret;
- setter_name = get_private_setter_name(ctx, name);
- if (setter_name == JS_ATOM_NULL)
- goto fail;
- emit_atom(s, setter_name);
- ret = add_private_class_field(s, fd, setter_name,
- JS_VAR_PRIVATE_SETTER, is_static);
- JS_FreeAtom(ctx, setter_name);
- if (ret < 0)
- goto fail;
- } else {
- emit_atom(s, name);
- }
- emit_u16(s, s->cur_func->scope_level);
- } else {
- if (name == JS_ATOM_NULL) {
- emit_op(s, OP_define_method_computed);
- } else {
- emit_op(s, OP_define_method);
- emit_atom(s, name);
- }
- emit_u8(s, OP_DEFINE_METHOD_GETTER + is_set);
- }
- } else if (prop_type == PROP_TYPE_IDENT && s->token.val != '(') {
- ClassFieldsDef *cf = &class_fields[is_static];
- JSAtom field_var_name = JS_ATOM_NULL;
- /* class field */
- /* XXX: spec: not consistent with method name checks */
- if (name == JS_ATOM_constructor || name == JS_ATOM_prototype) {
- js_parse_error(s, "invalid field name");
- goto fail;
- }
- if (is_private) {
- if (find_private_class_field(ctx, fd, name,
- fd->scope_level) >= 0) {
- goto private_field_already_defined;
- }
- if (add_private_class_field(s, fd, name,
- JS_VAR_PRIVATE_FIELD, is_static) < 0)
- goto fail;
- emit_op(s, OP_private_symbol);
- emit_atom(s, name);
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, name);
- emit_u16(s, s->cur_func->scope_level);
- }
- if (!cf->fields_init_fd) {
- if (emit_class_init_start(s, cf))
- goto fail;
- }
- if (name == JS_ATOM_NULL ) {
- /* save the computed field name into a variable */
- field_var_name = js_atom_concat_num(ctx, JS_ATOM_computed_field + is_static, cf->computed_fields_count);
- if (field_var_name == JS_ATOM_NULL)
- goto fail;
- if (define_var(s, fd, field_var_name, JS_VAR_DEF_CONST) < 0) {
- JS_FreeAtom(ctx, field_var_name);
- goto fail;
- }
- emit_op(s, OP_to_propkey);
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, field_var_name);
- emit_u16(s, s->cur_func->scope_level);
- }
- s->cur_func = cf->fields_init_fd;
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_this);
- emit_u16(s, 0);
- // expose class name to static initializers
- if (is_static && class_name != JS_ATOM_NULL) {
- emit_op(s, OP_dup);
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, class_name);
- emit_u16(s, s->cur_func->scope_level);
- }
- if (name == JS_ATOM_NULL) {
- emit_op(s, OP_scope_get_var);
- emit_atom(s, field_var_name);
- emit_u16(s, s->cur_func->scope_level);
- cf->computed_fields_count++;
- JS_FreeAtom(ctx, field_var_name);
- } else if (is_private) {
- emit_op(s, OP_scope_get_var);
- emit_atom(s, name);
- emit_u16(s, s->cur_func->scope_level);
- }
- if (s->token.val == '=') {
- if (next_token(s))
- goto fail;
- if (js_parse_assign_expr(s))
- goto fail;
- } else {
- emit_op(s, OP_undefined);
- }
- if (is_private) {
- set_object_name_computed(s);
- emit_op(s, OP_define_private_field);
- } else if (name == JS_ATOM_NULL) {
- set_object_name_computed(s);
- emit_op(s, OP_define_array_el);
- emit_op(s, OP_drop);
- } else {
- set_object_name(s, name);
- emit_op(s, OP_define_field);
- emit_atom(s, name);
- }
- s->cur_func = s->cur_func->parent;
- if (js_parse_expect_semi(s))
- goto fail;
- } else {
- JSParseFunctionEnum func_type;
- JSFunctionKindEnum func_kind;
- func_type = JS_PARSE_FUNC_METHOD;
- func_kind = JS_FUNC_NORMAL;
- if (prop_type == PROP_TYPE_STAR) {
- func_kind = JS_FUNC_GENERATOR;
- } else if (prop_type == PROP_TYPE_ASYNC) {
- func_kind = JS_FUNC_ASYNC;
- } else if (prop_type == PROP_TYPE_ASYNC_STAR) {
- func_kind = JS_FUNC_ASYNC_GENERATOR;
- } else if (name == JS_ATOM_constructor && !is_static) {
- if (ctor_fd) {
- js_parse_error(s, "property constructor appears more than once");
- goto fail;
- }
- if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE)
- func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
- else
- func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
- }
- if (is_private) {
- class_fields[is_static].need_brand = true;
- }
- if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL,
- start_ptr,
- s->token.line_num,
- s->token.col_num,
- JS_PARSE_EXPORT_NONE, &method_fd))
- goto fail;
- if (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR ||
- func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
- ctor_fd = method_fd;
- } else if (is_private) {
- method_fd->need_home_object = true; /* needed for brand check */
- if (find_private_class_field(ctx, fd, name,
- fd->scope_level) >= 0) {
- private_field_already_defined:
- js_parse_error(s, "private class field is already defined");
- goto fail;
- }
- if (add_private_class_field(s, fd, name,
- JS_VAR_PRIVATE_METHOD, is_static) < 0)
- goto fail;
- emit_op(s, OP_set_home_object);
- emit_op(s, OP_set_name);
- emit_atom(s, name);
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, name);
- emit_u16(s, s->cur_func->scope_level);
- } else {
- if (name == JS_ATOM_NULL) {
- emit_op(s, OP_define_method_computed);
- } else {
- emit_op(s, OP_define_method);
- emit_atom(s, name);
- }
- emit_u8(s, OP_DEFINE_METHOD_METHOD);
- }
- }
- if (is_static)
- emit_op(s, OP_swap);
- JS_FreeAtom(ctx, name);
- name = JS_ATOM_NULL;
- }
- if (s->token.val != '}') {
- js_parse_error(s, "expecting '%c'", '}');
- goto fail;
- }
- if (!ctor_fd) {
- if (js_parse_class_default_ctor(s, class_flags & JS_DEFINE_CLASS_HAS_HERITAGE, &ctor_fd))
- goto fail;
- }
- /* patch the constant pool index for the constructor */
- put_u32(fd->byte_code.buf + ctor_cpool_offset, ctor_fd->parent_cpool_idx);
- /* store the class source code in the constructor. */
- js_free(ctx, ctor_fd->source);
- ctor_fd->source_len = s->buf_ptr - class_start_ptr;
- ctor_fd->source = js_strndup(ctx, (const char *)class_start_ptr, ctor_fd->source_len);
- if (!ctor_fd->source)
- goto fail;
- /* consume the '}' */
- if (next_token(s))
- goto fail;
- {
- ClassFieldsDef *cf = &class_fields[0];
- int var_idx;
- if (cf->need_brand) {
- /* add a private brand to the prototype */
- emit_op(s, OP_dup);
- emit_op(s, OP_null);
- emit_op(s, OP_swap);
- emit_op(s, OP_add_brand);
- /* define the brand field in 'this' of the initializer */
- if (!cf->fields_init_fd) {
- if (emit_class_init_start(s, cf))
- goto fail;
- }
- /* patch the start of the function to enable the
- OP_add_brand_instance code */
- cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true;
- }
- /* store the function to initialize the fields to that it can be
- referenced by the constructor */
- var_idx = define_var(s, fd, JS_ATOM_class_fields_init,
- JS_VAR_DEF_CONST);
- if (var_idx < 0)
- goto fail;
- if (cf->fields_init_fd) {
- emit_class_init_end(s, cf);
- } else {
- emit_op(s, OP_undefined);
- }
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, JS_ATOM_class_fields_init);
- emit_u16(s, s->cur_func->scope_level);
- }
- /* drop the prototype */
- emit_op(s, OP_drop);
- if (class_fields[1].need_brand) {
- /* add a private brand to the class */
- emit_op(s, OP_dup);
- emit_op(s, OP_dup);
- emit_op(s, OP_add_brand);
- }
- /* initialize the static fields */
- if (class_fields[1].fields_init_fd != NULL) {
- ClassFieldsDef *cf = &class_fields[1];
- emit_op(s, OP_dup);
- emit_class_init_end(s, cf);
- emit_op(s, OP_call_method);
- emit_u16(s, 0);
- emit_op(s, OP_drop);
- }
- if (class_name != JS_ATOM_NULL) {
- /* store the class name in the scoped class name variable (it
- is independent from the class statement variable
- definition) */
- emit_op(s, OP_dup);
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, class_name);
- emit_u16(s, fd->scope_level);
- }
- pop_scope(s);
- pop_scope(s);
- /* the class statements have a block level scope */
- if (class_var_name != JS_ATOM_NULL) {
- if (define_var(s, fd, class_var_name, JS_VAR_DEF_LET) < 0)
- goto fail;
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, class_var_name);
- emit_u16(s, fd->scope_level);
- } else {
- if (class_name == JS_ATOM_NULL) {
- /* cannot use OP_set_name because the name of the class
- must be defined before the static initializers are
- executed */
- emit_op(s, OP_set_class_name);
- emit_u32(s, fd->last_opcode_pos + 1 - define_class_offset);
- }
- }
- if (export_flag != JS_PARSE_EXPORT_NONE) {
- if (!add_export_entry(s, fd->module,
- class_var_name,
- export_flag == JS_PARSE_EXPORT_NAMED ? class_var_name : JS_ATOM_default,
- JS_EXPORT_TYPE_LOCAL))
- goto fail;
- }
- JS_FreeAtom(ctx, class_name);
- JS_FreeAtom(ctx, class_var_name);
- fd->is_strict_mode = is_strict_mode;
- return 0;
- fail:
- JS_FreeAtom(ctx, name);
- JS_FreeAtom(ctx, class_name);
- JS_FreeAtom(ctx, class_var_name);
- fd->is_strict_mode = is_strict_mode;
- return -1;
- }
- static __exception int js_parse_array_literal(JSParseState *s)
- {
- uint32_t idx;
- bool need_length;
- if (next_token(s))
- return -1;
- /* small regular arrays are created on the stack */
- idx = 0;
- while (s->token.val != ']' && idx < 32) {
- if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS)
- break;
- if (js_parse_assign_expr(s))
- return -1;
- idx++;
- /* accept trailing comma */
- if (s->token.val == ',') {
- if (next_token(s))
- return -1;
- } else
- if (s->token.val != ']')
- goto done;
- }
- emit_op(s, OP_array_from);
- emit_u16(s, idx);
- /* larger arrays and holes are handled with explicit indices */
- need_length = false;
- while (s->token.val != ']' && idx < 0x7fffffff) {
- if (s->token.val == TOK_ELLIPSIS)
- break;
- need_length = true;
- if (s->token.val != ',') {
- if (js_parse_assign_expr(s))
- return -1;
- emit_op(s, OP_define_field);
- emit_u32(s, __JS_AtomFromUInt32(idx));
- need_length = false;
- }
- idx++;
- /* accept trailing comma */
- if (s->token.val == ',') {
- if (next_token(s))
- return -1;
- }
- }
- if (s->token.val == ']') {
- if (need_length) {
- /* Set the length: Cannot use OP_define_field because
- length is not configurable */
- emit_op(s, OP_dup);
- emit_op(s, OP_push_i32);
- emit_u32(s, idx);
- emit_op(s, OP_put_field);
- emit_atom(s, JS_ATOM_length);
- }
- goto done;
- }
- /* huge arrays and spread elements require a dynamic index on the stack */
- emit_op(s, OP_push_i32);
- emit_u32(s, idx);
- /* stack has array, index */
- while (s->token.val != ']') {
- if (s->token.val == TOK_ELLIPSIS) {
- if (next_token(s))
- return -1;
- if (js_parse_assign_expr(s))
- return -1;
- emit_op(s, OP_append);
- } else {
- need_length = true;
- if (s->token.val != ',') {
- if (js_parse_assign_expr(s))
- return -1;
- /* a idx val */
- emit_op(s, OP_define_array_el);
- need_length = false;
- }
- emit_op(s, OP_inc);
- }
- if (s->token.val != ',')
- break;
- if (next_token(s))
- return -1;
- }
- if (need_length) {
- /* Set the length: cannot use OP_define_field because
- length is not configurable */
- emit_op(s, OP_dup1); /* array length - array array length */
- emit_op(s, OP_put_field);
- emit_atom(s, JS_ATOM_length);
- } else {
- emit_op(s, OP_drop); /* array length - array */
- }
- done:
- return js_parse_expect(s, ']');
- }
- /* XXX: remove */
- static bool has_with_scope(JSFunctionDef *s, int scope_level)
- {
- /* check if scope chain contains a with statement */
- while (s) {
- int scope_idx = s->scopes[scope_level].first;
- while (scope_idx >= 0) {
- JSVarDef *vd = &s->vars[scope_idx];
- if (vd->var_name == JS_ATOM__with_)
- return true;
- scope_idx = vd->scope_next;
- }
- /* check parent scopes */
- scope_level = s->parent_scope_level;
- s = s->parent;
- }
- return false;
- }
- static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
- JSAtom *pname, int *plabel, int *pdepth, bool keep,
- int tok)
- {
- JSFunctionDef *fd;
- int opcode, scope, label, depth;
- JSAtom name;
- /* we check the last opcode to get the lvalue type */
- fd = s->cur_func;
- scope = 0;
- name = JS_ATOM_NULL;
- label = -1;
- depth = 0;
- switch(opcode = get_prev_opcode(fd)) {
- case OP_scope_get_var:
- name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
- scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
- if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) &&
- fd->is_strict_mode) {
- return js_parse_error(s, "invalid lvalue in strict mode");
- }
- if (name == JS_ATOM_this || name == JS_ATOM_new_target)
- goto invalid_lvalue;
- depth = 2; /* will generate OP_get_ref_value */
- break;
- case OP_get_field:
- name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
- depth = 1;
- break;
- case OP_scope_get_private_field:
- name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
- scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
- depth = 1;
- break;
- case OP_get_array_el:
- depth = 2;
- break;
- case OP_get_super_value:
- depth = 3;
- break;
- default:
- invalid_lvalue:
- if (tok == TOK_FOR) {
- return js_parse_error(s, "invalid for in/of left hand-side");
- } else if (tok == TOK_INC || tok == TOK_DEC) {
- return js_parse_error(s, "invalid increment/decrement operand");
- } else if (tok == '[' || tok == '{') {
- return js_parse_error(s, "invalid destructuring target");
- } else {
- return js_parse_error(s, "invalid assignment left-hand side");
- }
- }
- /* remove the last opcode */
- fd->byte_code.size = fd->last_opcode_pos;
- fd->last_opcode_pos = -1;
- if (keep) {
- /* get the value but keep the object/fields on the stack */
- switch(opcode) {
- case OP_scope_get_var:
- label = new_label(s);
- if (label < 0)
- return -1;
- emit_op(s, OP_scope_make_ref);
- emit_atom(s, name);
- emit_u32(s, label);
- emit_u16(s, scope);
- update_label(fd, label, 1);
- emit_op(s, OP_get_ref_value);
- opcode = OP_get_ref_value;
- break;
- case OP_get_field:
- emit_op(s, OP_get_field2);
- emit_atom(s, name);
- break;
- case OP_scope_get_private_field:
- emit_op(s, OP_scope_get_private_field2);
- emit_atom(s, name);
- emit_u16(s, scope);
- break;
- case OP_get_array_el:
- /* XXX: replace by a single opcode ? */
- emit_op(s, OP_to_propkey2);
- emit_op(s, OP_dup2);
- emit_op(s, OP_get_array_el);
- break;
- case OP_get_super_value:
- emit_op(s, OP_to_propkey);
- emit_op(s, OP_dup3);
- emit_op(s, OP_get_super_value);
- break;
- default:
- abort();
- }
- } else {
- switch(opcode) {
- case OP_scope_get_var:
- label = new_label(s);
- if (label < 0)
- return -1;
- emit_op(s, OP_scope_make_ref);
- emit_atom(s, name);
- emit_u32(s, label);
- emit_u16(s, scope);
- update_label(fd, label, 1);
- opcode = OP_get_ref_value;
- break;
- case OP_get_array_el:
- emit_op(s, OP_to_propkey2);
- break;
- case OP_get_super_value:
- emit_op(s, OP_to_propkey);
- break;
- }
- }
- *popcode = opcode;
- *pscope = scope;
- /* name has refcount for OP_get_field and OP_get_ref_value,
- and JS_ATOM_NULL for other opcodes */
- *pname = name;
- *plabel = label;
- if (pdepth)
- *pdepth = depth;
- return 0;
- }
- typedef enum {
- PUT_LVALUE_NOKEEP, /* [depth] v -> */
- PUT_LVALUE_NOKEEP_DEPTH, /* [depth] v -> , keep depth (currently
- just disable optimizations) */
- PUT_LVALUE_KEEP_TOP, /* [depth] v -> v */
- PUT_LVALUE_KEEP_SECOND, /* [depth] v0 v -> v0 */
- PUT_LVALUE_NOKEEP_BOTTOM, /* v [depth] -> */
- } PutLValueEnum;
- /* name has a live reference. 'is_let' is only used with opcode =
- OP_scope_get_var which is never generated by get_lvalue(). */
- static void put_lvalue(JSParseState *s, int opcode, int scope,
- JSAtom name, int label, PutLValueEnum special,
- bool is_let)
- {
- switch(opcode) {
- case OP_get_field:
- case OP_scope_get_private_field:
- /* depth = 1 */
- switch(special) {
- case PUT_LVALUE_NOKEEP:
- case PUT_LVALUE_NOKEEP_DEPTH:
- break;
- case PUT_LVALUE_KEEP_TOP:
- emit_op(s, OP_insert2); /* obj v -> v obj v */
- break;
- case PUT_LVALUE_KEEP_SECOND:
- emit_op(s, OP_perm3); /* obj v0 v -> v0 obj v */
- break;
- case PUT_LVALUE_NOKEEP_BOTTOM:
- emit_op(s, OP_swap);
- break;
- default:
- abort();
- }
- break;
- case OP_get_array_el:
- case OP_get_ref_value:
- /* depth = 2 */
- if (opcode == OP_get_ref_value) {
- JS_FreeAtom(s->ctx, name);
- emit_label(s, label);
- }
- switch(special) {
- case PUT_LVALUE_NOKEEP:
- emit_op(s, OP_nop); /* will trigger optimization */
- break;
- case PUT_LVALUE_NOKEEP_DEPTH:
- break;
- case PUT_LVALUE_KEEP_TOP:
- emit_op(s, OP_insert3); /* obj prop v -> v obj prop v */
- break;
- case PUT_LVALUE_KEEP_SECOND:
- emit_op(s, OP_perm4); /* obj prop v0 v -> v0 obj prop v */
- break;
- case PUT_LVALUE_NOKEEP_BOTTOM:
- emit_op(s, OP_rot3l);
- break;
- default:
- abort();
- }
- break;
- case OP_get_super_value:
- /* depth = 3 */
- switch(special) {
- case PUT_LVALUE_NOKEEP:
- case PUT_LVALUE_NOKEEP_DEPTH:
- break;
- case PUT_LVALUE_KEEP_TOP:
- emit_op(s, OP_insert4); /* this obj prop v -> v this obj prop v */
- break;
- case PUT_LVALUE_KEEP_SECOND:
- emit_op(s, OP_perm5); /* this obj prop v0 v -> v0 this obj prop v */
- break;
- case PUT_LVALUE_NOKEEP_BOTTOM:
- emit_op(s, OP_rot4l);
- break;
- default:
- abort();
- }
- break;
- default:
- break;
- }
- switch(opcode) {
- case OP_scope_get_var: /* val -- */
- assert(special == PUT_LVALUE_NOKEEP ||
- special == PUT_LVALUE_NOKEEP_DEPTH);
- emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var);
- emit_u32(s, name); /* has refcount */
- emit_u16(s, scope);
- break;
- case OP_get_field:
- emit_op(s, OP_put_field);
- emit_u32(s, name); /* name has refcount */
- break;
- case OP_scope_get_private_field:
- emit_op(s, OP_scope_put_private_field);
- emit_u32(s, name); /* name has refcount */
- emit_u16(s, scope);
- break;
- case OP_get_array_el:
- emit_op(s, OP_put_array_el);
- break;
- case OP_get_ref_value:
- emit_op(s, OP_put_ref_value);
- break;
- case OP_get_super_value:
- emit_op(s, OP_put_super_value);
- break;
- default:
- abort();
- }
- }
- static __exception int js_parse_expr_paren(JSParseState *s)
- {
- if (js_parse_expect(s, '('))
- return -1;
- if (js_parse_expr(s))
- return -1;
- if (js_parse_expect(s, ')'))
- return -1;
- return 0;
- }
- static int js_unsupported_keyword(JSParseState *s, JSAtom atom)
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
- return js_parse_error(s, "unsupported keyword: %s",
- JS_AtomGetStr(s->ctx, buf, sizeof(buf), atom));
- }
- static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
- {
- JSFunctionDef *fd = s->cur_func;
- JSVarDefEnum var_def_type;
- if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
- return js_parse_error(s, "yield is a reserved identifier");
- }
- if ((name == JS_ATOM_arguments || name == JS_ATOM_eval)
- && fd->is_strict_mode) {
- return js_parse_error(s, "invalid variable name in strict mode");
- }
- if (tok == TOK_LET || tok == TOK_CONST) {
- if (name == JS_ATOM_let)
- return js_parse_error(s, "invalid lexical variable name 'let'");
- // |undefined| is allowed as an identifier except at the global
- // scope of a classic script; sloppy or strict doesn't matter
- if (name == JS_ATOM_undefined
- && fd->scope_level == 1
- && fd->is_global_var
- && !fd->module) {
- return js_parse_error(s, "'undefined' already declared");
- }
- }
- switch(tok) {
- case TOK_LET:
- var_def_type = JS_VAR_DEF_LET;
- break;
- case TOK_CONST:
- var_def_type = JS_VAR_DEF_CONST;
- break;
- case TOK_VAR:
- var_def_type = JS_VAR_DEF_VAR;
- break;
- case TOK_CATCH:
- var_def_type = JS_VAR_DEF_CATCH;
- break;
- default:
- abort();
- }
- if (define_var(s, fd, name, var_def_type) < 0)
- return -1;
- return 0;
- }
- static void js_emit_spread_code(JSParseState *s, int depth)
- {
- int label_rest_next, label_rest_done;
- /* XXX: could check if enum object is an actual array and optimize
- slice extraction. enumeration record and target array are in a
- different order from OP_append case. */
- /* enum_rec xxx -- enum_rec xxx array 0 */
- emit_op(s, OP_array_from);
- emit_u16(s, 0);
- emit_op(s, OP_push_i32);
- emit_u32(s, 0);
- emit_label(s, label_rest_next = new_label(s));
- emit_op(s, OP_for_of_next);
- emit_u8(s, 2 + depth);
- label_rest_done = emit_goto(s, OP_if_true, -1);
- /* array idx val -- array idx */
- emit_op(s, OP_define_array_el);
- emit_op(s, OP_inc);
- emit_goto(s, OP_goto, label_rest_next);
- emit_label(s, label_rest_done);
- /* enum_rec xxx array idx undef -- enum_rec xxx array */
- emit_op(s, OP_drop);
- emit_op(s, OP_drop);
- }
- static int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name)
- {
- /* Check for duplicate parameter names */
- JSFunctionDef *fd = s->cur_func;
- int i;
- for (i = 0; i < fd->arg_count; i++) {
- if (fd->args[i].var_name == name)
- goto duplicate;
- }
- for (i = 0; i < fd->var_count; i++) {
- if (fd->vars[i].var_name == name)
- goto duplicate;
- }
- return 0;
- duplicate:
- return js_parse_error(s, "Duplicate parameter name not allowed in this context");
- }
- static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, bool is_arg)
- {
- JSAtom name;
- if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
- || (s->cur_func->is_strict_mode &&
- (s->token.u.ident.atom == JS_ATOM_eval || s->token.u.ident.atom == JS_ATOM_arguments))) {
- js_parse_error(s, "invalid destructuring target");
- return JS_ATOM_NULL;
- }
- name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
- if (is_arg && js_parse_check_duplicate_parameter(s, name))
- goto fail;
- if (next_token(s))
- goto fail;
- return name;
- fail:
- JS_FreeAtom(s->ctx, name);
- return JS_ATOM_NULL;
- }
- /* Return -1 if error, 0 if no initializer, 1 if an initializer is
- present at the top level. */
- static int js_parse_destructuring_element(JSParseState *s, int tok,
- bool is_arg, bool hasval,
- int has_ellipsis, // tri-state
- bool allow_initializer,
- bool export_flag)
- {
- int label_parse, label_assign, label_done, label_lvalue, depth_lvalue;
- int start_addr, assign_addr;
- JSAtom prop_name, var_name;
- int opcode, scope, tok1, skip_bits;
- bool has_initializer;
- label_lvalue = -1;
- if (has_ellipsis < 0) {
- /* pre-parse destructuration target for spread detection */
- js_parse_skip_parens_token(s, &skip_bits, false);
- has_ellipsis = skip_bits & SKIP_HAS_ELLIPSIS;
- }
- label_parse = new_label(s);
- label_assign = new_label(s);
- start_addr = s->cur_func->byte_code.size;
- if (hasval) {
- /* consume value from the stack */
- emit_op(s, OP_dup);
- emit_op(s, OP_undefined);
- emit_op(s, OP_strict_eq);
- emit_goto(s, OP_if_true, label_parse);
- emit_label(s, label_assign);
- } else {
- emit_goto(s, OP_goto, label_parse);
- emit_label(s, label_assign);
- /* leave value on the stack */
- emit_op(s, OP_dup);
- }
- assign_addr = s->cur_func->byte_code.size;
- if (s->token.val == '{') {
- if (next_token(s))
- return -1;
- /* throw an exception if the value cannot be converted to an object */
- emit_op(s, OP_to_object);
- if (has_ellipsis) {
- /* add excludeList on stack just below src object */
- emit_op(s, OP_object);
- emit_op(s, OP_swap);
- }
- while (s->token.val != '}') {
- int prop_type;
- if (s->token.val == TOK_ELLIPSIS) {
- if (!has_ellipsis) {
- JS_ThrowInternalError(s->ctx, "unexpected ellipsis token");
- return -1;
- }
- if (next_token(s))
- return -1;
- if (tok) {
- var_name = js_parse_destructuring_var(s, tok, is_arg);
- if (var_name == JS_ATOM_NULL)
- return -1;
- opcode = OP_scope_get_var;
- scope = s->cur_func->scope_level;
- label_lvalue = -1;
- depth_lvalue = 0;
- } else {
- if (js_parse_left_hand_side_expr(s))
- return -1;
- if (get_lvalue(s, &opcode, &scope, &var_name,
- &label_lvalue, &depth_lvalue, false, '{'))
- return -1;
- }
- if (s->token.val != '}') {
- js_parse_error(s, "assignment rest property must be last");
- goto var_error;
- }
- emit_op(s, OP_object); /* target */
- emit_op(s, OP_copy_data_properties);
- emit_u8(s, 0 | ((depth_lvalue + 1) << 2) | ((depth_lvalue + 2) << 5));
- goto set_val;
- }
- prop_type = js_parse_property_name(s, &prop_name, false, true, false);
- if (prop_type < 0)
- return -1;
- var_name = JS_ATOM_NULL;
- opcode = OP_scope_get_var;
- scope = s->cur_func->scope_level;
- label_lvalue = -1;
- depth_lvalue = 0;
- if (prop_type == PROP_TYPE_IDENT) {
- if (next_token(s))
- goto prop_error;
- if ((s->token.val == '[' || s->token.val == '{')
- && ((tok1 = js_parse_skip_parens_token(s, &skip_bits, false)) == ',' ||
- tok1 == '=' || tok1 == '}')) {
- if (prop_name == JS_ATOM_NULL) {
- /* computed property name on stack */
- if (has_ellipsis) {
- /* define the property in excludeList */
- emit_op(s, OP_to_propkey); /* avoid calling ToString twice */
- emit_op(s, OP_perm3); /* TOS: src excludeList prop */
- emit_op(s, OP_null); /* TOS: src excludeList prop null */
- emit_op(s, OP_define_array_el); /* TOS: src excludeList prop */
- emit_op(s, OP_perm3); /* TOS: excludeList src prop */
- }
- /* get the computed property from the source object */
- emit_op(s, OP_get_array_el2);
- } else {
- /* named property */
- if (has_ellipsis) {
- /* define the property in excludeList */
- emit_op(s, OP_swap); /* TOS: src excludeList */
- emit_op(s, OP_null); /* TOS: src excludeList null */
- emit_op(s, OP_define_field); /* TOS: src excludeList */
- emit_atom(s, prop_name);
- emit_op(s, OP_swap); /* TOS: excludeList src */
- }
- /* get the named property from the source object */
- emit_op(s, OP_get_field2);
- emit_u32(s, prop_name);
- }
- if (js_parse_destructuring_element(s, tok, is_arg, true, -1, true, export_flag) < 0)
- return -1;
- if (s->token.val == '}')
- break;
- /* accept a trailing comma before the '}' */
- if (js_parse_expect(s, ','))
- return -1;
- continue;
- }
- if (prop_name == JS_ATOM_NULL) {
- emit_op(s, OP_to_propkey2);
- if (has_ellipsis) {
- /* define the property in excludeList */
- emit_op(s, OP_perm3);
- emit_op(s, OP_null);
- emit_op(s, OP_define_array_el);
- emit_op(s, OP_perm3);
- }
- /* source prop -- source source prop */
- emit_op(s, OP_dup1);
- } else {
- if (has_ellipsis) {
- /* define the property in excludeList */
- emit_op(s, OP_swap);
- emit_op(s, OP_null);
- emit_op(s, OP_define_field);
- emit_atom(s, prop_name);
- emit_op(s, OP_swap);
- }
- /* source -- source source */
- emit_op(s, OP_dup);
- }
- if (tok) {
- var_name = js_parse_destructuring_var(s, tok, is_arg);
- if (var_name == JS_ATOM_NULL)
- goto prop_error;
- } else {
- if (js_parse_left_hand_side_expr(s))
- goto prop_error;
- lvalue:
- if (get_lvalue(s, &opcode, &scope, &var_name,
- &label_lvalue, &depth_lvalue, false, '{'))
- goto prop_error;
- /* swap ref and lvalue object if any */
- if (prop_name == JS_ATOM_NULL) {
- switch(depth_lvalue) {
- case 1:
- /* source prop x -> x source prop */
- emit_op(s, OP_rot3r);
- break;
- case 2:
- /* source prop x y -> x y source prop */
- emit_op(s, OP_swap2); /* t p2 s p1 */
- break;
- case 3:
- /* source prop x y z -> x y z source prop */
- emit_op(s, OP_rot5l);
- emit_op(s, OP_rot5l);
- break;
- }
- } else {
- switch(depth_lvalue) {
- case 1:
- /* source x -> x source */
- emit_op(s, OP_swap);
- break;
- case 2:
- /* source x y -> x y source */
- emit_op(s, OP_rot3l);
- break;
- case 3:
- /* source x y z -> x y z source */
- emit_op(s, OP_rot4l);
- break;
- }
- }
- }
- if (prop_name == JS_ATOM_NULL) {
- /* computed property name on stack */
- /* XXX: should have OP_get_array_el2x with depth */
- /* source prop -- val */
- emit_op(s, OP_get_array_el);
- } else {
- /* named property */
- /* XXX: should have OP_get_field2x with depth */
- /* source -- val */
- emit_op(s, OP_get_field);
- emit_u32(s, prop_name);
- }
- } else {
- /* prop_type = PROP_TYPE_VAR, cannot be a computed property */
- if (is_arg && js_parse_check_duplicate_parameter(s, prop_name))
- goto prop_error;
- if (s->cur_func->is_strict_mode &&
- (prop_name == JS_ATOM_eval || prop_name == JS_ATOM_arguments)) {
- js_parse_error(s, "invalid destructuring target");
- goto prop_error;
- }
- if (has_ellipsis) {
- /* define the property in excludeList */
- emit_op(s, OP_swap);
- emit_op(s, OP_null);
- emit_op(s, OP_define_field);
- emit_atom(s, prop_name);
- emit_op(s, OP_swap);
- }
- if (!tok || tok == TOK_VAR) {
- /* generate reference */
- /* source -- source source */
- emit_op(s, OP_dup);
- emit_op(s, OP_scope_get_var);
- emit_atom(s, prop_name);
- emit_u16(s, s->cur_func->scope_level);
- goto lvalue;
- }
- var_name = JS_DupAtom(s->ctx, prop_name);
- /* source -- source val */
- emit_op(s, OP_get_field2);
- emit_u32(s, prop_name);
- }
- set_val:
- if (tok) {
- if (js_define_var(s, var_name, tok))
- goto var_error;
- if (export_flag) {
- if (!add_export_entry(s, s->cur_func->module, var_name, var_name,
- JS_EXPORT_TYPE_LOCAL))
- goto var_error;
- }
- scope = s->cur_func->scope_level;
- }
- if (s->token.val == '=') { /* handle optional default value */
- int label_hasval;
- emit_op(s, OP_dup);
- emit_op(s, OP_undefined);
- emit_op(s, OP_strict_eq);
- label_hasval = emit_goto(s, OP_if_false, -1);
- if (next_token(s))
- goto var_error;
- emit_op(s, OP_drop);
- if (js_parse_assign_expr(s))
- goto var_error;
- if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
- set_object_name(s, var_name);
- emit_label(s, label_hasval);
- }
- /* store value into lvalue object */
- put_lvalue(s, opcode, scope, var_name, label_lvalue,
- PUT_LVALUE_NOKEEP_DEPTH,
- (tok == TOK_CONST || tok == TOK_LET));
- if (s->token.val == '}')
- break;
- /* accept a trailing comma before the '}' */
- if (js_parse_expect(s, ','))
- return -1;
- }
- /* drop the source object */
- emit_op(s, OP_drop);
- if (has_ellipsis) {
- emit_op(s, OP_drop); /* pop excludeList */
- }
- if (next_token(s))
- return -1;
- } else if (s->token.val == '[') {
- bool has_spread;
- int enum_depth;
- BlockEnv block_env;
- if (next_token(s))
- return -1;
- /* the block environment is only needed in generators in case
- 'yield' triggers a 'return' */
- push_break_entry(s->cur_func, &block_env,
- JS_ATOM_NULL, -1, -1, 2);
- block_env.has_iterator = true;
- emit_op(s, OP_for_of_start);
- has_spread = false;
- while (s->token.val != ']') {
- /* get the next value */
- if (s->token.val == TOK_ELLIPSIS) {
- if (next_token(s))
- return -1;
- if (s->token.val == ',' || s->token.val == ']')
- return js_parse_error(s, "missing binding pattern...");
- has_spread = true;
- }
- if (s->token.val == ',') {
- /* do nothing, skip the value, has_spread is false */
- emit_op(s, OP_for_of_next);
- emit_u8(s, 0);
- emit_op(s, OP_drop);
- emit_op(s, OP_drop);
- } else if ((s->token.val == '[' || s->token.val == '{')
- && ((tok1 = js_parse_skip_parens_token(s, &skip_bits, false)) == ',' ||
- tok1 == '=' || tok1 == ']')) {
- if (has_spread) {
- if (tok1 == '=')
- return js_parse_error(s, "rest element cannot have a default value");
- js_emit_spread_code(s, 0);
- } else {
- emit_op(s, OP_for_of_next);
- emit_u8(s, 0);
- emit_op(s, OP_drop);
- }
- if (js_parse_destructuring_element(s, tok, is_arg, true, skip_bits & SKIP_HAS_ELLIPSIS, true, export_flag) < 0)
- return -1;
- } else {
- var_name = JS_ATOM_NULL;
- enum_depth = 0;
- if (tok) {
- var_name = js_parse_destructuring_var(s, tok, is_arg);
- if (var_name == JS_ATOM_NULL)
- goto var_error;
- if (js_define_var(s, var_name, tok))
- goto var_error;
- opcode = OP_scope_get_var;
- scope = s->cur_func->scope_level;
- } else {
- if (js_parse_left_hand_side_expr(s))
- return -1;
- if (get_lvalue(s, &opcode, &scope, &var_name,
- &label_lvalue, &enum_depth, false, '[')) {
- return -1;
- }
- }
- if (has_spread) {
- js_emit_spread_code(s, enum_depth);
- } else {
- emit_op(s, OP_for_of_next);
- emit_u8(s, enum_depth);
- emit_op(s, OP_drop);
- }
- if (s->token.val == '=' && !has_spread) {
- /* handle optional default value */
- int label_hasval;
- emit_op(s, OP_dup);
- emit_op(s, OP_undefined);
- emit_op(s, OP_strict_eq);
- label_hasval = emit_goto(s, OP_if_false, -1);
- if (next_token(s))
- goto var_error;
- emit_op(s, OP_drop);
- if (js_parse_assign_expr(s))
- goto var_error;
- if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
- set_object_name(s, var_name);
- emit_label(s, label_hasval);
- }
- /* store value into lvalue object */
- put_lvalue(s, opcode, scope, var_name,
- label_lvalue, PUT_LVALUE_NOKEEP_DEPTH,
- (tok == TOK_CONST || tok == TOK_LET));
- }
- if (s->token.val == ']')
- break;
- if (has_spread)
- return js_parse_error(s, "rest element must be the last one");
- /* accept a trailing comma before the ']' */
- if (js_parse_expect(s, ','))
- return -1;
- }
- /* close iterator object:
- if completed, enum_obj has been replaced by undefined */
- emit_op(s, OP_iterator_close);
- pop_break_entry(s->cur_func);
- if (next_token(s))
- return -1;
- } else {
- return js_parse_error(s, "invalid assignment syntax");
- }
- if (s->token.val == '=' && allow_initializer) {
- label_done = emit_goto(s, OP_goto, -1);
- if (next_token(s))
- return -1;
- emit_label(s, label_parse);
- if (hasval)
- emit_op(s, OP_drop);
- if (js_parse_assign_expr(s))
- return -1;
- emit_goto(s, OP_goto, label_assign);
- emit_label(s, label_done);
- has_initializer = true;
- } else {
- /* normally hasval is true except if
- js_parse_skip_parens_token() was wrong in the parsing */
- // assert(hasval);
- if (!hasval) {
- js_parse_error(s, "too complicated destructuring expression");
- return -1;
- }
- /* remove test and decrement label ref count */
- memset(s->cur_func->byte_code.buf + start_addr, OP_nop,
- assign_addr - start_addr);
- s->cur_func->label_slots[label_parse].ref_count--;
- has_initializer = false;
- }
- return has_initializer;
- prop_error:
- JS_FreeAtom(s->ctx, prop_name);
- var_error:
- JS_FreeAtom(s->ctx, var_name);
- return -1;
- }
- typedef enum FuncCallType {
- FUNC_CALL_NORMAL,
- FUNC_CALL_NEW,
- FUNC_CALL_SUPER_CTOR,
- FUNC_CALL_TEMPLATE,
- } FuncCallType;
- static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
- int drop_count)
- {
- int label_next, i;
- if (*poptional_chaining_label < 0)
- *poptional_chaining_label = new_label(s);
- /* XXX: could be more efficient with a specific opcode */
- emit_op(s, OP_dup);
- emit_op(s, OP_is_undefined_or_null);
- label_next = emit_goto(s, OP_if_false, -1);
- for(i = 0; i < drop_count; i++)
- emit_op(s, OP_drop);
- emit_op(s, OP_undefined);
- emit_goto(s, OP_goto, *poptional_chaining_label);
- emit_label(s, label_next);
- }
- /* allowed parse_flags: PF_POSTFIX_CALL */
- static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
- {
- FuncCallType call_type;
- int optional_chaining_label;
- bool accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0;
- call_type = FUNC_CALL_NORMAL;
- switch(s->token.val) {
- case TOK_NUMBER:
- {
- JSValue val;
- val = s->token.u.num.val;
- if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
- emit_op(s, OP_push_i32);
- emit_u32(s, JS_VALUE_GET_INT(val));
- } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {
- int64_t v;
- v = JS_VALUE_GET_SHORT_BIG_INT(val);
- if (v >= INT32_MIN && v <= INT32_MAX) {
- emit_op(s, OP_push_bigint_i32);
- emit_u32(s, v);
- } else {
- goto large_number;
- }
- } else {
- large_number:
- if (emit_push_const(s, val, 0) < 0)
- return -1;
- }
- }
- if (next_token(s))
- return -1;
- break;
- case TOK_TEMPLATE:
- if (js_parse_template(s, 0, NULL))
- return -1;
- break;
- case TOK_STRING:
- if (emit_push_const(s, s->token.u.str.str, 1))
- return -1;
- if (next_token(s))
- return -1;
- break;
- case TOK_DIV_ASSIGN:
- s->buf_ptr -= 2;
- goto parse_regexp;
- case '/':
- s->buf_ptr--;
- parse_regexp:
- {
- JSValue str;
- int ret, backtrace_flags;
- if (!s->ctx->compile_regexp)
- return js_parse_error(s, "RegExp are not supported");
- /* the previous token is '/' or '/=', so no need to free */
- if (js_parse_regexp(s))
- return -1;
- ret = emit_push_const(s, s->token.u.regexp.body, 0);
- str = s->ctx->compile_regexp(s->ctx, s->token.u.regexp.body,
- s->token.u.regexp.flags);
- if (JS_IsException(str)) {
- /* add the line number info */
- backtrace_flags = 0;
- if (s->cur_func && s->cur_func->backtrace_barrier)
- backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
- build_backtrace(s->ctx, s->ctx->rt->current_exception, JS_UNDEFINED,
- s->filename,
- s->token.line_num,
- s->token.col_num,
- backtrace_flags);
- return -1;
- }
- ret = emit_push_const(s, str, 0);
- JS_FreeValue(s->ctx, str);
- if (ret)
- return -1;
- /* we use a specific opcode to be sure the correct
- function is called (otherwise the bytecode would have
- to be verified by the RegExp constructor) */
- emit_op(s, OP_regexp);
- if (next_token(s))
- return -1;
- }
- break;
- case '(':
- if (js_parse_expr_paren(s))
- return -1;
- break;
- case TOK_FUNCTION:
- if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
- JS_FUNC_NORMAL, JS_ATOM_NULL,
- s->token.ptr,
- s->token.line_num,
- s->token.col_num))
- return -1;
- break;
- case TOK_CLASS:
- if (js_parse_class(s, true, JS_PARSE_EXPORT_NONE))
- return -1;
- break;
- case TOK_NULL:
- if (next_token(s))
- return -1;
- emit_op(s, OP_null);
- break;
- case TOK_THIS:
- if (next_token(s))
- return -1;
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_this);
- emit_u16(s, 0);
- break;
- case TOK_FALSE:
- if (next_token(s))
- return -1;
- emit_op(s, OP_push_false);
- break;
- case TOK_TRUE:
- if (next_token(s))
- return -1;
- emit_op(s, OP_push_true);
- break;
- case TOK_IDENT:
- {
- JSAtom name;
- if (s->token.u.ident.is_reserved) {
- return js_parse_error_reserved_identifier(s);
- }
- if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
- peek_token(s, true) != '\n') {
- const uint8_t *source_ptr;
- int source_line_num;
- int source_col_num;
- source_ptr = s->token.ptr;
- source_line_num = s->token.line_num;
- source_col_num = s->token.col_num;
- if (next_token(s))
- return -1;
- if (s->token.val == TOK_FUNCTION) {
- if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
- JS_FUNC_ASYNC, JS_ATOM_NULL,
- source_ptr,
- source_line_num,
- source_col_num))
- return -1;
- } else {
- name = JS_DupAtom(s->ctx, JS_ATOM_async);
- goto do_get_var;
- }
- } else {
- if (s->token.u.ident.atom == JS_ATOM_arguments &&
- !s->cur_func->arguments_allowed) {
- js_parse_error(s, "'arguments' identifier is not allowed in class field initializer");
- return -1;
- }
- name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
- if (next_token(s)) { /* update line number before emitting code */
- JS_FreeAtom(s->ctx, name);
- return -1;
- }
- do_get_var:
- emit_op(s, OP_scope_get_var);
- emit_u32(s, name);
- emit_u16(s, s->cur_func->scope_level);
- }
- }
- break;
- case '{':
- case '[':
- {
- int skip_bits;
- if (js_parse_skip_parens_token(s, &skip_bits, false) == '=') {
- if (js_parse_destructuring_element(s, 0, false, false, skip_bits & SKIP_HAS_ELLIPSIS, true, false) < 0)
- return -1;
- } else {
- if (s->token.val == '{') {
- if (js_parse_object_literal(s))
- return -1;
- } else {
- if (js_parse_array_literal(s))
- return -1;
- }
- }
- }
- break;
- case TOK_NEW:
- if (next_token(s))
- return -1;
- if (s->token.val == '.') {
- if (next_token(s))
- return -1;
- if (!token_is_pseudo_keyword(s, JS_ATOM_target))
- return js_parse_error(s, "expecting target");
- if (!s->cur_func->new_target_allowed)
- return js_parse_error(s, "new.target only allowed within functions");
- if (next_token(s))
- return -1;
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_new_target);
- emit_u16(s, 0);
- } else {
- emit_source_loc(s);
- if (js_parse_postfix_expr(s, 0))
- return -1;
- accept_lparen = true;
- if (s->token.val != '(') {
- /* new operator on an object */
- emit_op(s, OP_dup);
- emit_op(s, OP_call_constructor);
- emit_u16(s, 0);
- } else {
- call_type = FUNC_CALL_NEW;
- }
- }
- break;
- case TOK_SUPER:
- if (next_token(s))
- return -1;
- if (s->token.val == '(') {
- if (!s->cur_func->super_call_allowed)
- return js_parse_error(s, "super() is only valid in a derived class constructor");
- call_type = FUNC_CALL_SUPER_CTOR;
- } else if (s->token.val == '.' || s->token.val == '[') {
- if (!s->cur_func->super_allowed)
- return js_parse_error(s, "'super' is only valid in a method");
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_this);
- emit_u16(s, 0);
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_home_object);
- emit_u16(s, 0);
- emit_op(s, OP_get_super);
- } else {
- return js_parse_error(s, "invalid use of 'super'");
- }
- break;
- case TOK_IMPORT:
- if (next_token(s))
- return -1;
- if (s->token.val == '.') {
- if (next_token(s))
- return -1;
- if (!token_is_pseudo_keyword(s, JS_ATOM_meta))
- return js_parse_error(s, "meta expected");
- if (!s->is_module)
- return js_parse_error(s, "import.meta only valid in module code");
- if (next_token(s))
- return -1;
- emit_op(s, OP_special_object);
- emit_u8(s, OP_SPECIAL_OBJECT_IMPORT_META);
- } else {
- if (js_parse_expect(s, '('))
- return -1;
- if (!accept_lparen)
- return js_parse_error(s, "invalid use of 'import()'");
- if (js_parse_assign_expr(s))
- return -1;
- if (js_parse_expect(s, ')'))
- return -1;
- emit_op(s, OP_import);
- }
- break;
- default:
- return js_parse_error(s, "unexpected token in expression: '%.*s'",
- (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
- }
- optional_chaining_label = -1;
- for(;;) {
- JSFunctionDef *fd = s->cur_func;
- bool has_optional_chain = false;
- if (s->token.val == TOK_QUESTION_MARK_DOT) {
- /* optional chaining */
- if (next_token(s))
- return -1;
- has_optional_chain = true;
- if (s->token.val == '(' && accept_lparen) {
- goto parse_func_call;
- } else if (s->token.val == '[') {
- goto parse_array_access;
- } else {
- goto parse_property;
- }
- } else if (s->token.val == TOK_TEMPLATE &&
- call_type == FUNC_CALL_NORMAL) {
- if (optional_chaining_label >= 0) {
- return js_parse_error(s, "template literal cannot appear in an optional chain");
- }
- call_type = FUNC_CALL_TEMPLATE;
- goto parse_func_call2;
- } else if (s->token.val == '(' && accept_lparen) {
- int opcode, arg_count, drop_count;
- /* function call */
- parse_func_call:
- if (next_token(s))
- return -1;
- if (call_type == FUNC_CALL_NORMAL) {
- parse_func_call2:
- emit_source_loc(s);
- switch(opcode = get_prev_opcode(fd)) {
- case OP_get_field:
- /* keep the object on the stack */
- fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
- drop_count = 2;
- break;
- case OP_get_field_opt_chain:
- {
- int opt_chain_label, next_label;
- opt_chain_label = get_u32(fd->byte_code.buf +
- fd->last_opcode_pos + 1 + 4 + 1);
- /* keep the object on the stack */
- fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
- fd->byte_code.size = fd->last_opcode_pos + 1 + 4;
- next_label = emit_goto(s, OP_goto, -1);
- emit_label(s, opt_chain_label);
- /* need an additional undefined value for the
- case where the optional field does not
- exists */
- emit_op(s, OP_undefined);
- emit_label(s, next_label);
- drop_count = 2;
- opcode = OP_get_field;
- }
- break;
- case OP_scope_get_private_field:
- /* keep the object on the stack */
- fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;
- drop_count = 2;
- break;
- case OP_get_array_el:
- /* keep the object on the stack */
- fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
- drop_count = 2;
- break;
- case OP_get_array_el_opt_chain:
- {
- int opt_chain_label, next_label;
- opt_chain_label = get_u32(fd->byte_code.buf +
- fd->last_opcode_pos + 1 + 1);
- /* keep the object on the stack */
- fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
- fd->byte_code.size = fd->last_opcode_pos + 1;
- next_label = emit_goto(s, OP_goto, -1);
- emit_label(s, opt_chain_label);
- /* need an additional undefined value for the
- case where the optional field does not
- exists */
- emit_op(s, OP_undefined);
- emit_label(s, next_label);
- drop_count = 2;
- opcode = OP_get_array_el;
- }
- break;
- case OP_scope_get_var:
- {
- JSAtom name;
- int scope;
- name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
- scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
- if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL && !has_optional_chain) {
- /* direct 'eval' */
- opcode = OP_eval;
- } else {
- /* verify if function name resolves to a simple
- get_loc/get_arg: a function call inside a `with`
- statement can resolve to a method call of the
- `with` context object
- */
- /* XXX: always generate the OP_scope_get_ref
- and remove it in variable resolution
- pass ? */
- if (has_with_scope(fd, scope)) {
- opcode = OP_scope_get_ref;
- fd->byte_code.buf[fd->last_opcode_pos] = opcode;
- }
- }
- drop_count = 1;
- }
- break;
- case OP_get_super_value:
- fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el;
- /* on stack: this func_obj */
- opcode = OP_get_array_el;
- drop_count = 2;
- break;
- default:
- opcode = OP_invalid;
- drop_count = 1;
- break;
- }
- if (has_optional_chain) {
- optional_chain_test(s, &optional_chaining_label,
- drop_count);
- }
- } else {
- opcode = OP_invalid;
- }
- if (call_type == FUNC_CALL_TEMPLATE) {
- if (js_parse_template(s, 1, &arg_count))
- return -1;
- goto emit_func_call;
- } else if (call_type == FUNC_CALL_SUPER_CTOR) {
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_this_active_func);
- emit_u16(s, 0);
- emit_op(s, OP_get_super);
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_new_target);
- emit_u16(s, 0);
- } else if (call_type == FUNC_CALL_NEW) {
- emit_op(s, OP_dup); /* new.target = function */
- }
- /* parse arguments */
- arg_count = 0;
- while (s->token.val != ')') {
- if (arg_count >= 65535) {
- return js_parse_error(s, "Too many arguments in function call (only %d allowed)",
- 65535 - 1);
- }
- if (s->token.val == TOK_ELLIPSIS)
- break;
- if (js_parse_assign_expr(s))
- return -1;
- arg_count++;
- if (s->token.val == ')')
- break;
- /* accept a trailing comma before the ')' */
- if (js_parse_expect(s, ','))
- return -1;
- }
- if (s->token.val == TOK_ELLIPSIS) {
- emit_op(s, OP_array_from);
- emit_u16(s, arg_count);
- emit_op(s, OP_push_i32);
- emit_u32(s, arg_count);
- /* on stack: array idx */
- while (s->token.val != ')') {
- if (s->token.val == TOK_ELLIPSIS) {
- if (next_token(s))
- return -1;
- if (js_parse_assign_expr(s))
- return -1;
- /* XXX: could pass is_last indicator? */
- emit_op(s, OP_append);
- } else {
- if (js_parse_assign_expr(s))
- return -1;
- /* array idx val */
- emit_op(s, OP_define_array_el);
- emit_op(s, OP_inc);
- }
- if (s->token.val == ')')
- break;
- /* accept a trailing comma before the ')' */
- if (js_parse_expect(s, ','))
- return -1;
- }
- if (next_token(s))
- return -1;
- /* drop the index */
- emit_op(s, OP_drop);
- /* apply function call */
- switch(opcode) {
- case OP_get_field:
- case OP_scope_get_private_field:
- case OP_get_array_el:
- case OP_scope_get_ref:
- /* obj func array -> func obj array */
- emit_op(s, OP_perm3);
- emit_op(s, OP_apply);
- emit_u16(s, call_type == FUNC_CALL_NEW);
- break;
- case OP_eval:
- emit_op(s, OP_apply_eval);
- emit_u16(s, fd->scope_level);
- fd->has_eval_call = true;
- break;
- default:
- if (call_type == FUNC_CALL_SUPER_CTOR) {
- emit_op(s, OP_apply);
- emit_u16(s, 1);
- /* set the 'this' value */
- emit_op(s, OP_dup);
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, JS_ATOM_this);
- emit_u16(s, 0);
- emit_class_field_init(s);
- } else if (call_type == FUNC_CALL_NEW) {
- /* obj func array -> func obj array */
- emit_op(s, OP_perm3);
- emit_op(s, OP_apply);
- emit_u16(s, 1);
- } else {
- /* func array -> func undef array */
- emit_op(s, OP_undefined);
- emit_op(s, OP_swap);
- emit_op(s, OP_apply);
- emit_u16(s, 0);
- }
- break;
- }
- } else {
- if (next_token(s))
- return -1;
- emit_func_call:
- switch(opcode) {
- case OP_get_field:
- case OP_scope_get_private_field:
- case OP_get_array_el:
- case OP_scope_get_ref:
- emit_op(s, OP_call_method);
- emit_u16(s, arg_count);
- break;
- case OP_eval:
- emit_op(s, OP_eval);
- emit_u16(s, arg_count);
- emit_u16(s, fd->scope_level);
- fd->has_eval_call = true;
- break;
- default:
- if (call_type == FUNC_CALL_SUPER_CTOR) {
- emit_op(s, OP_call_constructor);
- emit_u16(s, arg_count);
- /* set the 'this' value */
- emit_op(s, OP_dup);
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, JS_ATOM_this);
- emit_u16(s, 0);
- emit_class_field_init(s);
- } else if (call_type == FUNC_CALL_NEW) {
- emit_op(s, OP_call_constructor);
- emit_u16(s, arg_count);
- } else {
- emit_op(s, OP_call);
- emit_u16(s, arg_count);
- }
- break;
- }
- }
- call_type = FUNC_CALL_NORMAL;
- } else if (s->token.val == '.') {
- if (next_token(s))
- return -1;
- parse_property:
- if (s->token.val == TOK_PRIVATE_NAME) {
- /* private class field */
- if (get_prev_opcode(fd) == OP_get_super) {
- return js_parse_error(s, "private class field forbidden after super");
- }
- if (has_optional_chain) {
- optional_chain_test(s, &optional_chaining_label, 1);
- }
- emit_op(s, OP_scope_get_private_field);
- emit_atom(s, s->token.u.ident.atom);
- emit_u16(s, s->cur_func->scope_level);
- } else {
- if (!token_is_ident(s->token.val)) {
- return js_parse_error(s, "expecting field name");
- }
- if (get_prev_opcode(fd) == OP_get_super) {
- JSValue val;
- int ret;
- val = JS_AtomToValue(s->ctx, s->token.u.ident.atom);
- ret = emit_push_const(s, val, 1);
- JS_FreeValue(s->ctx, val);
- if (ret)
- return -1;
- emit_op(s, OP_get_super_value);
- } else {
- if (has_optional_chain) {
- optional_chain_test(s, &optional_chaining_label, 1);
- }
- emit_op(s, OP_get_field);
- emit_atom(s, s->token.u.ident.atom);
- }
- }
- if (next_token(s))
- return -1;
- } else if (s->token.val == '[') {
- int prev_op;
- parse_array_access:
- prev_op = get_prev_opcode(fd);
- if (has_optional_chain) {
- optional_chain_test(s, &optional_chaining_label, 1);
- }
- if (next_token(s))
- return -1;
- if (js_parse_expr(s))
- return -1;
- if (js_parse_expect(s, ']'))
- return -1;
- if (prev_op == OP_get_super) {
- emit_op(s, OP_get_super_value);
- } else {
- emit_op(s, OP_get_array_el);
- }
- } else {
- break;
- }
- }
- if (optional_chaining_label >= 0) {
- JSFunctionDef *fd = s->cur_func;
- int opcode;
- emit_label_raw(s, optional_chaining_label);
- /* modify the last opcode so that it is an indicator of an
- optional chain */
- opcode = get_prev_opcode(fd);
- if (opcode == OP_get_field || opcode == OP_get_array_el) {
- if (opcode == OP_get_field)
- opcode = OP_get_field_opt_chain;
- else
- opcode = OP_get_array_el_opt_chain;
- fd->byte_code.buf[fd->last_opcode_pos] = opcode;
- } else {
- fd->last_opcode_pos = -1;
- }
- }
- return 0;
- }
- static __exception int js_parse_delete(JSParseState *s)
- {
- JSFunctionDef *fd = s->cur_func;
- JSAtom name;
- int opcode;
- if (next_token(s))
- return -1;
- if (js_parse_unary(s, PF_POW_FORBIDDEN))
- return -1;
- switch(opcode = get_prev_opcode(fd)) {
- case OP_get_field:
- case OP_get_field_opt_chain:
- {
- JSValue val;
- int ret, opt_chain_label, next_label;
- if (opcode == OP_get_field_opt_chain) {
- opt_chain_label = get_u32(fd->byte_code.buf +
- fd->last_opcode_pos + 1 + 4 + 1);
- } else {
- opt_chain_label = -1;
- }
- name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
- fd->byte_code.size = fd->last_opcode_pos;
- val = JS_AtomToValue(s->ctx, name);
- ret = emit_push_const(s, val, 1);
- JS_FreeValue(s->ctx, val);
- JS_FreeAtom(s->ctx, name);
- if (ret)
- return ret;
- emit_op(s, OP_delete);
- if (opt_chain_label >= 0) {
- next_label = emit_goto(s, OP_goto, -1);
- emit_label(s, opt_chain_label);
- /* if the optional chain is not taken, return 'true' */
- emit_op(s, OP_drop);
- emit_op(s, OP_push_true);
- emit_label(s, next_label);
- }
- fd->last_opcode_pos = -1;
- }
- break;
- case OP_get_array_el:
- fd->byte_code.size = fd->last_opcode_pos;
- fd->last_opcode_pos = -1;
- emit_op(s, OP_delete);
- break;
- case OP_get_array_el_opt_chain:
- {
- int opt_chain_label, next_label;
- opt_chain_label = get_u32(fd->byte_code.buf +
- fd->last_opcode_pos + 1 + 1);
- fd->byte_code.size = fd->last_opcode_pos;
- emit_op(s, OP_delete);
- next_label = emit_goto(s, OP_goto, -1);
- emit_label(s, opt_chain_label);
- /* if the optional chain is not taken, return 'true' */
- emit_op(s, OP_drop);
- emit_op(s, OP_push_true);
- emit_label(s, next_label);
- fd->last_opcode_pos = -1;
- }
- break;
- case OP_scope_get_var:
- /* 'delete this': this is not a reference */
- name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
- if (name == JS_ATOM_this || name == JS_ATOM_new_target)
- goto ret_true;
- if (fd->is_strict_mode) {
- return js_parse_error(s, "cannot delete a direct reference in strict mode");
- } else {
- fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_delete_var;
- }
- break;
- case OP_scope_get_private_field:
- return js_parse_error(s, "cannot delete a private class field");
- case OP_get_super_value:
- fd->byte_code.size = fd->last_opcode_pos;
- fd->last_opcode_pos = -1;
- emit_op(s, OP_throw_error);
- emit_atom(s, JS_ATOM_NULL);
- emit_u8(s, JS_THROW_ERROR_DELETE_SUPER);
- break;
- default:
- ret_true:
- emit_op(s, OP_drop);
- emit_op(s, OP_push_true);
- break;
- }
- return 0;
- }
- /* allowed parse_flags: PF_POW_ALLOWED, PF_POW_FORBIDDEN */
- static __exception int js_parse_unary(JSParseState *s, int parse_flags)
- {
- int op;
- switch(s->token.val) {
- case '+':
- case '-':
- case '!':
- case '~':
- case TOK_VOID:
- op = s->token.val;
- if (next_token(s))
- return -1;
- if (js_parse_unary(s, PF_POW_FORBIDDEN))
- return -1;
- switch(op) {
- case '-':
- emit_op(s, OP_neg);
- break;
- case '+':
- emit_op(s, OP_plus);
- break;
- case '!':
- emit_op(s, OP_lnot);
- break;
- case '~':
- emit_op(s, OP_not);
- break;
- case TOK_VOID:
- emit_op(s, OP_drop);
- emit_op(s, OP_undefined);
- break;
- default:
- abort();
- }
- parse_flags = 0;
- break;
- case TOK_DEC:
- case TOK_INC:
- {
- int opcode, op, scope, label;
- JSAtom name;
- op = s->token.val;
- if (next_token(s))
- return -1;
- if (js_parse_unary(s, 0))
- return -1;
- if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, true, op))
- return -1;
- emit_op(s, OP_dec + op - TOK_DEC);
- put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP,
- false);
- }
- break;
- case TOK_TYPEOF:
- {
- JSFunctionDef *fd;
- if (next_token(s))
- return -1;
- if (js_parse_unary(s, PF_POW_FORBIDDEN))
- return -1;
- /* reference access should not return an exception, so we
- patch the get_var */
- fd = s->cur_func;
- if (get_prev_opcode(fd) == OP_scope_get_var) {
- fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef;
- }
- emit_op(s, OP_typeof);
- parse_flags = 0;
- }
- break;
- case TOK_DELETE:
- if (js_parse_delete(s))
- return -1;
- parse_flags = 0;
- break;
- case TOK_AWAIT:
- if (!(s->cur_func->func_kind & JS_FUNC_ASYNC))
- return js_parse_error(s, "unexpected 'await' keyword");
- if (!s->cur_func->in_function_body)
- return js_parse_error(s, "await in default expression");
- if (next_token(s))
- return -1;
- if (js_parse_unary(s, PF_POW_FORBIDDEN))
- return -1;
- s->cur_func->has_await = true;
- emit_op(s, OP_await);
- parse_flags = 0;
- break;
- default:
- if (js_parse_postfix_expr(s, PF_POSTFIX_CALL))
- return -1;
- if (!s->got_lf &&
- (s->token.val == TOK_DEC || s->token.val == TOK_INC)) {
- int opcode, op, scope, label;
- JSAtom name;
- op = s->token.val;
- if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, true, op))
- return -1;
- emit_op(s, OP_post_dec + op - TOK_DEC);
- put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND,
- false);
- if (next_token(s))
- return -1;
- }
- break;
- }
- if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) {
- if (s->token.val == TOK_POW) {
- /* Strict ES7 exponentiation syntax rules: To solve
- conficting semantics between different implementations
- regarding the precedence of prefix operators and the
- postifx exponential, ES7 specifies that -2**2 is a
- syntax error. */
- if (parse_flags & PF_POW_FORBIDDEN)
- return js_parse_error(s, "unparenthesized unary expression can't appear on the left-hand side of '**'");
- if (next_token(s))
- return -1;
- if (js_parse_unary(s, PF_POW_ALLOWED))
- return -1;
- emit_op(s, OP_pow);
- }
- }
- return 0;
- }
- /* allowed parse_flags: PF_IN_ACCEPTED */
- static __exception int js_parse_expr_binary(JSParseState *s, int level,
- int parse_flags)
- {
- int op, opcode;
- if (level == 0) {
- return js_parse_unary(s, PF_POW_ALLOWED);
- } else if (s->token.val == TOK_PRIVATE_NAME &&
- (parse_flags & PF_IN_ACCEPTED) && level == 4 &&
- peek_token(s, false) == TOK_IN) {
- JSAtom atom;
- atom = JS_DupAtom(s->ctx, s->token.u.ident.atom);
- if (next_token(s))
- goto fail_private_in;
- if (s->token.val != TOK_IN)
- goto fail_private_in;
- if (next_token(s))
- goto fail_private_in;
- if (js_parse_expr_binary(s, level - 1, parse_flags)) {
- fail_private_in:
- JS_FreeAtom(s->ctx, atom);
- return -1;
- }
- emit_op(s, OP_scope_in_private_field);
- emit_atom(s, atom);
- emit_u16(s, s->cur_func->scope_level);
- JS_FreeAtom(s->ctx, atom);
- return 0;
- } else {
- if (js_parse_expr_binary(s, level - 1, parse_flags))
- return -1;
- }
- for(;;) {
- op = s->token.val;
- switch(level) {
- case 1:
- switch(op) {
- case '*':
- opcode = OP_mul;
- break;
- case '/':
- opcode = OP_div;
- break;
- case '%':
- opcode = OP_mod;
- break;
- default:
- return 0;
- }
- break;
- case 2:
- switch(op) {
- case '+':
- opcode = OP_add;
- break;
- case '-':
- opcode = OP_sub;
- break;
- default:
- return 0;
- }
- break;
- case 3:
- switch(op) {
- case TOK_SHL:
- opcode = OP_shl;
- break;
- case TOK_SAR:
- opcode = OP_sar;
- break;
- case TOK_SHR:
- opcode = OP_shr;
- break;
- default:
- return 0;
- }
- break;
- case 4:
- switch(op) {
- case '<':
- opcode = OP_lt;
- break;
- case '>':
- opcode = OP_gt;
- break;
- case TOK_LTE:
- opcode = OP_lte;
- break;
- case TOK_GTE:
- opcode = OP_gte;
- break;
- case TOK_INSTANCEOF:
- opcode = OP_instanceof;
- break;
- case TOK_IN:
- if (parse_flags & PF_IN_ACCEPTED) {
- opcode = OP_in;
- } else {
- return 0;
- }
- break;
- default:
- return 0;
- }
- break;
- case 5:
- switch(op) {
- case TOK_EQ:
- opcode = OP_eq;
- break;
- case TOK_NEQ:
- opcode = OP_neq;
- break;
- case TOK_STRICT_EQ:
- opcode = OP_strict_eq;
- break;
- case TOK_STRICT_NEQ:
- opcode = OP_strict_neq;
- break;
- default:
- return 0;
- }
- break;
- case 6:
- switch(op) {
- case '&':
- opcode = OP_and;
- break;
- default:
- return 0;
- }
- break;
- case 7:
- switch(op) {
- case '^':
- opcode = OP_xor;
- break;
- default:
- return 0;
- }
- break;
- case 8:
- switch(op) {
- case '|':
- opcode = OP_or;
- break;
- default:
- return 0;
- }
- break;
- default:
- abort();
- }
- if (next_token(s))
- return -1;
- emit_source_loc(s);
- if (js_parse_expr_binary(s, level - 1, parse_flags))
- return -1;
- emit_op(s, opcode);
- }
- return 0;
- }
- /* allowed parse_flags: PF_IN_ACCEPTED */
- static __exception int js_parse_logical_and_or(JSParseState *s, int op,
- int parse_flags)
- {
- int label1;
- if (op == TOK_LAND) {
- if (js_parse_expr_binary(s, 8, parse_flags))
- return -1;
- } else {
- if (js_parse_logical_and_or(s, TOK_LAND, parse_flags))
- return -1;
- }
- if (s->token.val == op) {
- label1 = new_label(s);
- for(;;) {
- if (next_token(s))
- return -1;
- emit_op(s, OP_dup);
- emit_goto(s, op == TOK_LAND ? OP_if_false : OP_if_true, label1);
- emit_op(s, OP_drop);
- if (op == TOK_LAND) {
- if (js_parse_expr_binary(s, 8, parse_flags))
- return -1;
- } else {
- if (js_parse_logical_and_or(s, TOK_LAND, parse_flags))
- return -1;
- }
- if (s->token.val != op) {
- if (s->token.val == TOK_DOUBLE_QUESTION_MARK)
- return js_parse_error(s, "cannot mix ?? with && or ||");
- break;
- }
- }
- emit_label(s, label1);
- }
- return 0;
- }
- static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
- {
- int label1;
- if (js_parse_logical_and_or(s, TOK_LOR, parse_flags))
- return -1;
- if (s->token.val == TOK_DOUBLE_QUESTION_MARK) {
- label1 = new_label(s);
- for(;;) {
- if (next_token(s))
- return -1;
- emit_op(s, OP_dup);
- emit_op(s, OP_is_undefined_or_null);
- emit_goto(s, OP_if_false, label1);
- emit_op(s, OP_drop);
- if (js_parse_expr_binary(s, 8, parse_flags))
- return -1;
- if (s->token.val != TOK_DOUBLE_QUESTION_MARK)
- break;
- }
- emit_label(s, label1);
- }
- return 0;
- }
- /* allowed parse_flags: PF_IN_ACCEPTED */
- static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
- {
- int label1, label2;
- if (js_parse_coalesce_expr(s, parse_flags))
- return -1;
- if (s->token.val == '?') {
- if (next_token(s))
- return -1;
- label1 = emit_goto(s, OP_if_false, -1);
- if (js_parse_assign_expr(s))
- return -1;
- if (js_parse_expect(s, ':'))
- return -1;
- label2 = emit_goto(s, OP_goto, -1);
- emit_label(s, label1);
- if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED))
- return -1;
- emit_label(s, label2);
- }
- return 0;
- }
- /* allowed parse_flags: PF_IN_ACCEPTED */
- static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
- {
- int opcode, op, scope;
- JSAtom name0 = JS_ATOM_NULL;
- JSAtom name;
- if (s->token.val == TOK_YIELD) {
- bool is_star = false, is_async;
- if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR))
- return js_parse_error(s, "unexpected 'yield' keyword");
- if (!s->cur_func->in_function_body)
- return js_parse_error(s, "yield in default expression");
- if (next_token(s))
- return -1;
- /* XXX: is there a better method to detect 'yield' without
- parameters ? */
- if (s->token.val != ';' && s->token.val != ')' &&
- s->token.val != ']' && s->token.val != '}' &&
- s->token.val != ',' && s->token.val != ':' && !s->got_lf) {
- if (s->token.val == '*') {
- is_star = true;
- if (next_token(s))
- return -1;
- }
- if (js_parse_assign_expr2(s, parse_flags))
- return -1;
- } else {
- emit_op(s, OP_undefined);
- }
- is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR);
- if (is_star) {
- int label_loop, label_return, label_next;
- int label_return1, label_yield, label_throw, label_throw1;
- int label_throw2;
- label_loop = new_label(s);
- label_yield = new_label(s);
- emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start);
- /* remove the catch offset (XXX: could avoid pushing back
- undefined) */
- emit_op(s, OP_drop);
- emit_op(s, OP_undefined);
- emit_op(s, OP_undefined); /* initial value */
- emit_label(s, label_loop);
- emit_op(s, OP_iterator_next);
- if (is_async)
- emit_op(s, OP_await);
- emit_op(s, OP_iterator_check_object);
- emit_op(s, OP_get_field2);
- emit_atom(s, JS_ATOM_done);
- label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
- emit_label(s, label_yield);
- if (is_async) {
- /* OP_async_yield_star takes the value as parameter */
- emit_op(s, OP_get_field);
- emit_atom(s, JS_ATOM_value);
- emit_op(s, OP_async_yield_star);
- } else {
- /* OP_yield_star takes (value, done) as parameter */
- emit_op(s, OP_yield_star);
- }
- emit_op(s, OP_dup);
- label_return = emit_goto(s, OP_if_true, -1);
- emit_op(s, OP_drop);
- emit_goto(s, OP_goto, label_loop);
- emit_label(s, label_return);
- emit_op(s, OP_push_i32);
- emit_u32(s, 2);
- emit_op(s, OP_strict_eq);
- label_throw = emit_goto(s, OP_if_true, -1);
- /* return handling */
- if (is_async)
- emit_op(s, OP_await);
- emit_op(s, OP_iterator_call);
- emit_u8(s, 0);
- label_return1 = emit_goto(s, OP_if_true, -1);
- if (is_async)
- emit_op(s, OP_await);
- emit_op(s, OP_iterator_check_object);
- emit_op(s, OP_get_field2);
- emit_atom(s, JS_ATOM_done);
- emit_goto(s, OP_if_false, label_yield);
- emit_op(s, OP_get_field);
- emit_atom(s, JS_ATOM_value);
- emit_label(s, label_return1);
- emit_op(s, OP_nip);
- emit_op(s, OP_nip);
- emit_op(s, OP_nip);
- emit_return(s, true);
- /* throw handling */
- emit_label(s, label_throw);
- emit_op(s, OP_iterator_call);
- emit_u8(s, 1);
- label_throw1 = emit_goto(s, OP_if_true, -1);
- if (is_async)
- emit_op(s, OP_await);
- emit_op(s, OP_iterator_check_object);
- emit_op(s, OP_get_field2);
- emit_atom(s, JS_ATOM_done);
- emit_goto(s, OP_if_false, label_yield);
- emit_goto(s, OP_goto, label_next);
- /* close the iterator and throw a type error exception */
- emit_label(s, label_throw1);
- emit_op(s, OP_iterator_call);
- emit_u8(s, 2);
- label_throw2 = emit_goto(s, OP_if_true, -1);
- if (is_async)
- emit_op(s, OP_await);
- emit_label(s, label_throw2);
- emit_op(s, OP_throw_error);
- emit_atom(s, JS_ATOM_NULL);
- emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW);
- emit_label(s, label_next);
- emit_op(s, OP_get_field);
- emit_atom(s, JS_ATOM_value);
- emit_op(s, OP_nip); /* keep the value associated with
- done = true */
- emit_op(s, OP_nip);
- emit_op(s, OP_nip);
- } else {
- int label_next;
- if (is_async)
- emit_op(s, OP_await);
- emit_op(s, OP_yield);
- label_next = emit_goto(s, OP_if_false, -1);
- emit_return(s, true);
- emit_label(s, label_next);
- }
- return 0;
- } else if (s->token.val == '(' &&
- js_parse_skip_parens_token(s, NULL, true) == TOK_ARROW) {
- return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
- JS_FUNC_NORMAL, JS_ATOM_NULL,
- s->token.ptr, s->token.line_num,
- s->token.col_num);
- } else if (token_is_pseudo_keyword(s, JS_ATOM_async)) {
- const uint8_t *source_ptr;
- int tok, source_line_num, source_col_num;
- JSParsePos pos;
- /* fast test */
- tok = peek_token(s, true);
- if (tok == TOK_FUNCTION || tok == '\n')
- goto next;
- source_ptr = s->token.ptr;
- source_line_num = s->token.line_num;
- source_col_num = s->token.col_num;
- js_parse_get_pos(s, &pos);
- if (next_token(s))
- return -1;
- if ((s->token.val == '(' &&
- js_parse_skip_parens_token(s, NULL, true) == TOK_ARROW) ||
- (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
- peek_token(s, true) == TOK_ARROW)) {
- return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
- JS_FUNC_ASYNC, JS_ATOM_NULL,
- source_ptr, source_line_num,
- source_col_num);
- } else {
- /* undo the token parsing */
- if (js_parse_seek_token(s, &pos))
- return -1;
- }
- } else if (s->token.val == TOK_IDENT &&
- peek_token(s, true) == TOK_ARROW) {
- return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
- JS_FUNC_NORMAL, JS_ATOM_NULL,
- s->token.ptr, s->token.line_num,
- s->token.col_num);
- }
- next:
- if (s->token.val == TOK_IDENT) {
- /* name0 is used to check for OP_set_name pattern, not duplicated */
- name0 = s->token.u.ident.atom;
- }
- if (js_parse_cond_expr(s, parse_flags))
- return -1;
- op = s->token.val;
- if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_POW_ASSIGN)) {
- int label;
- if (next_token(s))
- return -1;
- if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
- return -1;
- // comply with rather obtuse evaluation order of computed properties:
- // obj[key]=val evaluates val->obj->key when obj is null/undefined
- // but key->obj->val when an object
- // FIXME(bnoordhuis) less stack shuffling; don't to_propkey twice in
- // happy path; replace `dup is_undefined_or_null if_true` with new
- // opcode if_undefined_or_null? replace `swap dup` with over?
- if (op == '=' && opcode == OP_get_array_el) {
- int label_next = -1;
- JSFunctionDef *fd = s->cur_func;
- assert(OP_to_propkey2 == fd->byte_code.buf[fd->last_opcode_pos]);
- fd->byte_code.size = fd->last_opcode_pos;
- fd->last_opcode_pos = -1;
- emit_op(s, OP_swap); // obj key -> key obj
- emit_op(s, OP_dup);
- emit_op(s, OP_is_undefined_or_null);
- label_next = emit_goto(s, OP_if_true, -1);
- emit_op(s, OP_swap);
- emit_op(s, OP_to_propkey);
- emit_op(s, OP_swap);
- emit_label(s, label_next);
- emit_op(s, OP_swap);
- }
- if (js_parse_assign_expr2(s, parse_flags)) {
- JS_FreeAtom(s->ctx, name);
- return -1;
- }
- if (op == '=' && opcode == OP_get_array_el) {
- emit_op(s, OP_swap); // obj key val -> obj val key
- emit_op(s, OP_to_propkey);
- emit_op(s, OP_swap);
- }
- if (op == '=') {
- if (opcode == OP_get_ref_value && name == name0) {
- set_object_name(s, name);
- }
- } else {
- emit_op(s, op - TOK_MUL_ASSIGN + OP_mul);
- }
- put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, false);
- } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) {
- int label, label1, depth_lvalue, label2;
- if (next_token(s))
- return -1;
- if (get_lvalue(s, &opcode, &scope, &name, &label,
- &depth_lvalue, true, op) < 0)
- return -1;
- emit_op(s, OP_dup);
- if (op == TOK_DOUBLE_QUESTION_MARK_ASSIGN)
- emit_op(s, OP_is_undefined_or_null);
- label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false,
- -1);
- emit_op(s, OP_drop);
- if (js_parse_assign_expr2(s, parse_flags)) {
- JS_FreeAtom(s->ctx, name);
- return -1;
- }
- if (opcode == OP_get_ref_value && name == name0) {
- set_object_name(s, name);
- }
- switch(depth_lvalue) {
- case 1:
- emit_op(s, OP_insert2);
- break;
- case 2:
- emit_op(s, OP_insert3);
- break;
- case 3:
- emit_op(s, OP_insert4);
- break;
- default:
- abort();
- }
- /* XXX: we disable the OP_put_ref_value optimization by not
- using put_lvalue() otherwise depth_lvalue is not correct */
- put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH,
- false);
- label2 = emit_goto(s, OP_goto, -1);
- emit_label(s, label1);
- /* remove the lvalue stack entries */
- while (depth_lvalue != 0) {
- emit_op(s, OP_nip);
- depth_lvalue--;
- }
- emit_label(s, label2);
- }
- return 0;
- }
- static __exception int js_parse_assign_expr(JSParseState *s)
- {
- return js_parse_assign_expr2(s, PF_IN_ACCEPTED);
- }
- /* allowed parse_flags: PF_IN_ACCEPTED */
- static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
- {
- bool comma = false;
- for(;;) {
- if (js_parse_assign_expr2(s, parse_flags))
- return -1;
- if (comma) {
- /* prevent get_lvalue from using the last expression
- as an lvalue. This also prevents the conversion of
- of get_var to get_ref for method lookup in function
- call inside `with` statement.
- */
- s->cur_func->last_opcode_pos = -1;
- }
- if (s->token.val != ',')
- break;
- comma = true;
- if (next_token(s))
- return -1;
- emit_op(s, OP_drop);
- }
- return 0;
- }
- static __exception int js_parse_expr(JSParseState *s)
- {
- return js_parse_expr2(s, PF_IN_ACCEPTED);
- }
- static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
- JSAtom label_name,
- int label_break, int label_cont,
- int drop_count)
- {
- be->prev = fd->top_break;
- fd->top_break = be;
- be->label_name = label_name;
- be->label_break = label_break;
- be->label_cont = label_cont;
- be->drop_count = drop_count;
- be->label_finally = -1;
- be->scope_level = fd->scope_level;
- be->has_iterator = false;
- be->is_regular_stmt = false;
- }
- static void pop_break_entry(JSFunctionDef *fd)
- {
- BlockEnv *be;
- be = fd->top_break;
- fd->top_break = be->prev;
- }
- static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
- {
- BlockEnv *top;
- int i, scope_level;
- scope_level = s->cur_func->scope_level;
- top = s->cur_func->top_break;
- while (top != NULL) {
- close_scopes(s, scope_level, top->scope_level);
- scope_level = top->scope_level;
- if (is_cont &&
- top->label_cont != -1 &&
- (name == JS_ATOM_NULL || top->label_name == name)) {
- /* continue stays inside the same block */
- emit_goto(s, OP_goto, top->label_cont);
- return 0;
- }
- if (!is_cont && top->label_break != -1) {
- if (top->label_name == name ||
- (name == JS_ATOM_NULL && !top->is_regular_stmt)) {
- emit_goto(s, OP_goto, top->label_break);
- return 0;
- }
- }
- i = 0;
- if (top->has_iterator) {
- emit_op(s, OP_iterator_close);
- i += 3;
- }
- for(; i < top->drop_count; i++)
- emit_op(s, OP_drop);
- if (top->label_finally != -1) {
- /* must push dummy value to keep same stack depth */
- emit_op(s, OP_undefined);
- emit_goto(s, OP_gosub, top->label_finally);
- emit_op(s, OP_drop);
- }
- top = top->prev;
- }
- if (name == JS_ATOM_NULL) {
- if (is_cont)
- return js_parse_error(s, "continue must be inside loop");
- else
- return js_parse_error(s, "break must be inside loop or switch");
- } else {
- return js_parse_error(s, "break/continue label not found");
- }
- }
- /* execute the finally blocks before return */
- static void emit_return(JSParseState *s, bool hasval)
- {
- BlockEnv *top;
- if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
- if (!hasval) {
- /* no value: direct return in case of async generator */
- emit_op(s, OP_undefined);
- hasval = true;
- } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
- /* the await must be done before handling the "finally" in
- case it raises an exception */
- emit_op(s, OP_await);
- }
- }
- top = s->cur_func->top_break;
- while (top != NULL) {
- if (top->has_iterator || top->label_finally != -1) {
- if (!hasval) {
- emit_op(s, OP_undefined);
- hasval = true;
- }
- /* Remove the stack elements up to and including the catch
- offset. When 'yield' is used in an expression we have
- no easy way to count them, so we use this specific
- instruction instead. */
- emit_op(s, OP_nip_catch);
- /* stack: iter_obj next ret_val */
- if (top->has_iterator) {
- if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
- int label_next, label_next2;
- emit_op(s, OP_nip); /* next */
- emit_op(s, OP_swap);
- emit_op(s, OP_get_field2);
- emit_atom(s, JS_ATOM_return);
- /* stack: iter_obj return_func */
- emit_op(s, OP_dup);
- emit_op(s, OP_is_undefined_or_null);
- label_next = emit_goto(s, OP_if_true, -1);
- emit_op(s, OP_call_method);
- emit_u16(s, 0);
- emit_op(s, OP_iterator_check_object);
- emit_op(s, OP_await);
- label_next2 = emit_goto(s, OP_goto, -1);
- emit_label(s, label_next);
- emit_op(s, OP_drop);
- emit_label(s, label_next2);
- emit_op(s, OP_drop);
- } else {
- emit_op(s, OP_rot3r);
- emit_op(s, OP_undefined); /* dummy catch offset */
- emit_op(s, OP_iterator_close);
- }
- } else {
- /* execute the "finally" block */
- emit_goto(s, OP_gosub, top->label_finally);
- }
- }
- top = top->prev;
- }
- if (s->cur_func->is_derived_class_constructor) {
- int label_return;
- /* 'this' can be uninitialized, so it may be accessed only if
- the derived class constructor does not return an object */
- if (hasval) {
- emit_op(s, OP_check_ctor_return);
- label_return = emit_goto(s, OP_if_false, -1);
- emit_op(s, OP_drop);
- } else {
- label_return = -1;
- }
- /* XXX: if this is not initialized, should throw the
- ReferenceError in the caller realm */
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_this);
- emit_u16(s, 0);
- emit_label(s, label_return);
- emit_op(s, OP_return);
- } else if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
- emit_op(s, OP_return_async);
- } else {
- emit_op(s, hasval ? OP_return : OP_return_undef);
- }
- }
- #define DECL_MASK_FUNC (1 << 0) /* allow normal function declaration */
- /* ored with DECL_MASK_FUNC if function declarations are allowed with a label */
- #define DECL_MASK_FUNC_WITH_LABEL (1 << 1)
- #define DECL_MASK_OTHER (1 << 2) /* all other declarations */
- #define DECL_MASK_ALL (DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL | DECL_MASK_OTHER)
- static __exception int js_parse_statement_or_decl(JSParseState *s,
- int decl_mask);
- static __exception int js_parse_statement(JSParseState *s)
- {
- return js_parse_statement_or_decl(s, 0);
- }
- static __exception int js_parse_block(JSParseState *s)
- {
- if (js_parse_expect(s, '{'))
- return -1;
- if (s->token.val != '}') {
- push_scope(s);
- for(;;) {
- if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
- return -1;
- if (s->token.val == '}')
- break;
- }
- pop_scope(s);
- }
- if (next_token(s))
- return -1;
- return 0;
- }
- /* allowed parse_flags: PF_IN_ACCEPTED */
- static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
- bool export_flag)
- {
- JSContext *ctx = s->ctx;
- JSFunctionDef *fd = s->cur_func;
- JSAtom name = JS_ATOM_NULL;
- for (;;) {
- if (s->token.val == TOK_IDENT) {
- if (s->token.u.ident.is_reserved) {
- return js_parse_error_reserved_identifier(s);
- }
- name = JS_DupAtom(ctx, s->token.u.ident.atom);
- if (name == JS_ATOM_let && (tok == TOK_LET || tok == TOK_CONST)) {
- js_parse_error(s, "'let' is not a valid lexical identifier");
- goto var_error;
- }
- if (next_token(s))
- goto var_error;
- if (js_define_var(s, name, tok))
- goto var_error;
- if (export_flag) {
- if (!add_export_entry(s, s->cur_func->module, name, name,
- JS_EXPORT_TYPE_LOCAL))
- goto var_error;
- }
- if (s->token.val == '=') {
- if (next_token(s))
- goto var_error;
- if (tok == TOK_VAR) {
- /* Must make a reference for proper `with` semantics */
- int opcode, scope, label;
- JSAtom name1;
- emit_op(s, OP_scope_get_var);
- emit_atom(s, name);
- emit_u16(s, fd->scope_level);
- if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, false, '=') < 0)
- goto var_error;
- if (js_parse_assign_expr2(s, parse_flags)) {
- JS_FreeAtom(ctx, name1);
- goto var_error;
- }
- set_object_name(s, name);
- put_lvalue(s, opcode, scope, name1, label,
- PUT_LVALUE_NOKEEP, false);
- } else {
- if (js_parse_assign_expr2(s, parse_flags))
- goto var_error;
- set_object_name(s, name);
- emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
- OP_scope_put_var_init : OP_scope_put_var);
- emit_atom(s, name);
- emit_u16(s, fd->scope_level);
- }
- } else {
- if (tok == TOK_CONST) {
- js_parse_error(s, "missing initializer for const variable");
- goto var_error;
- }
- if (tok == TOK_LET) {
- /* initialize lexical variable upon entering its scope */
- emit_op(s, OP_undefined);
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, name);
- emit_u16(s, fd->scope_level);
- }
- }
- JS_FreeAtom(ctx, name);
- } else {
- int skip_bits;
- if ((s->token.val == '[' || s->token.val == '{')
- && js_parse_skip_parens_token(s, &skip_bits, false) == '=') {
- emit_op(s, OP_undefined);
- if (js_parse_destructuring_element(s, tok, false, true, skip_bits & SKIP_HAS_ELLIPSIS, true, export_flag) < 0)
- return -1;
- } else {
- return js_parse_error(s, "variable name expected");
- }
- }
- if (s->token.val != ',')
- break;
- if (next_token(s))
- return -1;
- }
- return 0;
- var_error:
- JS_FreeAtom(ctx, name);
- return -1;
- }
- /* test if the current token is a label. Use simplistic look-ahead scanner */
- static bool is_label(JSParseState *s)
- {
- return (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
- peek_token(s, false) == ':');
- }
- /* test if the current token is a let keyword. Use simplistic look-ahead scanner */
- static int is_let(JSParseState *s, int decl_mask)
- {
- int res = false;
- if (token_is_pseudo_keyword(s, JS_ATOM_let)) {
- JSParsePos pos;
- js_parse_get_pos(s, &pos);
- for (;;) {
- if (next_token(s)) {
- res = -1;
- break;
- }
- if (s->token.val == '[') {
- /* let [ is a syntax restriction:
- it never introduces an ExpressionStatement */
- res = true;
- break;
- }
- if (s->token.val == '{' ||
- (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) ||
- s->token.val == TOK_LET ||
- s->token.val == TOK_YIELD ||
- s->token.val == TOK_AWAIT) {
- /* Check for possible ASI if not scanning for Declaration */
- /* XXX: should also check that `{` introduces a BindingPattern,
- but Firefox does not and rejects eval("let=1;let\n{if(1)2;}") */
- if (s->last_line_num == s->token.line_num || (decl_mask & DECL_MASK_OTHER)) {
- res = true;
- break;
- }
- break;
- }
- break;
- }
- if (js_parse_seek_token(s, &pos)) {
- res = -1;
- }
- }
- return res;
- }
- /* XXX: handle IteratorClose when exiting the loop before the
- enumeration is done */
- static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
- bool is_async)
- {
- JSContext *ctx = s->ctx;
- JSFunctionDef *fd = s->cur_func;
- JSAtom var_name;
- bool has_initializer, is_for_of, has_destructuring;
- int tok, tok1, opcode, scope, block_scope_level;
- int label_next, label_expr, label_cont, label_body, label_break;
- int pos_next, pos_expr;
- BlockEnv break_entry;
- has_initializer = false;
- has_destructuring = false;
- is_for_of = false;
- block_scope_level = fd->scope_level;
- label_cont = new_label(s);
- label_body = new_label(s);
- label_break = new_label(s);
- label_next = new_label(s);
- /* create scope for the lexical variables declared in the enumeration
- expressions. XXX: Not completely correct because of weird capturing
- semantics in `for (i of o) a.push(function(){return i})` */
- push_scope(s);
- /* local for_in scope starts here so individual elements
- can be closed in statement. */
- push_break_entry(s->cur_func, &break_entry,
- label_name, label_break, label_cont, 1);
- break_entry.scope_level = block_scope_level;
- label_expr = emit_goto(s, OP_goto, -1);
- pos_next = s->cur_func->byte_code.size;
- emit_label(s, label_next);
- tok = s->token.val;
- switch (is_let(s, DECL_MASK_OTHER)) {
- case true:
- tok = TOK_LET;
- break;
- case false:
- break;
- default:
- return -1;
- }
- if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
- if (next_token(s))
- return -1;
- if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
- if (s->token.val == '[' || s->token.val == '{') {
- if (js_parse_destructuring_element(s, tok, false, true, -1, false, false) < 0)
- return -1;
- has_destructuring = true;
- } else {
- return js_parse_error(s, "variable name expected");
- }
- var_name = JS_ATOM_NULL;
- } else {
- var_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- if (next_token(s)) {
- JS_FreeAtom(s->ctx, var_name);
- return -1;
- }
- if (js_define_var(s, var_name, tok)) {
- JS_FreeAtom(s->ctx, var_name);
- return -1;
- }
- emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
- OP_scope_put_var_init : OP_scope_put_var);
- emit_atom(s, var_name);
- emit_u16(s, fd->scope_level);
- }
- } else if (!is_async && token_is_pseudo_keyword(s, JS_ATOM_async) && peek_token(s, false) == TOK_OF) {
- return js_parse_error(s, "'for of' expression cannot start with 'async'");
- } else {
- int skip_bits;
- if ((s->token.val == '[' || s->token.val == '{')
- && ((tok1 = js_parse_skip_parens_token(s, &skip_bits, false)) == TOK_IN || tok1 == TOK_OF)) {
- if (js_parse_destructuring_element(s, 0, false, true, skip_bits & SKIP_HAS_ELLIPSIS, true, false) < 0)
- return -1;
- } else {
- int lvalue_label;
- if (js_parse_left_hand_side_expr(s))
- return -1;
- if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label,
- NULL, false, TOK_FOR))
- return -1;
- put_lvalue(s, opcode, scope, var_name, lvalue_label,
- PUT_LVALUE_NOKEEP_BOTTOM, false);
- }
- var_name = JS_ATOM_NULL;
- }
- emit_goto(s, OP_goto, label_body);
- pos_expr = s->cur_func->byte_code.size;
- emit_label(s, label_expr);
- if (s->token.val == '=') {
- /* XXX: potential scoping issue if inside `with` statement */
- has_initializer = true;
- /* parse and evaluate initializer prior to evaluating the
- object (only used with "for in" with a non lexical variable
- in non strict mode */
- if (next_token(s) || js_parse_assign_expr2(s, 0)) {
- JS_FreeAtom(ctx, var_name);
- return -1;
- }
- if (var_name != JS_ATOM_NULL) {
- emit_op(s, OP_scope_put_var);
- emit_atom(s, var_name);
- emit_u16(s, fd->scope_level);
- }
- }
- JS_FreeAtom(ctx, var_name);
- if (token_is_pseudo_keyword(s, JS_ATOM_of)) {
- is_for_of = true;
- break_entry.has_iterator = true;
- break_entry.drop_count += 2;
- if (has_initializer)
- goto initializer_error;
- } else if (s->token.val == TOK_IN) {
- if (is_async)
- return js_parse_error(s, "'for await' loop should be used with 'of'");
- if (has_initializer &&
- (tok != TOK_VAR || fd->is_strict_mode || has_destructuring)) {
- initializer_error:
- return js_parse_error(s, "a declaration in the head of a for-%s loop can't have an initializer",
- is_for_of ? "of" : "in");
- }
- } else {
- return js_parse_error(s, "expected 'of' or 'in' in for control expression");
- }
- if (next_token(s))
- return -1;
- if (is_for_of) {
- if (js_parse_assign_expr(s))
- return -1;
- } else {
- if (js_parse_expr(s))
- return -1;
- }
- /* close the scope after having evaluated the expression so that
- the TDZ values are in the closures */
- close_scopes(s, s->cur_func->scope_level, block_scope_level);
- if (is_for_of) {
- if (is_async)
- emit_op(s, OP_for_await_of_start);
- else
- emit_op(s, OP_for_of_start);
- /* on stack: enum_rec */
- } else {
- emit_op(s, OP_for_in_start);
- /* on stack: enum_obj */
- }
- emit_goto(s, OP_goto, label_cont);
- if (js_parse_expect(s, ')'))
- return -1;
- {
- /* move the `next` code here */
- DynBuf *bc = &s->cur_func->byte_code;
- int chunk_size = pos_expr - pos_next;
- int offset = bc->size - pos_next;
- int i;
- dbuf_realloc(bc, bc->size + chunk_size);
- dbuf_put(bc, bc->buf + pos_next, chunk_size);
- memset(bc->buf + pos_next, OP_nop, chunk_size);
- /* `next` part ends with a goto */
- s->cur_func->last_opcode_pos = bc->size - 5;
- /* relocate labels */
- for (i = label_cont; i < s->cur_func->label_count; i++) {
- LabelSlot *ls = &s->cur_func->label_slots[i];
- if (ls->pos >= pos_next && ls->pos < pos_expr)
- ls->pos += offset;
- }
- }
- emit_label(s, label_body);
- if (js_parse_statement(s))
- return -1;
- close_scopes(s, s->cur_func->scope_level, block_scope_level);
- emit_label(s, label_cont);
- if (is_for_of) {
- if (is_async) {
- /* call the next method */
- /* stack: iter_obj next catch_offset */
- emit_op(s, OP_dup3);
- emit_op(s, OP_drop);
- emit_op(s, OP_call_method);
- emit_u16(s, 0);
- /* get the result of the promise */
- emit_op(s, OP_await);
- /* unwrap the value and done values */
- emit_op(s, OP_iterator_get_value_done);
- } else {
- emit_op(s, OP_for_of_next);
- emit_u8(s, 0);
- }
- } else {
- emit_op(s, OP_for_in_next);
- }
- /* on stack: enum_rec / enum_obj value bool */
- emit_goto(s, OP_if_false, label_next);
- /* drop the undefined value from for_xx_next */
- emit_op(s, OP_drop);
- emit_label(s, label_break);
- if (is_for_of) {
- /* close and drop enum_rec */
- emit_op(s, OP_iterator_close);
- } else {
- emit_op(s, OP_drop);
- }
- pop_break_entry(s->cur_func);
- pop_scope(s);
- return 0;
- }
- static void set_eval_ret_undefined(JSParseState *s)
- {
- if (s->cur_func->eval_ret_idx >= 0) {
- emit_op(s, OP_undefined);
- emit_op(s, OP_put_loc);
- emit_u16(s, s->cur_func->eval_ret_idx);
- }
- }
- static __exception int js_parse_statement_or_decl(JSParseState *s,
- int decl_mask)
- {
- JSContext *ctx = s->ctx;
- JSAtom label_name;
- int tok;
- /* specific label handling */
- /* XXX: support multiple labels on loop statements */
- label_name = JS_ATOM_NULL;
- if (is_label(s)) {
- BlockEnv *be;
- label_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- for (be = s->cur_func->top_break; be; be = be->prev) {
- if (be->label_name == label_name) {
- js_parse_error(s, "duplicate label name");
- goto fail;
- }
- }
- if (next_token(s))
- goto fail;
- if (js_parse_expect(s, ':'))
- goto fail;
- if (s->token.val != TOK_FOR
- && s->token.val != TOK_DO
- && s->token.val != TOK_WHILE) {
- /* labelled regular statement */
- JSFunctionDef *fd = s->cur_func;
- int label_break, mask;
- BlockEnv break_entry;
- label_break = new_label(s);
- push_break_entry(fd, &break_entry, label_name, label_break, -1, 0);
- fd->top_break->is_regular_stmt = 1;
- if (!fd->is_strict_mode &&
- (decl_mask & DECL_MASK_FUNC_WITH_LABEL)) {
- mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL;
- } else {
- mask = 0;
- }
- if (js_parse_statement_or_decl(s, mask))
- goto fail;
- emit_label(s, label_break);
- pop_break_entry(fd);
- goto done;
- }
- }
- switch(tok = s->token.val) {
- case '{':
- if (js_parse_block(s))
- goto fail;
- break;
- case TOK_RETURN:
- if (s->cur_func->is_eval) {
- js_parse_error(s, "return not in a function");
- goto fail;
- }
- if (s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
- js_parse_error(s, "return in a static initializer block");
- goto fail;
- }
- if (next_token(s))
- goto fail;
- if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {
- if (js_parse_expr(s))
- goto fail;
- emit_return(s, true);
- } else {
- emit_return(s, false);
- }
- if (js_parse_expect_semi(s))
- goto fail;
- break;
- case TOK_THROW:
- if (next_token(s))
- goto fail;
- if (s->got_lf) {
- js_parse_error(s, "line terminator not allowed after throw");
- goto fail;
- }
- emit_source_loc(s);
- if (js_parse_expr(s))
- goto fail;
- emit_op(s, OP_throw);
- if (js_parse_expect_semi(s))
- goto fail;
- break;
- case TOK_LET:
- case TOK_CONST:
- haslet:
- if (!(decl_mask & DECL_MASK_OTHER)) {
- js_parse_error(s, "lexical declarations can't appear in single-statement context");
- goto fail;
- }
- /* fall thru */
- case TOK_VAR:
- if (next_token(s))
- goto fail;
- if (js_parse_var(s, PF_IN_ACCEPTED, tok, /*export_flag*/false))
- goto fail;
- if (js_parse_expect_semi(s))
- goto fail;
- break;
- case TOK_IF:
- {
- int label1, label2, mask;
- if (next_token(s))
- goto fail;
- /* create a new scope for `let f;if(1) function f(){}` */
- push_scope(s);
- set_eval_ret_undefined(s);
- if (js_parse_expr_paren(s))
- goto fail;
- label1 = emit_goto(s, OP_if_false, -1);
- if (s->cur_func->is_strict_mode)
- mask = 0;
- else
- mask = DECL_MASK_FUNC; /* Annex B.3.4 */
- if (js_parse_statement_or_decl(s, mask))
- goto fail;
- if (s->token.val == TOK_ELSE) {
- label2 = emit_goto(s, OP_goto, -1);
- if (next_token(s))
- goto fail;
- emit_label(s, label1);
- if (js_parse_statement_or_decl(s, mask))
- goto fail;
- label1 = label2;
- }
- emit_label(s, label1);
- pop_scope(s);
- }
- break;
- case TOK_WHILE:
- {
- int label_cont, label_break;
- BlockEnv break_entry;
- label_cont = new_label(s);
- label_break = new_label(s);
- push_break_entry(s->cur_func, &break_entry,
- label_name, label_break, label_cont, 0);
- if (next_token(s))
- goto fail;
- set_eval_ret_undefined(s);
- emit_label(s, label_cont);
- if (js_parse_expr_paren(s))
- goto fail;
- emit_goto(s, OP_if_false, label_break);
- if (js_parse_statement(s))
- goto fail;
- emit_goto(s, OP_goto, label_cont);
- emit_label(s, label_break);
- pop_break_entry(s->cur_func);
- }
- break;
- case TOK_DO:
- {
- int label_cont, label_break, label1;
- BlockEnv break_entry;
- label_cont = new_label(s);
- label_break = new_label(s);
- label1 = new_label(s);
- push_break_entry(s->cur_func, &break_entry,
- label_name, label_break, label_cont, 0);
- if (next_token(s))
- goto fail;
- emit_label(s, label1);
- set_eval_ret_undefined(s);
- if (js_parse_statement(s))
- goto fail;
- emit_label(s, label_cont);
- if (js_parse_expect(s, TOK_WHILE))
- goto fail;
- if (js_parse_expr_paren(s))
- goto fail;
- /* Insert semicolon if missing */
- if (s->token.val == ';') {
- if (next_token(s))
- goto fail;
- }
- emit_goto(s, OP_if_true, label1);
- emit_label(s, label_break);
- pop_break_entry(s->cur_func);
- }
- break;
- case TOK_FOR:
- {
- int label_cont, label_break, label_body, label_test;
- int pos_cont, pos_body, block_scope_level;
- BlockEnv break_entry;
- int tok, bits;
- bool is_async;
- if (next_token(s))
- goto fail;
- set_eval_ret_undefined(s);
- bits = 0;
- is_async = false;
- if (s->token.val == '(') {
- js_parse_skip_parens_token(s, &bits, false);
- } else if (s->token.val == TOK_AWAIT) {
- if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) {
- js_parse_error(s, "for await is only valid in asynchronous functions");
- goto fail;
- }
- is_async = true;
- if (next_token(s))
- goto fail;
- s->cur_func->has_await = true;
- }
- if (js_parse_expect(s, '('))
- goto fail;
- if (!(bits & SKIP_HAS_SEMI)) {
- /* parse for/in or for/of */
- if (js_parse_for_in_of(s, label_name, is_async))
- goto fail;
- break;
- }
- block_scope_level = s->cur_func->scope_level;
- /* create scope for the lexical variables declared in the initial,
- test and increment expressions */
- push_scope(s);
- /* initial expression */
- tok = s->token.val;
- if (tok != ';') {
- switch (is_let(s, DECL_MASK_OTHER)) {
- case true:
- tok = TOK_LET;
- break;
- case false:
- break;
- default:
- goto fail;
- }
- if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
- if (next_token(s))
- goto fail;
- if (js_parse_var(s, 0, tok, /*export_flag*/false))
- goto fail;
- } else {
- if (js_parse_expr2(s, false))
- goto fail;
- emit_op(s, OP_drop);
- }
- /* close the closures before the first iteration */
- close_scopes(s, s->cur_func->scope_level, block_scope_level);
- }
- if (js_parse_expect(s, ';'))
- goto fail;
- label_test = new_label(s);
- label_cont = new_label(s);
- label_body = new_label(s);
- label_break = new_label(s);
- push_break_entry(s->cur_func, &break_entry,
- label_name, label_break, label_cont, 0);
- /* test expression */
- if (s->token.val == ';') {
- /* no test expression */
- label_test = label_body;
- } else {
- emit_label(s, label_test);
- if (js_parse_expr(s))
- goto fail;
- emit_goto(s, OP_if_false, label_break);
- }
- if (js_parse_expect(s, ';'))
- goto fail;
- if (s->token.val == ')') {
- /* no end expression */
- break_entry.label_cont = label_cont = label_test;
- pos_cont = 0; /* avoid warning */
- } else {
- /* skip the end expression */
- emit_goto(s, OP_goto, label_body);
- pos_cont = s->cur_func->byte_code.size;
- emit_label(s, label_cont);
- if (js_parse_expr(s))
- goto fail;
- emit_op(s, OP_drop);
- if (label_test != label_body)
- emit_goto(s, OP_goto, label_test);
- }
- if (js_parse_expect(s, ')'))
- goto fail;
- pos_body = s->cur_func->byte_code.size;
- emit_label(s, label_body);
- if (js_parse_statement(s))
- goto fail;
- /* close the closures before the next iteration */
- /* XXX: check continue case */
- close_scopes(s, s->cur_func->scope_level, block_scope_level);
- if (label_test != label_body && label_cont != label_test) {
- /* move the increment code here */
- DynBuf *bc = &s->cur_func->byte_code;
- int chunk_size = pos_body - pos_cont;
- int offset = bc->size - pos_cont;
- int i;
- dbuf_realloc(bc, bc->size + chunk_size);
- dbuf_put(bc, bc->buf + pos_cont, chunk_size);
- memset(bc->buf + pos_cont, OP_nop, chunk_size);
- /* increment part ends with a goto */
- s->cur_func->last_opcode_pos = bc->size - 5;
- /* relocate labels */
- for (i = label_cont; i < s->cur_func->label_count; i++) {
- LabelSlot *ls = &s->cur_func->label_slots[i];
- if (ls->pos >= pos_cont && ls->pos < pos_body)
- ls->pos += offset;
- }
- } else {
- emit_goto(s, OP_goto, label_cont);
- }
- emit_label(s, label_break);
- pop_break_entry(s->cur_func);
- pop_scope(s);
- }
- break;
- case TOK_BREAK:
- case TOK_CONTINUE:
- {
- int is_cont = s->token.val - TOK_BREAK;
- int label;
- if (next_token(s))
- goto fail;
- if (!s->got_lf && s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
- label = s->token.u.ident.atom;
- else
- label = JS_ATOM_NULL;
- if (emit_break(s, label, is_cont))
- goto fail;
- if (label != JS_ATOM_NULL) {
- if (next_token(s))
- goto fail;
- }
- if (js_parse_expect_semi(s))
- goto fail;
- }
- break;
- case TOK_SWITCH:
- {
- int label_case, label_break, label1;
- int default_label_pos;
- BlockEnv break_entry;
- if (next_token(s))
- goto fail;
- set_eval_ret_undefined(s);
- if (js_parse_expr_paren(s))
- goto fail;
- push_scope(s);
- label_break = new_label(s);
- push_break_entry(s->cur_func, &break_entry,
- label_name, label_break, -1, 1);
- if (js_parse_expect(s, '{'))
- goto fail;
- default_label_pos = -1;
- label_case = -1;
- while (s->token.val != '}') {
- if (s->token.val == TOK_CASE) {
- label1 = -1;
- if (label_case >= 0) {
- /* skip the case if needed */
- label1 = emit_goto(s, OP_goto, -1);
- }
- emit_label(s, label_case);
- label_case = -1;
- for (;;) {
- /* parse a sequence of case clauses */
- if (next_token(s))
- goto fail;
- emit_op(s, OP_dup);
- if (js_parse_expr(s))
- goto fail;
- if (js_parse_expect(s, ':'))
- goto fail;
- emit_op(s, OP_strict_eq);
- if (s->token.val == TOK_CASE) {
- label1 = emit_goto(s, OP_if_true, label1);
- } else {
- label_case = emit_goto(s, OP_if_false, -1);
- emit_label(s, label1);
- break;
- }
- }
- } else if (s->token.val == TOK_DEFAULT) {
- if (next_token(s))
- goto fail;
- if (js_parse_expect(s, ':'))
- goto fail;
- if (default_label_pos >= 0) {
- js_parse_error(s, "duplicate default");
- goto fail;
- }
- if (label_case < 0) {
- /* falling thru direct from switch expression */
- label_case = emit_goto(s, OP_goto, -1);
- }
- /* Emit a dummy label opcode. Label will be patched after
- the end of the switch body. Do not use emit_label(s, 0)
- because it would clobber label 0 address, preventing
- proper optimizer operation.
- */
- emit_op(s, OP_label);
- emit_u32(s, 0);
- default_label_pos = s->cur_func->byte_code.size - 4;
- } else {
- if (label_case < 0) {
- /* falling thru direct from switch expression */
- js_parse_error(s, "invalid switch statement");
- goto fail;
- }
- if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
- goto fail;
- }
- }
- if (js_parse_expect(s, '}'))
- goto fail;
- if (default_label_pos >= 0) {
- /* Ugly patch for the the `default` label, shameful and risky */
- put_u32(s->cur_func->byte_code.buf + default_label_pos,
- label_case);
- s->cur_func->label_slots[label_case].pos = default_label_pos + 4;
- } else {
- emit_label(s, label_case);
- }
- emit_label(s, label_break);
- emit_op(s, OP_drop); /* drop the switch expression */
- pop_break_entry(s->cur_func);
- pop_scope(s);
- }
- break;
- case TOK_TRY:
- {
- int label_catch, label_catch2, label_finally, label_end;
- JSAtom name;
- BlockEnv block_env;
- set_eval_ret_undefined(s);
- if (next_token(s))
- goto fail;
- label_catch = new_label(s);
- label_catch2 = new_label(s);
- label_finally = new_label(s);
- label_end = new_label(s);
- emit_goto(s, OP_catch, label_catch);
- push_break_entry(s->cur_func, &block_env,
- JS_ATOM_NULL, -1, -1, 1);
- block_env.label_finally = label_finally;
- if (js_parse_block(s))
- goto fail;
- pop_break_entry(s->cur_func);
- if (js_is_live_code(s)) {
- /* drop the catch offset */
- emit_op(s, OP_drop);
- /* must push dummy value to keep same stack size */
- emit_op(s, OP_undefined);
- emit_goto(s, OP_gosub, label_finally);
- emit_op(s, OP_drop);
- emit_goto(s, OP_goto, label_end);
- }
- if (s->token.val == TOK_CATCH) {
- if (next_token(s))
- goto fail;
- push_scope(s); /* catch variable */
- emit_label(s, label_catch);
- if (s->token.val == '{') {
- /* support optional-catch-binding feature */
- emit_op(s, OP_drop); /* pop the exception object */
- } else {
- if (js_parse_expect(s, '('))
- goto fail;
- if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
- if (s->token.val == '[' || s->token.val == '{') {
- /* XXX: TOK_LET is not completely correct */
- if (js_parse_destructuring_element(s, TOK_LET, false, true, -1, true, false) < 0)
- goto fail;
- } else {
- js_parse_error(s, "identifier expected");
- goto fail;
- }
- } else {
- name = JS_DupAtom(ctx, s->token.u.ident.atom);
- if (next_token(s)
- || js_define_var(s, name, TOK_CATCH) < 0) {
- JS_FreeAtom(ctx, name);
- goto fail;
- }
- /* store the exception value in the catch variable */
- emit_op(s, OP_scope_put_var);
- emit_u32(s, name);
- emit_u16(s, s->cur_func->scope_level);
- }
- if (js_parse_expect(s, ')'))
- goto fail;
- }
- /* XXX: should keep the address to nop it out if there is no finally block */
- emit_goto(s, OP_catch, label_catch2);
- push_scope(s); /* catch block */
- push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
- -1, -1, 1);
- block_env.label_finally = label_finally;
- if (js_parse_block(s))
- goto fail;
- pop_break_entry(s->cur_func);
- pop_scope(s); /* catch block */
- pop_scope(s); /* catch variable */
- if (js_is_live_code(s)) {
- /* drop the catch2 offset */
- emit_op(s, OP_drop);
- /* XXX: should keep the address to nop it out if there is no finally block */
- /* must push dummy value to keep same stack size */
- emit_op(s, OP_undefined);
- emit_goto(s, OP_gosub, label_finally);
- emit_op(s, OP_drop);
- emit_goto(s, OP_goto, label_end);
- }
- /* catch exceptions thrown in the catch block to execute the
- * finally clause and rethrow the exception */
- emit_label(s, label_catch2);
- /* catch value is at TOS, no need to push undefined */
- emit_goto(s, OP_gosub, label_finally);
- emit_op(s, OP_throw);
- } else if (s->token.val == TOK_FINALLY) {
- /* finally without catch : execute the finally clause
- * and rethrow the exception */
- emit_label(s, label_catch);
- /* catch value is at TOS, no need to push undefined */
- emit_goto(s, OP_gosub, label_finally);
- emit_op(s, OP_throw);
- } else {
- js_parse_error(s, "expecting catch or finally");
- goto fail;
- }
- emit_label(s, label_finally);
- if (s->token.val == TOK_FINALLY) {
- int saved_eval_ret_idx = 0; /* avoid warning */
- if (next_token(s))
- goto fail;
- /* on the stack: ret_value gosub_ret_value */
- push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
- -1, -1, 2);
- if (s->cur_func->eval_ret_idx >= 0) {
- /* 'finally' updates eval_ret only if not a normal
- termination */
- saved_eval_ret_idx =
- add_var(s->ctx, s->cur_func, JS_ATOM__ret_);
- if (saved_eval_ret_idx < 0)
- goto fail;
- emit_op(s, OP_get_loc);
- emit_u16(s, s->cur_func->eval_ret_idx);
- emit_op(s, OP_put_loc);
- emit_u16(s, saved_eval_ret_idx);
- set_eval_ret_undefined(s);
- }
- if (js_parse_block(s))
- goto fail;
- if (s->cur_func->eval_ret_idx >= 0) {
- emit_op(s, OP_get_loc);
- emit_u16(s, saved_eval_ret_idx);
- emit_op(s, OP_put_loc);
- emit_u16(s, s->cur_func->eval_ret_idx);
- }
- pop_break_entry(s->cur_func);
- }
- emit_op(s, OP_ret);
- emit_label(s, label_end);
- }
- break;
- case ';':
- /* empty statement */
- if (next_token(s))
- goto fail;
- break;
- case TOK_WITH:
- if (s->cur_func->is_strict_mode) {
- js_parse_error(s, "invalid keyword: with");
- goto fail;
- } else {
- int with_idx;
- if (next_token(s))
- goto fail;
- if (js_parse_expr_paren(s))
- goto fail;
- push_scope(s);
- with_idx = define_var(s, s->cur_func, JS_ATOM__with_,
- JS_VAR_DEF_WITH);
- if (with_idx < 0)
- goto fail;
- emit_op(s, OP_to_object);
- emit_op(s, OP_put_loc);
- emit_u16(s, with_idx);
- set_eval_ret_undefined(s);
- if (js_parse_statement(s))
- goto fail;
- /* Popping scope drops lexical context for the with object variable */
- pop_scope(s);
- }
- break;
- case TOK_FUNCTION:
- /* ES6 Annex B.3.2 and B.3.3 semantics */
- if (!(decl_mask & DECL_MASK_FUNC))
- goto func_decl_error;
- if (!(decl_mask & DECL_MASK_OTHER) && peek_token(s, false) == '*')
- goto func_decl_error;
- goto parse_func_var;
- case TOK_IDENT:
- if (s->token.u.ident.is_reserved) {
- js_parse_error_reserved_identifier(s);
- goto fail;
- }
- /* Determine if `let` introduces a Declaration or an ExpressionStatement */
- switch (is_let(s, decl_mask)) {
- case true:
- tok = TOK_LET;
- goto haslet;
- case false:
- break;
- default:
- goto fail;
- }
- if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
- peek_token(s, true) == TOK_FUNCTION) {
- if (!(decl_mask & DECL_MASK_OTHER)) {
- func_decl_error:
- js_parse_error(s, "function declarations can't appear in single-statement context");
- goto fail;
- }
- parse_func_var:
- if (js_parse_function_decl(s, JS_PARSE_FUNC_VAR,
- JS_FUNC_NORMAL, JS_ATOM_NULL,
- s->token.ptr,
- s->token.line_num,
- s->token.col_num))
- goto fail;
- break;
- }
- goto hasexpr;
- case TOK_CLASS:
- if (!(decl_mask & DECL_MASK_OTHER)) {
- js_parse_error(s, "class declarations can't appear in single-statement context");
- goto fail;
- }
- if (js_parse_class(s, false, JS_PARSE_EXPORT_NONE))
- return -1;
- break;
- case TOK_DEBUGGER:
- /* currently no debugger, so just skip the keyword */
- if (next_token(s))
- goto fail;
- if (js_parse_expect_semi(s))
- goto fail;
- break;
- case TOK_ENUM:
- case TOK_EXPORT:
- case TOK_EXTENDS:
- js_unsupported_keyword(s, s->token.u.ident.atom);
- goto fail;
- default:
- hasexpr:
- emit_source_loc(s);
- if (js_parse_expr(s))
- goto fail;
- if (s->cur_func->eval_ret_idx >= 0) {
- /* store the expression value so that it can be returned
- by eval() */
- emit_op(s, OP_put_loc);
- emit_u16(s, s->cur_func->eval_ret_idx);
- } else {
- emit_op(s, OP_drop); /* drop the result */
- }
- if (js_parse_expect_semi(s))
- goto fail;
- break;
- }
- done:
- JS_FreeAtom(ctx, label_name);
- return 0;
- fail:
- JS_FreeAtom(ctx, label_name);
- return -1;
- }
- #endif // QJS_DISABLE_PARSER
- /* 'name' is freed */
- static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
- {
- JSModuleDef *m;
- m = js_mallocz(ctx, sizeof(*m));
- if (!m) {
- JS_FreeAtom(ctx, name);
- return NULL;
- }
- m->header.ref_count = 1;
- m->module_name = name;
- m->module_ns = JS_UNDEFINED;
- m->func_obj = JS_UNDEFINED;
- m->eval_exception = JS_UNDEFINED;
- m->meta_obj = JS_UNDEFINED;
- m->promise = JS_UNDEFINED;
- m->resolving_funcs[0] = JS_UNDEFINED;
- m->resolving_funcs[1] = JS_UNDEFINED;
- list_add_tail(&m->link, &ctx->loaded_modules);
- return m;
- }
- static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
- JS_MarkFunc *mark_func)
- {
- int i;
- for(i = 0; i < m->export_entries_count; i++) {
- JSExportEntry *me = &m->export_entries[i];
- if (me->export_type == JS_EXPORT_TYPE_LOCAL &&
- me->u.local.var_ref) {
- mark_func(rt, &me->u.local.var_ref->header);
- }
- }
- JS_MarkValue(rt, m->module_ns, mark_func);
- JS_MarkValue(rt, m->func_obj, mark_func);
- JS_MarkValue(rt, m->eval_exception, mark_func);
- JS_MarkValue(rt, m->meta_obj, mark_func);
- JS_MarkValue(rt, m->promise, mark_func);
- JS_MarkValue(rt, m->resolving_funcs[0], mark_func);
- JS_MarkValue(rt, m->resolving_funcs[1], mark_func);
- }
- static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
- {
- int i;
- JS_FreeAtom(ctx, m->module_name);
- for(i = 0; i < m->req_module_entries_count; i++) {
- JSReqModuleEntry *rme = &m->req_module_entries[i];
- JS_FreeAtom(ctx, rme->module_name);
- }
- js_free(ctx, m->req_module_entries);
- for(i = 0; i < m->export_entries_count; i++) {
- JSExportEntry *me = &m->export_entries[i];
- if (me->export_type == JS_EXPORT_TYPE_LOCAL)
- free_var_ref(ctx->rt, me->u.local.var_ref);
- JS_FreeAtom(ctx, me->export_name);
- JS_FreeAtom(ctx, me->local_name);
- }
- js_free(ctx, m->export_entries);
- js_free(ctx, m->star_export_entries);
- for(i = 0; i < m->import_entries_count; i++) {
- JSImportEntry *mi = &m->import_entries[i];
- JS_FreeAtom(ctx, mi->import_name);
- }
- js_free(ctx, m->import_entries);
- js_free(ctx, m->async_parent_modules);
- JS_FreeValue(ctx, m->module_ns);
- JS_FreeValue(ctx, m->func_obj);
- JS_FreeValue(ctx, m->eval_exception);
- JS_FreeValue(ctx, m->meta_obj);
- JS_FreeValue(ctx, m->promise);
- JS_FreeValue(ctx, m->resolving_funcs[0]);
- JS_FreeValue(ctx, m->resolving_funcs[1]);
- list_del(&m->link);
- js_free(ctx, m);
- }
- #ifndef QJS_DISABLE_PARSER
- static int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
- JSAtom module_name)
- {
- JSReqModuleEntry *rme;
- int i;
- /* no need to add the module request if it is already present */
- for(i = 0; i < m->req_module_entries_count; i++) {
- rme = &m->req_module_entries[i];
- if (rme->module_name == module_name)
- return i;
- }
- if (js_resize_array(ctx, (void **)&m->req_module_entries,
- sizeof(JSReqModuleEntry),
- &m->req_module_entries_size,
- m->req_module_entries_count + 1))
- return -1;
- rme = &m->req_module_entries[m->req_module_entries_count++];
- rme->module_name = JS_DupAtom(ctx, module_name);
- rme->module = NULL;
- return i;
- }
- #endif // QJS_DISABLE_PARSER
- static JSExportEntry *find_export_entry(JSContext *ctx, const JSModuleDef *m,
- JSAtom export_name)
- {
- JSExportEntry *me;
- int i;
- for(i = 0; i < m->export_entries_count; i++) {
- me = &m->export_entries[i];
- if (me->export_name == export_name)
- return me;
- }
- return NULL;
- }
- static JSExportEntry *add_export_entry2(JSContext *ctx,
- JSParseState *s, JSModuleDef *m,
- JSAtom local_name, JSAtom export_name,
- JSExportTypeEnum export_type)
- {
- JSExportEntry *me;
- if (find_export_entry(ctx, m, export_name)) {
- char buf1[ATOM_GET_STR_BUF_SIZE];
- if (s) {
- js_parse_error(s, "duplicate exported name '%s'",
- JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name));
- } else {
- JS_ThrowSyntaxErrorAtom(ctx, "duplicate exported name '%s'", export_name);
- }
- return NULL;
- }
- if (js_resize_array(ctx, (void **)&m->export_entries,
- sizeof(JSExportEntry),
- &m->export_entries_size,
- m->export_entries_count + 1))
- return NULL;
- me = &m->export_entries[m->export_entries_count++];
- memset(me, 0, sizeof(*me));
- me->local_name = JS_DupAtom(ctx, local_name);
- me->export_name = JS_DupAtom(ctx, export_name);
- me->export_type = export_type;
- return me;
- }
- #ifndef QJS_DISABLE_PARSER
- static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
- JSAtom local_name, JSAtom export_name,
- JSExportTypeEnum export_type)
- {
- return add_export_entry2(s->ctx, s, m, local_name, export_name,
- export_type);
- }
- static int add_star_export_entry(JSContext *ctx, JSModuleDef *m,
- int req_module_idx)
- {
- JSStarExportEntry *se;
- if (js_resize_array(ctx, (void **)&m->star_export_entries,
- sizeof(JSStarExportEntry),
- &m->star_export_entries_size,
- m->star_export_entries_count + 1))
- return -1;
- se = &m->star_export_entries[m->star_export_entries_count++];
- se->req_module_idx = req_module_idx;
- return 0;
- }
- #endif // QJS_DISABLE_PARSER
- /* create a C module */
- /* `name_str` may be pure ASCII or UTF-8 encoded */
- JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
- JSModuleInitFunc *func)
- {
- JSModuleDef *m;
- JSAtom name;
- name = JS_NewAtom(ctx, name_str);
- if (name == JS_ATOM_NULL)
- return NULL;
- m = js_new_module_def(ctx, name);
- if (!m)
- return NULL;
- m->init_func = func;
- return m;
- }
- /* `export_name` may be pure ASCII or UTF-8 encoded */
- int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name)
- {
- JSExportEntry *me;
- JSAtom name;
- name = JS_NewAtom(ctx, export_name);
- if (name == JS_ATOM_NULL)
- return -1;
- me = add_export_entry2(ctx, NULL, m, JS_ATOM_NULL, name,
- JS_EXPORT_TYPE_LOCAL);
- JS_FreeAtom(ctx, name);
- if (!me)
- return -1;
- else
- return 0;
- }
- /* `export_name` may be pure ASCII or UTF-8 encoded */
- int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
- JSValue val)
- {
- JSExportEntry *me;
- JSAtom name;
- name = JS_NewAtom(ctx, export_name);
- if (name == JS_ATOM_NULL)
- goto fail;
- me = find_export_entry(ctx, m, name);
- JS_FreeAtom(ctx, name);
- if (!me)
- goto fail;
- set_value(ctx, me->u.local.var_ref->pvalue, val);
- return 0;
- fail:
- JS_FreeValue(ctx, val);
- return -1;
- }
- void JS_SetModuleLoaderFunc(JSRuntime *rt,
- JSModuleNormalizeFunc *module_normalize,
- JSModuleLoaderFunc *module_loader, void *opaque)
- {
- rt->module_normalize_func = module_normalize;
- rt->module_loader_func = module_loader;
- rt->module_loader_opaque = opaque;
- }
- /* default module filename normalizer */
- static char *js_default_module_normalize_name(JSContext *ctx,
- const char *base_name,
- const char *name)
- {
- char *filename, *p;
- const char *r;
- int cap;
- int len;
- if (name[0] != '.') {
- /* if no initial dot, the module name is not modified */
- return js_strdup(ctx, name);
- }
- p = strrchr(base_name, '/');
- if (p)
- len = p - base_name;
- else
- len = 0;
- cap = len + strlen(name) + 1 + 1;
- filename = js_malloc(ctx, cap);
- if (!filename)
- return NULL;
- memcpy(filename, base_name, len);
- filename[len] = '\0';
- /* we only normalize the leading '..' or '.' */
- r = name;
- for(;;) {
- if (r[0] == '.' && r[1] == '/') {
- r += 2;
- } else if (r[0] == '.' && r[1] == '.' && r[2] == '/') {
- /* remove the last path element of filename, except if "."
- or ".." */
- if (filename[0] == '\0')
- break;
- p = strrchr(filename, '/');
- if (!p)
- p = filename;
- else
- p++;
- if (!strcmp(p, ".") || !strcmp(p, ".."))
- break;
- if (p > filename)
- p--;
- *p = '\0';
- r += 3;
- } else {
- break;
- }
- }
- if (filename[0] != '\0')
- js__pstrcat(filename, cap, "/");
- js__pstrcat(filename, cap, r);
- // printf("normalize: %s %s -> %s\n", base_name, name, filename);
- return filename;
- }
- static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name)
- {
- struct list_head *el;
- JSModuleDef *m;
- /* first look at the loaded modules */
- list_for_each(el, &ctx->loaded_modules) {
- m = list_entry(el, JSModuleDef, link);
- if (m->module_name == name)
- return m;
- }
- return NULL;
- }
- /* return NULL in case of exception (e.g. module could not be loaded) */
- /* `base_cname` and `cname1` may be pure ASCII or UTF-8 encoded */
- static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,
- const char *base_cname,
- const char *cname1)
- {
- JSRuntime *rt = ctx->rt;
- JSModuleDef *m;
- char *cname;
- JSAtom module_name;
- if (!rt->module_normalize_func) {
- cname = js_default_module_normalize_name(ctx, base_cname, cname1);
- } else {
- cname = rt->module_normalize_func(ctx, base_cname, cname1,
- rt->module_loader_opaque);
- }
- if (!cname)
- return NULL;
- module_name = JS_NewAtom(ctx, cname);
- if (module_name == JS_ATOM_NULL) {
- js_free(ctx, cname);
- return NULL;
- }
- /* first look at the loaded modules */
- m = js_find_loaded_module(ctx, module_name);
- if (m) {
- js_free(ctx, cname);
- JS_FreeAtom(ctx, module_name);
- return m;
- }
- JS_FreeAtom(ctx, module_name);
- /* load the module */
- if (!rt->module_loader_func) {
- /* XXX: use a syntax error ? */
- // XXX: update JS_DetectModule when you change this
- JS_ThrowReferenceError(ctx, "could not load module '%s'",
- cname);
- js_free(ctx, cname);
- return NULL;
- }
- m = rt->module_loader_func(ctx, cname, rt->module_loader_opaque);
- js_free(ctx, cname);
- return m;
- }
- static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,
- JSAtom base_module_name,
- JSAtom module_name1)
- {
- const char *base_cname, *cname;
- JSModuleDef *m;
- base_cname = JS_AtomToCString(ctx, base_module_name);
- if (!base_cname)
- return NULL;
- cname = JS_AtomToCString(ctx, module_name1);
- if (!cname) {
- JS_FreeCString(ctx, base_cname);
- return NULL;
- }
- m = js_host_resolve_imported_module(ctx, base_cname, cname);
- JS_FreeCString(ctx, base_cname);
- JS_FreeCString(ctx, cname);
- return m;
- }
- typedef struct JSResolveEntry {
- JSModuleDef *module;
- JSAtom name;
- } JSResolveEntry;
- typedef struct JSResolveState {
- JSResolveEntry *array;
- int size;
- int count;
- } JSResolveState;
- static int find_resolve_entry(JSResolveState *s,
- JSModuleDef *m, JSAtom name)
- {
- int i;
- for(i = 0; i < s->count; i++) {
- JSResolveEntry *re = &s->array[i];
- if (re->module == m && re->name == name)
- return i;
- }
- return -1;
- }
- static int add_resolve_entry(JSContext *ctx, JSResolveState *s,
- JSModuleDef *m, JSAtom name)
- {
- JSResolveEntry *re;
- if (js_resize_array(ctx, (void **)&s->array,
- sizeof(JSResolveEntry),
- &s->size, s->count + 1))
- return -1;
- re = &s->array[s->count++];
- re->module = m;
- re->name = JS_DupAtom(ctx, name);
- return 0;
- }
- typedef enum JSResolveResultEnum {
- JS_RESOLVE_RES_EXCEPTION = -1, /* memory alloc error */
- JS_RESOLVE_RES_FOUND = 0,
- JS_RESOLVE_RES_NOT_FOUND,
- JS_RESOLVE_RES_CIRCULAR,
- JS_RESOLVE_RES_AMBIGUOUS,
- } JSResolveResultEnum;
- static JSResolveResultEnum js_resolve_export1(JSContext *ctx,
- JSModuleDef **pmodule,
- JSExportEntry **pme,
- JSModuleDef *m,
- JSAtom export_name,
- JSResolveState *s)
- {
- JSExportEntry *me;
- *pmodule = NULL;
- *pme = NULL;
- if (find_resolve_entry(s, m, export_name) >= 0)
- return JS_RESOLVE_RES_CIRCULAR;
- if (add_resolve_entry(ctx, s, m, export_name) < 0)
- return JS_RESOLVE_RES_EXCEPTION;
- me = find_export_entry(ctx, m, export_name);
- if (me) {
- if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
- /* local export */
- *pmodule = m;
- *pme = me;
- return JS_RESOLVE_RES_FOUND;
- } else {
- /* indirect export */
- JSModuleDef *m1;
- m1 = m->req_module_entries[me->u.req_module_idx].module;
- if (me->local_name == JS_ATOM__star_) {
- /* export ns from */
- *pmodule = m;
- *pme = me;
- return JS_RESOLVE_RES_FOUND;
- } else {
- return js_resolve_export1(ctx, pmodule, pme, m1,
- me->local_name, s);
- }
- }
- } else {
- if (export_name != JS_ATOM_default) {
- /* not found in direct or indirect exports: try star exports */
- int i;
- for(i = 0; i < m->star_export_entries_count; i++) {
- JSStarExportEntry *se = &m->star_export_entries[i];
- JSModuleDef *m1, *res_m;
- JSExportEntry *res_me;
- JSResolveResultEnum ret;
- m1 = m->req_module_entries[se->req_module_idx].module;
- ret = js_resolve_export1(ctx, &res_m, &res_me, m1,
- export_name, s);
- if (ret == JS_RESOLVE_RES_AMBIGUOUS ||
- ret == JS_RESOLVE_RES_EXCEPTION) {
- return ret;
- } else if (ret == JS_RESOLVE_RES_FOUND) {
- if (*pme != NULL) {
- if (*pmodule != res_m ||
- res_me->local_name != (*pme)->local_name) {
- *pmodule = NULL;
- *pme = NULL;
- return JS_RESOLVE_RES_AMBIGUOUS;
- }
- } else {
- *pmodule = res_m;
- *pme = res_me;
- }
- }
- }
- if (*pme != NULL)
- return JS_RESOLVE_RES_FOUND;
- }
- return JS_RESOLVE_RES_NOT_FOUND;
- }
- }
- /* If the return value is JS_RESOLVE_RES_FOUND, return the module
- (*pmodule) and the corresponding local export entry
- (*pme). Otherwise return (NULL, NULL) */
- static JSResolveResultEnum js_resolve_export(JSContext *ctx,
- JSModuleDef **pmodule,
- JSExportEntry **pme,
- JSModuleDef *m,
- JSAtom export_name)
- {
- JSResolveState ss, *s = &ss;
- int i;
- JSResolveResultEnum ret;
- s->array = NULL;
- s->size = 0;
- s->count = 0;
- ret = js_resolve_export1(ctx, pmodule, pme, m, export_name, s);
- for(i = 0; i < s->count; i++)
- JS_FreeAtom(ctx, s->array[i].name);
- js_free(ctx, s->array);
- return ret;
- }
- static void js_resolve_export_throw_error(JSContext *ctx,
- JSResolveResultEnum res,
- JSModuleDef *m, JSAtom export_name)
- {
- char buf1[ATOM_GET_STR_BUF_SIZE];
- char buf2[ATOM_GET_STR_BUF_SIZE];
- switch(res) {
- case JS_RESOLVE_RES_EXCEPTION:
- break;
- default:
- case JS_RESOLVE_RES_NOT_FOUND:
- JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'",
- JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
- JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
- break;
- case JS_RESOLVE_RES_CIRCULAR:
- JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'",
- JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
- JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
- break;
- case JS_RESOLVE_RES_AMBIGUOUS:
- JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous",
- JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
- JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
- break;
- }
- }
- typedef enum {
- EXPORTED_NAME_AMBIGUOUS,
- EXPORTED_NAME_NORMAL,
- EXPORTED_NAME_NS,
- } ExportedNameEntryEnum;
- typedef struct ExportedNameEntry {
- JSAtom export_name;
- ExportedNameEntryEnum export_type;
- union {
- JSExportEntry *me; /* using when the list is built */
- JSVarRef *var_ref; /* EXPORTED_NAME_NORMAL */
- JSModuleDef *module; /* for EXPORTED_NAME_NS */
- } u;
- } ExportedNameEntry;
- typedef struct GetExportNamesState {
- JSModuleDef **modules;
- int modules_size;
- int modules_count;
- ExportedNameEntry *exported_names;
- int exported_names_size;
- int exported_names_count;
- } GetExportNamesState;
- static int find_exported_name(GetExportNamesState *s, JSAtom name)
- {
- int i;
- for(i = 0; i < s->exported_names_count; i++) {
- if (s->exported_names[i].export_name == name)
- return i;
- }
- return -1;
- }
- static __exception int get_exported_names(JSContext *ctx,
- GetExportNamesState *s,
- JSModuleDef *m, bool from_star)
- {
- ExportedNameEntry *en;
- int i, j;
- /* check circular reference */
- for(i = 0; i < s->modules_count; i++) {
- if (s->modules[i] == m)
- return 0;
- }
- if (js_resize_array(ctx, (void **)&s->modules, sizeof(s->modules[0]),
- &s->modules_size, s->modules_count + 1))
- return -1;
- s->modules[s->modules_count++] = m;
- for(i = 0; i < m->export_entries_count; i++) {
- JSExportEntry *me = &m->export_entries[i];
- if (from_star && me->export_name == JS_ATOM_default)
- continue;
- j = find_exported_name(s, me->export_name);
- if (j < 0) {
- if (js_resize_array(ctx, (void **)&s->exported_names, sizeof(s->exported_names[0]),
- &s->exported_names_size,
- s->exported_names_count + 1))
- return -1;
- en = &s->exported_names[s->exported_names_count++];
- en->export_name = me->export_name;
- /* avoid a second lookup for simple module exports */
- if (from_star || me->export_type != JS_EXPORT_TYPE_LOCAL)
- en->u.me = NULL;
- else
- en->u.me = me;
- } else {
- en = &s->exported_names[j];
- en->u.me = NULL;
- }
- }
- for(i = 0; i < m->star_export_entries_count; i++) {
- JSStarExportEntry *se = &m->star_export_entries[i];
- JSModuleDef *m1;
- m1 = m->req_module_entries[se->req_module_idx].module;
- if (get_exported_names(ctx, s, m1, true))
- return -1;
- }
- return 0;
- }
- /* Unfortunately, the spec gives a different behavior from GetOwnProperty ! */
- static int js_module_ns_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
- {
- return (find_own_property1(JS_VALUE_GET_OBJ(obj), atom) != NULL);
- }
- static const JSClassExoticMethods js_module_ns_exotic_methods = {
- .has_property = js_module_ns_has,
- };
- static int exported_names_cmp(const void *p1, const void *p2, void *opaque)
- {
- JSContext *ctx = opaque;
- const ExportedNameEntry *me1 = p1;
- const ExportedNameEntry *me2 = p2;
- JSValue str1, str2;
- int ret;
- /* XXX: should avoid allocation memory in atom comparison */
- str1 = JS_AtomToString(ctx, me1->export_name);
- str2 = JS_AtomToString(ctx, me2->export_name);
- if (JS_IsException(str1) || JS_IsException(str2)) {
- /* XXX: raise an error ? */
- ret = 0;
- } else {
- ret = js_string_compare(JS_VALUE_GET_STRING(str1),
- JS_VALUE_GET_STRING(str2));
- }
- JS_FreeValue(ctx, str1);
- JS_FreeValue(ctx, str2);
- return ret;
- }
- static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
- void *opaque)
- {
- JSModuleDef *m = opaque;
- return JS_GetModuleNamespace(ctx, m);
- }
- static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
- {
- JSValue obj;
- JSObject *p;
- GetExportNamesState s_s, *s = &s_s;
- int i, ret;
- JSProperty *pr;
- obj = JS_NewObjectClass(ctx, JS_CLASS_MODULE_NS);
- if (JS_IsException(obj))
- return obj;
- p = JS_VALUE_GET_OBJ(obj);
- memset(s, 0, sizeof(*s));
- ret = get_exported_names(ctx, s, m, false);
- js_free(ctx, s->modules);
- if (ret)
- goto fail;
- /* Resolve the exported names. The ambiguous exports are removed */
- for(i = 0; i < s->exported_names_count; i++) {
- ExportedNameEntry *en = &s->exported_names[i];
- JSResolveResultEnum res;
- JSExportEntry *res_me;
- JSModuleDef *res_m;
- if (en->u.me) {
- res_me = en->u.me; /* fast case: no resolution needed */
- res_m = m;
- res = JS_RESOLVE_RES_FOUND;
- } else {
- res = js_resolve_export(ctx, &res_m, &res_me, m,
- en->export_name);
- }
- if (res != JS_RESOLVE_RES_FOUND) {
- if (res != JS_RESOLVE_RES_AMBIGUOUS) {
- js_resolve_export_throw_error(ctx, res, m, en->export_name);
- goto fail;
- }
- en->export_type = EXPORTED_NAME_AMBIGUOUS;
- } else {
- if (res_me->local_name == JS_ATOM__star_) {
- en->export_type = EXPORTED_NAME_NS;
- en->u.module = res_m->req_module_entries[res_me->u.req_module_idx].module;
- } else {
- en->export_type = EXPORTED_NAME_NORMAL;
- if (res_me->u.local.var_ref) {
- en->u.var_ref = res_me->u.local.var_ref;
- } else {
- JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
- p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
- en->u.var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
- }
- }
- }
- }
- /* sort the exported names */
- rqsort(s->exported_names, s->exported_names_count,
- sizeof(s->exported_names[0]), exported_names_cmp, ctx);
- for(i = 0; i < s->exported_names_count; i++) {
- ExportedNameEntry *en = &s->exported_names[i];
- switch(en->export_type) {
- case EXPORTED_NAME_NORMAL:
- {
- JSVarRef *var_ref = en->u.var_ref;
- if (!var_ref) {
- js_resolve_export_throw_error(ctx, JS_RESOLVE_RES_CIRCULAR,
- m, en->export_name);
- goto fail;
- }
- pr = add_property(ctx, p, en->export_name,
- JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
- JS_PROP_VARREF);
- if (!pr)
- goto fail;
- var_ref->header.ref_count++;
- pr->u.var_ref = var_ref;
- }
- break;
- case EXPORTED_NAME_NS:
- /* the exported namespace must be created on demand */
- if (JS_DefineAutoInitProperty(ctx, obj,
- en->export_name,
- JS_AUTOINIT_ID_MODULE_NS,
- en->u.module, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
- goto fail;
- break;
- default:
- break;
- }
- }
- js_free(ctx, s->exported_names);
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_toStringTag,
- JS_AtomToString(ctx, JS_ATOM_Module),
- 0);
- p->extensible = false;
- return obj;
- fail:
- js_free(ctx, s->exported_names);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m)
- {
- if (JS_IsUndefined(m->module_ns)) {
- JSValue val;
- val = js_build_module_ns(ctx, m);
- if (JS_IsException(val))
- return JS_EXCEPTION;
- m->module_ns = val;
- }
- return js_dup(m->module_ns);
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE
- #define module_trace(ctx, ...) \
- do { \
- if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) \
- printf(__VA_ARGS__); \
- } while (0)
- #else
- #define module_trace(...)
- #endif
- /* Load all the required modules for module 'm' */
- static int js_resolve_module(JSContext *ctx, JSModuleDef *m)
- {
- int i;
- JSModuleDef *m1;
- if (m->resolved)
- return 0;
- #ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE
- if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) {
- char buf1[ATOM_GET_STR_BUF_SIZE];
- printf("resolving module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
- }
- #endif
- m->resolved = true;
- /* resolve each requested module */
- for(i = 0; i < m->req_module_entries_count; i++) {
- JSReqModuleEntry *rme = &m->req_module_entries[i];
- m1 = js_host_resolve_imported_module_atom(ctx, m->module_name,
- rme->module_name);
- if (!m1)
- return -1;
- rme->module = m1;
- /* already done in js_host_resolve_imported_module() except if
- the module was loaded with JS_EvalBinary() */
- if (js_resolve_module(ctx, m1) < 0)
- return -1;
- }
- return 0;
- }
- static JSVarRef *js_create_module_var(JSContext *ctx, bool is_lexical)
- {
- JSVarRef *var_ref;
- var_ref = js_malloc(ctx, sizeof(JSVarRef));
- if (!var_ref)
- return NULL;
- var_ref->header.ref_count = 1;
- if (is_lexical)
- var_ref->value = JS_UNINITIALIZED;
- else
- var_ref->value = JS_UNDEFINED;
- var_ref->pvalue = &var_ref->value;
- var_ref->is_detached = true;
- add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
- return var_ref;
- }
- /* Create the <eval> function associated with the module */
- static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
- {
- JSFunctionBytecode *b;
- int i;
- JSVarRef **var_refs;
- JSValue func_obj, bfunc;
- JSObject *p;
- bfunc = m->func_obj;
- func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
- JS_CLASS_BYTECODE_FUNCTION);
- if (JS_IsException(func_obj))
- return -1;
- b = JS_VALUE_GET_PTR(bfunc);
- p = JS_VALUE_GET_OBJ(func_obj);
- p->u.func.function_bytecode = b;
- b->header.ref_count++;
- p->u.func.home_object = NULL;
- p->u.func.var_refs = NULL;
- if (b->closure_var_count) {
- var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
- if (!var_refs)
- goto fail;
- p->u.func.var_refs = var_refs;
- /* create the global variables. The other variables are
- imported from other modules */
- for(i = 0; i < b->closure_var_count; i++) {
- JSClosureVar *cv = &b->closure_var[i];
- JSVarRef *var_ref;
- if (cv->is_local) {
- var_ref = js_create_module_var(ctx, cv->is_lexical);
- if (!var_ref)
- goto fail;
- module_trace(ctx, "local %d: %p\n", i, (void *)var_ref);
- var_refs[i] = var_ref;
- }
- }
- }
- m->func_obj = func_obj;
- JS_FreeValue(ctx, bfunc);
- return 0;
- fail:
- JS_FreeValue(ctx, func_obj);
- return -1;
- }
- /* must be done before js_link_module() because of cyclic references */
- static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
- {
- bool is_c_module;
- int i;
- JSVarRef *var_ref;
- if (m->func_created)
- return 0;
- is_c_module = (m->init_func != NULL);
- if (is_c_module) {
- /* initialize the exported variables */
- for(i = 0; i < m->export_entries_count; i++) {
- JSExportEntry *me = &m->export_entries[i];
- if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
- var_ref = js_create_module_var(ctx, false);
- if (!var_ref)
- return -1;
- me->u.local.var_ref = var_ref;
- }
- }
- } else {
- if (js_create_module_bytecode_function(ctx, m))
- return -1;
- }
- m->func_created = true;
- /* do it on the dependencies */
- for(i = 0; i < m->req_module_entries_count; i++) {
- JSReqModuleEntry *rme = &m->req_module_entries[i];
- if (js_create_module_function(ctx, rme->module) < 0)
- return -1;
- }
- return 0;
- }
- /* Prepare a module to be executed by resolving all the imported
- variables. */
- static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m,
- JSModuleDef **pstack_top, int index)
- {
- int i;
- JSImportEntry *mi;
- JSModuleDef *m1;
- JSVarRef **var_refs, *var_ref;
- JSObject *p;
- bool is_c_module;
- JSValue ret_val;
- if (js_check_stack_overflow(ctx->rt, 0)) {
- JS_ThrowStackOverflow(ctx);
- return -1;
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE
- if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) {
- char buf1[ATOM_GET_STR_BUF_SIZE];
- printf("js_inner_module_linking '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
- }
- #endif
- if (m->status == JS_MODULE_STATUS_LINKING ||
- m->status == JS_MODULE_STATUS_LINKED ||
- m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
- m->status == JS_MODULE_STATUS_EVALUATED)
- return index;
- assert(m->status == JS_MODULE_STATUS_UNLINKED);
- m->status = JS_MODULE_STATUS_LINKING;
- m->dfs_index = index;
- m->dfs_ancestor_index = index;
- index++;
- /* push 'm' on stack */
- m->stack_prev = *pstack_top;
- *pstack_top = m;
- for(i = 0; i < m->req_module_entries_count; i++) {
- JSReqModuleEntry *rme = &m->req_module_entries[i];
- m1 = rme->module;
- index = js_inner_module_linking(ctx, m1, pstack_top, index);
- if (index < 0)
- goto fail;
- assert(m1->status == JS_MODULE_STATUS_LINKING ||
- m1->status == JS_MODULE_STATUS_LINKED ||
- m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
- m1->status == JS_MODULE_STATUS_EVALUATED);
- if (m1->status == JS_MODULE_STATUS_LINKING) {
- m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,
- m1->dfs_ancestor_index);
- }
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE
- if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) {
- char buf1[ATOM_GET_STR_BUF_SIZE];
- printf("instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
- }
- #endif
- /* check the indirect exports */
- for(i = 0; i < m->export_entries_count; i++) {
- JSExportEntry *me = &m->export_entries[i];
- if (me->export_type == JS_EXPORT_TYPE_INDIRECT &&
- me->local_name != JS_ATOM__star_) {
- JSResolveResultEnum ret;
- JSExportEntry *res_me;
- JSModuleDef *res_m, *m1;
- m1 = m->req_module_entries[me->u.req_module_idx].module;
- ret = js_resolve_export(ctx, &res_m, &res_me, m1, me->local_name);
- if (ret != JS_RESOLVE_RES_FOUND) {
- js_resolve_export_throw_error(ctx, ret, m, me->export_name);
- goto fail;
- }
- }
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE
- if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) {
- printf("exported bindings:\n");
- for(i = 0; i < m->export_entries_count; i++) {
- JSExportEntry *me = &m->export_entries[i];
- printf(" name="); print_atom(ctx, me->export_name);
- printf(" local="); print_atom(ctx, me->local_name);
- printf(" type=%d idx=%d\n", me->export_type, me->u.local.var_idx);
- }
- }
- #endif
- is_c_module = (m->init_func != NULL);
- if (!is_c_module) {
- p = JS_VALUE_GET_OBJ(m->func_obj);
- var_refs = p->u.func.var_refs;
- for(i = 0; i < m->import_entries_count; i++) {
- mi = &m->import_entries[i];
- #ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE
- if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) {
- printf("import var_idx=%d name=", mi->var_idx);
- print_atom(ctx, mi->import_name);
- printf(": ");
- }
- #endif
- m1 = m->req_module_entries[mi->req_module_idx].module;
- if (mi->import_name == JS_ATOM__star_) {
- JSValue val;
- /* name space import */
- val = JS_GetModuleNamespace(ctx, m1);
- if (JS_IsException(val))
- goto fail;
- set_value(ctx, &var_refs[mi->var_idx]->value, val);
- module_trace(ctx, "namespace\n");
- } else {
- JSResolveResultEnum ret;
- JSExportEntry *res_me;
- JSModuleDef *res_m;
- JSObject *p1;
- ret = js_resolve_export(ctx, &res_m,
- &res_me, m1, mi->import_name);
- if (ret != JS_RESOLVE_RES_FOUND) {
- js_resolve_export_throw_error(ctx, ret, m1, mi->import_name);
- goto fail;
- }
- if (res_me->local_name == JS_ATOM__star_) {
- JSValue val;
- JSModuleDef *m2;
- /* name space import from */
- m2 = res_m->req_module_entries[res_me->u.req_module_idx].module;
- val = JS_GetModuleNamespace(ctx, m2);
- if (JS_IsException(val))
- goto fail;
- var_ref = js_create_module_var(ctx, true);
- if (!var_ref) {
- JS_FreeValue(ctx, val);
- goto fail;
- }
- set_value(ctx, &var_ref->value, val);
- var_refs[mi->var_idx] = var_ref;
- module_trace(ctx, "namespace from\n");
- } else {
- var_ref = res_me->u.local.var_ref;
- if (!var_ref) {
- p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
- var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
- }
- var_ref->header.ref_count++;
- var_refs[mi->var_idx] = var_ref;
- module_trace(ctx, "local export (var_ref=%p)\n", (void *)var_ref);
- }
- }
- }
- /* keep the exported variables in the module export entries (they
- are used when the eval function is deleted and cannot be
- initialized before in case imports are exported) */
- for(i = 0; i < m->export_entries_count; i++) {
- JSExportEntry *me = &m->export_entries[i];
- if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
- var_ref = var_refs[me->u.local.var_idx];
- var_ref->header.ref_count++;
- me->u.local.var_ref = var_ref;
- }
- }
- /* initialize the global variables */
- ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL);
- if (JS_IsException(ret_val))
- goto fail;
- JS_FreeValue(ctx, ret_val);
- }
- assert(m->dfs_ancestor_index <= m->dfs_index);
- if (m->dfs_index == m->dfs_ancestor_index) {
- for(;;) {
- /* pop m1 from stack */
- m1 = *pstack_top;
- *pstack_top = m1->stack_prev;
- m1->status = JS_MODULE_STATUS_LINKED;
- if (m1 == m)
- break;
- }
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE
- if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) {
- printf("js_inner_module_linking done\n");
- }
- #endif
- return index;
- fail:
- return -1;
- }
- /* Prepare a module to be executed by resolving all the imported
- variables. */
- static int js_link_module(JSContext *ctx, JSModuleDef *m)
- {
- JSModuleDef *stack_top, *m1;
- #ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE
- if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) {
- char buf1[ATOM_GET_STR_BUF_SIZE];
- printf("js_link_module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
- }
- #endif
- assert(m->status == JS_MODULE_STATUS_UNLINKED ||
- m->status == JS_MODULE_STATUS_LINKED ||
- m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
- m->status == JS_MODULE_STATUS_EVALUATED);
- stack_top = NULL;
- if (js_inner_module_linking(ctx, m, &stack_top, 0) < 0) {
- while (stack_top != NULL) {
- m1 = stack_top;
- assert(m1->status == JS_MODULE_STATUS_LINKING);
- m1->status = JS_MODULE_STATUS_UNLINKED;
- stack_top = m1->stack_prev;
- }
- return -1;
- }
- assert(stack_top == NULL);
- assert(m->status == JS_MODULE_STATUS_LINKED ||
- m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
- m->status == JS_MODULE_STATUS_EVALUATED);
- return 0;
- }
- /* return JS_ATOM_NULL if the name cannot be found. Only works with
- not striped bytecode functions. */
- JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
- {
- JSStackFrame *sf;
- JSFunctionBytecode *b;
- JSObject *p;
- /* XXX: currently we just use the filename of the englobing
- function. It does not work for eval(). Need to add a
- ScriptOrModule info in JSFunctionBytecode */
- sf = ctx->rt->current_stack_frame;
- if (!sf)
- return JS_ATOM_NULL;
- while (n_stack_levels-- > 0) {
- sf = sf->prev_frame;
- if (!sf)
- return JS_ATOM_NULL;
- }
- if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT)
- return JS_ATOM_NULL;
- p = JS_VALUE_GET_OBJ(sf->cur_func);
- if (!js_class_has_bytecode(p->class_id))
- return JS_ATOM_NULL;
- b = p->u.func.function_bytecode;
- return JS_DupAtom(ctx, b->filename);
- }
- JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m)
- {
- return JS_DupAtom(ctx, m->module_name);
- }
- JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m)
- {
- JSValue obj;
- /* allocate meta_obj only if requested to save memory */
- obj = m->meta_obj;
- if (JS_IsUndefined(obj)) {
- obj = JS_NewObjectProto(ctx, JS_NULL);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- m->meta_obj = obj;
- }
- return js_dup(obj);
- }
- static JSValue js_import_meta(JSContext *ctx)
- {
- JSAtom filename;
- JSModuleDef *m;
- filename = JS_GetScriptOrModuleName(ctx, 0);
- if (filename == JS_ATOM_NULL)
- goto fail;
- /* XXX: inefficient, need to add a module or script pointer in
- JSFunctionBytecode */
- m = js_find_loaded_module(ctx, filename);
- JS_FreeAtom(ctx, filename);
- if (!m) {
- fail:
- JS_ThrowTypeError(ctx, "import.meta not supported in this context");
- return JS_EXCEPTION;
- }
- return JS_GetImportMeta(ctx, m);
- }
- static JSValue JS_NewModuleValue(JSContext *ctx, JSModuleDef *m)
- {
- return js_dup(JS_MKPTR(JS_TAG_MODULE, m));
- }
- static JSValue js_load_module_rejected(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic,
- JSValueConst *func_data)
- {
- JSValueConst *resolving_funcs = func_data;
- JSValueConst error;
- JSValue ret;
- /* XXX: check if the test is necessary */
- if (argc >= 1)
- error = argv[0];
- else
- error = JS_UNDEFINED;
- ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, &error);
- JS_FreeValue(ctx, ret);
- return JS_UNDEFINED;
- }
- static JSValue js_load_module_fulfilled(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic,
- JSValueConst *func_data)
- {
- JSValueConst *resolving_funcs = func_data;
- JSModuleDef *m = JS_VALUE_GET_PTR(func_data[2]);
- JSValue ret, ns;
- /* return the module namespace */
- ns = JS_GetModuleNamespace(ctx, m);
- if (JS_IsException(ns)) {
- JSValue err = JS_GetException(ctx);
- js_load_module_rejected(ctx, JS_UNDEFINED, 1, vc(&err), 0, func_data);
- return JS_UNDEFINED;
- }
- ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1, vc(&ns));
- JS_FreeValue(ctx, ret);
- JS_FreeValue(ctx, ns);
- return JS_UNDEFINED;
- }
- static void JS_LoadModuleInternal(JSContext *ctx, const char *basename,
- const char *filename,
- JSValueConst *resolving_funcs)
- {
- JSValue evaluate_promise;
- JSModuleDef *m;
- JSValue ret, err, func_obj, evaluate_resolving_funcs[2];
- JSValueConst func_data[3];
- m = js_host_resolve_imported_module(ctx, basename, filename);
- if (!m)
- goto fail;
- if (js_resolve_module(ctx, m) < 0) {
- js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
- goto fail;
- }
- /* Evaluate the module code */
- func_obj = JS_NewModuleValue(ctx, m);
- evaluate_promise = JS_EvalFunction(ctx, func_obj);
- if (JS_IsException(evaluate_promise)) {
- fail:
- err = JS_GetException(ctx);
- ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, vc(&err));
- JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
- JS_FreeValue(ctx, err);
- return;
- }
- func_obj = JS_NewModuleValue(ctx, m);
- func_data[0] = resolving_funcs[0];
- func_data[1] = resolving_funcs[1];
- func_data[2] = func_obj;
- evaluate_resolving_funcs[0] = JS_NewCFunctionData(ctx, js_load_module_fulfilled, 0, 0, 3, func_data);
- evaluate_resolving_funcs[1] = JS_NewCFunctionData(ctx, js_load_module_rejected, 0, 0, 3, func_data);
- JS_FreeValue(ctx, func_obj);
- ret = js_promise_then(ctx, evaluate_promise, 2, vc(evaluate_resolving_funcs));
- JS_FreeValue(ctx, ret);
- JS_FreeValue(ctx, evaluate_resolving_funcs[0]);
- JS_FreeValue(ctx, evaluate_resolving_funcs[1]);
- JS_FreeValue(ctx, evaluate_promise);
- }
- /* Return a promise or an exception in case of memory error. Used by
- os.Worker() */
- JSValue JS_LoadModule(JSContext *ctx, const char *basename,
- const char *filename)
- {
- JSValue promise, resolving_funcs[2];
- promise = JS_NewPromiseCapability(ctx, resolving_funcs);
- if (JS_IsException(promise))
- return JS_EXCEPTION;
- JS_LoadModuleInternal(ctx, basename, filename, vc(resolving_funcs));
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- return promise;
- }
- static JSValue js_dynamic_import_job(JSContext *ctx,
- int argc, JSValueConst *argv)
- {
- JSValueConst *resolving_funcs = argv;
- JSValueConst basename_val = argv[2];
- JSValueConst specifier = argv[3];
- const char *basename = NULL, *filename;
- JSValue ret, err;
- if (!JS_IsString(basename_val)) {
- JS_ThrowTypeError(ctx, "no function filename for import()");
- goto exception;
- }
- basename = JS_ToCString(ctx, basename_val);
- if (!basename)
- goto exception;
- filename = JS_ToCString(ctx, specifier);
- if (!filename)
- goto exception;
- JS_LoadModuleInternal(ctx, basename, filename,
- resolving_funcs);
- JS_FreeCString(ctx, filename);
- JS_FreeCString(ctx, basename);
- return JS_UNDEFINED;
- exception:
- err = JS_GetException(ctx);
- ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, vc(&err));
- JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
- JS_FreeValue(ctx, err);
- JS_FreeCString(ctx, basename);
- return JS_UNDEFINED;
- }
- static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
- {
- JSAtom basename;
- JSValue promise, resolving_funcs[2], basename_val;
- JSValue args[4];
- basename = JS_GetScriptOrModuleName(ctx, 0);
- if (basename == JS_ATOM_NULL)
- basename_val = JS_NULL;
- else
- basename_val = JS_AtomToValue(ctx, basename);
- JS_FreeAtom(ctx, basename);
- if (JS_IsException(basename_val))
- return basename_val;
- promise = JS_NewPromiseCapability(ctx, resolving_funcs);
- if (JS_IsException(promise)) {
- JS_FreeValue(ctx, basename_val);
- return promise;
- }
- args[0] = resolving_funcs[0];
- args[1] = resolving_funcs[1];
- args[2] = basename_val;
- args[3] = unsafe_unconst(specifier);
- /* cannot run JS_LoadModuleInternal synchronously because it would
- cause an unexpected recursion in js_evaluate_module() */
- JS_EnqueueJob(ctx, js_dynamic_import_job, 4, vc(args));
- JS_FreeValue(ctx, basename_val);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- return promise;
- }
- static void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m)
- {
- m->status = JS_MODULE_STATUS_EVALUATED;
- if (!JS_IsUndefined(m->promise)) {
- JSValue ret_val;
- assert(m->cycle_root == m);
- JSValueConst value = JS_UNDEFINED;
- ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED, 1, &value);
- JS_FreeValue(ctx, ret_val);
- }
- }
- typedef struct {
- JSModuleDef **tab;
- int count;
- int size;
- } ExecModuleList;
- /* XXX: slow. Could use a linked list instead of ExecModuleList */
- static bool find_in_exec_module_list(ExecModuleList *exec_list, JSModuleDef *m)
- {
- int i;
- for(i = 0; i < exec_list->count; i++) {
- if (exec_list->tab[i] == m)
- return true;
- }
- return false;
- }
- static int gather_available_ancestors(JSContext *ctx, JSModuleDef *module,
- ExecModuleList *exec_list)
- {
- int i;
- if (js_check_stack_overflow(ctx->rt, 0)) {
- JS_ThrowStackOverflow(ctx);
- return -1;
- }
- for(i = 0; i < module->async_parent_modules_count; i++) {
- JSModuleDef *m = module->async_parent_modules[i];
- if (!find_in_exec_module_list(exec_list, m) &&
- !m->cycle_root->eval_has_exception) {
- assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
- assert(!m->eval_has_exception);
- assert(m->async_evaluation);
- assert(m->pending_async_dependencies > 0);
- m->pending_async_dependencies--;
- if (m->pending_async_dependencies == 0) {
- if (js_resize_array(ctx, (void **)&exec_list->tab, sizeof(exec_list->tab[0]), &exec_list->size, exec_list->count + 1)) {
- return -1;
- }
- exec_list->tab[exec_list->count++] = m;
- if (!m->has_tla) {
- if (gather_available_ancestors(ctx, m, exec_list))
- return -1;
- }
- }
- }
- }
- return 0;
- }
- static int exec_module_list_cmp(const void *p1, const void *p2, void *opaque)
- {
- JSModuleDef *m1 = *(JSModuleDef **)p1;
- JSModuleDef *m2 = *(JSModuleDef **)p2;
- return (m1->async_evaluation_timestamp > m2->async_evaluation_timestamp) -
- (m1->async_evaluation_timestamp < m2->async_evaluation_timestamp);
- }
- static int js_execute_async_module(JSContext *ctx, JSModuleDef *m);
- static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,
- JSValue *pvalue);
- static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic,
- JSValueConst *func_data)
- {
- JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);
- JSValueConst error = argv[0];
- int i;
- if (js_check_stack_overflow(ctx->rt, 0))
- return JS_ThrowStackOverflow(ctx);
- if (module->status == JS_MODULE_STATUS_EVALUATED) {
- assert(module->eval_has_exception);
- return JS_UNDEFINED;
- }
- assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
- assert(!module->eval_has_exception);
- assert(module->async_evaluation);
- module->eval_has_exception = true;
- module->eval_exception = js_dup(error);
- module->status = JS_MODULE_STATUS_EVALUATED;
- for(i = 0; i < module->async_parent_modules_count; i++) {
- JSModuleDef *m = module->async_parent_modules[i];
- JSValue m_obj = JS_NewModuleValue(ctx, m);
- js_async_module_execution_rejected(ctx, JS_UNDEFINED, 1, &error, 0,
- vc(&m_obj));
- JS_FreeValue(ctx, m_obj);
- }
- if (!JS_IsUndefined(module->promise)) {
- JSValue ret_val;
- assert(module->cycle_root == module);
- ret_val = JS_Call(ctx, module->resolving_funcs[1], JS_UNDEFINED,
- 1, &error);
- JS_FreeValue(ctx, ret_val);
- }
- return JS_UNDEFINED;
- }
- static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic,
- JSValueConst *func_data)
- {
- JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);
- ExecModuleList exec_list_s, *exec_list = &exec_list_s;
- int i;
- if (module->status == JS_MODULE_STATUS_EVALUATED) {
- assert(module->eval_has_exception);
- return JS_UNDEFINED;
- }
- assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
- assert(!module->eval_has_exception);
- assert(module->async_evaluation);
- module->async_evaluation = false;
- js_set_module_evaluated(ctx, module);
- exec_list->tab = NULL;
- exec_list->count = 0;
- exec_list->size = 0;
- if (gather_available_ancestors(ctx, module, exec_list) < 0) {
- js_free(ctx, exec_list->tab);
- return JS_EXCEPTION;
- }
- /* sort by increasing async_evaluation timestamp */
- rqsort(exec_list->tab, exec_list->count, sizeof(exec_list->tab[0]),
- exec_module_list_cmp, NULL);
- for(i = 0; i < exec_list->count; i++) {
- JSModuleDef *m = exec_list->tab[i];
- if (m->status == JS_MODULE_STATUS_EVALUATED) {
- assert(m->eval_has_exception);
- } else if (m->has_tla) {
- js_execute_async_module(ctx, m);
- } else {
- JSValue error;
- if (js_execute_sync_module(ctx, m, &error) < 0) {
- JSValue m_obj = JS_NewModuleValue(ctx, m);
- js_async_module_execution_rejected(ctx, JS_UNDEFINED,
- 1, vc(&error),
- 0, vc(&m_obj));
- JS_FreeValue(ctx, m_obj);
- JS_FreeValue(ctx, error);
- } else {
- js_set_module_evaluated(ctx, m);
- }
- }
- }
- js_free(ctx, exec_list->tab);
- return JS_UNDEFINED;
- }
- static int js_execute_async_module(JSContext *ctx, JSModuleDef *m)
- {
- JSValue promise, m_obj;
- JSValue resolve_funcs[2], ret_val;
- promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);
- if (JS_IsException(promise))
- return -1;
- m_obj = JS_NewModuleValue(ctx, m);
- resolve_funcs[0] = JS_NewCFunctionData(ctx, js_async_module_execution_fulfilled, 0, 0, 1, vc(&m_obj));
- resolve_funcs[1] = JS_NewCFunctionData(ctx, js_async_module_execution_rejected, 0, 0, 1, vc(&m_obj));
- ret_val = js_promise_then(ctx, promise, 2, vc(resolve_funcs));
- JS_FreeValue(ctx, ret_val);
- JS_FreeValue(ctx, m_obj);
- JS_FreeValue(ctx, resolve_funcs[0]);
- JS_FreeValue(ctx, resolve_funcs[1]);
- JS_FreeValue(ctx, promise);
- return 0;
- }
- /* return < 0 in case of exception. *pvalue contains the exception. */
- static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,
- JSValue *pvalue)
- {
- if (m->init_func) {
- /* C module init : no asynchronous execution */
- if (m->init_func(ctx, m) < 0)
- goto fail;
- } else {
- JSValue promise;
- JSPromiseStateEnum state;
- promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);
- if (JS_IsException(promise))
- goto fail;
- state = JS_PromiseState(ctx, promise);
- if (state == JS_PROMISE_FULFILLED) {
- JS_FreeValue(ctx, promise);
- } else if (state == JS_PROMISE_REJECTED) {
- *pvalue = JS_PromiseResult(ctx, promise);
- JS_FreeValue(ctx, promise);
- return -1;
- } else {
- JS_FreeValue(ctx, promise);
- JS_ThrowTypeError(ctx, "promise is pending");
- fail:
- *pvalue = JS_GetException(ctx);
- return -1;
- }
- }
- *pvalue = JS_UNDEFINED;
- return 0;
- }
- /* spec: InnerModuleEvaluation. Return (index, JS_UNDEFINED) or (-1,
- exception) */
- static int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m,
- int index, JSModuleDef **pstack_top,
- JSValue *pvalue)
- {
- JSModuleDef *m1;
- int i;
- if (js_check_stack_overflow(ctx->rt, 0)) {
- JS_ThrowStackOverflow(ctx);
- *pvalue = JS_GetException(ctx);
- return -1;
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_MODULE_RESOLVE
- if (check_dump_flag(ctx->rt, JS_DUMP_MODULE_RESOLVE)) {
- char buf1[ATOM_GET_STR_BUF_SIZE];
- printf("js_inner_module_evaluation '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
- }
- #endif
- if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
- m->status == JS_MODULE_STATUS_EVALUATED) {
- if (m->eval_has_exception) {
- *pvalue = js_dup(m->eval_exception);
- return -1;
- } else {
- *pvalue = JS_UNDEFINED;
- return index;
- }
- }
- if (m->status == JS_MODULE_STATUS_EVALUATING) {
- *pvalue = JS_UNDEFINED;
- return index;
- }
- assert(m->status == JS_MODULE_STATUS_LINKED);
- m->status = JS_MODULE_STATUS_EVALUATING;
- m->dfs_index = index;
- m->dfs_ancestor_index = index;
- m->pending_async_dependencies = 0;
- index++;
- /* push 'm' on stack */
- m->stack_prev = *pstack_top;
- *pstack_top = m;
- for(i = 0; i < m->req_module_entries_count; i++) {
- JSReqModuleEntry *rme = &m->req_module_entries[i];
- m1 = rme->module;
- index = js_inner_module_evaluation(ctx, m1, index, pstack_top, pvalue);
- if (index < 0)
- return -1;
- assert(m1->status == JS_MODULE_STATUS_EVALUATING ||
- m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
- m1->status == JS_MODULE_STATUS_EVALUATED);
- if (m1->status == JS_MODULE_STATUS_EVALUATING) {
- m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,
- m1->dfs_ancestor_index);
- } else {
- m1 = m1->cycle_root;
- assert(m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
- m1->status == JS_MODULE_STATUS_EVALUATED);
- if (m1->eval_has_exception) {
- *pvalue = js_dup(m1->eval_exception);
- return -1;
- }
- }
- if (m1->async_evaluation) {
- m->pending_async_dependencies++;
- if (js_resize_array(ctx, (void **)&m1->async_parent_modules, sizeof(m1->async_parent_modules[0]), &m1->async_parent_modules_size, m1->async_parent_modules_count + 1)) {
- *pvalue = JS_GetException(ctx);
- return -1;
- }
- m1->async_parent_modules[m1->async_parent_modules_count++] = m;
- }
- }
- if (m->pending_async_dependencies > 0) {
- assert(!m->async_evaluation);
- m->async_evaluation = true;
- m->async_evaluation_timestamp =
- ctx->rt->module_async_evaluation_next_timestamp++;
- } else if (m->has_tla) {
- assert(!m->async_evaluation);
- m->async_evaluation = true;
- m->async_evaluation_timestamp =
- ctx->rt->module_async_evaluation_next_timestamp++;
- js_execute_async_module(ctx, m);
- } else {
- if (js_execute_sync_module(ctx, m, pvalue) < 0)
- return -1;
- }
- assert(m->dfs_ancestor_index <= m->dfs_index);
- if (m->dfs_index == m->dfs_ancestor_index) {
- for(;;) {
- /* pop m1 from stack */
- m1 = *pstack_top;
- *pstack_top = m1->stack_prev;
- if (!m1->async_evaluation) {
- m1->status = JS_MODULE_STATUS_EVALUATED;
- } else {
- m1->status = JS_MODULE_STATUS_EVALUATING_ASYNC;
- }
- /* spec bug: cycle_root must be assigned before the test */
- m1->cycle_root = m;
- if (m1 == m)
- break;
- }
- }
- *pvalue = JS_UNDEFINED;
- return index;
- }
- /* Run the <eval> function of the module and of all its requested
- modules. Return a promise or an exception. */
- static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
- {
- JSModuleDef *m1, *stack_top;
- JSValue ret_val, result;
- assert(m->status == JS_MODULE_STATUS_LINKED ||
- m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
- m->status == JS_MODULE_STATUS_EVALUATED);
- if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
- m->status == JS_MODULE_STATUS_EVALUATED) {
- m = m->cycle_root;
- }
- /* a promise may be created only on the cycle_root of a cycle */
- if (!JS_IsUndefined(m->promise))
- return js_dup(m->promise);
- m->promise = JS_NewPromiseCapability(ctx, m->resolving_funcs);
- if (JS_IsException(m->promise))
- return JS_EXCEPTION;
- stack_top = NULL;
- if (js_inner_module_evaluation(ctx, m, 0, &stack_top, &result) < 0) {
- while (stack_top != NULL) {
- m1 = stack_top;
- assert(m1->status == JS_MODULE_STATUS_EVALUATING);
- m1->status = JS_MODULE_STATUS_EVALUATED;
- m1->eval_has_exception = true;
- m1->eval_exception = js_dup(result);
- m1->cycle_root = m; /* spec bug: should be present */
- stack_top = m1->stack_prev;
- }
- JS_FreeValue(ctx, result);
- assert(m->status == JS_MODULE_STATUS_EVALUATED);
- assert(m->eval_has_exception);
- ret_val = JS_Call(ctx, m->resolving_funcs[1], JS_UNDEFINED,
- 1, vc(&m->eval_exception));
- JS_FreeValue(ctx, ret_val);
- } else {
- assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
- m->status == JS_MODULE_STATUS_EVALUATED);
- assert(!m->eval_has_exception);
- if (!m->async_evaluation) {
- assert(m->status == JS_MODULE_STATUS_EVALUATED);
- JSValueConst value = JS_UNDEFINED;
- ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,
- 1, &value);
- JS_FreeValue(ctx, ret_val);
- }
- assert(stack_top == NULL);
- }
- return js_dup(m->promise);
- }
- #ifndef QJS_DISABLE_PARSER
- static __exception JSAtom js_parse_from_clause(JSParseState *s)
- {
- JSAtom module_name;
- if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {
- js_parse_error(s, "from clause expected");
- return JS_ATOM_NULL;
- }
- if (next_token(s))
- return JS_ATOM_NULL;
- if (s->token.val != TOK_STRING) {
- js_parse_error(s, "string expected");
- return JS_ATOM_NULL;
- }
- module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
- if (module_name == JS_ATOM_NULL)
- return JS_ATOM_NULL;
- if (next_token(s)) {
- JS_FreeAtom(s->ctx, module_name);
- return JS_ATOM_NULL;
- }
- return module_name;
- }
- static bool has_unmatched_surrogate(const uint16_t *s, size_t n)
- {
- size_t i;
- for (i = 0; i < n; i++) {
- if (is_lo_surrogate(s[i]))
- return true;
- if (!is_hi_surrogate(s[i]))
- continue;
- if (++i == n)
- return true;
- if (!is_lo_surrogate(s[i]))
- return true;
- }
- return false;
- }
- static __exception int js_parse_export(JSParseState *s)
- {
- JSContext *ctx = s->ctx;
- JSModuleDef *m = s->cur_func->module;
- JSAtom local_name, export_name;
- int first_export, idx, i, tok;
- JSAtom module_name;
- JSExportEntry *me;
- if (next_token(s))
- return -1;
- tok = s->token.val;
- if (tok == TOK_CLASS) {
- return js_parse_class(s, false, JS_PARSE_EXPORT_NAMED);
- } else if (tok == TOK_FUNCTION ||
- (token_is_pseudo_keyword(s, JS_ATOM_async) &&
- peek_token(s, true) == TOK_FUNCTION)) {
- return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
- JS_FUNC_NORMAL, JS_ATOM_NULL,
- s->token.ptr,
- s->token.line_num,
- s->token.col_num,
- JS_PARSE_EXPORT_NAMED, NULL);
- }
- if (next_token(s))
- return -1;
- switch(tok) {
- case '{':
- first_export = m->export_entries_count;
- bool has_string_binding = false;
- while (s->token.val != '}') {
- if (token_is_ident(s->token.val)) {
- local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- } else if (s->token.val == TOK_STRING) {
- local_name = JS_ValueToAtom(ctx, s->token.u.str.str);
- if (local_name == JS_ATOM_NULL)
- return -1;
- has_string_binding = true;
- } else {
- return js_parse_error(s, "identifier or string expected");
- }
- export_name = JS_ATOM_NULL;
- if (next_token(s))
- goto fail;
- if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
- if (next_token(s))
- goto fail;
- if (token_is_ident(s->token.val)) {
- export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- } else if (s->token.val == TOK_STRING) {
- JSString *p = JS_VALUE_GET_STRING(s->token.u.str.str);
- if (p->is_wide_char && has_unmatched_surrogate(str16(p), p->len)) {
- js_parse_error(s, "illegal export name");
- return -1;
- }
- export_name = JS_ValueToAtom(ctx, s->token.u.str.str);
- if (export_name == JS_ATOM_NULL) {
- return -1;
- }
- } else {
- js_parse_error(s, "identifier or string expected");
- goto fail;
- }
- if (next_token(s)) {
- fail:
- JS_FreeAtom(ctx, local_name);
- fail1:
- JS_FreeAtom(ctx, export_name);
- return -1;
- }
- } else {
- export_name = JS_DupAtom(ctx, local_name);
- }
- me = add_export_entry(s, m, local_name, export_name,
- JS_EXPORT_TYPE_LOCAL);
- JS_FreeAtom(ctx, local_name);
- JS_FreeAtom(ctx, export_name);
- if (!me)
- return -1;
- if (s->token.val != ',')
- break;
- if (next_token(s))
- return -1;
- }
- if (js_parse_expect(s, '}'))
- return -1;
- if (token_is_pseudo_keyword(s, JS_ATOM_from)) {
- module_name = js_parse_from_clause(s);
- if (module_name == JS_ATOM_NULL)
- return -1;
- idx = add_req_module_entry(ctx, m, module_name);
- JS_FreeAtom(ctx, module_name);
- if (idx < 0)
- return -1;
- for(i = first_export; i < m->export_entries_count; i++) {
- me = &m->export_entries[i];
- me->export_type = JS_EXPORT_TYPE_INDIRECT;
- me->u.req_module_idx = idx;
- }
- } else if (has_string_binding) {
- // Without 'from' clause, string literals cannot be used as local binding names
- return js_parse_error(s, "string export name only allowed with 'from' clause");
- }
- break;
- case '*':
- if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
- /* export ns from */
- if (next_token(s))
- return -1;
- if (token_is_ident(s->token.val)) {
- export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- } else if (s->token.val == TOK_STRING) {
- export_name = JS_ValueToAtom(ctx, s->token.u.str.str);
- if (export_name == JS_ATOM_NULL) {
- return -1;
- }
- } else {
- return js_parse_error(s, "identifier or string expected");
- }
- if (next_token(s))
- goto fail1;
- module_name = js_parse_from_clause(s);
- if (module_name == JS_ATOM_NULL)
- goto fail1;
- idx = add_req_module_entry(ctx, m, module_name);
- JS_FreeAtom(ctx, module_name);
- if (idx < 0)
- goto fail1;
- me = add_export_entry(s, m, JS_ATOM__star_, export_name,
- JS_EXPORT_TYPE_INDIRECT);
- JS_FreeAtom(ctx, export_name);
- if (!me)
- return -1;
- me->u.req_module_idx = idx;
- } else {
- module_name = js_parse_from_clause(s);
- if (module_name == JS_ATOM_NULL)
- return -1;
- idx = add_req_module_entry(ctx, m, module_name);
- JS_FreeAtom(ctx, module_name);
- if (idx < 0)
- return -1;
- if (add_star_export_entry(ctx, m, idx) < 0)
- return -1;
- }
- break;
- case TOK_DEFAULT:
- if (s->token.val == TOK_CLASS) {
- return js_parse_class(s, false, JS_PARSE_EXPORT_DEFAULT);
- } else if (s->token.val == TOK_FUNCTION ||
- (token_is_pseudo_keyword(s, JS_ATOM_async) &&
- peek_token(s, true) == TOK_FUNCTION)) {
- return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
- JS_FUNC_NORMAL, JS_ATOM_NULL,
- s->token.ptr,
- s->token.line_num,
- s->token.col_num,
- JS_PARSE_EXPORT_DEFAULT, NULL);
- } else {
- if (js_parse_assign_expr(s))
- return -1;
- }
- /* set the name of anonymous functions */
- set_object_name(s, JS_ATOM_default);
- /* store the value in the _default_ global variable and export
- it */
- local_name = JS_ATOM__default_;
- if (define_var(s, s->cur_func, local_name, JS_VAR_DEF_LET) < 0)
- return -1;
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, local_name);
- emit_u16(s, 0);
- if (!add_export_entry(s, m, local_name, JS_ATOM_default,
- JS_EXPORT_TYPE_LOCAL))
- return -1;
- break;
- case TOK_VAR:
- case TOK_LET:
- case TOK_CONST:
- return js_parse_var(s, PF_IN_ACCEPTED, tok, /*export_flag*/true);
- default:
- return js_parse_error(s, "invalid export syntax");
- }
- return js_parse_expect_semi(s);
- }
- static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
- bool is_local, bool is_arg,
- int var_idx, JSAtom var_name,
- bool is_const, bool is_lexical,
- JSVarKindEnum var_kind);
- static int add_import(JSParseState *s, JSModuleDef *m,
- JSAtom local_name, JSAtom import_name)
- {
- JSContext *ctx = s->ctx;
- int i, var_idx;
- JSImportEntry *mi;
- bool is_local;
- if (local_name == JS_ATOM_arguments || local_name == JS_ATOM_eval)
- return js_parse_error(s, "invalid import binding");
- if (local_name != JS_ATOM_default) {
- for (i = 0; i < s->cur_func->closure_var_count; i++) {
- if (s->cur_func->closure_var[i].var_name == local_name)
- return js_parse_error(s, "duplicate import binding");
- }
- }
- is_local = (import_name == JS_ATOM__star_);
- var_idx = add_closure_var(ctx, s->cur_func, is_local, false,
- m->import_entries_count,
- local_name, true, true, JS_VAR_NORMAL);
- if (var_idx < 0)
- return -1;
- if (js_resize_array(ctx, (void **)&m->import_entries,
- sizeof(JSImportEntry),
- &m->import_entries_size,
- m->import_entries_count + 1))
- return -1;
- mi = &m->import_entries[m->import_entries_count++];
- mi->import_name = JS_DupAtom(ctx, import_name);
- mi->var_idx = var_idx;
- return 0;
- }
- static __exception int js_parse_import(JSParseState *s)
- {
- JSContext *ctx = s->ctx;
- JSModuleDef *m = s->cur_func->module;
- JSAtom local_name, import_name, module_name;
- int first_import, i, idx;
- if (next_token(s))
- return -1;
- first_import = m->import_entries_count;
- if (s->token.val == TOK_STRING) {
- module_name = JS_ValueToAtom(ctx, s->token.u.str.str);
- if (module_name == JS_ATOM_NULL)
- return -1;
- if (next_token(s)) {
- JS_FreeAtom(ctx, module_name);
- return -1;
- }
- } else {
- if (s->token.val == TOK_IDENT) {
- if (s->token.u.ident.is_reserved) {
- return js_parse_error_reserved_identifier(s);
- }
- /* "default" import */
- local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- import_name = JS_ATOM_default;
- if (next_token(s))
- goto fail;
- if (add_import(s, m, local_name, import_name))
- goto fail;
- JS_FreeAtom(ctx, local_name);
- if (s->token.val != ',')
- goto end_import_clause;
- if (next_token(s))
- return -1;
- }
- if (s->token.val == '*') {
- /* name space import */
- if (next_token(s))
- return -1;
- if (!token_is_pseudo_keyword(s, JS_ATOM_as))
- return js_parse_error(s, "expecting 'as'");
- if (next_token(s))
- return -1;
- if (!token_is_ident(s->token.val)) {
- js_parse_error(s, "identifier expected");
- return -1;
- }
- local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- import_name = JS_ATOM__star_;
- if (next_token(s))
- goto fail;
- if (add_import(s, m, local_name, import_name))
- goto fail;
- JS_FreeAtom(ctx, local_name);
- } else if (s->token.val == '{') {
- if (next_token(s))
- return -1;
- while (s->token.val != '}') {
- if (token_is_ident(s->token.val)) {
- import_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- } else if (s->token.val == TOK_STRING) {
- import_name = JS_ValueToAtom(ctx, s->token.u.str.str);
- if (import_name == JS_ATOM_NULL)
- return -1;
- } else {
- return js_parse_error(s, "identifier or string expected expected");
- }
- local_name = JS_ATOM_NULL;
- if (next_token(s))
- goto fail;
- if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
- if (next_token(s))
- goto fail;
- if (!token_is_ident(s->token.val)) {
- js_parse_error(s, "identifier expected");
- goto fail;
- }
- local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- if (next_token(s)) {
- fail:
- JS_FreeAtom(ctx, local_name);
- JS_FreeAtom(ctx, import_name);
- return -1;
- }
- } else {
- local_name = JS_DupAtom(ctx, import_name);
- }
- if (add_import(s, m, local_name, import_name))
- goto fail;
- JS_FreeAtom(ctx, local_name);
- JS_FreeAtom(ctx, import_name);
- if (s->token.val != ',')
- break;
- if (next_token(s))
- return -1;
- }
- if (js_parse_expect(s, '}'))
- return -1;
- }
- end_import_clause:
- module_name = js_parse_from_clause(s);
- if (module_name == JS_ATOM_NULL)
- return -1;
- }
- idx = add_req_module_entry(ctx, m, module_name);
- JS_FreeAtom(ctx, module_name);
- if (idx < 0)
- return -1;
- for(i = first_import; i < m->import_entries_count; i++)
- m->import_entries[i].req_module_idx = idx;
- return js_parse_expect_semi(s);
- }
- static __exception int js_parse_source_element(JSParseState *s)
- {
- JSFunctionDef *fd = s->cur_func;
- int tok;
- if (s->token.val == TOK_FUNCTION ||
- (token_is_pseudo_keyword(s, JS_ATOM_async) &&
- peek_token(s, true) == TOK_FUNCTION)) {
- if (js_parse_function_decl(s, JS_PARSE_FUNC_STATEMENT,
- JS_FUNC_NORMAL, JS_ATOM_NULL,
- s->token.ptr,
- s->token.line_num,
- s->token.col_num))
- return -1;
- } else if (s->token.val == TOK_EXPORT && fd->module) {
- if (js_parse_export(s))
- return -1;
- } else if (s->token.val == TOK_IMPORT && fd->module &&
- ((tok = peek_token(s, false)) != '(' && tok != '.')) {
- /* the peek_token is needed to avoid confusion with ImportCall
- (dynamic import) or import.meta */
- if (js_parse_import(s))
- return -1;
- } else {
- if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
- return -1;
- }
- return 0;
- }
- /* `filename` may be pure ASCII or UTF-8 encoded */
- static JSFunctionDef *js_new_function_def(JSContext *ctx,
- JSFunctionDef *parent,
- bool is_eval,
- bool is_func_expr,
- const char *filename,
- int line_num,
- int col_num)
- {
- JSFunctionDef *fd;
- fd = js_mallocz(ctx, sizeof(*fd));
- if (!fd)
- return NULL;
- fd->ctx = ctx;
- init_list_head(&fd->child_list);
- /* insert in parent list */
- fd->parent = parent;
- fd->parent_cpool_idx = -1;
- if (parent) {
- list_add_tail(&fd->link, &parent->child_list);
- fd->is_strict_mode = parent->is_strict_mode;
- fd->parent_scope_level = parent->scope_level;
- }
- fd->is_eval = is_eval;
- fd->is_func_expr = is_func_expr;
- js_dbuf_init(ctx, &fd->byte_code);
- fd->last_opcode_pos = -1;
- fd->func_name = JS_ATOM_NULL;
- fd->var_object_idx = -1;
- fd->arg_var_object_idx = -1;
- fd->arguments_var_idx = -1;
- fd->arguments_arg_idx = -1;
- fd->func_var_idx = -1;
- fd->eval_ret_idx = -1;
- fd->this_var_idx = -1;
- fd->new_target_var_idx = -1;
- fd->this_active_func_var_idx = -1;
- fd->home_object_var_idx = -1;
- /* XXX: should distinguish arg, var and var object and body scopes */
- fd->scopes = fd->def_scope_array;
- fd->scope_size = countof(fd->def_scope_array);
- fd->scope_count = 1;
- fd->scopes[0].first = -1;
- fd->scopes[0].parent = -1;
- fd->scope_level = 0; /* 0: var/arg scope */
- fd->scope_first = -1;
- fd->body_scope = -1;
- fd->filename = JS_NewAtom(ctx, filename);
- fd->line_num = line_num;
- fd->col_num = col_num;
- js_dbuf_init(ctx, &fd->pc2line);
- //fd->pc2line_last_line_num = line_num;
- //fd->pc2line_last_pc = 0;
- return fd;
- }
- #endif // QJS_DISABLE_PARSER
- static void free_bytecode_atoms(JSRuntime *rt,
- const uint8_t *bc_buf, int bc_len,
- bool use_short_opcodes)
- {
- int pos, len, op;
- JSAtom atom;
- const JSOpCode *oi;
- pos = 0;
- while (pos < bc_len) {
- op = bc_buf[pos];
- if (use_short_opcodes)
- oi = &short_opcode_info(op);
- else
- oi = &opcode_info[op];
- len = oi->size;
- switch(oi->fmt) {
- case OP_FMT_atom:
- case OP_FMT_atom_u8:
- case OP_FMT_atom_u16:
- case OP_FMT_atom_label_u8:
- case OP_FMT_atom_label_u16:
- if ((pos + 1 + 4) > bc_len)
- break; /* may happen if there is not enough memory when emiting bytecode */
- atom = get_u32(bc_buf + pos + 1);
- JS_FreeAtomRT(rt, atom);
- break;
- default:
- break;
- }
- pos += len;
- }
- }
- #ifndef QJS_DISABLE_PARSER
- static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd)
- {
- int i;
- struct list_head *el, *el1;
- /* free the child functions */
- list_for_each_safe(el, el1, &fd->child_list) {
- JSFunctionDef *fd1;
- fd1 = list_entry(el, JSFunctionDef, link);
- js_free_function_def(ctx, fd1);
- }
- free_bytecode_atoms(ctx->rt, fd->byte_code.buf, fd->byte_code.size,
- fd->use_short_opcodes);
- dbuf_free(&fd->byte_code);
- js_free(ctx, fd->jump_slots);
- js_free(ctx, fd->label_slots);
- js_free(ctx, fd->source_loc_slots);
- for(i = 0; i < fd->cpool_count; i++) {
- JS_FreeValue(ctx, fd->cpool[i]);
- }
- js_free(ctx, fd->cpool);
- JS_FreeAtom(ctx, fd->func_name);
- for(i = 0; i < fd->var_count; i++) {
- JS_FreeAtom(ctx, fd->vars[i].var_name);
- }
- js_free(ctx, fd->vars);
- js_free(ctx, fd->vars_htab); // XXX can probably be freed earlier?
- for(i = 0; i < fd->arg_count; i++) {
- JS_FreeAtom(ctx, fd->args[i].var_name);
- }
- js_free(ctx, fd->args);
- for(i = 0; i < fd->global_var_count; i++) {
- JS_FreeAtom(ctx, fd->global_vars[i].var_name);
- }
- js_free(ctx, fd->global_vars);
- for(i = 0; i < fd->closure_var_count; i++) {
- JSClosureVar *cv = &fd->closure_var[i];
- JS_FreeAtom(ctx, cv->var_name);
- }
- js_free(ctx, fd->closure_var);
- if (fd->scopes != fd->def_scope_array)
- js_free(ctx, fd->scopes);
- JS_FreeAtom(ctx, fd->filename);
- dbuf_free(&fd->pc2line);
- js_free(ctx, fd->source);
- if (fd->parent) {
- /* remove in parent list */
- list_del(&fd->link);
- }
- js_free(ctx, fd);
- }
- #endif // QJS_DISABLE_PARSER
- #ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_*
- static const char *skip_lines(const char *p, int n) {
- while (p && n-- > 0 && *p) {
- while (*p && *p++ != '\n')
- continue;
- }
- return p;
- }
- static void print_lines(const char *source, int line, int line1) {
- const char *s = source;
- const char *p = skip_lines(s, line);
- if (p && *p) {
- while (line++ < line1) {
- p = skip_lines(s = p, 1);
- printf(";; %.*s", (int)(p - s), s);
- if (!*p) {
- if (p[-1] != '\n')
- printf("\n");
- break;
- }
- }
- }
- }
- static void dump_byte_code(JSContext *ctx, int pass,
- const uint8_t *tab, int len,
- const JSVarDef *args, int arg_count,
- const JSVarDef *vars, int var_count,
- const JSClosureVar *closure_var, int closure_var_count,
- const JSValue *cpool, uint32_t cpool_count,
- const char *source, int line_num,
- const LabelSlot *label_slots, JSFunctionBytecode *b,
- int start_pos)
- {
- const JSOpCode *oi;
- int pos, pos_next, op, size, idx, addr, line, line1, in_source;
- uint8_t *bits = js_mallocz(ctx, len * sizeof(*bits));
- bool use_short_opcodes = (b != NULL);
- if (start_pos != 0 || bits == NULL)
- goto no_labels;
- /* scan for jump targets */
- for (pos = 0; pos < len; pos = pos_next) {
- op = tab[pos];
- if (use_short_opcodes)
- oi = &short_opcode_info(op);
- else
- oi = &opcode_info[op];
- pos_next = pos + oi->size;
- if (op < OP_COUNT) {
- switch (oi->fmt) {
- case OP_FMT_label8:
- pos++;
- addr = (int8_t)tab[pos];
- goto has_addr;
- case OP_FMT_label16:
- pos++;
- addr = (int16_t)get_u16(tab + pos);
- goto has_addr;
- case OP_FMT_atom_label_u8:
- case OP_FMT_atom_label_u16:
- pos += 4;
- /* fall thru */
- case OP_FMT_label:
- case OP_FMT_label_u16:
- pos++;
- addr = get_u32(tab + pos);
- goto has_addr;
- has_addr:
- if (pass == 1)
- addr = label_slots[addr].pos;
- if (pass == 2)
- addr = label_slots[addr].pos2;
- if (pass == 3)
- addr += pos;
- if (addr >= 0 && addr < len)
- bits[addr] |= 1;
- break;
- }
- }
- }
- no_labels:
- in_source = 0;
- if (source) {
- /* Always print first line: needed if single line */
- print_lines(source, 0, 1);
- in_source = 1;
- }
- line1 = line = 1;
- pos = 0;
- while (pos < len) {
- op = tab[pos];
- if (source) {
- if (b) {
- int col1;
- line1 = find_line_num(ctx, b, pos, &col1) - line_num + 1;
- } else if (op == OP_source_loc) {
- line1 = get_u32(tab + pos + 1) - line_num + 1;
- }
- if (line1 > line) {
- if (!in_source)
- printf("\n");
- in_source = 1;
- print_lines(source, line, line1);
- line = line1;
- //bits[pos] |= 2;
- }
- }
- if (in_source)
- printf("\n");
- in_source = 0;
- if (op >= OP_COUNT) {
- printf("invalid opcode (0x%02x)\n", op);
- pos++;
- continue;
- }
- if (use_short_opcodes)
- oi = &short_opcode_info(op);
- else
- oi = &opcode_info[op];
- size = oi->size;
- if (pos + size > len) {
- printf("truncated opcode (0x%02x)\n", op);
- break;
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_HEX
- if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_HEX)) {
- int i, x, x0;
- x = x0 = printf("%5d ", pos);
- for (i = 0; i < size; i++) {
- if (i == 6) {
- printf("\n%*s", x = x0, "");
- }
- x += printf(" %02X", tab[pos + i]);
- }
- printf("%*s", x0 + 20 - x, "");
- }
- #endif
- if (bits && bits[pos]) {
- printf("%5d: ", pos);
- } else {
- printf(" ");
- }
- printf("%-15s", oi->name); /* align opcode arguments */
- pos++;
- switch(oi->fmt) {
- case OP_FMT_none_int:
- printf(" %d", op - OP_push_0);
- break;
- case OP_FMT_npopx:
- printf(" %d", op - OP_call0);
- break;
- case OP_FMT_u8:
- printf(" %u", get_u8(tab + pos));
- break;
- case OP_FMT_i8:
- printf(" %d", get_i8(tab + pos));
- break;
- case OP_FMT_u16:
- case OP_FMT_npop:
- printf(" %u", get_u16(tab + pos));
- break;
- case OP_FMT_npop_u16:
- printf(" %u,%u", get_u16(tab + pos), get_u16(tab + pos + 2));
- break;
- case OP_FMT_i16:
- printf(" %d", get_i16(tab + pos));
- break;
- case OP_FMT_i32:
- printf(" %d", get_i32(tab + pos));
- break;
- case OP_FMT_u32:
- printf(" %u", get_u32(tab + pos));
- break;
- case OP_FMT_u32x2:
- printf(" %u:%u", get_u32(tab + pos), get_u32(tab + pos + 4));
- break;
- case OP_FMT_label8:
- addr = get_i8(tab + pos);
- goto has_addr1;
- case OP_FMT_label16:
- addr = get_i16(tab + pos);
- goto has_addr1;
- case OP_FMT_label:
- case OP_FMT_label_u16:
- addr = get_u32(tab + pos);
- has_addr1:
- if (pass == 1)
- printf(" %d:%u", addr, label_slots[addr].pos);
- if (pass == 2)
- printf(" %d:%u", addr, label_slots[addr].pos2);
- if (pass == 3) {
- if (start_pos)
- printf(" %04x", addr + pos + start_pos);
- else
- printf(" %d", addr + pos);
- }
- if (oi->fmt == OP_FMT_label_u16)
- printf(",%u", get_u16(tab + pos + 4));
- break;
- case OP_FMT_const8:
- idx = get_u8(tab + pos);
- goto has_pool_idx;
- case OP_FMT_const:
- idx = get_u32(tab + pos);
- goto has_pool_idx;
- has_pool_idx:
- printf(" %-4u ; ", idx);
- if (idx < cpool_count) {
- JS_DumpValue(ctx->rt, cpool[idx]);
- }
- break;
- case OP_FMT_atom:
- printf(" ");
- print_atom(ctx, get_u32(tab + pos));
- break;
- case OP_FMT_atom_u8:
- printf(" ");
- print_atom(ctx, get_u32(tab + pos));
- printf(",%d", get_u8(tab + pos + 4));
- break;
- case OP_FMT_atom_u16:
- printf(" ");
- print_atom(ctx, get_u32(tab + pos));
- printf(",%d", get_u16(tab + pos + 4));
- break;
- case OP_FMT_atom_label_u8:
- case OP_FMT_atom_label_u16:
- printf(" ");
- print_atom(ctx, get_u32(tab + pos));
- addr = get_u32(tab + pos + 4);
- if (pass == 1)
- printf(",%u:%u", addr, label_slots[addr].pos);
- if (pass == 2)
- printf(",%u:%u", addr, label_slots[addr].pos2);
- if (pass == 3)
- printf(",%u", addr + pos + 4);
- if (oi->fmt == OP_FMT_atom_label_u8)
- printf(",%u", get_u8(tab + pos + 8));
- else
- printf(",%u", get_u16(tab + pos + 8));
- break;
- case OP_FMT_none_loc:
- if (op == OP_get_loc0_loc1) {
- printf(" 0, 1 ; ");
- if (var_count > 0)
- print_atom(ctx, vars[0].var_name);
- if (var_count > 1)
- print_atom(ctx, vars[1].var_name);
- } else {
- idx = (op - OP_get_loc0) % 4;
- goto has_loc;
- }
- break;
- case OP_FMT_loc8:
- idx = get_u8(tab + pos);
- goto has_loc;
- case OP_FMT_loc:
- idx = get_u16(tab + pos);
- has_loc:
- printf(" %-4d ; ", idx);
- if (idx < var_count) {
- print_atom(ctx, vars[idx].var_name);
- }
- break;
- case OP_FMT_none_arg:
- idx = (op - OP_get_arg0) % 4;
- goto has_arg;
- case OP_FMT_arg:
- idx = get_u16(tab + pos);
- has_arg:
- printf(" %-4d ; ", idx);
- if (idx < arg_count) {
- print_atom(ctx, args[idx].var_name);
- }
- break;
- case OP_FMT_none_var_ref:
- idx = (op - OP_get_var_ref0) % 4;
- goto has_var_ref;
- case OP_FMT_var_ref:
- idx = get_u16(tab + pos);
- has_var_ref:
- printf(" %-4d ; ", idx);
- if (idx < closure_var_count) {
- print_atom(ctx, closure_var[idx].var_name);
- }
- break;
- default:
- break;
- }
- printf("\n");
- pos += oi->size - 1;
- }
- if (source) {
- if (!in_source)
- printf("\n");
- print_lines(source, line, INT32_MAX);
- }
- js_free(ctx, bits);
- }
- // caveat emptor: intended to be called during execution of bytecode
- // and only works for pass3 bytecode
- static __maybe_unused void dump_single_byte_code(JSContext *ctx,
- const uint8_t *pc,
- JSFunctionBytecode *b,
- int start_pos)
- {
- JSVarDef *args, *vars;
- args = vars = b->vardefs;
- if (vars)
- vars = &vars[b->arg_count];
- dump_byte_code(ctx, /*pass*/3, pc, short_opcode_info(*pc).size,
- args, b->arg_count, vars, b->var_count,
- b->closure_var, b->closure_var_count,
- b->cpool, b->cpool_count,
- NULL, b->line_num,
- NULL, b, start_pos);
- }
- static __maybe_unused void print_func_name(JSFunctionBytecode *b)
- {
- print_lines(b->source, 0, 1);
- }
- static __maybe_unused void dump_pc2line(JSContext *ctx,
- const uint8_t *buf, int len,
- int line_num, int col_num)
- {
- const uint8_t *p_end, *p_next, *p;
- int pc, v;
- unsigned int op;
- if (len <= 0)
- return;
- printf("%5s %5s %5s\n", "PC", "LINE", "COLUMN");
- p = buf;
- p_end = buf + len;
- pc = 0;
- while (p < p_end) {
- op = *p++;
- if (op == 0) {
- v = utf8_decode_len(p, p_end - p, &p_next);
- if (v < 0)
- goto fail;
- pc += v;
- p = p_next;
- v = utf8_decode_len(p, p_end - p, &p_next);
- if (v < 0)
- goto fail;
- if (v & 1) {
- v = -(v >> 1) - 1;
- } else {
- v = v >> 1;
- }
- line_num += v;
- p = p_next;
- } else {
- op -= PC2LINE_OP_FIRST;
- pc += (op / PC2LINE_RANGE);
- line_num += (op % PC2LINE_RANGE) + PC2LINE_BASE;
- }
- v = utf8_decode_len(p, p_end - p, &p_next);
- if (v < 0)
- goto fail;
- if (v & 1) {
- v = -(v >> 1) - 1;
- } else {
- v = v >> 1;
- }
- col_num += v;
- p = p_next;
- printf("%5d %5d %5d\n", pc, line_num, col_num);
- }
- return;
- fail:
- printf("invalid pc2line encode pos=%d\n", (int)(p - buf));
- }
- static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionBytecode *b)
- {
- int i;
- char atom_buf[ATOM_GET_STR_BUF_SIZE];
- const char *str;
- const uint8_t *op;
- if (b->filename != JS_ATOM_NULL) {
- str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->filename);
- printf("%s:%d:%d: ", str, b->line_num, b->col_num);
- }
- str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name);
- printf("function: %s%s\n", &"*"[b->func_kind != JS_FUNC_GENERATOR], str);
- printf(" mode: %s\n", b->is_strict_mode ? "strict" : "sloppy");
- if (b->arg_count && b->vardefs) {
- printf(" args:");
- for(i = 0; i < b->arg_count; i++) {
- printf(" %s", JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf),
- b->vardefs[i].var_name));
- }
- printf("\n");
- }
- if (b->var_count && b->vardefs) {
- printf(" locals:\n");
- for(i = 0; i < b->var_count; i++) {
- JSVarDef *vd = &b->vardefs[b->arg_count + i];
- printf("%5d: %s %s", i,
- vd->var_kind == JS_VAR_CATCH ? "catch" :
- (vd->var_kind == JS_VAR_FUNCTION_DECL ||
- vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) ? "function" :
- vd->is_const ? "const" :
- vd->is_lexical ? "let" : "var",
- JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), vd->var_name));
- if (vd->scope_level)
- printf(" [level:%d next:%d]", vd->scope_level, vd->scope_next);
- printf("\n");
- }
- }
- if (b->closure_var_count) {
- printf(" closure vars:\n");
- for(i = 0; i < b->closure_var_count; i++) {
- JSClosureVar *cv = &b->closure_var[i];
- printf("%5d: %s %s:%s%d %s\n", i,
- JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), cv->var_name),
- cv->is_local ? "local" : "parent",
- cv->is_arg ? "arg" : "loc", cv->var_idx,
- cv->is_const ? "const" :
- cv->is_lexical ? "let" : "var");
- }
- }
- printf(" stack_size: %d\n", b->stack_size);
- printf(" byte_code_len: %d\n", b->byte_code_len);
- op = b->byte_code_buf;
- for (i = 0; op < &b->byte_code_buf[b->byte_code_len]; i++)
- op += short_opcode_info(*op).size;
- printf(" opcodes: %d\n", i);
- dump_byte_code(ctx, 3, b->byte_code_buf, b->byte_code_len,
- b->vardefs, b->arg_count,
- b->vardefs ? b->vardefs + b->arg_count : NULL, b->var_count,
- b->closure_var, b->closure_var_count,
- b->cpool, b->cpool_count,
- b->source, b->line_num, NULL, b, 0);
- #ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_PC2LINE
- if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_PC2LINE))
- dump_pc2line(ctx, b->pc2line_buf, b->pc2line_len, b->line_num, b->col_num);
- #endif
- printf("\n");
- }
- #endif
- #ifndef QJS_DISABLE_PARSER
- static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
- bool is_local, bool is_arg,
- int var_idx, JSAtom var_name,
- bool is_const, bool is_lexical,
- JSVarKindEnum var_kind)
- {
- JSClosureVar *cv;
- /* the closure variable indexes are currently stored on 16 bits */
- if (s->closure_var_count >= JS_MAX_LOCAL_VARS) {
- // XXX: add_closure_var() should take JSParseState *s and use js_parse_error
- JS_ThrowSyntaxError(ctx, "too many closure variables used (only %d allowed)",
- JS_MAX_LOCAL_VARS - 1);
- return -1;
- }
- if (js_resize_array(ctx, (void **)&s->closure_var,
- sizeof(s->closure_var[0]),
- &s->closure_var_size, s->closure_var_count + 1))
- return -1;
- cv = &s->closure_var[s->closure_var_count++];
- cv->is_local = is_local;
- cv->is_arg = is_arg;
- cv->is_const = is_const;
- cv->is_lexical = is_lexical;
- cv->var_kind = var_kind;
- cv->var_idx = var_idx;
- cv->var_name = JS_DupAtom(ctx, var_name);
- return s->closure_var_count - 1;
- }
- static int find_closure_var(JSContext *ctx, JSFunctionDef *s,
- JSAtom var_name)
- {
- int i;
- for(i = 0; i < s->closure_var_count; i++) {
- JSClosureVar *cv = &s->closure_var[i];
- if (cv->var_name == var_name)
- return i;
- }
- return -1;
- }
- /* 'fd' must be a parent of 's'. Create in 's' a closure referencing a
- local variable (is_local = true) or a closure (is_local = false) in
- 'fd' */
- static int get_closure_var2(JSContext *ctx, JSFunctionDef *s,
- JSFunctionDef *fd, bool is_local,
- bool is_arg, int var_idx, JSAtom var_name,
- bool is_const, bool is_lexical,
- JSVarKindEnum var_kind)
- {
- int i;
- if (fd != s->parent) {
- var_idx = get_closure_var2(ctx, s->parent, fd, is_local,
- is_arg, var_idx, var_name,
- is_const, is_lexical, var_kind);
- if (var_idx < 0)
- return -1;
- is_local = false;
- }
- for(i = 0; i < s->closure_var_count; i++) {
- JSClosureVar *cv = &s->closure_var[i];
- if (cv->var_idx == var_idx && cv->is_arg == is_arg &&
- cv->is_local == is_local)
- return i;
- }
- return add_closure_var(ctx, s, is_local, is_arg, var_idx, var_name,
- is_const, is_lexical, var_kind);
- }
- static int get_closure_var(JSContext *ctx, JSFunctionDef *s,
- JSFunctionDef *fd, bool is_arg,
- int var_idx, JSAtom var_name,
- bool is_const, bool is_lexical,
- JSVarKindEnum var_kind)
- {
- return get_closure_var2(ctx, s, fd, true, is_arg,
- var_idx, var_name, is_const, is_lexical,
- var_kind);
- }
- static int get_with_scope_opcode(int op)
- {
- if (op == OP_scope_get_var_undef)
- return OP_with_get_var;
- else
- return OP_with_get_var + (op - OP_scope_get_var);
- }
- static bool can_opt_put_ref_value(const uint8_t *bc_buf, int pos)
- {
- int opcode = bc_buf[pos];
- return (bc_buf[pos + 1] == OP_put_ref_value &&
- (opcode == OP_insert3 ||
- opcode == OP_perm4 ||
- opcode == OP_nop ||
- opcode == OP_rot3l));
- }
- static bool can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos)
- {
- int opcode = bc_buf[pos];
- return (bc_buf[pos + 1] == OP_put_ref_value &&
- (opcode == OP_insert3 ||
- opcode == OP_perm4 ||
- opcode == OP_nop ||
- opcode == OP_rot3l));
- }
- static int optimize_scope_make_ref(JSContext *ctx, JSFunctionDef *s,
- DynBuf *bc, uint8_t *bc_buf,
- LabelSlot *ls, int pos_next,
- int get_op, int var_idx)
- {
- int label_pos, end_pos, pos;
- /* XXX: should optimize `loc(a) += expr` as `expr add_loc(a)`
- but only if expr does not modify `a`.
- should scan the code between pos_next and label_pos
- for operations that can potentially change `a`:
- OP_scope_make_ref(a), function calls, jumps and gosub.
- */
- /* replace the reference get/put with normal variable
- accesses */
- if (bc_buf[pos_next] == OP_get_ref_value) {
- dbuf_putc(bc, get_op);
- dbuf_put_u16(bc, var_idx);
- pos_next++;
- }
- /* remove the OP_label to make room for replacement */
- /* label should have a refcount of 0 anyway */
- /* XXX: should avoid this patch by inserting nops in phase 1 */
- label_pos = ls->pos;
- pos = label_pos - 5;
- assert(bc_buf[pos] == OP_label);
- /* label points to an instruction pair:
- - insert3 / put_ref_value
- - perm4 / put_ref_value
- - rot3l / put_ref_value
- - nop / put_ref_value
- */
- end_pos = label_pos + 2;
- if (bc_buf[label_pos] == OP_insert3)
- bc_buf[pos++] = OP_dup;
- bc_buf[pos] = get_op + 1;
- put_u16(bc_buf + pos + 1, var_idx);
- pos += 3;
- /* pad with OP_nop */
- while (pos < end_pos)
- bc_buf[pos++] = OP_nop;
- return pos_next;
- }
- static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s,
- DynBuf *bc, uint8_t *bc_buf,
- LabelSlot *ls, int pos_next,
- JSAtom var_name)
- {
- int label_pos, end_pos, pos, op;
- bool is_strict_mode = s->is_strict_mode;
- /* replace the reference get/put with normal variable
- accesses */
- if (is_strict_mode) {
- /* need to check if the variable exists before evaluating the right
- expression */
- /* XXX: need an extra OP_true if destructuring an array */
- dbuf_putc(bc, OP_check_var);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- } else {
- /* XXX: need 2 extra OP_true if destructuring an array */
- }
- if (bc_buf[pos_next] == OP_get_ref_value) {
- dbuf_putc(bc, OP_get_var);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- pos_next++;
- }
- /* remove the OP_label to make room for replacement */
- /* label should have a refcount of 0 anyway */
- /* XXX: should have emitted several OP_nop to avoid this kludge */
- label_pos = ls->pos;
- pos = label_pos - 5;
- assert(bc_buf[pos] == OP_label);
- end_pos = label_pos + 2;
- op = bc_buf[label_pos];
- if (is_strict_mode) {
- if (op != OP_nop) {
- switch(op) {
- case OP_insert3:
- op = OP_insert2;
- break;
- case OP_perm4:
- op = OP_perm3;
- break;
- case OP_rot3l:
- op = OP_swap;
- break;
- default:
- abort();
- }
- bc_buf[pos++] = op;
- }
- } else {
- if (op == OP_insert3)
- bc_buf[pos++] = OP_dup;
- }
- if (is_strict_mode) {
- bc_buf[pos] = OP_put_var_strict;
- /* XXX: need 1 extra OP_drop if destructuring an array */
- } else {
- bc_buf[pos] = OP_put_var;
- /* XXX: need 2 extra OP_drop if destructuring an array */
- }
- put_u32(bc_buf + pos + 1, JS_DupAtom(ctx, var_name));
- pos += 5;
- /* pad with OP_nop */
- while (pos < end_pos)
- bc_buf[pos++] = OP_nop;
- return pos_next;
- }
- static int add_var_this(JSContext *ctx, JSFunctionDef *fd)
- {
- int idx;
- idx = add_var(ctx, fd, JS_ATOM_this);
- if (idx >= 0 && fd->is_derived_class_constructor) {
- JSVarDef *vd = &fd->vars[idx];
- /* XXX: should have is_this flag or var type */
- vd->is_lexical = 1; /* used to trigger 'uninitialized' checks
- in a derived class constructor */
- }
- return idx;
- }
- static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,
- JSAtom var_name)
- {
- int var_idx;
- if (!s->has_this_binding)
- return -1;
- switch(var_name) {
- case JS_ATOM_home_object:
- /* 'home_object' pseudo variable */
- if (s->home_object_var_idx < 0)
- s->home_object_var_idx = add_var(ctx, s, var_name);
- var_idx = s->home_object_var_idx;
- break;
- case JS_ATOM_this_active_func:
- /* 'this.active_func' pseudo variable */
- if (s->this_active_func_var_idx < 0)
- s->this_active_func_var_idx = add_var(ctx, s, var_name);
- var_idx = s->this_active_func_var_idx;
- break;
- case JS_ATOM_new_target:
- /* 'new.target' pseudo variable */
- if (s->new_target_var_idx < 0)
- s->new_target_var_idx = add_var(ctx, s, var_name);
- var_idx = s->new_target_var_idx;
- break;
- case JS_ATOM_this:
- /* 'this' pseudo variable */
- if (s->this_var_idx < 0)
- s->this_var_idx = add_var_this(ctx, s);
- var_idx = s->this_var_idx;
- break;
- default:
- var_idx = -1;
- break;
- }
- return var_idx;
- }
- /* test if 'var_name' is in the variable object on the stack. If is it
- the case, handle it and jump to 'label_done' */
- static void var_object_test(JSContext *ctx, JSFunctionDef *s,
- JSAtom var_name, int op, DynBuf *bc,
- int *plabel_done, bool is_with)
- {
- dbuf_putc(bc, get_with_scope_opcode(op));
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- if (*plabel_done < 0) {
- *plabel_done = new_label_fd(s);
- if (*plabel_done < 0) {
- dbuf_set_error(bc);
- return;
- }
- }
- dbuf_put_u32(bc, *plabel_done);
- dbuf_putc(bc, is_with);
- update_label(s, *plabel_done, 1);
- s->jump_size++;
- }
- /* return the position of the next opcode */
- static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
- JSAtom var_name, int scope_level, int op,
- DynBuf *bc, uint8_t *bc_buf,
- LabelSlot *ls, int pos_next)
- {
- int idx, var_idx, is_put;
- int label_done;
- JSFunctionDef *fd;
- JSVarDef *vd;
- bool is_pseudo_var, is_arg_scope;
- label_done = -1;
- /* XXX: could be simpler to use a specific function to
- resolve the pseudo variables */
- is_pseudo_var = (var_name == JS_ATOM_home_object ||
- var_name == JS_ATOM_this_active_func ||
- var_name == JS_ATOM_new_target ||
- var_name == JS_ATOM_this);
- /* resolve local scoped variables */
- var_idx = -1;
- for (idx = s->scopes[scope_level].first; idx >= 0;) {
- vd = &s->vars[idx];
- if (vd->var_name == var_name) {
- if (op == OP_scope_put_var || op == OP_scope_make_ref) {
- if (vd->is_const) {
- dbuf_putc(bc, OP_throw_error);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_putc(bc, JS_THROW_VAR_RO);
- goto done;
- }
- }
- var_idx = idx;
- break;
- } else
- if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
- dbuf_putc(bc, OP_get_loc);
- dbuf_put_u16(bc, idx);
- var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
- }
- idx = vd->scope_next;
- }
- is_arg_scope = (idx == ARG_SCOPE_END);
- if (var_idx < 0) {
- /* argument scope: variables are not visible but pseudo
- variables are visible */
- if (!is_arg_scope) {
- var_idx = find_var(ctx, s, var_name);
- }
- if (var_idx < 0 && is_pseudo_var)
- var_idx = resolve_pseudo_var(ctx, s, var_name);
- if (var_idx < 0 && var_name == JS_ATOM_arguments &&
- s->has_arguments_binding) {
- /* 'arguments' pseudo variable */
- var_idx = add_arguments_var(ctx, s);
- }
- if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) {
- /* add a new variable with the function name */
- var_idx = add_func_var(ctx, s, var_name);
- }
- }
- if (var_idx >= 0) {
- if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
- !(var_idx & ARGUMENT_VAR_OFFSET) &&
- s->vars[var_idx].is_const) {
- /* only happens when assigning a function expression name
- in strict mode */
- dbuf_putc(bc, OP_throw_error);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_putc(bc, JS_THROW_VAR_RO);
- goto done;
- }
- /* OP_scope_put_var_init is only used to initialize a
- lexical variable, so it is never used in a with or var object. It
- can be used with a closure (module global variable case). */
- switch (op) {
- case OP_scope_make_ref:
- if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
- s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
- /* Create a dummy object reference for the func_var */
- dbuf_putc(bc, OP_object);
- dbuf_putc(bc, OP_get_loc);
- dbuf_put_u16(bc, var_idx);
- dbuf_putc(bc, OP_define_field);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_putc(bc, OP_push_atom_value);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- } else
- if (label_done == -1 && can_opt_put_ref_value(bc_buf, ls->pos)) {
- int get_op;
- if (var_idx & ARGUMENT_VAR_OFFSET) {
- get_op = OP_get_arg;
- var_idx -= ARGUMENT_VAR_OFFSET;
- } else {
- if (s->vars[var_idx].is_lexical)
- get_op = OP_get_loc_check;
- else
- get_op = OP_get_loc;
- }
- pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
- pos_next, get_op, var_idx);
- } else {
- /* Create a dummy object with a named slot that is
- a reference to the local variable */
- if (var_idx & ARGUMENT_VAR_OFFSET) {
- dbuf_putc(bc, OP_make_arg_ref);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
- } else {
- dbuf_putc(bc, OP_make_loc_ref);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_put_u16(bc, var_idx);
- }
- }
- break;
- case OP_scope_get_ref:
- dbuf_putc(bc, OP_undefined);
- /* fall thru */
- case OP_scope_get_var_undef:
- case OP_scope_get_var:
- case OP_scope_put_var:
- case OP_scope_put_var_init:
- is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init);
- if (var_idx & ARGUMENT_VAR_OFFSET) {
- dbuf_putc(bc, OP_get_arg + is_put);
- dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
- } else {
- if (is_put) {
- if (s->vars[var_idx].is_lexical) {
- if (op == OP_scope_put_var_init) {
- /* 'this' can only be initialized once */
- if (var_name == JS_ATOM_this)
- dbuf_putc(bc, OP_put_loc_check_init);
- else
- dbuf_putc(bc, OP_put_loc);
- } else {
- dbuf_putc(bc, OP_put_loc_check);
- }
- } else {
- dbuf_putc(bc, OP_put_loc);
- }
- } else {
- if (s->vars[var_idx].is_lexical) {
- dbuf_putc(bc, OP_get_loc_check);
- } else {
- dbuf_putc(bc, OP_get_loc);
- }
- }
- dbuf_put_u16(bc, var_idx);
- }
- break;
- case OP_scope_delete_var:
- dbuf_putc(bc, OP_push_false);
- break;
- }
- goto done;
- }
- /* check eval object */
- if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) {
- dbuf_putc(bc, OP_get_loc);
- dbuf_put_u16(bc, s->var_object_idx);
- var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
- }
- /* check eval object in argument scope */
- if (s->arg_var_object_idx >= 0 && !is_pseudo_var) {
- dbuf_putc(bc, OP_get_loc);
- dbuf_put_u16(bc, s->arg_var_object_idx);
- var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
- }
- /* check parent scopes */
- for (fd = s; fd->parent;) {
- scope_level = fd->parent_scope_level;
- fd = fd->parent;
- for (idx = fd->scopes[scope_level].first; idx >= 0;) {
- vd = &fd->vars[idx];
- if (vd->var_name == var_name) {
- if (op == OP_scope_put_var || op == OP_scope_make_ref) {
- if (vd->is_const) {
- dbuf_putc(bc, OP_throw_error);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_putc(bc, JS_THROW_VAR_RO);
- goto done;
- }
- }
- var_idx = idx;
- break;
- } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
- vd->is_captured = 1;
- idx = get_closure_var(ctx, s, fd, false, idx, vd->var_name, false, false, JS_VAR_NORMAL);
- if (idx >= 0) {
- dbuf_putc(bc, OP_get_var_ref);
- dbuf_put_u16(bc, idx);
- var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
- }
- }
- idx = vd->scope_next;
- }
- is_arg_scope = (idx == ARG_SCOPE_END);
- if (var_idx >= 0)
- break;
- if (!is_arg_scope) {
- var_idx = find_var(ctx, fd, var_name);
- if (var_idx >= 0)
- break;
- }
- if (is_pseudo_var) {
- var_idx = resolve_pseudo_var(ctx, fd, var_name);
- if (var_idx >= 0)
- break;
- }
- if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) {
- var_idx = add_arguments_var(ctx, fd);
- break;
- }
- if (fd->is_func_expr && fd->func_name == var_name) {
- /* add a new variable with the function name */
- var_idx = add_func_var(ctx, fd, var_name);
- break;
- }
- /* check eval object */
- if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
- vd = &fd->vars[fd->var_object_idx];
- vd->is_captured = 1;
- idx = get_closure_var(ctx, s, fd, false,
- fd->var_object_idx, vd->var_name,
- false, false, JS_VAR_NORMAL);
- dbuf_putc(bc, OP_get_var_ref);
- dbuf_put_u16(bc, idx);
- var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
- }
- /* check eval object in argument scope */
- if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
- vd = &fd->vars[fd->arg_var_object_idx];
- vd->is_captured = 1;
- idx = get_closure_var(ctx, s, fd, false,
- fd->arg_var_object_idx, vd->var_name,
- false, false, JS_VAR_NORMAL);
- dbuf_putc(bc, OP_get_var_ref);
- dbuf_put_u16(bc, idx);
- var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
- }
- if (fd->is_eval)
- break; /* it it necessarily the top level function */
- }
- /* check direct eval scope (in the closure of the eval function
- which is necessarily at the top level) */
- if (!fd)
- fd = s;
- if (var_idx < 0 && fd->is_eval) {
- int idx1;
- for (idx1 = 0; idx1 < fd->closure_var_count; idx1++) {
- JSClosureVar *cv = &fd->closure_var[idx1];
- if (var_name == cv->var_name) {
- if (fd != s) {
- idx = get_closure_var2(ctx, s, fd,
- false,
- cv->is_arg, idx1,
- cv->var_name, cv->is_const,
- cv->is_lexical, cv->var_kind);
- } else {
- idx = idx1;
- }
- goto has_idx;
- } else if ((cv->var_name == JS_ATOM__var_ ||
- cv->var_name == JS_ATOM__arg_var_ ||
- cv->var_name == JS_ATOM__with_) && !is_pseudo_var) {
- int is_with = (cv->var_name == JS_ATOM__with_);
- if (fd != s) {
- idx = get_closure_var2(ctx, s, fd,
- false,
- cv->is_arg, idx1,
- cv->var_name, false, false,
- JS_VAR_NORMAL);
- } else {
- idx = idx1;
- }
- dbuf_putc(bc, OP_get_var_ref);
- dbuf_put_u16(bc, idx);
- var_object_test(ctx, s, var_name, op, bc, &label_done, is_with);
- }
- }
- }
- if (var_idx >= 0) {
- /* find the corresponding closure variable */
- if (var_idx & ARGUMENT_VAR_OFFSET) {
- fd->args[var_idx - ARGUMENT_VAR_OFFSET].is_captured = 1;
- idx = get_closure_var(ctx, s, fd,
- true, var_idx - ARGUMENT_VAR_OFFSET,
- var_name, false, false, JS_VAR_NORMAL);
- } else {
- fd->vars[var_idx].is_captured = 1;
- idx = get_closure_var(ctx, s, fd,
- false, var_idx,
- var_name,
- fd->vars[var_idx].is_const,
- fd->vars[var_idx].is_lexical,
- fd->vars[var_idx].var_kind);
- }
- if (idx >= 0) {
- has_idx:
- if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
- s->closure_var[idx].is_const) {
- dbuf_putc(bc, OP_throw_error);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_putc(bc, JS_THROW_VAR_RO);
- goto done;
- }
- switch (op) {
- case OP_scope_make_ref:
- if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
- /* Create a dummy object reference for the func_var */
- dbuf_putc(bc, OP_object);
- dbuf_putc(bc, OP_get_var_ref);
- dbuf_put_u16(bc, idx);
- dbuf_putc(bc, OP_define_field);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_putc(bc, OP_push_atom_value);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- } else
- if (label_done == -1 &&
- can_opt_put_ref_value(bc_buf, ls->pos)) {
- int get_op;
- if (s->closure_var[idx].is_lexical)
- get_op = OP_get_var_ref_check;
- else
- get_op = OP_get_var_ref;
- pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
- pos_next,
- get_op, idx);
- } else {
- /* Create a dummy object with a named slot that is
- a reference to the closure variable */
- dbuf_putc(bc, OP_make_var_ref_ref);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_put_u16(bc, idx);
- }
- break;
- case OP_scope_get_ref:
- /* XXX: should create a dummy object with a named slot that is
- a reference to the closure variable */
- dbuf_putc(bc, OP_undefined);
- /* fall thru */
- case OP_scope_get_var_undef:
- case OP_scope_get_var:
- case OP_scope_put_var:
- case OP_scope_put_var_init:
- is_put = (op == OP_scope_put_var ||
- op == OP_scope_put_var_init);
- if (is_put) {
- if (s->closure_var[idx].is_lexical) {
- if (op == OP_scope_put_var_init) {
- /* 'this' can only be initialized once */
- if (var_name == JS_ATOM_this)
- dbuf_putc(bc, OP_put_var_ref_check_init);
- else
- dbuf_putc(bc, OP_put_var_ref);
- } else {
- dbuf_putc(bc, OP_put_var_ref_check);
- }
- } else {
- dbuf_putc(bc, OP_put_var_ref);
- }
- } else {
- if (s->closure_var[idx].is_lexical) {
- dbuf_putc(bc, OP_get_var_ref_check);
- } else {
- dbuf_putc(bc, OP_get_var_ref);
- }
- }
- dbuf_put_u16(bc, idx);
- break;
- case OP_scope_delete_var:
- dbuf_putc(bc, OP_push_false);
- break;
- }
- goto done;
- }
- }
- /* global variable access */
- switch (op) {
- case OP_scope_make_ref:
- if (label_done == -1 && can_opt_put_global_ref_value(bc_buf, ls->pos)) {
- pos_next = optimize_scope_make_global_ref(ctx, s, bc, bc_buf, ls,
- pos_next, var_name);
- } else {
- dbuf_putc(bc, OP_make_var_ref);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- }
- break;
- case OP_scope_get_ref:
- /* XXX: should create a dummy object with a named slot that is
- a reference to the global variable */
- dbuf_putc(bc, OP_undefined);
- dbuf_putc(bc, OP_get_var);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- break;
- case OP_scope_get_var_undef:
- case OP_scope_get_var:
- case OP_scope_put_var:
- dbuf_putc(bc, OP_get_var_undef + (op - OP_scope_get_var_undef));
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- break;
- case OP_scope_put_var_init:
- dbuf_putc(bc, OP_put_var_init);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- break;
- case OP_scope_delete_var:
- dbuf_putc(bc, OP_delete_var);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- break;
- }
- done:
- if (label_done >= 0) {
- dbuf_putc(bc, OP_label);
- dbuf_put_u32(bc, label_done);
- s->label_slots[label_done].pos2 = bc->size;
- }
- return pos_next;
- }
- /* search in all scopes */
- static int find_private_class_field_all(JSContext *ctx, JSFunctionDef *fd,
- JSAtom name, int scope_level)
- {
- int idx;
- idx = fd->scopes[scope_level].first;
- while (idx >= 0) {
- if (fd->vars[idx].var_name == name)
- return idx;
- idx = fd->vars[idx].scope_next;
- }
- return -1;
- }
- static void get_loc_or_ref(DynBuf *bc, bool is_ref, int idx)
- {
- /* if the field is not initialized, the error is catched when
- accessing it */
- if (is_ref)
- dbuf_putc(bc, OP_get_var_ref);
- else
- dbuf_putc(bc, OP_get_loc);
- dbuf_put_u16(bc, idx);
- }
- static int resolve_scope_private_field1(JSContext *ctx,
- bool *pis_ref, int *pvar_kind,
- JSFunctionDef *s,
- JSAtom var_name, int scope_level)
- {
- int idx, var_kind;
- JSFunctionDef *fd;
- bool is_ref;
- fd = s;
- is_ref = false;
- for(;;) {
- idx = find_private_class_field_all(ctx, fd, var_name, scope_level);
- if (idx >= 0) {
- var_kind = fd->vars[idx].var_kind;
- if (is_ref) {
- idx = get_closure_var(ctx, s, fd, false, idx, var_name,
- true, true, JS_VAR_NORMAL);
- if (idx < 0)
- return -1;
- }
- break;
- }
- scope_level = fd->parent_scope_level;
- if (!fd->parent) {
- if (fd->is_eval) {
- /* closure of the eval function (top level) */
- for (idx = 0; idx < fd->closure_var_count; idx++) {
- JSClosureVar *cv = &fd->closure_var[idx];
- if (cv->var_name == var_name) {
- var_kind = cv->var_kind;
- is_ref = true;
- if (fd != s) {
- idx = get_closure_var2(ctx, s, fd,
- false,
- cv->is_arg, idx,
- cv->var_name, cv->is_const,
- cv->is_lexical,
- cv->var_kind);
- if (idx < 0)
- return -1;
- }
- goto done;
- }
- }
- }
- /* XXX: no line number info */
- // XXX: resolve_scope_private_field1() should take JSParseState *s and use js_parse_error_atom
- JS_ThrowSyntaxErrorAtom(ctx, "undefined private field '%s'",
- var_name);
- return -1;
- } else {
- fd = fd->parent;
- }
- is_ref = true;
- }
- done:
- *pis_ref = is_ref;
- *pvar_kind = var_kind;
- return idx;
- }
- /* return 0 if OK or -1 if the private field could not be resolved */
- static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
- JSAtom var_name, int scope_level, int op,
- DynBuf *bc)
- {
- int idx, var_kind;
- bool is_ref;
- idx = resolve_scope_private_field1(ctx, &is_ref, &var_kind, s,
- var_name, scope_level);
- if (idx < 0)
- return -1;
- assert(var_kind != JS_VAR_NORMAL);
- switch (op) {
- case OP_scope_get_private_field:
- case OP_scope_get_private_field2:
- switch(var_kind) {
- case JS_VAR_PRIVATE_FIELD:
- if (op == OP_scope_get_private_field2)
- dbuf_putc(bc, OP_dup);
- get_loc_or_ref(bc, is_ref, idx);
- dbuf_putc(bc, OP_get_private_field);
- break;
- case JS_VAR_PRIVATE_METHOD:
- get_loc_or_ref(bc, is_ref, idx);
- dbuf_putc(bc, OP_check_brand);
- if (op != OP_scope_get_private_field2)
- dbuf_putc(bc, OP_nip);
- break;
- case JS_VAR_PRIVATE_GETTER:
- case JS_VAR_PRIVATE_GETTER_SETTER:
- if (op == OP_scope_get_private_field2)
- dbuf_putc(bc, OP_dup);
- get_loc_or_ref(bc, is_ref, idx);
- dbuf_putc(bc, OP_check_brand);
- dbuf_putc(bc, OP_call_method);
- dbuf_put_u16(bc, 0);
- break;
- case JS_VAR_PRIVATE_SETTER:
- /* XXX: add clearer error message */
- dbuf_putc(bc, OP_throw_error);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_putc(bc, JS_THROW_VAR_RO);
- break;
- default:
- abort();
- }
- break;
- case OP_scope_put_private_field:
- switch(var_kind) {
- case JS_VAR_PRIVATE_FIELD:
- get_loc_or_ref(bc, is_ref, idx);
- dbuf_putc(bc, OP_put_private_field);
- break;
- case JS_VAR_PRIVATE_METHOD:
- case JS_VAR_PRIVATE_GETTER:
- /* XXX: add clearer error message */
- dbuf_putc(bc, OP_throw_error);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_putc(bc, JS_THROW_VAR_RO);
- break;
- case JS_VAR_PRIVATE_SETTER:
- case JS_VAR_PRIVATE_GETTER_SETTER:
- {
- JSAtom setter_name = get_private_setter_name(ctx, var_name);
- if (setter_name == JS_ATOM_NULL)
- return -1;
- idx = resolve_scope_private_field1(ctx, &is_ref,
- &var_kind, s,
- setter_name, scope_level);
- JS_FreeAtom(ctx, setter_name);
- if (idx < 0)
- return -1;
- assert(var_kind == JS_VAR_PRIVATE_SETTER);
- get_loc_or_ref(bc, is_ref, idx);
- dbuf_putc(bc, OP_swap);
- /* obj func value */
- dbuf_putc(bc, OP_rot3r);
- /* value obj func */
- dbuf_putc(bc, OP_check_brand);
- dbuf_putc(bc, OP_rot3l);
- /* obj func value */
- dbuf_putc(bc, OP_call_method);
- dbuf_put_u16(bc, 1);
- dbuf_putc(bc, OP_drop);
- }
- break;
- default:
- abort();
- }
- break;
- case OP_scope_in_private_field:
- get_loc_or_ref(bc, is_ref, idx);
- dbuf_putc(bc, OP_private_in);
- break;
- default:
- abort();
- }
- return 0;
- }
- static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
- int scope_level)
- {
- int idx;
- JSVarDef *vd;
- for (idx = s->scopes[scope_level].first; idx >= 0;) {
- vd = &s->vars[idx];
- vd->is_captured = 1;
- idx = vd->scope_next;
- }
- }
- /* XXX: should handle the argument scope generically */
- static bool is_var_in_arg_scope(const JSVarDef *vd)
- {
- return (vd->var_name == JS_ATOM_home_object ||
- vd->var_name == JS_ATOM_this_active_func ||
- vd->var_name == JS_ATOM_new_target ||
- vd->var_name == JS_ATOM_this ||
- vd->var_name == JS_ATOM__arg_var_ ||
- vd->var_kind == JS_VAR_FUNCTION_NAME);
- }
- static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
- {
- JSFunctionDef *fd;
- JSVarDef *vd;
- int i, scope_level, scope_idx;
- bool has_arguments_binding, has_this_binding, is_arg_scope;
- /* in non strict mode, variables are created in the caller's
- environment object */
- if (!s->is_eval && !s->is_strict_mode) {
- s->var_object_idx = add_var(ctx, s, JS_ATOM__var_);
- if (s->has_parameter_expressions) {
- /* an additional variable object is needed for the
- argument scope */
- s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_);
- }
- }
- /* eval can potentially use 'arguments' so we must define it */
- has_this_binding = s->has_this_binding;
- if (has_this_binding) {
- if (s->this_var_idx < 0)
- s->this_var_idx = add_var_this(ctx, s);
- if (s->new_target_var_idx < 0)
- s->new_target_var_idx = add_var(ctx, s, JS_ATOM_new_target);
- if (s->is_derived_class_constructor && s->this_active_func_var_idx < 0)
- s->this_active_func_var_idx = add_var(ctx, s, JS_ATOM_this_active_func);
- if (s->has_home_object && s->home_object_var_idx < 0)
- s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object);
- }
- has_arguments_binding = s->has_arguments_binding;
- if (has_arguments_binding) {
- add_arguments_var(ctx, s);
- /* also add an arguments binding in the argument scope to
- raise an error if a direct eval in the argument scope tries
- to redefine it */
- if (s->has_parameter_expressions && !s->is_strict_mode)
- add_arguments_arg(ctx, s);
- }
- if (s->is_func_expr && s->func_name != JS_ATOM_NULL)
- add_func_var(ctx, s, s->func_name);
- /* eval can use all the variables of the enclosing functions, so
- they must be all put in the closure. The closure variables are
- ordered by scope. It works only because no closure are created
- before. */
- assert(s->is_eval || s->closure_var_count == 0);
- /* XXX: inefficient, but eval performance is less critical */
- fd = s;
- for(;;) {
- scope_level = fd->parent_scope_level;
- fd = fd->parent;
- if (!fd)
- break;
- /* add 'this' if it was not previously added */
- if (!has_this_binding && fd->has_this_binding) {
- if (fd->this_var_idx < 0)
- fd->this_var_idx = add_var_this(ctx, fd);
- if (fd->new_target_var_idx < 0)
- fd->new_target_var_idx = add_var(ctx, fd, JS_ATOM_new_target);
- if (fd->is_derived_class_constructor && fd->this_active_func_var_idx < 0)
- fd->this_active_func_var_idx = add_var(ctx, fd, JS_ATOM_this_active_func);
- if (fd->has_home_object && fd->home_object_var_idx < 0)
- fd->home_object_var_idx = add_var(ctx, fd, JS_ATOM_home_object);
- has_this_binding = true;
- }
- /* add 'arguments' if it was not previously added */
- if (!has_arguments_binding && fd->has_arguments_binding) {
- add_arguments_var(ctx, fd);
- has_arguments_binding = true;
- }
- /* add function name */
- if (fd->is_func_expr && fd->func_name != JS_ATOM_NULL)
- add_func_var(ctx, fd, fd->func_name);
- /* add lexical variables */
- scope_idx = fd->scopes[scope_level].first;
- while (scope_idx >= 0) {
- vd = &fd->vars[scope_idx];
- vd->is_captured = 1;
- get_closure_var(ctx, s, fd, false, scope_idx,
- vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
- scope_idx = vd->scope_next;
- }
- is_arg_scope = (scope_idx == ARG_SCOPE_END);
- if (!is_arg_scope) {
- /* add unscoped variables */
- /* XXX: propagate is_const and var_kind too ? */
- for(i = 0; i < fd->arg_count; i++) {
- vd = &fd->args[i];
- if (vd->var_name != JS_ATOM_NULL) {
- get_closure_var(ctx, s, fd,
- true, i, vd->var_name, false,
- vd->is_lexical, JS_VAR_NORMAL);
- }
- }
- for(i = 0; i < fd->var_count; i++) {
- vd = &fd->vars[i];
- /* do not close top level last result */
- if (vd->scope_level == 0 &&
- vd->var_name != JS_ATOM__ret_ &&
- vd->var_name != JS_ATOM_NULL) {
- get_closure_var(ctx, s, fd,
- false, i, vd->var_name, false,
- vd->is_lexical, JS_VAR_NORMAL);
- }
- }
- } else {
- for(i = 0; i < fd->var_count; i++) {
- vd = &fd->vars[i];
- /* do not close top level last result */
- if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
- get_closure_var(ctx, s, fd,
- false, i, vd->var_name, false,
- vd->is_lexical, JS_VAR_NORMAL);
- }
- }
- }
- if (fd->is_eval) {
- int idx;
- /* add direct eval variables (we are necessarily at the
- top level) */
- for (idx = 0; idx < fd->closure_var_count; idx++) {
- JSClosureVar *cv = &fd->closure_var[idx];
- get_closure_var2(ctx, s, fd,
- false, cv->is_arg,
- idx, cv->var_name, cv->is_const,
- cv->is_lexical, cv->var_kind);
- }
- }
- }
- }
- static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
- JSVarDef *vd, int var_idx)
- {
- cv->is_local = true;
- cv->is_arg = false;
- cv->is_const = vd->is_const;
- cv->is_lexical = vd->is_lexical;
- cv->var_kind = vd->var_kind;
- cv->var_idx = var_idx;
- cv->var_name = JS_DupAtom(ctx, vd->var_name);
- }
- /* for direct eval compilation: add references to the variables of the
- calling function */
- static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
- JSFunctionBytecode *b, int scope_idx)
- {
- int i, count;
- JSVarDef *vd;
- bool is_arg_scope;
- count = b->arg_count + b->var_count + b->closure_var_count;
- s->closure_var = NULL;
- s->closure_var_count = 0;
- s->closure_var_size = count;
- if (count == 0)
- return 0;
- s->closure_var = js_malloc(ctx, sizeof(s->closure_var[0]) * count);
- if (!s->closure_var)
- return -1;
- /* Add lexical variables in scope at the point of evaluation */
- for (i = scope_idx; i >= 0;) {
- vd = &b->vardefs[b->arg_count + i];
- if (vd->scope_level > 0) {
- JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
- set_closure_from_var(ctx, cv, vd, i);
- }
- i = vd->scope_next;
- }
- is_arg_scope = (i == ARG_SCOPE_END);
- if (!is_arg_scope) {
- /* Add argument variables */
- for(i = 0; i < b->arg_count; i++) {
- JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
- vd = &b->vardefs[i];
- cv->is_local = true;
- cv->is_arg = true;
- cv->is_const = false;
- cv->is_lexical = false;
- cv->var_kind = JS_VAR_NORMAL;
- cv->var_idx = i;
- cv->var_name = JS_DupAtom(ctx, vd->var_name);
- }
- /* Add local non lexical variables */
- for(i = 0; i < b->var_count; i++) {
- vd = &b->vardefs[b->arg_count + i];
- if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) {
- JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
- set_closure_from_var(ctx, cv, vd, i);
- }
- }
- } else {
- /* only add pseudo variables */
- for(i = 0; i < b->var_count; i++) {
- vd = &b->vardefs[b->arg_count + i];
- if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
- JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
- set_closure_from_var(ctx, cv, vd, i);
- }
- }
- }
- for(i = 0; i < b->closure_var_count; i++) {
- JSClosureVar *cv0 = &b->closure_var[i];
- JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
- cv->is_local = false;
- cv->is_arg = cv0->is_arg;
- cv->is_const = cv0->is_const;
- cv->is_lexical = cv0->is_lexical;
- cv->var_kind = cv0->var_kind;
- cv->var_idx = i;
- cv->var_name = JS_DupAtom(ctx, cv0->var_name);
- }
- return 0;
- }
- typedef struct CodeContext {
- const uint8_t *bc_buf; /* code buffer */
- int bc_len; /* length of the code buffer */
- int pos; /* position past the matched code pattern */
- int line_num; /* last visited OP_source_loc parameter or -1 */
- int col_num; /* last visited OP_source_loc parameter or -1 */
- int op;
- int idx;
- int label;
- int val;
- JSAtom atom;
- } CodeContext;
- #define M2(op1, op2) ((uint32_t)(op1) | ((uint32_t)(op2) << 8))
- #define M3(op1, op2, op3) ((uint32_t)(op1) | ((uint32_t)(op2) << 8) | ((uint32_t)(op3) << 16))
- #define M4(op1, op2, op3, op4) ((uint32_t)(op1) | ((uint32_t)(op2) << 8) | ((uint32_t)(op3) << 16) | ((uint32_t)(op4) << 24))
- static bool code_match(CodeContext *s, int pos, ...)
- {
- const uint8_t *tab = s->bc_buf;
- int op, len, op1, line_num, col_num, pos_next;
- va_list ap;
- bool ret = false;
- line_num = -1;
- col_num = -1;
- va_start(ap, pos);
- for(;;) {
- op1 = va_arg(ap, int);
- if (op1 == -1) {
- s->pos = pos;
- s->line_num = line_num;
- s->col_num = col_num;
- ret = true;
- break;
- }
- for (;;) {
- if (pos >= s->bc_len)
- goto done;
- op = tab[pos];
- len = opcode_info[op].size;
- pos_next = pos + len;
- if (pos_next > s->bc_len)
- goto done;
- if (op == OP_source_loc) {
- line_num = get_u32(tab + pos + 1);
- col_num = get_u32(tab + pos + 5);
- pos = pos_next;
- } else {
- break;
- }
- }
- if (op != op1) {
- if (op1 == (uint8_t)op1 || !op)
- break;
- if (op != (uint8_t)op1
- && op != (uint8_t)(op1 >> 8)
- && op != (uint8_t)(op1 >> 16)
- && op != (uint8_t)(op1 >> 24)) {
- break;
- }
- s->op = op;
- }
- pos++;
- switch(opcode_info[op].fmt) {
- case OP_FMT_loc8:
- case OP_FMT_u8:
- {
- int idx = tab[pos];
- int arg = va_arg(ap, int);
- if (arg == -1) {
- s->idx = idx;
- } else {
- if (arg != idx)
- goto done;
- }
- break;
- }
- case OP_FMT_u16:
- case OP_FMT_npop:
- case OP_FMT_loc:
- case OP_FMT_arg:
- case OP_FMT_var_ref:
- {
- int idx = get_u16(tab + pos);
- int arg = va_arg(ap, int);
- if (arg == -1) {
- s->idx = idx;
- } else {
- if (arg != idx)
- goto done;
- }
- break;
- }
- case OP_FMT_i32:
- case OP_FMT_u32:
- case OP_FMT_label:
- case OP_FMT_const:
- {
- s->label = get_u32(tab + pos);
- break;
- }
- case OP_FMT_label_u16:
- {
- s->label = get_u32(tab + pos);
- s->val = get_u16(tab + pos + 4);
- break;
- }
- case OP_FMT_atom:
- {
- s->atom = get_u32(tab + pos);
- break;
- }
- case OP_FMT_atom_u8:
- {
- s->atom = get_u32(tab + pos);
- s->val = get_u8(tab + pos + 4);
- break;
- }
- case OP_FMT_atom_u16:
- {
- s->atom = get_u32(tab + pos);
- s->val = get_u16(tab + pos + 4);
- break;
- }
- case OP_FMT_atom_label_u8:
- {
- s->atom = get_u32(tab + pos);
- s->label = get_u32(tab + pos + 4);
- s->val = get_u8(tab + pos + 8);
- break;
- }
- default:
- break;
- }
- pos = pos_next;
- }
- done:
- va_end(ap);
- return ret;
- }
- static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc)
- {
- int i, idx, label_next = -1;
- /* add the hoisted functions in arguments and local variables */
- for(i = 0; i < s->arg_count; i++) {
- JSVarDef *vd = &s->args[i];
- if (vd->func_pool_idx >= 0) {
- dbuf_putc(bc, OP_fclosure);
- dbuf_put_u32(bc, vd->func_pool_idx);
- dbuf_putc(bc, OP_put_arg);
- dbuf_put_u16(bc, i);
- }
- }
- for(i = 0; i < s->var_count; i++) {
- JSVarDef *vd = &s->vars[i];
- if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {
- dbuf_putc(bc, OP_fclosure);
- dbuf_put_u32(bc, vd->func_pool_idx);
- dbuf_putc(bc, OP_put_loc);
- dbuf_put_u16(bc, i);
- }
- }
- /* the module global variables must be initialized before
- evaluating the module so that the exported functions are
- visible if there are cyclic module references */
- if (s->module) {
- label_next = new_label_fd(s);
- if (label_next < 0) {
- dbuf_set_error(bc);
- return;
- }
- /* if 'this' is true, initialize the global variables and return */
- dbuf_putc(bc, OP_push_this);
- dbuf_putc(bc, OP_if_false);
- dbuf_put_u32(bc, label_next);
- update_label(s, label_next, 1);
- s->jump_size++;
- }
- /* add the global variables (only happens if s->is_global_var is
- true) */
- for(i = 0; i < s->global_var_count; i++) {
- JSGlobalVar *hf = &s->global_vars[i];
- int has_closure = 0;
- bool force_init = hf->force_init;
- /* we are in an eval, so the closure contains all the
- enclosing variables */
- /* If the outer function has a variable environment,
- create a property for the variable there */
- for(idx = 0; idx < s->closure_var_count; idx++) {
- JSClosureVar *cv = &s->closure_var[idx];
- if (cv->var_name == hf->var_name) {
- has_closure = 2;
- force_init = false;
- break;
- }
- if (cv->var_name == JS_ATOM__var_ ||
- cv->var_name == JS_ATOM__arg_var_) {
- dbuf_putc(bc, OP_get_var_ref);
- dbuf_put_u16(bc, idx);
- has_closure = 1;
- force_init = true;
- break;
- }
- }
- if (!has_closure) {
- int flags;
- flags = 0;
- if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
- flags |= JS_PROP_CONFIGURABLE;
- if (hf->cpool_idx >= 0 && !hf->is_lexical) {
- /* global function definitions need a specific handling */
- dbuf_putc(bc, OP_fclosure);
- dbuf_put_u32(bc, hf->cpool_idx);
- dbuf_putc(bc, OP_define_func);
- dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
- dbuf_putc(bc, flags);
- goto done_global_var;
- } else {
- if (hf->is_lexical) {
- flags |= DEFINE_GLOBAL_LEX_VAR;
- if (!hf->is_const)
- flags |= JS_PROP_WRITABLE;
- }
- dbuf_putc(bc, OP_define_var);
- dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
- dbuf_putc(bc, flags);
- }
- }
- if (hf->cpool_idx >= 0 || force_init) {
- if (hf->cpool_idx >= 0) {
- dbuf_putc(bc, OP_fclosure);
- dbuf_put_u32(bc, hf->cpool_idx);
- if (hf->var_name == JS_ATOM__default_) {
- /* set default export function name */
- dbuf_putc(bc, OP_set_name);
- dbuf_put_u32(bc, JS_DupAtom(ctx, JS_ATOM_default));
- }
- } else {
- dbuf_putc(bc, OP_undefined);
- }
- if (has_closure == 2) {
- dbuf_putc(bc, OP_put_var_ref);
- dbuf_put_u16(bc, idx);
- } else if (has_closure == 1) {
- dbuf_putc(bc, OP_define_field);
- dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
- dbuf_putc(bc, OP_drop);
- } else {
- /* XXX: Check if variable is writable and enumerable */
- dbuf_putc(bc, OP_put_var);
- dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
- }
- }
- done_global_var:
- JS_FreeAtom(ctx, hf->var_name);
- }
- if (s->module) {
- dbuf_putc(bc, OP_return_undef);
- dbuf_putc(bc, OP_label);
- dbuf_put_u32(bc, label_next);
- s->label_slots[label_next].pos2 = bc->size;
- }
- js_free(ctx, s->global_vars);
- s->global_vars = NULL;
- s->global_var_count = 0;
- s->global_var_size = 0;
- }
- static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len,
- int pos, int *linep, int *colp)
- {
- int op, len, label;
- for (; pos < bc_len; pos += len) {
- op = bc_buf[pos];
- len = opcode_info[op].size;
- if (op == OP_source_loc) {
- *linep = get_u32(bc_buf + pos + 1);
- *colp = get_u32(bc_buf + pos + 5);
- } else if (op == OP_label) {
- label = get_u32(bc_buf + pos + 1);
- if (update_label(s, label, 0) > 0)
- break;
- assert(s->label_slots[label].first_reloc == NULL);
- } else {
- /* XXX: output a warning for unreachable code? */
- JSAtom atom;
- switch(opcode_info[op].fmt) {
- case OP_FMT_label:
- case OP_FMT_label_u16:
- label = get_u32(bc_buf + pos + 1);
- update_label(s, label, -1);
- break;
- case OP_FMT_atom_label_u8:
- case OP_FMT_atom_label_u16:
- label = get_u32(bc_buf + pos + 5);
- update_label(s, label, -1);
- /* fall thru */
- case OP_FMT_atom:
- case OP_FMT_atom_u8:
- case OP_FMT_atom_u16:
- atom = get_u32(bc_buf + pos + 1);
- JS_FreeAtom(s->ctx, atom);
- break;
- default:
- break;
- }
- }
- }
- return pos;
- }
- static int get_label_pos(JSFunctionDef *s, int label)
- {
- int i, pos;
- for (i = 0; i < 20; i++) {
- pos = s->label_slots[label].pos;
- for (;;) {
- switch (s->byte_code.buf[pos]) {
- case OP_source_loc:
- pos += 9;
- continue;
- case OP_label:
- pos += 5;
- continue;
- case OP_goto:
- label = get_u32(s->byte_code.buf + pos + 1);
- break;
- default:
- return pos;
- }
- break;
- }
- }
- return pos;
- }
- /* convert global variable accesses to local variables or closure
- variables when necessary */
- static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
- {
- int pos, pos_next, bc_len, op, len, i, idx, line_num, col_num;
- uint8_t *bc_buf;
- JSAtom var_name;
- DynBuf bc_out;
- CodeContext cc;
- int scope;
- cc.bc_buf = bc_buf = s->byte_code.buf;
- cc.bc_len = bc_len = s->byte_code.size;
- js_dbuf_init(ctx, &bc_out);
- /* first pass for runtime checks (must be done before the
- variables are created) */
- for(i = 0; i < s->global_var_count; i++) {
- JSGlobalVar *hf = &s->global_vars[i];
- int flags;
- /* check if global variable (XXX: simplify) */
- for(idx = 0; idx < s->closure_var_count; idx++) {
- JSClosureVar *cv = &s->closure_var[idx];
- if (cv->var_name == hf->var_name) {
- if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
- cv->is_lexical) {
- /* Check if a lexical variable is
- redefined as 'var'. XXX: Could abort
- compilation here, but for consistency
- with the other checks, we delay the
- error generation. */
- dbuf_putc(&bc_out, OP_throw_error);
- dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
- dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);
- }
- goto next;
- }
- if (cv->var_name == JS_ATOM__var_ ||
- cv->var_name == JS_ATOM__arg_var_)
- goto next;
- }
- dbuf_putc(&bc_out, OP_check_define_var);
- dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
- flags = 0;
- if (hf->is_lexical)
- flags |= DEFINE_GLOBAL_LEX_VAR;
- if (hf->cpool_idx >= 0)
- flags |= DEFINE_GLOBAL_FUNC_VAR;
- dbuf_putc(&bc_out, flags);
- next: ;
- }
- line_num = 0; /* avoid warning */
- col_num = 0;
- for (pos = 0; pos < bc_len; pos = pos_next) {
- op = bc_buf[pos];
- len = opcode_info[op].size;
- pos_next = pos + len;
- switch(op) {
- case OP_source_loc:
- line_num = get_u32(bc_buf + pos + 1);
- col_num = get_u32(bc_buf + pos + 5);
- s->source_loc_size++;
- goto no_change;
- case OP_eval: /* convert scope index to adjusted variable index */
- {
- int call_argc = get_u16(bc_buf + pos + 1);
- scope = get_u16(bc_buf + pos + 1 + 2);
- mark_eval_captured_variables(ctx, s, scope);
- dbuf_putc(&bc_out, op);
- dbuf_put_u16(&bc_out, call_argc);
- dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
- }
- break;
- case OP_apply_eval: /* convert scope index to adjusted variable index */
- scope = get_u16(bc_buf + pos + 1);
- mark_eval_captured_variables(ctx, s, scope);
- dbuf_putc(&bc_out, op);
- dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
- break;
- case OP_scope_get_var_undef:
- case OP_scope_get_var:
- case OP_scope_put_var:
- case OP_scope_delete_var:
- case OP_scope_get_ref:
- case OP_scope_put_var_init:
- var_name = get_u32(bc_buf + pos + 1);
- scope = get_u16(bc_buf + pos + 5);
- pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
- NULL, NULL, pos_next);
- JS_FreeAtom(ctx, var_name);
- break;
- case OP_scope_make_ref:
- {
- int label;
- LabelSlot *ls;
- var_name = get_u32(bc_buf + pos + 1);
- label = get_u32(bc_buf + pos + 5);
- scope = get_u16(bc_buf + pos + 9);
- ls = &s->label_slots[label];
- ls->ref_count--; /* always remove label reference */
- pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
- bc_buf, ls, pos_next);
- JS_FreeAtom(ctx, var_name);
- }
- break;
- case OP_scope_get_private_field:
- case OP_scope_get_private_field2:
- case OP_scope_put_private_field:
- case OP_scope_in_private_field:
- {
- int ret;
- var_name = get_u32(bc_buf + pos + 1);
- scope = get_u16(bc_buf + pos + 5);
- ret = resolve_scope_private_field(ctx, s, var_name, scope, op, &bc_out);
- if (ret < 0)
- goto fail;
- JS_FreeAtom(ctx, var_name);
- }
- break;
- case OP_gosub:
- s->jump_size++;
- {
- /* remove calls to empty finalizers */
- int label;
- LabelSlot *ls;
- label = get_u32(bc_buf + pos + 1);
- assert(label >= 0 && label < s->label_count);
- ls = &s->label_slots[label];
- if (code_match(&cc, ls->pos, OP_ret, -1)) {
- ls->ref_count--;
- break;
- }
- }
- goto no_change;
- case OP_insert3:
- /* Transformation: insert3 put_array_el|put_ref_value drop -> put_array_el|put_ref_value */
- if (code_match(&cc, pos_next, M2(OP_put_array_el, OP_put_ref_value), OP_drop, -1)) {
- dbuf_putc(&bc_out, cc.op);
- pos_next = cc.pos;
- if (cc.line_num == -1)
- break;
- if (cc.line_num != line_num || cc.col_num != col_num) {
- line_num = cc.line_num;
- col_num = cc.col_num;
- s->source_loc_size++;
- dbuf_putc(&bc_out, OP_source_loc);
- dbuf_put_u32(&bc_out, line_num);
- dbuf_put_u32(&bc_out, col_num);
- }
- break;
- }
- goto no_change;
- case OP_goto:
- s->jump_size++;
- /* fall thru */
- case OP_tail_call:
- case OP_tail_call_method:
- case OP_return:
- case OP_return_undef:
- case OP_throw:
- case OP_throw_error:
- case OP_ret:
- {
- /* remove dead code */
- int line = -1;
- int col = -1;
- dbuf_put(&bc_out, bc_buf + pos, len);
- pos = skip_dead_code(s, bc_buf, bc_len, pos + len,
- &line, &col);
- pos_next = pos;
- if (line < 0 || pos >= bc_len)
- break;
- if (line_num != line || col_num != col) {
- line_num = line;
- col_num = col;
- s->source_loc_size++;
- dbuf_putc(&bc_out, OP_source_loc);
- dbuf_put_u32(&bc_out, line_num);
- dbuf_put_u32(&bc_out, col_num);
- }
- break;
- }
- goto no_change;
- case OP_label:
- {
- int label;
- LabelSlot *ls;
- label = get_u32(bc_buf + pos + 1);
- assert(label >= 0 && label < s->label_count);
- ls = &s->label_slots[label];
- ls->pos2 = bc_out.size + opcode_info[op].size;
- }
- goto no_change;
- case OP_enter_scope:
- {
- int scope_idx, scope = get_u16(bc_buf + pos + 1);
- if (scope == s->body_scope) {
- instantiate_hoisted_definitions(ctx, s, &bc_out);
- }
- for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
- JSVarDef *vd = &s->vars[scope_idx];
- if (vd->scope_level == scope) {
- if (scope_idx != s->arguments_arg_idx) {
- if (vd->var_kind == JS_VAR_FUNCTION_DECL ||
- vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {
- /* Initialize lexical variable upon entering scope */
- dbuf_putc(&bc_out, OP_fclosure);
- dbuf_put_u32(&bc_out, vd->func_pool_idx);
- dbuf_putc(&bc_out, OP_put_loc);
- dbuf_put_u16(&bc_out, scope_idx);
- } else {
- /* XXX: should check if variable can be used
- before initialization */
- dbuf_putc(&bc_out, OP_set_loc_uninitialized);
- dbuf_put_u16(&bc_out, scope_idx);
- }
- }
- scope_idx = vd->scope_next;
- } else {
- break;
- }
- }
- }
- break;
- case OP_leave_scope:
- {
- int scope_idx, scope = get_u16(bc_buf + pos + 1);
- for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
- JSVarDef *vd = &s->vars[scope_idx];
- if (vd->scope_level == scope) {
- if (vd->is_captured) {
- dbuf_putc(&bc_out, OP_close_loc);
- dbuf_put_u16(&bc_out, scope_idx);
- }
- scope_idx = vd->scope_next;
- } else {
- break;
- }
- }
- }
- break;
- case OP_set_name:
- {
- /* remove dummy set_name opcodes */
- JSAtom name = get_u32(bc_buf + pos + 1);
- if (name == JS_ATOM_NULL)
- break;
- }
- goto no_change;
- case OP_if_false:
- case OP_if_true:
- case OP_catch:
- s->jump_size++;
- goto no_change;
- case OP_dup:
- /* Transformation: dup if_false(l1) drop, l1: if_false(l2) -> if_false(l2) */
- /* Transformation: dup if_true(l1) drop, l1: if_true(l2) -> if_true(l2) */
- if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), OP_drop, -1)) {
- int lab0, lab1, op1, pos1, line1, col1, pos2;
- lab0 = lab1 = cc.label;
- assert(lab1 >= 0 && lab1 < s->label_count);
- op1 = cc.op;
- pos1 = cc.pos;
- line1 = cc.line_num;
- col1 = cc.col_num;
- while (code_match(&cc, (pos2 = get_label_pos(s, lab1)), OP_dup, op1, OP_drop, -1)) {
- lab1 = cc.label;
- }
- if (code_match(&cc, pos2, op1, -1)) {
- s->jump_size++;
- update_label(s, lab0, -1);
- update_label(s, cc.label, +1);
- dbuf_putc(&bc_out, op1);
- dbuf_put_u32(&bc_out, cc.label);
- pos_next = pos1;
- if (line1 == -1)
- break;
- if (line1 != line_num || col1 != col_num) {
- line_num = line1;
- col_num = col1;
- s->source_loc_size++;
- dbuf_putc(&bc_out, OP_source_loc);
- dbuf_put_u32(&bc_out, line_num);
- dbuf_put_u32(&bc_out, col_num);
- }
- break;
- }
- }
- goto no_change;
- case OP_nop:
- /* remove erased code */
- break;
- case OP_set_class_name:
- /* only used during parsing */
- break;
- case OP_get_field_opt_chain: /* equivalent to OP_get_field */
- {
- JSAtom name = get_u32(bc_buf + pos + 1);
- dbuf_putc(&bc_out, OP_get_field);
- dbuf_put_u32(&bc_out, name);
- }
- break;
- case OP_get_array_el_opt_chain: /* equivalent to OP_get_array_el */
- dbuf_putc(&bc_out, OP_get_array_el);
- break;
- default:
- no_change:
- dbuf_put(&bc_out, bc_buf + pos, len);
- break;
- }
- }
- /* set the new byte code */
- dbuf_free(&s->byte_code);
- s->byte_code = bc_out;
- if (dbuf_error(&s->byte_code)) {
- JS_ThrowOutOfMemory(ctx);
- return -1;
- }
- return 0;
- fail:
- /* continue the copy to keep the atom refcounts consistent */
- /* XXX: find a better solution ? */
- for (; pos < bc_len; pos = pos_next) {
- op = bc_buf[pos];
- len = opcode_info[op].size;
- pos_next = pos + len;
- dbuf_put(&bc_out, bc_buf + pos, len);
- }
- dbuf_free(&s->byte_code);
- s->byte_code = bc_out;
- return -1;
- }
- /* the pc2line table gives a line number for each PC value */
- static void add_pc2line_info(JSFunctionDef *s, uint32_t pc,
- int line_num, int col_num)
- {
- if (s->source_loc_slots == NULL)
- return;
- if (s->source_loc_count >= s->source_loc_size)
- return;
- if (pc < s->line_number_last_pc)
- return;
- if (line_num == s->line_number_last)
- if (col_num == s->col_number_last)
- return;
- s->source_loc_slots[s->source_loc_count].pc = pc;
- s->source_loc_slots[s->source_loc_count].line_num = line_num;
- s->source_loc_slots[s->source_loc_count].col_num = col_num;
- s->source_loc_count++;
- s->line_number_last_pc = pc;
- s->line_number_last = line_num;
- s->col_number_last = col_num;
- }
- static void compute_pc2line_info(JSFunctionDef *s)
- {
- if (s->source_loc_slots) {
- int last_line_num = s->line_num;
- int last_col_num = s->col_num;
- uint32_t last_pc = 0;
- int i;
- js_dbuf_init(s->ctx, &s->pc2line);
- for (i = 0; i < s->source_loc_count; i++) {
- uint32_t pc = s->source_loc_slots[i].pc;
- int line_num = s->source_loc_slots[i].line_num;
- int col_num = s->source_loc_slots[i].col_num;
- int diff_pc, diff_line, diff_col;
- if (line_num < 0)
- continue;
- diff_pc = pc - last_pc;
- if (diff_pc < 0)
- continue;
- diff_line = line_num - last_line_num;
- diff_col = col_num - last_col_num;
- if (diff_line == 0 && diff_col == 0)
- continue;
- if (diff_line >= PC2LINE_BASE &&
- diff_line < PC2LINE_BASE + PC2LINE_RANGE &&
- diff_pc <= PC2LINE_DIFF_PC_MAX) {
- dbuf_putc(&s->pc2line, (diff_line - PC2LINE_BASE) +
- diff_pc * PC2LINE_RANGE + PC2LINE_OP_FIRST);
- } else {
- /* longer encoding */
- dbuf_putc(&s->pc2line, 0);
- dbuf_put_leb128(&s->pc2line, diff_pc);
- dbuf_put_sleb128(&s->pc2line, diff_line);
- }
- dbuf_put_sleb128(&s->pc2line, diff_col);
- last_pc = pc;
- last_line_num = line_num;
- last_col_num = col_num;
- }
- }
- }
- static RelocEntry *add_reloc(JSContext *ctx, LabelSlot *ls, uint32_t addr, int size)
- {
- RelocEntry *re;
- re = js_malloc(ctx, sizeof(*re));
- if (!re)
- return NULL;
- re->addr = addr;
- re->size = size;
- re->next = ls->first_reloc;
- ls->first_reloc = re;
- return re;
- }
- static bool code_has_label(CodeContext *s, int pos, int label)
- {
- while (pos < s->bc_len) {
- int op = s->bc_buf[pos];
- if (op == OP_source_loc) {
- pos += 9;
- continue;
- }
- if (op == OP_label) {
- int lab = get_u32(s->bc_buf + pos + 1);
- if (lab == label)
- return true;
- pos += 5;
- continue;
- }
- if (op == OP_goto) {
- int lab = get_u32(s->bc_buf + pos + 1);
- if (lab == label)
- return true;
- }
- break;
- }
- return false;
- }
- /* return the target label, following the OP_goto jumps
- the first opcode at destination is stored in *pop
- */
- static int find_jump_target(JSFunctionDef *s, int label, int *pop)
- {
- int i, pos, op;
- update_label(s, label, -1);
- for (i = 0; i < 10; i++) {
- assert(label >= 0 && label < s->label_count);
- pos = s->label_slots[label].pos2;
- for (;;) {
- switch(op = s->byte_code.buf[pos]) {
- case OP_source_loc:
- case OP_label:
- pos += opcode_info[op].size;
- continue;
- case OP_goto:
- label = get_u32(s->byte_code.buf + pos + 1);
- break;
- case OP_drop:
- /* ignore drop opcodes if followed by OP_return_undef */
- while (s->byte_code.buf[++pos] == OP_drop)
- continue;
- if (s->byte_code.buf[pos] == OP_return_undef)
- op = OP_return_undef;
- /* fall thru */
- default:
- goto done;
- }
- break;
- }
- }
- /* cycle detected, could issue a warning */
- done:
- *pop = op;
- update_label(s, label, +1);
- return label;
- }
- static void push_short_int(DynBuf *bc_out, int val)
- {
- if (val >= -1 && val <= 7) {
- dbuf_putc(bc_out, OP_push_0 + val);
- return;
- }
- if (val == (int8_t)val) {
- dbuf_putc(bc_out, OP_push_i8);
- dbuf_putc(bc_out, val);
- return;
- }
- if (val == (int16_t)val) {
- dbuf_putc(bc_out, OP_push_i16);
- dbuf_put_u16(bc_out, val);
- return;
- }
- dbuf_putc(bc_out, OP_push_i32);
- dbuf_put_u32(bc_out, val);
- }
- static void put_short_code(DynBuf *bc_out, int op, int idx)
- {
- if (idx < 4) {
- switch (op) {
- case OP_get_loc:
- dbuf_putc(bc_out, OP_get_loc0 + idx);
- return;
- case OP_put_loc:
- dbuf_putc(bc_out, OP_put_loc0 + idx);
- return;
- case OP_set_loc:
- dbuf_putc(bc_out, OP_set_loc0 + idx);
- return;
- case OP_get_arg:
- dbuf_putc(bc_out, OP_get_arg0 + idx);
- return;
- case OP_put_arg:
- dbuf_putc(bc_out, OP_put_arg0 + idx);
- return;
- case OP_set_arg:
- dbuf_putc(bc_out, OP_set_arg0 + idx);
- return;
- case OP_get_var_ref:
- dbuf_putc(bc_out, OP_get_var_ref0 + idx);
- return;
- case OP_put_var_ref:
- dbuf_putc(bc_out, OP_put_var_ref0 + idx);
- return;
- case OP_set_var_ref:
- dbuf_putc(bc_out, OP_set_var_ref0 + idx);
- return;
- case OP_call:
- dbuf_putc(bc_out, OP_call0 + idx);
- return;
- }
- }
- if (idx < 256) {
- switch (op) {
- case OP_get_loc:
- dbuf_putc(bc_out, OP_get_loc8);
- dbuf_putc(bc_out, idx);
- return;
- case OP_put_loc:
- dbuf_putc(bc_out, OP_put_loc8);
- dbuf_putc(bc_out, idx);
- return;
- case OP_set_loc:
- dbuf_putc(bc_out, OP_set_loc8);
- dbuf_putc(bc_out, idx);
- return;
- }
- }
- dbuf_putc(bc_out, op);
- dbuf_put_u16(bc_out, idx);
- }
- /* peephole optimizations and resolve goto/labels */
- static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
- {
- int pos, pos_next, bc_len, op, op1, len, i, line_num, col_num, patch_offsets;
- const uint8_t *bc_buf;
- DynBuf bc_out;
- LabelSlot *label_slots, *ls;
- RelocEntry *re, *re_next;
- CodeContext cc;
- int label;
- JumpSlot *jp;
- label_slots = s->label_slots;
- line_num = s->line_num;
- col_num = s->col_num;
- cc.bc_buf = bc_buf = s->byte_code.buf;
- cc.bc_len = bc_len = s->byte_code.size;
- js_dbuf_init(ctx, &bc_out);
- if (s->jump_size) {
- s->jump_slots = js_mallocz(s->ctx, sizeof(*s->jump_slots) * s->jump_size);
- if (s->jump_slots == NULL)
- return -1;
- }
- if (s->source_loc_size) {
- s->source_loc_slots = js_mallocz(s->ctx, sizeof(*s->source_loc_slots) * s->source_loc_size);
- if (s->source_loc_slots == NULL)
- return -1;
- s->line_number_last = s->line_num;
- s->col_number_last = s->col_num;
- s->line_number_last_pc = 0;
- }
- /* initialize the 'home_object' variable if needed */
- if (s->home_object_var_idx >= 0) {
- dbuf_putc(&bc_out, OP_special_object);
- dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_HOME_OBJECT);
- put_short_code(&bc_out, OP_put_loc, s->home_object_var_idx);
- }
- /* initialize the 'this.active_func' variable if needed */
- if (s->this_active_func_var_idx >= 0) {
- dbuf_putc(&bc_out, OP_special_object);
- dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
- put_short_code(&bc_out, OP_put_loc, s->this_active_func_var_idx);
- }
- /* initialize the 'new.target' variable if needed */
- if (s->new_target_var_idx >= 0) {
- dbuf_putc(&bc_out, OP_special_object);
- dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_NEW_TARGET);
- put_short_code(&bc_out, OP_put_loc, s->new_target_var_idx);
- }
- /* initialize the 'this' variable if needed. In a derived class
- constructor, this is initially uninitialized. */
- if (s->this_var_idx >= 0) {
- if (s->is_derived_class_constructor) {
- dbuf_putc(&bc_out, OP_set_loc_uninitialized);
- dbuf_put_u16(&bc_out, s->this_var_idx);
- } else {
- dbuf_putc(&bc_out, OP_push_this);
- put_short_code(&bc_out, OP_put_loc, s->this_var_idx);
- }
- }
- /* initialize the 'arguments' variable if needed */
- if (s->arguments_var_idx >= 0) {
- if (s->is_strict_mode || !s->has_simple_parameter_list) {
- dbuf_putc(&bc_out, OP_special_object);
- dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_ARGUMENTS);
- } else {
- dbuf_putc(&bc_out, OP_special_object);
- dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);
- }
- if (s->arguments_arg_idx >= 0)
- put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
- put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx);
- }
- /* initialize a reference to the current function if needed */
- if (s->func_var_idx >= 0) {
- dbuf_putc(&bc_out, OP_special_object);
- dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
- put_short_code(&bc_out, OP_put_loc, s->func_var_idx);
- }
- /* initialize the variable environment object if needed */
- if (s->var_object_idx >= 0) {
- dbuf_putc(&bc_out, OP_special_object);
- dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
- put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
- }
- if (s->arg_var_object_idx >= 0) {
- dbuf_putc(&bc_out, OP_special_object);
- dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
- put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx);
- }
- for (pos = 0; pos < bc_len; pos = pos_next) {
- int val;
- op = bc_buf[pos];
- len = opcode_info[op].size;
- pos_next = pos + len;
- switch(op) {
- case OP_source_loc:
- /* line number info (for debug). We put it in a separate
- compressed table to reduce memory usage and get better
- performance */
- line_num = get_u32(bc_buf + pos + 1);
- col_num = get_u32(bc_buf + pos + 5);
- break;
- case OP_label:
- {
- label = get_u32(bc_buf + pos + 1);
- assert(label >= 0 && label < s->label_count);
- ls = &label_slots[label];
- assert(ls->addr == -1);
- ls->addr = bc_out.size;
- /* resolve the relocation entries */
- for(re = ls->first_reloc; re != NULL; re = re_next) {
- int diff = ls->addr - re->addr;
- re_next = re->next;
- switch (re->size) {
- case 4:
- put_u32(bc_out.buf + re->addr, diff);
- break;
- case 2:
- assert(diff == (int16_t)diff);
- put_u16(bc_out.buf + re->addr, diff);
- break;
- case 1:
- assert(diff == (int8_t)diff);
- put_u8(bc_out.buf + re->addr, diff);
- break;
- }
- js_free(ctx, re);
- }
- ls->first_reloc = NULL;
- }
- break;
- case OP_call:
- case OP_call_method:
- {
- /* detect and transform tail calls */
- int argc;
- argc = get_u16(bc_buf + pos + 1);
- if (code_match(&cc, pos_next, OP_return, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- put_short_code(&bc_out, op + 1, argc);
- pos_next = skip_dead_code(s, bc_buf, bc_len, cc.pos,
- &line_num, &col_num);
- break;
- }
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- put_short_code(&bc_out, op, argc);
- break;
- }
- goto no_change;
- case OP_return:
- case OP_return_undef:
- case OP_return_async:
- case OP_throw:
- case OP_throw_error:
- pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next,
- &line_num, &col_num);
- goto no_change;
- case OP_goto:
- label = get_u32(bc_buf + pos + 1);
- has_goto:
- {
- /* Use custom matcher because multiple labels can follow */
- label = find_jump_target(s, label, &op1);
- if (code_has_label(&cc, pos_next, label)) {
- /* jump to next instruction: remove jump */
- update_label(s, label, -1);
- break;
- }
- if (op1 == OP_return || op1 == OP_return_undef || op1 == OP_throw) {
- /* jump to return/throw: remove jump, append return/throw */
- /* updating the line number obfuscates assembly listing */
- update_label(s, label, -1);
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, op1);
- pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next,
- &line_num, &col_num);
- break;
- }
- /* XXX: should duplicate single instructions followed by goto or return */
- /* For example, can match one of these followed by return:
- push_i32 / push_const / push_atom_value / get_var /
- undefined / null / push_false / push_true / get_ref_value /
- get_loc / get_arg / get_var_ref
- */
- }
- goto has_label;
- case OP_gosub:
- label = get_u32(bc_buf + pos + 1);
- goto has_label;
- case OP_catch:
- label = get_u32(bc_buf + pos + 1);
- goto has_label;
- case OP_if_true:
- case OP_if_false:
- label = get_u32(bc_buf + pos + 1);
- label = find_jump_target(s, label, &op1);
- /* transform if_false/if_true(l1) label(l1) -> drop label(l1) */
- if (code_has_label(&cc, pos_next, label)) {
- update_label(s, label, -1);
- dbuf_putc(&bc_out, OP_drop);
- break;
- }
- /* transform if_false(l1) goto(l2) label(l1) -> if_false(l2) label(l1) */
- if (code_match(&cc, pos_next, OP_goto, -1)) {
- int pos1 = cc.pos;
- int line1 = cc.line_num;
- int col1 = cc.col_num;
- if (code_has_label(&cc, pos1, label)) {
- if (line1 >= 0) line_num = line1;
- if (col1 >= 0) col_num = col1;
- pos_next = pos1;
- update_label(s, label, -1);
- label = cc.label;
- op ^= OP_if_true ^ OP_if_false;
- }
- }
- has_label:
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- if (op == OP_goto) {
- pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next,
- &line_num, &col_num);
- }
- assert(label >= 0 && label < s->label_count);
- ls = &label_slots[label];
- jp = &s->jump_slots[s->jump_count++];
- jp->op = op;
- jp->size = 4;
- jp->pos = bc_out.size + 1;
- jp->label = label;
- if (ls->addr == -1) {
- int diff = ls->pos2 - pos - 1;
- if (diff < 128 && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
- jp->size = 1;
- jp->op = OP_if_false8 + (op - OP_if_false);
- dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
- dbuf_putc(&bc_out, 0);
- if (!add_reloc(ctx, ls, bc_out.size - 1, 1))
- goto fail;
- break;
- }
- if (diff < 32768 && op == OP_goto) {
- jp->size = 2;
- jp->op = OP_goto16;
- dbuf_putc(&bc_out, OP_goto16);
- dbuf_put_u16(&bc_out, 0);
- if (!add_reloc(ctx, ls, bc_out.size - 2, 2))
- goto fail;
- break;
- }
- } else {
- int diff = ls->addr - bc_out.size - 1;
- if (diff == (int8_t)diff && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
- jp->size = 1;
- jp->op = OP_if_false8 + (op - OP_if_false);
- dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
- dbuf_putc(&bc_out, diff);
- break;
- }
- if (diff == (int16_t)diff && op == OP_goto) {
- jp->size = 2;
- jp->op = OP_goto16;
- dbuf_putc(&bc_out, OP_goto16);
- dbuf_put_u16(&bc_out, diff);
- break;
- }
- }
- dbuf_putc(&bc_out, op);
- dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
- if (ls->addr == -1) {
- /* unresolved yet: create a new relocation entry */
- if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
- goto fail;
- }
- break;
- case OP_with_get_var:
- case OP_with_put_var:
- case OP_with_delete_var:
- case OP_with_make_ref:
- case OP_with_get_ref:
- case OP_with_get_ref_undef:
- {
- JSAtom atom;
- int is_with;
- atom = get_u32(bc_buf + pos + 1);
- label = get_u32(bc_buf + pos + 5);
- is_with = bc_buf[pos + 9];
- label = find_jump_target(s, label, &op1);
- assert(label >= 0 && label < s->label_count);
- ls = &label_slots[label];
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- jp = &s->jump_slots[s->jump_count++];
- jp->op = op;
- jp->size = 4;
- jp->pos = bc_out.size + 5;
- jp->label = label;
- dbuf_putc(&bc_out, op);
- dbuf_put_u32(&bc_out, atom);
- dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
- if (ls->addr == -1) {
- /* unresolved yet: create a new relocation entry */
- if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
- goto fail;
- }
- dbuf_putc(&bc_out, is_with);
- }
- break;
- case OP_drop:
- /* remove useless drops before return */
- if (code_match(&cc, pos_next, OP_return_undef, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- break;
- }
- goto no_change;
- case OP_null:
- /* transform null strict_eq into is_null */
- if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_is_null);
- pos_next = cc.pos;
- break;
- }
- /* transform null strict_neq if_false/if_true -> is_null if_true/if_false */
- if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_is_null);
- pos_next = cc.pos;
- label = cc.label;
- op = cc.op ^ OP_if_false ^ OP_if_true;
- goto has_label;
- }
- /* fall thru */
- case OP_push_false:
- case OP_push_true:
- val = (op == OP_push_true);
- if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
- has_constant_test:
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- if (val == cc.op - OP_if_false) {
- /* transform null if_false(l1) -> goto l1 */
- /* transform false if_false(l1) -> goto l1 */
- /* transform true if_true(l1) -> goto l1 */
- pos_next = cc.pos;
- op = OP_goto;
- label = cc.label;
- goto has_goto;
- } else {
- /* transform null if_true(l1) -> nop */
- /* transform false if_true(l1) -> nop */
- /* transform true if_false(l1) -> nop */
- pos_next = cc.pos;
- update_label(s, cc.label, -1);
- break;
- }
- }
- goto no_change;
- case OP_push_i32:
- /* transform i32(val) neg -> i32(-val) */
- val = get_i32(bc_buf + pos + 1);
- if ((val != INT32_MIN && val != 0)
- && code_match(&cc, pos_next, OP_neg, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- if (code_match(&cc, cc.pos, OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- } else {
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- push_short_int(&bc_out, -val);
- }
- pos_next = cc.pos;
- break;
- }
- /* remove push/drop pairs generated by the parser */
- if (code_match(&cc, pos_next, OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- pos_next = cc.pos;
- break;
- }
- /* Optimize constant tests: `if (0)`, `if (1)`, `if (!0)`... */
- if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
- val = (val != 0);
- goto has_constant_test;
- }
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- push_short_int(&bc_out, val);
- break;
- case OP_push_bigint_i32:
- {
- /* transform i32(val) neg -> i32(-val) */
- val = get_i32(bc_buf + pos + 1);
- if (val != INT32_MIN
- && code_match(&cc, pos_next, OP_neg, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- if (code_match(&cc, cc.pos, OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- } else {
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_push_bigint_i32);
- dbuf_put_u32(&bc_out, -val);
- }
- pos_next = cc.pos;
- break;
- }
- }
- goto no_change;
- case OP_push_const:
- case OP_fclosure:
- {
- int idx = get_u32(bc_buf + pos + 1);
- if (idx < 256) {
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_push_const8 + op - OP_push_const);
- dbuf_putc(&bc_out, idx);
- break;
- }
- }
- goto no_change;
- case OP_get_field:
- {
- JSAtom atom = get_u32(bc_buf + pos + 1);
- if (atom == JS_ATOM_length) {
- JS_FreeAtom(ctx, atom);
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_get_length);
- break;
- }
- }
- goto no_change;
- case OP_push_atom_value:
- {
- JSAtom atom = get_u32(bc_buf + pos + 1);
- /* remove push/drop pairs generated by the parser */
- if (code_match(&cc, pos_next, OP_drop, -1)) {
- JS_FreeAtom(ctx, atom);
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- pos_next = cc.pos;
- break;
- }
- if (atom == JS_ATOM_empty_string) {
- JS_FreeAtom(ctx, atom);
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_push_empty_string);
- break;
- }
- }
- goto no_change;
- case OP_to_propkey:
- case OP_to_propkey2:
- /* remove redundant to_propkey/to_propkey2 opcodes when storing simple data */
- if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1)
- || code_match(&cc, pos_next, M3(OP_push_i32, OP_push_const, OP_push_atom_value), OP_put_array_el, -1)
- || code_match(&cc, pos_next, M4(OP_undefined, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) {
- break;
- }
- goto no_change;
- case OP_undefined:
- /* remove push/drop pairs generated by the parser */
- if (code_match(&cc, pos_next, OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- pos_next = cc.pos;
- break;
- }
- /* transform undefined return -> return_undefined */
- if (code_match(&cc, pos_next, OP_return, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_return_undef);
- pos_next = cc.pos;
- break;
- }
- /* transform undefined if_true(l1)/if_false(l1) -> nop/goto(l1) */
- if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
- val = 0;
- goto has_constant_test;
- }
- /* transform undefined strict_eq -> is_undefined */
- if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_is_undefined);
- pos_next = cc.pos;
- break;
- }
- /* transform undefined strict_neq if_false/if_true -> is_undefined if_true/if_false */
- if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_is_undefined);
- pos_next = cc.pos;
- label = cc.label;
- op = cc.op ^ OP_if_false ^ OP_if_true;
- goto has_label;
- }
- goto no_change;
- case OP_insert2:
- /* Transformation:
- insert2 put_field(a) drop -> put_field(a)
- insert2 put_var_strict(a) drop -> put_var_strict(a)
- */
- if (code_match(&cc, pos_next, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, cc.op);
- dbuf_put_u32(&bc_out, cc.atom);
- pos_next = cc.pos;
- break;
- }
- goto no_change;
- case OP_dup:
- {
- /* Transformation: dup put_x(n) drop -> put_x(n) */
- int op1, line2 = -1;
- /* Transformation: dup put_x(n) -> set_x(n) */
- if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- op1 = cc.op + 1; /* put_x -> set_x */
- pos_next = cc.pos;
- if (code_match(&cc, cc.pos, OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- op1 -= 1; /* set_x drop -> put_x */
- pos_next = cc.pos;
- if (code_match(&cc, cc.pos, op1 - 1, cc.idx, -1)) {
- line2 = cc.line_num; /* delay line number update */
- op1 += 1; /* put_x(n) get_x(n) -> set_x(n) */
- pos_next = cc.pos;
- }
- }
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- put_short_code(&bc_out, op1, cc.idx);
- if (line2 >= 0) line_num = line2;
- break;
- }
- }
- goto no_change;
- case OP_swap:
- // transformation: swap swap -> nothing!
- if (code_match(&cc, pos_next, OP_swap, -1, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- pos_next = cc.pos;
- break;
- }
- goto no_change;
- case OP_get_loc:
- {
- /* transformation:
- get_loc(n) post_dec put_loc(n) drop -> dec_loc(n)
- get_loc(n) post_inc put_loc(n) drop -> inc_loc(n)
- get_loc(n) dec dup put_loc(n) drop -> dec_loc(n)
- get_loc(n) inc dup put_loc(n) drop -> inc_loc(n)
- */
- int idx;
- idx = get_u16(bc_buf + pos + 1);
- if (idx >= 256)
- goto no_change;
- if (code_match(&cc, pos_next, M2(OP_post_dec, OP_post_inc), OP_put_loc, idx, OP_drop, -1) ||
- code_match(&cc, pos_next, M2(OP_dec, OP_inc), OP_dup, OP_put_loc, idx, OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, (cc.op == OP_inc || cc.op == OP_post_inc) ? OP_inc_loc : OP_dec_loc);
- dbuf_putc(&bc_out, idx);
- pos_next = cc.pos;
- break;
- }
- /* transformation:
- get_loc(n) push_atom_value(x) add dup put_loc(n) drop -> push_atom_value(x) add_loc(n)
- */
- if (code_match(&cc, pos_next, OP_push_atom_value, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- if (cc.atom == JS_ATOM_empty_string) {
- JS_FreeAtom(ctx, cc.atom);
- dbuf_putc(&bc_out, OP_push_empty_string);
- } else {
- dbuf_putc(&bc_out, OP_push_atom_value);
- dbuf_put_u32(&bc_out, cc.atom);
- }
- dbuf_putc(&bc_out, OP_add_loc);
- dbuf_putc(&bc_out, idx);
- pos_next = cc.pos;
- break;
- }
- /* transformation:
- get_loc(n) push_i32(x) add dup put_loc(n) drop -> push_i32(x) add_loc(n)
- */
- if (code_match(&cc, pos_next, OP_push_i32, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- push_short_int(&bc_out, cc.label);
- dbuf_putc(&bc_out, OP_add_loc);
- dbuf_putc(&bc_out, idx);
- pos_next = cc.pos;
- break;
- }
- /* transformation: XXX: also do these:
- get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x) add_loc(n)
- get_loc(n) get_arg(x) add dup put_loc(n) drop -> get_arg(x) add_loc(n)
- get_loc(n) get_var_ref(x) add dup put_loc(n) drop -> get_var_ref(x) add_loc(n)
- */
- if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- put_short_code(&bc_out, cc.op, cc.idx);
- dbuf_putc(&bc_out, OP_add_loc);
- dbuf_putc(&bc_out, idx);
- pos_next = cc.pos;
- break;
- }
- /* transformation: get_loc(0) get_loc(1) -> get_loc0_loc1 */
- if (idx == 0 && code_match(&cc, pos_next, OP_get_loc, 1, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_get_loc0_loc1);
- pos_next = cc.pos;
- break;
- }
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- put_short_code(&bc_out, op, idx);
- }
- break;
- case OP_get_arg:
- case OP_get_var_ref:
- {
- int idx;
- idx = get_u16(bc_buf + pos + 1);
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- put_short_code(&bc_out, op, idx);
- }
- break;
- case OP_put_loc:
- case OP_put_arg:
- case OP_put_var_ref:
- {
- /* transformation: put_x(n) get_x(n) -> set_x(n) */
- int idx;
- idx = get_u16(bc_buf + pos + 1);
- if (code_match(&cc, pos_next, op - 1, idx, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- put_short_code(&bc_out, op + 1, idx);
- pos_next = cc.pos;
- break;
- }
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- put_short_code(&bc_out, op, idx);
- }
- break;
- case OP_post_inc:
- case OP_post_dec:
- {
- /* transformation:
- post_inc put_x drop -> inc put_x
- post_inc perm3 put_field drop -> inc put_field
- post_inc perm3 put_var_strict drop -> inc put_var_strict
- post_inc perm4 put_array_el drop -> inc put_array_el
- */
- int op1, idx;
- if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- op1 = cc.op;
- idx = cc.idx;
- pos_next = cc.pos;
- if (code_match(&cc, cc.pos, op1 - 1, idx, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- op1 += 1; /* put_x(n) get_x(n) -> set_x(n) */
- pos_next = cc.pos;
- }
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
- put_short_code(&bc_out, op1, idx);
- break;
- }
- if (code_match(&cc, pos_next, OP_perm3, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
- dbuf_putc(&bc_out, cc.op);
- dbuf_put_u32(&bc_out, cc.atom);
- pos_next = cc.pos;
- break;
- }
- if (code_match(&cc, pos_next, OP_perm4, OP_put_array_el, OP_drop, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
- dbuf_putc(&bc_out, OP_put_array_el);
- pos_next = cc.pos;
- break;
- }
- }
- goto no_change;
- case OP_typeof:
- /* simplify typeof tests */
- if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq;
- int op2 = -1;
- switch (cc.atom) {
- case JS_ATOM_undefined:
- op2 = OP_typeof_is_undefined;
- break;
- case JS_ATOM_function:
- op2 = OP_typeof_is_function;
- break;
- }
- if (op2 >= 0) {
- /* transform typeof(s) == "<type>" into is_<type> */
- if (op1 == OP_strict_eq) {
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, op2);
- JS_FreeAtom(ctx, cc.atom);
- pos_next = cc.pos;
- break;
- }
- if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) {
- /* transform typeof(s) != "<type>" if_false into is_<type> if_true */
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, op2);
- JS_FreeAtom(ctx, cc.atom);
- pos_next = cc.pos;
- label = cc.label;
- op = OP_if_true;
- goto has_label;
- }
- }
- }
- goto no_change;
- case OP_object:
- if (code_match(&cc, pos_next, OP_null, OP_set_proto, -1)) {
- if (cc.line_num >= 0) line_num = cc.line_num;
- if (cc.col_num >= 0) col_num = cc.col_num;
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_putc(&bc_out, OP_special_object);
- dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_NULL_PROTO);
- pos_next = cc.pos;
- break;
- }
- goto no_change;
- default:
- no_change:
- add_pc2line_info(s, bc_out.size, line_num, col_num);
- dbuf_put(&bc_out, bc_buf + pos, len);
- break;
- }
- }
- /* check that there were no missing labels */
- for(i = 0; i < s->label_count; i++) {
- assert(label_slots[i].first_reloc == NULL);
- }
- /* more jump optimizations */
- patch_offsets = 0;
- for (i = 0, jp = s->jump_slots; i < s->jump_count; i++, jp++) {
- LabelSlot *ls;
- JumpSlot *jp1;
- int j, pos, diff, delta;
- delta = 3;
- switch (op = jp->op) {
- case OP_goto16:
- delta = 1;
- /* fall thru */
- case OP_if_false:
- case OP_if_true:
- case OP_goto:
- pos = jp->pos;
- diff = s->label_slots[jp->label].addr - pos;
- if (diff >= -128 && diff <= 127 + delta) {
- //put_u8(bc_out.buf + pos, diff);
- jp->size = 1;
- if (op == OP_goto16) {
- bc_out.buf[pos - 1] = jp->op = OP_goto8;
- } else {
- bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false);
- }
- goto shrink;
- } else
- if (diff == (int16_t)diff && op == OP_goto) {
- //put_u16(bc_out.buf + pos, diff);
- jp->size = 2;
- delta = 2;
- bc_out.buf[pos - 1] = jp->op = OP_goto16;
- shrink:
- /* XXX: should reduce complexity, using 2 finger copy scheme */
- memmove(bc_out.buf + pos + jp->size, bc_out.buf + pos + jp->size + delta,
- bc_out.size - pos - jp->size - delta);
- bc_out.size -= delta;
- patch_offsets++;
- for (j = 0, ls = s->label_slots; j < s->label_count; j++, ls++) {
- if (ls->addr > pos)
- ls->addr -= delta;
- }
- for (j = i + 1, jp1 = jp + 1; j < s->jump_count; j++, jp1++) {
- if (jp1->pos > pos)
- jp1->pos -= delta;
- }
- for (j = 0; j < s->source_loc_count; j++) {
- if (s->source_loc_slots[j].pc > pos)
- s->source_loc_slots[j].pc -= delta;
- }
- continue;
- }
- break;
- }
- }
- if (patch_offsets) {
- JumpSlot *jp1;
- int j;
- for (j = 0, jp1 = s->jump_slots; j < s->jump_count; j++, jp1++) {
- int diff1 = s->label_slots[jp1->label].addr - jp1->pos;
- switch (jp1->size) {
- case 1:
- put_u8(bc_out.buf + jp1->pos, diff1);
- break;
- case 2:
- put_u16(bc_out.buf + jp1->pos, diff1);
- break;
- case 4:
- put_u32(bc_out.buf + jp1->pos, diff1);
- break;
- }
- }
- }
- js_free(ctx, s->jump_slots);
- s->jump_slots = NULL;
- js_free(ctx, s->label_slots);
- s->label_slots = NULL;
- /* XXX: should delay until copying to runtime bytecode function */
- compute_pc2line_info(s);
- js_free(ctx, s->source_loc_slots);
- s->source_loc_slots = NULL;
- /* set the new byte code */
- dbuf_free(&s->byte_code);
- s->byte_code = bc_out;
- s->use_short_opcodes = true;
- if (dbuf_error(&s->byte_code)) {
- JS_ThrowOutOfMemory(ctx);
- return -1;
- }
- return 0;
- fail:
- /* XXX: not safe */
- dbuf_free(&bc_out);
- return -1;
- }
- /* compute the maximum stack size needed by the function */
- typedef struct StackSizeState {
- int bc_len;
- int stack_len_max;
- uint16_t *stack_level_tab;
- int32_t *catch_pos_tab;
- int *pc_stack;
- int pc_stack_len;
- int pc_stack_size;
- } StackSizeState;
- /* 'op' is only used for error indication */
- static __exception int ss_check(JSContext *ctx, StackSizeState *s,
- int pos, int op, int stack_len, int catch_pos)
- {
- if ((unsigned)pos >= s->bc_len) {
- JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
- return -1;
- }
- if (stack_len > s->stack_len_max) {
- s->stack_len_max = stack_len;
- if (s->stack_len_max > JS_STACK_SIZE_MAX) {
- JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
- return -1;
- }
- }
- if (s->stack_level_tab[pos] != 0xffff) {
- /* already explored: check that the stack size is consistent */
- if (s->stack_level_tab[pos] != stack_len) {
- JS_ThrowInternalError(ctx, "inconsistent stack size: %d %d (pc=%d)",
- s->stack_level_tab[pos], stack_len, pos);
- return -1;
- } else if (s->catch_pos_tab[pos] != catch_pos) {
- JS_ThrowInternalError(ctx, "inconsistent catch position: %d %d (pc=%d)",
- s->catch_pos_tab[pos], catch_pos, pos);
- return -1;
- } else {
- return 0;
- }
- }
- /* mark as explored and store the stack size */
- s->stack_level_tab[pos] = stack_len;
- s->catch_pos_tab[pos] = catch_pos;
- /* queue the new PC to explore */
- if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),
- &s->pc_stack_size, s->pc_stack_len + 1))
- return -1;
- s->pc_stack[s->pc_stack_len++] = pos;
- return 0;
- }
- static __exception int compute_stack_size(JSContext *ctx,
- JSFunctionDef *fd,
- int *pstack_size)
- {
- StackSizeState s_s, *s = &s_s;
- int i, diff, n_pop, pos_next, stack_len, pos, op, catch_pos, catch_level;
- const JSOpCode *oi;
- const uint8_t *bc_buf;
- bc_buf = fd->byte_code.buf;
- s->bc_len = fd->byte_code.size;
- /* bc_len > 0 */
- s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) *
- s->bc_len);
- if (!s->stack_level_tab)
- return -1;
- for(i = 0; i < s->bc_len; i++)
- s->stack_level_tab[i] = 0xffff;
- s->pc_stack = NULL;
- s->catch_pos_tab = js_malloc(ctx, sizeof(s->catch_pos_tab[0]) * s->bc_len);
- if (!s->catch_pos_tab)
- goto fail;
- s->stack_len_max = 0;
- s->pc_stack_len = 0;
- s->pc_stack_size = 0;
- /* breadth-first graph exploration */
- if (ss_check(ctx, s, 0, OP_invalid, 0, -1))
- goto fail;
- while (s->pc_stack_len > 0) {
- pos = s->pc_stack[--s->pc_stack_len];
- stack_len = s->stack_level_tab[pos];
- catch_pos = s->catch_pos_tab[pos];
- op = bc_buf[pos];
- if (op == 0 || op >= OP_COUNT) {
- JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos);
- goto fail;
- }
- oi = &short_opcode_info(op);
- #ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_STACK
- if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_STACK))
- printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos);
- #endif
- pos_next = pos + oi->size;
- if (pos_next > s->bc_len) {
- JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
- goto fail;
- }
- n_pop = oi->n_pop;
- /* call pops a variable number of arguments */
- if (oi->fmt == OP_FMT_npop || oi->fmt == OP_FMT_npop_u16) {
- n_pop += get_u16(bc_buf + pos + 1);
- } else if (oi->fmt == OP_FMT_npopx) {
- n_pop += op - OP_call0;
- }
- if (stack_len < n_pop) {
- JS_ThrowInternalError(ctx, "stack underflow (op=%d, pc=%d)", op, pos);
- goto fail;
- }
- stack_len += oi->n_push - n_pop;
- if (stack_len > s->stack_len_max) {
- s->stack_len_max = stack_len;
- if (s->stack_len_max > JS_STACK_SIZE_MAX) {
- JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
- goto fail;
- }
- }
- switch(op) {
- case OP_tail_call:
- case OP_tail_call_method:
- case OP_return:
- case OP_return_undef:
- case OP_return_async:
- case OP_throw:
- case OP_throw_error:
- case OP_ret:
- goto done_insn;
- case OP_goto:
- diff = get_u32(bc_buf + pos + 1);
- pos_next = pos + 1 + diff;
- break;
- case OP_goto16:
- diff = (int16_t)get_u16(bc_buf + pos + 1);
- pos_next = pos + 1 + diff;
- break;
- case OP_goto8:
- diff = (int8_t)bc_buf[pos + 1];
- pos_next = pos + 1 + diff;
- break;
- case OP_if_true8:
- case OP_if_false8:
- diff = (int8_t)bc_buf[pos + 1];
- if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
- goto fail;
- break;
- case OP_if_true:
- case OP_if_false:
- diff = get_u32(bc_buf + pos + 1);
- if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
- goto fail;
- break;
- case OP_gosub:
- diff = get_u32(bc_buf + pos + 1);
- if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1, catch_pos))
- goto fail;
- break;
- case OP_with_get_var:
- case OP_with_delete_var:
- diff = get_u32(bc_buf + pos + 5);
- if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1, catch_pos))
- goto fail;
- break;
- case OP_with_make_ref:
- case OP_with_get_ref:
- case OP_with_get_ref_undef:
- diff = get_u32(bc_buf + pos + 5);
- if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2, catch_pos))
- goto fail;
- break;
- case OP_with_put_var:
- diff = get_u32(bc_buf + pos + 5);
- if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1, catch_pos))
- goto fail;
- break;
- case OP_catch:
- diff = get_u32(bc_buf + pos + 1);
- if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
- goto fail;
- catch_pos = pos;
- break;
- case OP_for_of_start:
- case OP_for_await_of_start:
- catch_pos = pos;
- break;
- /* we assume the catch offset entry is only removed with
- some op codes */
- case OP_drop:
- catch_level = stack_len;
- goto check_catch;
- case OP_nip:
- catch_level = stack_len - 1;
- goto check_catch;
- case OP_nip1:
- catch_level = stack_len - 1;
- goto check_catch;
- case OP_iterator_close:
- catch_level = stack_len + 2;
- check_catch:
- /* Note: for for_of_start/for_await_of_start we consider
- the catch offset is on the first stack entry instead of
- the thirst */
- if (catch_pos >= 0) {
- int level;
- level = s->stack_level_tab[catch_pos];
- if (bc_buf[catch_pos] != OP_catch)
- level++; /* for_of_start, for_wait_of_start */
- /* catch_level = stack_level before op_catch is executed ? */
- if (catch_level == level) {
- catch_pos = s->catch_pos_tab[catch_pos];
- }
- }
- break;
- case OP_nip_catch:
- if (catch_pos < 0) {
- JS_ThrowInternalError(ctx, "nip_catch: no catch op (pc=%d)", pos);
- goto fail;
- }
- stack_len = s->stack_level_tab[catch_pos];
- if (bc_buf[catch_pos] != OP_catch)
- stack_len++; /* for_of_start, for_wait_of_start */
- stack_len++; /* no stack overflow is possible by construction */
- catch_pos = s->catch_pos_tab[catch_pos];
- break;
- default:
- break;
- }
- if (ss_check(ctx, s, pos_next, op, stack_len, catch_pos))
- goto fail;
- done_insn: ;
- }
- js_free(ctx, s->pc_stack);
- js_free(ctx, s->catch_pos_tab);
- js_free(ctx, s->stack_level_tab);
- *pstack_size = s->stack_len_max;
- return 0;
- fail:
- js_free(ctx, s->pc_stack);
- js_free(ctx, s->catch_pos_tab);
- js_free(ctx, s->stack_level_tab);
- *pstack_size = 0;
- return -1;
- }
- static int add_module_variables(JSContext *ctx, JSFunctionDef *fd)
- {
- int i, idx;
- JSModuleDef *m = fd->module;
- JSExportEntry *me;
- JSGlobalVar *hf;
- /* The imported global variables were added as closure variables
- in js_parse_import(). We add here the module global
- variables. */
- for(i = 0; i < fd->global_var_count; i++) {
- hf = &fd->global_vars[i];
- if (add_closure_var(ctx, fd, true, false, i, hf->var_name, hf->is_const,
- hf->is_lexical, JS_VAR_NORMAL) < 0)
- return -1;
- }
- /* resolve the variable names of the local exports */
- for(i = 0; i < m->export_entries_count; i++) {
- me = &m->export_entries[i];
- if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
- idx = find_closure_var(ctx, fd, me->local_name);
- if (idx < 0) {
- // XXX: add_module_variables() should take JSParseState *s and use js_parse_error_atom
- JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not exist",
- me->local_name);
- return -1;
- }
- me->u.local.var_idx = idx;
- }
- }
- return 0;
- }
- /* create a function object from a function definition. The function
- definition is freed. All the child functions are also created. It
- must be done this way to resolve all the variables. */
- static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
- {
- JSValue func_obj;
- JSFunctionBytecode *b;
- struct list_head *el, *el1;
- int stack_size, scope, idx;
- int function_size, byte_code_offset, cpool_offset;
- int closure_var_offset, vardefs_offset;
- /* recompute scope linkage */
- for (scope = 0; scope < fd->scope_count; scope++) {
- fd->scopes[scope].first = -1;
- }
- if (fd->has_parameter_expressions) {
- /* special end of variable list marker for the argument scope */
- fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END;
- }
- for (idx = 0; idx < fd->var_count; idx++) {
- JSVarDef *vd = &fd->vars[idx];
- vd->scope_next = fd->scopes[vd->scope_level].first;
- fd->scopes[vd->scope_level].first = idx;
- }
- for (scope = 2; scope < fd->scope_count; scope++) {
- JSVarScope *sd = &fd->scopes[scope];
- if (sd->first < 0)
- sd->first = fd->scopes[sd->parent].first;
- }
- for (idx = 0; idx < fd->var_count; idx++) {
- JSVarDef *vd = &fd->vars[idx];
- if (vd->scope_next < 0 && vd->scope_level > 1) {
- scope = fd->scopes[vd->scope_level].parent;
- vd->scope_next = fd->scopes[scope].first;
- }
- }
- /* if the function contains an eval call, the closure variables
- are used to compile the eval and they must be ordered by scope,
- so it is necessary to create the closure variables before any
- other variable lookup is done. */
- #ifndef QJS_DISABLE_PARSER
- if (fd->has_eval_call)
- add_eval_variables(ctx, fd);
- #endif // QJS_DISABLE_PARSER
- /* add the module global variables in the closure */
- if (fd->module) {
- if (add_module_variables(ctx, fd))
- goto fail;
- }
- /* first create all the child functions */
- list_for_each_safe(el, el1, &fd->child_list) {
- JSFunctionDef *fd1;
- int cpool_idx;
- fd1 = list_entry(el, JSFunctionDef, link);
- cpool_idx = fd1->parent_cpool_idx;
- func_obj = js_create_function(ctx, fd1);
- if (JS_IsException(func_obj))
- goto fail;
- /* save it in the constant pool */
- assert(cpool_idx >= 0);
- fd->cpool[cpool_idx] = func_obj;
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_PASS1
- if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_PASS1)) {
- printf("pass 1\n");
- dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size,
- fd->args, fd->arg_count, fd->vars, fd->var_count,
- fd->closure_var, fd->closure_var_count,
- fd->cpool, fd->cpool_count, fd->source, fd->line_num,
- fd->label_slots, NULL, 0);
- printf("\n");
- }
- #endif
- if (resolve_variables(ctx, fd))
- goto fail;
- #ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_PASS2
- if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_PASS2)) {
- printf("pass 2\n");
- dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size,
- fd->args, fd->arg_count, fd->vars, fd->var_count,
- fd->closure_var, fd->closure_var_count,
- fd->cpool, fd->cpool_count, fd->source, fd->line_num,
- fd->label_slots, NULL, 0);
- printf("\n");
- }
- #endif
- if (resolve_labels(ctx, fd))
- goto fail;
- if (compute_stack_size(ctx, fd, &stack_size) < 0)
- goto fail;
- function_size = sizeof(*b);
- cpool_offset = function_size;
- function_size += fd->cpool_count * sizeof(*fd->cpool);
- vardefs_offset = function_size;
- function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs);
- closure_var_offset = function_size;
- function_size += fd->closure_var_count * sizeof(*fd->closure_var);
- byte_code_offset = function_size;
- function_size += fd->byte_code.size;
- b = js_mallocz(ctx, function_size);
- if (!b)
- goto fail;
- b->header.ref_count = 1;
- b->byte_code_buf = (void *)((uint8_t*)b + byte_code_offset);
- b->byte_code_len = fd->byte_code.size;
- memcpy(b->byte_code_buf, fd->byte_code.buf, fd->byte_code.size);
- js_free(ctx, fd->byte_code.buf);
- fd->byte_code.buf = NULL;
- b->func_name = fd->func_name;
- if (fd->arg_count + fd->var_count > 0) {
- b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
- if (fd->arg_count > 0)
- memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
- if (fd->var_count > 0)
- memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
- b->var_count = fd->var_count;
- b->arg_count = fd->arg_count;
- b->defined_arg_count = fd->defined_arg_count;
- js_free(ctx, fd->args);
- js_free(ctx, fd->vars);
- js_free(ctx, fd->vars_htab);
- }
- b->cpool_count = fd->cpool_count;
- if (b->cpool_count) {
- b->cpool = (void *)((uint8_t*)b + cpool_offset);
- memcpy(b->cpool, fd->cpool, b->cpool_count * sizeof(*b->cpool));
- }
- js_free(ctx, fd->cpool);
- fd->cpool = NULL;
- b->stack_size = stack_size;
- /* XXX: source and pc2line info should be packed at the end of the
- JSFunctionBytecode structure, avoiding allocation overhead
- */
- b->filename = fd->filename;
- b->line_num = fd->line_num;
- b->col_num = fd->col_num;
- b->pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size);
- if (!b->pc2line_buf)
- b->pc2line_buf = fd->pc2line.buf;
- b->pc2line_len = fd->pc2line.size;
- b->source = fd->source;
- b->source_len = fd->source_len;
- if (fd->scopes != fd->def_scope_array)
- js_free(ctx, fd->scopes);
- b->closure_var_count = fd->closure_var_count;
- if (b->closure_var_count) {
- b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
- memcpy(b->closure_var, fd->closure_var, b->closure_var_count * sizeof(*b->closure_var));
- }
- js_free(ctx, fd->closure_var);
- fd->closure_var = NULL;
- b->has_prototype = fd->has_prototype;
- b->has_simple_parameter_list = fd->has_simple_parameter_list;
- b->is_strict_mode = fd->is_strict_mode;
- b->is_derived_class_constructor = fd->is_derived_class_constructor;
- b->func_kind = fd->func_kind;
- b->need_home_object = (fd->home_object_var_idx >= 0 ||
- fd->need_home_object);
- b->new_target_allowed = fd->new_target_allowed;
- b->super_call_allowed = fd->super_call_allowed;
- b->super_allowed = fd->super_allowed;
- b->arguments_allowed = fd->arguments_allowed;
- b->backtrace_barrier = fd->backtrace_barrier;
- b->realm = JS_DupContext(ctx);
- add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
- #ifdef ENABLE_DUMPS // JS_DUMP_BYTECODE_FINAL
- if (check_dump_flag(ctx->rt, JS_DUMP_BYTECODE_FINAL))
- js_dump_function_bytecode(ctx, b);
- #endif
- if (fd->parent) {
- /* remove from parent list */
- list_del(&fd->link);
- }
- js_free(ctx, fd);
- return JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
- fail:
- js_free_function_def(ctx, fd);
- return JS_EXCEPTION;
- }
- #endif // QJS_DISABLE_PARSER
- static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
- {
- int i;
- if (b->byte_code_buf)
- free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, true);
- if (b->vardefs) {
- for(i = 0; i < b->arg_count + b->var_count; i++) {
- JS_FreeAtomRT(rt, b->vardefs[i].var_name);
- }
- }
- for(i = 0; i < b->cpool_count; i++)
- JS_FreeValueRT(rt, b->cpool[i]);
- for(i = 0; i < b->closure_var_count; i++) {
- JSClosureVar *cv = &b->closure_var[i];
- JS_FreeAtomRT(rt, cv->var_name);
- }
- if (b->realm)
- JS_FreeContext(b->realm);
- JS_FreeAtomRT(rt, b->func_name);
- JS_FreeAtomRT(rt, b->filename);
- js_free_rt(rt, b->pc2line_buf);
- js_free_rt(rt, b->source);
- remove_gc_object(&b->header);
- if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && b->header.ref_count != 0) {
- list_add_tail(&b->header.link, &rt->gc_zero_ref_count_list);
- } else {
- js_free_rt(rt, b);
- }
- }
- #ifndef QJS_DISABLE_PARSER
- static __exception int js_parse_directives(JSParseState *s)
- {
- char str[20];
- JSParsePos pos;
- bool has_semi;
- if (s->token.val != TOK_STRING)
- return 0;
- js_parse_get_pos(s, &pos);
- while(s->token.val == TOK_STRING) {
- /* Copy actual source string representation */
- snprintf(str, sizeof str, "%.*s",
- (int)(s->buf_ptr - s->token.ptr - 2), s->token.ptr + 1);
- if (next_token(s))
- return -1;
- has_semi = false;
- switch (s->token.val) {
- case ';':
- if (next_token(s))
- return -1;
- has_semi = true;
- break;
- case '}':
- case TOK_EOF:
- has_semi = true;
- break;
- case TOK_NUMBER:
- case TOK_STRING:
- case TOK_TEMPLATE:
- case TOK_IDENT:
- case TOK_REGEXP:
- case TOK_DEC:
- case TOK_INC:
- case TOK_NULL:
- case TOK_FALSE:
- case TOK_TRUE:
- case TOK_IF:
- case TOK_RETURN:
- case TOK_VAR:
- case TOK_THIS:
- case TOK_DELETE:
- case TOK_TYPEOF:
- case TOK_NEW:
- case TOK_DO:
- case TOK_WHILE:
- case TOK_FOR:
- case TOK_SWITCH:
- case TOK_THROW:
- case TOK_TRY:
- case TOK_FUNCTION:
- case TOK_DEBUGGER:
- case TOK_WITH:
- case TOK_CLASS:
- case TOK_CONST:
- case TOK_ENUM:
- case TOK_EXPORT:
- case TOK_IMPORT:
- case TOK_SUPER:
- case TOK_INTERFACE:
- case TOK_LET:
- case TOK_PACKAGE:
- case TOK_PRIVATE:
- case TOK_PROTECTED:
- case TOK_PUBLIC:
- case TOK_STATIC:
- /* automatic insertion of ';' */
- if (s->got_lf)
- has_semi = true;
- break;
- default:
- break;
- }
- if (!has_semi)
- break;
- if (!strcmp(str, "use strict")) {
- s->cur_func->has_use_strict = true;
- s->cur_func->is_strict_mode = true;
- }
- }
- return js_parse_seek_token(s, &pos);
- }
- static bool js_invalid_strict_name(JSAtom name) {
- switch (name) {
- case JS_ATOM_eval:
- case JS_ATOM_arguments:
- case JS_ATOM_implements: // future strict reserved words
- case JS_ATOM_interface:
- case JS_ATOM_let:
- case JS_ATOM_package:
- case JS_ATOM_private:
- case JS_ATOM_protected:
- case JS_ATOM_public:
- case JS_ATOM_static:
- case JS_ATOM_yield:
- return true;
- default:
- return false;
- }
- }
- static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
- JSAtom func_name)
- {
- JSAtom name;
- int i, idx;
- if (fd->is_strict_mode) {
- if (!fd->has_simple_parameter_list && fd->has_use_strict) {
- return js_parse_error(s, "\"use strict\" not allowed in function with default or destructuring parameter");
- }
- if (js_invalid_strict_name(func_name)) {
- return js_parse_error(s, "invalid function name in strict code");
- }
- for (idx = 0; idx < fd->arg_count; idx++) {
- name = fd->args[idx].var_name;
- if (js_invalid_strict_name(name)) {
- return js_parse_error(s, "invalid argument name in strict code");
- }
- }
- }
- /* check async_generator case */
- if (fd->is_strict_mode
- || !fd->has_simple_parameter_list
- || (fd->func_type == JS_PARSE_FUNC_METHOD && fd->func_kind == JS_FUNC_ASYNC)
- || fd->func_type == JS_PARSE_FUNC_ARROW
- || fd->func_type == JS_PARSE_FUNC_METHOD) {
- for (idx = 0; idx < fd->arg_count; idx++) {
- name = fd->args[idx].var_name;
- if (name != JS_ATOM_NULL) {
- for (i = 0; i < idx; i++) {
- if (fd->args[i].var_name == name)
- goto duplicate;
- }
- /* Check if argument name duplicates a destructuring parameter */
- /* XXX: should have a flag for such variables */
- for (i = 0; i < fd->var_count; i++) {
- if (fd->vars[i].var_name == name &&
- fd->vars[i].scope_level == 0)
- goto duplicate;
- }
- }
- }
- }
- return 0;
- duplicate:
- return js_parse_error(s, "Duplicate parameter name not allowed in this context");
- }
- /* create a function to initialize class fields */
- static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s)
- {
- JSFunctionDef *fd;
- fd = js_new_function_def(s->ctx, s->cur_func, false, false,
- s->filename, 0, 0);
- if (!fd)
- return NULL;
- fd->func_name = JS_ATOM_NULL;
- fd->has_prototype = false;
- fd->has_home_object = true;
- fd->has_arguments_binding = false;
- fd->has_this_binding = true;
- fd->is_derived_class_constructor = false;
- fd->new_target_allowed = true;
- fd->super_call_allowed = false;
- fd->super_allowed = fd->has_home_object;
- fd->arguments_allowed = false;
- fd->func_kind = JS_FUNC_NORMAL;
- fd->func_type = JS_PARSE_FUNC_METHOD;
- return fd;
- }
- /* func_name must be JS_ATOM_NULL for JS_PARSE_FUNC_STATEMENT and
- JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW and JS_PARSE_FUNC_VAR */
- static __exception int js_parse_function_decl2(JSParseState *s,
- JSParseFunctionEnum func_type,
- JSFunctionKindEnum func_kind,
- JSAtom func_name,
- const uint8_t *ptr,
- int function_line_num,
- int function_col_num,
- JSParseExportEnum export_flag,
- JSFunctionDef **pfd)
- {
- JSContext *ctx = s->ctx;
- JSFunctionDef *fd = s->cur_func;
- bool is_expr;
- int func_idx, lexical_func_idx = -1;
- bool has_opt_arg;
- bool create_func_var = false;
- is_expr = (func_type != JS_PARSE_FUNC_STATEMENT &&
- func_type != JS_PARSE_FUNC_VAR);
- if (func_type == JS_PARSE_FUNC_STATEMENT ||
- func_type == JS_PARSE_FUNC_VAR ||
- func_type == JS_PARSE_FUNC_EXPR) {
- if (func_kind == JS_FUNC_NORMAL &&
- token_is_pseudo_keyword(s, JS_ATOM_async) &&
- peek_token(s, true) != '\n') {
- if (next_token(s))
- return -1;
- func_kind = JS_FUNC_ASYNC;
- }
- if (next_token(s))
- return -1;
- if (s->token.val == '*') {
- if (next_token(s))
- return -1;
- func_kind |= JS_FUNC_GENERATOR;
- }
- if (s->token.val == TOK_IDENT) {
- if (s->token.u.ident.is_reserved ||
- (s->token.u.ident.atom == JS_ATOM_yield &&
- func_type == JS_PARSE_FUNC_EXPR &&
- (func_kind & JS_FUNC_GENERATOR)) ||
- (s->token.u.ident.atom == JS_ATOM_await &&
- ((func_type == JS_PARSE_FUNC_EXPR &&
- (func_kind & JS_FUNC_ASYNC)) ||
- func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))) {
- return js_parse_error_reserved_identifier(s);
- }
- }
- if (s->token.val == TOK_IDENT ||
- (((s->token.val == TOK_YIELD && !fd->is_strict_mode) ||
- (s->token.val == TOK_AWAIT && !s->is_module)) &&
- func_type == JS_PARSE_FUNC_EXPR)) {
- func_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- if (next_token(s)) {
- JS_FreeAtom(ctx, func_name);
- return -1;
- }
- } else {
- if (func_type != JS_PARSE_FUNC_EXPR &&
- export_flag != JS_PARSE_EXPORT_DEFAULT) {
- return js_parse_error(s, "function name expected");
- }
- }
- } else if (func_type != JS_PARSE_FUNC_ARROW) {
- func_name = JS_DupAtom(ctx, func_name);
- }
- if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE &&
- (func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) {
- JSGlobalVar *hf;
- hf = find_global_var(fd, func_name);
- /* XXX: should check scope chain */
- if (hf && hf->scope_level == fd->scope_level) {
- js_parse_error(s, "invalid redefinition of global identifier in module code");
- JS_FreeAtom(ctx, func_name);
- return -1;
- }
- }
- if (func_type == JS_PARSE_FUNC_VAR) {
- if (!fd->is_strict_mode
- && func_kind == JS_FUNC_NORMAL
- && find_lexical_decl(ctx, fd, func_name, fd->scope_first, false) < 0
- && !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET))
- && !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) {
- create_func_var = true;
- }
- /* Create the lexical name here so that the function closure
- contains it */
- if (fd->is_eval &&
- (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
- fd->eval_type == JS_EVAL_TYPE_MODULE) &&
- fd->scope_level == fd->body_scope) {
- /* avoid creating a lexical variable in the global
- scope. XXX: check annex B */
- JSGlobalVar *hf;
- hf = find_global_var(fd, func_name);
- /* XXX: should check scope chain */
- if (hf && hf->scope_level == fd->scope_level) {
- js_parse_error(s, "invalid redefinition of global identifier");
- JS_FreeAtom(ctx, func_name);
- return -1;
- }
- } else {
- /* Always create a lexical name, fail if at the same scope as
- existing name */
- /* Lexical variable will be initialized upon entering scope */
- lexical_func_idx = define_var(s, fd, func_name,
- func_kind != JS_FUNC_NORMAL ?
- JS_VAR_DEF_NEW_FUNCTION_DECL :
- JS_VAR_DEF_FUNCTION_DECL);
- if (lexical_func_idx < 0) {
- JS_FreeAtom(ctx, func_name);
- return -1;
- }
- }
- }
- fd = js_new_function_def(ctx, fd, false, is_expr, s->filename,
- function_line_num, function_col_num);
- if (!fd) {
- JS_FreeAtom(ctx, func_name);
- return -1;
- }
- if (pfd)
- *pfd = fd;
- s->cur_func = fd;
- fd->func_name = func_name;
- /* XXX: test !fd->is_generator is always false */
- fd->has_prototype = (func_type == JS_PARSE_FUNC_STATEMENT ||
- func_type == JS_PARSE_FUNC_VAR ||
- func_type == JS_PARSE_FUNC_EXPR) &&
- func_kind == JS_FUNC_NORMAL;
- fd->has_home_object = (func_type == JS_PARSE_FUNC_METHOD ||
- func_type == JS_PARSE_FUNC_GETTER ||
- func_type == JS_PARSE_FUNC_SETTER ||
- func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
- func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
- fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW &&
- func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT);
- fd->has_this_binding = fd->has_arguments_binding;
- fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
- if (func_type == JS_PARSE_FUNC_ARROW) {
- fd->new_target_allowed = fd->parent->new_target_allowed;
- fd->super_call_allowed = fd->parent->super_call_allowed;
- fd->super_allowed = fd->parent->super_allowed;
- fd->arguments_allowed = fd->parent->arguments_allowed;
- } else if (func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
- fd->new_target_allowed = true; // although new.target === undefined
- fd->super_call_allowed = false;
- fd->super_allowed = true;
- fd->arguments_allowed = false;
- } else {
- fd->new_target_allowed = true;
- fd->super_call_allowed = fd->is_derived_class_constructor;
- fd->super_allowed = fd->has_home_object;
- fd->arguments_allowed = true;
- }
- /* fd->in_function_body == false prevents yield/await during the parsing
- of the arguments in generator/async functions. They are parsed as
- regular identifiers for other function kinds. */
- fd->func_kind = func_kind;
- fd->func_type = func_type;
- if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
- func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
- /* error if not invoked as a constructor */
- emit_op(s, OP_check_ctor);
- }
- if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
- emit_class_field_init(s);
- }
- /* parse arguments */
- fd->has_simple_parameter_list = true;
- fd->has_parameter_expressions = false;
- has_opt_arg = false;
- if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {
- JSAtom name;
- if (s->token.u.ident.is_reserved) {
- js_parse_error_reserved_identifier(s);
- goto fail;
- }
- name = s->token.u.ident.atom;
- if (add_arg(ctx, fd, name) < 0)
- goto fail;
- fd->defined_arg_count = 1;
- } else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
- if (s->token.val == '(') {
- int skip_bits;
- /* if there is an '=' inside the parameter list, we
- consider there is a parameter expression inside */
- js_parse_skip_parens_token(s, &skip_bits, false);
- if (skip_bits & SKIP_HAS_ASSIGNMENT)
- fd->has_parameter_expressions = true;
- if (next_token(s))
- goto fail;
- } else {
- if (js_parse_expect(s, '('))
- goto fail;
- }
- if (fd->has_parameter_expressions) {
- fd->scope_level = -1; /* force no parent scope */
- if (push_scope(s) < 0)
- return -1;
- }
- while (s->token.val != ')') {
- JSAtom name;
- bool rest = false;
- int idx, has_initializer;
- if (s->token.val == TOK_ELLIPSIS) {
- fd->has_simple_parameter_list = false;
- rest = true;
- if (next_token(s))
- goto fail;
- }
- if (s->token.val == '[' || s->token.val == '{') {
- fd->has_simple_parameter_list = false;
- if (rest) {
- emit_op(s, OP_rest);
- emit_u16(s, fd->arg_count);
- } else {
- /* unnamed arg for destructuring */
- idx = add_arg(ctx, fd, JS_ATOM_NULL);
- emit_op(s, OP_get_arg);
- emit_u16(s, idx);
- }
- has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, true, true, -1, true, false);
- if (has_initializer < 0)
- goto fail;
- if (has_initializer)
- has_opt_arg = true;
- if (!has_opt_arg)
- fd->defined_arg_count++;
- } else if (s->token.val == TOK_IDENT) {
- if (s->token.u.ident.is_reserved) {
- js_parse_error_reserved_identifier(s);
- goto fail;
- }
- name = s->token.u.ident.atom;
- if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
- js_parse_error_reserved_identifier(s);
- goto fail;
- }
- if (fd->has_parameter_expressions) {
- if (js_parse_check_duplicate_parameter(s, name))
- goto fail;
- if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)
- goto fail;
- }
- /* XXX: could avoid allocating an argument if rest is true */
- idx = add_arg(ctx, fd, name);
- if (idx < 0)
- goto fail;
- if (next_token(s))
- goto fail;
- if (rest) {
- emit_op(s, OP_rest);
- emit_u16(s, idx);
- if (fd->has_parameter_expressions) {
- emit_op(s, OP_dup);
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, name);
- emit_u16(s, fd->scope_level);
- }
- emit_op(s, OP_put_arg);
- emit_u16(s, idx);
- fd->has_simple_parameter_list = false;
- has_opt_arg = true;
- } else if (s->token.val == '=') {
- int label;
- fd->has_simple_parameter_list = false;
- has_opt_arg = true;
- if (next_token(s))
- goto fail;
- label = new_label(s);
- emit_op(s, OP_get_arg);
- emit_u16(s, idx);
- emit_op(s, OP_dup);
- emit_op(s, OP_undefined);
- emit_op(s, OP_strict_eq);
- emit_goto(s, OP_if_false, label);
- emit_op(s, OP_drop);
- if (js_parse_assign_expr(s))
- goto fail;
- set_object_name(s, name);
- emit_op(s, OP_dup);
- emit_op(s, OP_put_arg);
- emit_u16(s, idx);
- emit_label(s, label);
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, name);
- emit_u16(s, fd->scope_level);
- } else {
- if (!has_opt_arg) {
- fd->defined_arg_count++;
- }
- if (fd->has_parameter_expressions) {
- /* copy the argument to the argument scope */
- emit_op(s, OP_get_arg);
- emit_u16(s, idx);
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, name);
- emit_u16(s, fd->scope_level);
- }
- }
- } else {
- js_parse_error(s, "missing formal parameter");
- goto fail;
- }
- if (rest && s->token.val != ')') {
- js_parse_expect(s, ')');
- goto fail;
- }
- if (s->token.val == ')')
- break;
- if (js_parse_expect(s, ','))
- goto fail;
- }
- if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) ||
- (func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) {
- js_parse_error(s, "invalid number of arguments for getter or setter");
- goto fail;
- }
- }
- if (fd->has_parameter_expressions) {
- int idx;
- /* Copy the variables in the argument scope to the variable
- scope (see FunctionDeclarationInstantiation() in spec). The
- normal arguments are already present, so no need to copy
- them. */
- idx = fd->scopes[fd->scope_level].first;
- while (idx >= 0) {
- JSVarDef *vd = &fd->vars[idx];
- if (vd->scope_level != fd->scope_level)
- break;
- if (find_var(ctx, fd, vd->var_name) < 0) {
- if (add_var(ctx, fd, vd->var_name) < 0)
- goto fail;
- vd = &fd->vars[idx]; /* fd->vars may have been reallocated */
- emit_op(s, OP_scope_get_var);
- emit_atom(s, vd->var_name);
- emit_u16(s, fd->scope_level);
- emit_op(s, OP_scope_put_var);
- emit_atom(s, vd->var_name);
- emit_u16(s, 0);
- }
- idx = vd->scope_next;
- }
- /* the argument scope has no parent, hence we don't use pop_scope(s) */
- emit_op(s, OP_leave_scope);
- emit_u16(s, fd->scope_level);
- /* set the variable scope as the current scope */
- fd->scope_level = 0;
- fd->scope_first = fd->scopes[fd->scope_level].first;
- }
- if (next_token(s))
- goto fail;
- /* generator function: yield after the parameters are evaluated */
- if (func_kind == JS_FUNC_GENERATOR ||
- func_kind == JS_FUNC_ASYNC_GENERATOR)
- emit_op(s, OP_initial_yield);
- /* in generators, yield expression is forbidden during the parsing
- of the arguments */
- fd->in_function_body = true;
- push_scope(s); /* enter body scope */
- fd->body_scope = fd->scope_level;
- if (s->token.val == TOK_ARROW) {
- if (next_token(s))
- goto fail;
- if (s->token.val != '{') {
- if (js_parse_function_check_names(s, fd, func_name))
- goto fail;
- if (js_parse_assign_expr(s))
- goto fail;
- if (func_kind != JS_FUNC_NORMAL)
- emit_op(s, OP_return_async);
- else
- emit_op(s, OP_return);
- /* save the function source code */
- /* the end of the function source code is after the last
- token of the function source stored into s->last_ptr */
- fd->source_len = s->last_ptr - ptr;
- fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
- if (!fd->source)
- goto fail;
- goto done;
- }
- }
- // js_parse_class() already consumed the '{'
- if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT)
- if (js_parse_expect(s, '{'))
- goto fail;
- if (js_parse_directives(s))
- goto fail;
- /* in strict_mode, check function and argument names */
- if (js_parse_function_check_names(s, fd, func_name))
- goto fail;
- while (s->token.val != '}') {
- if (js_parse_source_element(s))
- goto fail;
- }
- /* save the function source code */
- fd->source_len = s->buf_ptr - ptr;
- fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
- if (!fd->source)
- goto fail;
- if (next_token(s)) {
- /* consume the '}' */
- goto fail;
- }
- /* in case there is no return, add one */
- if (js_is_live_code(s)) {
- emit_return(s, false);
- }
- done:
- s->cur_func = fd->parent;
- /* Reparse identifiers after the function is terminated so that
- the token is parsed in the englobing function. It could be done
- by just using next_token() here for normal functions, but it is
- necessary for arrow functions with an expression body. */
- reparse_ident_token(s);
- /* create the function object */
- {
- int idx;
- JSAtom func_name = fd->func_name;
- /* the real object will be set at the end of the compilation */
- idx = cpool_add(s, JS_NULL);
- fd->parent_cpool_idx = idx;
- if (is_expr) {
- /* for constructors, no code needs to be generated here */
- if (func_type != JS_PARSE_FUNC_CLASS_CONSTRUCTOR &&
- func_type != JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
- /* OP_fclosure creates the function object from the bytecode
- and adds the scope information */
- emit_op(s, OP_fclosure);
- emit_u32(s, idx);
- if (func_name == JS_ATOM_NULL) {
- emit_op(s, OP_set_name);
- emit_u32(s, JS_ATOM_NULL);
- }
- }
- } else if (func_type == JS_PARSE_FUNC_VAR) {
- emit_op(s, OP_fclosure);
- emit_u32(s, idx);
- if (create_func_var) {
- if (s->cur_func->is_global_var) {
- JSGlobalVar *hf;
- /* the global variable must be defined at the start of the
- function */
- hf = add_global_var(ctx, s->cur_func, func_name);
- if (!hf)
- goto fail;
- /* it is considered as defined at the top level
- (needed for annex B.3.3.4 and B.3.3.5
- checks) */
- hf->scope_level = 0;
- hf->force_init = s->cur_func->is_strict_mode;
- /* store directly into global var, bypass lexical scope */
- emit_op(s, OP_dup);
- emit_op(s, OP_scope_put_var);
- emit_atom(s, func_name);
- emit_u16(s, 0);
- } else {
- /* do not call define_var to bypass lexical scope check */
- func_idx = find_var(ctx, s->cur_func, func_name);
- if (func_idx < 0) {
- func_idx = add_var(ctx, s->cur_func, func_name);
- if (func_idx < 0)
- goto fail;
- }
- /* store directly into local var, bypass lexical catch scope */
- emit_op(s, OP_dup);
- emit_op(s, OP_scope_put_var);
- emit_atom(s, func_name);
- emit_u16(s, 0);
- }
- }
- if (lexical_func_idx >= 0) {
- /* lexical variable will be initialized upon entering scope */
- s->cur_func->vars[lexical_func_idx].func_pool_idx = idx;
- emit_op(s, OP_drop);
- } else {
- /* store function object into its lexical name */
- /* XXX: could use OP_put_loc directly */
- emit_op(s, OP_scope_put_var_init);
- emit_atom(s, func_name);
- emit_u16(s, s->cur_func->scope_level);
- }
- } else {
- if (!s->cur_func->is_global_var) {
- int var_idx = define_var(s, s->cur_func, func_name, JS_VAR_DEF_VAR);
- if (var_idx < 0)
- goto fail;
- /* the variable will be assigned at the top of the function */
- if (var_idx & ARGUMENT_VAR_OFFSET) {
- s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx;
- } else {
- s->cur_func->vars[var_idx].func_pool_idx = idx;
- }
- } else {
- JSAtom func_var_name;
- JSGlobalVar *hf;
- if (func_name == JS_ATOM_NULL)
- func_var_name = JS_ATOM__default_; /* export default */
- else
- func_var_name = func_name;
- /* the variable will be assigned at the top of the function */
- hf = add_global_var(ctx, s->cur_func, func_var_name);
- if (!hf)
- goto fail;
- hf->cpool_idx = idx;
- if (export_flag != JS_PARSE_EXPORT_NONE) {
- if (!add_export_entry(s, s->cur_func->module, func_var_name,
- export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL))
- goto fail;
- }
- }
- }
- }
- return 0;
- fail:
- s->cur_func = fd->parent;
- js_free_function_def(ctx, fd);
- if (pfd)
- *pfd = NULL;
- return -1;
- }
- static __exception int js_parse_function_decl(JSParseState *s,
- JSParseFunctionEnum func_type,
- JSFunctionKindEnum func_kind,
- JSAtom func_name,
- const uint8_t *ptr,
- int start_line,
- int start_col)
- {
- return js_parse_function_decl2(s, func_type, func_kind, func_name, ptr,
- start_line, start_col,
- JS_PARSE_EXPORT_NONE, NULL);
- }
- static __exception int js_parse_program(JSParseState *s)
- {
- JSFunctionDef *fd = s->cur_func;
- int idx;
- if (next_token(s))
- return -1;
- if (js_parse_directives(s))
- return -1;
- fd->is_global_var = (fd->eval_type == JS_EVAL_TYPE_GLOBAL) ||
- (fd->eval_type == JS_EVAL_TYPE_MODULE) ||
- !fd->is_strict_mode;
- if (!s->is_module) {
- /* hidden variable for the return value */
- fd->eval_ret_idx = idx = add_var(s->ctx, fd, JS_ATOM__ret_);
- if (idx < 0)
- return -1;
- }
- while (s->token.val != TOK_EOF) {
- if (js_parse_source_element(s))
- return -1;
- }
- if (!s->is_module) {
- /* return the value of the hidden variable eval_ret_idx */
- if (fd->func_kind == JS_FUNC_ASYNC) {
- /* wrap the return value in an object so that promises can
- be safely returned */
- emit_op(s, OP_object);
- emit_op(s, OP_dup);
- emit_op(s, OP_get_loc);
- emit_u16(s, fd->eval_ret_idx);
- emit_op(s, OP_put_field);
- emit_atom(s, JS_ATOM_value);
- } else {
- emit_op(s, OP_get_loc);
- emit_u16(s, fd->eval_ret_idx);
- }
- emit_return(s, true);
- } else {
- emit_return(s, false);
- }
- return 0;
- }
- #endif // QJS_DISABLE_PARSER
- static void js_parse_init(JSContext *ctx, JSParseState *s,
- const char *input, size_t input_len,
- const char *filename, int line)
- {
- memset(s, 0, sizeof(*s));
- s->ctx = ctx;
- s->filename = filename;
- s->line_num = line;
- s->col_num = 1;
- s->buf_start = s->buf_ptr = (const uint8_t *)input;
- s->buf_end = s->buf_ptr + input_len;
- s->mark = s->buf_ptr + min_int(1, input_len);
- s->eol = s->buf_ptr;
- s->token.val = ' ';
- s->token.line_num = 1;
- s->token.col_num = 1;
- }
- static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
- JSValueConst this_obj,
- JSVarRef **var_refs, JSStackFrame *sf)
- {
- JSValue ret_val;
- uint32_t tag;
- tag = JS_VALUE_GET_TAG(fun_obj);
- if (tag == JS_TAG_FUNCTION_BYTECODE) {
- fun_obj = js_closure(ctx, fun_obj, var_refs, sf);
- ret_val = JS_CallFree(ctx, fun_obj, this_obj, 0, NULL);
- } else if (tag == JS_TAG_MODULE) {
- JSModuleDef *m;
- m = JS_VALUE_GET_PTR(fun_obj);
- /* the module refcount should be >= 2 */
- JS_FreeValue(ctx, fun_obj);
- if (js_create_module_function(ctx, m) < 0)
- goto fail;
- if (js_link_module(ctx, m) < 0)
- goto fail;
- ret_val = js_evaluate_module(ctx, m);
- if (JS_IsException(ret_val)) {
- fail:
- return JS_EXCEPTION;
- }
- } else {
- JS_FreeValue(ctx, fun_obj);
- ret_val = JS_ThrowTypeError(ctx, "bytecode function expected");
- }
- return ret_val;
- }
- JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj)
- {
- return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL);
- }
- #ifndef QJS_DISABLE_PARSER
- /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
- /* `export_name` and `input` may be pure ASCII or UTF-8 encoded */
- static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
- const char *filename, int line, int flags, int scope_idx)
- {
- JSParseState s1, *s = &s1;
- int err, eval_type;
- JSValue fun_obj, ret_val;
- JSStackFrame *sf;
- JSVarRef **var_refs;
- JSFunctionBytecode *b;
- JSFunctionDef *fd;
- JSModuleDef *m;
- bool is_strict_mode;
- js_parse_init(ctx, s, input, input_len, filename, line);
- skip_shebang(&s->buf_ptr, s->buf_end);
- eval_type = flags & JS_EVAL_TYPE_MASK;
- m = NULL;
- if (eval_type == JS_EVAL_TYPE_DIRECT) {
- JSObject *p;
- sf = ctx->rt->current_stack_frame;
- assert(sf != NULL);
- assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT);
- p = JS_VALUE_GET_OBJ(sf->cur_func);
- assert(js_class_has_bytecode(p->class_id));
- b = p->u.func.function_bytecode;
- var_refs = p->u.func.var_refs;
- is_strict_mode = b->is_strict_mode;
- } else {
- sf = NULL;
- b = NULL;
- var_refs = NULL;
- is_strict_mode = (flags & JS_EVAL_FLAG_STRICT) != 0;
- if (eval_type == JS_EVAL_TYPE_MODULE) {
- JSAtom module_name = JS_NewAtom(ctx, filename);
- if (module_name == JS_ATOM_NULL)
- return JS_EXCEPTION;
- m = js_new_module_def(ctx, module_name);
- if (!m)
- return JS_EXCEPTION;
- is_strict_mode = true;
- }
- }
- fd = js_new_function_def(ctx, NULL, true, false, filename, line, 1);
- if (!fd)
- goto fail1;
- s->cur_func = fd;
- fd->eval_type = eval_type;
- fd->has_this_binding = (eval_type != JS_EVAL_TYPE_DIRECT);
- fd->backtrace_barrier = ((flags & JS_EVAL_FLAG_BACKTRACE_BARRIER) != 0);
- if (eval_type == JS_EVAL_TYPE_DIRECT) {
- fd->new_target_allowed = b->new_target_allowed;
- fd->super_call_allowed = b->super_call_allowed;
- fd->super_allowed = b->super_allowed;
- fd->arguments_allowed = b->arguments_allowed;
- } else {
- fd->new_target_allowed = false;
- fd->super_call_allowed = false;
- fd->super_allowed = false;
- fd->arguments_allowed = true;
- }
- fd->is_strict_mode = is_strict_mode;
- fd->func_name = JS_DupAtom(ctx, JS_ATOM__eval_);
- if (b) {
- if (add_closure_variables(ctx, fd, b, scope_idx))
- goto fail;
- }
- fd->module = m;
- if (m != NULL || (flags & JS_EVAL_FLAG_ASYNC)) {
- fd->in_function_body = true;
- fd->func_kind = JS_FUNC_ASYNC;
- }
- s->is_module = (m != NULL);
- s->allow_html_comments = !s->is_module;
- push_scope(s); /* body scope */
- fd->body_scope = fd->scope_level;
- err = js_parse_program(s);
- if (err) {
- fail:
- free_token(s, &s->token);
- js_free_function_def(ctx, fd);
- goto fail1;
- }
- if (m != NULL)
- m->has_tla = fd->has_await;
- /* create the function object and all the enclosed functions */
- fun_obj = js_create_function(ctx, fd);
- if (JS_IsException(fun_obj))
- goto fail1;
- /* Could add a flag to avoid resolution if necessary */
- if (m) {
- m->func_obj = fun_obj;
- if (js_resolve_module(ctx, m) < 0)
- goto fail1;
- fun_obj = JS_NewModuleValue(ctx, m);
- }
- if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
- ret_val = fun_obj;
- } else {
- ret_val = JS_EvalFunctionInternal(ctx, fun_obj, this_obj, var_refs, sf);
- }
- return ret_val;
- fail1:
- /* XXX: should free all the unresolved dependencies */
- if (m)
- js_free_module_def(ctx, m);
- return JS_EXCEPTION;
- }
- #endif // QJS_DISABLE_PARSER
- /* the indirection is needed to make 'eval' optional */
- static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
- const char *filename, int line, int flags, int scope_idx)
- {
- JSRuntime *rt = ctx->rt;
- if (unlikely(!ctx->eval_internal)) {
- return JS_ThrowTypeError(ctx, "eval is not supported");
- }
- if (!rt->current_stack_frame) {
- JS_FreeValueRT(rt, ctx->error_back_trace);
- ctx->error_back_trace = JS_UNDEFINED;
- }
- return ctx->eval_internal(ctx, this_obj, input, input_len, filename, line,
- flags, scope_idx);
- }
- static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
- JSValueConst val, int flags, int scope_idx)
- {
- JSValue ret;
- const char *str;
- size_t len;
- if (!JS_IsString(val))
- return js_dup(val);
- str = JS_ToCStringLen(ctx, &len, val);
- if (!str)
- return JS_EXCEPTION;
- ret = JS_EvalInternal(ctx, this_obj, str, len, "<input>", 1, flags, scope_idx);
- JS_FreeCString(ctx, str);
- return ret;
- }
- JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
- const char *filename, int eval_flags)
- {
- JSEvalOptions options = {
- .version = JS_EVAL_OPTIONS_VERSION,
- .filename = filename,
- .line_num = 1,
- .eval_flags = eval_flags
- };
- return JS_EvalThis2(ctx, this_obj, input, input_len, &options);
- }
- JSValue JS_EvalThis2(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
- JSEvalOptions *options)
- {
- const char *filename = "<unnamed>";
- int line = 1;
- int eval_flags = 0;
- if (options) {
- if (options->version != JS_EVAL_OPTIONS_VERSION)
- return JS_ThrowInternalError(ctx, "bad JSEvalOptions version");
- if (options->filename)
- filename = options->filename;
- if (options->line_num != 0)
- line = options->line_num;
- eval_flags = options->eval_flags;
- }
- JSValue ret;
- assert((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_GLOBAL ||
- (eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE);
- ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename, line,
- eval_flags, -1);
- return ret;
- }
- JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
- const char *filename, int eval_flags)
- {
- JSEvalOptions options = {
- .version = JS_EVAL_OPTIONS_VERSION,
- .filename = filename,
- .line_num = 1,
- .eval_flags = eval_flags
- };
- return JS_EvalThis2(ctx, ctx->global_obj, input, input_len, &options);
- }
- JSValue JS_Eval2(JSContext *ctx, const char *input, size_t input_len, JSEvalOptions *options)
- {
- return JS_EvalThis2(ctx, ctx->global_obj, input, input_len, options);
- }
- int JS_ResolveModule(JSContext *ctx, JSValueConst obj)
- {
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
- JSModuleDef *m = JS_VALUE_GET_PTR(obj);
- if (js_resolve_module(ctx, m) < 0) {
- js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
- return -1;
- }
- }
- return 0;
- }
- /*******************************************************************/
- /* object list */
- typedef struct {
- JSObject *obj;
- uint32_t hash_next; /* -1 if no next entry */
- } JSObjectListEntry;
- /* XXX: reuse it to optimize weak references */
- typedef struct {
- JSObjectListEntry *object_tab;
- int object_count;
- int object_size;
- uint32_t *hash_table;
- uint32_t hash_size;
- } JSObjectList;
- static void js_object_list_init(JSObjectList *s)
- {
- memset(s, 0, sizeof(*s));
- }
- static uint32_t js_object_list_get_hash(JSObject *p, uint32_t hash_size)
- {
- return ((uintptr_t)p * 3163) & (hash_size - 1);
- }
- static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s,
- uint32_t new_hash_size)
- {
- JSObjectListEntry *e;
- uint32_t i, h, *new_hash_table;
- new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size);
- if (!new_hash_table)
- return -1;
- js_free(ctx, s->hash_table);
- s->hash_table = new_hash_table;
- s->hash_size = new_hash_size;
- for(i = 0; i < s->hash_size; i++) {
- s->hash_table[i] = -1;
- }
- for(i = 0; i < s->object_count; i++) {
- e = &s->object_tab[i];
- h = js_object_list_get_hash(e->obj, s->hash_size);
- e->hash_next = s->hash_table[h];
- s->hash_table[h] = i;
- }
- return 0;
- }
- /* the reference count of 'obj' is not modified. Return 0 if OK, -1 if
- memory error */
- static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj)
- {
- JSObjectListEntry *e;
- uint32_t h, new_hash_size;
- if (js_resize_array(ctx, (void *)&s->object_tab,
- sizeof(s->object_tab[0]),
- &s->object_size, s->object_count + 1))
- return -1;
- if (unlikely((s->object_count + 1) >= s->hash_size)) {
- new_hash_size = max_uint32(s->hash_size, 4);
- while (new_hash_size <= s->object_count)
- new_hash_size *= 2;
- if (js_object_list_resize_hash(ctx, s, new_hash_size))
- return -1;
- }
- e = &s->object_tab[s->object_count++];
- h = js_object_list_get_hash(obj, s->hash_size);
- e->obj = obj;
- e->hash_next = s->hash_table[h];
- s->hash_table[h] = s->object_count - 1;
- return 0;
- }
- /* return -1 if not present or the object index */
- static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj)
- {
- JSObjectListEntry *e;
- uint32_t h, p;
- /* must test empty size because there is no hash table */
- if (s->object_count == 0)
- return -1;
- h = js_object_list_get_hash(obj, s->hash_size);
- p = s->hash_table[h];
- while (p != -1) {
- e = &s->object_tab[p];
- if (e->obj == obj)
- return p;
- p = e->hash_next;
- }
- return -1;
- }
- static void js_object_list_end(JSContext *ctx, JSObjectList *s)
- {
- js_free(ctx, s->object_tab);
- js_free(ctx, s->hash_table);
- }
- /*******************************************************************/
- /* binary object writer & reader */
- typedef enum BCTagEnum {
- BC_TAG_NULL = 1,
- BC_TAG_UNDEFINED,
- BC_TAG_BOOL_FALSE,
- BC_TAG_BOOL_TRUE,
- BC_TAG_INT32,
- BC_TAG_FLOAT64,
- BC_TAG_STRING,
- BC_TAG_OBJECT,
- BC_TAG_ARRAY,
- BC_TAG_BIG_INT,
- BC_TAG_TEMPLATE_OBJECT,
- BC_TAG_FUNCTION_BYTECODE,
- BC_TAG_MODULE,
- BC_TAG_TYPED_ARRAY,
- BC_TAG_ARRAY_BUFFER,
- BC_TAG_SHARED_ARRAY_BUFFER,
- BC_TAG_REGEXP,
- BC_TAG_DATE,
- BC_TAG_OBJECT_VALUE,
- BC_TAG_OBJECT_REFERENCE,
- BC_TAG_MAP,
- BC_TAG_SET,
- BC_TAG_SYMBOL,
- } BCTagEnum;
- #define BC_VERSION 21
- typedef struct BCWriterState {
- JSContext *ctx;
- DynBuf dbuf;
- bool allow_bytecode;
- bool allow_sab;
- bool allow_reference;
- bool allow_source;
- bool allow_debug;
- uint32_t first_atom;
- uint32_t *atom_to_idx;
- int atom_to_idx_size;
- JSAtom *idx_to_atom;
- int idx_to_atom_count;
- int idx_to_atom_size;
- uint8_t **sab_tab;
- int sab_tab_len;
- int sab_tab_size;
- /* list of referenced objects (used if allow_reference = true) */
- JSObjectList object_list;
- } BCWriterState;
- #ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT
- static const char * const bc_tag_str[] = {
- "invalid",
- "null",
- "undefined",
- "false",
- "true",
- "int32",
- "float64",
- "string",
- "object",
- "array",
- "BigInt",
- "template",
- "function",
- "module",
- "TypedArray",
- "ArrayBuffer",
- "SharedArrayBuffer",
- "RegExp",
- "Date",
- "ObjectValue",
- "ObjectReference",
- "Map",
- "Set",
- "Symbol",
- };
- static const char *bc_tag_name(uint8_t tag)
- {
- if (tag >= countof(bc_tag_str))
- return "<bad tag>";
- return bc_tag_str[tag];
- }
- #endif
- static void bc_put_u8(BCWriterState *s, uint8_t v)
- {
- dbuf_putc(&s->dbuf, v);
- }
- static void bc_put_u16(BCWriterState *s, uint16_t v)
- {
- if (is_be())
- v = bswap16(v);
- dbuf_put_u16(&s->dbuf, v);
- }
- static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
- {
- if (is_be())
- v = bswap32(v);
- dbuf_put_u32(&s->dbuf, v);
- }
- static void bc_put_u64(BCWriterState *s, uint64_t v)
- {
- if (is_be())
- v = bswap64(v);
- dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));
- }
- static void bc_put_leb128(BCWriterState *s, uint32_t v)
- {
- dbuf_put_leb128(&s->dbuf, v);
- }
- static void bc_put_sleb128(BCWriterState *s, int32_t v)
- {
- dbuf_put_sleb128(&s->dbuf, v);
- }
- static void bc_set_flags(uint32_t *pflags, int *pidx, uint32_t val, int n)
- {
- *pflags = *pflags | (val << *pidx);
- *pidx += n;
- }
- static int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom)
- {
- uint32_t v;
- if (atom < s->first_atom || __JS_AtomIsTaggedInt(atom)) {
- *pres = atom;
- return 0;
- }
- atom -= s->first_atom;
- if (atom < s->atom_to_idx_size && s->atom_to_idx[atom] != 0) {
- *pres = s->atom_to_idx[atom];
- return 0;
- }
- if (atom >= s->atom_to_idx_size) {
- int old_size, i;
- old_size = s->atom_to_idx_size;
- if (js_resize_array(s->ctx, (void **)&s->atom_to_idx,
- sizeof(s->atom_to_idx[0]), &s->atom_to_idx_size,
- atom + 1))
- return -1;
- /* XXX: could add a specific js_resize_array() function to do it */
- for(i = old_size; i < s->atom_to_idx_size; i++)
- s->atom_to_idx[i] = 0;
- }
- if (js_resize_array(s->ctx, (void **)&s->idx_to_atom,
- sizeof(s->idx_to_atom[0]),
- &s->idx_to_atom_size, s->idx_to_atom_count + 1))
- goto fail;
- v = s->idx_to_atom_count++;
- s->idx_to_atom[v] = atom + s->first_atom;
- v += s->first_atom;
- s->atom_to_idx[atom] = v;
- *pres = v;
- return 0;
- fail:
- *pres = 0;
- return -1;
- }
- static int bc_put_atom(BCWriterState *s, JSAtom atom)
- {
- uint32_t v;
- if (__JS_AtomIsTaggedInt(atom)) {
- v = (__JS_AtomToUInt32(atom) << 1) | 1;
- } else {
- if (bc_atom_to_idx(s, &v, atom))
- return -1;
- v <<= 1;
- }
- bc_put_leb128(s, v);
- return 0;
- }
- static void bc_byte_swap(uint8_t *bc_buf, int bc_len)
- {
- int pos, len, op, fmt;
- pos = 0;
- while (pos < bc_len) {
- op = bc_buf[pos];
- len = short_opcode_info(op).size;
- fmt = short_opcode_info(op).fmt;
- switch(fmt) {
- case OP_FMT_u16:
- case OP_FMT_i16:
- case OP_FMT_label16:
- case OP_FMT_npop:
- case OP_FMT_loc:
- case OP_FMT_arg:
- case OP_FMT_var_ref:
- put_u16(bc_buf + pos + 1,
- bswap16(get_u16(bc_buf + pos + 1)));
- break;
- case OP_FMT_i32:
- case OP_FMT_u32:
- case OP_FMT_const:
- case OP_FMT_label:
- case OP_FMT_atom:
- case OP_FMT_atom_u8:
- put_u32(bc_buf + pos + 1,
- bswap32(get_u32(bc_buf + pos + 1)));
- break;
- case OP_FMT_atom_u16:
- case OP_FMT_label_u16:
- put_u32(bc_buf + pos + 1,
- bswap32(get_u32(bc_buf + pos + 1)));
- put_u16(bc_buf + pos + 1 + 4,
- bswap16(get_u16(bc_buf + pos + 1 + 4)));
- break;
- case OP_FMT_atom_label_u8:
- case OP_FMT_atom_label_u16:
- put_u32(bc_buf + pos + 1,
- bswap32(get_u32(bc_buf + pos + 1)));
- put_u32(bc_buf + pos + 1 + 4,
- bswap32(get_u32(bc_buf + pos + 1 + 4)));
- if (fmt == OP_FMT_atom_label_u16) {
- put_u16(bc_buf + pos + 1 + 4 + 4,
- bswap16(get_u16(bc_buf + pos + 1 + 4 + 4)));
- }
- break;
- case OP_FMT_npop_u16:
- put_u16(bc_buf + pos + 1,
- bswap16(get_u16(bc_buf + pos + 1)));
- put_u16(bc_buf + pos + 1 + 2,
- bswap16(get_u16(bc_buf + pos + 1 + 2)));
- break;
- default:
- break;
- }
- pos += len;
- }
- }
- static int JS_WriteFunctionBytecode(BCWriterState *s,
- const JSFunctionBytecode *b)
- {
- int pos, len, bc_len, op;
- JSAtom atom;
- uint8_t *bc_buf;
- uint32_t val;
- bc_len = b->byte_code_len;
- bc_buf = js_malloc(s->ctx, bc_len);
- if (!bc_buf)
- return -1;
- memcpy(bc_buf, b->byte_code_buf, bc_len);
- pos = 0;
- while (pos < bc_len) {
- op = bc_buf[pos];
- len = short_opcode_info(op).size;
- switch(short_opcode_info(op).fmt) {
- case OP_FMT_atom:
- case OP_FMT_atom_u8:
- case OP_FMT_atom_u16:
- case OP_FMT_atom_label_u8:
- case OP_FMT_atom_label_u16:
- atom = get_u32(bc_buf + pos + 1);
- if (bc_atom_to_idx(s, &val, atom))
- goto fail;
- put_u32(bc_buf + pos + 1, val);
- break;
- default:
- break;
- }
- pos += len;
- }
- if (is_be())
- bc_byte_swap(bc_buf, bc_len);
- dbuf_put(&s->dbuf, bc_buf, bc_len);
- js_free(s->ctx, bc_buf);
- return 0;
- fail:
- js_free(s->ctx, bc_buf);
- return -1;
- }
- static void JS_WriteString(BCWriterState *s, JSString *p)
- {
- int i;
- bc_put_leb128(s, ((uint32_t)p->len << 1) | p->is_wide_char);
- if (p->is_wide_char) {
- for(i = 0; i < p->len; i++)
- bc_put_u16(s, str16(p)[i]);
- } else {
- dbuf_put(&s->dbuf, str8(p), p->len);
- }
- }
- static int JS_WriteBigInt(BCWriterState *s, JSValueConst obj)
- {
- JSBigIntBuf buf;
- JSBigInt *p;
- uint32_t len, i;
- js_limb_t v, b;
- int shift;
- bc_put_u8(s, BC_TAG_BIG_INT);
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_SHORT_BIG_INT)
- p = js_bigint_set_short(&buf, obj);
- else
- p = JS_VALUE_GET_PTR(obj);
- if (p->len == 1 && p->tab[0] == 0) {
- /* zero case */
- len = 0;
- } else {
- /* compute the length of the two's complement representation
- in bytes */
- len = p->len * (JS_LIMB_BITS / 8);
- v = p->tab[p->len - 1];
- shift = JS_LIMB_BITS - 8;
- while (shift > 0) {
- b = (v >> shift) & 0xff;
- if (b != 0x00 && b != 0xff)
- break;
- if ((b & 1) != ((v >> (shift - 1)) & 1))
- break;
- shift -= 8;
- len--;
- }
- }
- bc_put_leb128(s, len);
- if (len > 0) {
- for(i = 0; i < (len / (JS_LIMB_BITS / 8)); i++) {
- bc_put_u32(s, p->tab[i]);
- }
- for(i = 0; i < len % (JS_LIMB_BITS / 8); i++) {
- bc_put_u8(s, (p->tab[p->len - 1] >> (i * 8)) & 0xff);
- }
- }
- return 0;
- }
- static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj);
- static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
- {
- JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj);
- uint32_t flags;
- int idx, i;
- bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE);
- flags = idx = 0;
- bc_set_flags(&flags, &idx, b->has_prototype, 1);
- bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1);
- bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1);
- bc_set_flags(&flags, &idx, b->need_home_object, 1);
- bc_set_flags(&flags, &idx, b->func_kind, 2);
- bc_set_flags(&flags, &idx, b->new_target_allowed, 1);
- bc_set_flags(&flags, &idx, b->super_call_allowed, 1);
- bc_set_flags(&flags, &idx, b->super_allowed, 1);
- bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
- bc_set_flags(&flags, &idx, b->backtrace_barrier, 1);
- bc_set_flags(&flags, &idx, s->allow_debug, 1);
- assert(idx <= 16);
- bc_put_u16(s, flags);
- bc_put_u8(s, b->is_strict_mode);
- bc_put_atom(s, b->func_name);
- bc_put_leb128(s, b->arg_count);
- bc_put_leb128(s, b->var_count);
- bc_put_leb128(s, b->defined_arg_count);
- bc_put_leb128(s, b->stack_size);
- bc_put_leb128(s, b->closure_var_count);
- bc_put_leb128(s, b->cpool_count);
- bc_put_leb128(s, b->byte_code_len);
- if (b->vardefs) {
- /* XXX: this field is redundant */
- bc_put_leb128(s, b->arg_count + b->var_count);
- for(i = 0; i < b->arg_count + b->var_count; i++) {
- JSVarDef *vd = &b->vardefs[i];
- bc_put_atom(s, vd->var_name);
- bc_put_leb128(s, vd->scope_level);
- bc_put_leb128(s, vd->scope_next + 1);
- flags = idx = 0;
- bc_set_flags(&flags, &idx, vd->var_kind, 4);
- bc_set_flags(&flags, &idx, vd->is_const, 1);
- bc_set_flags(&flags, &idx, vd->is_lexical, 1);
- bc_set_flags(&flags, &idx, vd->is_captured, 1);
- assert(idx <= 8);
- bc_put_u8(s, flags);
- }
- } else {
- bc_put_leb128(s, 0);
- }
- for(i = 0; i < b->closure_var_count; i++) {
- JSClosureVar *cv = &b->closure_var[i];
- bc_put_atom(s, cv->var_name);
- bc_put_leb128(s, cv->var_idx);
- flags = idx = 0;
- bc_set_flags(&flags, &idx, cv->is_local, 1);
- bc_set_flags(&flags, &idx, cv->is_arg, 1);
- bc_set_flags(&flags, &idx, cv->is_const, 1);
- bc_set_flags(&flags, &idx, cv->is_lexical, 1);
- bc_set_flags(&flags, &idx, cv->var_kind, 4);
- assert(idx <= 8);
- bc_put_u8(s, flags);
- }
- // write constant pool before code so code can be disassembled
- // on the fly at read time
- for(i = 0; i < b->cpool_count; i++) {
- if (JS_WriteObjectRec(s, b->cpool[i]))
- goto fail;
- }
- if (JS_WriteFunctionBytecode(s, b))
- goto fail;
- if (s->allow_debug) {
- bc_put_atom(s, b->filename);
- bc_put_leb128(s, b->line_num);
- bc_put_leb128(s, b->col_num);
- bc_put_leb128(s, b->pc2line_len);
- dbuf_put(&s->dbuf, b->pc2line_buf, b->pc2line_len);
- if (s->allow_source && b->source) {
- bc_put_leb128(s, b->source_len);
- dbuf_put(&s->dbuf, b->source, b->source_len);
- } else {
- bc_put_leb128(s, 0);
- }
- }
- return 0;
- fail:
- return -1;
- }
- static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
- {
- JSModuleDef *m = JS_VALUE_GET_PTR(obj);
- int i;
- bc_put_u8(s, BC_TAG_MODULE);
- bc_put_atom(s, m->module_name);
- bc_put_leb128(s, m->req_module_entries_count);
- for(i = 0; i < m->req_module_entries_count; i++) {
- JSReqModuleEntry *rme = &m->req_module_entries[i];
- bc_put_atom(s, rme->module_name);
- }
- bc_put_leb128(s, m->export_entries_count);
- for(i = 0; i < m->export_entries_count; i++) {
- JSExportEntry *me = &m->export_entries[i];
- bc_put_u8(s, me->export_type);
- if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
- bc_put_leb128(s, me->u.local.var_idx);
- } else {
- bc_put_leb128(s, me->u.req_module_idx);
- bc_put_atom(s, me->local_name);
- }
- bc_put_atom(s, me->export_name);
- }
- bc_put_leb128(s, m->star_export_entries_count);
- for(i = 0; i < m->star_export_entries_count; i++) {
- JSStarExportEntry *se = &m->star_export_entries[i];
- bc_put_leb128(s, se->req_module_idx);
- }
- bc_put_leb128(s, m->import_entries_count);
- for(i = 0; i < m->import_entries_count; i++) {
- JSImportEntry *mi = &m->import_entries[i];
- bc_put_leb128(s, mi->var_idx);
- bc_put_atom(s, mi->import_name);
- bc_put_leb128(s, mi->req_module_idx);
- }
- bc_put_u8(s, m->has_tla);
- if (JS_WriteObjectRec(s, m->func_obj))
- goto fail;
- return 0;
- fail:
- return -1;
- }
- static int JS_WriteArray(BCWriterState *s, JSValueConst obj)
- {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- uint32_t i, len;
- JSValue val;
- int ret;
- bool is_template;
- if (s->allow_bytecode && !p->extensible) {
- /* not extensible array: we consider it is a
- template when we are saving bytecode */
- bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT);
- is_template = true;
- } else {
- bc_put_u8(s, BC_TAG_ARRAY);
- is_template = false;
- }
- if (js_get_length32(s->ctx, &len, obj))
- goto fail1;
- bc_put_leb128(s, len);
- for(i = 0; i < len; i++) {
- val = JS_GetPropertyUint32(s->ctx, obj, i);
- if (JS_IsException(val))
- goto fail1;
- ret = JS_WriteObjectRec(s, val);
- JS_FreeValue(s->ctx, val);
- if (ret)
- goto fail1;
- }
- if (is_template) {
- val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw);
- if (JS_IsException(val))
- goto fail1;
- ret = JS_WriteObjectRec(s, val);
- JS_FreeValue(s->ctx, val);
- if (ret)
- goto fail1;
- }
- return 0;
- fail1:
- return -1;
- }
- static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj)
- {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- uint32_t i, prop_count;
- JSShape *sh;
- JSShapeProperty *pr;
- int pass;
- JSAtom atom;
- bc_put_u8(s, BC_TAG_OBJECT);
- prop_count = 0;
- sh = p->shape;
- for(pass = 0; pass < 2; pass++) {
- if (pass == 1)
- bc_put_leb128(s, prop_count);
- for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
- atom = pr->atom;
- if (atom != JS_ATOM_NULL && (pr->flags & JS_PROP_ENUMERABLE)) {
- if (pr->flags & JS_PROP_TMASK) {
- JS_ThrowTypeError(s->ctx, "only value properties are supported");
- goto fail;
- }
- if (pass == 0) {
- prop_count++;
- } else {
- bc_put_atom(s, atom);
- if (JS_WriteObjectRec(s, p->prop[i].u.value))
- goto fail;
- }
- }
- }
- }
- return 0;
- fail:
- return -1;
- }
- static int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj)
- {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- JSTypedArray *ta = p->u.typed_array;
- bc_put_u8(s, BC_TAG_TYPED_ARRAY);
- bc_put_u8(s, p->class_id - JS_CLASS_UINT8C_ARRAY);
- bc_put_leb128(s, p->u.array.count);
- bc_put_leb128(s, ta->offset);
- if (JS_WriteObjectRec(s, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)))
- return -1;
- return 0;
- }
- static int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj)
- {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- JSArrayBuffer *abuf = p->u.array_buffer;
- if (abuf->detached) {
- JS_ThrowTypeErrorDetachedArrayBuffer(s->ctx);
- return -1;
- }
- bc_put_u8(s, BC_TAG_ARRAY_BUFFER);
- bc_put_leb128(s, abuf->byte_length);
- bc_put_leb128(s, abuf->max_byte_length);
- dbuf_put(&s->dbuf, abuf->data, abuf->byte_length);
- return 0;
- }
- static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj)
- {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- JSArrayBuffer *abuf = p->u.array_buffer;
- assert(!abuf->detached); /* SharedArrayBuffer are never detached */
- bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER);
- bc_put_leb128(s, abuf->byte_length);
- bc_put_leb128(s, abuf->max_byte_length);
- bc_put_u64(s, (uintptr_t)abuf->data);
- if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]),
- &s->sab_tab_size, s->sab_tab_len + 1))
- return -1;
- /* keep the SAB pointer so that the user can clone it or free it */
- s->sab_tab[s->sab_tab_len++] = abuf->data;
- return 0;
- }
- static int JS_WriteRegExp(BCWriterState *s, JSRegExp regexp)
- {
- JSString *bc = regexp.bytecode;
- assert(!bc->is_wide_char);
- JS_WriteString(s, regexp.pattern);
- if (is_be())
- lre_byte_swap(str8(bc), bc->len, /*is_byte_swapped*/false);
- JS_WriteString(s, bc);
- if (is_be())
- lre_byte_swap(str8(bc), bc->len, /*is_byte_swapped*/true);
- return 0;
- }
- static int JS_WriteMap(BCWriterState *s, struct JSMapState *map_state);
- static int JS_WriteSet(BCWriterState *s, struct JSMapState *map_state);
- static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
- {
- uint32_t tag;
- if (js_check_stack_overflow(s->ctx->rt, 0)) {
- JS_ThrowStackOverflow(s->ctx);
- return -1;
- }
- tag = JS_VALUE_GET_NORM_TAG(obj);
- switch(tag) {
- case JS_TAG_NULL:
- bc_put_u8(s, BC_TAG_NULL);
- break;
- case JS_TAG_UNDEFINED:
- bc_put_u8(s, BC_TAG_UNDEFINED);
- break;
- case JS_TAG_BOOL:
- bc_put_u8(s, BC_TAG_BOOL_FALSE + JS_VALUE_GET_INT(obj));
- break;
- case JS_TAG_INT:
- bc_put_u8(s, BC_TAG_INT32);
- bc_put_sleb128(s, JS_VALUE_GET_INT(obj));
- break;
- case JS_TAG_FLOAT64:
- {
- JSFloat64Union u;
- bc_put_u8(s, BC_TAG_FLOAT64);
- u.d = JS_VALUE_GET_FLOAT64(obj);
- bc_put_u64(s, u.u64);
- }
- break;
- case JS_TAG_STRING:
- {
- JSString *p = JS_VALUE_GET_STRING(obj);
- bc_put_u8(s, BC_TAG_STRING);
- JS_WriteString(s, p);
- }
- break;
- case JS_TAG_FUNCTION_BYTECODE:
- if (!s->allow_bytecode)
- goto invalid_tag;
- if (JS_WriteFunctionTag(s, obj))
- goto fail;
- break;
- case JS_TAG_MODULE:
- if (!s->allow_bytecode)
- goto invalid_tag;
- if (JS_WriteModule(s, obj))
- goto fail;
- break;
- case JS_TAG_OBJECT:
- {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- int ret, idx;
- if (s->allow_reference) {
- idx = js_object_list_find(s->ctx, &s->object_list, p);
- if (idx >= 0) {
- bc_put_u8(s, BC_TAG_OBJECT_REFERENCE);
- bc_put_leb128(s, idx);
- break;
- } else {
- if (js_object_list_add(s->ctx, &s->object_list, p))
- goto fail;
- }
- } else {
- if (p->tmp_mark) {
- JS_ThrowTypeError(s->ctx, "circular reference");
- goto fail;
- }
- p->tmp_mark = 1;
- }
- switch(p->class_id) {
- case JS_CLASS_ARRAY:
- ret = JS_WriteArray(s, obj);
- break;
- case JS_CLASS_OBJECT:
- ret = JS_WriteObjectTag(s, obj);
- break;
- case JS_CLASS_ARRAY_BUFFER:
- ret = JS_WriteArrayBuffer(s, obj);
- break;
- case JS_CLASS_SHARED_ARRAY_BUFFER:
- if (!s->allow_sab)
- goto invalid_tag;
- ret = JS_WriteSharedArrayBuffer(s, obj);
- break;
- case JS_CLASS_REGEXP:
- bc_put_u8(s, BC_TAG_REGEXP);
- ret = JS_WriteRegExp(s, p->u.regexp);
- break;
- case JS_CLASS_DATE:
- bc_put_u8(s, BC_TAG_DATE);
- ret = JS_WriteObjectRec(s, p->u.object_data);
- break;
- case JS_CLASS_NUMBER:
- case JS_CLASS_STRING:
- case JS_CLASS_BOOLEAN:
- case JS_CLASS_BIG_INT:
- bc_put_u8(s, BC_TAG_OBJECT_VALUE);
- ret = JS_WriteObjectRec(s, p->u.object_data);
- break;
- case JS_CLASS_MAP:
- bc_put_u8(s, BC_TAG_MAP);
- ret = JS_WriteMap(s, p->u.map_state);
- break;
- case JS_CLASS_SET:
- bc_put_u8(s, BC_TAG_SET);
- ret = JS_WriteSet(s, p->u.map_state);
- break;
- default:
- if (is_typed_array(p->class_id)) {
- ret = JS_WriteTypedArray(s, obj);
- } else {
- JS_ThrowTypeError(s->ctx, "unsupported object class");
- ret = -1;
- }
- break;
- }
- p->tmp_mark = 0;
- if (ret)
- goto fail;
- }
- break;
- case JS_TAG_SHORT_BIG_INT:
- case JS_TAG_BIG_INT:
- if (JS_WriteBigInt(s, obj))
- goto fail;
- break;
- case JS_TAG_SYMBOL:
- {
- JSAtomStruct *p = JS_VALUE_GET_PTR(obj);
- if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL && p->atom_type != JS_ATOM_TYPE_SYMBOL) {
- JS_ThrowTypeError(s->ctx, "unsupported symbol type");
- goto fail;
- }
- JSAtom atom = js_get_atom_index(s->ctx->rt, p);
- bc_put_u8(s, BC_TAG_SYMBOL);
- bc_put_atom(s, atom);
- }
- break;
- default:
- invalid_tag:
- JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag);
- goto fail;
- }
- return 0;
- fail:
- return -1;
- }
- /* create the atom table */
- static int JS_WriteObjectAtoms(BCWriterState *s)
- {
- JSRuntime *rt = s->ctx->rt;
- DynBuf dbuf1;
- int i, atoms_size;
- dbuf1 = s->dbuf;
- js_dbuf_init(s->ctx, &s->dbuf);
- bc_put_u8(s, BC_VERSION);
- bc_put_leb128(s, s->idx_to_atom_count);
- for(i = 0; i < s->idx_to_atom_count; i++) {
- JSAtom atom = s->idx_to_atom[i];
- if (__JS_AtomIsConst(atom)) {
- bc_put_u8(s, 0 /* the type */);
- /* TODO(saghul): encoding for tagged integers and keyword-ish atoms could be
- more efficient. */
- bc_put_u32(s, atom);
- } else {
- JSAtomStruct *p = rt->atom_array[atom];
- uint8_t type = p->atom_type;
- assert(type != JS_ATOM_TYPE_PRIVATE);
- bc_put_u8(s, type);
- JS_WriteString(s, p);
- }
- }
- /* XXX: should check for OOM in above phase */
- /* move the atoms at the start */
- /* XXX: could just append dbuf1 data, but it uses more memory if
- dbuf1 is larger than dbuf */
- atoms_size = s->dbuf.size;
- if (dbuf_realloc(&dbuf1, dbuf1.size + atoms_size))
- goto fail;
- memmove(dbuf1.buf + atoms_size, dbuf1.buf, dbuf1.size);
- memcpy(dbuf1.buf, s->dbuf.buf, atoms_size);
- dbuf1.size += atoms_size;
- dbuf_free(&s->dbuf);
- s->dbuf = dbuf1;
- return 0;
- fail:
- dbuf_free(&dbuf1);
- return -1;
- }
- uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
- int flags, JSSABTab *psab_tab)
- {
- BCWriterState ss, *s = &ss;
- memset(s, 0, sizeof(*s));
- s->ctx = ctx;
- s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
- s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
- s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);
- s->allow_source = ((flags & JS_WRITE_OBJ_STRIP_SOURCE) == 0);
- s->allow_debug = ((flags & JS_WRITE_OBJ_STRIP_DEBUG) == 0);
- /* XXX: could use a different version when bytecode is included */
- if (s->allow_bytecode)
- s->first_atom = JS_ATOM_END;
- else
- s->first_atom = 1;
- js_dbuf_init(ctx, &s->dbuf);
- js_object_list_init(&s->object_list);
- if (JS_WriteObjectRec(s, obj))
- goto fail;
- if (JS_WriteObjectAtoms(s))
- goto fail;
- js_object_list_end(ctx, &s->object_list);
- js_free(ctx, s->atom_to_idx);
- js_free(ctx, s->idx_to_atom);
- *psize = s->dbuf.size;
- if (psab_tab) {
- psab_tab->tab = s->sab_tab;
- psab_tab->len = s->sab_tab_len;
- } else {
- js_free(ctx, s->sab_tab);
- }
- return s->dbuf.buf;
- fail:
- js_object_list_end(ctx, &s->object_list);
- js_free(ctx, s->atom_to_idx);
- js_free(ctx, s->idx_to_atom);
- dbuf_free(&s->dbuf);
- *psize = 0;
- if (psab_tab) {
- psab_tab->tab = NULL;
- psab_tab->len = 0;
- }
- return NULL;
- }
- uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
- int flags)
- {
- return JS_WriteObject2(ctx, psize, obj, flags, NULL);
- }
- typedef struct BCReaderState {
- JSContext *ctx;
- const uint8_t *buf_start, *ptr, *buf_end;
- uint32_t first_atom;
- uint32_t idx_to_atom_count;
- JSAtom *idx_to_atom;
- int error_state;
- bool allow_sab;
- bool allow_bytecode;
- bool allow_reference;
- /* object references */
- JSObject **objects;
- int objects_count;
- int objects_size;
- /* SAB references */
- uint8_t **sab_tab;
- int sab_tab_len;
- int sab_tab_size;
- /* used for JS_DUMP_READ_OBJECT */
- const uint8_t *ptr_last;
- int level;
- } BCReaderState;
- #ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT
- static void JS_PRINTF_FORMAT_ATTR(2, 3) bc_read_trace(BCReaderState *s, JS_PRINTF_FORMAT const char *fmt, ...) {
- va_list ap;
- int i, n, n0;
- if (!check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT))
- return;
- if (!s->ptr_last)
- s->ptr_last = s->buf_start;
- n = n0 = 0;
- if (s->ptr > s->ptr_last || s->ptr == s->buf_start) {
- n0 = printf("%04x: ", (int)(s->ptr_last - s->buf_start));
- n += n0;
- }
- for (i = 0; s->ptr_last < s->ptr; i++) {
- if ((i & 7) == 0 && i > 0) {
- printf("\n%*s", n0, "");
- n = n0;
- }
- n += printf(" %02x", *s->ptr_last++);
- }
- if (*fmt == '}')
- s->level--;
- if (n < 32 + s->level * 2) {
- printf("%*s", 32 + s->level * 2 - n, "");
- }
- va_start(ap, fmt);
- vfprintf(stdout, fmt, ap);
- va_end(ap);
- if (strchr(fmt, '{'))
- s->level++;
- }
- #else
- #define bc_read_trace(...)
- #endif
- static int bc_read_error_end(BCReaderState *s)
- {
- if (!s->error_state) {
- JS_ThrowSyntaxError(s->ctx, "read after the end of the buffer");
- }
- return s->error_state = -1;
- }
- static int bc_get_u8(BCReaderState *s, uint8_t *pval)
- {
- if (unlikely(s->buf_end - s->ptr < 1)) {
- *pval = 0; /* avoid warning */
- return bc_read_error_end(s);
- }
- *pval = *s->ptr++;
- return 0;
- }
- static int bc_get_u16(BCReaderState *s, uint16_t *pval)
- {
- uint16_t v;
- if (unlikely(s->buf_end - s->ptr < 2)) {
- *pval = 0; /* avoid warning */
- return bc_read_error_end(s);
- }
- v = get_u16(s->ptr);
- if (is_be())
- v = bswap16(v);
- *pval = v;
- s->ptr += 2;
- return 0;
- }
- static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
- {
- uint32_t v;
- if (unlikely(s->buf_end - s->ptr < 4)) {
- *pval = 0; /* avoid warning */
- return bc_read_error_end(s);
- }
- v = get_u32(s->ptr);
- if (is_be())
- v = bswap32(v);
- *pval = v;
- s->ptr += 4;
- return 0;
- }
- static int bc_get_u64(BCReaderState *s, uint64_t *pval)
- {
- uint64_t v;
- if (unlikely(s->buf_end - s->ptr < 8)) {
- *pval = 0; /* avoid warning */
- return bc_read_error_end(s);
- }
- v = get_u64(s->ptr);
- if (is_be())
- v = bswap64(v);
- *pval = v;
- s->ptr += 8;
- return 0;
- }
- static int bc_get_leb128(BCReaderState *s, uint32_t *pval)
- {
- int ret;
- ret = get_leb128(pval, s->ptr, s->buf_end);
- if (unlikely(ret < 0))
- return bc_read_error_end(s);
- s->ptr += ret;
- return 0;
- }
- static int bc_get_sleb128(BCReaderState *s, int32_t *pval)
- {
- int ret;
- ret = get_sleb128(pval, s->ptr, s->buf_end);
- if (unlikely(ret < 0))
- return bc_read_error_end(s);
- s->ptr += ret;
- return 0;
- }
- /* XXX: used to read an `int` with a positive value */
- static int bc_get_leb128_int(BCReaderState *s, int *pval)
- {
- return bc_get_leb128(s, (uint32_t *)pval);
- }
- static int bc_get_leb128_u16(BCReaderState *s, uint16_t *pval)
- {
- uint32_t val;
- if (bc_get_leb128(s, &val)) {
- *pval = 0;
- return -1;
- }
- *pval = val;
- return 0;
- }
- static int bc_get_buf(BCReaderState *s, void *buf, uint32_t buf_len)
- {
- if (buf_len != 0) {
- if (unlikely(!buf || s->buf_end - s->ptr < buf_len))
- return bc_read_error_end(s);
- memcpy(buf, s->ptr, buf_len);
- s->ptr += buf_len;
- }
- return 0;
- }
- static int bc_idx_to_atom(BCReaderState *s, JSAtom *patom, uint32_t idx)
- {
- JSAtom atom;
- if (__JS_AtomIsTaggedInt(idx)) {
- atom = idx;
- } else if (idx < s->first_atom) {
- atom = JS_DupAtom(s->ctx, idx);
- } else {
- idx -= s->first_atom;
- if (idx >= s->idx_to_atom_count) {
- JS_ThrowSyntaxError(s->ctx, "invalid atom index (pos=%u)",
- (unsigned int)(s->ptr - s->buf_start));
- *patom = JS_ATOM_NULL;
- return s->error_state = -1;
- }
- atom = JS_DupAtom(s->ctx, s->idx_to_atom[idx]);
- }
- *patom = atom;
- return 0;
- }
- static int bc_get_atom(BCReaderState *s, JSAtom *patom)
- {
- uint32_t v;
- if (bc_get_leb128(s, &v))
- return -1;
- if (v & 1) {
- *patom = __JS_AtomFromUInt32(v >> 1);
- return 0;
- } else {
- return bc_idx_to_atom(s, patom, v >> 1);
- }
- }
- static JSString *JS_ReadString(BCReaderState *s)
- {
- uint32_t len;
- size_t size;
- bool is_wide_char;
- JSString *p;
- if (bc_get_leb128(s, &len))
- return NULL;
- is_wide_char = len & 1;
- len >>= 1;
- if (len > JS_STRING_LEN_MAX) {
- JS_ThrowInternalError(s->ctx, "string too long");
- return NULL;
- }
- p = js_alloc_string(s->ctx, len, is_wide_char);
- if (!p) {
- s->error_state = -1;
- return NULL;
- }
- size = (size_t)len << is_wide_char;
- if ((s->buf_end - s->ptr) < size) {
- bc_read_error_end(s);
- js_free_string(s->ctx->rt, p);
- return NULL;
- }
- memcpy(str8(p), s->ptr, size);
- s->ptr += size;
- if (is_wide_char) {
- if (is_be()) {
- uint32_t i;
- for (i = 0; i < len; i++)
- str16(p)[i] = bswap16(str16(p)[i]);
- }
- } else {
- str8(p)[size] = '\0'; /* add the trailing zero for 8 bit strings */
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT
- if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) {
- bc_read_trace(s, "%s", ""); // hex dump and indentation
- JS_DumpString(s->ctx->rt, p);
- printf("\n");
- }
- #endif
- return p;
- }
- static uint32_t bc_get_flags(uint32_t flags, int *pidx, int n)
- {
- uint32_t val;
- /* XXX: this does not work for n == 32 */
- val = (flags >> *pidx) & ((1U << n) - 1);
- *pidx += n;
- return val;
- }
- static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
- int byte_code_offset, uint32_t bc_len)
- {
- uint8_t *bc_buf;
- int pos, len, op;
- JSAtom atom;
- uint32_t idx;
- bc_buf = (uint8_t*)b + byte_code_offset;
- if (bc_get_buf(s, bc_buf, bc_len))
- return -1;
- b->byte_code_buf = bc_buf;
- if (is_be())
- bc_byte_swap(bc_buf, bc_len);
- pos = 0;
- while (pos < bc_len) {
- op = bc_buf[pos];
- len = short_opcode_info(op).size;
- switch(short_opcode_info(op).fmt) {
- case OP_FMT_atom:
- case OP_FMT_atom_u8:
- case OP_FMT_atom_u16:
- case OP_FMT_atom_label_u8:
- case OP_FMT_atom_label_u16:
- idx = get_u32(bc_buf + pos + 1);
- if (bc_idx_to_atom(s, &atom, idx)) {
- /* Note: the atoms will be freed up to this position */
- b->byte_code_len = pos;
- return -1;
- }
- put_u32(bc_buf + pos + 1, atom);
- break;
- default:
- break;
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT
- if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) {
- const uint8_t *save_ptr = s->ptr;
- s->ptr = s->ptr_last + len;
- s->level -= 4;
- bc_read_trace(s, "%s", ""); // hex dump + indent
- dump_single_byte_code(s->ctx, bc_buf + pos, b,
- s->ptr - s->buf_start - len);
- s->level += 4;
- s->ptr = save_ptr;
- }
- #endif
- pos += len;
- }
- return 0;
- }
- static JSValue JS_ReadBigInt(BCReaderState *s)
- {
- JSValue obj = JS_UNDEFINED;
- uint32_t len, i, n;
- JSBigInt *p;
- js_limb_t v;
- uint8_t v8;
- if (bc_get_leb128(s, &len))
- goto fail;
- bc_read_trace(s, "len=%" PRId64 "\n", (int64_t)len);
- if (len == 0) {
- /* zero case */
- bc_read_trace(s, "}\n");
- return __JS_NewShortBigInt(s->ctx, 0);
- }
- p = js_bigint_new(s->ctx, (len - 1) / (JS_LIMB_BITS / 8) + 1);
- if (!p)
- goto fail;
- for(i = 0; i < len / (JS_LIMB_BITS / 8); i++) {
- if (bc_get_u32(s, &v))
- goto fail;
- p->tab[i] = v;
- }
- n = len % (JS_LIMB_BITS / 8);
- if (n != 0) {
- int shift;
- v = 0;
- for(i = 0; i < n; i++) {
- if (bc_get_u8(s, &v8))
- goto fail;
- v |= (js_limb_t)v8 << (i * 8);
- }
- shift = JS_LIMB_BITS - n * 8;
- /* extend the sign */
- if (shift != 0) {
- v = (js_slimb_t)(v << shift) >> shift;
- }
- p->tab[p->len - 1] = v;
- }
- bc_read_trace(s, "}\n");
- return JS_CompactBigInt(s->ctx, p);
- fail:
- JS_FreeValue(s->ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue JS_ReadObjectRec(BCReaderState *s);
- static int BC_add_object_ref1(BCReaderState *s, JSObject *p)
- {
- if (s->allow_reference) {
- if (js_resize_array(s->ctx, (void *)&s->objects,
- sizeof(s->objects[0]),
- &s->objects_size, s->objects_count + 1))
- return -1;
- s->objects[s->objects_count++] = p;
- }
- return 0;
- }
- static int BC_add_object_ref(BCReaderState *s, JSValue obj)
- {
- return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj));
- }
- static JSValue JS_ReadFunctionTag(BCReaderState *s)
- {
- JSContext *ctx = s->ctx;
- JSFunctionBytecode bc, *b;
- JSValue obj = JS_UNDEFINED;
- uint16_t v16;
- uint8_t v8;
- int idx, i, local_count, has_debug_info;
- int function_size, cpool_offset, byte_code_offset;
- int closure_var_offset, vardefs_offset;
- memset(&bc, 0, sizeof(bc));
- bc.header.ref_count = 1;
- //bc.gc_header.mark = 0;
- if (bc_get_u16(s, &v16))
- goto fail;
- idx = 0;
- bc.has_prototype = bc_get_flags(v16, &idx, 1);
- bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1);
- bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1);
- bc.need_home_object = bc_get_flags(v16, &idx, 1);
- bc.func_kind = bc_get_flags(v16, &idx, 2);
- bc.new_target_allowed = bc_get_flags(v16, &idx, 1);
- bc.super_call_allowed = bc_get_flags(v16, &idx, 1);
- bc.super_allowed = bc_get_flags(v16, &idx, 1);
- bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
- bc.backtrace_barrier = bc_get_flags(v16, &idx, 1);
- has_debug_info = bc_get_flags(v16, &idx, 1);
- if (bc_get_u8(s, &v8))
- goto fail;
- bc.is_strict_mode = (v8 > 0);
- if (bc_get_atom(s, &bc.func_name))
- goto fail;
- if (bc_get_leb128_u16(s, &bc.arg_count))
- goto fail;
- if (bc_get_leb128_u16(s, &bc.var_count))
- goto fail;
- if (bc_get_leb128_u16(s, &bc.defined_arg_count))
- goto fail;
- if (bc_get_leb128_u16(s, &bc.stack_size))
- goto fail;
- if (bc_get_leb128_int(s, &bc.closure_var_count))
- goto fail;
- if (bc_get_leb128_int(s, &bc.cpool_count))
- goto fail;
- if (bc_get_leb128_int(s, &bc.byte_code_len))
- goto fail;
- if (bc_get_leb128_int(s, &local_count))
- goto fail;
- function_size = sizeof(*b);
- cpool_offset = function_size;
- function_size += bc.cpool_count * sizeof(*bc.cpool);
- vardefs_offset = function_size;
- function_size += local_count * sizeof(*bc.vardefs);
- closure_var_offset = function_size;
- function_size += bc.closure_var_count * sizeof(*bc.closure_var);
- byte_code_offset = function_size;
- function_size += bc.byte_code_len;
- b = js_mallocz(ctx, function_size);
- if (!b)
- goto fail;
- memcpy(b, &bc, sizeof(*b));
- bc.func_name = JS_ATOM_NULL;
- b->header.ref_count = 1;
- if (local_count != 0) {
- b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
- }
- if (b->closure_var_count != 0) {
- b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
- }
- if (b->cpool_count != 0) {
- b->cpool = (void *)((uint8_t*)b + cpool_offset);
- }
- add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
- obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
- #ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT
- if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) {
- if (b->func_name) {
- bc_read_trace(s, "name: ");
- print_atom(s->ctx, b->func_name);
- printf("\n");
- }
- }
- #endif
- bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n",
- b->arg_count, b->var_count, b->defined_arg_count,
- b->closure_var_count, b->cpool_count);
- bc_read_trace(s, "stack=%d bclen=%d locals=%d\n",
- b->stack_size, b->byte_code_len, local_count);
- if (local_count != 0) {
- bc_read_trace(s, "vars {\n");
- bc_read_trace(s, "off flags scope name\n");
- for(i = 0; i < local_count; i++) {
- JSVarDef *vd = &b->vardefs[i];
- if (bc_get_atom(s, &vd->var_name))
- goto fail;
- if (bc_get_leb128_int(s, &vd->scope_level))
- goto fail;
- if (bc_get_leb128_int(s, &vd->scope_next))
- goto fail;
- vd->scope_next--;
- if (bc_get_u8(s, &v8))
- goto fail;
- idx = 0;
- vd->var_kind = bc_get_flags(v8, &idx, 4);
- vd->is_const = bc_get_flags(v8, &idx, 1);
- vd->is_lexical = bc_get_flags(v8, &idx, 1);
- vd->is_captured = bc_get_flags(v8, &idx, 1);
- #ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT
- if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) {
- bc_read_trace(s, "%3d %d%c%c%c %4d ",
- i, vd->var_kind,
- vd->is_const ? 'C' : '.',
- vd->is_lexical ? 'L' : '.',
- vd->is_captured ? 'X' : '.',
- vd->scope_level);
- print_atom(s->ctx, vd->var_name);
- printf("\n");
- }
- #endif
- }
- bc_read_trace(s, "}\n");
- }
- if (b->closure_var_count != 0) {
- bc_read_trace(s, "closure vars {\n");
- bc_read_trace(s, "off flags idx name\n");
- for(i = 0; i < b->closure_var_count; i++) {
- JSClosureVar *cv = &b->closure_var[i];
- int var_idx;
- if (bc_get_atom(s, &cv->var_name))
- goto fail;
- if (bc_get_leb128_int(s, &var_idx))
- goto fail;
- cv->var_idx = var_idx;
- if (bc_get_u8(s, &v8))
- goto fail;
- idx = 0;
- cv->is_local = bc_get_flags(v8, &idx, 1);
- cv->is_arg = bc_get_flags(v8, &idx, 1);
- cv->is_const = bc_get_flags(v8, &idx, 1);
- cv->is_lexical = bc_get_flags(v8, &idx, 1);
- cv->var_kind = bc_get_flags(v8, &idx, 4);
- #ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT
- if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) {
- bc_read_trace(s, "%3d %d%c%c%c%c %3d ",
- i, cv->var_kind,
- cv->is_local ? 'L' : '.',
- cv->is_arg ? 'A' : '.',
- cv->is_const ? 'C' : '.',
- cv->is_lexical ? 'X' : '.',
- cv->var_idx);
- print_atom(s->ctx, cv->var_name);
- printf("\n");
- }
- #endif
- }
- bc_read_trace(s, "}\n");
- }
- if (b->cpool_count != 0) {
- bc_read_trace(s, "cpool {\n");
- for(i = 0; i < b->cpool_count; i++) {
- JSValue val;
- val = JS_ReadObjectRec(s);
- if (JS_IsException(val))
- goto fail;
- b->cpool[i] = val;
- }
- bc_read_trace(s, "}\n");
- }
- {
- bc_read_trace(s, "bytecode {\n");
- if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len))
- goto fail;
- bc_read_trace(s, "}\n");
- }
- if (!has_debug_info)
- goto nodebug;
- /* read optional debug information */
- bc_read_trace(s, "debug {\n");
- if (bc_get_atom(s, &b->filename))
- goto fail;
- if (bc_get_leb128_int(s, &b->line_num))
- goto fail;
- if (bc_get_leb128_int(s, &b->col_num))
- goto fail;
- #ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT
- if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) {
- bc_read_trace(s, "filename: ");
- print_atom(s->ctx, b->filename);
- printf(", line: %d, column: %d\n", b->line_num, b->col_num);
- }
- #endif
- if (bc_get_leb128_int(s, &b->pc2line_len))
- goto fail;
- if (b->pc2line_len) {
- bc_read_trace(s, "positions: %d bytes\n", b->pc2line_len);
- b->pc2line_buf = js_mallocz(ctx, b->pc2line_len);
- if (!b->pc2line_buf)
- goto fail;
- if (bc_get_buf(s, b->pc2line_buf, b->pc2line_len))
- goto fail;
- }
- if (bc_get_leb128_int(s, &b->source_len))
- goto fail;
- if (b->source_len) {
- bc_read_trace(s, "source: %d bytes\n", b->source_len);
- if (s->ptr_last)
- s->ptr_last += b->source_len; // omit source code hex dump
- /* b->source is a UTF-8 encoded null terminated C string */
- b->source = js_mallocz(ctx, b->source_len + 1);
- if (!b->source)
- goto fail;
- if (bc_get_buf(s, b->source, b->source_len))
- goto fail;
- }
- bc_read_trace(s, "}\n");
- nodebug:
- b->realm = JS_DupContext(ctx);
- return obj;
- fail:
- JS_FreeAtom(ctx, bc.func_name);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue JS_ReadModule(BCReaderState *s)
- {
- JSContext *ctx = s->ctx;
- JSValue obj;
- JSModuleDef *m = NULL;
- JSAtom module_name;
- int i;
- uint8_t v8;
- if (bc_get_atom(s, &module_name))
- goto fail;
- #ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT
- if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) {
- bc_read_trace(s, "name: ");
- print_atom(s->ctx, module_name);
- printf("\n");
- }
- #endif
- m = js_new_module_def(ctx, module_name);
- if (!m)
- goto fail;
- obj = js_dup(JS_MKPTR(JS_TAG_MODULE, m));
- if (bc_get_leb128_int(s, &m->req_module_entries_count))
- goto fail;
- obj = JS_NewModuleValue(ctx, m);
- if (m->req_module_entries_count != 0) {
- m->req_module_entries_size = m->req_module_entries_count;
- m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size);
- if (!m->req_module_entries)
- goto fail;
- for(i = 0; i < m->req_module_entries_count; i++) {
- JSReqModuleEntry *rme = &m->req_module_entries[i];
- JSModuleDef **pm = &rme->module;
- if (bc_get_atom(s, &rme->module_name))
- goto fail;
- // Resolves a module either from the cache or by requesting
- // it from the module loader. From cache is not ideal because
- // the module may not be the one it was a time of serialization
- // but directly petitioning the module loader is not correct
- // either because then the same module can get loaded twice.
- // JS_WriteModule() does not serialize modules transitively
- // because that doesn't work for C modules and is also prone
- // to loading the same JS module twice.
- *pm = js_host_resolve_imported_module_atom(s->ctx, m->module_name,
- rme->module_name);
- if (!*pm)
- goto fail;
- }
- }
- if (bc_get_leb128_int(s, &m->export_entries_count))
- goto fail;
- if (m->export_entries_count != 0) {
- m->export_entries_size = m->export_entries_count;
- m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size);
- if (!m->export_entries)
- goto fail;
- for(i = 0; i < m->export_entries_count; i++) {
- JSExportEntry *me = &m->export_entries[i];
- if (bc_get_u8(s, &v8))
- goto fail;
- me->export_type = v8;
- if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
- if (bc_get_leb128_int(s, &me->u.local.var_idx))
- goto fail;
- } else {
- if (bc_get_leb128_int(s, &me->u.req_module_idx))
- goto fail;
- if (bc_get_atom(s, &me->local_name))
- goto fail;
- }
- if (bc_get_atom(s, &me->export_name))
- goto fail;
- }
- }
- if (bc_get_leb128_int(s, &m->star_export_entries_count))
- goto fail;
- if (m->star_export_entries_count != 0) {
- m->star_export_entries_size = m->star_export_entries_count;
- m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size);
- if (!m->star_export_entries)
- goto fail;
- for(i = 0; i < m->star_export_entries_count; i++) {
- JSStarExportEntry *se = &m->star_export_entries[i];
- if (bc_get_leb128_int(s, &se->req_module_idx))
- goto fail;
- }
- }
- if (bc_get_leb128_int(s, &m->import_entries_count))
- goto fail;
- if (m->import_entries_count != 0) {
- m->import_entries_size = m->import_entries_count;
- m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size);
- if (!m->import_entries)
- goto fail;
- for(i = 0; i < m->import_entries_count; i++) {
- JSImportEntry *mi = &m->import_entries[i];
- if (bc_get_leb128_int(s, &mi->var_idx))
- goto fail;
- if (bc_get_atom(s, &mi->import_name))
- goto fail;
- if (bc_get_leb128_int(s, &mi->req_module_idx))
- goto fail;
- }
- }
- if (bc_get_u8(s, &v8))
- goto fail;
- m->has_tla = (v8 != 0);
- m->func_obj = JS_ReadObjectRec(s);
- if (JS_IsException(m->func_obj))
- goto fail;
- return obj;
- fail:
- if (m) {
- js_free_module_def(ctx, m);
- }
- return JS_EXCEPTION;
- }
- static JSValue JS_ReadObjectTag(BCReaderState *s)
- {
- JSContext *ctx = s->ctx;
- JSValue obj;
- uint32_t prop_count, i;
- JSAtom atom;
- JSValue val;
- int ret;
- obj = JS_NewObject(ctx);
- if (BC_add_object_ref(s, obj))
- goto fail;
- if (bc_get_leb128(s, &prop_count))
- goto fail;
- for(i = 0; i < prop_count; i++) {
- if (bc_get_atom(s, &atom))
- goto fail;
- #ifdef ENABLE_DUMPS // JS_DUMP_READ_OBJECT
- if (check_dump_flag(s->ctx->rt, JS_DUMP_READ_OBJECT)) {
- bc_read_trace(s, "propname: ");
- print_atom(s->ctx, atom);
- printf("\n");
- }
- #endif
- val = JS_ReadObjectRec(s);
- if (JS_IsException(val)) {
- JS_FreeAtom(ctx, atom);
- goto fail;
- }
- ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E);
- JS_FreeAtom(ctx, atom);
- if (ret < 0)
- goto fail;
- }
- return obj;
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue JS_ReadArray(BCReaderState *s, int tag)
- {
- JSContext *ctx = s->ctx;
- JSValue obj;
- uint32_t len, i;
- JSValue val;
- int ret, prop_flags;
- bool is_template;
- obj = JS_NewArray(ctx);
- if (BC_add_object_ref(s, obj))
- goto fail;
- is_template = (tag == BC_TAG_TEMPLATE_OBJECT);
- if (bc_get_leb128(s, &len))
- goto fail;
- for(i = 0; i < len; i++) {
- val = JS_ReadObjectRec(s);
- if (JS_IsException(val))
- goto fail;
- if (is_template)
- prop_flags = JS_PROP_ENUMERABLE;
- else
- prop_flags = JS_PROP_C_W_E;
- ret = JS_DefinePropertyValueUint32(ctx, obj, i, val,
- prop_flags);
- if (ret < 0)
- goto fail;
- }
- if (is_template) {
- val = JS_ReadObjectRec(s);
- if (JS_IsException(val))
- goto fail;
- if (!JS_IsUndefined(val)) {
- ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0);
- if (ret < 0)
- goto fail;
- }
- JS_PreventExtensions(ctx, obj);
- }
- return obj;
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue JS_ReadTypedArray(BCReaderState *s)
- {
- JSContext *ctx = s->ctx;
- JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED;
- uint8_t array_tag;
- JSValueConst args[3];
- uint32_t offset, len, idx;
- if (bc_get_u8(s, &array_tag))
- return JS_EXCEPTION;
- if (array_tag >= JS_TYPED_ARRAY_COUNT)
- return JS_ThrowTypeError(ctx, "invalid typed array");
- if (bc_get_leb128(s, &len))
- return JS_EXCEPTION;
- if (bc_get_leb128(s, &offset))
- return JS_EXCEPTION;
- /* XXX: this hack could be avoided if the typed array could be
- created before the array buffer */
- idx = s->objects_count;
- if (BC_add_object_ref1(s, NULL))
- goto fail;
- array_buffer = JS_ReadObjectRec(s);
- if (JS_IsException(array_buffer))
- return JS_EXCEPTION;
- if (!js_get_array_buffer(ctx, array_buffer)) {
- JS_FreeValue(ctx, array_buffer);
- return JS_EXCEPTION;
- }
- args[0] = array_buffer;
- args[1] = js_int64(offset);
- args[2] = js_int64(len);
- obj = js_typed_array_constructor(ctx, JS_UNDEFINED,
- 3, args,
- JS_CLASS_UINT8C_ARRAY + array_tag);
- if (JS_IsException(obj))
- goto fail;
- if (s->allow_reference) {
- s->objects[idx] = JS_VALUE_GET_OBJ(obj);
- }
- JS_FreeValue(ctx, array_buffer);
- return obj;
- fail:
- JS_FreeValue(ctx, array_buffer);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue JS_ReadArrayBuffer(BCReaderState *s)
- {
- JSContext *ctx = s->ctx;
- uint32_t byte_length, max_byte_length;
- uint64_t max_byte_length_u64, *pmax_byte_length = NULL;
- JSValue obj;
- if (bc_get_leb128(s, &byte_length))
- return JS_EXCEPTION;
- if (bc_get_leb128(s, &max_byte_length))
- return JS_EXCEPTION;
- if (max_byte_length < byte_length)
- return JS_ThrowTypeError(ctx, "invalid array buffer");
- if (max_byte_length != UINT32_MAX) {
- max_byte_length_u64 = max_byte_length;
- pmax_byte_length = &max_byte_length_u64;
- }
- if (unlikely(s->buf_end - s->ptr < byte_length)) {
- bc_read_error_end(s);
- return JS_EXCEPTION;
- }
- // makes a copy of the input
- obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED,
- byte_length, pmax_byte_length,
- JS_CLASS_ARRAY_BUFFER,
- (uint8_t*)s->ptr,
- js_array_buffer_free, NULL,
- /*alloc_flag*/true);
- if (JS_IsException(obj))
- goto fail;
- if (BC_add_object_ref(s, obj))
- goto fail;
- s->ptr += byte_length;
- return obj;
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s)
- {
- JSContext *ctx = s->ctx;
- uint32_t byte_length, max_byte_length;
- uint64_t max_byte_length_u64, *pmax_byte_length = NULL;
- uint8_t *data_ptr;
- JSValue obj;
- uint64_t u64;
- if (bc_get_leb128(s, &byte_length))
- return JS_EXCEPTION;
- if (bc_get_leb128(s, &max_byte_length))
- return JS_EXCEPTION;
- if (max_byte_length < byte_length)
- return JS_ThrowTypeError(ctx, "invalid array buffer");
- if (max_byte_length != UINT32_MAX) {
- max_byte_length_u64 = max_byte_length;
- pmax_byte_length = &max_byte_length_u64;
- }
- if (bc_get_u64(s, &u64))
- return JS_EXCEPTION;
- data_ptr = (uint8_t *)(uintptr_t)u64;
- if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]),
- &s->sab_tab_size, s->sab_tab_len + 1))
- return JS_EXCEPTION;
- /* keep the SAB pointer so that the user can clone it or free it */
- s->sab_tab[s->sab_tab_len++] = data_ptr;
- /* the SharedArrayBuffer is cloned */
- obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED,
- byte_length, pmax_byte_length,
- JS_CLASS_SHARED_ARRAY_BUFFER,
- data_ptr,
- NULL, NULL, false);
- if (JS_IsException(obj))
- goto fail;
- if (BC_add_object_ref(s, obj))
- goto fail;
- return obj;
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue JS_ReadRegExp(BCReaderState *s)
- {
- JSContext *ctx = s->ctx;
- JSString *pattern;
- JSString *bc;
- pattern = JS_ReadString(s);
- if (!pattern)
- return JS_EXCEPTION;
- bc = JS_ReadString(s);
- if (!bc) {
- js_free_string(ctx->rt, pattern);
- return JS_EXCEPTION;
- }
- if (bc->is_wide_char) {
- js_free_string(ctx->rt, pattern);
- js_free_string(ctx->rt, bc);
- return JS_ThrowInternalError(ctx, "bad regexp bytecode");
- }
- if (is_be())
- lre_byte_swap(str8(bc), bc->len, /*is_byte_swapped*/true);
- return js_regexp_constructor_internal(ctx, JS_UNDEFINED,
- JS_MKPTR(JS_TAG_STRING, pattern),
- JS_MKPTR(JS_TAG_STRING, bc));
- }
- static JSValue JS_ReadDate(BCReaderState *s)
- {
- JSContext *ctx = s->ctx;
- JSValue val, obj = JS_UNDEFINED;
- val = JS_ReadObjectRec(s);
- if (JS_IsException(val))
- goto fail;
- if (!JS_IsNumber(val)) {
- JS_ThrowTypeError(ctx, "Number tag expected for date");
- goto fail;
- }
- obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE],
- JS_CLASS_DATE);
- if (JS_IsException(obj))
- goto fail;
- if (BC_add_object_ref(s, obj))
- goto fail;
- JS_SetObjectData(ctx, obj, val);
- return obj;
- fail:
- JS_FreeValue(ctx, val);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue JS_ReadObjectValue(BCReaderState *s)
- {
- JSContext *ctx = s->ctx;
- JSValue val, obj = JS_UNDEFINED;
- val = JS_ReadObjectRec(s);
- if (JS_IsException(val))
- goto fail;
- obj = JS_ToObject(ctx, val);
- if (JS_IsException(obj))
- goto fail;
- if (BC_add_object_ref(s, obj))
- goto fail;
- JS_FreeValue(ctx, val);
- return obj;
- fail:
- JS_FreeValue(ctx, val);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue JS_ReadMap(BCReaderState *s);
- static JSValue JS_ReadSet(BCReaderState *s);
- static JSValue JS_ReadObjectRec(BCReaderState *s)
- {
- JSContext *ctx = s->ctx;
- uint8_t tag;
- JSValue obj = JS_UNDEFINED;
- if (js_check_stack_overflow(ctx->rt, 0))
- return JS_ThrowStackOverflow(ctx);
- if (bc_get_u8(s, &tag))
- return JS_EXCEPTION;
- bc_read_trace(s, "%s {\n", bc_tag_name(tag));
- switch(tag) {
- case BC_TAG_NULL:
- obj = JS_NULL;
- break;
- case BC_TAG_UNDEFINED:
- obj = JS_UNDEFINED;
- break;
- case BC_TAG_BOOL_FALSE:
- case BC_TAG_BOOL_TRUE:
- obj = js_bool(tag - BC_TAG_BOOL_FALSE);
- break;
- case BC_TAG_INT32:
- {
- int32_t val;
- if (bc_get_sleb128(s, &val))
- return JS_EXCEPTION;
- bc_read_trace(s, "%d\n", val);
- obj = js_int32(val);
- }
- break;
- case BC_TAG_FLOAT64:
- {
- JSFloat64Union u;
- if (bc_get_u64(s, &u.u64))
- return JS_EXCEPTION;
- bc_read_trace(s, "%g\n", u.d);
- obj = js_float64(u.d);
- }
- break;
- case BC_TAG_STRING:
- {
- JSString *p;
- p = JS_ReadString(s);
- if (!p)
- return JS_EXCEPTION;
- obj = JS_MKPTR(JS_TAG_STRING, p);
- }
- break;
- case BC_TAG_FUNCTION_BYTECODE:
- if (!s->allow_bytecode)
- goto no_allow_bytecode;
- obj = JS_ReadFunctionTag(s);
- break;
- case BC_TAG_MODULE:
- if (!s->allow_bytecode) {
- no_allow_bytecode:
- return JS_ThrowSyntaxError(ctx, "no bytecode allowed");
- }
- obj = JS_ReadModule(s);
- break;
- case BC_TAG_OBJECT:
- obj = JS_ReadObjectTag(s);
- break;
- case BC_TAG_ARRAY:
- case BC_TAG_TEMPLATE_OBJECT:
- obj = JS_ReadArray(s, tag);
- break;
- case BC_TAG_TYPED_ARRAY:
- obj = JS_ReadTypedArray(s);
- break;
- case BC_TAG_ARRAY_BUFFER:
- obj = JS_ReadArrayBuffer(s);
- break;
- case BC_TAG_SHARED_ARRAY_BUFFER:
- if (!s->allow_sab || !ctx->rt->sab_funcs.sab_dup)
- goto invalid_tag;
- obj = JS_ReadSharedArrayBuffer(s);
- break;
- case BC_TAG_REGEXP:
- obj = JS_ReadRegExp(s);
- break;
- case BC_TAG_DATE:
- obj = JS_ReadDate(s);
- break;
- case BC_TAG_OBJECT_VALUE:
- obj = JS_ReadObjectValue(s);
- break;
- case BC_TAG_BIG_INT:
- obj = JS_ReadBigInt(s);
- break;
- case BC_TAG_OBJECT_REFERENCE:
- {
- uint32_t val;
- if (!s->allow_reference)
- return JS_ThrowSyntaxError(ctx, "object references are not allowed");
- if (bc_get_leb128(s, &val))
- return JS_EXCEPTION;
- bc_read_trace(s, "%u\n", val);
- if (val >= s->objects_count) {
- return JS_ThrowSyntaxError(ctx, "invalid object reference (%u >= %u)",
- val, s->objects_count);
- }
- obj = js_dup(JS_MKPTR(JS_TAG_OBJECT, s->objects[val]));
- }
- break;
- case BC_TAG_MAP:
- obj = JS_ReadMap(s);
- break;
- case BC_TAG_SET:
- obj = JS_ReadSet(s);
- break;
- case BC_TAG_SYMBOL:
- {
- JSAtom atom;
- if (bc_get_atom(s, &atom))
- return JS_EXCEPTION;
- if (__JS_AtomIsConst(atom)) {
- obj = JS_AtomToValue(s->ctx, atom);
- } else {
- JSAtomStruct *p = s->ctx->rt->atom_array[atom];
- obj = JS_NewSymbolFromAtom(s->ctx, atom, p->atom_type);
- }
- }
- break;
- default:
- invalid_tag:
- return JS_ThrowSyntaxError(ctx, "invalid tag (tag=%d pos=%u)",
- tag, (unsigned int)(s->ptr - s->buf_start));
- }
- bc_read_trace(s, "}\n");
- return obj;
- }
- static int JS_ReadObjectAtoms(BCReaderState *s)
- {
- uint8_t v8, type;
- JSString *p;
- int i;
- JSAtom atom;
- if (bc_get_u8(s, &v8))
- return -1;
- if (v8 != BC_VERSION) {
- JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)",
- v8, BC_VERSION);
- return -1;
- }
- if (bc_get_leb128(s, &s->idx_to_atom_count))
- return -1;
- if (s->idx_to_atom_count > 1000*1000) {
- JS_ThrowInternalError(s->ctx, "unreasonable atom count: %u",
- s->idx_to_atom_count);
- return -1;
- }
- bc_read_trace(s, "%u atom indexes {\n", s->idx_to_atom_count);
- if (s->idx_to_atom_count != 0) {
- s->idx_to_atom = js_mallocz(s->ctx, s->idx_to_atom_count *
- sizeof(s->idx_to_atom[0]));
- if (!s->idx_to_atom)
- return s->error_state = -1;
- }
- for(i = 0; i < s->idx_to_atom_count; i++) {
- if (bc_get_u8(s, &type)) {
- return -1;
- }
- if (type == 0) {
- if (bc_get_u32(s, &atom))
- return -1;
- if (!__JS_AtomIsConst(atom)) {
- JS_ThrowInternalError(s->ctx, "out of range atom");
- return -1;
- }
- } else {
- if (type < JS_ATOM_TYPE_STRING || type >= JS_ATOM_TYPE_PRIVATE) {
- JS_ThrowInternalError(s->ctx, "invalid symbol type %d", type);
- return -1;
- }
- p = JS_ReadString(s);
- if (!p)
- return -1;
- atom = __JS_NewAtom(s->ctx->rt, p, type);
- }
- if (atom == JS_ATOM_NULL)
- return s->error_state = -1;
- s->idx_to_atom[i] = atom;
- }
- bc_read_trace(s, "}\n");
- return 0;
- }
- static void bc_reader_free(BCReaderState *s)
- {
- int i;
- if (s->idx_to_atom) {
- for(i = 0; i < s->idx_to_atom_count; i++) {
- JS_FreeAtom(s->ctx, s->idx_to_atom[i]);
- }
- js_free(s->ctx, s->idx_to_atom);
- }
- js_free(s->ctx, s->objects);
- }
- JSValue JS_ReadObject2(JSContext *ctx, const uint8_t *buf, size_t buf_len,
- int flags, JSSABTab *psab_tab)
- {
- BCReaderState ss, *s = &ss;
- JSValue obj;
- ctx->binary_object_count += 1;
- ctx->binary_object_size += buf_len;
- memset(s, 0, sizeof(*s));
- s->ctx = ctx;
- s->buf_start = buf;
- s->buf_end = buf + buf_len;
- s->ptr = buf;
- s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0);
- s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0);
- s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0);
- if (s->allow_bytecode)
- s->first_atom = JS_ATOM_END;
- else
- s->first_atom = 1;
- if (JS_ReadObjectAtoms(s)) {
- obj = JS_EXCEPTION;
- } else {
- obj = JS_ReadObjectRec(s);
- }
- if (psab_tab) {
- psab_tab->tab = s->sab_tab;
- psab_tab->len = s->sab_tab_len;
- } else {
- js_free(ctx, s->sab_tab);
- }
- bc_reader_free(s);
- return obj;
- }
- JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
- int flags)
- {
- return JS_ReadObject2(ctx, buf, buf_len, flags, NULL);
- }
- /*******************************************************************/
- /* runtime functions & objects */
- static JSValue js_string_constructor(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv);
- static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv);
- static JSValue js_number_constructor(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv);
- static int check_function(JSContext *ctx, JSValueConst obj)
- {
- if (likely(JS_IsFunction(ctx, obj)))
- return 0;
- JS_ThrowTypeErrorNotAFunction(ctx);
- return -1;
- }
- static int check_exception_free(JSContext *ctx, JSValue obj)
- {
- JS_FreeValue(ctx, obj);
- return JS_IsException(obj);
- }
- /* `export_name` may be pure ASCII or UTF-8 encoded */
- static JSAtom find_atom(JSContext *ctx, const char *name)
- {
- JSAtom atom;
- int len;
- if (*name == '[') {
- name++;
- len = strlen(name) - 1;
- /* We assume 8 bit non null strings, which is the case for these
- symbols */
- for(atom = JS_ATOM_Symbol_toPrimitive; atom < JS_ATOM_END; atom++) {
- JSAtomStruct *p = ctx->rt->atom_array[atom];
- JSString *str = p;
- if (str->len == len && !memcmp(str8(str), name, len))
- return JS_DupAtom(ctx, atom);
- }
- abort();
- } else {
- atom = JS_NewAtom(ctx, name);
- }
- return atom;
- }
- static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
- JSAtom atom, void *opaque)
- {
- const JSCFunctionListEntry *e = opaque;
- JSValue val;
- switch(e->def_type) {
- case JS_DEF_CFUNC:
- val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
- e->name, e->u.func.length, e->u.func.cproto, e->magic);
- break;
- case JS_DEF_PROP_STRING:
- val = JS_NewAtomString(ctx, e->u.str);
- break;
- case JS_DEF_OBJECT:
- val = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
- break;
- default:
- abort();
- }
- return val;
- }
- static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
- JSAtom atom,
- const JSCFunctionListEntry *e)
- {
- JSValue val;
- int prop_flags = e->prop_flags;
- switch(e->def_type) {
- case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */
- {
- JSAtom atom1 = find_atom(ctx, e->u.alias.name);
- switch (e->u.alias.base) {
- case -1:
- val = JS_GetProperty(ctx, obj, atom1);
- break;
- case 0:
- val = JS_GetProperty(ctx, ctx->global_obj, atom1);
- break;
- case 1:
- val = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], atom1);
- break;
- default:
- abort();
- }
- JS_FreeAtom(ctx, atom1);
- if (atom == JS_ATOM_Symbol_toPrimitive) {
- /* Symbol.toPrimitive functions are not writable */
- prop_flags = JS_PROP_CONFIGURABLE;
- } else if (atom == JS_ATOM_Symbol_hasInstance) {
- /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
- prop_flags = 0;
- }
- }
- break;
- case JS_DEF_CFUNC:
- if (atom == JS_ATOM_Symbol_toPrimitive) {
- /* Symbol.toPrimitive functions are not writable */
- prop_flags = JS_PROP_CONFIGURABLE;
- } else if (atom == JS_ATOM_Symbol_hasInstance) {
- /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
- prop_flags = 0;
- }
- JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
- (void *)e, prop_flags);
- return 0;
- case JS_DEF_CGETSET: /* XXX: use autoinit again ? */
- case JS_DEF_CGETSET_MAGIC:
- {
- JSValue getter, setter;
- char buf[64];
- getter = JS_UNDEFINED;
- if (e->u.getset.get.generic) {
- snprintf(buf, sizeof(buf), "get %s", e->name);
- getter = JS_NewCFunction2(ctx, e->u.getset.get.generic,
- buf, 0, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_getter_magic : JS_CFUNC_getter,
- e->magic);
- }
- setter = JS_UNDEFINED;
- if (e->u.getset.set.generic) {
- snprintf(buf, sizeof(buf), "set %s", e->name);
- setter = JS_NewCFunction2(ctx, e->u.getset.set.generic,
- buf, 1, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_setter_magic : JS_CFUNC_setter,
- e->magic);
- }
- JS_DefinePropertyGetSet(ctx, obj, atom, getter, setter, prop_flags);
- return 0;
- }
- break;
- case JS_DEF_PROP_INT32:
- val = js_int32(e->u.i32);
- break;
- case JS_DEF_PROP_INT64:
- val = js_int64(e->u.i64);
- break;
- case JS_DEF_PROP_DOUBLE:
- val = js_float64(e->u.f64);
- break;
- case JS_DEF_PROP_UNDEFINED:
- val = JS_UNDEFINED;
- break;
- case JS_DEF_PROP_STRING:
- case JS_DEF_OBJECT:
- JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
- (void *)e, prop_flags);
- return 0;
- default:
- abort();
- }
- JS_DefinePropertyValue(ctx, obj, atom, val, prop_flags);
- return 0;
- }
- int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
- const JSCFunctionListEntry *tab, int len)
- {
- int i, ret;
- for (i = 0; i < len; i++) {
- const JSCFunctionListEntry *e = &tab[i];
- JSAtom atom = find_atom(ctx, e->name);
- if (atom == JS_ATOM_NULL)
- return -1;
- ret = JS_InstantiateFunctionListItem(ctx, obj, atom, e);
- JS_FreeAtom(ctx, atom);
- if (ret)
- return -1;
- }
- return 0;
- }
- int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
- const JSCFunctionListEntry *tab, int len)
- {
- int i;
- for(i = 0; i < len; i++) {
- if (JS_AddModuleExport(ctx, m, tab[i].name))
- return -1;
- }
- return 0;
- }
- int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
- const JSCFunctionListEntry *tab, int len)
- {
- int i;
- JSValue val;
- for(i = 0; i < len; i++) {
- const JSCFunctionListEntry *e = &tab[i];
- switch(e->def_type) {
- case JS_DEF_CFUNC:
- val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
- e->name, e->u.func.length, e->u.func.cproto, e->magic);
- break;
- case JS_DEF_PROP_STRING:
- /* `e->u.str` may be pure ASCII or UTF-8 encoded */
- val = JS_NewString(ctx, e->u.str);
- break;
- case JS_DEF_PROP_INT32:
- val = js_int32(e->u.i32);
- break;
- case JS_DEF_PROP_INT64:
- val = js_int64(e->u.i64);
- break;
- case JS_DEF_PROP_DOUBLE:
- val = js_float64(e->u.f64);
- break;
- case JS_DEF_OBJECT:
- val = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
- break;
- default:
- abort();
- }
- if (JS_SetModuleExport(ctx, m, e->name, val))
- return -1;
- }
- return 0;
- }
- /* Note: 'func_obj' is not necessarily a constructor */
- static void JS_SetConstructor2(JSContext *ctx,
- JSValueConst func_obj,
- JSValueConst proto,
- int proto_flags, int ctor_flags)
- {
- JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype,
- js_dup(proto), proto_flags);
- JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
- js_dup(func_obj), ctor_flags);
- }
- void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
- JSValueConst proto)
- {
- JS_SetConstructor2(ctx, func_obj, proto,
- 0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- }
- static void JS_NewGlobalCConstructor2(JSContext *ctx,
- JSValue func_obj,
- const char *name,
- JSValueConst proto)
- {
- JS_DefinePropertyValueStr(ctx, ctx->global_obj, name,
- js_dup(func_obj),
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- JS_SetConstructor(ctx, func_obj, proto);
- JS_FreeValue(ctx, func_obj);
- }
- static JSValue JS_NewGlobalCConstructor(JSContext *ctx, const char *name,
- JSCFunction *func, int length,
- JSValueConst proto)
- {
- JSValue func_obj;
- func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor_or_func, 0);
- JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
- return func_obj;
- }
- static JSValue JS_NewGlobalCConstructorOnly(JSContext *ctx, const char *name,
- JSCFunction *func, int length,
- JSValue proto)
- {
- JSValue func_obj;
- func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor, 0);
- JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
- return func_obj;
- }
- static JSValue js_global_eval(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return JS_EvalObject(ctx, ctx->global_obj, argv[0], JS_EVAL_TYPE_INDIRECT, -1);
- }
- static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- double d;
- if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
- return JS_EXCEPTION;
- return js_bool(isnan(d));
- }
- static JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- bool res;
- double d;
- if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
- return JS_EXCEPTION;
- res = isfinite(d);
- return js_bool(res);
- }
- static JSValue js_microtask_job(JSContext *ctx,
- int argc, JSValueConst *argv)
- {
- return JS_Call(ctx, argv[0], ctx->global_obj, 0, NULL);
- }
- static JSValue js_global_queueMicrotask(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- if (check_function(ctx, argv[0]))
- return JS_EXCEPTION;
- if (JS_EnqueueJob(ctx, js_microtask_job, 1, &argv[0]))
- return JS_EXCEPTION;
- return JS_UNDEFINED;
- }
- /* Object class */
- JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
- {
- int tag = JS_VALUE_GET_NORM_TAG(val);
- JSValue obj;
- switch(tag) {
- default:
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- return JS_ThrowTypeError(ctx, "Cannot convert undefined or null to object");
- case JS_TAG_OBJECT:
- case JS_TAG_EXCEPTION:
- return js_dup(val);
- case JS_TAG_SHORT_BIG_INT:
- case JS_TAG_BIG_INT:
- obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
- goto set_value;
- case JS_TAG_INT:
- case JS_TAG_FLOAT64:
- obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
- goto set_value;
- case JS_TAG_STRING:
- /* XXX: should call the string constructor */
- {
- JSString *p1 = JS_VALUE_GET_STRING(val);
- obj = JS_NewObjectClass(ctx, JS_CLASS_STRING);
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, js_int32(p1->len), 0);
- }
- goto set_value;
- case JS_TAG_BOOL:
- obj = JS_NewObjectClass(ctx, JS_CLASS_BOOLEAN);
- goto set_value;
- case JS_TAG_SYMBOL:
- obj = JS_NewObjectClass(ctx, JS_CLASS_SYMBOL);
- set_value:
- if (!JS_IsException(obj))
- JS_SetObjectData(ctx, obj, js_dup(val));
- return obj;
- }
- }
- static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val)
- {
- JSValue obj = JS_ToObject(ctx, val);
- JS_FreeValue(ctx, val);
- return obj;
- }
- static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
- JSValueConst desc)
- {
- JSValue val, getter, setter;
- int present;
- int flags;
- if (!JS_IsObject(desc)) {
- JS_ThrowTypeError(ctx, "Property description must be an object");
- return -1;
- }
- flags = 0;
- val = JS_UNDEFINED;
- getter = JS_UNDEFINED;
- setter = JS_UNDEFINED;
- present = JS_HasProperty(ctx, desc, JS_ATOM_enumerable);
- if (present < 0)
- goto fail;
- if (present) {
- JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable);
- if (JS_IsException(prop))
- goto fail;
- flags |= JS_PROP_HAS_ENUMERABLE;
- if (JS_ToBoolFree(ctx, prop))
- flags |= JS_PROP_ENUMERABLE;
- }
- present = JS_HasProperty(ctx, desc, JS_ATOM_configurable);
- if (present < 0)
- goto fail;
- if (present) {
- JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);
- if (JS_IsException(prop))
- goto fail;
- flags |= JS_PROP_HAS_CONFIGURABLE;
- if (JS_ToBoolFree(ctx, prop))
- flags |= JS_PROP_CONFIGURABLE;
- }
- present = JS_HasProperty(ctx, desc, JS_ATOM_value);
- if (present < 0)
- goto fail;
- if (present) {
- flags |= JS_PROP_HAS_VALUE;
- val = JS_GetProperty(ctx, desc, JS_ATOM_value);
- if (JS_IsException(val))
- goto fail;
- }
- present = JS_HasProperty(ctx, desc, JS_ATOM_writable);
- if (present < 0)
- goto fail;
- if (present) {
- JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);
- if (JS_IsException(prop))
- goto fail;
- flags |= JS_PROP_HAS_WRITABLE;
- if (JS_ToBoolFree(ctx, prop))
- flags |= JS_PROP_WRITABLE;
- }
- present = JS_HasProperty(ctx, desc, JS_ATOM_get);
- if (present < 0)
- goto fail;
- if (present) {
- flags |= JS_PROP_HAS_GET;
- getter = JS_GetProperty(ctx, desc, JS_ATOM_get);
- if (JS_IsException(getter) ||
- !(JS_IsUndefined(getter) || JS_IsFunction(ctx, getter))) {
- JS_ThrowTypeError(ctx, "Getter must be a function");
- goto fail;
- }
- }
- present = JS_HasProperty(ctx, desc, JS_ATOM_set);
- if (present < 0)
- goto fail;
- if (present) {
- flags |= JS_PROP_HAS_SET;
- setter = JS_GetProperty(ctx, desc, JS_ATOM_set);
- if (JS_IsException(setter) ||
- !(JS_IsUndefined(setter) || JS_IsFunction(ctx, setter))) {
- JS_ThrowTypeError(ctx, "Setter must be a function");
- goto fail;
- }
- }
- if ((flags & (JS_PROP_HAS_SET | JS_PROP_HAS_GET)) &&
- (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) {
- JS_ThrowTypeError(ctx, "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute");
- goto fail;
- }
- d->flags = flags;
- d->value = val;
- d->getter = getter;
- d->setter = setter;
- return 0;
- fail:
- JS_FreeValue(ctx, val);
- JS_FreeValue(ctx, getter);
- JS_FreeValue(ctx, setter);
- return -1;
- }
- static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
- JSAtom prop, JSValueConst desc,
- int flags)
- {
- JSPropertyDescriptor d;
- int ret;
- if (js_obj_to_desc(ctx, &d, desc) < 0)
- return -1;
- ret = JS_DefineProperty(ctx, obj, prop,
- d.value, d.getter, d.setter, d.flags | flags);
- js_free_desc(ctx, &d);
- return ret;
- }
- static __exception int JS_ObjectDefineProperties(JSContext *ctx,
- JSValueConst obj,
- JSValueConst properties)
- {
- JSValue props, desc;
- JSObject *p;
- JSPropertyEnum *atoms;
- uint32_t len, i;
- int ret = -1;
- if (!JS_IsObject(obj)) {
- JS_ThrowTypeError(ctx, "Object.defineProperties called on non-object");
- return -1;
- }
- desc = JS_UNDEFINED;
- props = JS_ToObject(ctx, properties);
- if (JS_IsException(props))
- return -1;
- p = JS_VALUE_GET_OBJ(props);
- if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0)
- goto exception;
- // XXX: ECMA specifies that all descriptions should be validated before
- // modifying the object. This would require allocating an array
- // JSPropertyDescriptor and use 2 separate loops.
- for(i = 0; i < len; i++) {
- JS_FreeValue(ctx, desc);
- desc = JS_GetProperty(ctx, props, atoms[i].atom);
- if (JS_IsException(desc))
- goto exception;
- if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc,
- JS_PROP_THROW | JS_PROP_DEFINE_PROPERTY) < 0)
- goto exception;
- }
- ret = 0;
- exception:
- js_free_prop_enum(ctx, atoms, len);
- JS_FreeValue(ctx, props);
- JS_FreeValue(ctx, desc);
- return ret;
- }
- static JSValue js_object_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- JSValue ret;
- if (!JS_IsUndefined(new_target) &&
- JS_VALUE_GET_OBJ(new_target) !=
- JS_VALUE_GET_OBJ(JS_GetActiveFunction(ctx))) {
- ret = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
- } else {
- int tag = JS_VALUE_GET_NORM_TAG(argv[0]);
- switch(tag) {
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- ret = JS_NewObject(ctx);
- break;
- default:
- ret = JS_ToObject(ctx, argv[0]);
- break;
- }
- }
- return ret;
- }
- static JSValue js_object_create(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst proto, props;
- JSValue obj;
- proto = argv[0];
- if (!JS_IsObject(proto) && !JS_IsNull(proto))
- return JS_ThrowTypeError(ctx, "object prototype may only be an Object or null");
- obj = JS_NewObjectProto(ctx, proto);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- props = argv[1];
- if (!JS_IsUndefined(props)) {
- if (JS_ObjectDefineProperties(ctx, obj, props)) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- }
- return obj;
- }
- static JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValueConst val = argv[0];
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) {
- /* ES6 feature non compatible with ES5.1: primitive types are
- accepted */
- if (magic || JS_VALUE_GET_TAG(val) == JS_TAG_NULL ||
- JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- }
- return JS_GetPrototype(ctx, val);
- }
- static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst obj = argv[0];
- if (JS_SetPrototypeInternal(ctx, obj, argv[1], true) < 0)
- return JS_EXCEPTION;
- return js_dup(obj);
- }
- /* magic = 1 if called as Reflect.defineProperty */
- static JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValueConst obj, prop, desc;
- int ret, flags;
- JSAtom atom;
- obj = argv[0];
- prop = argv[1];
- desc = argv[2];
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- atom = JS_ValueToAtom(ctx, prop);
- if (unlikely(atom == JS_ATOM_NULL))
- return JS_EXCEPTION;
- flags = JS_PROP_THROW | JS_PROP_DEFINE_PROPERTY;
- if (magic)
- flags = JS_PROP_REFLECT_DEFINE_PROPERTY;
- ret = JS_DefinePropertyDesc(ctx, obj, atom, desc, flags);
- JS_FreeAtom(ctx, atom);
- if (ret < 0) {
- return JS_EXCEPTION;
- } else if (magic) {
- return js_bool(ret);
- } else {
- return js_dup(obj);
- }
- }
- static JSValue js_object_defineProperties(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // defineProperties(obj, properties)
- JSValueConst obj = argv[0];
- if (JS_ObjectDefineProperties(ctx, obj, argv[1]))
- return JS_EXCEPTION;
- return js_dup(obj);
- }
- /* magic = 1 if called as __defineSetter__ */
- static JSValue js_object___defineGetter__(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValue obj;
- JSValueConst prop, value, get, set;
- int ret, flags;
- JSAtom atom;
- prop = argv[0];
- value = argv[1];
- obj = JS_ToObject(ctx, this_val);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- if (check_function(ctx, value)) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- atom = JS_ValueToAtom(ctx, prop);
- if (unlikely(atom == JS_ATOM_NULL)) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- flags = JS_PROP_THROW |
- JS_PROP_HAS_ENUMERABLE | JS_PROP_ENUMERABLE |
- JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE;
- if (magic) {
- get = JS_UNDEFINED;
- set = value;
- flags |= JS_PROP_HAS_SET;
- } else {
- get = value;
- set = JS_UNDEFINED;
- flags |= JS_PROP_HAS_GET;
- }
- ret = JS_DefineProperty(ctx, obj, atom, JS_UNDEFINED, get, set, flags);
- JS_FreeValue(ctx, obj);
- JS_FreeAtom(ctx, atom);
- if (ret < 0) {
- return JS_EXCEPTION;
- } else {
- return JS_UNDEFINED;
- }
- }
- static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValueConst prop;
- JSAtom atom;
- JSValue ret, obj;
- JSPropertyDescriptor desc;
- int res, flags;
- if (magic) {
- /* Reflect.getOwnPropertyDescriptor case */
- if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- obj = js_dup(argv[0]);
- } else {
- obj = JS_ToObject(ctx, argv[0]);
- if (JS_IsException(obj))
- return obj;
- }
- prop = argv[1];
- atom = JS_ValueToAtom(ctx, prop);
- if (unlikely(atom == JS_ATOM_NULL))
- goto exception;
- ret = JS_UNDEFINED;
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
- res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), atom);
- if (res < 0)
- goto exception;
- if (res) {
- ret = JS_NewObject(ctx);
- if (JS_IsException(ret))
- goto exception1;
- flags = JS_PROP_C_W_E | JS_PROP_THROW;
- if (desc.flags & JS_PROP_GETSET) {
- if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, js_dup(desc.getter), flags) < 0
- || JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, js_dup(desc.setter), flags) < 0)
- goto exception1;
- } else {
- if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, js_dup(desc.value), flags) < 0
- || JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
- js_bool(desc.flags & JS_PROP_WRITABLE),
- flags) < 0)
- goto exception1;
- }
- if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
- js_bool(desc.flags & JS_PROP_ENUMERABLE),
- flags) < 0
- || JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
- js_bool(desc.flags & JS_PROP_CONFIGURABLE),
- flags) < 0)
- goto exception1;
- js_free_desc(ctx, &desc);
- }
- }
- JS_FreeAtom(ctx, atom);
- JS_FreeValue(ctx, obj);
- return ret;
- exception1:
- js_free_desc(ctx, &desc);
- JS_FreeValue(ctx, ret);
- exception:
- JS_FreeAtom(ctx, atom);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- //getOwnPropertyDescriptors(obj)
- JSValue obj, r;
- JSObject *p;
- JSPropertyEnum *props;
- uint32_t len, i;
- r = JS_UNDEFINED;
- obj = JS_ToObject(ctx, argv[0]);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- p = JS_VALUE_GET_OBJ(obj);
- if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p,
- JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
- goto exception;
- r = JS_NewObject(ctx);
- if (JS_IsException(r))
- goto exception;
- for(i = 0; i < len; i++) {
- JSValue atomValue, desc;
- JSValueConst args[2];
- atomValue = JS_AtomToValue(ctx, props[i].atom);
- if (JS_IsException(atomValue))
- goto exception;
- args[0] = obj;
- args[1] = atomValue;
- desc = js_object_getOwnPropertyDescriptor(ctx, JS_UNDEFINED, 2, args, 0);
- JS_FreeValue(ctx, atomValue);
- if (JS_IsException(desc))
- goto exception;
- if (!JS_IsUndefined(desc)) {
- if (JS_DefinePropertyValue(ctx, r, props[i].atom, desc,
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- }
- }
- js_free_prop_enum(ctx, props, len);
- JS_FreeValue(ctx, obj);
- return r;
- exception:
- js_free_prop_enum(ctx, props, len);
- JS_FreeValue(ctx, obj);
- JS_FreeValue(ctx, r);
- return JS_EXCEPTION;
- }
- static JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1,
- int flags, int kind)
- {
- JSValue obj, r, val, key, value;
- JSObject *p;
- JSPropertyEnum *atoms;
- uint32_t len, i, j;
- r = JS_UNDEFINED;
- val = JS_UNDEFINED;
- obj = JS_ToObject(ctx, obj1);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- p = JS_VALUE_GET_OBJ(obj);
- if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, flags & ~JS_GPN_ENUM_ONLY))
- goto exception;
- r = JS_NewArray(ctx);
- if (JS_IsException(r))
- goto exception;
- for(j = i = 0; i < len; i++) {
- JSAtom atom = atoms[i].atom;
- if (flags & JS_GPN_ENUM_ONLY) {
- JSPropertyDescriptor desc;
- int res;
- /* Check if property is still enumerable */
- res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
- if (res < 0)
- goto exception;
- if (!res)
- continue;
- js_free_desc(ctx, &desc);
- if (!(desc.flags & JS_PROP_ENUMERABLE))
- continue;
- }
- switch(kind) {
- default:
- case JS_ITERATOR_KIND_KEY:
- val = JS_AtomToValue(ctx, atom);
- if (JS_IsException(val))
- goto exception;
- break;
- case JS_ITERATOR_KIND_VALUE:
- val = JS_GetProperty(ctx, obj, atom);
- if (JS_IsException(val))
- goto exception;
- break;
- case JS_ITERATOR_KIND_KEY_AND_VALUE:
- val = JS_NewArray(ctx);
- if (JS_IsException(val))
- goto exception;
- key = JS_AtomToValue(ctx, atom);
- if (JS_IsException(key))
- goto exception1;
- if (JS_CreateDataPropertyUint32(ctx, val, 0, key, JS_PROP_THROW) < 0)
- goto exception1;
- value = JS_GetProperty(ctx, obj, atom);
- if (JS_IsException(value))
- goto exception1;
- if (JS_CreateDataPropertyUint32(ctx, val, 1, value, JS_PROP_THROW) < 0)
- goto exception1;
- break;
- }
- if (JS_CreateDataPropertyUint32(ctx, r, j++, val, 0) < 0)
- goto exception;
- }
- goto done;
- exception1:
- JS_FreeValue(ctx, val);
- exception:
- JS_FreeValue(ctx, r);
- r = JS_EXCEPTION;
- done:
- js_free_prop_enum(ctx, atoms, len);
- JS_FreeValue(ctx, obj);
- return r;
- }
- static JSValue js_object_getOwnPropertyNames(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return JS_GetOwnPropertyNames2(ctx, argv[0],
- JS_GPN_STRING_MASK, JS_ITERATOR_KIND_KEY);
- }
- static JSValue js_object_getOwnPropertySymbols(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return JS_GetOwnPropertyNames2(ctx, argv[0],
- JS_GPN_SYMBOL_MASK, JS_ITERATOR_KIND_KEY);
- }
- static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue res, iter, next, groups, k, v, prop;
- JSValueConst cb, args[2];
- int64_t idx;
- int done;
- // "is function?" check must be observed before argv[0] is accessed
- cb = argv[1];
- if (check_function(ctx, cb))
- return JS_EXCEPTION;
- // TODO(bnoordhuis) add fast path for arrays but as groupBy() is
- // defined in terms of iterators, the fast path must check that
- // this[Symbol.iterator] is the built-in array iterator
- iter = JS_GetIterator(ctx, argv[0], /*is_async*/false);
- if (JS_IsException(iter))
- return JS_EXCEPTION;
- k = JS_UNDEFINED;
- v = JS_UNDEFINED;
- prop = JS_UNDEFINED;
- groups = JS_UNDEFINED;
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- goto exception;
- groups = JS_NewObjectProto(ctx, JS_NULL);
- if (JS_IsException(groups))
- goto exception;
- for (idx = 0; ; idx++) {
- v = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
- if (JS_IsException(v))
- goto exception;
- if (done)
- break; // v is JS_UNDEFINED
- args[0] = v;
- args[1] = js_int64(idx);
- k = JS_Call(ctx, cb, ctx->global_obj, 2, args);
- if (JS_IsException(k))
- goto exception;
- k = js_dup(k);
- prop = JS_GetPropertyValue(ctx, groups, k);
- if (JS_IsException(prop))
- goto exception;
- if (JS_IsUndefined(prop)) {
- prop = JS_NewArray(ctx);
- if (JS_IsException(prop))
- goto exception;
- k = js_dup(k);
- prop = js_dup(prop);
- if (JS_SetPropertyValue(ctx, groups, k, prop,
- JS_PROP_C_W_E|JS_PROP_THROW) < 0) {
- goto exception;
- }
- }
- res = js_array_push(ctx, prop, 1, vc(&v), /*unshift*/0);
- if (JS_IsException(res))
- goto exception;
- // res is an int64
- JS_FreeValue(ctx, prop);
- JS_FreeValue(ctx, k);
- JS_FreeValue(ctx, v);
- prop = JS_UNDEFINED;
- k = JS_UNDEFINED;
- v = JS_UNDEFINED;
- }
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, next);
- return groups;
- exception:
- JS_FreeValue(ctx, prop);
- JS_FreeValue(ctx, k);
- JS_FreeValue(ctx, v);
- JS_FreeValue(ctx, groups);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, next);
- return JS_EXCEPTION;
- }
- static JSValue js_object_keys(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int kind)
- {
- return JS_GetOwnPropertyNames2(ctx, argv[0],
- JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK, kind);
- }
- static JSValue js_object_isExtensible(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int reflect)
- {
- JSValueConst obj;
- int ret;
- obj = argv[0];
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
- if (reflect)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- else
- return JS_FALSE;
- }
- ret = JS_IsExtensible(ctx, obj);
- if (ret < 0)
- return JS_EXCEPTION;
- else
- return js_bool(ret);
- }
- static JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int reflect)
- {
- JSValueConst obj;
- int ret;
- obj = argv[0];
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
- if (reflect)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- else
- return js_dup(obj);
- }
- ret = JS_PreventExtensions(ctx, obj);
- if (ret < 0)
- return JS_EXCEPTION;
- if (reflect) {
- return js_bool(ret);
- } else {
- if (!ret)
- return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
- return js_dup(obj);
- }
- }
- static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj;
- JSAtom atom;
- JSObject *p;
- int ret;
- atom = JS_ValueToAtom(ctx, argv[0]); /* must be done first */
- if (unlikely(atom == JS_ATOM_NULL))
- return JS_EXCEPTION;
- obj = JS_ToObject(ctx, this_val);
- if (JS_IsException(obj)) {
- JS_FreeAtom(ctx, atom);
- return obj;
- }
- p = JS_VALUE_GET_OBJ(obj);
- ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
- JS_FreeAtom(ctx, atom);
- JS_FreeValue(ctx, obj);
- if (ret < 0)
- return JS_EXCEPTION;
- else
- return js_bool(ret);
- }
- static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj;
- JSAtom atom;
- JSObject *p;
- int ret;
- obj = JS_ToObject(ctx, argv[0]);
- if (JS_IsException(obj))
- return obj;
- atom = JS_ValueToAtom(ctx, argv[1]);
- if (unlikely(atom == JS_ATOM_NULL)) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- p = JS_VALUE_GET_OBJ(obj);
- ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
- JS_FreeAtom(ctx, atom);
- JS_FreeValue(ctx, obj);
- if (ret < 0)
- return JS_EXCEPTION;
- else
- return js_bool(ret);
- }
- static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return JS_ToObject(ctx, this_val);
- }
- static JSValue js_object_toString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj, tag;
- int is_array;
- JSAtom atom;
- JSObject *p;
- if (JS_IsNull(this_val)) {
- tag = js_new_string8(ctx, "Null");
- } else if (JS_IsUndefined(this_val)) {
- tag = js_new_string8(ctx, "Undefined");
- } else {
- obj = JS_ToObject(ctx, this_val);
- if (JS_IsException(obj))
- return obj;
- is_array = js_is_array(ctx, obj);
- if (is_array < 0) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- if (is_array) {
- atom = JS_ATOM_Array;
- } else if (JS_IsFunction(ctx, obj)) {
- atom = JS_ATOM_Function;
- } else {
- p = JS_VALUE_GET_OBJ(obj);
- switch(p->class_id) {
- case JS_CLASS_STRING:
- case JS_CLASS_ARGUMENTS:
- case JS_CLASS_MAPPED_ARGUMENTS:
- case JS_CLASS_ERROR:
- case JS_CLASS_BOOLEAN:
- case JS_CLASS_NUMBER:
- case JS_CLASS_DATE:
- case JS_CLASS_REGEXP:
- atom = ctx->rt->class_array[p->class_id].class_name;
- break;
- default:
- atom = JS_ATOM_Object;
- break;
- }
- }
- tag = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_toStringTag);
- JS_FreeValue(ctx, obj);
- if (JS_IsException(tag))
- return JS_EXCEPTION;
- if (!JS_IsString(tag)) {
- JS_FreeValue(ctx, tag);
- tag = JS_AtomToString(ctx, atom);
- }
- }
- return JS_ConcatString3(ctx, "[object ", tag, "]");
- }
- JSValue JS_ToObjectString(JSContext *ctx, JSValueConst val)
- {
- return js_object_toString(ctx, val, 0, NULL);
- }
- static JSValue js_object_toLocaleString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return JS_Invoke(ctx, this_val, JS_ATOM_toString, 0, NULL);
- }
- static JSValue js_object_assign(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // Object.assign(obj, source1)
- JSValue obj, s;
- int i;
- s = JS_UNDEFINED;
- obj = JS_ToObject(ctx, argv[0]);
- if (JS_IsException(obj))
- goto exception;
- for (i = 1; i < argc; i++) {
- if (!JS_IsNull(argv[i]) && !JS_IsUndefined(argv[i])) {
- s = JS_ToObject(ctx, argv[i]);
- if (JS_IsException(s))
- goto exception;
- if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, true))
- goto exception;
- JS_FreeValue(ctx, s);
- }
- }
- return obj;
- exception:
- JS_FreeValue(ctx, obj);
- JS_FreeValue(ctx, s);
- return JS_EXCEPTION;
- }
- static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int freeze_flag)
- {
- JSValueConst obj = argv[0];
- JSObject *p;
- JSTypedArray *ta;
- JSArrayBuffer *abuf;
- JSPropertyEnum *props;
- uint32_t len, i;
- int flags, desc_flags, res;
- if (!JS_IsObject(obj))
- return js_dup(obj);
- p = JS_VALUE_GET_OBJ(obj);
- if (p->class_id == JS_CLASS_MODULE_NS) {
- return JS_ThrowTypeError(ctx, "cannot %s module namespace",
- freeze_flag ? "freeze" : "seal");
- }
- res = JS_PreventExtensions(ctx, obj);
- if (res < 0)
- return JS_EXCEPTION;
- if (!res) {
- return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
- }
- if (freeze_flag && is_typed_array(p->class_id)) {
- ta = p->u.typed_array;
- abuf = ta->buffer->u.array_buffer;
- if (array_buffer_is_resizable(abuf) || typed_array_is_oob(p))
- return JS_ThrowTypeError(ctx, "cannot freeze resizable typed array");
- }
- flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
- if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
- return JS_EXCEPTION;
- for(i = 0; i < len; i++) {
- JSPropertyDescriptor desc;
- JSAtom prop = props[i].atom;
- desc_flags = JS_PROP_THROW | JS_PROP_HAS_CONFIGURABLE;
- if (freeze_flag) {
- res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
- if (res < 0)
- goto exception;
- if (res) {
- if (desc.flags & JS_PROP_WRITABLE)
- desc_flags |= JS_PROP_HAS_WRITABLE;
- js_free_desc(ctx, &desc);
- }
- }
- if (JS_DefineProperty(ctx, obj, prop, JS_UNDEFINED,
- JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0)
- goto exception;
- }
- js_free_prop_enum(ctx, props, len);
- return js_dup(obj);
- exception:
- js_free_prop_enum(ctx, props, len);
- return JS_EXCEPTION;
- }
- static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int is_frozen)
- {
- JSValueConst obj = argv[0];
- JSObject *p;
- JSPropertyEnum *props;
- uint32_t len, i;
- int flags, res;
- if (!JS_IsObject(obj))
- return JS_TRUE;
- p = JS_VALUE_GET_OBJ(obj);
- flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
- if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
- return JS_EXCEPTION;
- for(i = 0; i < len; i++) {
- JSPropertyDescriptor desc;
- JSAtom prop = props[i].atom;
- res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
- if (res < 0)
- goto exception;
- if (res) {
- js_free_desc(ctx, &desc);
- if ((desc.flags & JS_PROP_CONFIGURABLE)
- || (is_frozen && (desc.flags & JS_PROP_WRITABLE))) {
- res = false;
- goto done;
- }
- }
- }
- res = JS_IsExtensible(ctx, obj);
- if (res < 0)
- return JS_EXCEPTION;
- res ^= 1;
- done:
- js_free_prop_enum(ctx, props, len);
- return js_bool(res);
- exception:
- js_free_prop_enum(ctx, props, len);
- return JS_EXCEPTION;
- }
- int JS_SealObject(JSContext *ctx, JSValueConst obj)
- {
- JSValue value = js_object_seal(ctx, JS_UNDEFINED, 1, &obj, 0);
- int result = JS_IsException(value) ? -1 : true;
- JS_FreeValue(ctx, value);
- return result;
- }
- int JS_FreezeObject(JSContext *ctx, JSValueConst obj)
- {
- JSValue value = js_object_seal(ctx, JS_UNDEFINED, 1, &obj, 1);
- int result = JS_IsException(value) ? -1 : true;
- JS_FreeValue(ctx, value);
- return result;
- }
- static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj, iter, next_method = JS_UNDEFINED;
- JSValueConst iterable;
- int done;
- /* RequireObjectCoercible() not necessary because it is tested in
- JS_GetIterator() by JS_GetProperty() */
- iterable = argv[0];
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj))
- return obj;
- iter = JS_GetIterator(ctx, iterable, false);
- if (JS_IsException(iter))
- goto fail;
- next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next_method))
- goto fail;
- for(;;) {
- JSValue key, value, item;
- item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
- if (JS_IsException(item))
- goto fail;
- if (done)
- break;
- key = JS_UNDEFINED;
- value = JS_UNDEFINED;
- if (!JS_IsObject(item)) {
- JS_ThrowTypeErrorNotAnObject(ctx);
- goto fail1;
- }
- key = JS_GetPropertyUint32(ctx, item, 0);
- if (JS_IsException(key))
- goto fail1;
- value = JS_GetPropertyUint32(ctx, item, 1);
- if (JS_IsException(value)) {
- JS_FreeValue(ctx, key);
- goto fail1;
- }
- if (JS_DefinePropertyValueValue(ctx, obj, key, value,
- JS_PROP_C_W_E | JS_PROP_THROW) < 0) {
- fail1:
- JS_FreeValue(ctx, item);
- goto fail;
- }
- JS_FreeValue(ctx, item);
- }
- JS_FreeValue(ctx, next_method);
- JS_FreeValue(ctx, iter);
- return obj;
- fail:
- if (JS_IsObject(iter)) {
- /* close the iterator object, preserving pending exception */
- JS_IteratorClose(ctx, iter, true);
- }
- JS_FreeValue(ctx, next_method);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_object_is(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_bool(js_same_value(ctx, argv[0], argv[1]));
- }
- static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj,
- JSValueConst defaultConstructor)
- {
- JSValue ctor, species;
- if (!JS_IsObject(obj))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
- if (JS_IsException(ctor))
- return ctor;
- if (JS_IsUndefined(ctor))
- return js_dup(defaultConstructor);
- if (!JS_IsObject(ctor)) {
- JS_FreeValue(ctx, ctor);
- return JS_ThrowTypeErrorNotAnObject(ctx);
- }
- species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
- JS_FreeValue(ctx, ctor);
- if (JS_IsException(species))
- return species;
- if (JS_IsUndefined(species) || JS_IsNull(species))
- return js_dup(defaultConstructor);
- if (!JS_IsConstructor(ctx, species)) {
- JS_ThrowTypeErrorNotAConstructor(ctx, species);
- JS_FreeValue(ctx, species);
- return JS_EXCEPTION;
- }
- return species;
- }
- static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val)
- {
- JSValue val, ret;
- val = JS_ToObject(ctx, this_val);
- if (JS_IsException(val))
- return val;
- ret = JS_GetPrototype(ctx, val);
- JS_FreeValue(ctx, val);
- return ret;
- }
- static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val,
- JSValueConst proto)
- {
- if (JS_IsUndefined(this_val) || JS_IsNull(this_val))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- if (!JS_IsObject(proto) && !JS_IsNull(proto))
- return JS_UNDEFINED;
- if (JS_SetPrototypeInternal(ctx, this_val, proto, true) < 0)
- return JS_EXCEPTION;
- else
- return JS_UNDEFINED;
- }
- static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj, v1;
- JSValueConst v;
- int res;
- v = argv[0];
- if (!JS_IsObject(v))
- return JS_FALSE;
- obj = JS_ToObject(ctx, this_val);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- v1 = js_dup(v);
- for(;;) {
- v1 = JS_GetPrototypeFree(ctx, v1);
- if (JS_IsException(v1))
- goto exception;
- if (JS_IsNull(v1)) {
- res = false;
- break;
- }
- if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) {
- res = true;
- break;
- }
- /* avoid infinite loop (possible with proxies) */
- if (js_poll_interrupts(ctx))
- goto exception;
- }
- JS_FreeValue(ctx, v1);
- JS_FreeValue(ctx, obj);
- return js_bool(res);
- exception:
- JS_FreeValue(ctx, v1);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj, res = JS_EXCEPTION;
- JSAtom prop = JS_ATOM_NULL;
- JSPropertyDescriptor desc;
- int has_prop;
- obj = JS_ToObject(ctx, this_val);
- if (JS_IsException(obj))
- goto exception;
- prop = JS_ValueToAtom(ctx, argv[0]);
- if (unlikely(prop == JS_ATOM_NULL))
- goto exception;
- has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
- if (has_prop < 0)
- goto exception;
- if (has_prop) {
- res = js_bool(desc.flags & JS_PROP_ENUMERABLE);
- js_free_desc(ctx, &desc);
- } else {
- res = JS_FALSE;
- }
- exception:
- JS_FreeAtom(ctx, prop);
- JS_FreeValue(ctx, obj);
- return res;
- }
- static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int setter)
- {
- JSValue obj, res = JS_EXCEPTION;
- JSAtom prop = JS_ATOM_NULL;
- JSPropertyDescriptor desc;
- int has_prop;
- obj = JS_ToObject(ctx, this_val);
- if (JS_IsException(obj))
- goto exception;
- prop = JS_ValueToAtom(ctx, argv[0]);
- if (unlikely(prop == JS_ATOM_NULL))
- goto exception;
- for (;;) {
- has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
- if (has_prop < 0)
- goto exception;
- if (has_prop) {
- if (desc.flags & JS_PROP_GETSET)
- res = js_dup(setter ? desc.setter : desc.getter);
- else
- res = JS_UNDEFINED;
- js_free_desc(ctx, &desc);
- break;
- }
- obj = JS_GetPrototypeFree(ctx, obj);
- if (JS_IsException(obj))
- goto exception;
- if (JS_IsNull(obj)) {
- res = JS_UNDEFINED;
- break;
- }
- /* avoid infinite loop (possible with proxies) */
- if (js_poll_interrupts(ctx))
- goto exception;
- }
- exception:
- JS_FreeAtom(ctx, prop);
- JS_FreeValue(ctx, obj);
- return res;
- }
- static const JSCFunctionListEntry js_object_funcs[] = {
- JS_CFUNC_DEF("create", 2, js_object_create ),
- JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 0 ),
- JS_CFUNC_DEF("setPrototypeOf", 2, js_object_setPrototypeOf ),
- JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 0 ),
- JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ),
- JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ),
- JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ),
- JS_CFUNC_DEF("groupBy", 2, js_object_groupBy ),
- JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ),
- JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ),
- JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ),
- JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 0 ),
- JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 0 ),
- JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 0 ),
- JS_CFUNC_DEF("getOwnPropertyDescriptors", 1, js_object_getOwnPropertyDescriptors ),
- JS_CFUNC_DEF("is", 2, js_object_is ),
- JS_CFUNC_DEF("assign", 2, js_object_assign ),
- JS_CFUNC_MAGIC_DEF("seal", 1, js_object_seal, 0 ),
- JS_CFUNC_MAGIC_DEF("freeze", 1, js_object_seal, 1 ),
- JS_CFUNC_MAGIC_DEF("isSealed", 1, js_object_isSealed, 0 ),
- JS_CFUNC_MAGIC_DEF("isFrozen", 1, js_object_isSealed, 1 ),
- JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries ),
- JS_CFUNC_DEF("hasOwn", 2, js_object_hasOwn ),
- };
- static const JSCFunctionListEntry js_object_proto_funcs[] = {
- JS_CFUNC_DEF("toString", 0, js_object_toString ),
- JS_CFUNC_DEF("toLocaleString", 0, js_object_toLocaleString ),
- JS_CFUNC_DEF("valueOf", 0, js_object_valueOf ),
- JS_CFUNC_DEF("hasOwnProperty", 1, js_object_hasOwnProperty ),
- JS_CFUNC_DEF("isPrototypeOf", 1, js_object_isPrototypeOf ),
- JS_CFUNC_DEF("propertyIsEnumerable", 1, js_object_propertyIsEnumerable ),
- JS_CGETSET_DEF("__proto__", js_object_get___proto__, js_object_set___proto__ ),
- JS_CFUNC_MAGIC_DEF("__defineGetter__", 2, js_object___defineGetter__, 0 ),
- JS_CFUNC_MAGIC_DEF("__defineSetter__", 2, js_object___defineGetter__, 1 ),
- JS_CFUNC_MAGIC_DEF("__lookupGetter__", 1, js_object___lookupGetter__, 0 ),
- JS_CFUNC_MAGIC_DEF("__lookupSetter__", 1, js_object___lookupGetter__, 1 ),
- };
- /* Function class */
- static JSValue js_function_proto(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return JS_UNDEFINED;
- }
- /* XXX: add a specific eval mode so that Function("}), ({") is rejected */
- static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv, int magic)
- {
- JSFunctionKindEnum func_kind = magic;
- int i, n, ret;
- JSValue s, proto, obj = JS_UNDEFINED;
- StringBuffer b_s, *b = &b_s;
- string_buffer_init(ctx, b, 0);
- string_buffer_putc8(b, '(');
- if (func_kind == JS_FUNC_ASYNC || func_kind == JS_FUNC_ASYNC_GENERATOR) {
- string_buffer_puts8(b, "async ");
- }
- string_buffer_puts8(b, "function");
- if (func_kind == JS_FUNC_GENERATOR || func_kind == JS_FUNC_ASYNC_GENERATOR) {
- string_buffer_putc8(b, '*');
- }
- string_buffer_puts8(b, " anonymous(");
- n = argc - 1;
- for(i = 0; i < n; i++) {
- if (i != 0) {
- string_buffer_putc8(b, ',');
- }
- if (string_buffer_concat_value(b, argv[i]))
- goto fail;
- }
- string_buffer_puts8(b, "\n) {\n");
- if (n >= 0) {
- if (string_buffer_concat_value(b, argv[n]))
- goto fail;
- }
- string_buffer_puts8(b, "\n})");
- s = string_buffer_end(b);
- if (JS_IsException(s))
- goto fail1;
- obj = JS_EvalObject(ctx, ctx->global_obj, s, JS_EVAL_TYPE_INDIRECT, -1);
- JS_FreeValue(ctx, s);
- if (JS_IsException(obj))
- goto fail1;
- if (!JS_IsUndefined(new_target)) {
- /* set the prototype */
- proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
- if (JS_IsException(proto))
- goto fail1;
- if (!JS_IsObject(proto)) {
- JSContext *realm;
- JS_FreeValue(ctx, proto);
- realm = JS_GetFunctionRealm(ctx, new_target);
- if (!realm)
- goto fail1;
- proto = js_dup(realm->class_proto[func_kind_to_class_id[func_kind]]);
- }
- ret = JS_SetPrototypeInternal(ctx, obj, proto, true);
- JS_FreeValue(ctx, proto);
- if (ret < 0)
- goto fail1;
- }
- return obj;
- fail:
- string_buffer_free(b);
- fail1:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
- JSValueConst obj)
- {
- JSValue len_val;
- len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
- if (JS_IsException(len_val)) {
- *pres = 0;
- return -1;
- }
- return JS_ToUint32Free(ctx, pres, len_val);
- }
- static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
- JSValueConst obj)
- {
- JSValue len_val;
- len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
- if (JS_IsException(len_val)) {
- *pres = 0;
- return -1;
- }
- return JS_ToLengthFree(ctx, pres, len_val);
- }
- static __exception int js_set_length64(JSContext *ctx, JSValueConst obj,
- int64_t len)
- {
- return JS_SetProperty(ctx, obj, JS_ATOM_length, js_int64(len));
- }
- static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len)
- {
- uint32_t i;
- for(i = 0; i < len; i++) {
- JS_FreeValue(ctx, tab[i]);
- }
- js_free(ctx, tab);
- }
- /* XXX: should use ValueArray */
- static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
- JSValueConst array_arg)
- {
- uint32_t len, i;
- JSValue *tab, ret;
- JSObject *p;
- if (JS_VALUE_GET_TAG(array_arg) != JS_TAG_OBJECT) {
- JS_ThrowTypeError(ctx, "not a object");
- return NULL;
- }
- if (js_get_length32(ctx, &len, array_arg))
- return NULL;
- if (len > JS_MAX_LOCAL_VARS) {
- // XXX: check for stack overflow?
- JS_ThrowRangeError(ctx, "too many arguments in function call (only %d allowed)",
- JS_MAX_LOCAL_VARS);
- return NULL;
- }
- /* avoid allocating 0 bytes */
- tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len));
- if (!tab)
- return NULL;
- p = JS_VALUE_GET_OBJ(array_arg);
- if ((p->class_id == JS_CLASS_ARRAY || p->class_id == JS_CLASS_ARGUMENTS) &&
- p->fast_array &&
- len == p->u.array.count) {
- for(i = 0; i < len; i++) {
- tab[i] = js_dup(p->u.array.u.values[i]);
- }
- } else {
- for(i = 0; i < len; i++) {
- ret = JS_GetPropertyUint32(ctx, array_arg, i);
- if (JS_IsException(ret)) {
- free_arg_list(ctx, tab, i);
- return NULL;
- }
- tab[i] = ret;
- }
- }
- *plen = len;
- return tab;
- }
- /* magic value: 0 = normal apply, 1 = apply for constructor, 2 =
- Reflect.apply */
- static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValueConst this_arg, array_arg;
- uint32_t len;
- JSValue *tab, ret;
- if (check_function(ctx, this_val))
- return JS_EXCEPTION;
- this_arg = argv[0];
- array_arg = argv[1];
- if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED ||
- JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) {
- return JS_Call(ctx, this_val, this_arg, 0, NULL);
- }
- tab = build_arg_list(ctx, &len, array_arg);
- if (!tab)
- return JS_EXCEPTION;
- if (magic & 1) {
- ret = JS_CallConstructor2(ctx, this_val, this_arg, len, vc(tab));
- } else {
- ret = JS_Call(ctx, this_val, this_arg, len, vc(tab));
- }
- free_arg_list(ctx, tab, len);
- return ret;
- }
- static JSValue js_function_call(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- if (argc <= 0) {
- return JS_Call(ctx, this_val, JS_UNDEFINED, 0, NULL);
- } else {
- return JS_Call(ctx, this_val, argv[0], argc - 1, argv + 1);
- }
- }
- static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSBoundFunction *bf;
- JSValue func_obj, name1, len_val;
- JSObject *p;
- int arg_count, i, ret;
- if (check_function(ctx, this_val))
- return JS_EXCEPTION;
- func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
- JS_CLASS_BOUND_FUNCTION);
- if (JS_IsException(func_obj))
- return JS_EXCEPTION;
- p = JS_VALUE_GET_OBJ(func_obj);
- p->is_constructor = JS_IsConstructor(ctx, this_val);
- arg_count = max_int(0, argc - 1);
- bf = js_malloc(ctx, sizeof(*bf) + arg_count * sizeof(JSValue));
- if (!bf)
- goto exception;
- bf->func_obj = js_dup(this_val);
- bf->this_val = js_dup(argv[0]);
- bf->argc = arg_count;
- for(i = 0; i < arg_count; i++) {
- bf->argv[i] = js_dup(argv[i + 1]);
- }
- p->u.bound_function = bf;
- /* XXX: the spec could be simpler by only using GetOwnProperty */
- ret = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_length);
- if (ret < 0)
- goto exception;
- if (!ret) {
- len_val = js_int32(0);
- } else {
- len_val = JS_GetProperty(ctx, this_val, JS_ATOM_length);
- if (JS_IsException(len_val))
- goto exception;
- if (JS_VALUE_GET_TAG(len_val) == JS_TAG_INT) {
- /* most common case */
- int len1 = JS_VALUE_GET_INT(len_val);
- if (len1 <= arg_count)
- len1 = 0;
- else
- len1 -= arg_count;
- len_val = js_int32(len1);
- } else if (JS_VALUE_GET_NORM_TAG(len_val) == JS_TAG_FLOAT64) {
- double d = JS_VALUE_GET_FLOAT64(len_val);
- if (isnan(d)) {
- d = 0.0;
- } else {
- d = trunc(d);
- if (d <= (double)arg_count)
- d = 0.0;
- else
- d -= (double)arg_count; /* also converts -0 to +0 */
- }
- len_val = js_number(d);
- } else {
- JS_FreeValue(ctx, len_val);
- len_val = js_int32(0);
- }
- }
- JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length,
- len_val, JS_PROP_CONFIGURABLE);
- name1 = JS_GetProperty(ctx, this_val, JS_ATOM_name);
- if (JS_IsException(name1))
- goto exception;
- if (!JS_IsString(name1)) {
- JS_FreeValue(ctx, name1);
- name1 = js_empty_string(ctx->rt);
- }
- name1 = JS_ConcatString3(ctx, "bound ", name1, "");
- if (JS_IsException(name1))
- goto exception;
- JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name1,
- JS_PROP_CONFIGURABLE);
- return func_obj;
- exception:
- JS_FreeValue(ctx, func_obj);
- return JS_EXCEPTION;
- }
- static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSObject *p;
- JSFunctionKindEnum func_kind = JS_FUNC_NORMAL;
- if (check_function(ctx, this_val))
- return JS_EXCEPTION;
- p = JS_VALUE_GET_OBJ(this_val);
- if (js_class_has_bytecode(p->class_id)) {
- JSFunctionBytecode *b = p->u.func.function_bytecode;
- /* `b->source` must be pure ASCII or UTF-8 encoded */
- if (b->source)
- return JS_NewStringLen(ctx, b->source, b->source_len);
- }
- {
- JSValue name;
- const char *pref, *suff;
- switch(func_kind) {
- default:
- case JS_FUNC_NORMAL:
- pref = "function ";
- break;
- case JS_FUNC_GENERATOR:
- pref = "function *";
- break;
- case JS_FUNC_ASYNC:
- pref = "async function ";
- break;
- case JS_FUNC_ASYNC_GENERATOR:
- pref = "async function *";
- break;
- }
- suff = "() {\n [native code]\n}";
- name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
- if (JS_IsUndefined(name))
- name = js_empty_string(ctx->rt);
- return JS_ConcatString3(ctx, pref, name, suff);
- }
- }
- static JSValue js_function_hasInstance(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int ret;
- ret = JS_OrdinaryIsInstanceOf(ctx, argv[0], this_val);
- if (ret < 0)
- return JS_EXCEPTION;
- else
- return js_bool(ret);
- }
- static const JSCFunctionListEntry js_function_proto_funcs[] = {
- JS_CFUNC_DEF("call", 1, js_function_call ),
- JS_CFUNC_MAGIC_DEF("apply", 2, js_function_apply, 0 ),
- JS_CFUNC_DEF("bind", 1, js_function_bind ),
- JS_CFUNC_DEF("toString", 0, js_function_toString ),
- JS_CFUNC_DEF("[Symbol.hasInstance]", 1, js_function_hasInstance ),
- JS_CGETSET_DEF("fileName", js_function_proto_fileName, NULL ),
- JS_CGETSET_MAGIC_DEF("lineNumber", js_function_proto_int32, NULL,
- offsetof(JSFunctionBytecode, line_num)),
- JS_CGETSET_MAGIC_DEF("columnNumber", js_function_proto_int32, NULL,
- offsetof(JSFunctionBytecode, col_num)),
- };
- /* Error class */
- static JSValue iterator_to_array(JSContext *ctx, JSValueConst items)
- {
- JSValue iter, next_method = JS_UNDEFINED;
- JSValue v, r = JS_UNDEFINED;
- int64_t k;
- int done;
- iter = JS_GetIterator(ctx, items, false);
- if (JS_IsException(iter))
- goto exception;
- next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next_method))
- goto exception;
- r = JS_NewArray(ctx);
- if (JS_IsException(r))
- goto exception;
- for (k = 0;; k++) {
- v = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
- if (JS_IsException(v))
- goto exception_close;
- if (done)
- break;
- if (JS_DefinePropertyValueInt64(ctx, r, k, v,
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception_close;
- }
- done:
- JS_FreeValue(ctx, next_method);
- JS_FreeValue(ctx, iter);
- return r;
- exception_close:
- JS_IteratorClose(ctx, iter, true);
- exception:
- JS_FreeValue(ctx, r);
- r = JS_EXCEPTION;
- goto done;
- }
- static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv, int magic)
- {
- JSValue obj, msg, proto, cause;
- JSValueConst message;
- int present, opts;
- if (JS_IsUndefined(new_target))
- new_target = JS_GetActiveFunction(ctx);
- proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
- if (JS_IsException(proto))
- return proto;
- if (!JS_IsObject(proto)) {
- JSContext *realm;
- JSValue proto1;
- JS_FreeValue(ctx, proto);
- realm = JS_GetFunctionRealm(ctx, new_target);
- if (!realm)
- return JS_EXCEPTION;
- if (magic < 0) {
- proto1 = realm->class_proto[JS_CLASS_ERROR];
- } else {
- proto1 = realm->native_error_proto[magic];
- }
- proto = js_dup(proto1);
- }
- obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR);
- JS_FreeValue(ctx, proto);
- if (JS_IsException(obj))
- return obj;
- if (magic == JS_AGGREGATE_ERROR) {
- message = argv[1];
- opts = 2;
- } else {
- message = argv[0];
- opts = 1;
- }
- if (!JS_IsUndefined(message)) {
- msg = JS_ToString(ctx, message);
- if (unlikely(JS_IsException(msg)))
- goto exception;
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg,
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- }
- if (argc > opts && JS_VALUE_GET_TAG(argv[opts]) == JS_TAG_OBJECT) {
- present = JS_HasProperty(ctx, argv[opts], JS_ATOM_cause);
- if (unlikely(present < 0))
- goto exception;
- if (present) {
- cause = JS_GetProperty(ctx, argv[opts], JS_ATOM_cause);
- if (unlikely(JS_IsException(cause)))
- goto exception;
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_cause, cause,
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- }
- }
- if (magic == JS_AGGREGATE_ERROR) {
- JSValue error_list = iterator_to_array(ctx, argv[0]);
- if (JS_IsException(error_list))
- goto exception;
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list,
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- }
- /* skip the Error() function in the backtrace */
- build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
- return obj;
- exception:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue name, msg;
- if (!JS_IsObject(this_val))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
- if (JS_IsUndefined(name))
- name = JS_AtomToString(ctx, JS_ATOM_Error);
- else
- name = JS_ToStringFree(ctx, name);
- if (JS_IsException(name))
- return JS_EXCEPTION;
- msg = JS_GetProperty(ctx, this_val, JS_ATOM_message);
- if (JS_IsUndefined(msg))
- msg = js_empty_string(ctx->rt);
- else
- msg = JS_ToStringFree(ctx, msg);
- if (JS_IsException(msg)) {
- JS_FreeValue(ctx, name);
- return JS_EXCEPTION;
- }
- if (!JS_IsEmptyString(name) && !JS_IsEmptyString(msg))
- name = JS_ConcatString3(ctx, "", name, ": ");
- return JS_ConcatString(ctx, name, msg);
- }
- static const JSCFunctionListEntry js_error_proto_funcs[] = {
- JS_CFUNC_DEF("toString", 0, js_error_toString ),
- JS_PROP_STRING_DEF("name", "Error", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
- JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
- };
- static JSValue js_error_isError(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_bool(JS_IsError(argv[0]));
- }
- static JSValue js_error_get_stackTraceLimit(JSContext *ctx, JSValueConst this_val)
- {
- JSValue val;
- val = JS_ToObject(ctx, this_val);
- if (JS_IsException(val))
- return val;
- JS_FreeValue(ctx, val);
- return js_dup(ctx->error_stack_trace_limit);
- }
- static JSValue js_error_set_stackTraceLimit(JSContext *ctx, JSValueConst this_val, JSValueConst value)
- {
- if (JS_IsUndefined(this_val) || JS_IsNull(this_val))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- ctx->error_stack_trace_limit = js_dup(value);
- return JS_UNDEFINED;
- }
- static JSValue js_error_get_prepareStackTrace(JSContext *ctx, JSValueConst this_val)
- {
- JSValue val;
- val = JS_ToObject(ctx, this_val);
- if (JS_IsException(val))
- return val;
- JS_FreeValue(ctx, val);
- return js_dup(ctx->error_prepare_stack);
- }
- static JSValue js_error_set_prepareStackTrace(JSContext *ctx, JSValueConst this_val, JSValueConst value)
- {
- if (JS_IsUndefined(this_val) || JS_IsNull(this_val))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- JS_FreeValue(ctx, ctx->error_prepare_stack);
- ctx->error_prepare_stack = js_dup(value);
- return JS_UNDEFINED;
- }
- static JSValue js_error_capture_stack_trace(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst v = argv[0];
- if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- build_backtrace(ctx, v, argv[1], NULL, 0, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL|JS_BACKTRACE_FLAG_FILTER_FUNC);
- return JS_UNDEFINED;
- }
- static const JSCFunctionListEntry js_error_funcs[] = {
- JS_CFUNC_DEF("isError", 1, js_error_isError ),
- JS_CFUNC_DEF("captureStackTrace", 2, js_error_capture_stack_trace),
- JS_CGETSET_DEF("stackTraceLimit", js_error_get_stackTraceLimit, js_error_set_stackTraceLimit ),
- JS_CGETSET_DEF("prepareStackTrace", js_error_get_prepareStackTrace, js_error_set_prepareStackTrace ),
- };
- /* AggregateError */
- /* used by C code. */
- static JSValue js_aggregate_error_constructor(JSContext *ctx,
- JSValueConst errors)
- {
- JSValue obj;
- obj = JS_NewObjectProtoClass(ctx,
- ctx->native_error_proto[JS_AGGREGATE_ERROR],
- JS_CLASS_ERROR);
- if (JS_IsException(obj))
- return obj;
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, js_dup(errors),
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- return obj;
- }
- /* Array */
- static int JS_CopySubArray(JSContext *ctx,
- JSValue obj, int64_t to_pos,
- int64_t from_pos, int64_t count, int dir)
- {
- JSObject *p;
- int64_t i, from, to, len;
- JSValue val;
- int fromPresent;
- p = NULL;
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
- p = JS_VALUE_GET_OBJ(obj);
- if (p->class_id != JS_CLASS_ARRAY || !p->fast_array) {
- p = NULL;
- }
- }
- for (i = 0; i < count; ) {
- if (dir < 0) {
- from = from_pos + count - i - 1;
- to = to_pos + count - i - 1;
- } else {
- from = from_pos + i;
- to = to_pos + i;
- }
- if (p && p->fast_array &&
- from >= 0 && from < (len = p->u.array.count) &&
- to >= 0 && to < len) {
- int64_t l, j;
- /* Fast path for fast arrays. Since we don't look at the
- prototype chain, we can optimize only the cases where
- all the elements are present in the array. */
- l = count - i;
- if (dir < 0) {
- l = min_int64(l, from + 1);
- l = min_int64(l, to + 1);
- for(j = 0; j < l; j++) {
- set_value(ctx, &p->u.array.u.values[to - j],
- js_dup(p->u.array.u.values[from - j]));
- }
- } else {
- l = min_int64(l, len - from);
- l = min_int64(l, len - to);
- for(j = 0; j < l; j++) {
- set_value(ctx, &p->u.array.u.values[to + j],
- js_dup(p->u.array.u.values[from + j]));
- }
- }
- i += l;
- } else {
- fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
- if (fromPresent < 0)
- goto exception;
- if (fromPresent) {
- if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
- goto exception;
- } else {
- if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)
- goto exception;
- }
- i++;
- }
- }
- return 0;
- exception:
- return -1;
- }
- static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- JSValue obj;
- int i;
- obj = js_create_from_ctor(ctx, new_target, JS_CLASS_ARRAY);
- if (JS_IsException(obj))
- return obj;
- if (argc == 1 && JS_IsNumber(argv[0])) {
- uint32_t len;
- if (JS_ToArrayLengthFree(ctx, &len, js_dup(argv[0]), true))
- goto fail;
- if (JS_SetProperty(ctx, obj, JS_ATOM_length, js_uint32(len)) < 0)
- goto fail;
- } else {
- for(i = 0; i < argc; i++) {
- if (JS_SetPropertyUint32(ctx, obj, i, js_dup(argv[i])) < 0)
- goto fail;
- }
- }
- return obj;
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_array_from(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // from(items, mapfn = void 0, this_arg = void 0)
- JSValueConst items = argv[0], mapfn, this_arg;
- JSValueConst args[2];
- JSValue stack[2];
- JSValue iter, r, v, v2, arrayLike;
- int64_t k, len;
- int done, mapping;
- mapping = false;
- mapfn = JS_UNDEFINED;
- this_arg = JS_UNDEFINED;
- r = JS_UNDEFINED;
- arrayLike = JS_UNDEFINED;
- stack[0] = JS_UNDEFINED;
- stack[1] = JS_UNDEFINED;
- if (argc > 1) {
- mapfn = argv[1];
- if (!JS_IsUndefined(mapfn)) {
- if (check_function(ctx, mapfn))
- goto exception;
- mapping = 1;
- if (argc > 2)
- this_arg = argv[2];
- }
- }
- iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
- if (JS_IsException(iter))
- goto exception;
- if (!JS_IsUndefined(iter)) {
- JS_FreeValue(ctx, iter);
- if (JS_IsConstructor(ctx, this_val))
- r = JS_CallConstructor(ctx, this_val, 0, NULL);
- else
- r = JS_NewArray(ctx);
- if (JS_IsException(r))
- goto exception;
- stack[0] = js_dup(items);
- if (js_for_of_start(ctx, &stack[1], false))
- goto exception;
- for (k = 0;; k++) {
- v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
- if (JS_IsException(v))
- goto exception_close;
- if (done)
- break;
- if (mapping) {
- args[0] = v;
- args[1] = js_int32(k);
- v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
- JS_FreeValue(ctx, v);
- v = v2;
- if (JS_IsException(v))
- goto exception_close;
- }
- if (JS_DefinePropertyValueInt64(ctx, r, k, v,
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception_close;
- }
- } else {
- arrayLike = JS_ToObject(ctx, items);
- if (JS_IsException(arrayLike))
- goto exception;
- if (js_get_length64(ctx, &len, arrayLike) < 0)
- goto exception;
- v = js_int64(len);
- args[0] = v;
- if (JS_IsConstructor(ctx, this_val)) {
- r = JS_CallConstructor(ctx, this_val, 1, args);
- } else {
- r = js_array_constructor(ctx, JS_UNDEFINED, 1, args);
- }
- JS_FreeValue(ctx, v);
- if (JS_IsException(r))
- goto exception;
- for(k = 0; k < len; k++) {
- v = JS_GetPropertyInt64(ctx, arrayLike, k);
- if (JS_IsException(v))
- goto exception;
- if (mapping) {
- args[0] = v;
- args[1] = js_int32(k);
- v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
- JS_FreeValue(ctx, v);
- v = v2;
- if (JS_IsException(v))
- goto exception;
- }
- if (JS_DefinePropertyValueInt64(ctx, r, k, v,
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- }
- }
- if (JS_SetProperty(ctx, r, JS_ATOM_length, js_uint32(k)) < 0)
- goto exception;
- goto done;
- exception_close:
- if (!JS_IsUndefined(stack[0]))
- JS_IteratorClose(ctx, stack[0], true);
- exception:
- JS_FreeValue(ctx, r);
- r = JS_EXCEPTION;
- done:
- JS_FreeValue(ctx, arrayLike);
- JS_FreeValue(ctx, stack[0]);
- JS_FreeValue(ctx, stack[1]);
- return r;
- }
- static JSValue js_array_of(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue n, obj;
- int i;
- if (JS_IsConstructor(ctx, this_val)) {
- n = js_int32(argc);
- obj = JS_CallConstructor(ctx, this_val, 1, vc(&n));
- } else {
- obj = JS_NewArray(ctx);
- }
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- for(i = 0; i < argc; i++) {
- if (JS_CreateDataPropertyUint32(ctx, obj, i, js_dup(argv[i]),
- JS_PROP_THROW) < 0) {
- goto fail;
- }
- }
- if (JS_SetProperty(ctx, obj, JS_ATOM_length, js_uint32(argc)) < 0) {
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- return obj;
- }
- static JSValue js_array_isArray(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int ret;
- ret = js_is_array(ctx, argv[0]);
- if (ret < 0)
- return JS_EXCEPTION;
- else
- return js_bool(ret);
- }
- static JSValue js_get_this(JSContext *ctx, JSValueConst this_val)
- {
- return js_dup(this_val);
- }
- static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj,
- JSValueConst len_val)
- {
- JSValue ctor, ret, species;
- int res;
- JSContext *realm;
- res = js_is_array(ctx, obj);
- if (res < 0)
- return JS_EXCEPTION;
- if (!res)
- return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
- ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
- if (JS_IsException(ctor))
- return ctor;
- if (JS_IsConstructor(ctx, ctor)) {
- /* legacy web compatibility */
- realm = JS_GetFunctionRealm(ctx, ctor);
- if (!realm) {
- JS_FreeValue(ctx, ctor);
- return JS_EXCEPTION;
- }
- if (realm != ctx &&
- js_same_value(ctx, ctor, realm->array_ctor)) {
- JS_FreeValue(ctx, ctor);
- ctor = JS_UNDEFINED;
- }
- }
- if (JS_IsObject(ctor)) {
- species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
- JS_FreeValue(ctx, ctor);
- if (JS_IsException(species))
- return species;
- ctor = species;
- if (JS_IsNull(ctor))
- ctor = JS_UNDEFINED;
- }
- if (JS_IsUndefined(ctor)) {
- return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
- } else {
- ret = JS_CallConstructor(ctx, ctor, 1, &len_val);
- JS_FreeValue(ctx, ctor);
- return ret;
- }
- }
- static const JSCFunctionListEntry js_array_funcs[] = {
- JS_CFUNC_DEF("isArray", 1, js_array_isArray ),
- JS_CFUNC_DEF("from", 1, js_array_from ),
- JS_CFUNC_DEF("of", 0, js_array_of ),
- JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
- };
- static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj)
- {
- JSValue val;
- if (!JS_IsObject(obj))
- return false;
- val = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_isConcatSpreadable);
- if (JS_IsException(val))
- return -1;
- if (!JS_IsUndefined(val))
- return JS_ToBoolFree(ctx, val);
- return js_is_array(ctx, obj);
- }
- static JSValue js_array_at(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj, ret;
- int64_t len, idx;
- ret = JS_EXCEPTION;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- if (JS_ToInt64Sat(ctx, &idx, argv[0]))
- goto exception;
- if (idx < 0)
- idx = len + idx;
- if (idx < 0 || idx >= len) {
- ret = JS_UNDEFINED;
- } else {
- ret = JS_GetPropertyInt64(ctx, obj, idx);
- }
- exception:
- JS_FreeValue(ctx, obj);
- return ret;
- }
- static JSValue js_array_with(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue arr, obj, ret, *arrp, *pval;
- JSObject *p;
- int64_t i, len, idx;
- uint32_t count32;
- ret = JS_EXCEPTION;
- arr = JS_UNDEFINED;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- if (len > UINT32_MAX) {
- JS_ThrowRangeError(ctx, "invalid array length");
- goto exception;
- }
- if (JS_ToInt64Sat(ctx, &idx, argv[0]))
- goto exception;
- if (idx < 0)
- idx = len + idx;
- if (idx < 0 || idx >= len) {
- JS_ThrowRangeError(ctx, "invalid array index: %" PRId64, idx);
- goto exception;
- }
- arr = JS_NewArray(ctx);
- if (JS_IsException(arr))
- goto exception;
- p = JS_VALUE_GET_OBJ(arr);
- if (expand_fast_array(ctx, p, len) < 0)
- goto exception;
- p->u.array.count = len;
- i = 0;
- pval = p->u.array.u.values;
- if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
- for (; i < idx; i++, pval++)
- *pval = js_dup(arrp[i]);
- *pval = js_dup(argv[1]);
- for (i++, pval++; i < len; i++, pval++)
- *pval = js_dup(arrp[i]);
- } else {
- for (; i < idx; i++, pval++)
- if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
- goto fill_and_fail;
- *pval = js_dup(argv[1]);
- for (i++, pval++; i < len; i++, pval++) {
- if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
- fill_and_fail:
- for (; i < len; i++, pval++)
- *pval = JS_UNDEFINED;
- goto exception;
- }
- }
- }
- if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(len)) < 0)
- goto exception;
- ret = arr;
- arr = JS_UNDEFINED;
- exception:
- JS_FreeValue(ctx, arr);
- JS_FreeValue(ctx, obj);
- return ret;
- }
- static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj, arr, val;
- JSValueConst e;
- int64_t len, k, n;
- int i, res;
- arr = JS_UNDEFINED;
- obj = JS_ToObject(ctx, this_val);
- if (JS_IsException(obj))
- goto exception;
- arr = JS_ArraySpeciesCreate(ctx, obj, js_int32(0));
- if (JS_IsException(arr))
- goto exception;
- n = 0;
- for (i = -1; i < argc; i++) {
- if (i < 0)
- e = obj;
- else
- e = argv[i];
- res = JS_isConcatSpreadable(ctx, e);
- if (res < 0)
- goto exception;
- if (res) {
- if (js_get_length64(ctx, &len, e))
- goto exception;
- if (n + len > MAX_SAFE_INTEGER) {
- JS_ThrowTypeError(ctx, "Array loo long");
- goto exception;
- }
- for (k = 0; k < len; k++, n++) {
- res = JS_TryGetPropertyInt64(ctx, e, k, &val);
- if (res < 0)
- goto exception;
- if (res) {
- if (JS_DefinePropertyValueInt64(ctx, arr, n, val,
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- }
- }
- } else {
- if (n >= MAX_SAFE_INTEGER) {
- JS_ThrowTypeError(ctx, "Array loo long");
- goto exception;
- }
- if (JS_DefinePropertyValueInt64(ctx, arr, n, js_dup(e),
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- n++;
- }
- }
- if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(n)) < 0)
- goto exception;
- JS_FreeValue(ctx, obj);
- return arr;
- exception:
- JS_FreeValue(ctx, arr);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- #define special_every 0
- #define special_some 1
- #define special_forEach 2
- #define special_map 3
- #define special_filter 4
- #define special_TA 8
- static JSObject *get_typed_array(JSContext *ctx, JSValueConst this_val)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
- goto fail;
- p = JS_VALUE_GET_OBJ(this_val);
- if (!is_typed_array(p->class_id)) {
- fail:
- JS_ThrowTypeError(ctx, "not a TypedArray");
- return NULL;
- }
- return p;
- }
- // Be *very* careful if you touch the typed array's memory directly:
- // the length is only valid until the next call into JS land because
- // JS code can detach or resize the backing array buffer. Functions
- // like JS_GetProperty and JS_ToIndex call JS code.
- //
- // Exclusively reading or writing elements with JS_GetProperty,
- // JS_GetPropertyInt64, JS_SetProperty, etc. is safe because they
- // perform bounds checks, as does js_get_fast_array_element.
- static int js_typed_array_get_length_unsafe(JSContext *ctx, JSValueConst obj)
- {
- JSObject *p;
- p = get_typed_array(ctx, obj);
- if (!p)
- return -1;
- if (typed_array_is_oob(p)) {
- JS_ThrowTypeErrorArrayBufferOOB(ctx);
- return -1;
- }
- return p->u.array.count;
- }
- static JSValue js_typed_array___speciesCreate(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv);
- static JSValue js_array_every(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int special)
- {
- JSValue obj, val, index_val, res, ret;
- JSValueConst args[3];
- JSValueConst func, this_arg;
- int64_t len, k, n;
- int present;
- ret = JS_UNDEFINED;
- val = JS_UNDEFINED;
- if (special & special_TA) {
- obj = js_dup(this_val);
- len = js_typed_array_get_length_unsafe(ctx, obj);
- if (len < 0)
- goto exception;
- } else {
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- }
- func = argv[0];
- this_arg = JS_UNDEFINED;
- if (argc > 1)
- this_arg = argv[1];
- if (check_function(ctx, func))
- goto exception;
- switch (special) {
- case special_every:
- case special_every | special_TA:
- ret = JS_TRUE;
- break;
- case special_some:
- case special_some | special_TA:
- ret = JS_FALSE;
- break;
- case special_map:
- /* XXX: JS_ArraySpeciesCreate should take int64_t */
- ret = JS_ArraySpeciesCreate(ctx, obj, js_int64(len));
- if (JS_IsException(ret))
- goto exception;
- break;
- case special_filter:
- ret = JS_ArraySpeciesCreate(ctx, obj, js_int32(0));
- if (JS_IsException(ret))
- goto exception;
- break;
- case special_map | special_TA:
- args[0] = obj;
- args[1] = js_int32(len);
- ret = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
- if (JS_IsException(ret))
- goto exception;
- break;
- case special_filter | special_TA:
- ret = JS_NewArray(ctx);
- if (JS_IsException(ret))
- goto exception;
- break;
- }
- n = 0;
- for(k = 0; k < len; k++) {
- if (special & special_TA) {
- val = JS_GetPropertyInt64(ctx, obj, k);
- if (JS_IsException(val))
- goto exception;
- present = true;
- } else {
- present = JS_TryGetPropertyInt64(ctx, obj, k, &val);
- if (present < 0)
- goto exception;
- }
- if (present) {
- index_val = js_int64(k);
- args[0] = val;
- args[1] = index_val;
- args[2] = obj;
- res = JS_Call(ctx, func, this_arg, 3, args);
- JS_FreeValue(ctx, index_val);
- if (JS_IsException(res))
- goto exception;
- switch (special) {
- case special_every:
- case special_every | special_TA:
- if (!JS_ToBoolFree(ctx, res)) {
- ret = JS_FALSE;
- goto done;
- }
- break;
- case special_some:
- case special_some | special_TA:
- if (JS_ToBoolFree(ctx, res)) {
- ret = JS_TRUE;
- goto done;
- }
- break;
- case special_map:
- if (JS_DefinePropertyValueInt64(ctx, ret, k, res,
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- break;
- case special_map | special_TA:
- if (JS_SetPropertyValue(ctx, ret, js_int32(k), res, JS_PROP_THROW) < 0)
- goto exception;
- break;
- case special_filter:
- case special_filter | special_TA:
- if (JS_ToBoolFree(ctx, res)) {
- if (JS_DefinePropertyValueInt64(ctx, ret, n++, js_dup(val),
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- }
- break;
- default:
- JS_FreeValue(ctx, res);
- break;
- }
- JS_FreeValue(ctx, val);
- val = JS_UNDEFINED;
- }
- }
- done:
- if (special == (special_filter | special_TA)) {
- JSValue arr;
- args[0] = obj;
- args[1] = js_int32(n);
- arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
- if (JS_IsException(arr))
- goto exception;
- args[0] = ret;
- res = JS_Invoke(ctx, arr, JS_ATOM_set, 1, args);
- if (check_exception_free(ctx, res)) {
- JS_FreeValue(ctx, arr);
- goto exception;
- }
- JS_FreeValue(ctx, ret);
- ret = arr;
- }
- JS_FreeValue(ctx, val);
- JS_FreeValue(ctx, obj);
- return ret;
- exception:
- JS_FreeValue(ctx, ret);
- JS_FreeValue(ctx, val);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- #define special_reduce 0
- #define special_reduceRight 1
- static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int special)
- {
- JSValue obj, val, index_val, acc, acc1;
- JSValueConst args[4];
- JSValueConst func;
- int64_t len, k, k1;
- int present;
- acc = JS_UNDEFINED;
- val = JS_UNDEFINED;
- if (special & special_TA) {
- obj = js_dup(this_val);
- len = js_typed_array_get_length_unsafe(ctx, obj);
- if (len < 0)
- goto exception;
- } else {
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- }
- func = argv[0];
- if (check_function(ctx, func))
- goto exception;
- k = 0;
- if (argc > 1) {
- acc = js_dup(argv[1]);
- } else {
- for(;;) {
- if (k >= len) {
- JS_ThrowTypeError(ctx, "empty array");
- goto exception;
- }
- k1 = (special & special_reduceRight) ? len - k - 1 : k;
- k++;
- if (special & special_TA) {
- acc = JS_GetPropertyInt64(ctx, obj, k1);
- if (JS_IsException(acc))
- goto exception;
- break;
- } else {
- present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc);
- if (present < 0)
- goto exception;
- if (present)
- break;
- }
- }
- }
- for (; k < len; k++) {
- k1 = (special & special_reduceRight) ? len - k - 1 : k;
- if (special & special_TA) {
- val = JS_GetPropertyInt64(ctx, obj, k1);
- if (JS_IsException(val))
- goto exception;
- present = true;
- } else {
- present = JS_TryGetPropertyInt64(ctx, obj, k1, &val);
- if (present < 0)
- goto exception;
- }
- if (present) {
- index_val = js_int64(k1);
- args[0] = acc;
- args[1] = val;
- args[2] = index_val;
- args[3] = obj;
- acc1 = JS_Call(ctx, func, JS_UNDEFINED, 4, args);
- JS_FreeValue(ctx, index_val);
- JS_FreeValue(ctx, val);
- val = JS_UNDEFINED;
- if (JS_IsException(acc1))
- goto exception;
- JS_FreeValue(ctx, acc);
- acc = acc1;
- }
- }
- JS_FreeValue(ctx, obj);
- return acc;
- exception:
- JS_FreeValue(ctx, acc);
- JS_FreeValue(ctx, val);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_array_fill(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj;
- int64_t len, start, end;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- start = 0;
- if (argc > 1 && !JS_IsUndefined(argv[1])) {
- if (JS_ToInt64Clamp(ctx, &start, argv[1], 0, len, len))
- goto exception;
- }
- end = len;
- if (argc > 2 && !JS_IsUndefined(argv[2])) {
- if (JS_ToInt64Clamp(ctx, &end, argv[2], 0, len, len))
- goto exception;
- }
- /* XXX: should special case fast arrays */
- while (start < end) {
- if (JS_SetPropertyInt64(ctx, obj, start, js_dup(argv[0])) < 0)
- goto exception;
- start++;
- }
- return obj;
- exception:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj, val;
- int64_t len, n;
- JSValue *arrp;
- uint32_t count;
- int res;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- res = true;
- if (len > 0) {
- n = 0;
- if (argc > 1) {
- if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
- goto exception;
- }
- if (js_get_fast_array(ctx, obj, &arrp, &count)) {
- for (; n < count; n++) {
- if (js_strict_eq2(ctx, js_dup(argv[0]), js_dup(arrp[n]),
- JS_EQ_SAME_VALUE_ZERO)) {
- goto done;
- }
- }
- }
- for (; n < len; n++) {
- val = JS_GetPropertyInt64(ctx, obj, n);
- if (JS_IsException(val))
- goto exception;
- if (js_strict_eq2(ctx, js_dup(argv[0]), val,
- JS_EQ_SAME_VALUE_ZERO)) {
- goto done;
- }
- }
- }
- res = false;
- done:
- JS_FreeValue(ctx, obj);
- return js_bool(res);
- exception:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj, val;
- int64_t len, n;
- JSValue *arrp;
- uint32_t count;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- if (len > 0) {
- n = 0;
- if (argc > 1) {
- if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
- goto exception;
- }
- if (js_get_fast_array(ctx, obj, &arrp, &count)) {
- for (; n < count; n++) {
- if (js_strict_eq2(ctx, js_dup(argv[0]), js_dup(arrp[n]),
- JS_EQ_STRICT)) {
- goto done;
- }
- }
- }
- for (; n < len; n++) {
- int present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
- if (present < 0)
- goto exception;
- if (present) {
- if (js_strict_eq2(ctx, js_dup(argv[0]), val, JS_EQ_STRICT)) {
- goto done;
- }
- }
- }
- }
- n = -1;
- done:
- JS_FreeValue(ctx, obj);
- return js_int64(n);
- exception:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj, val;
- int64_t len, n;
- JSValue *arrp;
- uint32_t count;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- if (len > 0) {
- n = len - 1;
- if (argc > 1) {
- if (JS_ToInt64Clamp(ctx, &n, argv[1], -1, len - 1, len))
- goto exception;
- }
- if (js_get_fast_array(ctx, obj, &arrp, &count) && count == len) {
- for (; n >= 0; n--) {
- if (js_strict_eq2(ctx, js_dup(argv[0]), js_dup(arrp[n]),
- JS_EQ_STRICT)) {
- goto done;
- }
- }
- }
- for (; n >= 0; n--) {
- int present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
- if (present < 0)
- goto exception;
- if (present) {
- if (js_strict_eq2(ctx, js_dup(argv[0]), val, JS_EQ_STRICT)) {
- goto done;
- }
- }
- }
- }
- n = -1;
- done:
- JS_FreeValue(ctx, obj);
- return js_int64(n);
- exception:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- enum {
- ArrayFind,
- ArrayFindIndex,
- ArrayFindLast,
- ArrayFindLastIndex,
- };
- static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int mode)
- {
- JSValueConst func, this_arg;
- JSValueConst args[3];
- JSValue obj, val, index_val, res;
- int64_t len, k, end;
- int dir;
- index_val = JS_UNDEFINED;
- val = JS_UNDEFINED;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- func = argv[0];
- if (check_function(ctx, func))
- goto exception;
- this_arg = JS_UNDEFINED;
- if (argc > 1)
- this_arg = argv[1];
- k = 0;
- dir = 1;
- end = len;
- if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {
- k = len - 1;
- dir = -1;
- end = -1;
- }
- // TODO(bnoordhuis) add fast path for fast arrays
- for(; k != end; k += dir) {
- index_val = js_int64(k);
- val = JS_GetPropertyValue(ctx, obj, index_val);
- if (JS_IsException(val))
- goto exception;
- args[0] = val;
- args[1] = index_val;
- args[2] = this_val;
- res = JS_Call(ctx, func, this_arg, 3, args);
- if (JS_IsException(res))
- goto exception;
- if (JS_ToBoolFree(ctx, res)) {
- if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {
- JS_FreeValue(ctx, val);
- JS_FreeValue(ctx, obj);
- return index_val;
- } else {
- JS_FreeValue(ctx, index_val);
- JS_FreeValue(ctx, obj);
- return val;
- }
- }
- JS_FreeValue(ctx, val);
- JS_FreeValue(ctx, index_val);
- }
- JS_FreeValue(ctx, obj);
- if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)
- return js_int32(-1);
- else
- return JS_UNDEFINED;
- exception:
- JS_FreeValue(ctx, index_val);
- JS_FreeValue(ctx, val);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_array_toString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj, method, ret;
- obj = JS_ToObject(ctx, this_val);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- method = JS_GetProperty(ctx, obj, JS_ATOM_join);
- if (JS_IsException(method)) {
- ret = JS_EXCEPTION;
- } else
- if (!JS_IsFunction(ctx, method)) {
- /* Use intrinsic Object.prototype.toString */
- JS_FreeValue(ctx, method);
- ret = js_object_toString(ctx, obj, 0, NULL);
- } else {
- ret = JS_CallFree(ctx, method, obj, 0, NULL);
- }
- JS_FreeValue(ctx, obj);
- return ret;
- }
- static JSValue js_array_join(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int toLocaleString)
- {
- JSValue obj, sep = JS_UNDEFINED, el;
- StringBuffer b_s, *b = &b_s;
- JSString *p = NULL;
- int64_t i, n;
- int c;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &n, obj))
- goto exception;
- c = ','; /* default separator */
- if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
- sep = JS_ToString(ctx, argv[0]);
- if (JS_IsException(sep))
- goto exception;
- p = JS_VALUE_GET_STRING(sep);
- if (p->len == 1 && !p->is_wide_char)
- c = str8(p)[0];
- else
- c = -1;
- }
- string_buffer_init(ctx, b, 0);
- for(i = 0; i < n; i++) {
- if (i > 0) {
- if (c >= 0) {
- string_buffer_putc8(b, c);
- } else {
- string_buffer_concat(b, p, 0, p->len);
- }
- }
- el = JS_GetPropertyUint32(ctx, obj, i);
- if (JS_IsException(el))
- goto fail;
- if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
- if (toLocaleString) {
- el = JS_ToLocaleStringFree(ctx, el);
- }
- if (string_buffer_concat_value_free(b, el))
- goto fail;
- }
- }
- JS_FreeValue(ctx, sep);
- JS_FreeValue(ctx, obj);
- return string_buffer_end(b);
- fail:
- string_buffer_free(b);
- JS_FreeValue(ctx, sep);
- exception:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_array_pop(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int shift)
- {
- JSValue obj, res = JS_UNDEFINED;
- int64_t len, newLen;
- JSValue *arrp;
- uint32_t count32;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- newLen = 0;
- if (len > 0) {
- newLen = len - 1;
- /* Special case fast arrays */
- if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- if (shift) {
- res = arrp[0];
- memmove(arrp, arrp + 1, (count32 - 1) * sizeof(*arrp));
- p->u.array.count--;
- } else {
- res = arrp[count32 - 1];
- p->u.array.count--;
- }
- } else {
- if (shift) {
- res = JS_GetPropertyInt64(ctx, obj, 0);
- if (JS_IsException(res))
- goto exception;
- if (JS_CopySubArray(ctx, obj, 0, 1, len - 1, +1))
- goto exception;
- } else {
- res = JS_GetPropertyInt64(ctx, obj, newLen);
- if (JS_IsException(res))
- goto exception;
- }
- if (JS_DeletePropertyInt64(ctx, obj, newLen, JS_PROP_THROW) < 0)
- goto exception;
- }
- }
- if (JS_SetProperty(ctx, obj, JS_ATOM_length, js_int64(newLen)) < 0)
- goto exception;
- JS_FreeValue(ctx, obj);
- return res;
- exception:
- JS_FreeValue(ctx, res);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int unshift)
- {
- JSValue obj;
- int i;
- int64_t len, from, newLen;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- newLen = len + argc;
- if (newLen > MAX_SAFE_INTEGER) {
- JS_ThrowTypeError(ctx, "Array loo long");
- goto exception;
- }
- from = len;
- if (unshift && argc > 0) {
- if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
- goto exception;
- from = 0;
- }
- for(i = 0; i < argc; i++) {
- if (JS_SetPropertyInt64(ctx, obj, from + i, js_dup(argv[i])) < 0)
- goto exception;
- }
- if (JS_SetProperty(ctx, obj, JS_ATOM_length, js_int64(newLen)) < 0)
- goto exception;
- JS_FreeValue(ctx, obj);
- return js_int64(newLen);
- exception:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj, lval, hval;
- JSValue *arrp;
- int64_t len, l, h;
- int l_present, h_present;
- uint32_t count32;
- lval = JS_UNDEFINED;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- /* Special case fast arrays */
- if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
- uint32_t ll, hh;
- if (count32 > 1) {
- for (ll = 0, hh = count32 - 1; ll < hh; ll++, hh--) {
- lval = arrp[ll];
- arrp[ll] = arrp[hh];
- arrp[hh] = lval;
- }
- }
- return obj;
- }
- for (l = 0, h = len - 1; l < h; l++, h--) {
- l_present = JS_TryGetPropertyInt64(ctx, obj, l, &lval);
- if (l_present < 0)
- goto exception;
- h_present = JS_TryGetPropertyInt64(ctx, obj, h, &hval);
- if (h_present < 0)
- goto exception;
- if (h_present) {
- if (JS_SetPropertyInt64(ctx, obj, l, hval) < 0)
- goto exception;
- if (l_present) {
- if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
- lval = JS_UNDEFINED;
- goto exception;
- }
- lval = JS_UNDEFINED;
- } else {
- if (JS_DeletePropertyInt64(ctx, obj, h, JS_PROP_THROW) < 0)
- goto exception;
- }
- } else {
- if (l_present) {
- if (JS_DeletePropertyInt64(ctx, obj, l, JS_PROP_THROW) < 0)
- goto exception;
- if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
- lval = JS_UNDEFINED;
- goto exception;
- }
- lval = JS_UNDEFINED;
- }
- }
- }
- return obj;
- exception:
- JS_FreeValue(ctx, lval);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- // Note: a.toReversed() is a.slice().reverse() with the twist that a.slice()
- // leaves holes in sparse arrays intact whereas a.toReversed() replaces them
- // with undefined, thus in effect creating a dense array.
- // Does not use Array[@@species], always returns a base Array.
- static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue arr, obj, ret, *arrp, *pval;
- JSObject *p;
- int64_t i, len;
- uint32_t count32;
- ret = JS_EXCEPTION;
- arr = JS_UNDEFINED;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- if (len > UINT32_MAX) {
- JS_ThrowRangeError(ctx, "invalid array length");
- goto exception;
- }
- arr = JS_NewArray(ctx);
- if (JS_IsException(arr))
- goto exception;
- if (len > 0) {
- p = JS_VALUE_GET_OBJ(arr);
- if (expand_fast_array(ctx, p, len) < 0)
- goto exception;
- p->u.array.count = len;
- i = len - 1;
- pval = p->u.array.u.values;
- if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
- for (; i >= 0; i--, pval++)
- *pval = js_dup(arrp[i]);
- } else {
- // Query order is observable; test262 expects descending order.
- for (; i >= 0; i--, pval++) {
- if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
- // Exception; initialize remaining elements.
- for (; i >= 0; i--, pval++)
- *pval = JS_UNDEFINED;
- goto exception;
- }
- }
- }
- if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(len)) < 0)
- goto exception;
- }
- ret = arr;
- arr = JS_UNDEFINED;
- exception:
- JS_FreeValue(ctx, arr);
- JS_FreeValue(ctx, obj);
- return ret;
- }
- static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int splice)
- {
- JSValue obj, arr, val, len_val;
- int64_t len, start, k, final, n, count, del_count, new_len;
- int kPresent;
- JSValue *arrp;
- uint32_t count32, i, item_count;
- arr = JS_UNDEFINED;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
- goto exception;
- if (splice) {
- if (argc == 0) {
- item_count = 0;
- del_count = 0;
- } else if (argc == 1) {
- item_count = 0;
- del_count = len - start;
- } else {
- item_count = argc - 2;
- if (JS_ToInt64Clamp(ctx, &del_count, argv[1], 0, len - start, 0))
- goto exception;
- }
- if (len + item_count - del_count > MAX_SAFE_INTEGER) {
- JS_ThrowTypeError(ctx, "Array loo long");
- goto exception;
- }
- count = del_count;
- } else {
- item_count = 0; /* avoid warning */
- final = len;
- if (!JS_IsUndefined(argv[1])) {
- if (JS_ToInt64Clamp(ctx, &final, argv[1], 0, len, len))
- goto exception;
- }
- count = max_int64(final - start, 0);
- }
- len_val = js_int64(count);
- arr = JS_ArraySpeciesCreate(ctx, obj, len_val);
- JS_FreeValue(ctx, len_val);
- if (JS_IsException(arr))
- goto exception;
- k = start;
- final = start + count;
- n = 0;
- /* The fast array test on arr ensures that
- JS_CreateDataPropertyUint32() won't modify obj in case arr is
- an exotic object */
- /* Special case fast arrays */
- if (js_get_fast_array(ctx, obj, &arrp, &count32) &&
- js_is_fast_array(ctx, arr)) {
- /* XXX: should share code with fast array constructor */
- for (; k < final && k < count32; k++, n++) {
- if (JS_CreateDataPropertyUint32(ctx, arr, n, js_dup(arrp[k]), JS_PROP_THROW) < 0)
- goto exception;
- }
- }
- /* Copy the remaining elements if any (handle case of inherited properties) */
- for (; k < final; k++, n++) {
- kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val);
- if (kPresent < 0)
- goto exception;
- if (kPresent) {
- if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0)
- goto exception;
- }
- }
- if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(n)) < 0)
- goto exception;
- if (splice) {
- new_len = len + item_count - del_count;
- if (item_count != del_count) {
- if (JS_CopySubArray(ctx, obj, start + item_count,
- start + del_count, len - (start + del_count),
- item_count <= del_count ? +1 : -1) < 0)
- goto exception;
- for (k = len; k-- > new_len; ) {
- if (JS_DeletePropertyInt64(ctx, obj, k, JS_PROP_THROW) < 0)
- goto exception;
- }
- }
- for (i = 0; i < item_count; i++) {
- if (JS_SetPropertyInt64(ctx, obj, start + i, js_dup(argv[i + 2])) < 0)
- goto exception;
- }
- if (JS_SetProperty(ctx, obj, JS_ATOM_length, js_int64(new_len)) < 0)
- goto exception;
- }
- JS_FreeValue(ctx, obj);
- return arr;
- exception:
- JS_FreeValue(ctx, obj);
- JS_FreeValue(ctx, arr);
- return JS_EXCEPTION;
- }
- static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue arr, obj, ret, *arrp, *pval, *last;
- JSObject *p;
- int64_t i, j, len, newlen, start, add, del;
- uint32_t count32;
- pval = NULL;
- last = NULL;
- ret = JS_EXCEPTION;
- arr = JS_UNDEFINED;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- start = 0;
- if (argc > 0)
- if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
- goto exception;
- del = 0;
- if (argc > 0)
- del = len - start;
- if (argc > 1)
- if (JS_ToInt64Clamp(ctx, &del, argv[1], 0, del, 0))
- goto exception;
- add = 0;
- if (argc > 2)
- add = argc - 2;
- newlen = len + add - del;
- if (newlen > UINT32_MAX) {
- // Per spec: TypeError if newlen >= 2**53, RangeError below
- if (newlen > MAX_SAFE_INTEGER) {
- JS_ThrowTypeError(ctx, "invalid array length");
- } else {
- JS_ThrowRangeError(ctx, "invalid array length");
- }
- goto exception;
- }
- arr = JS_NewArray(ctx);
- if (JS_IsException(arr))
- goto exception;
- if (newlen <= 0)
- goto done;
- p = JS_VALUE_GET_OBJ(arr);
- if (expand_fast_array(ctx, p, newlen) < 0)
- goto exception;
- p->u.array.count = newlen;
- pval = &p->u.array.u.values[0];
- last = &p->u.array.u.values[newlen];
- if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
- for (i = 0; i < start; i++, pval++)
- *pval = js_dup(arrp[i]);
- for (j = 0; j < add; j++, pval++)
- *pval = js_dup(argv[2 + j]);
- for (i += del; i < len; i++, pval++)
- *pval = js_dup(arrp[i]);
- } else {
- for (i = 0; i < start; i++, pval++)
- if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
- goto exception;
- for (j = 0; j < add; j++, pval++)
- *pval = js_dup(argv[2 + j]);
- for (i += del; i < len; i++, pval++)
- if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
- goto exception;
- }
- assert(pval == last);
- if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(newlen)) < 0)
- goto exception;
- done:
- ret = arr;
- arr = JS_UNDEFINED;
- exception:
- while (pval != last)
- *pval++ = JS_UNDEFINED;
- JS_FreeValue(ctx, arr);
- JS_FreeValue(ctx, obj);
- return ret;
- }
- static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj;
- int64_t len, from, to, final, count;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- if (JS_ToInt64Clamp(ctx, &to, argv[0], 0, len, len))
- goto exception;
- if (JS_ToInt64Clamp(ctx, &from, argv[1], 0, len, len))
- goto exception;
- final = len;
- if (argc > 2 && !JS_IsUndefined(argv[2])) {
- if (JS_ToInt64Clamp(ctx, &final, argv[2], 0, len, len))
- goto exception;
- }
- count = min_int64(final - from, len - to);
- if (JS_CopySubArray(ctx, obj, to, from, count,
- (from < to && to < from + count) ? -1 : +1))
- goto exception;
- return obj;
- exception:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
- JSValueConst source, int64_t sourceLen,
- int64_t targetIndex, int depth,
- JSValueConst mapperFunction,
- JSValueConst thisArg)
- {
- JSValue element;
- int64_t sourceIndex, elementLen;
- int present, is_array;
- if (js_check_stack_overflow(ctx->rt, 0)) {
- JS_ThrowStackOverflow(ctx);
- return -1;
- }
- for (sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
- present = JS_TryGetPropertyInt64(ctx, source, sourceIndex, &element);
- if (present < 0)
- return -1;
- if (!present)
- continue;
- if (!JS_IsUndefined(mapperFunction)) {
- JSValue index = js_int64(sourceIndex);
- JSValueConst args[3] = { element, index, source };
- JSValue ret = JS_Call(ctx, mapperFunction, thisArg, 3, args);
- JS_FreeValue(ctx, element);
- JS_FreeValue(ctx, index);
- if (JS_IsException(ret))
- return -1;
- element = ret;
- }
- if (depth > 0) {
- is_array = js_is_array(ctx, element);
- if (is_array < 0)
- goto fail;
- if (is_array) {
- if (js_get_length64(ctx, &elementLen, element) < 0)
- goto fail;
- targetIndex = JS_FlattenIntoArray(ctx, target, element,
- elementLen, targetIndex,
- depth - 1,
- JS_UNDEFINED, JS_UNDEFINED);
- if (targetIndex < 0)
- goto fail;
- JS_FreeValue(ctx, element);
- continue;
- }
- }
- if (targetIndex >= MAX_SAFE_INTEGER) {
- JS_ThrowTypeError(ctx, "Array too long");
- goto fail;
- }
- if (JS_DefinePropertyValueInt64(ctx, target, targetIndex, element,
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- return -1;
- targetIndex++;
- }
- return targetIndex;
- fail:
- JS_FreeValue(ctx, element);
- return -1;
- }
- static JSValue js_array_flatten(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int map)
- {
- JSValue obj, arr;
- JSValueConst mapperFunction, thisArg;
- int64_t sourceLen;
- int depthNum;
- arr = JS_UNDEFINED;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &sourceLen, obj))
- goto exception;
- depthNum = 1;
- mapperFunction = JS_UNDEFINED;
- thisArg = JS_UNDEFINED;
- if (map) {
- mapperFunction = argv[0];
- if (argc > 1) {
- thisArg = argv[1];
- }
- if (check_function(ctx, mapperFunction))
- goto exception;
- } else {
- if (argc > 0 && !JS_IsUndefined(argv[0])) {
- if (JS_ToInt32Sat(ctx, &depthNum, argv[0]) < 0)
- goto exception;
- }
- }
- arr = JS_ArraySpeciesCreate(ctx, obj, js_int32(0));
- if (JS_IsException(arr))
- goto exception;
- if (JS_FlattenIntoArray(ctx, arr, obj, sourceLen, 0, depthNum,
- mapperFunction, thisArg) < 0)
- goto exception;
- JS_FreeValue(ctx, obj);
- return arr;
- exception:
- JS_FreeValue(ctx, obj);
- JS_FreeValue(ctx, arr);
- return JS_EXCEPTION;
- }
- /* Array sort */
- typedef struct ValueSlot {
- JSValue val;
- JSString *str;
- int64_t pos;
- } ValueSlot;
- struct array_sort_context {
- JSContext *ctx;
- int exception;
- int has_method;
- JSValueConst method;
- };
- static int js_array_cmp_generic(const void *a, const void *b, void *opaque) {
- struct array_sort_context *psc = opaque;
- JSContext *ctx = psc->ctx;
- JSValueConst argv[2];
- JSValue res;
- ValueSlot *ap = (ValueSlot *)(void *)a;
- ValueSlot *bp = (ValueSlot *)(void *)b;
- int cmp;
- if (psc->exception)
- return 0;
- if (psc->has_method) {
- /* custom sort function is specified as returning 0 for identical
- * objects: avoid method call overhead.
- */
- if (!memcmp(&ap->val, &bp->val, sizeof(ap->val)))
- goto cmp_same;
- argv[0] = ap->val;
- argv[1] = bp->val;
- res = JS_Call(ctx, psc->method, JS_UNDEFINED, 2, argv);
- if (JS_IsException(res))
- goto exception;
- if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
- int val = JS_VALUE_GET_INT(res);
- cmp = (val > 0) - (val < 0);
- } else {
- double val;
- if (JS_ToFloat64Free(ctx, &val, res) < 0)
- goto exception;
- cmp = (val > 0) - (val < 0);
- }
- } else {
- /* Not supposed to bypass ToString even for identical objects as
- * tested in test262/test/built-ins/Array/prototype/sort/bug_596_1.js
- */
- if (!ap->str) {
- JSValue str = JS_ToString(ctx, ap->val);
- if (JS_IsException(str))
- goto exception;
- ap->str = JS_VALUE_GET_STRING(str);
- }
- if (!bp->str) {
- JSValue str = JS_ToString(ctx, bp->val);
- if (JS_IsException(str))
- goto exception;
- bp->str = JS_VALUE_GET_STRING(str);
- }
- cmp = js_string_compare(ap->str, bp->str);
- }
- if (cmp != 0)
- return cmp;
- cmp_same:
- /* make sort stable: compare array offsets */
- return (ap->pos > bp->pos) - (ap->pos < bp->pos);
- exception:
- psc->exception = 1;
- return 0;
- }
- static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- struct array_sort_context asc = { ctx, 0, 0, argv[0] };
- JSValue obj = JS_UNDEFINED;
- ValueSlot *array = NULL;
- size_t array_size = 0, pos = 0, n = 0;
- int64_t i, len, undefined_count = 0;
- int present;
- if (!JS_IsUndefined(asc.method)) {
- if (check_function(ctx, asc.method))
- goto exception;
- asc.has_method = 1;
- }
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- /* XXX: should special case fast arrays */
- for (i = 0; i < len; i++) {
- if (pos >= array_size) {
- size_t new_size, slack;
- ValueSlot *new_array;
- new_size = (array_size + (array_size >> 1) + 31) & ~15;
- new_array = js_realloc2(ctx, array, new_size * sizeof(*array), &slack);
- if (new_array == NULL)
- goto exception;
- new_size += slack / sizeof(*new_array);
- array = new_array;
- array_size = new_size;
- }
- present = JS_TryGetPropertyInt64(ctx, obj, i, &array[pos].val);
- if (present < 0)
- goto exception;
- if (present == 0)
- continue;
- if (JS_IsUndefined(array[pos].val)) {
- undefined_count++;
- continue;
- }
- array[pos].str = NULL;
- array[pos].pos = i;
- pos++;
- }
- rqsort(array, pos, sizeof(*array), js_array_cmp_generic, &asc);
- if (asc.exception)
- goto exception;
- /* XXX: should special case fast arrays */
- while (n < pos) {
- if (array[n].str)
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
- if (array[n].pos == n) {
- JS_FreeValue(ctx, array[n].val);
- } else {
- if (JS_SetPropertyInt64(ctx, obj, n, array[n].val) < 0) {
- n++;
- goto exception;
- }
- }
- n++;
- }
- js_free(ctx, array);
- for (i = n; undefined_count-- > 0; i++) {
- if (JS_SetPropertyInt64(ctx, obj, i, JS_UNDEFINED) < 0)
- goto fail;
- }
- for (; i < len; i++) {
- if (JS_DeletePropertyInt64(ctx, obj, i, JS_PROP_THROW) < 0)
- goto fail;
- }
- return obj;
- exception:
- for (; n < pos; n++) {
- JS_FreeValue(ctx, array[n].val);
- if (array[n].str)
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
- }
- js_free(ctx, array);
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- // Note: a.toSorted() is a.slice().sort() with the twist that a.slice()
- // leaves holes in sparse arrays intact whereas a.toSorted() replaces them
- // with undefined, thus in effect creating a dense array.
- // Does not use Array[@@species], always returns a base Array.
- static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue arr, obj, ret, *arrp, *pval;
- JSObject *p;
- int64_t i, len;
- uint32_t count32;
- if (!JS_IsUndefined(argv[0]))
- if (check_function(ctx, argv[0]))
- return JS_EXCEPTION;
- ret = JS_EXCEPTION;
- arr = JS_UNDEFINED;
- obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- if (len > UINT32_MAX) {
- JS_ThrowRangeError(ctx, "invalid array length");
- goto exception;
- }
- arr = JS_NewArray(ctx);
- if (JS_IsException(arr))
- goto exception;
- if (len > 0) {
- p = JS_VALUE_GET_OBJ(arr);
- if (expand_fast_array(ctx, p, len) < 0)
- goto exception;
- p->u.array.count = len;
- i = 0;
- pval = p->u.array.u.values;
- if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
- for (; i < len; i++, pval++)
- *pval = js_dup(arrp[i]);
- } else {
- for (; i < len; i++, pval++) {
- if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
- for (; i < len; i++, pval++)
- *pval = JS_UNDEFINED;
- goto exception;
- }
- }
- }
- if (JS_SetProperty(ctx, arr, JS_ATOM_length, js_int64(len)) < 0)
- goto exception;
- }
- ret = js_array_sort(ctx, arr, argc, argv);
- if (JS_IsException(ret))
- goto exception;
- JS_FreeValue(ctx, ret);
- ret = arr;
- arr = JS_UNDEFINED;
- exception:
- JS_FreeValue(ctx, arr);
- JS_FreeValue(ctx, obj);
- return ret;
- }
- typedef struct JSArrayIteratorData {
- JSValue obj;
- JSIteratorKindEnum kind;
- uint32_t idx;
- } JSArrayIteratorData;
- static void js_array_iterator_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSArrayIteratorData *it = p->u.array_iterator_data;
- if (it) {
- JS_FreeValueRT(rt, it->obj);
- js_free_rt(rt, it);
- }
- }
- static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSArrayIteratorData *it = p->u.array_iterator_data;
- if (it) {
- JS_MarkValue(rt, it->obj, mark_func);
- }
- }
- static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab)
- {
- JSValue obj;
- int i;
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- for(i = 0; i < len; i++) {
- if (JS_CreateDataPropertyUint32(ctx, obj, i, js_dup(tab[i]), 0) < 0) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- }
- return obj;
- }
- static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValue enum_obj, arr;
- JSArrayIteratorData *it;
- JSIteratorKindEnum kind;
- int class_id;
- kind = magic & 3;
- if (magic & 4) {
- /* string iterator case */
- arr = JS_ToStringCheckObject(ctx, this_val);
- class_id = JS_CLASS_STRING_ITERATOR;
- } else {
- arr = JS_ToObject(ctx, this_val);
- class_id = JS_CLASS_ARRAY_ITERATOR;
- }
- if (JS_IsException(arr))
- goto fail;
- enum_obj = JS_NewObjectClass(ctx, class_id);
- if (JS_IsException(enum_obj))
- goto fail;
- it = js_malloc(ctx, sizeof(*it));
- if (!it)
- goto fail1;
- it->obj = arr;
- it->kind = kind;
- it->idx = 0;
- JS_SetOpaqueInternal(enum_obj, it);
- return enum_obj;
- fail1:
- JS_FreeValue(ctx, enum_obj);
- fail:
- JS_FreeValue(ctx, arr);
- return JS_EXCEPTION;
- }
- static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int *pdone, int magic)
- {
- JSArrayIteratorData *it;
- uint32_t len, idx;
- JSValue val, obj;
- JSObject *p;
- it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_ITERATOR);
- if (!it)
- goto fail1;
- if (JS_IsUndefined(it->obj))
- goto done;
- p = JS_VALUE_GET_OBJ(it->obj);
- if (is_typed_array(p->class_id)) {
- if (typed_array_is_oob(p)) {
- JS_ThrowTypeErrorArrayBufferOOB(ctx);
- goto fail1;
- }
- len = p->u.array.count;
- } else {
- if (js_get_length32(ctx, &len, it->obj)) {
- fail1:
- *pdone = false;
- return JS_EXCEPTION;
- }
- }
- idx = it->idx;
- if (idx >= len) {
- JS_FreeValue(ctx, it->obj);
- it->obj = JS_UNDEFINED;
- done:
- *pdone = true;
- return JS_UNDEFINED;
- }
- it->idx = idx + 1;
- *pdone = false;
- if (it->kind == JS_ITERATOR_KIND_KEY) {
- return js_uint32(idx);
- } else {
- val = JS_GetPropertyUint32(ctx, it->obj, idx);
- if (JS_IsException(val))
- return JS_EXCEPTION;
- if (it->kind == JS_ITERATOR_KIND_VALUE) {
- return val;
- } else {
- JSValueConst args[2];
- JSValue num;
- num = js_uint32(idx);
- args[0] = num;
- args[1] = val;
- obj = js_create_array(ctx, 2, args);
- JS_FreeValue(ctx, val);
- JS_FreeValue(ctx, num);
- return obj;
- }
- }
- }
- typedef struct JSIteratorWrapData {
- JSValue wrapped_iter;
- JSValue wrapped_next;
- } JSIteratorWrapData;
- static void js_iterator_wrap_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSIteratorWrapData *it = p->u.iterator_wrap_data;
- if (it) {
- JS_FreeValueRT(rt, it->wrapped_iter);
- JS_FreeValueRT(rt, it->wrapped_next);
- js_free_rt(rt, it);
- }
- }
- static void js_iterator_wrap_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSIteratorWrapData *it = p->u.iterator_wrap_data;
- if (it) {
- JS_MarkValue(rt, it->wrapped_iter, mark_func);
- JS_MarkValue(rt, it->wrapped_next, mark_func);
- }
- }
- static JSValue js_iterator_wrap_next(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int *pdone, int magic)
- {
- JSIteratorWrapData *it;
- JSValue method, ret;
- it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_WRAP);
- if (!it)
- return JS_EXCEPTION;
- if (magic == GEN_MAGIC_NEXT)
- return JS_IteratorNext(ctx, it->wrapped_iter, it->wrapped_next, argc, argv, pdone);
- method = JS_GetProperty(ctx, it->wrapped_iter, JS_ATOM_return);
- if (JS_IsException(method))
- return JS_EXCEPTION;
- if (JS_IsNull(method) || JS_IsUndefined(method)) {
- *pdone = true;
- return JS_UNDEFINED;
- }
- ret = JS_IteratorNext2(ctx, it->wrapped_iter, method, argc, argv, pdone);
- JS_FreeValue(ctx, method);
- return ret;
- }
- static const JSCFunctionListEntry js_iterator_wrap_proto_funcs[] = {
- JS_ITERATOR_NEXT_DEF("next", 0, js_iterator_wrap_next, GEN_MAGIC_NEXT ),
- JS_ITERATOR_NEXT_DEF("return", 0, js_iterator_wrap_next, GEN_MAGIC_RETURN ),
- };
- static JSValue js_iterator_constructor_getset(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv,
- int magic,
- JSValueConst *func_data)
- {
- int ret;
- if (argc > 0) { // if setter
- if (!JS_IsObject(argv[0]))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- ret = JS_DefinePropertyValue(ctx, this_val, JS_ATOM_constructor,
- js_dup(argv[0]),
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- if (ret < 0)
- return JS_EXCEPTION;
- }
- return js_dup(func_data[0]);
- }
- static JSValue js_iterator_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- JSObject *p;
- if (JS_TAG_OBJECT != JS_VALUE_GET_TAG(new_target))
- return JS_ThrowTypeError(ctx, "constructor requires 'new'");
- p = JS_VALUE_GET_OBJ(new_target);
- if (p->class_id == JS_CLASS_C_FUNCTION)
- if (p->u.cfunc.c_function.generic == js_iterator_constructor)
- return JS_ThrowTypeError(ctx, "abstract class not constructable");
- return js_create_from_ctor(ctx, new_target, JS_CLASS_ITERATOR);
- }
- // note: deliberately doesn't use space-saving bit fields for
- // |index|, |count| and |running| because tcc miscompiles them
- typedef struct JSIteratorConcatData {
- int index, count; // elements (not pairs!) in values[] array
- bool running;
- JSValue iter, next, values[]; // array of (object, method) pairs
- } JSIteratorConcatData;
- static void js_iterator_concat_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSIteratorConcatData *it = p->u.iterator_concat_data;
- if (it) {
- JS_FreeValueRT(rt, it->iter);
- JS_FreeValueRT(rt, it->next);
- for (int i = it->index; i < it->count; i++)
- JS_FreeValueRT(rt, it->values[i]);
- js_free_rt(rt, it);
- }
- }
- static void js_iterator_concat_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSIteratorConcatData *it = p->u.iterator_concat_data;
- if (it) {
- JS_MarkValue(rt, it->iter, mark_func);
- JS_MarkValue(rt, it->next, mark_func);
- for (int i = it->index; i < it->count; i++)
- JS_MarkValue(rt, it->values[i], mark_func);
- }
- }
- static JSValue js_iterator_concat_next(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue iter, item, next, val, *obj, *meth;
- JSIteratorConcatData *it;
- JSPropertyDescriptor d;
- int done, ret;
- it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_CONCAT);
- if (!it)
- return JS_EXCEPTION;
- if (it->running)
- return JS_ThrowTypeError(ctx, "already running");
- next:
- if (it->index >= it->count)
- return js_create_iterator_result(ctx, JS_UNDEFINED, /*done*/true);
- obj = &it->values[it->index + 0];
- meth = &it->values[it->index + 1];
- iter = it->iter;
- if (JS_IsUndefined(iter)) {
- iter = JS_GetIterator2(ctx, *obj, *meth);
- if (JS_IsException(iter))
- return JS_EXCEPTION;
- it->iter = iter;
- }
- next = it->next;
- if (JS_IsUndefined(next)) {
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- return JS_EXCEPTION;
- it->next = next;
- }
- it->running = true;
- item = JS_IteratorNext2(ctx, iter, next, 0, NULL, &done);
- it->running = false;
- if (JS_IsException(item))
- return JS_EXCEPTION;
- if (!done)
- return js_create_iterator_result(ctx, item, /*done*/false);
- // done==1 means really done, done==2 means "unknown, inspect object"
- if (done == 2) {
- val = JS_GetProperty(ctx, item, JS_ATOM_done);
- if (JS_IsException(val)) {
- JS_FreeValue(ctx, item);
- return JS_EXCEPTION;
- }
- done = JS_ToBoolFree(ctx, val);
- }
- if (done) {
- JS_FreeValue(ctx, item);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, next);
- it->iter = JS_UNDEFINED;
- it->next = JS_UNDEFINED;
- JS_FreeValue(ctx, *meth);
- JS_FreeValue(ctx, *obj);
- it->index += 2;
- goto next;
- }
- // not done, construct { done: false, value: xxx } object
- // copy .value verbatim from source object, spec doesn't
- // allow dereferencing getters here
- d = (JSPropertyDescriptor){
- .value = JS_UNDEFINED,
- .getter = JS_UNDEFINED,
- .setter = JS_UNDEFINED,
- };
- ret = JS_GetOwnProperty(ctx, &d, item, JS_ATOM_value);
- JS_FreeValue(ctx, item);
- if (ret < 0)
- return JS_EXCEPTION;
- if (d.flags & JS_PROP_GETSET) {
- d.flags |= JS_PROP_HAS_GET | JS_PROP_HAS_SET;
- } else {
- d.flags |= JS_PROP_HAS_VALUE;
- }
- item = JS_NewObject(ctx);
- if (JS_IsException(item))
- goto fail;
- if (JS_DefinePropertyValue(ctx, item, JS_ATOM_done, JS_FALSE,
- JS_PROP_C_W_E) < 0) {
- goto fail;
- }
- if (JS_DefineProperty(ctx, item, JS_ATOM_value, d.value, d.getter,
- d.setter, d.flags | JS_PROP_C_W_E) < 0) {
- fail:
- JS_FreeValue(ctx, item);
- item = JS_EXCEPTION;
- }
- js_free_desc(ctx, &d);
- return item;
- }
- static JSValue js_iterator_concat_return(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSIteratorConcatData *it;
- JSValue ret;
- it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_CONCAT);
- if (!it)
- return JS_EXCEPTION;
- if (it->running)
- return JS_ThrowTypeError(ctx, "already running");
- ret = JS_UNDEFINED;
- if (!JS_IsUndefined(it->iter)) {
- ret = JS_GetProperty(ctx, it->iter, JS_ATOM_return);
- if (JS_IsException(ret))
- return JS_EXCEPTION;
- it->running = true;
- ret = JS_CallFree(ctx, ret, it->iter, 0, NULL);
- it->running = false;
- }
- while (it->index < it->count)
- JS_FreeValue(ctx, it->values[it->index++]);
- JS_FreeValue(ctx, it->iter);
- JS_FreeValue(ctx, it->next);
- it->iter = JS_UNDEFINED;
- it->next = JS_UNDEFINED;
- return ret;
- }
- // note: |next| and |return| don't use JS_ITERATOR_NEXT_DEF because |next|
- // has to return a full { value: xxx, done: xxx } step object - it must
- // copy getters and setters from the inner iterator's step object
- // slightly inefficient because of the intermediate step object that is
- // created but that can't be helped right now
- static const JSCFunctionListEntry js_iterator_concat_proto_funcs[] = {
- JS_CFUNC_DEF("next", 1, js_iterator_concat_next ),
- JS_CFUNC_DEF("return", 1, js_iterator_concat_return ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Iterator Concat", JS_PROP_CONFIGURABLE ),
- };
- static JSValue js_iterator_concat(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSIteratorConcatData *it;
- JSValue obj, method;
- it = js_malloc(ctx, sizeof(*it) + 2*argc * sizeof(it->values[0]));
- if (!it)
- return JS_EXCEPTION;
- it->running = false;
- it->index = 0;
- it->count = 0;
- it->iter = JS_UNDEFINED;
- it->next = JS_UNDEFINED;
- for (int i = 0; i < argc; i++) {
- JSValueConst obj = argv[i];
- if (!JS_IsObject(obj)) {
- JS_ThrowTypeErrorNotAnObject(ctx);
- goto fail;
- }
- method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
- if (JS_IsException(method))
- goto fail;
- if (!JS_IsFunction(ctx, method)) {
- JS_ThrowTypeErrorNotAFunction(ctx);
- JS_FreeValue(ctx, method);
- goto fail;
- }
- it->values[it->count++] = js_dup(obj);
- it->values[it->count++] = method;
- }
- obj = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_CONCAT);
- if (JS_IsException(obj))
- goto fail;
- JS_SetOpaqueInternal(obj, it);
- return obj;
- fail:
- for (int i = 0; i < it->count; i++)
- JS_FreeValue(ctx, it->values[i]);
- js_free(ctx, it);
- return JS_EXCEPTION;
- }
- static JSValue js_iterator_from(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue method, iter;
- JSIteratorWrapData *it;
- int ret;
- JSValueConst obj = argv[0];
- if (JS_IsString(obj)) {
- method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
- if (JS_IsException(method))
- return JS_EXCEPTION;
- return JS_CallFree(ctx, method, obj, 0, NULL);
- }
- if (!JS_IsObject(obj))
- return JS_ThrowTypeError(ctx, "Iterator.from called on non-object");
- ret = JS_OrdinaryIsInstanceOf(ctx, obj, ctx->iterator_ctor);
- if (ret < 0)
- return JS_EXCEPTION;
- if (ret)
- return js_dup(obj);
- method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
- if (JS_IsException(method))
- return JS_EXCEPTION;
- if (JS_IsNull(method) || JS_IsUndefined(method)) {
- method = JS_GetProperty(ctx, obj, JS_ATOM_next);
- if (JS_IsException(method))
- return JS_EXCEPTION;
- iter = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_WRAP);
- if (JS_IsException(iter))
- goto fail;
- it = js_malloc(ctx, sizeof(*it));
- if (!it)
- goto fail;
- it->wrapped_iter = js_dup(obj);
- it->wrapped_next = method;
- JS_SetOpaqueInternal(iter, it);
- } else {
- iter = JS_GetIterator2(ctx, obj, method);
- JS_FreeValue(ctx, method);
- if (JS_IsException(iter))
- return JS_EXCEPTION;
- }
- return iter;
- fail:
- JS_FreeValue(ctx, method);
- JS_FreeValue(ctx, iter);
- return JS_EXCEPTION;
- }
- static int check_iterator(JSContext *ctx, JSValueConst obj)
- {
- if (!JS_IsObject(obj)) {
- JS_ThrowTypeErrorNotAnObject(ctx);
- return -1;
- }
- return 0;
- }
- typedef struct JSIteratorHelperData {
- JSValue obj;
- JSValue next;
- JSValue func; // predicate (filter) or mapper (flatMap, map)
- JSValue inner; // innerValue (flatMap)
- int64_t count; // limit (drop, take) or counter (filter, map, flatMap)
- JSIteratorHelperKindEnum kind : 8;
- uint8_t executing : 1;
- uint8_t done : 1;
- } JSIteratorHelperData;
- static JSValue js_create_iterator_helper(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValueConst func;
- JSValue obj, method;
- int64_t count;
- JSIteratorHelperData *it;
- if (check_iterator(ctx, this_val) < 0)
- return JS_EXCEPTION;
- func = JS_UNDEFINED;
- count = 0;
- switch(magic) {
- case JS_ITERATOR_HELPER_KIND_DROP:
- case JS_ITERATOR_HELPER_KIND_TAKE:
- {
- JSValue v;
- double dlimit;
- v = JS_ToNumber(ctx, argv[0]);
- if (JS_IsException(v))
- goto fail;
- // Check for Infinity.
- if (JS_ToFloat64(ctx, &dlimit, v)) {
- JS_FreeValue(ctx, v);
- goto fail;
- }
- if (isnan(dlimit)) {
- JS_FreeValue(ctx, v);
- goto range_error;
- }
- if (!isfinite(dlimit)) {
- JS_FreeValue(ctx, v);
- if (dlimit < 0)
- goto range_error;
- else
- count = MAX_SAFE_INTEGER;
- } else {
- v = JS_ToIntegerFree(ctx, v);
- if (JS_IsException(v))
- goto fail;
- if (JS_ToInt64Free(ctx, &count, v))
- goto fail;
- }
- if (count < 0)
- goto range_error;
- }
- break;
- case JS_ITERATOR_HELPER_KIND_FILTER:
- case JS_ITERATOR_HELPER_KIND_FLAT_MAP:
- case JS_ITERATOR_HELPER_KIND_MAP:
- {
- func = argv[0];
- if (check_function(ctx, func))
- goto fail;
- }
- break;
- default:
- abort();
- break;
- }
- method = JS_GetProperty(ctx, this_val, JS_ATOM_next);
- if (JS_IsException(method))
- goto fail;
- obj = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_HELPER);
- if (JS_IsException(obj)) {
- JS_FreeValue(ctx, method);
- goto fail;
- }
- it = js_malloc(ctx, sizeof(*it));
- if (!it) {
- JS_FreeValue(ctx, obj);
- JS_FreeValue(ctx, method);
- goto fail;
- }
- it->kind = magic;
- it->obj = js_dup(this_val);
- it->func = js_dup(func);
- it->next = method;
- it->inner = JS_UNDEFINED;
- it->count = count;
- it->executing = 0;
- it->done = 0;
- JS_SetOpaqueInternal(obj, it);
- return obj;
- range_error:
- JS_ThrowRangeError(ctx, "must be positive");
- fail:
- JS_IteratorClose(ctx, this_val, true);
- return JS_EXCEPTION;
- }
- static JSValue js_iterator_proto_func(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValue item, method, ret, func, index_val, r;
- JSValueConst args[2];
- int64_t idx;
- int done;
- if (check_iterator(ctx, this_val) < 0)
- return JS_EXCEPTION;
- func = JS_UNDEFINED;
- method = JS_UNDEFINED;
- if (check_function(ctx, argv[0]))
- goto fail;
- func = js_dup(argv[0]);
- method = JS_GetProperty(ctx, this_val, JS_ATOM_next);
- if (JS_IsException(method))
- goto fail;
- r = JS_UNDEFINED;
- switch(magic) {
- case JS_ITERATOR_HELPER_KIND_EVERY:
- {
- r = JS_TRUE;
- for (idx = 0; /*empty*/; idx++) {
- item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
- if (JS_IsException(item))
- goto fail;
- if (done)
- break;
- index_val = js_int64(idx);
- args[0] = item;
- args[1] = index_val;
- ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);
- JS_FreeValue(ctx, item);
- JS_FreeValue(ctx, index_val);
- if (JS_IsException(ret))
- goto fail;
- if (!JS_ToBoolFree(ctx, ret)) {
- if (JS_IteratorClose(ctx, this_val, false) < 0)
- r = JS_EXCEPTION;
- else
- r = JS_FALSE;
- break;
- }
- index_val = JS_UNDEFINED;
- ret = JS_UNDEFINED;
- item = JS_UNDEFINED;
- }
- }
- break;
- case JS_ITERATOR_HELPER_KIND_FIND:
- {
- for (idx = 0; /*empty*/; idx++) {
- item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
- if (JS_IsException(item))
- goto fail;
- if (done)
- break;
- index_val = js_int64(idx);
- args[0] = item;
- args[1] = index_val;
- ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);
- JS_FreeValue(ctx, index_val);
- if (JS_IsException(ret)) {
- JS_FreeValue(ctx, item);
- goto fail;
- }
- if (JS_ToBoolFree(ctx, ret)) {
- if (JS_IteratorClose(ctx, this_val, false) < 0) {
- JS_FreeValue(ctx, item);
- r = JS_EXCEPTION;
- } else {
- r = item;
- }
- break;
- }
- index_val = JS_UNDEFINED;
- ret = JS_UNDEFINED;
- item = JS_UNDEFINED;
- }
- }
- break;
- case JS_ITERATOR_HELPER_KIND_FOR_EACH:
- {
- for (idx = 0; /*empty*/; idx++) {
- item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
- if (JS_IsException(item))
- goto fail;
- if (done)
- break;
- index_val = js_int64(idx);
- args[0] = item;
- args[1] = index_val;
- ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);
- JS_FreeValue(ctx, item);
- JS_FreeValue(ctx, index_val);
- if (JS_IsException(ret))
- goto fail;
- JS_FreeValue(ctx, ret);
- index_val = JS_UNDEFINED;
- ret = JS_UNDEFINED;
- item = JS_UNDEFINED;
- }
- }
- break;
- case JS_ITERATOR_HELPER_KIND_SOME:
- {
- r = JS_FALSE;
- for (idx = 0; /*empty*/; idx++) {
- item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
- if (JS_IsException(item))
- goto fail;
- if (done)
- break;
- index_val = js_int64(idx);
- args[0] = item;
- args[1] = index_val;
- ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);
- JS_FreeValue(ctx, item);
- JS_FreeValue(ctx, index_val);
- if (JS_IsException(ret))
- goto fail;
- if (JS_ToBoolFree(ctx, ret)) {
- if (JS_IteratorClose(ctx, this_val, false) < 0)
- r = JS_EXCEPTION;
- else
- r = JS_TRUE;
- break;
- }
- index_val = JS_UNDEFINED;
- ret = JS_UNDEFINED;
- item = JS_UNDEFINED;
- }
- }
- break;
- default:
- abort();
- break;
- }
- JS_FreeValue(ctx, func);
- JS_FreeValue(ctx, method);
- return r;
- fail:
- JS_IteratorClose(ctx, this_val, true);
- JS_FreeValue(ctx, func);
- JS_FreeValue(ctx, method);
- return JS_EXCEPTION;
- }
- static JSValue js_iterator_proto_reduce(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue item, method, ret, func, index_val, acc;
- JSValueConst args[3];
- int64_t idx;
- int done;
- if (check_iterator(ctx, this_val) < 0)
- return JS_EXCEPTION;
- acc = JS_UNDEFINED;
- func = JS_UNDEFINED;
- method = JS_UNDEFINED;
- if (check_function(ctx, argv[0]))
- goto exception;
- func = js_dup(argv[0]);
- method = JS_GetProperty(ctx, this_val, JS_ATOM_next);
- if (JS_IsException(method))
- goto exception;
- if (argc > 1) {
- acc = js_dup(argv[1]);
- idx = 0;
- } else {
- acc = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
- if (JS_IsException(acc))
- goto exception;
- if (done) {
- JS_ThrowTypeError(ctx, "empty iterator");
- goto exception;
- }
- idx = 1;
- }
- for (/* empty */; /*empty*/; idx++) {
- item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
- if (JS_IsException(item))
- goto exception;
- if (done)
- break;
- index_val = js_int64(idx);
- args[0] = acc;
- args[1] = item;
- args[2] = index_val;
- ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);
- JS_FreeValue(ctx, item);
- JS_FreeValue(ctx, index_val);
- if (JS_IsException(ret))
- goto exception;
- JS_FreeValue(ctx, acc);
- acc = ret;
- index_val = JS_UNDEFINED;
- ret = JS_UNDEFINED;
- item = JS_UNDEFINED;
- }
- JS_FreeValue(ctx, func);
- JS_FreeValue(ctx, method);
- return acc;
- exception:
- JS_IteratorClose(ctx, this_val, true);
- JS_FreeValue(ctx, acc);
- JS_FreeValue(ctx, func);
- JS_FreeValue(ctx, method);
- return JS_EXCEPTION;
- }
- static JSValue js_iterator_proto_toArray(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue item, method, result;
- int64_t idx;
- int done;
- result = JS_UNDEFINED;
- if (check_iterator(ctx, this_val) < 0)
- return JS_EXCEPTION;
- method = JS_GetProperty(ctx, this_val, JS_ATOM_next);
- if (JS_IsException(method))
- return JS_EXCEPTION;
- result = JS_NewArray(ctx);
- if (JS_IsException(result))
- goto exception;
- for (idx = 0; /*empty*/; idx++) {
- item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
- if (JS_IsException(item))
- goto exception;
- if (done)
- break;
- if (JS_DefinePropertyValueInt64(ctx, result, idx, item,
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- }
- if (JS_SetProperty(ctx, result, JS_ATOM_length, js_uint32(idx)) < 0)
- goto exception;
- JS_FreeValue(ctx, method);
- return result;
- exception:
- JS_FreeValue(ctx, result);
- JS_FreeValue(ctx, method);
- return JS_EXCEPTION;
- }
- static JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_dup(this_val);
- }
- static JSValue js_iterator_proto_get_toStringTag(JSContext *ctx, JSValueConst this_val)
- {
- return JS_AtomToString(ctx, JS_ATOM_Iterator);
- }
- static JSValue js_iterator_proto_set_toStringTag(JSContext *ctx, JSValueConst this_val, JSValueConst val)
- {
- int res;
- if (check_iterator(ctx, this_val) < 0)
- return JS_EXCEPTION;
- if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_ITERATOR]))
- return JS_ThrowTypeError(ctx, "Cannot assign to read only property");
- res = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_Symbol_toStringTag);
- if (res < 0)
- return JS_EXCEPTION;
- if (res) {
- if (JS_SetProperty(ctx, this_val, JS_ATOM_Symbol_toStringTag, js_dup(val)) < 0)
- return JS_EXCEPTION;
- } else {
- if (JS_DefinePropertyValue(ctx, this_val, JS_ATOM_Symbol_toStringTag, js_dup(val), JS_PROP_C_W_E) < 0)
- return JS_EXCEPTION;
- }
- return JS_UNDEFINED;
- }
- static void js_iterator_helper_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSIteratorHelperData *it = p->u.iterator_helper_data;
- if (it) {
- JS_FreeValueRT(rt, it->obj);
- JS_FreeValueRT(rt, it->func);
- JS_FreeValueRT(rt, it->next);
- JS_FreeValueRT(rt, it->inner);
- js_free_rt(rt, it);
- }
- }
- static void js_iterator_helper_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSIteratorHelperData *it = p->u.iterator_helper_data;
- if (it) {
- JS_MarkValue(rt, it->obj, mark_func);
- JS_MarkValue(rt, it->func, mark_func);
- JS_MarkValue(rt, it->next, mark_func);
- JS_MarkValue(rt, it->inner, mark_func);
- }
- }
- static JSValue js_iterator_helper_next(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int *pdone, int magic)
- {
- JSIteratorHelperData *it;
- JSValue ret;
- *pdone = false;
- it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_HELPER);
- if (!it)
- return JS_EXCEPTION;
- if (it->executing)
- return JS_ThrowTypeError(ctx, "cannot invoke a running iterator");
- if (it->done) {
- *pdone = true;
- return JS_UNDEFINED;
- }
- it->executing = 1;
- switch (it->kind) {
- case JS_ITERATOR_HELPER_KIND_DROP:
- {
- JSValue item, method;
- if (magic == GEN_MAGIC_NEXT) {
- method = js_dup(it->next);
- } else {
- method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);
- if (JS_IsException(method))
- goto fail;
- }
- while (it->count > 0) {
- it->count--;
- item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);
- if (JS_IsException(item)) {
- JS_FreeValue(ctx, method);
- goto fail;
- }
- JS_FreeValue(ctx, item);
- if (magic == GEN_MAGIC_RETURN)
- *pdone = true;
- if (*pdone) {
- JS_FreeValue(ctx, method);
- ret = JS_UNDEFINED;
- goto done;
- }
- }
- item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);
- JS_FreeValue(ctx, method);
- if (JS_IsException(item))
- goto fail;
- ret = item;
- goto done;
- }
- break;
- case JS_ITERATOR_HELPER_KIND_FILTER:
- {
- JSValue item, method, selected, index_val;
- JSValueConst args[2];
- if (magic == GEN_MAGIC_NEXT) {
- method = js_dup(it->next);
- } else {
- method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);
- if (JS_IsException(method))
- goto fail;
- }
- filter_again:
- item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);
- if (JS_IsException(item)) {
- JS_FreeValue(ctx, method);
- goto fail;
- }
- if (*pdone || magic == GEN_MAGIC_RETURN) {
- JS_FreeValue(ctx, method);
- ret = item;
- goto done;
- }
- index_val = js_int64(it->count++);
- args[0] = item;
- args[1] = index_val;
- selected = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args);
- JS_FreeValue(ctx, index_val);
- if (JS_IsException(selected)) {
- JS_FreeValue(ctx, method);
- goto fail;
- }
- if (JS_ToBoolFree(ctx, selected)) {
- JS_FreeValue(ctx, method);
- ret = item;
- goto done;
- }
- goto filter_again;
- }
- break;
- case JS_ITERATOR_HELPER_KIND_FLAT_MAP:
- {
- JSValue item, method, index_val, iter;
- JSValueConst args[2];
- flat_map_again:
- if (JS_IsUndefined(it->inner)) {
- if (magic == GEN_MAGIC_NEXT) {
- method = js_dup(it->next);
- } else {
- method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);
- if (JS_IsException(method))
- goto fail;
- }
- item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);
- JS_FreeValue(ctx, method);
- if (JS_IsException(item))
- goto fail;
- if (*pdone || magic == GEN_MAGIC_RETURN) {
- ret = item;
- goto done;
- }
- index_val = js_int64(it->count++);
- args[0] = item;
- args[1] = index_val;
- ret = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args);
- JS_FreeValue(ctx, item);
- JS_FreeValue(ctx, index_val);
- if (JS_IsException(ret))
- goto fail;
- if (!JS_IsObject(ret)) {
- JS_FreeValue(ctx, ret);
- JS_ThrowTypeError(ctx, "not an object");
- goto fail;
- }
- method = JS_GetProperty(ctx, ret, JS_ATOM_Symbol_iterator);
- if (JS_IsException(method)) {
- JS_FreeValue(ctx, ret);
- goto fail;
- }
- if (JS_IsNull(method) || JS_IsUndefined(method)) {
- JS_FreeValue(ctx, method);
- iter = ret;
- } else {
- iter = JS_GetIterator2(ctx, ret, method);
- JS_FreeValue(ctx, method);
- JS_FreeValue(ctx, ret);
- if (JS_IsException(iter))
- goto fail;
- }
- it->inner = iter;
- }
- if (magic == GEN_MAGIC_NEXT)
- method = JS_GetProperty(ctx, it->inner, JS_ATOM_next);
- else
- method = JS_GetProperty(ctx, it->inner, JS_ATOM_return);
- if (JS_IsException(method)) {
- inner_fail:
- JS_IteratorClose(ctx, it->inner, false);
- JS_FreeValue(ctx, it->inner);
- it->inner = JS_UNDEFINED;
- goto fail;
- }
- if (magic == GEN_MAGIC_RETURN && (JS_IsUndefined(method) || JS_IsNull(method))) {
- goto inner_end;
- } else {
- item = JS_IteratorNext(ctx, it->inner, method, 0, NULL, pdone);
- JS_FreeValue(ctx, method);
- if (JS_IsException(item))
- goto inner_fail;
- }
- if (*pdone) {
- inner_end:
- *pdone = false; // The outer iterator must continue.
- JS_IteratorClose(ctx, it->inner, false);
- JS_FreeValue(ctx, it->inner);
- it->inner = JS_UNDEFINED;
- goto flat_map_again;
- }
- ret = item;
- goto done;
- }
- break;
- case JS_ITERATOR_HELPER_KIND_MAP:
- {
- JSValue item, method, index_val;
- JSValueConst args[2];
- if (magic == GEN_MAGIC_NEXT) {
- method = js_dup(it->next);
- } else {
- method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);
- if (JS_IsException(method))
- goto fail;
- }
- item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);
- JS_FreeValue(ctx, method);
- if (JS_IsException(item))
- goto fail;
- if (*pdone || magic == GEN_MAGIC_RETURN) {
- ret = item;
- goto done;
- }
- index_val = js_int64(it->count++);
- args[0] = item;
- args[1] = index_val;
- ret = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args);
- JS_FreeValue(ctx, index_val);
- if (JS_IsException(ret))
- goto fail;
- goto done;
- }
- break;
- case JS_ITERATOR_HELPER_KIND_TAKE:
- {
- JSValue item, method;
- if (it->count > 0) {
- if (magic == GEN_MAGIC_NEXT) {
- method = js_dup(it->next);
- } else {
- method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);
- if (JS_IsException(method))
- goto fail;
- }
- it->count--;
- item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);
- JS_FreeValue(ctx, method);
- if (JS_IsException(item))
- goto fail;
- ret = item;
- goto done;
- }
- *pdone = true;
- if (JS_IteratorClose(ctx, it->obj, false))
- ret = JS_EXCEPTION;
- else
- ret = JS_UNDEFINED;
- goto done;
- }
- break;
- default:
- abort();
- }
- done:
- it->done = magic == GEN_MAGIC_NEXT ? *pdone : 1;
- it->executing = 0;
- return ret;
- fail:
- /* close the iterator object, preserving pending exception */
- JS_IteratorClose(ctx, it->obj, true);
- ret = JS_EXCEPTION;
- goto done;
- }
- static const JSCFunctionListEntry js_iterator_funcs[] = {
- JS_CFUNC_DEF("concat", 0, js_iterator_concat ),
- JS_CFUNC_DEF("from", 1, js_iterator_from ),
- };
- static const JSCFunctionListEntry js_iterator_proto_funcs[] = {
- JS_CFUNC_MAGIC_DEF("drop", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_DROP ),
- JS_CFUNC_MAGIC_DEF("filter", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_FILTER ),
- JS_CFUNC_MAGIC_DEF("flatMap", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_FLAT_MAP ),
- JS_CFUNC_MAGIC_DEF("map", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_MAP ),
- JS_CFUNC_MAGIC_DEF("take", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_TAKE ),
- JS_CFUNC_MAGIC_DEF("every", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_EVERY ),
- JS_CFUNC_MAGIC_DEF("find", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_FIND),
- JS_CFUNC_MAGIC_DEF("forEach", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_FOR_EACH ),
- JS_CFUNC_MAGIC_DEF("some", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_SOME ),
- JS_CFUNC_DEF("reduce", 1, js_iterator_proto_reduce ),
- JS_CFUNC_DEF("toArray", 0, js_iterator_proto_toArray ),
- JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator ),
- JS_CGETSET_DEF("[Symbol.toStringTag]", js_iterator_proto_get_toStringTag, js_iterator_proto_set_toStringTag),
- };
- static const JSCFunctionListEntry js_iterator_helper_proto_funcs[] = {
- JS_ITERATOR_NEXT_DEF("next", 0, js_iterator_helper_next, GEN_MAGIC_NEXT ),
- JS_ITERATOR_NEXT_DEF("return", 0, js_iterator_helper_next, GEN_MAGIC_RETURN ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Iterator Helper", JS_PROP_CONFIGURABLE ),
- };
- static const JSCFunctionListEntry js_array_proto_funcs[] = {
- JS_CFUNC_DEF("at", 1, js_array_at ),
- JS_CFUNC_DEF("with", 2, js_array_with ),
- JS_CFUNC_DEF("concat", 1, js_array_concat ),
- JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ),
- JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ),
- JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach ),
- JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map ),
- JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter ),
- JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ),
- JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ),
- JS_CFUNC_DEF("fill", 1, js_array_fill ),
- JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, ArrayFind ),
- JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, ArrayFindIndex ),
- JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, ArrayFindLast ),
- JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, ArrayFindLastIndex ),
- JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ),
- JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ),
- JS_CFUNC_DEF("includes", 1, js_array_includes ),
- JS_CFUNC_MAGIC_DEF("join", 1, js_array_join, 0 ),
- JS_CFUNC_DEF("toString", 0, js_array_toString ),
- JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_array_join, 1 ),
- JS_CFUNC_MAGIC_DEF("pop", 0, js_array_pop, 0 ),
- JS_CFUNC_MAGIC_DEF("push", 1, js_array_push, 0 ),
- JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ),
- JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ),
- JS_CFUNC_DEF("reverse", 0, js_array_reverse ),
- JS_CFUNC_DEF("toReversed", 0, js_array_toReversed ),
- JS_CFUNC_DEF("sort", 1, js_array_sort ),
- JS_CFUNC_DEF("toSorted", 1, js_array_toSorted ),
- JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ),
- JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ),
- JS_CFUNC_DEF("toSpliced", 2, js_array_toSpliced ),
- JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ),
- JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ),
- JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ),
- JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ),
- JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
- JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ),
- JS_CFUNC_MAGIC_DEF("entries", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
- };
- static const JSCFunctionListEntry js_array_iterator_proto_funcs[] = {
- JS_ITERATOR_NEXT_DEF("next", 0, js_array_iterator_next, 0 ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Array Iterator", JS_PROP_CONFIGURABLE ),
- };
- /* Number */
- static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- JSValue val, obj;
- if (argc == 0) {
- val = js_int32(0);
- } else {
- val = JS_ToNumeric(ctx, argv[0]);
- if (JS_IsException(val))
- return val;
- switch(JS_VALUE_GET_TAG(val)) {
- case JS_TAG_SHORT_BIG_INT:
- val = js_int64(JS_VALUE_GET_SHORT_BIG_INT(val));
- if (JS_IsException(val))
- return val;
- break;
- case JS_TAG_BIG_INT:
- {
- JSBigInt *p = JS_VALUE_GET_PTR(val);
- double d;
- d = js_bigint_to_float64(ctx, p);
- JS_FreeValue(ctx, val);
- val = js_float64(d);
- }
- break;
- default:
- break;
- }
- }
- if (!JS_IsUndefined(new_target)) {
- obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);
- if (!JS_IsException(obj))
- JS_SetObjectData(ctx, obj, val);
- return obj;
- } else {
- return val;
- }
- }
- static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- if (!JS_IsNumber(argv[0]))
- return JS_FALSE;
- return js_global_isNaN(ctx, this_val, argc, argv);
- }
- static JSValue js_number_isFinite(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- if (!JS_IsNumber(argv[0]))
- return JS_FALSE;
- return js_global_isFinite(ctx, this_val, argc, argv);
- }
- static JSValue js_number_isInteger(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int ret;
- ret = JS_NumberIsInteger(ctx, argv[0]);
- if (ret < 0)
- return JS_EXCEPTION;
- else
- return js_bool(ret);
- }
- static JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- double d;
- if (!JS_IsNumber(argv[0]))
- return JS_FALSE;
- if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
- return JS_EXCEPTION;
- return js_bool(is_safe_integer(d));
- }
- static const JSCFunctionListEntry js_number_funcs[] = {
- /* global ParseInt and parseFloat should be defined already or delayed */
- JS_ALIAS_BASE_DEF("parseInt", "parseInt", 0 ),
- JS_ALIAS_BASE_DEF("parseFloat", "parseFloat", 0 ),
- JS_CFUNC_DEF("isNaN", 1, js_number_isNaN ),
- JS_CFUNC_DEF("isFinite", 1, js_number_isFinite ),
- JS_CFUNC_DEF("isInteger", 1, js_number_isInteger ),
- JS_CFUNC_DEF("isSafeInteger", 1, js_number_isSafeInteger ),
- JS_PROP_DOUBLE_DEF("MAX_VALUE", 1.7976931348623157e+308, 0 ),
- JS_PROP_DOUBLE_DEF("MIN_VALUE", 5e-324, 0 ),
- JS_PROP_U2D_DEF("NaN", 0x7FF8ull<<48, 0 ), // workaround for msvc
- JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", -INFINITY, 0 ),
- JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", INFINITY, 0 ),
- JS_PROP_DOUBLE_DEF("EPSILON", 2.220446049250313e-16, 0 ), /* ES6 */
- JS_PROP_DOUBLE_DEF("MAX_SAFE_INTEGER", 9007199254740991.0, 0 ), /* ES6 */
- JS_PROP_DOUBLE_DEF("MIN_SAFE_INTEGER", -9007199254740991.0, 0 ), /* ES6 */
- };
- static JSValue js_thisNumberValue(JSContext *ctx, JSValueConst this_val)
- {
- if (JS_IsNumber(this_val))
- return js_dup(this_val);
- if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(this_val);
- if (p->class_id == JS_CLASS_NUMBER) {
- if (JS_IsNumber(p->u.object_data))
- return js_dup(p->u.object_data);
- }
- }
- return JS_ThrowTypeError(ctx, "not a number");
- }
- static JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_thisNumberValue(ctx, this_val);
- }
- static int js_get_radix(JSContext *ctx, JSValueConst val)
- {
- int radix;
- if (JS_ToInt32Sat(ctx, &radix, val))
- return -1;
- if (radix < 2 || radix > 36) {
- JS_ThrowRangeError(ctx, "toString() radix argument must be between 2 and 36");
- return -1;
- }
- return radix;
- }
- static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValue val;
- int base, flags;
- double d;
- val = js_thisNumberValue(ctx, this_val);
- if (JS_IsException(val))
- return val;
- if (magic || JS_IsUndefined(argv[0])) {
- base = 10;
- } else {
- base = js_get_radix(ctx, argv[0]);
- if (base < 0)
- goto fail;
- }
- if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
- char buf1[70];
- int len;
- len = i64toa_radix(buf1, JS_VALUE_GET_INT(val), base);
- return js_new_string8_len(ctx, buf1, len);
- }
- if (JS_ToFloat64Free(ctx, &d, val))
- return JS_EXCEPTION;
- flags = JS_DTOA_FORMAT_FREE;
- if (base != 10)
- flags |= JS_DTOA_EXP_DISABLED;
- return js_dtoa2(ctx, d, base, 0, flags);
- fail:
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val;
- int f, flags;
- double d;
- val = js_thisNumberValue(ctx, this_val);
- if (JS_IsException(val))
- return val;
- if (JS_ToFloat64Free(ctx, &d, val))
- return JS_EXCEPTION;
- if (JS_ToInt32Sat(ctx, &f, argv[0]))
- return JS_EXCEPTION;
- if (f < 0 || f > 100)
- return JS_ThrowRangeError(ctx, "invalid number of digits");
- if (fabs(d) >= 1e21)
- flags = JS_DTOA_FORMAT_FREE;
- else
- flags = JS_DTOA_FORMAT_FRAC;
- return js_dtoa2(ctx, d, 10, f, flags);
- }
- static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val;
- int f, flags;
- double d;
- val = js_thisNumberValue(ctx, this_val);
- if (JS_IsException(val))
- return val;
- if (JS_ToFloat64Free(ctx, &d, val))
- return JS_EXCEPTION;
- if (JS_ToInt32Sat(ctx, &f, argv[0]))
- return JS_EXCEPTION;
- if (!isfinite(d)) {
- return JS_ToStringFree(ctx, __JS_NewFloat64(d));
- }
- if (JS_IsUndefined(argv[0])) {
- flags = JS_DTOA_FORMAT_FREE;
- f = 0;
- } else {
- if (f < 0 || f > 100)
- return JS_ThrowRangeError(ctx, "invalid number of digits");
- f++;
- flags = JS_DTOA_FORMAT_FIXED;
- }
- return js_dtoa2(ctx, d, 10, f, flags | JS_DTOA_EXP_ENABLED);
- }
- static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val;
- int p;
- double d;
- val = js_thisNumberValue(ctx, this_val);
- if (JS_IsException(val))
- return val;
- if (JS_ToFloat64Free(ctx, &d, val))
- return JS_EXCEPTION;
- if (JS_IsUndefined(argv[0]))
- goto to_string;
- if (JS_ToInt32Sat(ctx, &p, argv[0]))
- return JS_EXCEPTION;
- if (!isfinite(d)) {
- to_string:
- return JS_ToStringFree(ctx, __JS_NewFloat64(d));
- }
- if (p < 1 || p > 100)
- return JS_ThrowRangeError(ctx, "invalid number of digits");
- return js_dtoa2(ctx, d, 10, p, JS_DTOA_FORMAT_FIXED);
- }
- static const JSCFunctionListEntry js_number_proto_funcs[] = {
- JS_CFUNC_DEF("toExponential", 1, js_number_toExponential ),
- JS_CFUNC_DEF("toFixed", 1, js_number_toFixed ),
- JS_CFUNC_DEF("toPrecision", 1, js_number_toPrecision ),
- JS_CFUNC_MAGIC_DEF("toString", 1, js_number_toString, 0 ),
- JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_number_toString, 1 ),
- JS_CFUNC_DEF("valueOf", 0, js_number_valueOf ),
- };
- static JSValue js_parseInt(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *str, *p;
- int radix, flags;
- JSValue ret;
- str = JS_ToCString(ctx, argv[0]);
- if (!str)
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &radix, argv[1])) {
- JS_FreeCString(ctx, str);
- return JS_EXCEPTION;
- }
- if (radix != 0 && (radix < 2 || radix > 36)) {
- ret = JS_NAN;
- } else {
- p = str;
- p += skip_spaces(p);
- flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;
- ret = js_atof(ctx, p, NULL, radix, flags);
- }
- JS_FreeCString(ctx, str);
- return ret;
- }
- static JSValue js_parseFloat(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *str, *p;
- JSValue ret;
- str = JS_ToCString(ctx, argv[0]);
- if (!str)
- return JS_EXCEPTION;
- p = str;
- p += skip_spaces(p);
- ret = js_atof(ctx, p, NULL, 10, 0);
- JS_FreeCString(ctx, str);
- return ret;
- }
- /* Boolean */
- static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- JSValue val, obj;
- val = js_bool(JS_ToBool(ctx, argv[0]));
- if (!JS_IsUndefined(new_target)) {
- obj = js_create_from_ctor(ctx, new_target, JS_CLASS_BOOLEAN);
- if (!JS_IsException(obj))
- JS_SetObjectData(ctx, obj, val);
- return obj;
- } else {
- return val;
- }
- }
- static JSValue js_thisBooleanValue(JSContext *ctx, JSValueConst this_val)
- {
- if (JS_VALUE_GET_TAG(this_val) == JS_TAG_BOOL)
- return js_dup(this_val);
- if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(this_val);
- if (p->class_id == JS_CLASS_BOOLEAN) {
- if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_BOOL)
- return p->u.object_data;
- }
- }
- return JS_ThrowTypeError(ctx, "not a boolean");
- }
- static JSValue js_boolean_toString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val = js_thisBooleanValue(ctx, this_val);
- if (JS_IsException(val))
- return val;
- return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
- JS_ATOM_true : JS_ATOM_false);
- }
- static JSValue js_boolean_valueOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_thisBooleanValue(ctx, this_val);
- }
- static const JSCFunctionListEntry js_boolean_proto_funcs[] = {
- JS_CFUNC_DEF("toString", 0, js_boolean_toString ),
- JS_CFUNC_DEF("valueOf", 0, js_boolean_valueOf ),
- };
- /* String */
- static int js_string_get_own_property(JSContext *ctx,
- JSPropertyDescriptor *desc,
- JSValueConst obj, JSAtom prop)
- {
- JSObject *p;
- JSString *p1;
- uint32_t idx, ch;
- /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
- if (__JS_AtomIsTaggedInt(prop)) {
- p = JS_VALUE_GET_OBJ(obj);
- if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
- p1 = JS_VALUE_GET_STRING(p->u.object_data);
- idx = __JS_AtomToUInt32(prop);
- if (idx < p1->len) {
- if (desc) {
- ch = string_get(p1, idx);
- desc->flags = JS_PROP_ENUMERABLE;
- desc->value = js_new_string_char(ctx, ch);
- desc->getter = JS_UNDEFINED;
- desc->setter = JS_UNDEFINED;
- }
- return true;
- }
- }
- }
- return false;
- }
- static int js_string_define_own_property(JSContext *ctx,
- JSValueConst this_obj,
- JSAtom prop, JSValueConst val,
- JSValueConst getter,
- JSValueConst setter, int flags)
- {
- uint32_t idx;
- JSObject *p;
- JSString *p1, *p2;
- if (__JS_AtomIsTaggedInt(prop)) {
- idx = __JS_AtomToUInt32(prop);
- p = JS_VALUE_GET_OBJ(this_obj);
- if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING)
- goto def;
- p1 = JS_VALUE_GET_STRING(p->u.object_data);
- if (idx >= p1->len)
- goto def;
- if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags))
- goto fail;
- /* check that the same value is configured */
- if (flags & JS_PROP_HAS_VALUE) {
- if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
- goto fail;
- p2 = JS_VALUE_GET_STRING(val);
- if (p2->len != 1)
- goto fail;
- if (string_get(p1, idx) != string_get(p2, 0)) {
- fail:
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
- }
- }
- return true;
- } else {
- def:
- return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
- flags | JS_PROP_NO_EXOTIC);
- }
- }
- static int js_string_delete_property(JSContext *ctx,
- JSValueConst obj, JSAtom prop)
- {
- uint32_t idx;
- if (__JS_AtomIsTaggedInt(prop)) {
- idx = __JS_AtomToUInt32(prop);
- if (idx < js_string_obj_get_length(ctx, obj)) {
- return false;
- }
- }
- return true;
- }
- static const JSClassExoticMethods js_string_exotic_methods = {
- .get_own_property = js_string_get_own_property,
- .define_own_property = js_string_define_own_property,
- .delete_property = js_string_delete_property,
- };
- static JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- JSValue val, obj;
- if (argc == 0) {
- val = js_empty_string(ctx->rt);
- } else {
- if (JS_IsUndefined(new_target) && JS_IsSymbol(argv[0])) {
- JSAtomStruct *p = JS_VALUE_GET_PTR(argv[0]);
- val = JS_ConcatString3(ctx, "Symbol(", JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)), ")");
- } else {
- val = JS_ToString(ctx, argv[0]);
- }
- if (JS_IsException(val))
- return val;
- }
- if (!JS_IsUndefined(new_target)) {
- JSString *p1 = JS_VALUE_GET_STRING(val);
- obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING);
- if (JS_IsException(obj)) {
- JS_FreeValue(ctx, val);
- } else {
- JS_SetObjectData(ctx, obj, val);
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, js_int32(p1->len), 0);
- }
- return obj;
- } else {
- return val;
- }
- }
- static JSValue js_thisStringValue(JSContext *ctx, JSValueConst this_val)
- {
- if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING)
- return js_dup(this_val);
- if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(this_val);
- if (p->class_id == JS_CLASS_STRING) {
- if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING)
- return js_dup(p->u.object_data);
- }
- }
- return JS_ThrowTypeError(ctx, "not a string");
- }
- static JSValue js_string_fromCharCode(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int i;
- StringBuffer b_s, *b = &b_s;
- // shortcut for single argument common case
- if (argc == 1 && JS_VALUE_GET_TAG(argv[0]) == JS_TAG_INT) {
- uint16_t c16 = JS_VALUE_GET_INT(argv[0]);
- return js_new_string_char(ctx, c16);
- }
- string_buffer_init(ctx, b, argc);
- for(i = 0; i < argc; i++) {
- int32_t c;
- if (JS_ToInt32(ctx, &c, argv[i]) || string_buffer_putc16(b, c & 0xffff)) {
- string_buffer_free(b);
- return JS_EXCEPTION;
- }
- }
- return string_buffer_end(b);
- }
- static JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- double d;
- int i, c;
- StringBuffer b_s, *b = NULL;
- // shortcut for single argument common case
- if (argc == 1 && JS_VALUE_GET_TAG(argv[0]) == JS_TAG_INT) {
- c = JS_VALUE_GET_INT(argv[0]);
- if (c < 0 || c > 0x10ffff)
- goto range_error;
- if (c <= 0xffff) {
- return js_new_string_char(ctx, c);
- } else {
- uint16_t c16[2];
- c16[0] = get_hi_surrogate(c);
- c16[1] = get_lo_surrogate(c);
- return js_new_string16_len(ctx, c16, 2);
- }
- }
- /* XXX: could pre-compute string length if all arguments are JS_TAG_INT */
- b = &b_s;
- if (string_buffer_init(ctx, b, argc))
- goto fail;
- for(i = 0; i < argc; i++) {
- if (JS_VALUE_GET_TAG(argv[i]) == JS_TAG_INT) {
- c = JS_VALUE_GET_INT(argv[i]);
- if (c < 0 || c > 0x10ffff)
- goto range_error;
- } else {
- if (JS_ToFloat64(ctx, &d, argv[i]))
- goto fail;
- if (!(d >= 0 && d <= 0x10ffff) || (c = (int)d) != d)
- goto range_error;
- }
- if (string_buffer_putc(b, c))
- goto fail;
- }
- return string_buffer_end(b);
- range_error:
- JS_ThrowRangeError(ctx, "invalid code point");
- fail:
- if (b) string_buffer_free(b);
- return JS_EXCEPTION;
- }
- static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // raw(temp,...a)
- JSValue cooked, val, raw;
- StringBuffer b_s, *b = &b_s;
- int64_t i, n;
- string_buffer_init(ctx, b, 0);
- raw = JS_UNDEFINED;
- cooked = JS_ToObject(ctx, argv[0]);
- if (JS_IsException(cooked))
- goto exception;
- raw = JS_ToObjectFree(ctx, JS_GetProperty(ctx, cooked, JS_ATOM_raw));
- if (JS_IsException(raw))
- goto exception;
- if (js_get_length64(ctx, &n, raw) < 0)
- goto exception;
- for (i = 0; i < n; i++) {
- val = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, raw, i));
- if (JS_IsException(val))
- goto exception;
- string_buffer_concat_value_free(b, val);
- if (i < n - 1 && i + 1 < argc) {
- if (string_buffer_concat_value(b, argv[i + 1]))
- goto exception;
- }
- }
- JS_FreeValue(ctx, cooked);
- JS_FreeValue(ctx, raw);
- return string_buffer_end(b);
- exception:
- JS_FreeValue(ctx, cooked);
- JS_FreeValue(ctx, raw);
- string_buffer_free(b);
- return JS_EXCEPTION;
- }
- /* only used in test262 */
- JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- uint32_t start, end, i, n;
- StringBuffer b_s, *b = &b_s;
- if (JS_ToUint32(ctx, &start, argv[0]) ||
- JS_ToUint32(ctx, &end, argv[1]))
- return JS_EXCEPTION;
- end = min_uint32(end, 0x10ffff + 1);
- if (start > end) {
- start = end;
- }
- n = end - start;
- if (end > 0x10000) {
- n += end - max_uint32(start, 0x10000);
- }
- if (string_buffer_init2(ctx, b, n, end >= 0x100))
- return JS_EXCEPTION;
- for(i = start; i < end; i++) {
- string_buffer_putc(b, i);
- }
- return string_buffer_end(b);
- }
- static JSValue js_string_at(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val, ret;
- JSString *p;
- int idx, c;
- val = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(val))
- return val;
- p = JS_VALUE_GET_STRING(val);
- if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- if (idx < 0)
- idx = p->len + idx;
- if (idx < 0 || idx >= p->len) {
- ret = JS_UNDEFINED;
- } else {
- c = string_get(p, idx);
- ret = js_new_string_char(ctx, c);
- }
- JS_FreeValue(ctx, val);
- return ret;
- }
- static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val, ret;
- JSString *p;
- int idx, c;
- val = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(val))
- return val;
- p = JS_VALUE_GET_STRING(val);
- if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- if (idx < 0 || idx >= p->len) {
- ret = JS_NAN;
- } else {
- c = string_get(p, idx);
- ret = js_int32(c);
- }
- JS_FreeValue(ctx, val);
- return ret;
- }
- static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val, ret;
- JSString *p;
- int idx, c;
- val = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(val))
- return val;
- p = JS_VALUE_GET_STRING(val);
- if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- if (idx < 0 || idx >= p->len) {
- ret = js_empty_string(ctx->rt);
- } else {
- c = string_get(p, idx);
- ret = js_new_string_char(ctx, c);
- }
- JS_FreeValue(ctx, val);
- return ret;
- }
- static JSValue js_string_codePointAt(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val, ret;
- JSString *p;
- int idx, c;
- val = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(val))
- return val;
- p = JS_VALUE_GET_STRING(val);
- if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- if (idx < 0 || idx >= p->len) {
- ret = JS_UNDEFINED;
- } else {
- c = string_getc(p, &idx);
- ret = js_int32(c);
- }
- JS_FreeValue(ctx, val);
- return ret;
- }
- static JSValue js_string_concat(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue r;
- int i;
- /* XXX: Use more efficient method */
- /* XXX: This method is OK if r has a single refcount */
- /* XXX: should use string_buffer? */
- r = JS_ToStringCheckObject(ctx, this_val);
- for (i = 0; i < argc; i++) {
- if (JS_IsException(r))
- break;
- r = JS_ConcatString(ctx, r, js_dup(argv[i]));
- }
- return r;
- }
- static int string_cmp(JSString *p1, JSString *p2, int x1, int x2, int len)
- {
- int i, c1, c2;
- for (i = 0; i < len; i++) {
- if ((c1 = string_get(p1, x1 + i)) != (c2 = string_get(p2, x2 + i)))
- return c1 - c2;
- }
- return 0;
- }
- static int string_indexof_char(JSString *p, int c, int from)
- {
- /* assuming 0 <= from <= p->len */
- int i, len = p->len;
- if (p->is_wide_char) {
- for (i = from; i < len; i++) {
- if (str16(p)[i] == c)
- return i;
- }
- } else {
- if ((c & ~0xff) == 0) {
- for (i = from; i < len; i++) {
- if (str8(p)[i] == (uint8_t)c)
- return i;
- }
- }
- }
- return -1;
- }
- static int string_indexof(JSString *p1, JSString *p2, int from)
- {
- /* assuming 0 <= from <= p1->len */
- int c, i, j, len1 = p1->len, len2 = p2->len;
- if (len2 == 0)
- return from;
- for (i = from, c = string_get(p2, 0); i + len2 <= len1; i = j + 1) {
- j = string_indexof_char(p1, c, i);
- if (j < 0 || j + len2 > len1)
- break;
- if (!string_cmp(p1, p2, j + 1, 1, len2 - 1))
- return j;
- }
- return -1;
- }
- static int64_t string_advance_index(JSString *p, int64_t index, bool unicode)
- {
- if (!unicode || index >= p->len || !p->is_wide_char) {
- index++;
- } else {
- int index32 = (int)index;
- string_getc(p, &index32);
- index = index32;
- }
- return index;
- }
- static JSValue js_string_isWellFormed(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue str;
- JSValue ret;
- JSString *p;
- uint32_t c, i, n;
- ret = JS_TRUE;
- str = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(str))
- return JS_EXCEPTION;
- p = JS_VALUE_GET_STRING(str);
- if (!p->is_wide_char || p->len == 0)
- goto done; // by definition well-formed
- for (i = 0, n = p->len; i < n; i++) {
- c = str16(p)[i];
- if (!is_surrogate(c))
- continue;
- if (is_lo_surrogate(c) || i + 1 == n)
- break;
- c = str16(p)[++i];
- if (!is_lo_surrogate(c))
- break;
- }
- if (i < n)
- ret = JS_FALSE;
- done:
- JS_FreeValue(ctx, str);
- return ret;
- }
- static JSValue js_string_toWellFormed(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue str;
- JSValue ret;
- JSString *p;
- uint32_t c, i, n;
- str = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(str))
- return JS_EXCEPTION;
- p = JS_VALUE_GET_STRING(str);
- if (!p->is_wide_char || p->len == 0)
- return str; // by definition well-formed
- // TODO(bnoordhuis) don't clone when input is well-formed
- ret = js_new_string16_len(ctx, str16(p), p->len);
- JS_FreeValue(ctx, str);
- if (JS_IsException(ret))
- return JS_EXCEPTION;
- p = JS_VALUE_GET_STRING(ret);
- for (i = 0, n = p->len; i < n; i++) {
- c = str16(p)[i];
- if (!is_surrogate(c))
- continue;
- if (is_lo_surrogate(c) || i + 1 == n) {
- str16(p)[i] = 0xFFFD;
- continue;
- }
- c = str16(p)[++i];
- if (!is_lo_surrogate(c))
- str16(p)[--i] = 0xFFFD;
- }
- return ret;
- }
- static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int lastIndexOf)
- {
- JSValue str, v;
- int i, len, v_len, pos, start, stop, ret, inc;
- JSString *p;
- JSString *p1;
- str = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(str))
- return str;
- v = JS_ToString(ctx, argv[0]);
- if (JS_IsException(v))
- goto fail;
- p = JS_VALUE_GET_STRING(str);
- p1 = JS_VALUE_GET_STRING(v);
- len = p->len;
- v_len = p1->len;
- if (lastIndexOf) {
- pos = len - v_len;
- if (argc > 1) {
- double d;
- if (JS_ToFloat64(ctx, &d, argv[1]))
- goto fail;
- if (!isnan(d)) {
- if (d <= 0)
- pos = 0;
- else if (d < pos)
- pos = d;
- }
- }
- start = pos;
- stop = 0;
- inc = -1;
- } else {
- pos = 0;
- if (argc > 1) {
- if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
- goto fail;
- }
- start = pos;
- stop = len - v_len;
- inc = 1;
- }
- ret = -1;
- if (len >= v_len && inc * (stop - start) >= 0) {
- for (i = start;; i += inc) {
- if (!string_cmp(p, p1, i, 0, v_len)) {
- ret = i;
- break;
- }
- if (i == stop)
- break;
- }
- }
- JS_FreeValue(ctx, str);
- JS_FreeValue(ctx, v);
- return js_int32(ret);
- fail:
- JS_FreeValue(ctx, str);
- JS_FreeValue(ctx, v);
- return JS_EXCEPTION;
- }
- /* return < 0 if exception or true/false */
- static int js_is_regexp(JSContext *ctx, JSValueConst obj);
- static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValue str, v = JS_UNDEFINED;
- int i, len, v_len, pos, start, stop, ret;
- JSString *p;
- JSString *p1;
- str = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(str))
- return str;
- ret = js_is_regexp(ctx, argv[0]);
- if (ret) {
- if (ret > 0)
- JS_ThrowTypeError(ctx, "regexp not supported");
- goto fail;
- }
- v = JS_ToString(ctx, argv[0]);
- if (JS_IsException(v))
- goto fail;
- p = JS_VALUE_GET_STRING(str);
- p1 = JS_VALUE_GET_STRING(v);
- len = p->len;
- v_len = p1->len;
- pos = (magic == 2) ? len : 0;
- if (argc > 1 && !JS_IsUndefined(argv[1])) {
- if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
- goto fail;
- }
- len -= v_len;
- ret = 0;
- if (magic == 0) {
- start = pos;
- stop = len;
- } else {
- if (magic == 1) {
- if (pos > len)
- goto done;
- } else {
- pos -= v_len;
- }
- start = stop = pos;
- }
- if (start >= 0 && start <= stop) {
- for (i = start;; i++) {
- if (!string_cmp(p, p1, i, 0, v_len)) {
- ret = 1;
- break;
- }
- if (i == stop)
- break;
- }
- }
- done:
- JS_FreeValue(ctx, str);
- JS_FreeValue(ctx, v);
- return js_bool(ret);
- fail:
- JS_FreeValue(ctx, str);
- JS_FreeValue(ctx, v);
- return JS_EXCEPTION;
- }
- static int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp)
- {
- int ret;
- JSValue flags;
- ret = js_is_regexp(ctx, regexp);
- if (ret < 0)
- return -1;
- if (ret) {
- flags = JS_GetProperty(ctx, regexp, JS_ATOM_flags);
- if (JS_IsException(flags))
- return -1;
- if (JS_IsUndefined(flags) || JS_IsNull(flags)) {
- JS_ThrowTypeError(ctx, "cannot convert to object");
- return -1;
- }
- flags = JS_ToStringFree(ctx, flags);
- if (JS_IsException(flags))
- return -1;
- ret = string_indexof_char(JS_VALUE_GET_STRING(flags), 'g', 0);
- JS_FreeValue(ctx, flags);
- if (ret < 0) {
- JS_ThrowTypeError(ctx, "regexp must have the 'g' flag");
- return -1;
- }
- }
- return 0;
- }
- static JSValue js_string_match(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int atom)
- {
- // match(rx), search(rx), matchAll(rx)
- // atom is JS_ATOM_Symbol_match, JS_ATOM_Symbol_search, or JS_ATOM_Symbol_matchAll
- JSValueConst O = this_val, regexp = argv[0], args[2];
- JSValue matcher, S, rx, result, str;
- int args_len;
- if (JS_IsUndefined(O) || JS_IsNull(O))
- return JS_ThrowTypeError(ctx, "cannot convert to object");
- if (JS_IsObject(regexp)) {
- matcher = JS_GetProperty(ctx, regexp, atom);
- if (JS_IsException(matcher))
- return JS_EXCEPTION;
- if (atom == JS_ATOM_Symbol_matchAll) {
- if (check_regexp_g_flag(ctx, regexp) < 0) {
- JS_FreeValue(ctx, matcher);
- return JS_EXCEPTION;
- }
- }
- if (!JS_IsUndefined(matcher) && !JS_IsNull(matcher)) {
- return JS_CallFree(ctx, matcher, regexp, 1, &O);
- }
- }
- S = JS_ToString(ctx, O);
- if (JS_IsException(S))
- return JS_EXCEPTION;
- args_len = 1;
- args[0] = regexp;
- str = JS_UNDEFINED;
- if (atom == JS_ATOM_Symbol_matchAll) {
- str = js_new_string8(ctx, "g");
- if (JS_IsException(str))
- goto fail;
- args[args_len++] = str;
- }
- rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args);
- JS_FreeValue(ctx, str);
- if (JS_IsException(rx)) {
- fail:
- JS_FreeValue(ctx, S);
- return JS_EXCEPTION;
- }
- result = JS_InvokeFree(ctx, rx, atom, 1, vc(&S));
- JS_FreeValue(ctx, S);
- return result;
- }
- static JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // GetSubstitution(matched, str, position, captures, namedCaptures, rep)
- JSValueConst matched, str, captures, namedCaptures, rep;
- JSValue capture, name, s;
- uint32_t position, len, matched_len, captures_len;
- int i, j, j0, k, k1;
- int c, c1;
- StringBuffer b_s, *b = &b_s;
- JSString *sp, *rp;
- matched = argv[0];
- str = argv[1];
- captures = argv[3];
- namedCaptures = argv[4];
- rep = argv[5];
- if (!JS_IsString(rep) || !JS_IsString(str))
- return JS_ThrowTypeError(ctx, "not a string");
- sp = JS_VALUE_GET_STRING(str);
- rp = JS_VALUE_GET_STRING(rep);
- string_buffer_init(ctx, b, 0);
- captures_len = 0;
- if (!JS_IsUndefined(captures)) {
- if (js_get_length32(ctx, &captures_len, captures))
- goto exception;
- }
- if (js_get_length32(ctx, &matched_len, matched))
- goto exception;
- if (JS_ToUint32(ctx, &position, argv[2]) < 0)
- goto exception;
- len = rp->len;
- i = 0;
- for(;;) {
- j = string_indexof_char(rp, '$', i);
- if (j < 0 || j + 1 >= len)
- break;
- string_buffer_concat(b, rp, i, j);
- j0 = j++;
- c = string_get(rp, j++);
- if (c == '$') {
- string_buffer_putc8(b, '$');
- } else if (c == '&') {
- if (string_buffer_concat_value(b, matched))
- goto exception;
- } else if (c == '`') {
- string_buffer_concat(b, sp, 0, position);
- } else if (c == '\'') {
- string_buffer_concat(b, sp, position + matched_len, sp->len);
- } else if (c >= '0' && c <= '9') {
- k = c - '0';
- if (j < len) {
- c1 = string_get(rp, j);
- if (c1 >= '0' && c1 <= '9') {
- /* This behavior is specified in ES6 and refined in ECMA 2019 */
- /* ECMA 2019 does not have the extra test, but
- Test262 S15.5.4.11_A3_T1..3 require this behavior */
- k1 = k * 10 + c1 - '0';
- if (k1 >= 1 && k1 < captures_len) {
- k = k1;
- j++;
- }
- }
- }
- if (k >= 1 && k < captures_len) {
- s = JS_GetPropertyInt64(ctx, captures, k);
- if (JS_IsException(s))
- goto exception;
- if (!JS_IsUndefined(s)) {
- if (string_buffer_concat_value_free(b, s))
- goto exception;
- }
- } else {
- goto norep;
- }
- } else if (c == '<' && !JS_IsUndefined(namedCaptures)) {
- k = string_indexof_char(rp, '>', j);
- if (k < 0)
- goto norep;
- name = js_sub_string(ctx, rp, j, k);
- if (JS_IsException(name))
- goto exception;
- capture = JS_GetPropertyValue(ctx, namedCaptures, name);
- if (JS_IsException(capture))
- goto exception;
- if (!JS_IsUndefined(capture)) {
- if (string_buffer_concat_value_free(b, capture))
- goto exception;
- }
- j = k + 1;
- } else {
- norep:
- string_buffer_concat(b, rp, j0, j);
- }
- i = j;
- }
- string_buffer_concat(b, rp, i, rp->len);
- return string_buffer_end(b);
- exception:
- string_buffer_free(b);
- return JS_EXCEPTION;
- }
- static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int is_replaceAll)
- {
- // replace(rx, rep)
- JSValueConst O = this_val, searchValue = argv[0], replaceValue = argv[1];
- JSValueConst args[6];
- JSValue str, search_str, replaceValue_str, repl_str;
- JSString *sp, *searchp;
- StringBuffer b_s, *b = &b_s;
- int pos, functionalReplace, endOfLastMatch;
- bool is_first;
- if (JS_IsUndefined(O) || JS_IsNull(O))
- return JS_ThrowTypeError(ctx, "cannot convert to object");
- search_str = JS_UNDEFINED;
- replaceValue_str = JS_UNDEFINED;
- repl_str = JS_UNDEFINED;
- if (JS_IsObject(searchValue)) {
- JSValue replacer;
- if (is_replaceAll) {
- if (check_regexp_g_flag(ctx, searchValue) < 0)
- return JS_EXCEPTION;
- }
- replacer = JS_GetProperty(ctx, searchValue, JS_ATOM_Symbol_replace);
- if (JS_IsException(replacer))
- return JS_EXCEPTION;
- if (!JS_IsUndefined(replacer) && !JS_IsNull(replacer)) {
- args[0] = O;
- args[1] = replaceValue;
- return JS_CallFree(ctx, replacer, searchValue, 2, args);
- }
- }
- string_buffer_init(ctx, b, 0);
- str = JS_ToString(ctx, O);
- if (JS_IsException(str))
- goto exception;
- search_str = JS_ToString(ctx, searchValue);
- if (JS_IsException(search_str))
- goto exception;
- functionalReplace = JS_IsFunction(ctx, replaceValue);
- if (!functionalReplace) {
- replaceValue_str = JS_ToString(ctx, replaceValue);
- if (JS_IsException(replaceValue_str))
- goto exception;
- }
- sp = JS_VALUE_GET_STRING(str);
- searchp = JS_VALUE_GET_STRING(search_str);
- endOfLastMatch = 0;
- is_first = true;
- for(;;) {
- if (unlikely(searchp->len == 0)) {
- if (is_first)
- pos = 0;
- else if (endOfLastMatch >= sp->len)
- pos = -1;
- else
- pos = endOfLastMatch + 1;
- } else {
- pos = string_indexof(sp, searchp, endOfLastMatch);
- }
- if (pos < 0) {
- if (is_first) {
- string_buffer_free(b);
- JS_FreeValue(ctx, search_str);
- JS_FreeValue(ctx, replaceValue_str);
- return str;
- } else {
- break;
- }
- }
- if (functionalReplace) {
- args[0] = search_str;
- args[1] = js_int32(pos);
- args[2] = str;
- repl_str = JS_ToStringFree(ctx, JS_Call(ctx, replaceValue, JS_UNDEFINED, 3, args));
- } else {
- args[0] = search_str;
- args[1] = str;
- args[2] = js_int32(pos);
- args[3] = JS_UNDEFINED;
- args[4] = JS_UNDEFINED;
- args[5] = replaceValue_str;
- repl_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
- }
- if (JS_IsException(repl_str))
- goto exception;
- string_buffer_concat(b, sp, endOfLastMatch, pos);
- string_buffer_concat_value_free(b, repl_str);
- endOfLastMatch = pos + searchp->len;
- is_first = false;
- if (!is_replaceAll)
- break;
- }
- string_buffer_concat(b, sp, endOfLastMatch, sp->len);
- JS_FreeValue(ctx, search_str);
- JS_FreeValue(ctx, replaceValue_str);
- JS_FreeValue(ctx, str);
- return string_buffer_end(b);
- exception:
- string_buffer_free(b);
- JS_FreeValue(ctx, search_str);
- JS_FreeValue(ctx, replaceValue_str);
- JS_FreeValue(ctx, str);
- return JS_EXCEPTION;
- }
- static JSValue js_string_split(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // split(sep, limit)
- JSValueConst O = this_val, separator = argv[0], limit = argv[1];
- JSValueConst args[2];
- JSValue S, A, R, T;
- uint32_t lim, lengthA;
- int64_t p, q, s, r, e;
- JSString *sp, *rp;
- if (JS_IsUndefined(O) || JS_IsNull(O))
- return JS_ThrowTypeError(ctx, "cannot convert to object");
- S = JS_UNDEFINED;
- A = JS_UNDEFINED;
- R = JS_UNDEFINED;
- if (JS_IsObject(separator)) {
- JSValue splitter;
- splitter = JS_GetProperty(ctx, separator, JS_ATOM_Symbol_split);
- if (JS_IsException(splitter))
- return JS_EXCEPTION;
- if (!JS_IsUndefined(splitter) && !JS_IsNull(splitter)) {
- args[0] = O;
- args[1] = limit;
- return JS_CallFree(ctx, splitter, separator, 2, args);
- }
- }
- S = JS_ToString(ctx, O);
- if (JS_IsException(S))
- goto exception;
- A = JS_NewArray(ctx);
- if (JS_IsException(A))
- goto exception;
- lengthA = 0;
- if (JS_IsUndefined(limit)) {
- lim = 0xffffffff;
- } else {
- if (JS_ToUint32(ctx, &lim, limit) < 0)
- goto exception;
- }
- sp = JS_VALUE_GET_STRING(S);
- s = sp->len;
- R = JS_ToString(ctx, separator);
- if (JS_IsException(R))
- goto exception;
- rp = JS_VALUE_GET_STRING(R);
- r = rp->len;
- p = 0;
- if (lim == 0)
- goto done;
- if (JS_IsUndefined(separator))
- goto add_tail;
- if (s == 0) {
- if (r != 0)
- goto add_tail;
- goto done;
- }
- q = p;
- for (q = p; (q += !r) <= s - r - !r; q = p = e + r) {
- e = string_indexof(sp, rp, q);
- if (e < 0)
- break;
- T = js_sub_string(ctx, sp, p, e);
- if (JS_IsException(T))
- goto exception;
- if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T, 0) < 0)
- goto exception;
- if (lengthA == lim)
- goto done;
- }
- add_tail:
- T = js_sub_string(ctx, sp, p, s);
- if (JS_IsException(T))
- goto exception;
- if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T,0 ) < 0)
- goto exception;
- done:
- JS_FreeValue(ctx, S);
- JS_FreeValue(ctx, R);
- return A;
- exception:
- JS_FreeValue(ctx, A);
- JS_FreeValue(ctx, S);
- JS_FreeValue(ctx, R);
- return JS_EXCEPTION;
- }
- static JSValue js_string_substring(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue str, ret;
- int a, b, start, end;
- JSString *p;
- str = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(str))
- return str;
- p = JS_VALUE_GET_STRING(str);
- if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, p->len, 0)) {
- JS_FreeValue(ctx, str);
- return JS_EXCEPTION;
- }
- b = p->len;
- if (!JS_IsUndefined(argv[1])) {
- if (JS_ToInt32Clamp(ctx, &b, argv[1], 0, p->len, 0)) {
- JS_FreeValue(ctx, str);
- return JS_EXCEPTION;
- }
- }
- if (a < b) {
- start = a;
- end = b;
- } else {
- start = b;
- end = a;
- }
- ret = js_sub_string(ctx, p, start, end);
- JS_FreeValue(ctx, str);
- return ret;
- }
- static JSValue js_string_substr(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue str, ret;
- int a, len, n;
- JSString *p;
- str = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(str))
- return str;
- p = JS_VALUE_GET_STRING(str);
- len = p->len;
- if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, len, len)) {
- JS_FreeValue(ctx, str);
- return JS_EXCEPTION;
- }
- n = len - a;
- if (!JS_IsUndefined(argv[1])) {
- if (JS_ToInt32Clamp(ctx, &n, argv[1], 0, len - a, 0)) {
- JS_FreeValue(ctx, str);
- return JS_EXCEPTION;
- }
- }
- ret = js_sub_string(ctx, p, a, a + n);
- JS_FreeValue(ctx, str);
- return ret;
- }
- static JSValue js_string_slice(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue str, ret;
- int len, start, end;
- JSString *p;
- str = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(str))
- return str;
- p = JS_VALUE_GET_STRING(str);
- len = p->len;
- if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) {
- JS_FreeValue(ctx, str);
- return JS_EXCEPTION;
- }
- end = len;
- if (!JS_IsUndefined(argv[1])) {
- if (JS_ToInt32Clamp(ctx, &end, argv[1], 0, len, len)) {
- JS_FreeValue(ctx, str);
- return JS_EXCEPTION;
- }
- }
- ret = js_sub_string(ctx, p, start, max_int(end, start));
- JS_FreeValue(ctx, str);
- return ret;
- }
- static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int padEnd)
- {
- JSValue str, v = JS_UNDEFINED;
- StringBuffer b_s, *b = &b_s;
- JSString *p, *p1 = NULL;
- int n, len, c = ' ';
- str = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(str))
- goto fail1;
- if (JS_ToInt32Sat(ctx, &n, argv[0]))
- goto fail2;
- p = JS_VALUE_GET_STRING(str);
- len = p->len;
- if (len >= n)
- return str;
- if (argc > 1 && !JS_IsUndefined(argv[1])) {
- v = JS_ToString(ctx, argv[1]);
- if (JS_IsException(v))
- goto fail2;
- p1 = JS_VALUE_GET_STRING(v);
- if (p1->len == 0) {
- JS_FreeValue(ctx, v);
- return str;
- }
- if (p1->len == 1) {
- c = string_get(p1, 0);
- p1 = NULL;
- }
- }
- if (n > JS_STRING_LEN_MAX) {
- JS_ThrowRangeError(ctx, "invalid string length");
- goto fail3;
- }
- if (string_buffer_init(ctx, b, n))
- goto fail3;
- n -= len;
- if (padEnd) {
- if (string_buffer_concat(b, p, 0, len))
- goto fail;
- }
- if (p1) {
- while (n > 0) {
- int chunk = min_int(n, p1->len);
- if (string_buffer_concat(b, p1, 0, chunk))
- goto fail;
- n -= chunk;
- }
- } else {
- if (string_buffer_fill(b, c, n))
- goto fail;
- }
- if (!padEnd) {
- if (string_buffer_concat(b, p, 0, len))
- goto fail;
- }
- JS_FreeValue(ctx, v);
- JS_FreeValue(ctx, str);
- return string_buffer_end(b);
- fail:
- string_buffer_free(b);
- fail3:
- JS_FreeValue(ctx, v);
- fail2:
- JS_FreeValue(ctx, str);
- fail1:
- return JS_EXCEPTION;
- }
- static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue str;
- StringBuffer b_s, *b = &b_s;
- JSString *p;
- int64_t val;
- int n, len;
- str = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(str))
- goto fail;
- if (JS_ToInt64Sat(ctx, &val, argv[0]))
- goto fail;
- if (val < 0 || val > 2147483647) {
- JS_ThrowRangeError(ctx, "invalid repeat count");
- goto fail;
- }
- n = val;
- p = JS_VALUE_GET_STRING(str);
- len = p->len;
- if (len == 0 || n == 1)
- return str;
- if (val * len > JS_STRING_LEN_MAX) {
- JS_ThrowRangeError(ctx, "invalid string length");
- goto fail;
- }
- if (string_buffer_init2(ctx, b, n * len, p->is_wide_char))
- goto fail;
- if (len == 1) {
- string_buffer_fill(b, string_get(p, 0), n);
- } else {
- while (n-- > 0) {
- string_buffer_concat(b, p, 0, len);
- }
- }
- JS_FreeValue(ctx, str);
- return string_buffer_end(b);
- fail:
- JS_FreeValue(ctx, str);
- return JS_EXCEPTION;
- }
- static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValue str, ret;
- int a, b, len;
- JSString *p;
- str = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(str))
- return str;
- p = JS_VALUE_GET_STRING(str);
- a = 0;
- b = len = p->len;
- if (magic & 1) {
- while (a < len && lre_is_space(string_get(p, a)))
- a++;
- }
- if (magic & 2) {
- while (b > a && lre_is_space(string_get(p, b - 1)))
- b--;
- }
- ret = js_sub_string(ctx, p, a, b);
- JS_FreeValue(ctx, str);
- return ret;
- }
- /* return 0 if before the first char */
- static int string_prevc(JSString *p, int *pidx)
- {
- int idx, c, c1;
- idx = *pidx;
- if (idx <= 0)
- return 0;
- idx--;
- if (p->is_wide_char) {
- c = str16(p)[idx];
- if (is_lo_surrogate(c) && idx > 0) {
- c1 = str16(p)[idx - 1];
- if (is_hi_surrogate(c1)) {
- c = from_surrogate(c1, c);
- idx--;
- }
- }
- } else {
- c = str8(p)[idx];
- }
- *pidx = idx;
- return c;
- }
- static bool test_final_sigma(JSString *p, int sigma_pos)
- {
- int k, c1;
- /* before C: skip case ignorable chars and check there is
- a cased letter */
- k = sigma_pos;
- for(;;) {
- c1 = string_prevc(p, &k);
- if (!lre_is_case_ignorable(c1))
- break;
- }
- if (!lre_is_cased(c1))
- return false;
- /* after C: skip case ignorable chars and check there is
- no cased letter */
- k = sigma_pos + 1;
- for(;;) {
- if (k >= p->len)
- return true;
- c1 = string_getc(p, &k);
- if (!lre_is_case_ignorable(c1))
- break;
- }
- return !lre_is_cased(c1);
- }
- static int to_utf32_buf(JSContext *ctx, JSString *p, uint32_t **pbuf)
- {
- uint32_t *b;
- int i, j, n;
- j = -1;
- n = p->len;
- b = js_malloc(ctx, max_int(1, n) * sizeof(*b));
- if (b)
- for (i = j = 0; i < n;)
- b[j++] = string_getc(p, &i);
- *pbuf = b;
- return j;
- }
- static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int i, n, an, bn, cmp;
- uint32_t *as, *bs, *ts;
- JSValue a, b, ret;
- ret = JS_EXCEPTION;
- as = NULL;
- bs = NULL;
- a = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(a))
- return JS_EXCEPTION;
- b = JS_ToString(ctx, argv[0]);
- if (JS_IsException(b))
- goto exception;
- an = to_utf32_buf(ctx, JS_VALUE_GET_STRING(a), &as);
- if (an == -1)
- goto exception;
- bn = to_utf32_buf(ctx, JS_VALUE_GET_STRING(b), &bs);
- if (bn == -1)
- goto exception;
- // TODO(bnoordhuis) skip normalization when input is latin1
- an = unicode_normalize(&ts, as, an, UNICODE_NFC, ctx,
- (DynBufReallocFunc *)js_realloc);
- if (an == -1)
- goto exception;
- js_free(ctx, as);
- as = ts;
- // TODO(bnoordhuis) skip normalization when input is latin1
- bn = unicode_normalize(&ts, bs, bn, UNICODE_NFC, ctx,
- (DynBufReallocFunc *)js_realloc);
- if (bn == -1)
- goto exception;
- js_free(ctx, bs);
- bs = ts;
- n = min_int(an, bn);
- for (i = 0; i < n; i++)
- if (as[i] != bs[i])
- break;
- if (i < n)
- cmp = compare_u32(as[i], bs[i]);
- else
- cmp = compare_u32(an, bn);
- ret = js_int32(cmp);
- exception:
- JS_FreeValue(ctx, a);
- JS_FreeValue(ctx, b);
- js_free(ctx, as);
- js_free(ctx, bs);
- return ret;
- }
- static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int to_lower)
- {
- JSValue val;
- StringBuffer b_s, *b = &b_s;
- JSString *p;
- int i, c, j, l;
- uint32_t res[LRE_CC_RES_LEN_MAX];
- val = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(val))
- return val;
- p = JS_VALUE_GET_STRING(val);
- if (p->len == 0)
- return val;
- if (string_buffer_init(ctx, b, p->len))
- goto fail;
- for(i = 0; i < p->len;) {
- c = string_getc(p, &i);
- if (c == 0x3a3 && to_lower && test_final_sigma(p, i - 1)) {
- res[0] = 0x3c2; /* final sigma */
- l = 1;
- } else {
- l = lre_case_conv(res, c, to_lower);
- }
- for(j = 0; j < l; j++) {
- if (string_buffer_putc(b, res[j]))
- goto fail;
- }
- }
- JS_FreeValue(ctx, val);
- return string_buffer_end(b);
- fail:
- JS_FreeValue(ctx, val);
- string_buffer_free(b);
- return JS_EXCEPTION;
- }
- /* return (-1, NULL) if exception, otherwise (len, buf) */
- static int JS_ToUTF32String(JSContext *ctx, uint32_t **pbuf, JSValue val1)
- {
- JSValue val;
- int len;
- val = JS_ToString(ctx, val1);
- if (JS_IsException(val))
- return -1;
- len = to_utf32_buf(ctx, JS_VALUE_GET_STRING(val), pbuf);
- JS_FreeValue(ctx, val);
- return len;
- }
- static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len)
- {
- int i;
- StringBuffer b_s, *b = &b_s;
- if (string_buffer_init(ctx, b, len))
- return JS_EXCEPTION;
- for(i = 0; i < len; i++) {
- if (string_buffer_putc(b, buf[i]))
- goto fail;
- }
- return string_buffer_end(b);
- fail:
- string_buffer_free(b);
- return JS_EXCEPTION;
- }
- static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *form, *p;
- size_t form_len;
- int is_compat, buf_len, out_len;
- UnicodeNormalizationEnum n_type;
- JSValue val;
- uint32_t *buf, *out_buf;
- val = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(val))
- return val;
- buf = NULL; // appease bogus -Wmaybe-uninitialized warning
- buf_len = JS_ToUTF32String(ctx, &buf, val);
- JS_FreeValue(ctx, val);
- if (buf_len < 0)
- return JS_EXCEPTION;
- if (argc == 0 || JS_IsUndefined(argv[0])) {
- n_type = UNICODE_NFC;
- } else {
- form = JS_ToCStringLen(ctx, &form_len, argv[0]);
- if (!form)
- goto fail1;
- p = form;
- if (p[0] != 'N' || p[1] != 'F')
- goto bad_form;
- p += 2;
- is_compat = false;
- if (*p == 'K') {
- is_compat = true;
- p++;
- }
- if (*p == 'C' || *p == 'D') {
- n_type = UNICODE_NFC + is_compat * 2 + (*p - 'C');
- if ((p + 1 - form) != form_len)
- goto bad_form;
- } else {
- bad_form:
- JS_FreeCString(ctx, form);
- JS_ThrowRangeError(ctx, "bad normalization form");
- fail1:
- js_free(ctx, buf);
- return JS_EXCEPTION;
- }
- JS_FreeCString(ctx, form);
- }
- out_len = unicode_normalize(&out_buf, buf, buf_len, n_type,
- ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
- js_free(ctx, buf);
- if (out_len < 0)
- return JS_EXCEPTION;
- val = JS_NewUTF32String(ctx, out_buf, out_len);
- js_free(ctx, out_buf);
- return val;
- }
- /* also used for String.prototype.valueOf */
- static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_thisStringValue(ctx, this_val);
- }
- /* String Iterator */
- static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int *pdone, int magic)
- {
- JSArrayIteratorData *it;
- uint32_t idx, c, start;
- JSString *p;
- it = JS_GetOpaque2(ctx, this_val, JS_CLASS_STRING_ITERATOR);
- if (!it) {
- *pdone = false;
- return JS_EXCEPTION;
- }
- if (JS_IsUndefined(it->obj))
- goto done;
- p = JS_VALUE_GET_STRING(it->obj);
- idx = it->idx;
- if (idx >= p->len) {
- JS_FreeValue(ctx, it->obj);
- it->obj = JS_UNDEFINED;
- done:
- *pdone = true;
- return JS_UNDEFINED;
- }
- start = idx;
- c = string_getc(p, (int *)&idx);
- it->idx = idx;
- *pdone = false;
- if (c <= 0xffff) {
- return js_new_string_char(ctx, c);
- } else {
- return js_new_string16_len(ctx, str16(p) + start, 2);
- }
- }
- /* ES6 Annex B 2.3.2 etc. */
- enum {
- magic_string_anchor,
- magic_string_big,
- magic_string_blink,
- magic_string_bold,
- magic_string_fixed,
- magic_string_fontcolor,
- magic_string_fontsize,
- magic_string_italics,
- magic_string_link,
- magic_string_small,
- magic_string_strike,
- magic_string_sub,
- magic_string_sup,
- };
- static JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValue str;
- JSString *p;
- StringBuffer b_s, *b = &b_s;
- static struct { const char *tag, *attr; } const defs[] = {
- { "a", "name" }, { "big", NULL }, { "blink", NULL }, { "b", NULL },
- { "tt", NULL }, { "font", "color" }, { "font", "size" }, { "i", NULL },
- { "a", "href" }, { "small", NULL }, { "strike", NULL },
- { "sub", NULL }, { "sup", NULL },
- };
- str = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(str))
- return JS_EXCEPTION;
- string_buffer_init(ctx, b, 7);
- string_buffer_putc8(b, '<');
- string_buffer_puts8(b, defs[magic].tag);
- if (defs[magic].attr) {
- // r += " " + attr + "=\"" + value + "\"";
- JSValue value;
- int i;
- string_buffer_putc8(b, ' ');
- string_buffer_puts8(b, defs[magic].attr);
- string_buffer_puts8(b, "=\"");
- value = JS_ToStringCheckObject(ctx, argv[0]);
- if (JS_IsException(value)) {
- JS_FreeValue(ctx, str);
- string_buffer_free(b);
- return JS_EXCEPTION;
- }
- p = JS_VALUE_GET_STRING(value);
- for (i = 0; i < p->len; i++) {
- int c = string_get(p, i);
- if (c == '"') {
- string_buffer_puts8(b, """);
- } else {
- string_buffer_putc16(b, c);
- }
- }
- JS_FreeValue(ctx, value);
- string_buffer_putc8(b, '\"');
- }
- // return r + ">" + str + "</" + tag + ">";
- string_buffer_putc8(b, '>');
- string_buffer_concat_value_free(b, str);
- string_buffer_puts8(b, "</");
- string_buffer_puts8(b, defs[magic].tag);
- string_buffer_putc8(b, '>');
- return string_buffer_end(b);
- }
- static const JSCFunctionListEntry js_string_funcs[] = {
- JS_CFUNC_DEF("fromCharCode", 1, js_string_fromCharCode ),
- JS_CFUNC_DEF("fromCodePoint", 1, js_string_fromCodePoint ),
- JS_CFUNC_DEF("raw", 1, js_string_raw ),
- };
- static const JSCFunctionListEntry js_string_proto_funcs[] = {
- JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE ),
- JS_CFUNC_DEF("at", 1, js_string_at ),
- JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt ),
- JS_CFUNC_DEF("charAt", 1, js_string_charAt ),
- JS_CFUNC_DEF("concat", 1, js_string_concat ),
- JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ),
- JS_CFUNC_DEF("isWellFormed", 0, js_string_isWellFormed ),
- JS_CFUNC_DEF("toWellFormed", 0, js_string_toWellFormed ),
- JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ),
- JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ),
- JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0 ),
- JS_CFUNC_MAGIC_DEF("endsWith", 1, js_string_includes, 2 ),
- JS_CFUNC_MAGIC_DEF("startsWith", 1, js_string_includes, 1 ),
- JS_CFUNC_MAGIC_DEF("match", 1, js_string_match, JS_ATOM_Symbol_match ),
- JS_CFUNC_MAGIC_DEF("matchAll", 1, js_string_match, JS_ATOM_Symbol_matchAll ),
- JS_CFUNC_MAGIC_DEF("search", 1, js_string_match, JS_ATOM_Symbol_search ),
- JS_CFUNC_DEF("split", 2, js_string_split ),
- JS_CFUNC_DEF("substring", 2, js_string_substring ),
- JS_CFUNC_DEF("substr", 2, js_string_substr ),
- JS_CFUNC_DEF("slice", 2, js_string_slice ),
- JS_CFUNC_DEF("repeat", 1, js_string_repeat ),
- JS_CFUNC_MAGIC_DEF("replace", 2, js_string_replace, 0 ),
- JS_CFUNC_MAGIC_DEF("replaceAll", 2, js_string_replace, 1 ),
- JS_CFUNC_MAGIC_DEF("padEnd", 1, js_string_pad, 1 ),
- JS_CFUNC_MAGIC_DEF("padStart", 1, js_string_pad, 0 ),
- JS_CFUNC_MAGIC_DEF("trim", 0, js_string_trim, 3 ),
- JS_CFUNC_MAGIC_DEF("trimEnd", 0, js_string_trim, 2 ),
- JS_ALIAS_DEF("trimRight", "trimEnd" ),
- JS_CFUNC_MAGIC_DEF("trimStart", 0, js_string_trim, 1 ),
- JS_ALIAS_DEF("trimLeft", "trimStart" ),
- JS_CFUNC_DEF("toString", 0, js_string_toString ),
- JS_CFUNC_DEF("valueOf", 0, js_string_toString ),
- JS_CFUNC_DEF("localeCompare", 1, js_string_localeCompare ),
- JS_CFUNC_DEF("normalize", 0, js_string_normalize ),
- JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
- JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
- JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ),
- JS_CFUNC_MAGIC_DEF("toLocaleUpperCase", 0, js_string_toLowerCase, 0 ),
- JS_CFUNC_MAGIC_DEF("[Symbol.iterator]", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4 ),
- /* ES6 Annex B 2.3.2 etc. */
- JS_CFUNC_MAGIC_DEF("anchor", 1, js_string_CreateHTML, magic_string_anchor ),
- JS_CFUNC_MAGIC_DEF("big", 0, js_string_CreateHTML, magic_string_big ),
- JS_CFUNC_MAGIC_DEF("blink", 0, js_string_CreateHTML, magic_string_blink ),
- JS_CFUNC_MAGIC_DEF("bold", 0, js_string_CreateHTML, magic_string_bold ),
- JS_CFUNC_MAGIC_DEF("fixed", 0, js_string_CreateHTML, magic_string_fixed ),
- JS_CFUNC_MAGIC_DEF("fontcolor", 1, js_string_CreateHTML, magic_string_fontcolor ),
- JS_CFUNC_MAGIC_DEF("fontsize", 1, js_string_CreateHTML, magic_string_fontsize ),
- JS_CFUNC_MAGIC_DEF("italics", 0, js_string_CreateHTML, magic_string_italics ),
- JS_CFUNC_MAGIC_DEF("link", 1, js_string_CreateHTML, magic_string_link ),
- JS_CFUNC_MAGIC_DEF("small", 0, js_string_CreateHTML, magic_string_small ),
- JS_CFUNC_MAGIC_DEF("strike", 0, js_string_CreateHTML, magic_string_strike ),
- JS_CFUNC_MAGIC_DEF("sub", 0, js_string_CreateHTML, magic_string_sub ),
- JS_CFUNC_MAGIC_DEF("sup", 0, js_string_CreateHTML, magic_string_sup ),
- };
- static const JSCFunctionListEntry js_string_iterator_proto_funcs[] = {
- JS_ITERATOR_NEXT_DEF("next", 0, js_string_iterator_next, 0 ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "String Iterator", JS_PROP_CONFIGURABLE ),
- };
- /* Math */
- /* precondition: a and b are not NaN */
- static double js_fmin(double a, double b)
- {
- if (a == 0 && b == 0) {
- JSFloat64Union a1, b1;
- a1.d = a;
- b1.d = b;
- a1.u64 |= b1.u64;
- return a1.d;
- } else {
- return fmin(a, b);
- }
- }
- /* precondition: a and b are not NaN */
- static double js_fmax(double a, double b)
- {
- if (a == 0 && b == 0) {
- JSFloat64Union a1, b1;
- a1.d = a;
- b1.d = b;
- a1.u64 &= b1.u64;
- return a1.d;
- } else {
- return fmax(a, b);
- }
- }
- static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- bool is_max = magic;
- double r, a;
- int i;
- uint32_t tag;
- if (unlikely(argc == 0)) {
- return js_float64(is_max ? NEG_INF : INF);
- }
- tag = JS_VALUE_GET_TAG(argv[0]);
- if (tag == JS_TAG_INT) {
- int a1, r1 = JS_VALUE_GET_INT(argv[0]);
- for(i = 1; i < argc; i++) {
- tag = JS_VALUE_GET_TAG(argv[i]);
- if (tag != JS_TAG_INT) {
- r = r1;
- goto generic_case;
- }
- a1 = JS_VALUE_GET_INT(argv[i]);
- if (is_max)
- r1 = max_int(r1, a1);
- else
- r1 = min_int(r1, a1);
- }
- return js_int32(r1);
- } else {
- if (JS_ToFloat64(ctx, &r, argv[0]))
- return JS_EXCEPTION;
- i = 1;
- generic_case:
- while (i < argc) {
- if (JS_ToFloat64(ctx, &a, argv[i]))
- return JS_EXCEPTION;
- if (!isnan(r)) {
- if (isnan(a)) {
- r = a;
- } else {
- if (is_max)
- r = js_fmax(r, a);
- else
- r = js_fmin(r, a);
- }
- }
- i++;
- }
- return js_number(r);
- }
- }
- static double js_math_sign(double a)
- {
- if (isnan(a) || a == 0.0)
- return a;
- if (a < 0)
- return -1;
- else
- return 1;
- }
- static double js_math_round(double a)
- {
- JSFloat64Union u;
- uint64_t frac_mask, one;
- unsigned int e, s;
- u.d = a;
- e = (u.u64 >> 52) & 0x7ff;
- if (e < 1023) {
- /* abs(a) < 1 */
- if (e == (1023 - 1) && u.u64 != 0xbfe0000000000000) {
- /* abs(a) > 0.5 or a = 0.5: return +/-1.0 */
- u.u64 = (u.u64 & ((uint64_t)1 << 63)) | ((uint64_t)1023 << 52);
- } else {
- /* return +/-0.0 */
- u.u64 &= (uint64_t)1 << 63;
- }
- } else if (e < (1023 + 52)) {
- s = u.u64 >> 63;
- one = (uint64_t)1 << (52 - (e - 1023));
- frac_mask = one - 1;
- u.u64 += (one >> 1) - s;
- u.u64 &= ~frac_mask; /* truncate to an integer */
- }
- /* otherwise: abs(a) >= 2^52, or NaN, +/-Infinity: no change */
- return u.d;
- }
- static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- double r, a;
- int i;
- r = 0;
- if (argc > 0) {
- if (JS_ToFloat64(ctx, &r, argv[0]))
- return JS_EXCEPTION;
- if (argc == 1) {
- r = fabs(r);
- } else {
- /* use the built-in function to minimize precision loss */
- for (i = 1; i < argc; i++) {
- if (JS_ToFloat64(ctx, &a, argv[i]))
- return JS_EXCEPTION;
- r = hypot(r, a);
- }
- }
- }
- return js_float64(r);
- }
- static double js_math_f16round(double a)
- {
- return fromfp16(tofp16(a));
- }
- static double js_math_fround(double a)
- {
- return (float)a;
- }
- static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- uint32_t a, b, c;
- int32_t d;
- if (JS_ToUint32(ctx, &a, argv[0]))
- return JS_EXCEPTION;
- if (JS_ToUint32(ctx, &b, argv[1]))
- return JS_EXCEPTION;
- c = a * b;
- memcpy(&d, &c, sizeof(d));
- return js_int32(d);
- }
- static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- uint32_t a, r;
- if (JS_ToUint32(ctx, &a, argv[0]))
- return JS_EXCEPTION;
- if (a == 0)
- r = 32;
- else
- r = clz32(a);
- return js_int32(r);
- }
- /* we add one extra limb to avoid having to test for overflows during the sum */
- #define SUM_PRECISE_ACC_LEN 34
- typedef enum {
- SUM_PRECISE_STATE_MINUS_ZERO,
- SUM_PRECISE_STATE_FINITE,
- SUM_PRECISE_STATE_INFINITY,
- SUM_PRECISE_STATE_MINUS_INFINITY, /* must be after SUM_PRECISE_STATE_INFINITY */
- SUM_PRECISE_STATE_NAN, /* must be after SUM_PRECISE_STATE_MINUS_INFINITY */
- } SumPreciseStateEnum;
- typedef struct {
- uint64_t acc[SUM_PRECISE_ACC_LEN];
- int n_limbs; /* acc is not necessarily normalized */
- SumPreciseStateEnum state;
- } SumPreciseState;
- static void sum_precise_init(SumPreciseState *s)
- {
- s->state = SUM_PRECISE_STATE_MINUS_ZERO;
- s->acc[0] = 0;
- s->n_limbs = 1;
- }
- #define ADDC64(res, carry_out, op1, op2, carry_in) \
- do { \
- uint64_t __v, __a, __k, __k1; \
- __v = (op1); \
- __a = __v + (op2); \
- __k1 = __a < __v; \
- __k = (carry_in); \
- __a = __a + __k; \
- carry_out = (__a < __k) | __k1; \
- res = __a; \
- } while (0)
- static void sum_precise_add(SumPreciseState *s, double d)
- {
- uint64_t a, m, a0, carry, acc_sign, a_sign;
- int sgn, e, p, n, i;
- unsigned shift;
- a = float64_as_uint64(d);
- sgn = a >> 63;
- e = (a >> 52) & ((1 << 11) - 1);
- m = a & (((uint64_t)1 << 52) - 1);
- if (unlikely(e == 2047)) {
- if (m == 0) {
- /* +/- infinity */
- if (s->state == SUM_PRECISE_STATE_NAN ||
- (s->state == SUM_PRECISE_STATE_MINUS_INFINITY && !sgn) ||
- (s->state == SUM_PRECISE_STATE_INFINITY && sgn)) {
- s->state = SUM_PRECISE_STATE_NAN;
- } else {
- s->state = SUM_PRECISE_STATE_INFINITY + sgn;
- }
- } else {
- /* NaN */
- s->state = SUM_PRECISE_STATE_NAN;
- }
- } else if (e == 0) {
- if (likely(m == 0)) {
- /* zero */
- if (s->state == SUM_PRECISE_STATE_MINUS_ZERO && !sgn)
- s->state = SUM_PRECISE_STATE_FINITE;
- } else {
- /* subnormal */
- p = 0;
- shift = 0;
- goto add;
- }
- } else {
- m |= (uint64_t)1 << 52;
- shift = e - 1;
- p = shift / 64;
- /* 'p' is the position of a0 in acc */
- shift %= 64;
- add:
- if (s->state >= SUM_PRECISE_STATE_INFINITY)
- return;
- s->state = SUM_PRECISE_STATE_FINITE;
- n = s->n_limbs;
- acc_sign = (int64_t)s->acc[n - 1] >> 63;
- /* sign extend acc */
- for(i = n; i <= p; i++)
- s->acc[i] = acc_sign;
- carry = sgn;
- a_sign = -sgn;
- a0 = m << shift;
- ADDC64(s->acc[p], carry, s->acc[p], a0 ^ a_sign, carry);
- if (shift >= 12) {
- p++;
- if (p >= n)
- s->acc[p] = acc_sign;
- a0 = m >> (64 - shift);
- ADDC64(s->acc[p], carry, s->acc[p], a0 ^ a_sign, carry);
- }
- p++;
- if (p >= n) {
- n = p;
- } else {
- /* carry */
- for(i = p; i < n; i++) {
- /* if 'a' positive: stop condition: carry = 0.
- if 'a' negative: stop condition: carry = 1. */
- if (carry == sgn)
- goto done;
- ADDC64(s->acc[i], carry, s->acc[i], a_sign, carry);
- }
- }
- /* extend the accumulator if needed */
- a0 = carry + acc_sign + a_sign;
- /* -1 <= a0 <= 1 (if both acc and a are negative, carry is set) */
- if (a0 != ((int64_t)s->acc[n - 1] >> 63)) {
- s->acc[n++] = a0;
- }
- done:
- s->n_limbs = n;
- }
- }
- static double sum_precise_get_result(SumPreciseState *s)
- {
- int n, shift, e, p, is_neg, i;
- uint64_t m, addend, carry;
- if (s->state != SUM_PRECISE_STATE_FINITE) {
- switch(s->state) {
- default:
- case SUM_PRECISE_STATE_MINUS_ZERO:
- return -0.0;
- case SUM_PRECISE_STATE_INFINITY:
- return INFINITY;
- case SUM_PRECISE_STATE_MINUS_INFINITY:
- return -INFINITY;
- case SUM_PRECISE_STATE_NAN:
- return NAN;
- }
- }
- /* extract the sign and absolute value */
- n = s->n_limbs;
- is_neg = s->acc[n - 1] >> 63;
- if (is_neg) {
- /* acc = -acc */
- carry = 1;
- for(i = 0; i < n; i++) {
- ADDC64(s->acc[i], carry, ~s->acc[i], 0, carry);
- }
- }
- /* normalize */
- while (n > 0 && s->acc[n - 1] == 0)
- n--;
- /* zero result. The spec tells it is always positive in the finite case */
- if (n == 0)
- return 0.0;
- /* subnormal case */
- if (n == 1 && s->acc[0] < ((uint64_t)1 << 52))
- return uint64_as_float64(((uint64_t)is_neg << 63) | s->acc[0]);
- /* normal case */
- e = n * 64;
- p = n - 1;
- m = s->acc[p];
- shift = clz64(m);
- e = e - shift - 52;
- if (shift != 0) {
- m <<= shift;
- if (p > 0) {
- int shift1;
- uint64_t nz;
- p--;
- shift1 = 64 - shift;
- nz = s->acc[p] & (((uint64_t)1 << shift1) - 1);
- m = m | (s->acc[p] >> shift1) | (nz != 0);
- }
- }
- if ((m & ((1 << 10) - 1)) == 0) {
- /* see if the LSB part is non zero for the final rounding */
- while (p > 0) {
- p--;
- if (s->acc[p] != 0) {
- m |= 1;
- break;
- }
- }
- }
- /* rounding to nearest with ties to even */
- addend = (1 << 10) - 1 + ((m >> 11) & 1);
- m = (m + addend) >> 11;
- /* handle overflow in the rounding */
- if (m == 0)
- e++;
- if (unlikely(e >= 2047)) {
- /* infinity */
- return uint64_as_float64(((uint64_t)is_neg << 63) | ((uint64_t)2047 << 52));
- } else {
- m &= (((uint64_t)1 << 52) - 1);
- return uint64_as_float64(((uint64_t)is_neg << 63) | ((uint64_t)e << 52) | m);
- }
- }
- static JSValue js_math_sumPrecise(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue iter, next, item, ret;
- uint32_t tag;
- int done;
- double d;
- SumPreciseState s_s, *s = &s_s;
- iter = JS_GetIterator(ctx, argv[0], /*is_async*/false);
- if (JS_IsException(iter))
- return JS_EXCEPTION;
- ret = JS_EXCEPTION;
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- goto fail;
- sum_precise_init(s);
- for (;;) {
- item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
- if (JS_IsException(item))
- goto fail;
- if (done)
- break;
- tag = JS_VALUE_GET_TAG(item);
- if (JS_TAG_IS_FLOAT64(tag)) {
- d = JS_VALUE_GET_FLOAT64(item);
- } else if (tag == JS_TAG_INT) {
- d = JS_VALUE_GET_INT(item);
- } else {
- JS_FreeValue(ctx, item);
- JS_ThrowTypeError(ctx, "not a number");
- JS_IteratorClose(ctx, iter, /*is_exception_pending*/true);
- goto fail;
- }
- sum_precise_add(s, d);
- }
- ret = js_float64(sum_precise_get_result(s));
- fail:
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, next);
- return ret;
- }
- /* xorshift* random number generator by Marsaglia */
- static uint64_t xorshift64star(uint64_t *pstate)
- {
- uint64_t x;
- x = *pstate;
- x ^= x >> 12;
- x ^= x << 25;
- x ^= x >> 27;
- *pstate = x;
- return x * 0x2545F4914F6CDD1D;
- }
- static void js_random_init(JSContext *ctx)
- {
- ctx->random_state = js__gettimeofday_us();
- /* the state must be non zero */
- if (ctx->random_state == 0)
- ctx->random_state = 1;
- }
- static JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSFloat64Union u;
- uint64_t v;
- v = xorshift64star(&ctx->random_state);
- /* 1.0 <= u.d < 2 */
- u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12);
- return js_float64(u.d - 1.0);
- }
- /* use local wrappers for math functions to
- - avoid initializing data with dynamic library entry points.
- - avoid some overhead if the call can be inlined at compile or link time.
- */
- static double js_math_fabs(double d) { return fabs(d); }
- static double js_math_floor(double d) { return floor(d); }
- static double js_math_ceil(double d) { return ceil(d); }
- static double js_math_sqrt(double d) { return sqrt(d); }
- static double js_math_acos(double d) { return acos(d); }
- static double js_math_asin(double d) { return asin(d); }
- static double js_math_atan(double d) { return atan(d); }
- static double js_math_atan2(double a, double b) { return atan2(a, b); }
- static double js_math_cos(double d) { return cos(d); }
- static double js_math_exp(double d) { return exp(d); }
- static double js_math_log(double d) { return log(d); }
- static double js_math_sin(double d) { return sin(d); }
- static double js_math_tan(double d) { return tan(d); }
- static double js_math_trunc(double d) { return trunc(d); }
- static double js_math_cosh(double d) { return cosh(d); }
- static double js_math_sinh(double d) { return sinh(d); }
- static double js_math_tanh(double d) { return tanh(d); }
- static double js_math_acosh(double d) { return acosh(d); }
- static double js_math_asinh(double d) { return asinh(d); }
- static double js_math_atanh(double d) { return atanh(d); }
- static double js_math_expm1(double d) { return expm1(d); }
- static double js_math_log1p(double d) { return log1p(d); }
- static double js_math_log2(double d) { return log2(d); }
- static double js_math_log10(double d) { return log10(d); }
- static double js_math_cbrt(double d) { return cbrt(d); }
- static const JSCFunctionListEntry js_math_funcs[] = {
- JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
- JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
- JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, js_math_fabs ),
- JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, js_math_floor ),
- JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, js_math_ceil ),
- JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
- JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, js_math_sqrt ),
- JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, js_math_acos ),
- JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, js_math_asin ),
- JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, js_math_atan ),
- JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, js_math_atan2 ),
- JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, js_math_cos ),
- JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, js_math_exp ),
- JS_CFUNC_SPECIAL_DEF("log", 1, f_f, js_math_log ),
- JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_math_pow ),
- JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, js_math_sin ),
- JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, js_math_tan ),
- /* ES6 */
- JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, js_math_trunc ),
- JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign ),
- JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, js_math_cosh ),
- JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, js_math_sinh ),
- JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, js_math_tanh ),
- JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, js_math_acosh ),
- JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, js_math_asinh ),
- JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, js_math_atanh ),
- JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, js_math_expm1 ),
- JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, js_math_log1p ),
- JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, js_math_log2 ),
- JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, js_math_log10 ),
- JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, js_math_cbrt ),
- JS_CFUNC_DEF("hypot", 2, js_math_hypot ),
- JS_CFUNC_DEF("random", 0, js_math_random ),
- JS_CFUNC_SPECIAL_DEF("f16round", 1, f_f, js_math_f16round ),
- JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ),
- JS_CFUNC_DEF("imul", 2, js_math_imul ),
- JS_CFUNC_DEF("clz32", 1, js_math_clz32 ),
- JS_CFUNC_DEF("sumPrecise", 1, js_math_sumPrecise ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Math", JS_PROP_CONFIGURABLE ),
- JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0 ),
- JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0 ),
- JS_PROP_DOUBLE_DEF("LN2", 0.6931471805599453, 0 ),
- JS_PROP_DOUBLE_DEF("LOG2E", 1.4426950408889634, 0 ),
- JS_PROP_DOUBLE_DEF("LOG10E", 0.4342944819032518, 0 ),
- JS_PROP_DOUBLE_DEF("PI", 3.141592653589793, 0 ),
- JS_PROP_DOUBLE_DEF("SQRT1_2", 0.7071067811865476, 0 ),
- JS_PROP_DOUBLE_DEF("SQRT2", 1.4142135623730951, 0 ),
- };
- static const JSCFunctionListEntry js_math_obj[] = {
- JS_OBJECT_DEF("Math", js_math_funcs, countof(js_math_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
- };
- /* Date */
- /* OS dependent. d = argv[0] is in ms from 1970. Return the difference
- between UTC time and local time 'd' in minutes */
- static int getTimezoneOffset(int64_t time) {
- #if defined(_WIN32)
- DWORD r;
- TIME_ZONE_INFORMATION t;
- r = GetTimeZoneInformation(&t);
- if (r == TIME_ZONE_ID_INVALID)
- return 0;
- if (r == TIME_ZONE_ID_DAYLIGHT)
- return (int)(t.Bias + t.DaylightBias);
- return (int)t.Bias;
- #else
- time_t ti;
- struct tm tm;
- time /= 1000; /* convert to seconds */
- if (sizeof(time_t) == 4) {
- /* on 32-bit systems, we need to clamp the time value to the
- range of `time_t`. This is better than truncating values to
- 32 bits and hopefully provides the same result as 64-bit
- implementation of localtime_r.
- */
- if ((time_t)-1 < 0) {
- if (time < INT32_MIN) {
- time = INT32_MIN;
- } else if (time > INT32_MAX) {
- time = INT32_MAX;
- }
- } else {
- if (time < 0) {
- time = 0;
- } else if (time > UINT32_MAX) {
- time = UINT32_MAX;
- }
- }
- }
- ti = time;
- localtime_r(&ti, &tm);
- #ifdef NO_TM_GMTOFF
- struct tm gmt;
- gmtime_r(&ti, &gmt);
- /* disable DST adjustment on the local tm struct */
- tm.tm_isdst = 0;
- return (int)difftime(mktime(&gmt), mktime(&tm)) / 60;
- #else
- return -tm.tm_gmtoff / 60;
- #endif /* NO_TM_GMTOFF */
- #endif
- }
- /* RegExp */
- static void js_regexp_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSRegExp *re = &p->u.regexp;
- JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->bytecode));
- JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->pattern));
- }
- /* create a string containing the RegExp bytecode */
- static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
- JSValueConst flags)
- {
- const char *str;
- int re_flags, mask;
- uint8_t *re_bytecode_buf;
- size_t i, len;
- int re_bytecode_len;
- JSValue ret;
- char error_msg[64];
- re_flags = 0;
- if (!JS_IsUndefined(flags)) {
- str = JS_ToCStringLen(ctx, &len, flags);
- if (!str)
- return JS_EXCEPTION;
- /* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */
- for (i = 0; i < len; i++) {
- switch(str[i]) {
- case 'd':
- mask = LRE_FLAG_INDICES;
- break;
- case 'g':
- mask = LRE_FLAG_GLOBAL;
- break;
- case 'i':
- mask = LRE_FLAG_IGNORECASE;
- break;
- case 'm':
- mask = LRE_FLAG_MULTILINE;
- break;
- case 's':
- mask = LRE_FLAG_DOTALL;
- break;
- case 'u':
- mask = LRE_FLAG_UNICODE;
- break;
- case 'v':
- mask = LRE_FLAG_UNICODE_SETS;
- break;
- case 'y':
- mask = LRE_FLAG_STICKY;
- break;
- default:
- goto bad_flags;
- }
- if ((re_flags & mask) != 0) {
- bad_flags:
- JS_FreeCString(ctx, str);
- return JS_ThrowSyntaxError(ctx, "invalid regular expression flags");
- }
- re_flags |= mask;
- }
- JS_FreeCString(ctx, str);
- }
- if (re_flags & LRE_FLAG_UNICODE)
- if (re_flags & LRE_FLAG_UNICODE_SETS)
- return JS_ThrowSyntaxError(ctx, "invalid regular expression flags");
- str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & LRE_FLAG_UNICODE));
- if (!str)
- return JS_EXCEPTION;
- re_bytecode_buf = lre_compile(&re_bytecode_len, error_msg,
- sizeof(error_msg), str, len, re_flags, ctx);
- JS_FreeCString(ctx, str);
- if (!re_bytecode_buf) {
- JS_ThrowSyntaxError(ctx, "%s", error_msg);
- return JS_EXCEPTION;
- }
- ret = js_new_string8_len(ctx, (char *)re_bytecode_buf, re_bytecode_len);
- js_free(ctx, re_bytecode_buf);
- return ret;
- }
- /* create a RegExp object from a string containing the RegExp bytecode
- and the source pattern */
- static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
- JSValue pattern, JSValue bc)
- {
- JSValue obj;
- JSObject *p;
- JSRegExp *re;
- /* sanity check */
- if (JS_VALUE_GET_TAG(bc) != JS_TAG_STRING ||
- JS_VALUE_GET_TAG(pattern) != JS_TAG_STRING) {
- JS_ThrowTypeError(ctx, "string expected");
- fail:
- JS_FreeValue(ctx, bc);
- JS_FreeValue(ctx, pattern);
- return JS_EXCEPTION;
- }
- obj = js_create_from_ctor(ctx, ctor, JS_CLASS_REGEXP);
- if (JS_IsException(obj))
- goto fail;
- p = JS_VALUE_GET_OBJ(obj);
- re = &p->u.regexp;
- re->pattern = JS_VALUE_GET_STRING(pattern);
- re->bytecode = JS_VALUE_GET_STRING(bc);
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_lastIndex, js_int32(0),
- JS_PROP_WRITABLE);
- return obj;
- }
- static JSRegExp *js_get_regexp(JSContext *ctx, JSValueConst obj,
- bool throw_error)
- {
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- if (p->class_id == JS_CLASS_REGEXP)
- return &p->u.regexp;
- }
- if (throw_error) {
- JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
- }
- return NULL;
- }
- /* return < 0 if exception or true/false */
- static int js_is_regexp(JSContext *ctx, JSValueConst obj)
- {
- JSValue m;
- if (!JS_IsObject(obj))
- return false;
- m = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_match);
- if (JS_IsException(m))
- return -1;
- if (!JS_IsUndefined(m))
- return JS_ToBoolFree(ctx, m);
- return js_get_regexp(ctx, obj, false) != NULL;
- }
- static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- JSValue pattern, flags, bc, val;
- JSValueConst pat, flags1;
- JSRegExp *re;
- int pat_is_regexp;
- pat = argv[0];
- flags1 = argv[1];
- pat_is_regexp = js_is_regexp(ctx, pat);
- if (pat_is_regexp < 0)
- return JS_EXCEPTION;
- if (JS_IsUndefined(new_target)) {
- /* called as a function */
- new_target = JS_GetActiveFunction(ctx);
- if (pat_is_regexp && JS_IsUndefined(flags1)) {
- JSValue ctor;
- bool res;
- ctor = JS_GetProperty(ctx, pat, JS_ATOM_constructor);
- if (JS_IsException(ctor))
- return ctor;
- res = js_same_value(ctx, ctor, new_target);
- JS_FreeValue(ctx, ctor);
- if (res)
- return js_dup(pat);
- }
- }
- re = js_get_regexp(ctx, pat, false);
- if (re) {
- pattern = js_dup(JS_MKPTR(JS_TAG_STRING, re->pattern));
- if (JS_IsUndefined(flags1)) {
- bc = js_dup(JS_MKPTR(JS_TAG_STRING, re->bytecode));
- goto no_compilation;
- } else {
- flags = JS_ToString(ctx, flags1);
- if (JS_IsException(flags))
- goto fail;
- }
- } else {
- flags = JS_UNDEFINED;
- if (pat_is_regexp) {
- pattern = JS_GetProperty(ctx, pat, JS_ATOM_source);
- if (JS_IsException(pattern))
- goto fail;
- if (JS_IsUndefined(flags1)) {
- flags = JS_GetProperty(ctx, pat, JS_ATOM_flags);
- if (JS_IsException(flags))
- goto fail;
- } else {
- flags = js_dup(flags1);
- }
- } else {
- pattern = js_dup(pat);
- flags = js_dup(flags1);
- }
- if (JS_IsUndefined(pattern)) {
- pattern = js_empty_string(ctx->rt);
- } else {
- val = pattern;
- pattern = JS_ToString(ctx, val);
- JS_FreeValue(ctx, val);
- if (JS_IsException(pattern))
- goto fail;
- }
- }
- bc = js_compile_regexp(ctx, pattern, flags);
- if (JS_IsException(bc))
- goto fail;
- JS_FreeValue(ctx, flags);
- no_compilation:
- return js_regexp_constructor_internal(ctx, new_target, pattern, bc);
- fail:
- JS_FreeValue(ctx, pattern);
- JS_FreeValue(ctx, flags);
- return JS_EXCEPTION;
- }
- static JSValue js_regexp_compile(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRegExp *re1, *re;
- JSValueConst pattern1, flags1;
- JSValue bc, pattern;
- re = js_get_regexp(ctx, this_val, true);
- if (!re)
- return JS_EXCEPTION;
- pattern1 = argv[0];
- flags1 = argv[1];
- re1 = js_get_regexp(ctx, pattern1, false);
- if (re1) {
- if (!JS_IsUndefined(flags1))
- return JS_ThrowTypeError(ctx, "flags must be undefined");
- pattern = js_dup(JS_MKPTR(JS_TAG_STRING, re1->pattern));
- bc = js_dup(JS_MKPTR(JS_TAG_STRING, re1->bytecode));
- } else {
- bc = JS_UNDEFINED;
- if (JS_IsUndefined(pattern1))
- pattern = js_empty_string(ctx->rt);
- else
- pattern = JS_ToString(ctx, pattern1);
- if (JS_IsException(pattern))
- goto fail;
- bc = js_compile_regexp(ctx, pattern, flags1);
- if (JS_IsException(bc))
- goto fail;
- }
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
- re->pattern = JS_VALUE_GET_STRING(pattern);
- re->bytecode = JS_VALUE_GET_STRING(bc);
- if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
- js_int32(0)) < 0)
- return JS_EXCEPTION;
- return js_dup(this_val);
- fail:
- JS_FreeValue(ctx, pattern);
- JS_FreeValue(ctx, bc);
- return JS_EXCEPTION;
- }
- static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val)
- {
- JSRegExp *re;
- JSString *p;
- StringBuffer b_s, *b = &b_s;
- int i, n, c, c2, bra;
- if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
- goto empty_regex;
- re = js_get_regexp(ctx, this_val, true);
- if (!re)
- return JS_EXCEPTION;
- p = re->pattern;
- if (p->len == 0) {
- empty_regex:
- return js_new_string8(ctx, "(?:)");
- }
- string_buffer_init2(ctx, b, p->len, p->is_wide_char);
- /* Escape '/' and newline sequences as needed */
- bra = 0;
- for (i = 0, n = p->len; i < n;) {
- c2 = -1;
- switch (c = string_get(p, i++)) {
- case '\\':
- if (i < n)
- c2 = string_get(p, i++);
- break;
- case ']':
- bra = 0;
- break;
- case '[':
- if (!bra) {
- if (i < n && string_get(p, i) == ']')
- c2 = string_get(p, i++);
- bra = 1;
- }
- break;
- case '\n':
- c = '\\';
- c2 = 'n';
- break;
- case '\r':
- c = '\\';
- c2 = 'r';
- break;
- case '/':
- if (!bra) {
- c = '\\';
- c2 = '/';
- }
- break;
- }
- string_buffer_putc16(b, c);
- if (c2 >= 0)
- string_buffer_putc16(b, c2);
- }
- return string_buffer_end(b);
- }
- static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mask)
- {
- JSRegExp *re;
- int flags;
- if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- re = js_get_regexp(ctx, this_val, false);
- if (!re) {
- if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
- return JS_UNDEFINED;
- else
- return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
- }
- flags = lre_get_flags(str8(re->bytecode));
- return js_bool(flags & mask);
- }
- static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val)
- {
- char str[8], *p = str;
- int res;
- if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "hasIndices"));
- if (res < 0)
- goto exception;
- if (res)
- *p++ = 'd';
- res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_global));
- if (res < 0)
- goto exception;
- if (res)
- *p++ = 'g';
- res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "ignoreCase"));
- if (res < 0)
- goto exception;
- if (res)
- *p++ = 'i';
- res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "multiline"));
- if (res < 0)
- goto exception;
- if (res)
- *p++ = 'm';
- res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "dotAll"));
- if (res < 0)
- goto exception;
- if (res)
- *p++ = 's';
- res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_unicode));
- if (res < 0)
- goto exception;
- if (res)
- *p++ = 'u';
- res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "unicodeSets"));
- if (res < 0)
- goto exception;
- if (res)
- *p++ = 'v';
- res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "sticky"));
- if (res < 0)
- goto exception;
- if (res)
- *p++ = 'y';
- if (p == str)
- return js_empty_string(ctx->rt);
- return js_new_string8_len(ctx, str, p - str);
- exception:
- return JS_EXCEPTION;
- }
- static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue pattern, flags;
- StringBuffer b_s, *b = &b_s;
- if (!JS_IsObject(this_val))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- string_buffer_init(ctx, b, 0);
- string_buffer_putc8(b, '/');
- pattern = JS_GetProperty(ctx, this_val, JS_ATOM_source);
- if (string_buffer_concat_value_free(b, pattern))
- goto fail;
- string_buffer_putc8(b, '/');
- flags = JS_GetProperty(ctx, this_val, JS_ATOM_flags);
- if (string_buffer_concat_value_free(b, flags))
- goto fail;
- return string_buffer_end(b);
- fail:
- string_buffer_free(b);
- return JS_EXCEPTION;
- }
- bool lre_check_stack_overflow(void *opaque, size_t alloca_size)
- {
- JSContext *ctx = opaque;
- return js_check_stack_overflow(ctx->rt, alloca_size);
- }
- int lre_check_timeout(void *opaque)
- {
- JSContext *ctx = opaque;
- JSRuntime *rt = ctx->rt;
- return (rt->interrupt_handler &&
- rt->interrupt_handler(rt, rt->interrupt_opaque));
- }
- void *lre_realloc(void *opaque, void *ptr, size_t size)
- {
- JSContext *ctx = opaque;
- /* No JS exception is raised here */
- return js_realloc_rt(ctx->rt, ptr, size);
- }
- static JSValue js_regexp_escape(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- StringBuffer b_s, *b = &b_s;
- JSString *p;
- uint32_t c, i;
- char s[16];
- if (!JS_IsString(argv[0]))
- return JS_ThrowTypeError(ctx, "not a string");
- p = JS_VALUE_GET_STRING(argv[0]);
- string_buffer_init2(ctx, b, 0, p->is_wide_char);
- for (i = 0; i < p->len; i++) {
- c = p->is_wide_char ? (uint32_t)str16(p)[i] : (uint32_t)str8(p)[i];
- if (c < 33) {
- if (c >= 9 && c <= 13) {
- string_buffer_putc8(b, '\\');
- string_buffer_putc8(b, "tnvfr"[c - 9]);
- } else {
- goto hex2;
- }
- } else if (c < 128) {
- if ((c >= '0' && c <= '9')
- || (c >= 'A' && c <= 'Z')
- || (c >= 'a' && c <= 'z')) {
- if (i == 0)
- goto hex2;
- } else if (strchr(",-=<>#&!%:;@~'`\"", c)) {
- goto hex2;
- } else if (c != '_') {
- string_buffer_putc8(b, '\\');
- }
- string_buffer_putc8(b, c);
- } else if (c < 256) {
- hex2:
- snprintf(s, sizeof(s), "\\x%02x", c);
- string_buffer_puts8(b, s);
- } else if (is_surrogate(c) || lre_is_white_space(c) || c == 0xFEFF) {
- snprintf(s, sizeof(s), "\\u%04x", c);
- string_buffer_puts8(b, s);
- } else {
- string_buffer_putc16(b, c);
- }
- }
- return string_buffer_end(b);
- }
- static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRegExp *re = js_get_regexp(ctx, this_val, true);
- JSString *str;
- JSValue t, ret, str_val, obj, val, groups;
- JSValue indices, indices_groups;
- uint8_t *re_bytecode;
- uint8_t **capture, *str_buf;
- int rc, capture_count, shift, i, re_flags;
- int64_t last_index;
- const char *group_name_ptr;
- if (!re)
- return JS_EXCEPTION;
- str_val = JS_ToString(ctx, argv[0]);
- if (JS_IsException(str_val))
- return JS_EXCEPTION;
- ret = JS_EXCEPTION;
- obj = JS_NULL;
- groups = JS_UNDEFINED;
- indices = JS_UNDEFINED;
- indices_groups = JS_UNDEFINED;
- capture = NULL;
- val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
- if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
- goto fail;
- re_bytecode = str8(re->bytecode);
- re_flags = lre_get_flags(re_bytecode);
- if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
- last_index = 0;
- }
- str = JS_VALUE_GET_STRING(str_val);
- capture_count = lre_get_capture_count(re_bytecode);
- if (capture_count > 0) {
- capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
- if (!capture)
- goto fail;
- }
- shift = str->is_wide_char;
- str_buf = str8(str);
- if (last_index > str->len) {
- rc = 2;
- } else {
- rc = lre_exec(capture, re_bytecode,
- str_buf, last_index, str->len,
- shift, ctx);
- }
- if (rc != 1) {
- if (rc >= 0) {
- if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
- if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
- js_int32(0)) < 0)
- goto fail;
- }
- } else {
- if (rc == LRE_RET_TIMEOUT) {
- JS_ThrowInterrupted(ctx);
- } else {
- JS_ThrowInternalError(ctx, "out of memory in regexp execution");
- }
- goto fail;
- }
- } else {
- int prop_flags;
- if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
- if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
- js_int32((capture[1] - str_buf) >> shift)) < 0)
- goto fail;
- }
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj))
- goto fail;
- prop_flags = JS_PROP_C_W_E | JS_PROP_THROW;
- group_name_ptr = lre_get_groupnames(re_bytecode);
- if (group_name_ptr) {
- groups = JS_NewObjectProto(ctx, JS_NULL);
- if (JS_IsException(groups))
- goto fail;
- }
- if (re_flags & LRE_FLAG_INDICES) {
- indices = JS_NewArray(ctx);
- if (JS_IsException(indices))
- goto fail;
- if (group_name_ptr) {
- indices_groups = JS_NewObjectProto(ctx, JS_NULL);
- if (JS_IsException(indices_groups))
- goto fail;
- }
- }
- for(i = 0; i < capture_count; i++) {
- const char *name = NULL;
- uint8_t **match = &capture[2 * i];
- int start = -1;
- int end = -1;
- if (group_name_ptr && i > 0) {
- if (*group_name_ptr) name = group_name_ptr;
- group_name_ptr += strlen(group_name_ptr) + 1;
- }
- if (match[0] && match[1]) {
- start = (match[0] - str_buf) >> shift;
- end = (match[1] - str_buf) >> shift;
- }
- if (!JS_IsUndefined(indices)) {
- JSValue val = JS_UNDEFINED;
- if (start != -1) {
- val = JS_NewArray(ctx);
- if (JS_IsException(val))
- goto fail;
- if (JS_DefinePropertyValueUint32(ctx, val, 0,
- js_int32(start),
- prop_flags) < 0) {
- JS_FreeValue(ctx, val);
- goto fail;
- }
- if (JS_DefinePropertyValueUint32(ctx, val, 1,
- js_int32(end),
- prop_flags) < 0) {
- JS_FreeValue(ctx, val);
- goto fail;
- }
- }
- if (name && !JS_IsUndefined(indices_groups)) {
- val = js_dup(val);
- if (JS_DefinePropertyValueStr(ctx, indices_groups,
- name, val, prop_flags) < 0) {
- JS_FreeValue(ctx, val);
- goto fail;
- }
- }
- if (JS_DefinePropertyValueUint32(ctx, indices, i, val,
- prop_flags) < 0) {
- goto fail;
- }
- }
- JSValue val = JS_UNDEFINED;
- if (start != -1) {
- val = js_sub_string(ctx, str, start, end);
- if (JS_IsException(val))
- goto fail;
- }
- if (name) {
- if (JS_DefinePropertyValueStr(ctx, groups, name,
- js_dup(val),
- prop_flags) < 0) {
- JS_FreeValue(ctx, val);
- goto fail;
- }
- }
- if (JS_DefinePropertyValueUint32(ctx, obj, i, val, prop_flags) < 0)
- goto fail;
- }
- t = groups, groups = JS_UNDEFINED;
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups,
- t, prop_flags) < 0) {
- goto fail;
- }
- t = js_int32((capture[0] - str_buf) >> shift);
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index, t, prop_flags) < 0)
- goto fail;
- t = str_val, str_val = JS_UNDEFINED;
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, t, prop_flags) < 0)
- goto fail;
- if (!JS_IsUndefined(indices)) {
- t = indices_groups, indices_groups = JS_UNDEFINED;
- if (JS_DefinePropertyValue(ctx, indices, JS_ATOM_groups,
- t, prop_flags) < 0) {
- goto fail;
- }
- t = indices, indices = JS_UNDEFINED;
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_indices,
- t, prop_flags) < 0) {
- goto fail;
- }
- }
- }
- ret = obj;
- obj = JS_UNDEFINED;
- fail:
- JS_FreeValue(ctx, indices_groups);
- JS_FreeValue(ctx, indices);
- JS_FreeValue(ctx, str_val);
- JS_FreeValue(ctx, groups);
- JS_FreeValue(ctx, obj);
- js_free(ctx, capture);
- return ret;
- }
- /* delete portions of a string that match a given regex */
- static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValue arg)
- {
- JSRegExp *re = js_get_regexp(ctx, this_val, true);
- JSString *str;
- JSValue str_val, val;
- uint8_t *re_bytecode;
- int ret;
- uint8_t **capture, *str_buf;
- int capture_count, shift, re_flags;
- int next_src_pos, start, end;
- int64_t last_index;
- StringBuffer b_s, *b = &b_s;
- if (!re)
- return JS_EXCEPTION;
- string_buffer_init(ctx, b, 0);
- capture = NULL;
- str_val = JS_ToString(ctx, arg);
- if (JS_IsException(str_val))
- goto fail;
- str = JS_VALUE_GET_STRING(str_val);
- re_bytecode = str8(re->bytecode);
- re_flags = lre_get_flags(re_bytecode);
- if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
- last_index = 0;
- } else {
- val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
- if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
- goto fail;
- }
- capture_count = lre_get_capture_count(re_bytecode);
- if (capture_count > 0) {
- capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
- if (!capture)
- goto fail;
- }
- shift = str->is_wide_char;
- str_buf = str8(str);
- next_src_pos = 0;
- for (;;) {
- if (last_index > str->len)
- break;
- ret = lre_exec(capture, re_bytecode,
- str_buf, last_index, str->len, shift, ctx);
- if (ret != 1) {
- if (ret >= 0) {
- if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
- if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
- js_int32(0)) < 0)
- goto fail;
- }
- } else {
- if (ret == LRE_RET_TIMEOUT) {
- JS_ThrowInterrupted(ctx);
- } else {
- JS_ThrowInternalError(ctx, "out of memory in regexp execution");
- }
- goto fail;
- }
- break;
- }
- start = (capture[0] - str_buf) >> shift;
- end = (capture[1] - str_buf) >> shift;
- last_index = end;
- if (next_src_pos < start) {
- if (string_buffer_concat(b, str, next_src_pos, start))
- goto fail;
- }
- next_src_pos = end;
- if (!(re_flags & LRE_FLAG_GLOBAL)) {
- if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
- js_int32(end)) < 0)
- goto fail;
- break;
- }
- if (end == start) {
- if (!(re_flags & LRE_FLAG_UNICODE) || (unsigned)end >= str->len || !str->is_wide_char) {
- end++;
- } else {
- string_getc(str, &end);
- }
- }
- last_index = end;
- }
- if (string_buffer_concat(b, str, next_src_pos, str->len))
- goto fail;
- JS_FreeValue(ctx, str_val);
- js_free(ctx, capture);
- return string_buffer_end(b);
- fail:
- JS_FreeValue(ctx, str_val);
- js_free(ctx, capture);
- string_buffer_free(b);
- return JS_EXCEPTION;
- }
- static JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s)
- {
- JSValue method, ret;
- method = JS_GetProperty(ctx, r, JS_ATOM_exec);
- if (JS_IsException(method))
- return method;
- if (JS_IsFunction(ctx, method)) {
- ret = JS_CallFree(ctx, method, r, 1, &s);
- if (JS_IsException(ret))
- return ret;
- if (!JS_IsObject(ret) && !JS_IsNull(ret)) {
- JS_FreeValue(ctx, ret);
- return JS_ThrowTypeError(ctx, "RegExp exec method must return an object or null");
- }
- return ret;
- }
- JS_FreeValue(ctx, method);
- return js_regexp_exec(ctx, r, 1, &s);
- }
- static JSValue js_regexp_test(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val;
- bool ret;
- val = JS_RegExpExec(ctx, this_val, argv[0]);
- if (JS_IsException(val))
- return JS_EXCEPTION;
- ret = !JS_IsNull(val);
- JS_FreeValue(ctx, val);
- return js_bool(ret);
- }
- static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // [Symbol.match](str)
- JSValueConst rx = this_val;
- JSValue A, S, flags, result, matchStr;
- int global, n, fullUnicode, isEmpty;
- JSString *p;
- if (!JS_IsObject(rx))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- A = JS_UNDEFINED;
- flags = JS_UNDEFINED;
- result = JS_UNDEFINED;
- matchStr = JS_UNDEFINED;
- S = JS_ToString(ctx, argv[0]);
- if (JS_IsException(S))
- goto exception;
- flags = JS_GetProperty(ctx, rx, JS_ATOM_flags);
- if (JS_IsException(flags))
- goto exception;
- flags = JS_ToStringFree(ctx, flags);
- if (JS_IsException(flags))
- goto exception;
- p = JS_VALUE_GET_STRING(flags);
- // TODO(bnoordhuis) query 'u' flag the same way?
- global = (-1 != string_indexof_char(p, 'g', 0));
- if (!global) {
- A = JS_RegExpExec(ctx, rx, S);
- } else {
- fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
- if (fullUnicode < 0)
- goto exception;
- if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, js_int32(0)) < 0)
- goto exception;
- A = JS_NewArray(ctx);
- if (JS_IsException(A))
- goto exception;
- n = 0;
- for(;;) {
- JS_FreeValue(ctx, result);
- result = JS_RegExpExec(ctx, rx, S);
- if (JS_IsException(result))
- goto exception;
- if (JS_IsNull(result))
- break;
- matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
- if (JS_IsException(matchStr))
- goto exception;
- isEmpty = JS_IsEmptyString(matchStr);
- if (JS_SetPropertyInt64(ctx, A, n++, matchStr) < 0)
- goto exception;
- if (isEmpty) {
- int64_t thisIndex, nextIndex;
- if (JS_ToLengthFree(ctx, &thisIndex,
- JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
- goto exception;
- p = JS_VALUE_GET_STRING(S);
- nextIndex = string_advance_index(p, thisIndex, fullUnicode);
- if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, js_int64(nextIndex)) < 0)
- goto exception;
- }
- }
- if (n == 0) {
- JS_FreeValue(ctx, A);
- A = JS_NULL;
- }
- }
- JS_FreeValue(ctx, result);
- JS_FreeValue(ctx, flags);
- JS_FreeValue(ctx, S);
- return A;
- exception:
- JS_FreeValue(ctx, A);
- JS_FreeValue(ctx, result);
- JS_FreeValue(ctx, flags);
- JS_FreeValue(ctx, S);
- return JS_EXCEPTION;
- }
- typedef struct JSRegExpStringIteratorData {
- JSValue iterating_regexp;
- JSValue iterated_string;
- bool global;
- bool unicode;
- int done;
- } JSRegExpStringIteratorData;
- static void js_regexp_string_iterator_finalizer(JSRuntime *rt,
- JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
- if (it) {
- JS_FreeValueRT(rt, it->iterating_regexp);
- JS_FreeValueRT(rt, it->iterated_string);
- js_free_rt(rt, it);
- }
- }
- static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
- if (it) {
- JS_MarkValue(rt, it->iterating_regexp, mark_func);
- JS_MarkValue(rt, it->iterated_string, mark_func);
- }
- }
- static JSValue js_regexp_string_iterator_next(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv,
- int *pdone, int magic)
- {
- JSRegExpStringIteratorData *it;
- JSValue R, S;
- JSValue matchStr = JS_UNDEFINED, match = JS_UNDEFINED;
- JSString *sp;
- it = JS_GetOpaque2(ctx, this_val, JS_CLASS_REGEXP_STRING_ITERATOR);
- if (!it)
- goto exception;
- if (it->done) {
- *pdone = true;
- return JS_UNDEFINED;
- }
- R = it->iterating_regexp;
- S = it->iterated_string;
- match = JS_RegExpExec(ctx, R, S);
- if (JS_IsException(match))
- goto exception;
- if (JS_IsNull(match)) {
- it->done = true;
- *pdone = true;
- return JS_UNDEFINED;
- } else if (it->global) {
- matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, match, 0));
- if (JS_IsException(matchStr))
- goto exception;
- if (JS_IsEmptyString(matchStr)) {
- int64_t thisIndex, nextIndex;
- if (JS_ToLengthFree(ctx, &thisIndex,
- JS_GetProperty(ctx, R, JS_ATOM_lastIndex)) < 0)
- goto exception;
- sp = JS_VALUE_GET_STRING(S);
- nextIndex = string_advance_index(sp, thisIndex, it->unicode);
- if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex, js_int64(nextIndex)) < 0)
- goto exception;
- }
- JS_FreeValue(ctx, matchStr);
- } else {
- it->done = true;
- }
- *pdone = false;
- return match;
- exception:
- JS_FreeValue(ctx, match);
- JS_FreeValue(ctx, matchStr);
- *pdone = false;
- return JS_EXCEPTION;
- }
- static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // [Symbol.matchAll](str)
- JSValueConst R = this_val;
- JSValue S, C, flags, matcher, iter;
- JSValueConst args[2];
- JSString *strp;
- int64_t lastIndex;
- JSRegExpStringIteratorData *it;
- if (!JS_IsObject(R))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- C = JS_UNDEFINED;
- flags = JS_UNDEFINED;
- matcher = JS_UNDEFINED;
- iter = JS_UNDEFINED;
- S = JS_ToString(ctx, argv[0]);
- if (JS_IsException(S))
- goto exception;
- C = JS_SpeciesConstructor(ctx, R, ctx->regexp_ctor);
- if (JS_IsException(C))
- goto exception;
- flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, R, JS_ATOM_flags));
- if (JS_IsException(flags))
- goto exception;
- args[0] = R;
- args[1] = flags;
- matcher = JS_CallConstructor(ctx, C, 2, args);
- if (JS_IsException(matcher))
- goto exception;
- if (JS_ToLengthFree(ctx, &lastIndex,
- JS_GetProperty(ctx, R, JS_ATOM_lastIndex)))
- goto exception;
- if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex, js_int64(lastIndex)) < 0)
- goto exception;
- iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR);
- if (JS_IsException(iter))
- goto exception;
- it = js_malloc(ctx, sizeof(*it));
- if (!it)
- goto exception;
- it->iterating_regexp = matcher;
- it->iterated_string = S;
- strp = JS_VALUE_GET_STRING(flags);
- it->global = string_indexof_char(strp, 'g', 0) >= 0;
- it->unicode = string_indexof_char(strp, 'u', 0) >= 0;
- it->done = false;
- JS_SetOpaqueInternal(iter, it);
- JS_FreeValue(ctx, C);
- JS_FreeValue(ctx, flags);
- return iter;
- exception:
- JS_FreeValue(ctx, S);
- JS_FreeValue(ctx, C);
- JS_FreeValue(ctx, flags);
- JS_FreeValue(ctx, matcher);
- JS_FreeValue(ctx, iter);
- return JS_EXCEPTION;
- }
- typedef struct ValueBuffer {
- JSContext *ctx;
- JSValue *arr;
- JSValue def[4];
- int len;
- int size;
- int error_status;
- } ValueBuffer;
- static int value_buffer_init(JSContext *ctx, ValueBuffer *b)
- {
- b->ctx = ctx;
- b->len = 0;
- b->size = 4;
- b->error_status = 0;
- b->arr = b->def;
- return 0;
- }
- static void value_buffer_free(ValueBuffer *b)
- {
- while (b->len > 0)
- JS_FreeValue(b->ctx, b->arr[--b->len]);
- if (b->arr != b->def)
- js_free(b->ctx, b->arr);
- b->arr = b->def;
- b->size = 4;
- }
- static int value_buffer_append(ValueBuffer *b, JSValue val)
- {
- if (b->error_status)
- return -1;
- if (b->len >= b->size) {
- int new_size = (b->len + (b->len >> 1) + 31) & ~16;
- size_t slack;
- JSValue *new_arr;
- if (b->arr == b->def) {
- new_arr = js_realloc2(b->ctx, NULL, sizeof(*b->arr) * new_size, &slack);
- if (new_arr)
- memcpy(new_arr, b->def, sizeof b->def);
- } else {
- new_arr = js_realloc2(b->ctx, b->arr, sizeof(*b->arr) * new_size, &slack);
- }
- if (!new_arr) {
- value_buffer_free(b);
- JS_FreeValue(b->ctx, val);
- b->error_status = -1;
- return -1;
- }
- new_size += slack / sizeof(*new_arr);
- b->arr = new_arr;
- b->size = new_size;
- }
- b->arr[b->len++] = val;
- return 0;
- }
- static int js_is_standard_regexp(JSContext *ctx, JSValueConst rx)
- {
- JSValue val;
- int res;
- val = JS_GetProperty(ctx, rx, JS_ATOM_constructor);
- if (JS_IsException(val))
- return -1;
- // rx.constructor === RegExp
- res = js_same_value(ctx, val, ctx->regexp_ctor);
- JS_FreeValue(ctx, val);
- if (res) {
- val = JS_GetProperty(ctx, rx, JS_ATOM_exec);
- if (JS_IsException(val))
- return -1;
- // rx.exec === RE_exec
- res = JS_IsCFunction(ctx, val, js_regexp_exec, 0);
- JS_FreeValue(ctx, val);
- }
- return res;
- }
- static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // [Symbol.replace](str, rep)
- JSValueConst rx = this_val, rep = argv[1];
- JSValueConst args[6];
- JSValue flags, str, rep_val, matched, tab, rep_str, namedCaptures, res;
- JSString *p, *sp, *rp;
- StringBuffer b_s, *b = &b_s;
- ValueBuffer v_b, *results = &v_b;
- int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode;
- uint32_t nCaptures;
- int64_t position;
- if (!JS_IsObject(rx))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- string_buffer_init(ctx, b, 0);
- value_buffer_init(ctx, results);
- rep_val = JS_UNDEFINED;
- matched = JS_UNDEFINED;
- tab = JS_UNDEFINED;
- flags = JS_UNDEFINED;
- rep_str = JS_UNDEFINED;
- namedCaptures = JS_UNDEFINED;
- str = JS_ToString(ctx, argv[0]);
- if (JS_IsException(str))
- goto exception;
- sp = JS_VALUE_GET_STRING(str);
- rp = NULL;
- functionalReplace = JS_IsFunction(ctx, rep);
- if (!functionalReplace) {
- rep_val = JS_ToString(ctx, rep);
- if (JS_IsException(rep_val))
- goto exception;
- rp = JS_VALUE_GET_STRING(rep_val);
- }
- flags = JS_GetProperty(ctx, rx, JS_ATOM_flags);
- if (JS_IsException(flags))
- goto exception;
- flags = JS_ToStringFree(ctx, flags);
- if (JS_IsException(flags))
- goto exception;
- p = JS_VALUE_GET_STRING(flags);
- // TODO(bnoordhuis) query 'u' flag the same way?
- fullUnicode = 0;
- is_global = (-1 != string_indexof_char(p, 'g', 0));
- if (is_global) {
- fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
- if (fullUnicode < 0)
- goto exception;
- if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, js_int32(0)) < 0)
- goto exception;
- }
- if (rp && rp->len == 0 && is_global && js_is_standard_regexp(ctx, rx)) {
- /* use faster version for simple cases */
- res = JS_RegExpDelete(ctx, rx, str);
- goto done;
- }
- for(;;) {
- JSValue result;
- result = JS_RegExpExec(ctx, rx, str);
- if (JS_IsException(result))
- goto exception;
- if (JS_IsNull(result))
- break;
- if (value_buffer_append(results, result) < 0)
- goto exception;
- if (!is_global)
- break;
- JS_FreeValue(ctx, matched);
- matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
- if (JS_IsException(matched))
- goto exception;
- if (JS_IsEmptyString(matched)) {
- /* always advance of at least one char */
- int64_t thisIndex, nextIndex;
- if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
- goto exception;
- nextIndex = string_advance_index(sp, thisIndex, fullUnicode);
- if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, js_int64(nextIndex)) < 0)
- goto exception;
- }
- }
- nextSourcePosition = 0;
- for(j = 0; j < results->len; j++) {
- JSValue result;
- result = results->arr[j];
- if (js_get_length32(ctx, &nCaptures, result) < 0)
- goto exception;
- JS_FreeValue(ctx, matched);
- matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
- if (JS_IsException(matched))
- goto exception;
- if (JS_ToLengthFree(ctx, &position, JS_GetProperty(ctx, result, JS_ATOM_index)))
- goto exception;
- if (position > sp->len)
- position = sp->len;
- else if (position < 0)
- position = 0;
- /* ignore substition if going backward (can happen
- with custom regexp object) */
- JS_FreeValue(ctx, tab);
- tab = JS_NewArray(ctx);
- if (JS_IsException(tab))
- goto exception;
- if (JS_DefinePropertyValueInt64(ctx, tab, 0, js_dup(matched),
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- for(n = 1; n < nCaptures; n++) {
- JSValue capN;
- capN = JS_GetPropertyInt64(ctx, result, n);
- if (JS_IsException(capN))
- goto exception;
- if (!JS_IsUndefined(capN)) {
- capN = JS_ToStringFree(ctx, capN);
- if (JS_IsException(capN))
- goto exception;
- }
- if (JS_DefinePropertyValueInt64(ctx, tab, n, capN,
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- }
- JS_FreeValue(ctx, namedCaptures);
- namedCaptures = JS_GetProperty(ctx, result, JS_ATOM_groups);
- if (JS_IsException(namedCaptures))
- goto exception;
- if (functionalReplace) {
- if (JS_DefinePropertyValueInt64(ctx, tab, n++, js_int32(position), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- if (JS_DefinePropertyValueInt64(ctx, tab, n++, js_dup(str), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- if (!JS_IsUndefined(namedCaptures)) {
- if (JS_DefinePropertyValueInt64(ctx, tab, n++, js_dup(namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- }
- args[0] = JS_UNDEFINED;
- args[1] = tab;
- JS_FreeValue(ctx, rep_str);
- rep_str = JS_ToStringFree(ctx, js_function_apply(ctx, rep, 2, args, 0));
- } else {
- JSValue namedCaptures1;
- if (!JS_IsUndefined(namedCaptures)) {
- namedCaptures1 = JS_ToObject(ctx, namedCaptures);
- if (JS_IsException(namedCaptures1))
- goto exception;
- } else {
- namedCaptures1 = JS_UNDEFINED;
- }
- args[0] = matched;
- args[1] = str;
- args[2] = js_int32(position);
- args[3] = tab;
- args[4] = namedCaptures1;
- args[5] = rep_val;
- JS_FreeValue(ctx, rep_str);
- rep_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
- JS_FreeValue(ctx, namedCaptures1);
- }
- if (JS_IsException(rep_str))
- goto exception;
- if (position >= nextSourcePosition) {
- string_buffer_concat(b, sp, nextSourcePosition, position);
- string_buffer_concat_value(b, rep_str);
- nextSourcePosition = position + JS_VALUE_GET_STRING(matched)->len;
- }
- }
- string_buffer_concat(b, sp, nextSourcePosition, sp->len);
- res = string_buffer_end(b);
- goto done1;
- exception:
- res = JS_EXCEPTION;
- done:
- string_buffer_free(b);
- done1:
- value_buffer_free(results);
- JS_FreeValue(ctx, rep_val);
- JS_FreeValue(ctx, matched);
- JS_FreeValue(ctx, flags);
- JS_FreeValue(ctx, tab);
- JS_FreeValue(ctx, rep_str);
- JS_FreeValue(ctx, namedCaptures);
- JS_FreeValue(ctx, str);
- return res;
- }
- static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst rx = this_val;
- JSValue str, previousLastIndex, currentLastIndex, result, index;
- if (!JS_IsObject(rx))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- result = JS_UNDEFINED;
- currentLastIndex = JS_UNDEFINED;
- previousLastIndex = JS_UNDEFINED;
- str = JS_ToString(ctx, argv[0]);
- if (JS_IsException(str))
- goto exception;
- previousLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
- if (JS_IsException(previousLastIndex))
- goto exception;
- if (!js_same_value(ctx, previousLastIndex, js_int32(0))) {
- if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, js_int32(0)) < 0) {
- goto exception;
- }
- }
- result = JS_RegExpExec(ctx, rx, str);
- if (JS_IsException(result))
- goto exception;
- currentLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
- if (JS_IsException(currentLastIndex))
- goto exception;
- if (js_same_value(ctx, currentLastIndex, previousLastIndex)) {
- JS_FreeValue(ctx, previousLastIndex);
- } else {
- if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) {
- previousLastIndex = JS_UNDEFINED;
- goto exception;
- }
- }
- JS_FreeValue(ctx, str);
- JS_FreeValue(ctx, currentLastIndex);
- if (JS_IsNull(result)) {
- return js_int32(-1);
- } else {
- index = JS_GetProperty(ctx, result, JS_ATOM_index);
- JS_FreeValue(ctx, result);
- return index;
- }
- exception:
- JS_FreeValue(ctx, result);
- JS_FreeValue(ctx, str);
- JS_FreeValue(ctx, currentLastIndex);
- JS_FreeValue(ctx, previousLastIndex);
- return JS_EXCEPTION;
- }
- static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // [Symbol.split](str, limit)
- JSValueConst rx = this_val;
- JSValueConst args[2];
- JSValue str, ctor, splitter, A, flags, z, sub;
- JSString *strp;
- uint32_t lim, size, p, q;
- int unicodeMatching;
- int64_t lengthA, e, numberOfCaptures, i;
- if (!JS_IsObject(rx))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- ctor = JS_UNDEFINED;
- splitter = JS_UNDEFINED;
- A = JS_UNDEFINED;
- flags = JS_UNDEFINED;
- z = JS_UNDEFINED;
- str = JS_ToString(ctx, argv[0]);
- if (JS_IsException(str))
- goto exception;
- ctor = JS_SpeciesConstructor(ctx, rx, ctx->regexp_ctor);
- if (JS_IsException(ctor))
- goto exception;
- flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_flags));
- if (JS_IsException(flags))
- goto exception;
- strp = JS_VALUE_GET_STRING(flags);
- unicodeMatching = string_indexof_char(strp, 'u', 0) >= 0;
- if (string_indexof_char(strp, 'y', 0) < 0) {
- flags = JS_ConcatString3(ctx, "", flags, "y");
- if (JS_IsException(flags))
- goto exception;
- }
- args[0] = rx;
- args[1] = flags;
- splitter = JS_CallConstructor(ctx, ctor, 2, args);
- if (JS_IsException(splitter))
- goto exception;
- A = JS_NewArray(ctx);
- if (JS_IsException(A))
- goto exception;
- lengthA = 0;
- if (JS_IsUndefined(argv[1])) {
- lim = 0xffffffff;
- } else {
- if (JS_ToUint32(ctx, &lim, argv[1]) < 0)
- goto exception;
- if (lim == 0)
- goto done;
- }
- strp = JS_VALUE_GET_STRING(str);
- p = q = 0;
- size = strp->len;
- if (size == 0) {
- z = JS_RegExpExec(ctx, splitter, str);
- if (JS_IsException(z))
- goto exception;
- if (JS_IsNull(z))
- goto add_tail;
- goto done;
- }
- while (q < size) {
- if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, js_int32(q)) < 0)
- goto exception;
- JS_FreeValue(ctx, z);
- z = JS_RegExpExec(ctx, splitter, str);
- if (JS_IsException(z))
- goto exception;
- if (JS_IsNull(z)) {
- q = string_advance_index(strp, q, unicodeMatching);
- } else {
- if (JS_ToLengthFree(ctx, &e, JS_GetProperty(ctx, splitter, JS_ATOM_lastIndex)))
- goto exception;
- if (e > size)
- e = size;
- if (e == p) {
- q = string_advance_index(strp, q, unicodeMatching);
- } else {
- sub = js_sub_string(ctx, strp, p, q);
- if (JS_IsException(sub))
- goto exception;
- if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub,
- JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- if (lengthA == lim)
- goto done;
- p = e;
- if (js_get_length64(ctx, &numberOfCaptures, z))
- goto exception;
- for(i = 1; i < numberOfCaptures; i++) {
- sub = JS_GetPropertyInt64(ctx, z, i);
- if (JS_IsException(sub))
- goto exception;
- if (!JS_IsUndefined(sub)) {
- sub = JS_ToStringFree(ctx, sub);
- if (JS_IsException(sub))
- goto exception;
- }
- if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- if (lengthA == lim)
- goto done;
- }
- q = p;
- }
- }
- }
- add_tail:
- if (p > size)
- p = size;
- sub = js_sub_string(ctx, strp, p, size);
- if (JS_IsException(sub))
- goto exception;
- if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception;
- goto done;
- exception:
- JS_FreeValue(ctx, A);
- A = JS_EXCEPTION;
- done:
- JS_FreeValue(ctx, str);
- JS_FreeValue(ctx, ctor);
- JS_FreeValue(ctx, splitter);
- JS_FreeValue(ctx, flags);
- JS_FreeValue(ctx, z);
- return A;
- }
- static const JSCFunctionListEntry js_regexp_funcs[] = {
- JS_CFUNC_DEF("escape", 1, js_regexp_escape ),
- JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
- };
- static const JSCFunctionListEntry js_regexp_proto_funcs[] = {
- JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ),
- JS_CGETSET_DEF("source", js_regexp_get_source, NULL ),
- JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, LRE_FLAG_GLOBAL ),
- JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, LRE_FLAG_IGNORECASE ),
- JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, LRE_FLAG_MULTILINE ),
- JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, LRE_FLAG_DOTALL ),
- JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE ),
- JS_CGETSET_MAGIC_DEF("unicodeSets", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE_SETS ),
- JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, LRE_FLAG_STICKY ),
- JS_CGETSET_MAGIC_DEF("hasIndices", js_regexp_get_flag, NULL, LRE_FLAG_INDICES ),
- JS_CFUNC_DEF("exec", 1, js_regexp_exec ),
- JS_CFUNC_DEF("compile", 2, js_regexp_compile ),
- JS_CFUNC_DEF("test", 1, js_regexp_test ),
- JS_CFUNC_DEF("toString", 0, js_regexp_toString ),
- JS_CFUNC_DEF("[Symbol.replace]", 2, js_regexp_Symbol_replace ),
- JS_CFUNC_DEF("[Symbol.match]", 1, js_regexp_Symbol_match ),
- JS_CFUNC_DEF("[Symbol.matchAll]", 1, js_regexp_Symbol_matchAll ),
- JS_CFUNC_DEF("[Symbol.search]", 1, js_regexp_Symbol_search ),
- JS_CFUNC_DEF("[Symbol.split]", 2, js_regexp_Symbol_split ),
- };
- static const JSCFunctionListEntry js_regexp_string_iterator_proto_funcs[] = {
- JS_ITERATOR_NEXT_DEF("next", 0, js_regexp_string_iterator_next, 0 ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "RegExp String Iterator", JS_PROP_CONFIGURABLE ),
- };
- void JS_AddIntrinsicRegExpCompiler(JSContext *ctx)
- {
- ctx->compile_regexp = js_compile_regexp;
- }
- void JS_AddIntrinsicRegExp(JSContext *ctx)
- {
- JSValue obj;
- JS_AddIntrinsicRegExpCompiler(ctx);
- ctx->class_proto[JS_CLASS_REGEXP] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP], js_regexp_proto_funcs,
- countof(js_regexp_proto_funcs));
- obj = JS_NewGlobalCConstructor(ctx, "RegExp", js_regexp_constructor, 2,
- ctx->class_proto[JS_CLASS_REGEXP]);
- ctx->regexp_ctor = js_dup(obj);
- JS_SetPropertyFunctionList(ctx, obj, js_regexp_funcs, countof(js_regexp_funcs));
- ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR] =
- JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR],
- js_regexp_string_iterator_proto_funcs,
- countof(js_regexp_string_iterator_proto_funcs));
- }
- /* JSON */
- static JSValue json_parse_value(JSParseState *s)
- {
- JSContext *ctx = s->ctx;
- JSValue val = JS_NULL;
- int ret;
- switch(s->token.val) {
- case '{':
- {
- JSValue prop_val;
- JSAtom prop_name;
- if (json_next_token(s))
- goto fail;
- val = JS_NewObject(ctx);
- if (JS_IsException(val))
- goto fail;
- if (s->token.val != '}') {
- for(;;) {
- if (s->token.val == TOK_STRING) {
- prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
- if (prop_name == JS_ATOM_NULL)
- goto fail;
- } else {
- json_parse_error(s, s->token.ptr, "Expected property name or '}'");
- goto fail;
- }
- if (json_next_token(s))
- goto fail1;
- if (s->token.val != ':') {
- json_parse_error(s, s->token.ptr, "Expected ':' after property name");
- goto fail1;
- }
- if (json_next_token(s))
- goto fail1;
- prop_val = json_parse_value(s);
- if (JS_IsException(prop_val)) {
- fail1:
- JS_FreeAtom(ctx, prop_name);
- goto fail;
- }
- ret = JS_DefinePropertyValue(ctx, val, prop_name,
- prop_val, JS_PROP_C_W_E);
- JS_FreeAtom(ctx, prop_name);
- if (ret < 0)
- goto fail;
- if (s->token.val == '}')
- break;
- if (s->token.val != ',') {
- json_parse_error(s, s->token.ptr, "Expected ',' or '}' after property value");
- goto fail;
- }
- if (json_next_token(s))
- goto fail;
- }
- }
- if (json_next_token(s))
- goto fail;
- }
- break;
- case '[':
- {
- JSValue el;
- uint32_t idx;
- if (json_next_token(s))
- goto fail;
- val = JS_NewArray(ctx);
- if (JS_IsException(val))
- goto fail;
- if (s->token.val != ']') {
- for(idx = 0;; idx++) {
- el = json_parse_value(s);
- if (JS_IsException(el))
- goto fail;
- ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);
- if (ret < 0)
- goto fail;
- if (s->token.val == ']')
- break;
- if (s->token.val != ',') {
- json_parse_error(s, s->token.ptr, "Expected ',' or ']' after array element");
- goto fail;
- }
- if (json_next_token(s))
- goto fail;
- }
- }
- if (json_next_token(s))
- goto fail;
- }
- break;
- case TOK_STRING:
- val = js_dup(s->token.u.str.str);
- if (json_next_token(s))
- goto fail;
- break;
- case TOK_NUMBER:
- val = s->token.u.num.val;
- if (json_next_token(s))
- goto fail;
- break;
- case TOK_IDENT:
- if (s->token.u.ident.atom == JS_ATOM_false ||
- s->token.u.ident.atom == JS_ATOM_true) {
- val = js_bool(s->token.u.ident.atom == JS_ATOM_true);
- } else if (s->token.u.ident.atom == JS_ATOM_null) {
- val = JS_NULL;
- } else {
- goto def_token;
- }
- if (json_next_token(s))
- goto fail;
- break;
- default:
- def_token:
- if (s->token.val == TOK_EOF) {
- js_parse_error(s, "Unexpected end of JSON input");
- } else {
- js_parse_error(s, "unexpected token: '%.*s'",
- (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
- }
- goto fail;
- }
- return val;
- fail:
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
- JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, const char *filename)
- {
- JSParseState s1, *s = &s1;
- JSValue val = JS_UNDEFINED;
- js_parse_init(ctx, s, buf, buf_len, filename, 1);
- if (json_next_token(s))
- goto fail;
- val = json_parse_value(s);
- if (JS_IsException(val))
- goto fail;
- if (s->token.val != TOK_EOF) {
- if (js_parse_error(s, "unexpected data at the end"))
- goto fail;
- }
- return val;
- fail:
- JS_FreeValue(ctx, val);
- free_token(s, &s->token);
- return JS_EXCEPTION;
- }
- static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
- JSAtom name, JSValueConst reviver)
- {
- JSValue val, new_el, name_val, res;
- JSValueConst args[2];
- int ret, is_array;
- uint32_t i, len = 0;
- JSAtom prop;
- JSPropertyEnum *atoms = NULL;
- if (js_check_stack_overflow(ctx->rt, 0)) {
- return JS_ThrowStackOverflow(ctx);
- }
- val = JS_GetProperty(ctx, holder, name);
- if (JS_IsException(val))
- return val;
- if (JS_IsObject(val)) {
- is_array = js_is_array(ctx, val);
- if (is_array < 0)
- goto fail;
- if (is_array) {
- if (js_get_length32(ctx, &len, val))
- goto fail;
- } else {
- ret = JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, JS_VALUE_GET_OBJ(val), JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
- if (ret < 0)
- goto fail;
- }
- for(i = 0; i < len; i++) {
- if (is_array) {
- prop = JS_NewAtomUInt32(ctx, i);
- if (prop == JS_ATOM_NULL)
- goto fail;
- } else {
- prop = JS_DupAtom(ctx, atoms[i].atom);
- }
- new_el = internalize_json_property(ctx, val, prop, reviver);
- if (JS_IsException(new_el)) {
- JS_FreeAtom(ctx, prop);
- goto fail;
- }
- if (JS_IsUndefined(new_el)) {
- ret = JS_DeleteProperty(ctx, val, prop, 0);
- } else {
- ret = JS_DefinePropertyValue(ctx, val, prop, new_el, JS_PROP_C_W_E);
- }
- JS_FreeAtom(ctx, prop);
- if (ret < 0)
- goto fail;
- }
- }
- js_free_prop_enum(ctx, atoms, len);
- atoms = NULL;
- name_val = JS_AtomToValue(ctx, name);
- if (JS_IsException(name_val))
- goto fail;
- args[0] = name_val;
- args[1] = val;
- res = JS_Call(ctx, reviver, holder, 2, args);
- JS_FreeValue(ctx, name_val);
- JS_FreeValue(ctx, val);
- return res;
- fail:
- js_free_prop_enum(ctx, atoms, len);
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue obj, root;
- JSValueConst reviver;
- const char *str;
- size_t len;
- str = JS_ToCStringLen(ctx, &len, argv[0]);
- if (!str)
- return JS_EXCEPTION;
- obj = JS_ParseJSON(ctx, str, len, "<input>");
- JS_FreeCString(ctx, str);
- if (JS_IsException(obj))
- return obj;
- if (argc > 1 && JS_IsFunction(ctx, argv[1])) {
- reviver = argv[1];
- root = JS_NewObject(ctx);
- if (JS_IsException(root)) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj,
- JS_PROP_C_W_E) < 0) {
- JS_FreeValue(ctx, root);
- return JS_EXCEPTION;
- }
- obj = internalize_json_property(ctx, root, JS_ATOM_empty_string,
- reviver);
- JS_FreeValue(ctx, root);
- }
- return obj;
- }
- typedef struct JSONStringifyContext {
- JSValueConst replacer_func;
- JSValue stack;
- JSValue property_list;
- JSValue gap;
- JSValue empty;
- StringBuffer *b;
- } JSONStringifyContext;
- static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) {
- JSValue r = JS_ToQuotedString(ctx, val);
- JS_FreeValue(ctx, val);
- return r;
- }
- static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
- JSValueConst holder, JSValue val,
- JSValueConst key)
- {
- JSValue v;
- JSValueConst args[2];
- if (JS_IsObject(val) || JS_IsBigInt(val)) {
- JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
- if (JS_IsException(f))
- goto exception;
- if (JS_IsFunction(ctx, f)) {
- v = JS_CallFree(ctx, f, val, 1, &key);
- JS_FreeValue(ctx, val);
- val = v;
- if (JS_IsException(val))
- goto exception;
- } else {
- JS_FreeValue(ctx, f);
- }
- }
- if (!JS_IsUndefined(jsc->replacer_func)) {
- args[0] = key;
- args[1] = val;
- v = JS_Call(ctx, jsc->replacer_func, holder, 2, args);
- JS_FreeValue(ctx, val);
- val = v;
- if (JS_IsException(val))
- goto exception;
- }
- switch (JS_VALUE_GET_NORM_TAG(val)) {
- case JS_TAG_OBJECT:
- if (JS_IsFunction(ctx, val))
- break;
- case JS_TAG_STRING:
- case JS_TAG_INT:
- case JS_TAG_FLOAT64:
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- case JS_TAG_SHORT_BIG_INT:
- case JS_TAG_BIG_INT:
- case JS_TAG_EXCEPTION:
- return val;
- default:
- break;
- }
- JS_FreeValue(ctx, val);
- return JS_UNDEFINED;
- exception:
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
- JSValueConst holder, JSValue val,
- JSValueConst indent)
- {
- JSValue indent1, sep, sep1, tab, v, prop;
- JSObject *p;
- int64_t i, len;
- int cl, ret;
- bool has_content;
- indent1 = JS_UNDEFINED;
- sep = JS_UNDEFINED;
- sep1 = JS_UNDEFINED;
- tab = JS_UNDEFINED;
- prop = JS_UNDEFINED;
- if (js_check_stack_overflow(ctx->rt, 0)) {
- JS_ThrowStackOverflow(ctx);
- goto exception;
- }
- if (JS_IsObject(val)) {
- p = JS_VALUE_GET_OBJ(val);
- cl = p->class_id;
- if (cl == JS_CLASS_STRING) {
- val = JS_ToStringFree(ctx, val);
- if (JS_IsException(val))
- goto exception;
- goto concat_primitive;
- } else if (cl == JS_CLASS_NUMBER) {
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val))
- goto exception;
- goto concat_primitive;
- } else if (cl == JS_CLASS_BOOLEAN || cl == JS_CLASS_BIG_INT) {
- set_value(ctx, &val, js_dup(p->u.object_data));
- goto concat_primitive;
- }
- v = js_array_includes(ctx, jsc->stack, 1, vc(&val));
- if (JS_IsException(v))
- goto exception;
- if (JS_ToBoolFree(ctx, v)) {
- JS_ThrowTypeError(ctx, "circular reference");
- goto exception;
- }
- indent1 = JS_ConcatString(ctx, js_dup(indent), js_dup(jsc->gap));
- if (JS_IsException(indent1))
- goto exception;
- if (!JS_IsEmptyString(jsc->gap)) {
- sep = JS_ConcatString3(ctx, "\n", js_dup(indent1), "");
- if (JS_IsException(sep))
- goto exception;
- sep1 = js_new_string8(ctx, " ");
- if (JS_IsException(sep1))
- goto exception;
- } else {
- sep = js_dup(jsc->empty);
- sep1 = js_dup(jsc->empty);
- }
- v = js_array_push(ctx, jsc->stack, 1, vc(&val), 0);
- if (check_exception_free(ctx, v))
- goto exception;
- ret = js_is_array(ctx, val);
- if (ret < 0)
- goto exception;
- if (ret) {
- if (js_get_length64(ctx, &len, val))
- goto exception;
- string_buffer_putc8(jsc->b, '[');
- for(i = 0; i < len; i++) {
- if (i > 0)
- string_buffer_putc8(jsc->b, ',');
- string_buffer_concat_value(jsc->b, sep);
- v = JS_GetPropertyInt64(ctx, val, i);
- if (JS_IsException(v))
- goto exception;
- /* XXX: could do this string conversion only when needed */
- prop = JS_ToStringFree(ctx, js_int64(i));
- if (JS_IsException(prop))
- goto exception;
- v = js_json_check(ctx, jsc, val, v, prop);
- JS_FreeValue(ctx, prop);
- prop = JS_UNDEFINED;
- if (JS_IsException(v))
- goto exception;
- if (JS_IsUndefined(v))
- v = JS_NULL;
- if (js_json_to_str(ctx, jsc, val, v, indent1))
- goto exception;
- }
- if (len > 0 && !JS_IsEmptyString(jsc->gap)) {
- string_buffer_putc8(jsc->b, '\n');
- string_buffer_concat_value(jsc->b, indent);
- }
- string_buffer_putc8(jsc->b, ']');
- } else {
- if (!JS_IsUndefined(jsc->property_list))
- tab = js_dup(jsc->property_list);
- else
- tab = js_object_keys(ctx, JS_UNDEFINED, 1, vc(&val),
- JS_ITERATOR_KIND_KEY);
- if (JS_IsException(tab))
- goto exception;
- if (js_get_length64(ctx, &len, tab))
- goto exception;
- string_buffer_putc8(jsc->b, '{');
- has_content = false;
- for(i = 0; i < len; i++) {
- JS_FreeValue(ctx, prop);
- prop = JS_GetPropertyInt64(ctx, tab, i);
- if (JS_IsException(prop))
- goto exception;
- v = JS_GetPropertyValue(ctx, val, js_dup(prop));
- if (JS_IsException(v))
- goto exception;
- v = js_json_check(ctx, jsc, val, v, prop);
- if (JS_IsException(v))
- goto exception;
- if (!JS_IsUndefined(v)) {
- if (has_content)
- string_buffer_putc8(jsc->b, ',');
- prop = JS_ToQuotedStringFree(ctx, prop);
- if (JS_IsException(prop)) {
- JS_FreeValue(ctx, v);
- goto exception;
- }
- string_buffer_concat_value(jsc->b, sep);
- string_buffer_concat_value(jsc->b, prop);
- string_buffer_putc8(jsc->b, ':');
- string_buffer_concat_value(jsc->b, sep1);
- if (js_json_to_str(ctx, jsc, val, v, indent1))
- goto exception;
- has_content = true;
- }
- }
- if (has_content && JS_VALUE_GET_STRING(jsc->gap)->len != 0) {
- string_buffer_putc8(jsc->b, '\n');
- string_buffer_concat_value(jsc->b, indent);
- }
- string_buffer_putc8(jsc->b, '}');
- }
- if (check_exception_free(ctx, js_array_pop(ctx, jsc->stack, 0, NULL, 0)))
- goto exception;
- JS_FreeValue(ctx, val);
- JS_FreeValue(ctx, tab);
- JS_FreeValue(ctx, sep);
- JS_FreeValue(ctx, sep1);
- JS_FreeValue(ctx, indent1);
- JS_FreeValue(ctx, prop);
- return 0;
- }
- concat_primitive:
- switch (JS_VALUE_GET_NORM_TAG(val)) {
- case JS_TAG_STRING:
- val = JS_ToQuotedStringFree(ctx, val);
- if (JS_IsException(val))
- goto exception;
- goto concat_value;
- case JS_TAG_FLOAT64:
- if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {
- val = JS_NULL;
- }
- goto concat_value;
- case JS_TAG_INT:
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- concat_value:
- return string_buffer_concat_value_free(jsc->b, val);
- case JS_TAG_SHORT_BIG_INT:
- case JS_TAG_BIG_INT:
- JS_ThrowTypeError(ctx, "BigInt are forbidden in JSON.stringify");
- goto exception;
- default:
- JS_FreeValue(ctx, val);
- return 0;
- }
- exception:
- JS_FreeValue(ctx, val);
- JS_FreeValue(ctx, tab);
- JS_FreeValue(ctx, sep);
- JS_FreeValue(ctx, sep1);
- JS_FreeValue(ctx, indent1);
- JS_FreeValue(ctx, prop);
- return -1;
- }
- JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
- JSValueConst replacer, JSValueConst space0)
- {
- StringBuffer b_s;
- JSONStringifyContext jsc_s, *jsc = &jsc_s;
- JSValue val, v, space, ret, wrapper;
- int res;
- int64_t i, j, n;
- jsc->replacer_func = JS_UNDEFINED;
- jsc->stack = JS_UNDEFINED;
- jsc->property_list = JS_UNDEFINED;
- jsc->gap = JS_UNDEFINED;
- jsc->b = &b_s;
- jsc->empty = js_empty_string(ctx->rt);
- ret = JS_UNDEFINED;
- wrapper = JS_UNDEFINED;
- string_buffer_init(ctx, jsc->b, 0);
- jsc->stack = JS_NewArray(ctx);
- if (JS_IsException(jsc->stack))
- goto exception;
- if (JS_IsFunction(ctx, replacer)) {
- jsc->replacer_func = replacer;
- } else {
- res = js_is_array(ctx, replacer);
- if (res < 0)
- goto exception;
- if (res) {
- /* XXX: enumeration is not fully correct */
- jsc->property_list = JS_NewArray(ctx);
- if (JS_IsException(jsc->property_list))
- goto exception;
- if (js_get_length64(ctx, &n, replacer))
- goto exception;
- for (i = j = 0; i < n; i++) {
- JSValue present;
- v = JS_GetPropertyInt64(ctx, replacer, i);
- if (JS_IsException(v))
- goto exception;
- if (JS_IsObject(v)) {
- JSObject *p = JS_VALUE_GET_OBJ(v);
- if (p->class_id == JS_CLASS_STRING ||
- p->class_id == JS_CLASS_NUMBER) {
- v = JS_ToStringFree(ctx, v);
- if (JS_IsException(v))
- goto exception;
- } else {
- JS_FreeValue(ctx, v);
- continue;
- }
- } else if (JS_IsNumber(v)) {
- v = JS_ToStringFree(ctx, v);
- if (JS_IsException(v))
- goto exception;
- } else if (!JS_IsString(v)) {
- JS_FreeValue(ctx, v);
- continue;
- }
- present = js_array_includes(ctx, jsc->property_list,
- 1, vc(&v));
- if (JS_IsException(present)) {
- JS_FreeValue(ctx, v);
- goto exception;
- }
- if (!JS_ToBoolFree(ctx, present)) {
- JS_SetPropertyInt64(ctx, jsc->property_list, j++, v);
- } else {
- JS_FreeValue(ctx, v);
- }
- }
- }
- }
- space = js_dup(space0);
- if (JS_IsObject(space)) {
- JSObject *p = JS_VALUE_GET_OBJ(space);
- if (p->class_id == JS_CLASS_NUMBER) {
- space = JS_ToNumberFree(ctx, space);
- } else if (p->class_id == JS_CLASS_STRING) {
- space = JS_ToStringFree(ctx, space);
- }
- if (JS_IsException(space)) {
- JS_FreeValue(ctx, space);
- goto exception;
- }
- }
- if (JS_IsNumber(space)) {
- int n;
- if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0))
- goto exception;
- jsc->gap = JS_NewStringLen(ctx, " ", n);
- } else if (JS_IsString(space)) {
- JSString *p = JS_VALUE_GET_STRING(space);
- jsc->gap = js_sub_string(ctx, p, 0, min_int(p->len, 10));
- } else {
- jsc->gap = js_dup(jsc->empty);
- }
- JS_FreeValue(ctx, space);
- if (JS_IsException(jsc->gap))
- goto exception;
- wrapper = JS_NewObject(ctx);
- if (JS_IsException(wrapper))
- goto exception;
- if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string,
- js_dup(obj), JS_PROP_C_W_E) < 0)
- goto exception;
- val = js_dup(obj);
- val = js_json_check(ctx, jsc, wrapper, val, jsc->empty);
- if (JS_IsException(val))
- goto exception;
- if (JS_IsUndefined(val)) {
- ret = JS_UNDEFINED;
- goto done1;
- }
- if (js_json_to_str(ctx, jsc, wrapper, val, jsc->empty))
- goto exception;
- ret = string_buffer_end(jsc->b);
- goto done;
- exception:
- ret = JS_EXCEPTION;
- done1:
- string_buffer_free(jsc->b);
- done:
- JS_FreeValue(ctx, wrapper);
- JS_FreeValue(ctx, jsc->empty);
- JS_FreeValue(ctx, jsc->gap);
- JS_FreeValue(ctx, jsc->property_list);
- JS_FreeValue(ctx, jsc->stack);
- return ret;
- }
- static JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // stringify(val, replacer, space)
- return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]);
- }
- static const JSCFunctionListEntry js_json_funcs[] = {
- JS_CFUNC_DEF("parse", 2, js_json_parse ),
- JS_CFUNC_DEF("stringify", 3, js_json_stringify ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "JSON", JS_PROP_CONFIGURABLE ),
- };
- static const JSCFunctionListEntry js_json_obj[] = {
- JS_OBJECT_DEF("JSON", js_json_funcs, countof(js_json_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
- };
- void JS_AddIntrinsicJSON(JSContext *ctx)
- {
- /* add JSON as autoinit object */
- JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_json_obj, countof(js_json_obj));
- }
- /* Reflect */
- static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2);
- }
- static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst func, array_arg, new_target;
- JSValue *tab, ret;
- uint32_t len;
- func = argv[0];
- array_arg = argv[1];
- if (argc > 2) {
- new_target = argv[2];
- if (!JS_IsConstructor(ctx, new_target))
- return JS_ThrowTypeErrorNotAConstructor(ctx, new_target);
- } else {
- new_target = func;
- }
- tab = build_arg_list(ctx, &len, array_arg);
- if (!tab)
- return JS_EXCEPTION;
- ret = JS_CallConstructor2(ctx, func, new_target, len, vc(tab));
- free_arg_list(ctx, tab, len);
- return ret;
- }
- static JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst obj;
- JSAtom atom;
- int ret;
- obj = argv[0];
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- atom = JS_ValueToAtom(ctx, argv[1]);
- if (unlikely(atom == JS_ATOM_NULL))
- return JS_EXCEPTION;
- ret = JS_DeleteProperty(ctx, obj, atom, 0);
- JS_FreeAtom(ctx, atom);
- if (ret < 0)
- return JS_EXCEPTION;
- else
- return js_bool(ret);
- }
- static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst obj, prop, receiver;
- JSAtom atom;
- JSValue ret;
- obj = argv[0];
- prop = argv[1];
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- if (argc > 2)
- receiver = argv[2];
- else
- receiver = obj;
- atom = JS_ValueToAtom(ctx, prop);
- if (unlikely(atom == JS_ATOM_NULL))
- return JS_EXCEPTION;
- ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, false);
- JS_FreeAtom(ctx, atom);
- return ret;
- }
- static JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst obj, prop;
- JSAtom atom;
- int ret;
- obj = argv[0];
- prop = argv[1];
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- atom = JS_ValueToAtom(ctx, prop);
- if (unlikely(atom == JS_ATOM_NULL))
- return JS_EXCEPTION;
- ret = JS_HasProperty(ctx, obj, atom);
- JS_FreeAtom(ctx, atom);
- if (ret < 0)
- return JS_EXCEPTION;
- else
- return js_bool(ret);
- }
- static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst obj, prop, val, receiver;
- int ret;
- JSAtom atom;
- obj = argv[0];
- prop = argv[1];
- val = argv[2];
- if (argc > 3)
- receiver = argv[3];
- else
- receiver = obj;
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- atom = JS_ValueToAtom(ctx, prop);
- if (unlikely(atom == JS_ATOM_NULL))
- return JS_EXCEPTION;
- ret = JS_SetPropertyInternal2(ctx, obj, atom, js_dup(val), receiver, 0);
- JS_FreeAtom(ctx, atom);
- if (ret < 0)
- return JS_EXCEPTION;
- else
- return js_bool(ret);
- }
- static JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int ret;
- ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], false);
- if (ret < 0)
- return JS_EXCEPTION;
- else
- return js_bool(ret);
- }
- static JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- return JS_GetOwnPropertyNames2(ctx, argv[0],
- JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK,
- JS_ITERATOR_KIND_KEY);
- }
- static const JSCFunctionListEntry js_reflect_funcs[] = {
- JS_CFUNC_DEF("apply", 3, js_reflect_apply ),
- JS_CFUNC_DEF("construct", 2, js_reflect_construct ),
- JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 1 ),
- JS_CFUNC_DEF("deleteProperty", 2, js_reflect_deleteProperty ),
- JS_CFUNC_DEF("get", 2, js_reflect_get ),
- JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 1 ),
- JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 1 ),
- JS_CFUNC_DEF("has", 2, js_reflect_has ),
- JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 1 ),
- JS_CFUNC_DEF("ownKeys", 1, js_reflect_ownKeys ),
- JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 1 ),
- JS_CFUNC_DEF("set", 3, js_reflect_set ),
- JS_CFUNC_DEF("setPrototypeOf", 2, js_reflect_setPrototypeOf ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Reflect", JS_PROP_CONFIGURABLE ),
- };
- static const JSCFunctionListEntry js_reflect_obj[] = {
- JS_OBJECT_DEF("Reflect", js_reflect_funcs, countof(js_reflect_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
- };
- /* Proxy */
- static void js_proxy_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
- if (s) {
- JS_FreeValueRT(rt, s->target);
- JS_FreeValueRT(rt, s->handler);
- js_free_rt(rt, s);
- }
- }
- static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
- if (s) {
- JS_MarkValue(rt, s->target, mark_func);
- JS_MarkValue(rt, s->handler, mark_func);
- }
- }
- static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx)
- {
- return JS_ThrowTypeError(ctx, "revoked proxy");
- }
- static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,
- JSValueConst obj, JSAtom name)
- {
- JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
- JSValue method;
- /* safer to test recursion in all proxy methods */
- if (js_check_stack_overflow(ctx->rt, 0)) {
- JS_ThrowStackOverflow(ctx);
- return NULL;
- }
- /* 's' should never be NULL */
- if (s->is_revoked) {
- JS_ThrowTypeErrorRevokedProxy(ctx);
- return NULL;
- }
- method = JS_GetProperty(ctx, s->handler, name);
- if (JS_IsException(method))
- return NULL;
- if (JS_IsNull(method))
- method = JS_UNDEFINED;
- *pmethod = method;
- return s;
- }
- static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
- {
- JSProxyData *s;
- JSValue method, ret, proto1;
- int res;
- s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf);
- if (!s)
- return JS_EXCEPTION;
- if (JS_IsUndefined(method))
- return JS_GetPrototype(ctx, s->target);
- ret = JS_CallFree(ctx, method, s->handler, 1, vc(&s->target));
- if (JS_IsException(ret))
- return ret;
- if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL &&
- JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
- goto fail;
- }
- res = JS_IsExtensible(ctx, s->target);
- if (res < 0) {
- JS_FreeValue(ctx, ret);
- return JS_EXCEPTION;
- }
- if (!res) {
- /* check invariant */
- proto1 = JS_GetPrototype(ctx, s->target);
- if (JS_IsException(proto1)) {
- JS_FreeValue(ctx, ret);
- return JS_EXCEPTION;
- }
- if (JS_VALUE_GET_OBJ(proto1) != JS_VALUE_GET_OBJ(ret)) {
- JS_FreeValue(ctx, proto1);
- fail:
- JS_FreeValue(ctx, ret);
- return JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
- }
- JS_FreeValue(ctx, proto1);
- }
- return ret;
- }
- static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
- JSValueConst proto_val, bool throw_flag)
- {
- JSProxyData *s;
- JSValue method, ret, proto1;
- JSValueConst args[2];
- bool res;
- int res2;
- s = get_proxy_method(ctx, &method, obj, JS_ATOM_setPrototypeOf);
- if (!s)
- return -1;
- if (JS_IsUndefined(method))
- return JS_SetPrototypeInternal(ctx, s->target, proto_val, throw_flag);
- args[0] = s->target;
- args[1] = proto_val;
- ret = JS_CallFree(ctx, method, s->handler, 2, args);
- if (JS_IsException(ret))
- return -1;
- res = JS_ToBoolFree(ctx, ret);
- if (!res) {
- if (throw_flag) {
- JS_ThrowTypeError(ctx, "proxy: bad prototype");
- return -1;
- } else {
- return false;
- }
- }
- res2 = JS_IsExtensible(ctx, s->target);
- if (res2 < 0)
- return -1;
- if (!res2) {
- proto1 = JS_GetPrototype(ctx, s->target);
- if (JS_IsException(proto1))
- return -1;
- if (JS_VALUE_GET_OBJ(proto_val) != JS_VALUE_GET_OBJ(proto1)) {
- JS_FreeValue(ctx, proto1);
- JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
- return -1;
- }
- JS_FreeValue(ctx, proto1);
- }
- return true;
- }
- static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj)
- {
- JSProxyData *s;
- JSValue method, ret;
- bool res;
- int res2;
- s = get_proxy_method(ctx, &method, obj, JS_ATOM_isExtensible);
- if (!s)
- return -1;
- if (JS_IsUndefined(method))
- return JS_IsExtensible(ctx, s->target);
- ret = JS_CallFree(ctx, method, s->handler, 1, vc(&s->target));
- if (JS_IsException(ret))
- return -1;
- res = JS_ToBoolFree(ctx, ret);
- res2 = JS_IsExtensible(ctx, s->target);
- if (res2 < 0)
- return res2;
- if (res != res2) {
- JS_ThrowTypeError(ctx, "proxy: inconsistent isExtensible");
- return -1;
- }
- return res;
- }
- static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj)
- {
- JSProxyData *s;
- JSValue method, ret;
- bool res;
- int res2;
- s = get_proxy_method(ctx, &method, obj, JS_ATOM_preventExtensions);
- if (!s)
- return -1;
- if (JS_IsUndefined(method))
- return JS_PreventExtensions(ctx, s->target);
- ret = JS_CallFree(ctx, method, s->handler, 1, vc(&s->target));
- if (JS_IsException(ret))
- return -1;
- res = JS_ToBoolFree(ctx, ret);
- if (res) {
- res2 = JS_IsExtensible(ctx, s->target);
- if (res2 < 0)
- return res2;
- if (res2) {
- JS_ThrowTypeError(ctx, "proxy: inconsistent preventExtensions");
- return -1;
- }
- }
- return res;
- }
- static int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
- {
- JSProxyData *s;
- JSValue method, ret1, atom_val;
- int res;
- JSObject *p;
- JSValueConst args[2];
- bool ret, res2;
- s = get_proxy_method(ctx, &method, obj, JS_ATOM_has);
- if (!s)
- return -1;
- if (JS_IsUndefined(method))
- return JS_HasProperty(ctx, s->target, atom);
- atom_val = JS_AtomToValue(ctx, atom);
- if (JS_IsException(atom_val)) {
- JS_FreeValue(ctx, method);
- return -1;
- }
- args[0] = s->target;
- args[1] = atom_val;
- ret1 = JS_CallFree(ctx, method, s->handler, 2, args);
- JS_FreeValue(ctx, atom_val);
- if (JS_IsException(ret1))
- return -1;
- ret = JS_ToBoolFree(ctx, ret1);
- if (!ret) {
- JSPropertyDescriptor desc;
- p = JS_VALUE_GET_OBJ(s->target);
- res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
- if (res < 0)
- return -1;
- if (res) {
- res2 = !(desc.flags & JS_PROP_CONFIGURABLE);
- js_free_desc(ctx, &desc);
- if (res2 || !p->extensible) {
- JS_ThrowTypeError(ctx, "proxy: inconsistent has");
- return -1;
- }
- }
- }
- return ret;
- }
- static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
- JSValueConst receiver)
- {
- JSProxyData *s;
- JSValue method, ret, atom_val;
- int res;
- JSValueConst args[3];
- JSPropertyDescriptor desc;
- s = get_proxy_method(ctx, &method, obj, JS_ATOM_get);
- if (!s)
- return JS_EXCEPTION;
- /* Note: recursion is possible thru the prototype of s->target */
- if (JS_IsUndefined(method))
- return JS_GetPropertyInternal(ctx, s->target, atom, receiver, false);
- atom_val = JS_AtomToValue(ctx, atom);
- if (JS_IsException(atom_val)) {
- JS_FreeValue(ctx, method);
- return JS_EXCEPTION;
- }
- args[0] = s->target;
- args[1] = atom_val;
- args[2] = receiver;
- ret = JS_CallFree(ctx, method, s->handler, 3, args);
- JS_FreeValue(ctx, atom_val);
- if (JS_IsException(ret))
- return JS_EXCEPTION;
- res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
- if (res < 0) {
- JS_FreeValue(ctx, ret);
- return JS_EXCEPTION;
- }
- if (res) {
- if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
- if (!js_same_value(ctx, desc.value, ret)) {
- goto fail;
- }
- } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET) {
- if (JS_IsUndefined(desc.getter) && !JS_IsUndefined(ret)) {
- fail:
- js_free_desc(ctx, &desc);
- JS_FreeValue(ctx, ret);
- return JS_ThrowTypeError(ctx, "proxy: inconsistent get");
- }
- }
- js_free_desc(ctx, &desc);
- }
- return ret;
- }
- static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
- JSValueConst value, JSValueConst receiver, int flags)
- {
- JSProxyData *s;
- JSValue method, ret1, atom_val;
- bool ret;
- int res;
- JSValueConst args[4];
- s = get_proxy_method(ctx, &method, obj, JS_ATOM_set);
- if (!s)
- return -1;
- if (JS_IsUndefined(method)) {
- return JS_SetPropertyInternal2(ctx, s->target, atom,
- js_dup(value), receiver, flags);
- }
- atom_val = JS_AtomToValue(ctx, atom);
- if (JS_IsException(atom_val)) {
- JS_FreeValue(ctx, method);
- return -1;
- }
- args[0] = s->target;
- args[1] = atom_val;
- args[2] = value;
- args[3] = receiver;
- ret1 = JS_CallFree(ctx, method, s->handler, 4, args);
- JS_FreeValue(ctx, atom_val);
- if (JS_IsException(ret1))
- return -1;
- ret = JS_ToBoolFree(ctx, ret1);
- if (ret) {
- JSPropertyDescriptor desc;
- res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
- if (res < 0)
- return -1;
- if (res) {
- if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
- if (!js_same_value(ctx, desc.value, value)) {
- goto fail;
- }
- } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET && JS_IsUndefined(desc.setter)) {
- fail:
- js_free_desc(ctx, &desc);
- JS_ThrowTypeError(ctx, "proxy: inconsistent set");
- return -1;
- }
- js_free_desc(ctx, &desc);
- }
- } else {
- if ((flags & JS_PROP_THROW) ||
- ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
- JS_ThrowTypeError(ctx, "proxy: cannot set property");
- return -1;
- }
- }
- return ret;
- }
- static JSValue js_create_desc(JSContext *ctx, JSValueConst val,
- JSValueConst getter, JSValueConst setter,
- int flags)
- {
- JSValue ret;
- ret = JS_NewObject(ctx);
- if (JS_IsException(ret))
- return ret;
- if (flags & JS_PROP_HAS_GET) {
- JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, js_dup(getter),
- JS_PROP_C_W_E);
- }
- if (flags & JS_PROP_HAS_SET) {
- JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, js_dup(setter),
- JS_PROP_C_W_E);
- }
- if (flags & JS_PROP_HAS_VALUE) {
- JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, js_dup(val),
- JS_PROP_C_W_E);
- }
- if (flags & JS_PROP_HAS_WRITABLE) {
- JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
- js_bool(flags & JS_PROP_WRITABLE),
- JS_PROP_C_W_E);
- }
- if (flags & JS_PROP_HAS_ENUMERABLE) {
- JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
- js_bool(flags & JS_PROP_ENUMERABLE),
- JS_PROP_C_W_E);
- }
- if (flags & JS_PROP_HAS_CONFIGURABLE) {
- JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
- js_bool(flags & JS_PROP_CONFIGURABLE),
- JS_PROP_C_W_E);
- }
- return ret;
- }
- static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc,
- JSValueConst obj, JSAtom prop)
- {
- JSProxyData *s;
- JSValue method, trap_result_obj, prop_val;
- int res, target_desc_ret, ret;
- JSObject *p;
- JSValueConst args[2];
- JSPropertyDescriptor result_desc, target_desc;
- s = get_proxy_method(ctx, &method, obj, JS_ATOM_getOwnPropertyDescriptor);
- if (!s)
- return -1;
- p = JS_VALUE_GET_OBJ(s->target);
- if (JS_IsUndefined(method)) {
- return JS_GetOwnPropertyInternal(ctx, pdesc, p, prop);
- }
- prop_val = JS_AtomToValue(ctx, prop);
- if (JS_IsException(prop_val)) {
- JS_FreeValue(ctx, method);
- return -1;
- }
- args[0] = s->target;
- args[1] = prop_val;
- trap_result_obj = JS_CallFree(ctx, method, s->handler, 2, args);
- JS_FreeValue(ctx, prop_val);
- if (JS_IsException(trap_result_obj))
- return -1;
- if (!JS_IsObject(trap_result_obj) && !JS_IsUndefined(trap_result_obj)) {
- JS_FreeValue(ctx, trap_result_obj);
- goto fail;
- }
- target_desc_ret = JS_GetOwnPropertyInternal(ctx, &target_desc, p, prop);
- if (target_desc_ret < 0) {
- JS_FreeValue(ctx, trap_result_obj);
- return -1;
- }
- if (target_desc_ret)
- js_free_desc(ctx, &target_desc);
- if (JS_IsUndefined(trap_result_obj)) {
- if (target_desc_ret) {
- if (!(target_desc.flags & JS_PROP_CONFIGURABLE) || !p->extensible)
- goto fail;
- }
- ret = false;
- } else {
- int flags1, extensible_target;
- extensible_target = JS_IsExtensible(ctx, s->target);
- if (extensible_target < 0) {
- JS_FreeValue(ctx, trap_result_obj);
- return -1;
- }
- res = js_obj_to_desc(ctx, &result_desc, trap_result_obj);
- JS_FreeValue(ctx, trap_result_obj);
- if (res < 0)
- return -1;
- if (target_desc_ret) {
- /* convert result_desc.flags to defineProperty flags */
- flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE;
- if (result_desc.flags & JS_PROP_GETSET)
- flags1 |= JS_PROP_HAS_GET | JS_PROP_HAS_SET;
- else
- flags1 |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE;
- /* XXX: not complete check: need to compare value &
- getter/setter as in defineproperty */
- if (!check_define_prop_flags(target_desc.flags, flags1))
- goto fail1;
- } else {
- if (!extensible_target)
- goto fail1;
- }
- if (!(result_desc.flags & JS_PROP_CONFIGURABLE)) {
- if (!target_desc_ret || (target_desc.flags & JS_PROP_CONFIGURABLE))
- goto fail1;
- if ((result_desc.flags &
- (JS_PROP_GETSET | JS_PROP_WRITABLE)) == 0 &&
- target_desc_ret &&
- (target_desc.flags & JS_PROP_WRITABLE) != 0) {
- /* proxy-missing-checks */
- fail1:
- js_free_desc(ctx, &result_desc);
- fail:
- JS_ThrowTypeError(ctx, "proxy: inconsistent getOwnPropertyDescriptor");
- return -1;
- }
- }
- ret = true;
- if (pdesc) {
- *pdesc = result_desc;
- } else {
- js_free_desc(ctx, &result_desc);
- }
- }
- return ret;
- }
- static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,
- JSAtom prop, JSValueConst val,
- JSValueConst getter,
- JSValueConst setter, int flags)
- {
- JSProxyData *s;
- JSValue method, ret1, prop_val, desc_val;
- int res;
- JSObject *p;
- JSValueConst args[3];
- JSPropertyDescriptor desc;
- bool ret, setting_not_configurable;
- s = get_proxy_method(ctx, &method, obj, JS_ATOM_defineProperty);
- if (!s)
- return -1;
- if (JS_IsUndefined(method)) {
- return JS_DefineProperty(ctx, s->target, prop, val, getter, setter, flags);
- }
- prop_val = JS_AtomToValue(ctx, prop);
- if (JS_IsException(prop_val)) {
- JS_FreeValue(ctx, method);
- return -1;
- }
- desc_val = js_create_desc(ctx, val, getter, setter, flags);
- if (JS_IsException(desc_val)) {
- JS_FreeValue(ctx, prop_val);
- JS_FreeValue(ctx, method);
- return -1;
- }
- args[0] = s->target;
- args[1] = prop_val;
- args[2] = desc_val;
- ret1 = JS_CallFree(ctx, method, s->handler, 3, args);
- JS_FreeValue(ctx, prop_val);
- JS_FreeValue(ctx, desc_val);
- if (JS_IsException(ret1))
- return -1;
- ret = JS_ToBoolFree(ctx, ret1);
- if (!ret) {
- if (flags & JS_PROP_THROW) {
- JS_ThrowTypeError(ctx, "proxy: defineProperty exception");
- return -1;
- } else {
- return 0;
- }
- }
- p = JS_VALUE_GET_OBJ(s->target);
- res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
- if (res < 0)
- return -1;
- setting_not_configurable = ((flags & (JS_PROP_HAS_CONFIGURABLE |
- JS_PROP_CONFIGURABLE)) ==
- JS_PROP_HAS_CONFIGURABLE);
- if (!res) {
- if (!p->extensible || setting_not_configurable)
- goto fail;
- } else {
- if (!check_define_prop_flags(desc.flags, flags) ||
- ((desc.flags & JS_PROP_CONFIGURABLE) && setting_not_configurable)) {
- goto fail1;
- }
- if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
- if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) ==
- JS_PROP_GETSET) {
- if ((flags & JS_PROP_HAS_GET) &&
- !js_same_value(ctx, getter, desc.getter)) {
- goto fail1;
- }
- if ((flags & JS_PROP_HAS_SET) &&
- !js_same_value(ctx, setter, desc.setter)) {
- goto fail1;
- }
- }
- } else if (flags & JS_PROP_HAS_VALUE) {
- if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) ==
- JS_PROP_WRITABLE && !(flags & JS_PROP_WRITABLE)) {
- /* missing-proxy-check feature */
- goto fail1;
- } else if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
- !js_same_value(ctx, val, desc.value)) {
- goto fail1;
- }
- }
- if (flags & JS_PROP_HAS_WRITABLE) {
- if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE |
- JS_PROP_WRITABLE)) == JS_PROP_WRITABLE) {
- /* proxy-missing-checks */
- fail1:
- js_free_desc(ctx, &desc);
- fail:
- JS_ThrowTypeError(ctx, "proxy: inconsistent defineProperty");
- return -1;
- }
- }
- js_free_desc(ctx, &desc);
- }
- return 1;
- }
- static int js_proxy_delete_property(JSContext *ctx, JSValueConst obj,
- JSAtom atom)
- {
- JSProxyData *s;
- JSValue method, ret, atom_val;
- int res2, is_extensible;
- bool res;
- JSValueConst args[2];
- s = get_proxy_method(ctx, &method, obj, JS_ATOM_deleteProperty);
- if (!s)
- return -1;
- if (JS_IsUndefined(method)) {
- return JS_DeleteProperty(ctx, s->target, atom, 0);
- }
- atom_val = JS_AtomToValue(ctx, atom);;
- if (JS_IsException(atom_val)) {
- JS_FreeValue(ctx, method);
- return -1;
- }
- args[0] = s->target;
- args[1] = atom_val;
- ret = JS_CallFree(ctx, method, s->handler, 2, args);
- JS_FreeValue(ctx, atom_val);
- if (JS_IsException(ret))
- return -1;
- res = JS_ToBoolFree(ctx, ret);
- if (res) {
- JSPropertyDescriptor desc;
- res2 = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
- if (res2 < 0)
- return -1;
- if (res2) {
- if (!(desc.flags & JS_PROP_CONFIGURABLE))
- goto fail;
- is_extensible = JS_IsExtensible(ctx, s->target);
- if (is_extensible < 0)
- goto fail1;
- if (!is_extensible) {
- /* proxy-missing-checks */
- fail:
- JS_ThrowTypeError(ctx, "proxy: inconsistent deleteProperty");
- fail1:
- js_free_desc(ctx, &desc);
- return -1;
- }
- js_free_desc(ctx, &desc);
- }
- }
- return res;
- }
- /* return the index of the property or -1 if not found */
- static int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom)
- {
- int i;
- for(i = 0; i < n; i++) {
- if (tab[i].atom == atom)
- return i;
- }
- return -1;
- }
- static int js_proxy_get_own_property_names(JSContext *ctx,
- JSPropertyEnum **ptab,
- uint32_t *plen,
- JSValueConst obj)
- {
- JSProxyData *s;
- JSValue method, prop_array, val;
- uint32_t len, i, len2;
- JSPropertyEnum *tab, *tab2;
- JSAtom atom;
- JSPropertyDescriptor desc;
- int res, is_extensible, idx;
- s = get_proxy_method(ctx, &method, obj, JS_ATOM_ownKeys);
- if (!s)
- return -1;
- if (JS_IsUndefined(method)) {
- return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
- JS_VALUE_GET_OBJ(s->target),
- JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);
- }
- prop_array = JS_CallFree(ctx, method, s->handler, 1, vc(&s->target));
- if (JS_IsException(prop_array))
- return -1;
- tab = NULL;
- len = 0;
- tab2 = NULL;
- len2 = 0;
- if (js_get_length32(ctx, &len, prop_array))
- goto fail;
- if (len > 0) {
- tab = js_mallocz(ctx, sizeof(tab[0]) * len);
- if (!tab)
- goto fail;
- }
- for(i = 0; i < len; i++) {
- val = JS_GetPropertyUint32(ctx, prop_array, i);
- if (JS_IsException(val))
- goto fail;
- if (!JS_IsString(val) && !JS_IsSymbol(val)) {
- JS_FreeValue(ctx, val);
- JS_ThrowTypeError(ctx, "proxy: properties must be strings or symbols");
- goto fail;
- }
- atom = JS_ValueToAtom(ctx, val);
- JS_FreeValue(ctx, val);
- if (atom == JS_ATOM_NULL)
- goto fail;
- tab[i].atom = atom;
- tab[i].is_enumerable = false; /* XXX: redundant? */
- }
- /* check duplicate properties (XXX: inefficient, could store the
- * properties an a temporary object to use the hash) */
- for(i = 1; i < len; i++) {
- if (find_prop_key(tab, i, tab[i].atom) >= 0) {
- JS_ThrowTypeError(ctx, "proxy: duplicate property");
- goto fail;
- }
- }
- is_extensible = JS_IsExtensible(ctx, s->target);
- if (is_extensible < 0)
- goto fail;
- /* check if there are non configurable properties */
- if (s->is_revoked) {
- JS_ThrowTypeErrorRevokedProxy(ctx);
- goto fail;
- }
- if (JS_GetOwnPropertyNamesInternal(ctx, &tab2, &len2, JS_VALUE_GET_OBJ(s->target),
- JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
- goto fail;
- for(i = 0; i < len2; i++) {
- if (s->is_revoked) {
- JS_ThrowTypeErrorRevokedProxy(ctx);
- goto fail;
- }
- res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target),
- tab2[i].atom);
- if (res < 0)
- goto fail;
- if (res) { /* safety, property should be found */
- js_free_desc(ctx, &desc);
- if (!(desc.flags & JS_PROP_CONFIGURABLE) || !is_extensible) {
- idx = find_prop_key(tab, len, tab2[i].atom);
- if (idx < 0) {
- JS_ThrowTypeError(ctx, "proxy: target property must be present in proxy ownKeys");
- goto fail;
- }
- /* mark the property as found */
- if (!is_extensible)
- tab[idx].is_enumerable = true;
- }
- }
- }
- if (!is_extensible) {
- /* check that all property in 'tab' were checked */
- for(i = 0; i < len; i++) {
- if (!tab[i].is_enumerable) {
- JS_ThrowTypeError(ctx, "proxy: property not present in target were returned by non extensible proxy");
- goto fail;
- }
- }
- }
- js_free_prop_enum(ctx, tab2, len2);
- JS_FreeValue(ctx, prop_array);
- *ptab = tab;
- *plen = len;
- return 0;
- fail:
- js_free_prop_enum(ctx, tab2, len2);
- js_free_prop_enum(ctx, tab, len);
- JS_FreeValue(ctx, prop_array);
- return -1;
- }
- static JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj,
- JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- JSProxyData *s;
- JSValue method, arg_array, ret;
- JSValueConst args[3];
- s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_construct);
- if (!s)
- return JS_EXCEPTION;
- if (!JS_IsConstructor(ctx, s->target))
- return JS_ThrowTypeErrorNotAConstructor(ctx, s->target);
- if (JS_IsUndefined(method))
- return JS_CallConstructor2(ctx, s->target, new_target, argc, argv);
- arg_array = js_create_array(ctx, argc, argv);
- if (JS_IsException(arg_array)) {
- ret = JS_EXCEPTION;
- goto fail;
- }
- args[0] = s->target;
- args[1] = arg_array;
- args[2] = new_target;
- ret = JS_Call(ctx, method, s->handler, 3, args);
- if (!JS_IsException(ret) && JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
- JS_FreeValue(ctx, ret);
- ret = JS_ThrowTypeErrorNotAnObject(ctx);
- }
- fail:
- JS_FreeValue(ctx, method);
- JS_FreeValue(ctx, arg_array);
- return ret;
- }
- static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_obj,
- int argc, JSValueConst *argv, int flags)
- {
- JSProxyData *s;
- JSValue method, arg_array, ret;
- JSValueConst args[3];
- if (flags & JS_CALL_FLAG_CONSTRUCTOR)
- return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv);
- s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply);
- if (!s)
- return JS_EXCEPTION;
- if (!s->is_func) {
- JS_FreeValue(ctx, method);
- return JS_ThrowTypeErrorNotAFunction(ctx);
- }
- if (JS_IsUndefined(method))
- return JS_Call(ctx, s->target, this_obj, argc, argv);
- arg_array = js_create_array(ctx, argc, argv);
- if (JS_IsException(arg_array)) {
- ret = JS_EXCEPTION;
- goto fail;
- }
- args[0] = s->target;
- args[1] = this_obj;
- args[2] = arg_array;
- ret = JS_Call(ctx, method, s->handler, 3, args);
- fail:
- JS_FreeValue(ctx, method);
- JS_FreeValue(ctx, arg_array);
- return ret;
- }
- static int js_proxy_isArray(JSContext *ctx, JSValueConst obj)
- {
- JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
- if (!s)
- return false;
- if (js_check_stack_overflow(ctx->rt, 0)) {
- JS_ThrowStackOverflow(ctx);
- return -1;
- }
- if (s->is_revoked) {
- JS_ThrowTypeErrorRevokedProxy(ctx);
- return -1;
- }
- return js_is_array(ctx, s->target);
- }
- static const JSClassExoticMethods js_proxy_exotic_methods = {
- .get_own_property = js_proxy_get_own_property,
- .define_own_property = js_proxy_define_own_property,
- .delete_property = js_proxy_delete_property,
- .get_own_property_names = js_proxy_get_own_property_names,
- .has_property = js_proxy_has,
- .get_property = js_proxy_get,
- .set_property = js_proxy_set,
- };
- static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst target, handler;
- JSValue obj;
- JSProxyData *s;
- target = argv[0];
- handler = argv[1];
- if (JS_VALUE_GET_TAG(target) != JS_TAG_OBJECT ||
- JS_VALUE_GET_TAG(handler) != JS_TAG_OBJECT)
- return JS_ThrowTypeErrorNotAnObject(ctx);
- obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_PROXY);
- if (JS_IsException(obj))
- return obj;
- s = js_malloc(ctx, sizeof(JSProxyData));
- if (!s) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- s->target = js_dup(target);
- s->handler = js_dup(handler);
- s->is_func = JS_IsFunction(ctx, target);
- s->is_revoked = false;
- JS_SetOpaqueInternal(obj, s);
- JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target));
- return obj;
- }
- static JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic,
- JSValueConst *func_data)
- {
- JSProxyData *s = JS_GetOpaque(func_data[0], JS_CLASS_PROXY);
- if (s) {
- /* We do not free the handler and target in case they are
- referenced as constants in the C call stack */
- s->is_revoked = true;
- JS_FreeValue(ctx, unsafe_unconst(func_data[0]));
- func_data[0] = JS_NULL;
- }
- return JS_UNDEFINED;
- }
- static JSValue js_proxy_revoke_constructor(JSContext *ctx,
- JSValueConst proxy_obj)
- {
- return JS_NewCFunctionData(ctx, js_proxy_revoke, 0, 0, 1, &proxy_obj);
- }
- static JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue proxy_obj, revoke_obj = JS_UNDEFINED, obj;
- proxy_obj = js_proxy_constructor(ctx, JS_UNDEFINED, argc, argv);
- if (JS_IsException(proxy_obj))
- goto fail;
- revoke_obj = js_proxy_revoke_constructor(ctx, proxy_obj);
- if (JS_IsException(revoke_obj))
- goto fail;
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj))
- goto fail;
- // XXX: exceptions?
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_proxy, proxy_obj, JS_PROP_C_W_E);
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_revoke, revoke_obj, JS_PROP_C_W_E);
- return obj;
- fail:
- JS_FreeValue(ctx, proxy_obj);
- JS_FreeValue(ctx, revoke_obj);
- return JS_EXCEPTION;
- }
- static const JSCFunctionListEntry js_proxy_funcs[] = {
- JS_CFUNC_DEF("revocable", 2, js_proxy_revocable ),
- };
- static const JSClassShortDef js_proxy_class_def[] = {
- { JS_ATOM_Object, js_proxy_finalizer, js_proxy_mark }, /* JS_CLASS_PROXY */
- };
- void JS_AddIntrinsicProxy(JSContext *ctx)
- {
- JSRuntime *rt = ctx->rt;
- JSValue obj1;
- if (!JS_IsRegisteredClass(rt, JS_CLASS_PROXY)) {
- init_class_range(rt, js_proxy_class_def, JS_CLASS_PROXY,
- countof(js_proxy_class_def));
- rt->class_array[JS_CLASS_PROXY].exotic = &js_proxy_exotic_methods;
- rt->class_array[JS_CLASS_PROXY].call = js_proxy_call;
- }
- obj1 = JS_NewCFunction2(ctx, js_proxy_constructor, "Proxy", 2,
- JS_CFUNC_constructor, 0);
- JS_SetConstructorBit(ctx, obj1, true);
- JS_SetPropertyFunctionList(ctx, obj1, js_proxy_funcs,
- countof(js_proxy_funcs));
- JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Proxy",
- obj1, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- }
- bool JS_IsProxy(JSValueConst val)
- {
- if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- return p->class_id == JS_CLASS_PROXY;
- }
- return false;
- }
- static JSValue js_get_proxy_field(JSContext *ctx, JSValueConst proxy,
- int offset)
- {
- if (JS_VALUE_GET_TAG(proxy) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(proxy);
- if (p->class_id == JS_CLASS_PROXY) {
- JSProxyData *s = JS_GetOpaque(proxy, JS_CLASS_PROXY);
- if (s->is_revoked)
- return JS_ThrowTypeErrorRevokedProxy(ctx);
- return js_dup(*(JSValue *)((char *)s + offset));
- }
- }
- return JS_ThrowTypeError(ctx, "not a proxy");
- }
- JSValue JS_GetProxyTarget(JSContext *ctx, JSValueConst proxy)
- {
- return js_get_proxy_field(ctx, proxy, offsetof(JSProxyData, target));
- }
- JSValue JS_GetProxyHandler(JSContext *ctx, JSValueConst proxy)
- {
- return js_get_proxy_field(ctx, proxy, offsetof(JSProxyData, handler));
- }
- /* Symbol */
- static JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- JSValue str;
- JSString *p;
- if (!JS_IsUndefined(new_target))
- return JS_ThrowTypeErrorNotAConstructor(ctx, new_target);
- if (argc == 0 || JS_IsUndefined(argv[0])) {
- p = NULL;
- } else {
- str = JS_ToString(ctx, argv[0]);
- if (JS_IsException(str))
- return JS_EXCEPTION;
- p = JS_VALUE_GET_STRING(str);
- }
- return JS_NewSymbolInternal(ctx, p, JS_ATOM_TYPE_SYMBOL);
- }
- static JSValue js_thisSymbolValue(JSContext *ctx, JSValueConst this_val)
- {
- if (JS_VALUE_GET_TAG(this_val) == JS_TAG_SYMBOL)
- return js_dup(this_val);
- if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(this_val);
- if (p->class_id == JS_CLASS_SYMBOL) {
- if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_SYMBOL)
- return js_dup(p->u.object_data);
- }
- }
- return JS_ThrowTypeError(ctx, "not a symbol");
- }
- static JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val, ret;
- val = js_thisSymbolValue(ctx, this_val);
- if (JS_IsException(val))
- return val;
- /* XXX: use JS_ToStringInternal() with a flags */
- ret = js_string_constructor(ctx, JS_UNDEFINED, 1, vc(&val));
- JS_FreeValue(ctx, val);
- return ret;
- }
- static JSValue js_symbol_valueOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_thisSymbolValue(ctx, this_val);
- }
- static JSValue js_symbol_get_description(JSContext *ctx, JSValueConst this_val)
- {
- JSValue val, ret;
- JSAtomStruct *p;
- val = js_thisSymbolValue(ctx, this_val);
- if (JS_IsException(val))
- return val;
- p = JS_VALUE_GET_PTR(val);
- if (p->len == 0 && p->is_wide_char != 0) {
- ret = JS_UNDEFINED;
- } else {
- ret = JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p));
- }
- JS_FreeValue(ctx, val);
- return ret;
- }
- static const JSCFunctionListEntry js_symbol_proto_funcs[] = {
- JS_CFUNC_DEF("toString", 0, js_symbol_toString ),
- JS_CFUNC_DEF("valueOf", 0, js_symbol_valueOf ),
- // XXX: should have writable: false
- JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_symbol_valueOf ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Symbol", JS_PROP_CONFIGURABLE ),
- JS_CGETSET_DEF("description", js_symbol_get_description, NULL ),
- };
- static JSValue js_symbol_for(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue str;
- str = JS_ToString(ctx, argv[0]);
- if (JS_IsException(str))
- return JS_EXCEPTION;
- return JS_NewSymbolInternal(ctx, JS_VALUE_GET_STRING(str), JS_ATOM_TYPE_GLOBAL_SYMBOL);
- }
- static JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSAtomStruct *p;
- if (!JS_IsSymbol(argv[0]))
- return JS_ThrowTypeError(ctx, "not a symbol");
- p = JS_VALUE_GET_PTR(argv[0]);
- if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL)
- return JS_UNDEFINED;
- return js_dup(JS_MKPTR(JS_TAG_STRING, p));
- }
- static const JSCFunctionListEntry js_symbol_funcs[] = {
- JS_CFUNC_DEF("for", 1, js_symbol_for ),
- JS_CFUNC_DEF("keyFor", 1, js_symbol_keyFor ),
- };
- /* Set/Map/WeakSet/WeakMap */
- #define MAGIC_SET (1 << 0)
- #define MAGIC_WEAK (1 << 1)
- static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv, int magic)
- {
- JSMapState *s;
- JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED;
- JSValueConst arr;
- bool is_set, is_weak;
- is_set = magic & MAGIC_SET;
- is_weak = ((magic & MAGIC_WEAK) != 0);
- obj = js_create_from_ctor(ctx, new_target, JS_CLASS_MAP + magic);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- s = js_mallocz(ctx, sizeof(*s));
- if (!s)
- goto fail;
- init_list_head(&s->records);
- s->is_weak = is_weak;
- JS_SetOpaqueInternal(obj, s);
- s->hash_size = 1;
- s->hash_table = js_malloc(ctx, sizeof(s->hash_table[0]) * s->hash_size);
- if (!s->hash_table)
- goto fail;
- init_list_head(&s->hash_table[0]);
- s->record_count_threshold = 4;
- arr = JS_UNDEFINED;
- if (argc > 0)
- arr = argv[0];
- if (!JS_IsUndefined(arr) && !JS_IsNull(arr)) {
- JSValue item, ret;
- int done;
- adder = JS_GetProperty(ctx, obj, is_set ? JS_ATOM_add : JS_ATOM_set);
- if (JS_IsException(adder))
- goto fail;
- if (!JS_IsFunction(ctx, adder)) {
- JS_ThrowTypeError(ctx, "set/add is not a function");
- goto fail;
- }
- iter = JS_GetIterator(ctx, arr, false);
- if (JS_IsException(iter))
- goto fail;
- next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next_method))
- goto fail;
- for(;;) {
- item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
- if (JS_IsException(item))
- goto fail;
- if (done)
- break;
- if (is_set) {
- ret = JS_Call(ctx, adder, obj, 1, vc(&item));
- if (JS_IsException(ret)) {
- JS_FreeValue(ctx, item);
- goto fail;
- }
- } else {
- JSValue key, value;
- JSValueConst args[2];
- key = JS_UNDEFINED;
- value = JS_UNDEFINED;
- if (!JS_IsObject(item)) {
- JS_ThrowTypeErrorNotAnObject(ctx);
- goto fail1;
- }
- key = JS_GetPropertyUint32(ctx, item, 0);
- if (JS_IsException(key))
- goto fail1;
- value = JS_GetPropertyUint32(ctx, item, 1);
- if (JS_IsException(value))
- goto fail1;
- args[0] = key;
- args[1] = value;
- ret = JS_Call(ctx, adder, obj, 2, args);
- if (JS_IsException(ret)) {
- fail1:
- JS_FreeValue(ctx, item);
- JS_FreeValue(ctx, key);
- JS_FreeValue(ctx, value);
- goto fail;
- }
- JS_FreeValue(ctx, key);
- JS_FreeValue(ctx, value);
- }
- JS_FreeValue(ctx, ret);
- JS_FreeValue(ctx, item);
- }
- JS_FreeValue(ctx, next_method);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, adder);
- }
- return obj;
- fail:
- if (JS_IsObject(iter)) {
- /* close the iterator object, preserving pending exception */
- JS_IteratorClose(ctx, iter, true);
- }
- JS_FreeValue(ctx, next_method);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, adder);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- /* XXX: could normalize strings to speed up comparison */
- static JSValue map_normalize_key(JSContext *ctx, JSValue key)
- {
- uint32_t tag = JS_VALUE_GET_TAG(key);
- // convert -0.0 to +0.0
- // not a leak; |key| and return value are not heap-allocated
- if (JS_TAG_IS_FLOAT64(tag) && JS_VALUE_GET_FLOAT64(key) == 0.0)
- return js_int32(0);
- return key;
- }
- static JSValueConst map_normalize_key_const(JSContext *ctx, JSValueConst key)
- {
- return safe_const(map_normalize_key(ctx, unsafe_unconst(key)));
- }
- /* XXX: better hash ? */
- static uint32_t map_hash_key(JSContext *ctx, JSValueConst key)
- {
- uint32_t tag = JS_VALUE_GET_NORM_TAG(key);
- uint32_t h;
- double d;
- JSFloat64Union u;
- JSBigInt *r;
- switch(tag) {
- case JS_TAG_BOOL:
- h = JS_VALUE_GET_INT(key);
- break;
- case JS_TAG_STRING:
- h = hash_string(JS_VALUE_GET_STRING(key), 0);
- break;
- case JS_TAG_OBJECT:
- case JS_TAG_SYMBOL:
- h = (uintptr_t)JS_VALUE_GET_PTR(key) * 3163;
- break;
- case JS_TAG_INT:
- d = JS_VALUE_GET_INT(key);
- goto hash_float64;
- case JS_TAG_SHORT_BIG_INT:
- d = JS_VALUE_GET_SHORT_BIG_INT(key);
- goto hash_float64;
- case JS_TAG_BIG_INT:
- r = JS_VALUE_GET_PTR(key);
- h = hash_string8((void *)r->tab, r->len * sizeof(*r->tab), 0);
- break;
- case JS_TAG_FLOAT64:
- d = JS_VALUE_GET_FLOAT64(key);
- /* normalize the NaN */
- if (isnan(d))
- d = NAN;
- hash_float64:
- u.d = d;
- h = (u.u32[0] ^ u.u32[1]) * 3163;
- return h ^= JS_TAG_FLOAT64;
- default:
- h = 0;
- break;
- }
- h ^= tag;
- return h;
- }
- static JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s,
- JSValueConst key)
- {
- struct list_head *el;
- JSMapRecord *mr;
- uint32_t h;
- h = map_hash_key(ctx, key) & (s->hash_size - 1);
- list_for_each(el, &s->hash_table[h]) {
- mr = list_entry(el, JSMapRecord, hash_link);
- if (js_same_value_zero(ctx, mr->key, key))
- return mr;
- }
- return NULL;
- }
- static void map_hash_resize(JSContext *ctx, JSMapState *s)
- {
- uint32_t new_hash_size, i, h;
- struct list_head *new_hash_table, *el;
- JSMapRecord *mr;
- /* XXX: no reporting of memory allocation failure */
- if (s->hash_size == 1)
- new_hash_size = 4;
- else
- new_hash_size = s->hash_size * 2;
- new_hash_table = js_realloc(ctx, s->hash_table,
- sizeof(new_hash_table[0]) * new_hash_size);
- if (!new_hash_table)
- return;
- for(i = 0; i < new_hash_size; i++)
- init_list_head(&new_hash_table[i]);
- list_for_each(el, &s->records) {
- mr = list_entry(el, JSMapRecord, link);
- if (!mr->empty) {
- h = map_hash_key(ctx, mr->key) & (new_hash_size - 1);
- list_add_tail(&mr->hash_link, &new_hash_table[h]);
- }
- }
- s->hash_table = new_hash_table;
- s->hash_size = new_hash_size;
- s->record_count_threshold = new_hash_size * 2;
- }
- static JSWeakRefRecord **get_first_weak_ref(JSValueConst key)
- {
- switch (JS_VALUE_GET_TAG(key)) {
- case JS_TAG_OBJECT:
- {
- JSObject *p = JS_VALUE_GET_OBJ(key);
- return &p->first_weak_ref;
- }
- break;
- case JS_TAG_SYMBOL:
- {
- JSAtomStruct *p = JS_VALUE_GET_PTR(key);
- return &p->first_weak_ref;
- }
- break;
- default:
- abort();
- }
- return NULL; // pacify compiler
- }
- static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
- JSValueConst key)
- {
- uint32_t h;
- JSMapRecord *mr;
- mr = js_malloc(ctx, sizeof(*mr));
- if (!mr)
- return NULL;
- mr->ref_count = 1;
- mr->map = s;
- mr->empty = false;
- if (s->is_weak) {
- JSWeakRefRecord *wr = js_malloc(ctx, sizeof(*wr));
- if (!wr) {
- js_free(ctx, mr);
- return NULL;
- }
- wr->kind = JS_WEAK_REF_KIND_MAP;
- wr->u.map_record = mr;
- insert_weakref_record(key, wr);
- mr->key = unsafe_unconst(key);
- } else {
- mr->key = js_dup(key);
- }
- h = map_hash_key(ctx, key) & (s->hash_size - 1);
- list_add_tail(&mr->hash_link, &s->hash_table[h]);
- list_add_tail(&mr->link, &s->records);
- s->record_count++;
- if (s->record_count >= s->record_count_threshold) {
- map_hash_resize(ctx, s);
- }
- return mr;
- }
- /* Remove the weak reference from the object weak
- reference list. we don't use a doubly linked list to
- save space, assuming a given object has few weak
- references to it */
- static void delete_map_weak_ref(JSRuntime *rt, JSMapRecord *mr)
- {
- JSWeakRefRecord **pwr, *wr;
- pwr = get_first_weak_ref(mr->key);
- for(;;) {
- wr = *pwr;
- assert(wr != NULL);
- if (wr->kind == JS_WEAK_REF_KIND_MAP && wr->u.map_record == mr)
- break;
- pwr = &wr->next_weak_ref;
- }
- *pwr = wr->next_weak_ref;
- js_free_rt(rt, wr);
- }
- static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)
- {
- if (mr->empty)
- return;
- list_del(&mr->hash_link);
- if (s->is_weak) {
- delete_map_weak_ref(rt, mr);
- } else {
- JS_FreeValueRT(rt, mr->key);
- }
- JS_FreeValueRT(rt, mr->value);
- if (--mr->ref_count == 0) {
- list_del(&mr->link);
- js_free_rt(rt, mr);
- } else {
- /* keep a zombie record for iterators */
- mr->empty = true;
- mr->key = JS_UNDEFINED;
- mr->value = JS_UNDEFINED;
- }
- s->record_count--;
- }
- static void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
- {
- if (--mr->ref_count == 0) {
- /* the record can be safely removed */
- assert(mr->empty);
- list_del(&mr->link);
- js_free_rt(rt, mr);
- }
- }
- static JSValue js_map_set(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
- JSMapRecord *mr;
- JSValueConst key, value;
- int is_set;
- if (!s)
- return JS_EXCEPTION;
- is_set = (magic & MAGIC_SET);
- key = map_normalize_key_const(ctx, argv[0]);
- if (s->is_weak && !is_valid_weakref_target(key))
- return JS_ThrowTypeError(ctx, "invalid value used as %s key", is_set ? "WeakSet" : "WeakMap");
- if (is_set)
- value = JS_UNDEFINED;
- else
- value = argv[1];
- mr = map_find_record(ctx, s, key);
- if (mr) {
- JS_FreeValue(ctx, mr->value);
- } else {
- mr = map_add_record(ctx, s, key);
- if (!mr)
- return JS_EXCEPTION;
- }
- mr->value = js_dup(value);
- return js_dup(this_val);
- }
- static JSValue js_map_get(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
- JSMapRecord *mr;
- JSValueConst key;
- if (!s)
- return JS_EXCEPTION;
- key = map_normalize_key_const(ctx, argv[0]);
- mr = map_find_record(ctx, s, key);
- if (!mr)
- return JS_UNDEFINED;
- else
- return js_dup(mr->value);
- }
- static JSValue js_map_getOrInsert(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- bool computed = magic & 1;
- JSClassID class_id = magic >> 1;
- JSMapState *s = JS_GetOpaque2(ctx, this_val, class_id);
- JSMapRecord *mr;
- JSValueConst key;
- JSValue value;
- if (!s)
- return JS_EXCEPTION;
- if (computed && check_function(ctx, argv[1]))
- return JS_EXCEPTION;
- key = map_normalize_key_const(ctx, argv[0]);
- if (s->is_weak && !is_valid_weakref_target(key))
- return JS_ThrowTypeError(ctx, "invalid value used as WeakMap key");
- mr = map_find_record(ctx, s, key);
- if (!mr) {
- if (computed) {
- value = JS_Call(ctx, argv[1], JS_UNDEFINED, 1, &key);
- if (JS_IsException(value))
- return JS_EXCEPTION;
- mr = map_find_record(ctx, s, key);
- if (mr)
- map_delete_record(ctx->rt, s, mr);
- } else {
- value = js_dup(argv[1]);
- }
- mr = map_add_record(ctx, s, key);
- if (!mr) {
- JS_FreeValue(ctx, value);
- return JS_EXCEPTION;
- }
- mr->value = value;
- }
- return js_dup(mr->value);
- }
- static JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
- JSMapRecord *mr;
- JSValueConst key;
- if (!s)
- return JS_EXCEPTION;
- key = map_normalize_key_const(ctx, argv[0]);
- mr = map_find_record(ctx, s, key);
- return js_bool(mr != NULL);
- }
- static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
- JSMapRecord *mr;
- JSValueConst key;
- if (!s)
- return JS_EXCEPTION;
- key = map_normalize_key_const(ctx, argv[0]);
- mr = map_find_record(ctx, s, key);
- if (!mr)
- return JS_FALSE;
- map_delete_record(ctx->rt, s, mr);
- return JS_TRUE;
- }
- static JSValue js_map_clear(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
- struct list_head *el, *el1;
- JSMapRecord *mr;
- if (!s)
- return JS_EXCEPTION;
- list_for_each_safe(el, el1, &s->records) {
- mr = list_entry(el, JSMapRecord, link);
- map_delete_record(ctx->rt, s, mr);
- }
- return JS_UNDEFINED;
- }
- static JSValue js_map_get_size(JSContext *ctx, JSValueConst this_val, int magic)
- {
- JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
- if (!s)
- return JS_EXCEPTION;
- return js_uint32(s->record_count);
- }
- static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
- JSValueConst func, this_arg;
- JSValue ret, args[3];
- struct list_head *el;
- JSMapRecord *mr;
- if (!s)
- return JS_EXCEPTION;
- func = argv[0];
- if (argc > 1)
- this_arg = argv[1];
- else
- this_arg = JS_UNDEFINED;
- if (check_function(ctx, func))
- return JS_EXCEPTION;
- /* Note: the list can be modified while traversing it, but the
- current element is locked */
- el = s->records.next;
- while (el != &s->records) {
- mr = list_entry(el, JSMapRecord, link);
- if (!mr->empty) {
- mr->ref_count++;
- /* must duplicate in case the record is deleted */
- args[1] = js_dup(mr->key);
- if (magic)
- args[0] = args[1];
- else
- args[0] = js_dup(mr->value);
- args[2] = unsafe_unconst(this_val);
- ret = JS_Call(ctx, func, this_arg, 3, vc(args));
- JS_FreeValue(ctx, args[0]);
- if (!magic)
- JS_FreeValue(ctx, args[1]);
- el = el->next;
- map_decref_record(ctx->rt, mr);
- if (JS_IsException(ret))
- return ret;
- JS_FreeValue(ctx, ret);
- } else {
- el = el->next;
- }
- }
- return JS_UNDEFINED;
- }
- static JSValue js_map_groupBy(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue res, iter, next, groups, k, v, prop;
- JSValueConst cb, args[2];
- int64_t idx;
- int done;
- // "is function?" check must be observed before argv[0] is accessed
- cb = argv[1];
- if (check_function(ctx, cb))
- return JS_EXCEPTION;
- iter = JS_GetIterator(ctx, argv[0], /*is_async*/false);
- if (JS_IsException(iter))
- return JS_EXCEPTION;
- k = JS_UNDEFINED;
- v = JS_UNDEFINED;
- prop = JS_UNDEFINED;
- groups = JS_UNDEFINED;
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- goto exception;
- groups = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, 0);
- if (JS_IsException(groups))
- goto exception;
- for (idx = 0; ; idx++) {
- v = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
- if (JS_IsException(v))
- goto exception;
- if (done)
- break; // v is JS_UNDEFINED
- args[0] = v;
- args[1] = js_int64(idx);
- k = JS_Call(ctx, cb, ctx->global_obj, 2, args);
- if (JS_IsException(k))
- goto exception;
- prop = js_map_get(ctx, groups, 1, vc(&k), 0);
- if (JS_IsException(prop))
- goto exception;
- if (JS_IsUndefined(prop)) {
- prop = JS_NewArray(ctx);
- if (JS_IsException(prop))
- goto exception;
- args[0] = k;
- args[1] = prop;
- res = js_map_set(ctx, groups, 2, args, 0);
- if (JS_IsException(res))
- goto exception;
- JS_FreeValue(ctx, res);
- }
- res = js_array_push(ctx, prop, 1, vc(&v), /*unshift*/0);
- if (JS_IsException(res))
- goto exception;
- // res is an int64
- JS_FreeValue(ctx, prop);
- JS_FreeValue(ctx, k);
- JS_FreeValue(ctx, v);
- prop = JS_UNDEFINED;
- k = JS_UNDEFINED;
- v = JS_UNDEFINED;
- }
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, next);
- return groups;
- exception:
- JS_FreeValue(ctx, prop);
- JS_FreeValue(ctx, k);
- JS_FreeValue(ctx, v);
- JS_FreeValue(ctx, groups);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, next);
- return JS_EXCEPTION;
- }
- static void js_map_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p;
- JSMapState *s;
- struct list_head *el, *el1;
- JSMapRecord *mr;
- p = JS_VALUE_GET_OBJ(val);
- s = p->u.map_state;
- if (s) {
- /* if the object is deleted we are sure that no iterator is
- using it */
- list_for_each_safe(el, el1, &s->records) {
- mr = list_entry(el, JSMapRecord, link);
- if (!mr->empty) {
- if (s->is_weak)
- delete_map_weak_ref(rt, mr);
- else
- JS_FreeValueRT(rt, mr->key);
- JS_FreeValueRT(rt, mr->value);
- }
- js_free_rt(rt, mr);
- }
- js_free_rt(rt, s->hash_table);
- js_free_rt(rt, s);
- }
- }
- static void js_map_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSMapState *s;
- struct list_head *el;
- JSMapRecord *mr;
- s = p->u.map_state;
- if (s) {
- assert(!s->is_weak);
- list_for_each(el, &s->records) {
- mr = list_entry(el, JSMapRecord, link);
- JS_MarkValue(rt, mr->key, mark_func);
- JS_MarkValue(rt, mr->value, mark_func);
- }
- }
- }
- /* Map Iterator */
- typedef struct JSMapIteratorData {
- JSValue obj;
- JSIteratorKindEnum kind;
- JSMapRecord *cur_record;
- } JSMapIteratorData;
- static void js_map_iterator_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p;
- JSMapIteratorData *it;
- p = JS_VALUE_GET_OBJ(val);
- it = p->u.map_iterator_data;
- if (it) {
- /* During the GC sweep phase the Map finalizer may be
- called before the Map iterator finalizer */
- if (JS_IsLiveObject(rt, it->obj) && it->cur_record) {
- map_decref_record(rt, it->cur_record);
- }
- JS_FreeValueRT(rt, it->obj);
- js_free_rt(rt, it);
- }
- }
- static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSMapIteratorData *it;
- it = p->u.map_iterator_data;
- if (it) {
- /* the record is already marked by the object */
- JS_MarkValue(rt, it->obj, mark_func);
- }
- }
- static JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSIteratorKindEnum kind;
- JSMapState *s;
- JSMapIteratorData *it;
- JSValue enum_obj;
- kind = magic >> 2;
- magic &= 3;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
- if (!s)
- return JS_EXCEPTION;
- enum_obj = JS_NewObjectClass(ctx, JS_CLASS_MAP_ITERATOR + magic);
- if (JS_IsException(enum_obj))
- goto fail;
- it = js_malloc(ctx, sizeof(*it));
- if (!it) {
- JS_FreeValue(ctx, enum_obj);
- goto fail;
- }
- it->obj = js_dup(this_val);
- it->kind = kind;
- it->cur_record = NULL;
- JS_SetOpaqueInternal(enum_obj, it);
- return enum_obj;
- fail:
- return JS_EXCEPTION;
- }
- static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int *pdone, int magic)
- {
- JSMapIteratorData *it;
- JSMapState *s;
- JSMapRecord *mr;
- struct list_head *el;
- it = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP_ITERATOR + magic);
- if (!it) {
- *pdone = false;
- return JS_EXCEPTION;
- }
- if (JS_IsUndefined(it->obj))
- goto done;
- s = JS_GetOpaque(it->obj, JS_CLASS_MAP + magic);
- assert(s != NULL);
- if (!it->cur_record) {
- el = s->records.next;
- } else {
- mr = it->cur_record;
- el = mr->link.next;
- map_decref_record(ctx->rt, mr); /* the record can be freed here */
- }
- for(;;) {
- if (el == &s->records) {
- /* no more record */
- it->cur_record = NULL;
- JS_FreeValue(ctx, it->obj);
- it->obj = JS_UNDEFINED;
- done:
- /* end of enumeration */
- *pdone = true;
- return JS_UNDEFINED;
- }
- mr = list_entry(el, JSMapRecord, link);
- if (!mr->empty)
- break;
- /* get the next record */
- el = mr->link.next;
- }
- /* lock the record so that it won't be freed */
- mr->ref_count++;
- it->cur_record = mr;
- *pdone = false;
- if (it->kind == JS_ITERATOR_KIND_KEY) {
- return js_dup(mr->key);
- } else {
- JSValueConst args[2];
- args[0] = mr->key;
- if (magic)
- args[1] = mr->key;
- else
- args[1] = mr->value;
- if (it->kind == JS_ITERATOR_KIND_VALUE) {
- return js_dup(args[1]);
- } else {
- return js_create_array(ctx, 2, args);
- }
- }
- }
- static JSValue js_map_read(BCReaderState *s, int magic)
- {
- JSContext *ctx = s->ctx;
- JSValue obj, rv, argv[2];
- uint32_t i, prop_count;
- argv[0] = JS_UNDEFINED;
- argv[1] = JS_UNDEFINED;
- obj = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, magic);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- if (BC_add_object_ref(s, obj))
- goto fail;
- if (bc_get_leb128(s, &prop_count))
- goto fail;
- for(i = 0; i < prop_count; i++) {
- argv[0] = JS_ReadObjectRec(s);
- if (JS_IsException(argv[0]))
- goto fail;
- if (!(magic & MAGIC_SET)) {
- argv[1] = JS_ReadObjectRec(s);
- if (JS_IsException(argv[1]))
- goto fail;
- }
- rv = js_map_set(ctx, obj, countof(argv), vc(argv), magic);
- if (JS_IsException(rv))
- goto fail;
- JS_FreeValue(ctx, rv);
- JS_FreeValue(ctx, argv[0]);
- JS_FreeValue(ctx, argv[1]);
- argv[0] = JS_UNDEFINED;
- argv[1] = JS_UNDEFINED;
- }
- return obj;
- fail:
- JS_FreeValue(ctx, obj);
- JS_FreeValue(ctx, argv[0]);
- JS_FreeValue(ctx, argv[1]);
- return JS_EXCEPTION;
- }
- static int js_map_write(BCWriterState *s, struct JSMapState *map_state,
- int magic)
- {
- struct list_head *el;
- JSMapRecord *mr;
- bc_put_leb128(s, map_state ? map_state->record_count : 0);
- if (map_state) {
- list_for_each(el, &map_state->records) {
- mr = list_entry(el, JSMapRecord, link);
- if (JS_WriteObjectRec(s, mr->key))
- return -1;
- // mr->value is always JS_UNDEFINED for sets
- if (!(magic & MAGIC_SET))
- if (JS_WriteObjectRec(s, mr->value))
- return -1;
- }
- }
- return 0;
- }
- static JSValue JS_ReadMap(BCReaderState *s)
- {
- return js_map_read(s, 0);
- }
- static JSValue JS_ReadSet(BCReaderState *s)
- {
- return js_map_read(s, MAGIC_SET);
- }
- static int JS_WriteMap(BCWriterState *s, struct JSMapState *map_state)
- {
- return js_map_write(s, map_state, 0);
- }
- static int JS_WriteSet(BCWriterState *s, struct JSMapState *map_state)
- {
- return js_map_write(s, map_state, MAGIC_SET);
- }
- static int js_setlike_get_props(JSContext *ctx, JSValueConst setlike,
- uint64_t *psize, JSValue *phas, JSValue *pkeys)
- {
- JSValue has, keys, v;
- JSMapState *s;
- uint64_t size;
- double d;
- keys = JS_UNDEFINED;
- has = JS_UNDEFINED;
- s = JS_GetOpaque(setlike, JS_CLASS_SET);
- if (s) {
- size = s->record_count;
- } else {
- v = JS_GetProperty(ctx, setlike, JS_ATOM_size);
- if (JS_IsException(v))
- return -1;
- if (JS_IsUndefined(v)) {
- JS_ThrowTypeError(ctx, ".size is undefined");
- return -1;
- }
- if (JS_ToFloat64Free(ctx, &d, v) < 0)
- return -1;
- if (d < 0) {
- JS_ThrowRangeError(ctx, ".size is not a legal size");
- return -1;
- }
- if (isnan(d)) {
- JS_ThrowTypeError(ctx, ".size is not a legal size");
- return -1;
- }
- if (isinf(d) || d > (double)MAX_SAFE_INTEGER) {
- size = UINT64_MAX;
- } else {
- size = (uint64_t)d; // cast for expository reasons
- }
- }
- has = JS_GetProperty(ctx, setlike, JS_ATOM_has);
- if (JS_IsException(has))
- return -1;
- if (!JS_IsFunction(ctx, has)) {
- JS_ThrowTypeError(ctx, ".has is not a function");
- goto fail;
- }
- keys = JS_GetProperty(ctx, setlike, JS_ATOM_keys);
- if (JS_IsException(keys))
- goto fail;
- if (!JS_IsFunction(ctx, keys)) {
- JS_ThrowTypeError(ctx, ".keys is not a function");
- goto fail;
- }
- *psize = size;
- *phas = has;
- *pkeys = keys;
- return 0;
- fail:
- JS_FreeValue(ctx, has);
- JS_FreeValue(ctx, keys);
- return -1;
- }
- static JSValue js_set_isDisjointFrom(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue has, item, iter, keys, next, rv, rval;
- JSValueConst setlike;
- int done;
- bool found;
- JSMapState *s;
- uint64_t size;
- int ok;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- return JS_EXCEPTION;
- setlike = argv[0];
- if (js_setlike_get_props(ctx, setlike, &size, &has, &keys) < 0)
- return JS_EXCEPTION;
- iter = JS_UNDEFINED;
- next = JS_UNDEFINED;
- rval = JS_EXCEPTION;
- if (s->record_count > size) {
- iter = JS_Call(ctx, keys, setlike, 0, NULL);
- if (JS_IsException(iter))
- goto exception;
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- goto exception;
- found = false;
- for (;;) {
- item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
- if (JS_IsException(item))
- goto exception;
- if (done) // item is JS_UNDEFINED
- break;
- item = map_normalize_key(ctx, item);
- found = (NULL != map_find_record(ctx, s, item));
- JS_FreeValue(ctx, item);
- if (!found)
- continue;
- if (JS_IteratorClose(ctx, iter, /*is_exception_pending*/false) < 0)
- goto exception;
- break;
- }
- } else {
- iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET);
- if (JS_IsException(iter))
- goto exception;
- found = false;
- do {
- item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET);
- if (JS_IsException(item))
- goto exception;
- if (done) // item is JS_UNDEFINED
- break;
- rv = JS_Call(ctx, has, setlike, 1, vc(&item));
- JS_FreeValue(ctx, item);
- ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION
- if (ok < 0)
- goto exception;
- found = (ok > 0);
- } while (!found);
- }
- rval = !found ? JS_TRUE : JS_FALSE;
- exception:
- JS_FreeValue(ctx, has);
- JS_FreeValue(ctx, keys);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, next);
- return rval;
- }
- static JSValue js_set_isSubsetOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue has, item, iter, keys, next, rv, rval;
- JSValueConst setlike;
- bool found;
- JSMapState *s;
- uint64_t size;
- int done, ok;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- return JS_EXCEPTION;
- setlike = argv[0];
- if (js_setlike_get_props(ctx, setlike, &size, &has, &keys) < 0)
- return JS_EXCEPTION;
- iter = JS_UNDEFINED;
- next = JS_UNDEFINED;
- rval = JS_EXCEPTION;
- found = false;
- if (s->record_count > size)
- goto fini;
- iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET);
- if (JS_IsException(iter))
- goto exception;
- found = true;
- do {
- item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET);
- if (JS_IsException(item))
- goto exception;
- if (done) // item is JS_UNDEFINED
- break;
- rv = JS_Call(ctx, has, setlike, 1, vc(&item));
- JS_FreeValue(ctx, item);
- ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION
- if (ok < 0)
- goto exception;
- found = (ok > 0);
- } while (found);
- fini:
- rval = found ? JS_TRUE : JS_FALSE;
- exception:
- JS_FreeValue(ctx, has);
- JS_FreeValue(ctx, keys);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, next);
- return rval;
- }
- static JSValue js_set_isSupersetOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue has, item, iter, keys, next, rval;
- JSValueConst setlike;
- int done;
- bool found;
- JSMapState *s;
- uint64_t size;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- return JS_EXCEPTION;
- setlike = argv[0];
- if (js_setlike_get_props(ctx, setlike, &size, &has, &keys) < 0)
- return JS_EXCEPTION;
- iter = JS_UNDEFINED;
- next = JS_UNDEFINED;
- rval = JS_EXCEPTION;
- found = false;
- if (s->record_count < size)
- goto fini;
- iter = JS_Call(ctx, keys, setlike, 0, NULL);
- if (JS_IsException(iter))
- goto exception;
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- goto exception;
- found = true;
- for (;;) {
- item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
- if (JS_IsException(item))
- goto exception;
- if (done) // item is JS_UNDEFINED
- break;
- item = map_normalize_key(ctx, item);
- found = (NULL != map_find_record(ctx, s, item));
- JS_FreeValue(ctx, item);
- if (found)
- continue;
- if (JS_IteratorClose(ctx, iter, /*is_exception_pending*/false) < 0)
- goto exception;
- break;
- }
- fini:
- rval = found ? JS_TRUE : JS_FALSE;
- exception:
- JS_FreeValue(ctx, has);
- JS_FreeValue(ctx, keys);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, next);
- return rval;
- }
- static JSValue js_set_intersection(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue has, item, iter, keys, newset, next, rv;
- JSValueConst setlike;
- JSMapState *s, *t;
- JSMapRecord *mr;
- uint64_t size;
- int done, ok;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- return JS_EXCEPTION;
- setlike = argv[0];
- if (js_setlike_get_props(ctx, setlike, &size, &has, &keys) < 0)
- return JS_EXCEPTION;
- iter = JS_UNDEFINED;
- next = JS_UNDEFINED;
- newset = JS_UNDEFINED;
- if (s->record_count > size) {
- iter = JS_Call(ctx, keys, setlike, 0, NULL);
- if (JS_IsException(iter))
- goto exception;
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- goto exception;
- newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);
- if (JS_IsException(newset))
- goto exception;
- t = JS_GetOpaque(newset, JS_CLASS_SET);
- for (;;) {
- item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
- if (JS_IsException(item))
- goto exception;
- if (done) // item is JS_UNDEFINED
- break;
- item = map_normalize_key(ctx, item);
- if (!map_find_record(ctx, s, item)) {
- JS_FreeValue(ctx, item);
- } else if (map_find_record(ctx, t, item)) {
- JS_FreeValue(ctx, item); // no duplicates
- } else if ((mr = map_add_record(ctx, t, item))) {
- mr->value = JS_UNDEFINED;
- } else {
- JS_FreeValue(ctx, item);
- goto exception;
- }
- }
- } else {
- iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET);
- if (JS_IsException(iter))
- goto exception;
- newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);
- if (JS_IsException(newset))
- goto exception;
- t = JS_GetOpaque(newset, JS_CLASS_SET);
- for (;;) {
- item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET);
- if (JS_IsException(item))
- goto exception;
- if (done) // item is JS_UNDEFINED
- break;
- rv = JS_Call(ctx, has, setlike, 1, vc(&item));
- ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION
- if (ok > 0) {
- item = map_normalize_key(ctx, item);
- if (map_find_record(ctx, t, item)) {
- JS_FreeValue(ctx, item); // no duplicates
- } else if ((mr = map_add_record(ctx, t, item))) {
- mr->value = JS_UNDEFINED;
- } else {
- JS_FreeValue(ctx, item);
- goto exception;
- }
- } else {
- JS_FreeValue(ctx, item);
- if (ok < 0)
- goto exception;
- }
- }
- }
- goto fini;
- exception:
- JS_FreeValue(ctx, newset);
- newset = JS_EXCEPTION;
- fini:
- JS_FreeValue(ctx, has);
- JS_FreeValue(ctx, keys);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, next);
- return newset;
- }
- static JSValue js_set_difference(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue has, item, iter, keys, newset, next, rv;
- JSValueConst setlike;
- JSMapState *s, *t;
- JSMapRecord *mr;
- uint64_t size;
- int done;
- int ok;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- return JS_EXCEPTION;
- setlike = argv[0];
- if (js_setlike_get_props(ctx, setlike, &size, &has, &keys) < 0)
- return JS_EXCEPTION;
- iter = JS_UNDEFINED;
- next = JS_UNDEFINED;
- newset = JS_UNDEFINED;
- if (s->record_count > size) {
- iter = JS_Call(ctx, keys, setlike, 0, NULL);
- if (JS_IsException(iter))
- goto exception;
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- goto exception;
- newset = js_map_constructor(ctx, JS_UNDEFINED, 1, &this_val, MAGIC_SET);
- if (JS_IsException(newset))
- goto exception;
- t = JS_GetOpaque(newset, JS_CLASS_SET);
- for (;;) {
- item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
- if (JS_IsException(item))
- goto exception;
- if (done) // item is JS_UNDEFINED
- break;
- item = map_normalize_key(ctx, item);
- mr = map_find_record(ctx, t, item);
- if (mr)
- map_delete_record(ctx->rt, t, mr);
- JS_FreeValue(ctx, item);
- }
- } else {
- iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET);
- if (JS_IsException(iter))
- goto exception;
- newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);
- if (JS_IsException(newset))
- goto exception;
- t = JS_GetOpaque(newset, JS_CLASS_SET);
- for (;;) {
- item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET);
- if (JS_IsException(item))
- goto exception;
- if (done) // item is JS_UNDEFINED
- break;
- rv = JS_Call(ctx, has, setlike, 1, vc(&item));
- ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION
- if (ok == 0) {
- item = map_normalize_key(ctx, item);
- if (map_find_record(ctx, t, item)) {
- JS_FreeValue(ctx, item); // no duplicates
- } else if ((mr = map_add_record(ctx, t, item))) {
- mr->value = JS_UNDEFINED;
- } else {
- JS_FreeValue(ctx, item);
- goto exception;
- }
- } else {
- JS_FreeValue(ctx, item);
- if (ok < 0)
- goto exception;
- }
- }
- }
- goto fini;
- exception:
- JS_FreeValue(ctx, newset);
- newset = JS_EXCEPTION;
- fini:
- JS_FreeValue(ctx, has);
- JS_FreeValue(ctx, keys);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, next);
- return newset;
- }
- static JSValue js_set_symmetricDifference(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue has, item, iter, keys, newset, next;
- JSValueConst setlike;
- struct list_head *el;
- JSMapState *s, *t;
- JSMapRecord *mr;
- uint64_t size;
- int done;
- bool present;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- return JS_EXCEPTION;
- setlike = argv[0];
- if (js_setlike_get_props(ctx, setlike, &size, &has, &keys) < 0)
- return JS_EXCEPTION;
- JS_FreeValue(ctx, has);
- iter = JS_UNDEFINED;
- next = JS_UNDEFINED;
- newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);
- if (JS_IsException(newset))
- goto exception;
- t = JS_GetOpaque(newset, JS_CLASS_SET);
- // can't clone this_val using js_map_constructor(),
- // test262 mandates we don't call the .add method
- list_for_each(el, &s->records) {
- mr = list_entry(el, JSMapRecord, link);
- if (mr->empty)
- continue;
- mr = map_add_record(ctx, t, js_dup(mr->key));
- if (!mr)
- goto exception;
- mr->value = JS_UNDEFINED;
- }
- iter = JS_Call(ctx, keys, setlike, 0, NULL);
- if (JS_IsException(iter))
- goto exception;
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- goto exception;
- for (;;) {
- item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
- if (JS_IsException(item))
- goto exception;
- if (done) // item is JS_UNDEFINED
- break;
- // note the subtlety here: due to mutating iterators, it's
- // possible for keys to disappear during iteration; test262
- // still expects us to maintain insertion order though, so
- // we first check |this|, then |new|; |new| is a copy of |this|
- // - if item exists in |this|, delete (if it exists) from |new|
- // - if item misses in |this| and |new|, add to |new|
- // - if item exists in |new| but misses in |this|, *don't* add it,
- // mutating iterator erased it
- item = map_normalize_key(ctx, item);
- present = (NULL != map_find_record(ctx, s, item));
- mr = map_find_record(ctx, t, item);
- if (present) {
- if (mr)
- map_delete_record(ctx->rt, t, mr);
- JS_FreeValue(ctx, item);
- } else if (mr) {
- JS_FreeValue(ctx, item);
- } else {
- mr = map_add_record(ctx, t, item);
- if (!mr) {
- JS_FreeValue(ctx, item);
- goto exception;
- }
- mr->value = JS_UNDEFINED;
- }
- }
- goto fini;
- exception:
- JS_FreeValue(ctx, newset);
- newset = JS_EXCEPTION;
- fini:
- JS_FreeValue(ctx, keys);
- JS_FreeValue(ctx, next);
- JS_FreeValue(ctx, iter);
- return newset;
- }
- static JSValue js_set_union(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue has, item, iter, keys, newset, next, rv;
- JSValueConst setlike;
- struct list_head *el;
- JSMapState *s, *t;
- JSMapRecord *mr;
- uint64_t size;
- int done;
- iter = JS_UNDEFINED;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- return JS_EXCEPTION;
- setlike = argv[0];
- if (js_setlike_get_props(ctx, setlike, &size, &has, &keys) < 0)
- return JS_EXCEPTION;
- JS_FreeValue(ctx, has);
- iter = JS_UNDEFINED;
- next = JS_UNDEFINED;
- newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);
- if (JS_IsException(newset))
- goto exception;
- t = JS_GetOpaque(newset, JS_CLASS_SET);
- list_for_each(el, &s->records) {
- mr = list_entry(el, JSMapRecord, link);
- if (mr->empty)
- continue;
- mr = map_add_record(ctx, t, js_dup(mr->key));
- if (!mr)
- goto exception;
- mr->value = JS_UNDEFINED;
- }
- iter = JS_Call(ctx, keys, setlike, 0, NULL);
- if (JS_IsException(iter))
- goto exception;
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- goto exception;
- for (;;) {
- item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
- if (JS_IsException(item))
- goto exception;
- if (done) // item is JS_UNDEFINED
- break;
- rv = js_map_set(ctx, newset, 1, vc(&item), MAGIC_SET);
- JS_FreeValue(ctx, item);
- if (JS_IsException(rv))
- goto exception;
- JS_FreeValue(ctx, rv);
- }
- goto fini;
- exception:
- JS_FreeValue(ctx, newset);
- newset = JS_EXCEPTION;
- fini:
- JS_FreeValue(ctx, keys);
- JS_FreeValue(ctx, next);
- JS_FreeValue(ctx, iter);
- return newset;
- }
- static const JSCFunctionListEntry js_map_funcs[] = {
- JS_CFUNC_DEF("groupBy", 2, js_map_groupBy ),
- JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
- };
- static const JSCFunctionListEntry js_set_funcs[] = {
- JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
- };
- static const JSCFunctionListEntry js_map_proto_funcs[] = {
- JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, 0 ),
- JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, 0 ),
- JS_CFUNC_MAGIC_DEF("getOrInsert", 2, js_map_getOrInsert,
- JS_CLASS_MAP<<1 | /*computed*/false ),
- JS_CFUNC_MAGIC_DEF("getOrInsertComputed", 2, js_map_getOrInsert,
- JS_CLASS_MAP<<1 | /*computed*/true ),
- JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, 0 ),
- JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, 0 ),
- JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, 0 ),
- JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, 0),
- JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, 0 ),
- JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_VALUE << 2) | 0 ),
- JS_CFUNC_MAGIC_DEF("keys", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | 0 ),
- JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | 0 ),
- JS_ALIAS_DEF("[Symbol.iterator]", "entries" ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map", JS_PROP_CONFIGURABLE ),
- };
- static const JSCFunctionListEntry js_map_iterator_proto_funcs[] = {
- JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, 0 ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map Iterator", JS_PROP_CONFIGURABLE ),
- };
- static const JSCFunctionListEntry js_set_proto_funcs[] = {
- JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET ),
- JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET ),
- JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET ),
- JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, MAGIC_SET ),
- JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ),
- JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ),
- JS_CFUNC_DEF("isDisjointFrom", 1, js_set_isDisjointFrom ),
- JS_CFUNC_DEF("isSubsetOf", 1, js_set_isSubsetOf ),
- JS_CFUNC_DEF("isSupersetOf", 1, js_set_isSupersetOf ),
- JS_CFUNC_DEF("intersection", 1, js_set_intersection ),
- JS_CFUNC_DEF("difference", 1, js_set_difference ),
- JS_CFUNC_DEF("symmetricDifference", 1, js_set_symmetricDifference ),
- JS_CFUNC_DEF("union", 1, js_set_union ),
- JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ),
- JS_ALIAS_DEF("keys", "values" ),
- JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
- JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | MAGIC_SET ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set", JS_PROP_CONFIGURABLE ),
- };
- static const JSCFunctionListEntry js_set_iterator_proto_funcs[] = {
- JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, MAGIC_SET ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set Iterator", JS_PROP_CONFIGURABLE ),
- };
- static const JSCFunctionListEntry js_weak_map_proto_funcs[] = {
- JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, MAGIC_WEAK ),
- JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, MAGIC_WEAK ),
- JS_CFUNC_MAGIC_DEF("getOrInsert", 2, js_map_getOrInsert,
- JS_CLASS_WEAKMAP<<1 | /*computed*/false ),
- JS_CFUNC_MAGIC_DEF("getOrInsertComputed", 2, js_map_getOrInsert,
- JS_CLASS_WEAKMAP<<1 | /*computed*/true ),
- JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_WEAK ),
- JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_WEAK ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakMap", JS_PROP_CONFIGURABLE ),
- };
- static const JSCFunctionListEntry js_weak_set_proto_funcs[] = {
- JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET | MAGIC_WEAK ),
- JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET | MAGIC_WEAK ),
- JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET | MAGIC_WEAK ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakSet", JS_PROP_CONFIGURABLE ),
- };
- static const JSCFunctionListEntry * const js_map_proto_funcs_ptr[6] = {
- js_map_proto_funcs,
- js_set_proto_funcs,
- js_weak_map_proto_funcs,
- js_weak_set_proto_funcs,
- js_map_iterator_proto_funcs,
- js_set_iterator_proto_funcs,
- };
- static const uint8_t js_map_proto_funcs_count[6] = {
- countof(js_map_proto_funcs),
- countof(js_set_proto_funcs),
- countof(js_weak_map_proto_funcs),
- countof(js_weak_set_proto_funcs),
- countof(js_map_iterator_proto_funcs),
- countof(js_set_iterator_proto_funcs),
- };
- void JS_AddIntrinsicMapSet(JSContext *ctx)
- {
- int i;
- JSValue obj1;
- char buf[ATOM_GET_STR_BUF_SIZE];
- for(i = 0; i < 4; i++) {
- const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf),
- JS_ATOM_Map + i);
- int class_id = JS_CLASS_MAP + i;
- ctx->class_proto[class_id] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[class_id],
- js_map_proto_funcs_ptr[i],
- js_map_proto_funcs_count[i]);
- obj1 = JS_NewCFunctionMagic(ctx, js_map_constructor, name, 0,
- JS_CFUNC_constructor_magic, i);
- if (class_id == JS_CLASS_MAP)
- JS_SetPropertyFunctionList(ctx, obj1, js_map_funcs, countof(js_map_funcs));
- else if (class_id == JS_CLASS_SET)
- JS_SetPropertyFunctionList(ctx, obj1, js_set_funcs, countof(js_set_funcs));
- JS_NewGlobalCConstructor2(ctx, obj1, name, ctx->class_proto[class_id]);
- }
- for(i = 0; i < 2; i++) {
- ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] =
- JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP_ITERATOR + i],
- js_map_proto_funcs_ptr[i + 4],
- js_map_proto_funcs_count[i + 4]);
- }
- }
- /* Generator */
- static const JSCFunctionListEntry js_generator_function_proto_funcs[] = {
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "GeneratorFunction", JS_PROP_CONFIGURABLE),
- };
- static const JSCFunctionListEntry js_generator_proto_funcs[] = {
- JS_ITERATOR_NEXT_DEF("next", 1, js_generator_next, GEN_MAGIC_NEXT ),
- JS_ITERATOR_NEXT_DEF("return", 1, js_generator_next, GEN_MAGIC_RETURN ),
- JS_ITERATOR_NEXT_DEF("throw", 1, js_generator_next, GEN_MAGIC_THROW ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Generator", JS_PROP_CONFIGURABLE),
- };
- /* Promise */
- typedef struct JSPromiseData {
- JSPromiseStateEnum promise_state;
- /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */
- struct list_head promise_reactions[2];
- bool is_handled; /* Note: only useful to debug */
- JSValue promise_result;
- } JSPromiseData;
- typedef struct JSPromiseFunctionDataResolved {
- int ref_count;
- bool already_resolved;
- } JSPromiseFunctionDataResolved;
- typedef struct JSPromiseFunctionData {
- JSValue promise;
- JSPromiseFunctionDataResolved *presolved;
- } JSPromiseFunctionData;
- typedef struct JSPromiseReactionData {
- struct list_head link; /* not used in promise_reaction_job */
- JSValue resolving_funcs[2];
- JSValue handler;
- } JSPromiseReactionData;
- JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValueConst promise)
- {
- JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
- if (!s)
- return -1;
- return s->promise_state;
- }
- JSValue JS_PromiseResult(JSContext *ctx, JSValueConst promise)
- {
- JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
- if (!s)
- return JS_UNDEFINED;
- return js_dup(s->promise_result);
- }
- bool JS_IsPromise(JSValueConst val)
- {
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return false;
- return JS_VALUE_GET_OBJ(val)->class_id == JS_CLASS_PROMISE;
- }
- static int js_create_resolving_functions(JSContext *ctx, JSValue *args,
- JSValueConst promise);
- static void promise_reaction_data_free(JSRuntime *rt,
- JSPromiseReactionData *rd)
- {
- JS_FreeValueRT(rt, rd->resolving_funcs[0]);
- JS_FreeValueRT(rt, rd->resolving_funcs[1]);
- JS_FreeValueRT(rt, rd->handler);
- js_free_rt(rt, rd);
- }
- #ifdef ENABLE_DUMPS // JS_DUMP_PROMISE
- #define promise_trace(ctx, ...) \
- do { \
- if (check_dump_flag(ctx->rt, JS_DUMP_PROMISE)) \
- printf(__VA_ARGS__); \
- } while (0)
- #else
- #define promise_trace(...)
- #endif
- static JSValue promise_reaction_job(JSContext *ctx, int argc,
- JSValueConst *argv)
- {
- JSValueConst handler, func;
- JSValue res, res2;
- JSValueConst arg;
- bool is_reject;
- assert(argc == 5);
- handler = argv[2];
- is_reject = JS_ToBool(ctx, argv[3]);
- arg = argv[4];
- promise_trace(ctx, "promise_reaction_job: is_reject=%d\n", is_reject);
- if (JS_IsUndefined(handler)) {
- if (is_reject) {
- res = JS_Throw(ctx, js_dup(arg));
- } else {
- res = js_dup(arg);
- }
- } else {
- res = JS_Call(ctx, handler, JS_UNDEFINED, 1, &arg);
- }
- is_reject = JS_IsException(res);
- if (is_reject) {
- if (unlikely(JS_IsUncatchableError(ctx->rt->current_exception)))
- return JS_EXCEPTION;
- res = JS_GetException(ctx);
- }
- func = argv[is_reject];
- /* as an extension, we support undefined as value to avoid
- creating a dummy promise in the 'await' implementation of async
- functions */
- if (!JS_IsUndefined(func)) {
- res2 = JS_Call(ctx, func, JS_UNDEFINED, 1, vc(&res));
- } else {
- res2 = JS_UNDEFINED;
- }
- JS_FreeValue(ctx, res);
- return res2;
- }
- void JS_SetPromiseHook(JSRuntime *rt, JSPromiseHook promise_hook, void *opaque)
- {
- rt->promise_hook = promise_hook;
- rt->promise_hook_opaque = opaque;
- }
- void JS_SetHostPromiseRejectionTracker(JSRuntime *rt,
- JSHostPromiseRejectionTracker *cb,
- void *opaque)
- {
- rt->host_promise_rejection_tracker = cb;
- rt->host_promise_rejection_tracker_opaque = opaque;
- }
- static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise,
- JSValueConst value, bool is_reject)
- {
- JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
- struct list_head *el, *el1;
- JSPromiseReactionData *rd;
- JSValueConst args[5];
- if (!s || s->promise_state != JS_PROMISE_PENDING)
- return; /* should never happen */
- set_value(ctx, &s->promise_result, js_dup(value));
- s->promise_state = JS_PROMISE_FULFILLED + is_reject;
- promise_trace(ctx, "fulfill_or_reject_promise: is_reject=%d\n", is_reject);
- if (s->promise_state == JS_PROMISE_FULFILLED) {
- JSRuntime *rt = ctx->rt;
- if (rt->promise_hook) {
- rt->promise_hook(ctx, JS_PROMISE_HOOK_RESOLVE, promise,
- JS_UNDEFINED, rt->promise_hook_opaque);
- }
- }
- if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
- JSRuntime *rt = ctx->rt;
- if (rt->host_promise_rejection_tracker)
- rt->host_promise_rejection_tracker(ctx, promise, value, false,
- rt->host_promise_rejection_tracker_opaque);
- }
- list_for_each_safe(el, el1, &s->promise_reactions[is_reject]) {
- rd = list_entry(el, JSPromiseReactionData, link);
- args[0] = rd->resolving_funcs[0];
- args[1] = rd->resolving_funcs[1];
- args[2] = rd->handler;
- args[3] = js_bool(is_reject);
- args[4] = value;
- JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
- list_del(&rd->link);
- promise_reaction_data_free(ctx->rt, rd);
- }
- list_for_each_safe(el, el1, &s->promise_reactions[1 - is_reject]) {
- rd = list_entry(el, JSPromiseReactionData, link);
- list_del(&rd->link);
- promise_reaction_data_free(ctx->rt, rd);
- }
- }
- static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
- int argc, JSValueConst *argv)
- {
- JSValueConst promise, thenable, then;
- JSValue args[2], res;
- JSRuntime *rt;
- promise_trace(ctx, "js_promise_resolve_thenable_job\n");
- assert(argc == 3);
- promise = argv[0];
- thenable = argv[1];
- then = argv[2];
- if (js_create_resolving_functions(ctx, args, promise) < 0)
- return JS_EXCEPTION;
- rt = ctx->rt;
- if (rt->promise_hook) {
- rt->promise_hook(ctx, JS_PROMISE_HOOK_BEFORE, promise, JS_UNDEFINED,
- rt->promise_hook_opaque);
- }
- res = JS_Call(ctx, then, thenable, 2, vc(args));
- if (rt->promise_hook) {
- rt->promise_hook(ctx, JS_PROMISE_HOOK_AFTER, promise, JS_UNDEFINED,
- rt->promise_hook_opaque);
- }
- if (JS_IsException(res)) {
- JSValue error = JS_GetException(ctx);
- res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, vc(&error));
- JS_FreeValue(ctx, error);
- }
- JS_FreeValue(ctx, args[0]);
- JS_FreeValue(ctx, args[1]);
- return res;
- }
- static void js_promise_resolve_function_free_resolved(JSRuntime *rt,
- JSPromiseFunctionDataResolved *sr)
- {
- if (--sr->ref_count == 0) {
- js_free_rt(rt, sr);
- }
- }
- static int js_create_resolving_functions(JSContext *ctx,
- JSValue *resolving_funcs,
- JSValueConst promise)
- {
- JSValue obj;
- JSPromiseFunctionData *s;
- JSPromiseFunctionDataResolved *sr;
- int i, ret;
- sr = js_malloc(ctx, sizeof(*sr));
- if (!sr)
- return -1;
- sr->ref_count = 1;
- sr->already_resolved = false; /* must be shared between the two functions */
- ret = 0;
- for(i = 0; i < 2; i++) {
- obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
- JS_CLASS_PROMISE_RESOLVE_FUNCTION + i);
- if (JS_IsException(obj))
- goto fail;
- s = js_malloc(ctx, sizeof(*s));
- if (!s) {
- JS_FreeValue(ctx, obj);
- fail:
- if (i != 0)
- JS_FreeValue(ctx, resolving_funcs[0]);
- ret = -1;
- break;
- }
- sr->ref_count++;
- s->presolved = sr;
- s->promise = js_dup(promise);
- JS_SetOpaqueInternal(obj, s);
- js_function_set_properties(ctx, obj, JS_ATOM_empty_string, 1);
- resolving_funcs[i] = obj;
- }
- js_promise_resolve_function_free_resolved(ctx->rt, sr);
- return ret;
- }
- static void js_promise_resolve_function_finalizer(JSRuntime *rt,
- JSValueConst val)
- {
- JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
- if (s) {
- js_promise_resolve_function_free_resolved(rt, s->presolved);
- JS_FreeValueRT(rt, s->promise);
- js_free_rt(rt, s);
- }
- }
- static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
- if (s) {
- JS_MarkValue(rt, s->promise, mark_func);
- }
- }
- static JSValue js_promise_resolve_function_call(JSContext *ctx,
- JSValueConst func_obj,
- JSValueConst this_val,
- int argc, JSValueConst *argv,
- int flags)
- {
- JSObject *p = JS_VALUE_GET_OBJ(func_obj);
- JSPromiseFunctionData *s;
- JSValueConst args[3];
- JSValueConst resolution;
- JSValue then;
- bool is_reject;
- s = p->u.promise_function_data;
- if (!s || s->presolved->already_resolved)
- return JS_UNDEFINED;
- s->presolved->already_resolved = true;
- is_reject = p->class_id - JS_CLASS_PROMISE_RESOLVE_FUNCTION;
- if (argc > 0)
- resolution = argv[0];
- else
- resolution = JS_UNDEFINED;
- #ifdef ENABLE_DUMPS // JS_DUMP_PROMISE
- if (check_dump_flag(ctx->rt, JS_DUMP_PROMISE)) {
- printf("js_promise_resolving_function_call: is_reject=%d resolution=", is_reject);
- JS_DumpValue(ctx->rt, resolution);
- printf("\n");
- }
- #endif
- if (is_reject || !JS_IsObject(resolution)) {
- goto done;
- } else if (js_same_value(ctx, resolution, s->promise)) {
- JS_ThrowTypeError(ctx, "promise self resolution");
- goto fail_reject;
- }
- then = JS_GetProperty(ctx, resolution, JS_ATOM_then);
- if (JS_IsException(then)) {
- JSValue error;
- fail_reject:
- error = JS_GetException(ctx);
- fulfill_or_reject_promise(ctx, s->promise, error, true);
- JS_FreeValue(ctx, error);
- } else if (!JS_IsFunction(ctx, then)) {
- JS_FreeValue(ctx, then);
- done:
- fulfill_or_reject_promise(ctx, s->promise, resolution, is_reject);
- } else {
- args[0] = s->promise;
- args[1] = resolution;
- args[2] = then;
- JS_EnqueueJob(ctx, js_promise_resolve_thenable_job, 3, args);
- JS_FreeValue(ctx, then);
- }
- return JS_UNDEFINED;
- }
- static void js_promise_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
- struct list_head *el, *el1;
- int i;
- if (!s)
- return;
- for(i = 0; i < 2; i++) {
- list_for_each_safe(el, el1, &s->promise_reactions[i]) {
- JSPromiseReactionData *rd =
- list_entry(el, JSPromiseReactionData, link);
- promise_reaction_data_free(rt, rd);
- }
- }
- JS_FreeValueRT(rt, s->promise_result);
- js_free_rt(rt, s);
- }
- static void js_promise_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
- struct list_head *el;
- int i;
- if (!s)
- return;
- for(i = 0; i < 2; i++) {
- list_for_each(el, &s->promise_reactions[i]) {
- JSPromiseReactionData *rd =
- list_entry(el, JSPromiseReactionData, link);
- JS_MarkValue(rt, rd->resolving_funcs[0], mark_func);
- JS_MarkValue(rt, rd->resolving_funcs[1], mark_func);
- JS_MarkValue(rt, rd->handler, mark_func);
- }
- }
- JS_MarkValue(rt, s->promise_result, mark_func);
- }
- static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- JSValueConst executor;
- JSValue obj;
- JSPromiseData *s;
- JSRuntime *rt;
- JSValue args[2], ret;
- int i;
- executor = argv[0];
- if (check_function(ctx, executor))
- return JS_EXCEPTION;
- obj = js_create_from_ctor(ctx, new_target, JS_CLASS_PROMISE);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- s = js_mallocz(ctx, sizeof(*s));
- if (!s)
- goto fail;
- s->promise_state = JS_PROMISE_PENDING;
- s->is_handled = false;
- for(i = 0; i < 2; i++)
- init_list_head(&s->promise_reactions[i]);
- s->promise_result = JS_UNDEFINED;
- JS_SetOpaqueInternal(obj, s);
- if (js_create_resolving_functions(ctx, args, obj))
- goto fail;
- rt = ctx->rt;
- if (rt->promise_hook) {
- JSValueConst parent_promise = JS_UNDEFINED;
- if (rt->parent_promise)
- parent_promise = rt->parent_promise->value;
- rt->promise_hook(ctx, JS_PROMISE_HOOK_INIT, obj, parent_promise,
- rt->promise_hook_opaque);
- }
- ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, vc(args));
- if (JS_IsException(ret)) {
- JSValue ret2, error;
- error = JS_GetException(ctx);
- ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, vc(&error));
- JS_FreeValue(ctx, error);
- if (JS_IsException(ret2))
- goto fail1;
- JS_FreeValue(ctx, ret2);
- }
- JS_FreeValue(ctx, ret);
- JS_FreeValue(ctx, args[0]);
- JS_FreeValue(ctx, args[1]);
- return obj;
- fail1:
- JS_FreeValue(ctx, args[0]);
- JS_FreeValue(ctx, args[1]);
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_promise_executor(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv,
- int magic, JSValueConst *func_data)
- {
- int i;
- for(i = 0; i < 2; i++) {
- if (!JS_IsUndefined(func_data[i]))
- return JS_ThrowTypeError(ctx, "resolving function already set");
- func_data[i] = js_dup(argv[i]);
- }
- return JS_UNDEFINED;
- }
- static JSValue js_promise_executor_new(JSContext *ctx)
- {
- JSValueConst func_data[2];
- func_data[0] = JS_UNDEFINED;
- func_data[1] = JS_UNDEFINED;
- return JS_NewCFunctionData(ctx, js_promise_executor, 2,
- 0, 2, func_data);
- }
- static JSValue js_new_promise_capability(JSContext *ctx,
- JSValue *resolving_funcs,
- JSValueConst ctor)
- {
- JSValue executor, result_promise;
- JSCFunctionDataRecord *s;
- int i;
- executor = js_promise_executor_new(ctx);
- if (JS_IsException(executor))
- return JS_EXCEPTION;
- if (JS_IsUndefined(ctor)) {
- result_promise = js_promise_constructor(ctx, ctor, 1, vc(&executor));
- } else {
- result_promise = JS_CallConstructor(ctx, ctor, 1, vc(&executor));
- }
- if (JS_IsException(result_promise))
- goto fail;
- s = JS_GetOpaque(executor, JS_CLASS_C_FUNCTION_DATA);
- for(i = 0; i < 2; i++) {
- if (check_function(ctx, s->data[i]))
- goto fail;
- }
- for(i = 0; i < 2; i++)
- resolving_funcs[i] = js_dup(s->data[i]);
- JS_FreeValue(ctx, executor);
- return result_promise;
- fail:
- JS_FreeValue(ctx, executor);
- JS_FreeValue(ctx, result_promise);
- return JS_EXCEPTION;
- }
- JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs)
- {
- return js_new_promise_capability(ctx, resolving_funcs, JS_UNDEFINED);
- }
- static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValue result_promise, resolving_funcs[2], ret;
- bool is_reject = magic;
- if (!JS_IsObject(this_val))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- if (!is_reject && JS_GetOpaque(argv[0], JS_CLASS_PROMISE)) {
- JSValue ctor;
- bool is_same;
- ctor = JS_GetProperty(ctx, argv[0], JS_ATOM_constructor);
- if (JS_IsException(ctor))
- return ctor;
- is_same = js_same_value(ctx, ctor, this_val);
- JS_FreeValue(ctx, ctor);
- if (is_same)
- return js_dup(argv[0]);
- }
- result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
- if (JS_IsException(result_promise))
- return result_promise;
- ret = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, argv);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- if (JS_IsException(ret)) {
- JS_FreeValue(ctx, result_promise);
- return ret;
- }
- JS_FreeValue(ctx, ret);
- return result_promise;
- }
- static JSValue js_promise_withResolvers(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue result_promise, resolving_funcs[2], obj;
- if (!JS_IsObject(this_val))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
- if (JS_IsException(result_promise))
- return JS_EXCEPTION;
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj))
- goto exception;
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_promise, result_promise,
- JS_PROP_C_W_E) < 0) {
- goto exception;
- }
- result_promise = JS_UNDEFINED;
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_resolve, resolving_funcs[0],
- JS_PROP_C_W_E) < 0) {
- goto exception;
- }
- resolving_funcs[0] = JS_UNDEFINED;
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1],
- JS_PROP_C_W_E) < 0) {
- goto exception;
- }
- return obj;
- exception:
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- JS_FreeValue(ctx, result_promise);
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_promise_try(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue result_promise, resolving_funcs[2], ret, ret2;
- bool is_reject = 0;
- if (!JS_IsObject(this_val))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
- if (JS_IsException(result_promise))
- return result_promise;
- ret = JS_Call(ctx, argv[0], JS_UNDEFINED, argc - 1, argv + 1);
- if (JS_IsException(ret)) {
- is_reject = 1;
- ret = JS_GetException(ctx);
- }
- ret2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, vc(&ret));
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- JS_FreeValue(ctx, ret);
- if (JS_IsException(ret2)) {
- JS_FreeValue(ctx, result_promise);
- return ret2;
- }
- JS_FreeValue(ctx, ret2);
- return result_promise;
- }
- static __exception int remainingElementsCount_add(JSContext *ctx,
- JSValueConst resolve_element_env,
- int addend)
- {
- JSValue val;
- int remainingElementsCount;
- val = JS_GetPropertyUint32(ctx, resolve_element_env, 0);
- if (JS_IsException(val))
- return -1;
- if (JS_ToInt32Free(ctx, &remainingElementsCount, val))
- return -1;
- remainingElementsCount += addend;
- if (JS_SetPropertyUint32(ctx, resolve_element_env, 0,
- js_int32(remainingElementsCount)) < 0)
- return -1;
- return (remainingElementsCount == 0);
- }
- #define PROMISE_MAGIC_all 0
- #define PROMISE_MAGIC_allSettled 1
- #define PROMISE_MAGIC_any 2
- static JSValue js_promise_all_resolve_element(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv,
- int magic,
- JSValueConst *func_data)
- {
- int resolve_type = magic & 3;
- int is_reject = magic & 4;
- bool alreadyCalled = JS_ToBool(ctx, func_data[0]);
- JSValueConst values = func_data[2];
- JSValueConst resolve = func_data[3];
- JSValueConst resolve_element_env = func_data[4];
- JSValue ret, obj;
- int is_zero, index;
- if (JS_ToInt32(ctx, &index, func_data[1]))
- return JS_EXCEPTION;
- if (alreadyCalled)
- return JS_UNDEFINED;
- func_data[0] = JS_TRUE;
- if (resolve_type == PROMISE_MAGIC_allSettled) {
- JSValue str;
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- str = js_new_string8(ctx, is_reject ? "rejected" : "fulfilled");
- if (JS_IsException(str))
- goto fail1;
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_status,
- str,
- JS_PROP_C_W_E) < 0)
- goto fail1;
- if (JS_DefinePropertyValue(ctx, obj,
- is_reject ? JS_ATOM_reason : JS_ATOM_value,
- js_dup(argv[0]),
- JS_PROP_C_W_E) < 0) {
- fail1:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- } else {
- obj = js_dup(argv[0]);
- }
- if (JS_DefinePropertyValueUint32(ctx, values, index,
- obj, JS_PROP_C_W_E) < 0)
- return JS_EXCEPTION;
- is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
- if (is_zero < 0)
- return JS_EXCEPTION;
- if (is_zero) {
- if (resolve_type == PROMISE_MAGIC_any) {
- JSValue error;
- error = js_aggregate_error_constructor(ctx, values);
- if (JS_IsException(error))
- return JS_EXCEPTION;
- ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, vc(&error));
- JS_FreeValue(ctx, error);
- } else {
- ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, &values);
- }
- if (JS_IsException(ret))
- return ret;
- JS_FreeValue(ctx, ret);
- }
- return JS_UNDEFINED;
- }
- /* magic = 0: Promise.all 1: Promise.allSettled */
- static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
- JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED;
- JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element;
- JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED;
- JSValueConst then_args[2], resolve_element_data[5];
- int done, index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any);
- if (!JS_IsObject(this_val))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
- if (JS_IsException(result_promise))
- return result_promise;
- promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
- if (JS_IsException(promise_resolve) ||
- check_function(ctx, promise_resolve))
- goto fail_reject;
- iter = JS_GetIterator(ctx, argv[0], false);
- if (JS_IsException(iter)) {
- JSValue error;
- fail_reject:
- error = JS_GetException(ctx);
- ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, vc(&error));
- JS_FreeValue(ctx, error);
- if (JS_IsException(ret))
- goto fail;
- JS_FreeValue(ctx, ret);
- } else {
- next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next_method))
- goto fail_reject;
- values = JS_NewArray(ctx);
- if (JS_IsException(values))
- goto fail_reject;
- resolve_element_env = JS_NewArray(ctx);
- if (JS_IsException(resolve_element_env))
- goto fail_reject;
- /* remainingElementsCount field */
- if (JS_DefinePropertyValueUint32(ctx, resolve_element_env, 0,
- js_int32(1),
- JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
- goto fail_reject;
- index = 0;
- for(;;) {
- /* XXX: conformance: should close the iterator if error on 'done'
- access, but not on 'value' access */
- item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
- if (JS_IsException(item))
- goto fail_reject;
- if (done)
- break;
- next_promise = JS_Call(ctx, promise_resolve,
- this_val, 1, vc(&item));
- JS_FreeValue(ctx, item);
- if (JS_IsException(next_promise)) {
- fail_reject1:
- JS_IteratorClose(ctx, iter, true);
- goto fail_reject;
- }
- resolve_element_data[0] = JS_FALSE;
- resolve_element_data[1] = js_int32(index);
- resolve_element_data[2] = values;
- resolve_element_data[3] = resolving_funcs[is_promise_any];
- resolve_element_data[4] = resolve_element_env;
- resolve_element =
- JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
- magic, 5, resolve_element_data);
- if (JS_IsException(resolve_element)) {
- JS_FreeValue(ctx, next_promise);
- goto fail_reject1;
- }
- if (magic == PROMISE_MAGIC_allSettled) {
- reject_element =
- JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
- magic | 4, 5, resolve_element_data);
- if (JS_IsException(reject_element)) {
- JS_FreeValue(ctx, next_promise);
- goto fail_reject1;
- }
- } else if (magic == PROMISE_MAGIC_any) {
- if (JS_DefinePropertyValueUint32(ctx, values, index,
- JS_UNDEFINED, JS_PROP_C_W_E) < 0)
- goto fail_reject1;
- reject_element = resolve_element;
- resolve_element = js_dup(resolving_funcs[0]);
- } else {
- reject_element = js_dup(resolving_funcs[1]);
- }
- if (remainingElementsCount_add(ctx, resolve_element_env, 1) < 0) {
- JS_FreeValue(ctx, next_promise);
- JS_FreeValue(ctx, resolve_element);
- JS_FreeValue(ctx, reject_element);
- goto fail_reject1;
- }
- then_args[0] = resolve_element;
- then_args[1] = reject_element;
- ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2, then_args);
- JS_FreeValue(ctx, resolve_element);
- JS_FreeValue(ctx, reject_element);
- if (check_exception_free(ctx, ret))
- goto fail_reject1;
- index++;
- }
- is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
- if (is_zero < 0)
- goto fail_reject;
- if (is_zero) {
- if (magic == PROMISE_MAGIC_any) {
- JSValue error;
- error = js_aggregate_error_constructor(ctx, values);
- if (JS_IsException(error))
- goto fail_reject;
- JS_FreeValue(ctx, values);
- values = error;
- }
- ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED,
- 1, vc(&values));
- if (check_exception_free(ctx, ret))
- goto fail_reject;
- }
- }
- done:
- JS_FreeValue(ctx, promise_resolve);
- JS_FreeValue(ctx, resolve_element_env);
- JS_FreeValue(ctx, values);
- JS_FreeValue(ctx, next_method);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- return result_promise;
- fail:
- JS_FreeValue(ctx, result_promise);
- result_promise = JS_EXCEPTION;
- goto done;
- }
- static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
- JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED;
- JSValue promise_resolve = JS_UNDEFINED;
- int done;
- if (!JS_IsObject(this_val))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
- if (JS_IsException(result_promise))
- return result_promise;
- promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
- if (JS_IsException(promise_resolve) ||
- check_function(ctx, promise_resolve))
- goto fail_reject;
- iter = JS_GetIterator(ctx, argv[0], false);
- if (JS_IsException(iter)) {
- JSValue error;
- fail_reject:
- error = JS_GetException(ctx);
- ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, vc(&error));
- JS_FreeValue(ctx, error);
- if (JS_IsException(ret))
- goto fail;
- JS_FreeValue(ctx, ret);
- } else {
- next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next_method))
- goto fail_reject;
- for(;;) {
- /* XXX: conformance: should close the iterator if error on 'done'
- access, but not on 'value' access */
- item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
- if (JS_IsException(item))
- goto fail_reject;
- if (done)
- break;
- next_promise = JS_Call(ctx, promise_resolve,
- this_val, 1, vc(&item));
- JS_FreeValue(ctx, item);
- if (JS_IsException(next_promise)) {
- fail_reject1:
- JS_IteratorClose(ctx, iter, true);
- goto fail_reject;
- }
- ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2,
- vc(resolving_funcs));
- if (check_exception_free(ctx, ret))
- goto fail_reject1;
- }
- }
- done:
- JS_FreeValue(ctx, promise_resolve);
- JS_FreeValue(ctx, next_method);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- return result_promise;
- fail:
- //JS_FreeValue(ctx, next_method); // why not???
- JS_FreeValue(ctx, result_promise);
- result_promise = JS_EXCEPTION;
- goto done;
- }
- static __exception int perform_promise_then(JSContext *ctx,
- JSValueConst promise,
- JSValueConst *resolve_reject,
- JSValueConst *cap_resolving_funcs)
- {
- JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
- JSPromiseReactionData *rd_array[2], *rd;
- int i, j;
- rd_array[0] = NULL;
- rd_array[1] = NULL;
- for(i = 0; i < 2; i++) {
- JSValueConst handler;
- rd = js_mallocz(ctx, sizeof(*rd));
- if (!rd) {
- if (i == 1)
- promise_reaction_data_free(ctx->rt, rd_array[0]);
- return -1;
- }
- for(j = 0; j < 2; j++)
- rd->resolving_funcs[j] = js_dup(cap_resolving_funcs[j]);
- handler = resolve_reject[i];
- if (!JS_IsFunction(ctx, handler))
- handler = JS_UNDEFINED;
- rd->handler = js_dup(handler);
- rd_array[i] = rd;
- }
- if (s->promise_state == JS_PROMISE_PENDING) {
- for(i = 0; i < 2; i++)
- list_add_tail(&rd_array[i]->link, &s->promise_reactions[i]);
- } else {
- JSValueConst args[5];
- if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
- JSRuntime *rt = ctx->rt;
- if (rt->host_promise_rejection_tracker)
- rt->host_promise_rejection_tracker(ctx, promise, s->promise_result,
- true, rt->host_promise_rejection_tracker_opaque);
- }
- i = s->promise_state - JS_PROMISE_FULFILLED;
- rd = rd_array[i];
- args[0] = rd->resolving_funcs[0];
- args[1] = rd->resolving_funcs[1];
- args[2] = rd->handler;
- args[3] = js_bool(i);
- args[4] = s->promise_result;
- JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
- for(i = 0; i < 2; i++)
- promise_reaction_data_free(ctx->rt, rd_array[i]);
- }
- s->is_handled = true;
- return 0;
- }
- static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue ctor, result_promise, resolving_funcs[2];
- bool have_promise_hook;
- JSValueLink link;
- JSPromiseData *s;
- JSRuntime *rt;
- int i, ret;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_PROMISE);
- if (!s)
- return JS_EXCEPTION;
- ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
- if (JS_IsException(ctor))
- return ctor;
- rt = ctx->rt;
- // always restore, even if js_new_promise_capability callee removes hook
- have_promise_hook = (rt->promise_hook != NULL);
- if (have_promise_hook) {
- link = (JSValueLink){rt->parent_promise, this_val};
- rt->parent_promise = &link;
- }
- result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
- if (have_promise_hook)
- rt->parent_promise = link.next;
- JS_FreeValue(ctx, ctor);
- if (JS_IsException(result_promise))
- return result_promise;
- ret = perform_promise_then(ctx, this_val, argv, vc(resolving_funcs));
- for(i = 0; i < 2; i++)
- JS_FreeValue(ctx, resolving_funcs[i]);
- if (ret) {
- JS_FreeValue(ctx, result_promise);
- return JS_EXCEPTION;
- }
- return result_promise;
- }
- static JSValue js_promise_catch(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst args[2];
- args[0] = JS_UNDEFINED;
- args[1] = argv[0];
- return JS_Invoke(ctx, this_val, JS_ATOM_then, 2, args);
- }
- static JSValue js_promise_finally_value_thunk(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int magic, JSValueConst *func_data)
- {
- return js_dup(func_data[0]);
- }
- static JSValue js_promise_finally_thrower(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int magic, JSValueConst *func_data)
- {
- return JS_Throw(ctx, js_dup(func_data[0]));
- }
- static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int magic, JSValueConst *func_data)
- {
- JSValueConst ctor = func_data[0];
- JSValueConst onFinally = func_data[1];
- JSValue res, promise, ret, then_func;
- res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);
- if (JS_IsException(res))
- return res;
- promise = js_promise_resolve(ctx, ctor, 1, vc(&res), 0);
- JS_FreeValue(ctx, res);
- if (JS_IsException(promise))
- return promise;
- if (magic == 0) {
- then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,
- 0, 1, argv);
- } else {
- then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 0,
- 0, 1, argv);
- }
- if (JS_IsException(then_func)) {
- JS_FreeValue(ctx, promise);
- return then_func;
- }
- ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, vc(&then_func));
- JS_FreeValue(ctx, then_func);
- return ret;
- }
- static JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst onFinally = argv[0];
- JSValue ctor, ret;
- JSValue then_funcs[2];
- JSValueConst func_data[2];
- int i;
- ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
- if (JS_IsException(ctor))
- return ctor;
- if (!JS_IsFunction(ctx, onFinally)) {
- then_funcs[0] = js_dup(onFinally);
- then_funcs[1] = js_dup(onFinally);
- } else {
- func_data[0] = ctor;
- func_data[1] = onFinally;
- for(i = 0; i < 2; i++) {
- then_funcs[i] = JS_NewCFunctionData(ctx, js_promise_then_finally_func, 1, i, 2, func_data);
- if (JS_IsException(then_funcs[i])) {
- if (i == 1)
- JS_FreeValue(ctx, then_funcs[0]);
- JS_FreeValue(ctx, ctor);
- return JS_EXCEPTION;
- }
- }
- }
- JS_FreeValue(ctx, ctor);
- ret = JS_Invoke(ctx, this_val, JS_ATOM_then, 2, vc(then_funcs));
- JS_FreeValue(ctx, then_funcs[0]);
- JS_FreeValue(ctx, then_funcs[1]);
- return ret;
- }
- static const JSCFunctionListEntry js_promise_funcs[] = {
- JS_CFUNC_MAGIC_DEF("resolve", 1, js_promise_resolve, 0 ),
- JS_CFUNC_MAGIC_DEF("reject", 1, js_promise_resolve, 1 ),
- JS_CFUNC_MAGIC_DEF("all", 1, js_promise_all, PROMISE_MAGIC_all ),
- JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ),
- JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ),
- JS_CFUNC_DEF("try", 1, js_promise_try ),
- JS_CFUNC_DEF("race", 1, js_promise_race ),
- JS_CFUNC_DEF("withResolvers", 0, js_promise_withResolvers ),
- JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
- };
- static const JSCFunctionListEntry js_promise_proto_funcs[] = {
- JS_CFUNC_DEF("then", 2, js_promise_then ),
- JS_CFUNC_DEF("catch", 1, js_promise_catch ),
- JS_CFUNC_DEF("finally", 1, js_promise_finally ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Promise", JS_PROP_CONFIGURABLE ),
- };
- /* AsyncFunction */
- static const JSCFunctionListEntry js_async_function_proto_funcs[] = {
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncFunction", JS_PROP_CONFIGURABLE ),
- };
- static JSValue js_async_from_sync_iterator_unwrap(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv,
- int magic, JSValueConst *func_data)
- {
- return js_create_iterator_result(ctx, js_dup(argv[0]),
- JS_ToBool(ctx, func_data[0]));
- }
- static JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx,
- bool done)
- {
- JSValueConst func_data[1];
- func_data[0] = js_bool(done);
- return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap,
- 1, 0, 1, func_data);
- }
- /* AsyncIteratorPrototype */
- static const JSCFunctionListEntry js_async_iterator_proto_funcs[] = {
- JS_CFUNC_DEF("[Symbol.asyncIterator]", 0, js_iterator_proto_iterator ),
- };
- /* AsyncFromSyncIteratorPrototype */
- typedef struct JSAsyncFromSyncIteratorData {
- JSValue sync_iter;
- JSValue next_method;
- } JSAsyncFromSyncIteratorData;
- static void js_async_from_sync_iterator_finalizer(JSRuntime *rt,
- JSValueConst val)
- {
- JSAsyncFromSyncIteratorData *s =
- JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
- if (s) {
- JS_FreeValueRT(rt, s->sync_iter);
- JS_FreeValueRT(rt, s->next_method);
- js_free_rt(rt, s);
- }
- }
- static void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSAsyncFromSyncIteratorData *s =
- JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
- if (s) {
- JS_MarkValue(rt, s->sync_iter, mark_func);
- JS_MarkValue(rt, s->next_method, mark_func);
- }
- }
- static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
- JSValue sync_iter)
- {
- JSValue async_iter, next_method;
- JSAsyncFromSyncIteratorData *s;
- next_method = JS_GetProperty(ctx, sync_iter, JS_ATOM_next);
- if (JS_IsException(next_method))
- return JS_EXCEPTION;
- async_iter = JS_NewObjectClass(ctx, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
- if (JS_IsException(async_iter)) {
- JS_FreeValue(ctx, next_method);
- return async_iter;
- }
- s = js_mallocz(ctx, sizeof(*s));
- if (!s) {
- JS_FreeValue(ctx, async_iter);
- JS_FreeValue(ctx, next_method);
- return JS_EXCEPTION;
- }
- s->sync_iter = js_dup(sync_iter);
- s->next_method = next_method;
- JS_SetOpaqueInternal(async_iter, s);
- return async_iter;
- }
- static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int magic)
- {
- JSValue promise, resolving_funcs[2], value, err, method;
- JSAsyncFromSyncIteratorData *s;
- int done;
- int is_reject;
- promise = JS_NewPromiseCapability(ctx, resolving_funcs);
- if (JS_IsException(promise))
- return JS_EXCEPTION;
- s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
- if (!s) {
- JS_ThrowTypeError(ctx, "not an Async-from-Sync Iterator");
- goto reject;
- }
- if (magic == GEN_MAGIC_NEXT) {
- method = js_dup(s->next_method);
- } else {
- method = JS_GetProperty(ctx, s->sync_iter,
- magic == GEN_MAGIC_RETURN ? JS_ATOM_return :
- JS_ATOM_throw);
- if (JS_IsException(method))
- goto reject;
- if (JS_IsUndefined(method) || JS_IsNull(method)) {
- if (magic == GEN_MAGIC_RETURN) {
- err = js_create_iterator_result(ctx, js_dup(argv[0]), true);
- is_reject = 0;
- } else if (JS_IteratorClose(ctx, s->sync_iter, false)) {
- err = JS_GetException(ctx);
- is_reject = 1;
- } else {
- err = JS_MakeError2(ctx, JS_TYPE_ERROR, /*add_backtrace*/true,
- "throw is not a method");
- is_reject = 1;
- }
- goto done_resolve;
- }
- }
- value = JS_IteratorNext2(ctx, s->sync_iter, method,
- argc >= 1 ? 1 : 0, argv, &done);
- JS_FreeValue(ctx, method);
- if (JS_IsException(value))
- goto reject;
- if (done == 2) {
- JSValue obj = value;
- value = JS_IteratorGetCompleteValue(ctx, obj, &done);
- JS_FreeValue(ctx, obj);
- if (JS_IsException(value))
- goto reject;
- }
- if (JS_IsException(value)) {
- JSValue res2;
- reject:
- err = JS_GetException(ctx);
- is_reject = 1;
- done_resolve:
- res2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED,
- 1, vc(&err));
- JS_FreeValue(ctx, err);
- JS_FreeValue(ctx, res2);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- return promise;
- }
- {
- JSValue value_wrapper_promise, resolve_reject[2];
- int res;
- value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor,
- 1, vc(&value), 0);
- if (JS_IsException(value_wrapper_promise)) {
- JS_FreeValue(ctx, value);
- goto reject;
- }
- resolve_reject[0] =
- js_async_from_sync_iterator_unwrap_func_create(ctx, done);
- if (JS_IsException(resolve_reject[0])) {
- JS_FreeValue(ctx, value_wrapper_promise);
- goto fail;
- }
- JS_FreeValue(ctx, value);
- resolve_reject[1] = JS_UNDEFINED;
- res = perform_promise_then(ctx, value_wrapper_promise,
- vc(resolve_reject),
- vc(resolving_funcs));
- JS_FreeValue(ctx, resolve_reject[0]);
- JS_FreeValue(ctx, value_wrapper_promise);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- if (res) {
- JS_FreeValue(ctx, promise);
- return JS_EXCEPTION;
- }
- }
- return promise;
- fail:
- JS_FreeValue(ctx, value);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- JS_FreeValue(ctx, promise);
- return JS_EXCEPTION;
- }
- static const JSCFunctionListEntry js_async_from_sync_iterator_proto_funcs[] = {
- JS_CFUNC_MAGIC_DEF("next", 1, js_async_from_sync_iterator_next, GEN_MAGIC_NEXT ),
- JS_CFUNC_MAGIC_DEF("return", 1, js_async_from_sync_iterator_next, GEN_MAGIC_RETURN ),
- JS_CFUNC_MAGIC_DEF("throw", 1, js_async_from_sync_iterator_next, GEN_MAGIC_THROW ),
- };
- /* AsyncGeneratorFunction */
- static const JSCFunctionListEntry js_async_generator_function_proto_funcs[] = {
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGeneratorFunction", JS_PROP_CONFIGURABLE ),
- };
- /* AsyncGenerator prototype */
- static const JSCFunctionListEntry js_async_generator_proto_funcs[] = {
- JS_CFUNC_MAGIC_DEF("next", 1, js_async_generator_next, GEN_MAGIC_NEXT ),
- JS_CFUNC_MAGIC_DEF("return", 1, js_async_generator_next, GEN_MAGIC_RETURN ),
- JS_CFUNC_MAGIC_DEF("throw", 1, js_async_generator_next, GEN_MAGIC_THROW ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGenerator", JS_PROP_CONFIGURABLE ),
- };
- static JSClassShortDef const js_async_class_def[] = {
- { JS_ATOM_Promise, js_promise_finalizer, js_promise_mark }, /* JS_CLASS_PROMISE */
- { JS_ATOM_PromiseResolveFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_RESOLVE_FUNCTION */
- { JS_ATOM_PromiseRejectFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_REJECT_FUNCTION */
- { JS_ATOM_AsyncFunction, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_ASYNC_FUNCTION */
- { JS_ATOM_AsyncFunctionResolve, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_RESOLVE */
- { JS_ATOM_AsyncFunctionReject, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_REJECT */
- { JS_ATOM_empty_string, js_async_from_sync_iterator_finalizer, js_async_from_sync_iterator_mark }, /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
- { JS_ATOM_AsyncGeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_ASYNC_GENERATOR_FUNCTION */
- { JS_ATOM_AsyncGenerator, js_async_generator_finalizer, js_async_generator_mark }, /* JS_CLASS_ASYNC_GENERATOR */
- };
- void JS_AddIntrinsicPromise(JSContext *ctx)
- {
- JSRuntime *rt = ctx->rt;
- JSValue obj1;
- if (!JS_IsRegisteredClass(rt, JS_CLASS_PROMISE)) {
- init_class_range(rt, js_async_class_def, JS_CLASS_PROMISE,
- countof(js_async_class_def));
- rt->class_array[JS_CLASS_PROMISE_RESOLVE_FUNCTION].call = js_promise_resolve_function_call;
- rt->class_array[JS_CLASS_PROMISE_REJECT_FUNCTION].call = js_promise_resolve_function_call;
- rt->class_array[JS_CLASS_ASYNC_FUNCTION].call = js_async_function_call;
- rt->class_array[JS_CLASS_ASYNC_FUNCTION_RESOLVE].call = js_async_function_resolve_call;
- rt->class_array[JS_CLASS_ASYNC_FUNCTION_REJECT].call = js_async_function_resolve_call;
- rt->class_array[JS_CLASS_ASYNC_GENERATOR_FUNCTION].call = js_async_generator_function_call;
- }
- /* Promise */
- ctx->class_proto[JS_CLASS_PROMISE] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_PROMISE],
- js_promise_proto_funcs,
- countof(js_promise_proto_funcs));
- obj1 = JS_NewCFunction2(ctx, js_promise_constructor, "Promise", 1,
- JS_CFUNC_constructor, 0);
- ctx->promise_ctor = js_dup(obj1);
- JS_SetPropertyFunctionList(ctx, obj1,
- js_promise_funcs,
- countof(js_promise_funcs));
- JS_NewGlobalCConstructor2(ctx, obj1, "Promise",
- ctx->class_proto[JS_CLASS_PROMISE]);
- /* Used to squelch a -Wcast-function-type warning. */
- JSCFunctionType ft;
- /* AsyncFunction */
- ctx->class_proto[JS_CLASS_ASYNC_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
- ft.generic_magic = js_function_constructor;
- obj1 = JS_NewCFunction3(ctx, ft.generic,
- "AsyncFunction", 1,
- JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC,
- ctx->function_ctor);
- JS_SetPropertyFunctionList(ctx,
- ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
- js_async_function_proto_funcs,
- countof(js_async_function_proto_funcs));
- JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
- 0, JS_PROP_CONFIGURABLE);
- JS_FreeValue(ctx, obj1);
- /* AsyncIteratorPrototype */
- ctx->async_iterator_proto = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->async_iterator_proto,
- js_async_iterator_proto_funcs,
- countof(js_async_iterator_proto_funcs));
- /* AsyncFromSyncIteratorPrototype */
- ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR] =
- JS_NewObjectProto(ctx, ctx->async_iterator_proto);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR],
- js_async_from_sync_iterator_proto_funcs,
- countof(js_async_from_sync_iterator_proto_funcs));
- /* AsyncGeneratorPrototype */
- ctx->class_proto[JS_CLASS_ASYNC_GENERATOR] =
- JS_NewObjectProto(ctx, ctx->async_iterator_proto);
- JS_SetPropertyFunctionList(ctx,
- ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
- js_async_generator_proto_funcs,
- countof(js_async_generator_proto_funcs));
- /* AsyncGeneratorFunction */
- ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION] =
- JS_NewObjectProto(ctx, ctx->function_proto);
- ft.generic_magic = js_function_constructor;
- obj1 = JS_NewCFunction3(ctx, ft.generic,
- "AsyncGeneratorFunction", 1,
- JS_CFUNC_constructor_or_func_magic,
- JS_FUNC_ASYNC_GENERATOR,
- ctx->function_ctor);
- JS_SetPropertyFunctionList(ctx,
- ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
- js_async_generator_function_proto_funcs,
- countof(js_async_generator_function_proto_funcs));
- JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
- ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
- JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
- JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
- 0, JS_PROP_CONFIGURABLE);
- JS_FreeValue(ctx, obj1);
- }
- /* URI handling */
- static int string_get_hex(JSString *p, int k, int n) {
- int c = 0, h;
- while (n-- > 0) {
- if ((h = from_hex(string_get(p, k++))) < 0)
- return -1;
- c = (c << 4) | h;
- }
- return c;
- }
- static int isURIReserved(int c) {
- return c < 0x100 && memchr(";/?:@&=+$,#", c, sizeof(";/?:@&=+$,#") - 1) != NULL;
- }
- static int JS_PRINTF_FORMAT_ATTR(2, 3) js_throw_URIError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- JS_ThrowError(ctx, JS_URI_ERROR, fmt, ap);
- va_end(ap);
- return -1;
- }
- static int hex_decode(JSContext *ctx, JSString *p, int k) {
- int c;
- if (k >= p->len || string_get(p, k) != '%')
- return js_throw_URIError(ctx, "expecting %%");
- if (k + 2 >= p->len || (c = string_get_hex(p, k + 1, 2)) < 0)
- return js_throw_URIError(ctx, "expecting hex digit");
- return c;
- }
- static JSValue js_global_decodeURI(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int isComponent)
- {
- JSValue str;
- StringBuffer b_s, *b = &b_s;
- JSString *p;
- int k, c, c1, n, c_min;
- str = JS_ToString(ctx, argv[0]);
- if (JS_IsException(str))
- return str;
- string_buffer_init(ctx, b, 0);
- p = JS_VALUE_GET_STRING(str);
- for (k = 0; k < p->len;) {
- c = string_get(p, k);
- if (c == '%') {
- c = hex_decode(ctx, p, k);
- if (c < 0)
- goto fail;
- k += 3;
- if (c < 0x80) {
- if (!isComponent && isURIReserved(c)) {
- c = '%';
- k -= 2;
- }
- } else {
- /* Decode URI-encoded UTF-8 sequence */
- if (c >= 0xc0 && c <= 0xdf) {
- n = 1;
- c_min = 0x80;
- c &= 0x1f;
- } else if (c >= 0xe0 && c <= 0xef) {
- n = 2;
- c_min = 0x800;
- c &= 0xf;
- } else if (c >= 0xf0 && c <= 0xf7) {
- n = 3;
- c_min = 0x10000;
- c &= 0x7;
- } else {
- n = 0;
- c_min = 1;
- c = 0;
- }
- while (n-- > 0) {
- c1 = hex_decode(ctx, p, k);
- if (c1 < 0)
- goto fail;
- k += 3;
- if ((c1 & 0xc0) != 0x80) {
- c = 0;
- break;
- }
- c = (c << 6) | (c1 & 0x3f);
- }
- if (c < c_min || c > 0x10FFFF || is_surrogate(c)) {
- js_throw_URIError(ctx, "malformed UTF-8");
- goto fail;
- }
- }
- } else {
- k++;
- }
- string_buffer_putc(b, c);
- }
- JS_FreeValue(ctx, str);
- return string_buffer_end(b);
- fail:
- JS_FreeValue(ctx, str);
- string_buffer_free(b);
- return JS_EXCEPTION;
- }
- static int isUnescaped(int c) {
- static char const unescaped_chars[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "@*_+-./";
- return c < 0x100 &&
- memchr(unescaped_chars, c, sizeof(unescaped_chars) - 1);
- }
- static int isURIUnescaped(int c, int isComponent) {
- return c < 0x100 &&
- ((c >= 0x61 && c <= 0x7a) ||
- (c >= 0x41 && c <= 0x5a) ||
- (c >= 0x30 && c <= 0x39) ||
- memchr("-_.!~*'()", c, sizeof("-_.!~*'()") - 1) != NULL ||
- (!isComponent && isURIReserved(c)));
- }
- static int encodeURI_hex(StringBuffer *b, int c) {
- uint8_t buf[6];
- int n = 0;
- const char *hex = "0123456789ABCDEF";
- buf[n++] = '%';
- if (c >= 256) {
- buf[n++] = 'u';
- buf[n++] = hex[(c >> 12) & 15];
- buf[n++] = hex[(c >> 8) & 15];
- }
- buf[n++] = hex[(c >> 4) & 15];
- buf[n++] = hex[(c >> 0) & 15];
- return string_buffer_write8(b, buf, n);
- }
- static JSValue js_global_encodeURI(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv,
- int isComponent)
- {
- JSValue str;
- StringBuffer b_s, *b = &b_s;
- JSString *p;
- int k, c, c1;
- str = JS_ToString(ctx, argv[0]);
- if (JS_IsException(str))
- return str;
- p = JS_VALUE_GET_STRING(str);
- string_buffer_init(ctx, b, p->len);
- for (k = 0; k < p->len;) {
- c = string_get(p, k);
- k++;
- if (isURIUnescaped(c, isComponent)) {
- string_buffer_putc16(b, c);
- } else {
- if (is_lo_surrogate(c)) {
- js_throw_URIError(ctx, "invalid character");
- goto fail;
- } else if (is_hi_surrogate(c)) {
- if (k >= p->len) {
- js_throw_URIError(ctx, "expecting surrogate pair");
- goto fail;
- }
- c1 = string_get(p, k);
- k++;
- if (!is_lo_surrogate(c1)) {
- js_throw_URIError(ctx, "expecting surrogate pair");
- goto fail;
- }
- c = from_surrogate(c, c1);
- }
- if (c < 0x80) {
- encodeURI_hex(b, c);
- } else {
- /* XXX: use C UTF-8 conversion ? */
- if (c < 0x800) {
- encodeURI_hex(b, (c >> 6) | 0xc0);
- } else {
- if (c < 0x10000) {
- encodeURI_hex(b, (c >> 12) | 0xe0);
- } else {
- encodeURI_hex(b, (c >> 18) | 0xf0);
- encodeURI_hex(b, ((c >> 12) & 0x3f) | 0x80);
- }
- encodeURI_hex(b, ((c >> 6) & 0x3f) | 0x80);
- }
- encodeURI_hex(b, (c & 0x3f) | 0x80);
- }
- }
- }
- JS_FreeValue(ctx, str);
- return string_buffer_end(b);
- fail:
- JS_FreeValue(ctx, str);
- string_buffer_free(b);
- return JS_EXCEPTION;
- }
- static JSValue js_global_escape(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue str;
- StringBuffer b_s, *b = &b_s;
- JSString *p;
- int i, len, c;
- str = JS_ToString(ctx, argv[0]);
- if (JS_IsException(str))
- return str;
- p = JS_VALUE_GET_STRING(str);
- string_buffer_init(ctx, b, p->len);
- for (i = 0, len = p->len; i < len; i++) {
- c = string_get(p, i);
- if (isUnescaped(c)) {
- string_buffer_putc16(b, c);
- } else {
- encodeURI_hex(b, c);
- }
- }
- JS_FreeValue(ctx, str);
- return string_buffer_end(b);
- }
- static JSValue js_global_unescape(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue str;
- StringBuffer b_s, *b = &b_s;
- JSString *p;
- int i, len, c, n;
- str = JS_ToString(ctx, argv[0]);
- if (JS_IsException(str))
- return str;
- string_buffer_init(ctx, b, 0);
- p = JS_VALUE_GET_STRING(str);
- for (i = 0, len = p->len; i < len; i++) {
- c = string_get(p, i);
- if (c == '%') {
- if (i + 6 <= len
- && string_get(p, i + 1) == 'u'
- && (n = string_get_hex(p, i + 2, 4)) >= 0) {
- c = n;
- i += 6 - 1;
- } else
- if (i + 3 <= len
- && (n = string_get_hex(p, i + 1, 2)) >= 0) {
- c = n;
- i += 3 - 1;
- }
- }
- string_buffer_putc16(b, c);
- }
- JS_FreeValue(ctx, str);
- return string_buffer_end(b);
- }
- /* global object */
- static const JSCFunctionListEntry js_global_funcs[] = {
- JS_CFUNC_DEF("parseInt", 2, js_parseInt ),
- JS_CFUNC_DEF("parseFloat", 1, js_parseFloat ),
- JS_CFUNC_DEF("isNaN", 1, js_global_isNaN ),
- JS_CFUNC_DEF("isFinite", 1, js_global_isFinite ),
- JS_CFUNC_DEF("queueMicrotask", 1, js_global_queueMicrotask ),
- JS_CFUNC_MAGIC_DEF("decodeURI", 1, js_global_decodeURI, 0 ),
- JS_CFUNC_MAGIC_DEF("decodeURIComponent", 1, js_global_decodeURI, 1 ),
- JS_CFUNC_MAGIC_DEF("encodeURI", 1, js_global_encodeURI, 0 ),
- JS_CFUNC_MAGIC_DEF("encodeURIComponent", 1, js_global_encodeURI, 1 ),
- JS_CFUNC_DEF("escape", 1, js_global_escape ),
- JS_CFUNC_DEF("unescape", 1, js_global_unescape ),
- JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ),
- JS_PROP_U2D_DEF("NaN", 0x7FF8ull<<48, 0 ), // workaround for msvc
- JS_PROP_UNDEFINED_DEF("undefined", 0 ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "global", JS_PROP_CONFIGURABLE ),
- };
- /* Date */
- static int64_t math_mod(int64_t a, int64_t b) {
- /* return positive modulo */
- int64_t m = a % b;
- return m + (m < 0) * b;
- }
- static int64_t floor_div_int64(int64_t a, int64_t b) {
- /* integer division rounding toward -Infinity */
- int64_t m = a % b;
- return (a - (m + (m < 0) * b)) / b;
- }
- static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv);
- static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp,
- JSValueConst this_val)
- {
- if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(this_val);
- if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data))
- return JS_ToFloat64(ctx, valp, p->u.object_data);
- }
- JS_ThrowTypeError(ctx, "not a Date object");
- return -1;
- }
- static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double v)
- {
- if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(this_val);
- if (p->class_id == JS_CLASS_DATE) {
- JS_FreeValue(ctx, p->u.object_data);
- p->u.object_data = js_float64(v);
- return js_dup(p->u.object_data);
- }
- }
- return JS_ThrowTypeError(ctx, "not a Date object");
- }
- static int64_t days_from_year(int64_t y) {
- return 365 * (y - 1970) + floor_div_int64(y - 1969, 4) -
- floor_div_int64(y - 1901, 100) + floor_div_int64(y - 1601, 400);
- }
- static int64_t days_in_year(int64_t y) {
- return 365 + !(y % 4) - !(y % 100) + !(y % 400);
- }
- /* return the year, update days */
- static int64_t year_from_days(int64_t *days) {
- int64_t y, d1, nd, d = *days;
- y = floor_div_int64(d * 10000, 3652425) + 1970;
- /* the initial approximation is very good, so only a few
- iterations are necessary */
- for(;;) {
- d1 = d - days_from_year(y);
- if (d1 < 0) {
- y--;
- d1 += days_in_year(y);
- } else {
- nd = days_in_year(y);
- if (d1 < nd)
- break;
- d1 -= nd;
- y++;
- }
- }
- *days = d1;
- return y;
- }
- static int const month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
- static char const day_names[] = "SunMonTueWedThuFriSat";
- static __exception int get_date_fields(JSContext *ctx, JSValueConst obj,
- double fields[minimum_length(9)],
- int is_local, int force)
- {
- double dval;
- int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;
- if (JS_ThisTimeValue(ctx, &dval, obj))
- return -1;
- if (isnan(dval)) {
- if (!force)
- return false; /* NaN */
- d = 0; /* initialize all fields to 0 */
- } else {
- d = dval; /* assuming -8.64e15 <= dval <= -8.64e15 */
- if (is_local) {
- tz = -getTimezoneOffset(d);
- d += tz * 60000;
- }
- }
- /* result is >= 0, we can use % */
- h = math_mod(d, 86400000);
- days = (d - h) / 86400000;
- ms = h % 1000;
- h = (h - ms) / 1000;
- s = h % 60;
- h = (h - s) / 60;
- m = h % 60;
- h = (h - m) / 60;
- wd = math_mod(days + 4, 7); /* week day */
- y = year_from_days(&days);
- for(i = 0; i < 11; i++) {
- md = month_days[i];
- if (i == 1)
- md += days_in_year(y) - 365;
- if (days < md)
- break;
- days -= md;
- }
- fields[0] = y;
- fields[1] = i;
- fields[2] = days + 1;
- fields[3] = h;
- fields[4] = m;
- fields[5] = s;
- fields[6] = ms;
- fields[7] = wd;
- fields[8] = tz;
- return true;
- }
- static double time_clip(double t) {
- if (t >= -8.64e15 && t <= 8.64e15)
- return trunc(t) + 0.0; /* convert -0 to +0 */
- else
- return NAN;
- }
- /* The spec mandates the use of 'double' and it specifies the order
- of the operations */
- static double set_date_fields(double fields[minimum_length(7)], int is_local) {
- double y, m, dt, ym, mn, day, h, s, milli, time, tv;
- int yi, mi, i;
- int64_t days;
- volatile double temp; /* enforce evaluation order */
- /* emulate 21.4.1.15 MakeDay ( year, month, date ) */
- y = fields[0];
- m = fields[1];
- dt = fields[2];
- ym = y + floor(m / 12);
- mn = fmod(m, 12);
- if (mn < 0)
- mn += 12;
- if (ym < -271821 || ym > 275760)
- return NAN;
- yi = ym;
- mi = mn;
- days = days_from_year(yi);
- for(i = 0; i < mi; i++) {
- days += month_days[i];
- if (i == 1)
- days += days_in_year(yi) - 365;
- }
- day = days + dt - 1;
- /* emulate 21.4.1.14 MakeTime ( hour, min, sec, ms ) */
- h = fields[3];
- m = fields[4];
- s = fields[5];
- milli = fields[6];
- /* Use a volatile intermediary variable to ensure order of evaluation
- * as specified in ECMA. This fixes a test262 error on
- * test262/test/built-ins/Date/UTC/fp-evaluation-order.js.
- * Without the volatile qualifier, the compile can generate code
- * that performs the computation in a different order or with instructions
- * that produce a different result such as FMA (float multiply and add).
- */
- time = h * 3600000;
- time += (temp = m * 60000);
- time += (temp = s * 1000);
- time += milli;
- /* emulate 21.4.1.16 MakeDate ( day, time ) */
- tv = (temp = day * 86400000) + time; /* prevent generation of FMA */
- if (!isfinite(tv))
- return NAN;
- /* adjust for local time and clip */
- if (is_local) {
- int64_t ti = tv < INT64_MIN ? INT64_MIN : tv >= 0x1p63 ? INT64_MAX : (int64_t)tv;
- tv += getTimezoneOffset(ti) * 60000;
- }
- return time_clip(tv);
- }
- static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- // get_date_field(obj, n, is_local)
- double fields[9];
- int res, n, is_local;
- is_local = magic & 0x0F;
- n = (magic >> 4) & 0x0F;
- res = get_date_fields(ctx, this_val, fields, is_local, 0);
- if (res < 0)
- return JS_EXCEPTION;
- if (!res)
- return JS_NAN;
- if (magic & 0x100) { // getYear
- fields[0] -= 1900;
- }
- return js_number(fields[n]);
- }
- static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- // _field(obj, first_field, end_field, args, is_local)
- double fields[9];
- int res, first_field, end_field, is_local, i, n;
- double d, a;
- d = NAN;
- first_field = (magic >> 8) & 0x0F;
- end_field = (magic >> 4) & 0x0F;
- is_local = magic & 0x0F;
- res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0);
- if (res < 0)
- return JS_EXCEPTION;
- // Argument coercion is observable and must be done unconditionally.
- n = min_int(argc, end_field - first_field);
- for(i = 0; i < n; i++) {
- if (JS_ToFloat64(ctx, &a, argv[i]))
- return JS_EXCEPTION;
- if (!isfinite(a))
- res = false;
- fields[first_field + i] = trunc(a);
- }
- if (!res)
- return JS_NAN;
- if (argc > 0)
- d = set_date_fields(fields, is_local);
- return JS_SetThisTimeValue(ctx, this_val, d);
- }
- /* fmt:
- 0: toUTCString: "Tue, 02 Jan 2018 23:04:46 GMT"
- 1: toString: "Wed Jan 03 2018 00:05:22 GMT+0100 (CET)"
- 2: toISOString: "2018-01-02T23:02:56.927Z"
- 3: toLocaleString: "1/2/2018, 11:40:40 PM"
- part: 1=date, 2=time 3=all
- XXX: should use a variant of strftime().
- */
- static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- // _string(obj, fmt, part)
- char buf[64];
- double fields[9];
- int res, fmt, part, pos;
- int y, mon, d, h, m, s, ms, wd, tz;
- fmt = (magic >> 4) & 0x0F;
- part = magic & 0x0F;
- res = get_date_fields(ctx, this_val, fields, fmt & 1, 0);
- if (res < 0)
- return JS_EXCEPTION;
- if (!res) {
- if (fmt == 2)
- return JS_ThrowRangeError(ctx, "Date value is NaN");
- else
- return js_new_string8(ctx, "Invalid Date");
- }
- y = fields[0];
- mon = fields[1];
- d = fields[2];
- h = fields[3];
- m = fields[4];
- s = fields[5];
- ms = fields[6];
- wd = fields[7];
- tz = fields[8];
- pos = 0;
- if (part & 1) { /* date part */
- switch(fmt) {
- case 0:
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- "%.3s, %02d %.3s %0*d ",
- day_names + wd * 3, d,
- month_names + mon * 3, 4 + (y < 0), y);
- break;
- case 1:
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- "%.3s %.3s %02d %0*d",
- day_names + wd * 3,
- month_names + mon * 3, d, 4 + (y < 0), y);
- if (part == 3) {
- buf[pos++] = ' ';
- }
- break;
- case 2:
- if (y >= 0 && y <= 9999) {
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- "%04d", y);
- } else {
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- "%+07d", y);
- }
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- "-%02d-%02dT", mon + 1, d);
- break;
- case 3:
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- "%02d/%02d/%0*d", mon + 1, d, 4 + (y < 0), y);
- if (part == 3) {
- buf[pos++] = ',';
- buf[pos++] = ' ';
- }
- break;
- }
- }
- if (part & 2) { /* time part */
- switch(fmt) {
- case 0:
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- "%02d:%02d:%02d GMT", h, m, s);
- break;
- case 1:
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- "%02d:%02d:%02d GMT", h, m, s);
- if (tz < 0) {
- buf[pos++] = '-';
- tz = -tz;
- } else {
- buf[pos++] = '+';
- }
- /* tz is >= 0, can use % */
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- "%02d%02d", tz / 60, tz % 60);
- /* XXX: tack the time zone code? */
- break;
- case 2:
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- "%02d:%02d:%02d.%03dZ", h, m, s, ms);
- break;
- case 3:
- pos += snprintf(buf + pos, sizeof(buf) - pos,
- "%02d:%02d:%02d %cM", (h + 11) % 12 + 1, m, s,
- (h < 12) ? 'A' : 'P');
- break;
- }
- }
- if (!pos) {
- // XXX: should throw exception?
- return js_empty_string(ctx->rt);
- }
- return js_new_string8_len(ctx, buf, pos);
- }
- /* OS dependent: return the UTC time in ms since 1970. */
- static int64_t date_now(void) {
- return js__gettimeofday_us() / 1000;
- }
- static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- // Date(y, mon, d, h, m, s, ms)
- JSValue rv;
- int i, n;
- double a, val;
- if (JS_IsUndefined(new_target)) {
- /* invoked as function */
- argc = 0;
- }
- n = argc;
- if (n == 0) {
- val = date_now();
- } else if (n == 1) {
- JSValue v, dv;
- if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
- if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data)) {
- if (JS_ToFloat64(ctx, &val, p->u.object_data))
- return JS_EXCEPTION;
- val = time_clip(val);
- goto has_val;
- }
- }
- v = JS_ToPrimitive(ctx, argv[0], HINT_NONE);
- if (JS_IsString(v)) {
- dv = js_Date_parse(ctx, JS_UNDEFINED, 1, vc(&v));
- JS_FreeValue(ctx, v);
- if (JS_IsException(dv))
- return JS_EXCEPTION;
- if (JS_ToFloat64Free(ctx, &val, dv))
- return JS_EXCEPTION;
- } else {
- if (JS_ToFloat64Free(ctx, &val, v))
- return JS_EXCEPTION;
- }
- val = time_clip(val);
- } else {
- double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
- if (n > 7)
- n = 7;
- for(i = 0; i < n; i++) {
- if (JS_ToFloat64(ctx, &a, argv[i]))
- return JS_EXCEPTION;
- if (!isfinite(a))
- break;
- fields[i] = trunc(a);
- if (i == 0 && fields[0] >= 0 && fields[0] < 100)
- fields[0] += 1900;
- }
- val = (i == n) ? set_date_fields(fields, 1) : NAN;
- }
- has_val:
- rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE);
- if (!JS_IsException(rv))
- JS_SetObjectData(ctx, rv, js_float64(val));
- if (!JS_IsException(rv) && JS_IsUndefined(new_target)) {
- /* invoked as a function, return (new Date()).toString(); */
- JSValue s;
- s = get_date_string(ctx, rv, 0, NULL, 0x13);
- JS_FreeValue(ctx, rv);
- rv = s;
- }
- return rv;
- }
- static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // UTC(y, mon, d, h, m, s, ms)
- double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
- int i, n;
- double a;
- n = argc;
- if (n == 0)
- return JS_NAN;
- if (n > 7)
- n = 7;
- for(i = 0; i < n; i++) {
- if (JS_ToFloat64(ctx, &a, argv[i]))
- return JS_EXCEPTION;
- if (!isfinite(a))
- return JS_NAN;
- fields[i] = trunc(a);
- if (i == 0 && fields[0] >= 0 && fields[0] < 100)
- fields[0] += 1900;
- }
- return js_float64(set_date_fields(fields, 0));
- }
- /* Date string parsing */
- static bool string_skip_char(const uint8_t *sp, int *pp, int c) {
- if (sp[*pp] == c) {
- *pp += 1;
- return true;
- } else {
- return false;
- }
- }
- /* skip spaces, update offset, return next char */
- static int string_skip_spaces(const uint8_t *sp, int *pp) {
- int c;
- while ((c = sp[*pp]) == ' ')
- *pp += 1;
- return c;
- }
- /* skip dashes dots and commas */
- static int string_skip_separators(const uint8_t *sp, int *pp) {
- int c;
- while ((c = sp[*pp]) == '-' || c == '/' || c == '.' || c == ',')
- *pp += 1;
- return c;
- }
- /* skip a word, stop on spaces, digits and separators, update offset */
- static int string_skip_until(const uint8_t *sp, int *pp, const char *stoplist) {
- int c;
- while (!strchr(stoplist, c = sp[*pp]))
- *pp += 1;
- return c;
- }
- /* parse a numeric field (max_digits = 0 -> no maximum) */
- static bool string_get_digits(const uint8_t *sp, int *pp, int *pval,
- int min_digits, int max_digits)
- {
- int v = 0;
- int c, p = *pp, p_start;
- p_start = p;
- while ((c = sp[p]) >= '0' && c <= '9') {
- /* arbitrary limit to 9 digits */
- if (v >= 100000000)
- return false;
- v = v * 10 + c - '0';
- p++;
- if (p - p_start == max_digits)
- break;
- }
- if (p - p_start < min_digits)
- return false;
- *pval = v;
- *pp = p;
- return true;
- }
- static bool string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) {
- /* parse optional fractional part as milliseconds and truncate. */
- /* spec does not indicate which rounding should be used */
- int mul = 100, ms = 0, c, p_start, p = *pp;
- c = sp[p];
- if (c == '.' || c == ',') {
- p++;
- p_start = p;
- while ((c = sp[p]) >= '0' && c <= '9') {
- ms += (c - '0') * mul;
- mul /= 10;
- p++;
- if (p - p_start == 9)
- break;
- }
- if (p > p_start) {
- /* only consume the separator if digits are present */
- *pval = ms;
- *pp = p;
- }
- }
- return true;
- }
- static bool string_get_tzoffset(const uint8_t *sp, int *pp, int *tzp, bool strict) {
- int tz = 0, sgn, hh, mm, p = *pp;
- sgn = sp[p++];
- if (sgn == '+' || sgn == '-') {
- int n = p;
- if (!string_get_digits(sp, &p, &hh, 1, 0))
- return false;
- n = p - n;
- if (strict && n != 2 && n != 4)
- return false;
- while (n > 4) {
- n -= 2;
- hh /= 100;
- }
- if (n > 2) {
- mm = hh % 100;
- hh = hh / 100;
- } else {
- mm = 0;
- if (string_skip_char(sp, &p, ':') /* optional separator */
- && !string_get_digits(sp, &p, &mm, 2, 2))
- return false;
- }
- if (hh > 23 || mm > 59)
- return false;
- tz = hh * 60 + mm;
- if (sgn != '+')
- tz = -tz;
- } else
- if (sgn != 'Z') {
- return false;
- }
- *pp = p;
- *tzp = tz;
- return true;
- }
- static bool string_match(const uint8_t *sp, int *pp, const char *s) {
- int p = *pp;
- while (*s != '\0') {
- if (to_upper_ascii(sp[p]) != to_upper_ascii(*s++))
- return false;
- p++;
- }
- *pp = p;
- return true;
- }
- static int find_abbrev(const uint8_t *sp, int p, const char *list, int count) {
- int n, i;
- for (n = 0; n < count; n++) {
- for (i = 0;; i++) {
- if (to_upper_ascii(sp[p + i]) != to_upper_ascii(list[n * 3 + i]))
- break;
- if (i == 2)
- return n;
- }
- }
- return -1;
- }
- static bool string_get_month(const uint8_t *sp, int *pp, int *pval) {
- int n;
- n = find_abbrev(sp, *pp, month_names, 12);
- if (n < 0)
- return false;
- *pval = n + 1;
- *pp += 3;
- return true;
- }
- /* parse toISOString format */
- static bool js_date_parse_isostring(const uint8_t *sp, int fields[9], bool *is_local) {
- int sgn, i, p = 0;
- /* initialize fields to the beginning of the Epoch */
- for (i = 0; i < 9; i++) {
- fields[i] = (i == 2);
- }
- *is_local = false;
- /* year is either yyyy digits or [+-]yyyyyy */
- sgn = sp[p];
- if (sgn == '-' || sgn == '+') {
- p++;
- if (!string_get_digits(sp, &p, &fields[0], 6, 6))
- return false;
- if (sgn == '-') {
- if (fields[0] == 0)
- return false; // reject -000000
- fields[0] = -fields[0];
- }
- } else {
- if (!string_get_digits(sp, &p, &fields[0], 4, 4))
- return false;
- }
- if (string_skip_char(sp, &p, '-')) {
- if (!string_get_digits(sp, &p, &fields[1], 2, 2)) /* month */
- return false;
- if (fields[1] < 1)
- return false;
- fields[1] -= 1;
- if (string_skip_char(sp, &p, '-')) {
- if (!string_get_digits(sp, &p, &fields[2], 2, 2)) /* day */
- return false;
- if (fields[2] < 1)
- return false;
- }
- }
- if (string_skip_char(sp, &p, 'T')) {
- *is_local = true;
- if (!string_get_digits(sp, &p, &fields[3], 2, 2) /* hour */
- || !string_skip_char(sp, &p, ':')
- || !string_get_digits(sp, &p, &fields[4], 2, 2)) { /* minute */
- fields[3] = 100; // reject unconditionally
- return true;
- }
- if (string_skip_char(sp, &p, ':')) {
- if (!string_get_digits(sp, &p, &fields[5], 2, 2)) /* second */
- return false;
- string_get_milliseconds(sp, &p, &fields[6]);
- }
- }
- /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
- if (sp[p]) {
- *is_local = false;
- if (!string_get_tzoffset(sp, &p, &fields[8], true))
- return false;
- }
- /* error if extraneous characters */
- return sp[p] == '\0';
- }
- static struct {
- char name[6];
- int16_t offset;
- } const js_tzabbr[] = {
- { "GMT", 0 }, // Greenwich Mean Time
- { "UTC", 0 }, // Coordinated Universal Time
- { "UT", 0 }, // Universal Time
- { "Z", 0 }, // Zulu Time
- { "EDT", -4 * 60 }, // Eastern Daylight Time
- { "EST", -5 * 60 }, // Eastern Standard Time
- { "CDT", -5 * 60 }, // Central Daylight Time
- { "CST", -6 * 60 }, // Central Standard Time
- { "MDT", -6 * 60 }, // Mountain Daylight Time
- { "MST", -7 * 60 }, // Mountain Standard Time
- { "PDT", -7 * 60 }, // Pacific Daylight Time
- { "PST", -8 * 60 }, // Pacific Standard Time
- { "WET", +0 * 60 }, // Western European Time
- { "WEST", +1 * 60 }, // Western European Summer Time
- { "CET", +1 * 60 }, // Central European Time
- { "CEST", +2 * 60 }, // Central European Summer Time
- { "EET", +2 * 60 }, // Eastern European Time
- { "EEST", +3 * 60 }, // Eastern European Summer Time
- };
- static bool string_get_tzabbr(const uint8_t *sp, int *pp, int *offset) {
- size_t i;
- for (i = 0; i < countof(js_tzabbr); i++) {
- if (string_match(sp, pp, js_tzabbr[i].name)) {
- *offset = js_tzabbr[i].offset;
- return true;
- }
- }
- return false;
- }
- /* parse toString, toUTCString and other formats */
- static bool js_date_parse_otherstring(const uint8_t *sp,
- int fields[minimum_length(9)],
- bool *is_local) {
- int c, i, val, p = 0, p_start;
- int num[3];
- bool has_year = false;
- bool has_mon = false;
- bool has_time = false;
- int num_index = 0;
- /* initialize fields to the beginning of 2001-01-01 */
- fields[0] = 2001;
- fields[1] = 1;
- fields[2] = 1;
- for (i = 3; i < 9; i++) {
- fields[i] = 0;
- }
- *is_local = true;
- while (string_skip_spaces(sp, &p)) {
- p_start = p;
- if ((c = sp[p]) == '+' || c == '-') {
- if (has_time && string_get_tzoffset(sp, &p, &fields[8], false)) {
- *is_local = false;
- } else {
- p++;
- if (string_get_digits(sp, &p, &val, 1, 0)) {
- if (c == '-') {
- if (val == 0)
- return false;
- val = -val;
- }
- fields[0] = val;
- has_year = true;
- }
- }
- } else
- if (string_get_digits(sp, &p, &val, 1, 0)) {
- if (string_skip_char(sp, &p, ':')) {
- /* time part */
- fields[3] = val;
- if (!string_get_digits(sp, &p, &fields[4], 1, 2))
- return false;
- if (string_skip_char(sp, &p, ':')) {
- if (!string_get_digits(sp, &p, &fields[5], 1, 2))
- return false;
- string_get_milliseconds(sp, &p, &fields[6]);
- } else
- if (sp[p] != '\0' && sp[p] != ' ')
- return false;
- has_time = true;
- } else {
- if (p - p_start > 2) {
- fields[0] = val;
- has_year = true;
- } else
- if (val < 1 || val > 31) {
- fields[0] = val + (val < 100) * 1900 + (val < 50) * 100;
- has_year = true;
- } else {
- if (num_index == 3)
- return false;
- num[num_index++] = val;
- }
- }
- } else
- if (string_get_month(sp, &p, &fields[1])) {
- has_mon = true;
- string_skip_until(sp, &p, "0123456789 -/(");
- } else
- if (has_time && string_match(sp, &p, "PM")) {
- /* hours greater than 12 will be incremented and
- rejected by the range check in js_Date_parse */
- /* 00:00 PM will be silently converted as 12:00 */
- if (fields[3] != 12)
- fields[3] += 12;
- continue;
- } else
- if (has_time && string_match(sp, &p, "AM")) {
- /* 00:00 AM will be silently accepted */
- if (fields[3] > 12)
- return false;
- if (fields[3] == 12)
- fields[3] -= 12;
- continue;
- } else
- if (string_get_tzabbr(sp, &p, &fields[8])) {
- *is_local = false;
- continue;
- } else
- if (c == '(') { /* skip parenthesized phrase */
- int level = 0;
- while ((c = sp[p]) != '\0') {
- p++;
- level += (c == '(');
- level -= (c == ')');
- if (!level)
- break;
- }
- if (level > 0)
- return false;
- } else
- if (c == ')') {
- return false;
- } else {
- if (has_year + has_mon + has_time + num_index)
- return false;
- /* skip a word */
- string_skip_until(sp, &p, " -/(");
- }
- string_skip_separators(sp, &p);
- }
- if (num_index + has_year + has_mon > 3)
- return false;
- switch (num_index) {
- case 0:
- if (!has_year)
- return false;
- break;
- case 1:
- if (has_mon)
- fields[2] = num[0];
- else
- fields[1] = num[0];
- break;
- case 2:
- if (has_year) {
- fields[1] = num[0];
- fields[2] = num[1];
- } else
- if (has_mon) {
- fields[0] = num[1] + (num[1] < 100) * 1900 + (num[1] < 50) * 100;
- fields[2] = num[0];
- } else {
- fields[1] = num[0];
- fields[2] = num[1];
- }
- break;
- case 3:
- fields[0] = num[2] + (num[2] < 100) * 1900 + (num[2] < 50) * 100;
- fields[1] = num[0];
- fields[2] = num[1];
- break;
- default:
- return false;
- }
- if (fields[1] < 1 || fields[2] < 1)
- return false;
- fields[1] -= 1;
- return true;
- }
- static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue s, rv;
- int fields[9];
- double fields1[9];
- double d;
- int i, c;
- JSString *sp;
- uint8_t buf[128];
- bool is_local;
- rv = JS_NAN;
- s = JS_ToString(ctx, argv[0]);
- if (JS_IsException(s))
- return JS_EXCEPTION;
- sp = JS_VALUE_GET_STRING(s);
- /* convert the string as a byte array */
- for (i = 0; i < sp->len && i < (int)countof(buf) - 1; i++) {
- c = string_get(sp, i);
- if (c > 255)
- c = (c == 0x2212) ? '-' : 'x';
- buf[i] = c;
- }
- buf[i] = '\0';
- if (js_date_parse_isostring(buf, fields, &is_local)
- || js_date_parse_otherstring(buf, fields, &is_local)) {
- static int const field_max[6] = { 0, 11, 31, 24, 59, 59 };
- bool valid = true;
- /* check field maximum values */
- for (i = 1; i < 6; i++) {
- if (fields[i] > field_max[i])
- valid = false;
- }
- /* special case 24:00:00.000 */
- if (fields[3] == 24 && (fields[4] | fields[5] | fields[6]))
- valid = false;
- if (valid) {
- for(i = 0; i < 7; i++)
- fields1[i] = fields[i];
- d = set_date_fields(fields1, is_local) - fields[8] * 60000;
- rv = js_float64(d);
- }
- }
- JS_FreeValue(ctx, s);
- return rv;
- }
- static JSValue js_Date_now(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // now()
- return js_int64(date_now());
- }
- static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // Symbol_toPrimitive(hint)
- JSValueConst obj = this_val;
- JSAtom hint = JS_ATOM_NULL;
- int hint_num;
- if (!JS_IsObject(obj))
- return JS_ThrowTypeErrorNotAnObject(ctx);
- if (JS_IsString(argv[0])) {
- hint = JS_ValueToAtom(ctx, argv[0]);
- if (hint == JS_ATOM_NULL)
- return JS_EXCEPTION;
- JS_FreeAtom(ctx, hint);
- }
- switch (hint) {
- case JS_ATOM_number:
- case JS_ATOM_integer:
- hint_num = HINT_NUMBER;
- break;
- case JS_ATOM_string:
- case JS_ATOM_default:
- hint_num = HINT_STRING;
- break;
- default:
- return JS_ThrowTypeError(ctx, "invalid hint");
- }
- return JS_ToPrimitive(ctx, obj, hint_num | HINT_FORCE_ORDINARY);
- }
- static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // getTimezoneOffset()
- double v;
- if (JS_ThisTimeValue(ctx, &v, this_val))
- return JS_EXCEPTION;
- if (isnan(v))
- return JS_NAN;
- else
- /* assuming -8.64e15 <= v <= -8.64e15 */
- return js_int64(getTimezoneOffset((int64_t)trunc(v)));
- }
- static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // getTime()
- double v;
- if (JS_ThisTimeValue(ctx, &v, this_val))
- return JS_EXCEPTION;
- return js_float64(v);
- }
- static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // setTime(v)
- double v;
- if (JS_ThisTimeValue(ctx, &v, this_val) || JS_ToFloat64(ctx, &v, argv[0]))
- return JS_EXCEPTION;
- return JS_SetThisTimeValue(ctx, this_val, time_clip(v));
- }
- static JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // setYear(y)
- double y;
- JSValue d, ret;
- if (JS_ThisTimeValue(ctx, &y, this_val) || JS_ToFloat64(ctx, &y, argv[0]))
- return JS_EXCEPTION;
- y = +y;
- if (isnan(y))
- return JS_SetThisTimeValue(ctx, this_val, y);
- if (isfinite(y)) {
- y = trunc(y);
- if (y >= 0 && y < 100)
- y += 1900;
- }
- d = js_float64(y);
- ret = set_date_field(ctx, this_val, 1, vc(&d), 0x011);
- JS_FreeValue(ctx, d);
- return ret;
- }
- static JSValue js_date_toJSON(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // toJSON(key)
- JSValue obj, tv, method, rv;
- double d;
- rv = JS_EXCEPTION;
- tv = JS_UNDEFINED;
- obj = JS_ToObject(ctx, this_val);
- tv = JS_ToPrimitive(ctx, obj, HINT_NUMBER);
- if (JS_IsException(tv))
- goto exception;
- if (JS_IsNumber(tv)) {
- if (JS_ToFloat64(ctx, &d, tv) < 0)
- goto exception;
- if (!isfinite(d)) {
- rv = JS_NULL;
- goto done;
- }
- }
- method = JS_GetPropertyStr(ctx, obj, "toISOString");
- if (JS_IsException(method))
- goto exception;
- if (!JS_IsFunction(ctx, method)) {
- JS_ThrowTypeError(ctx, "object needs toISOString method");
- JS_FreeValue(ctx, method);
- goto exception;
- }
- rv = JS_CallFree(ctx, method, obj, 0, NULL);
- exception:
- done:
- JS_FreeValue(ctx, obj);
- JS_FreeValue(ctx, tv);
- return rv;
- }
- static const JSCFunctionListEntry js_date_funcs[] = {
- JS_CFUNC_DEF("now", 0, js_Date_now ),
- JS_CFUNC_DEF("parse", 1, js_Date_parse ),
- JS_CFUNC_DEF("UTC", 7, js_Date_UTC ),
- };
- static const JSCFunctionListEntry js_date_proto_funcs[] = {
- JS_CFUNC_DEF("valueOf", 0, js_date_getTime ),
- JS_CFUNC_MAGIC_DEF("toString", 0, get_date_string, 0x13 ),
- JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_date_Symbol_toPrimitive ),
- JS_CFUNC_MAGIC_DEF("toUTCString", 0, get_date_string, 0x03 ),
- JS_ALIAS_DEF("toGMTString", "toUTCString" ),
- JS_CFUNC_MAGIC_DEF("toISOString", 0, get_date_string, 0x23 ),
- JS_CFUNC_MAGIC_DEF("toDateString", 0, get_date_string, 0x11 ),
- JS_CFUNC_MAGIC_DEF("toTimeString", 0, get_date_string, 0x12 ),
- JS_CFUNC_MAGIC_DEF("toLocaleString", 0, get_date_string, 0x33 ),
- JS_CFUNC_MAGIC_DEF("toLocaleDateString", 0, get_date_string, 0x31 ),
- JS_CFUNC_MAGIC_DEF("toLocaleTimeString", 0, get_date_string, 0x32 ),
- JS_CFUNC_DEF("getTimezoneOffset", 0, js_date_getTimezoneOffset ),
- JS_CFUNC_DEF("getTime", 0, js_date_getTime ),
- JS_CFUNC_MAGIC_DEF("getYear", 0, get_date_field, 0x101 ),
- JS_CFUNC_MAGIC_DEF("getFullYear", 0, get_date_field, 0x01 ),
- JS_CFUNC_MAGIC_DEF("getUTCFullYear", 0, get_date_field, 0x00 ),
- JS_CFUNC_MAGIC_DEF("getMonth", 0, get_date_field, 0x11 ),
- JS_CFUNC_MAGIC_DEF("getUTCMonth", 0, get_date_field, 0x10 ),
- JS_CFUNC_MAGIC_DEF("getDate", 0, get_date_field, 0x21 ),
- JS_CFUNC_MAGIC_DEF("getUTCDate", 0, get_date_field, 0x20 ),
- JS_CFUNC_MAGIC_DEF("getHours", 0, get_date_field, 0x31 ),
- JS_CFUNC_MAGIC_DEF("getUTCHours", 0, get_date_field, 0x30 ),
- JS_CFUNC_MAGIC_DEF("getMinutes", 0, get_date_field, 0x41 ),
- JS_CFUNC_MAGIC_DEF("getUTCMinutes", 0, get_date_field, 0x40 ),
- JS_CFUNC_MAGIC_DEF("getSeconds", 0, get_date_field, 0x51 ),
- JS_CFUNC_MAGIC_DEF("getUTCSeconds", 0, get_date_field, 0x50 ),
- JS_CFUNC_MAGIC_DEF("getMilliseconds", 0, get_date_field, 0x61 ),
- JS_CFUNC_MAGIC_DEF("getUTCMilliseconds", 0, get_date_field, 0x60 ),
- JS_CFUNC_MAGIC_DEF("getDay", 0, get_date_field, 0x71 ),
- JS_CFUNC_MAGIC_DEF("getUTCDay", 0, get_date_field, 0x70 ),
- JS_CFUNC_DEF("setTime", 1, js_date_setTime ),
- JS_CFUNC_MAGIC_DEF("setMilliseconds", 1, set_date_field, 0x671 ),
- JS_CFUNC_MAGIC_DEF("setUTCMilliseconds", 1, set_date_field, 0x670 ),
- JS_CFUNC_MAGIC_DEF("setSeconds", 2, set_date_field, 0x571 ),
- JS_CFUNC_MAGIC_DEF("setUTCSeconds", 2, set_date_field, 0x570 ),
- JS_CFUNC_MAGIC_DEF("setMinutes", 3, set_date_field, 0x471 ),
- JS_CFUNC_MAGIC_DEF("setUTCMinutes", 3, set_date_field, 0x470 ),
- JS_CFUNC_MAGIC_DEF("setHours", 4, set_date_field, 0x371 ),
- JS_CFUNC_MAGIC_DEF("setUTCHours", 4, set_date_field, 0x370 ),
- JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231 ),
- JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230 ),
- JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131 ),
- JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130 ),
- JS_CFUNC_DEF("setYear", 1, js_date_setYear ),
- JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031 ),
- JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030 ),
- JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ),
- };
- JSValue JS_NewDate(JSContext *ctx, double epoch_ms)
- {
- JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_DATE);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- JS_SetObjectData(ctx, obj, js_float64(time_clip(epoch_ms)));
- return obj;
- }
- bool JS_IsDate(JSValueConst v)
- {
- if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
- return false;
- return JS_VALUE_GET_OBJ(v)->class_id == JS_CLASS_DATE;
- }
- void JS_AddIntrinsicDate(JSContext *ctx)
- {
- JSValue obj;
- /* Date */
- ctx->class_proto[JS_CLASS_DATE] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATE], js_date_proto_funcs,
- countof(js_date_proto_funcs));
- obj = JS_NewGlobalCConstructor(ctx, "Date", js_date_constructor, 7,
- ctx->class_proto[JS_CLASS_DATE]);
- JS_SetPropertyFunctionList(ctx, obj, js_date_funcs, countof(js_date_funcs));
- }
- /* eval */
- void JS_AddIntrinsicEval(JSContext *ctx)
- {
- #ifndef QJS_DISABLE_PARSER
- ctx->eval_internal = __JS_EvalInternal;
- #endif // QJS_DISABLE_PARSER
- }
- /* BigInt */
- static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
- {
- uint32_t tag;
- redo:
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- case JS_TAG_BOOL:
- val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
- break;
- case JS_TAG_SHORT_BIG_INT:
- case JS_TAG_BIG_INT:
- break;
- case JS_TAG_FLOAT64:
- {
- double d = JS_VALUE_GET_FLOAT64(val);
- JSBigInt *r;
- int res;
- r = js_bigint_from_float64(ctx, &res, d);
- if (!r) {
- if (res == 0) {
- val = JS_EXCEPTION;
- } else if (res == 1) {
- val = JS_ThrowRangeError(ctx, "cannot convert to BigInt: not an integer");
- } else {
- val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to BigInt"); }
- } else {
- val = JS_CompactBigInt(ctx, r);
- }
- }
- break;
- case JS_TAG_STRING:
- val = JS_StringToBigIntErr(ctx, val);
- break;
- case JS_TAG_OBJECT:
- val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
- if (JS_IsException(val))
- break;
- goto redo;
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- default:
- JS_FreeValue(ctx, val);
- return JS_ThrowTypeError(ctx, "cannot convert to BigInt");
- }
- return val;
- }
- static JSValue js_bigint_constructor(JSContext *ctx,
- JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- if (!JS_IsUndefined(new_target))
- return JS_ThrowTypeErrorNotAConstructor(ctx, new_target);
- return JS_ToBigIntCtorFree(ctx, js_dup(argv[0]));
- }
- static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
- {
- if (JS_IsBigInt(this_val))
- return js_dup(this_val);
- if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(this_val);
- if (p->class_id == JS_CLASS_BIG_INT) {
- if (JS_IsBigInt(p->u.object_data))
- return js_dup(p->u.object_data);
- }
- }
- return JS_ThrowTypeError(ctx, "not a BigInt");
- }
- static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val;
- int base;
- JSValue ret;
- val = js_thisBigIntValue(ctx, this_val);
- if (JS_IsException(val))
- return val;
- if (argc == 0 || JS_IsUndefined(argv[0])) {
- base = 10;
- } else {
- base = js_get_radix(ctx, argv[0]);
- if (base < 0)
- goto fail;
- }
- ret = js_bigint_to_string1(ctx, val, base);
- JS_FreeValue(ctx, val);
- return ret;
- fail:
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_thisBigIntValue(ctx, this_val);
- }
- static JSValue js_bigint_asUintN(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv, int asIntN)
- {
- uint64_t bits;
- JSValue res, a;
- if (JS_ToIndex(ctx, &bits, argv[0]))
- return JS_EXCEPTION;
- a = JS_ToBigInt(ctx, argv[1]);
- if (JS_IsException(a))
- return JS_EXCEPTION;
- if (bits == 0) {
- JS_FreeValue(ctx, a);
- res = __JS_NewShortBigInt(ctx, 0);
- } else if (JS_VALUE_GET_TAG(a) == JS_TAG_SHORT_BIG_INT) {
- /* fast case */
- if (bits >= JS_SHORT_BIG_INT_BITS) {
- res = a;
- } else {
- uint64_t v;
- int shift;
- shift = 64 - bits;
- v = JS_VALUE_GET_SHORT_BIG_INT(a);
- v = v << shift;
- if (asIntN)
- v = (int64_t)v >> shift;
- else
- v = v >> shift;
- res = __JS_NewShortBigInt(ctx, v);
- }
- } else {
- JSBigInt *r, *p = JS_VALUE_GET_PTR(a);
- if (bits >= p->len * JS_LIMB_BITS) {
- res = a;
- } else {
- int len, shift, i;
- js_limb_t v;
- len = (bits + JS_LIMB_BITS - 1) / JS_LIMB_BITS;
- r = js_bigint_new(ctx, len);
- if (!r) {
- JS_FreeValue(ctx, a);
- return JS_EXCEPTION;
- }
- r->len = len;
- for(i = 0; i < len - 1; i++)
- r->tab[i] = p->tab[i];
- shift = (-bits) & (JS_LIMB_BITS - 1);
- /* 0 <= shift <= JS_LIMB_BITS - 1 */
- v = p->tab[len - 1] << shift;
- if (asIntN)
- v = (js_slimb_t)v >> shift;
- else
- v = v >> shift;
- r->tab[len - 1] = v;
- r = js_bigint_normalize(ctx, r);
- JS_FreeValue(ctx, a);
- res = JS_CompactBigInt(ctx, r);
- }
- }
- return res;
- }
- static const JSCFunctionListEntry js_bigint_funcs[] = {
- JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ),
- JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ),
- };
- static const JSCFunctionListEntry js_bigint_proto_funcs[] = {
- JS_CFUNC_DEF("toString", 0, js_bigint_toString ),
- JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ),
- };
- void JS_AddIntrinsicBigInt(JSContext *ctx)
- {
- JSValue obj1;
- ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
- js_bigint_proto_funcs,
- countof(js_bigint_proto_funcs));
- obj1 = JS_NewGlobalCConstructor(ctx, "BigInt", js_bigint_constructor, 1,
- ctx->class_proto[JS_CLASS_BIG_INT]);
- JS_SetPropertyFunctionList(ctx, obj1, js_bigint_funcs,
- countof(js_bigint_funcs));
- }
- static const char * const native_error_name[JS_NATIVE_ERROR_COUNT] = {
- "EvalError", "RangeError", "ReferenceError",
- "SyntaxError", "TypeError", "URIError",
- "InternalError", "AggregateError",
- };
- /* Minimum amount of objects to be able to compile code and display
- error messages. No JSAtom should be allocated by this function. */
- static void JS_AddIntrinsicBasicObjects(JSContext *ctx)
- {
- JSValue proto;
- int i;
- ctx->class_proto[JS_CLASS_OBJECT] = JS_NewObjectProto(ctx, JS_NULL);
- ctx->global_obj = JS_NewObject(ctx);
- ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL);
- ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0,
- JS_CFUNC_generic, 0,
- ctx->class_proto[JS_CLASS_OBJECT]);
- ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = js_dup(ctx->function_proto);
- ctx->class_proto[JS_CLASS_ERROR] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ERROR],
- js_error_proto_funcs,
- countof(js_error_proto_funcs));
- for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
- proto = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ERROR]);
- JS_DefinePropertyValue(ctx, proto, JS_ATOM_name,
- JS_NewAtomString(ctx, native_error_name[i]),
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- JS_DefinePropertyValue(ctx, proto, JS_ATOM_message,
- js_empty_string(ctx->rt),
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- ctx->native_error_proto[i] = proto;
- }
- /* the array prototype is an array */
- ctx->class_proto[JS_CLASS_ARRAY] =
- JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
- JS_CLASS_ARRAY);
- ctx->array_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]),
- JS_PROP_INITIAL_HASH_SIZE, 1);
- add_shape_property(ctx, &ctx->array_shape, NULL,
- JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH);
- /* XXX: could test it on first context creation to ensure that no
- new atoms are created in JS_AddIntrinsicBasicObjects(). It is
- necessary to avoid useless renumbering of atoms after
- JS_EvalBinary() if it is done just after
- JS_AddIntrinsicBasicObjects(). */
- // assert(ctx->rt->atom_count == JS_ATOM_END);
- }
- void JS_AddIntrinsicBaseObjects(JSContext *ctx)
- {
- int i;
- JSValue obj, number_obj;
- JSValue obj1;
- ctx->throw_type_error = JS_NewCFunction(ctx, js_throw_type_error, NULL, 0);
- /* add caller and arguments properties to throw a TypeError */
- JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_caller, JS_UNDEFINED,
- ctx->throw_type_error, ctx->throw_type_error,
- JS_PROP_HAS_GET | JS_PROP_HAS_SET |
- JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
- JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_arguments, JS_UNDEFINED,
- ctx->throw_type_error, ctx->throw_type_error,
- JS_PROP_HAS_GET | JS_PROP_HAS_SET |
- JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
- JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, vc(&ctx->throw_type_error), 1));
- /* Object */
- obj = JS_NewGlobalCConstructor(ctx, "Object", js_object_constructor, 1,
- ctx->class_proto[JS_CLASS_OBJECT]);
- JS_SetPropertyFunctionList(ctx, obj, js_object_funcs, countof(js_object_funcs));
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_OBJECT],
- js_object_proto_funcs, countof(js_object_proto_funcs));
- /* Function */
- JS_SetPropertyFunctionList(ctx, ctx->function_proto, js_function_proto_funcs, countof(js_function_proto_funcs));
- ctx->function_ctor = JS_NewCFunctionMagic(ctx, js_function_constructor,
- "Function", 1, JS_CFUNC_constructor_or_func_magic,
- JS_FUNC_NORMAL);
- JS_NewGlobalCConstructor2(ctx, js_dup(ctx->function_ctor), "Function",
- ctx->function_proto);
- /* Error */
- ctx->error_ctor = JS_NewCFunctionMagic(ctx, js_error_constructor,
- "Error", 1, JS_CFUNC_constructor_or_func_magic, -1);
- JS_NewGlobalCConstructor2(ctx, js_dup(ctx->error_ctor),
- "Error", ctx->class_proto[JS_CLASS_ERROR]);
- JS_SetPropertyFunctionList(ctx, ctx->error_ctor, js_error_funcs, countof(js_error_funcs));
- /* Used to squelch a -Wcast-function-type warning. */
- JSCFunctionType ft = { .generic_magic = js_error_constructor };
- for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
- JSValue func_obj;
- int n_args;
- n_args = 1 + (i == JS_AGGREGATE_ERROR);
- func_obj = JS_NewCFunction3(ctx, ft.generic,
- native_error_name[i], n_args,
- JS_CFUNC_constructor_or_func_magic, i,
- ctx->error_ctor);
- JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i],
- ctx->native_error_proto[i]);
- }
- /* CallSite */
- _JS_AddIntrinsicCallSite(ctx);
- /* Iterator */
- ctx->class_proto[JS_CLASS_ITERATOR] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ITERATOR],
- js_iterator_proto_funcs,
- countof(js_iterator_proto_funcs));
- obj = JS_NewGlobalCConstructor(ctx, "Iterator", js_iterator_constructor, 0,
- ctx->class_proto[JS_CLASS_ITERATOR]);
- // quirk: Iterator.prototype.constructor is an accessor property
- // TODO(bnoordhuis) mildly inefficient because JS_NewGlobalCConstructor
- // first creates a .constructor value property that we then replace with
- // an accessor
- ctx->iterator_ctor_getset = JS_NewCFunctionData(ctx, js_iterator_constructor_getset,
- 0, 0, 1, vc(&obj));
- JS_DefineProperty(ctx, ctx->class_proto[JS_CLASS_ITERATOR],
- JS_ATOM_constructor, JS_UNDEFINED,
- ctx->iterator_ctor_getset, ctx->iterator_ctor_getset,
- JS_PROP_HAS_GET|JS_PROP_HAS_SET|JS_PROP_WRITABLE|JS_PROP_CONFIGURABLE);
- ctx->iterator_ctor = js_dup(obj);
- JS_SetPropertyFunctionList(ctx, obj,
- js_iterator_funcs,
- countof(js_iterator_funcs));
- ctx->class_proto[JS_CLASS_ITERATOR_CONCAT] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ITERATOR_CONCAT],
- js_iterator_concat_proto_funcs,
- countof(js_iterator_concat_proto_funcs));
- ctx->class_proto[JS_CLASS_ITERATOR_HELPER] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ITERATOR_HELPER],
- js_iterator_helper_proto_funcs,
- countof(js_iterator_helper_proto_funcs));
- ctx->class_proto[JS_CLASS_ITERATOR_WRAP] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ITERATOR_WRAP],
- js_iterator_wrap_proto_funcs,
- countof(js_iterator_wrap_proto_funcs));
- /* Array */
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY],
- js_array_proto_funcs,
- countof(js_array_proto_funcs));
- obj = JS_NewGlobalCConstructor(ctx, "Array", js_array_constructor, 1,
- ctx->class_proto[JS_CLASS_ARRAY]);
- ctx->array_ctor = js_dup(obj);
- JS_SetPropertyFunctionList(ctx, obj, js_array_funcs,
- countof(js_array_funcs));
- JS_DefineAutoInitProperty(ctx, obj, JS_ATOM_fromAsync,
- JS_AUTOINIT_ID_BYTECODE,
- (void *)(uintptr_t)JS_BUILTIN_ARRAY_FROMASYNC,
- JS_PROP_WRITABLE|JS_PROP_CONFIGURABLE);
- /* XXX: create auto_initializer */
- {
- /* initialize Array.prototype[Symbol.unscopables] */
- static const char unscopables[] =
- "copyWithin" "\0"
- "entries" "\0"
- "fill" "\0"
- "find" "\0"
- "findIndex" "\0"
- "findLast" "\0"
- "findLastIndex" "\0"
- "flat" "\0"
- "flatMap" "\0"
- "includes" "\0"
- "keys" "\0"
- "toReversed" "\0"
- "toSorted" "\0"
- "toSpliced" "\0"
- "values" "\0";
- const char *p = unscopables;
- obj1 = JS_NewObjectProto(ctx, JS_NULL);
- for(p = unscopables; *p; p += strlen(p) + 1) {
- JS_DefinePropertyValueStr(ctx, obj1, p, JS_TRUE, JS_PROP_C_W_E);
- }
- JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ARRAY],
- JS_ATOM_Symbol_unscopables, obj1,
- JS_PROP_CONFIGURABLE);
- }
- /* needed to initialize arguments[Symbol.iterator] */
- ctx->array_proto_values =
- JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_values);
- ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_ITERATOR],
- js_array_iterator_proto_funcs,
- countof(js_array_iterator_proto_funcs));
- /* parseFloat and parseInteger must be defined before Number
- because of the Number.parseFloat and Number.parseInteger
- aliases */
- JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_global_funcs,
- countof(js_global_funcs));
- /* Number */
- ctx->class_proto[JS_CLASS_NUMBER] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
- JS_CLASS_NUMBER);
- JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_NUMBER], js_int32(0));
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_NUMBER],
- js_number_proto_funcs,
- countof(js_number_proto_funcs));
- number_obj = JS_NewGlobalCConstructor(ctx, "Number", js_number_constructor, 1,
- ctx->class_proto[JS_CLASS_NUMBER]);
- JS_SetPropertyFunctionList(ctx, number_obj, js_number_funcs, countof(js_number_funcs));
- /* Boolean */
- ctx->class_proto[JS_CLASS_BOOLEAN] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
- JS_CLASS_BOOLEAN);
- JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], JS_FALSE);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], js_boolean_proto_funcs,
- countof(js_boolean_proto_funcs));
- JS_NewGlobalCConstructor(ctx, "Boolean", js_boolean_constructor, 1,
- ctx->class_proto[JS_CLASS_BOOLEAN]);
- /* String */
- ctx->class_proto[JS_CLASS_STRING] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
- JS_CLASS_STRING);
- JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_STRING], js_empty_string(ctx->rt));
- obj = JS_NewGlobalCConstructor(ctx, "String", js_string_constructor, 1,
- ctx->class_proto[JS_CLASS_STRING]);
- JS_SetPropertyFunctionList(ctx, obj, js_string_funcs,
- countof(js_string_funcs));
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_funcs,
- countof(js_string_proto_funcs));
- ctx->class_proto[JS_CLASS_STRING_ITERATOR] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING_ITERATOR],
- js_string_iterator_proto_funcs,
- countof(js_string_iterator_proto_funcs));
- /* Math: create as autoinit object */
- js_random_init(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_math_obj, countof(js_math_obj));
- /* ES6 Reflect: create as autoinit object */
- JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_reflect_obj, countof(js_reflect_obj));
- /* ES6 Symbol */
- ctx->class_proto[JS_CLASS_SYMBOL] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SYMBOL], js_symbol_proto_funcs,
- countof(js_symbol_proto_funcs));
- obj = JS_NewGlobalCConstructor(ctx, "Symbol", js_symbol_constructor, 0,
- ctx->class_proto[JS_CLASS_SYMBOL]);
- JS_SetPropertyFunctionList(ctx, obj, js_symbol_funcs,
- countof(js_symbol_funcs));
- for(i = JS_ATOM_Symbol_toPrimitive; i < JS_ATOM_END; i++) {
- char buf[ATOM_GET_STR_BUF_SIZE];
- const char *str, *p;
- str = JS_AtomGetStr(ctx, buf, sizeof(buf), i);
- /* skip "Symbol." */
- p = strchr(str, '.');
- if (p)
- str = p + 1;
- JS_DefinePropertyValueStr(ctx, obj, str, JS_AtomToValue(ctx, i), 0);
- }
- /* ES6 Generator */
- ctx->class_proto[JS_CLASS_GENERATOR] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_GENERATOR],
- js_generator_proto_funcs,
- countof(js_generator_proto_funcs));
- ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
- obj1 = JS_NewCFunctionMagic(ctx, js_function_constructor,
- "GeneratorFunction", 1,
- JS_CFUNC_constructor_or_func_magic, JS_FUNC_GENERATOR);
- JS_SetPropertyFunctionList(ctx,
- ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
- js_generator_function_proto_funcs,
- countof(js_generator_function_proto_funcs));
- JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
- ctx->class_proto[JS_CLASS_GENERATOR],
- JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
- JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
- 0, JS_PROP_CONFIGURABLE);
- JS_FreeValue(ctx, obj1);
- /* global properties */
- ctx->eval_obj = JS_NewCFunction(ctx, js_global_eval, "eval", 1);
- JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_eval,
- js_dup(ctx->eval_obj),
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis,
- js_dup(ctx->global_obj),
- JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
- }
- /* Typed Arrays */
- static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = {
- 0, 0, 0, 1, 1, 2, 2,
- 3, 3, // BigInt64Array, BigUint64Array
- 1, 2, 3 // Float16Array, Float32Array, Float64Array
- };
- static JSValue js_array_buffer_constructor3(JSContext *ctx,
- JSValueConst new_target,
- uint64_t len, uint64_t *max_len,
- JSClassID class_id,
- uint8_t *buf,
- JSFreeArrayBufferDataFunc *free_func,
- void *opaque, bool alloc_flag)
- {
- JSRuntime *rt = ctx->rt;
- JSValue obj;
- JSArrayBuffer *abuf = NULL;
- uint64_t sab_alloc_len;
- if (!alloc_flag && buf && max_len && free_func != js_array_buffer_free) {
- // not observable from JS land, only through C API misuse;
- // JS code cannot create externally managed buffers directly
- return JS_ThrowInternalError(ctx,
- "resizable ArrayBuffers not supported "
- "for externally managed buffers");
- }
- obj = js_create_from_ctor(ctx, new_target, class_id);
- if (JS_IsException(obj))
- return obj;
- /* XXX: we are currently limited to 2 GB */
- if (len > INT32_MAX) {
- JS_ThrowRangeError(ctx, "invalid array buffer length");
- goto fail;
- }
- if (max_len && *max_len > INT32_MAX) {
- JS_ThrowRangeError(ctx, "invalid max array buffer length");
- goto fail;
- }
- abuf = js_malloc(ctx, sizeof(*abuf));
- if (!abuf)
- goto fail;
- abuf->byte_length = len;
- abuf->max_byte_length = max_len ? *max_len : -1;
- if (alloc_flag) {
- if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
- rt->sab_funcs.sab_alloc) {
- // TOOD(bnoordhuis) resizing backing memory for SABs atomically
- // is hard so we cheat and allocate |maxByteLength| bytes upfront
- sab_alloc_len = max_len ? *max_len : len;
- abuf->data = rt->sab_funcs.sab_alloc(rt->sab_funcs.sab_opaque,
- max_int(sab_alloc_len, 1));
- if (!abuf->data)
- goto fail;
- memset(abuf->data, 0, sab_alloc_len);
- } else {
- /* the allocation must be done after the object creation */
- abuf->data = js_mallocz(ctx, max_int(len, 1));
- if (!abuf->data)
- goto fail;
- }
- } else {
- if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
- rt->sab_funcs.sab_dup) {
- rt->sab_funcs.sab_dup(rt->sab_funcs.sab_opaque, buf);
- }
- abuf->data = buf;
- }
- init_list_head(&abuf->array_list);
- abuf->detached = false;
- abuf->shared = (class_id == JS_CLASS_SHARED_ARRAY_BUFFER);
- abuf->opaque = opaque;
- abuf->free_func = free_func;
- if (alloc_flag && buf)
- memcpy(abuf->data, buf, len);
- JS_SetOpaqueInternal(obj, abuf);
- return obj;
- fail:
- JS_FreeValue(ctx, obj);
- js_free(ctx, abuf);
- return JS_EXCEPTION;
- }
- static void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr)
- {
- js_free_rt(rt, ptr);
- }
- static JSValue js_array_buffer_constructor2(JSContext *ctx,
- JSValueConst new_target,
- uint64_t len, uint64_t *max_len,
- JSClassID class_id)
- {
- return js_array_buffer_constructor3(ctx, new_target, len, max_len,
- class_id, NULL, js_array_buffer_free,
- NULL, true);
- }
- static JSValue js_array_buffer_constructor1(JSContext *ctx,
- JSValueConst new_target,
- uint64_t len, uint64_t *max_len)
- {
- return js_array_buffer_constructor2(ctx, new_target, len, max_len,
- JS_CLASS_ARRAY_BUFFER);
- }
- JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
- JSFreeArrayBufferDataFunc *free_func, void *opaque,
- bool is_shared)
- {
- JSClassID class_id =
- is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER;
- return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL, class_id,
- buf, free_func, opaque, false);
- }
- bool JS_IsArrayBuffer(JSValueConst obj) {
- return JS_GetClassID(obj) == JS_CLASS_ARRAY_BUFFER;
- }
- /* create a new ArrayBuffer of length 'len' and copy 'buf' to it */
- JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len)
- {
- return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL,
- JS_CLASS_ARRAY_BUFFER,
- (uint8_t *)buf,
- js_array_buffer_free, NULL,
- true);
- }
- static JSValue js_array_buffer_constructor0(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv,
- JSClassID class_id)
- {
- uint64_t len, max_len, *pmax_len = NULL;
- JSValue obj, val;
- int64_t i;
- if (JS_ToIndex(ctx, &len, argv[0]))
- return JS_EXCEPTION;
- if (argc < 2)
- goto next;
- if (!JS_IsObject(argv[1]))
- goto next;
- obj = JS_ToObject(ctx, argv[1]);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- val = JS_GetProperty(ctx, obj, JS_ATOM_maxByteLength);
- JS_FreeValue(ctx, obj);
- if (JS_IsException(val))
- return JS_EXCEPTION;
- if (JS_IsUndefined(val))
- goto next;
- if (JS_ToInt64Free(ctx, &i, val))
- return JS_EXCEPTION;
- // don't have to check i < 0 because len >= 0
- if (len > i || i > MAX_SAFE_INTEGER)
- return JS_ThrowRangeError(ctx, "invalid array buffer max length");
- max_len = i;
- pmax_len = &max_len;
- next:
- return js_array_buffer_constructor2(ctx, new_target, len, pmax_len,
- class_id);
- }
- static JSValue js_array_buffer_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- return js_array_buffer_constructor0(ctx, new_target, argc, argv,
- JS_CLASS_ARRAY_BUFFER);
- }
- static JSValue js_shared_array_buffer_constructor(JSContext *ctx,
- JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- return js_array_buffer_constructor0(ctx, new_target, argc, argv,
- JS_CLASS_SHARED_ARRAY_BUFFER);
- }
- /* also used for SharedArrayBuffer */
- static void js_array_buffer_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSArrayBuffer *abuf = p->u.array_buffer;
- struct list_head *el, *el1;
- if (abuf) {
- /* The ArrayBuffer finalizer may be called before the typed
- array finalizers using it, so abuf->array_list is not
- necessarily empty. */
- list_for_each_safe(el, el1, &abuf->array_list) {
- JSTypedArray *ta;
- JSObject *p1;
- ta = list_entry(el, JSTypedArray, link);
- ta->link.prev = NULL;
- ta->link.next = NULL;
- p1 = ta->obj;
- /* Note: the typed array length and offset fields are not modified */
- if (p1->class_id != JS_CLASS_DATAVIEW) {
- p1->u.array.count = 0;
- p1->u.array.u.ptr = NULL;
- }
- }
- if (abuf->shared && rt->sab_funcs.sab_free) {
- rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data);
- } else {
- if (abuf->free_func)
- abuf->free_func(rt, abuf->opaque, abuf->data);
- }
- js_free_rt(rt, abuf);
- }
- }
- static JSValue js_array_buffer_isView(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
- p = JS_VALUE_GET_OBJ(argv[0]);
- return js_bool(is_typed_array(p->class_id) ||
- p->class_id == JS_CLASS_DATAVIEW);
- }
- return JS_FALSE;
- }
- static const JSCFunctionListEntry js_array_buffer_funcs[] = {
- JS_CFUNC_DEF("isView", 1, js_array_buffer_isView ),
- JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
- };
- static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx)
- {
- return JS_ThrowTypeError(ctx, "ArrayBuffer is detached");
- }
- static JSValue JS_ThrowTypeErrorArrayBufferOOB(JSContext *ctx)
- {
- return JS_ThrowTypeError(ctx, "ArrayBuffer is detached or resized");
- }
- // #sec-get-arraybuffer.prototype.detached
- static JSValue js_array_buffer_get_detached(JSContext *ctx,
- JSValueConst this_val)
- {
- JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_BUFFER);
- if (!abuf)
- return JS_EXCEPTION;
- if (abuf->shared)
- return JS_ThrowTypeError(ctx, "detached called on SharedArrayBuffer");
- return js_bool(abuf->detached);
- }
- static JSValue js_array_buffer_get_byteLength(JSContext *ctx,
- JSValueConst this_val,
- int class_id)
- {
- JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
- if (!abuf)
- return JS_EXCEPTION;
- /* return 0 if detached */
- return js_uint32(abuf->byte_length);
- }
- static JSValue js_array_buffer_get_maxByteLength(JSContext *ctx,
- JSValueConst this_val,
- int class_id)
- {
- JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
- if (!abuf)
- return JS_EXCEPTION;
- if (array_buffer_is_resizable(abuf))
- return js_uint32(abuf->max_byte_length);
- return js_uint32(abuf->byte_length);
- }
- static JSValue js_array_buffer_get_resizable(JSContext *ctx,
- JSValueConst this_val,
- int class_id)
- {
- JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
- if (!abuf)
- return JS_EXCEPTION;
- return js_bool(array_buffer_is_resizable(abuf));
- }
- void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
- {
- JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
- struct list_head *el;
- if (!abuf || abuf->detached)
- return;
- if (abuf->free_func)
- abuf->free_func(ctx->rt, abuf->opaque, abuf->data);
- abuf->data = NULL;
- abuf->byte_length = 0;
- abuf->detached = true;
- list_for_each(el, &abuf->array_list) {
- JSTypedArray *ta;
- JSObject *p;
- ta = list_entry(el, JSTypedArray, link);
- p = ta->obj;
- /* Note: the typed array length and offset fields are not modified */
- if (p->class_id != JS_CLASS_DATAVIEW) {
- p->u.array.count = 0;
- p->u.array.u.ptr = NULL;
- }
- }
- }
- /* get an ArrayBuffer or SharedArrayBuffer */
- static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- goto fail;
- p = JS_VALUE_GET_OBJ(obj);
- if (p->class_id != JS_CLASS_ARRAY_BUFFER &&
- p->class_id != JS_CLASS_SHARED_ARRAY_BUFFER) {
- fail:
- JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_ARRAY_BUFFER);
- return NULL;
- }
- return p->u.array_buffer;
- }
- /* return NULL if exception. WARNING: any JS call can detach the
- buffer and render the returned pointer invalid */
- uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj)
- {
- JSArrayBuffer *abuf = js_get_array_buffer(ctx, obj);
- if (!abuf)
- goto fail;
- if (abuf->detached) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- goto fail;
- }
- *psize = abuf->byte_length;
- return abuf->data;
- fail:
- *psize = 0;
- return NULL;
- }
- static bool array_buffer_is_resizable(const JSArrayBuffer *abuf)
- {
- return abuf->max_byte_length >= 0;
- }
- static void js_array_buffer_update_typed_arrays(JSArrayBuffer *abuf)
- {
- uint32_t size_log2, size_elem;
- struct list_head *el;
- JSTypedArray *ta;
- JSObject *p;
- uint8_t *data;
- int64_t len;
- len = abuf->byte_length;
- data = abuf->data;
- list_for_each(el, &abuf->array_list) {
- ta = list_entry(el, JSTypedArray, link);
- p = ta->obj;
- if (p->class_id == JS_CLASS_DATAVIEW) {
- if (ta->track_rab && ta->offset < len)
- ta->length = len - ta->offset;
- continue;
- }
- p->u.array.count = 0;
- p->u.array.u.ptr = NULL;
- size_log2 = typed_array_size_log2(p->class_id);
- size_elem = 1 << size_log2;
- if (ta->track_rab) {
- if (len >= (int64_t)ta->offset + size_elem) {
- p->u.array.count = (len - ta->offset) >> size_log2;
- p->u.array.u.ptr = &data[ta->offset];
- }
- } else {
- if (len >= (int64_t)ta->offset + ta->length) {
- p->u.array.count = ta->length >> size_log2;
- p->u.array.u.ptr = &data[ta->offset];
- }
- }
- }
- }
- // ES #sec-arraybuffer.prototype.transfer
- static JSValue js_array_buffer_transfer(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- bool transfer_to_fixed_length = magic & 1;
- JSArrayBuffer *abuf;
- uint64_t new_len, old_len, max_len, *pmax_len;
- uint8_t *bs, *new_bs;
- abuf = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_BUFFER);
- if (!abuf)
- return JS_EXCEPTION;
- if (abuf->shared)
- return JS_ThrowTypeError(ctx, "cannot transfer a SharedArrayBuffer");
- if (argc < 1 || JS_IsUndefined(argv[0]))
- new_len = abuf->byte_length;
- else if (JS_ToIndex(ctx, &new_len, argv[0]))
- return JS_EXCEPTION;
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- pmax_len = NULL;
- if (!transfer_to_fixed_length) {
- if (array_buffer_is_resizable(abuf)) { // carry over maxByteLength
- max_len = abuf->max_byte_length;
- if (new_len > max_len)
- return JS_ThrowTypeError(ctx, "invalid array buffer length");
- // TODO(bnoordhuis) support externally managed RABs
- if (abuf->free_func == js_array_buffer_free)
- pmax_len = &max_len;
- }
- }
- /* create an empty AB */
- if (new_len == 0) {
- JS_DetachArrayBuffer(ctx, this_val);
- return js_array_buffer_constructor2(ctx, JS_UNDEFINED, 0, pmax_len,
- JS_CLASS_ARRAY_BUFFER);
- }
- bs = abuf->data;
- old_len = abuf->byte_length;
- /* if length mismatch, realloc. Otherwise, use the same backing buffer. */
- if (new_len != old_len) {
- new_bs = js_realloc(ctx, bs, new_len);
- if (!new_bs)
- return JS_EXCEPTION;
- bs = new_bs;
- if (new_len > old_len)
- memset(bs + old_len, 0, new_len - old_len);
- }
- /* neuter the backing buffer */
- abuf->data = NULL;
- abuf->byte_length = 0;
- abuf->detached = true;
- js_array_buffer_update_typed_arrays(abuf);
- return js_array_buffer_constructor3(ctx, JS_UNDEFINED, new_len, pmax_len,
- JS_CLASS_ARRAY_BUFFER,
- bs, abuf->free_func,
- NULL, false);
- }
- static JSValue js_array_buffer_resize(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int class_id)
- {
- JSArrayBuffer *abuf;
- uint8_t *data;
- int64_t len;
- abuf = JS_GetOpaque2(ctx, this_val, class_id);
- if (!abuf)
- return JS_EXCEPTION;
- if (JS_ToInt64(ctx, &len, argv[0]))
- return JS_EXCEPTION;
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- if (!array_buffer_is_resizable(abuf))
- return JS_ThrowTypeError(ctx, "array buffer is not resizable");
- // TODO(bnoordhuis) support externally managed RABs
- if (abuf->free_func != js_array_buffer_free)
- return JS_ThrowTypeError(ctx, "external array buffer is not resizable");
- if (len < 0 || len > abuf->max_byte_length) {
- bad_length:
- return JS_ThrowRangeError(ctx, "invalid array buffer length");
- }
- // SABs can only grow and we don't need to realloc because
- // js_array_buffer_constructor3 commits all memory upfront;
- // regular RABs are resizable both ways and realloc
- if (abuf->shared) {
- if (len < abuf->byte_length)
- goto bad_length;
- // Note this is off-spec; there's supposed to be a single atomic
- // |byteLength| property that's shared across SABs but we store
- // it per SAB instead. That means when thread A calls sab.grow(2)
- // at time t0, and thread B calls sab.grow(1) at time t1, we don't
- // throw a TypeError in thread B as the spec says we should,
- // instead both threads get their own view of the backing memory,
- // 2 bytes big in A, and 1 byte big in B
- abuf->byte_length = len;
- } else {
- data = js_realloc(ctx, abuf->data, max_int(len, 1));
- if (!data)
- return JS_EXCEPTION;
- if (len > abuf->byte_length)
- memset(&data[abuf->byte_length], 0, len - abuf->byte_length);
- abuf->byte_length = len;
- abuf->data = data;
- }
- js_array_buffer_update_typed_arrays(abuf);
- return JS_UNDEFINED;
- }
- static JSValue js_array_buffer_slice(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv, int class_id)
- {
- JSArrayBuffer *abuf, *new_abuf;
- int64_t len, start, end, new_len;
- JSValue ctor, new_obj;
- abuf = JS_GetOpaque2(ctx, this_val, class_id);
- if (!abuf)
- return JS_EXCEPTION;
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- len = abuf->byte_length;
- if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
- return JS_EXCEPTION;
- end = len;
- if (!JS_IsUndefined(argv[1])) {
- if (JS_ToInt64Clamp(ctx, &end, argv[1], 0, len, len))
- return JS_EXCEPTION;
- }
- new_len = max_int64(end - start, 0);
- ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
- if (JS_IsException(ctor))
- return ctor;
- if (JS_IsUndefined(ctor)) {
- new_obj = js_array_buffer_constructor2(ctx, JS_UNDEFINED, new_len,
- NULL, class_id);
- } else {
- JSValue args[1];
- args[0] = js_int64(new_len);
- new_obj = JS_CallConstructor(ctx, ctor, 1, vc(args));
- JS_FreeValue(ctx, ctor);
- JS_FreeValue(ctx, args[0]);
- }
- if (JS_IsException(new_obj))
- return new_obj;
- new_abuf = JS_GetOpaque2(ctx, new_obj, class_id);
- if (!new_abuf)
- goto fail;
- if (js_same_value(ctx, new_obj, this_val)) {
- JS_ThrowTypeError(ctx, "cannot use identical ArrayBuffer");
- goto fail;
- }
- if (new_abuf->detached) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- goto fail;
- }
- if (new_abuf->byte_length < new_len) {
- JS_ThrowTypeError(ctx, "new ArrayBuffer is too small");
- goto fail;
- }
- /* must test again because of side effects */
- if (abuf->detached || abuf->byte_length < start + new_len) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- goto fail;
- }
- memcpy(new_abuf->data, abuf->data + start, new_len);
- return new_obj;
- fail:
- JS_FreeValue(ctx, new_obj);
- return JS_EXCEPTION;
- }
- static const JSCFunctionListEntry js_array_buffer_proto_funcs[] = {
- JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_ARRAY_BUFFER ),
- JS_CGETSET_MAGIC_DEF("maxByteLength", js_array_buffer_get_maxByteLength, NULL, JS_CLASS_ARRAY_BUFFER ),
- JS_CGETSET_MAGIC_DEF("resizable", js_array_buffer_get_resizable, NULL, JS_CLASS_ARRAY_BUFFER ),
- JS_CGETSET_DEF("detached", js_array_buffer_get_detached, NULL ),
- JS_CFUNC_MAGIC_DEF("resize", 1, js_array_buffer_resize, JS_CLASS_ARRAY_BUFFER ),
- JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_ARRAY_BUFFER ),
- JS_CFUNC_MAGIC_DEF("transfer", 0, js_array_buffer_transfer, 0 ),
- JS_CFUNC_MAGIC_DEF("transferToFixedLength", 0, js_array_buffer_transfer, 1 ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "ArrayBuffer", JS_PROP_CONFIGURABLE ),
- };
- /* SharedArrayBuffer */
- static const JSCFunctionListEntry js_shared_array_buffer_funcs[] = {
- JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
- };
- static const JSCFunctionListEntry js_shared_array_buffer_proto_funcs[] = {
- JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),
- JS_CGETSET_MAGIC_DEF("maxByteLength", js_array_buffer_get_maxByteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),
- JS_CGETSET_MAGIC_DEF("growable", js_array_buffer_get_resizable, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),
- JS_CFUNC_MAGIC_DEF("grow", 1, js_array_buffer_resize, JS_CLASS_SHARED_ARRAY_BUFFER ),
- JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_SHARED_ARRAY_BUFFER ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "SharedArrayBuffer", JS_PROP_CONFIGURABLE ),
- };
- static bool is_typed_array(JSClassID class_id)
- {
- return class_id >= JS_CLASS_UINT8C_ARRAY && class_id <= JS_CLASS_FLOAT64_ARRAY;
- }
- // is the typed array detached or out of bounds relative to its RAB?
- // |p| must be a typed array, *not* a DataView
- static bool typed_array_is_oob(JSObject *p)
- {
- JSArrayBuffer *abuf;
- JSTypedArray *ta;
- int len, size_elem;
- int64_t end;
- assert(is_typed_array(p->class_id));
- ta = p->u.typed_array;
- abuf = ta->buffer->u.array_buffer;
- if (abuf->detached)
- return true;
- len = abuf->byte_length;
- if (ta->offset > len)
- return true;
- if (ta->track_rab)
- return false;
- if (len < (int64_t)ta->offset + ta->length)
- return true;
- size_elem = 1 << typed_array_size_log2(p->class_id);
- end = (int64_t)ta->offset + (int64_t)p->u.array.count * size_elem;
- return end > len;
- }
- /* WARNING: 'p' must be a typed array. Works even if the array buffer
- is detached */
- static uint32_t typed_array_length(JSObject *p)
- {
- JSTypedArray *ta = p->u.typed_array;
- int size_log2 = typed_array_size_log2(p->class_id);
- return ta->length >> size_log2;
- }
- static int validate_typed_array(JSContext *ctx, JSValueConst this_val)
- {
- JSObject *p;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return -1;
- if (typed_array_is_oob(p)) {
- JS_ThrowTypeErrorArrayBufferOOB(ctx);
- return -1;
- }
- return 0;
- }
- static JSValue js_typed_array_get_length(JSContext *ctx, JSValueConst this_val)
- {
- JSObject *p;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- return js_int32(p->u.array.count);
- }
- static JSValue js_typed_array_get_buffer(JSContext *ctx, JSValueConst this_val)
- {
- JSObject *p;
- JSTypedArray *ta;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- ta = p->u.typed_array;
- return js_dup(JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
- }
- static JSValue js_typed_array_get_byteLength(JSContext *ctx, JSValueConst this_val)
- {
- uint32_t size_log2;
- JSTypedArray *ta;
- JSObject *p;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- if (typed_array_is_oob(p))
- return js_int32(0);
- ta = p->u.typed_array;
- if (!ta->track_rab)
- return js_uint32(ta->length);
- size_log2 = typed_array_size_log2(p->class_id);
- return js_int64((int64_t)p->u.array.count << size_log2);
- }
- static JSValue js_typed_array_get_byteOffset(JSContext *ctx, JSValueConst this_val)
- {
- JSObject *p;
- JSTypedArray *ta;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- if (typed_array_is_oob(p))
- return js_int32(0);
- ta = p->u.typed_array;
- return js_uint32(ta->offset);
- }
- JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,
- JSTypedArrayEnum type)
- {
- if (type < JS_TYPED_ARRAY_UINT8C || type > JS_TYPED_ARRAY_FLOAT64)
- return JS_ThrowRangeError(ctx, "invalid typed array type");
- return js_typed_array_constructor(ctx, JS_UNDEFINED, argc, argv,
- JS_CLASS_UINT8C_ARRAY + type);
- }
- /* Return the buffer associated to the typed array or an exception if
- it is not a typed array or if the buffer is detached. pbyte_offset,
- pbyte_length or pbytes_per_element can be NULL. */
- JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
- size_t *pbyte_offset,
- size_t *pbyte_length,
- size_t *pbytes_per_element)
- {
- JSObject *p;
- JSTypedArray *ta;
- p = get_typed_array(ctx, obj);
- if (!p)
- return JS_EXCEPTION;
- if (typed_array_is_oob(p))
- return JS_ThrowTypeErrorArrayBufferOOB(ctx);
- ta = p->u.typed_array;
- if (pbyte_offset)
- *pbyte_offset = ta->offset;
- if (pbyte_length)
- *pbyte_length = ta->length;
- if (pbytes_per_element) {
- *pbytes_per_element = 1 << typed_array_size_log2(p->class_id);
- }
- return js_dup(JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
- }
- /* return NULL if exception. WARNING: any JS call can detach the
- buffer and render the returned pointer invalid */
- uint8_t *JS_GetUint8Array(JSContext *ctx, size_t *psize, JSValueConst obj)
- {
- JSObject *p;
- JSTypedArray *ta;
- JSArrayBuffer *abuf;
- p = get_typed_array(ctx, obj);
- if (!p)
- goto fail;
- if (typed_array_is_oob(p)) {
- JS_ThrowTypeErrorArrayBufferOOB(ctx);
- goto fail;
- }
- if (p->class_id != JS_CLASS_UINT8_ARRAY && p->class_id != JS_CLASS_UINT8C_ARRAY) {
- JS_ThrowTypeError(ctx, "not a Uint8Array");
- goto fail;
- }
- ta = p->u.typed_array;
- abuf = ta->buffer->u.array_buffer;
- *psize = ta->length;
- return abuf->data + ta->offset;
- fail:
- *psize = 0;
- return NULL;
- }
- static JSValue js_typed_array_get_toStringTag(JSContext *ctx,
- JSValueConst this_val)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
- return JS_UNDEFINED;
- p = JS_VALUE_GET_OBJ(this_val);
- if (!is_typed_array(p->class_id))
- return JS_UNDEFINED;
- return JS_AtomToString(ctx, ctx->rt->class_array[p->class_id].class_name);
- }
- static JSValue js_typed_array_set_internal(JSContext *ctx,
- JSValueConst dst,
- JSValueConst src,
- JSValueConst off)
- {
- JSObject *p;
- JSObject *src_p;
- uint32_t i;
- int64_t dst_len, src_len, offset;
- JSValue val, src_obj = JS_UNDEFINED;
- p = get_typed_array(ctx, dst);
- if (!p)
- goto fail;
- if (JS_ToInt64Sat(ctx, &offset, off))
- goto fail;
- if (offset < 0)
- goto range_error;
- if (typed_array_is_oob(p)) {
- detached:
- JS_ThrowTypeErrorArrayBufferOOB(ctx);
- goto fail;
- }
- dst_len = p->u.array.count;
- src_obj = JS_ToObject(ctx, src);
- if (JS_IsException(src_obj))
- goto fail;
- src_p = JS_VALUE_GET_OBJ(src_obj);
- if (is_typed_array(src_p->class_id)) {
- JSTypedArray *dest_ta = p->u.typed_array;
- JSArrayBuffer *dest_abuf = dest_ta->buffer->u.array_buffer;
- JSTypedArray *src_ta = src_p->u.typed_array;
- JSArrayBuffer *src_abuf = src_ta->buffer->u.array_buffer;
- int shift = typed_array_size_log2(p->class_id);
- if (typed_array_is_oob(src_p))
- goto detached;
- src_len = src_p->u.array.count;
- if (offset > dst_len - src_len)
- goto range_error;
- /* copying between typed objects */
- if (src_p->class_id == p->class_id) {
- /* same type, use memmove */
- memmove(dest_abuf->data + dest_ta->offset + (offset << shift),
- src_abuf->data + src_ta->offset, src_len << shift);
- goto done;
- }
- if (dest_abuf->data == src_abuf->data) {
- /* copying between the same buffer using different types of mappings
- would require a temporary buffer */
- }
- /* otherwise, default behavior is slow but correct */
- } else {
- // can change |dst| as a side effect; per spec,
- // perform the range check against its old length
- if (js_get_length64(ctx, &src_len, src_obj))
- goto fail;
- if (offset > dst_len - src_len) {
- range_error:
- JS_ThrowRangeError(ctx, "invalid array length");
- goto fail;
- }
- }
- for(i = 0; i < src_len; i++) {
- val = JS_GetPropertyUint32(ctx, src_obj, i);
- if (JS_IsException(val))
- goto fail;
- // Per spec: detaching the TA mid-iteration is allowed and should
- // not throw an exception. Because iteration over the source array is
- // observable, we cannot bail out early when the TA is first detached.
- if (typed_array_is_oob(p)) {
- JS_FreeValue(ctx, val);
- } else if (JS_SetPropertyUint32(ctx, dst, offset + i, val) < 0) {
- goto fail;
- }
- }
- done:
- JS_FreeValue(ctx, src_obj);
- return JS_UNDEFINED;
- fail:
- JS_FreeValue(ctx, src_obj);
- return JS_EXCEPTION;
- }
- static JSValue js_typed_array_at(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSObject *p;
- int64_t idx, len;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- if (typed_array_is_oob(p))
- return JS_ThrowTypeErrorArrayBufferOOB(ctx);
- len = p->u.array.count;
- // note: can change p->u.array.count
- if (JS_ToInt64Sat(ctx, &idx, argv[0]))
- return JS_EXCEPTION;
- if (idx < 0)
- idx = len + idx;
- if (idx < 0 || idx >= p->u.array.count)
- return JS_UNDEFINED;
- switch (p->class_id) {
- case JS_CLASS_INT8_ARRAY:
- return js_int32(p->u.array.u.int8_ptr[idx]);
- case JS_CLASS_UINT8C_ARRAY:
- case JS_CLASS_UINT8_ARRAY:
- return js_int32(p->u.array.u.uint8_ptr[idx]);
- case JS_CLASS_INT16_ARRAY:
- return js_int32(p->u.array.u.int16_ptr[idx]);
- case JS_CLASS_UINT16_ARRAY:
- return js_int32(p->u.array.u.uint16_ptr[idx]);
- case JS_CLASS_INT32_ARRAY:
- return js_int32(p->u.array.u.int32_ptr[idx]);
- case JS_CLASS_UINT32_ARRAY:
- return js_uint32(p->u.array.u.uint32_ptr[idx]);
- case JS_CLASS_FLOAT16_ARRAY:
- return js_float64(fromfp16(p->u.array.u.fp16_ptr[idx]));
- case JS_CLASS_FLOAT32_ARRAY:
- return js_float64(p->u.array.u.float_ptr[idx]);
- case JS_CLASS_FLOAT64_ARRAY:
- return js_float64(p->u.array.u.double_ptr[idx]);
- case JS_CLASS_BIG_INT64_ARRAY:
- return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
- case JS_CLASS_BIG_UINT64_ARRAY:
- return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
- }
- abort(); /* unreachable */
- return JS_UNDEFINED;
- }
- static JSValue js_typed_array_with(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue arr, val;
- JSObject *p;
- int64_t idx;
- uint32_t len, oldlen, newlen;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- oldlen = p->u.array.count;
- if (JS_ToInt64Sat(ctx, &idx, argv[0]))
- return JS_EXCEPTION;
- val = JS_ToPrimitive(ctx, argv[1], HINT_NUMBER);
- if (JS_IsException(val))
- return JS_EXCEPTION;
- newlen = p->u.array.count;
- if (idx < 0)
- idx = newlen + idx;
- if (idx < 0 || idx >= newlen) {
- JS_FreeValue(ctx, val);
- return JS_ThrowRangeError(ctx, "invalid array index");
- }
- len = min_uint32(oldlen, newlen);
- arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
- p->class_id, len);
- if (JS_IsException(arr)) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- if (idx < len && JS_SetPropertyInt64(ctx, arr, idx, val) < 0) {
- JS_FreeValue(ctx, arr);
- return JS_EXCEPTION;
- }
- return arr;
- }
- static JSValue js_typed_array_set(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst offset = JS_UNDEFINED;
- if (argc > 1) {
- offset = argv[1];
- }
- return js_typed_array_set_internal(ctx, this_val, argv[0], offset);
- }
- static JSValue js_create_typed_array_iterator(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- if (validate_typed_array(ctx, this_val))
- return JS_EXCEPTION;
- return js_create_array_iterator(ctx, this_val, argc, argv, magic);
- }
- static JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor,
- int argc, JSValueConst *argv)
- {
- JSValue ret;
- int new_len;
- int64_t len;
- ret = JS_CallConstructor(ctx, ctor, argc, argv);
- if (JS_IsException(ret))
- return ret;
- /* validate the typed array */
- new_len = js_typed_array_get_length_unsafe(ctx, ret);
- if (new_len < 0)
- goto fail;
- if (argc == 1) {
- /* ensure that it is large enough */
- if (JS_ToLengthFree(ctx, &len, js_dup(argv[0])))
- goto fail;
- if (new_len < len) {
- JS_ThrowTypeError(ctx, "TypedArray length is too small");
- fail:
- JS_FreeValue(ctx, ret);
- return JS_EXCEPTION;
- }
- }
- return ret;
- }
- static JSValue js_typed_array___speciesCreate(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst obj;
- JSObject *p;
- JSValue ctor, ret;
- int argc1;
- obj = argv[0];
- p = get_typed_array(ctx, obj);
- if (!p)
- return JS_EXCEPTION;
- ctor = JS_SpeciesConstructor(ctx, obj, JS_UNDEFINED);
- if (JS_IsException(ctor))
- return ctor;
- argc1 = max_int(argc - 1, 0);
- if (JS_IsUndefined(ctor)) {
- ret = js_typed_array_constructor(ctx, JS_UNDEFINED, argc1, argv + 1,
- p->class_id);
- } else {
- ret = js_typed_array_create(ctx, ctor, argc1, argv + 1);
- JS_FreeValue(ctx, ctor);
- }
- return ret;
- }
- static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- // from(items, mapfn = void 0, this_arg = void 0)
- JSValueConst items = argv[0], mapfn, this_arg;
- JSValueConst args[2];
- JSValue stack[2];
- JSValue iter, arr, r, v, v2;
- int64_t k, len;
- int done, mapping;
- mapping = false;
- mapfn = JS_UNDEFINED;
- this_arg = JS_UNDEFINED;
- r = JS_UNDEFINED;
- arr = JS_UNDEFINED;
- stack[0] = JS_UNDEFINED;
- stack[1] = JS_UNDEFINED;
- if (argc > 1) {
- mapfn = argv[1];
- if (!JS_IsUndefined(mapfn)) {
- if (check_function(ctx, mapfn))
- goto exception;
- mapping = 1;
- if (argc > 2)
- this_arg = argv[2];
- }
- }
- iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
- if (JS_IsException(iter))
- goto exception;
- if (!JS_IsUndefined(iter)) {
- JS_FreeValue(ctx, iter);
- arr = JS_NewArray(ctx);
- if (JS_IsException(arr))
- goto exception;
- stack[0] = js_dup(items);
- if (js_for_of_start(ctx, &stack[1], false))
- goto exception;
- for (k = 0;; k++) {
- v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
- if (JS_IsException(v))
- goto exception_close;
- if (done)
- break;
- if (JS_DefinePropertyValueInt64(ctx, arr, k, v, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
- goto exception_close;
- }
- } else {
- arr = JS_ToObject(ctx, items);
- if (JS_IsException(arr))
- goto exception;
- }
- if (js_get_length64(ctx, &len, arr) < 0)
- goto exception;
- v = js_int64(len);
- r = js_typed_array_create(ctx, this_val, 1, vc(&v));
- JS_FreeValue(ctx, v);
- if (JS_IsException(r))
- goto exception;
- for(k = 0; k < len; k++) {
- v = JS_GetPropertyInt64(ctx, arr, k);
- if (JS_IsException(v))
- goto exception;
- if (mapping) {
- args[0] = v;
- args[1] = js_int32(k);
- v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
- JS_FreeValue(ctx, v);
- v = v2;
- if (JS_IsException(v))
- goto exception;
- }
- if (JS_SetPropertyInt64(ctx, r, k, v) < 0)
- goto exception;
- }
- goto done;
- exception_close:
- if (!JS_IsUndefined(stack[0]))
- JS_IteratorClose(ctx, stack[0], true);
- exception:
- JS_FreeValue(ctx, r);
- r = JS_EXCEPTION;
- done:
- JS_FreeValue(ctx, arr);
- JS_FreeValue(ctx, stack[0]);
- JS_FreeValue(ctx, stack[1]);
- return r;
- }
- static JSValue js_typed_array_of(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue v, obj;
- int i;
- v = js_int32(argc);
- obj = js_typed_array_create(ctx, this_val, 1, vc(&v));
- if (JS_IsException(obj))
- return obj;
- for(i = 0; i < argc; i++) {
- if (JS_SetPropertyUint32(ctx, obj, i, js_dup(argv[i])) < 0) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- }
- return obj;
- }
- static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSObject *p;
- int len, to, from, final, count, shift, space;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- if (typed_array_is_oob(p))
- return JS_ThrowTypeErrorArrayBufferOOB(ctx);
- len = p->u.array.count;
- if (JS_ToInt32Clamp(ctx, &to, argv[0], 0, len, len))
- return JS_EXCEPTION;
- if (JS_ToInt32Clamp(ctx, &from, argv[1], 0, len, len))
- return JS_EXCEPTION;
- final = len;
- if (argc > 2 && !JS_IsUndefined(argv[2])) {
- if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
- return JS_EXCEPTION;
- }
- if (typed_array_is_oob(p))
- return JS_ThrowTypeErrorArrayBufferOOB(ctx);
- // RAB may have been resized by evil .valueOf method
- space = p->u.array.count - max_int(to, from);
- count = min_int(final - from, len - to);
- count = min_int(count, space);
- if (count > 0) {
- shift = typed_array_size_log2(p->class_id);
- memmove(p->u.array.u.uint8_ptr + (to << shift),
- p->u.array.u.uint8_ptr + (from << shift),
- count << shift);
- }
- return js_dup(this_val);
- }
- static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSObject *p;
- int len, k, final, shift;
- uint64_t v64;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- if (typed_array_is_oob(p))
- return JS_ThrowTypeErrorArrayBufferOOB(ctx);
- len = p->u.array.count;
- if (p->class_id == JS_CLASS_UINT8C_ARRAY) {
- int32_t v;
- if (JS_ToUint8ClampFree(ctx, &v, js_dup(argv[0])))
- return JS_EXCEPTION;
- v64 = v;
- } else if (p->class_id <= JS_CLASS_UINT32_ARRAY) {
- uint32_t v;
- if (JS_ToUint32(ctx, &v, argv[0]))
- return JS_EXCEPTION;
- v64 = v;
- } else
- if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
- if (JS_ToBigInt64(ctx, (int64_t *)&v64, argv[0]))
- return JS_EXCEPTION;
- } else {
- double d;
- if (JS_ToFloat64(ctx, &d, argv[0]))
- return JS_EXCEPTION;
- if (p->class_id == JS_CLASS_FLOAT16_ARRAY) {
- v64 = tofp16(d);
- } else if (p->class_id == JS_CLASS_FLOAT32_ARRAY) {
- union {
- float f;
- uint32_t u32;
- } u;
- u.f = d;
- v64 = u.u32;
- } else {
- JSFloat64Union u;
- u.d = d;
- v64 = u.u64;
- }
- }
- k = 0;
- if (argc > 1) {
- if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
- return JS_EXCEPTION;
- }
- final = len;
- if (argc > 2 && !JS_IsUndefined(argv[2])) {
- if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
- return JS_EXCEPTION;
- }
- if (typed_array_is_oob(p))
- return JS_ThrowTypeErrorArrayBufferOOB(ctx);
- // RAB may have been resized by evil .valueOf method
- final = min_int(final, p->u.array.count);
- shift = typed_array_size_log2(p->class_id);
- switch(shift) {
- case 0:
- if (k < final) {
- memset(p->u.array.u.uint8_ptr + k, v64, final - k);
- }
- break;
- case 1:
- for(; k < final; k++) {
- p->u.array.u.uint16_ptr[k] = v64;
- }
- break;
- case 2:
- for(; k < final; k++) {
- p->u.array.u.uint32_ptr[k] = v64;
- }
- break;
- case 3:
- for(; k < final; k++) {
- p->u.array.u.uint64_ptr[k] = v64;
- }
- break;
- default:
- abort();
- }
- return js_dup(this_val);
- }
- static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int mode)
- {
- JSValueConst func, this_arg, args[3];
- JSValue val, index_val, res;
- int len, k, end;
- int dir;
- val = JS_UNDEFINED;
- len = js_typed_array_get_length_unsafe(ctx, this_val);
- if (len < 0)
- goto exception;
- func = argv[0];
- if (check_function(ctx, func))
- goto exception;
- this_arg = JS_UNDEFINED;
- if (argc > 1)
- this_arg = argv[1];
- k = 0;
- dir = 1;
- end = len;
- if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {
- k = len - 1;
- dir = -1;
- end = -1;
- }
- for(; k != end; k += dir) {
- index_val = js_int32(k);
- val = JS_GetPropertyValue(ctx, this_val, index_val);
- if (JS_IsException(val))
- goto exception;
- args[0] = val;
- args[1] = index_val;
- args[2] = this_val;
- res = JS_Call(ctx, func, this_arg, 3, args);
- if (JS_IsException(res))
- goto exception;
- if (JS_ToBoolFree(ctx, res)) {
- if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {
- JS_FreeValue(ctx, val);
- return index_val;
- } else {
- return val;
- }
- }
- JS_FreeValue(ctx, val);
- }
- if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)
- return js_int32(-1);
- else
- return JS_UNDEFINED;
- exception:
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- #define special_indexOf 0
- #define special_lastIndexOf 1
- #define special_includes -1
- static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int special)
- {
- JSObject *p;
- int len, tag, is_int, is_bigint, k, stop, inc, res = -1;
- int64_t v64;
- double d;
- float f;
- uint16_t hf;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- if (typed_array_is_oob(p))
- return JS_ThrowTypeErrorArrayBufferOOB(ctx);
- len = p->u.array.count;
- if (len == 0)
- goto done;
- if (special == special_lastIndexOf) {
- k = len - 1;
- if (argc > 1) {
- int64_t k1;
- if (JS_ToInt64Clamp(ctx, &k1, argv[1], -1, len - 1, len))
- goto exception;
- k = k1;
- if (k < 0)
- goto done;
- }
- stop = -1;
- inc = -1;
- } else {
- k = 0;
- if (argc > 1) {
- if (JS_ToInt32Sat(ctx, &k, argv[1]))
- goto exception;
- if (k < 0) {
- k += len;
- if (k < 0)
- k = 0;
- } else if (k > len) {
- k = len;
- }
- }
- stop = len;
- inc = 1;
- }
- /* if the array was detached, no need to go further (but no
- exception is raised) */
- if (typed_array_is_oob(p) || len > p->u.array.count) {
- /* "includes" scans all the properties, so "undefined" can match */
- if (special == special_includes)
- if (JS_IsUndefined(argv[0]))
- if (k < typed_array_length(p))
- res = 0;
- goto done;
- }
- // RAB may have been resized by evil .valueOf method
- len = min_int(len, p->u.array.count);
- if (len == 0)
- goto done;
- k = min_int(k, len);
- stop = min_int(stop, len);
- is_bigint = 0;
- is_int = 0; /* avoid warning */
- v64 = 0; /* avoid warning */
- tag = JS_VALUE_GET_NORM_TAG(argv[0]);
- if (tag == JS_TAG_INT) {
- is_int = 1;
- v64 = JS_VALUE_GET_INT(argv[0]);
- d = v64;
- } else
- if (tag == JS_TAG_FLOAT64) {
- d = JS_VALUE_GET_FLOAT64(argv[0]);
- if (d >= INT64_MIN && d < 0x1p63) {
- v64 = d;
- is_int = (v64 == d);
- }
- } else if (tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT) {
- JSBigIntBuf buf1;
- JSBigInt *p1;
- int sz = (64 / JS_LIMB_BITS);
- if (tag == JS_TAG_SHORT_BIG_INT)
- p1 = js_bigint_set_short(&buf1, argv[0]);
- else
- p1 = JS_VALUE_GET_PTR(argv[0]);
- if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
- if (p1->len > sz)
- goto done; /* does not fit an int64 : cannot be found */
- } else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
- if (js_bigint_sign(p1))
- goto done; /* v < 0 */
- if (p1->len <= sz) {
- /* OK */
- } else if (p1->len == sz + 1 && p1->tab[sz] == 0) {
- /* 2^63 <= v <= 2^64-1 */
- } else {
- goto done;
- }
- } else {
- goto done;
- }
- if (JS_ToBigInt64(ctx, &v64, argv[0]))
- goto exception;
- d = 0;
- is_bigint = 1;
- } else {
- goto done;
- }
- switch (p->class_id) {
- case JS_CLASS_INT8_ARRAY:
- if (is_int && (int8_t)v64 == v64)
- goto scan8;
- break;
- case JS_CLASS_UINT8C_ARRAY:
- case JS_CLASS_UINT8_ARRAY:
- if (is_int && (uint8_t)v64 == v64) {
- const uint8_t *pv, *pp;
- uint16_t v;
- scan8:
- pv = p->u.array.u.uint8_ptr;
- v = v64;
- if (inc > 0) {
- pp = NULL;
- if (pv)
- pp = memchr(pv + k, v, len - k);
- if (pp)
- res = pp - pv;
- } else {
- for (; k != stop; k += inc) {
- if (pv[k] == v) {
- res = k;
- break;
- }
- }
- }
- }
- break;
- case JS_CLASS_INT16_ARRAY:
- if (is_int && (int16_t)v64 == v64)
- goto scan16;
- break;
- case JS_CLASS_UINT16_ARRAY:
- if (is_int && (uint16_t)v64 == v64) {
- const uint16_t *pv;
- uint16_t v;
- scan16:
- pv = p->u.array.u.uint16_ptr;
- v = v64;
- for (; k != stop; k += inc) {
- if (pv[k] == v) {
- res = k;
- break;
- }
- }
- }
- break;
- case JS_CLASS_INT32_ARRAY:
- if (is_int && (int32_t)v64 == v64)
- goto scan32;
- break;
- case JS_CLASS_UINT32_ARRAY:
- if (is_int && (uint32_t)v64 == v64) {
- const uint32_t *pv;
- uint32_t v;
- scan32:
- pv = p->u.array.u.uint32_ptr;
- v = v64;
- for (; k != stop; k += inc) {
- if (pv[k] == v) {
- res = k;
- break;
- }
- }
- }
- break;
- case JS_CLASS_FLOAT16_ARRAY:
- if (is_bigint)
- break;
- if (isnan(d)) {
- const uint16_t *pv = p->u.array.u.fp16_ptr;
- /* special case: indexOf returns -1, includes finds NaN */
- if (special != special_includes)
- goto done;
- for (; k != stop; k += inc) {
- if (isfp16nan(pv[k])) {
- res = k;
- break;
- }
- }
- } else if (d == 0) {
- // special case: includes also finds negative zero
- const uint16_t *pv = p->u.array.u.fp16_ptr;
- for (; k != stop; k += inc) {
- if (isfp16zero(pv[k])) {
- res = k;
- break;
- }
- }
- } else if (hf = tofp16(d), d == fromfp16(hf)) {
- const uint16_t *pv = p->u.array.u.fp16_ptr;
- for (; k != stop; k += inc) {
- if (pv[k] == hf) {
- res = k;
- break;
- }
- }
- }
- break;
- case JS_CLASS_FLOAT32_ARRAY:
- if (is_bigint)
- break;
- if (isnan(d)) {
- const float *pv = p->u.array.u.float_ptr;
- /* special case: indexOf returns -1, includes finds NaN */
- if (special != special_includes)
- goto done;
- for (; k != stop; k += inc) {
- if (isnan(pv[k])) {
- res = k;
- break;
- }
- }
- } else if ((f = (float)d) == d) {
- const float *pv = p->u.array.u.float_ptr;
- for (; k != stop; k += inc) {
- if (pv[k] == f) {
- res = k;
- break;
- }
- }
- }
- break;
- case JS_CLASS_FLOAT64_ARRAY:
- if (is_bigint)
- break;
- if (isnan(d)) {
- const double *pv = p->u.array.u.double_ptr;
- /* special case: indexOf returns -1, includes finds NaN */
- if (special != special_includes)
- goto done;
- for (; k != stop; k += inc) {
- if (isnan(pv[k])) {
- res = k;
- break;
- }
- }
- } else {
- const double *pv = p->u.array.u.double_ptr;
- for (; k != stop; k += inc) {
- if (pv[k] == d) {
- res = k;
- break;
- }
- }
- }
- break;
- case JS_CLASS_BIG_INT64_ARRAY:
- if (is_bigint) {
- goto scan64;
- }
- break;
- case JS_CLASS_BIG_UINT64_ARRAY:
- if (is_bigint) {
- const uint64_t *pv;
- uint64_t v;
- scan64:
- pv = p->u.array.u.uint64_ptr;
- v = v64;
- for (; k != stop; k += inc) {
- if (pv[k] == v) {
- res = k;
- break;
- }
- }
- }
- break;
- }
- done:
- if (special == special_includes)
- return js_bool(res >= 0);
- else
- return js_int32(res);
- exception:
- return JS_EXCEPTION;
- }
- static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int toLocaleString)
- {
- JSValue sep = JS_UNDEFINED, el;
- StringBuffer b_s, *b = &b_s;
- JSString *s = NULL;
- JSObject *p;
- int i, len, oldlen, newlen;
- int c;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- if (typed_array_is_oob(p))
- return JS_ThrowTypeErrorArrayBufferOOB(ctx);
- len = oldlen = newlen = p->u.array.count;
- c = ','; /* default separator */
- if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
- sep = JS_ToString(ctx, argv[0]);
- if (JS_IsException(sep))
- goto exception;
- s = JS_VALUE_GET_STRING(sep);
- if (s->len == 1 && !s->is_wide_char)
- c = str8(s)[0];
- else
- c = -1;
- // ToString(sep) can detach or resize the arraybuffer as a side effect
- newlen = p->u.array.count;
- len = min_int(len, newlen);
- }
- string_buffer_init(ctx, b, 0);
- /* XXX: optimize with direct access */
- for(i = 0; i < len; i++) {
- if (i > 0) {
- if (c >= 0) {
- if (string_buffer_putc8(b, c))
- goto fail;
- } else {
- if (string_buffer_concat(b, s, 0, s->len))
- goto fail;
- }
- }
- el = JS_GetPropertyUint32(ctx, this_val, i);
- /* Can return undefined for example if the typed array is detached */
- if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
- if (JS_IsException(el))
- goto fail;
- if (toLocaleString) {
- el = JS_ToLocaleStringFree(ctx, el);
- }
- if (string_buffer_concat_value_free(b, el))
- goto fail;
- }
- }
- // add extra separators in case RAB was resized by evil .valueOf method
- i = max_int(1, newlen);
- for(/*empty*/; i < oldlen; i++) {
- if (c >= 0) {
- if (string_buffer_putc8(b, c))
- goto fail;
- } else {
- if (string_buffer_concat(b, s, 0, s->len))
- goto fail;
- }
- }
- JS_FreeValue(ctx, sep);
- return string_buffer_end(b);
- fail:
- string_buffer_free(b);
- JS_FreeValue(ctx, sep);
- exception:
- return JS_EXCEPTION;
- }
- static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSObject *p;
- int len;
- len = js_typed_array_get_length_unsafe(ctx, this_val);
- if (len < 0)
- return JS_EXCEPTION;
- if (len > 0) {
- p = JS_VALUE_GET_OBJ(this_val);
- switch (typed_array_size_log2(p->class_id)) {
- case 0:
- {
- uint8_t *p1 = p->u.array.u.uint8_ptr;
- uint8_t *p2 = p1 + len - 1;
- while (p1 < p2) {
- uint8_t v = *p1;
- *p1++ = *p2;
- *p2-- = v;
- }
- }
- break;
- case 1:
- {
- uint16_t *p1 = p->u.array.u.uint16_ptr;
- uint16_t *p2 = p1 + len - 1;
- while (p1 < p2) {
- uint16_t v = *p1;
- *p1++ = *p2;
- *p2-- = v;
- }
- }
- break;
- case 2:
- {
- uint32_t *p1 = p->u.array.u.uint32_ptr;
- uint32_t *p2 = p1 + len - 1;
- while (p1 < p2) {
- uint32_t v = *p1;
- *p1++ = *p2;
- *p2-- = v;
- }
- }
- break;
- case 3:
- {
- uint64_t *p1 = p->u.array.u.uint64_ptr;
- uint64_t *p2 = p1 + len - 1;
- while (p1 < p2) {
- uint64_t v = *p1;
- *p1++ = *p2;
- *p2-- = v;
- }
- }
- break;
- default:
- abort();
- }
- }
- return js_dup(this_val);
- }
- static JSValue js_typed_array_toReversed(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue arr, ret;
- JSObject *p;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
- p->class_id, p->u.array.count);
- if (JS_IsException(arr))
- return JS_EXCEPTION;
- ret = js_typed_array_reverse(ctx, arr, argc, argv);
- JS_FreeValue(ctx, arr);
- return ret;
- }
- static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst args[2];
- JSValue arr, val;
- JSObject *p, *p1;
- int n, len, start, final, count, shift, space;
- arr = JS_UNDEFINED;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- if (typed_array_is_oob(p))
- return JS_ThrowTypeErrorArrayBufferOOB(ctx);
- len = p->u.array.count;
- if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
- goto exception;
- final = len;
- if (!JS_IsUndefined(argv[1])) {
- if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
- goto exception;
- }
- count = max_int(final - start, 0);
- args[0] = this_val;
- args[1] = js_int32(count);
- arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
- if (JS_IsException(arr))
- goto exception;
- if (count > 0) {
- if (validate_typed_array(ctx, this_val)
- || validate_typed_array(ctx, arr))
- goto exception;
- if (len != p->u.array.count)
- goto slow_path;
- p1 = get_typed_array(ctx, arr);
- if (p1 != NULL && p->class_id == p1->class_id &&
- typed_array_length(p1) >= count &&
- typed_array_length(p) >= start + count) {
- shift = typed_array_size_log2(p->class_id);
- memmove(p1->u.array.u.uint8_ptr,
- p->u.array.u.uint8_ptr + (start << shift),
- count << shift);
- } else {
- slow_path:
- space = max_int(0, p->u.array.count - start);
- count = min_int(count, space);
- for (n = 0; n < count; n++) {
- val = JS_GetPropertyValue(ctx, this_val, js_int32(start + n));
- if (JS_IsException(val))
- goto exception;
- if (JS_SetPropertyValue(ctx, arr, js_int32(n), val,
- JS_PROP_THROW) < 0)
- goto exception;
- }
- }
- }
- return arr;
- exception:
- JS_FreeValue(ctx, arr);
- return JS_EXCEPTION;
- }
- static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSArrayBuffer *abuf;
- JSTypedArray *ta;
- JSValueConst args[4];
- JSValue arr, byteOffset, ta_buffer;
- JSObject *p;
- int len, start, final, count, shift, offset;
- p = get_typed_array(ctx, this_val);
- if (!p)
- goto exception;
- len = p->u.array.count;
- if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
- goto exception;
- final = len;
- if (!JS_IsUndefined(argv[1])) {
- if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
- goto exception;
- }
- count = max_int(final - start, 0);
- byteOffset = js_typed_array_get_byteOffset(ctx, this_val);
- if (JS_IsException(byteOffset))
- goto exception;
- ta = p->u.typed_array;
- abuf = ta->buffer->u.array_buffer;
- if (ta->offset > abuf->byte_length)
- goto range_error;
- if (ta->offset == abuf->byte_length && count > 0) {
- range_error:
- JS_ThrowRangeError(ctx, "invalid offset");
- goto exception;
- }
- shift = typed_array_size_log2(p->class_id);
- offset = JS_VALUE_GET_INT(byteOffset) + (start << shift);
- JS_FreeValue(ctx, byteOffset);
- ta_buffer = js_typed_array_get_buffer(ctx, this_val);
- if (JS_IsException(ta_buffer))
- goto exception;
- args[0] = this_val;
- args[1] = safe_const(ta_buffer);
- args[2] = safe_const(js_int32(offset));
- args[3] = safe_const(js_int32(count));
- // result is length-tracking if source TA is and no explicit count is given
- if (ta->track_rab && JS_IsUndefined(argv[1]))
- args[3] = JS_UNDEFINED;
- arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 4, args);
- JS_FreeValue(ctx, ta_buffer);
- return arr;
- exception:
- return JS_EXCEPTION;
- }
- /* TypedArray.prototype.sort */
- static int js_cmp_doubles(double x, double y)
- {
- if (isnan(x)) return isnan(y) ? 0 : +1;
- if (isnan(y)) return -1;
- if (x < y) return -1;
- if (x > y) return 1;
- if (x != 0) return 0;
- if (signbit(x)) return signbit(y) ? 0 : -1;
- else return signbit(y) ? 1 : 0;
- }
- static int js_TA_cmp_int8(const void *a, const void *b, void *opaque) {
- return *(const int8_t *)a - *(const int8_t *)b;
- }
- static int js_TA_cmp_uint8(const void *a, const void *b, void *opaque) {
- return *(const uint8_t *)a - *(const uint8_t *)b;
- }
- static int js_TA_cmp_int16(const void *a, const void *b, void *opaque) {
- return *(const int16_t *)a - *(const int16_t *)b;
- }
- static int js_TA_cmp_uint16(const void *a, const void *b, void *opaque) {
- return *(const uint16_t *)a - *(const uint16_t *)b;
- }
- static int js_TA_cmp_int32(const void *a, const void *b, void *opaque) {
- int32_t x = *(const int32_t *)a;
- int32_t y = *(const int32_t *)b;
- return (y < x) - (y > x);
- }
- static int js_TA_cmp_uint32(const void *a, const void *b, void *opaque) {
- uint32_t x = *(const uint32_t *)a;
- uint32_t y = *(const uint32_t *)b;
- return (y < x) - (y > x);
- }
- static int js_TA_cmp_int64(const void *a, const void *b, void *opaque) {
- int64_t x = *(const int64_t *)a;
- int64_t y = *(const int64_t *)b;
- return (y < x) - (y > x);
- }
- static int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) {
- uint64_t x = *(const uint64_t *)a;
- uint64_t y = *(const uint64_t *)b;
- return (y < x) - (y > x);
- }
- static int js_TA_cmp_float16(const void *a, const void *b, void *opaque) {
- return js_cmp_doubles(fromfp16(*(const uint16_t *)a),
- fromfp16(*(const uint16_t *)b));
- }
- static int js_TA_cmp_float32(const void *a, const void *b, void *opaque) {
- return js_cmp_doubles(*(const float *)a, *(const float *)b);
- }
- static int js_TA_cmp_float64(const void *a, const void *b, void *opaque) {
- return js_cmp_doubles(*(const double *)a, *(const double *)b);
- }
- static JSValue js_TA_get_int8(JSContext *ctx, const void *a) {
- return js_int32(*(const int8_t *)a);
- }
- static JSValue js_TA_get_uint8(JSContext *ctx, const void *a) {
- return js_int32(*(const uint8_t *)a);
- }
- static JSValue js_TA_get_int16(JSContext *ctx, const void *a) {
- return js_int32(*(const int16_t *)a);
- }
- static JSValue js_TA_get_uint16(JSContext *ctx, const void *a) {
- return js_int32(*(const uint16_t *)a);
- }
- static JSValue js_TA_get_int32(JSContext *ctx, const void *a) {
- return js_int32(*(const int32_t *)a);
- }
- static JSValue js_TA_get_uint32(JSContext *ctx, const void *a) {
- return js_uint32(*(const uint32_t *)a);
- }
- static JSValue js_TA_get_int64(JSContext *ctx, const void *a) {
- return JS_NewBigInt64(ctx, *(int64_t *)a);
- }
- static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) {
- return JS_NewBigUint64(ctx, *(uint64_t *)a);
- }
- static JSValue js_TA_get_float16(JSContext *ctx, const void *a) {
- return js_float64(fromfp16(*(const uint16_t *)a));
- }
- static JSValue js_TA_get_float32(JSContext *ctx, const void *a) {
- return js_float64(*(const float *)a);
- }
- static JSValue js_TA_get_float64(JSContext *ctx, const void *a) {
- return js_float64(*(const double *)a);
- }
- struct TA_sort_context {
- JSContext *ctx;
- int exception;
- JSValueConst arr;
- JSValueConst cmp;
- JSValue (*getfun)(JSContext *ctx, const void *a);
- int elt_size;
- };
- static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {
- struct TA_sort_context *psc = opaque;
- JSContext *ctx = psc->ctx;
- uint32_t a_idx, b_idx;
- JSValue argv[2];
- JSValue res;
- JSObject *p;
- int cmp;
- p = JS_VALUE_GET_OBJ(psc->arr);
- if (typed_array_is_oob(p))
- return 0;
- cmp = 0;
- if (!psc->exception) {
- a_idx = *(uint32_t *)a;
- b_idx = *(uint32_t *)b;
- if (a_idx >= p->u.array.count || b_idx >= p->u.array.count)
- return 0;
- argv[0] = psc->getfun(ctx, (char *)p->u.array.u.ptr +
- a_idx * (size_t)psc->elt_size);
- argv[1] = psc->getfun(ctx, (char *)p->u.array.u.ptr +
- b_idx * (size_t)(psc->elt_size));
- res = JS_Call(ctx, psc->cmp, JS_UNDEFINED, 2, vc(argv));
- if (JS_IsException(res)) {
- psc->exception = 1;
- goto done;
- }
- if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
- int val = JS_VALUE_GET_INT(res);
- cmp = (val > 0) - (val < 0);
- } else {
- double val;
- if (JS_ToFloat64Free(ctx, &val, res) < 0) {
- psc->exception = 1;
- goto done;
- } else {
- cmp = (val > 0) - (val < 0);
- }
- }
- if (cmp == 0) {
- /* make sort stable: compare array offsets */
- cmp = (a_idx > b_idx) - (a_idx < b_idx);
- }
- done:
- JS_FreeValue(ctx, argv[0]);
- JS_FreeValue(ctx, argv[1]);
- }
- return cmp;
- }
- static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSObject *p;
- int len;
- size_t elt_size;
- struct TA_sort_context tsc;
- int (*cmpfun)(const void *a, const void *b, void *opaque);
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- if (typed_array_is_oob(p))
- return JS_ThrowTypeErrorArrayBufferOOB(ctx);
- tsc.ctx = ctx;
- tsc.exception = 0;
- tsc.arr = this_val;
- tsc.cmp = argv[0];
- if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))
- return JS_EXCEPTION;
- len = p->u.array.count;
- if (len > 1) {
- switch (p->class_id) {
- case JS_CLASS_INT8_ARRAY:
- tsc.getfun = js_TA_get_int8;
- cmpfun = js_TA_cmp_int8;
- break;
- case JS_CLASS_UINT8C_ARRAY:
- case JS_CLASS_UINT8_ARRAY:
- tsc.getfun = js_TA_get_uint8;
- cmpfun = js_TA_cmp_uint8;
- break;
- case JS_CLASS_INT16_ARRAY:
- tsc.getfun = js_TA_get_int16;
- cmpfun = js_TA_cmp_int16;
- break;
- case JS_CLASS_UINT16_ARRAY:
- tsc.getfun = js_TA_get_uint16;
- cmpfun = js_TA_cmp_uint16;
- break;
- case JS_CLASS_INT32_ARRAY:
- tsc.getfun = js_TA_get_int32;
- cmpfun = js_TA_cmp_int32;
- break;
- case JS_CLASS_UINT32_ARRAY:
- tsc.getfun = js_TA_get_uint32;
- cmpfun = js_TA_cmp_uint32;
- break;
- case JS_CLASS_BIG_INT64_ARRAY:
- tsc.getfun = js_TA_get_int64;
- cmpfun = js_TA_cmp_int64;
- break;
- case JS_CLASS_BIG_UINT64_ARRAY:
- tsc.getfun = js_TA_get_uint64;
- cmpfun = js_TA_cmp_uint64;
- break;
- case JS_CLASS_FLOAT16_ARRAY:
- tsc.getfun = js_TA_get_float16;
- cmpfun = js_TA_cmp_float16;
- break;
- case JS_CLASS_FLOAT32_ARRAY:
- tsc.getfun = js_TA_get_float32;
- cmpfun = js_TA_cmp_float32;
- break;
- case JS_CLASS_FLOAT64_ARRAY:
- tsc.getfun = js_TA_get_float64;
- cmpfun = js_TA_cmp_float64;
- break;
- default:
- abort();
- }
- elt_size = 1 << typed_array_size_log2(p->class_id);
- if (!JS_IsUndefined(tsc.cmp)) {
- uint32_t *array_idx;
- void *array_tmp;
- size_t i, j;
- /* XXX: a stable sort would use less memory */
- array_idx = js_malloc(ctx, len * sizeof(array_idx[0]));
- if (!array_idx)
- return JS_EXCEPTION;
- for(i = 0; i < len; i++)
- array_idx[i] = i;
- tsc.elt_size = elt_size;
- rqsort(array_idx, len, sizeof(array_idx[0]),
- js_TA_cmp_generic, &tsc);
- if (tsc.exception)
- goto fail;
- // per spec: typed array can be detached mid-iteration
- if (typed_array_is_oob(p))
- goto done;
- len = min_int(len, p->u.array.count);
- if (len == 0)
- goto done;
- array_tmp = js_malloc(ctx, len * elt_size);
- if (!array_tmp) {
- fail:
- js_free(ctx, array_idx);
- return JS_EXCEPTION;
- }
- memcpy(array_tmp, p->u.array.u.ptr, len * elt_size);
- switch(elt_size) {
- case 1:
- for(i = 0; i < len; i++) {
- j = array_idx[i];
- p->u.array.u.uint8_ptr[i] = ((uint8_t *)array_tmp)[j];
- }
- break;
- case 2:
- for(i = 0; i < len; i++) {
- j = array_idx[i];
- p->u.array.u.uint16_ptr[i] = ((uint16_t *)array_tmp)[j];
- }
- break;
- case 4:
- for(i = 0; i < len; i++) {
- j = array_idx[i];
- p->u.array.u.uint32_ptr[i] = ((uint32_t *)array_tmp)[j];
- }
- break;
- case 8:
- for(i = 0; i < len; i++) {
- j = array_idx[i];
- p->u.array.u.uint64_ptr[i] = ((uint64_t *)array_tmp)[j];
- }
- break;
- default:
- abort();
- }
- js_free(ctx, array_tmp);
- done:
- js_free(ctx, array_idx);
- } else {
- rqsort(p->u.array.u.ptr, len, elt_size, cmpfun, &tsc);
- if (tsc.exception)
- return JS_EXCEPTION;
- }
- }
- return js_dup(this_val);
- }
- static JSValue js_typed_array_toSorted(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue arr, ret;
- JSObject *p;
- p = get_typed_array(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
- p->class_id, p->u.array.count);
- if (JS_IsException(arr))
- return JS_EXCEPTION;
- ret = js_typed_array_sort(ctx, arr, argc, argv);
- JS_FreeValue(ctx, arr);
- return ret;
- }
- static const JSCFunctionListEntry js_typed_array_base_funcs[] = {
- JS_CFUNC_DEF("from", 1, js_typed_array_from ),
- JS_CFUNC_DEF("of", 0, js_typed_array_of ),
- JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
- };
- static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {
- JS_CGETSET_DEF("length", js_typed_array_get_length, NULL ),
- JS_CFUNC_DEF("at", 1, js_typed_array_at ),
- JS_CFUNC_DEF("with", 2, js_typed_array_with ),
- JS_CGETSET_DEF("buffer", js_typed_array_get_buffer, NULL ),
- JS_CGETSET_DEF("byteLength", js_typed_array_get_byteLength, NULL ),
- JS_CGETSET_DEF("byteOffset", js_typed_array_get_byteOffset, NULL ),
- JS_CFUNC_DEF("set", 1, js_typed_array_set ),
- JS_CFUNC_MAGIC_DEF("values", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_VALUE ),
- JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
- JS_CFUNC_MAGIC_DEF("keys", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY ),
- JS_CFUNC_MAGIC_DEF("entries", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
- JS_CGETSET_DEF("[Symbol.toStringTag]", js_typed_array_get_toStringTag, NULL ),
- JS_CFUNC_DEF("copyWithin", 2, js_typed_array_copyWithin ),
- JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every | special_TA ),
- JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some | special_TA ),
- JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach | special_TA ),
- JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map | special_TA ),
- JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter | special_TA ),
- JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ),
- JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ),
- JS_CFUNC_DEF("fill", 1, js_typed_array_fill ),
- JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, ArrayFind ),
- JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, ArrayFindIndex ),
- JS_CFUNC_MAGIC_DEF("findLast", 1, js_typed_array_find, ArrayFindLast ),
- JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_typed_array_find, ArrayFindLastIndex ),
- JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ),
- JS_CFUNC_DEF("toReversed", 0, js_typed_array_toReversed ),
- JS_CFUNC_DEF("slice", 2, js_typed_array_slice ),
- JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ),
- JS_CFUNC_DEF("sort", 1, js_typed_array_sort ),
- JS_CFUNC_DEF("toSorted", 1, js_typed_array_toSorted ),
- JS_CFUNC_MAGIC_DEF("join", 1, js_typed_array_join, 0 ),
- JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_typed_array_join, 1 ),
- JS_CFUNC_MAGIC_DEF("indexOf", 1, js_typed_array_indexOf, special_indexOf ),
- JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_typed_array_indexOf, special_lastIndexOf ),
- JS_CFUNC_MAGIC_DEF("includes", 1, js_typed_array_indexOf, special_includes ),
- //JS_ALIAS_BASE_DEF("toString", "toString", 2 /* Array.prototype. */), @@@
- };
- static JSValue js_typed_array_base_constructor(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return JS_ThrowTypeError(ctx, "cannot be called");
- }
- /* 'obj' must be an allocated typed array object */
- static int typed_array_init(JSContext *ctx, JSValue obj, JSValue buffer,
- uint64_t offset, uint64_t len, bool track_rab)
- {
- JSTypedArray *ta;
- JSObject *p, *pbuffer;
- JSArrayBuffer *abuf;
- int size_log2;
- p = JS_VALUE_GET_OBJ(obj);
- size_log2 = typed_array_size_log2(p->class_id);
- ta = js_malloc(ctx, sizeof(*ta));
- if (!ta) {
- JS_FreeValue(ctx, buffer);
- return -1;
- }
- pbuffer = JS_VALUE_GET_OBJ(buffer);
- abuf = pbuffer->u.array_buffer;
- ta->obj = p;
- ta->buffer = pbuffer;
- ta->offset = offset;
- ta->length = len << size_log2;
- ta->track_rab = track_rab;
- list_add_tail(&ta->link, &abuf->array_list);
- p->u.typed_array = ta;
- p->u.array.count = len;
- p->u.array.u.ptr = abuf->data + offset;
- return 0;
- }
- static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,
- JSValueConst obj, JSValueConst method)
- {
- JSValue arr, iter, next_method = JS_UNDEFINED, val;
- int done;
- uint32_t k;
- *plen = 0;
- arr = JS_NewArray(ctx);
- if (JS_IsException(arr))
- return arr;
- iter = JS_GetIterator2(ctx, obj, method);
- if (JS_IsException(iter))
- goto fail;
- next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next_method))
- goto fail;
- k = 0;
- for(;;) {
- val = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
- if (JS_IsException(val))
- goto fail;
- if (done)
- break;
- if (JS_CreateDataPropertyUint32(ctx, arr, k, val, JS_PROP_THROW) < 0)
- goto fail;
- k++;
- }
- JS_FreeValue(ctx, next_method);
- JS_FreeValue(ctx, iter);
- *plen = k;
- return arr;
- fail:
- JS_FreeValue(ctx, next_method);
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, arr);
- return JS_EXCEPTION;
- }
- static JSValue js_typed_array_constructor_obj(JSContext *ctx,
- JSValueConst new_target,
- JSValueConst obj,
- int classid)
- {
- JSValue iter, ret, arr = JS_UNDEFINED, val, buffer;
- uint32_t i;
- int size_log2;
- int64_t len;
- size_log2 = typed_array_size_log2(classid);
- ret = js_create_from_ctor(ctx, new_target, classid);
- if (JS_IsException(ret))
- return JS_EXCEPTION;
- iter = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
- if (JS_IsException(iter))
- goto fail;
- if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
- uint32_t len1;
- arr = js_array_from_iterator(ctx, &len1, obj, iter);
- JS_FreeValue(ctx, iter);
- if (JS_IsException(arr))
- goto fail;
- len = len1;
- } else {
- if (js_get_length64(ctx, &len, obj))
- goto fail;
- arr = js_dup(obj);
- }
- buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
- len << size_log2,
- NULL);
- if (JS_IsException(buffer))
- goto fail;
- if (typed_array_init(ctx, ret, buffer, 0, len, /*track_rab*/false))
- goto fail;
- for(i = 0; i < len; i++) {
- val = JS_GetPropertyUint32(ctx, arr, i);
- if (JS_IsException(val))
- goto fail;
- if (JS_SetPropertyUint32(ctx, ret, i, val) < 0)
- goto fail;
- }
- JS_FreeValue(ctx, arr);
- return ret;
- fail:
- JS_FreeValue(ctx, arr);
- JS_FreeValue(ctx, ret);
- return JS_EXCEPTION;
- }
- static JSValue js_typed_array_constructor_ta(JSContext *ctx,
- JSValueConst new_target,
- JSValueConst src_obj,
- int classid, uint32_t len)
- {
- JSObject *p, *src_buffer;
- JSTypedArray *ta;
- JSValue obj, buffer;
- uint32_t i;
- int size_log2;
- JSArrayBuffer *src_abuf, *abuf;
- obj = js_create_from_ctor(ctx, new_target, classid);
- if (JS_IsException(obj))
- return obj;
- p = JS_VALUE_GET_OBJ(src_obj);
- if (typed_array_is_oob(p)) {
- JS_ThrowTypeErrorArrayBufferOOB(ctx);
- goto fail;
- }
- ta = p->u.typed_array;
- src_buffer = ta->buffer;
- src_abuf = src_buffer->u.array_buffer;
- size_log2 = typed_array_size_log2(classid);
- buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
- (uint64_t)len << size_log2,
- NULL);
- if (JS_IsException(buffer))
- goto fail;
- /* necessary because it could have been detached */
- if (typed_array_is_oob(p)) {
- JS_FreeValue(ctx, buffer);
- JS_ThrowTypeErrorArrayBufferOOB(ctx);
- goto fail;
- }
- abuf = JS_GetOpaque(buffer, JS_CLASS_ARRAY_BUFFER);
- if (typed_array_init(ctx, obj, buffer, 0, len, /*track_rab*/false))
- goto fail;
- if (p->class_id == classid) {
- /* same type: copy the content */
- memcpy(abuf->data, src_abuf->data + ta->offset, abuf->byte_length);
- } else {
- for(i = 0; i < len; i++) {
- JSValue val;
- val = JS_GetPropertyUint32(ctx, src_obj, i);
- if (JS_IsException(val))
- goto fail;
- if (JS_SetPropertyUint32(ctx, obj, i, val) < 0)
- goto fail;
- }
- }
- return obj;
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_typed_array_constructor(JSContext *ctx,
- JSValueConst new_target,
- int argc, JSValueConst *argv,
- int classid)
- {
- bool track_rab = false;
- JSValue buffer, obj;
- JSArrayBuffer *abuf;
- int size_log2;
- uint64_t len, offset;
- size_log2 = typed_array_size_log2(classid);
- if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) {
- if (JS_ToIndex(ctx, &len, argv[0]))
- return JS_EXCEPTION;
- buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
- len << size_log2,
- NULL);
- if (JS_IsException(buffer))
- return JS_EXCEPTION;
- offset = 0;
- } else {
- JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
- if (p->class_id == JS_CLASS_ARRAY_BUFFER ||
- p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER) {
- abuf = p->u.array_buffer;
- if (JS_ToIndex(ctx, &offset, argv[1]))
- return JS_EXCEPTION;
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- if ((offset & ((1 << size_log2) - 1)) != 0 ||
- offset > abuf->byte_length)
- return JS_ThrowRangeError(ctx, "invalid offset");
- if (JS_IsUndefined(argv[2])) {
- track_rab = array_buffer_is_resizable(abuf);
- if (!track_rab)
- if ((abuf->byte_length & ((1 << size_log2) - 1)) != 0)
- goto invalid_length;
- len = (abuf->byte_length - offset) >> size_log2;
- } else {
- if (JS_ToIndex(ctx, &len, argv[2]))
- return JS_EXCEPTION;
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- if ((offset + (len << size_log2)) > abuf->byte_length) {
- invalid_length:
- return JS_ThrowRangeError(ctx, "invalid length");
- }
- }
- buffer = js_dup(argv[0]);
- } else {
- if (is_typed_array(p->class_id)) {
- return js_typed_array_constructor_ta(ctx, new_target, argv[0],
- classid, p->u.array.count);
- } else {
- return js_typed_array_constructor_obj(ctx, new_target, argv[0], classid);
- }
- }
- }
- obj = js_create_from_ctor(ctx, new_target, classid);
- if (JS_IsException(obj)) {
- JS_FreeValue(ctx, buffer);
- return JS_EXCEPTION;
- }
- if (typed_array_init(ctx, obj, buffer, offset, len, track_rab)) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- return obj;
- }
- static void js_typed_array_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSTypedArray *ta = p->u.typed_array;
- if (ta) {
- /* during the GC the finalizers are called in an arbitrary
- order so the ArrayBuffer finalizer may have been called */
- if (ta->link.next) {
- list_del(&ta->link);
- }
- JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
- js_free_rt(rt, ta);
- }
- }
- static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSObject *p = JS_VALUE_GET_OBJ(val);
- JSTypedArray *ta = p->u.typed_array;
- if (ta) {
- JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer), mark_func);
- }
- }
- static JSValue js_dataview_constructor(JSContext *ctx,
- JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- bool recompute_len = false;
- bool track_rab = false;
- JSArrayBuffer *abuf;
- uint64_t offset;
- uint32_t len;
- JSValueConst buffer;
- JSValue obj;
- JSTypedArray *ta;
- JSObject *p;
- buffer = argv[0];
- abuf = js_get_array_buffer(ctx, buffer);
- if (!abuf)
- return JS_EXCEPTION;
- offset = 0;
- if (argc > 1) {
- if (JS_ToIndex(ctx, &offset, argv[1]))
- return JS_EXCEPTION;
- }
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- if (offset > abuf->byte_length)
- return JS_ThrowRangeError(ctx, "invalid byteOffset");
- len = abuf->byte_length - offset;
- if (argc > 2 && !JS_IsUndefined(argv[2])) {
- uint64_t l;
- if (JS_ToIndex(ctx, &l, argv[2]))
- return JS_EXCEPTION;
- if (l > len)
- return JS_ThrowRangeError(ctx, "invalid byteLength");
- len = l;
- } else {
- recompute_len = true;
- track_rab = array_buffer_is_resizable(abuf);
- }
- obj = js_create_from_ctor(ctx, new_target, JS_CLASS_DATAVIEW);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- if (abuf->detached) {
- /* could have been detached in js_create_from_ctor() */
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- goto fail;
- }
- // RAB could have been resized in js_create_from_ctor()
- if (offset > abuf->byte_length) {
- goto out_of_bound;
- } else if (recompute_len) {
- len = abuf->byte_length - offset;
- } else if (offset + len > abuf->byte_length) {
- out_of_bound:
- JS_ThrowRangeError(ctx, "invalid byteOffset or byteLength");
- goto fail;
- }
- ta = js_malloc(ctx, sizeof(*ta));
- if (!ta) {
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- p = JS_VALUE_GET_OBJ(obj);
- ta->obj = p;
- ta->buffer = JS_VALUE_GET_OBJ(js_dup(buffer));
- ta->offset = offset;
- ta->length = len;
- ta->track_rab = track_rab;
- list_add_tail(&ta->link, &abuf->array_list);
- p->u.typed_array = ta;
- return obj;
- }
- // is the DataView out of bounds relative to its parent arraybuffer?
- static bool dataview_is_oob(JSObject *p)
- {
- JSArrayBuffer *abuf;
- JSTypedArray *ta;
- assert(p->class_id == JS_CLASS_DATAVIEW);
- ta = p->u.typed_array;
- abuf = ta->buffer->u.array_buffer;
- if (abuf->detached)
- return true;
- if (ta->offset > abuf->byte_length)
- return true;
- if (ta->track_rab)
- return false;
- return (int64_t)ta->offset + ta->length > abuf->byte_length;
- }
- static JSObject *get_dataview(JSContext *ctx, JSValueConst this_val)
- {
- JSObject *p;
- if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
- goto fail;
- p = JS_VALUE_GET_OBJ(this_val);
- if (p->class_id != JS_CLASS_DATAVIEW) {
- fail:
- JS_ThrowTypeError(ctx, "not a DataView");
- return NULL;
- }
- return p;
- }
- static JSValue js_dataview_get_buffer(JSContext *ctx, JSValueConst this_val)
- {
- JSObject *p;
- JSTypedArray *ta;
- p = get_dataview(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- ta = p->u.typed_array;
- return js_dup(JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
- }
- static JSValue js_dataview_get_byteLength(JSContext *ctx, JSValueConst this_val)
- {
- JSArrayBuffer *abuf;
- JSTypedArray *ta;
- JSObject *p;
- p = get_dataview(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- if (dataview_is_oob(p))
- return JS_ThrowTypeErrorArrayBufferOOB(ctx);
- ta = p->u.typed_array;
- if (ta->track_rab) {
- abuf = ta->buffer->u.array_buffer;
- return js_uint32(abuf->byte_length - ta->offset);
- }
- return js_uint32(ta->length);
- }
- static JSValue js_dataview_get_byteOffset(JSContext *ctx, JSValueConst this_val)
- {
- JSTypedArray *ta;
- JSObject *p;
- p = get_dataview(ctx, this_val);
- if (!p)
- return JS_EXCEPTION;
- if (dataview_is_oob(p))
- return JS_ThrowTypeErrorArrayBufferOOB(ctx);
- ta = p->u.typed_array;
- return js_uint32(ta->offset);
- }
- static JSValue js_dataview_getValue(JSContext *ctx,
- JSValueConst this_obj,
- int argc, JSValueConst *argv, int class_id)
- {
- JSTypedArray *ta;
- JSArrayBuffer *abuf;
- bool littleEndian, is_swap;
- int size;
- uint8_t *ptr;
- uint32_t v;
- uint64_t pos;
- ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
- if (!ta)
- return JS_EXCEPTION;
- size = 1 << typed_array_size_log2(class_id);
- if (JS_ToIndex(ctx, &pos, argv[0]))
- return JS_EXCEPTION;
- littleEndian = argc > 1 && JS_ToBool(ctx, argv[1]);
- is_swap = littleEndian ^ !is_be();
- abuf = ta->buffer->u.array_buffer;
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- // order matters: this check should come before the next one
- if ((pos + size) > ta->length)
- return JS_ThrowRangeError(ctx, "out of bound");
- // test262 expects a TypeError for this and V8, in its infinite wisdom,
- // throws a "detached array buffer" exception, but IMO that doesn't make
- // sense because the buffer is not in fact detached, it's still there
- if ((int64_t)ta->offset + ta->length > abuf->byte_length)
- return JS_ThrowTypeError(ctx, "out of bound");
- ptr = abuf->data + ta->offset + pos;
- switch(class_id) {
- case JS_CLASS_INT8_ARRAY:
- return js_int32(*(int8_t *)ptr);
- case JS_CLASS_UINT8_ARRAY:
- return js_int32(*(uint8_t *)ptr);
- case JS_CLASS_INT16_ARRAY:
- v = get_u16(ptr);
- if (is_swap)
- v = bswap16(v);
- return js_int32((int16_t)v);
- case JS_CLASS_UINT16_ARRAY:
- v = get_u16(ptr);
- if (is_swap)
- v = bswap16(v);
- return js_int32(v);
- case JS_CLASS_INT32_ARRAY:
- v = get_u32(ptr);
- if (is_swap)
- v = bswap32(v);
- return js_int32(v);
- case JS_CLASS_UINT32_ARRAY:
- v = get_u32(ptr);
- if (is_swap)
- v = bswap32(v);
- return js_uint32(v);
- case JS_CLASS_BIG_INT64_ARRAY:
- {
- uint64_t v;
- v = get_u64(ptr);
- if (is_swap)
- v = bswap64(v);
- return JS_NewBigInt64(ctx, v);
- }
- break;
- case JS_CLASS_BIG_UINT64_ARRAY:
- {
- uint64_t v;
- v = get_u64(ptr);
- if (is_swap)
- v = bswap64(v);
- return JS_NewBigUint64(ctx, v);
- }
- break;
- case JS_CLASS_FLOAT16_ARRAY:
- {
- uint16_t v;
- v = get_u16(ptr);
- if (is_swap)
- v = bswap16(v);
- return js_float64(fromfp16(v));
- }
- case JS_CLASS_FLOAT32_ARRAY:
- {
- union {
- float f;
- uint32_t i;
- } u;
- v = get_u32(ptr);
- if (is_swap)
- v = bswap32(v);
- u.i = v;
- return js_float64(u.f);
- }
- case JS_CLASS_FLOAT64_ARRAY:
- {
- union {
- double f;
- uint64_t i;
- } u;
- u.i = get_u64(ptr);
- if (is_swap)
- u.i = bswap64(u.i);
- return js_float64(u.f);
- }
- default:
- abort();
- }
- return JS_EXCEPTION; // pacify compiler
- }
- static JSValue js_dataview_setValue(JSContext *ctx,
- JSValueConst this_obj,
- int argc, JSValueConst *argv, int class_id)
- {
- JSTypedArray *ta;
- JSArrayBuffer *abuf;
- bool littleEndian, is_swap;
- int size;
- uint8_t *ptr;
- uint64_t v64;
- uint32_t v;
- uint64_t pos;
- JSValueConst val;
- ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
- if (!ta)
- return JS_EXCEPTION;
- size = 1 << typed_array_size_log2(class_id);
- if (JS_ToIndex(ctx, &pos, argv[0]))
- return JS_EXCEPTION;
- val = argv[1];
- v = 0; /* avoid warning */
- v64 = 0; /* avoid warning */
- if (class_id <= JS_CLASS_UINT32_ARRAY) {
- if (JS_ToUint32(ctx, &v, val))
- return JS_EXCEPTION;
- } else if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
- if (JS_ToBigInt64(ctx, (int64_t *)&v64, val))
- return JS_EXCEPTION;
- } else {
- double d;
- if (JS_ToFloat64(ctx, &d, val))
- return JS_EXCEPTION;
- if (class_id == JS_CLASS_FLOAT16_ARRAY) {
- v = tofp16(d);
- } else if (class_id == JS_CLASS_FLOAT32_ARRAY) {
- union {
- float f;
- uint32_t i;
- } u;
- u.f = d;
- v = u.i;
- } else {
- JSFloat64Union u;
- u.d = d;
- v64 = u.u64;
- }
- }
- littleEndian = argc > 2 && JS_ToBool(ctx, argv[2]);
- is_swap = littleEndian ^ !is_be();
- abuf = ta->buffer->u.array_buffer;
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- // order matters: this check should come before the next one
- if ((pos + size) > ta->length)
- return JS_ThrowRangeError(ctx, "out of bound");
- // test262 expects a TypeError for this and V8, in its infinite wisdom,
- // throws a "detached array buffer" exception, but IMO that doesn't make
- // sense because the buffer is not in fact detached, it's still there
- if ((int64_t)ta->offset + ta->length > abuf->byte_length)
- return JS_ThrowTypeError(ctx, "out of bound");
- ptr = abuf->data + ta->offset + pos;
- switch(class_id) {
- case JS_CLASS_INT8_ARRAY:
- case JS_CLASS_UINT8_ARRAY:
- *ptr = v;
- break;
- case JS_CLASS_INT16_ARRAY:
- case JS_CLASS_UINT16_ARRAY:
- case JS_CLASS_FLOAT16_ARRAY:
- if (is_swap)
- v = bswap16(v);
- put_u16(ptr, v);
- break;
- case JS_CLASS_INT32_ARRAY:
- case JS_CLASS_UINT32_ARRAY:
- case JS_CLASS_FLOAT32_ARRAY:
- if (is_swap)
- v = bswap32(v);
- put_u32(ptr, v);
- break;
- case JS_CLASS_BIG_INT64_ARRAY:
- case JS_CLASS_BIG_UINT64_ARRAY:
- case JS_CLASS_FLOAT64_ARRAY:
- if (is_swap)
- v64 = bswap64(v64);
- put_u64(ptr, v64);
- break;
- default:
- abort();
- }
- return JS_UNDEFINED;
- }
- static const JSCFunctionListEntry js_dataview_proto_funcs[] = {
- JS_CGETSET_DEF("buffer", js_dataview_get_buffer, NULL ),
- JS_CGETSET_DEF("byteLength", js_dataview_get_byteLength, NULL ),
- JS_CGETSET_DEF("byteOffset", js_dataview_get_byteOffset, NULL ),
- JS_CFUNC_MAGIC_DEF("getInt8", 1, js_dataview_getValue, JS_CLASS_INT8_ARRAY ),
- JS_CFUNC_MAGIC_DEF("getUint8", 1, js_dataview_getValue, JS_CLASS_UINT8_ARRAY ),
- JS_CFUNC_MAGIC_DEF("getInt16", 1, js_dataview_getValue, JS_CLASS_INT16_ARRAY ),
- JS_CFUNC_MAGIC_DEF("getUint16", 1, js_dataview_getValue, JS_CLASS_UINT16_ARRAY ),
- JS_CFUNC_MAGIC_DEF("getInt32", 1, js_dataview_getValue, JS_CLASS_INT32_ARRAY ),
- JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ),
- JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ),
- JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ),
- JS_CFUNC_MAGIC_DEF("getFloat16", 1, js_dataview_getValue, JS_CLASS_FLOAT16_ARRAY ),
- JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ),
- JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ),
- JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ),
- JS_CFUNC_MAGIC_DEF("setUint8", 2, js_dataview_setValue, JS_CLASS_UINT8_ARRAY ),
- JS_CFUNC_MAGIC_DEF("setInt16", 2, js_dataview_setValue, JS_CLASS_INT16_ARRAY ),
- JS_CFUNC_MAGIC_DEF("setUint16", 2, js_dataview_setValue, JS_CLASS_UINT16_ARRAY ),
- JS_CFUNC_MAGIC_DEF("setInt32", 2, js_dataview_setValue, JS_CLASS_INT32_ARRAY ),
- JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ),
- JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ),
- JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ),
- JS_CFUNC_MAGIC_DEF("setFloat16", 2, js_dataview_setValue, JS_CLASS_FLOAT16_ARRAY ),
- JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ),
- JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE ),
- };
- static JSValue js_new_uint8array(JSContext *ctx, JSValue buffer)
- {
- if (JS_IsException(buffer))
- return JS_EXCEPTION;
- JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_UINT8_ARRAY);
- if (JS_IsException(obj)) {
- JS_FreeValue(ctx, buffer);
- return JS_EXCEPTION;
- }
- JSArrayBuffer *abuf = js_get_array_buffer(ctx, buffer);
- assert(abuf != NULL);
- if (typed_array_init(ctx, obj, buffer, 0, abuf->byte_length, /*track_rab*/false)) {
- // 'buffer' is freed on error above.
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- return obj;
- }
- JSValue JS_NewUint8Array(JSContext *ctx, uint8_t *buf, size_t len,
- JSFreeArrayBufferDataFunc *free_func, void *opaque,
- bool is_shared)
- {
- JSClassID class_id =
- is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER;
- JSValue buffer = js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL,
- class_id, buf, free_func,
- opaque, false);
- return js_new_uint8array(ctx, buffer);
- }
- JSValue JS_NewUint8ArrayCopy(JSContext *ctx, const uint8_t *buf, size_t len)
- {
- JSValue buffer = js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL,
- JS_CLASS_ARRAY_BUFFER,
- (uint8_t *)buf,
- js_array_buffer_free, NULL,
- true);
- return js_new_uint8array(ctx, buffer);
- }
- int JS_GetTypedArrayType(JSValueConst obj)
- {
- JSClassID class_id = JS_GetClassID(obj);
- if (is_typed_array(class_id))
- return class_id - JS_CLASS_UINT8C_ARRAY;
- else
- return -1;
- }
- /* Atomics */
- #ifdef CONFIG_ATOMICS
- typedef enum AtomicsOpEnum {
- ATOMICS_OP_ADD,
- ATOMICS_OP_AND,
- ATOMICS_OP_OR,
- ATOMICS_OP_SUB,
- ATOMICS_OP_XOR,
- ATOMICS_OP_EXCHANGE,
- ATOMICS_OP_COMPARE_EXCHANGE,
- ATOMICS_OP_LOAD,
- } AtomicsOpEnum;
- static void *js_atomics_get_ptr(JSContext *ctx,
- JSArrayBuffer **pabuf,
- int *psize_log2, JSClassID *pclass_id,
- JSValueConst obj, JSValueConst idx_val,
- int is_waitable)
- {
- JSObject *p;
- JSTypedArray *ta;
- JSArrayBuffer *abuf;
- void *ptr;
- uint64_t idx;
- bool err;
- int size_log2;
- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
- goto fail;
- p = JS_VALUE_GET_OBJ(obj);
- if (is_waitable)
- err = (p->class_id != JS_CLASS_INT32_ARRAY &&
- p->class_id != JS_CLASS_BIG_INT64_ARRAY);
- else
- err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
- p->class_id <= JS_CLASS_BIG_UINT64_ARRAY);
- if (err) {
- fail:
- JS_ThrowTypeError(ctx, "integer TypedArray expected");
- return NULL;
- }
- ta = p->u.typed_array;
- abuf = ta->buffer->u.array_buffer;
- if (!abuf->shared) {
- if (is_waitable == 2) {
- JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray");
- return NULL;
- }
- if (abuf->detached) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- return NULL;
- }
- }
- if (JS_ToIndex(ctx, &idx, idx_val)) {
- return NULL;
- }
- /* if the array buffer is detached, p->u.array.count = 0 */
- if (idx >= p->u.array.count) {
- JS_ThrowRangeError(ctx, "out-of-bound access");
- return NULL;
- }
- size_log2 = typed_array_size_log2(p->class_id);
- ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
- if (pabuf)
- *pabuf = abuf;
- if (psize_log2)
- *psize_log2 = size_log2;
- if (pclass_id)
- *pclass_id = p->class_id;
- return ptr;
- }
- static JSValue js_atomics_op(JSContext *ctx,
- JSValueConst this_obj,
- int argc, JSValueConst *argv, int op)
- {
- int size_log2;
- uint64_t v, a, rep_val;
- void *ptr;
- JSValue ret;
- JSClassID class_id;
- JSArrayBuffer *abuf;
- ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, &class_id,
- argv[0], argv[1], 0);
- if (!ptr)
- return JS_EXCEPTION;
- rep_val = 0;
- if (op == ATOMICS_OP_LOAD) {
- v = 0;
- } else {
- if (size_log2 == 3) {
- int64_t v64;
- if (JS_ToBigInt64(ctx, &v64, argv[2]))
- return JS_EXCEPTION;
- v = v64;
- if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
- if (JS_ToBigInt64(ctx, &v64, argv[3]))
- return JS_EXCEPTION;
- rep_val = v64;
- }
- } else {
- uint32_t v32;
- if (JS_ToUint32(ctx, &v32, argv[2]))
- return JS_EXCEPTION;
- v = v32;
- if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
- if (JS_ToUint32(ctx, &v32, argv[3]))
- return JS_EXCEPTION;
- rep_val = v32;
- }
- }
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- }
- switch(op | (size_log2 << 3)) {
- #define OP(op_name, func_name) \
- case ATOMICS_OP_ ## op_name | (0 << 3): \
- a = func_name((_Atomic uint8_t *)ptr, v); \
- break; \
- case ATOMICS_OP_ ## op_name | (1 << 3): \
- a = func_name((_Atomic uint16_t *)ptr, v); \
- break; \
- case ATOMICS_OP_ ## op_name | (2 << 3): \
- a = func_name((_Atomic uint32_t *)ptr, v); \
- break; \
- case ATOMICS_OP_ ## op_name | (3 << 3): \
- a = func_name((_Atomic uint64_t *)ptr, v); \
- break;
- OP(ADD, atomic_fetch_add)
- OP(AND, atomic_fetch_and)
- OP(OR, atomic_fetch_or)
- OP(SUB, atomic_fetch_sub)
- OP(XOR, atomic_fetch_xor)
- OP(EXCHANGE, atomic_exchange)
- #undef OP
- case ATOMICS_OP_LOAD | (0 << 3):
- a = atomic_load((_Atomic uint8_t *)ptr);
- break;
- case ATOMICS_OP_LOAD | (1 << 3):
- a = atomic_load((_Atomic uint16_t *)ptr);
- break;
- case ATOMICS_OP_LOAD | (2 << 3):
- a = atomic_load((_Atomic uint32_t *)ptr);
- break;
- case ATOMICS_OP_LOAD | (3 << 3):
- a = atomic_load((_Atomic uint64_t *)ptr);
- break;
- case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3):
- {
- uint8_t v1 = v;
- atomic_compare_exchange_strong((_Atomic uint8_t *)ptr, &v1, rep_val);
- a = v1;
- }
- break;
- case ATOMICS_OP_COMPARE_EXCHANGE | (1 << 3):
- {
- uint16_t v1 = v;
- atomic_compare_exchange_strong((_Atomic uint16_t *)ptr, &v1, rep_val);
- a = v1;
- }
- break;
- case ATOMICS_OP_COMPARE_EXCHANGE | (2 << 3):
- {
- uint32_t v1 = v;
- atomic_compare_exchange_strong((_Atomic uint32_t *)ptr, &v1, rep_val);
- a = v1;
- }
- break;
- case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3):
- {
- uint64_t v1 = v;
- atomic_compare_exchange_strong((_Atomic uint64_t *)ptr, &v1, rep_val);
- a = v1;
- }
- break;
- default:
- abort();
- }
- switch(class_id) {
- case JS_CLASS_INT8_ARRAY:
- a = (int8_t)a;
- goto done;
- case JS_CLASS_UINT8_ARRAY:
- a = (uint8_t)a;
- goto done;
- case JS_CLASS_INT16_ARRAY:
- a = (int16_t)a;
- goto done;
- case JS_CLASS_UINT16_ARRAY:
- a = (uint16_t)a;
- goto done;
- case JS_CLASS_INT32_ARRAY:
- done:
- ret = js_int32(a);
- break;
- case JS_CLASS_UINT32_ARRAY:
- ret = js_uint32(a);
- break;
- case JS_CLASS_BIG_INT64_ARRAY:
- ret = JS_NewBigInt64(ctx, a);
- break;
- case JS_CLASS_BIG_UINT64_ARRAY:
- ret = JS_NewBigUint64(ctx, a);
- break;
- default:
- abort();
- }
- return ret;
- }
- static JSValue js_atomics_store(JSContext *ctx,
- JSValueConst this_obj,
- int argc, JSValueConst *argv)
- {
- int size_log2;
- void *ptr;
- JSValue ret;
- JSArrayBuffer *abuf;
- ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, NULL,
- argv[0], argv[1], 0);
- if (!ptr)
- return JS_EXCEPTION;
- if (size_log2 == 3) {
- int64_t v64;
- ret = JS_ToBigIntFree(ctx, js_dup(argv[2]));
- if (JS_IsException(ret))
- return ret;
- if (JS_ToBigInt64(ctx, &v64, ret)) {
- JS_FreeValue(ctx, ret);
- return JS_EXCEPTION;
- }
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- atomic_store((_Atomic uint64_t *)ptr, v64);
- } else {
- uint32_t v;
- /* XXX: spec, would be simpler to return the written value */
- ret = JS_ToIntegerFree(ctx, js_dup(argv[2]));
- if (JS_IsException(ret))
- return ret;
- if (JS_ToUint32(ctx, &v, ret)) {
- JS_FreeValue(ctx, ret);
- return JS_EXCEPTION;
- }
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- switch(size_log2) {
- case 0:
- atomic_store((_Atomic uint8_t *)ptr, v);
- break;
- case 1:
- atomic_store((_Atomic uint16_t *)ptr, v);
- break;
- case 2:
- atomic_store((_Atomic uint32_t *)ptr, v);
- break;
- default:
- abort();
- }
- }
- return ret;
- }
- static JSValue js_atomics_isLockFree(JSContext *ctx,
- JSValueConst this_obj,
- int argc, JSValueConst *argv)
- {
- int v, ret;
- if (JS_ToInt32Sat(ctx, &v, argv[0]))
- return JS_EXCEPTION;
- ret = (v == 1 || v == 2 || v == 4 || v == 8);
- return js_bool(ret);
- }
- typedef struct JSAtomicsWaiter {
- struct list_head link;
- bool linked;
- js_cond_t cond;
- int32_t *ptr;
- } JSAtomicsWaiter;
- static js_once_t js_atomics_once = JS_ONCE_INIT;
- static js_mutex_t js_atomics_mutex;
- static struct list_head js_atomics_waiter_list =
- LIST_HEAD_INIT(js_atomics_waiter_list);
- // no-op: Atomics.pause() is not allowed to block or yield to another
- // thread, only to hint the CPU that it should back off for a bit;
- // the amount of work we do here is a good enough substitute
- static JSValue js_atomics_pause(JSContext *ctx, JSValueConst this_obj,
- int argc, JSValueConst *argv)
- {
- double d;
- if (argc > 0) {
- switch (JS_VALUE_GET_TAG(argv[0])) {
- case JS_TAG_FLOAT64: // accepted if and only if fraction == 0.0
- d = JS_VALUE_GET_FLOAT64(argv[0]);
- if (isfinite(d))
- if (0 == modf(d, &d))
- break;
- // fallthru
- default:
- return JS_ThrowTypeError(ctx, "not an integral number");
- case JS_TAG_UNDEFINED:
- case JS_TAG_INT:
- break;
- }
- }
- return JS_UNDEFINED;
- }
- static JSValue js_atomics_wait(JSContext *ctx,
- JSValueConst this_obj,
- int argc, JSValueConst *argv)
- {
- int64_t v;
- int32_t v32;
- void *ptr;
- int64_t timeout;
- JSAtomicsWaiter waiter_s, *waiter;
- int ret, size_log2, res;
- double d;
- ptr = js_atomics_get_ptr(ctx, NULL, &size_log2, NULL,
- argv[0], argv[1], 2);
- if (!ptr)
- return JS_EXCEPTION;
- if (size_log2 == 3) {
- if (JS_ToBigInt64(ctx, &v, argv[2]))
- return JS_EXCEPTION;
- } else {
- if (JS_ToInt32(ctx, &v32, argv[2]))
- return JS_EXCEPTION;
- v = v32;
- }
- if (JS_ToFloat64(ctx, &d, argv[3]))
- return JS_EXCEPTION;
- if (isnan(d) || d >= 0x1p63)
- timeout = INT64_MAX;
- else if (d < 0)
- timeout = 0;
- else
- timeout = (int64_t)d;
- if (!ctx->rt->can_block)
- return JS_ThrowTypeError(ctx, "cannot block in this thread");
- /* XXX: inefficient if large number of waiters, should hash on
- 'ptr' value */
- js_mutex_lock(&js_atomics_mutex);
- if (size_log2 == 3) {
- res = *(int64_t *)ptr != v;
- } else {
- res = *(int32_t *)ptr != v;
- }
- if (res) {
- js_mutex_unlock(&js_atomics_mutex);
- return JS_AtomToString(ctx, JS_ATOM_not_equal);
- }
- waiter = &waiter_s;
- waiter->ptr = ptr;
- js_cond_init(&waiter->cond);
- waiter->linked = true;
- list_add_tail(&waiter->link, &js_atomics_waiter_list);
- if (timeout == INT64_MAX) {
- js_cond_wait(&waiter->cond, &js_atomics_mutex);
- ret = 0;
- } else {
- ret = js_cond_timedwait(&waiter->cond, &js_atomics_mutex, timeout * 1e6 /* to ns */);
- }
- if (waiter->linked)
- list_del(&waiter->link);
- js_mutex_unlock(&js_atomics_mutex);
- js_cond_destroy(&waiter->cond);
- if (ret == -1) {
- return JS_AtomToString(ctx, JS_ATOM_timed_out);
- } else {
- return JS_AtomToString(ctx, JS_ATOM_ok);
- }
- }
- static JSValue js_atomics_notify(JSContext *ctx,
- JSValueConst this_obj,
- int argc, JSValueConst *argv)
- {
- struct list_head *el, *el1, waiter_list;
- int32_t count, n;
- void *ptr;
- JSAtomicsWaiter *waiter;
- JSArrayBuffer *abuf;
- ptr = js_atomics_get_ptr(ctx, &abuf, NULL, NULL, argv[0], argv[1], 1);
- if (!ptr)
- return JS_EXCEPTION;
- if (JS_IsUndefined(argv[2])) {
- count = INT32_MAX;
- } else {
- if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0))
- return JS_EXCEPTION;
- }
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- n = 0;
- if (abuf->shared && count > 0) {
- js_mutex_lock(&js_atomics_mutex);
- init_list_head(&waiter_list);
- list_for_each_safe(el, el1, &js_atomics_waiter_list) {
- waiter = list_entry(el, JSAtomicsWaiter, link);
- if (waiter->ptr == ptr) {
- list_del(&waiter->link);
- waiter->linked = false;
- list_add_tail(&waiter->link, &waiter_list);
- n++;
- if (n >= count)
- break;
- }
- }
- list_for_each(el, &waiter_list) {
- waiter = list_entry(el, JSAtomicsWaiter, link);
- js_cond_signal(&waiter->cond);
- }
- js_mutex_unlock(&js_atomics_mutex);
- }
- return js_int32(n);
- }
- static const JSCFunctionListEntry js_atomics_funcs[] = {
- JS_CFUNC_MAGIC_DEF("add", 3, js_atomics_op, ATOMICS_OP_ADD ),
- JS_CFUNC_MAGIC_DEF("and", 3, js_atomics_op, ATOMICS_OP_AND ),
- JS_CFUNC_MAGIC_DEF("or", 3, js_atomics_op, ATOMICS_OP_OR ),
- JS_CFUNC_MAGIC_DEF("sub", 3, js_atomics_op, ATOMICS_OP_SUB ),
- JS_CFUNC_MAGIC_DEF("xor", 3, js_atomics_op, ATOMICS_OP_XOR ),
- JS_CFUNC_MAGIC_DEF("exchange", 3, js_atomics_op, ATOMICS_OP_EXCHANGE ),
- JS_CFUNC_MAGIC_DEF("compareExchange", 4, js_atomics_op, ATOMICS_OP_COMPARE_EXCHANGE ),
- JS_CFUNC_MAGIC_DEF("load", 2, js_atomics_op, ATOMICS_OP_LOAD ),
- JS_CFUNC_DEF("store", 3, js_atomics_store ),
- JS_CFUNC_DEF("isLockFree", 1, js_atomics_isLockFree ),
- JS_CFUNC_DEF("pause", 0, js_atomics_pause ),
- JS_CFUNC_DEF("wait", 4, js_atomics_wait ),
- JS_CFUNC_DEF("notify", 3, js_atomics_notify ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Atomics", JS_PROP_CONFIGURABLE ),
- };
- static const JSCFunctionListEntry js_atomics_obj[] = {
- JS_OBJECT_DEF("Atomics", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
- };
- static void js__atomics_init(void) {
- js_mutex_init(&js_atomics_mutex);
- }
- /* TODO(saghul) make this public and not dependent on typed arrays? */
- void JS_AddIntrinsicAtomics(JSContext *ctx)
- {
- js_once(&js_atomics_once, js__atomics_init);
- /* add Atomics as autoinit object */
- JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj));
- }
- #endif /* CONFIG_ATOMICS */
- void JS_AddIntrinsicTypedArrays(JSContext *ctx)
- {
- JSValue typed_array_base_proto, typed_array_base_func;
- JSValue array_buffer_func, shared_array_buffer_func;
- int i;
- ctx->class_proto[JS_CLASS_ARRAY_BUFFER] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_BUFFER],
- js_array_buffer_proto_funcs,
- countof(js_array_buffer_proto_funcs));
- array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "ArrayBuffer",
- js_array_buffer_constructor, 1,
- ctx->class_proto[JS_CLASS_ARRAY_BUFFER]);
- JS_SetPropertyFunctionList(ctx, array_buffer_func,
- js_array_buffer_funcs,
- countof(js_array_buffer_funcs));
- ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER],
- js_shared_array_buffer_proto_funcs,
- countof(js_shared_array_buffer_proto_funcs));
- shared_array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "SharedArrayBuffer",
- js_shared_array_buffer_constructor, 1,
- ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER]);
- JS_SetPropertyFunctionList(ctx, shared_array_buffer_func,
- js_shared_array_buffer_funcs,
- countof(js_shared_array_buffer_funcs));
- typed_array_base_proto = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, typed_array_base_proto,
- js_typed_array_base_proto_funcs,
- countof(js_typed_array_base_proto_funcs));
- /* TypedArray.prototype.toString must be the same object as Array.prototype.toString */
- JSValue obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_toString);
- /* XXX: should use alias method in JSCFunctionListEntry */ //@@@
- JS_DefinePropertyValue(ctx, typed_array_base_proto, JS_ATOM_toString, obj,
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- typed_array_base_func = JS_NewCFunction(ctx, js_typed_array_base_constructor,
- "TypedArray", 0);
- JS_SetPropertyFunctionList(ctx, typed_array_base_func,
- js_typed_array_base_funcs,
- countof(js_typed_array_base_funcs));
- JS_SetConstructor(ctx, typed_array_base_func, typed_array_base_proto);
- JS_SetConstructorBit(ctx, typed_array_base_func, true);
- /* Used to squelch a -Wcast-function-type warning. */
- JSCFunctionType ft = { .generic_magic = js_typed_array_constructor };
- for(i = JS_CLASS_UINT8C_ARRAY; i < JS_CLASS_UINT8C_ARRAY + JS_TYPED_ARRAY_COUNT; i++) {
- JSValue func_obj;
- char buf[ATOM_GET_STR_BUF_SIZE];
- const char *name;
- ctx->class_proto[i] = JS_NewObjectProto(ctx, typed_array_base_proto);
- JS_DefinePropertyValueStr(ctx, ctx->class_proto[i],
- "BYTES_PER_ELEMENT",
- js_int32(1 << typed_array_size_log2(i)),
- 0);
- name = JS_AtomGetStr(ctx, buf, sizeof(buf),
- JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY);
- func_obj = JS_NewCFunction3(ctx, ft.generic,
- name, 3, JS_CFUNC_constructor_magic, i,
- typed_array_base_func);
- JS_NewGlobalCConstructor2(ctx, func_obj, name, ctx->class_proto[i]);
- JS_DefinePropertyValueStr(ctx, func_obj,
- "BYTES_PER_ELEMENT",
- js_int32(1 << typed_array_size_log2(i)),
- 0);
- }
- JS_FreeValue(ctx, typed_array_base_proto);
- JS_FreeValue(ctx, typed_array_base_func);
- /* DataView */
- ctx->class_proto[JS_CLASS_DATAVIEW] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATAVIEW],
- js_dataview_proto_funcs,
- countof(js_dataview_proto_funcs));
- JS_NewGlobalCConstructorOnly(ctx, "DataView",
- js_dataview_constructor, 1,
- ctx->class_proto[JS_CLASS_DATAVIEW]);
- /* Atomics */
- #ifdef CONFIG_ATOMICS
- JS_AddIntrinsicAtomics(ctx);
- #endif
- }
- /* Performance */
- static double js__now_ms(void)
- {
- return js__hrtime_ns() / 1e6;
- }
- static JSValue js_perf_now(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
- {
- return js_float64(js__now_ms() - ctx->time_origin);
- }
- static const JSCFunctionListEntry js_perf_proto_funcs[] = {
- JS_CFUNC_DEF2("now", 0, js_perf_now, JS_PROP_ENUMERABLE),
- };
- void JS_AddPerformance(JSContext *ctx)
- {
- ctx->time_origin = js__now_ms();
- JSValue performance = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, performance, js_perf_proto_funcs, countof(js_perf_proto_funcs));
- JS_DefinePropertyValueStr(ctx, performance, "timeOrigin",
- js_float64(ctx->time_origin),
- JS_PROP_ENUMERABLE);
- JS_DefinePropertyValueStr(ctx, ctx->global_obj, "performance",
- js_dup(performance),
- JS_PROP_WRITABLE | JS_PROP_ENUMERABLE | JS_PROP_CONFIGURABLE);
- JS_FreeValue(ctx, performance);
- }
- /* Equality comparisons and sameness */
- int JS_IsEqual(JSContext *ctx, JSValueConst op1, JSValueConst op2)
- {
- JSValue sp[2] = { js_dup(op1), js_dup(op2) };
- if (js_eq_slow(ctx, endof(sp), 0))
- return -1;
- return JS_VALUE_GET_BOOL(sp[0]);
- }
- bool JS_IsStrictEqual(JSContext *ctx, JSValueConst op1, JSValueConst op2)
- {
- return js_strict_eq2(ctx, js_dup(op1), js_dup(op2), JS_EQ_STRICT);
- }
- bool JS_IsSameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2)
- {
- return js_same_value(ctx, op1, op2);
- }
- bool JS_IsSameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
- {
- return js_same_value_zero(ctx, op1, op2);
- }
- /* WeakRef */
- typedef struct JSWeakRefData {
- JSValueConst target;
- JSValue obj;
- } JSWeakRefData;
- static JSWeakRefData js_weakref_sentinel;
- static void js_weakref_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSWeakRefData *wrd = JS_GetOpaque(val, JS_CLASS_WEAK_REF);
- if (!wrd || wrd == &js_weakref_sentinel)
- return;
- /* Delete weak ref */
- JSWeakRefRecord **pwr, *wr;
- pwr = get_first_weak_ref(wrd->target);
- for(;;) {
- wr = *pwr;
- assert(wr != NULL);
- if (wr->kind == JS_WEAK_REF_KIND_WEAK_REF && wr->u.weak_ref_data == wrd)
- break;
- pwr = &wr->next_weak_ref;
- }
- *pwr = wr->next_weak_ref;
- js_free_rt(rt, wrd);
- js_free_rt(rt, wr);
- }
- static JSValue js_weakref_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- if (JS_IsUndefined(new_target))
- return JS_ThrowTypeError(ctx, "constructor requires 'new'");
- JSValueConst arg = argv[0];
- if (!is_valid_weakref_target(arg))
- return JS_ThrowTypeError(ctx, "invalid target");
- // TODO(saghul): short-circuit if the refcount is 1?
- JSValue obj = js_create_from_ctor(ctx, new_target, JS_CLASS_WEAK_REF);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- JSWeakRefData *wrd = js_malloc(ctx, sizeof(*wrd));
- if (!wrd) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- JSWeakRefRecord *wr = js_malloc(ctx, sizeof(*wr));
- if (!wr) {
- JS_FreeValue(ctx, obj);
- js_free(ctx, wrd);
- return JS_EXCEPTION;
- }
- wrd->target = arg;
- wrd->obj = obj;
- wr->kind = JS_WEAK_REF_KIND_WEAK_REF;
- wr->u.weak_ref_data = wrd;
- insert_weakref_record(arg, wr);
- JS_SetOpaqueInternal(obj, wrd);
- return obj;
- }
- static JSValue js_weakref_deref(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
- {
- JSWeakRefData *wrd = JS_GetOpaque2(ctx, this_val, JS_CLASS_WEAK_REF);
- if (!wrd)
- return JS_EXCEPTION;
- if (wrd == &js_weakref_sentinel)
- return JS_UNDEFINED;
- return js_dup(wrd->target);
- }
- static const JSCFunctionListEntry js_weakref_proto_funcs[] = {
- JS_CFUNC_DEF("deref", 0, js_weakref_deref ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakRef", JS_PROP_CONFIGURABLE ),
- };
- static const JSClassShortDef js_weakref_class_def[] = {
- { JS_ATOM_WeakRef, js_weakref_finalizer, NULL }, /* JS_CLASS_WEAK_REF */
- };
- typedef struct JSFinRecEntry {
- struct list_head link;
- JSValueConst obj;
- JSValueConst target;
- JSValue held_val;
- JSValue token;
- } JSFinRecEntry;
- typedef struct JSFinalizationRegistryData {
- struct list_head entries;
- JSContext *ctx;
- JSValue cb;
- } JSFinalizationRegistryData;
- static void delete_finrec_weakref(JSRuntime *rt, JSFinRecEntry *fre)
- {
- JSWeakRefRecord **pwr, *wr;
- pwr = get_first_weak_ref(fre->target);
- for(;;) {
- wr = *pwr;
- assert(wr != NULL);
- if (wr->kind == JS_WEAK_REF_KIND_FINALIZATION_REGISTRY_ENTRY && wr->u.fin_rec_entry == fre)
- break;
- pwr = &wr->next_weak_ref;
- }
- *pwr = wr->next_weak_ref;
- js_free_rt(rt, wr);
- }
- static void js_finrec_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY);
- if (frd) {
- struct list_head *el, *el1;
- /* first pass to remove the weak ref entries and avoid having them modified
- by freeing a token / held value. */
- list_for_each_safe(el, el1, &frd->entries) {
- JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
- delete_finrec_weakref(rt, fre);
- }
- /* second pass to actually free all objects. */
- list_for_each_safe(el, el1, &frd->entries) {
- JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
- list_del(&fre->link);
- JS_FreeValueRT(rt, fre->held_val);
- JS_FreeValueRT(rt, fre->token);
- js_free_rt(rt, fre);
- }
- JS_FreeValueRT(rt, frd->cb);
- js_free_rt(rt, frd);
- }
- }
- static void js_finrec_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY);
- if (frd) {
- JS_MarkValue(rt, frd->cb, mark_func);
- struct list_head *el;
- list_for_each(el, &frd->entries) {
- JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
- JS_MarkValue(rt, fre->held_val, mark_func);
- JS_MarkValue(rt, fre->token, mark_func);
- }
- }
- }
- static JSValue js_finrec_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- if (JS_IsUndefined(new_target))
- return JS_ThrowTypeError(ctx, "constructor requires 'new'");
- JSValueConst cb = argv[0];
- if (check_function(ctx, cb))
- return JS_EXCEPTION;
- JSValue obj = js_create_from_ctor(ctx, new_target, JS_CLASS_FINALIZATION_REGISTRY);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- JSFinalizationRegistryData *frd = js_malloc(ctx, sizeof(*frd));
- if (!frd) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- init_list_head(&frd->entries);
- frd->ctx = ctx;
- frd->cb = js_dup(cb);
- JS_SetOpaqueInternal(obj, frd);
- return obj;
- }
- static JSValue js_finrec_register(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSFinalizationRegistryData *frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY);
- if (!frd)
- return JS_EXCEPTION;
- JSValueConst target = argv[0];
- JSValueConst held_val = argv[1];
- // The function length needs to return 2, so the 3rd argument won't be initialized.
- JSValueConst token = argc > 2 ? argv[2] : JS_UNDEFINED;
- if (!is_valid_weakref_target(target))
- return JS_ThrowTypeError(ctx, "invalid target");
- if (js_same_value(ctx, target, this_val))
- return JS_UNDEFINED;
- if (!JS_IsUndefined(held_val) && js_same_value(ctx, target, held_val))
- return JS_ThrowTypeError(ctx, "held value cannot be the target");
- if (!JS_IsUndefined(token) && !is_valid_weakref_target(token))
- return JS_ThrowTypeError(ctx, "invalid unregister token");
- JSFinRecEntry *fre = js_malloc(ctx, sizeof(*fre));
- if (!fre)
- return JS_EXCEPTION;
- JSWeakRefRecord *wr = js_malloc(ctx, sizeof(*wr));
- if (!wr) {
- js_free(ctx, fre);
- return JS_EXCEPTION;
- }
- fre->obj = this_val;
- fre->target = target;
- fre->held_val = js_dup(held_val);
- fre->token = js_dup(token);
- list_add_tail(&fre->link, &frd->entries);
- wr->kind = JS_WEAK_REF_KIND_FINALIZATION_REGISTRY_ENTRY;
- wr->u.fin_rec_entry = fre;
- insert_weakref_record(target, wr);
- return JS_UNDEFINED;
- }
- static JSValue js_finrec_unregister(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
- {
- JSFinalizationRegistryData *frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY);
- if (!frd)
- return JS_EXCEPTION;
- JSValueConst token = argv[0];
- if (!is_valid_weakref_target(token))
- return JS_ThrowTypeError(ctx, "invalid unregister token");
- struct list_head *el, *el1;
- bool removed = false;
- list_for_each_safe(el, el1, &frd->entries) {
- JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
- if (js_same_value(ctx, fre->token, token)) {
- list_del(&fre->link);
- delete_finrec_weakref(ctx->rt, fre);
- JS_FreeValue(ctx, fre->held_val);
- JS_FreeValue(ctx, fre->token);
- js_free(ctx, fre);
- removed = true;
- }
- }
- return js_bool(removed);
- }
- static const JSCFunctionListEntry js_finrec_proto_funcs[] = {
- JS_CFUNC_DEF("register", 2, js_finrec_register ),
- JS_CFUNC_DEF("unregister", 1, js_finrec_unregister ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "FinalizationRegistry", JS_PROP_CONFIGURABLE ),
- };
- static const JSClassShortDef js_finrec_class_def[] = {
- { JS_ATOM_FinalizationRegistry, js_finrec_finalizer, js_finrec_mark }, /* JS_CLASS_FINALIZATION_REGISTRY */
- };
- static JSValue js_finrec_job(JSContext *ctx, int argc, JSValueConst *argv)
- {
- return JS_Call(ctx, argv[0], JS_UNDEFINED, 1, &argv[1]);
- }
- void JS_AddIntrinsicWeakRef(JSContext *ctx)
- {
- JSRuntime *rt = ctx->rt;
- /* WeakRef */
- if (!JS_IsRegisteredClass(rt, JS_CLASS_WEAK_REF)) {
- init_class_range(rt, js_weakref_class_def, JS_CLASS_WEAK_REF,
- countof(js_weakref_class_def));
- }
- ctx->class_proto[JS_CLASS_WEAK_REF] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_WEAK_REF],
- js_weakref_proto_funcs,
- countof(js_weakref_proto_funcs));
- JS_NewGlobalCConstructor(ctx, "WeakRef", js_weakref_constructor, 1, ctx->class_proto[JS_CLASS_WEAK_REF]);
- /* FinalizationRegistry */
- if (!JS_IsRegisteredClass(rt, JS_CLASS_FINALIZATION_REGISTRY)) {
- init_class_range(rt, js_finrec_class_def, JS_CLASS_FINALIZATION_REGISTRY,
- countof(js_finrec_class_def));
- }
- ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY],
- js_finrec_proto_funcs,
- countof(js_finrec_proto_funcs));
- JS_NewGlobalCConstructor(ctx, "FinalizationRegistry", js_finrec_constructor, 1, ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY]);
- }
- static void reset_weak_ref(JSRuntime *rt, JSWeakRefRecord **first_weak_ref)
- {
- JSWeakRefRecord *wr, *wr_next;
- JSWeakRefData *wrd;
- JSMapRecord *mr;
- JSMapState *s;
- JSFinRecEntry *fre;
- /* first pass to remove the records from the WeakMap/WeakSet
- lists */
- for(wr = *first_weak_ref; wr != NULL; wr = wr->next_weak_ref) {
- switch(wr->kind) {
- case JS_WEAK_REF_KIND_MAP:
- mr = wr->u.map_record;
- s = mr->map;
- assert(s->is_weak);
- assert(!mr->empty); /* no iterator on WeakMap/WeakSet */
- list_del(&mr->hash_link);
- list_del(&mr->link);
- s->record_count--;
- break;
- case JS_WEAK_REF_KIND_WEAK_REF:
- wrd = wr->u.weak_ref_data;
- wrd->target = JS_UNDEFINED;
- break;
- case JS_WEAK_REF_KIND_FINALIZATION_REGISTRY_ENTRY:
- fre = wr->u.fin_rec_entry;
- list_del(&fre->link);
- break;
- default:
- abort();
- }
- }
- /* second pass to free the values to avoid modifying the weak
- reference list while traversing it. */
- for(wr = *first_weak_ref; wr != NULL; wr = wr_next) {
- wr_next = wr->next_weak_ref;
- switch(wr->kind) {
- case JS_WEAK_REF_KIND_MAP:
- mr = wr->u.map_record;
- JS_FreeValueRT(rt, mr->value);
- js_free_rt(rt, mr);
- break;
- case JS_WEAK_REF_KIND_WEAK_REF:
- wrd = wr->u.weak_ref_data;
- JS_SetOpaqueInternal(wrd->obj, &js_weakref_sentinel);
- js_free_rt(rt, wrd);
- break;
- case JS_WEAK_REF_KIND_FINALIZATION_REGISTRY_ENTRY: {
- fre = wr->u.fin_rec_entry;
- JSFinalizationRegistryData *frd = JS_GetOpaque(fre->obj, JS_CLASS_FINALIZATION_REGISTRY);
- assert(frd != NULL);
- /**
- * During the GC sweep phase the held object might be collected first.
- */
- if (!rt->in_free && (!JS_IsObject(fre->held_val) || JS_IsLiveObject(rt, fre->held_val))) {
- JSValueConst args[2];
- args[0] = frd->cb;
- args[1] = fre->held_val;
- JS_EnqueueJob(frd->ctx, js_finrec_job, 2, args);
- }
- JS_FreeValueRT(rt, fre->held_val);
- JS_FreeValueRT(rt, fre->token);
- js_free_rt(rt, fre);
- break;
- }
- default:
- abort();
- }
- js_free_rt(rt, wr);
- }
- *first_weak_ref = NULL; /* fail safe */
- }
- static bool is_valid_weakref_target(JSValueConst val)
- {
- switch (JS_VALUE_GET_TAG(val)) {
- case JS_TAG_OBJECT:
- break;
- case JS_TAG_SYMBOL: {
- // Per spec: prohibit symbols registered with Symbol.for()
- JSAtomStruct *p = JS_VALUE_GET_PTR(val);
- if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL)
- break;
- // fallthru
- }
- default:
- return false;
- }
- return true;
- }
- static void insert_weakref_record(JSValueConst target,
- struct JSWeakRefRecord *wr)
- {
- JSWeakRefRecord **pwr = get_first_weak_ref(target);
- /* Add the weak reference */
- wr->next_weak_ref = *pwr;
- *pwr = wr;
- }
- /* CallSite */
- static void js_callsite_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSCallSiteData *csd = JS_GetOpaque(val, JS_CLASS_CALL_SITE);
- if (csd) {
- JS_FreeValueRT(rt, csd->filename);
- JS_FreeValueRT(rt, csd->func);
- JS_FreeValueRT(rt, csd->func_name);
- js_free_rt(rt, csd);
- }
- }
- static void js_callsite_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSCallSiteData *csd = JS_GetOpaque(val, JS_CLASS_CALL_SITE);
- if (csd) {
- JS_MarkValue(rt, csd->filename, mark_func);
- JS_MarkValue(rt, csd->func, mark_func);
- JS_MarkValue(rt, csd->func_name, mark_func);
- }
- }
- static JSValue js_new_callsite(JSContext *ctx, JSCallSiteData *csd) {
- JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_CALL_SITE);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- JSCallSiteData *csd1 = js_malloc(ctx, sizeof(*csd));
- if (!csd1) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- memcpy(csd1, csd, sizeof(*csd));
- JS_SetOpaqueInternal(obj, csd1);
- return obj;
- }
- static void js_new_callsite_data(JSContext *ctx, JSCallSiteData *csd, JSStackFrame *sf)
- {
- const char *func_name_str;
- JSObject *p;
- csd->func = js_dup(sf->cur_func);
- /* func_name_str is UTF-8 encoded if needed */
- func_name_str = get_func_name(ctx, sf->cur_func);
- if (!func_name_str || func_name_str[0] == '\0')
- csd->func_name = JS_NULL;
- else
- csd->func_name = JS_NewString(ctx, func_name_str);
- JS_FreeCString(ctx, func_name_str);
- if (JS_IsException(csd->func_name))
- csd->func_name = JS_NULL;
- p = JS_VALUE_GET_OBJ(sf->cur_func);
- if (js_class_has_bytecode(p->class_id)) {
- JSFunctionBytecode *b = p->u.func.function_bytecode;
- int line_num1, col_num1;
- line_num1 = find_line_num(ctx, b,
- sf->cur_pc - b->byte_code_buf - 1,
- &col_num1);
- csd->native = false;
- csd->line_num = line_num1;
- csd->col_num = col_num1;
- csd->filename = JS_AtomToString(ctx, b->filename);
- if (JS_IsException(csd->filename)) {
- csd->filename = JS_NULL;
- JS_FreeValue(ctx, JS_GetException(ctx)); // Clear exception.
- }
- } else {
- csd->native = true;
- csd->line_num = -1;
- csd->col_num = -1;
- csd->filename = JS_NULL;
- }
- }
- static void js_new_callsite_data2(JSContext *ctx, JSCallSiteData *csd, const char *filename, int line_num, int col_num)
- {
- csd->func = JS_NULL;
- csd->func_name = JS_NULL;
- csd->native = false;
- csd->line_num = line_num;
- csd->col_num = col_num;
- /* filename is UTF-8 encoded if needed (original argument to __JS_EvalInternal()) */
- csd->filename = JS_NewString(ctx, filename);
- if (JS_IsException(csd->filename)) {
- csd->filename = JS_NULL;
- JS_FreeValue(ctx, JS_GetException(ctx)); // Clear exception.
- }
- }
- static JSValue js_callsite_getfield(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic)
- {
- JSCallSiteData *csd = JS_GetOpaque2(ctx, this_val, JS_CLASS_CALL_SITE);
- if (!csd)
- return JS_EXCEPTION;
- JSValue *field = (void *)((char *)csd + magic);
- return js_dup(*field);
- }
- static JSValue js_callsite_isnative(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
- {
- JSCallSiteData *csd = JS_GetOpaque2(ctx, this_val, JS_CLASS_CALL_SITE);
- if (!csd)
- return JS_EXCEPTION;
- return js_bool(csd->native);
- }
- static JSValue js_callsite_getnumber(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic)
- {
- JSCallSiteData *csd = JS_GetOpaque2(ctx, this_val, JS_CLASS_CALL_SITE);
- if (!csd)
- return JS_EXCEPTION;
- int *field = (void *)((char *)csd + magic);
- return js_int32(*field);
- }
- static const JSCFunctionListEntry js_callsite_proto_funcs[] = {
- JS_CFUNC_DEF("isNative", 0, js_callsite_isnative),
- JS_CFUNC_MAGIC_DEF("getFileName", 0, js_callsite_getfield, offsetof(JSCallSiteData, filename)),
- JS_CFUNC_MAGIC_DEF("getFunction", 0, js_callsite_getfield, offsetof(JSCallSiteData, func)),
- JS_CFUNC_MAGIC_DEF("getFunctionName", 0, js_callsite_getfield, offsetof(JSCallSiteData, func_name)),
- JS_CFUNC_MAGIC_DEF("getColumnNumber", 0, js_callsite_getnumber, offsetof(JSCallSiteData, col_num)),
- JS_CFUNC_MAGIC_DEF("getLineNumber", 0, js_callsite_getnumber, offsetof(JSCallSiteData, line_num)),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "CallSite", JS_PROP_CONFIGURABLE ),
- };
- static const JSClassShortDef js_callsite_class_def[] = {
- { JS_ATOM_CallSite, js_callsite_finalizer, js_callsite_mark }, /* JS_CLASS_CALL_SITE */
- };
- static void _JS_AddIntrinsicCallSite(JSContext *ctx)
- {
- JSRuntime *rt = ctx->rt;
- if (!JS_IsRegisteredClass(rt, JS_CLASS_CALL_SITE)) {
- init_class_range(rt, js_callsite_class_def, JS_CLASS_CALL_SITE,
- countof(js_callsite_class_def));
- }
- ctx->class_proto[JS_CLASS_CALL_SITE] = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_CALL_SITE],
- js_callsite_proto_funcs,
- countof(js_callsite_proto_funcs));
- }
- /* DOMException */
- typedef struct JSDOMExceptionData {
- JSValue name;
- JSValue message;
- int code;
- } JSDOMExceptionData;
- typedef struct JSDOMExceptionNameDef {
- const char * const name;
- const char * const code_name;
- } JSDOMExceptionNameDef;
- static const JSDOMExceptionNameDef js_dom_exception_names_table[] = {
- { "IndexSizeError", "INDEX_SIZE_ERR" },
- { NULL, "DOMSTRING_SIZE_ERR" },
- { "HierarchyRequestError", "HIERARCHY_REQUEST_ERR" },
- { "WrongDocumentError", "WRONG_DOCUMENT_ERR" },
- { "InvalidCharacterError", "INVALID_CHARACTER_ERR" },
- { NULL, "NO_DATA_ALLOWED_ERR" },
- { "NoModificationAllowedError", "NO_MODIFICATION_ALLOWED_ERR" },
- { "NotFoundError", "NOT_FOUND_ERR" },
- { "NotSupportedError", "NOT_SUPPORTED_ERR" },
- { "InUseAttributeError", "INUSE_ATTRIBUTE_ERR" },
- { "InvalidStateError", "INVALID_STATE_ERR" },
- { "SyntaxError", "SYNTAX_ERR" },
- { "InvalidModificationError", "INVALID_MODIFICATION_ERR" },
- { "NamespaceError", "NAMESPACE_ERR" },
- { "InvalidAccessError", "INVALID_ACCESS_ERR" },
- { NULL, "VALIDATION_ERR" },
- { "TypeMismatchError", "TYPE_MISMATCH_ERR" },
- { "SecurityError", "SECURITY_ERR" },
- { "NetworkError", "NETWORK_ERR" },
- { "AbortError", "ABORT_ERR" },
- { "URLMismatchError", "URL_MISMATCH_ERR" },
- { "QuotaExceededError", "QUOTA_EXCEEDED_ERR" },
- { "TimeoutError", "TIMEOUT_ERR" },
- { "InvalidNodeTypeError", "INVALID_NODE_TYPE_ERR" },
- { "DataCloneError", "DATA_CLONE_ERR" }
- };
- static void js_domexception_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSDOMExceptionData *s = JS_GetOpaque(val, JS_CLASS_DOM_EXCEPTION);
- if (s) {
- JS_FreeValueRT(rt, s->name);
- JS_FreeValueRT(rt, s->message);
- js_free_rt(rt, s);
- }
- }
- static void js_domexception_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
- {
- JSDOMExceptionData *s = JS_GetOpaque(val, JS_CLASS_DOM_EXCEPTION);
- if (s) {
- JS_MarkValue(rt, s->name, mark_func);
- JS_MarkValue(rt, s->message, mark_func);
- }
- }
- static JSValue js_domexception_constructor0(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv,
- int backtrace_flags)
- {
- JSDOMExceptionData *s;
- JSValue obj, message, name;
- obj = js_create_from_ctor(ctx, new_target, JS_CLASS_DOM_EXCEPTION);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- if (!JS_IsUndefined(argv[0]))
- message = JS_ToString(ctx, argv[0]);
- else
- message = js_empty_string(ctx->rt);
- if (JS_IsException(message))
- goto fail1;
- if (!JS_IsUndefined(argv[1]))
- name = JS_ToString(ctx, argv[1]);
- else
- name = JS_AtomToString(ctx, JS_ATOM_Error);
- if (JS_IsException(name))
- goto fail2;
- s = js_malloc(ctx, sizeof(*s));
- if (!s)
- goto fail3;
- s->name = name;
- s->message = message;
- s->code = -1;
- JS_SetOpaqueInternal(obj, s);
- build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0, backtrace_flags);
- return obj;
- fail3:
- JS_FreeValue(ctx, name);
- fail2:
- JS_FreeValue(ctx, message);
- fail1:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_domexception_constructor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- if (JS_IsUndefined(new_target))
- return JS_ThrowTypeError(ctx, "constructor requires 'new'");
- return js_domexception_constructor0(ctx, new_target, argc, argv,
- JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
- }
- static JSValue js_domexception_getfield(JSContext *ctx, JSValueConst this_val,
- int magic)
- {
- JSDOMExceptionData *s;
- JSValue *valp;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_DOM_EXCEPTION);
- if (!s)
- return JS_EXCEPTION;
- valp = (void *)((char *)s + magic);
- return js_dup(*valp);
- }
- static JSValue js_domexception_get_code(JSContext *ctx, JSValueConst this_val)
- {
- JSDOMExceptionData *s;
- const char *name, *it;
- int i;
- size_t len;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_DOM_EXCEPTION);
- if (!s)
- return JS_EXCEPTION;
- if (s->code == -1) {
- name = JS_ToCStringLen(ctx, &len, s->name);
- if (!name)
- return JS_EXCEPTION;
- for (i = 0; i < countof(js_dom_exception_names_table); i++) {
- it = js_dom_exception_names_table[i].name;
- if (it && !strcmp(it, name) && len == strlen(it)) {
- s->code = i;
- break;
- }
- }
- s->code++;
- JS_FreeCString(ctx, name);
- }
- return js_int32(s->code);
- }
- static const JSCFunctionListEntry js_domexception_proto_funcs[] = {
- JS_CGETSET_MAGIC_DEF("name", js_domexception_getfield, NULL,
- offsetof(JSDOMExceptionData, name) ),
- JS_CGETSET_MAGIC_DEF("message", js_domexception_getfield, NULL,
- offsetof(JSDOMExceptionData, message) ),
- JS_CGETSET_DEF("code", js_domexception_get_code, NULL ),
- JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DOMException", JS_PROP_CONFIGURABLE ),
- };
- static const JSClassShortDef js_domexception_class_def[] = {
- { JS_ATOM_DOMException, js_domexception_finalizer, js_domexception_mark }, /* JS_CLASS_DOM_EXCEPTION */
- };
- JSValue JS_PRINTF_FORMAT_ATTR(3, 4) JS_ThrowDOMException(JSContext *ctx, const char *name, JS_PRINTF_FORMAT const char *fmt, ...)
- {
- JSValue obj, js_name, js_message;
- JSValueConst argv[2];
- va_list ap;
- char buf[256];
- assert(JS_IsRegisteredClass(ctx->rt, JS_CLASS_DOM_EXCEPTION));
- va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
- js_name = JS_NewString(ctx, name);
- if (JS_IsException(js_name))
- return JS_EXCEPTION;
- js_message = JS_NewString(ctx, buf);
- if (JS_IsException(js_message)) {
- JS_FreeValue(ctx, js_name);
- return JS_EXCEPTION;
- }
- argv[0] = js_message;
- argv[1] = js_name;
- obj = js_domexception_constructor0(ctx, JS_UNDEFINED, 2, argv, 0);
- JS_FreeValue(ctx, js_message);
- JS_FreeValue(ctx, js_name);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- return JS_Throw(ctx, obj);
- }
- void JS_AddIntrinsicDOMException(JSContext *ctx)
- {
- JSRuntime *rt = ctx->rt;
- int i;
- JSAtom name;
- JSValue ctor, proto;
- if (!JS_IsRegisteredClass(rt, JS_CLASS_DOM_EXCEPTION)) {
- init_class_range(rt, js_domexception_class_def, JS_CLASS_DOM_EXCEPTION,
- countof(js_domexception_class_def));
- }
- proto = JS_NewObjectClass(ctx, JS_CLASS_ERROR);
- JS_SetPropertyFunctionList(ctx, proto,
- js_domexception_proto_funcs,
- countof(js_domexception_proto_funcs));
- ctor = JS_NewCFunction2(ctx, js_domexception_constructor, "DOMException", 2,
- JS_CFUNC_constructor_or_func, 0);
- JS_SetConstructor(ctx, ctor, proto);
- for (i = 0; i < countof(js_dom_exception_names_table); i++) {
- name = JS_NewAtom(ctx, js_dom_exception_names_table[i].code_name);
- JS_DefinePropertyValue(ctx, proto, name, js_int32(i + 1),
- JS_PROP_ENUMERABLE);
- JS_DefinePropertyValue(ctx, ctor, name, js_int32(i + 1),
- JS_PROP_ENUMERABLE);
- JS_FreeAtom(ctx, name);
- }
- JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_DOMException, ctor,
- JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- ctx->class_proto[JS_CLASS_DOM_EXCEPTION] = proto;
- }
- bool JS_DetectModule(const char *input, size_t input_len)
- {
- #ifndef QJS_DISABLE_PARSER
- JSRuntime *rt;
- JSContext *ctx;
- JSValue val;
- bool is_module;
- is_module = true;
- rt = JS_NewRuntime();
- if (!rt)
- return false;
- ctx = JS_NewContextRaw(rt);
- if (!ctx) {
- JS_FreeRuntime(rt);
- return false;
- }
- JS_AddIntrinsicRegExpCompiler(ctx); // otherwise regexp literals don't parse
- val = __JS_EvalInternal(ctx, JS_UNDEFINED, input, input_len, "<unnamed>", 1,
- JS_EVAL_TYPE_MODULE|JS_EVAL_FLAG_COMPILE_ONLY, -1);
- if (JS_IsException(val)) {
- const char *msg = JS_ToCString(ctx, rt->current_exception);
- // gruesome hack to recognize exceptions from import statements;
- // necessary because we don't pass in a module loader
- is_module = !!strstr(msg, "ReferenceError: could not load module");
- JS_FreeCString(ctx, msg);
- }
- JS_FreeValue(ctx, val);
- JS_FreeContext(ctx);
- JS_FreeRuntime(rt);
- return is_module;
- #else
- return false;
- #endif // QJS_DISABLE_PARSER
- }
- uintptr_t js_std_cmd(int cmd, ...) {
- JSContext *ctx;
- JSRuntime *rt;
- JSValue *pv;
- uintptr_t rv;
- va_list ap;
- rv = 0;
- va_start(ap, cmd);
- switch (cmd) {
- case 0: // GetOpaque
- rt = va_arg(ap, JSRuntime *);
- rv = (uintptr_t)rt->libc_opaque;
- break;
- case 1: // SetOpaque
- rt = va_arg(ap, JSRuntime *);
- rt->libc_opaque = va_arg(ap, void *);
- break;
- case 2: // ErrorBackTrace
- ctx = va_arg(ap, JSContext *);
- pv = va_arg(ap, JSValue *);
- *pv = ctx->error_back_trace;
- ctx->error_back_trace = JS_UNDEFINED;
- break;
- case 3: // GetStringKind
- ctx = va_arg(ap, JSContext *);
- pv = va_arg(ap, JSValue *);
- rv = -1;
- if (JS_IsString(*pv))
- rv = JS_VALUE_GET_STRING(*pv)->kind;
- break;
- default:
- rv = -1;
- }
- va_end(ap);
- return rv;
- }
- #undef malloc
- #undef free
- #undef realloc
- /*
- * C utilities
- *
- * Copyright (c) 2017 Fabrice Bellard
- * Copyright (c) 2018 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include <assert.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include <time.h>
- #if !defined(_MSC_VER)
- #include <sys/time.h>
- #endif
- #if defined(_WIN32)
- #include <windows.h>
- #include <process.h> // _beginthread
- #endif
- #if defined(__APPLE__)
- #include <mach-o/dyld.h>
- #endif
- #undef NANOSEC
- #define NANOSEC ((uint64_t) 1e9)
- #ifdef __GNUC__
- #pragma GCC visibility push(default)
- #endif
- void js__pstrcpy(char *buf, int buf_size, const char *str)
- {
- int c;
- char *q = buf;
- if (buf_size <= 0)
- return;
- for(;;) {
- c = *str++;
- if (c == 0 || q >= buf + buf_size - 1)
- break;
- *q++ = c;
- }
- *q = '\0';
- }
- /* strcat and truncate. */
- char *js__pstrcat(char *buf, int buf_size, const char *s)
- {
- int len;
- len = strlen(buf);
- if (len < buf_size)
- js__pstrcpy(buf + len, buf_size - len, s);
- return buf;
- }
- int js__strstart(const char *str, const char *val, const char **ptr)
- {
- const char *p, *q;
- p = str;
- q = val;
- while (*q != '\0') {
- if (*p != *q)
- return 0;
- p++;
- q++;
- }
- if (ptr)
- *ptr = p;
- return 1;
- }
- int js__has_suffix(const char *str, const char *suffix)
- {
- size_t len = strlen(str);
- size_t slen = strlen(suffix);
- return (len >= slen && !memcmp(str + len - slen, suffix, slen));
- }
- /* Dynamic buffer package */
- static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size)
- {
- if (unlikely(size == 0)) {
- free(ptr);
- return NULL;
- }
- return realloc(ptr, size);
- }
- void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func)
- {
- memset(s, 0, sizeof(*s));
- if (!realloc_func)
- realloc_func = dbuf_default_realloc;
- s->opaque = opaque;
- s->realloc_func = realloc_func;
- }
- void dbuf_init(DynBuf *s)
- {
- dbuf_init2(s, NULL, NULL);
- }
- /* return < 0 if error */
- int dbuf_realloc(DynBuf *s, size_t new_size)
- {
- size_t size;
- uint8_t *new_buf;
- if (new_size > s->allocated_size) {
- if (s->error)
- return -1;
- size = s->allocated_size * 3 / 2;
- if (size > new_size)
- new_size = size;
- new_buf = s->realloc_func(s->opaque, s->buf, new_size);
- if (!new_buf) {
- s->error = true;
- return -1;
- }
- s->buf = new_buf;
- s->allocated_size = new_size;
- }
- return 0;
- }
- int dbuf_write(DynBuf *s, size_t offset, const void *data, size_t len)
- {
- size_t end;
- end = offset + len;
- if (dbuf_realloc(s, end))
- return -1;
- memcpy(s->buf + offset, data, len);
- if (end > s->size)
- s->size = end;
- return 0;
- }
- int dbuf_put(DynBuf *s, const void *data, size_t len)
- {
- if (unlikely((s->size + len) > s->allocated_size)) {
- if (dbuf_realloc(s, s->size + len))
- return -1;
- }
- if (len > 0) {
- memcpy(s->buf + s->size, data, len);
- s->size += len;
- }
- return 0;
- }
- int dbuf_put_self(DynBuf *s, size_t offset, size_t len)
- {
- if (unlikely((s->size + len) > s->allocated_size)) {
- if (dbuf_realloc(s, s->size + len))
- return -1;
- }
- memcpy(s->buf + s->size, s->buf + offset, len);
- s->size += len;
- return 0;
- }
- int dbuf_putc(DynBuf *s, uint8_t c)
- {
- return dbuf_put(s, &c, 1);
- }
- int dbuf_putstr(DynBuf *s, const char *str)
- {
- return dbuf_put(s, (const uint8_t *)str, strlen(str));
- }
- int JS_PRINTF_FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, JS_PRINTF_FORMAT const char *fmt, ...)
- {
- va_list ap;
- char buf[128];
- int len;
- va_start(ap, fmt);
- len = vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
- if (len < (int)sizeof(buf)) {
- /* fast case */
- return dbuf_put(s, (uint8_t *)buf, len);
- } else {
- if (dbuf_realloc(s, s->size + len + 1))
- return -1;
- va_start(ap, fmt);
- vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size,
- fmt, ap);
- va_end(ap);
- s->size += len;
- }
- return 0;
- }
- void dbuf_free(DynBuf *s)
- {
- /* we test s->buf as a fail safe to avoid crashing if dbuf_free()
- is called twice */
- if (s->buf) {
- s->realloc_func(s->opaque, s->buf, 0);
- }
- memset(s, 0, sizeof(*s));
- }
- /*--- UTF-8 utility functions --*/
- /* Note: only encode valid codepoints (0x0000..0x10FFFF).
- At most UTF8_CHAR_LEN_MAX bytes are output. */
- /* Compute the number of bytes of the UTF-8 encoding for a codepoint
- `c` is a code-point.
- Returns the number of bytes. If a codepoint is beyond 0x10FFFF the
- return value is 3 as the codepoint would be encoded as 0xFFFD.
- */
- size_t utf8_encode_len(uint32_t c)
- {
- if (c < 0x80)
- return 1;
- if (c < 0x800)
- return 2;
- if (c < 0x10000)
- return 3;
- if (c < 0x110000)
- return 4;
- return 3;
- }
- /* Encode a codepoint in UTF-8
- `buf` points to an array of at least `UTF8_CHAR_LEN_MAX` bytes
- `c` is a code-point.
- Returns the number of bytes. If a codepoint is beyond 0x10FFFF the
- return value is 3 and the codepoint is encoded as 0xFFFD.
- No null byte is stored after the encoded bytes.
- Return value is in range 1..4
- */
- size_t utf8_encode(uint8_t buf[minimum_length(UTF8_CHAR_LEN_MAX)], uint32_t c)
- {
- if (c < 0x80) {
- buf[0] = c;
- return 1;
- }
- if (c < 0x800) {
- buf[0] = (c >> 6) | 0xC0;
- buf[1] = (c & 0x3F) | 0x80;
- return 2;
- }
- if (c < 0x10000) {
- buf[0] = (c >> 12) | 0xE0;
- buf[1] = ((c >> 6) & 0x3F) | 0x80;
- buf[2] = (c & 0x3F) | 0x80;
- return 3;
- }
- if (c < 0x110000) {
- buf[0] = (c >> 18) | 0xF0;
- buf[1] = ((c >> 12) & 0x3F) | 0x80;
- buf[2] = ((c >> 6) & 0x3F) | 0x80;
- buf[3] = (c & 0x3F) | 0x80;
- return 4;
- }
- buf[0] = (0xFFFD >> 12) | 0xE0;
- buf[1] = ((0xFFFD >> 6) & 0x3F) | 0x80;
- buf[2] = (0xFFFD & 0x3F) | 0x80;
- return 3;
- }
- /* Decode a single code point from a UTF-8 encoded array of bytes
- `p` is a valid pointer to an array of bytes
- `pp` is a valid pointer to a `const uint8_t *` to store a pointer
- to the byte following the current sequence.
- Return the code point at `p`, in the range `0..0x10FFFF`
- Return 0xFFFD on error. Only a single byte is consumed in this case
- The maximum length for a UTF-8 byte sequence is 4 bytes.
- This implements the algorithm specified in whatwg.org, except it accepts
- UTF-8 encoded surrogates as JavaScript allows them in strings.
- The source string is assumed to have at least UTF8_CHAR_LEN_MAX bytes
- or be null terminated.
- If `p[0]` is '\0', the return value is `0` and the byte is consumed.
- cf: https://encoding.spec.whatwg.org/#utf-8-encoder
- */
- uint32_t utf8_decode(const uint8_t *p, const uint8_t **pp)
- {
- uint32_t c;
- uint8_t lower, upper;
- c = *p++;
- if (c < 0x80) {
- *pp = p;
- return c;
- }
- switch(c) {
- case 0xC2: case 0xC3:
- case 0xC4: case 0xC5: case 0xC6: case 0xC7:
- case 0xC8: case 0xC9: case 0xCA: case 0xCB:
- case 0xCC: case 0xCD: case 0xCE: case 0xCF:
- case 0xD0: case 0xD1: case 0xD2: case 0xD3:
- case 0xD4: case 0xD5: case 0xD6: case 0xD7:
- case 0xD8: case 0xD9: case 0xDA: case 0xDB:
- case 0xDC: case 0xDD: case 0xDE: case 0xDF:
- if (*p >= 0x80 && *p <= 0xBF) {
- *pp = p + 1;
- return ((c - 0xC0) << 6) + (*p - 0x80);
- }
- // otherwise encoding error
- break;
- case 0xE0:
- lower = 0xA0; /* reject invalid encoding */
- goto need2;
- case 0xE1: case 0xE2: case 0xE3:
- case 0xE4: case 0xE5: case 0xE6: case 0xE7:
- case 0xE8: case 0xE9: case 0xEA: case 0xEB:
- case 0xEC: case 0xED: case 0xEE: case 0xEF:
- lower = 0x80;
- need2:
- if (*p >= lower && *p <= 0xBF && p[1] >= 0x80 && p[1] <= 0xBF) {
- *pp = p + 2;
- return ((c - 0xE0) << 12) + ((*p - 0x80) << 6) + (p[1] - 0x80);
- }
- // otherwise encoding error
- break;
- case 0xF0:
- lower = 0x90; /* reject invalid encoding */
- upper = 0xBF;
- goto need3;
- case 0xF4:
- lower = 0x80;
- upper = 0x8F; /* reject values above 0x10FFFF */
- goto need3;
- case 0xF1: case 0xF2: case 0xF3:
- lower = 0x80;
- upper = 0xBF;
- need3:
- if (*p >= lower && *p <= upper && p[1] >= 0x80 && p[1] <= 0xBF
- && p[2] >= 0x80 && p[2] <= 0xBF) {
- *pp = p + 3;
- return ((c - 0xF0) << 18) + ((*p - 0x80) << 12) +
- ((p[1] - 0x80) << 6) + (p[2] - 0x80);
- }
- // otherwise encoding error
- break;
- default:
- // invalid lead byte
- break;
- }
- *pp = p;
- return 0xFFFD;
- }
- uint32_t utf8_decode_len(const uint8_t *p, size_t max_len, const uint8_t **pp) {
- switch (max_len) {
- case 0:
- *pp = p;
- return 0xFFFD;
- case 1:
- if (*p < 0x80)
- goto good;
- break;
- case 2:
- if (*p < 0xE0)
- goto good;
- break;
- case 3:
- if (*p < 0xF0)
- goto good;
- break;
- default:
- good:
- return utf8_decode(p, pp);
- }
- *pp = p + 1;
- return 0xFFFD;
- }
- /* Scan a UTF-8 encoded buffer for content type
- `buf` is a valid pointer to a UTF-8 encoded string
- `len` is the number of bytes to scan
- `plen` points to a `size_t` variable to receive the number of units
- Return value is a mask of bits.
- - `UTF8_PLAIN_ASCII`: return value for 7-bit ASCII plain text
- - `UTF8_NON_ASCII`: bit for non ASCII code points (8-bit or more)
- - `UTF8_HAS_16BIT`: bit for 16-bit code points
- - `UTF8_HAS_NON_BMP1`: bit for non-BMP1 code points, needs UTF-16 surrogate pairs
- - `UTF8_HAS_ERRORS`: bit for encoding errors
- */
- int utf8_scan(const char *buf, size_t buf_len, size_t *plen)
- {
- const uint8_t *p, *p_end, *p_next;
- size_t i, len;
- int kind;
- uint8_t cbits;
- kind = UTF8_PLAIN_ASCII;
- cbits = 0;
- len = buf_len;
- // TODO: handle more than 1 byte at a time
- for (i = 0; i < buf_len; i++)
- cbits |= buf[i];
- if (cbits >= 0x80) {
- p = (const uint8_t *)buf;
- p_end = p + buf_len;
- kind = UTF8_NON_ASCII;
- len = 0;
- while (p < p_end) {
- len++;
- if (*p++ >= 0x80) {
- /* parse UTF-8 sequence, check for encoding error */
- uint32_t c = utf8_decode_len(p - 1, p_end - (p - 1), &p_next);
- if (p_next == p)
- kind |= UTF8_HAS_ERRORS;
- p = p_next;
- if (c > 0xFF) {
- kind |= UTF8_HAS_16BIT;
- if (c > 0xFFFF) {
- len++;
- kind |= UTF8_HAS_NON_BMP1;
- }
- }
- }
- }
- }
- *plen = len;
- return kind;
- }
- /* Decode a string encoded in UTF-8 into an array of bytes
- `src` points to the source string. It is assumed to be correctly encoded
- and only contains code points below 0x800
- `src_len` is the length of the source string
- `dest` points to the destination array, it can be null if `dest_len` is `0`
- `dest_len` is the length of the destination array. A null
- terminator is stored at the end of the array unless `dest_len` is `0`.
- */
- size_t utf8_decode_buf8(uint8_t *dest, size_t dest_len, const char *src, size_t src_len)
- {
- const uint8_t *p, *p_end;
- size_t i;
- p = (const uint8_t *)src;
- p_end = p + src_len;
- for (i = 0; p < p_end; i++) {
- uint32_t c = *p++;
- if (c >= 0xC0)
- c = (c << 6) + *p++ - ((0xC0 << 6) + 0x80);
- if (i < dest_len)
- dest[i] = c;
- }
- if (i < dest_len)
- dest[i] = '\0';
- else if (dest_len > 0)
- dest[dest_len - 1] = '\0';
- return i;
- }
- /* Decode a string encoded in UTF-8 into an array of 16-bit words
- `src` points to the source string. It is assumed to be correctly encoded.
- `src_len` is the length of the source string
- `dest` points to the destination array, it can be null if `dest_len` is `0`
- `dest_len` is the length of the destination array. No null terminator is
- stored at the end of the array.
- */
- size_t utf8_decode_buf16(uint16_t *dest, size_t dest_len, const char *src, size_t src_len)
- {
- const uint8_t *p, *p_end;
- size_t i;
- p = (const uint8_t *)src;
- p_end = p + src_len;
- for (i = 0; p < p_end; i++) {
- uint32_t c = *p++;
- if (c >= 0x80) {
- /* parse utf-8 sequence */
- c = utf8_decode_len(p - 1, p_end - (p - 1), &p);
- /* encoding errors are converted as 0xFFFD and use a single byte */
- if (c > 0xFFFF) {
- if (i < dest_len)
- dest[i] = get_hi_surrogate(c);
- i++;
- c = get_lo_surrogate(c);
- }
- }
- if (i < dest_len)
- dest[i] = c;
- }
- return i;
- }
- /* Encode a buffer of 8-bit bytes as a UTF-8 encoded string
- `src` points to the source buffer.
- `src_len` is the length of the source buffer
- `dest` points to the destination array, it can be null if `dest_len` is `0`
- `dest_len` is the length in bytes of the destination array. A null
- terminator is stored at the end of the array unless `dest_len` is `0`.
- */
- size_t utf8_encode_buf8(char *dest, size_t dest_len, const uint8_t *src, size_t src_len)
- {
- size_t i, j;
- uint32_t c;
- for (i = j = 0; i < src_len; i++) {
- c = src[i];
- if (c < 0x80) {
- if (j + 1 >= dest_len)
- goto overflow;
- dest[j++] = c;
- } else {
- if (j + 2 >= dest_len)
- goto overflow;
- dest[j++] = (c >> 6) | 0xC0;
- dest[j++] = (c & 0x3F) | 0x80;
- }
- }
- if (j < dest_len)
- dest[j] = '\0';
- return j;
- overflow:
- if (j < dest_len)
- dest[j] = '\0';
- while (i < src_len)
- j += 1 + (src[i++] >= 0x80);
- return j;
- }
- /* Encode a buffer of 16-bit code points as a UTF-8 encoded string
- `src` points to the source buffer.
- `src_len` is the length of the source buffer
- `dest` points to the destination array, it can be null if `dest_len` is `0`
- `dest_len` is the length in bytes of the destination array. A null
- terminator is stored at the end of the array unless `dest_len` is `0`.
- */
- size_t utf8_encode_buf16(char *dest, size_t dest_len, const uint16_t *src, size_t src_len)
- {
- size_t i, j;
- uint32_t c;
- for (i = j = 0; i < src_len;) {
- c = src[i++];
- if (c < 0x80) {
- if (j + 1 >= dest_len)
- goto overflow;
- dest[j++] = c;
- } else {
- if (is_hi_surrogate(c) && i < src_len && is_lo_surrogate(src[i]))
- c = from_surrogate(c, src[i++]);
- if (j + utf8_encode_len(c) >= dest_len)
- goto overflow;
- j += utf8_encode((uint8_t *)dest + j, c);
- }
- }
- if (j < dest_len)
- dest[j] = '\0';
- return j;
- overflow:
- i -= 1 + (c > 0xFFFF);
- if (j < dest_len)
- dest[j] = '\0';
- while (i < src_len) {
- c = src[i++];
- if (c < 0x80) {
- j++;
- } else {
- if (is_hi_surrogate(c) && i < src_len && is_lo_surrogate(src[i]))
- c = from_surrogate(c, src[i++]);
- j += utf8_encode_len(c);
- }
- }
- return j;
- }
- /*---- sorting with opaque argument ----*/
- typedef void (*exchange_f)(void *a, void *b, size_t size);
- typedef int (*cmp_f)(const void *, const void *, void *opaque);
- static void exchange_bytes(void *a, void *b, size_t size) {
- uint8_t *ap = (uint8_t *)a;
- uint8_t *bp = (uint8_t *)b;
- while (size-- != 0) {
- uint8_t t = *ap;
- *ap++ = *bp;
- *bp++ = t;
- }
- }
- static void exchange_one_byte(void *a, void *b, size_t size) {
- uint8_t *ap = (uint8_t *)a;
- uint8_t *bp = (uint8_t *)b;
- uint8_t t = *ap;
- *ap = *bp;
- *bp = t;
- }
- static void exchange_int16s(void *a, void *b, size_t size) {
- uint16_t *ap = (uint16_t *)a;
- uint16_t *bp = (uint16_t *)b;
- for (size /= sizeof(uint16_t); size-- != 0;) {
- uint16_t t = *ap;
- *ap++ = *bp;
- *bp++ = t;
- }
- }
- static void exchange_one_int16(void *a, void *b, size_t size) {
- uint16_t *ap = (uint16_t *)a;
- uint16_t *bp = (uint16_t *)b;
- uint16_t t = *ap;
- *ap = *bp;
- *bp = t;
- }
- static void exchange_int32s(void *a, void *b, size_t size) {
- uint32_t *ap = (uint32_t *)a;
- uint32_t *bp = (uint32_t *)b;
- for (size /= sizeof(uint32_t); size-- != 0;) {
- uint32_t t = *ap;
- *ap++ = *bp;
- *bp++ = t;
- }
- }
- static void exchange_one_int32(void *a, void *b, size_t size) {
- uint32_t *ap = (uint32_t *)a;
- uint32_t *bp = (uint32_t *)b;
- uint32_t t = *ap;
- *ap = *bp;
- *bp = t;
- }
- static void exchange_int64s(void *a, void *b, size_t size) {
- uint64_t *ap = (uint64_t *)a;
- uint64_t *bp = (uint64_t *)b;
- for (size /= sizeof(uint64_t); size-- != 0;) {
- uint64_t t = *ap;
- *ap++ = *bp;
- *bp++ = t;
- }
- }
- static void exchange_one_int64(void *a, void *b, size_t size) {
- uint64_t *ap = (uint64_t *)a;
- uint64_t *bp = (uint64_t *)b;
- uint64_t t = *ap;
- *ap = *bp;
- *bp = t;
- }
- static void exchange_int128s(void *a, void *b, size_t size) {
- uint64_t *ap = (uint64_t *)a;
- uint64_t *bp = (uint64_t *)b;
- for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) {
- uint64_t t = ap[0];
- uint64_t u = ap[1];
- ap[0] = bp[0];
- ap[1] = bp[1];
- bp[0] = t;
- bp[1] = u;
- }
- }
- static void exchange_one_int128(void *a, void *b, size_t size) {
- uint64_t *ap = (uint64_t *)a;
- uint64_t *bp = (uint64_t *)b;
- uint64_t t = ap[0];
- uint64_t u = ap[1];
- ap[0] = bp[0];
- ap[1] = bp[1];
- bp[0] = t;
- bp[1] = u;
- }
- static inline exchange_f exchange_func(const void *base, size_t size) {
- switch (((uintptr_t)base | (uintptr_t)size) & 15) {
- case 0:
- if (size == sizeof(uint64_t) * 2)
- return exchange_one_int128;
- else
- return exchange_int128s;
- case 8:
- if (size == sizeof(uint64_t))
- return exchange_one_int64;
- else
- return exchange_int64s;
- case 4:
- case 12:
- if (size == sizeof(uint32_t))
- return exchange_one_int32;
- else
- return exchange_int32s;
- case 2:
- case 6:
- case 10:
- case 14:
- if (size == sizeof(uint16_t))
- return exchange_one_int16;
- else
- return exchange_int16s;
- default:
- if (size == 1)
- return exchange_one_byte;
- else
- return exchange_bytes;
- }
- }
- static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
- {
- uint8_t *basep = (uint8_t *)base;
- size_t i, n, c, r;
- exchange_f swap = exchange_func(base, size);
- if (nmemb > 1) {
- i = (nmemb / 2) * size;
- n = nmemb * size;
- while (i > 0) {
- i -= size;
- for (r = i; (c = r * 2 + size) < n; r = c) {
- if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0)
- c += size;
- if (cmp(basep + r, basep + c, opaque) > 0)
- break;
- swap(basep + r, basep + c, size);
- }
- }
- for (i = n - size; i > 0; i -= size) {
- swap(basep, basep + i, size);
- for (r = 0; (c = r * 2 + size) < i; r = c) {
- if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0)
- c += size;
- if (cmp(basep + r, basep + c, opaque) > 0)
- break;
- swap(basep + r, basep + c, size);
- }
- }
- }
- }
- static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque)
- {
- return cmp(a, b, opaque) < 0 ?
- (cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) :
- (cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c ));
- }
- /* pointer based version with local stack and insertion sort threshhold */
- void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
- {
- struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack;
- uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m;
- size_t m4, i, lt, gt, span, span2;
- int c, depth;
- exchange_f swap = exchange_func(base, size);
- exchange_f swap_block = exchange_func(base, size | 128);
- if (nmemb < 2 || size <= 0)
- return;
- sp->base = (uint8_t *)base;
- sp->count = nmemb;
- sp->depth = 0;
- sp++;
- while (sp > stack) {
- sp--;
- ptr = sp->base;
- nmemb = sp->count;
- depth = sp->depth;
- while (nmemb > 6) {
- if (++depth > 50) {
- /* depth check to ensure worst case logarithmic time */
- heapsortx(ptr, nmemb, size, cmp, opaque);
- nmemb = 0;
- break;
- }
- /* select median of 3 from 1/4, 1/2, 3/4 positions */
- /* should use median of 5 or 9? */
- m4 = (nmemb >> 2) * size;
- m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque);
- swap(ptr, m, size); /* move the pivot to the start or the array */
- i = lt = 1;
- pi = plt = ptr + size;
- gt = nmemb;
- pj = pgt = top = ptr + nmemb * size;
- for (;;) {
- while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) {
- if (c == 0) {
- swap(plt, pi, size);
- lt++;
- plt += size;
- }
- i++;
- pi += size;
- }
- while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) {
- if (c == 0) {
- gt--;
- pgt -= size;
- swap(pgt, pj, size);
- }
- }
- if (pi >= pj)
- break;
- swap(pi, pj, size);
- i++;
- pi += size;
- }
- /* array has 4 parts:
- * from 0 to lt excluded: elements identical to pivot
- * from lt to pi excluded: elements smaller than pivot
- * from pi to gt excluded: elements greater than pivot
- * from gt to n excluded: elements identical to pivot
- */
- /* move elements identical to pivot in the middle of the array: */
- /* swap values in ranges [0..lt[ and [i-lt..i[
- swapping the smallest span between lt and i-lt is sufficient
- */
- span = plt - ptr;
- span2 = pi - plt;
- lt = i - lt;
- if (span > span2)
- span = span2;
- swap_block(ptr, pi - span, span);
- /* swap values in ranges [gt..top[ and [i..top-(top-gt)[
- swapping the smallest span between top-gt and gt-i is sufficient
- */
- span = top - pgt;
- span2 = pgt - pi;
- pgt = top - span2;
- gt = nmemb - (gt - i);
- if (span > span2)
- span = span2;
- swap_block(pi, top - span, span);
- /* now array has 3 parts:
- * from 0 to lt excluded: elements smaller than pivot
- * from lt to gt excluded: elements identical to pivot
- * from gt to n excluded: elements greater than pivot
- */
- /* stack the larger segment and keep processing the smaller one
- to minimize stack use for pathological distributions */
- if (lt > nmemb - gt) {
- sp->base = ptr;
- sp->count = lt;
- sp->depth = depth;
- sp++;
- ptr = pgt;
- nmemb -= gt;
- } else {
- sp->base = pgt;
- sp->count = nmemb - gt;
- sp->depth = depth;
- sp++;
- nmemb = lt;
- }
- }
- /* Use insertion sort for small fragments */
- for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) {
- for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size)
- swap(pj, pj - size, size);
- }
- }
- }
- /*---- Portable time functions ----*/
- #ifdef _WIN32
- // From: https://stackoverflow.com/a/26085827
- static int gettimeofday_msvc(struct timeval *tp)
- {
- static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL);
- SYSTEMTIME system_time;
- FILETIME file_time;
- uint64_t time;
- GetSystemTime(&system_time);
- SystemTimeToFileTime(&system_time, &file_time);
- time = ((uint64_t)file_time.dwLowDateTime);
- time += ((uint64_t)file_time.dwHighDateTime) << 32;
- tp->tv_sec = (long)((time - EPOCH) / 10000000L);
- tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
- return 0;
- }
- uint64_t js__hrtime_ns(void) {
- LARGE_INTEGER counter, frequency;
- double scaled_freq;
- double result;
- if (!QueryPerformanceFrequency(&frequency))
- abort();
- assert(frequency.QuadPart != 0);
- if (!QueryPerformanceCounter(&counter))
- abort();
- assert(counter.QuadPart != 0);
- /* Because we have no guarantee about the order of magnitude of the
- * performance counter interval, integer math could cause this computation
- * to overflow. Therefore we resort to floating point math.
- */
- scaled_freq = (double) frequency.QuadPart / NANOSEC;
- result = (double) counter.QuadPart / scaled_freq;
- return (uint64_t) result;
- }
- #else
- uint64_t js__hrtime_ns(void) {
- struct timespec t;
- if (clock_gettime(CLOCK_MONOTONIC, &t))
- abort();
- return t.tv_sec * NANOSEC + t.tv_nsec;
- }
- #endif
- int64_t js__gettimeofday_us(void) {
- struct timeval tv;
- #ifdef _WIN32
- gettimeofday_msvc(&tv);
- #else
- gettimeofday(&tv, NULL);
- #endif
- return ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
- }
- #if defined(_WIN32)
- int js_exepath(char *buffer, size_t *size_ptr) {
- int utf8_len, utf16_buffer_len, utf16_len;
- WCHAR* utf16_buffer;
- if (buffer == NULL || size_ptr == NULL || *size_ptr == 0)
- return -1;
- if (*size_ptr > 32768) {
- /* Windows paths can never be longer than this. */
- utf16_buffer_len = 32768;
- } else {
- utf16_buffer_len = (int)*size_ptr;
- }
- utf16_buffer = malloc(sizeof(WCHAR) * utf16_buffer_len);
- if (!utf16_buffer)
- return -1;
- /* Get the path as UTF-16. */
- utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
- if (utf16_len <= 0)
- goto error;
- /* Convert to UTF-8 */
- utf8_len = WideCharToMultiByte(CP_UTF8,
- 0,
- utf16_buffer,
- -1,
- buffer,
- (int)*size_ptr,
- NULL,
- NULL);
- if (utf8_len == 0)
- goto error;
- free(utf16_buffer);
- /* utf8_len *does* include the terminating null at this point, but the
- * returned size shouldn't. */
- *size_ptr = utf8_len - 1;
- return 0;
- error:
- free(utf16_buffer);
- return -1;
- }
- #elif defined(__APPLE__)
- int js_exepath(char *buffer, size_t *size) {
- /* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */
- char abspath[PATH_MAX * 2 + 1];
- char exepath[PATH_MAX + 1];
- uint32_t exepath_size;
- size_t abspath_size;
- if (buffer == NULL || size == NULL || *size == 0)
- return -1;
- exepath_size = sizeof(exepath);
- if (_NSGetExecutablePath(exepath, &exepath_size))
- return -1;
- if (realpath(exepath, abspath) != abspath)
- return -1;
- abspath_size = strlen(abspath);
- if (abspath_size == 0)
- return -1;
- *size -= 1;
- if (*size > abspath_size)
- *size = abspath_size;
- memcpy(buffer, abspath, *size);
- buffer[*size] = '\0';
- return 0;
- }
- #elif defined(__linux__) || defined(__GNU__)
- int js_exepath(char *buffer, size_t *size) {
- ssize_t n;
- if (buffer == NULL || size == NULL || *size == 0)
- return -1;
- n = *size - 1;
- if (n > 0)
- n = readlink("/proc/self/exe", buffer, n);
- if (n == -1)
- return n;
- buffer[n] = '\0';
- *size = n;
- return 0;
- }
- #else
- int js_exepath(char* buffer, size_t* size_ptr) {
- return -1;
- }
- #endif
- /*--- Cross-platform threading APIs. ----*/
- #if JS_HAVE_THREADS
- #if defined(_WIN32)
- typedef void (*js__once_cb)(void);
- typedef struct {
- js__once_cb callback;
- } js__once_data_t;
- static int WINAPI js__once_inner(INIT_ONCE *once, void *param, void **context) {
- js__once_data_t *data = param;
- data->callback();
- return 1;
- }
- void js_once(js_once_t *guard, js__once_cb callback) {
- js__once_data_t data = { .callback = callback };
- InitOnceExecuteOnce(guard, js__once_inner, (void*) &data, NULL);
- }
- void js_mutex_init(js_mutex_t *mutex) {
- InitializeCriticalSection(mutex);
- }
- void js_mutex_destroy(js_mutex_t *mutex) {
- DeleteCriticalSection(mutex);
- }
- void js_mutex_lock(js_mutex_t *mutex) {
- EnterCriticalSection(mutex);
- }
- void js_mutex_unlock(js_mutex_t *mutex) {
- LeaveCriticalSection(mutex);
- }
- void js_cond_init(js_cond_t *cond) {
- InitializeConditionVariable(cond);
- }
- void js_cond_destroy(js_cond_t *cond) {
- /* nothing to do */
- (void) cond;
- }
- void js_cond_signal(js_cond_t *cond) {
- WakeConditionVariable(cond);
- }
- void js_cond_broadcast(js_cond_t *cond) {
- WakeAllConditionVariable(cond);
- }
- void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex) {
- if (!SleepConditionVariableCS(cond, mutex, INFINITE))
- abort();
- }
- int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) {
- if (SleepConditionVariableCS(cond, mutex, (DWORD)(timeout / 1e6)))
- return 0;
- if (GetLastError() != ERROR_TIMEOUT)
- abort();
- return -1;
- }
- int js_thread_create(js_thread_t *thrd, void (*start)(void *), void *arg,
- int flags)
- {
- HANDLE h, cp;
- *thrd = INVALID_HANDLE_VALUE;
- if (flags & ~JS_THREAD_CREATE_DETACHED)
- return -1;
- h = (HANDLE)_beginthread(start, /*stacksize*/2<<20, arg);
- if (!h)
- return -1;
- if (flags & JS_THREAD_CREATE_DETACHED)
- return 0;
- // _endthread() automatically closes the handle but we want to wait on
- // it so make a copy. Race-y for very short-lived threads. Can be solved
- // by switching to _beginthreadex(CREATE_SUSPENDED) but means changing
- // |start| from __cdecl to __stdcall.
- cp = GetCurrentProcess();
- if (DuplicateHandle(cp, h, cp, thrd, 0, FALSE, DUPLICATE_SAME_ACCESS))
- return 0;
- return -1;
- }
- int js_thread_join(js_thread_t thrd)
- {
- if (WaitForSingleObject(thrd, INFINITE))
- return -1;
- CloseHandle(thrd);
- return 0;
- }
- #else /* !defined(_WIN32) */
- void js_once(js_once_t *guard, void (*callback)(void)) {
- if (pthread_once(guard, callback))
- abort();
- }
- void js_mutex_init(js_mutex_t *mutex) {
- if (pthread_mutex_init(mutex, NULL))
- abort();
- }
- void js_mutex_destroy(js_mutex_t *mutex) {
- if (pthread_mutex_destroy(mutex))
- abort();
- }
- void js_mutex_lock(js_mutex_t *mutex) {
- if (pthread_mutex_lock(mutex))
- abort();
- }
- void js_mutex_unlock(js_mutex_t *mutex) {
- if (pthread_mutex_unlock(mutex))
- abort();
- }
- void js_cond_init(js_cond_t *cond) {
- #if defined(__APPLE__) && defined(__MACH__)
- if (pthread_cond_init(cond, NULL))
- abort();
- #else
- pthread_condattr_t attr;
- if (pthread_condattr_init(&attr))
- abort();
- if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC))
- abort();
- if (pthread_cond_init(cond, &attr))
- abort();
- if (pthread_condattr_destroy(&attr))
- abort();
- #endif
- }
- void js_cond_destroy(js_cond_t *cond) {
- #if defined(__APPLE__) && defined(__MACH__)
- /* It has been reported that destroying condition variables that have been
- * signalled but not waited on can sometimes result in application crashes.
- * See https://codereview.chromium.org/1323293005.
- */
- pthread_mutex_t mutex;
- struct timespec ts;
- int err;
- if (pthread_mutex_init(&mutex, NULL))
- abort();
- if (pthread_mutex_lock(&mutex))
- abort();
- ts.tv_sec = 0;
- ts.tv_nsec = 1;
- err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts);
- if (err != 0 && err != ETIMEDOUT)
- abort();
- if (pthread_mutex_unlock(&mutex))
- abort();
- if (pthread_mutex_destroy(&mutex))
- abort();
- #endif /* defined(__APPLE__) && defined(__MACH__) */
- if (pthread_cond_destroy(cond))
- abort();
- }
- void js_cond_signal(js_cond_t *cond) {
- if (pthread_cond_signal(cond))
- abort();
- }
- void js_cond_broadcast(js_cond_t *cond) {
- if (pthread_cond_broadcast(cond))
- abort();
- }
- void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex) {
- #if defined(__APPLE__) && defined(__MACH__)
- int r;
- errno = 0;
- r = pthread_cond_wait(cond, mutex);
- /* Workaround for a bug in OS X at least up to 13.6
- * See https://github.com/libuv/libuv/issues/4165
- */
- if (r == EINVAL && errno == EBUSY)
- return;
- if (r)
- abort();
- #else
- if (pthread_cond_wait(cond, mutex))
- abort();
- #endif
- }
- int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) {
- int r;
- struct timespec ts;
- #if !defined(__APPLE__)
- timeout += js__hrtime_ns();
- #endif
- ts.tv_sec = timeout / NANOSEC;
- ts.tv_nsec = timeout % NANOSEC;
- #if defined(__APPLE__) && defined(__MACH__)
- r = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
- #else
- r = pthread_cond_timedwait(cond, mutex, &ts);
- #endif
- if (r == 0)
- return 0;
- if (r == ETIMEDOUT)
- return -1;
- abort();
- /* Pacify some compilers. */
- return -1;
- }
- int js_thread_create(js_thread_t *thrd, void (*start)(void *), void *arg,
- int flags)
- {
- union {
- void (*x)(void *);
- void *(*f)(void *);
- } u = {start};
- pthread_attr_t attr;
- int ret;
- if (flags & ~JS_THREAD_CREATE_DETACHED)
- return -1;
- if (pthread_attr_init(&attr))
- return -1;
- ret = -1;
- if (pthread_attr_setstacksize(&attr, 2<<20))
- goto fail;
- if (flags & JS_THREAD_CREATE_DETACHED)
- if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
- goto fail;
- if (pthread_create(thrd, &attr, u.f, arg))
- goto fail;
- ret = 0;
- fail:
- pthread_attr_destroy(&attr);
- return ret;
- }
- int js_thread_join(js_thread_t thrd)
- {
- if (pthread_join(thrd, NULL))
- return -1;
- return 0;
- }
- #endif /* !defined(_WIN32) */
- #endif /* JS_HAVE_THREADS */
- #ifdef __GNUC__
- #pragma GCC visibility pop
- #endif
- /*
- * Tiny float64 printing and parsing library
- *
- * Copyright (c) 2024 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <inttypes.h>
- #include <string.h>
- #include <assert.h>
- #include <ctype.h>
- // #include <sys/time.h>
- #include <math.h>
- // #include <setjmp.h>
- /*
- TODO:
- - test n_digits=101 instead of 100
- - simplify subnormal handling
- - reduce max memory usage
- - free format: could add shortcut if exact result
- - use 64 bit limb_t when possible
- - use another algorithm for free format dtoa in base 10 (ryu ?)
- */
- #define USE_POW5_TABLE
- /* use fast path to print small integers in free format */
- #define USE_FAST_INT
- #define LIMB_LOG2_BITS 5
- #define LIMB_BITS (1 << LIMB_LOG2_BITS)
- typedef int32_t slimb_t;
- typedef uint32_t limb_t;
- typedef uint64_t dlimb_t;
- #define LIMB_DIGITS 9
- #define JS_RADIX_MAX 36
- #define DBIGNUM_LEN_MAX 52 /* ~ 2^(1072+53)*36^100 (dtoa) */
- #define MANT_LEN_MAX 18 /* < 36^100 */
- typedef intptr_t mp_size_t;
- /* the represented number is sum(i, tab[i]*2^(LIMB_BITS * i)) */
- typedef struct {
- int len; /* >= 1 */
- limb_t tab[];
- } mpb_t;
- static limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n)
- {
- size_t i;
- limb_t k, a;
- k=b;
- for(i=0;i<n;i++) {
- if (k == 0)
- break;
- a = tab[i] + k;
- k = (a < k);
- tab[i] = a;
- }
- return k;
- }
- /* tabr[] = taba[] * b + l. Return the high carry */
- static limb_t mp_mul1(limb_t *tabr, const limb_t *taba, limb_t n,
- limb_t b, limb_t l)
- {
- limb_t i;
- dlimb_t t;
- for(i = 0; i < n; i++) {
- t = (dlimb_t)taba[i] * (dlimb_t)b + l;
- tabr[i] = t;
- l = t >> LIMB_BITS;
- }
- return l;
- }
- /* WARNING: d must be >= 2^(LIMB_BITS-1) */
- static inline limb_t udiv1norm_init(limb_t d)
- {
- limb_t a0, a1;
- a1 = -d - 1;
- a0 = -1;
- return (((dlimb_t)a1 << LIMB_BITS) | a0) / d;
- }
- /* return the quotient and the remainder in '*pr'of 'a1*2^LIMB_BITS+a0
- / d' with 0 <= a1 < d. */
- static inline limb_t udiv1norm(limb_t *pr, limb_t a1, limb_t a0,
- limb_t d, limb_t d_inv)
- {
- limb_t n1m, n_adj, q, r, ah;
- dlimb_t a;
- n1m = ((slimb_t)a0 >> (LIMB_BITS - 1));
- n_adj = a0 + (n1m & d);
- a = (dlimb_t)d_inv * (a1 - n1m) + n_adj;
- q = (a >> LIMB_BITS) + a1;
- /* compute a - q * r and update q so that the remainder is between
- 0 and d - 1 */
- a = ((dlimb_t)a1 << LIMB_BITS) | a0;
- a = a - (dlimb_t)q * d - d;
- ah = a >> LIMB_BITS;
- q += 1 + ah;
- r = (limb_t)a + (ah & d);
- *pr = r;
- return q;
- }
- static limb_t mp_div1(limb_t *tabr, const limb_t *taba, limb_t n,
- limb_t b, limb_t r)
- {
- slimb_t i;
- dlimb_t a1;
- for(i = n - 1; i >= 0; i--) {
- a1 = ((dlimb_t)r << LIMB_BITS) | taba[i];
- tabr[i] = a1 / b;
- r = a1 % b;
- }
- return r;
- }
- /* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift).
- 1 <= shift <= LIMB_BITS - 1 */
- static limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n,
- int shift, limb_t high)
- {
- mp_size_t i;
- limb_t l, a;
- assert(shift >= 1 && shift < LIMB_BITS);
- l = high;
- for(i = n - 1; i >= 0; i--) {
- a = tab[i];
- tab_r[i] = (a >> shift) | (l << (LIMB_BITS - shift));
- l = a;
- }
- return l & (((limb_t)1 << shift) - 1);
- }
- /* r = (a << shift) + low. 1 <= shift <= LIMB_BITS - 1, 0 <= low <
- 2^shift. */
- static limb_t mp_shl(limb_t *tab_r, const limb_t *tab, mp_size_t n,
- int shift, limb_t low)
- {
- mp_size_t i;
- limb_t l, a;
- assert(shift >= 1 && shift < LIMB_BITS);
- l = low;
- for(i = 0; i < n; i++) {
- a = tab[i];
- tab_r[i] = (a << shift) | l;
- l = (a >> (LIMB_BITS - shift));
- }
- return l;
- }
- static no_inline limb_t mp_div1norm(limb_t *tabr, const limb_t *taba, limb_t n,
- limb_t b, limb_t r, limb_t b_inv, int shift)
- {
- slimb_t i;
- if (shift != 0) {
- r = (r << shift) | mp_shl(tabr, taba, n, shift, 0);
- }
- for(i = n - 1; i >= 0; i--) {
- tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv);
- }
- r >>= shift;
- return r;
- }
- static __maybe_unused void mpb_dump(const char *str, const mpb_t *a)
- {
- int i;
-
- printf("%s= 0x", str);
- for(i = a->len - 1; i >= 0; i--) {
- printf("%08x", a->tab[i]);
- if (i != 0)
- printf("_");
- }
- printf("\n");
- }
- static void mpb_renorm(mpb_t *r)
- {
- while (r->len > 1 && r->tab[r->len - 1] == 0)
- r->len--;
- }
- #ifdef USE_POW5_TABLE
- static const uint32_t pow5_table[17] = {
- 0x00000005, 0x00000019, 0x0000007d, 0x00000271,
- 0x00000c35, 0x00003d09, 0x0001312d, 0x0005f5e1,
- 0x001dcd65, 0x009502f9, 0x02e90edd, 0x0e8d4a51,
- 0x48c27395, 0x6bcc41e9, 0x1afd498d, 0x86f26fc1,
- 0xa2bc2ec5,
- };
- static const uint8_t pow5h_table[4] = {
- 0x00000001, 0x00000007, 0x00000023, 0x000000b1,
- };
- static const uint32_t pow5_inv_table[13] = {
- 0x99999999, 0x47ae147a, 0x0624dd2f, 0xa36e2eb1,
- 0x4f8b588e, 0x0c6f7a0b, 0xad7f29ab, 0x5798ee23,
- 0x12e0be82, 0xb7cdfd9d, 0x5fd7fe17, 0x19799812,
- 0xc25c2684,
- };
- #endif
- /* return a^b */
- static uint64_t pow_ui(uint32_t a, uint32_t b)
- {
- int i, n_bits;
- uint64_t r;
- if (b == 0)
- return 1;
- if (b == 1)
- return a;
- #ifdef USE_POW5_TABLE
- if ((a == 5 || a == 10) && b <= 17) {
- r = pow5_table[b - 1];
- if (b >= 14) {
- r |= (uint64_t)pow5h_table[b - 14] << 32;
- }
- if (a == 10)
- r <<= b;
- return r;
- }
- #endif
- r = a;
- n_bits = 32 - clz32(b);
- for(i = n_bits - 2; i >= 0; i--) {
- r *= r;
- if ((b >> i) & 1)
- r *= a;
- }
- return r;
- }
- static uint32_t pow_ui_inv(uint32_t *pr_inv, int *pshift, uint32_t a, uint32_t b)
- {
- uint32_t r_inv, r;
- int shift;
- #ifdef USE_POW5_TABLE
- if (a == 5 && b >= 1 && b <= 13) {
- r = pow5_table[b - 1];
- shift = clz32(r);
- r <<= shift;
- r_inv = pow5_inv_table[b - 1];
- } else
- #endif
- {
- r = pow_ui(a, b);
- shift = clz32(r);
- r <<= shift;
- r_inv = udiv1norm_init(r);
- }
- *pshift = shift;
- *pr_inv = r_inv;
- return r;
- }
- enum {
- JS_RNDN, /* round to nearest, ties to even */
- JS_RNDNA, /* round to nearest, ties away from zero */
- JS_RNDZ,
- };
- static int mpb_get_bit(const mpb_t *r, int k)
- {
- int l;
-
- l = (unsigned)k / LIMB_BITS;
- k = k & (LIMB_BITS - 1);
- if (l >= r->len)
- return 0;
- else
- return (r->tab[l] >> k) & 1;
- }
- /* compute round(r / 2^shift). 'shift' can be negative */
- static void mpb_shr_round(mpb_t *r, int shift, int rnd_mode)
- {
- int l, i;
- if (shift == 0)
- return;
- if (shift < 0) {
- shift = -shift;
- l = (unsigned)shift / LIMB_BITS;
- shift = shift & (LIMB_BITS - 1);
- if (shift != 0) {
- r->tab[r->len] = mp_shl(r->tab, r->tab, r->len, shift, 0);
- r->len++;
- mpb_renorm(r);
- }
- if (l > 0) {
- for(i = r->len - 1; i >= 0; i--)
- r->tab[i + l] = r->tab[i];
- for(i = 0; i < l; i++)
- r->tab[i] = 0;
- r->len += l;
- }
- } else {
- limb_t bit1, bit2;
- int k, add_one;
-
- switch(rnd_mode) {
- default:
- case JS_RNDZ:
- add_one = 0;
- break;
- case JS_RNDN:
- case JS_RNDNA:
- bit1 = mpb_get_bit(r, shift - 1);
- if (bit1) {
- if (rnd_mode == JS_RNDNA) {
- bit2 = 1;
- } else {
- /* bit2 = oring of all the bits after bit1 */
- bit2 = 0;
- if (shift >= 2) {
- k = shift - 1;
- l = (unsigned)k / LIMB_BITS;
- k = k & (LIMB_BITS - 1);
- for(i = 0; i < min_int(l, r->len); i++)
- bit2 |= r->tab[i];
- if (l < r->len)
- bit2 |= r->tab[l] & (((limb_t)1 << k) - 1);
- }
- }
- if (bit2) {
- add_one = 1;
- } else {
- /* round to even */
- add_one = mpb_get_bit(r, shift);
- }
- } else {
- add_one = 0;
- }
- break;
- }
- l = (unsigned)shift / LIMB_BITS;
- shift = shift & (LIMB_BITS - 1);
- if (l >= r->len) {
- r->len = 1;
- r->tab[0] = add_one;
- } else {
- if (l > 0) {
- r->len -= l;
- for(i = 0; i < r->len; i++)
- r->tab[i] = r->tab[i + l];
- }
- if (shift != 0) {
- mp_shr(r->tab, r->tab, r->len, shift, 0);
- mpb_renorm(r);
- }
- if (add_one) {
- limb_t a;
- a = mp_add_ui(r->tab, 1, r->len);
- if (a)
- r->tab[r->len++] = a;
- }
- }
- }
- }
- /* return -1, 0 or 1 */
- static int mpb_cmp(const mpb_t *a, const mpb_t *b)
- {
- mp_size_t i;
- if (a->len < b->len)
- return -1;
- else if (a->len > b->len)
- return 1;
- for(i = a->len - 1; i >= 0; i--) {
- if (a->tab[i] != b->tab[i]) {
- if (a->tab[i] < b->tab[i])
- return -1;
- else
- return 1;
- }
- }
- return 0;
- }
- static void mpb_set_u64(mpb_t *r, uint64_t m)
- {
- #if LIMB_BITS == 64
- r->tab[0] = m;
- r->len = 1;
- #else
- r->tab[0] = m;
- r->tab[1] = m >> LIMB_BITS;
- if (r->tab[1] == 0)
- r->len = 1;
- else
- r->len = 2;
- #endif
- }
- static uint64_t mpb_get_u64(mpb_t *r)
- {
- #if LIMB_BITS == 64
- return r->tab[0];
- #else
- if (r->len == 1) {
- return r->tab[0];
- } else {
- return r->tab[0] | ((uint64_t)r->tab[1] << LIMB_BITS);
- }
- #endif
- }
- /* floor_log2() = position of the first non zero bit or -1 if zero. */
- static int mpb_floor_log2(mpb_t *a)
- {
- limb_t v;
- v = a->tab[a->len - 1];
- if (v == 0)
- return -1;
- else
- return a->len * LIMB_BITS - 1 - clz32(v);
- }
- #define MUL_LOG2_RADIX_BASE_LOG2 24
- /* round((1 << MUL_LOG2_RADIX_BASE_LOG2)/log2(i + 2)) */
- static const uint32_t mul_log2_radix_table[JS_RADIX_MAX - 1] = {
- 0x000000, 0xa1849d, 0x000000, 0x6e40d2,
- 0x6308c9, 0x5b3065, 0x000000, 0x50c24e,
- 0x4d104d, 0x4a0027, 0x4768ce, 0x452e54,
- 0x433d00, 0x418677, 0x000000, 0x3ea16b,
- 0x3d645a, 0x3c43c2, 0x3b3b9a, 0x3a4899,
- 0x39680b, 0x3897b3, 0x37d5af, 0x372069,
- 0x367686, 0x35d6df, 0x354072, 0x34b261,
- 0x342bea, 0x33ac62, 0x000000, 0x32bfd9,
- 0x3251dd, 0x31e8d6, 0x318465,
- };
- /* return floor(a / log2(radix)) for -2048 <= a <= 2047 */
- static int mul_log2_radix(int a, int radix)
- {
- int radix_bits, mult;
- if ((radix & (radix - 1)) == 0) {
- /* if the radix is a power of two better to do it exactly */
- radix_bits = 31 - clz32(radix);
- if (a < 0)
- a -= radix_bits - 1;
- return a / radix_bits;
- } else {
- mult = mul_log2_radix_table[radix - 2];
- return ((int64_t)a * mult) >> MUL_LOG2_RADIX_BASE_LOG2;
- }
- }
- #if 0
- static void build_mul_log2_radix_table(void)
- {
- int base, radix, mult, col, base_log2;
- base_log2 = 24;
- base = 1 << base_log2;
- col = 0;
- for(radix = 2; radix <= 36; radix++) {
- if ((radix & (radix - 1)) == 0)
- mult = 0;
- else
- mult = lrint((double)base / log2(radix));
- printf("0x%06x, ", mult);
- if (++col == 4) {
- printf("\n");
- col = 0;
- }
- }
- printf("\n");
- }
- static void mul_log2_radix_test(void)
- {
- int radix, i, ref, r;
-
- for(radix = 2; radix <= 36; radix++) {
- for(i = -2048; i <= 2047; i++) {
- ref = (int)floor((double)i / log2(radix));
- r = mul_log2_radix(i, radix);
- if (ref != r) {
- printf("ERROR: radix=%d i=%d r=%d ref=%d\n",
- radix, i, r, ref);
- exit(1);
- }
- }
- }
- if (0)
- build_mul_log2_radix_table();
- }
- #endif
- static void u32toa_len(char *buf, uint32_t n, size_t len)
- {
- int digit, i;
- for(i = len - 1; i >= 0; i--) {
- digit = n % 10;
- n = n / 10;
- buf[i] = digit + '0';
- }
- }
- /* for power of 2 radixes. len >= 1 */
- static void u64toa_bin_len(char *buf, uint64_t n, unsigned int radix_bits, int len)
- {
- int digit, i;
- unsigned int mask;
- mask = (1 << radix_bits) - 1;
- for(i = len - 1; i >= 0; i--) {
- digit = n & mask;
- n >>= radix_bits;
- if (digit < 10)
- digit += '0';
- else
- digit += 'a' - 10;
- buf[i] = digit;
- }
- }
- /* len >= 1. 2 <= radix <= 36 */
- static void limb_to_a(char *buf, limb_t n, unsigned int radix, int len)
- {
- int digit, i;
- if (radix == 10) {
- /* specific case with constant divisor */
- #if LIMB_BITS == 32
- u32toa_len(buf, n, len);
- #else
- /* XXX: optimize */
- for(i = len - 1; i >= 0; i--) {
- digit = (limb_t)n % 10;
- n = (limb_t)n / 10;
- buf[i] = digit + '0';
- }
- #endif
- } else {
- for(i = len - 1; i >= 0; i--) {
- digit = (limb_t)n % radix;
- n = (limb_t)n / radix;
- if (digit < 10)
- digit += '0';
- else
- digit += 'a' - 10;
- buf[i] = digit;
- }
- }
- }
- size_t u32toa(char *buf, uint32_t n)
- {
- char buf1[10], *q;
- size_t len;
-
- q = buf1 + sizeof(buf1);
- do {
- *--q = n % 10 + '0';
- n /= 10;
- } while (n != 0);
- len = buf1 + sizeof(buf1) - q;
- memcpy(buf, q, len);
- return len;
- }
- size_t i32toa(char *buf, int32_t n)
- {
- if (n >= 0) {
- return u32toa(buf, n);
- } else {
- buf[0] = '-';
- return u32toa(buf + 1, -(uint32_t)n) + 1;
- }
- }
- #ifdef USE_FAST_INT
- size_t u64toa(char *buf, uint64_t n)
- {
- if (n < 0x100000000) {
- return u32toa(buf, n);
- } else {
- uint64_t n1;
- char *q = buf;
- uint32_t n2;
-
- n1 = n / 1000000000;
- n %= 1000000000;
- if (n1 >= 0x100000000) {
- n2 = n1 / 1000000000;
- n1 = n1 % 1000000000;
- /* at most two digits */
- if (n2 >= 10) {
- *q++ = n2 / 10 + '0';
- n2 %= 10;
- }
- *q++ = n2 + '0';
- u32toa_len(q, n1, 9);
- q += 9;
- } else {
- q += u32toa(q, n1);
- }
- u32toa_len(q, n, 9);
- q += 9;
- return q - buf;
- }
- }
- size_t i64toa(char *buf, int64_t n)
- {
- if (n >= 0) {
- return u64toa(buf, n);
- } else {
- buf[0] = '-';
- return u64toa(buf + 1, -(uint64_t)n) + 1;
- }
- }
- /* XXX: only tested for 1 <= n < 2^53 */
- size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix)
- {
- int radix_bits, l;
- if (likely(radix == 10))
- return u64toa(buf, n);
- if ((radix & (radix - 1)) == 0) {
- radix_bits = 31 - clz32(radix);
- if (n == 0)
- l = 1;
- else
- l = (64 - clz64(n) + radix_bits - 1) / radix_bits;
- u64toa_bin_len(buf, n, radix_bits, l);
- return l;
- } else {
- char buf1[41], *q; /* maximum length for radix = 3 */
- size_t len;
- int digit;
- q = buf1 + sizeof(buf1);
- do {
- digit = n % radix;
- n /= radix;
- if (digit < 10)
- digit += '0';
- else
- digit += 'a' - 10;
- *--q = digit;
- } while (n != 0);
- len = buf1 + sizeof(buf1) - q;
- memcpy(buf, q, len);
- return len;
- }
- }
- size_t i64toa_radix(char *buf, int64_t n, unsigned int radix)
- {
- if (n >= 0) {
- return u64toa_radix(buf, n, radix);
- } else {
- buf[0] = '-';
- return u64toa_radix(buf + 1, -(uint64_t)n, radix) + 1;
- }
- }
- #endif /* USE_FAST_INT */
- static const uint8_t digits_per_limb_table[JS_RADIX_MAX - 1] = {
- #if LIMB_BITS == 32
- 32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- #else
- 64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12,
- #endif
- };
- static const uint32_t radix_base_table[JS_RADIX_MAX - 1] = {
- 0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395,
- 0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91,
- 0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021,
- 0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571,
- 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d,
- 0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51,
- 0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899,
- 0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1,
- 0x5c13d840, 0x6d91b519, 0x81bf1000,
- };
- /* XXX: remove the table ? */
- static uint8_t dtoa_max_digits_table[JS_RADIX_MAX - 1] = {
- 54, 35, 28, 24, 22, 20, 19, 18, 17, 17, 16, 16, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12,
- };
- /* we limit the maximum number of significant digits for atod to about
- 128 bits of precision for non power of two bases. The only
- requirement for Javascript is at least 20 digits in base 10. For
- power of two bases, we do an exact rounding in all the cases. */
- static uint8_t atod_max_digits_table[JS_RADIX_MAX - 1] = {
- 64, 80, 32, 55, 49, 45, 21, 40, 38, 37, 35, 34, 33, 32, 16, 31, 30, 30, 29, 29, 28, 28, 27, 27, 27, 26, 26, 26, 26, 25, 12, 25, 25, 24, 24,
- };
- /* if abs(d) >= B^max_exponent, it is an overflow */
- static const int16_t max_exponent[JS_RADIX_MAX - 1] = {
- 1024, 647, 512, 442, 397, 365, 342, 324,
- 309, 297, 286, 277, 269, 263, 256, 251,
- 246, 242, 237, 234, 230, 227, 224, 221,
- 218, 216, 214, 211, 209, 207, 205, 203,
- 202, 200, 199,
- };
- /* if abs(d) <= B^min_exponent, it is an underflow */
- static const int16_t min_exponent[JS_RADIX_MAX - 1] = {
- -1075, -679, -538, -463, -416, -383, -359, -340,
- -324, -311, -300, -291, -283, -276, -269, -263,
- -258, -254, -249, -245, -242, -238, -235, -232,
- -229, -227, -224, -222, -220, -217, -215, -214,
- -212, -210, -208,
- };
- #if 0
- void build_tables(void)
- {
- int r, j, radix, n, col, i;
-
- /* radix_base_table */
- for(radix = 2; radix <= 36; radix++) {
- r = 1;
- for(j = 0; j < digits_per_limb_table[radix - 2]; j++) {
- r *= radix;
- }
- printf(" 0x%08x,", r);
- if ((radix % 4) == 1)
- printf("\n");
- }
- printf("\n");
- /* dtoa_max_digits_table */
- for(radix = 2; radix <= 36; radix++) {
- /* Note: over estimated when the radix is a power of two */
- printf(" %d,", 1 + (int)ceil(53.0 / log2(radix)));
- }
- printf("\n");
- /* atod_max_digits_table */
- for(radix = 2; radix <= 36; radix++) {
- if ((radix & (radix - 1)) == 0) {
- /* 64 bits is more than enough */
- n = (int)floor(64.0 / log2(radix));
- } else {
- n = (int)floor(128.0 / log2(radix));
- }
- printf(" %d,", n);
- }
- printf("\n");
- printf("static const int16_t max_exponent[JS_RADIX_MAX - 1] = {\n");
- col = 0;
- for(radix = 2; radix <= 36; radix++) {
- printf("%5d, ", (int)ceil(1024 / log2(radix)));
- if (++col == 8) {
- col = 0;
- printf("\n");
- }
- }
- printf("\n};\n\n");
- printf("static const int16_t min_exponent[JS_RADIX_MAX - 1] = {\n");
- col = 0;
- for(radix = 2; radix <= 36; radix++) {
- printf("%5d, ", (int)floor(-1075 / log2(radix)));
- if (++col == 8) {
- col = 0;
- printf("\n");
- }
- }
- printf("\n};\n\n");
- printf("static const uint32_t pow5_table[16] = {\n");
- col = 0;
- for(i = 2; i <= 17; i++) {
- r = 1;
- for(j = 0; j < i; j++) {
- r *= 5;
- }
- printf("0x%08x, ", r);
- if (++col == 4) {
- col = 0;
- printf("\n");
- }
- }
- printf("\n};\n\n");
- /* high part */
- printf("static const uint8_t pow5h_table[4] = {\n");
- col = 0;
- for(i = 14; i <= 17; i++) {
- uint64_t r1;
- r1 = 1;
- for(j = 0; j < i; j++) {
- r1 *= 5;
- }
- printf("0x%08x, ", (uint32_t)(r1 >> 32));
- if (++col == 4) {
- col = 0;
- printf("\n");
- }
- }
- printf("\n};\n\n");
- }
- #endif
- /* n_digits >= 1. 0 <= dot_pos <= n_digits. If dot_pos == n_digits,
- the dot is not displayed. 'a' is modified. */
- static int output_digits(char *buf,
- mpb_t *a, int radix, int n_digits1,
- int dot_pos)
- {
- int n_digits, digits_per_limb, radix_bits, n, len;
- n_digits = n_digits1;
- if ((radix & (radix - 1)) == 0) {
- /* radix = 2^radix_bits */
- radix_bits = 31 - clz32(radix);
- } else {
- radix_bits = 0;
- }
- digits_per_limb = digits_per_limb_table[radix - 2];
- if (radix_bits != 0) {
- for(;;) {
- n = min_int(n_digits, digits_per_limb);
- n_digits -= n;
- u64toa_bin_len(buf + n_digits, a->tab[0], radix_bits, n);
- if (n_digits == 0)
- break;
- mpb_shr_round(a, digits_per_limb * radix_bits, JS_RNDZ);
- }
- } else {
- limb_t r;
- while (n_digits != 0) {
- n = min_int(n_digits, digits_per_limb);
- n_digits -= n;
- r = mp_div1(a->tab, a->tab, a->len, radix_base_table[radix - 2], 0);
- mpb_renorm(a);
- limb_to_a(buf + n_digits, r, radix, n);
- }
- }
- /* add the dot */
- len = n_digits1;
- if (dot_pos != n_digits1) {
- memmove(buf + dot_pos + 1, buf + dot_pos, n_digits1 - dot_pos);
- buf[dot_pos] = '.';
- len++;
- }
- return len;
- }
- /* return (a, e_offset) such that a = a * (radix1*2^radix_shift)^f *
- 2^-e_offset. 'f' can be negative. */
- static int mul_pow(mpb_t *a, int radix1, int radix_shift, int f, bool is_int, int e)
- {
- int e_offset, d, n, n0;
- e_offset = -f * radix_shift;
- if (radix1 != 1) {
- d = digits_per_limb_table[radix1 - 2];
- if (f >= 0) {
- limb_t h, b;
-
- b = 0;
- n0 = 0;
- while (f != 0) {
- n = min_int(f, d);
- if (n != n0) {
- b = pow_ui(radix1, n);
- n0 = n;
- }
- h = mp_mul1(a->tab, a->tab, a->len, b, 0);
- if (h != 0) {
- a->tab[a->len++] = h;
- }
- f -= n;
- }
- } else {
- int extra_bits, l, shift;
- limb_t r, rem, b, b_inv;
-
- f = -f;
- l = (f + d - 1) / d; /* high bound for the number of limbs (XXX: make it better) */
- e_offset += l * LIMB_BITS;
- if (!is_int) {
- /* at least 'e' bits are needed in the final result for rounding */
- extra_bits = max_int(e - mpb_floor_log2(a), 0);
- } else {
- /* at least two extra bits are needed in the final result
- for rounding */
- extra_bits = max_int(2 + e - e_offset, 0);
- }
- e_offset += extra_bits;
- mpb_shr_round(a, -(l * LIMB_BITS + extra_bits), JS_RNDZ);
-
- b = 0;
- b_inv = 0;
- shift = 0;
- n0 = 0;
- rem = 0;
- while (f != 0) {
- n = min_int(f, d);
- if (n != n0) {
- b = pow_ui_inv(&b_inv, &shift, radix1, n);
- n0 = n;
- }
- r = mp_div1norm(a->tab, a->tab, a->len, b, 0, b_inv, shift);
- rem |= r;
- mpb_renorm(a);
- f -= n;
- }
- /* if the remainder is non zero, use it for rounding */
- a->tab[0] |= (rem != 0);
- }
- }
- return e_offset;
- }
- /* tmp1 = round(m*2^e*radix^f). 'tmp0' is a temporary storage */
- static void mul_pow_round(mpb_t *tmp1, uint64_t m, int e, int radix1, int radix_shift, int f,
- int rnd_mode)
- {
- int e_offset;
- mpb_set_u64(tmp1, m);
- e_offset = mul_pow(tmp1, radix1, radix_shift, f, true, e);
- mpb_shr_round(tmp1, -e + e_offset, rnd_mode);
- }
- /* return round(a*2^e_offset) rounded as a float64. 'a' is modified */
- static uint64_t round_to_d(int *pe, mpb_t *a, int e_offset, int rnd_mode)
- {
- int e;
- uint64_t m;
- if (a->tab[0] == 0 && a->len == 1) {
- /* zero result */
- m = 0;
- e = 0; /* don't care */
- } else {
- int prec, prec1, e_min;
- e = mpb_floor_log2(a) + 1 - e_offset;
- prec1 = 53;
- e_min = -1021;
- if (e < e_min) {
- /* subnormal result or zero */
- prec = prec1 - (e_min - e);
- } else {
- prec = prec1;
- }
- mpb_shr_round(a, e + e_offset - prec, rnd_mode);
- m = mpb_get_u64(a);
- m <<= (53 - prec);
- /* mantissa overflow due to rounding */
- if (m >= (uint64_t)1 << 53) {
- m >>= 1;
- e++;
- }
- }
- *pe = e;
- return m;
- }
- /* return (m, e) such that m*2^(e-53) = round(a * radix^f) with 2^52
- <= m < 2^53 or m = 0.
- 'a' is modified. */
- static uint64_t mul_pow_round_to_d(int *pe, mpb_t *a,
- int radix1, int radix_shift, int f, int rnd_mode)
- {
- int e_offset;
- e_offset = mul_pow(a, radix1, radix_shift, f, false, 55);
- return round_to_d(pe, a, e_offset, rnd_mode);
- }
- #ifdef JS_DTOA_DUMP_STATS
- static int out_len_count[17];
- void js_dtoa_dump_stats(void)
- {
- int i, sum;
- sum = 0;
- for(i = 0; i < 17; i++)
- sum += out_len_count[i];
- for(i = 0; i < 17; i++) {
- printf("%2d %8d %5.2f%%\n",
- i + 1, out_len_count[i], (double)out_len_count[i] / sum * 100);
- }
- }
- #endif
- /* return a maximum bound of the string length. The bound depends on
- 'd' only if format = JS_DTOA_FORMAT_FRAC or if JS_DTOA_EXP_DISABLED
- is enabled. */
- int js_dtoa_max_len(double d, int radix, int n_digits, int flags)
- {
- int fmt = flags & JS_DTOA_FORMAT_MASK;
- int n, e;
- uint64_t a;
- if (fmt != JS_DTOA_FORMAT_FRAC) {
- if (fmt == JS_DTOA_FORMAT_FREE) {
- n = dtoa_max_digits_table[radix - 2];
- } else {
- n = n_digits;
- }
- if ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_DISABLED) {
- /* no exponential */
- a = float64_as_uint64(d);
- e = (a >> 52) & 0x7ff;
- if (e == 0x7ff) {
- /* NaN, Infinity */
- n = 0;
- } else {
- e -= 1023;
- /* XXX: adjust */
- n += 10 + abs(mul_log2_radix(e - 1, radix));
- }
- } else {
- /* extra: sign, 1 dot and exponent "e-1000" */
- n += 1 + 1 + 6;
- }
- } else {
- a = float64_as_uint64(d);
- e = (a >> 52) & 0x7ff;
- if (e == 0x7ff) {
- /* NaN, Infinity */
- n = 0;
- } else {
- /* high bound for the integer part */
- e -= 1023;
- /* x < 2^(e + 1) */
- if (e < 0) {
- n = 1;
- } else {
- n = 2 + mul_log2_radix(e - 1, radix);
- }
- /* sign, extra digit, 1 dot */
- n += 1 + 1 + 1 + n_digits;
- }
- }
- return max_int(n, 9); /* also include NaN and [-]Infinity */
- }
- #if defined(__SANITIZE_ADDRESS__) && 0
- static void *dtoa_malloc(uint64_t **pptr, size_t size)
- {
- return malloc(size);
- }
- static void dtoa_free(void *ptr)
- {
- free(ptr);
- }
- #else
- static void *dtoa_malloc(uint64_t **pptr, size_t size)
- {
- void *ret;
- ret = *pptr;
- *pptr += (size + 7) / 8;
- return ret;
- }
- static void dtoa_free(void *ptr)
- {
- }
- #endif
- /* return the length */
- int js_dtoa(char *buf, double d, int radix, int n_digits, int flags,
- JSDTOATempMem *tmp_mem)
- {
- uint64_t a, m, *mptr = tmp_mem->mem;
- int e, sgn, l, E, P, i, E_max, radix1, radix_shift;
- char *q;
- mpb_t *tmp1, *mant_max;
- int fmt = flags & JS_DTOA_FORMAT_MASK;
- tmp1 = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * DBIGNUM_LEN_MAX);
- mant_max = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * MANT_LEN_MAX);
- assert((mptr - tmp_mem->mem) <= sizeof(JSDTOATempMem) / sizeof(mptr[0]));
- radix_shift = ctz32(radix);
- radix1 = radix >> radix_shift;
- a = float64_as_uint64(d);
- sgn = a >> 63;
- e = (a >> 52) & 0x7ff;
- m = a & (((uint64_t)1 << 52) - 1);
- q = buf;
- if (e == 0x7ff) {
- if (m == 0) {
- if (sgn)
- *q++ = '-';
- memcpy(q, "Infinity", 8);
- q += 8;
- } else {
- memcpy(q, "NaN", 3);
- q += 3;
- }
- goto done;
- } else if (e == 0) {
- if (m == 0) {
- tmp1->len = 1;
- tmp1->tab[0] = 0;
- E = 1;
- if (fmt == JS_DTOA_FORMAT_FREE)
- P = 1;
- else if (fmt == JS_DTOA_FORMAT_FRAC)
- P = n_digits + 1;
- else
- P = n_digits;
- /* "-0" is displayed as "0" if JS_DTOA_MINUS_ZERO is not present */
- if (sgn && (flags & JS_DTOA_MINUS_ZERO))
- *q++ = '-';
- goto output;
- }
- /* denormal number: convert to a normal number */
- l = clz64(m) - 11;
- e -= l - 1;
- m <<= l;
- } else {
- m |= (uint64_t)1 << 52;
- }
- if (sgn)
- *q++ = '-';
- /* remove the bias */
- e -= 1022;
- /* d = 2^(e-53)*m */
- // printf("m=0x%016" PRIx64 " e=%d\n", m, e);
- #ifdef USE_FAST_INT
- if (fmt == JS_DTOA_FORMAT_FREE &&
- e >= 1 && e <= 53 &&
- (m & (((uint64_t)1 << (53 - e)) - 1)) == 0 &&
- (flags & JS_DTOA_EXP_MASK) != JS_DTOA_EXP_ENABLED) {
- m >>= 53 - e;
- /* 'm' is never zero */
- q += u64toa_radix(q, m, radix);
- goto done;
- }
- #endif
-
- /* this choice of E implies F=round(x*B^(P-E) is such as:
- B^(P-1) <= F < 2.B^P. */
- E = 1 + mul_log2_radix(e - 1, radix);
-
- if (fmt == JS_DTOA_FORMAT_FREE) {
- int P_max, E0, e1, E_found, P_found;
- uint64_t m1, mant_found, mant, mant_max1;
- /* P_max is guarranteed to work by construction */
- P_max = dtoa_max_digits_table[radix - 2];
- E0 = E;
- E_found = 0;
- P_found = 0;
- mant_found = 0;
- /* find the minimum number of digits by successive tries */
- P = P_max; /* P_max is guarateed to work */
- for(;;) {
- /* mant_max always fits on 64 bits */
- mant_max1 = pow_ui(radix, P);
- /* compute the mantissa in base B */
- E = E0;
- for(;;) {
- /* XXX: add inexact flag */
- mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, P - E, JS_RNDN);
- mant = mpb_get_u64(tmp1);
- if (mant < mant_max1)
- break;
- E++; /* at most one iteration is possible */
- }
- /* remove useless trailing zero digits */
- while ((mant % radix) == 0) {
- mant /= radix;
- P--;
- }
- /* garanteed to work for P = P_max */
- if (P_found == 0)
- goto prec_found;
- /* convert back to base 2 */
- mpb_set_u64(tmp1, mant);
- m1 = mul_pow_round_to_d(&e1, tmp1, radix1, radix_shift, E - P, JS_RNDN);
- // printf("P=%2d: m=0x%016" PRIx64 " e=%d m1=0x%016" PRIx64 " e1=%d\n", P, m, e, m1, e1);
- /* Note: (m, e) is never zero here, so the exponent for m1
- = 0 does not matter */
- if (m1 == m && e1 == e) {
- prec_found:
- P_found = P;
- E_found = E;
- mant_found = mant;
- if (P == 1)
- break;
- P--; /* try lower exponent */
- } else {
- break;
- }
- }
- P = P_found;
- E = E_found;
- mpb_set_u64(tmp1, mant_found);
- #ifdef JS_DTOA_DUMP_STATS
- if (radix == 10) {
- out_len_count[P - 1]++;
- }
- #endif
- } else if (fmt == JS_DTOA_FORMAT_FRAC) {
- int len;
- assert(n_digits >= 0 && n_digits <= JS_DTOA_MAX_DIGITS);
- /* P = max_int(E, 1) + n_digits; */
- /* frac is rounded using RNDNA */
- mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, n_digits, JS_RNDNA);
- /* we add one extra digit on the left and remove it if needed
- to avoid testing if the result is < radix^P */
- len = output_digits(q, tmp1, radix, max_int(E + 1, 1) + n_digits,
- max_int(E + 1, 1));
- if (q[0] == '0' && len >= 2 && q[1] != '.') {
- len--;
- memmove(q, q + 1, len);
- }
- q += len;
- goto done;
- } else {
- int pow_shift;
- assert(n_digits >= 1 && n_digits <= JS_DTOA_MAX_DIGITS);
- P = n_digits;
- /* mant_max = radix^P */
- mant_max->len = 1;
- mant_max->tab[0] = 1;
- pow_shift = mul_pow(mant_max, radix1, radix_shift, P, false, 0);
- mpb_shr_round(mant_max, pow_shift, JS_RNDZ);
-
- for(;;) {
- /* fixed and frac are rounded using RNDNA */
- mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, P - E, JS_RNDNA);
- if (mpb_cmp(tmp1, mant_max) < 0)
- break;
- E++; /* at most one iteration is possible */
- }
- }
- output:
- if (fmt == JS_DTOA_FORMAT_FIXED)
- E_max = n_digits;
- else
- E_max = dtoa_max_digits_table[radix - 2] + 4;
- if ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_ENABLED ||
- ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_AUTO && (E <= -6 || E > E_max))) {
- q += output_digits(q, tmp1, radix, P, 1);
- E--;
- if (radix == 10) {
- *q++ = 'e';
- } else if (radix1 == 1 && radix_shift <= 4) {
- E *= radix_shift;
- *q++ = 'p';
- } else {
- *q++ = '@';
- }
- if (E < 0) {
- *q++ = '-';
- E = -E;
- } else {
- *q++ = '+';
- }
- q += u32toa(q, E);
- } else if (E <= 0) {
- *q++ = '0';
- *q++ = '.';
- for(i = 0; i < -E; i++)
- *q++ = '0';
- q += output_digits(q, tmp1, radix, P, P);
- } else {
- q += output_digits(q, tmp1, radix, P, min_int(P, E));
- for(i = 0; i < E - P; i++)
- *q++ = '0';
- }
- done:
- *q = '\0';
- dtoa_free(mant_max);
- dtoa_free(tmp1);
- return q - buf;
- }
- static inline int to_digit(int c)
- {
- if (c >= '0' && c <= '9')
- return c - '0';
- else if (c >= 'A' && c <= 'Z')
- return c - 'A' + 10;
- else if (c >= 'a' && c <= 'z')
- return c - 'a' + 10;
- else
- return 36;
- }
- /* r = r * radix_base + a. radix_base = 0 means radix_base = 2^32 */
- static void mpb_mul1_base(mpb_t *r, limb_t radix_base, limb_t a)
- {
- int i;
- if (r->tab[0] == 0 && r->len == 1) {
- r->tab[0] = a;
- } else {
- if (radix_base == 0) {
- for(i = r->len; i >= 0; i--) {
- r->tab[i + 1] = r->tab[i];
- }
- r->tab[0] = a;
- } else {
- r->tab[r->len] = mp_mul1(r->tab, r->tab, r->len,
- radix_base, a);
- }
- r->len++;
- mpb_renorm(r);
- }
- }
- /* XXX: add fast path for small integers */
- double js_atod(const char *str, const char **pnext, int radix, int flags,
- JSATODTempMem *tmp_mem)
- {
- uint64_t *mptr = tmp_mem->mem;
- const char *p, *p_start;
- limb_t cur_limb, radix_base, extra_digits;
- int is_neg, digit_count, limb_digit_count, digits_per_limb, sep, radix1, radix_shift;
- int radix_bits, expn, e, max_digits, expn_offset, dot_pos, sig_pos, pos;
- mpb_t *tmp0;
- double dval;
- bool is_bin_exp, is_zero, expn_overflow;
- uint64_t m, a;
- tmp0 = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * DBIGNUM_LEN_MAX);
- assert((mptr - tmp_mem->mem) <= sizeof(JSATODTempMem) / sizeof(mptr[0]));
- /* optional separator between digits */
- sep = (flags & JS_ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
- p = str;
- is_neg = 0;
- if (p[0] == '+') {
- p++;
- p_start = p;
- } else if (p[0] == '-') {
- is_neg = 1;
- p++;
- p_start = p;
- } else {
- p_start = p;
- }
-
- if (p[0] == '0') {
- if ((p[1] == 'x' || p[1] == 'X') &&
- (radix == 0 || radix == 16)) {
- p += 2;
- radix = 16;
- } else if ((p[1] == 'o' || p[1] == 'O') &&
- radix == 0 && (flags & JS_ATOD_ACCEPT_BIN_OCT)) {
- p += 2;
- radix = 8;
- } else if ((p[1] == 'b' || p[1] == 'B') &&
- radix == 0 && (flags & JS_ATOD_ACCEPT_BIN_OCT)) {
- p += 2;
- radix = 2;
- } else if ((p[1] >= '0' && p[1] <= '9') &&
- radix == 0 && (flags & JS_ATOD_ACCEPT_LEGACY_OCTAL)) {
- int i;
- sep = 256;
- for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)
- continue;
- if (p[i] == '8' || p[i] == '9')
- goto no_prefix;
- p += 1;
- radix = 8;
- } else {
- goto no_prefix;
- }
- /* there must be a digit after the prefix */
- if (to_digit((uint8_t)*p) >= radix)
- goto fail;
- no_prefix: ;
- } else {
- if (!(flags & JS_ATOD_INT_ONLY) && js__strstart(p, "Infinity", &p))
- goto overflow;
- }
- if (radix == 0)
- radix = 10;
- cur_limb = 0;
- expn_offset = 0;
- digit_count = 0;
- limb_digit_count = 0;
- max_digits = atod_max_digits_table[radix - 2];
- digits_per_limb = digits_per_limb_table[radix - 2];
- radix_base = radix_base_table[radix - 2];
- radix_shift = ctz32(radix);
- radix1 = radix >> radix_shift;
- if (radix1 == 1) {
- /* radix = 2^radix_bits */
- radix_bits = radix_shift;
- } else {
- radix_bits = 0;
- }
- tmp0->len = 1;
- tmp0->tab[0] = 0;
- extra_digits = 0;
- pos = 0;
- dot_pos = -1;
- /* skip leading zeros */
- for(;;) {
- if (*p == '.' && (p > p_start || to_digit(p[1]) < radix) &&
- !(flags & JS_ATOD_INT_ONLY)) {
- if (*p == sep)
- goto fail;
- if (dot_pos >= 0)
- break;
- dot_pos = pos;
- p++;
- }
- if (*p == sep && p > p_start && p[1] == '0')
- p++;
- if (*p != '0')
- break;
- p++;
- pos++;
- }
-
- sig_pos = pos;
- for(;;) {
- limb_t c;
- if (*p == '.' && (p > p_start || to_digit(p[1]) < radix) &&
- !(flags & JS_ATOD_INT_ONLY)) {
- if (*p == sep)
- goto fail;
- if (dot_pos >= 0)
- break;
- dot_pos = pos;
- p++;
- }
- if (*p == sep && p > p_start && to_digit(p[1]) < radix)
- p++;
- c = to_digit(*p);
- if (c >= radix)
- break;
- p++;
- pos++;
- if (digit_count < max_digits) {
- /* XXX: could be faster when radix_bits != 0 */
- cur_limb = cur_limb * radix + c;
- limb_digit_count++;
- if (limb_digit_count == digits_per_limb) {
- mpb_mul1_base(tmp0, radix_base, cur_limb);
- cur_limb = 0;
- limb_digit_count = 0;
- }
- digit_count++;
- } else {
- extra_digits |= c;
- }
- }
- if (limb_digit_count != 0) {
- mpb_mul1_base(tmp0, pow_ui(radix, limb_digit_count), cur_limb);
- }
- if (digit_count == 0) {
- is_zero = true;
- expn_offset = 0;
- } else {
- is_zero = false;
- if (dot_pos < 0)
- dot_pos = pos;
- expn_offset = sig_pos + digit_count - dot_pos;
- }
-
- /* Use the extra digits for rounding if the base is a power of
- two. Otherwise they are just truncated. */
- if (radix_bits != 0 && extra_digits != 0) {
- tmp0->tab[0] |= 1;
- }
-
- /* parse the exponent, if any */
- expn = 0;
- expn_overflow = false;
- is_bin_exp = false;
- if (!(flags & JS_ATOD_INT_ONLY) &&
- ((radix == 10 && (*p == 'e' || *p == 'E')) ||
- (radix != 10 && (*p == '@' ||
- (radix_bits >= 1 && radix_bits <= 4 && (*p == 'p' || *p == 'P'))))) &&
- p > p_start) {
- bool exp_is_neg;
- int c;
- is_bin_exp = (*p == 'p' || *p == 'P');
- p++;
- exp_is_neg = false;
- if (*p == '+') {
- p++;
- } else if (*p == '-') {
- exp_is_neg = true;
- p++;
- }
- c = to_digit(*p);
- if (c >= 10)
- goto fail; /* XXX: could stop before the exponent part */
- expn = c;
- p++;
- for(;;) {
- if (*p == sep && to_digit(p[1]) < 10)
- p++;
- c = to_digit(*p);
- if (c >= 10)
- break;
- if (!expn_overflow) {
- if (unlikely(expn > ((INT32_MAX - 2 - 9) / 10))) {
- expn_overflow = true;
- } else {
- expn = expn * 10 + c;
- }
- }
- p++;
- }
- if (exp_is_neg)
- expn = -expn;
- /* if zero result, the exponent can be arbitrarily large */
- if (!is_zero && expn_overflow) {
- if (exp_is_neg)
- a = 0;
- else
- a = (uint64_t)0x7ff << 52; /* infinity */
- goto done;
- }
- }
- if (p == p_start)
- goto fail;
- if (is_zero) {
- a = 0;
- } else {
- int expn1;
- if (radix_bits != 0) {
- if (!is_bin_exp)
- expn *= radix_bits;
- expn -= expn_offset * radix_bits;
- expn1 = expn + digit_count * radix_bits;
- if (expn1 >= 1024 + radix_bits)
- goto overflow;
- else if (expn1 <= -1075)
- goto underflow;
- m = round_to_d(&e, tmp0, -expn, JS_RNDN);
- } else {
- expn -= expn_offset;
- expn1 = expn + digit_count;
- if (expn1 >= max_exponent[radix - 2] + 1)
- goto overflow;
- else if (expn1 <= min_exponent[radix - 2])
- goto underflow;
- m = mul_pow_round_to_d(&e, tmp0, radix1, radix_shift, expn, JS_RNDN);
- }
- if (m == 0) {
- underflow:
- a = 0;
- } else if (e > 1024) {
- overflow:
- /* overflow */
- a = (uint64_t)0x7ff << 52;
- } else if (e < -1073) {
- /* underflow */
- /* XXX: check rounding */
- a = 0;
- } else if (e < -1021) {
- /* subnormal */
- a = m >> (-e - 1021);
- } else {
- a = ((uint64_t)(e + 1022) << 52) | (m & (((uint64_t)1 << 52) - 1));
- }
- }
- done:
- a |= (uint64_t)is_neg << 63;
- dval = uint64_as_float64(a);
- done1:
- if (pnext)
- *pnext = p;
- dtoa_free(tmp0);
- return dval;
- fail:
- dval = NAN;
- goto done1;
- }
- /*
- * Regular Expression Engine
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <inttypes.h>
- #include <string.h>
- #include <assert.h>
- /*
- TODO:
- - Add a lock step execution mode (=linear time execution guaranteed)
- when the regular expression is "simple" i.e. no backreference nor
- complicated lookahead. The opcodes are designed for this execution
- model.
- */
- #if defined(TEST)
- #define DUMP_REOP
- #endif
- typedef enum {
- #define DEF(id, size) REOP_ ## id,
- /*
- * Regular Expression Engine
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifdef DEF
- DEF(invalid, 1) /* never used */
- DEF(char8, 2) /* 7 bits in fact */
- DEF(char16, 3)
- DEF(char32, 5)
- DEF(dot, 1)
- DEF(any, 1) /* same as dot but match any character including line terminator */
- DEF(line_start, 1)
- DEF(line_end, 1)
- DEF(goto, 5)
- DEF(split_goto_first, 5)
- DEF(split_next_first, 5)
- DEF(match, 1)
- DEF(save_start, 2) /* save start position */
- DEF(save_end, 2) /* save end position, must come after saved_start */
- DEF(save_reset, 3) /* reset save positions */
- DEF(loop, 5) /* decrement the top the stack and goto if != 0 */
- DEF(push_i32, 5) /* push integer on the stack */
- DEF(drop, 1)
- DEF(word_boundary, 1)
- DEF(not_word_boundary, 1)
- DEF(back_reference, 2)
- DEF(backward_back_reference, 2) /* must come after back_reference */
- DEF(range, 3) /* variable length */
- DEF(range32, 3) /* variable length */
- DEF(lookahead, 5)
- DEF(negative_lookahead, 5)
- DEF(push_char_pos, 1) /* push the character position on the stack */
- DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */
- DEF(prev, 1) /* go to the previous char */
- DEF(simple_greedy_quant, 17)
- #endif /* DEF */
- #undef DEF
- REOP_COUNT,
- } REOPCodeEnum;
- #define CAPTURE_COUNT_MAX 255
- #define STACK_SIZE_MAX 255
- /* must be large enough to have a negligible runtime cost and small
- enough to call the interrupt callback often. */
- #define INTERRUPT_COUNTER_INIT 10000
- /* unicode code points */
- #define CP_LS 0x2028
- #define CP_PS 0x2029
- #define TMP_BUF_SIZE 128
- // invariant: is_unicode ^ unicode_sets (or neither, but not both)
- typedef struct {
- DynBuf byte_code;
- const uint8_t *buf_ptr;
- const uint8_t *buf_end;
- const uint8_t *buf_start;
- int re_flags;
- bool is_unicode;
- bool unicode_sets;
- bool ignore_case;
- bool dotall;
- int capture_count;
- int total_capture_count; /* -1 = not computed yet */
- int has_named_captures; /* -1 = don't know, 0 = no, 1 = yes */
- void *opaque;
- DynBuf group_names;
- union {
- char error_msg[TMP_BUF_SIZE];
- char tmp_buf[TMP_BUF_SIZE];
- } u;
- } REParseState;
- typedef struct {
- #ifdef DUMP_REOP
- const char *name;
- #endif
- uint8_t size;
- } REOpCode;
- static const REOpCode reopcode_info[REOP_COUNT] = {
- #ifdef DUMP_REOP
- #define DEF(id, size) { #id, size },
- #else
- #define DEF(id, size) { size },
- #endif
- /*
- * Regular Expression Engine
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifdef DEF
- DEF(invalid, 1) /* never used */
- DEF(char8, 2) /* 7 bits in fact */
- DEF(char16, 3)
- DEF(char32, 5)
- DEF(dot, 1)
- DEF(any, 1) /* same as dot but match any character including line terminator */
- DEF(line_start, 1)
- DEF(line_end, 1)
- DEF(goto, 5)
- DEF(split_goto_first, 5)
- DEF(split_next_first, 5)
- DEF(match, 1)
- DEF(save_start, 2) /* save start position */
- DEF(save_end, 2) /* save end position, must come after saved_start */
- DEF(save_reset, 3) /* reset save positions */
- DEF(loop, 5) /* decrement the top the stack and goto if != 0 */
- DEF(push_i32, 5) /* push integer on the stack */
- DEF(drop, 1)
- DEF(word_boundary, 1)
- DEF(not_word_boundary, 1)
- DEF(back_reference, 2)
- DEF(backward_back_reference, 2) /* must come after back_reference */
- DEF(range, 3) /* variable length */
- DEF(range32, 3) /* variable length */
- DEF(lookahead, 5)
- DEF(negative_lookahead, 5)
- DEF(push_char_pos, 1) /* push the character position on the stack */
- DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */
- DEF(prev, 1) /* go to the previous char */
- DEF(simple_greedy_quant, 17)
- #endif /* DEF */
- #undef DEF
- };
- #define RE_HEADER_FLAGS 0
- #define RE_HEADER_CAPTURE_COUNT 2
- #define RE_HEADER_STACK_SIZE 3
- #define RE_HEADER_BYTECODE_LEN 4
- #define RE_HEADER_LEN 8
- static inline int lre_is_digit(int c) {
- return c >= '0' && c <= '9';
- }
- /* insert 'len' bytes at position 'pos'. Return < 0 if error. */
- static int dbuf_insert(DynBuf *s, int pos, int len)
- {
- if (dbuf_realloc(s, s->size + len))
- return -1;
- memmove(s->buf + pos + len, s->buf + pos, s->size - pos);
- s->size += len;
- return 0;
- }
- static const uint16_t char_range_d[] = {
- 1,
- 0x0030, 0x0039 + 1,
- };
- /* code point ranges for Zs,Zl or Zp property */
- static const uint16_t char_range_s[] = {
- 10,
- 0x0009, 0x000D + 1,
- 0x0020, 0x0020 + 1,
- 0x00A0, 0x00A0 + 1,
- 0x1680, 0x1680 + 1,
- 0x2000, 0x200A + 1,
- /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */
- /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */
- 0x2028, 0x2029 + 1,
- 0x202F, 0x202F + 1,
- 0x205F, 0x205F + 1,
- 0x3000, 0x3000 + 1,
- /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */
- 0xFEFF, 0xFEFF + 1,
- };
- bool lre_is_space(int c)
- {
- int i, n, low, high;
- n = (countof(char_range_s) - 1) / 2;
- for(i = 0; i < n; i++) {
- low = char_range_s[2 * i + 1];
- if (c < low)
- return false;
- high = char_range_s[2 * i + 2];
- if (c < high)
- return true;
- }
- return false;
- }
- uint32_t const lre_id_start_table_ascii[4] = {
- /* $ A-Z _ a-z */
- 0x00000000, 0x00000010, 0x87FFFFFE, 0x07FFFFFE
- };
- uint32_t const lre_id_continue_table_ascii[4] = {
- /* $ 0-9 A-Z _ a-z */
- 0x00000000, 0x03FF0010, 0x87FFFFFE, 0x07FFFFFE
- };
- static const uint16_t char_range_w[] = {
- 4,
- 0x0030, 0x0039 + 1,
- 0x0041, 0x005A + 1,
- 0x005F, 0x005F + 1,
- 0x0061, 0x007A + 1,
- };
- #define CLASS_RANGE_BASE 0x40000000
- typedef enum {
- CHAR_RANGE_d,
- CHAR_RANGE_D,
- CHAR_RANGE_s,
- CHAR_RANGE_S,
- CHAR_RANGE_w,
- CHAR_RANGE_W,
- } CharRangeEnum;
- static const uint16_t *char_range_table[] = {
- char_range_d,
- char_range_s,
- char_range_w,
- };
- static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c)
- {
- bool invert;
- const uint16_t *c_pt;
- int len, i;
- invert = c & 1;
- c_pt = char_range_table[c >> 1];
- len = *c_pt++;
- cr_init(cr, s->opaque, lre_realloc);
- for(i = 0; i < len * 2; i++) {
- if (cr_add_point(cr, c_pt[i]))
- goto fail;
- }
- if (invert) {
- if (cr_invert(cr))
- goto fail;
- }
- return 0;
- fail:
- cr_free(cr);
- return -1;
- }
- #ifdef DUMP_REOP
- static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
- int buf_len)
- {
- int pos, len, opcode, bc_len, re_flags, i;
- uint32_t val;
- assert(buf_len >= RE_HEADER_LEN);
- re_flags = lre_get_flags(buf);
- bc_len = get_u32(buf + RE_HEADER_BYTECODE_LEN);
- assert(bc_len + RE_HEADER_LEN <= buf_len);
- printf("flags: 0x%x capture_count=%d stack_size=%d\n",
- re_flags, buf[RE_HEADER_CAPTURE_COUNT], buf[RE_HEADER_STACK_SIZE]);
- if (re_flags & LRE_FLAG_NAMED_GROUPS) {
- const char *p;
- p = (char *)buf + RE_HEADER_LEN + bc_len;
- printf("named groups: ");
- for(i = 1; i < buf[RE_HEADER_CAPTURE_COUNT]; i++) {
- if (i != 1)
- printf(",");
- printf("<%s>", p);
- p += strlen(p) + 1;
- }
- printf("\n");
- assert(p == (char *)(buf + buf_len));
- }
- printf("bytecode_len=%d\n", bc_len);
- buf += RE_HEADER_LEN;
- pos = 0;
- while (pos < bc_len) {
- printf("%5u: ", pos);
- opcode = buf[pos];
- len = reopcode_info[opcode].size;
- if (opcode >= REOP_COUNT) {
- printf(" invalid opcode=0x%02x\n", opcode);
- break;
- }
- if ((pos + len) > bc_len) {
- printf(" buffer overflow (opcode=0x%02x)\n", opcode);
- break;
- }
- printf("%s", reopcode_info[opcode].name);
- switch(opcode) {
- case REOP_char8:
- val = get_u8(buf + pos + 1);
- goto printchar;
- case REOP_char16:
- val = get_u16(buf + pos + 1);
- goto printchar;
- case REOP_char32:
- val = get_u32(buf + pos + 1);
- printchar:
- if (val >= ' ' && val <= 126)
- printf(" '%c'", val);
- else
- printf(" 0x%08x", val);
- break;
- case REOP_goto:
- case REOP_split_goto_first:
- case REOP_split_next_first:
- case REOP_loop:
- case REOP_lookahead:
- case REOP_negative_lookahead:
- val = get_u32(buf + pos + 1);
- val += (pos + 5);
- printf(" %u", val);
- break;
- case REOP_simple_greedy_quant:
- printf(" %u %u %u %u",
- get_u32(buf + pos + 1) + (pos + 17),
- get_u32(buf + pos + 1 + 4),
- get_u32(buf + pos + 1 + 8),
- get_u32(buf + pos + 1 + 12));
- break;
- case REOP_save_start:
- case REOP_save_end:
- case REOP_back_reference:
- case REOP_backward_back_reference:
- printf(" %u", buf[pos + 1]);
- break;
- case REOP_save_reset:
- printf(" %u %u", buf[pos + 1], buf[pos + 2]);
- break;
- case REOP_push_i32:
- val = get_u32(buf + pos + 1);
- printf(" %d", val);
- break;
- case REOP_range:
- {
- int n, i;
- n = get_u16(buf + pos + 1);
- len += n * 4;
- for(i = 0; i < n * 2; i++) {
- val = get_u16(buf + pos + 3 + i * 2);
- printf(" 0x%04x", val);
- }
- }
- break;
- case REOP_range32:
- {
- int n, i;
- n = get_u16(buf + pos + 1);
- len += n * 8;
- for(i = 0; i < n * 2; i++) {
- val = get_u32(buf + pos + 3 + i * 4);
- printf(" 0x%08x", val);
- }
- }
- break;
- default:
- break;
- }
- printf("\n");
- pos += len;
- }
- }
- #endif
- static void re_emit_op(REParseState *s, int op)
- {
- dbuf_putc(&s->byte_code, op);
- }
- /* return the offset of the u32 value */
- static int re_emit_op_u32(REParseState *s, int op, uint32_t val)
- {
- int pos;
- dbuf_putc(&s->byte_code, op);
- pos = s->byte_code.size;
- dbuf_put_u32(&s->byte_code, val);
- return pos;
- }
- static int re_emit_goto(REParseState *s, int op, uint32_t val)
- {
- int pos;
- dbuf_putc(&s->byte_code, op);
- pos = s->byte_code.size;
- dbuf_put_u32(&s->byte_code, val - (pos + 4));
- return pos;
- }
- static void re_emit_op_u8(REParseState *s, int op, uint32_t val)
- {
- dbuf_putc(&s->byte_code, op);
- dbuf_putc(&s->byte_code, val);
- }
- static void re_emit_op_u16(REParseState *s, int op, uint32_t val)
- {
- dbuf_putc(&s->byte_code, op);
- dbuf_put_u16(&s->byte_code, val);
- }
- static int JS_PRINTF_FORMAT_ATTR(2, 3) re_parse_error(REParseState *s, const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(s->u.error_msg, sizeof(s->u.error_msg), fmt, ap);
- va_end(ap);
- return -1;
- }
- static int re_parse_out_of_memory(REParseState *s)
- {
- return re_parse_error(s, "out of memory");
- }
- /* If allow_overflow is false, return -1 in case of
- overflow. Otherwise return INT32_MAX. */
- static int parse_digits(const uint8_t **pp, bool allow_overflow)
- {
- const uint8_t *p;
- uint64_t v;
- int c;
- p = *pp;
- v = 0;
- for(;;) {
- c = *p;
- if (c < '0' || c > '9')
- break;
- v = v * 10 + c - '0';
- if (v >= INT32_MAX) {
- if (allow_overflow)
- v = INT32_MAX;
- else
- return -1;
- }
- p++;
- }
- *pp = p;
- return v;
- }
- static int re_parse_expect(REParseState *s, const uint8_t **pp, int c)
- {
- const uint8_t *p;
- p = *pp;
- if (*p != c)
- return re_parse_error(s, "expecting '%c'", c);
- p++;
- *pp = p;
- return 0;
- }
- /* Parse an escape sequence, *pp points after the '\':
- allow_utf16 value:
- 0 : no UTF-16 escapes allowed
- 1 : UTF-16 escapes allowed
- 2 : UTF-16 escapes allowed and escapes of surrogate pairs are
- converted to a unicode character (unicode regexp case).
- Return the unicode char and update *pp if recognized,
- return -1 if malformed escape,
- return -2 otherwise. */
- int lre_parse_escape(const uint8_t **pp, int allow_utf16)
- {
- const uint8_t *p;
- uint32_t c;
- p = *pp;
- c = *p++;
- switch(c) {
- case 'b':
- c = '\b';
- break;
- case 'f':
- c = '\f';
- break;
- case 'n':
- c = '\n';
- break;
- case 'r':
- c = '\r';
- break;
- case 't':
- c = '\t';
- break;
- case 'v':
- c = '\v';
- break;
- case 'x':
- case 'u':
- {
- int h, n, i;
- uint32_t c1;
- if (*p == '{' && allow_utf16) {
- p++;
- c = 0;
- for(;;) {
- h = from_hex(*p++);
- if (h < 0)
- return -1;
- c = (c << 4) | h;
- if (c > 0x10FFFF)
- return -1;
- if (*p == '}')
- break;
- }
- p++;
- } else {
- if (c == 'x') {
- n = 2;
- } else {
- n = 4;
- }
- c = 0;
- for(i = 0; i < n; i++) {
- h = from_hex(*p++);
- if (h < 0) {
- return -1;
- }
- c = (c << 4) | h;
- }
- if (is_hi_surrogate(c) &&
- allow_utf16 == 2 && p[0] == '\\' && p[1] == 'u') {
- /* convert an escaped surrogate pair into a
- unicode char */
- c1 = 0;
- for(i = 0; i < 4; i++) {
- h = from_hex(p[2 + i]);
- if (h < 0)
- break;
- c1 = (c1 << 4) | h;
- }
- if (i == 4 && is_lo_surrogate(c1)) {
- p += 6;
- c = from_surrogate(c, c1);
- }
- }
- }
- }
- break;
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- c -= '0';
- if (allow_utf16 == 2) {
- /* only accept \0 not followed by digit */
- if (c != 0 || lre_is_digit(*p))
- return -1;
- } else {
- /* parse a legacy octal sequence */
- uint32_t v;
- v = *p - '0';
- if (v > 7)
- break;
- c = (c << 3) | v;
- p++;
- if (c >= 32)
- break;
- v = *p - '0';
- if (v > 7)
- break;
- c = (c << 3) | v;
- p++;
- }
- break;
- default:
- return -2;
- }
- *pp = p;
- return c;
- }
- /* XXX: we use the same chars for name and value */
- static bool is_unicode_char(int c)
- {
- return ((c >= '0' && c <= '9') ||
- (c >= 'A' && c <= 'Z') ||
- (c >= 'a' && c <= 'z') ||
- (c == '_'));
- }
- static int parse_unicode_property(REParseState *s, CharRange *cr,
- const uint8_t **pp, bool is_inv)
- {
- const uint8_t *p;
- char name[64], value[64];
- char *q;
- bool script_ext;
- int ret;
- p = *pp;
- if (*p != '{')
- return re_parse_error(s, "expecting '{' after \\p");
- p++;
- q = name;
- while (is_unicode_char(*p)) {
- if ((q - name) >= sizeof(name) - 1)
- goto unknown_property_name;
- *q++ = *p++;
- }
- *q = '\0';
- q = value;
- if (*p == '=') {
- p++;
- while (is_unicode_char(*p)) {
- if ((q - value) >= sizeof(value) - 1)
- return re_parse_error(s, "unknown unicode property value");
- *q++ = *p++;
- }
- }
- *q = '\0';
- if (*p != '}')
- return re_parse_error(s, "expecting '}'");
- p++;
- // printf("name=%s value=%s\n", name, value);
- if (!strcmp(name, "Script") || !strcmp(name, "sc")) {
- script_ext = false;
- goto do_script;
- } else if (!strcmp(name, "Script_Extensions") || !strcmp(name, "scx")) {
- script_ext = true;
- do_script:
- cr_init(cr, s->opaque, lre_realloc);
- ret = unicode_script(cr, value, script_ext);
- if (ret) {
- cr_free(cr);
- if (ret == -2)
- return re_parse_error(s, "unknown unicode script");
- else
- goto out_of_memory;
- }
- } else if (!strcmp(name, "General_Category") || !strcmp(name, "gc")) {
- cr_init(cr, s->opaque, lre_realloc);
- ret = unicode_general_category(cr, value);
- if (ret) {
- cr_free(cr);
- if (ret == -2)
- return re_parse_error(s, "unknown unicode general category");
- else
- goto out_of_memory;
- }
- } else if (value[0] == '\0') {
- cr_init(cr, s->opaque, lre_realloc);
- ret = unicode_general_category(cr, name);
- if (ret == -1) {
- cr_free(cr);
- goto out_of_memory;
- }
- if (ret < 0) {
- ret = unicode_prop(cr, name);
- if (ret) {
- cr_free(cr);
- if (ret == -2)
- goto unknown_property_name;
- else
- goto out_of_memory;
- }
- }
- } else {
- unknown_property_name:
- return re_parse_error(s, "unknown unicode property name");
- }
- if (is_inv) {
- if (cr_invert(cr)) {
- cr_free(cr);
- return -1;
- }
- }
- *pp = p;
- return 0;
- out_of_memory:
- return re_parse_out_of_memory(s);
- }
- /* return -1 if error otherwise the character or a class range
- (CLASS_RANGE_BASE). In case of class range, 'cr' is
- initialized. Otherwise, it is ignored. */
- static int get_class_atom(REParseState *s, CharRange *cr,
- const uint8_t **pp, bool inclass)
- {
- const uint8_t *p, *p_next;
- uint32_t c;
- int ret;
- p = *pp;
- c = *p;
- switch(c) {
- case '\\':
- p++;
- if (p >= s->buf_end)
- goto unexpected_end;
- c = *p++;
- switch(c) {
- case 'd':
- c = CHAR_RANGE_d;
- goto class_range;
- case 'D':
- c = CHAR_RANGE_D;
- goto class_range;
- case 's':
- c = CHAR_RANGE_s;
- goto class_range;
- case 'S':
- c = CHAR_RANGE_S;
- goto class_range;
- case 'w':
- c = CHAR_RANGE_w;
- goto class_range;
- case 'W':
- c = CHAR_RANGE_W;
- class_range:
- if (cr_init_char_range(s, cr, c))
- return -1;
- c = CLASS_RANGE_BASE;
- break;
- case 'c':
- c = *p;
- if ((c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (((c >= '0' && c <= '9') || c == '_') &&
- inclass && !s->is_unicode)) { /* Annex B.1.4 */
- c &= 0x1f;
- p++;
- } else if (s->is_unicode) {
- goto invalid_escape;
- } else {
- /* otherwise return '\' and 'c' */
- p--;
- c = '\\';
- }
- break;
- case 'p':
- case 'P':
- if (s->is_unicode) {
- if (parse_unicode_property(s, cr, &p, (c == 'P')))
- return -1;
- c = CLASS_RANGE_BASE;
- break;
- }
- /* fall thru */
- default:
- p--;
- ret = lre_parse_escape(&p, s->is_unicode * 2);
- if (ret >= 0) {
- c = ret;
- } else {
- if (ret == -2 && *p != '\0' && strchr("^$\\.*+?()[]{}|/", *p)) {
- /* always valid to escape these characters */
- goto normal_char;
- } else if (s->is_unicode) {
- // special case: allowed inside [] but not outside
- if (ret == -2 && *p == '-' && inclass)
- goto normal_char;
- invalid_escape:
- return re_parse_error(s, "invalid escape sequence in regular expression");
- } else {
- /* just ignore the '\' */
- goto normal_char;
- }
- }
- break;
- }
- break;
- case '\0':
- if (p >= s->buf_end) {
- unexpected_end:
- return re_parse_error(s, "unexpected end");
- }
- /* fall thru */
- default:
- normal_char:
- p++;
- if (c >= 0x80) {
- c = utf8_decode(p - 1, &p_next);
- if (p_next == p)
- return re_parse_error(s, "invalid UTF-8 sequence");
- p = p_next;
- if (c > 0xFFFF && !s->is_unicode) {
- // TODO(chqrlie): should handle non BMP-1 code points in
- // the calling function and no require the source string
- // to be CESU-8 encoded if not s->is_unicode
- return re_parse_error(s, "malformed unicode char");
- }
- }
- break;
- }
- *pp = p;
- return c;
- }
- static int re_emit_range(REParseState *s, const CharRange *cr)
- {
- int len, i;
- uint32_t high;
- len = (unsigned)cr->len / 2;
- if (len >= 65535)
- return re_parse_error(s, "too many ranges");
- if (len == 0) {
- /* not sure it can really happen. Emit a match that is always
- false */
- re_emit_op_u32(s, REOP_char32, -1);
- } else {
- high = cr->points[cr->len - 1];
- if (high == UINT32_MAX)
- high = cr->points[cr->len - 2];
- if (high <= 0xffff) {
- /* can use 16 bit ranges with the conversion that 0xffff =
- infinity */
- re_emit_op_u16(s, REOP_range, len);
- for(i = 0; i < cr->len; i += 2) {
- dbuf_put_u16(&s->byte_code, cr->points[i]);
- high = cr->points[i + 1] - 1;
- if (high == UINT32_MAX - 1)
- high = 0xffff;
- dbuf_put_u16(&s->byte_code, high);
- }
- } else {
- re_emit_op_u16(s, REOP_range32, len);
- for(i = 0; i < cr->len; i += 2) {
- dbuf_put_u32(&s->byte_code, cr->points[i]);
- dbuf_put_u32(&s->byte_code, cr->points[i + 1] - 1);
- }
- }
- }
- return 0;
- }
- // s->unicode turns patterns like []] into syntax errors
- // s->unicode_sets turns more patterns into errors, like [a-] or [[]
- static int re_parse_char_class(REParseState *s, const uint8_t **pp)
- {
- const uint8_t *p;
- uint32_t c1, c2;
- CharRange cr_s, *cr = &cr_s;
- CharRange cr1_s, *cr1 = &cr1_s;
- bool invert;
- cr_init(cr, s->opaque, lre_realloc);
- p = *pp;
- p++; /* skip '[' */
- if (s->unicode_sets) {
- static const char verboten[] =
- "()[{}/-|" "\0"
- "&&!!##$$%%**++,,..::;;<<==>>??@@``~~" "\0"
- "^^^_^^";
- const char *s = verboten;
- int n = 1;
- do {
- if (!memcmp(s, p, n))
- if (p[n] == ']')
- goto invalid_class_range;
- s += n;
- if (!*s) {
- s++;
- n++;
- }
- } while (n < 4);
- }
- invert = false;
- if (*p == '^') {
- p++;
- invert = true;
- }
- for(;;) {
- if (*p == ']')
- break;
- c1 = get_class_atom(s, cr1, &p, true);
- if ((int)c1 < 0)
- goto fail;
- if (*p == '-' && p[1] == ']' && s->unicode_sets) {
- if (c1 >= CLASS_RANGE_BASE)
- cr_free(cr1);
- goto invalid_class_range;
- }
- if (*p == '-' && p[1] != ']') {
- const uint8_t *p0 = p + 1;
- if (c1 >= CLASS_RANGE_BASE) {
- if (s->is_unicode) {
- cr_free(cr1);
- goto invalid_class_range;
- }
- /* Annex B: match '-' character */
- goto class_atom;
- }
- c2 = get_class_atom(s, cr1, &p0, true);
- if ((int)c2 < 0)
- goto fail;
- if (c2 >= CLASS_RANGE_BASE) {
- cr_free(cr1);
- if (s->is_unicode) {
- goto invalid_class_range;
- }
- /* Annex B: match '-' character */
- goto class_atom;
- }
- p = p0;
- if (c2 < c1) {
- invalid_class_range:
- re_parse_error(s, "invalid class range");
- goto fail;
- }
- if (cr_union_interval(cr, c1, c2))
- goto memory_error;
- } else {
- class_atom:
- if (c1 >= CLASS_RANGE_BASE) {
- int ret;
- ret = cr_union1(cr, cr1->points, cr1->len);
- cr_free(cr1);
- if (ret)
- goto memory_error;
- } else {
- if (cr_union_interval(cr, c1, c1))
- goto memory_error;
- }
- }
- }
- if (s->ignore_case) {
- if (cr_regexp_canonicalize(cr, s->is_unicode))
- goto memory_error;
- }
- if (invert) {
- if (cr_invert(cr))
- goto memory_error;
- }
- if (re_emit_range(s, cr))
- goto fail;
- cr_free(cr);
- p++; /* skip ']' */
- *pp = p;
- return 0;
- memory_error:
- re_parse_out_of_memory(s);
- fail:
- cr_free(cr);
- return -1;
- }
- /* Return:
- - true if the opcodes may not advance the char pointer
- - false if the opcodes always advance the char pointer
- */
- static bool re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len)
- {
- int pos, opcode, len;
- uint32_t val;
- bool ret;
- ret = true;
- pos = 0;
- while (pos < bc_buf_len) {
- opcode = bc_buf[pos];
- len = reopcode_info[opcode].size;
- switch(opcode) {
- case REOP_range:
- val = get_u16(bc_buf + pos + 1);
- len += val * 4;
- goto simple_char;
- case REOP_range32:
- val = get_u16(bc_buf + pos + 1);
- len += val * 8;
- goto simple_char;
- case REOP_char32:
- case REOP_char16:
- case REOP_char8:
- case REOP_dot:
- case REOP_any:
- simple_char:
- ret = false;
- break;
- case REOP_line_start:
- case REOP_line_end:
- case REOP_push_i32:
- case REOP_push_char_pos:
- case REOP_drop:
- case REOP_word_boundary:
- case REOP_not_word_boundary:
- case REOP_prev:
- /* no effect */
- break;
- case REOP_save_start:
- case REOP_save_end:
- case REOP_save_reset:
- case REOP_back_reference:
- case REOP_backward_back_reference:
- break;
- default:
- /* safe behvior: we cannot predict the outcome */
- return true;
- }
- pos += len;
- }
- return ret;
- }
- /* return -1 if a simple quantifier cannot be used. Otherwise return
- the number of characters in the atom. */
- static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len)
- {
- int pos, opcode, len, count;
- uint32_t val;
- count = 0;
- pos = 0;
- while (pos < bc_buf_len) {
- opcode = bc_buf[pos];
- len = reopcode_info[opcode].size;
- switch(opcode) {
- case REOP_range:
- val = get_u16(bc_buf + pos + 1);
- len += val * 4;
- goto simple_char;
- case REOP_range32:
- val = get_u16(bc_buf + pos + 1);
- len += val * 8;
- goto simple_char;
- case REOP_char32:
- case REOP_char16:
- case REOP_char8:
- case REOP_dot:
- case REOP_any:
- simple_char:
- count++;
- break;
- case REOP_line_start:
- case REOP_line_end:
- case REOP_word_boundary:
- case REOP_not_word_boundary:
- break;
- default:
- return -1;
- }
- pos += len;
- }
- return count;
- }
- /* '*pp' is the first char after '<' */
- static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp)
- {
- const uint8_t *p, *p_next;
- uint32_t c, d;
- char *q;
- p = *pp;
- q = buf;
- for(;;) {
- c = *p++;
- if (c == '\\') {
- if (*p != 'u')
- return -1;
- c = lre_parse_escape(&p, 2); // accept surrogate pairs
- if ((int)c < 0)
- return -1;
- } else if (c == '>') {
- break;
- } else if (c >= 0x80) {
- c = utf8_decode(p - 1, &p_next);
- if (p_next == p)
- return -1;
- p = p_next;
- if (is_hi_surrogate(c)) {
- d = utf8_decode(p, &p_next);
- if (is_lo_surrogate(d)) {
- c = from_surrogate(c, d);
- p = p_next;
- }
- }
- }
- if (q == buf) {
- if (!lre_js_is_ident_first(c))
- return -1;
- } else {
- if (!lre_js_is_ident_next(c))
- return -1;
- }
- if ((q - buf + UTF8_CHAR_LEN_MAX + 1) > buf_size)
- return -1;
- if (c < 0x80) {
- *q++ = c;
- } else {
- q += utf8_encode((uint8_t*)q, c);
- }
- }
- if (q == buf)
- return -1;
- *q = '\0';
- *pp = p;
- return 0;
- }
- /* if capture_name = NULL: return the number of captures + 1.
- Otherwise, return the capture index corresponding to capture_name
- or -1 if none */
- static int re_parse_captures(REParseState *s, int *phas_named_captures,
- const char *capture_name)
- {
- const uint8_t *p;
- int capture_index;
- char name[TMP_BUF_SIZE];
- capture_index = 1;
- *phas_named_captures = 0;
- for (p = s->buf_start; p < s->buf_end; p++) {
- switch (*p) {
- case '(':
- if (p[1] == '?') {
- if (p[2] == '<' && p[3] != '=' && p[3] != '!') {
- *phas_named_captures = 1;
- /* potential named capture */
- if (capture_name) {
- p += 3;
- if (re_parse_group_name(name, sizeof(name), &p) == 0) {
- if (!strcmp(name, capture_name))
- return capture_index;
- }
- }
- capture_index++;
- if (capture_index >= CAPTURE_COUNT_MAX)
- goto done;
- }
- } else {
- capture_index++;
- if (capture_index >= CAPTURE_COUNT_MAX)
- goto done;
- }
- break;
- case '\\':
- p++;
- break;
- case '[':
- for (p += 1 + (*p == ']'); p < s->buf_end && *p != ']'; p++) {
- if (*p == '\\')
- p++;
- }
- break;
- }
- }
- done:
- if (capture_name)
- return -1;
- else
- return capture_index;
- }
- static int re_count_captures(REParseState *s)
- {
- if (s->total_capture_count < 0) {
- s->total_capture_count = re_parse_captures(s, &s->has_named_captures,
- NULL);
- }
- return s->total_capture_count;
- }
- static bool re_has_named_captures(REParseState *s)
- {
- if (s->has_named_captures < 0)
- re_count_captures(s);
- return s->has_named_captures;
- }
- static int find_group_name(REParseState *s, const char *name)
- {
- const char *p, *buf_end;
- size_t len, name_len;
- int capture_index;
- p = (char *)s->group_names.buf;
- if (!p) return -1;
- buf_end = (char *)s->group_names.buf + s->group_names.size;
- name_len = strlen(name);
- capture_index = 1;
- while (p < buf_end) {
- len = strlen(p);
- if (len == name_len && memcmp(name, p, name_len) == 0)
- return capture_index;
- p += len + 1;
- capture_index++;
- }
- return -1;
- }
- static int re_parse_disjunction(REParseState *s, bool is_backward_dir);
- static int re_parse_term(REParseState *s, bool is_backward_dir)
- {
- const uint8_t *p;
- int c, last_atom_start, quant_min, quant_max, last_capture_count;
- bool greedy, add_zero_advance_check, is_neg, is_backward_lookahead;
- CharRange cr_s, *cr = &cr_s;
- last_atom_start = -1;
- last_capture_count = 0;
- p = s->buf_ptr;
- c = *p;
- switch(c) {
- case '^':
- p++;
- re_emit_op(s, REOP_line_start);
- break;
- case '$':
- p++;
- re_emit_op(s, REOP_line_end);
- break;
- case '.':
- p++;
- last_atom_start = s->byte_code.size;
- last_capture_count = s->capture_count;
- if (is_backward_dir)
- re_emit_op(s, REOP_prev);
- re_emit_op(s, s->dotall ? REOP_any : REOP_dot);
- if (is_backward_dir)
- re_emit_op(s, REOP_prev);
- break;
- case '{':
- if (s->is_unicode) {
- return re_parse_error(s, "syntax error");
- } else if (!lre_is_digit(p[1])) {
- /* Annex B: we accept '{' not followed by digits as a
- normal atom */
- goto parse_class_atom;
- } else {
- const uint8_t *p1 = p + 1;
- /* Annex B: error if it is like a repetition count */
- parse_digits(&p1, true);
- if (*p1 == ',') {
- p1++;
- if (lre_is_digit(*p1)) {
- parse_digits(&p1, true);
- }
- }
- if (*p1 != '}') {
- goto parse_class_atom;
- }
- }
- /* fall thru */
- case '*':
- case '+':
- case '?':
- return re_parse_error(s, "nothing to repeat");
- case '(':
- if (p[1] == '?') {
- if (p[2] == ':') {
- p += 3;
- last_atom_start = s->byte_code.size;
- last_capture_count = s->capture_count;
- s->buf_ptr = p;
- if (re_parse_disjunction(s, is_backward_dir))
- return -1;
- p = s->buf_ptr;
- if (re_parse_expect(s, &p, ')'))
- return -1;
- } else if ((p[2] == '=' || p[2] == '!')) {
- is_neg = (p[2] == '!');
- is_backward_lookahead = false;
- p += 3;
- goto lookahead;
- } else if (p[2] == '<' &&
- (p[3] == '=' || p[3] == '!')) {
- int pos;
- is_neg = (p[3] == '!');
- is_backward_lookahead = true;
- p += 4;
- /* lookahead */
- lookahead:
- /* Annex B allows lookahead to be used as an atom for
- the quantifiers */
- if (!s->is_unicode && !is_backward_lookahead) {
- last_atom_start = s->byte_code.size;
- last_capture_count = s->capture_count;
- }
- pos = re_emit_op_u32(s, REOP_lookahead + is_neg, 0);
- s->buf_ptr = p;
- if (re_parse_disjunction(s, is_backward_lookahead))
- return -1;
- p = s->buf_ptr;
- if (re_parse_expect(s, &p, ')'))
- return -1;
- re_emit_op(s, REOP_match);
- /* jump after the 'match' after the lookahead is successful */
- if (dbuf_error(&s->byte_code))
- return -1;
- put_u32(s->byte_code.buf + pos, s->byte_code.size - (pos + 4));
- } else if (p[2] == '<') {
- p += 3;
- if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf),
- &p)) {
- return re_parse_error(s, "invalid group name");
- }
- if (find_group_name(s, s->u.tmp_buf) > 0) {
- return re_parse_error(s, "duplicate group name");
- }
- /* group name with a trailing zero */
- dbuf_put(&s->group_names, (uint8_t *)s->u.tmp_buf,
- strlen(s->u.tmp_buf) + 1);
- s->has_named_captures = 1;
- goto parse_capture;
- } else {
- return re_parse_error(s, "invalid group");
- }
- } else {
- int capture_index;
- p++;
- /* capture without group name */
- dbuf_putc(&s->group_names, 0);
- parse_capture:
- if (s->capture_count >= CAPTURE_COUNT_MAX)
- return re_parse_error(s, "too many captures");
- last_atom_start = s->byte_code.size;
- last_capture_count = s->capture_count;
- capture_index = s->capture_count++;
- re_emit_op_u8(s, REOP_save_start + is_backward_dir,
- capture_index);
- s->buf_ptr = p;
- if (re_parse_disjunction(s, is_backward_dir))
- return -1;
- p = s->buf_ptr;
- re_emit_op_u8(s, REOP_save_start + 1 - is_backward_dir,
- capture_index);
- if (re_parse_expect(s, &p, ')'))
- return -1;
- }
- break;
- case '\\':
- switch(p[1]) {
- case 'b':
- case 'B':
- re_emit_op(s, REOP_word_boundary + (p[1] != 'b'));
- p += 2;
- break;
- case 'k':
- {
- const uint8_t *p1;
- int dummy_res;
- p1 = p;
- if (p1[2] != '<') {
- /* annex B: we tolerate invalid group names in non
- unicode mode if there is no named capture
- definition */
- if (s->is_unicode || re_has_named_captures(s))
- return re_parse_error(s, "expecting group name");
- else
- goto parse_class_atom;
- }
- p1 += 3;
- if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf),
- &p1)) {
- if (s->is_unicode || re_has_named_captures(s))
- return re_parse_error(s, "invalid group name");
- else
- goto parse_class_atom;
- }
- c = find_group_name(s, s->u.tmp_buf);
- if (c < 0) {
- /* no capture name parsed before, try to look
- after (inefficient, but hopefully not common */
- c = re_parse_captures(s, &dummy_res, s->u.tmp_buf);
- if (c < 0) {
- if (s->is_unicode || re_has_named_captures(s))
- return re_parse_error(s, "group name not defined");
- else
- goto parse_class_atom;
- }
- }
- p = p1;
- }
- goto emit_back_reference;
- case '0':
- p += 2;
- c = 0;
- if (s->is_unicode) {
- if (lre_is_digit(*p)) {
- return re_parse_error(s, "invalid decimal escape in regular expression");
- }
- } else {
- /* Annex B.1.4: accept legacy octal */
- if (*p >= '0' && *p <= '7') {
- c = *p++ - '0';
- if (*p >= '0' && *p <= '7') {
- c = (c << 3) + *p++ - '0';
- }
- }
- }
- goto normal_char;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8':
- case '9':
- {
- const uint8_t *q = ++p;
- c = parse_digits(&p, false);
- if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) {
- if (!s->is_unicode) {
- /* Annex B.1.4: accept legacy octal */
- p = q;
- if (*p <= '7') {
- c = 0;
- if (*p <= '3')
- c = *p++ - '0';
- if (*p >= '0' && *p <= '7') {
- c = (c << 3) + *p++ - '0';
- if (*p >= '0' && *p <= '7') {
- c = (c << 3) + *p++ - '0';
- }
- }
- } else {
- c = *p++;
- }
- goto normal_char;
- }
- return re_parse_error(s, "back reference out of range in regular expression");
- }
- emit_back_reference:
- last_atom_start = s->byte_code.size;
- last_capture_count = s->capture_count;
- re_emit_op_u8(s, REOP_back_reference + is_backward_dir, c);
- }
- break;
- default:
- goto parse_class_atom;
- }
- break;
- case '[':
- last_atom_start = s->byte_code.size;
- last_capture_count = s->capture_count;
- if (is_backward_dir)
- re_emit_op(s, REOP_prev);
- if (re_parse_char_class(s, &p))
- return -1;
- if (is_backward_dir)
- re_emit_op(s, REOP_prev);
- break;
- case ']':
- case '}':
- if (s->is_unicode)
- return re_parse_error(s, "syntax error");
- goto parse_class_atom;
- default:
- parse_class_atom:
- c = get_class_atom(s, cr, &p, false);
- if ((int)c < 0)
- return -1;
- normal_char:
- last_atom_start = s->byte_code.size;
- last_capture_count = s->capture_count;
- if (is_backward_dir)
- re_emit_op(s, REOP_prev);
- if (c >= CLASS_RANGE_BASE) {
- int ret;
- /* Note: canonicalization is not needed */
- ret = re_emit_range(s, cr);
- cr_free(cr);
- if (ret)
- return -1;
- } else {
- if (s->ignore_case)
- c = lre_canonicalize(c, s->is_unicode);
- if (c <= 0x7f)
- re_emit_op_u8(s, REOP_char8, c);
- else if (c <= 0xffff)
- re_emit_op_u16(s, REOP_char16, c);
- else
- re_emit_op_u32(s, REOP_char32, c);
- }
- if (is_backward_dir)
- re_emit_op(s, REOP_prev);
- break;
- }
- /* quantifier */
- if (last_atom_start >= 0) {
- c = *p;
- switch(c) {
- case '*':
- p++;
- quant_min = 0;
- quant_max = INT32_MAX;
- goto quantifier;
- case '+':
- p++;
- quant_min = 1;
- quant_max = INT32_MAX;
- goto quantifier;
- case '?':
- p++;
- quant_min = 0;
- quant_max = 1;
- goto quantifier;
- case '{':
- {
- const uint8_t *p1 = p;
- /* As an extension (see ES6 annex B), we accept '{' not
- followed by digits as a normal atom */
- if (!lre_is_digit(p[1])) {
- if (s->is_unicode)
- goto invalid_quant_count;
- break;
- }
- p++;
- quant_min = parse_digits(&p, true);
- quant_max = quant_min;
- if (*p == ',') {
- p++;
- if (lre_is_digit(*p)) {
- quant_max = parse_digits(&p, true);
- if (quant_max < quant_min) {
- invalid_quant_count:
- return re_parse_error(s, "invalid repetition count");
- }
- } else {
- quant_max = INT32_MAX; /* infinity */
- }
- }
- if (*p != '}' && !s->is_unicode) {
- /* Annex B: normal atom if invalid '{' syntax */
- p = p1;
- break;
- }
- if (re_parse_expect(s, &p, '}'))
- return -1;
- }
- quantifier:
- greedy = true;
- if (*p == '?') {
- p++;
- greedy = false;
- }
- if (last_atom_start < 0) {
- return re_parse_error(s, "nothing to repeat");
- }
- if (greedy) {
- int len, pos;
- if (quant_max > 0) {
- /* specific optimization for simple quantifiers */
- if (dbuf_error(&s->byte_code))
- goto out_of_memory;
- len = re_is_simple_quantifier(s->byte_code.buf + last_atom_start,
- s->byte_code.size - last_atom_start);
- if (len > 0) {
- re_emit_op(s, REOP_match);
- if (dbuf_insert(&s->byte_code, last_atom_start, 17))
- goto out_of_memory;
- pos = last_atom_start;
- s->byte_code.buf[pos++] = REOP_simple_greedy_quant;
- put_u32(&s->byte_code.buf[pos],
- s->byte_code.size - last_atom_start - 17);
- pos += 4;
- put_u32(&s->byte_code.buf[pos], quant_min);
- pos += 4;
- put_u32(&s->byte_code.buf[pos], quant_max);
- pos += 4;
- put_u32(&s->byte_code.buf[pos], len);
- pos += 4;
- goto done;
- }
- }
- if (dbuf_error(&s->byte_code))
- goto out_of_memory;
- }
- /* the spec tells that if there is no advance when
- running the atom after the first quant_min times,
- then there is no match. We remove this test when we
- are sure the atom always advances the position. */
- add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start,
- s->byte_code.size - last_atom_start);
- {
- int len, pos;
- len = s->byte_code.size - last_atom_start;
- if (quant_min == 0) {
- /* need to reset the capture in case the atom is
- not executed */
- if (last_capture_count != s->capture_count) {
- if (dbuf_insert(&s->byte_code, last_atom_start, 3))
- goto out_of_memory;
- s->byte_code.buf[last_atom_start++] = REOP_save_reset;
- s->byte_code.buf[last_atom_start++] = last_capture_count;
- s->byte_code.buf[last_atom_start++] = s->capture_count - 1;
- }
- if (quant_max == 0) {
- s->byte_code.size = last_atom_start;
- } else if (quant_max == 1 || quant_max == INT32_MAX) {
- bool has_goto = (quant_max == INT32_MAX);
- if (dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check))
- goto out_of_memory;
- s->byte_code.buf[last_atom_start] = REOP_split_goto_first +
- greedy;
- put_u32(s->byte_code.buf + last_atom_start + 1,
- len + 5 * has_goto + add_zero_advance_check * 2);
- if (add_zero_advance_check) {
- s->byte_code.buf[last_atom_start + 1 + 4] = REOP_push_char_pos;
- re_emit_op(s, REOP_check_advance);
- }
- if (has_goto)
- re_emit_goto(s, REOP_goto, last_atom_start);
- } else {
- if (dbuf_insert(&s->byte_code, last_atom_start, 10 + add_zero_advance_check))
- goto out_of_memory;
- pos = last_atom_start;
- s->byte_code.buf[pos++] = REOP_push_i32;
- put_u32(s->byte_code.buf + pos, quant_max);
- pos += 4;
- s->byte_code.buf[pos++] = REOP_split_goto_first + greedy;
- put_u32(s->byte_code.buf + pos, len + 5 + add_zero_advance_check * 2);
- pos += 4;
- if (add_zero_advance_check) {
- s->byte_code.buf[pos++] = REOP_push_char_pos;
- re_emit_op(s, REOP_check_advance);
- }
- re_emit_goto(s, REOP_loop, last_atom_start + 5);
- re_emit_op(s, REOP_drop);
- }
- } else if (quant_min == 1 && quant_max == INT32_MAX &&
- !add_zero_advance_check) {
- re_emit_goto(s, REOP_split_next_first - greedy,
- last_atom_start);
- } else {
- if (quant_min == 1) {
- /* nothing to add */
- } else {
- if (dbuf_insert(&s->byte_code, last_atom_start, 5))
- goto out_of_memory;
- s->byte_code.buf[last_atom_start] = REOP_push_i32;
- put_u32(s->byte_code.buf + last_atom_start + 1,
- quant_min);
- last_atom_start += 5;
- re_emit_goto(s, REOP_loop, last_atom_start);
- re_emit_op(s, REOP_drop);
- }
- if (quant_max == INT32_MAX) {
- pos = s->byte_code.size;
- re_emit_op_u32(s, REOP_split_goto_first + greedy,
- len + 5 + add_zero_advance_check * 2);
- if (add_zero_advance_check)
- re_emit_op(s, REOP_push_char_pos);
- /* copy the atom */
- dbuf_put_self(&s->byte_code, last_atom_start, len);
- if (add_zero_advance_check)
- re_emit_op(s, REOP_check_advance);
- re_emit_goto(s, REOP_goto, pos);
- } else if (quant_max > quant_min) {
- re_emit_op_u32(s, REOP_push_i32, quant_max - quant_min);
- pos = s->byte_code.size;
- re_emit_op_u32(s, REOP_split_goto_first + greedy,
- len + 5 + add_zero_advance_check * 2);
- if (add_zero_advance_check)
- re_emit_op(s, REOP_push_char_pos);
- /* copy the atom */
- dbuf_put_self(&s->byte_code, last_atom_start, len);
- if (add_zero_advance_check)
- re_emit_op(s, REOP_check_advance);
- re_emit_goto(s, REOP_loop, pos);
- re_emit_op(s, REOP_drop);
- }
- }
- last_atom_start = -1;
- }
- break;
- default:
- break;
- }
- }
- done:
- s->buf_ptr = p;
- return 0;
- out_of_memory:
- return re_parse_out_of_memory(s);
- }
- static int re_parse_alternative(REParseState *s, bool is_backward_dir)
- {
- const uint8_t *p;
- int ret;
- size_t start, term_start, end, term_size;
- start = s->byte_code.size;
- for(;;) {
- p = s->buf_ptr;
- if (p >= s->buf_end)
- break;
- if (*p == '|' || *p == ')')
- break;
- term_start = s->byte_code.size;
- ret = re_parse_term(s, is_backward_dir);
- if (ret)
- return ret;
- if (is_backward_dir) {
- /* reverse the order of the terms (XXX: inefficient, but
- speed is not really critical here) */
- end = s->byte_code.size;
- term_size = end - term_start;
- if (dbuf_realloc(&s->byte_code, end + term_size))
- return -1;
- memmove(s->byte_code.buf + start + term_size,
- s->byte_code.buf + start,
- end - start);
- memcpy(s->byte_code.buf + start, s->byte_code.buf + end,
- term_size);
- }
- }
- return 0;
- }
- static int re_parse_disjunction(REParseState *s, bool is_backward_dir)
- {
- int start, len, pos;
- if (lre_check_stack_overflow(s->opaque, 0))
- return re_parse_error(s, "stack overflow");
- start = s->byte_code.size;
- if (re_parse_alternative(s, is_backward_dir))
- return -1;
- while (*s->buf_ptr == '|') {
- s->buf_ptr++;
- len = s->byte_code.size - start;
- /* insert a split before the first alternative */
- if (dbuf_insert(&s->byte_code, start, 5)) {
- return re_parse_out_of_memory(s);
- }
- s->byte_code.buf[start] = REOP_split_next_first;
- put_u32(s->byte_code.buf + start + 1, len + 5);
- pos = re_emit_op_u32(s, REOP_goto, 0);
- if (re_parse_alternative(s, is_backward_dir))
- return -1;
- /* patch the goto */
- len = s->byte_code.size - (pos + 4);
- put_u32(s->byte_code.buf + pos, len);
- }
- return 0;
- }
- /* the control flow is recursive so the analysis can be linear */
- static int lre_compute_stack_size(const uint8_t *bc_buf, int bc_buf_len)
- {
- int stack_size, stack_size_max, pos, opcode, len;
- uint32_t val;
- stack_size = 0;
- stack_size_max = 0;
- bc_buf += RE_HEADER_LEN;
- bc_buf_len -= RE_HEADER_LEN;
- pos = 0;
- while (pos < bc_buf_len) {
- opcode = bc_buf[pos];
- len = reopcode_info[opcode].size;
- assert(opcode < REOP_COUNT);
- assert((pos + len) <= bc_buf_len);
- switch(opcode) {
- case REOP_push_i32:
- case REOP_push_char_pos:
- stack_size++;
- if (stack_size > stack_size_max) {
- if (stack_size > STACK_SIZE_MAX)
- return -1;
- stack_size_max = stack_size;
- }
- break;
- case REOP_drop:
- case REOP_check_advance:
- assert(stack_size > 0);
- stack_size--;
- break;
- case REOP_range:
- val = get_u16(bc_buf + pos + 1);
- len += val * 4;
- break;
- case REOP_range32:
- val = get_u16(bc_buf + pos + 1);
- len += val * 8;
- break;
- }
- pos += len;
- }
- return stack_size_max;
- }
- /* 'buf' must be a zero terminated UTF-8 string of length buf_len.
- Return NULL if error and allocate an error message in *perror_msg,
- otherwise the compiled bytecode and its length in plen.
- */
- uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
- const char *buf, size_t buf_len, int re_flags,
- void *opaque)
- {
- REParseState s_s, *s = &s_s;
- int stack_size;
- bool is_sticky;
- memset(s, 0, sizeof(*s));
- s->opaque = opaque;
- s->buf_ptr = (const uint8_t *)buf;
- s->buf_end = s->buf_ptr + buf_len;
- s->buf_start = s->buf_ptr;
- s->re_flags = re_flags;
- s->is_unicode = ((re_flags & LRE_FLAG_UNICODE) != 0);
- is_sticky = ((re_flags & LRE_FLAG_STICKY) != 0);
- s->ignore_case = ((re_flags & LRE_FLAG_IGNORECASE) != 0);
- s->dotall = ((re_flags & LRE_FLAG_DOTALL) != 0);
- s->unicode_sets = ((re_flags & LRE_FLAG_UNICODE_SETS) != 0);
- s->capture_count = 1;
- s->total_capture_count = -1;
- s->has_named_captures = -1;
- dbuf_init2(&s->byte_code, opaque, lre_realloc);
- dbuf_init2(&s->group_names, opaque, lre_realloc);
- dbuf_put_u16(&s->byte_code, re_flags); /* first element is the flags */
- dbuf_putc(&s->byte_code, 0); /* second element is the number of captures */
- dbuf_putc(&s->byte_code, 0); /* stack size */
- dbuf_put_u32(&s->byte_code, 0); /* bytecode length */
- if (!is_sticky) {
- /* iterate thru all positions (about the same as .*?( ... ) )
- . We do it without an explicit loop so that lock step
- thread execution will be possible in an optimized
- implementation */
- re_emit_op_u32(s, REOP_split_goto_first, 1 + 5);
- re_emit_op(s, REOP_any);
- re_emit_op_u32(s, REOP_goto, -(5 + 1 + 5));
- }
- re_emit_op_u8(s, REOP_save_start, 0);
- if (re_parse_disjunction(s, false)) {
- error:
- dbuf_free(&s->byte_code);
- dbuf_free(&s->group_names);
- js__pstrcpy(error_msg, error_msg_size, s->u.error_msg);
- *plen = 0;
- return NULL;
- }
- re_emit_op_u8(s, REOP_save_end, 0);
- re_emit_op(s, REOP_match);
- if (*s->buf_ptr != '\0') {
- re_parse_error(s, "extraneous characters at the end");
- goto error;
- }
- if (dbuf_error(&s->byte_code)) {
- re_parse_out_of_memory(s);
- goto error;
- }
- stack_size = lre_compute_stack_size(s->byte_code.buf, s->byte_code.size);
- if (stack_size < 0) {
- re_parse_error(s, "too many imbricated quantifiers");
- goto error;
- }
- s->byte_code.buf[RE_HEADER_CAPTURE_COUNT] = s->capture_count;
- s->byte_code.buf[RE_HEADER_STACK_SIZE] = stack_size;
- put_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN,
- s->byte_code.size - RE_HEADER_LEN);
- /* add the named groups if needed */
- if (s->group_names.size > (s->capture_count - 1)) {
- dbuf_put(&s->byte_code, s->group_names.buf, s->group_names.size);
- put_u16(s->byte_code.buf + RE_HEADER_FLAGS,
- LRE_FLAG_NAMED_GROUPS | lre_get_flags(s->byte_code.buf));
- }
- dbuf_free(&s->group_names);
- #ifdef DUMP_REOP
- lre_dump_bytecode(s->byte_code.buf, s->byte_code.size);
- #endif
- error_msg[0] = '\0';
- *plen = s->byte_code.size;
- return s->byte_code.buf;
- }
- static bool is_line_terminator(uint32_t c)
- {
- return (c == '\n' || c == '\r' || c == CP_LS || c == CP_PS);
- }
- static bool is_word_char(uint32_t c)
- {
- return ((c >= '0' && c <= '9') ||
- (c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (c == '_'));
- }
- #define GET_CHAR(c, cptr, cbuf_end, cbuf_type) \
- do { \
- if (cbuf_type == 0) { \
- c = *cptr++; \
- } else { \
- const uint16_t *_p = (const uint16_t *)cptr; \
- const uint16_t *_end = (const uint16_t *)cbuf_end; \
- c = *_p++; \
- if (is_hi_surrogate(c)) \
- if (cbuf_type == 2) \
- if (_p < _end) \
- if (is_lo_surrogate(*_p)) \
- c = from_surrogate(c, *_p++); \
- cptr = (const void *)_p; \
- } \
- } while (0)
- #define PEEK_CHAR(c, cptr, cbuf_end, cbuf_type) \
- do { \
- if (cbuf_type == 0) { \
- c = cptr[0]; \
- } else { \
- const uint16_t *_p = (const uint16_t *)cptr; \
- const uint16_t *_end = (const uint16_t *)cbuf_end; \
- c = *_p++; \
- if (is_hi_surrogate(c)) \
- if (cbuf_type == 2) \
- if (_p < _end) \
- if (is_lo_surrogate(*_p)) \
- c = from_surrogate(c, *_p); \
- } \
- } while (0)
- #define PEEK_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \
- do { \
- if (cbuf_type == 0) { \
- c = cptr[-1]; \
- } else { \
- const uint16_t *_p = (const uint16_t *)cptr - 1; \
- const uint16_t *_start = (const uint16_t *)cbuf_start; \
- c = *_p; \
- if (is_lo_surrogate(c)) \
- if (cbuf_type == 2) \
- if (_p > _start) \
- if (is_hi_surrogate(_p[-1])) \
- c = from_surrogate(*--_p, c); \
- } \
- } while (0)
- #define GET_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \
- do { \
- if (cbuf_type == 0) { \
- cptr--; \
- c = cptr[0]; \
- } else { \
- const uint16_t *_p = (const uint16_t *)cptr - 1; \
- const uint16_t *_start = (const uint16_t *)cbuf_start; \
- c = *_p; \
- if (is_lo_surrogate(c)) \
- if (cbuf_type == 2) \
- if (_p > _start) \
- if (is_hi_surrogate(_p[-1])) \
- c = from_surrogate(*--_p, c); \
- cptr = (const void *)_p; \
- } \
- } while (0)
- #define PREV_CHAR(cptr, cbuf_start, cbuf_type) \
- do { \
- if (cbuf_type == 0) { \
- cptr--; \
- } else { \
- const uint16_t *_p = (const uint16_t *)cptr - 1; \
- const uint16_t *_start = (const uint16_t *)cbuf_start; \
- if (is_lo_surrogate(*_p)) \
- if (cbuf_type == 2) \
- if (_p > _start) \
- if (is_hi_surrogate(_p[-1])) \
- _p--; \
- cptr = (const void *)_p; \
- } \
- } while (0)
- typedef uintptr_t StackInt;
- typedef enum {
- RE_EXEC_STATE_SPLIT,
- RE_EXEC_STATE_LOOKAHEAD,
- RE_EXEC_STATE_NEGATIVE_LOOKAHEAD,
- RE_EXEC_STATE_GREEDY_QUANT,
- } REExecStateEnum;
- typedef struct REExecState {
- REExecStateEnum type : 8;
- uint8_t stack_len;
- size_t count; /* only used for RE_EXEC_STATE_GREEDY_QUANT */
- const uint8_t *cptr;
- const uint8_t *pc;
- void *buf[];
- } REExecState;
- typedef struct {
- const uint8_t *cbuf;
- const uint8_t *cbuf_end;
- /* 0 = 8 bit chars, 1 = 16 bit chars, 2 = 16 bit chars, UTF-16 */
- int cbuf_type;
- int capture_count;
- int stack_size_max;
- bool multi_line;
- bool ignore_case;
- bool is_unicode;
- int interrupt_counter;
- void *opaque; /* used for stack overflow check */
- size_t state_size;
- uint8_t *state_stack;
- size_t state_stack_size;
- size_t state_stack_len;
- } REExecContext;
- static int push_state(REExecContext *s,
- uint8_t **capture,
- StackInt *stack, size_t stack_len,
- const uint8_t *pc, const uint8_t *cptr,
- REExecStateEnum type, size_t count)
- {
- REExecState *rs;
- uint8_t *new_stack;
- size_t new_size, i, n;
- StackInt *stack_buf;
- if (unlikely((s->state_stack_len + 1) > s->state_stack_size)) {
- /* reallocate the stack */
- new_size = s->state_stack_size * 3 / 2;
- if (new_size < 8)
- new_size = 8;
- new_stack = lre_realloc(s->opaque, s->state_stack, new_size * s->state_size);
- if (!new_stack)
- return -1;
- s->state_stack_size = new_size;
- s->state_stack = new_stack;
- }
- rs = (REExecState *)(s->state_stack + s->state_stack_len * s->state_size);
- s->state_stack_len++;
- rs->type = type;
- rs->count = count;
- rs->stack_len = stack_len;
- rs->cptr = cptr;
- rs->pc = pc;
- n = 2 * s->capture_count;
- for(i = 0; i < n; i++)
- rs->buf[i] = capture[i];
- stack_buf = (StackInt *)(rs->buf + n);
- for(i = 0; i < stack_len; i++)
- stack_buf[i] = stack[i];
- return 0;
- }
- static int lre_poll_timeout(REExecContext *s)
- {
- if (unlikely(--s->interrupt_counter <= 0)) {
- s->interrupt_counter = INTERRUPT_COUNTER_INIT;
- if (lre_check_timeout(s->opaque))
- return LRE_RET_TIMEOUT;
- }
- return 0;
- }
- /* return 1 if match, 0 if not match or < 0 if error. */
- static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
- StackInt *stack, int stack_len,
- const uint8_t *pc, const uint8_t *cptr,
- bool no_recurse)
- {
- int opcode, ret;
- int cbuf_type;
- uint32_t val, c;
- const uint8_t *cbuf_end;
- cbuf_type = s->cbuf_type;
- cbuf_end = s->cbuf_end;
- for(;;) {
- // printf("top=%p: pc=%d\n", th_list.top, (int)(pc - (bc_buf + RE_HEADER_LEN)));
- opcode = *pc++;
- switch(opcode) {
- case REOP_match:
- {
- REExecState *rs;
- if (no_recurse)
- return (intptr_t)cptr;
- ret = 1;
- goto recurse;
- no_match:
- if (no_recurse)
- return 0;
- ret = 0;
- recurse:
- for(;;) {
- if (lre_poll_timeout(s))
- return LRE_RET_TIMEOUT;
- if (s->state_stack_len == 0)
- return ret;
- rs = (REExecState *)(s->state_stack +
- (s->state_stack_len - 1) * s->state_size);
- if (rs->type == RE_EXEC_STATE_SPLIT) {
- if (!ret) {
- pop_state:
- memcpy(capture, rs->buf,
- sizeof(capture[0]) * 2 * s->capture_count);
- pop_state1:
- pc = rs->pc;
- cptr = rs->cptr;
- stack_len = rs->stack_len;
- memcpy(stack, rs->buf + 2 * s->capture_count,
- stack_len * sizeof(stack[0]));
- s->state_stack_len--;
- break;
- }
- } else if (rs->type == RE_EXEC_STATE_GREEDY_QUANT) {
- if (!ret) {
- uint32_t char_count, i;
- memcpy(capture, rs->buf,
- sizeof(capture[0]) * 2 * s->capture_count);
- stack_len = rs->stack_len;
- memcpy(stack, rs->buf + 2 * s->capture_count,
- stack_len * sizeof(stack[0]));
- pc = rs->pc;
- cptr = rs->cptr;
- /* go backward */
- char_count = get_u32(pc + 12);
- for(i = 0; i < char_count; i++) {
- PREV_CHAR(cptr, s->cbuf, cbuf_type);
- }
- pc = (pc + 16) + (int)get_u32(pc);
- rs->cptr = cptr;
- rs->count--;
- if (rs->count == 0) {
- s->state_stack_len--;
- }
- break;
- }
- } else {
- ret = ((rs->type == RE_EXEC_STATE_LOOKAHEAD && ret) ||
- (rs->type == RE_EXEC_STATE_NEGATIVE_LOOKAHEAD && !ret));
- if (ret) {
- /* keep the capture in case of positive lookahead */
- if (rs->type == RE_EXEC_STATE_LOOKAHEAD)
- goto pop_state1;
- else
- goto pop_state;
- }
- }
- s->state_stack_len--;
- }
- }
- break;
- case REOP_char32:
- val = get_u32(pc);
- pc += 4;
- goto test_char;
- case REOP_char16:
- val = get_u16(pc);
- pc += 2;
- goto test_char;
- case REOP_char8:
- val = get_u8(pc);
- pc += 1;
- test_char:
- if (cptr >= cbuf_end)
- goto no_match;
- GET_CHAR(c, cptr, cbuf_end, cbuf_type);
- if (s->ignore_case) {
- c = lre_canonicalize(c, s->is_unicode);
- }
- if (val != c)
- goto no_match;
- break;
- case REOP_split_goto_first:
- case REOP_split_next_first:
- {
- const uint8_t *pc1;
- val = get_u32(pc);
- pc += 4;
- if (opcode == REOP_split_next_first) {
- pc1 = pc + (int)val;
- } else {
- pc1 = pc;
- pc = pc + (int)val;
- }
- ret = push_state(s, capture, stack, stack_len,
- pc1, cptr, RE_EXEC_STATE_SPLIT, 0);
- if (ret < 0)
- return LRE_RET_MEMORY_ERROR;
- break;
- }
- case REOP_lookahead:
- case REOP_negative_lookahead:
- val = get_u32(pc);
- pc += 4;
- ret = push_state(s, capture, stack, stack_len,
- pc + (int)val, cptr,
- RE_EXEC_STATE_LOOKAHEAD + opcode - REOP_lookahead,
- 0);
- if (ret < 0)
- return LRE_RET_MEMORY_ERROR;
- break;
- case REOP_goto:
- val = get_u32(pc);
- pc += 4 + (int)val;
- if (lre_poll_timeout(s))
- return LRE_RET_TIMEOUT;
- break;
- case REOP_line_start:
- if (cptr == s->cbuf)
- break;
- if (!s->multi_line)
- goto no_match;
- PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);
- if (!is_line_terminator(c))
- goto no_match;
- break;
- case REOP_line_end:
- if (cptr == cbuf_end)
- break;
- if (!s->multi_line)
- goto no_match;
- PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);
- if (!is_line_terminator(c))
- goto no_match;
- break;
- case REOP_dot:
- if (cptr == cbuf_end)
- goto no_match;
- GET_CHAR(c, cptr, cbuf_end, cbuf_type);
- if (is_line_terminator(c))
- goto no_match;
- break;
- case REOP_any:
- if (cptr == cbuf_end)
- goto no_match;
- GET_CHAR(c, cptr, cbuf_end, cbuf_type);
- break;
- case REOP_save_start:
- case REOP_save_end:
- val = *pc++;
- assert(val < s->capture_count);
- capture[2 * val + opcode - REOP_save_start] = (uint8_t *)cptr;
- break;
- case REOP_save_reset:
- {
- uint32_t val2;
- val = pc[0];
- val2 = pc[1];
- pc += 2;
- assert(val2 < s->capture_count);
- while (val <= val2) {
- capture[2 * val] = NULL;
- capture[2 * val + 1] = NULL;
- val++;
- }
- }
- break;
- case REOP_push_i32:
- val = get_u32(pc);
- pc += 4;
- stack[stack_len++] = val;
- break;
- case REOP_drop:
- stack_len--;
- break;
- case REOP_loop:
- val = get_u32(pc);
- pc += 4;
- if (--stack[stack_len - 1] != 0) {
- pc += (int)val;
- if (lre_poll_timeout(s))
- return LRE_RET_TIMEOUT;
- }
- break;
- case REOP_push_char_pos:
- stack[stack_len++] = (uintptr_t)cptr;
- break;
- case REOP_check_advance:
- if (stack[--stack_len] == (uintptr_t)cptr)
- goto no_match;
- break;
- case REOP_word_boundary:
- case REOP_not_word_boundary:
- {
- bool v1, v2;
- /* char before */
- if (cptr == s->cbuf) {
- v1 = false;
- } else {
- PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);
- v1 = is_word_char(c);
- }
- /* current char */
- if (cptr >= cbuf_end) {
- v2 = false;
- } else {
- PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);
- v2 = is_word_char(c);
- }
- if (v1 ^ v2 ^ (REOP_not_word_boundary - opcode))
- goto no_match;
- }
- break;
- case REOP_back_reference:
- case REOP_backward_back_reference:
- {
- const uint8_t *cptr1, *cptr1_end, *cptr1_start;
- uint32_t c1, c2;
- val = *pc++;
- if (val >= s->capture_count)
- goto no_match;
- cptr1_start = capture[2 * val];
- cptr1_end = capture[2 * val + 1];
- if (!cptr1_start || !cptr1_end)
- break;
- if (opcode == REOP_back_reference) {
- cptr1 = cptr1_start;
- while (cptr1 < cptr1_end) {
- if (cptr >= cbuf_end)
- goto no_match;
- GET_CHAR(c1, cptr1, cptr1_end, cbuf_type);
- GET_CHAR(c2, cptr, cbuf_end, cbuf_type);
- if (s->ignore_case) {
- c1 = lre_canonicalize(c1, s->is_unicode);
- c2 = lre_canonicalize(c2, s->is_unicode);
- }
- if (c1 != c2)
- goto no_match;
- }
- } else {
- cptr1 = cptr1_end;
- while (cptr1 > cptr1_start) {
- if (cptr == s->cbuf)
- goto no_match;
- GET_PREV_CHAR(c1, cptr1, cptr1_start, cbuf_type);
- GET_PREV_CHAR(c2, cptr, s->cbuf, cbuf_type);
- if (s->ignore_case) {
- c1 = lre_canonicalize(c1, s->is_unicode);
- c2 = lre_canonicalize(c2, s->is_unicode);
- }
- if (c1 != c2)
- goto no_match;
- }
- }
- }
- break;
- case REOP_range:
- {
- int n;
- uint32_t low, high, idx_min, idx_max, idx;
- n = get_u16(pc); /* n must be >= 1 */
- pc += 2;
- if (cptr >= cbuf_end)
- goto no_match;
- GET_CHAR(c, cptr, cbuf_end, cbuf_type);
- if (s->ignore_case) {
- c = lre_canonicalize(c, s->is_unicode);
- }
- idx_min = 0;
- low = get_u16(pc + 0 * 4);
- if (c < low)
- goto no_match;
- idx_max = n - 1;
- high = get_u16(pc + idx_max * 4 + 2);
- /* 0xffff in for last value means +infinity */
- if (unlikely(c >= 0xffff) && high == 0xffff)
- goto range_match;
- if (c > high)
- goto no_match;
- while (idx_min <= idx_max) {
- idx = (idx_min + idx_max) / 2;
- low = get_u16(pc + idx * 4);
- high = get_u16(pc + idx * 4 + 2);
- if (c < low)
- idx_max = idx - 1;
- else if (c > high)
- idx_min = idx + 1;
- else
- goto range_match;
- }
- goto no_match;
- range_match:
- pc += 4 * n;
- }
- break;
- case REOP_range32:
- {
- int n;
- uint32_t low, high, idx_min, idx_max, idx;
- n = get_u16(pc); /* n must be >= 1 */
- pc += 2;
- if (cptr >= cbuf_end)
- goto no_match;
- GET_CHAR(c, cptr, cbuf_end, cbuf_type);
- if (s->ignore_case) {
- c = lre_canonicalize(c, s->is_unicode);
- }
- idx_min = 0;
- low = get_u32(pc + 0 * 8);
- if (c < low)
- goto no_match;
- idx_max = n - 1;
- high = get_u32(pc + idx_max * 8 + 4);
- if (c > high)
- goto no_match;
- while (idx_min <= idx_max) {
- idx = (idx_min + idx_max) / 2;
- low = get_u32(pc + idx * 8);
- high = get_u32(pc + idx * 8 + 4);
- if (c < low)
- idx_max = idx - 1;
- else if (c > high)
- idx_min = idx + 1;
- else
- goto range32_match;
- }
- goto no_match;
- range32_match:
- pc += 8 * n;
- }
- break;
- case REOP_prev:
- /* go to the previous char */
- if (cptr == s->cbuf)
- goto no_match;
- PREV_CHAR(cptr, s->cbuf, cbuf_type);
- break;
- case REOP_simple_greedy_quant:
- {
- uint32_t next_pos, quant_min, quant_max;
- size_t q;
- intptr_t res;
- const uint8_t *pc1;
- next_pos = get_u32(pc);
- quant_min = get_u32(pc + 4);
- quant_max = get_u32(pc + 8);
- pc += 16;
- pc1 = pc;
- pc += (int)next_pos;
- q = 0;
- for(;;) {
- if (lre_poll_timeout(s))
- return LRE_RET_TIMEOUT;
- res = lre_exec_backtrack(s, capture, stack, stack_len,
- pc1, cptr, true);
- if (res == LRE_RET_MEMORY_ERROR ||
- res == LRE_RET_TIMEOUT)
- return res;
- if (!res)
- break;
- cptr = (uint8_t *)res;
- q++;
- if (q >= quant_max && quant_max != INT32_MAX)
- break;
- }
- if (q < quant_min)
- goto no_match;
- if (q > quant_min) {
- /* will examine all matches down to quant_min */
- ret = push_state(s, capture, stack, stack_len,
- pc1 - 16, cptr,
- RE_EXEC_STATE_GREEDY_QUANT,
- q - quant_min);
- if (ret < 0)
- return LRE_RET_MEMORY_ERROR;
- }
- }
- break;
- default:
- abort();
- }
- }
- }
- /* Return 1 if match, 0 if not match or < 0 if error (see LRE_RET_x). cindex is the
- starting position of the match and must be such as 0 <= cindex <=
- clen. */
- int lre_exec(uint8_t **capture,
- const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,
- int cbuf_type, void *opaque)
- {
- REExecContext s_s, *s = &s_s;
- int re_flags, i, alloca_size, ret;
- StackInt *stack_buf;
- re_flags = lre_get_flags(bc_buf);
- s->multi_line = (re_flags & LRE_FLAG_MULTILINE) != 0;
- s->ignore_case = (re_flags & LRE_FLAG_IGNORECASE) != 0;
- s->is_unicode = (re_flags & LRE_FLAG_UNICODE) != 0;
- s->capture_count = bc_buf[RE_HEADER_CAPTURE_COUNT];
- s->stack_size_max = bc_buf[RE_HEADER_STACK_SIZE];
- s->cbuf = cbuf;
- s->cbuf_end = cbuf + (clen << cbuf_type);
- s->cbuf_type = cbuf_type;
- if (s->cbuf_type == 1 && s->is_unicode)
- s->cbuf_type = 2;
- s->interrupt_counter = INTERRUPT_COUNTER_INIT;
- s->opaque = opaque;
- s->state_size = sizeof(REExecState) +
- s->capture_count * sizeof(capture[0]) * 2 +
- s->stack_size_max * sizeof(stack_buf[0]);
- s->state_stack = NULL;
- s->state_stack_len = 0;
- s->state_stack_size = 0;
- for(i = 0; i < s->capture_count * 2; i++)
- capture[i] = NULL;
- alloca_size = s->stack_size_max * sizeof(stack_buf[0]);
- stack_buf = alloca(alloca_size);
- ret = lre_exec_backtrack(s, capture, stack_buf, 0, bc_buf + RE_HEADER_LEN,
- cbuf + (cindex << cbuf_type), false);
- lre_realloc(s->opaque, s->state_stack, 0);
- return ret;
- }
- int lre_get_capture_count(const uint8_t *bc_buf)
- {
- return bc_buf[RE_HEADER_CAPTURE_COUNT];
- }
- int lre_get_flags(const uint8_t *bc_buf)
- {
- return get_u16(bc_buf + RE_HEADER_FLAGS);
- }
- /* Return NULL if no group names. Otherwise, return a pointer to
- 'capture_count - 1' zero terminated UTF-8 strings. */
- const char *lre_get_groupnames(const uint8_t *bc_buf)
- {
- uint32_t re_bytecode_len;
- if ((lre_get_flags(bc_buf) & LRE_FLAG_NAMED_GROUPS) == 0)
- return NULL;
- re_bytecode_len = get_u32(bc_buf + RE_HEADER_BYTECODE_LEN);
- return (const char *)(bc_buf + RE_HEADER_LEN + re_bytecode_len);
- }
- void lre_byte_swap(uint8_t *buf, size_t len, bool is_byte_swapped)
- {
- uint8_t *p, *pe;
- uint32_t n, r, nw;
- p = buf;
- if (len < RE_HEADER_LEN)
- abort();
- // format is:
- // <header>
- // <bytecode>
- // <capture group name 1>
- // <capture group name 2>
- // etc.
- inplace_bswap16(&p[RE_HEADER_FLAGS]);
- n = get_u32(&p[RE_HEADER_BYTECODE_LEN]);
- inplace_bswap32(&p[RE_HEADER_BYTECODE_LEN]);
- if (is_byte_swapped)
- n = bswap32(n);
- if (n > len - RE_HEADER_LEN)
- abort();
- p = &buf[RE_HEADER_LEN];
- pe = &p[n];
- while (p < pe) {
- n = reopcode_info[*p].size;
- switch (n) {
- case 1:
- case 2:
- break;
- case 3:
- switch (*p) {
- case REOP_save_reset: // has two 8 bit arguments
- break;
- case REOP_range32: // variable length
- nw = get_u16(&p[1]); // number of pairs of uint32_t
- if (is_byte_swapped)
- n = bswap16(n);
- for (r = 3 + 8 * nw; n < r; n += 4)
- inplace_bswap32(&p[n]);
- goto doswap16;
- case REOP_range: // variable length
- nw = get_u16(&p[1]); // number of pairs of uint16_t
- if (is_byte_swapped)
- n = bswap16(n);
- for (r = 3 + 4 * nw; n < r; n += 2)
- inplace_bswap16(&p[n]);
- goto doswap16;
- default:
- doswap16:
- inplace_bswap16(&p[1]);
- break;
- }
- break;
- case 5:
- inplace_bswap32(&p[1]);
- break;
- case 17:
- assert(*p == REOP_simple_greedy_quant);
- inplace_bswap32(&p[1]);
- inplace_bswap32(&p[5]);
- inplace_bswap32(&p[9]);
- inplace_bswap32(&p[13]);
- break;
- default:
- abort();
- }
- p = &p[n];
- }
- }
- #ifdef TEST
- bool lre_check_stack_overflow(void *opaque, size_t alloca_size)
- {
- return false;
- }
- void *lre_realloc(void *opaque, void *ptr, size_t size)
- {
- return realloc(ptr, size);
- }
- int main(int argc, char **argv)
- {
- int len, flags, ret, i;
- uint8_t *bc;
- char error_msg[64];
- uint8_t *capture[CAPTURE_COUNT_MAX * 2];
- const char *input;
- int input_len, capture_count;
- if (argc < 4) {
- printf("usage: %s regexp flags input\n", argv[0]);
- exit(1);
- }
- flags = atoi(argv[2]);
- bc = lre_compile(&len, error_msg, sizeof(error_msg), argv[1],
- strlen(argv[1]), flags, NULL);
- if (!bc) {
- fprintf(stderr, "error: %s\n", error_msg);
- exit(1);
- }
- input = argv[3];
- input_len = strlen(input);
- ret = lre_exec(capture, bc, (uint8_t *)input, 0, input_len, 0, NULL);
- printf("ret=%d\n", ret);
- if (ret == 1) {
- capture_count = lre_get_capture_count(bc);
- for(i = 0; i < 2 * capture_count; i++) {
- uint8_t *ptr;
- ptr = capture[i];
- printf("%d: ", i);
- if (!ptr)
- printf("<nil>");
- else
- printf("%u", (int)(ptr - (uint8_t *)input));
- printf("\n");
- }
- }
- return 0;
- }
- #endif
- /*
- * Unicode utilities
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include <assert.h>
- // note: stored as 4 bit tag, not much room left
- enum {
- RUN_TYPE_U,
- RUN_TYPE_L,
- RUN_TYPE_UF,
- RUN_TYPE_LF,
- RUN_TYPE_UL,
- RUN_TYPE_LSU,
- RUN_TYPE_U2L_399_EXT2,
- RUN_TYPE_UF_D20,
- RUN_TYPE_UF_D1_EXT,
- RUN_TYPE_U_EXT,
- RUN_TYPE_LF_EXT,
- RUN_TYPE_UF_EXT2,
- RUN_TYPE_LF_EXT2,
- RUN_TYPE_UF_EXT3,
- };
- static int lre_case_conv1(uint32_t c, int conv_type)
- {
- uint32_t res[LRE_CC_RES_LEN_MAX];
- lre_case_conv(res, c, conv_type);
- return res[0];
- }
- /* case conversion using the table entry 'idx' with value 'v' */
- static int lre_case_conv_entry(uint32_t *res, uint32_t c, int conv_type, uint32_t idx, uint32_t v)
- {
- uint32_t code, data, type, a, is_lower;
- is_lower = (conv_type != 0);
- type = (v >> (32 - 17 - 7 - 4)) & 0xf;
- data = ((v & 0xf) << 8) | case_conv_table2[idx];
- code = v >> (32 - 17);
- switch(type) {
- case RUN_TYPE_U:
- case RUN_TYPE_L:
- case RUN_TYPE_UF:
- case RUN_TYPE_LF:
- if (conv_type == (type & 1) ||
- (type >= RUN_TYPE_UF && conv_type == 2)) {
- c = c - code + (case_conv_table1[data] >> (32 - 17));
- }
- break;
- case RUN_TYPE_UL:
- a = c - code;
- if ((a & 1) != (1 - is_lower))
- break;
- c = (a ^ 1) + code;
- break;
- case RUN_TYPE_LSU:
- a = c - code;
- if (a == 1) {
- c += 2 * is_lower - 1;
- } else if (a == (1 - is_lower) * 2) {
- c += (2 * is_lower - 1) * 2;
- }
- break;
- case RUN_TYPE_U2L_399_EXT2:
- if (!is_lower) {
- res[0] = c - code + case_conv_ext[data >> 6];
- res[1] = 0x399;
- return 2;
- } else {
- c = c - code + case_conv_ext[data & 0x3f];
- }
- break;
- case RUN_TYPE_UF_D20:
- if (conv_type == 1)
- break;
- c = data + (conv_type == 2) * 0x20;
- break;
- case RUN_TYPE_UF_D1_EXT:
- if (conv_type == 1)
- break;
- c = case_conv_ext[data] + (conv_type == 2);
- break;
- case RUN_TYPE_U_EXT:
- case RUN_TYPE_LF_EXT:
- if (is_lower != (type - RUN_TYPE_U_EXT))
- break;
- c = case_conv_ext[data];
- break;
- case RUN_TYPE_LF_EXT2:
- if (!is_lower)
- break;
- res[0] = c - code + case_conv_ext[data >> 6];
- res[1] = case_conv_ext[data & 0x3f];
- return 2;
- case RUN_TYPE_UF_EXT2:
- if (conv_type == 1)
- break;
- res[0] = c - code + case_conv_ext[data >> 6];
- res[1] = case_conv_ext[data & 0x3f];
- if (conv_type == 2) {
- /* convert to lower */
- res[0] = lre_case_conv1(res[0], 1);
- res[1] = lre_case_conv1(res[1], 1);
- }
- return 2;
- default:
- case RUN_TYPE_UF_EXT3:
- if (conv_type == 1)
- break;
- res[0] = case_conv_ext[data >> 8];
- res[1] = case_conv_ext[(data >> 4) & 0xf];
- res[2] = case_conv_ext[data & 0xf];
- if (conv_type == 2) {
- /* convert to lower */
- res[0] = lre_case_conv1(res[0], 1);
- res[1] = lre_case_conv1(res[1], 1);
- res[2] = lre_case_conv1(res[2], 1);
- }
- return 3;
- }
- res[0] = c;
- return 1;
- }
- /* conv_type:
- 0 = to upper
- 1 = to lower
- 2 = case folding (= to lower with modifications)
- */
- int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
- {
- if (c < 128) {
- if (conv_type) {
- if (c >= 'A' && c <= 'Z') {
- c = c - 'A' + 'a';
- }
- } else {
- if (c >= 'a' && c <= 'z') {
- c = c - 'a' + 'A';
- }
- }
- } else {
- uint32_t v, code, len;
- int idx, idx_min, idx_max;
- idx_min = 0;
- idx_max = countof(case_conv_table1) - 1;
- while (idx_min <= idx_max) {
- idx = (unsigned)(idx_max + idx_min) / 2;
- v = case_conv_table1[idx];
- code = v >> (32 - 17);
- len = (v >> (32 - 17 - 7)) & 0x7f;
- if (c < code) {
- idx_max = idx - 1;
- } else if (c >= code + len) {
- idx_min = idx + 1;
- } else {
- return lre_case_conv_entry(res, c, conv_type, idx, v);
- }
- }
- }
- res[0] = c;
- return 1;
- }
- static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, bool is_unicode)
- {
- uint32_t res[LRE_CC_RES_LEN_MAX];
- int len;
- if (is_unicode) {
- len = lre_case_conv_entry(res, c, 2, idx, v);
- if (len == 1) {
- c = res[0];
- } else {
- /* handle the few specific multi-character cases (see
- unicode_gen.c:dump_case_folding_special_cases()) */
- if (c == 0xfb06) {
- c = 0xfb05;
- } else if (c == 0x01fd3) {
- c = 0x390;
- } else if (c == 0x01fe3) {
- c = 0x3b0;
- }
- }
- } else {
- if (likely(c < 128)) {
- if (c >= 'a' && c <= 'z')
- c = c - 'a' + 'A';
- } else {
- /* legacy regexp: to upper case if single char >= 128 */
- len = lre_case_conv_entry(res, c, false, idx, v);
- if (len == 1 && res[0] >= 128)
- c = res[0];
- }
- }
- return c;
- }
- /* JS regexp specific rules for case folding */
- int lre_canonicalize(uint32_t c, bool is_unicode)
- {
- if (c < 128) {
- /* fast case */
- if (is_unicode) {
- if (c >= 'A' && c <= 'Z') {
- c = c - 'A' + 'a';
- }
- } else {
- if (c >= 'a' && c <= 'z') {
- c = c - 'a' + 'A';
- }
- }
- } else {
- uint32_t v, code, len;
- int idx, idx_min, idx_max;
- idx_min = 0;
- idx_max = countof(case_conv_table1) - 1;
- while (idx_min <= idx_max) {
- idx = (unsigned)(idx_max + idx_min) / 2;
- v = case_conv_table1[idx];
- code = v >> (32 - 17);
- len = (v >> (32 - 17 - 7)) & 0x7f;
- if (c < code) {
- idx_max = idx - 1;
- } else if (c >= code + len) {
- idx_min = idx + 1;
- } else {
- return lre_case_folding_entry(c, idx, v, is_unicode);
- }
- }
- }
- return c;
- }
- static uint32_t get_le24(const uint8_t *ptr)
- {
- return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16);
- }
- #define UNICODE_INDEX_BLOCK_LEN 32
- /* return -1 if not in table, otherwise the offset in the block */
- static int get_index_pos(uint32_t *pcode, uint32_t c,
- const uint8_t *index_table, int index_table_len)
- {
- uint32_t code, v;
- int idx_min, idx_max, idx;
- idx_min = 0;
- v = get_le24(index_table);
- code = v & ((1 << 21) - 1);
- if (c < code) {
- *pcode = 0;
- return 0;
- }
- idx_max = index_table_len - 1;
- code = get_le24(index_table + idx_max * 3);
- if (c >= code)
- return -1;
- /* invariant: tab[idx_min] <= c < tab2[idx_max] */
- while ((idx_max - idx_min) > 1) {
- idx = (idx_max + idx_min) / 2;
- v = get_le24(index_table + idx * 3);
- code = v & ((1 << 21) - 1);
- if (c < code) {
- idx_max = idx;
- } else {
- idx_min = idx;
- }
- }
- v = get_le24(index_table + idx_min * 3);
- *pcode = v & ((1 << 21) - 1);
- return (idx_min + 1) * UNICODE_INDEX_BLOCK_LEN + (v >> 21);
- }
- static bool lre_is_in_table(uint32_t c, const uint8_t *table,
- const uint8_t *index_table, int index_table_len)
- {
- uint32_t code, b, bit;
- int pos;
- const uint8_t *p;
- pos = get_index_pos(&code, c, index_table, index_table_len);
- if (pos < 0)
- return false; /* outside the table */
- p = table + pos;
- bit = 0;
- for(;;) {
- b = *p++;
- if (b < 64) {
- code += (b >> 3) + 1;
- if (c < code)
- return bit;
- bit ^= 1;
- code += (b & 7) + 1;
- } else if (b >= 0x80) {
- code += b - 0x80 + 1;
- } else if (b < 0x60) {
- code += (((b - 0x40) << 8) | p[0]) + 1;
- p++;
- } else {
- code += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1;
- p += 2;
- }
- if (c < code)
- return bit;
- bit ^= 1;
- }
- }
- bool lre_is_cased(uint32_t c)
- {
- uint32_t v, code, len;
- int idx, idx_min, idx_max;
- idx_min = 0;
- idx_max = countof(case_conv_table1) - 1;
- while (idx_min <= idx_max) {
- idx = (unsigned)(idx_max + idx_min) / 2;
- v = case_conv_table1[idx];
- code = v >> (32 - 17);
- len = (v >> (32 - 17 - 7)) & 0x7f;
- if (c < code) {
- idx_max = idx - 1;
- } else if (c >= code + len) {
- idx_min = idx + 1;
- } else {
- return true;
- }
- }
- return lre_is_in_table(c, unicode_prop_Cased1_table,
- unicode_prop_Cased1_index,
- sizeof(unicode_prop_Cased1_index) / 3);
- }
- bool lre_is_case_ignorable(uint32_t c)
- {
- return lre_is_in_table(c, unicode_prop_Case_Ignorable_table,
- unicode_prop_Case_Ignorable_index,
- sizeof(unicode_prop_Case_Ignorable_index) / 3);
- }
- /* character range */
- static __maybe_unused void cr_dump(CharRange *cr)
- {
- int i;
- for(i = 0; i < cr->len; i++)
- printf("%d: 0x%04x\n", i, cr->points[i]);
- }
- static void *cr_default_realloc(void *opaque, void *ptr, size_t size)
- {
- return realloc(ptr, size);
- }
- void cr_init(CharRange *cr, void *mem_opaque, DynBufReallocFunc *realloc_func)
- {
- cr->len = cr->size = 0;
- cr->points = NULL;
- cr->mem_opaque = mem_opaque;
- cr->realloc_func = realloc_func ? realloc_func : cr_default_realloc;
- }
- void cr_free(CharRange *cr)
- {
- cr->realloc_func(cr->mem_opaque, cr->points, 0);
- }
- int cr_realloc(CharRange *cr, int size)
- {
- int new_size;
- uint32_t *new_buf;
- if (size > cr->size) {
- new_size = max_int(size, cr->size * 3 / 2);
- new_buf = cr->realloc_func(cr->mem_opaque, cr->points,
- new_size * sizeof(cr->points[0]));
- if (!new_buf)
- return -1;
- cr->points = new_buf;
- cr->size = new_size;
- }
- return 0;
- }
- int cr_copy(CharRange *cr, const CharRange *cr1)
- {
- if (cr_realloc(cr, cr1->len))
- return -1;
- memcpy(cr->points, cr1->points, sizeof(cr->points[0]) * cr1->len);
- cr->len = cr1->len;
- return 0;
- }
- /* merge consecutive intervals and remove empty intervals */
- static void cr_compress(CharRange *cr)
- {
- int i, j, k, len;
- uint32_t *pt;
- pt = cr->points;
- len = cr->len;
- i = 0;
- j = 0;
- k = 0;
- while ((i + 1) < len) {
- if (pt[i] == pt[i + 1]) {
- /* empty interval */
- i += 2;
- } else {
- j = i;
- while ((j + 3) < len && pt[j + 1] == pt[j + 2])
- j += 2;
- /* just copy */
- pt[k] = pt[i];
- pt[k + 1] = pt[j + 1];
- k += 2;
- i = j + 2;
- }
- }
- cr->len = k;
- }
- /* union or intersection */
- int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
- const uint32_t *b_pt, int b_len, int op)
- {
- int a_idx, b_idx, is_in;
- uint32_t v;
- a_idx = 0;
- b_idx = 0;
- for(;;) {
- /* get one more point from a or b in increasing order */
- if (a_idx < a_len && b_idx < b_len) {
- if (a_pt[a_idx] < b_pt[b_idx]) {
- goto a_add;
- } else if (a_pt[a_idx] == b_pt[b_idx]) {
- v = a_pt[a_idx];
- a_idx++;
- b_idx++;
- } else {
- goto b_add;
- }
- } else if (a_idx < a_len) {
- a_add:
- v = a_pt[a_idx++];
- } else if (b_idx < b_len) {
- b_add:
- v = b_pt[b_idx++];
- } else {
- break;
- }
- /* add the point if the in/out status changes */
- switch(op) {
- case CR_OP_UNION:
- is_in = (a_idx & 1) | (b_idx & 1);
- break;
- case CR_OP_INTER:
- is_in = (a_idx & 1) & (b_idx & 1);
- break;
- case CR_OP_XOR:
- is_in = (a_idx & 1) ^ (b_idx & 1);
- break;
- default:
- abort();
- }
- if (is_in != (cr->len & 1)) {
- if (cr_add_point(cr, v))
- return -1;
- }
- }
- cr_compress(cr);
- return 0;
- }
- int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len)
- {
- CharRange a = *cr;
- int ret;
- cr->len = 0;
- cr->size = 0;
- cr->points = NULL;
- ret = cr_op(cr, a.points, a.len, b_pt, b_len, CR_OP_UNION);
- cr_free(&a);
- return ret;
- }
- int cr_invert(CharRange *cr)
- {
- int len;
- len = cr->len;
- if (cr_realloc(cr, len + 2))
- return -1;
- memmove(cr->points + 1, cr->points, len * sizeof(cr->points[0]));
- cr->points[0] = 0;
- cr->points[len + 1] = UINT32_MAX;
- cr->len = len + 2;
- cr_compress(cr);
- return 0;
- }
- bool lre_is_id_start(uint32_t c)
- {
- return lre_is_in_table(c, unicode_prop_ID_Start_table,
- unicode_prop_ID_Start_index,
- sizeof(unicode_prop_ID_Start_index) / 3);
- }
- bool lre_is_id_continue(uint32_t c)
- {
- return lre_is_id_start(c) ||
- lre_is_in_table(c, unicode_prop_ID_Continue1_table,
- unicode_prop_ID_Continue1_index,
- sizeof(unicode_prop_ID_Continue1_index) / 3);
- }
- bool lre_is_white_space(uint32_t c)
- {
- return lre_is_in_table(c, unicode_prop_White_Space_table,
- unicode_prop_White_Space_index,
- sizeof(unicode_prop_White_Space_index) / 3);
- }
- #define UNICODE_DECOMP_LEN_MAX 18
- typedef enum {
- DECOMP_TYPE_C1, /* 16 bit char */
- DECOMP_TYPE_L1, /* 16 bit char table */
- DECOMP_TYPE_L2,
- DECOMP_TYPE_L3,
- DECOMP_TYPE_L4,
- DECOMP_TYPE_L5, /* XXX: not used */
- DECOMP_TYPE_L6, /* XXX: could remove */
- DECOMP_TYPE_L7, /* XXX: could remove */
- DECOMP_TYPE_LL1, /* 18 bit char table */
- DECOMP_TYPE_LL2,
- DECOMP_TYPE_S1, /* 8 bit char table */
- DECOMP_TYPE_S2,
- DECOMP_TYPE_S3,
- DECOMP_TYPE_S4,
- DECOMP_TYPE_S5,
- DECOMP_TYPE_I1, /* increment 16 bit char value */
- DECOMP_TYPE_I2_0,
- DECOMP_TYPE_I2_1,
- DECOMP_TYPE_I3_1,
- DECOMP_TYPE_I3_2,
- DECOMP_TYPE_I4_1,
- DECOMP_TYPE_I4_2,
- DECOMP_TYPE_B1, /* 16 bit base + 8 bit offset */
- DECOMP_TYPE_B2,
- DECOMP_TYPE_B3,
- DECOMP_TYPE_B4,
- DECOMP_TYPE_B5,
- DECOMP_TYPE_B6,
- DECOMP_TYPE_B7,
- DECOMP_TYPE_B8,
- DECOMP_TYPE_B18,
- DECOMP_TYPE_LS2,
- DECOMP_TYPE_PAT3,
- DECOMP_TYPE_S2_UL,
- DECOMP_TYPE_LS2_UL,
- } DecompTypeEnum;
- static uint32_t unicode_get_short_code(uint32_t c)
- {
- static const uint16_t unicode_short_table[2] = { 0x2044, 0x2215 };
- if (c < 0x80)
- return c;
- else if (c < 0x80 + 0x50)
- return c - 0x80 + 0x300;
- else
- return unicode_short_table[c - 0x80 - 0x50];
- }
- static uint32_t unicode_get_lower_simple(uint32_t c)
- {
- if (c < 0x100 || (c >= 0x410 && c <= 0x42f))
- c += 0x20;
- else
- c++;
- return c;
- }
- static uint16_t unicode_get16(const uint8_t *p)
- {
- return p[0] | (p[1] << 8);
- }
- static int unicode_decomp_entry(uint32_t *res, uint32_t c,
- int idx, uint32_t code, uint32_t len,
- uint32_t type)
- {
- uint32_t c1;
- int l, i, p;
- const uint8_t *d;
- if (type == DECOMP_TYPE_C1) {
- res[0] = unicode_decomp_table2[idx];
- return 1;
- } else {
- d = unicode_decomp_data + unicode_decomp_table2[idx];
- switch(type) {
- case DECOMP_TYPE_L1:
- case DECOMP_TYPE_L2:
- case DECOMP_TYPE_L3:
- case DECOMP_TYPE_L4:
- case DECOMP_TYPE_L5:
- case DECOMP_TYPE_L6:
- case DECOMP_TYPE_L7:
- l = type - DECOMP_TYPE_L1 + 1;
- d += (c - code) * l * 2;
- for(i = 0; i < l; i++) {
- if ((res[i] = unicode_get16(d + 2 * i)) == 0)
- return 0;
- }
- return l;
- case DECOMP_TYPE_LL1:
- case DECOMP_TYPE_LL2:
- {
- uint32_t k, p;
- l = type - DECOMP_TYPE_LL1 + 1;
- k = (c - code) * l;
- p = len * l * 2;
- for(i = 0; i < l; i++) {
- c1 = unicode_get16(d + 2 * k) |
- (((d[p + (k / 4)] >> ((k % 4) * 2)) & 3) << 16);
- if (!c1)
- return 0;
- res[i] = c1;
- k++;
- }
- }
- return l;
- case DECOMP_TYPE_S1:
- case DECOMP_TYPE_S2:
- case DECOMP_TYPE_S3:
- case DECOMP_TYPE_S4:
- case DECOMP_TYPE_S5:
- l = type - DECOMP_TYPE_S1 + 1;
- d += (c - code) * l;
- for(i = 0; i < l; i++) {
- if ((res[i] = unicode_get_short_code(d[i])) == 0)
- return 0;
- }
- return l;
- case DECOMP_TYPE_I1:
- l = 1;
- p = 0;
- goto decomp_type_i;
- case DECOMP_TYPE_I2_0:
- case DECOMP_TYPE_I2_1:
- case DECOMP_TYPE_I3_1:
- case DECOMP_TYPE_I3_2:
- case DECOMP_TYPE_I4_1:
- case DECOMP_TYPE_I4_2:
- l = 2 + ((type - DECOMP_TYPE_I2_0) >> 1);
- p = ((type - DECOMP_TYPE_I2_0) & 1) + (l > 2);
- decomp_type_i:
- for(i = 0; i < l; i++) {
- c1 = unicode_get16(d + 2 * i);
- if (i == p)
- c1 += c - code;
- res[i] = c1;
- }
- return l;
- case DECOMP_TYPE_B18:
- l = 18;
- goto decomp_type_b;
- case DECOMP_TYPE_B1:
- case DECOMP_TYPE_B2:
- case DECOMP_TYPE_B3:
- case DECOMP_TYPE_B4:
- case DECOMP_TYPE_B5:
- case DECOMP_TYPE_B6:
- case DECOMP_TYPE_B7:
- case DECOMP_TYPE_B8:
- l = type - DECOMP_TYPE_B1 + 1;
- decomp_type_b:
- {
- uint32_t c_min;
- c_min = unicode_get16(d);
- d += 2 + (c - code) * l;
- for(i = 0; i < l; i++) {
- c1 = d[i];
- if (c1 == 0xff)
- c1 = 0x20;
- else
- c1 += c_min;
- res[i] = c1;
- }
- }
- return l;
- case DECOMP_TYPE_LS2:
- d += (c - code) * 3;
- if (!(res[0] = unicode_get16(d)))
- return 0;
- res[1] = unicode_get_short_code(d[2]);
- return 2;
- case DECOMP_TYPE_PAT3:
- res[0] = unicode_get16(d);
- res[2] = unicode_get16(d + 2);
- d += 4 + (c - code) * 2;
- res[1] = unicode_get16(d);
- return 3;
- case DECOMP_TYPE_S2_UL:
- case DECOMP_TYPE_LS2_UL:
- c1 = c - code;
- if (type == DECOMP_TYPE_S2_UL) {
- d += c1 & ~1;
- c = unicode_get_short_code(*d);
- d++;
- } else {
- d += (c1 >> 1) * 3;
- c = unicode_get16(d);
- d += 2;
- }
- if (c1 & 1)
- c = unicode_get_lower_simple(c);
- res[0] = c;
- res[1] = unicode_get_short_code(*d);
- return 2;
- }
- }
- return 0;
- }
- /* return the length of the decomposition (length <=
- UNICODE_DECOMP_LEN_MAX) or 0 if no decomposition */
- static int unicode_decomp_char(uint32_t *res, uint32_t c, bool is_compat1)
- {
- uint32_t v, type, is_compat, code, len;
- int idx_min, idx_max, idx;
- idx_min = 0;
- idx_max = countof(unicode_decomp_table1) - 1;
- while (idx_min <= idx_max) {
- idx = (idx_max + idx_min) / 2;
- v = unicode_decomp_table1[idx];
- code = v >> (32 - 18);
- len = (v >> (32 - 18 - 7)) & 0x7f;
- // printf("idx=%d code=%05x len=%d\n", idx, code, len);
- if (c < code) {
- idx_max = idx - 1;
- } else if (c >= code + len) {
- idx_min = idx + 1;
- } else {
- is_compat = v & 1;
- if (is_compat1 < is_compat)
- break;
- type = (v >> (32 - 18 - 7 - 6)) & 0x3f;
- return unicode_decomp_entry(res, c, idx, code, len, type);
- }
- }
- return 0;
- }
- /* return 0 if no pair found */
- static int unicode_compose_pair(uint32_t c0, uint32_t c1)
- {
- uint32_t code, len, type, v, idx1, d_idx, d_offset, ch;
- int idx_min, idx_max, idx, d;
- uint32_t pair[2];
- idx_min = 0;
- idx_max = countof(unicode_comp_table) - 1;
- while (idx_min <= idx_max) {
- idx = (idx_max + idx_min) / 2;
- idx1 = unicode_comp_table[idx];
- /* idx1 represent an entry of the decomposition table */
- d_idx = idx1 >> 6;
- d_offset = idx1 & 0x3f;
- v = unicode_decomp_table1[d_idx];
- code = v >> (32 - 18);
- len = (v >> (32 - 18 - 7)) & 0x7f;
- type = (v >> (32 - 18 - 7 - 6)) & 0x3f;
- ch = code + d_offset;
- unicode_decomp_entry(pair, ch, d_idx, code, len, type);
- d = c0 - pair[0];
- if (d == 0)
- d = c1 - pair[1];
- if (d < 0) {
- idx_max = idx - 1;
- } else if (d > 0) {
- idx_min = idx + 1;
- } else {
- return ch;
- }
- }
- return 0;
- }
- /* return the combining class of character c (between 0 and 255) */
- static int unicode_get_cc(uint32_t c)
- {
- uint32_t code, n, type, cc, c1, b;
- int pos;
- const uint8_t *p;
- pos = get_index_pos(&code, c,
- unicode_cc_index, sizeof(unicode_cc_index) / 3);
- if (pos < 0)
- return 0;
- p = unicode_cc_table + pos;
- for(;;) {
- b = *p++;
- type = b >> 6;
- n = b & 0x3f;
- if (n < 48) {
- } else if (n < 56) {
- n = (n - 48) << 8;
- n |= *p++;
- n += 48;
- } else {
- n = (n - 56) << 8;
- n |= *p++ << 8;
- n |= *p++;
- n += 48 + (1 << 11);
- }
- if (type <= 1)
- p++;
- c1 = code + n + 1;
- if (c < c1) {
- switch(type) {
- case 0:
- cc = p[-1];
- break;
- case 1:
- cc = p[-1] + c - code;
- break;
- case 2:
- cc = 0;
- break;
- default:
- case 3:
- cc = 230;
- break;
- }
- return cc;
- }
- code = c1;
- }
- }
- static void sort_cc(int *buf, int len)
- {
- int i, j, k, cc, cc1, start, ch1;
- for(i = 0; i < len; i++) {
- cc = unicode_get_cc(buf[i]);
- if (cc != 0) {
- start = i;
- j = i + 1;
- while (j < len) {
- ch1 = buf[j];
- cc1 = unicode_get_cc(ch1);
- if (cc1 == 0)
- break;
- k = j - 1;
- while (k >= start) {
- if (unicode_get_cc(buf[k]) <= cc1)
- break;
- buf[k + 1] = buf[k];
- k--;
- }
- buf[k + 1] = ch1;
- j++;
- }
- i = j;
- }
- }
- }
- static void to_nfd_rec(DynBuf *dbuf,
- const int *src, int src_len, int is_compat)
- {
- uint32_t c, v;
- int i, l;
- uint32_t res[UNICODE_DECOMP_LEN_MAX];
- for(i = 0; i < src_len; i++) {
- c = src[i];
- if (c >= 0xac00 && c < 0xd7a4) {
- /* Hangul decomposition */
- c -= 0xac00;
- dbuf_put_u32(dbuf, 0x1100 + c / 588);
- dbuf_put_u32(dbuf, 0x1161 + (c % 588) / 28);
- v = c % 28;
- if (v != 0)
- dbuf_put_u32(dbuf, 0x11a7 + v);
- } else {
- l = unicode_decomp_char(res, c, is_compat);
- if (l) {
- to_nfd_rec(dbuf, (int *)res, l, is_compat);
- } else {
- dbuf_put_u32(dbuf, c);
- }
- }
- }
- }
- /* return 0 if not found */
- static int compose_pair(uint32_t c0, uint32_t c1)
- {
- /* Hangul composition */
- if (c0 >= 0x1100 && c0 < 0x1100 + 19 &&
- c1 >= 0x1161 && c1 < 0x1161 + 21) {
- return 0xac00 + (c0 - 0x1100) * 588 + (c1 - 0x1161) * 28;
- } else if (c0 >= 0xac00 && c0 < 0xac00 + 11172 &&
- (c0 - 0xac00) % 28 == 0 &&
- c1 >= 0x11a7 && c1 < 0x11a7 + 28) {
- return c0 + c1 - 0x11a7;
- } else {
- return unicode_compose_pair(c0, c1);
- }
- }
- int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
- UnicodeNormalizationEnum n_type,
- void *opaque, DynBufReallocFunc *realloc_func)
- {
- int *buf, buf_len, i, p, starter_pos, cc, last_cc, out_len;
- bool is_compat;
- DynBuf dbuf_s, *dbuf = &dbuf_s;
- is_compat = n_type >> 1;
- dbuf_init2(dbuf, opaque, realloc_func);
- if (dbuf_realloc(dbuf, sizeof(int) * src_len))
- goto fail;
- /* common case: latin1 is unaffected by NFC */
- if (n_type == UNICODE_NFC) {
- for(i = 0; i < src_len; i++) {
- if (src[i] >= 0x100)
- goto not_latin1;
- }
- buf = (int *)dbuf->buf;
- memcpy(buf, src, src_len * sizeof(int));
- *pdst = (uint32_t *)buf;
- return src_len;
- not_latin1: ;
- }
- to_nfd_rec(dbuf, (const int *)src, src_len, is_compat);
- if (dbuf_error(dbuf)) {
- fail:
- *pdst = NULL;
- return -1;
- }
- buf = (int *)dbuf->buf;
- buf_len = dbuf->size / sizeof(int);
- sort_cc(buf, buf_len);
- if (buf_len <= 1 || (n_type & 1) != 0) {
- /* NFD / NFKD */
- *pdst = (uint32_t *)buf;
- return buf_len;
- }
- i = 1;
- out_len = 1;
- while (i < buf_len) {
- /* find the starter character and test if it is blocked from
- the character at 'i' */
- last_cc = unicode_get_cc(buf[i]);
- starter_pos = out_len - 1;
- while (starter_pos >= 0) {
- cc = unicode_get_cc(buf[starter_pos]);
- if (cc == 0)
- break;
- if (cc >= last_cc)
- goto next;
- last_cc = 256;
- starter_pos--;
- }
- if (starter_pos >= 0 &&
- (p = compose_pair(buf[starter_pos], buf[i])) != 0) {
- buf[starter_pos] = p;
- i++;
- } else {
- next:
- buf[out_len++] = buf[i++];
- }
- }
- *pdst = (uint32_t *)buf;
- return out_len;
- }
- /* char ranges for various unicode properties */
- static int unicode_find_name(const char *name_table, const char *name)
- {
- const char *p, *r;
- int pos;
- size_t name_len, len;
- p = name_table;
- pos = 0;
- name_len = strlen(name);
- while (*p) {
- for(;;) {
- r = strchr(p, ',');
- if (!r)
- len = strlen(p);
- else
- len = r - p;
- if (len == name_len && !memcmp(p, name, name_len))
- return pos;
- p += len + 1;
- if (!r)
- break;
- }
- pos++;
- }
- return -1;
- }
- /* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2
- if not found */
- int unicode_script(CharRange *cr,
- const char *script_name, bool is_ext)
- {
- int script_idx;
- const uint8_t *p, *p_end;
- uint32_t c, c1, b, n, v, v_len, i, type;
- CharRange cr1_s = { 0 }, *cr1 = NULL;
- CharRange cr2_s = { 0 }, *cr2 = &cr2_s;
- bool is_common;
- script_idx = unicode_find_name(unicode_script_name_table, script_name);
- if (script_idx < 0)
- return -2;
- /* Note: we remove the "Unknown" Script */
- script_idx += UNICODE_SCRIPT_Unknown + 1;
- is_common = (script_idx == UNICODE_SCRIPT_Common ||
- script_idx == UNICODE_SCRIPT_Inherited);
- if (is_ext) {
- cr1 = &cr1_s;
- cr_init(cr1, cr->mem_opaque, cr->realloc_func);
- cr_init(cr2, cr->mem_opaque, cr->realloc_func);
- } else {
- cr1 = cr;
- }
- p = unicode_script_table;
- p_end = unicode_script_table + countof(unicode_script_table);
- c = 0;
- while (p < p_end) {
- b = *p++;
- type = b >> 7;
- n = b & 0x7f;
- if (n < 96) {
- } else if (n < 112) {
- n = (n - 96) << 8;
- n |= *p++;
- n += 96;
- } else {
- n = (n - 112) << 16;
- n |= *p++ << 8;
- n |= *p++;
- n += 96 + (1 << 12);
- }
- if (type == 0)
- v = 0;
- else
- v = *p++;
- c1 = c + n + 1;
- if (v == script_idx) {
- if (cr_add_interval(cr1, c, c1))
- goto fail;
- }
- c = c1;
- }
- if (is_ext) {
- /* add the script extensions */
- p = unicode_script_ext_table;
- p_end = unicode_script_ext_table + countof(unicode_script_ext_table);
- c = 0;
- while (p < p_end) {
- b = *p++;
- if (b < 128) {
- n = b;
- } else if (b < 128 + 64) {
- n = (b - 128) << 8;
- n |= *p++;
- n += 128;
- } else {
- n = (b - 128 - 64) << 16;
- n |= *p++ << 8;
- n |= *p++;
- n += 128 + (1 << 14);
- }
- c1 = c + n + 1;
- v_len = *p++;
- if (is_common) {
- if (v_len != 0) {
- if (cr_add_interval(cr2, c, c1))
- goto fail;
- }
- } else {
- for(i = 0; i < v_len; i++) {
- if (p[i] == script_idx) {
- if (cr_add_interval(cr2, c, c1))
- goto fail;
- break;
- }
- }
- }
- p += v_len;
- c = c1;
- }
- if (is_common) {
- /* remove all the characters with script extensions */
- if (cr_invert(cr2))
- goto fail;
- if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len,
- CR_OP_INTER))
- goto fail;
- } else {
- if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len,
- CR_OP_UNION))
- goto fail;
- }
- cr_free(cr1);
- cr_free(cr2);
- }
- return 0;
- fail:
- if (is_ext) {
- cr_free(cr1);
- cr_free(cr2);
- }
- goto fail;
- }
- #define M(id) (1U << UNICODE_GC_ ## id)
- static int unicode_general_category1(CharRange *cr, uint32_t gc_mask)
- {
- const uint8_t *p, *p_end;
- uint32_t c, c0, b, n, v;
- p = unicode_gc_table;
- p_end = unicode_gc_table + countof(unicode_gc_table);
- c = 0;
- while (p < p_end) {
- b = *p++;
- n = b >> 5;
- v = b & 0x1f;
- if (n == 7) {
- n = *p++;
- if (n < 128) {
- n += 7;
- } else if (n < 128 + 64) {
- n = (n - 128) << 8;
- n |= *p++;
- n += 7 + 128;
- } else {
- n = (n - 128 - 64) << 16;
- n |= *p++ << 8;
- n |= *p++;
- n += 7 + 128 + (1 << 14);
- }
- }
- c0 = c;
- c += n + 1;
- if (v == 31) {
- /* run of Lu / Ll */
- b = gc_mask & (M(Lu) | M(Ll));
- if (b != 0) {
- if (b == (M(Lu) | M(Ll))) {
- goto add_range;
- } else {
- c0 += ((gc_mask & M(Ll)) != 0);
- for(; c0 < c; c0 += 2) {
- if (cr_add_interval(cr, c0, c0 + 1))
- return -1;
- }
- }
- }
- } else if ((gc_mask >> v) & 1) {
- add_range:
- if (cr_add_interval(cr, c0, c))
- return -1;
- }
- }
- return 0;
- }
- static int unicode_prop1(CharRange *cr, int prop_idx)
- {
- const uint8_t *p, *p_end;
- uint32_t c, c0, b, bit;
- p = unicode_prop_table[prop_idx];
- p_end = p + unicode_prop_len_table[prop_idx];
- c = 0;
- bit = 0;
- while (p < p_end) {
- c0 = c;
- b = *p++;
- if (b < 64) {
- c += (b >> 3) + 1;
- if (bit) {
- if (cr_add_interval(cr, c0, c))
- return -1;
- }
- bit ^= 1;
- c0 = c;
- c += (b & 7) + 1;
- } else if (b >= 0x80) {
- c += b - 0x80 + 1;
- } else if (b < 0x60) {
- c += (((b - 0x40) << 8) | p[0]) + 1;
- p++;
- } else {
- c += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1;
- p += 2;
- }
- if (bit) {
- if (cr_add_interval(cr, c0, c))
- return -1;
- }
- bit ^= 1;
- }
- return 0;
- }
- #define CASE_U (1 << 0)
- #define CASE_L (1 << 1)
- #define CASE_F (1 << 2)
- /* use the case conversion table to generate range of characters.
- CASE_U: set char if modified by uppercasing,
- CASE_L: set char if modified by lowercasing,
- CASE_F: set char if modified by case folding,
- */
- static int unicode_case1(CharRange *cr, int case_mask)
- {
- #define MR(x) (1 << RUN_TYPE_ ## x)
- const uint32_t tab_run_mask[3] = {
- MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) |
- MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
- MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2),
- MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
- };
- #undef MR
- uint32_t mask, v, code, type, len, i, idx;
- if (case_mask == 0)
- return 0;
- mask = 0;
- for(i = 0; i < 3; i++) {
- if ((case_mask >> i) & 1)
- mask |= tab_run_mask[i];
- }
- for(idx = 0; idx < countof(case_conv_table1); idx++) {
- v = case_conv_table1[idx];
- type = (v >> (32 - 17 - 7 - 4)) & 0xf;
- code = v >> (32 - 17);
- len = (v >> (32 - 17 - 7)) & 0x7f;
- if ((mask >> type) & 1) {
- // printf("%d: type=%d %04x %04x\n", idx, type, code, code + len - 1);
- switch(type) {
- case RUN_TYPE_UL:
- if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
- goto def_case;
- code += ((case_mask & CASE_U) != 0);
- for(i = 0; i < len; i += 2) {
- if (cr_add_interval(cr, code + i, code + i + 1))
- return -1;
- }
- break;
- case RUN_TYPE_LSU:
- if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
- goto def_case;
- if (!(case_mask & CASE_U)) {
- if (cr_add_interval(cr, code, code + 1))
- return -1;
- }
- if (cr_add_interval(cr, code + 1, code + 2))
- return -1;
- if (case_mask & CASE_U) {
- if (cr_add_interval(cr, code + 2, code + 3))
- return -1;
- }
- break;
- default:
- def_case:
- if (cr_add_interval(cr, code, code + len))
- return -1;
- break;
- }
- }
- }
- return 0;
- }
- static int point_cmp(const void *p1, const void *p2, void *arg)
- {
- uint32_t v1 = *(uint32_t *)p1;
- uint32_t v2 = *(uint32_t *)p2;
- return (v1 > v2) - (v1 < v2);
- }
- static void cr_sort_and_remove_overlap(CharRange *cr)
- {
- uint32_t start, end, start1, end1, i, j;
- /* the resulting ranges are not necessarily sorted and may overlap */
- rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp, NULL);
- j = 0;
- for(i = 0; i < cr->len; ) {
- start = cr->points[i];
- end = cr->points[i + 1];
- i += 2;
- while (i < cr->len) {
- start1 = cr->points[i];
- end1 = cr->points[i + 1];
- if (start1 > end) {
- /* |------|
- * |-------| */
- break;
- } else if (end1 <= end) {
- /* |------|
- * |--| */
- i += 2;
- } else {
- /* |------|
- * |-------| */
- end = end1;
- i += 2;
- }
- }
- cr->points[j] = start;
- cr->points[j + 1] = end;
- j += 2;
- }
- cr->len = j;
- }
- /* canonicalize a character set using the JS regex case folding rules
- (see lre_canonicalize()) */
- int cr_regexp_canonicalize(CharRange *cr, bool is_unicode)
- {
- CharRange cr_inter, cr_mask, cr_result, cr_sub;
- uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d;
- cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func);
- cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func);
- cr_init(&cr_result, cr->mem_opaque, cr->realloc_func);
- cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func);
- if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U))
- goto fail;
- if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
- goto fail;
- if (cr_invert(&cr_mask))
- goto fail;
- if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
- goto fail;
- /* cr_inter = cr & cr_mask */
- /* cr_sub = cr & ~cr_mask */
- /* use the case conversion table to compute the result */
- d_start = -1;
- d_end = -1;
- idx = 0;
- v = case_conv_table1[idx];
- code = v >> (32 - 17);
- len = (v >> (32 - 17 - 7)) & 0x7f;
- for(i = 0; i < cr_inter.len; i += 2) {
- start = cr_inter.points[i];
- end = cr_inter.points[i + 1];
- for(c = start; c < end; c++) {
- for(;;) {
- if (c >= code && c < code + len)
- break;
- idx++;
- assert(idx < countof(case_conv_table1));
- v = case_conv_table1[idx];
- code = v >> (32 - 17);
- len = (v >> (32 - 17 - 7)) & 0x7f;
- }
- d = lre_case_folding_entry(c, idx, v, is_unicode);
- /* try to merge with the current interval */
- if (d_start == -1) {
- d_start = d;
- d_end = d + 1;
- } else if (d_end == d) {
- d_end++;
- } else {
- cr_add_interval(&cr_result, d_start, d_end);
- d_start = d;
- d_end = d + 1;
- }
- }
- }
- if (d_start != -1) {
- if (cr_add_interval(&cr_result, d_start, d_end))
- goto fail;
- }
- /* the resulting ranges are not necessarily sorted and may overlap */
- cr_sort_and_remove_overlap(&cr_result);
- /* or with the character not affected by the case folding */
- cr->len = 0;
- if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len, CR_OP_UNION))
- goto fail;
- cr_free(&cr_inter);
- cr_free(&cr_mask);
- cr_free(&cr_result);
- cr_free(&cr_sub);
- return 0;
- fail:
- cr_free(&cr_inter);
- cr_free(&cr_mask);
- cr_free(&cr_result);
- cr_free(&cr_sub);
- return -1;
- }
- typedef enum {
- POP_GC,
- POP_PROP,
- POP_CASE,
- POP_UNION,
- POP_INTER,
- POP_XOR,
- POP_INVERT,
- POP_END,
- } PropOPEnum;
- #define POP_STACK_LEN_MAX 4
- static int unicode_prop_ops(CharRange *cr, ...)
- {
- va_list ap;
- CharRange stack[POP_STACK_LEN_MAX];
- int stack_len, op, ret, i;
- uint32_t a;
- va_start(ap, cr);
- stack_len = 0;
- for(;;) {
- op = va_arg(ap, int);
- switch(op) {
- case POP_GC:
- assert(stack_len < POP_STACK_LEN_MAX);
- a = va_arg(ap, int);
- cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func);
- if (unicode_general_category1(&stack[stack_len - 1], a))
- goto fail;
- break;
- case POP_PROP:
- assert(stack_len < POP_STACK_LEN_MAX);
- a = va_arg(ap, int);
- cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func);
- if (unicode_prop1(&stack[stack_len - 1], a))
- goto fail;
- break;
- case POP_CASE:
- assert(stack_len < POP_STACK_LEN_MAX);
- a = va_arg(ap, int);
- cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func);
- if (unicode_case1(&stack[stack_len - 1], a))
- goto fail;
- break;
- case POP_UNION:
- case POP_INTER:
- case POP_XOR:
- {
- CharRange *cr1, *cr2, *cr3;
- assert(stack_len >= 2);
- assert(stack_len < POP_STACK_LEN_MAX);
- cr1 = &stack[stack_len - 2];
- cr2 = &stack[stack_len - 1];
- cr3 = &stack[stack_len++];
- cr_init(cr3, cr->mem_opaque, cr->realloc_func);
- if (cr_op(cr3, cr1->points, cr1->len,
- cr2->points, cr2->len, op - POP_UNION + CR_OP_UNION))
- goto fail;
- cr_free(cr1);
- cr_free(cr2);
- *cr1 = *cr3;
- stack_len -= 2;
- }
- break;
- case POP_INVERT:
- assert(stack_len >= 1);
- if (cr_invert(&stack[stack_len - 1]))
- goto fail;
- break;
- case POP_END:
- goto done;
- default:
- abort();
- }
- }
- done:
- va_end(ap);
- assert(stack_len == 1);
- ret = cr_copy(cr, &stack[0]);
- cr_free(&stack[0]);
- return ret;
- fail:
- va_end(ap);
- for(i = 0; i < stack_len; i++)
- cr_free(&stack[i]);
- return -1;
- }
- static const uint32_t unicode_gc_mask_table[] = {
- M(Lu) | M(Ll) | M(Lt), /* LC */
- M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo), /* L */
- M(Mn) | M(Mc) | M(Me), /* M */
- M(Nd) | M(Nl) | M(No), /* N */
- M(Sm) | M(Sc) | M(Sk) | M(So), /* S */
- M(Pc) | M(Pd) | M(Ps) | M(Pe) | M(Pi) | M(Pf) | M(Po), /* P */
- M(Zs) | M(Zl) | M(Zp), /* Z */
- M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn), /* C */
- };
- /* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2
- if not found */
- int unicode_general_category(CharRange *cr, const char *gc_name)
- {
- int gc_idx;
- uint32_t gc_mask;
- gc_idx = unicode_find_name(unicode_gc_name_table, gc_name);
- if (gc_idx < 0)
- return -2;
- if (gc_idx <= UNICODE_GC_Co) {
- gc_mask = (uint64_t)1 << gc_idx;
- } else {
- gc_mask = unicode_gc_mask_table[gc_idx - UNICODE_GC_LC];
- }
- return unicode_general_category1(cr, gc_mask);
- }
- /* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2
- if not found */
- int unicode_prop(CharRange *cr, const char *prop_name)
- {
- int prop_idx, ret;
- prop_idx = unicode_find_name(unicode_prop_name_table, prop_name);
- if (prop_idx < 0)
- return -2;
- prop_idx += UNICODE_PROP_ASCII_Hex_Digit;
- ret = 0;
- switch(prop_idx) {
- case UNICODE_PROP_ASCII:
- if (cr_add_interval(cr, 0x00, 0x7f + 1))
- return -1;
- break;
- case UNICODE_PROP_Any:
- if (cr_add_interval(cr, 0x00000, 0x10ffff + 1))
- return -1;
- break;
- case UNICODE_PROP_Assigned:
- ret = unicode_prop_ops(cr,
- POP_GC, M(Cn),
- POP_INVERT,
- POP_END);
- break;
- case UNICODE_PROP_Math:
- ret = unicode_prop_ops(cr,
- POP_GC, M(Sm),
- POP_PROP, UNICODE_PROP_Other_Math,
- POP_UNION,
- POP_END);
- break;
- case UNICODE_PROP_Lowercase:
- ret = unicode_prop_ops(cr,
- POP_GC, M(Ll),
- POP_PROP, UNICODE_PROP_Other_Lowercase,
- POP_UNION,
- POP_END);
- break;
- case UNICODE_PROP_Uppercase:
- ret = unicode_prop_ops(cr,
- POP_GC, M(Lu),
- POP_PROP, UNICODE_PROP_Other_Uppercase,
- POP_UNION,
- POP_END);
- break;
- case UNICODE_PROP_Cased:
- ret = unicode_prop_ops(cr,
- POP_GC, M(Lu) | M(Ll) | M(Lt),
- POP_PROP, UNICODE_PROP_Other_Uppercase,
- POP_UNION,
- POP_PROP, UNICODE_PROP_Other_Lowercase,
- POP_UNION,
- POP_END);
- break;
- case UNICODE_PROP_Alphabetic:
- ret = unicode_prop_ops(cr,
- POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl),
- POP_PROP, UNICODE_PROP_Other_Uppercase,
- POP_UNION,
- POP_PROP, UNICODE_PROP_Other_Lowercase,
- POP_UNION,
- POP_PROP, UNICODE_PROP_Other_Alphabetic,
- POP_UNION,
- POP_END);
- break;
- case UNICODE_PROP_Grapheme_Base:
- ret = unicode_prop_ops(cr,
- POP_GC, M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn) | M(Zl) | M(Zp) | M(Me) | M(Mn),
- POP_PROP, UNICODE_PROP_Other_Grapheme_Extend,
- POP_UNION,
- POP_INVERT,
- POP_END);
- break;
- case UNICODE_PROP_Grapheme_Extend:
- ret = unicode_prop_ops(cr,
- POP_GC, M(Me) | M(Mn),
- POP_PROP, UNICODE_PROP_Other_Grapheme_Extend,
- POP_UNION,
- POP_END);
- break;
- case UNICODE_PROP_XID_Start:
- ret = unicode_prop_ops(cr,
- POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl),
- POP_PROP, UNICODE_PROP_Other_ID_Start,
- POP_UNION,
- POP_PROP, UNICODE_PROP_Pattern_Syntax,
- POP_PROP, UNICODE_PROP_Pattern_White_Space,
- POP_UNION,
- POP_PROP, UNICODE_PROP_XID_Start1,
- POP_UNION,
- POP_INVERT,
- POP_INTER,
- POP_END);
- break;
- case UNICODE_PROP_XID_Continue:
- ret = unicode_prop_ops(cr,
- POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) |
- M(Mn) | M(Mc) | M(Nd) | M(Pc),
- POP_PROP, UNICODE_PROP_Other_ID_Start,
- POP_UNION,
- POP_PROP, UNICODE_PROP_Other_ID_Continue,
- POP_UNION,
- POP_PROP, UNICODE_PROP_Pattern_Syntax,
- POP_PROP, UNICODE_PROP_Pattern_White_Space,
- POP_UNION,
- POP_PROP, UNICODE_PROP_XID_Continue1,
- POP_UNION,
- POP_INVERT,
- POP_INTER,
- POP_END);
- break;
- case UNICODE_PROP_Changes_When_Uppercased:
- ret = unicode_case1(cr, CASE_U);
- break;
- case UNICODE_PROP_Changes_When_Lowercased:
- ret = unicode_case1(cr, CASE_L);
- break;
- case UNICODE_PROP_Changes_When_Casemapped:
- ret = unicode_case1(cr, CASE_U | CASE_L | CASE_F);
- break;
- case UNICODE_PROP_Changes_When_Titlecased:
- ret = unicode_prop_ops(cr,
- POP_CASE, CASE_U,
- POP_PROP, UNICODE_PROP_Changes_When_Titlecased1,
- POP_XOR,
- POP_END);
- break;
- case UNICODE_PROP_Changes_When_Casefolded:
- ret = unicode_prop_ops(cr,
- POP_CASE, CASE_F,
- POP_PROP, UNICODE_PROP_Changes_When_Casefolded1,
- POP_XOR,
- POP_END);
- break;
- case UNICODE_PROP_Changes_When_NFKC_Casefolded:
- ret = unicode_prop_ops(cr,
- POP_CASE, CASE_F,
- POP_PROP, UNICODE_PROP_Changes_When_NFKC_Casefolded1,
- POP_XOR,
- POP_END);
- break;
- /* we use the existing tables */
- case UNICODE_PROP_ID_Continue:
- ret = unicode_prop_ops(cr,
- POP_PROP, UNICODE_PROP_ID_Start,
- POP_PROP, UNICODE_PROP_ID_Continue1,
- POP_XOR,
- POP_END);
- break;
- default:
- if (prop_idx >= countof(unicode_prop_table))
- return -2;
- ret = unicode_prop1(cr, prop_idx);
- break;
- }
- return ret;
- }
- #ifdef QJS_BUILD_LIBC
- /*
- * QuickJS C library
- *
- * Copyright (c) 2017-2018 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifndef QUICKJS_LIBC_H
- #define QUICKJS_LIBC_H
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- #if defined(__GNUC__) || defined(__clang__)
- #define JS_EXTERN __attribute__((visibility("default")))
- #else
- #define JS_EXTERN /* nothing */
- #endif
- JS_EXTERN JSModuleDef *js_init_module_std(JSContext *ctx,
- const char *module_name);
- JS_EXTERN JSModuleDef *js_init_module_os(JSContext *ctx,
- const char *module_name);
- JS_EXTERN JSModuleDef *js_init_module_bjson(JSContext *ctx,
- const char *module_name);
- JS_EXTERN void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
- JS_EXTERN int js_std_loop(JSContext *ctx);
- JS_EXTERN JSValue js_std_await(JSContext *ctx, JSValue obj);
- JS_EXTERN void js_std_init_handlers(JSRuntime *rt);
- JS_EXTERN void js_std_free_handlers(JSRuntime *rt);
- JS_EXTERN void js_std_dump_error(JSContext *ctx);
- JS_EXTERN uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len,
- const char *filename);
- JS_EXTERN int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
- bool use_realpath, bool is_main);
- JS_EXTERN JSModuleDef *js_module_loader(JSContext *ctx,
- const char *module_name, void *opaque);
- JS_EXTERN void js_std_eval_binary(JSContext *ctx, const uint8_t *buf,
- size_t buf_len, int flags);
- JS_EXTERN void js_std_promise_rejection_tracker(JSContext *ctx,
- JSValueConst promise,
- JSValueConst reason,
- bool is_handled,
- void *opaque);
- JS_EXTERN void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));
- #undef JS_EXTERN
- #ifdef __cplusplus
- } /* extern "C" { */
- #endif
- #endif /* QUICKJS_LIBC_H */
- /*
- * QuickJS C library
- *
- * Copyright (c) 2017-2021 Fabrice Bellard
- * Copyright (c) 2017-2021 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <inttypes.h>
- #include <string.h>
- #include <assert.h>
- #include <errno.h>
- #include <fcntl.h>
- #if !defined(_MSC_VER)
- #include <sys/time.h>
- #include <unistd.h>
- #endif
- #include <time.h>
- #include <signal.h>
- #include <limits.h>
- #include <sys/stat.h>
- #if !defined(_MSC_VER)
- #include <dirent.h>
- #endif
- #if defined(_WIN32)
- #include <windows.h>
- #include <direct.h>
- #include <io.h>
- #include <conio.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <sys/utime.h>
- #define popen _popen
- #define pclose _pclose
- #define rmdir _rmdir
- #define getcwd _getcwd
- #define chdir _chdir
- #else
- #include <sys/ioctl.h>
- #include <poll.h>
- #if !defined(__wasi__)
- #include <dlfcn.h>
- #include <termios.h>
- #include <sys/resource.h>
- #include <sys/wait.h>
- #include <grp.h>
- #endif
- #if defined(__APPLE__)
- typedef sig_t sighandler_t;
- #include <crt_externs.h>
- #define environ (*_NSGetEnviron())
- #endif
- #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
- typedef sig_t sighandler_t;
- extern char **environ;
- #endif
- #endif /* _WIN32 */
- #if JS_HAVE_THREADS
- #define USE_WORKER // enable os.Worker
- #endif
- #ifndef S_IFBLK
- #define S_IFBLK 0
- #endif
- #ifndef S_IFIFO
- #define S_IFIFO 0
- #endif
- #ifndef MAX_SAFE_INTEGER // already defined in amalgamation builds
- #define MAX_SAFE_INTEGER (((int64_t) 1 << 53) - 1)
- #endif
- #ifndef QJS_NATIVE_MODULE_SUFFIX
- #ifdef _WIN32
- #define QJS_NATIVE_MODULE_SUFFIX ".dll"
- #else
- #define QJS_NATIVE_MODULE_SUFFIX ".so"
- #endif
- #endif
- /* TODO:
- - add socket calls
- */
- typedef struct {
- struct list_head link;
- int fd;
- JSValue rw_func[2];
- } JSOSRWHandler;
- typedef struct {
- struct list_head link;
- int sig_num;
- JSValue func;
- } JSOSSignalHandler;
- typedef struct {
- struct list_head link;
- int64_t timer_id;
- uint8_t repeats:1;
- int64_t timeout;
- int64_t delay;
- JSValue func;
- } JSOSTimer;
- typedef struct {
- struct list_head link;
- JSValue promise;
- JSValue reason;
- } JSRejectedPromiseEntry;
- #ifdef USE_WORKER
- typedef struct {
- struct list_head link;
- uint8_t *data;
- size_t data_len;
- /* list of SharedArrayBuffers, necessary to free the message */
- uint8_t **sab_tab;
- size_t sab_tab_len;
- } JSWorkerMessage;
- typedef struct JSWaker {
- #ifdef _WIN32
- HANDLE handle;
- #else
- int read_fd;
- int write_fd;
- #endif
- } JSWaker;
- typedef struct {
- int ref_count;
- js_mutex_t mutex;
- struct list_head msg_queue; /* list of JSWorkerMessage.link */
- JSWaker waker;
- } JSWorkerMessagePipe;
- typedef struct {
- struct list_head link;
- JSWorkerMessagePipe *recv_pipe;
- JSValue on_message_func;
- } JSWorkerMessageHandler;
- #endif // USE_WORKER
- typedef struct JSThreadState {
- struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */
- struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */
- struct list_head os_timers; /* list of JSOSTimer.link */
- struct list_head port_list; /* list of JSWorkerMessageHandler.link */
- struct list_head rejected_promise_list; /* list of JSRejectedPromiseEntry.link */
- int eval_script_recurse; /* only used in the main thread */
- int64_t next_timer_id; /* for setTimeout / setInterval */
- bool can_js_os_poll;
- /* not used in the main thread */
- #ifdef USE_WORKER
- JSWorkerMessagePipe *recv_pipe, *send_pipe;
- #else
- void *recv_pipe;
- #endif // USE_WORKER
- JSClassID std_file_class_id;
- JSClassID worker_class_id;
- } JSThreadState;
- static uint64_t os_pending_signals;
- static void *js_std_dbuf_realloc(void *opaque, void *ptr, size_t size)
- {
- JSRuntime *rt = opaque;
- return js_realloc_rt(rt, ptr, size);
- }
- static void js_std_dbuf_init(JSContext *ctx, DynBuf *s)
- {
- dbuf_init2(s, JS_GetRuntime(ctx), js_std_dbuf_realloc);
- }
- static bool my_isdigit(int c)
- {
- return (c >= '0' && c <= '9');
- }
- static JSThreadState *js_get_thread_state(JSRuntime *rt)
- {
- return (JSThreadState *)js_std_cmd(/*GetOpaque*/0, rt);
- }
- static void js_set_thread_state(JSRuntime *rt, JSThreadState *ts)
- {
- js_std_cmd(/*SetOpaque*/1, rt, ts);
- }
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wformat-nonliteral"
- #endif // __GNUC__
- static JSValue js_printf_internal(JSContext *ctx,
- int argc, JSValueConst *argv, FILE *fp)
- {
- char fmtbuf[32];
- uint8_t cbuf[UTF8_CHAR_LEN_MAX+1];
- JSValue res;
- DynBuf dbuf;
- const char *fmt_str = NULL;
- const uint8_t *fmt, *fmt_end;
- const uint8_t *p;
- char *q;
- int i, c, len, mod;
- size_t fmt_len;
- int32_t int32_arg;
- int64_t int64_arg;
- double double_arg;
- const char *string_arg;
- js_std_dbuf_init(ctx, &dbuf);
- if (argc > 0) {
- fmt_str = JS_ToCStringLen(ctx, &fmt_len, argv[0]);
- if (!fmt_str)
- goto fail;
- i = 1;
- fmt = (const uint8_t *)fmt_str;
- fmt_end = fmt + fmt_len;
- while (fmt < fmt_end) {
- for (p = fmt; fmt < fmt_end && *fmt != '%'; fmt++)
- continue;
- dbuf_put(&dbuf, p, fmt - p);
- if (fmt >= fmt_end)
- break;
- q = fmtbuf;
- *q++ = *fmt++; /* copy '%' */
- /* flags */
- for(;;) {
- c = *fmt;
- if (c == '0' || c == '#' || c == '+' || c == '-' || c == ' ' ||
- c == '\'') {
- if (q >= fmtbuf + sizeof(fmtbuf) - 1)
- goto invalid;
- *q++ = c;
- fmt++;
- } else {
- break;
- }
- }
- /* width */
- if (*fmt == '*') {
- if (i >= argc)
- goto missing;
- if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
- goto fail;
- q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
- fmt++;
- } else {
- while (my_isdigit(*fmt)) {
- if (q >= fmtbuf + sizeof(fmtbuf) - 1)
- goto invalid;
- *q++ = *fmt++;
- }
- }
- if (*fmt == '.') {
- if (q >= fmtbuf + sizeof(fmtbuf) - 1)
- goto invalid;
- *q++ = *fmt++;
- if (*fmt == '*') {
- if (i >= argc)
- goto missing;
- if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
- goto fail;
- q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
- fmt++;
- } else {
- while (my_isdigit(*fmt)) {
- if (q >= fmtbuf + sizeof(fmtbuf) - 1)
- goto invalid;
- *q++ = *fmt++;
- }
- }
- }
- /* we only support the "l" modifier for 64 bit numbers */
- mod = ' ';
- if (*fmt == 'l') {
- mod = *fmt++;
- }
- /* type */
- c = *fmt++;
- if (q >= fmtbuf + sizeof(fmtbuf) - 1)
- goto invalid;
- *q++ = c;
- *q = '\0';
- switch (c) {
- case 'c':
- if (i >= argc)
- goto missing;
- if (JS_IsString(argv[i])) {
- // TODO(chqrlie) need an API to wrap charCodeAt and codePointAt */
- string_arg = JS_ToCString(ctx, argv[i++]);
- if (!string_arg)
- goto fail;
- int32_arg = utf8_decode((const uint8_t *)string_arg, &p);
- JS_FreeCString(ctx, string_arg);
- } else {
- if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
- goto fail;
- }
- // XXX: throw an exception?
- if ((unsigned)int32_arg > 0x10FFFF)
- int32_arg = 0xFFFD;
- /* ignore conversion flags, width and precision */
- len = utf8_encode(cbuf, int32_arg);
- dbuf_put(&dbuf, cbuf, len);
- break;
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- if (i >= argc)
- goto missing;
- if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))
- goto fail;
- if (mod == 'l') {
- /* 64 bit number */
- #if defined(_WIN32)
- if (q >= fmtbuf + sizeof(fmtbuf) - 3)
- goto invalid;
- q[2] = q[-1];
- q[-1] = 'I';
- q[0] = '6';
- q[1] = '4';
- q[3] = '\0';
- dbuf_printf(&dbuf, fmtbuf, (int64_t)int64_arg);
- #else
- if (q >= fmtbuf + sizeof(fmtbuf) - 2)
- goto invalid;
- q[1] = q[-1];
- q[-1] = q[0] = 'l';
- q[2] = '\0';
- dbuf_printf(&dbuf, fmtbuf, (long long)int64_arg);
- #endif
- } else {
- dbuf_printf(&dbuf, fmtbuf, (int)int64_arg);
- }
- break;
- case 's':
- if (i >= argc)
- goto missing;
- /* XXX: handle strings containing null characters */
- string_arg = JS_ToCString(ctx, argv[i++]);
- if (!string_arg)
- goto fail;
- dbuf_printf(&dbuf, fmtbuf, string_arg);
- JS_FreeCString(ctx, string_arg);
- break;
- case 'e':
- case 'f':
- case 'g':
- case 'a':
- case 'E':
- case 'F':
- case 'G':
- case 'A':
- if (i >= argc)
- goto missing;
- if (JS_ToFloat64(ctx, &double_arg, argv[i++]))
- goto fail;
- dbuf_printf(&dbuf, fmtbuf, double_arg);
- break;
- case '%':
- dbuf_putc(&dbuf, '%');
- break;
- default:
- /* XXX: should support an extension mechanism */
- invalid:
- JS_ThrowTypeError(ctx, "invalid conversion specifier in format string");
- goto fail;
- missing:
- JS_ThrowReferenceError(ctx, "missing argument for conversion specifier");
- goto fail;
- }
- }
- JS_FreeCString(ctx, fmt_str);
- }
- if (dbuf.error) {
- res = JS_ThrowOutOfMemory(ctx);
- } else {
- if (fp) {
- len = fwrite(dbuf.buf, 1, dbuf.size, fp);
- res = JS_NewInt32(ctx, len);
- } else {
- res = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size);
- }
- }
- dbuf_free(&dbuf);
- return res;
- fail:
- JS_FreeCString(ctx, fmt_str);
- dbuf_free(&dbuf);
- return JS_EXCEPTION;
- }
- #ifdef __GNUC__
- #pragma GCC diagnostic pop // ignored "-Wformat-nonliteral"
- #endif // __GNUC__
- uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename)
- {
- FILE *f;
- size_t n, len;
- uint8_t *p, *buf, tmp[8192];
- f = fopen(filename, "rb");
- if (!f)
- return NULL;
- buf = NULL;
- len = 0;
- do {
- n = fread(tmp, 1, sizeof(tmp), f);
- if (ctx) {
- p = js_realloc(ctx, buf, len + n + 1);
- } else {
- p = realloc(buf, len + n + 1);
- }
- if (!p) {
- if (ctx) {
- js_free(ctx, buf);
- } else {
- free(buf);
- }
- fclose(f);
- return NULL;
- }
- memcpy(&p[len], tmp, n);
- buf = p;
- len += n;
- buf[len] = '\0';
- } while (n == sizeof(tmp));
- fclose(f);
- *pbuf_len = len;
- return buf;
- }
- /* load and evaluate a file */
- static JSValue js_loadScript(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- uint8_t *buf;
- const char *filename;
- JSValue ret;
- size_t buf_len;
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- return JS_EXCEPTION;
- buf = js_load_file(ctx, &buf_len, filename);
- if (!buf) {
- JS_ThrowReferenceError(ctx, "could not load '%s'", filename);
- JS_FreeCString(ctx, filename);
- return JS_EXCEPTION;
- }
- ret = JS_Eval(ctx, (char *)buf, buf_len, filename,
- JS_EVAL_TYPE_GLOBAL);
- js_free(ctx, buf);
- JS_FreeCString(ctx, filename);
- return ret;
- }
- static int get_bool_option(JSContext *ctx, bool *pbool,
- JSValueConst obj,
- const char *option)
- {
- JSValue val;
- val = JS_GetPropertyStr(ctx, obj, option);
- if (JS_IsException(val))
- return -1;
- if (!JS_IsUndefined(val)) {
- *pbool = JS_ToBool(ctx, val);
- }
- JS_FreeValue(ctx, val);
- return 0;
- }
- static void free_buf(JSRuntime *rt, void *opaque, void *ptr) {
- js_free_rt(rt, ptr);
- }
- /* load a file as a UTF-8 encoded string or Uint8Array */
- static JSValue js_std_loadFile(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- uint8_t *buf;
- const char *filename;
- JSValueConst options_obj;
- JSValue ret;
- size_t buf_len;
- bool binary = false;
- if (argc >= 2) {
- options_obj = argv[1];
- if (get_bool_option(ctx, &binary, options_obj,
- "binary"))
- return JS_EXCEPTION;
- }
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- return JS_EXCEPTION;
- buf = js_load_file(ctx, &buf_len, filename);
- JS_FreeCString(ctx, filename);
- if (!buf)
- return JS_NULL;
- if (binary) {
- ret = JS_NewUint8Array(ctx, buf, buf_len, free_buf, NULL, false);
- } else {
- ret = JS_NewStringLen(ctx, (char *)buf, buf_len);
- js_free(ctx, buf);
- }
- return ret;
- }
- static JSValue js_std_writeFile(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *filename;
- const char *mode;
- const void *buf;
- size_t len, n;
- JSValueConst data;
- JSValue val, ret, unref;
- bool release;
- FILE *fp;
- ret = JS_EXCEPTION;
- len = 0;
- buf = "";
- mode = "w";
- data = argv[1];
- unref = JS_UNDEFINED;
- release = false;
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- return JS_EXCEPTION;
- if (JS_IsObject(data)) {
- val = JS_GetPropertyStr(ctx, data, "buffer");
- if (JS_IsException(val))
- goto exception;
- if (JS_IsArrayBuffer(val)) {
- data = unref = val;
- } else {
- JS_FreeValue(ctx, val);
- }
- }
- if (JS_IsArrayBuffer(data)) {
- buf = JS_GetArrayBuffer(ctx, &len, data);
- mode = "wb";
- } else if (!JS_IsUndefined(data)) {
- buf = JS_ToCStringLen(ctx, &len, data);
- release = true;
- }
- if (!buf)
- goto exception;
- fp = fopen(filename, mode);
- if (!fp) {
- JS_ThrowPlainError(ctx, "error opening %s for writing", filename);
- goto exception;
- }
- n = fwrite(buf, len, 1, fp);
- fclose(fp);
- if (n != 1) {
- JS_ThrowPlainError(ctx, "error writing to %s", filename);
- goto exception;
- }
- ret = JS_UNDEFINED;
- exception:
- JS_FreeCString(ctx, filename);
- if (release)
- JS_FreeCString(ctx, buf);
- JS_FreeValue(ctx, unref);
- return ret;
- }
- typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,
- const char *module_name);
- #if defined(_WIN32)
- static JSModuleDef *js_module_loader_so(JSContext *ctx,
- const char *module_name)
- {
- JSModuleDef *m;
- HINSTANCE hd;
- JSInitModuleFunc *init;
- char *filename = NULL;
- size_t len = strlen(module_name);
- bool is_absolute = len > 2 && ((module_name[0] >= 'A' && module_name[0] <= 'Z') ||
- (module_name[0] >= 'a' && module_name[0] <= 'z')) && module_name[1] == ':';
- bool is_relative = len > 2 && module_name[0] == '.' && (module_name[1] == '/' || module_name[1] == '\\');
- if (is_absolute || is_relative) {
- filename = (char *)module_name;
- } else {
- filename = js_malloc(ctx, len + 2 + 1);
- if (!filename)
- return NULL;
- strcpy(filename, "./");
- strcpy(filename + 2, module_name);
- }
- hd = LoadLibraryA(filename);
- if (filename != module_name)
- js_free(ctx, filename);
- if (hd == NULL) {
- JS_ThrowReferenceError(ctx, "js_load_module '%s' error: %lu",
- module_name, GetLastError());
- goto fail;
- }
- init = (JSInitModuleFunc *)(uintptr_t)GetProcAddress(hd, "js_init_module");
- if (!init) {
- JS_ThrowReferenceError(ctx, "js_init_module '%s' not found: %lu",
- module_name, GetLastError());
- goto fail;
- }
- m = init(ctx, module_name);
- if (!m) {
- JS_ThrowReferenceError(ctx, "js_call_module '%s' initialization error",
- module_name);
- fail:
- if (hd != NULL)
- FreeLibrary(hd);
- return NULL;
- }
- return m;
- }
- #elif defined(__wasi__)
- static JSModuleDef *js_module_loader_so(JSContext *ctx,
- const char *module_name)
- {
- JS_ThrowReferenceError(ctx, "shared library modules are not supported yet");
- return NULL;
- }
- #else
- static JSModuleDef *js_module_loader_so(JSContext *ctx,
- const char *module_name)
- {
- JSModuleDef *m;
- void *hd;
- JSInitModuleFunc *init;
- char *filename;
- if (!strchr(module_name, '/')) {
- /* must add a '/' so that the DLL is not searched in the
- system library paths */
- filename = js_malloc(ctx, strlen(module_name) + 2 + 1);
- if (!filename)
- return NULL;
- strcpy(filename, "./");
- strcpy(filename + 2, module_name);
- } else {
- filename = (char *)module_name;
- }
- /* C module */
- hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
- if (filename != module_name)
- js_free(ctx, filename);
- if (!hd) {
- JS_ThrowReferenceError(ctx, "could not load module filename '%s' as shared library: %s",
- module_name, dlerror());
- goto fail;
- }
- *(void **) (&init) = dlsym(hd, "js_init_module");
- if (!init) {
- JS_ThrowReferenceError(ctx, "could not load module filename '%s': js_init_module not found",
- module_name);
- goto fail;
- }
- m = init(ctx, module_name);
- if (!m) {
- JS_ThrowReferenceError(ctx, "could not load module filename '%s': initialization error",
- module_name);
- fail:
- if (hd)
- dlclose(hd);
- return NULL;
- }
- return m;
- }
- #endif /* !_WIN32 */
- int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
- bool use_realpath, bool is_main)
- {
- JSModuleDef *m;
- char buf[JS__PATH_MAX + 16];
- JSValue meta_obj;
- JSAtom module_name_atom;
- const char *module_name;
- assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE);
- m = JS_VALUE_GET_PTR(func_val);
- module_name_atom = JS_GetModuleName(ctx, m);
- module_name = JS_AtomToCString(ctx, module_name_atom);
- JS_FreeAtom(ctx, module_name_atom);
- if (!module_name)
- return -1;
- if (!strchr(module_name, ':')) {
- strcpy(buf, "file://");
- #if !defined(_WIN32) && !defined(__wasi__)
- /* realpath() cannot be used with modules compiled with qjsc
- because the corresponding module source code is not
- necessarily present */
- if (use_realpath) {
- char *res = realpath(module_name, buf + strlen(buf));
- if (!res) {
- JS_ThrowTypeError(ctx, "realpath failure");
- JS_FreeCString(ctx, module_name);
- return -1;
- }
- } else
- #endif
- {
- js__pstrcat(buf, sizeof(buf), module_name);
- }
- } else {
- js__pstrcpy(buf, sizeof(buf), module_name);
- }
- JS_FreeCString(ctx, module_name);
- meta_obj = JS_GetImportMeta(ctx, m);
- if (JS_IsException(meta_obj))
- return -1;
- JS_DefinePropertyValueStr(ctx, meta_obj, "url",
- JS_NewString(ctx, buf),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, meta_obj, "main",
- JS_NewBool(ctx, is_main),
- JS_PROP_C_W_E);
- JS_FreeValue(ctx, meta_obj);
- return 0;
- }
- JSModuleDef *js_module_loader(JSContext *ctx,
- const char *module_name, void *opaque)
- {
- JSModuleDef *m;
- if (js__has_suffix(module_name, QJS_NATIVE_MODULE_SUFFIX)) {
- m = js_module_loader_so(ctx, module_name);
- } else {
- size_t buf_len;
- uint8_t *buf;
- JSValue func_val;
- buf = js_load_file(ctx, &buf_len, module_name);
- if (!buf) {
- JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
- module_name);
- return NULL;
- }
- /* compile the module */
- func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
- JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
- js_free(ctx, buf);
- if (JS_IsException(func_val))
- return NULL;
- if (js_module_set_import_meta(ctx, func_val, true, false) < 0) {
- JS_FreeValue(ctx, func_val);
- return NULL;
- }
- /* the module is already referenced, so we must free it */
- m = JS_VALUE_GET_PTR(func_val);
- JS_FreeValue(ctx, func_val);
- }
- return m;
- }
- static JSValue js_std_exit(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int status;
- if (JS_ToInt32(ctx, &status, argv[0]))
- status = -1;
- exit(status);
- return JS_UNDEFINED;
- }
- static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *name, *str;
- name = JS_ToCString(ctx, argv[0]);
- if (!name)
- return JS_EXCEPTION;
- str = getenv(name);
- JS_FreeCString(ctx, name);
- if (!str)
- return JS_UNDEFINED;
- else
- return JS_NewString(ctx, str);
- }
- #if defined(_WIN32)
- static void setenv(const char *name, const char *value, int overwrite)
- {
- char *str;
- size_t name_len, value_len;
- name_len = strlen(name);
- value_len = strlen(value);
- str = malloc(name_len + 1 + value_len + 1);
- memcpy(str, name, name_len);
- str[name_len] = '=';
- memcpy(str + name_len + 1, value, value_len);
- str[name_len + 1 + value_len] = '\0';
- _putenv(str);
- free(str);
- }
- static void unsetenv(const char *name)
- {
- setenv(name, "", true);
- }
- #endif /* _WIN32 */
- static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *name, *value;
- name = JS_ToCString(ctx, argv[0]);
- if (!name)
- return JS_EXCEPTION;
- value = JS_ToCString(ctx, argv[1]);
- if (!value) {
- JS_FreeCString(ctx, name);
- return JS_EXCEPTION;
- }
- setenv(name, value, true);
- JS_FreeCString(ctx, name);
- JS_FreeCString(ctx, value);
- return JS_UNDEFINED;
- }
- static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *name;
- name = JS_ToCString(ctx, argv[0]);
- if (!name)
- return JS_EXCEPTION;
- unsetenv(name);
- JS_FreeCString(ctx, name);
- return JS_UNDEFINED;
- }
- /* return an object containing the list of the available environment
- variables. */
- static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- char **envp;
- const char *name, *p, *value;
- JSValue obj;
- uint32_t idx;
- size_t name_len;
- JSAtom atom;
- int ret;
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- envp = environ;
- for(idx = 0; envp[idx] != NULL; idx++) {
- name = envp[idx];
- p = strchr(name, '=');
- name_len = p - name;
- if (!p)
- continue;
- value = p + 1;
- atom = JS_NewAtomLen(ctx, name, name_len);
- if (atom == JS_ATOM_NULL)
- goto fail;
- ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value),
- JS_PROP_C_W_E);
- JS_FreeAtom(ctx, atom);
- if (ret < 0)
- goto fail;
- }
- return obj;
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JS_RunGC(JS_GetRuntime(ctx));
- return JS_UNDEFINED;
- }
- static int interrupt_handler(JSRuntime *rt, void *opaque)
- {
- return (os_pending_signals >> SIGINT) & 1;
- }
- static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- const char *str = NULL;
- size_t len;
- JSValue ret, obj;
- JSValueConst options_obj, arg;
- bool backtrace_barrier = false;
- bool eval_function = false;
- bool eval_module = false;
- bool compile_only = false;
- bool compile_module = false;
- bool is_async = false;
- int flags;
- if (argc >= 2) {
- options_obj = argv[1];
- if (get_bool_option(ctx, &backtrace_barrier, options_obj,
- "backtrace_barrier"))
- return JS_EXCEPTION;
- if (get_bool_option(ctx, &eval_function, options_obj,
- "eval_function"))
- return JS_EXCEPTION;
- if (get_bool_option(ctx, &eval_module, options_obj,
- "eval_module"))
- return JS_EXCEPTION;
- if (get_bool_option(ctx, &compile_only, options_obj,
- "compile_only"))
- return JS_EXCEPTION;
- if (get_bool_option(ctx, &compile_module, options_obj,
- "compile_module"))
- return JS_EXCEPTION;
- if (get_bool_option(ctx, &is_async, options_obj,
- "async"))
- return JS_EXCEPTION;
- }
- if (eval_module) {
- arg = argv[0];
- if (JS_VALUE_GET_TAG(arg) != JS_TAG_MODULE)
- return JS_ThrowTypeError(ctx, "not a module");
- if (JS_ResolveModule(ctx, arg) < 0)
- return JS_EXCEPTION;
- if (js_module_set_import_meta(ctx, arg, false, false) < 0)
- return JS_EXCEPTION;
- return JS_EvalFunction(ctx, JS_DupValue(ctx, arg));
- }
- if (!eval_function) {
- str = JS_ToCStringLen(ctx, &len, argv[0]);
- if (!str)
- return JS_EXCEPTION;
- }
- if (!ts->recv_pipe && ++ts->eval_script_recurse == 1) {
- /* install the interrupt handler */
- JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL);
- }
- flags = compile_module ? JS_EVAL_TYPE_MODULE : JS_EVAL_TYPE_GLOBAL;
- if (backtrace_barrier)
- flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER;
- if (compile_only)
- flags |= JS_EVAL_FLAG_COMPILE_ONLY;
- if (is_async)
- flags |= JS_EVAL_FLAG_ASYNC;
- if (eval_function) {
- obj = JS_DupValue(ctx, argv[0]);
- ret = JS_EvalFunction(ctx, obj); // takes ownership of |obj|
- } else {
- ret = JS_Eval(ctx, str, len, "<evalScript>", flags);
- }
- JS_FreeCString(ctx, str);
- if (!ts->recv_pipe && --ts->eval_script_recurse == 0) {
- /* remove the interrupt handler */
- JS_SetInterruptHandler(JS_GetRuntime(ctx), NULL, NULL);
- os_pending_signals &= ~((uint64_t)1 << SIGINT);
- /* convert the uncatchable "interrupted" error into a normal error
- so that it can be caught by the REPL */
- if (JS_IsException(ret))
- JS_ResetUncatchableError(ctx);
- }
- return ret;
- }
- typedef struct {
- FILE *f;
- bool is_popen;
- } JSSTDFile;
- static bool is_stdio(FILE *f)
- {
- return f == stdin || f == stdout || f == stderr;
- }
- static void js_std_file_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSThreadState *ts = js_get_thread_state(rt);
- JSSTDFile *s = JS_GetOpaque(val, ts->std_file_class_id);
- if (s) {
- if (s->f && !is_stdio(s->f)) {
- #if !defined(__wasi__)
- if (s->is_popen)
- pclose(s->f);
- else
- #endif
- fclose(s->f);
- }
- js_free_rt(rt, s);
- }
- }
- static ssize_t js_get_errno(ssize_t ret)
- {
- if (ret == -1)
- ret = -errno;
- return ret;
- }
- static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int err;
- if (JS_ToInt32(ctx, &err, argv[0]))
- return JS_EXCEPTION;
- return JS_NewString(ctx, strerror(err));
- }
- static JSValue js_new_std_file(JSContext *ctx, FILE *f, bool is_popen)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSSTDFile *s;
- JSValue obj;
- obj = JS_NewObjectClass(ctx, ts->std_file_class_id);
- if (JS_IsException(obj))
- return obj;
- s = js_mallocz(ctx, sizeof(*s));
- if (!s) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- s->is_popen = is_popen;
- s->f = f;
- JS_SetOpaque(obj, s);
- return obj;
- }
- static void js_set_error_object(JSContext *ctx, JSValueConst obj, int err)
- {
- if (!JS_IsUndefined(obj)) {
- JS_SetPropertyStr(ctx, obj, "errno", JS_NewInt32(ctx, err));
- }
- }
- static JSValue js_std_open(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *filename, *mode = NULL;
- FILE *f;
- int err;
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- goto fail;
- mode = JS_ToCString(ctx, argv[1]);
- if (!mode)
- goto fail;
- if (mode[strspn(mode, "rwa+bx")] != '\0') {
- JS_ThrowTypeError(ctx, "invalid file mode");
- goto fail;
- }
- f = fopen(filename, mode);
- if (!f)
- err = errno;
- else
- err = 0;
- if (argc >= 3)
- js_set_error_object(ctx, argv[2], err);
- JS_FreeCString(ctx, filename);
- JS_FreeCString(ctx, mode);
- if (!f)
- return JS_NULL;
- return js_new_std_file(ctx, f, false);
- fail:
- JS_FreeCString(ctx, filename);
- JS_FreeCString(ctx, mode);
- return JS_EXCEPTION;
- }
- #if !defined(__wasi__)
- static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *filename, *mode = NULL;
- FILE *f;
- int err;
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- goto fail;
- mode = JS_ToCString(ctx, argv[1]);
- if (!mode)
- goto fail;
- if (strcmp(mode, "r") && strcmp(mode, "w")) {
- JS_ThrowTypeError(ctx, "invalid file mode");
- goto fail;
- }
- f = popen(filename, mode);
- if (!f)
- err = errno;
- else
- err = 0;
- if (argc >= 3)
- js_set_error_object(ctx, argv[2], err);
- JS_FreeCString(ctx, filename);
- JS_FreeCString(ctx, mode);
- if (!f)
- return JS_NULL;
- return js_new_std_file(ctx, f, true);
- fail:
- JS_FreeCString(ctx, filename);
- JS_FreeCString(ctx, mode);
- return JS_EXCEPTION;
- }
- #endif // !defined(__wasi__)
- static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *mode;
- FILE *f;
- int fd, err;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- mode = JS_ToCString(ctx, argv[1]);
- if (!mode)
- goto fail;
- if (mode[strspn(mode, "rwa+")] != '\0') {
- JS_ThrowTypeError(ctx, "invalid file mode");
- goto fail;
- }
- f = fdopen(fd, mode);
- if (!f)
- err = errno;
- else
- err = 0;
- if (argc >= 3)
- js_set_error_object(ctx, argv[2], err);
- JS_FreeCString(ctx, mode);
- if (!f)
- return JS_NULL;
- return js_new_std_file(ctx, f, false);
- fail:
- JS_FreeCString(ctx, mode);
- return JS_EXCEPTION;
- }
- #if !defined(__wasi__)
- static JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f;
- f = tmpfile();
- if (argc >= 1)
- js_set_error_object(ctx, argv[0], f ? 0 : errno);
- if (!f)
- return JS_NULL;
- return js_new_std_file(ctx, f, false);
- }
- #endif
- static JSValue js_std_sprintf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_printf_internal(ctx, argc, argv, NULL);
- }
- static JSValue js_std_printf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return js_printf_internal(ctx, argc, argv, stdout);
- }
- static FILE *js_std_file_get(JSContext *ctx, JSValueConst obj)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSSTDFile *s = JS_GetOpaque2(ctx, obj, ts->std_file_class_id);
- if (!s)
- return NULL;
- if (!s->f) {
- JS_ThrowTypeError(ctx, "invalid file handle");
- return NULL;
- }
- return s->f;
- }
- static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- FILE *f;
- int i;
- const char *str;
- size_t len;
- if (magic == 0) {
- f = stdout;
- } else {
- f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- }
- for(i = 0; i < argc; i++) {
- str = JS_ToCStringLen(ctx, &len, argv[i]);
- if (!str)
- return JS_EXCEPTION;
- fwrite(str, 1, len, f);
- JS_FreeCString(ctx, str);
- }
- return JS_UNDEFINED;
- }
- static JSValue js_std_file_close(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSSTDFile *s = JS_GetOpaque2(ctx, this_val, ts->std_file_class_id);
- int err;
- if (!s)
- return JS_EXCEPTION;
- if (!s->f)
- return JS_ThrowTypeError(ctx, "invalid file handle");
- if (is_stdio(s->f))
- return JS_ThrowTypeError(ctx, "cannot close stdio");
- #if !defined(__wasi__)
- if (s->is_popen)
- err = js_get_errno(pclose(s->f));
- else
- #endif
- err = js_get_errno(fclose(s->f));
- s->f = NULL;
- return JS_NewInt32(ctx, err);
- }
- static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- return js_printf_internal(ctx, argc, argv, f);
- }
- static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- fflush(f);
- return JS_UNDEFINED;
- }
- static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int is_bigint)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- int64_t pos;
- if (!f)
- return JS_EXCEPTION;
- #if defined(__linux__) || defined(__GLIBC__)
- pos = ftello(f);
- #else
- pos = ftell(f);
- #endif
- if (is_bigint)
- return JS_NewBigInt64(ctx, pos);
- else
- return JS_NewInt64(ctx, pos);
- }
- static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- int64_t pos;
- int whence, ret;
- if (!f)
- return JS_EXCEPTION;
- if (JS_ToInt64Ext(ctx, &pos, argv[0]))
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &whence, argv[1]))
- return JS_EXCEPTION;
- #if defined(__linux__) || defined(__GLIBC__)
- ret = fseeko(f, pos, whence);
- #else
- ret = fseek(f, pos, whence);
- #endif
- if (ret < 0)
- ret = -errno;
- return JS_NewInt32(ctx, ret);
- }
- static JSValue js_std_file_eof(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- return JS_NewBool(ctx, feof(f));
- }
- static JSValue js_std_file_error(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- return JS_NewBool(ctx, ferror(f));
- }
- static JSValue js_std_file_clearerr(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- clearerr(f);
- return JS_UNDEFINED;
- }
- static JSValue js_std_file_fileno(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- return JS_NewInt32(ctx, fileno(f));
- }
- static JSValue js_std_file_read_write(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- uint64_t pos, len;
- size_t size, ret;
- uint8_t *buf;
- if (!f)
- return JS_EXCEPTION;
- if (JS_ToIndex(ctx, &pos, argv[1]))
- return JS_EXCEPTION;
- if (JS_ToIndex(ctx, &len, argv[2]))
- return JS_EXCEPTION;
- buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
- if (!buf)
- return JS_EXCEPTION;
- if (pos + len > size)
- return JS_ThrowRangeError(ctx, "read/write array buffer overflow");
- if (magic)
- ret = fwrite(buf + pos, 1, len, f);
- else
- ret = fread(buf + pos, 1, len, f);
- return JS_NewInt64(ctx, ret);
- }
- /* XXX: could use less memory and go faster */
- static JSValue js_std_file_getline(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- int c;
- DynBuf dbuf;
- JSValue obj;
- if (!f)
- return JS_EXCEPTION;
- js_std_dbuf_init(ctx, &dbuf);
- for(;;) {
- c = fgetc(f);
- if (c == EOF) {
- if (dbuf.size == 0) {
- /* EOF */
- dbuf_free(&dbuf);
- return JS_NULL;
- } else {
- break;
- }
- }
- if (c == '\n')
- break;
- if (dbuf_putc(&dbuf, c)) {
- dbuf_free(&dbuf);
- return JS_ThrowOutOfMemory(ctx);
- }
- }
- obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size);
- dbuf_free(&dbuf);
- return obj;
- }
- /* XXX: could use less memory and go faster */
- static JSValue js_std_file_readAs(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- int c;
- DynBuf dbuf;
- JSValue obj;
- uint64_t max_size64;
- size_t max_size;
- JSValueConst max_size_val;
- if (!f)
- return JS_EXCEPTION;
- if (argc >= 1)
- max_size_val = argv[0];
- else
- max_size_val = JS_UNDEFINED;
- max_size = (size_t)-1;
- if (!JS_IsUndefined(max_size_val)) {
- if (JS_ToIndex(ctx, &max_size64, max_size_val))
- return JS_EXCEPTION;
- if (max_size64 < max_size)
- max_size = max_size64;
- }
- js_std_dbuf_init(ctx, &dbuf);
- while (max_size != 0) {
- c = fgetc(f);
- if (c == EOF)
- break;
- if (dbuf_putc(&dbuf, c)) {
- dbuf_free(&dbuf);
- return JS_EXCEPTION;
- }
- max_size--;
- }
- if (magic) {
- obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size);
- } else {
- obj = JS_NewArrayBufferCopy(ctx, dbuf.buf, dbuf.size);
- }
- dbuf_free(&dbuf);
- return obj;
- }
- static JSValue js_std_file_getByte(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- if (!f)
- return JS_EXCEPTION;
- return JS_NewInt32(ctx, fgetc(f));
- }
- static JSValue js_std_file_putByte(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- FILE *f = js_std_file_get(ctx, this_val);
- int c;
- if (!f)
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &c, argv[0]))
- return JS_EXCEPTION;
- c = fputc(c, f);
- return JS_NewInt32(ctx, c);
- }
- /* urlGet */
- #if !defined(__wasi__)
- #define URL_GET_PROGRAM "curl -s -i --"
- #define URL_GET_BUF_SIZE 4096
- static int http_get_header_line(FILE *f, char *buf, size_t buf_size,
- DynBuf *dbuf)
- {
- int c;
- char *p;
- p = buf;
- for(;;) {
- c = fgetc(f);
- if (c < 0)
- return -1;
- if ((p - buf) < buf_size - 1)
- *p++ = c;
- if (dbuf)
- dbuf_putc(dbuf, c);
- if (c == '\n')
- break;
- }
- *p = '\0';
- return 0;
- }
- static int http_get_status(const char *buf)
- {
- const char *p = buf;
- while (*p != ' ' && *p != '\0')
- p++;
- if (*p != ' ')
- return 0;
- while (*p == ' ')
- p++;
- return atoi(p);
- }
- static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *url;
- DynBuf cmd_buf;
- DynBuf data_buf_s, *data_buf = &data_buf_s;
- DynBuf header_buf_s, *header_buf = &header_buf_s;
- char *buf;
- size_t i, len;
- int status;
- JSValue response = JS_UNDEFINED, ret_obj;
- JSValueConst options_obj;
- FILE *f;
- bool binary_flag, full_flag;
- url = JS_ToCString(ctx, argv[0]);
- if (!url)
- return JS_EXCEPTION;
- binary_flag = false;
- full_flag = false;
- if (argc >= 2) {
- options_obj = argv[1];
- if (get_bool_option(ctx, &binary_flag, options_obj, "binary"))
- goto fail_obj;
- if (get_bool_option(ctx, &full_flag, options_obj, "full")) {
- fail_obj:
- JS_FreeCString(ctx, url);
- return JS_EXCEPTION;
- }
- }
- js_std_dbuf_init(ctx, &cmd_buf);
- dbuf_printf(&cmd_buf, "%s '", URL_GET_PROGRAM);
- for(i = 0; url[i] != '\0'; i++) {
- unsigned char c = url[i];
- switch (c) {
- case '\'':
- /* shell single quoted string does not support \' */
- dbuf_putstr(&cmd_buf, "'\\''");
- break;
- case '[': case ']': case '{': case '}': case '\\':
- /* prevent interpretation by curl as range or set specification */
- dbuf_putc(&cmd_buf, '\\');
- /* FALLTHROUGH */
- default:
- dbuf_putc(&cmd_buf, c);
- break;
- }
- }
- JS_FreeCString(ctx, url);
- dbuf_putstr(&cmd_buf, "'");
- dbuf_putc(&cmd_buf, '\0');
- if (dbuf_error(&cmd_buf)) {
- dbuf_free(&cmd_buf);
- return JS_EXCEPTION;
- }
- // printf("%s\n", (char *)cmd_buf.buf);
- f = popen((char *)cmd_buf.buf, "r");
- dbuf_free(&cmd_buf);
- if (!f) {
- return JS_ThrowTypeError(ctx, "could not start curl");
- }
- js_std_dbuf_init(ctx, data_buf);
- js_std_dbuf_init(ctx, header_buf);
- buf = js_malloc(ctx, URL_GET_BUF_SIZE);
- if (!buf)
- goto fail;
- /* get the HTTP status */
- if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, NULL) < 0) {
- status = 0;
- goto bad_header;
- }
- status = http_get_status(buf);
- if (!full_flag && !(status >= 200 && status <= 299)) {
- goto bad_header;
- }
- /* wait until there is an empty line */
- for(;;) {
- if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, header_buf) < 0) {
- bad_header:
- response = JS_NULL;
- goto done;
- }
- if (!strcmp(buf, "\r\n"))
- break;
- }
- if (dbuf_error(header_buf))
- goto fail;
- header_buf->size -= 2; /* remove the trailing CRLF */
- /* download the data */
- for(;;) {
- len = fread(buf, 1, URL_GET_BUF_SIZE, f);
- if (len == 0)
- break;
- dbuf_put(data_buf, (uint8_t *)buf, len);
- }
- if (dbuf_error(data_buf))
- goto fail;
- if (binary_flag) {
- response = JS_NewArrayBufferCopy(ctx,
- data_buf->buf, data_buf->size);
- } else {
- response = JS_NewStringLen(ctx, (char *)data_buf->buf, data_buf->size);
- }
- if (JS_IsException(response))
- goto fail;
- done:
- js_free(ctx, buf);
- buf = NULL;
- pclose(f);
- f = NULL;
- dbuf_free(data_buf);
- data_buf = NULL;
- if (full_flag) {
- ret_obj = JS_NewObject(ctx);
- if (JS_IsException(ret_obj))
- goto fail;
- JS_DefinePropertyValueStr(ctx, ret_obj, "response",
- response,
- JS_PROP_C_W_E);
- if (!JS_IsNull(response)) {
- JS_DefinePropertyValueStr(ctx, ret_obj, "responseHeaders",
- JS_NewStringLen(ctx, (char *)header_buf->buf,
- header_buf->size),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, ret_obj, "status",
- JS_NewInt32(ctx, status),
- JS_PROP_C_W_E);
- }
- } else {
- ret_obj = response;
- }
- dbuf_free(header_buf);
- return ret_obj;
- fail:
- if (f)
- pclose(f);
- js_free(ctx, buf);
- if (data_buf)
- dbuf_free(data_buf);
- if (header_buf)
- dbuf_free(header_buf);
- JS_FreeValue(ctx, response);
- return JS_EXCEPTION;
- }
- #endif // !defined(__wasi__)
- static JSClassDef js_std_file_class = {
- "FILE",
- .finalizer = js_std_file_finalizer,
- };
- static const JSCFunctionListEntry js_std_error_props[] = {
- /* various errno values */
- #define DEF(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE )
- DEF(EINVAL),
- DEF(EIO),
- DEF(EACCES),
- DEF(EEXIST),
- DEF(ENOSPC),
- DEF(ENOSYS),
- DEF(EBUSY),
- DEF(ENOENT),
- DEF(EPERM),
- DEF(EPIPE),
- DEF(EBADF),
- #undef DEF
- };
- static const JSCFunctionListEntry js_std_funcs[] = {
- JS_CFUNC_DEF("exit", 1, js_std_exit ),
- JS_CFUNC_DEF("gc", 0, js_std_gc ),
- JS_CFUNC_DEF("evalScript", 1, js_evalScript ),
- JS_CFUNC_DEF("loadScript", 1, js_loadScript ),
- JS_CFUNC_DEF("getenv", 1, js_std_getenv ),
- JS_CFUNC_DEF("setenv", 1, js_std_setenv ),
- JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ),
- JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ),
- #if !defined(__wasi__)
- JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ),
- #endif
- JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
- JS_CFUNC_DEF("writeFile", 2, js_std_writeFile ),
- JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
- /* FILE I/O */
- JS_CFUNC_DEF("open", 2, js_std_open ),
- #if !defined(__wasi__)
- JS_CFUNC_DEF("popen", 2, js_std_popen ),
- JS_CFUNC_DEF("tmpfile", 0, js_std_tmpfile ),
- #endif
- JS_CFUNC_DEF("fdopen", 2, js_std_fdopen ),
- JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 0 ),
- JS_CFUNC_DEF("printf", 1, js_std_printf ),
- JS_CFUNC_DEF("sprintf", 1, js_std_sprintf ),
- JS_PROP_INT32_DEF("SEEK_SET", SEEK_SET, JS_PROP_CONFIGURABLE ),
- JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ),
- JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ),
- JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE),
- };
- static const JSCFunctionListEntry js_std_file_proto_funcs[] = {
- JS_CFUNC_DEF("close", 0, js_std_file_close ),
- JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 1 ),
- JS_CFUNC_DEF("printf", 1, js_std_file_printf ),
- JS_CFUNC_DEF("flush", 0, js_std_file_flush ),
- JS_CFUNC_MAGIC_DEF("tell", 0, js_std_file_tell, 0 ),
- JS_CFUNC_MAGIC_DEF("tello", 0, js_std_file_tell, 1 ),
- JS_CFUNC_DEF("seek", 2, js_std_file_seek ),
- JS_CFUNC_DEF("eof", 0, js_std_file_eof ),
- JS_CFUNC_DEF("fileno", 0, js_std_file_fileno ),
- JS_CFUNC_DEF("error", 0, js_std_file_error ),
- JS_CFUNC_DEF("clearerr", 0, js_std_file_clearerr ),
- JS_CFUNC_MAGIC_DEF("read", 3, js_std_file_read_write, 0 ),
- JS_CFUNC_MAGIC_DEF("write", 3, js_std_file_read_write, 1 ),
- JS_CFUNC_DEF("getline", 0, js_std_file_getline ),
- JS_CFUNC_MAGIC_DEF("readAsArrayBuffer", 0, js_std_file_readAs, 0 ),
- JS_CFUNC_MAGIC_DEF("readAsString", 0, js_std_file_readAs, 1 ),
- JS_CFUNC_DEF("getByte", 0, js_std_file_getByte ),
- JS_CFUNC_DEF("putByte", 1, js_std_file_putByte ),
- /* setvbuf, ... */
- };
- static int js_std_init(JSContext *ctx, JSModuleDef *m)
- {
- JSValue proto;
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- /* FILE class */
- /* the class ID is created once */
- JS_NewClassID(rt, &ts->std_file_class_id);
- /* the class is created once per runtime */
- JS_NewClass(rt, ts->std_file_class_id, &js_std_file_class);
- proto = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, proto, js_std_file_proto_funcs,
- countof(js_std_file_proto_funcs));
- JS_SetClassProto(ctx, ts->std_file_class_id, proto);
- JS_SetModuleExportList(ctx, m, js_std_funcs,
- countof(js_std_funcs));
- JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, false));
- JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, false));
- JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, false));
- return 0;
- }
- JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name)
- {
- JSModuleDef *m;
- m = JS_NewCModule(ctx, module_name, js_std_init);
- if (!m)
- return NULL;
- JS_AddModuleExportList(ctx, m, js_std_funcs, countof(js_std_funcs));
- JS_AddModuleExport(ctx, m, "in");
- JS_AddModuleExport(ctx, m, "out");
- JS_AddModuleExport(ctx, m, "err");
- return m;
- }
- /**********************************************************/
- /* 'os' object */
- static JSValue js_os_open(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *filename;
- int flags, mode, ret;
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &flags, argv[1]))
- goto fail;
- if (argc >= 3 && !JS_IsUndefined(argv[2])) {
- if (JS_ToInt32(ctx, &mode, argv[2])) {
- fail:
- JS_FreeCString(ctx, filename);
- return JS_EXCEPTION;
- }
- } else {
- mode = 0666;
- }
- #if defined(_WIN32)
- /* force binary mode by default */
- if (!(flags & O_TEXT))
- flags |= O_BINARY;
- #endif
- ret = js_get_errno(open(filename, flags, mode));
- JS_FreeCString(ctx, filename);
- return JS_NewInt32(ctx, ret);
- }
- static JSValue js_os_close(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd, ret;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- ret = js_get_errno(close(fd));
- return JS_NewInt32(ctx, ret);
- }
- static JSValue js_os_seek(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd, whence;
- int64_t pos, ret;
- bool is_bigint;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- is_bigint = JS_IsBigInt(argv[1]);
- if (JS_ToInt64Ext(ctx, &pos, argv[1]))
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &whence, argv[2]))
- return JS_EXCEPTION;
- ret = lseek(fd, pos, whence);
- if (ret == -1)
- ret = -errno;
- if (is_bigint)
- return JS_NewBigInt64(ctx, ret);
- else
- return JS_NewInt64(ctx, ret);
- }
- static JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- int fd;
- uint64_t pos, len;
- size_t size;
- ssize_t ret;
- uint8_t *buf;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- if (JS_ToIndex(ctx, &pos, argv[2]))
- return JS_EXCEPTION;
- if (JS_ToIndex(ctx, &len, argv[3]))
- return JS_EXCEPTION;
- buf = JS_GetArrayBuffer(ctx, &size, argv[1]);
- if (!buf)
- return JS_EXCEPTION;
- if (pos + len > size)
- return JS_ThrowRangeError(ctx, "read/write array buffer overflow");
- if (magic)
- ret = js_get_errno(write(fd, buf + pos, len));
- else
- ret = js_get_errno(read(fd, buf + pos, len));
- return JS_NewInt64(ctx, ret);
- }
- static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- return JS_NewBool(ctx, (isatty(fd) != 0));
- }
- #if defined(_WIN32)
- static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd;
- HANDLE handle;
- CONSOLE_SCREEN_BUFFER_INFO info;
- JSValue obj;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- handle = (HANDLE)_get_osfhandle(fd);
- if (!GetConsoleScreenBufferInfo(handle, &info))
- return JS_NULL;
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj))
- return obj;
- JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, info.dwSize.X), JS_PROP_C_W_E);
- JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, info.dwSize.Y), JS_PROP_C_W_E);
- return obj;
- }
- /* Windows 10 built-in VT100 emulation */
- #define __ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
- #define __ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
- static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd;
- HANDLE handle;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- handle = (HANDLE)_get_osfhandle(fd);
- SetConsoleMode(handle, ENABLE_WINDOW_INPUT | __ENABLE_VIRTUAL_TERMINAL_INPUT);
- _setmode(fd, _O_BINARY);
- if (fd == 0) {
- handle = (HANDLE)_get_osfhandle(1); /* corresponding output */
- SetConsoleMode(handle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | __ENABLE_VIRTUAL_TERMINAL_PROCESSING);
- }
- return JS_UNDEFINED;
- }
- #elif !defined(__wasi__)
- static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd;
- struct winsize ws;
- JSValue obj;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- if (ioctl(fd, TIOCGWINSZ, &ws) == 0 &&
- ws.ws_col >= 4 && ws.ws_row >= 4) {
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj))
- return obj;
- JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ws.ws_col), JS_PROP_C_W_E);
- JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, ws.ws_row), JS_PROP_C_W_E);
- return obj;
- } else {
- return JS_NULL;
- }
- }
- static struct termios oldtty;
- static void term_exit(void)
- {
- tcsetattr(0, TCSANOW, &oldtty);
- }
- /* XXX: should add a way to go back to normal mode */
- static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- struct termios tty;
- int fd;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- memset(&tty, 0, sizeof(tty));
- tcgetattr(fd, &tty);
- oldtty = tty;
- tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
- |INLCR|IGNCR|ICRNL|IXON);
- tty.c_oflag |= OPOST;
- tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
- tty.c_cflag &= ~(CSIZE|PARENB);
- tty.c_cflag |= CS8;
- tty.c_cc[VMIN] = 1;
- tty.c_cc[VTIME] = 0;
- tcsetattr(fd, TCSANOW, &tty);
- atexit(term_exit);
- return JS_UNDEFINED;
- }
- #endif /* !_WIN32 && !__wasi__ */
- static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *filename;
- int ret;
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- return JS_EXCEPTION;
- #if defined(_WIN32)
- {
- struct stat st;
- if (stat(filename, &st) == 0 && (st.st_mode & _S_IFDIR)) {
- ret = rmdir(filename);
- } else {
- ret = unlink(filename);
- }
- }
- #else
- ret = remove(filename);
- #endif
- ret = js_get_errno(ret);
- JS_FreeCString(ctx, filename);
- return JS_NewInt32(ctx, ret);
- }
- static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *oldpath, *newpath;
- int ret;
- oldpath = JS_ToCString(ctx, argv[0]);
- if (!oldpath)
- return JS_EXCEPTION;
- newpath = JS_ToCString(ctx, argv[1]);
- if (!newpath) {
- JS_FreeCString(ctx, oldpath);
- return JS_EXCEPTION;
- }
- ret = js_get_errno(rename(oldpath, newpath));
- JS_FreeCString(ctx, oldpath);
- JS_FreeCString(ctx, newpath);
- return JS_NewInt32(ctx, ret);
- }
- static bool is_main_thread(JSRuntime *rt)
- {
- JSThreadState *ts = js_get_thread_state(rt);
- return !ts->recv_pipe;
- }
- static JSOSRWHandler *find_rh(JSThreadState *ts, int fd)
- {
- JSOSRWHandler *rh;
- struct list_head *el;
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- if (rh->fd == fd)
- return rh;
- }
- return NULL;
- }
- static void free_rw_handler(JSRuntime *rt, JSOSRWHandler *rh)
- {
- int i;
- list_del(&rh->link);
- for(i = 0; i < 2; i++) {
- JS_FreeValueRT(rt, rh->rw_func[i]);
- }
- js_free_rt(rt, rh);
- }
- static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSOSRWHandler *rh;
- int fd;
- JSValueConst func;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- func = argv[1];
- if (JS_IsNull(func)) {
- rh = find_rh(ts, fd);
- if (rh) {
- JS_FreeValue(ctx, rh->rw_func[magic]);
- rh->rw_func[magic] = JS_NULL;
- if (JS_IsNull(rh->rw_func[0]) &&
- JS_IsNull(rh->rw_func[1])) {
- /* remove the entry */
- free_rw_handler(JS_GetRuntime(ctx), rh);
- }
- }
- } else {
- if (!JS_IsFunction(ctx, func))
- return JS_ThrowTypeError(ctx, "not a function");
- rh = find_rh(ts, fd);
- if (!rh) {
- rh = js_mallocz(ctx, sizeof(*rh));
- if (!rh)
- return JS_EXCEPTION;
- rh->fd = fd;
- rh->rw_func[0] = JS_NULL;
- rh->rw_func[1] = JS_NULL;
- list_add_tail(&rh->link, &ts->os_rw_handlers);
- }
- JS_FreeValue(ctx, rh->rw_func[magic]);
- rh->rw_func[magic] = JS_DupValue(ctx, func);
- }
- return JS_UNDEFINED;
- }
- static JSOSSignalHandler *find_sh(JSThreadState *ts, int sig_num)
- {
- JSOSSignalHandler *sh;
- struct list_head *el;
- list_for_each(el, &ts->os_signal_handlers) {
- sh = list_entry(el, JSOSSignalHandler, link);
- if (sh->sig_num == sig_num)
- return sh;
- }
- return NULL;
- }
- static void free_sh(JSRuntime *rt, JSOSSignalHandler *sh)
- {
- list_del(&sh->link);
- JS_FreeValueRT(rt, sh->func);
- js_free_rt(rt, sh);
- }
- static void os_signal_handler(int sig_num)
- {
- os_pending_signals |= ((uint64_t)1 << sig_num);
- }
- #if defined(_WIN32)
- typedef void (*sighandler_t)(int sig_num);
- #endif
- static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSOSSignalHandler *sh;
- uint32_t sig_num;
- JSValueConst func;
- sighandler_t handler;
- if (!is_main_thread(rt))
- return JS_ThrowTypeError(ctx, "signal handler can only be set in the main thread");
- if (JS_ToUint32(ctx, &sig_num, argv[0]))
- return JS_EXCEPTION;
- if (sig_num >= 64)
- return JS_ThrowRangeError(ctx, "invalid signal number");
- func = argv[1];
- /* func = null: SIG_DFL, func = undefined, SIG_IGN */
- if (JS_IsNull(func) || JS_IsUndefined(func)) {
- sh = find_sh(ts, sig_num);
- if (sh) {
- free_sh(JS_GetRuntime(ctx), sh);
- }
- if (JS_IsNull(func))
- handler = SIG_DFL;
- else
- handler = SIG_IGN;
- signal(sig_num, handler);
- } else {
- if (!JS_IsFunction(ctx, func))
- return JS_ThrowTypeError(ctx, "not a function");
- sh = find_sh(ts, sig_num);
- if (!sh) {
- sh = js_mallocz(ctx, sizeof(*sh));
- if (!sh)
- return JS_EXCEPTION;
- sh->sig_num = sig_num;
- list_add_tail(&sh->link, &ts->os_signal_handlers);
- }
- JS_FreeValue(ctx, sh->func);
- sh->func = JS_DupValue(ctx, func);
- signal(sig_num, os_signal_handler);
- }
- return JS_UNDEFINED;
- }
- #if !defined(_WIN32) && !defined(__wasi__)
- static JSValue js_os_cputime(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- struct rusage ru;
- int64_t cputime;
- cputime = 0;
- if (!getrusage(RUSAGE_SELF, &ru))
- cputime = (int64_t)ru.ru_utime.tv_sec * 1000000 + ru.ru_utime.tv_usec;
- return JS_NewInt64(ctx, cputime);
- }
- #endif
- static JSValue js_os_exepath(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- char buf[JS__PATH_MAX];
- size_t len = sizeof(buf);
- if (js_exepath(buf, &len))
- return JS_UNDEFINED;
- return JS_NewStringLen(ctx, buf, len);
- }
- static JSValue js_os_now(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return JS_NewInt64(ctx, js__hrtime_ns() / 1000);
- }
- static uint64_t js__hrtime_ms(void)
- {
- return js__hrtime_ns() / (1000 * 1000);
- }
- static void free_timer(JSRuntime *rt, JSOSTimer *th)
- {
- list_del(&th->link);
- JS_FreeValueRT(rt, th->func);
- js_free_rt(rt, th);
- }
- // TODO(bnoordhuis) accept string as first arg and eval at timer expiry
- // TODO(bnoordhuis) retain argv[2..] as args for callback if argc > 2
- static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- int64_t delay;
- JSValueConst func;
- JSOSTimer *th;
- func = argv[0];
- if (!JS_IsFunction(ctx, func))
- return JS_ThrowTypeError(ctx, "not a function");
- if (JS_ToInt64(ctx, &delay, argv[1]))
- return JS_EXCEPTION;
- if (delay < 1)
- delay = 1;
- th = js_mallocz(ctx, sizeof(*th));
- if (!th)
- return JS_EXCEPTION;
- th->timer_id = ts->next_timer_id++;
- if (ts->next_timer_id > MAX_SAFE_INTEGER)
- ts->next_timer_id = 1;
- th->repeats = (magic > 0);
- th->timeout = js__hrtime_ms() + delay;
- th->delay = delay;
- th->func = JS_DupValue(ctx, func);
- list_add_tail(&th->link, &ts->os_timers);
- return JS_NewInt64(ctx, th->timer_id);
- }
- static JSOSTimer *find_timer_by_id(JSThreadState *ts, int timer_id)
- {
- struct list_head *el;
- if (timer_id <= 0)
- return NULL;
- list_for_each(el, &ts->os_timers) {
- JSOSTimer *th = list_entry(el, JSOSTimer, link);
- if (th->timer_id == timer_id)
- return th;
- }
- return NULL;
- }
- static JSValue js_os_clearTimeout(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSOSTimer *th;
- int64_t timer_id;
- if (JS_ToInt64(ctx, &timer_id, argv[0]))
- return JS_EXCEPTION;
- th = find_timer_by_id(ts, timer_id);
- if (!th)
- return JS_UNDEFINED;
- free_timer(rt, th);
- return JS_UNDEFINED;
- }
- /* return a promise */
- static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- int64_t delay;
- JSOSTimer *th;
- JSValue promise, resolving_funcs[2];
- if (JS_ToInt64(ctx, &delay, argv[0]))
- return JS_EXCEPTION;
- promise = JS_NewPromiseCapability(ctx, resolving_funcs);
- if (JS_IsException(promise))
- return JS_EXCEPTION;
- th = js_mallocz(ctx, sizeof(*th));
- if (!th) {
- JS_FreeValue(ctx, promise);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- return JS_EXCEPTION;
- }
- th->timer_id = -1;
- th->timeout = js__hrtime_ms() + delay;
- th->func = JS_DupValue(ctx, resolving_funcs[0]);
- list_add_tail(&th->link, &ts->os_timers);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- return promise;
- }
- static int call_handler(JSContext *ctx, JSValue func)
- {
- int r;
- JSValue ret, func1;
- /* 'func' might be destroyed when calling itself (if it frees the
- handler), so must take extra care */
- func1 = JS_DupValue(ctx, func);
- ret = JS_Call(ctx, func1, JS_UNDEFINED, 0, NULL);
- JS_FreeValue(ctx, func1);
- r = 0;
- if (JS_IsException(ret))
- r = -1;
- JS_FreeValue(ctx, ret);
- return r;
- }
- static int js_os_run_timers(JSRuntime *rt, JSContext *ctx, JSThreadState *ts, int *min_delay)
- {
- JSValue func;
- JSOSTimer *th;
- int64_t cur_time, delay;
- struct list_head *el;
- int r;
- if (list_empty(&ts->os_timers)) {
- *min_delay = -1;
- return 0;
- }
- cur_time = js__hrtime_ms();
- *min_delay = INT32_MAX;
- list_for_each(el, &ts->os_timers) {
- th = list_entry(el, JSOSTimer, link);
- delay = th->timeout - cur_time;
- if (delay > 0) {
- *min_delay = min_int(*min_delay, delay);
- } else {
- *min_delay = 0;
- func = JS_DupValueRT(rt, th->func);
- if (th->repeats)
- th->timeout = cur_time + th->delay;
- else
- free_timer(rt, th);
- r = call_handler(ctx, func);
- JS_FreeValueRT(rt, func);
- return r;
- }
- }
- return 0;
- }
- #ifdef USE_WORKER
- #ifdef _WIN32
- static int js_waker_init(JSWaker *w)
- {
- w->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
- return w->handle ? 0 : -1;
- }
- static void js_waker_signal(JSWaker *w)
- {
- SetEvent(w->handle);
- }
- static void js_waker_clear(JSWaker *w)
- {
- ResetEvent(w->handle);
- }
- static void js_waker_close(JSWaker *w)
- {
- CloseHandle(w->handle);
- w->handle = INVALID_HANDLE_VALUE;
- }
- #else // !_WIN32
- static int js_waker_init(JSWaker *w)
- {
- int fds[2];
- if (pipe(fds) < 0)
- return -1;
- w->read_fd = fds[0];
- w->write_fd = fds[1];
- return 0;
- }
- static void js_waker_signal(JSWaker *w)
- {
- int ret;
- for(;;) {
- ret = write(w->write_fd, "", 1);
- if (ret == 1)
- break;
- if (ret < 0 && (errno != EAGAIN || errno != EINTR))
- break;
- }
- }
- static void js_waker_clear(JSWaker *w)
- {
- uint8_t buf[16];
- int ret;
- for(;;) {
- ret = read(w->read_fd, buf, sizeof(buf));
- if (ret >= 0)
- break;
- if (errno != EAGAIN && errno != EINTR)
- break;
- }
- }
- static void js_waker_close(JSWaker *w)
- {
- close(w->read_fd);
- close(w->write_fd);
- w->read_fd = -1;
- w->write_fd = -1;
- }
- #endif // _WIN32
- static void js_free_message(JSWorkerMessage *msg);
- /* return 1 if a message was handled, 0 if no message */
- static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
- JSWorkerMessageHandler *port)
- {
- JSWorkerMessagePipe *ps = port->recv_pipe;
- int ret;
- struct list_head *el;
- JSWorkerMessage *msg;
- JSValue obj, data_obj, func, retval;
- js_mutex_lock(&ps->mutex);
- if (!list_empty(&ps->msg_queue)) {
- el = ps->msg_queue.next;
- msg = list_entry(el, JSWorkerMessage, link);
- /* remove the message from the queue */
- list_del(&msg->link);
- // drain read end of pipe
- if (list_empty(&ps->msg_queue))
- js_waker_clear(&ps->waker);
- js_mutex_unlock(&ps->mutex);
- data_obj = JS_ReadObject(ctx, msg->data, msg->data_len,
- JS_READ_OBJ_SAB | JS_READ_OBJ_REFERENCE);
- js_free_message(msg);
- if (JS_IsException(data_obj))
- goto fail;
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj)) {
- JS_FreeValue(ctx, data_obj);
- goto fail;
- }
- JS_DefinePropertyValueStr(ctx, obj, "data", data_obj, JS_PROP_C_W_E);
- /* 'func' might be destroyed when calling itself (if it frees the
- handler), so must take extra care */
- func = JS_DupValue(ctx, port->on_message_func);
- retval = JS_Call(ctx, func, JS_UNDEFINED, 1, (JSValueConst *)&obj);
- JS_FreeValue(ctx, obj);
- JS_FreeValue(ctx, func);
- if (JS_IsException(retval)) {
- fail:
- js_std_dump_error(ctx);
- } else {
- JS_FreeValue(ctx, retval);
- }
- ret = 1;
- } else {
- js_mutex_unlock(&ps->mutex);
- ret = 0;
- }
- return ret;
- }
- #endif // USE_WORKER
- #if defined(_WIN32)
- static int js_os_poll(JSContext *ctx)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- int min_delay, count;
- JSOSRWHandler *rh;
- struct list_head *el;
- HANDLE handles[MAXIMUM_WAIT_OBJECTS]; // 64
- /* XXX: handle signals if useful */
- if (js_os_run_timers(rt, ctx, ts, &min_delay))
- return -1;
- if (min_delay == 0)
- return 0; // expired timer
- if (min_delay < 0)
- if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->port_list))
- return -1; /* no more events */
- count = 0;
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0]))
- handles[count++] = (HANDLE)_get_osfhandle(rh->fd); // stdin
- if (count == (int)countof(handles))
- break;
- }
- list_for_each(el, &ts->port_list) {
- JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
- if (JS_IsNull(port->on_message_func))
- continue;
- handles[count++] = port->recv_pipe->waker.handle;
- if (count == (int)countof(handles))
- break;
- }
- if (count > 0) {
- DWORD ret, timeout = INFINITE;
- if (min_delay != -1)
- timeout = min_delay;
- ret = WaitForMultipleObjects(count, handles, FALSE, timeout);
- if (ret < count) {
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
- return call_handler(ctx, rh->rw_func[0]);
- /* must stop because the list may have been modified */
- }
- }
- list_for_each(el, &ts->port_list) {
- JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
- if (!JS_IsNull(port->on_message_func)) {
- JSWorkerMessagePipe *ps = port->recv_pipe;
- if (ps->waker.handle == handles[ret]) {
- if (handle_posted_message(rt, ctx, port))
- goto done;
- }
- }
- }
- }
- } else {
- Sleep(min_delay);
- }
- done:
- return 0;
- }
- #else // !defined(_WIN32)
- static int js_os_poll(JSContext *ctx)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- int r, w, ret, nfds, min_delay;
- JSOSRWHandler *rh;
- struct list_head *el;
- struct pollfd *pfd, *pfds, pfds_local[64];
- /* only check signals in the main thread */
- if (!ts->recv_pipe &&
- unlikely(os_pending_signals != 0)) {
- JSOSSignalHandler *sh;
- uint64_t mask;
- list_for_each(el, &ts->os_signal_handlers) {
- sh = list_entry(el, JSOSSignalHandler, link);
- mask = (uint64_t)1 << sh->sig_num;
- if (os_pending_signals & mask) {
- os_pending_signals &= ~mask;
- return call_handler(ctx, sh->func);
- }
- }
- }
- if (js_os_run_timers(rt, ctx, ts, &min_delay))
- return -1;
- if (min_delay == 0)
- return 0; // expired timer
- if (min_delay < 0)
- if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->port_list))
- return -1; /* no more events */
- nfds = 0;
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- nfds += (!JS_IsNull(rh->rw_func[0]) || !JS_IsNull(rh->rw_func[1]));
- }
- #ifdef USE_WORKER
- list_for_each(el, &ts->port_list) {
- JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
- nfds += !JS_IsNull(port->on_message_func);
- }
- #endif // USE_WORKER
- pfd = pfds = pfds_local;
- if (nfds > (int)countof(pfds_local)) {
- pfd = pfds = js_malloc(ctx, nfds * sizeof(*pfd));
- if (!pfd)
- return -1;
- }
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- r = POLLIN * !JS_IsNull(rh->rw_func[0]);
- w = POLLOUT * !JS_IsNull(rh->rw_func[1]);
- if (r || w)
- *pfd++ = (struct pollfd){rh->fd, r|w, 0};
- }
- #ifdef USE_WORKER
- list_for_each(el, &ts->port_list) {
- JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
- if (!JS_IsNull(port->on_message_func)) {
- JSWorkerMessagePipe *ps = port->recv_pipe;
- *pfd++ = (struct pollfd){ps->waker.read_fd, POLLIN, 0};
- }
- }
- #endif // USE_WORKER
- // FIXME(bnoordhuis) the loop below is quadratic in theory but
- // linear-ish in practice because we bail out on the first hit,
- // i.e., it's probably good enough for now
- ret = 0;
- nfds = poll(pfds, nfds, min_delay);
- for (pfd = pfds; nfds-- > 0; pfd++) {
- rh = find_rh(ts, pfd->fd);
- if (rh) {
- r = (POLLERR|POLLHUP|POLLNVAL|POLLIN) * !JS_IsNull(rh->rw_func[0]);
- w = (POLLERR|POLLHUP|POLLNVAL|POLLOUT) * !JS_IsNull(rh->rw_func[1]);
- if (r & pfd->revents) {
- ret = call_handler(ctx, rh->rw_func[0]);
- goto done;
- /* must stop because the list may have been modified */
- }
- if (w & pfd->revents) {
- ret = call_handler(ctx, rh->rw_func[1]);
- goto done;
- /* must stop because the list may have been modified */
- }
- } else {
- #ifdef USE_WORKER
- list_for_each(el, &ts->port_list) {
- JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
- if (!JS_IsNull(port->on_message_func)) {
- JSWorkerMessagePipe *ps = port->recv_pipe;
- if (pfd->fd == ps->waker.read_fd) {
- if (handle_posted_message(rt, ctx, port))
- goto done;
- }
- }
- }
- #endif // USE_WORKER
- }
- }
- done:
- if (pfds != pfds_local)
- js_free(ctx, pfds);
- return ret;
- }
- #endif // defined(_WIN32)
- static JSValue make_obj_error(JSContext *ctx,
- JSValue obj,
- int err)
- {
- JSValue arr;
- if (JS_IsException(obj))
- return obj;
- arr = JS_NewArray(ctx);
- if (JS_IsException(arr))
- return JS_EXCEPTION;
- JS_DefinePropertyValueUint32(ctx, arr, 0, obj,
- JS_PROP_C_W_E);
- JS_DefinePropertyValueUint32(ctx, arr, 1, JS_NewInt32(ctx, err),
- JS_PROP_C_W_E);
- return arr;
- }
- static JSValue make_string_error(JSContext *ctx,
- const char *buf,
- int err)
- {
- return make_obj_error(ctx, JS_NewString(ctx, buf), err);
- }
- /* return [cwd, errorcode] */
- static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- char buf[JS__PATH_MAX];
- int err;
- if (!getcwd(buf, sizeof(buf))) {
- buf[0] = '\0';
- err = errno;
- } else {
- err = 0;
- }
- return make_string_error(ctx, buf, err);
- }
- static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *target;
- int err;
- target = JS_ToCString(ctx, argv[0]);
- if (!target)
- return JS_EXCEPTION;
- err = js_get_errno(chdir(target));
- JS_FreeCString(ctx, target);
- return JS_NewInt32(ctx, err);
- }
- static JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int mode, ret;
- const char *path;
- if (argc >= 2) {
- if (JS_ToInt32(ctx, &mode, argv[1]))
- return JS_EXCEPTION;
- } else {
- mode = 0777;
- }
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- #if defined(_WIN32)
- (void)mode;
- ret = js_get_errno(mkdir(path));
- #else
- ret = js_get_errno(mkdir(path, mode));
- #endif
- JS_FreeCString(ctx, path);
- return JS_NewInt32(ctx, ret);
- }
- /* return [array, errorcode] */
- static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- #ifdef _WIN32
- const char *path;
- JSValue obj;
- int err;
- uint32_t len;
- HANDLE h;
- WIN32_FIND_DATAA d;
- char s[1024];
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj)) {
- JS_FreeCString(ctx, path);
- return JS_EXCEPTION;
- }
- snprintf(s, sizeof(s), "%s/*", path);
- JS_FreeCString(ctx, path);
- err = 0;
- h = FindFirstFileA(s, &d);
- if (h == INVALID_HANDLE_VALUE)
- err = GetLastError();
- if (err)
- goto done;
- JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewString(ctx, "."),
- JS_PROP_C_W_E);
- for (len = 1; FindNextFileA(h, &d); len++) {
- JS_DefinePropertyValueUint32(ctx, obj, len,
- JS_NewString(ctx, d.cFileName),
- JS_PROP_C_W_E);
- }
- FindClose(h);
- done:
- return make_obj_error(ctx, obj, err);
- #else
- const char *path;
- DIR *f;
- struct dirent *d;
- JSValue obj;
- int err;
- uint32_t len;
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj)) {
- JS_FreeCString(ctx, path);
- return JS_EXCEPTION;
- }
- f = opendir(path);
- if (!f)
- err = errno;
- else
- err = 0;
- JS_FreeCString(ctx, path);
- if (!f)
- goto done;
- len = 0;
- for(;;) {
- errno = 0;
- d = readdir(f);
- if (!d) {
- err = errno;
- break;
- }
- JS_DefinePropertyValueUint32(ctx, obj, len++,
- JS_NewString(ctx, d->d_name),
- JS_PROP_C_W_E);
- }
- closedir(f);
- done:
- return make_obj_error(ctx, obj, err);
- #endif
- }
- #if !defined(_WIN32)
- static int64_t timespec_to_ms(const struct timespec *tv)
- {
- return (int64_t)tv->tv_sec * 1000 + (tv->tv_nsec / 1000000);
- }
- #endif
- /* return [obj, errcode] */
- static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int is_lstat)
- {
- const char *path;
- int err, res;
- struct stat st;
- JSValue obj;
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- #if defined(_WIN32)
- res = stat(path, &st);
- #else
- if (is_lstat)
- res = lstat(path, &st);
- else
- res = stat(path, &st);
- #endif
- err = (res < 0) ? errno : 0;
- JS_FreeCString(ctx, path);
- if (res < 0) {
- obj = JS_NULL;
- } else {
- obj = JS_NewObject(ctx);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- JS_DefinePropertyValueStr(ctx, obj, "dev",
- JS_NewInt64(ctx, st.st_dev),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "ino",
- JS_NewInt64(ctx, st.st_ino),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "mode",
- JS_NewInt32(ctx, st.st_mode),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "nlink",
- JS_NewInt64(ctx, st.st_nlink),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "uid",
- JS_NewInt64(ctx, st.st_uid),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "gid",
- JS_NewInt64(ctx, st.st_gid),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "rdev",
- JS_NewInt64(ctx, st.st_rdev),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "size",
- JS_NewInt64(ctx, st.st_size),
- JS_PROP_C_W_E);
- #if !defined(_WIN32)
- JS_DefinePropertyValueStr(ctx, obj, "blocks",
- JS_NewInt64(ctx, st.st_blocks),
- JS_PROP_C_W_E);
- #endif
- #if defined(_WIN32)
- JS_DefinePropertyValueStr(ctx, obj, "atime",
- JS_NewInt64(ctx, (int64_t)st.st_atime * 1000),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "mtime",
- JS_NewInt64(ctx, (int64_t)st.st_mtime * 1000),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "ctime",
- JS_NewInt64(ctx, (int64_t)st.st_ctime * 1000),
- JS_PROP_C_W_E);
- #elif defined(__APPLE__)
- JS_DefinePropertyValueStr(ctx, obj, "atime",
- JS_NewInt64(ctx, timespec_to_ms(&st.st_atimespec)),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "mtime",
- JS_NewInt64(ctx, timespec_to_ms(&st.st_mtimespec)),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "ctime",
- JS_NewInt64(ctx, timespec_to_ms(&st.st_ctimespec)),
- JS_PROP_C_W_E);
- #else
- JS_DefinePropertyValueStr(ctx, obj, "atime",
- JS_NewInt64(ctx, timespec_to_ms(&st.st_atim)),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "mtime",
- JS_NewInt64(ctx, timespec_to_ms(&st.st_mtim)),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueStr(ctx, obj, "ctime",
- JS_NewInt64(ctx, timespec_to_ms(&st.st_ctim)),
- JS_PROP_C_W_E);
- #endif
- }
- return make_obj_error(ctx, obj, err);
- }
- #if !defined(_WIN32)
- static void ms_to_timeval(struct timeval *tv, uint64_t v)
- {
- tv->tv_sec = v / 1000;
- tv->tv_usec = (v % 1000) * 1000;
- }
- #endif
- static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *path;
- int64_t atime, mtime;
- int ret;
- if (JS_ToInt64(ctx, &atime, argv[1]))
- return JS_EXCEPTION;
- if (JS_ToInt64(ctx, &mtime, argv[2]))
- return JS_EXCEPTION;
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- #if defined(_WIN32)
- {
- struct _utimbuf times;
- times.actime = atime / 1000;
- times.modtime = mtime / 1000;
- ret = js_get_errno(_utime(path, ×));
- }
- #else
- {
- struct timeval times[2];
- ms_to_timeval(×[0], atime);
- ms_to_timeval(×[1], mtime);
- ret = js_get_errno(utimes(path, times));
- }
- #endif
- JS_FreeCString(ctx, path);
- return JS_NewInt32(ctx, ret);
- }
- /* sleep(delay_ms) */
- static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int64_t delay;
- int ret;
- if (JS_ToInt64(ctx, &delay, argv[0]))
- return JS_EXCEPTION;
- if (delay < 0)
- delay = 0;
- #if defined(_WIN32)
- {
- if (delay > INT32_MAX)
- delay = INT32_MAX;
- Sleep(delay);
- ret = 0;
- }
- #else
- {
- struct timespec ts;
- ts.tv_sec = delay / 1000;
- ts.tv_nsec = (delay % 1000) * 1000000;
- ret = js_get_errno(nanosleep(&ts, NULL));
- }
- #endif
- return JS_NewInt32(ctx, ret);
- }
- #if defined(_WIN32)
- static char *realpath(const char *path, char *buf)
- {
- if (!_fullpath(buf, path, JS__PATH_MAX)) {
- errno = ENOENT;
- return NULL;
- } else {
- return buf;
- }
- }
- #endif
- #if !defined(__wasi__)
- /* return [path, errorcode] */
- static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *path;
- char buf[JS__PATH_MAX], *res;
- int err;
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- res = realpath(path, buf);
- JS_FreeCString(ctx, path);
- if (!res) {
- buf[0] = '\0';
- err = errno;
- } else {
- err = 0;
- }
- return make_string_error(ctx, buf, err);
- }
- #endif
- #if !defined(_WIN32) && !defined(__wasi__)
- static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *target, *linkpath;
- int err;
- target = JS_ToCString(ctx, argv[0]);
- if (!target)
- return JS_EXCEPTION;
- linkpath = JS_ToCString(ctx, argv[1]);
- if (!linkpath) {
- JS_FreeCString(ctx, target);
- return JS_EXCEPTION;
- }
- err = js_get_errno(symlink(target, linkpath));
- JS_FreeCString(ctx, target);
- JS_FreeCString(ctx, linkpath);
- return JS_NewInt32(ctx, err);
- }
- /* return [path, errorcode] */
- static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- const char *path;
- char buf[JS__PATH_MAX];
- int err;
- ssize_t res;
- path = JS_ToCString(ctx, argv[0]);
- if (!path)
- return JS_EXCEPTION;
- res = readlink(path, buf, sizeof(buf) - 1);
- if (res < 0) {
- buf[0] = '\0';
- err = errno;
- } else {
- buf[res] = '\0';
- err = 0;
- }
- JS_FreeCString(ctx, path);
- return make_string_error(ctx, buf, err);
- }
- static char **build_envp(JSContext *ctx, JSValue obj)
- {
- uint32_t len, i;
- JSPropertyEnum *tab;
- char **envp, *pair;
- const char *key, *str;
- JSValue val;
- size_t key_len, str_len;
- if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj,
- JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0)
- return NULL;
- envp = js_mallocz(ctx, sizeof(envp[0]) * ((size_t)len + 1));
- if (!envp)
- goto fail;
- for(i = 0; i < len; i++) {
- val = JS_GetProperty(ctx, obj, tab[i].atom);
- if (JS_IsException(val))
- goto fail;
- str = JS_ToCString(ctx, val);
- JS_FreeValue(ctx, val);
- if (!str)
- goto fail;
- key = JS_AtomToCString(ctx, tab[i].atom);
- if (!key) {
- JS_FreeCString(ctx, str);
- goto fail;
- }
- key_len = strlen(key);
- str_len = strlen(str);
- pair = js_malloc(ctx, key_len + str_len + 2);
- if (!pair) {
- JS_FreeCString(ctx, key);
- JS_FreeCString(ctx, str);
- goto fail;
- }
- memcpy(pair, key, key_len);
- pair[key_len] = '=';
- memcpy(pair + key_len + 1, str, str_len);
- pair[key_len + 1 + str_len] = '\0';
- envp[i] = pair;
- JS_FreeCString(ctx, key);
- JS_FreeCString(ctx, str);
- }
- done:
- for(i = 0; i < len; i++)
- JS_FreeAtom(ctx, tab[i].atom);
- js_free(ctx, tab);
- return envp;
- fail:
- if (envp) {
- for(i = 0; i < len; i++)
- js_free(ctx, envp[i]);
- js_free(ctx, envp);
- envp = NULL;
- }
- goto done;
- }
- /* execvpe is not available on non GNU systems */
- static int my_execvpe(const char *filename, char **argv, char **envp)
- {
- char *path, *p, *p_next, *p1;
- char buf[JS__PATH_MAX];
- size_t filename_len, path_len;
- bool eacces_error;
- filename_len = strlen(filename);
- if (filename_len == 0) {
- errno = ENOENT;
- return -1;
- }
- if (strchr(filename, '/'))
- return execve(filename, argv, envp);
- path = getenv("PATH");
- if (!path)
- path = (char *)"/bin:/usr/bin";
- eacces_error = false;
- p = path;
- for(p = path; p != NULL; p = p_next) {
- p1 = strchr(p, ':');
- if (!p1) {
- p_next = NULL;
- path_len = strlen(p);
- } else {
- p_next = p1 + 1;
- path_len = p1 - p;
- }
- /* path too long */
- if ((path_len + 1 + filename_len + 1) > JS__PATH_MAX)
- continue;
- memcpy(buf, p, path_len);
- buf[path_len] = '/';
- memcpy(buf + path_len + 1, filename, filename_len);
- buf[path_len + 1 + filename_len] = '\0';
- execve(buf, argv, envp);
- switch(errno) {
- case EACCES:
- eacces_error = true;
- break;
- case ENOENT:
- case ENOTDIR:
- break;
- default:
- return -1;
- }
- }
- if (eacces_error)
- errno = EACCES;
- return -1;
- }
- static void (*js_os_exec_closefrom)(int);
- #if !defined(EMSCRIPTEN) && !defined(__wasi__)
- static js_once_t js_os_exec_once = JS_ONCE_INIT;
- static void js_os_exec_once_init(void)
- {
- *(void **) (&js_os_exec_closefrom) = dlsym(RTLD_DEFAULT, "closefrom");
- }
- #endif
- /* exec(args[, options]) -> exitcode */
- static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValueConst options, args = argv[0];
- JSValue val, ret_val;
- const char **exec_argv, *file = NULL, *str, *cwd = NULL;
- char **envp = environ;
- uint32_t exec_argc, i;
- int ret, pid, status;
- bool block_flag = true, use_path = true;
- static const char *std_name[3] = { "stdin", "stdout", "stderr" };
- int std_fds[3];
- uint32_t uid = -1, gid = -1;
- int ngroups = -1;
- gid_t groups[64];
- val = JS_GetPropertyStr(ctx, args, "length");
- if (JS_IsException(val))
- return JS_EXCEPTION;
- ret = JS_ToUint32(ctx, &exec_argc, val);
- JS_FreeValue(ctx, val);
- if (ret)
- return JS_EXCEPTION;
- /* arbitrary limit to avoid overflow */
- if (exec_argc < 1 || exec_argc > 65535) {
- return JS_ThrowTypeError(ctx, "invalid number of arguments");
- }
- exec_argv = js_mallocz(ctx, sizeof(exec_argv[0]) * (exec_argc + 1));
- if (!exec_argv)
- return JS_EXCEPTION;
- for(i = 0; i < exec_argc; i++) {
- val = JS_GetPropertyUint32(ctx, args, i);
- if (JS_IsException(val))
- goto exception;
- str = JS_ToCString(ctx, val);
- JS_FreeValue(ctx, val);
- if (!str)
- goto exception;
- exec_argv[i] = str;
- }
- exec_argv[exec_argc] = NULL;
- for(i = 0; i < 3; i++)
- std_fds[i] = i;
- /* get the options, if any */
- if (argc >= 2) {
- options = argv[1];
- if (get_bool_option(ctx, &block_flag, options, "block"))
- goto exception;
- if (get_bool_option(ctx, &use_path, options, "usePath"))
- goto exception;
- val = JS_GetPropertyStr(ctx, options, "file");
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- file = JS_ToCString(ctx, val);
- JS_FreeValue(ctx, val);
- if (!file)
- goto exception;
- }
- val = JS_GetPropertyStr(ctx, options, "cwd");
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- cwd = JS_ToCString(ctx, val);
- JS_FreeValue(ctx, val);
- if (!cwd)
- goto exception;
- }
- /* stdin/stdout/stderr handles */
- for(i = 0; i < 3; i++) {
- val = JS_GetPropertyStr(ctx, options, std_name[i]);
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- int fd;
- ret = JS_ToInt32(ctx, &fd, val);
- JS_FreeValue(ctx, val);
- if (ret)
- goto exception;
- std_fds[i] = fd;
- }
- }
- val = JS_GetPropertyStr(ctx, options, "env");
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- envp = build_envp(ctx, val);
- JS_FreeValue(ctx, val);
- if (!envp)
- goto exception;
- }
- val = JS_GetPropertyStr(ctx, options, "uid");
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- ret = JS_ToUint32(ctx, &uid, val);
- JS_FreeValue(ctx, val);
- if (ret)
- goto exception;
- }
- val = JS_GetPropertyStr(ctx, options, "gid");
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- ret = JS_ToUint32(ctx, &gid, val);
- JS_FreeValue(ctx, val);
- if (ret)
- goto exception;
- }
- val = JS_GetPropertyStr(ctx, options, "groups");
- if (JS_IsException(val))
- goto exception;
- if (!JS_IsUndefined(val)) {
- int64_t idx, len;
- JSValue prop;
- uint32_t id;
- ngroups = 0;
- if (JS_GetLength(ctx, val, &len)) {
- JS_FreeValue(ctx, val);
- goto exception;
- }
- for (idx = 0; idx < len; idx++) {
- prop = JS_GetPropertyInt64(ctx, val, idx);
- if (JS_IsException(prop))
- break;
- if (JS_IsUndefined(prop))
- continue;
- ret = JS_ToUint32(ctx, &id, prop);
- JS_FreeValue(ctx, prop);
- if (ret)
- break;
- if (ngroups == countof(groups)) {
- JS_ThrowRangeError(ctx, "too many groups");
- break;
- }
- groups[ngroups++] = id;
- }
- JS_FreeValue(ctx, val);
- if (idx < len)
- goto exception;
- }
- }
- #if !defined(EMSCRIPTEN) && !defined(__wasi__)
- // should happen pre-fork because it calls dlsym()
- // and that's not an async-signal-safe function
- js_once(&js_os_exec_once, js_os_exec_once_init);
- #endif
- pid = fork();
- if (pid < 0) {
- JS_ThrowTypeError(ctx, "fork error");
- goto exception;
- }
- if (pid == 0) {
- /* child */
- /* remap the stdin/stdout/stderr handles if necessary */
- for(i = 0; i < 3; i++) {
- if (std_fds[i] != i) {
- if (dup2(std_fds[i], i) < 0)
- _exit(127);
- }
- }
- if (js_os_exec_closefrom) {
- js_os_exec_closefrom(3);
- } else {
- int fd_max = sysconf(_SC_OPEN_MAX);
- for(i = 3; i < fd_max; i++)
- close(i);
- }
- if (cwd) {
- if (chdir(cwd) < 0)
- _exit(127);
- }
- if (ngroups != -1) {
- if (setgroups(ngroups, groups) < 0)
- _exit(127);
- }
- if (uid != -1) {
- if (setuid(uid) < 0)
- _exit(127);
- }
- if (gid != -1) {
- if (setgid(gid) < 0)
- _exit(127);
- }
- if (!file)
- file = exec_argv[0];
- if (use_path)
- ret = my_execvpe(file, (char **)exec_argv, envp);
- else
- ret = execve(file, (char **)exec_argv, envp);
- _exit(127);
- }
- /* parent */
- if (block_flag) {
- for(;;) {
- ret = waitpid(pid, &status, 0);
- if (ret == pid) {
- if (WIFEXITED(status)) {
- ret = WEXITSTATUS(status);
- break;
- } else if (WIFSIGNALED(status)) {
- ret = -WTERMSIG(status);
- break;
- }
- }
- }
- } else {
- ret = pid;
- }
- ret_val = JS_NewInt32(ctx, ret);
- done:
- JS_FreeCString(ctx, file);
- JS_FreeCString(ctx, cwd);
- for(i = 0; i < exec_argc; i++)
- JS_FreeCString(ctx, exec_argv[i]);
- js_free(ctx, exec_argv);
- if (envp != environ) {
- char **p;
- p = envp;
- while (*p != NULL) {
- js_free(ctx, *p);
- p++;
- }
- js_free(ctx, envp);
- }
- return ret_val;
- exception:
- ret_val = JS_EXCEPTION;
- goto done;
- }
- /* getpid() -> pid */
- static JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- return JS_NewInt32(ctx, getpid());
- }
- /* waitpid(pid, block) -> [pid, status] */
- static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int pid, status, options, ret;
- JSValue obj;
- if (JS_ToInt32(ctx, &pid, argv[0]))
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &options, argv[1]))
- return JS_EXCEPTION;
- ret = waitpid(pid, &status, options);
- if (ret < 0) {
- ret = -errno;
- status = 0;
- }
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj))
- return obj;
- JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ret),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, status),
- JS_PROP_C_W_E);
- return obj;
- }
- /* pipe() -> [read_fd, write_fd] or null if error */
- static JSValue js_os_pipe(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int pipe_fds[2], ret;
- JSValue obj;
- ret = pipe(pipe_fds);
- if (ret < 0)
- return JS_NULL;
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj))
- return obj;
- JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, pipe_fds[0]),
- JS_PROP_C_W_E);
- JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, pipe_fds[1]),
- JS_PROP_C_W_E);
- return obj;
- }
- /* kill(pid, sig) */
- static JSValue js_os_kill(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int pid, sig, ret;
- if (JS_ToInt32(ctx, &pid, argv[0]))
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &sig, argv[1]))
- return JS_EXCEPTION;
- ret = js_get_errno(kill(pid, sig));
- return JS_NewInt32(ctx, ret);
- }
- /* dup(fd) */
- static JSValue js_os_dup(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd, ret;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- ret = js_get_errno(dup(fd));
- return JS_NewInt32(ctx, ret);
- }
- /* dup2(fd) */
- static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int fd, fd2, ret;
- if (JS_ToInt32(ctx, &fd, argv[0]))
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &fd2, argv[1]))
- return JS_EXCEPTION;
- ret = js_get_errno(dup2(fd, fd2));
- return JS_NewInt32(ctx, ret);
- }
- #endif /* !_WIN32 */
- #ifdef USE_WORKER
- /* Worker */
- typedef struct {
- JSWorkerMessagePipe *recv_pipe;
- JSWorkerMessagePipe *send_pipe;
- JSWorkerMessageHandler *msg_handler;
- } JSWorkerData;
- typedef struct {
- char *filename; /* module filename */
- char *basename; /* module base name */
- JSWorkerMessagePipe *recv_pipe, *send_pipe;
- } WorkerFuncArgs;
- typedef struct {
- int ref_count;
- uint64_t buf[];
- } JSSABHeader;
- static JSContext *(*js_worker_new_context_func)(JSRuntime *rt);
- static int atomic_add_int(int *ptr, int v)
- {
- return atomic_fetch_add((_Atomic uint32_t*)ptr, v) + v;
- }
- /* shared array buffer allocator */
- static void *js_sab_alloc(void *opaque, size_t size)
- {
- JSSABHeader *sab;
- sab = malloc(sizeof(JSSABHeader) + size);
- if (!sab)
- return NULL;
- sab->ref_count = 1;
- return sab->buf;
- }
- static void js_sab_free(void *opaque, void *ptr)
- {
- JSSABHeader *sab;
- int ref_count;
- sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader));
- ref_count = atomic_add_int(&sab->ref_count, -1);
- assert(ref_count >= 0);
- if (ref_count == 0) {
- free(sab);
- }
- }
- static void js_sab_dup(void *opaque, void *ptr)
- {
- JSSABHeader *sab;
- sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader));
- atomic_add_int(&sab->ref_count, 1);
- }
- static JSWorkerMessagePipe *js_new_message_pipe(void)
- {
- JSWorkerMessagePipe *ps;
- ps = malloc(sizeof(*ps));
- if (!ps)
- return NULL;
- if (js_waker_init(&ps->waker)) {
- free(ps);
- return NULL;
- }
- ps->ref_count = 1;
- init_list_head(&ps->msg_queue);
- js_mutex_init(&ps->mutex);
- return ps;
- }
- static JSWorkerMessagePipe *js_dup_message_pipe(JSWorkerMessagePipe *ps)
- {
- atomic_add_int(&ps->ref_count, 1);
- return ps;
- }
- static void js_free_message(JSWorkerMessage *msg)
- {
- size_t i;
- /* free the SAB */
- for(i = 0; i < msg->sab_tab_len; i++) {
- js_sab_free(NULL, msg->sab_tab[i]);
- }
- free(msg->sab_tab);
- free(msg->data);
- free(msg);
- }
- static void js_free_message_pipe(JSWorkerMessagePipe *ps)
- {
- struct list_head *el, *el1;
- JSWorkerMessage *msg;
- int ref_count;
- if (!ps)
- return;
- ref_count = atomic_add_int(&ps->ref_count, -1);
- assert(ref_count >= 0);
- if (ref_count == 0) {
- list_for_each_safe(el, el1, &ps->msg_queue) {
- msg = list_entry(el, JSWorkerMessage, link);
- js_free_message(msg);
- }
- js_mutex_destroy(&ps->mutex);
- js_waker_close(&ps->waker);
- free(ps);
- }
- }
- static void js_free_port(JSRuntime *rt, JSWorkerMessageHandler *port)
- {
- if (port) {
- js_free_message_pipe(port->recv_pipe);
- JS_FreeValueRT(rt, port->on_message_func);
- list_del(&port->link);
- js_free_rt(rt, port);
- }
- }
- static void js_worker_finalizer(JSRuntime *rt, JSValueConst val)
- {
- JSThreadState *ts = js_get_thread_state(rt);
- JSWorkerData *worker = JS_GetOpaque(val, ts->worker_class_id);
- if (worker) {
- js_free_message_pipe(worker->recv_pipe);
- js_free_message_pipe(worker->send_pipe);
- js_free_port(rt, worker->msg_handler);
- js_free_rt(rt, worker);
- }
- }
- static JSClassDef js_worker_class = {
- "Worker",
- .finalizer = js_worker_finalizer,
- };
- static void worker_func(void *opaque)
- {
- WorkerFuncArgs *args = opaque;
- JSRuntime *rt;
- JSThreadState *ts;
- JSContext *ctx;
- JSValue val;
- rt = JS_NewRuntime();
- if (rt == NULL) {
- fprintf(stderr, "JS_NewRuntime failure");
- exit(1);
- }
- js_std_init_handlers(rt);
- JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
- /* set the pipe to communicate with the parent */
- ts = js_get_thread_state(rt);
- ts->recv_pipe = args->recv_pipe;
- ts->send_pipe = args->send_pipe;
- /* function pointer to avoid linking the whole JS_NewContext() if
- not needed */
- ctx = js_worker_new_context_func(rt);
- if (ctx == NULL) {
- fprintf(stderr, "JS_NewContext failure");
- }
- JS_SetCanBlock(rt, true);
- js_std_add_helpers(ctx, -1, NULL);
- val = JS_LoadModule(ctx, args->basename, args->filename);
- free(args->filename);
- free(args->basename);
- free(args);
- val = js_std_await(ctx, val);
- if (JS_IsException(val))
- js_std_dump_error(ctx);
- JS_FreeValue(ctx, val);
- js_std_loop(ctx);
- js_std_free_handlers(rt);
- JS_FreeContext(ctx);
- JS_FreeRuntime(rt);
- }
- static JSValue js_worker_ctor_internal(JSContext *ctx, JSValueConst new_target,
- JSWorkerMessagePipe *recv_pipe,
- JSWorkerMessagePipe *send_pipe)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSValue obj = JS_UNDEFINED, proto;
- JSWorkerData *s;
- /* create the object */
- if (JS_IsUndefined(new_target)) {
- proto = JS_GetClassProto(ctx, ts->worker_class_id);
- } else {
- proto = JS_GetPropertyStr(ctx, new_target, "prototype");
- if (JS_IsException(proto))
- goto fail;
- }
- obj = JS_NewObjectProtoClass(ctx, proto, ts->worker_class_id);
- JS_FreeValue(ctx, proto);
- if (JS_IsException(obj))
- goto fail;
- s = js_mallocz(ctx, sizeof(*s));
- if (!s)
- goto fail;
- s->recv_pipe = js_dup_message_pipe(recv_pipe);
- s->send_pipe = js_dup_message_pipe(send_pipe);
- JS_SetOpaque(obj, s);
- return obj;
- fail:
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- WorkerFuncArgs *args = NULL;
- js_thread_t thr;
- JSValue obj = JS_UNDEFINED;
- int ret;
- const char *filename = NULL, *basename;
- JSAtom basename_atom;
- /* XXX: in order to avoid problems with resource liberation, we
- don't support creating workers inside workers */
- if (!is_main_thread(rt))
- return JS_ThrowTypeError(ctx, "cannot create a worker inside a worker");
- /* base name, assuming the calling function is a normal JS
- function */
- basename_atom = JS_GetScriptOrModuleName(ctx, 1);
- if (basename_atom == JS_ATOM_NULL) {
- return JS_ThrowTypeError(ctx, "could not determine calling script or module name");
- }
- basename = JS_AtomToCString(ctx, basename_atom);
- JS_FreeAtom(ctx, basename_atom);
- if (!basename)
- goto fail;
- /* module name */
- filename = JS_ToCString(ctx, argv[0]);
- if (!filename)
- goto fail;
- args = malloc(sizeof(*args));
- if (!args)
- goto oom_fail;
- memset(args, 0, sizeof(*args));
- args->filename = strdup(filename);
- args->basename = strdup(basename);
- /* ports */
- args->recv_pipe = js_new_message_pipe();
- if (!args->recv_pipe)
- goto oom_fail;
- args->send_pipe = js_new_message_pipe();
- if (!args->send_pipe)
- goto oom_fail;
- obj = js_worker_ctor_internal(ctx, new_target,
- args->send_pipe, args->recv_pipe);
- if (JS_IsException(obj))
- goto fail;
- ret = js_thread_create(&thr, worker_func, args, JS_THREAD_CREATE_DETACHED);
- if (ret != 0) {
- JS_ThrowTypeError(ctx, "could not create worker");
- goto fail;
- }
- JS_FreeCString(ctx, basename);
- JS_FreeCString(ctx, filename);
- return obj;
- oom_fail:
- JS_ThrowOutOfMemory(ctx);
- fail:
- JS_FreeCString(ctx, basename);
- JS_FreeCString(ctx, filename);
- if (args) {
- free(args->filename);
- free(args->basename);
- js_free_message_pipe(args->recv_pipe);
- js_free_message_pipe(args->send_pipe);
- free(args);
- }
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, ts->worker_class_id);
- JSWorkerMessagePipe *ps;
- size_t data_len, i;
- uint8_t *data;
- JSWorkerMessage *msg;
- JSSABTab sab_tab;
- if (!worker)
- return JS_EXCEPTION;
- data = JS_WriteObject2(ctx, &data_len, argv[0],
- JS_WRITE_OBJ_SAB | JS_WRITE_OBJ_REFERENCE,
- &sab_tab);
- if (!data)
- return JS_EXCEPTION;
- msg = malloc(sizeof(*msg));
- if (!msg)
- goto fail;
- msg->data = NULL;
- msg->sab_tab = NULL;
- /* must reallocate because the allocator may be different */
- msg->data = malloc(data_len);
- if (!msg->data)
- goto fail;
- memcpy(msg->data, data, data_len);
- msg->data_len = data_len;
- if (sab_tab.len > 0) {
- msg->sab_tab = malloc(sizeof(msg->sab_tab[0]) * sab_tab.len);
- if (!msg->sab_tab)
- goto fail;
- memcpy(msg->sab_tab, sab_tab.tab, sizeof(msg->sab_tab[0]) * sab_tab.len);
- }
- msg->sab_tab_len = sab_tab.len;
- js_free(ctx, data);
- js_free(ctx, sab_tab.tab);
- /* increment the SAB reference counts */
- for(i = 0; i < msg->sab_tab_len; i++) {
- js_sab_dup(NULL, msg->sab_tab[i]);
- }
- ps = worker->send_pipe;
- js_mutex_lock(&ps->mutex);
- /* indicate that data is present */
- if (list_empty(&ps->msg_queue))
- js_waker_signal(&ps->waker);
- list_add_tail(&msg->link, &ps->msg_queue);
- js_mutex_unlock(&ps->mutex);
- return JS_UNDEFINED;
- fail:
- if (msg) {
- free(msg->data);
- free(msg->sab_tab);
- free(msg);
- }
- js_free(ctx, data);
- js_free(ctx, sab_tab.tab);
- return JS_EXCEPTION;
- }
- static JSValue js_worker_set_onmessage(JSContext *ctx, JSValueConst this_val,
- JSValueConst func)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, ts->worker_class_id);
- JSWorkerMessageHandler *port;
- if (!worker)
- return JS_EXCEPTION;
- port = worker->msg_handler;
- if (JS_IsNull(func)) {
- if (port) {
- js_free_port(rt, port);
- worker->msg_handler = NULL;
- }
- } else {
- if (!JS_IsFunction(ctx, func))
- return JS_ThrowTypeError(ctx, "not a function");
- if (!port) {
- port = js_mallocz(ctx, sizeof(*port));
- if (!port)
- return JS_EXCEPTION;
- port->recv_pipe = js_dup_message_pipe(worker->recv_pipe);
- port->on_message_func = JS_NULL;
- list_add_tail(&port->link, &ts->port_list);
- worker->msg_handler = port;
- }
- JS_FreeValue(ctx, port->on_message_func);
- port->on_message_func = JS_DupValue(ctx, func);
- }
- return JS_UNDEFINED;
- }
- static JSValue js_worker_get_onmessage(JSContext *ctx, JSValueConst this_val)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, ts->worker_class_id);
- JSWorkerMessageHandler *port;
- if (!worker)
- return JS_EXCEPTION;
- port = worker->msg_handler;
- if (port) {
- return JS_DupValue(ctx, port->on_message_func);
- } else {
- return JS_NULL;
- }
- }
- static const JSCFunctionListEntry js_worker_proto_funcs[] = {
- JS_CFUNC_DEF("postMessage", 1, js_worker_postMessage ),
- JS_CGETSET_DEF("onmessage", js_worker_get_onmessage, js_worker_set_onmessage ),
- };
- #endif /* USE_WORKER */
- void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt))
- {
- #ifdef USE_WORKER
- js_worker_new_context_func = func;
- #endif
- }
- #if defined(_WIN32)
- #define OS_PLATFORM "win32"
- #elif defined(__APPLE__)
- #define OS_PLATFORM "darwin"
- #elif defined(EMSCRIPTEN)
- #define OS_PLATFORM "js"
- #elif defined(__CYGWIN__)
- #define OS_PLATFORM "cygwin"
- #elif defined(__linux__)
- #define OS_PLATFORM "linux"
- #elif defined(__OpenBSD__)
- #define OS_PLATFORM "openbsd"
- #elif defined(__NetBSD__)
- #define OS_PLATFORM "netbsd"
- #elif defined(__FreeBSD__)
- #define OS_PLATFORM "freebsd"
- #elif defined(__wasi__)
- #define OS_PLATFORM "wasi"
- #elif defined(__GNU__)
- #define OS_PLATFORM "hurd"
- #else
- #define OS_PLATFORM "unknown"
- #endif
- #define OS_FLAG(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE )
- static const JSCFunctionListEntry js_os_funcs[] = {
- JS_CFUNC_DEF("open", 2, js_os_open ),
- OS_FLAG(O_RDONLY),
- OS_FLAG(O_WRONLY),
- OS_FLAG(O_RDWR),
- OS_FLAG(O_APPEND),
- OS_FLAG(O_CREAT),
- OS_FLAG(O_EXCL),
- OS_FLAG(O_TRUNC),
- #if defined(_WIN32)
- OS_FLAG(O_BINARY),
- OS_FLAG(O_TEXT),
- #endif
- JS_CFUNC_DEF("close", 1, js_os_close ),
- JS_CFUNC_DEF("seek", 3, js_os_seek ),
- JS_CFUNC_MAGIC_DEF("read", 4, js_os_read_write, 0 ),
- JS_CFUNC_MAGIC_DEF("write", 4, js_os_read_write, 1 ),
- JS_CFUNC_DEF("isatty", 1, js_os_isatty ),
- #if !defined(__wasi__)
- JS_CFUNC_DEF("ttyGetWinSize", 1, js_os_ttyGetWinSize ),
- JS_CFUNC_DEF("ttySetRaw", 1, js_os_ttySetRaw ),
- #endif
- JS_CFUNC_DEF("remove", 1, js_os_remove ),
- JS_CFUNC_DEF("rename", 2, js_os_rename ),
- JS_CFUNC_MAGIC_DEF("setReadHandler", 2, js_os_setReadHandler, 0 ),
- JS_CFUNC_MAGIC_DEF("setWriteHandler", 2, js_os_setReadHandler, 1 ),
- JS_CFUNC_DEF("signal", 2, js_os_signal ),
- OS_FLAG(SIGINT),
- OS_FLAG(SIGABRT),
- OS_FLAG(SIGFPE),
- OS_FLAG(SIGILL),
- OS_FLAG(SIGSEGV),
- OS_FLAG(SIGTERM),
- #if !defined(_WIN32) && !defined(__wasi__)
- OS_FLAG(SIGQUIT),
- OS_FLAG(SIGPIPE),
- OS_FLAG(SIGALRM),
- OS_FLAG(SIGUSR1),
- OS_FLAG(SIGUSR2),
- OS_FLAG(SIGCHLD),
- OS_FLAG(SIGCONT),
- OS_FLAG(SIGSTOP),
- OS_FLAG(SIGTSTP),
- OS_FLAG(SIGTTIN),
- OS_FLAG(SIGTTOU),
- JS_CFUNC_DEF("cputime", 0, js_os_cputime ),
- #endif
- JS_CFUNC_DEF("exePath", 0, js_os_exepath ),
- JS_CFUNC_DEF("now", 0, js_os_now ),
- JS_CFUNC_MAGIC_DEF("setTimeout", 2, js_os_setTimeout, 0 ),
- JS_CFUNC_MAGIC_DEF("setInterval", 2, js_os_setTimeout, 1 ),
- // per spec: both functions can cancel timeouts and intervals
- JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ),
- JS_CFUNC_DEF("clearInterval", 1, js_os_clearTimeout ),
- JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ),
- JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),
- JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),
- JS_CFUNC_DEF("chdir", 0, js_os_chdir ),
- JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ),
- JS_CFUNC_DEF("readdir", 1, js_os_readdir ),
- /* st_mode constants */
- OS_FLAG(S_IFMT),
- OS_FLAG(S_IFIFO),
- OS_FLAG(S_IFCHR),
- OS_FLAG(S_IFDIR),
- OS_FLAG(S_IFBLK),
- OS_FLAG(S_IFREG),
- #if !defined(_WIN32)
- OS_FLAG(S_IFSOCK),
- OS_FLAG(S_IFLNK),
- OS_FLAG(S_ISGID),
- OS_FLAG(S_ISUID),
- #endif
- JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ),
- JS_CFUNC_DEF("utimes", 3, js_os_utimes ),
- JS_CFUNC_DEF("sleep", 1, js_os_sleep ),
- #if !defined(__wasi__)
- JS_CFUNC_DEF("realpath", 1, js_os_realpath ),
- #endif
- #if !defined(_WIN32) && !defined(__wasi__)
- JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ),
- JS_CFUNC_DEF("symlink", 2, js_os_symlink ),
- JS_CFUNC_DEF("readlink", 1, js_os_readlink ),
- JS_CFUNC_DEF("exec", 1, js_os_exec ),
- JS_CFUNC_DEF("getpid", 0, js_os_getpid ),
- JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ),
- OS_FLAG(WNOHANG),
- JS_CFUNC_DEF("pipe", 0, js_os_pipe ),
- JS_CFUNC_DEF("kill", 2, js_os_kill ),
- JS_CFUNC_DEF("dup", 1, js_os_dup ),
- JS_CFUNC_DEF("dup2", 2, js_os_dup2 ),
- #endif
- };
- static int js_os_init(JSContext *ctx, JSModuleDef *m)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- ts->can_js_os_poll = true;
- #ifdef USE_WORKER
- {
- JSValue proto, obj;
- /* Worker class */
- JS_NewClassID(rt, &ts->worker_class_id);
- JS_NewClass(rt, ts->worker_class_id, &js_worker_class);
- proto = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, proto, js_worker_proto_funcs, countof(js_worker_proto_funcs));
- obj = JS_NewCFunction2(ctx, js_worker_ctor, "Worker", 1,
- JS_CFUNC_constructor, 0);
- JS_SetConstructor(ctx, obj, proto);
- JS_SetClassProto(ctx, ts->worker_class_id, proto);
- /* set 'Worker.parent' if necessary */
- if (ts->recv_pipe && ts->send_pipe) {
- JS_DefinePropertyValueStr(ctx, obj, "parent",
- js_worker_ctor_internal(ctx, JS_UNDEFINED, ts->recv_pipe, ts->send_pipe),
- JS_PROP_C_W_E);
- }
- JS_SetModuleExport(ctx, m, "Worker", obj);
- }
- #endif /* USE_WORKER */
- return JS_SetModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs));
- }
- JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name)
- {
- JSModuleDef *m;
- m = JS_NewCModule(ctx, module_name, js_os_init);
- if (!m)
- return NULL;
- JS_AddModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs));
- #ifdef USE_WORKER
- JS_AddModuleExport(ctx, m, "Worker");
- #endif
- return m;
- }
- /**********************************************************/
- static JSValue js_print(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- #ifdef _WIN32
- HANDLE handle;
- DWORD mode;
- #endif
- const char *s;
- JSValueConst v;
- DynBuf b;
- int i;
- dbuf_init(&b);
- for(i = 0; i < argc; i++) {
- v = argv[i];
- s = JS_ToCString(ctx, v);
- if (!s && JS_IsObject(v)) {
- JS_FreeValue(ctx, JS_GetException(ctx));
- JSValue t = JS_ToObjectString(ctx, v);
- s = JS_ToCString(ctx, t);
- JS_FreeValue(ctx, t);
- }
- if (s) {
- dbuf_printf(&b, "%s%s", &" "[!i], s);
- JS_FreeCString(ctx, s);
- } else {
- dbuf_printf(&b, "%s<exception>", &" "[!i]);
- JS_FreeValue(ctx, JS_GetException(ctx));
- }
- }
- dbuf_putc(&b, '\n');
- #ifdef _WIN32
- // use WriteConsoleA with CP_UTF8 for better Unicode handling vis-a-vis
- // the mangling that happens when going through msvcrt's stdio layer,
- // *except* when stdout is redirected to something that is not a console
- handle = (HANDLE)_get_osfhandle(/*STDOUT_FILENO*/1); // don't CloseHandle
- if (GetFileType(handle) != FILE_TYPE_CHAR)
- goto fallback;
- if (!GetConsoleMode(handle, &mode))
- goto fallback;
- handle = GetStdHandle(STD_OUTPUT_HANDLE);
- if (handle == INVALID_HANDLE_VALUE)
- goto fallback;
- mode = GetConsoleOutputCP();
- SetConsoleOutputCP(CP_UTF8);
- WriteConsoleA(handle, b.buf, b.size, NULL, NULL);
- SetConsoleOutputCP(mode);
- FlushFileBuffers(handle);
- goto done;
- fallback:
- #endif
- fwrite(b.buf, 1, b.size, stdout);
- fflush(stdout);
- goto done; // avoid unused label warning
- done:
- dbuf_free(&b);
- return JS_UNDEFINED;
- }
- void js_std_add_helpers(JSContext *ctx, int argc, char **argv)
- {
- JSValue global_obj, console, args;
- int i;
- /* XXX: should these global definitions be enumerable? */
- global_obj = JS_GetGlobalObject(ctx);
- console = JS_NewObject(ctx);
- JS_SetPropertyStr(ctx, console, "log",
- JS_NewCFunction(ctx, js_print, "log", 1));
- JS_SetPropertyStr(ctx, global_obj, "console", console);
- /* same methods as the mozilla JS shell */
- if (argc >= 0) {
- args = JS_NewArray(ctx);
- for(i = 0; i < argc; i++) {
- JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, argv[i]));
- }
- JS_SetPropertyStr(ctx, global_obj, "scriptArgs", args);
- }
- JS_SetPropertyStr(ctx, global_obj, "print",
- JS_NewCFunction(ctx, js_print, "print", 1));
- JS_FreeValue(ctx, global_obj);
- }
- static void js_std_finalize(JSRuntime *rt, void *arg)
- {
- JSThreadState *ts = arg;
- js_set_thread_state(rt, NULL);
- js_free_rt(rt, ts);
- }
- void js_std_init_handlers(JSRuntime *rt)
- {
- JSThreadState *ts;
- ts = js_mallocz_rt(rt, sizeof(*ts));
- if (!ts) {
- fprintf(stderr, "Could not allocate memory for the worker");
- exit(1);
- }
- init_list_head(&ts->os_rw_handlers);
- init_list_head(&ts->os_signal_handlers);
- init_list_head(&ts->os_timers);
- init_list_head(&ts->port_list);
- init_list_head(&ts->rejected_promise_list);
- ts->next_timer_id = 1;
- js_set_thread_state(rt, ts);
- JS_AddRuntimeFinalizer(rt, js_std_finalize, ts);
- #ifdef USE_WORKER
- /* set the SharedArrayBuffer memory handlers */
- {
- JSSharedArrayBufferFunctions sf;
- memset(&sf, 0, sizeof(sf));
- sf.sab_alloc = js_sab_alloc;
- sf.sab_free = js_sab_free;
- sf.sab_dup = js_sab_dup;
- JS_SetSharedArrayBufferFunctions(rt, &sf);
- }
- #endif
- }
- static void free_rp(JSRuntime *rt, JSRejectedPromiseEntry *rp)
- {
- list_del(&rp->link);
- JS_FreeValueRT(rt, rp->promise);
- JS_FreeValueRT(rt, rp->reason);
- js_free_rt(rt, rp);
- }
- void js_std_free_handlers(JSRuntime *rt)
- {
- JSThreadState *ts = js_get_thread_state(rt);
- struct list_head *el, *el1;
- list_for_each_safe(el, el1, &ts->os_rw_handlers) {
- JSOSRWHandler *rh = list_entry(el, JSOSRWHandler, link);
- free_rw_handler(rt, rh);
- }
- list_for_each_safe(el, el1, &ts->os_signal_handlers) {
- JSOSSignalHandler *sh = list_entry(el, JSOSSignalHandler, link);
- free_sh(rt, sh);
- }
- list_for_each_safe(el, el1, &ts->os_timers) {
- JSOSTimer *th = list_entry(el, JSOSTimer, link);
- free_timer(rt, th);
- }
- list_for_each_safe(el, el1, &ts->rejected_promise_list) {
- JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
- free_rp(rt, rp);
- }
- #ifdef USE_WORKER
- /* XXX: free port_list ? */
- js_free_message_pipe(ts->recv_pipe);
- js_free_message_pipe(ts->send_pipe);
- #endif
- }
- static void js_dump_obj(JSContext *ctx, FILE *f, JSValueConst val)
- {
- const char *str;
- str = JS_ToCString(ctx, val);
- if (str) {
- fprintf(f, "%s\n", str);
- JS_FreeCString(ctx, str);
- } else {
- fprintf(f, "[exception]\n");
- }
- }
- static void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val)
- {
- JSValue val;
- bool is_error;
- is_error = JS_IsError(exception_val);
- js_dump_obj(ctx, stderr, exception_val);
- if (is_error) {
- val = JS_GetPropertyStr(ctx, exception_val, "stack");
- } else {
- js_std_cmd(/*ErrorBackTrace*/2, ctx, &val);
- }
- if (!JS_IsUndefined(val)) {
- js_dump_obj(ctx, stderr, val);
- JS_FreeValue(ctx, val);
- }
- }
- void js_std_dump_error(JSContext *ctx)
- {
- JSValue exception_val;
- exception_val = JS_GetException(ctx);
- js_std_dump_error1(ctx, exception_val);
- JS_FreeValue(ctx, exception_val);
- }
- static JSRejectedPromiseEntry *find_rejected_promise(JSContext *ctx, JSThreadState *ts,
- JSValueConst promise)
- {
- struct list_head *el;
- list_for_each(el, &ts->rejected_promise_list) {
- JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
- if (JS_IsSameValue(ctx, rp->promise, promise))
- return rp;
- }
- return NULL;
- }
- void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
- JSValueConst reason,
- bool is_handled, void *opaque)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSRejectedPromiseEntry *rp = find_rejected_promise(ctx, ts, promise);
- if (is_handled) {
- /* the rejection is handled, so the entry can be removed if present */
- if (rp)
- free_rp(rt, rp);
- } else {
- /* add a new entry if needed */
- if (!rp) {
- rp = js_malloc_rt(rt, sizeof(*rp));
- if (rp) {
- rp->promise = JS_DupValue(ctx, promise);
- rp->reason = JS_DupValue(ctx, reason);
- list_add_tail(&rp->link, &ts->rejected_promise_list);
- }
- }
- }
- }
- /* check if there are pending promise rejections. It must be done
- asynchrously in case a rejected promise is handled later. Currently
- we do it once the application is about to sleep. It could be done
- more often if needed. */
- static void js_std_promise_rejection_check(JSContext *ctx)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- struct list_head *el;
- if (unlikely(!list_empty(&ts->rejected_promise_list))) {
- list_for_each(el, &ts->rejected_promise_list) {
- JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
- fprintf(stderr, "Possibly unhandled promise rejection: ");
- js_std_dump_error1(ctx, rp->reason);
- fflush(stderr);
- }
- exit(1);
- }
- }
- /* main loop which calls the user JS callbacks */
- int js_std_loop(JSContext *ctx)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSContext *ctx1;
- int err;
- for(;;) {
- /* execute the pending jobs */
- for(;;) {
- err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
- if (err <= 0) {
- if (err < 0)
- goto done;
- break;
- }
- }
- js_std_promise_rejection_check(ctx);
- if (!ts->can_js_os_poll || js_os_poll(ctx))
- break;
- }
- done:
- return JS_HasException(ctx);
- }
- /* Wait for a promise and execute pending jobs while waiting for
- it. Return the promise result or JS_EXCEPTION in case of promise
- rejection. */
- JSValue js_std_await(JSContext *ctx, JSValue obj)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- JSValue ret;
- int state;
- for(;;) {
- state = JS_PromiseState(ctx, obj);
- if (state == JS_PROMISE_FULFILLED) {
- ret = JS_PromiseResult(ctx, obj);
- JS_FreeValue(ctx, obj);
- break;
- } else if (state == JS_PROMISE_REJECTED) {
- ret = JS_Throw(ctx, JS_PromiseResult(ctx, obj));
- JS_FreeValue(ctx, obj);
- break;
- } else if (state == JS_PROMISE_PENDING) {
- JSContext *ctx1;
- int err;
- err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
- if (err < 0) {
- js_std_dump_error(ctx1);
- }
- if (err == 0)
- js_std_promise_rejection_check(ctx);
- if (ts->can_js_os_poll)
- js_os_poll(ctx);
- } else {
- /* not a promise */
- ret = obj;
- break;
- }
- }
- return ret;
- }
- void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
- int load_only)
- {
- JSValue obj, val;
- obj = JS_ReadObject(ctx, buf, buf_len, JS_READ_OBJ_BYTECODE);
- if (JS_IsException(obj))
- goto exception;
- if (load_only) {
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
- if (js_module_set_import_meta(ctx, obj, false, false) < 0)
- goto exception;
- }
- JS_FreeValue(ctx, obj);
- } else {
- if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
- if (JS_ResolveModule(ctx, obj) < 0) {
- JS_FreeValue(ctx, obj);
- goto exception;
- }
- if (js_module_set_import_meta(ctx, obj, false, true) < 0)
- goto exception;
- val = JS_EvalFunction(ctx, obj);
- val = js_std_await(ctx, val);
- } else {
- val = JS_EvalFunction(ctx, obj);
- }
- if (JS_IsException(val)) {
- exception:
- js_std_dump_error(ctx);
- exit(1);
- }
- JS_FreeValue(ctx, val);
- }
- }
- static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- uint8_t *buf;
- uint64_t pos, len;
- JSValue obj;
- size_t size;
- int flags;
- if (JS_ToIndex(ctx, &pos, argv[1]))
- return JS_EXCEPTION;
- if (JS_ToIndex(ctx, &len, argv[2]))
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &flags, argv[3]))
- return JS_EXCEPTION;
- buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
- if (!buf)
- return JS_EXCEPTION;
- if (pos + len > size)
- return JS_ThrowRangeError(ctx, "array buffer overflow");
- obj = JS_ReadObject(ctx, buf + pos, len, flags);
- return obj;
- }
- static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- size_t len;
- uint8_t *buf;
- JSValue array;
- int flags;
- if (JS_ToInt32(ctx, &flags, argv[1]))
- return JS_EXCEPTION;
- buf = JS_WriteObject(ctx, &len, argv[0], flags);
- if (!buf)
- return JS_EXCEPTION;
- array = JS_NewArrayBufferCopy(ctx, buf, len);
- js_free(ctx, buf);
- return array;
- }
- static const JSCFunctionListEntry js_bjson_funcs[] = {
- JS_CFUNC_DEF("read", 4, js_bjson_read ),
- JS_CFUNC_DEF("write", 2, js_bjson_write ),
- #define DEF(x) JS_PROP_INT32_DEF(#x, JS_##x, JS_PROP_CONFIGURABLE)
- DEF(READ_OBJ_BYTECODE),
- DEF(READ_OBJ_REFERENCE),
- DEF(READ_OBJ_SAB),
- DEF(WRITE_OBJ_BYTECODE),
- DEF(WRITE_OBJ_REFERENCE),
- DEF(WRITE_OBJ_SAB),
- DEF(WRITE_OBJ_STRIP_DEBUG),
- DEF(WRITE_OBJ_STRIP_SOURCE),
- #undef DEF
- };
- static int js_bjson_init(JSContext *ctx, JSModuleDef *m)
- {
- return JS_SetModuleExportList(ctx, m, js_bjson_funcs,
- countof(js_bjson_funcs));
- }
- JSModuleDef *js_init_module_bjson(JSContext *ctx, const char *module_name)
- {
- JSModuleDef *m;
- m = JS_NewCModule(ctx, module_name, js_bjson_init);
- if (!m)
- return NULL;
- JS_AddModuleExportList(ctx, m, js_bjson_funcs, countof(js_bjson_funcs));
- return m;
- }
- #endif // QJS_BUILD_LIBC
|