| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842298432984429845298462984729848298492985029851298522985329854298552985629857298582985929860298612986229863298642986529866298672986829869298702987129872298732987429875298762987729878298792988029881298822988329884298852988629887298882988929890298912989229893298942989529896298972989829899299002990129902299032990429905299062990729908299092991029911299122991329914299152991629917299182991929920299212992229923299242992529926299272992829929299302993129932299332993429935299362993729938299392994029941299422994329944299452994629947299482994929950299512995229953299542995529956299572995829959299602996129962299632996429965299662996729968299692997029971299722997329974299752997629977299782997929980299812998229983299842998529986299872998829989299902999129992299932999429995299962999729998299993000030001300023000330004300053000630007300083000930010300113001230013300143001530016300173001830019300203002130022300233002430025300263002730028300293003030031300323003330034300353003630037300383003930040300413004230043300443004530046300473004830049300503005130052300533005430055300563005730058300593006030061300623006330064300653006630067300683006930070300713007230073300743007530076300773007830079300803008130082300833008430085300863008730088300893009030091300923009330094300953009630097300983009930100301013010230103301043010530106301073010830109301103011130112301133011430115301163011730118301193012030121301223012330124301253012630127301283012930130301313013230133301343013530136301373013830139301403014130142301433014430145301463014730148301493015030151301523015330154301553015630157301583015930160301613016230163301643016530166301673016830169301703017130172301733017430175301763017730178301793018030181301823018330184301853018630187301883018930190301913019230193301943019530196301973019830199302003020130202302033020430205302063020730208302093021030211302123021330214302153021630217302183021930220302213022230223302243022530226302273022830229302303023130232302333023430235302363023730238302393024030241302423024330244302453024630247302483024930250302513025230253302543025530256302573025830259302603026130262302633026430265302663026730268302693027030271302723027330274302753027630277302783027930280302813028230283302843028530286302873028830289302903029130292302933029430295302963029730298302993030030301303023030330304303053030630307303083030930310303113031230313303143031530316303173031830319303203032130322303233032430325303263032730328303293033030331303323033330334303353033630337303383033930340303413034230343303443034530346303473034830349303503035130352303533035430355303563035730358303593036030361303623036330364303653036630367303683036930370303713037230373303743037530376303773037830379303803038130382303833038430385303863038730388303893039030391303923039330394303953039630397303983039930400304013040230403304043040530406304073040830409304103041130412304133041430415304163041730418304193042030421304223042330424304253042630427304283042930430304313043230433304343043530436304373043830439304403044130442304433044430445304463044730448304493045030451304523045330454304553045630457304583045930460304613046230463304643046530466304673046830469304703047130472304733047430475304763047730478304793048030481304823048330484304853048630487304883048930490304913049230493304943049530496304973049830499305003050130502305033050430505305063050730508305093051030511305123051330514305153051630517305183051930520305213052230523305243052530526305273052830529305303053130532305333053430535305363053730538305393054030541305423054330544305453054630547305483054930550305513055230553305543055530556305573055830559305603056130562305633056430565305663056730568305693057030571305723057330574305753057630577305783057930580305813058230583305843058530586305873058830589305903059130592305933059430595305963059730598305993060030601306023060330604306053060630607306083060930610306113061230613306143061530616306173061830619306203062130622306233062430625306263062730628306293063030631306323063330634306353063630637306383063930640306413064230643306443064530646306473064830649306503065130652306533065430655306563065730658306593066030661306623066330664306653066630667306683066930670306713067230673306743067530676306773067830679306803068130682306833068430685306863068730688306893069030691306923069330694306953069630697306983069930700307013070230703307043070530706307073070830709307103071130712307133071430715307163071730718307193072030721307223072330724307253072630727307283072930730307313073230733307343073530736307373073830739307403074130742307433074430745307463074730748307493075030751307523075330754307553075630757307583075930760307613076230763307643076530766307673076830769307703077130772307733077430775307763077730778307793078030781307823078330784307853078630787307883078930790307913079230793307943079530796307973079830799308003080130802308033080430805308063080730808308093081030811308123081330814308153081630817308183081930820308213082230823308243082530826308273082830829308303083130832308333083430835308363083730838308393084030841308423084330844308453084630847308483084930850308513085230853308543085530856308573085830859308603086130862308633086430865308663086730868308693087030871308723087330874308753087630877308783087930880308813088230883308843088530886308873088830889308903089130892308933089430895308963089730898308993090030901309023090330904309053090630907309083090930910309113091230913309143091530916309173091830919309203092130922309233092430925309263092730928309293093030931309323093330934309353093630937309383093930940309413094230943309443094530946309473094830949309503095130952309533095430955309563095730958309593096030961309623096330964309653096630967309683096930970309713097230973309743097530976309773097830979309803098130982309833098430985309863098730988309893099030991309923099330994309953099630997309983099931000310013100231003310043100531006310073100831009310103101131012310133101431015310163101731018310193102031021310223102331024310253102631027310283102931030310313103231033310343103531036310373103831039310403104131042310433104431045310463104731048310493105031051310523105331054310553105631057310583105931060310613106231063310643106531066310673106831069310703107131072310733107431075310763107731078310793108031081310823108331084310853108631087310883108931090310913109231093310943109531096310973109831099311003110131102311033110431105311063110731108311093111031111311123111331114311153111631117311183111931120311213112231123311243112531126311273112831129311303113131132311333113431135311363113731138311393114031141311423114331144311453114631147311483114931150311513115231153311543115531156311573115831159311603116131162311633116431165311663116731168311693117031171311723117331174311753117631177311783117931180311813118231183311843118531186311873118831189311903119131192311933119431195311963119731198311993120031201312023120331204312053120631207312083120931210312113121231213312143121531216312173121831219312203122131222312233122431225312263122731228312293123031231312323123331234312353123631237312383123931240312413124231243312443124531246312473124831249312503125131252312533125431255312563125731258312593126031261312623126331264312653126631267312683126931270312713127231273312743127531276312773127831279312803128131282312833128431285312863128731288312893129031291312923129331294312953129631297312983129931300313013130231303313043130531306313073130831309313103131131312313133131431315313163131731318313193132031321313223132331324313253132631327313283132931330313313133231333313343133531336313373133831339313403134131342313433134431345313463134731348313493135031351313523135331354313553135631357313583135931360313613136231363313643136531366313673136831369313703137131372313733137431375313763137731378313793138031381313823138331384313853138631387313883138931390313913139231393313943139531396313973139831399314003140131402314033140431405314063140731408314093141031411314123141331414314153141631417314183141931420314213142231423314243142531426314273142831429314303143131432314333143431435314363143731438314393144031441314423144331444314453144631447314483144931450314513145231453314543145531456314573145831459314603146131462314633146431465314663146731468314693147031471314723147331474314753147631477314783147931480314813148231483314843148531486314873148831489314903149131492314933149431495314963149731498314993150031501315023150331504315053150631507315083150931510315113151231513315143151531516315173151831519315203152131522315233152431525315263152731528315293153031531315323153331534315353153631537315383153931540315413154231543315443154531546315473154831549315503155131552315533155431555315563155731558315593156031561315623156331564315653156631567315683156931570315713157231573315743157531576315773157831579315803158131582315833158431585315863158731588315893159031591315923159331594315953159631597315983159931600316013160231603316043160531606316073160831609316103161131612316133161431615316163161731618316193162031621316223162331624316253162631627316283162931630316313163231633316343163531636316373163831639316403164131642316433164431645316463164731648316493165031651316523165331654316553165631657316583165931660316613166231663316643166531666316673166831669316703167131672316733167431675316763167731678316793168031681316823168331684316853168631687316883168931690316913169231693316943169531696316973169831699317003170131702317033170431705317063170731708317093171031711317123171331714317153171631717317183171931720317213172231723317243172531726317273172831729317303173131732317333173431735317363173731738317393174031741317423174331744317453174631747317483174931750317513175231753317543175531756317573175831759317603176131762317633176431765317663176731768317693177031771317723177331774317753177631777317783177931780317813178231783317843178531786317873178831789317903179131792317933179431795317963179731798317993180031801318023180331804318053180631807318083180931810318113181231813318143181531816318173181831819318203182131822318233182431825318263182731828318293183031831318323183331834318353183631837318383183931840318413184231843318443184531846318473184831849318503185131852318533185431855318563185731858318593186031861318623186331864318653186631867318683186931870318713187231873318743187531876318773187831879318803188131882318833188431885318863188731888318893189031891318923189331894318953189631897318983189931900319013190231903319043190531906319073190831909319103191131912319133191431915319163191731918319193192031921319223192331924319253192631927319283192931930319313193231933319343193531936319373193831939319403194131942319433194431945319463194731948319493195031951319523195331954319553195631957319583195931960319613196231963319643196531966319673196831969319703197131972319733197431975319763197731978319793198031981319823198331984319853198631987319883198931990319913199231993319943199531996319973199831999320003200132002320033200432005320063200732008320093201032011320123201332014320153201632017320183201932020320213202232023320243202532026320273202832029320303203132032320333203432035320363203732038320393204032041320423204332044320453204632047320483204932050320513205232053320543205532056320573205832059320603206132062320633206432065320663206732068320693207032071320723207332074320753207632077320783207932080320813208232083320843208532086320873208832089320903209132092320933209432095320963209732098320993210032101321023210332104321053210632107321083210932110321113211232113321143211532116321173211832119321203212132122321233212432125321263212732128321293213032131321323213332134321353213632137321383213932140321413214232143321443214532146321473214832149321503215132152321533215432155321563215732158321593216032161321623216332164321653216632167321683216932170321713217232173321743217532176321773217832179321803218132182321833218432185321863218732188321893219032191321923219332194321953219632197321983219932200322013220232203322043220532206322073220832209322103221132212322133221432215322163221732218322193222032221322223222332224322253222632227322283222932230322313223232233322343223532236322373223832239322403224132242322433224432245322463224732248322493225032251322523225332254322553225632257322583225932260322613226232263322643226532266322673226832269322703227132272322733227432275322763227732278322793228032281322823228332284322853228632287322883228932290322913229232293322943229532296322973229832299323003230132302323033230432305323063230732308323093231032311323123231332314323153231632317323183231932320323213232232323323243232532326323273232832329323303233132332323333233432335323363233732338323393234032341323423234332344323453234632347323483234932350323513235232353323543235532356323573235832359323603236132362323633236432365323663236732368323693237032371323723237332374323753237632377323783237932380323813238232383323843238532386323873238832389323903239132392323933239432395323963239732398323993240032401324023240332404324053240632407324083240932410324113241232413324143241532416324173241832419324203242132422324233242432425324263242732428324293243032431324323243332434324353243632437324383243932440324413244232443324443244532446324473244832449324503245132452324533245432455324563245732458324593246032461324623246332464324653246632467324683246932470324713247232473324743247532476324773247832479324803248132482324833248432485324863248732488324893249032491324923249332494324953249632497324983249932500325013250232503325043250532506325073250832509325103251132512325133251432515325163251732518325193252032521325223252332524325253252632527325283252932530325313253232533325343253532536325373253832539325403254132542325433254432545325463254732548325493255032551325523255332554325553255632557325583255932560325613256232563325643256532566325673256832569325703257132572325733257432575325763257732578325793258032581325823258332584325853258632587325883258932590325913259232593325943259532596325973259832599326003260132602326033260432605326063260732608326093261032611326123261332614326153261632617326183261932620326213262232623326243262532626326273262832629326303263132632326333263432635326363263732638326393264032641326423264332644326453264632647326483264932650326513265232653326543265532656326573265832659326603266132662326633266432665326663266732668326693267032671326723267332674326753267632677326783267932680326813268232683326843268532686326873268832689326903269132692326933269432695326963269732698326993270032701327023270332704327053270632707327083270932710327113271232713327143271532716327173271832719327203272132722327233272432725327263272732728327293273032731327323273332734327353273632737327383273932740327413274232743327443274532746327473274832749327503275132752327533275432755327563275732758327593276032761327623276332764327653276632767327683276932770327713277232773327743277532776327773277832779327803278132782327833278432785327863278732788327893279032791327923279332794327953279632797327983279932800328013280232803328043280532806328073280832809328103281132812328133281432815328163281732818328193282032821328223282332824328253282632827328283282932830328313283232833328343283532836328373283832839328403284132842328433284432845328463284732848328493285032851328523285332854328553285632857328583285932860328613286232863328643286532866328673286832869328703287132872328733287432875328763287732878328793288032881328823288332884328853288632887328883288932890328913289232893328943289532896328973289832899329003290132902329033290432905329063290732908329093291032911329123291332914329153291632917329183291932920329213292232923329243292532926329273292832929329303293132932329333293432935329363293732938329393294032941329423294332944329453294632947329483294932950329513295232953329543295532956329573295832959329603296132962329633296432965329663296732968329693297032971329723297332974329753297632977329783297932980329813298232983329843298532986329873298832989329903299132992329933299432995329963299732998329993300033001330023300333004330053300633007330083300933010330113301233013330143301533016330173301833019330203302133022330233302433025330263302733028330293303033031330323303333034330353303633037330383303933040330413304233043330443304533046330473304833049330503305133052330533305433055330563305733058330593306033061330623306333064330653306633067330683306933070330713307233073330743307533076330773307833079330803308133082330833308433085330863308733088330893309033091330923309333094330953309633097330983309933100331013310233103331043310533106331073310833109331103311133112331133311433115331163311733118331193312033121331223312333124331253312633127331283312933130331313313233133331343313533136331373313833139331403314133142331433314433145331463314733148331493315033151331523315333154331553315633157331583315933160331613316233163331643316533166331673316833169331703317133172331733317433175331763317733178331793318033181331823318333184331853318633187331883318933190331913319233193331943319533196331973319833199332003320133202332033320433205332063320733208332093321033211332123321333214332153321633217332183321933220332213322233223332243322533226332273322833229332303323133232332333323433235332363323733238332393324033241332423324333244332453324633247332483324933250332513325233253332543325533256332573325833259332603326133262332633326433265332663326733268332693327033271332723327333274332753327633277332783327933280332813328233283332843328533286332873328833289332903329133292332933329433295332963329733298332993330033301333023330333304333053330633307333083330933310333113331233313333143331533316333173331833319333203332133322333233332433325333263332733328333293333033331333323333333334333353333633337333383333933340333413334233343333443334533346333473334833349333503335133352333533335433355333563335733358333593336033361333623336333364333653336633367333683336933370333713337233373333743337533376333773337833379333803338133382333833338433385333863338733388333893339033391333923339333394333953339633397333983339933400334013340233403334043340533406334073340833409334103341133412334133341433415334163341733418334193342033421334223342333424334253342633427334283342933430334313343233433334343343533436334373343833439334403344133442334433344433445334463344733448334493345033451334523345333454334553345633457334583345933460334613346233463334643346533466334673346833469334703347133472334733347433475334763347733478334793348033481334823348333484334853348633487334883348933490334913349233493334943349533496334973349833499335003350133502335033350433505335063350733508335093351033511335123351333514335153351633517335183351933520335213352233523335243352533526335273352833529335303353133532335333353433535335363353733538335393354033541335423354333544335453354633547335483354933550335513355233553335543355533556335573355833559335603356133562335633356433565335663356733568335693357033571335723357333574335753357633577335783357933580335813358233583335843358533586335873358833589335903359133592335933359433595335963359733598335993360033601336023360333604336053360633607336083360933610336113361233613336143361533616336173361833619336203362133622336233362433625336263362733628336293363033631336323363333634336353363633637336383363933640336413364233643336443364533646336473364833649336503365133652336533365433655336563365733658336593366033661336623366333664336653366633667336683366933670336713367233673336743367533676336773367833679336803368133682336833368433685336863368733688336893369033691336923369333694336953369633697336983369933700337013370233703337043370533706337073370833709337103371133712337133371433715337163371733718337193372033721337223372333724337253372633727337283372933730337313373233733337343373533736337373373833739337403374133742337433374433745337463374733748337493375033751337523375333754337553375633757337583375933760337613376233763337643376533766337673376833769337703377133772337733377433775337763377733778337793378033781337823378333784337853378633787337883378933790337913379233793337943379533796337973379833799338003380133802338033380433805338063380733808338093381033811338123381333814338153381633817338183381933820338213382233823338243382533826338273382833829338303383133832338333383433835338363383733838338393384033841338423384333844338453384633847338483384933850338513385233853338543385533856338573385833859338603386133862338633386433865338663386733868338693387033871338723387333874338753387633877338783387933880338813388233883338843388533886338873388833889338903389133892338933389433895338963389733898338993390033901339023390333904339053390633907339083390933910339113391233913339143391533916339173391833919339203392133922339233392433925339263392733928339293393033931339323393333934339353393633937339383393933940339413394233943339443394533946339473394833949339503395133952339533395433955339563395733958339593396033961339623396333964339653396633967339683396933970339713397233973339743397533976339773397833979339803398133982339833398433985339863398733988339893399033991339923399333994339953399633997339983399934000340013400234003340043400534006340073400834009340103401134012340133401434015340163401734018340193402034021340223402334024340253402634027340283402934030340313403234033340343403534036340373403834039340403404134042340433404434045340463404734048340493405034051340523405334054340553405634057340583405934060340613406234063340643406534066340673406834069340703407134072340733407434075340763407734078340793408034081340823408334084340853408634087340883408934090340913409234093340943409534096340973409834099341003410134102341033410434105341063410734108341093411034111341123411334114341153411634117341183411934120341213412234123341243412534126341273412834129341303413134132341333413434135341363413734138341393414034141341423414334144341453414634147341483414934150341513415234153341543415534156341573415834159341603416134162341633416434165341663416734168341693417034171341723417334174341753417634177341783417934180341813418234183341843418534186341873418834189341903419134192341933419434195341963419734198341993420034201342023420334204342053420634207342083420934210342113421234213342143421534216342173421834219342203422134222342233422434225342263422734228342293423034231342323423334234342353423634237342383423934240342413424234243342443424534246342473424834249342503425134252342533425434255342563425734258342593426034261342623426334264342653426634267342683426934270342713427234273342743427534276342773427834279342803428134282342833428434285342863428734288342893429034291342923429334294342953429634297342983429934300343013430234303343043430534306343073430834309343103431134312343133431434315343163431734318343193432034321343223432334324343253432634327343283432934330343313433234333343343433534336343373433834339343403434134342343433434434345343463434734348343493435034351343523435334354343553435634357343583435934360343613436234363343643436534366343673436834369343703437134372343733437434375343763437734378343793438034381343823438334384343853438634387343883438934390343913439234393343943439534396343973439834399344003440134402344033440434405344063440734408344093441034411344123441334414344153441634417344183441934420344213442234423344243442534426344273442834429344303443134432344333443434435344363443734438344393444034441344423444334444344453444634447344483444934450344513445234453344543445534456344573445834459344603446134462344633446434465344663446734468344693447034471344723447334474344753447634477344783447934480344813448234483344843448534486344873448834489344903449134492344933449434495344963449734498344993450034501345023450334504345053450634507345083450934510345113451234513345143451534516345173451834519345203452134522345233452434525345263452734528345293453034531345323453334534345353453634537345383453934540345413454234543345443454534546345473454834549345503455134552345533455434555345563455734558345593456034561345623456334564345653456634567345683456934570345713457234573345743457534576345773457834579345803458134582345833458434585345863458734588345893459034591345923459334594345953459634597345983459934600346013460234603346043460534606346073460834609346103461134612346133461434615346163461734618346193462034621346223462334624346253462634627346283462934630346313463234633346343463534636346373463834639346403464134642346433464434645346463464734648346493465034651346523465334654346553465634657346583465934660346613466234663346643466534666346673466834669346703467134672346733467434675346763467734678346793468034681346823468334684346853468634687346883468934690346913469234693346943469534696346973469834699347003470134702347033470434705347063470734708347093471034711347123471334714347153471634717347183471934720347213472234723347243472534726347273472834729347303473134732347333473434735347363473734738347393474034741347423474334744347453474634747347483474934750347513475234753347543475534756347573475834759347603476134762347633476434765347663476734768347693477034771347723477334774347753477634777347783477934780347813478234783347843478534786347873478834789347903479134792347933479434795347963479734798347993480034801348023480334804348053480634807348083480934810348113481234813348143481534816348173481834819348203482134822348233482434825348263482734828348293483034831348323483334834348353483634837348383483934840348413484234843348443484534846348473484834849348503485134852348533485434855348563485734858348593486034861348623486334864348653486634867348683486934870348713487234873348743487534876348773487834879348803488134882348833488434885348863488734888348893489034891348923489334894348953489634897348983489934900349013490234903349043490534906349073490834909349103491134912349133491434915349163491734918349193492034921349223492334924349253492634927349283492934930349313493234933349343493534936349373493834939349403494134942349433494434945349463494734948349493495034951349523495334954349553495634957349583495934960349613496234963349643496534966349673496834969349703497134972349733497434975349763497734978349793498034981349823498334984349853498634987349883498934990349913499234993349943499534996349973499834999350003500135002350033500435005350063500735008350093501035011350123501335014350153501635017350183501935020350213502235023350243502535026350273502835029350303503135032350333503435035350363503735038350393504035041350423504335044350453504635047350483504935050350513505235053350543505535056350573505835059350603506135062350633506435065350663506735068350693507035071350723507335074350753507635077350783507935080350813508235083350843508535086350873508835089350903509135092350933509435095350963509735098350993510035101351023510335104351053510635107351083510935110351113511235113351143511535116351173511835119351203512135122351233512435125351263512735128351293513035131351323513335134351353513635137351383513935140351413514235143351443514535146351473514835149351503515135152351533515435155351563515735158351593516035161351623516335164351653516635167351683516935170351713517235173351743517535176351773517835179351803518135182351833518435185351863518735188351893519035191351923519335194351953519635197351983519935200352013520235203352043520535206352073520835209352103521135212352133521435215352163521735218352193522035221352223522335224352253522635227352283522935230352313523235233352343523535236352373523835239352403524135242352433524435245352463524735248352493525035251352523525335254352553525635257352583525935260352613526235263352643526535266352673526835269352703527135272352733527435275352763527735278352793528035281352823528335284352853528635287352883528935290352913529235293352943529535296352973529835299353003530135302353033530435305353063530735308353093531035311353123531335314353153531635317353183531935320353213532235323353243532535326353273532835329353303533135332353333533435335353363533735338353393534035341353423534335344353453534635347353483534935350353513535235353353543535535356353573535835359353603536135362353633536435365353663536735368353693537035371353723537335374353753537635377353783537935380353813538235383353843538535386353873538835389353903539135392353933539435395353963539735398353993540035401354023540335404354053540635407354083540935410354113541235413354143541535416354173541835419354203542135422354233542435425354263542735428354293543035431354323543335434354353543635437354383543935440354413544235443354443544535446354473544835449354503545135452354533545435455354563545735458354593546035461354623546335464354653546635467354683546935470354713547235473354743547535476354773547835479354803548135482354833548435485354863548735488354893549035491354923549335494354953549635497354983549935500355013550235503355043550535506355073550835509355103551135512355133551435515355163551735518355193552035521355223552335524355253552635527355283552935530355313553235533355343553535536355373553835539355403554135542355433554435545355463554735548355493555035551355523555335554355553555635557355583555935560355613556235563355643556535566355673556835569355703557135572355733557435575355763557735578355793558035581355823558335584355853558635587355883558935590355913559235593355943559535596355973559835599356003560135602356033560435605356063560735608356093561035611356123561335614356153561635617356183561935620356213562235623356243562535626356273562835629356303563135632356333563435635356363563735638356393564035641356423564335644356453564635647356483564935650356513565235653356543565535656356573565835659356603566135662356633566435665356663566735668356693567035671356723567335674356753567635677356783567935680356813568235683356843568535686356873568835689356903569135692356933569435695356963569735698356993570035701357023570335704357053570635707357083570935710357113571235713357143571535716357173571835719357203572135722357233572435725357263572735728357293573035731357323573335734357353573635737357383573935740357413574235743357443574535746357473574835749357503575135752357533575435755357563575735758357593576035761357623576335764357653576635767357683576935770357713577235773357743577535776357773577835779357803578135782357833578435785357863578735788357893579035791357923579335794357953579635797357983579935800358013580235803358043580535806358073580835809358103581135812358133581435815358163581735818358193582035821358223582335824358253582635827358283582935830358313583235833358343583535836358373583835839358403584135842358433584435845358463584735848358493585035851358523585335854358553585635857358583585935860358613586235863358643586535866358673586835869358703587135872358733587435875358763587735878358793588035881358823588335884358853588635887358883588935890358913589235893358943589535896358973589835899359003590135902359033590435905359063590735908359093591035911359123591335914359153591635917359183591935920359213592235923359243592535926359273592835929359303593135932359333593435935359363593735938359393594035941359423594335944359453594635947359483594935950359513595235953359543595535956359573595835959359603596135962359633596435965359663596735968359693597035971359723597335974359753597635977359783597935980359813598235983359843598535986359873598835989359903599135992359933599435995359963599735998359993600036001360023600336004360053600636007360083600936010360113601236013360143601536016360173601836019360203602136022360233602436025360263602736028360293603036031360323603336034360353603636037360383603936040360413604236043360443604536046360473604836049360503605136052360533605436055360563605736058360593606036061360623606336064360653606636067360683606936070360713607236073360743607536076360773607836079360803608136082360833608436085360863608736088360893609036091360923609336094360953609636097360983609936100361013610236103361043610536106361073610836109361103611136112361133611436115361163611736118361193612036121361223612336124361253612636127361283612936130361313613236133361343613536136361373613836139361403614136142361433614436145361463614736148361493615036151361523615336154361553615636157361583615936160361613616236163361643616536166361673616836169361703617136172361733617436175361763617736178361793618036181361823618336184361853618636187361883618936190361913619236193361943619536196361973619836199362003620136202362033620436205362063620736208362093621036211362123621336214362153621636217362183621936220362213622236223362243622536226362273622836229362303623136232362333623436235362363623736238362393624036241362423624336244362453624636247362483624936250362513625236253362543625536256362573625836259362603626136262362633626436265362663626736268362693627036271362723627336274362753627636277362783627936280362813628236283362843628536286362873628836289362903629136292362933629436295362963629736298362993630036301363023630336304363053630636307363083630936310363113631236313363143631536316363173631836319363203632136322363233632436325363263632736328363293633036331363323633336334363353633636337363383633936340363413634236343363443634536346363473634836349363503635136352363533635436355363563635736358363593636036361363623636336364363653636636367363683636936370363713637236373363743637536376363773637836379363803638136382363833638436385363863638736388363893639036391363923639336394363953639636397363983639936400364013640236403364043640536406364073640836409364103641136412364133641436415364163641736418364193642036421364223642336424364253642636427364283642936430364313643236433364343643536436364373643836439364403644136442364433644436445364463644736448364493645036451364523645336454364553645636457364583645936460364613646236463364643646536466364673646836469364703647136472364733647436475364763647736478364793648036481364823648336484364853648636487364883648936490364913649236493364943649536496364973649836499365003650136502365033650436505365063650736508365093651036511365123651336514365153651636517365183651936520365213652236523365243652536526365273652836529365303653136532365333653436535365363653736538365393654036541365423654336544365453654636547365483654936550365513655236553365543655536556365573655836559365603656136562365633656436565365663656736568365693657036571365723657336574365753657636577365783657936580365813658236583365843658536586365873658836589365903659136592365933659436595365963659736598365993660036601366023660336604366053660636607366083660936610366113661236613366143661536616366173661836619366203662136622366233662436625366263662736628366293663036631366323663336634366353663636637366383663936640366413664236643366443664536646366473664836649366503665136652366533665436655366563665736658366593666036661366623666336664366653666636667366683666936670366713667236673366743667536676366773667836679366803668136682366833668436685366863668736688366893669036691366923669336694366953669636697366983669936700367013670236703367043670536706367073670836709367103671136712367133671436715367163671736718367193672036721367223672336724367253672636727367283672936730367313673236733367343673536736367373673836739367403674136742367433674436745367463674736748367493675036751367523675336754367553675636757367583675936760367613676236763367643676536766367673676836769367703677136772367733677436775367763677736778367793678036781367823678336784367853678636787367883678936790367913679236793367943679536796367973679836799368003680136802368033680436805368063680736808368093681036811368123681336814368153681636817368183681936820368213682236823368243682536826368273682836829368303683136832368333683436835368363683736838368393684036841368423684336844368453684636847368483684936850368513685236853368543685536856368573685836859368603686136862368633686436865368663686736868368693687036871368723687336874368753687636877368783687936880368813688236883368843688536886368873688836889368903689136892368933689436895368963689736898368993690036901369023690336904369053690636907369083690936910369113691236913369143691536916369173691836919369203692136922369233692436925369263692736928369293693036931369323693336934369353693636937369383693936940369413694236943369443694536946369473694836949369503695136952369533695436955369563695736958369593696036961369623696336964369653696636967369683696936970369713697236973369743697536976369773697836979369803698136982369833698436985369863698736988369893699036991369923699336994369953699636997369983699937000370013700237003370043700537006370073700837009370103701137012370133701437015370163701737018370193702037021370223702337024370253702637027370283702937030370313703237033370343703537036370373703837039370403704137042370433704437045370463704737048370493705037051370523705337054370553705637057370583705937060370613706237063370643706537066370673706837069370703707137072370733707437075370763707737078370793708037081370823708337084370853708637087370883708937090370913709237093370943709537096370973709837099371003710137102371033710437105371063710737108371093711037111371123711337114371153711637117371183711937120371213712237123371243712537126371273712837129371303713137132371333713437135371363713737138371393714037141371423714337144371453714637147371483714937150371513715237153371543715537156371573715837159371603716137162371633716437165371663716737168371693717037171371723717337174371753717637177371783717937180371813718237183371843718537186371873718837189371903719137192371933719437195371963719737198371993720037201372023720337204372053720637207372083720937210372113721237213372143721537216372173721837219372203722137222372233722437225372263722737228372293723037231372323723337234372353723637237372383723937240372413724237243372443724537246372473724837249372503725137252372533725437255372563725737258372593726037261372623726337264372653726637267372683726937270372713727237273372743727537276372773727837279372803728137282372833728437285372863728737288372893729037291372923729337294372953729637297372983729937300373013730237303373043730537306373073730837309373103731137312373133731437315373163731737318373193732037321373223732337324373253732637327373283732937330373313733237333373343733537336373373733837339373403734137342373433734437345373463734737348373493735037351373523735337354373553735637357373583735937360373613736237363373643736537366373673736837369373703737137372373733737437375373763737737378373793738037381373823738337384373853738637387373883738937390373913739237393373943739537396373973739837399374003740137402374033740437405374063740737408374093741037411374123741337414374153741637417374183741937420374213742237423374243742537426374273742837429374303743137432374333743437435374363743737438374393744037441374423744337444374453744637447374483744937450374513745237453374543745537456374573745837459374603746137462374633746437465374663746737468374693747037471374723747337474374753747637477374783747937480374813748237483374843748537486374873748837489374903749137492374933749437495374963749737498374993750037501375023750337504375053750637507375083750937510375113751237513375143751537516375173751837519375203752137522375233752437525375263752737528375293753037531375323753337534375353753637537375383753937540375413754237543375443754537546375473754837549375503755137552375533755437555375563755737558375593756037561375623756337564375653756637567375683756937570375713757237573375743757537576375773757837579375803758137582375833758437585375863758737588375893759037591375923759337594375953759637597375983759937600376013760237603376043760537606376073760837609376103761137612376133761437615376163761737618376193762037621376223762337624376253762637627376283762937630376313763237633376343763537636376373763837639376403764137642376433764437645376463764737648376493765037651376523765337654376553765637657376583765937660376613766237663376643766537666376673766837669376703767137672376733767437675376763767737678376793768037681376823768337684376853768637687376883768937690376913769237693376943769537696376973769837699377003770137702377033770437705377063770737708377093771037711377123771337714377153771637717377183771937720377213772237723377243772537726377273772837729377303773137732377333773437735377363773737738377393774037741377423774337744377453774637747377483774937750377513775237753377543775537756377573775837759377603776137762377633776437765377663776737768377693777037771377723777337774377753777637777377783777937780377813778237783377843778537786377873778837789377903779137792377933779437795377963779737798377993780037801378023780337804378053780637807378083780937810378113781237813378143781537816378173781837819378203782137822378233782437825378263782737828378293783037831378323783337834378353783637837378383783937840378413784237843378443784537846378473784837849378503785137852378533785437855378563785737858378593786037861378623786337864378653786637867378683786937870378713787237873378743787537876378773787837879378803788137882378833788437885378863788737888378893789037891378923789337894378953789637897378983789937900379013790237903379043790537906379073790837909379103791137912379133791437915379163791737918379193792037921379223792337924379253792637927379283792937930379313793237933379343793537936379373793837939379403794137942379433794437945379463794737948379493795037951379523795337954379553795637957379583795937960379613796237963379643796537966379673796837969379703797137972379733797437975379763797737978379793798037981379823798337984379853798637987379883798937990379913799237993379943799537996379973799837999380003800138002380033800438005380063800738008380093801038011380123801338014380153801638017380183801938020380213802238023380243802538026380273802838029380303803138032380333803438035380363803738038380393804038041380423804338044380453804638047380483804938050380513805238053380543805538056380573805838059380603806138062380633806438065380663806738068380693807038071380723807338074380753807638077380783807938080380813808238083380843808538086380873808838089380903809138092380933809438095380963809738098380993810038101381023810338104381053810638107381083810938110381113811238113381143811538116381173811838119381203812138122381233812438125381263812738128381293813038131381323813338134381353813638137381383813938140381413814238143381443814538146381473814838149381503815138152381533815438155381563815738158381593816038161381623816338164381653816638167381683816938170381713817238173381743817538176381773817838179381803818138182381833818438185381863818738188381893819038191381923819338194381953819638197381983819938200382013820238203382043820538206382073820838209382103821138212382133821438215382163821738218382193822038221382223822338224382253822638227382283822938230382313823238233382343823538236382373823838239382403824138242382433824438245382463824738248382493825038251382523825338254382553825638257382583825938260382613826238263382643826538266382673826838269382703827138272382733827438275382763827738278382793828038281382823828338284382853828638287382883828938290382913829238293382943829538296382973829838299383003830138302383033830438305383063830738308383093831038311383123831338314383153831638317383183831938320383213832238323383243832538326383273832838329383303833138332383333833438335383363833738338383393834038341383423834338344383453834638347383483834938350383513835238353383543835538356383573835838359383603836138362383633836438365383663836738368383693837038371383723837338374383753837638377383783837938380383813838238383383843838538386383873838838389383903839138392383933839438395383963839738398383993840038401384023840338404384053840638407384083840938410384113841238413384143841538416384173841838419384203842138422384233842438425384263842738428384293843038431384323843338434384353843638437384383843938440384413844238443384443844538446384473844838449384503845138452384533845438455384563845738458384593846038461384623846338464384653846638467384683846938470384713847238473384743847538476384773847838479384803848138482384833848438485384863848738488384893849038491384923849338494384953849638497384983849938500385013850238503385043850538506385073850838509385103851138512385133851438515385163851738518385193852038521385223852338524385253852638527385283852938530385313853238533385343853538536385373853838539385403854138542385433854438545385463854738548385493855038551385523855338554385553855638557385583855938560385613856238563385643856538566385673856838569385703857138572385733857438575385763857738578385793858038581385823858338584385853858638587385883858938590385913859238593385943859538596385973859838599386003860138602386033860438605386063860738608386093861038611386123861338614386153861638617386183861938620386213862238623386243862538626386273862838629386303863138632386333863438635386363863738638386393864038641386423864338644386453864638647386483864938650386513865238653386543865538656386573865838659386603866138662386633866438665386663866738668386693867038671386723867338674386753867638677386783867938680386813868238683386843868538686386873868838689386903869138692386933869438695386963869738698386993870038701387023870338704387053870638707387083870938710387113871238713387143871538716387173871838719387203872138722387233872438725387263872738728387293873038731387323873338734387353873638737387383873938740387413874238743387443874538746387473874838749387503875138752387533875438755387563875738758387593876038761387623876338764387653876638767387683876938770387713877238773387743877538776387773877838779387803878138782387833878438785387863878738788387893879038791387923879338794387953879638797387983879938800388013880238803388043880538806388073880838809388103881138812388133881438815388163881738818388193882038821388223882338824388253882638827388283882938830388313883238833388343883538836388373883838839388403884138842388433884438845388463884738848388493885038851388523885338854388553885638857388583885938860388613886238863388643886538866388673886838869388703887138872388733887438875388763887738878388793888038881388823888338884388853888638887388883888938890388913889238893388943889538896388973889838899389003890138902389033890438905389063890738908389093891038911389123891338914389153891638917389183891938920389213892238923389243892538926389273892838929389303893138932389333893438935389363893738938389393894038941389423894338944389453894638947389483894938950389513895238953389543895538956389573895838959389603896138962389633896438965389663896738968389693897038971389723897338974389753897638977389783897938980389813898238983389843898538986389873898838989389903899138992389933899438995389963899738998389993900039001390023900339004390053900639007390083900939010390113901239013390143901539016390173901839019390203902139022390233902439025390263902739028390293903039031390323903339034390353903639037390383903939040390413904239043390443904539046390473904839049390503905139052390533905439055390563905739058390593906039061390623906339064390653906639067390683906939070390713907239073390743907539076390773907839079390803908139082390833908439085390863908739088390893909039091390923909339094390953909639097390983909939100391013910239103391043910539106391073910839109391103911139112391133911439115391163911739118391193912039121391223912339124391253912639127391283912939130391313913239133391343913539136391373913839139391403914139142391433914439145391463914739148391493915039151391523915339154391553915639157391583915939160391613916239163391643916539166391673916839169391703917139172391733917439175391763917739178391793918039181391823918339184391853918639187391883918939190391913919239193391943919539196391973919839199392003920139202392033920439205392063920739208392093921039211392123921339214392153921639217392183921939220392213922239223392243922539226392273922839229392303923139232392333923439235392363923739238392393924039241392423924339244392453924639247392483924939250392513925239253392543925539256392573925839259392603926139262392633926439265392663926739268392693927039271392723927339274392753927639277392783927939280392813928239283392843928539286392873928839289392903929139292392933929439295392963929739298392993930039301393023930339304393053930639307393083930939310393113931239313393143931539316393173931839319393203932139322393233932439325393263932739328393293933039331393323933339334393353933639337393383933939340393413934239343393443934539346393473934839349393503935139352393533935439355393563935739358393593936039361393623936339364393653936639367393683936939370393713937239373393743937539376393773937839379393803938139382393833938439385393863938739388393893939039391393923939339394393953939639397393983939939400394013940239403394043940539406394073940839409394103941139412394133941439415394163941739418394193942039421394223942339424394253942639427394283942939430394313943239433394343943539436394373943839439394403944139442394433944439445394463944739448394493945039451394523945339454394553945639457394583945939460394613946239463394643946539466394673946839469394703947139472394733947439475394763947739478394793948039481394823948339484394853948639487394883948939490394913949239493394943949539496394973949839499395003950139502395033950439505395063950739508395093951039511395123951339514395153951639517395183951939520395213952239523395243952539526395273952839529395303953139532395333953439535395363953739538395393954039541395423954339544395453954639547395483954939550395513955239553395543955539556395573955839559395603956139562395633956439565395663956739568395693957039571395723957339574395753957639577395783957939580395813958239583395843958539586395873958839589395903959139592395933959439595395963959739598395993960039601396023960339604396053960639607396083960939610396113961239613396143961539616396173961839619396203962139622396233962439625396263962739628396293963039631396323963339634396353963639637396383963939640396413964239643396443964539646396473964839649396503965139652396533965439655396563965739658396593966039661396623966339664396653966639667396683966939670396713967239673396743967539676396773967839679396803968139682396833968439685396863968739688396893969039691396923969339694396953969639697396983969939700397013970239703397043970539706397073970839709397103971139712397133971439715397163971739718397193972039721397223972339724397253972639727397283972939730397313973239733397343973539736397373973839739397403974139742397433974439745397463974739748397493975039751397523975339754397553975639757397583975939760397613976239763397643976539766397673976839769397703977139772397733977439775397763977739778397793978039781397823978339784397853978639787397883978939790397913979239793397943979539796397973979839799398003980139802398033980439805398063980739808398093981039811398123981339814398153981639817398183981939820398213982239823398243982539826398273982839829398303983139832398333983439835398363983739838398393984039841398423984339844398453984639847398483984939850398513985239853398543985539856398573985839859398603986139862398633986439865398663986739868398693987039871398723987339874398753987639877398783987939880398813988239883398843988539886398873988839889398903989139892398933989439895398963989739898398993990039901399023990339904399053990639907399083990939910399113991239913399143991539916399173991839919399203992139922399233992439925399263992739928399293993039931399323993339934399353993639937399383993939940399413994239943399443994539946399473994839949399503995139952399533995439955399563995739958399593996039961399623996339964399653996639967399683996939970399713997239973399743997539976399773997839979399803998139982399833998439985399863998739988399893999039991399923999339994399953999639997399983999940000400014000240003400044000540006400074000840009400104001140012400134001440015400164001740018400194002040021400224002340024400254002640027400284002940030400314003240033400344003540036400374003840039400404004140042400434004440045400464004740048400494005040051400524005340054400554005640057400584005940060400614006240063400644006540066400674006840069400704007140072400734007440075400764007740078400794008040081400824008340084400854008640087400884008940090400914009240093400944009540096400974009840099401004010140102401034010440105401064010740108401094011040111401124011340114401154011640117401184011940120401214012240123401244012540126401274012840129401304013140132401334013440135401364013740138401394014040141401424014340144401454014640147401484014940150401514015240153401544015540156401574015840159401604016140162401634016440165401664016740168401694017040171401724017340174401754017640177401784017940180401814018240183401844018540186401874018840189401904019140192401934019440195401964019740198401994020040201402024020340204402054020640207402084020940210402114021240213402144021540216402174021840219402204022140222402234022440225402264022740228402294023040231402324023340234402354023640237402384023940240402414024240243402444024540246402474024840249402504025140252402534025440255402564025740258402594026040261402624026340264402654026640267402684026940270402714027240273402744027540276402774027840279402804028140282402834028440285402864028740288402894029040291402924029340294402954029640297402984029940300403014030240303403044030540306403074030840309403104031140312403134031440315403164031740318403194032040321403224032340324403254032640327403284032940330403314033240333403344033540336403374033840339403404034140342403434034440345403464034740348403494035040351403524035340354403554035640357403584035940360403614036240363403644036540366403674036840369403704037140372403734037440375403764037740378403794038040381403824038340384403854038640387403884038940390403914039240393403944039540396403974039840399404004040140402404034040440405404064040740408404094041040411404124041340414404154041640417404184041940420404214042240423404244042540426404274042840429404304043140432404334043440435404364043740438404394044040441404424044340444404454044640447404484044940450404514045240453404544045540456404574045840459404604046140462404634046440465404664046740468404694047040471404724047340474404754047640477404784047940480404814048240483404844048540486404874048840489404904049140492404934049440495404964049740498404994050040501405024050340504405054050640507405084050940510405114051240513405144051540516405174051840519405204052140522405234052440525405264052740528405294053040531405324053340534405354053640537405384053940540405414054240543405444054540546405474054840549405504055140552405534055440555405564055740558405594056040561405624056340564405654056640567405684056940570405714057240573405744057540576405774057840579405804058140582405834058440585405864058740588405894059040591405924059340594405954059640597405984059940600406014060240603406044060540606406074060840609406104061140612406134061440615406164061740618406194062040621406224062340624406254062640627406284062940630406314063240633406344063540636406374063840639406404064140642406434064440645406464064740648406494065040651406524065340654406554065640657406584065940660406614066240663406644066540666406674066840669406704067140672406734067440675406764067740678406794068040681406824068340684406854068640687406884068940690406914069240693406944069540696406974069840699407004070140702407034070440705407064070740708407094071040711407124071340714407154071640717407184071940720407214072240723407244072540726407274072840729407304073140732407334073440735407364073740738407394074040741407424074340744407454074640747407484074940750407514075240753407544075540756407574075840759407604076140762407634076440765407664076740768407694077040771407724077340774407754077640777407784077940780407814078240783407844078540786407874078840789407904079140792407934079440795407964079740798407994080040801408024080340804408054080640807408084080940810408114081240813408144081540816408174081840819408204082140822408234082440825408264082740828408294083040831408324083340834408354083640837408384083940840408414084240843408444084540846408474084840849408504085140852408534085440855408564085740858408594086040861408624086340864408654086640867408684086940870408714087240873408744087540876408774087840879408804088140882408834088440885408864088740888408894089040891408924089340894408954089640897408984089940900409014090240903409044090540906409074090840909409104091140912409134091440915409164091740918409194092040921409224092340924409254092640927409284092940930409314093240933409344093540936409374093840939409404094140942409434094440945409464094740948409494095040951409524095340954409554095640957409584095940960409614096240963409644096540966409674096840969409704097140972409734097440975409764097740978409794098040981409824098340984409854098640987409884098940990409914099240993409944099540996409974099840999410004100141002410034100441005410064100741008410094101041011410124101341014410154101641017410184101941020410214102241023410244102541026410274102841029410304103141032410334103441035410364103741038410394104041041410424104341044410454104641047410484104941050410514105241053410544105541056410574105841059410604106141062410634106441065410664106741068410694107041071410724107341074410754107641077410784107941080410814108241083410844108541086410874108841089410904109141092410934109441095410964109741098410994110041101411024110341104411054110641107411084110941110411114111241113411144111541116411174111841119411204112141122411234112441125411264112741128411294113041131411324113341134411354113641137411384113941140411414114241143411444114541146411474114841149411504115141152411534115441155411564115741158411594116041161411624116341164411654116641167411684116941170411714117241173411744117541176411774117841179411804118141182411834118441185411864118741188411894119041191411924119341194411954119641197411984119941200412014120241203412044120541206412074120841209412104121141212412134121441215412164121741218412194122041221412224122341224412254122641227412284122941230412314123241233412344123541236412374123841239412404124141242412434124441245412464124741248412494125041251412524125341254412554125641257412584125941260412614126241263412644126541266412674126841269412704127141272412734127441275412764127741278412794128041281412824128341284412854128641287412884128941290412914129241293412944129541296412974129841299413004130141302413034130441305413064130741308413094131041311413124131341314413154131641317413184131941320413214132241323413244132541326413274132841329413304133141332413334133441335413364133741338413394134041341413424134341344413454134641347413484134941350413514135241353413544135541356413574135841359413604136141362413634136441365413664136741368413694137041371413724137341374413754137641377413784137941380413814138241383413844138541386413874138841389413904139141392413934139441395413964139741398413994140041401414024140341404414054140641407414084140941410414114141241413414144141541416414174141841419414204142141422414234142441425414264142741428414294143041431414324143341434414354143641437414384143941440414414144241443414444144541446414474144841449414504145141452414534145441455414564145741458414594146041461414624146341464414654146641467414684146941470414714147241473414744147541476414774147841479414804148141482414834148441485414864148741488414894149041491414924149341494414954149641497414984149941500415014150241503415044150541506415074150841509415104151141512415134151441515415164151741518415194152041521415224152341524415254152641527415284152941530415314153241533415344153541536415374153841539415404154141542415434154441545415464154741548415494155041551415524155341554415554155641557415584155941560415614156241563415644156541566415674156841569415704157141572415734157441575415764157741578415794158041581415824158341584415854158641587415884158941590415914159241593415944159541596415974159841599416004160141602416034160441605416064160741608416094161041611416124161341614416154161641617416184161941620416214162241623416244162541626416274162841629416304163141632416334163441635416364163741638416394164041641416424164341644416454164641647416484164941650416514165241653416544165541656416574165841659416604166141662416634166441665416664166741668416694167041671416724167341674416754167641677416784167941680416814168241683416844168541686416874168841689416904169141692416934169441695416964169741698416994170041701417024170341704417054170641707417084170941710417114171241713417144171541716417174171841719417204172141722417234172441725417264172741728417294173041731417324173341734417354173641737417384173941740417414174241743417444174541746417474174841749417504175141752417534175441755417564175741758417594176041761417624176341764417654176641767417684176941770417714177241773417744177541776417774177841779417804178141782417834178441785417864178741788417894179041791417924179341794417954179641797417984179941800418014180241803418044180541806418074180841809418104181141812418134181441815418164181741818418194182041821418224182341824418254182641827418284182941830418314183241833418344183541836418374183841839418404184141842418434184441845418464184741848418494185041851418524185341854418554185641857418584185941860418614186241863418644186541866418674186841869418704187141872418734187441875418764187741878418794188041881418824188341884418854188641887418884188941890418914189241893418944189541896418974189841899419004190141902419034190441905419064190741908419094191041911419124191341914419154191641917419184191941920419214192241923419244192541926419274192841929419304193141932419334193441935419364193741938419394194041941419424194341944419454194641947419484194941950419514195241953419544195541956419574195841959419604196141962419634196441965419664196741968419694197041971419724197341974419754197641977419784197941980419814198241983419844198541986419874198841989419904199141992419934199441995419964199741998419994200042001420024200342004420054200642007420084200942010420114201242013420144201542016420174201842019420204202142022420234202442025420264202742028420294203042031420324203342034420354203642037420384203942040420414204242043420444204542046420474204842049420504205142052420534205442055420564205742058420594206042061420624206342064420654206642067420684206942070420714207242073420744207542076420774207842079420804208142082420834208442085420864208742088420894209042091420924209342094420954209642097420984209942100421014210242103421044210542106421074210842109421104211142112421134211442115421164211742118421194212042121421224212342124421254212642127421284212942130421314213242133421344213542136421374213842139421404214142142421434214442145421464214742148421494215042151421524215342154421554215642157421584215942160421614216242163421644216542166421674216842169421704217142172421734217442175421764217742178421794218042181421824218342184421854218642187421884218942190421914219242193421944219542196421974219842199422004220142202422034220442205422064220742208422094221042211422124221342214422154221642217422184221942220422214222242223422244222542226422274222842229422304223142232422334223442235422364223742238422394224042241422424224342244422454224642247422484224942250422514225242253422544225542256422574225842259422604226142262422634226442265422664226742268422694227042271422724227342274422754227642277422784227942280422814228242283422844228542286422874228842289422904229142292422934229442295422964229742298422994230042301423024230342304423054230642307423084230942310423114231242313423144231542316423174231842319423204232142322423234232442325423264232742328423294233042331423324233342334423354233642337423384233942340423414234242343423444234542346423474234842349423504235142352423534235442355423564235742358423594236042361423624236342364423654236642367423684236942370423714237242373423744237542376423774237842379423804238142382423834238442385423864238742388423894239042391423924239342394423954239642397423984239942400424014240242403424044240542406424074240842409424104241142412424134241442415424164241742418424194242042421424224242342424424254242642427424284242942430424314243242433424344243542436424374243842439424404244142442424434244442445424464244742448424494245042451424524245342454424554245642457424584245942460424614246242463424644246542466424674246842469424704247142472424734247442475424764247742478424794248042481424824248342484424854248642487424884248942490424914249242493424944249542496424974249842499425004250142502425034250442505425064250742508425094251042511425124251342514425154251642517425184251942520425214252242523425244252542526425274252842529425304253142532425334253442535425364253742538425394254042541425424254342544425454254642547425484254942550425514255242553425544255542556425574255842559425604256142562425634256442565425664256742568425694257042571425724257342574425754257642577425784257942580425814258242583425844258542586425874258842589425904259142592425934259442595425964259742598425994260042601426024260342604426054260642607426084260942610426114261242613426144261542616426174261842619426204262142622426234262442625426264262742628426294263042631426324263342634426354263642637426384263942640426414264242643426444264542646426474264842649426504265142652426534265442655426564265742658426594266042661426624266342664426654266642667426684266942670426714267242673426744267542676426774267842679426804268142682426834268442685426864268742688426894269042691426924269342694426954269642697426984269942700427014270242703427044270542706427074270842709427104271142712427134271442715427164271742718427194272042721427224272342724427254272642727427284272942730427314273242733427344273542736427374273842739427404274142742427434274442745427464274742748427494275042751427524275342754427554275642757427584275942760427614276242763427644276542766427674276842769427704277142772427734277442775427764277742778427794278042781427824278342784427854278642787427884278942790427914279242793427944279542796427974279842799428004280142802428034280442805428064280742808428094281042811428124281342814428154281642817428184281942820428214282242823428244282542826428274282842829428304283142832428334283442835428364283742838428394284042841428424284342844428454284642847428484284942850428514285242853428544285542856428574285842859428604286142862428634286442865428664286742868428694287042871428724287342874428754287642877428784287942880428814288242883428844288542886428874288842889428904289142892428934289442895428964289742898428994290042901429024290342904429054290642907429084290942910429114291242913429144291542916429174291842919429204292142922429234292442925429264292742928429294293042931429324293342934429354293642937429384293942940429414294242943429444294542946429474294842949429504295142952429534295442955429564295742958429594296042961429624296342964429654296642967429684296942970429714297242973429744297542976429774297842979429804298142982429834298442985429864298742988429894299042991429924299342994429954299642997429984299943000430014300243003430044300543006430074300843009430104301143012430134301443015430164301743018430194302043021430224302343024430254302643027430284302943030430314303243033430344303543036430374303843039430404304143042430434304443045430464304743048430494305043051430524305343054430554305643057430584305943060430614306243063430644306543066430674306843069430704307143072430734307443075430764307743078430794308043081430824308343084430854308643087430884308943090430914309243093430944309543096430974309843099431004310143102431034310443105431064310743108431094311043111431124311343114431154311643117431184311943120431214312243123431244312543126431274312843129431304313143132431334313443135431364313743138431394314043141431424314343144431454314643147431484314943150431514315243153431544315543156431574315843159431604316143162431634316443165431664316743168431694317043171431724317343174431754317643177431784317943180431814318243183431844318543186431874318843189431904319143192431934319443195431964319743198431994320043201432024320343204432054320643207432084320943210432114321243213432144321543216432174321843219432204322143222432234322443225432264322743228432294323043231432324323343234432354323643237432384323943240432414324243243432444324543246432474324843249432504325143252432534325443255432564325743258432594326043261432624326343264432654326643267432684326943270432714327243273432744327543276432774327843279432804328143282432834328443285432864328743288432894329043291432924329343294432954329643297432984329943300433014330243303433044330543306433074330843309433104331143312433134331443315433164331743318433194332043321433224332343324433254332643327433284332943330433314333243333433344333543336433374333843339433404334143342433434334443345433464334743348433494335043351433524335343354433554335643357433584335943360433614336243363433644336543366433674336843369433704337143372433734337443375433764337743378433794338043381433824338343384433854338643387433884338943390433914339243393433944339543396433974339843399434004340143402434034340443405434064340743408434094341043411434124341343414434154341643417434184341943420434214342243423434244342543426434274342843429434304343143432434334343443435434364343743438434394344043441434424344343444434454344643447434484344943450434514345243453434544345543456434574345843459434604346143462434634346443465434664346743468434694347043471434724347343474434754347643477434784347943480434814348243483434844348543486434874348843489434904349143492434934349443495434964349743498434994350043501435024350343504435054350643507435084350943510435114351243513435144351543516435174351843519435204352143522435234352443525435264352743528435294353043531435324353343534435354353643537435384353943540435414354243543435444354543546435474354843549435504355143552435534355443555435564355743558435594356043561435624356343564435654356643567435684356943570435714357243573435744357543576435774357843579435804358143582435834358443585435864358743588435894359043591435924359343594435954359643597435984359943600436014360243603436044360543606436074360843609436104361143612436134361443615436164361743618436194362043621436224362343624436254362643627436284362943630436314363243633436344363543636436374363843639436404364143642436434364443645436464364743648436494365043651436524365343654436554365643657436584365943660436614366243663436644366543666436674366843669436704367143672436734367443675436764367743678436794368043681436824368343684436854368643687436884368943690436914369243693436944369543696436974369843699437004370143702437034370443705437064370743708437094371043711437124371343714437154371643717437184371943720437214372243723437244372543726437274372843729437304373143732437334373443735437364373743738437394374043741437424374343744437454374643747437484374943750437514375243753437544375543756437574375843759437604376143762437634376443765437664376743768437694377043771437724377343774437754377643777437784377943780437814378243783437844378543786437874378843789437904379143792437934379443795437964379743798437994380043801438024380343804438054380643807438084380943810438114381243813438144381543816438174381843819438204382143822438234382443825438264382743828438294383043831438324383343834438354383643837438384383943840438414384243843438444384543846438474384843849438504385143852438534385443855438564385743858438594386043861438624386343864438654386643867438684386943870438714387243873438744387543876438774387843879438804388143882438834388443885438864388743888438894389043891438924389343894438954389643897438984389943900439014390243903439044390543906439074390843909439104391143912439134391443915439164391743918439194392043921439224392343924439254392643927439284392943930439314393243933439344393543936439374393843939439404394143942439434394443945439464394743948439494395043951439524395343954439554395643957439584395943960439614396243963439644396543966439674396843969439704397143972439734397443975439764397743978439794398043981439824398343984439854398643987439884398943990439914399243993439944399543996439974399843999440004400144002440034400444005440064400744008440094401044011440124401344014440154401644017440184401944020440214402244023440244402544026440274402844029440304403144032440334403444035440364403744038440394404044041440424404344044440454404644047440484404944050440514405244053440544405544056440574405844059440604406144062440634406444065440664406744068440694407044071440724407344074440754407644077440784407944080440814408244083440844408544086440874408844089440904409144092440934409444095440964409744098440994410044101441024410344104441054410644107441084410944110441114411244113441144411544116441174411844119441204412144122441234412444125441264412744128441294413044131441324413344134441354413644137441384413944140441414414244143441444414544146441474414844149441504415144152441534415444155441564415744158441594416044161441624416344164441654416644167441684416944170441714417244173441744417544176441774417844179441804418144182441834418444185441864418744188441894419044191441924419344194441954419644197441984419944200442014420244203442044420544206442074420844209442104421144212442134421444215442164421744218442194422044221442224422344224442254422644227442284422944230442314423244233442344423544236442374423844239442404424144242442434424444245442464424744248442494425044251442524425344254442554425644257442584425944260442614426244263442644426544266442674426844269442704427144272442734427444275442764427744278442794428044281442824428344284442854428644287442884428944290442914429244293442944429544296442974429844299443004430144302443034430444305443064430744308443094431044311443124431344314443154431644317443184431944320443214432244323443244432544326443274432844329443304433144332443334433444335443364433744338443394434044341443424434344344443454434644347443484434944350443514435244353443544435544356443574435844359443604436144362443634436444365443664436744368443694437044371443724437344374443754437644377443784437944380443814438244383443844438544386443874438844389443904439144392443934439444395443964439744398443994440044401444024440344404444054440644407444084440944410444114441244413444144441544416444174441844419444204442144422444234442444425444264442744428444294443044431444324443344434444354443644437444384443944440444414444244443444444444544446444474444844449444504445144452444534445444455444564445744458444594446044461444624446344464444654446644467444684446944470444714447244473444744447544476444774447844479444804448144482444834448444485444864448744488444894449044491444924449344494444954449644497444984449944500445014450244503445044450544506445074450844509445104451144512445134451444515445164451744518445194452044521445224452344524445254452644527445284452944530445314453244533445344453544536445374453844539445404454144542445434454444545445464454744548445494455044551445524455344554445554455644557445584455944560445614456244563445644456544566445674456844569445704457144572445734457444575445764457744578445794458044581445824458344584445854458644587445884458944590445914459244593445944459544596445974459844599446004460144602446034460444605446064460744608446094461044611446124461344614446154461644617446184461944620446214462244623446244462544626446274462844629446304463144632446334463444635446364463744638446394464044641446424464344644446454464644647446484464944650446514465244653446544465544656446574465844659446604466144662446634466444665446664466744668446694467044671446724467344674446754467644677446784467944680446814468244683446844468544686446874468844689446904469144692446934469444695446964469744698446994470044701447024470344704447054470644707447084470944710447114471244713447144471544716447174471844719447204472144722447234472444725447264472744728447294473044731447324473344734447354473644737447384473944740447414474244743447444474544746447474474844749447504475144752447534475444755447564475744758447594476044761447624476344764447654476644767447684476944770447714477244773447744477544776447774477844779447804478144782447834478444785447864478744788447894479044791447924479344794447954479644797447984479944800448014480244803448044480544806448074480844809448104481144812448134481444815448164481744818448194482044821448224482344824448254482644827448284482944830448314483244833448344483544836448374483844839448404484144842448434484444845448464484744848448494485044851448524485344854448554485644857448584485944860448614486244863448644486544866448674486844869448704487144872448734487444875448764487744878448794488044881448824488344884448854488644887448884488944890448914489244893448944489544896448974489844899449004490144902449034490444905449064490744908449094491044911449124491344914449154491644917449184491944920449214492244923449244492544926449274492844929449304493144932449334493444935449364493744938449394494044941449424494344944449454494644947449484494944950449514495244953449544495544956449574495844959449604496144962449634496444965449664496744968449694497044971449724497344974449754497644977449784497944980449814498244983449844498544986449874498844989449904499144992449934499444995449964499744998449994500045001450024500345004450054500645007450084500945010450114501245013450144501545016450174501845019450204502145022450234502445025450264502745028450294503045031450324503345034450354503645037450384503945040450414504245043450444504545046450474504845049450504505145052450534505445055450564505745058450594506045061450624506345064450654506645067450684506945070450714507245073450744507545076450774507845079450804508145082450834508445085450864508745088450894509045091450924509345094450954509645097450984509945100451014510245103451044510545106451074510845109451104511145112451134511445115451164511745118451194512045121451224512345124451254512645127451284512945130451314513245133451344513545136451374513845139451404514145142451434514445145451464514745148451494515045151451524515345154451554515645157451584515945160451614516245163451644516545166451674516845169451704517145172451734517445175451764517745178451794518045181451824518345184451854518645187451884518945190451914519245193451944519545196451974519845199452004520145202452034520445205452064520745208452094521045211452124521345214452154521645217452184521945220452214522245223452244522545226452274522845229452304523145232452334523445235452364523745238452394524045241452424524345244452454524645247452484524945250452514525245253452544525545256452574525845259452604526145262452634526445265452664526745268452694527045271452724527345274452754527645277452784527945280452814528245283452844528545286452874528845289452904529145292452934529445295452964529745298452994530045301453024530345304453054530645307453084530945310453114531245313453144531545316453174531845319453204532145322453234532445325453264532745328453294533045331453324533345334453354533645337453384533945340453414534245343453444534545346453474534845349453504535145352453534535445355453564535745358453594536045361453624536345364453654536645367453684536945370453714537245373453744537545376453774537845379453804538145382453834538445385453864538745388453894539045391453924539345394453954539645397453984539945400454014540245403454044540545406454074540845409454104541145412454134541445415454164541745418454194542045421454224542345424454254542645427454284542945430454314543245433454344543545436454374543845439454404544145442454434544445445454464544745448454494545045451454524545345454454554545645457454584545945460454614546245463454644546545466454674546845469454704547145472454734547445475454764547745478454794548045481454824548345484454854548645487454884548945490454914549245493454944549545496454974549845499455004550145502455034550445505455064550745508455094551045511455124551345514455154551645517455184551945520455214552245523455244552545526455274552845529455304553145532455334553445535455364553745538455394554045541455424554345544455454554645547455484554945550455514555245553455544555545556455574555845559455604556145562455634556445565455664556745568455694557045571455724557345574455754557645577455784557945580455814558245583455844558545586455874558845589455904559145592455934559445595455964559745598455994560045601456024560345604456054560645607456084560945610456114561245613456144561545616456174561845619456204562145622456234562445625456264562745628456294563045631456324563345634456354563645637456384563945640456414564245643456444564545646456474564845649456504565145652456534565445655456564565745658456594566045661456624566345664456654566645667456684566945670456714567245673456744567545676456774567845679456804568145682456834568445685456864568745688456894569045691456924569345694456954569645697456984569945700457014570245703457044570545706457074570845709457104571145712457134571445715457164571745718457194572045721457224572345724457254572645727457284572945730457314573245733457344573545736457374573845739457404574145742457434574445745457464574745748457494575045751457524575345754457554575645757457584575945760457614576245763457644576545766457674576845769457704577145772457734577445775457764577745778457794578045781457824578345784457854578645787457884578945790457914579245793457944579545796457974579845799458004580145802458034580445805458064580745808458094581045811458124581345814458154581645817458184581945820458214582245823458244582545826458274582845829458304583145832458334583445835458364583745838458394584045841458424584345844458454584645847458484584945850458514585245853458544585545856458574585845859458604586145862458634586445865458664586745868458694587045871458724587345874458754587645877458784587945880458814588245883458844588545886458874588845889458904589145892458934589445895458964589745898458994590045901459024590345904459054590645907459084590945910459114591245913459144591545916459174591845919459204592145922459234592445925459264592745928459294593045931459324593345934459354593645937459384593945940459414594245943459444594545946459474594845949459504595145952459534595445955459564595745958459594596045961459624596345964459654596645967459684596945970459714597245973459744597545976459774597845979459804598145982459834598445985459864598745988459894599045991459924599345994459954599645997459984599946000460014600246003460044600546006460074600846009460104601146012460134601446015460164601746018460194602046021460224602346024460254602646027460284602946030460314603246033460344603546036460374603846039460404604146042460434604446045460464604746048460494605046051460524605346054460554605646057460584605946060460614606246063460644606546066460674606846069460704607146072460734607446075460764607746078460794608046081460824608346084460854608646087460884608946090460914609246093460944609546096460974609846099461004610146102461034610446105461064610746108461094611046111461124611346114461154611646117461184611946120461214612246123461244612546126461274612846129461304613146132461334613446135461364613746138461394614046141461424614346144461454614646147461484614946150461514615246153461544615546156461574615846159461604616146162461634616446165461664616746168461694617046171461724617346174461754617646177461784617946180461814618246183461844618546186461874618846189461904619146192461934619446195461964619746198461994620046201462024620346204462054620646207462084620946210462114621246213462144621546216462174621846219462204622146222462234622446225462264622746228462294623046231462324623346234462354623646237462384623946240462414624246243462444624546246462474624846249462504625146252462534625446255462564625746258462594626046261462624626346264462654626646267462684626946270462714627246273462744627546276462774627846279462804628146282462834628446285462864628746288462894629046291462924629346294462954629646297462984629946300463014630246303463044630546306463074630846309463104631146312463134631446315463164631746318463194632046321463224632346324463254632646327463284632946330463314633246333463344633546336463374633846339463404634146342463434634446345463464634746348463494635046351463524635346354463554635646357463584635946360463614636246363463644636546366463674636846369463704637146372463734637446375463764637746378463794638046381463824638346384463854638646387463884638946390463914639246393463944639546396463974639846399464004640146402464034640446405464064640746408464094641046411464124641346414464154641646417464184641946420464214642246423464244642546426464274642846429464304643146432464334643446435464364643746438464394644046441464424644346444464454644646447464484644946450464514645246453464544645546456464574645846459464604646146462464634646446465464664646746468464694647046471464724647346474464754647646477464784647946480464814648246483464844648546486464874648846489464904649146492464934649446495464964649746498464994650046501465024650346504465054650646507465084650946510465114651246513465144651546516465174651846519465204652146522465234652446525465264652746528465294653046531465324653346534465354653646537465384653946540465414654246543465444654546546465474654846549465504655146552465534655446555465564655746558465594656046561465624656346564465654656646567465684656946570465714657246573465744657546576465774657846579465804658146582465834658446585465864658746588465894659046591465924659346594465954659646597465984659946600466014660246603466044660546606466074660846609466104661146612466134661446615466164661746618466194662046621466224662346624466254662646627466284662946630466314663246633466344663546636466374663846639466404664146642466434664446645466464664746648466494665046651466524665346654466554665646657466584665946660466614666246663466644666546666466674666846669466704667146672466734667446675466764667746678466794668046681466824668346684466854668646687466884668946690466914669246693466944669546696466974669846699467004670146702467034670446705467064670746708467094671046711467124671346714467154671646717467184671946720467214672246723467244672546726467274672846729467304673146732467334673446735467364673746738467394674046741467424674346744467454674646747467484674946750467514675246753467544675546756467574675846759467604676146762467634676446765467664676746768467694677046771467724677346774467754677646777467784677946780467814678246783467844678546786467874678846789467904679146792467934679446795467964679746798467994680046801468024680346804468054680646807468084680946810468114681246813468144681546816468174681846819468204682146822468234682446825468264682746828468294683046831468324683346834468354683646837468384683946840468414684246843468444684546846468474684846849468504685146852468534685446855468564685746858468594686046861468624686346864468654686646867468684686946870468714687246873468744687546876468774687846879468804688146882468834688446885468864688746888468894689046891468924689346894468954689646897468984689946900469014690246903469044690546906469074690846909469104691146912469134691446915469164691746918469194692046921469224692346924469254692646927469284692946930469314693246933469344693546936469374693846939469404694146942469434694446945469464694746948469494695046951469524695346954469554695646957469584695946960469614696246963469644696546966469674696846969469704697146972469734697446975469764697746978469794698046981469824698346984469854698646987469884698946990469914699246993469944699546996469974699846999470004700147002470034700447005470064700747008470094701047011470124701347014470154701647017470184701947020470214702247023470244702547026470274702847029470304703147032470334703447035470364703747038470394704047041470424704347044470454704647047470484704947050470514705247053470544705547056470574705847059470604706147062470634706447065470664706747068470694707047071470724707347074470754707647077470784707947080470814708247083470844708547086470874708847089470904709147092470934709447095470964709747098470994710047101471024710347104471054710647107471084710947110471114711247113471144711547116471174711847119471204712147122471234712447125471264712747128471294713047131471324713347134471354713647137471384713947140471414714247143471444714547146471474714847149471504715147152471534715447155471564715747158471594716047161471624716347164471654716647167471684716947170471714717247173471744717547176471774717847179471804718147182471834718447185471864718747188471894719047191471924719347194471954719647197471984719947200472014720247203472044720547206472074720847209472104721147212472134721447215472164721747218472194722047221472224722347224472254722647227472284722947230472314723247233472344723547236472374723847239472404724147242472434724447245472464724747248472494725047251472524725347254472554725647257472584725947260472614726247263472644726547266472674726847269472704727147272472734727447275472764727747278472794728047281472824728347284472854728647287472884728947290472914729247293472944729547296472974729847299473004730147302473034730447305473064730747308473094731047311473124731347314473154731647317473184731947320473214732247323473244732547326473274732847329473304733147332473334733447335473364733747338473394734047341473424734347344473454734647347473484734947350473514735247353473544735547356473574735847359473604736147362473634736447365473664736747368473694737047371473724737347374473754737647377473784737947380473814738247383473844738547386473874738847389473904739147392473934739447395473964739747398473994740047401474024740347404474054740647407474084740947410474114741247413474144741547416474174741847419474204742147422474234742447425474264742747428474294743047431474324743347434474354743647437474384743947440474414744247443474444744547446474474744847449474504745147452474534745447455474564745747458474594746047461474624746347464474654746647467474684746947470474714747247473474744747547476474774747847479474804748147482474834748447485474864748747488474894749047491474924749347494474954749647497474984749947500475014750247503475044750547506475074750847509475104751147512475134751447515475164751747518475194752047521475224752347524475254752647527475284752947530475314753247533475344753547536475374753847539475404754147542475434754447545475464754747548475494755047551475524755347554475554755647557475584755947560475614756247563475644756547566475674756847569475704757147572475734757447575475764757747578475794758047581475824758347584475854758647587475884758947590475914759247593475944759547596475974759847599476004760147602476034760447605476064760747608476094761047611476124761347614476154761647617476184761947620476214762247623476244762547626476274762847629476304763147632476334763447635476364763747638476394764047641476424764347644476454764647647476484764947650476514765247653476544765547656476574765847659476604766147662476634766447665476664766747668476694767047671476724767347674476754767647677476784767947680476814768247683476844768547686476874768847689476904769147692476934769447695476964769747698476994770047701477024770347704477054770647707477084770947710477114771247713477144771547716477174771847719477204772147722477234772447725477264772747728477294773047731477324773347734477354773647737477384773947740477414774247743477444774547746477474774847749477504775147752477534775447755477564775747758477594776047761477624776347764477654776647767477684776947770477714777247773477744777547776477774777847779477804778147782477834778447785477864778747788477894779047791477924779347794477954779647797477984779947800478014780247803478044780547806478074780847809478104781147812478134781447815478164781747818478194782047821478224782347824478254782647827478284782947830478314783247833478344783547836478374783847839478404784147842478434784447845478464784747848478494785047851478524785347854478554785647857478584785947860478614786247863478644786547866478674786847869478704787147872478734787447875478764787747878478794788047881478824788347884478854788647887478884788947890478914789247893478944789547896478974789847899479004790147902479034790447905479064790747908479094791047911479124791347914479154791647917479184791947920479214792247923479244792547926479274792847929479304793147932479334793447935479364793747938479394794047941479424794347944479454794647947479484794947950479514795247953479544795547956479574795847959479604796147962479634796447965479664796747968479694797047971479724797347974479754797647977479784797947980479814798247983479844798547986479874798847989479904799147992479934799447995479964799747998479994800048001480024800348004480054800648007480084800948010480114801248013480144801548016480174801848019480204802148022480234802448025480264802748028480294803048031480324803348034480354803648037480384803948040480414804248043480444804548046480474804848049480504805148052480534805448055480564805748058480594806048061480624806348064480654806648067480684806948070480714807248073480744807548076480774807848079480804808148082480834808448085480864808748088480894809048091480924809348094480954809648097480984809948100481014810248103481044810548106481074810848109481104811148112481134811448115481164811748118481194812048121481224812348124481254812648127481284812948130481314813248133481344813548136481374813848139481404814148142481434814448145481464814748148481494815048151481524815348154481554815648157481584815948160481614816248163481644816548166481674816848169481704817148172481734817448175481764817748178481794818048181481824818348184481854818648187481884818948190481914819248193481944819548196481974819848199482004820148202482034820448205482064820748208482094821048211482124821348214482154821648217482184821948220482214822248223482244822548226482274822848229482304823148232482334823448235482364823748238482394824048241482424824348244482454824648247482484824948250482514825248253482544825548256482574825848259482604826148262482634826448265482664826748268482694827048271482724827348274482754827648277482784827948280482814828248283482844828548286482874828848289482904829148292482934829448295482964829748298482994830048301483024830348304483054830648307483084830948310483114831248313483144831548316483174831848319483204832148322483234832448325483264832748328483294833048331483324833348334483354833648337483384833948340483414834248343483444834548346483474834848349483504835148352483534835448355483564835748358483594836048361483624836348364483654836648367483684836948370483714837248373483744837548376483774837848379483804838148382483834838448385483864838748388483894839048391483924839348394483954839648397483984839948400484014840248403484044840548406484074840848409484104841148412484134841448415484164841748418484194842048421484224842348424484254842648427484284842948430484314843248433484344843548436484374843848439484404844148442484434844448445484464844748448484494845048451484524845348454484554845648457484584845948460484614846248463484644846548466484674846848469484704847148472484734847448475484764847748478484794848048481484824848348484484854848648487484884848948490484914849248493484944849548496484974849848499485004850148502485034850448505485064850748508485094851048511485124851348514485154851648517485184851948520485214852248523485244852548526485274852848529485304853148532485334853448535485364853748538485394854048541485424854348544485454854648547485484854948550485514855248553485544855548556485574855848559485604856148562485634856448565485664856748568485694857048571485724857348574485754857648577485784857948580485814858248583485844858548586485874858848589485904859148592485934859448595485964859748598485994860048601486024860348604486054860648607486084860948610486114861248613486144861548616486174861848619486204862148622486234862448625486264862748628486294863048631486324863348634486354863648637486384863948640486414864248643486444864548646486474864848649486504865148652486534865448655486564865748658486594866048661486624866348664486654866648667486684866948670486714867248673486744867548676486774867848679486804868148682486834868448685486864868748688486894869048691486924869348694486954869648697486984869948700487014870248703487044870548706487074870848709487104871148712487134871448715487164871748718487194872048721487224872348724487254872648727487284872948730487314873248733487344873548736487374873848739487404874148742487434874448745487464874748748487494875048751487524875348754487554875648757487584875948760487614876248763487644876548766487674876848769487704877148772487734877448775487764877748778487794878048781487824878348784487854878648787487884878948790487914879248793487944879548796487974879848799488004880148802488034880448805488064880748808488094881048811488124881348814488154881648817488184881948820488214882248823488244882548826488274882848829488304883148832488334883448835488364883748838488394884048841488424884348844488454884648847488484884948850488514885248853488544885548856488574885848859488604886148862488634886448865488664886748868488694887048871488724887348874488754887648877488784887948880488814888248883488844888548886488874888848889488904889148892488934889448895488964889748898488994890048901489024890348904489054890648907489084890948910489114891248913489144891548916489174891848919489204892148922489234892448925489264892748928489294893048931489324893348934489354893648937489384893948940489414894248943489444894548946489474894848949489504895148952489534895448955489564895748958489594896048961489624896348964489654896648967489684896948970489714897248973489744897548976489774897848979489804898148982489834898448985489864898748988489894899048991489924899348994489954899648997489984899949000490014900249003490044900549006490074900849009490104901149012490134901449015490164901749018490194902049021490224902349024490254902649027490284902949030490314903249033490344903549036490374903849039490404904149042490434904449045490464904749048490494905049051490524905349054490554905649057490584905949060490614906249063490644906549066490674906849069490704907149072490734907449075490764907749078490794908049081490824908349084490854908649087490884908949090490914909249093490944909549096490974909849099491004910149102491034910449105491064910749108491094911049111491124911349114491154911649117491184911949120491214912249123491244912549126491274912849129491304913149132491334913449135491364913749138491394914049141491424914349144491454914649147491484914949150491514915249153491544915549156491574915849159491604916149162491634916449165491664916749168491694917049171491724917349174491754917649177491784917949180491814918249183491844918549186491874918849189491904919149192491934919449195491964919749198491994920049201492024920349204492054920649207492084920949210492114921249213492144921549216492174921849219492204922149222492234922449225492264922749228492294923049231492324923349234492354923649237492384923949240492414924249243492444924549246492474924849249492504925149252492534925449255492564925749258492594926049261492624926349264492654926649267492684926949270492714927249273492744927549276492774927849279492804928149282492834928449285492864928749288492894929049291492924929349294492954929649297492984929949300493014930249303493044930549306493074930849309493104931149312493134931449315493164931749318493194932049321493224932349324493254932649327493284932949330493314933249333493344933549336493374933849339493404934149342493434934449345493464934749348493494935049351493524935349354493554935649357493584935949360493614936249363493644936549366493674936849369493704937149372493734937449375493764937749378493794938049381493824938349384493854938649387493884938949390493914939249393493944939549396493974939849399494004940149402494034940449405494064940749408494094941049411494124941349414494154941649417494184941949420494214942249423494244942549426494274942849429494304943149432494334943449435494364943749438494394944049441494424944349444494454944649447494484944949450494514945249453494544945549456494574945849459494604946149462494634946449465494664946749468494694947049471494724947349474494754947649477494784947949480494814948249483494844948549486494874948849489494904949149492494934949449495494964949749498494994950049501495024950349504495054950649507495084950949510495114951249513495144951549516495174951849519495204952149522495234952449525495264952749528495294953049531495324953349534495354953649537495384953949540495414954249543495444954549546495474954849549495504955149552495534955449555495564955749558495594956049561495624956349564495654956649567495684956949570495714957249573495744957549576495774957849579495804958149582495834958449585495864958749588495894959049591495924959349594495954959649597495984959949600496014960249603496044960549606496074960849609496104961149612496134961449615496164961749618496194962049621496224962349624496254962649627496284962949630496314963249633496344963549636496374963849639496404964149642496434964449645496464964749648496494965049651496524965349654496554965649657496584965949660496614966249663496644966549666496674966849669496704967149672496734967449675496764967749678496794968049681496824968349684496854968649687496884968949690496914969249693496944969549696496974969849699497004970149702497034970449705497064970749708497094971049711497124971349714497154971649717497184971949720497214972249723497244972549726497274972849729497304973149732497334973449735497364973749738497394974049741497424974349744497454974649747497484974949750497514975249753497544975549756497574975849759497604976149762497634976449765497664976749768497694977049771497724977349774497754977649777497784977949780497814978249783497844978549786497874978849789497904979149792497934979449795497964979749798497994980049801498024980349804498054980649807498084980949810498114981249813498144981549816498174981849819498204982149822498234982449825498264982749828498294983049831498324983349834498354983649837498384983949840498414984249843498444984549846498474984849849498504985149852498534985449855498564985749858498594986049861498624986349864498654986649867498684986949870498714987249873498744987549876498774987849879498804988149882498834988449885498864988749888498894989049891498924989349894498954989649897498984989949900499014990249903499044990549906499074990849909499104991149912499134991449915499164991749918499194992049921499224992349924499254992649927499284992949930499314993249933499344993549936499374993849939499404994149942499434994449945499464994749948499494995049951499524995349954499554995649957499584995949960499614996249963499644996549966499674996849969499704997149972499734997449975499764997749978499794998049981499824998349984499854998649987499884998949990499914999249993499944999549996499974999849999500005000150002500035000450005500065000750008500095001050011500125001350014500155001650017500185001950020500215002250023500245002550026500275002850029500305003150032500335003450035500365003750038500395004050041500425004350044500455004650047500485004950050500515005250053500545005550056500575005850059500605006150062500635006450065500665006750068500695007050071500725007350074500755007650077500785007950080500815008250083500845008550086500875008850089500905009150092500935009450095500965009750098500995010050101501025010350104501055010650107501085010950110501115011250113501145011550116501175011850119501205012150122501235012450125501265012750128501295013050131501325013350134501355013650137501385013950140501415014250143501445014550146501475014850149501505015150152501535015450155501565015750158501595016050161501625016350164501655016650167501685016950170501715017250173501745017550176501775017850179501805018150182501835018450185501865018750188501895019050191501925019350194501955019650197501985019950200502015020250203502045020550206502075020850209502105021150212502135021450215502165021750218502195022050221502225022350224502255022650227502285022950230502315023250233502345023550236502375023850239502405024150242502435024450245502465024750248502495025050251502525025350254502555025650257502585025950260502615026250263502645026550266502675026850269502705027150272502735027450275502765027750278502795028050281502825028350284502855028650287502885028950290502915029250293502945029550296502975029850299503005030150302503035030450305503065030750308503095031050311503125031350314503155031650317503185031950320503215032250323503245032550326503275032850329503305033150332503335033450335503365033750338503395034050341503425034350344503455034650347503485034950350503515035250353503545035550356503575035850359503605036150362503635036450365503665036750368503695037050371503725037350374503755037650377503785037950380503815038250383503845038550386503875038850389503905039150392503935039450395503965039750398503995040050401504025040350404504055040650407504085040950410504115041250413504145041550416504175041850419504205042150422504235042450425504265042750428504295043050431504325043350434504355043650437504385043950440504415044250443504445044550446504475044850449504505045150452504535045450455504565045750458504595046050461504625046350464504655046650467504685046950470504715047250473504745047550476504775047850479504805048150482504835048450485504865048750488504895049050491504925049350494504955049650497504985049950500505015050250503505045050550506505075050850509505105051150512505135051450515505165051750518505195052050521505225052350524505255052650527505285052950530505315053250533505345053550536505375053850539505405054150542505435054450545505465054750548505495055050551505525055350554505555055650557505585055950560505615056250563505645056550566505675056850569505705057150572505735057450575505765057750578505795058050581505825058350584505855058650587505885058950590505915059250593505945059550596505975059850599506005060150602506035060450605506065060750608506095061050611506125061350614506155061650617506185061950620506215062250623506245062550626506275062850629506305063150632506335063450635506365063750638506395064050641506425064350644506455064650647506485064950650506515065250653506545065550656506575065850659506605066150662506635066450665506665066750668506695067050671506725067350674506755067650677506785067950680506815068250683506845068550686506875068850689506905069150692506935069450695506965069750698506995070050701507025070350704507055070650707507085070950710507115071250713507145071550716507175071850719507205072150722507235072450725507265072750728507295073050731507325073350734507355073650737507385073950740507415074250743507445074550746507475074850749507505075150752507535075450755507565075750758507595076050761507625076350764507655076650767507685076950770507715077250773507745077550776507775077850779507805078150782507835078450785507865078750788507895079050791507925079350794507955079650797507985079950800508015080250803508045080550806508075080850809508105081150812508135081450815508165081750818508195082050821508225082350824508255082650827508285082950830508315083250833508345083550836508375083850839508405084150842508435084450845508465084750848508495085050851508525085350854508555085650857508585085950860508615086250863508645086550866508675086850869508705087150872508735087450875508765087750878508795088050881508825088350884508855088650887508885088950890508915089250893508945089550896508975089850899509005090150902509035090450905509065090750908509095091050911509125091350914509155091650917509185091950920509215092250923509245092550926509275092850929509305093150932509335093450935509365093750938509395094050941509425094350944509455094650947509485094950950509515095250953509545095550956509575095850959509605096150962509635096450965509665096750968509695097050971509725097350974509755097650977509785097950980509815098250983509845098550986509875098850989509905099150992509935099450995509965099750998509995100051001510025100351004510055100651007510085100951010510115101251013510145101551016510175101851019510205102151022510235102451025510265102751028510295103051031510325103351034510355103651037510385103951040510415104251043510445104551046510475104851049510505105151052510535105451055510565105751058510595106051061510625106351064510655106651067510685106951070510715107251073510745107551076510775107851079510805108151082510835108451085510865108751088510895109051091510925109351094510955109651097510985109951100511015110251103511045110551106511075110851109511105111151112511135111451115511165111751118511195112051121511225112351124511255112651127511285112951130511315113251133511345113551136511375113851139511405114151142511435114451145511465114751148511495115051151511525115351154511555115651157511585115951160511615116251163511645116551166511675116851169511705117151172511735117451175511765117751178511795118051181511825118351184511855118651187511885118951190511915119251193511945119551196511975119851199512005120151202512035120451205512065120751208512095121051211512125121351214512155121651217512185121951220512215122251223512245122551226512275122851229512305123151232512335123451235512365123751238512395124051241512425124351244512455124651247512485124951250512515125251253512545125551256512575125851259512605126151262512635126451265512665126751268512695127051271512725127351274512755127651277512785127951280512815128251283512845128551286512875128851289512905129151292512935129451295512965129751298512995130051301513025130351304513055130651307513085130951310513115131251313513145131551316513175131851319513205132151322513235132451325513265132751328513295133051331513325133351334513355133651337513385133951340513415134251343513445134551346513475134851349513505135151352513535135451355513565135751358513595136051361513625136351364513655136651367513685136951370513715137251373513745137551376513775137851379513805138151382513835138451385513865138751388513895139051391513925139351394513955139651397513985139951400514015140251403514045140551406514075140851409514105141151412514135141451415514165141751418514195142051421514225142351424514255142651427514285142951430514315143251433514345143551436514375143851439514405144151442514435144451445514465144751448514495145051451514525145351454514555145651457514585145951460514615146251463514645146551466514675146851469514705147151472514735147451475514765147751478514795148051481514825148351484514855148651487514885148951490514915149251493514945149551496514975149851499515005150151502515035150451505515065150751508515095151051511515125151351514515155151651517515185151951520515215152251523515245152551526515275152851529515305153151532515335153451535515365153751538515395154051541515425154351544515455154651547515485154951550515515155251553515545155551556515575155851559515605156151562515635156451565515665156751568515695157051571515725157351574515755157651577515785157951580515815158251583515845158551586515875158851589515905159151592515935159451595515965159751598515995160051601516025160351604516055160651607516085160951610516115161251613516145161551616516175161851619516205162151622516235162451625516265162751628516295163051631516325163351634516355163651637516385163951640516415164251643516445164551646516475164851649516505165151652516535165451655516565165751658516595166051661516625166351664516655166651667516685166951670516715167251673516745167551676516775167851679516805168151682516835168451685516865168751688516895169051691516925169351694516955169651697516985169951700517015170251703517045170551706517075170851709517105171151712517135171451715517165171751718517195172051721517225172351724517255172651727517285172951730517315173251733517345173551736517375173851739517405174151742517435174451745517465174751748517495175051751517525175351754517555175651757517585175951760517615176251763517645176551766517675176851769517705177151772517735177451775517765177751778517795178051781517825178351784517855178651787517885178951790517915179251793517945179551796517975179851799518005180151802518035180451805518065180751808518095181051811518125181351814518155181651817518185181951820518215182251823518245182551826518275182851829518305183151832518335183451835518365183751838518395184051841518425184351844518455184651847518485184951850518515185251853518545185551856518575185851859518605186151862518635186451865518665186751868518695187051871518725187351874518755187651877518785187951880518815188251883518845188551886518875188851889518905189151892518935189451895518965189751898518995190051901519025190351904519055190651907519085190951910519115191251913519145191551916519175191851919519205192151922519235192451925519265192751928519295193051931519325193351934519355193651937519385193951940519415194251943519445194551946519475194851949519505195151952519535195451955519565195751958519595196051961519625196351964519655196651967519685196951970519715197251973519745197551976519775197851979519805198151982519835198451985519865198751988519895199051991519925199351994519955199651997519985199952000520015200252003520045200552006520075200852009520105201152012520135201452015520165201752018520195202052021520225202352024520255202652027520285202952030520315203252033520345203552036520375203852039520405204152042520435204452045520465204752048520495205052051520525205352054520555205652057520585205952060520615206252063520645206552066520675206852069520705207152072520735207452075520765207752078520795208052081520825208352084520855208652087520885208952090520915209252093520945209552096520975209852099521005210152102521035210452105521065210752108521095211052111521125211352114521155211652117521185211952120521215212252123521245212552126521275212852129521305213152132521335213452135521365213752138521395214052141521425214352144521455214652147521485214952150521515215252153521545215552156521575215852159521605216152162521635216452165521665216752168521695217052171521725217352174521755217652177521785217952180521815218252183521845218552186521875218852189521905219152192521935219452195521965219752198521995220052201522025220352204522055220652207522085220952210522115221252213522145221552216522175221852219522205222152222522235222452225522265222752228522295223052231522325223352234522355223652237522385223952240522415224252243522445224552246522475224852249522505225152252522535225452255522565225752258522595226052261522625226352264522655226652267522685226952270522715227252273522745227552276522775227852279522805228152282522835228452285522865228752288522895229052291522925229352294522955229652297522985229952300523015230252303523045230552306523075230852309523105231152312523135231452315523165231752318523195232052321523225232352324523255232652327523285232952330523315233252333523345233552336523375233852339523405234152342523435234452345523465234752348523495235052351523525235352354523555235652357523585235952360523615236252363523645236552366523675236852369523705237152372523735237452375523765237752378523795238052381523825238352384523855238652387523885238952390523915239252393523945239552396523975239852399524005240152402524035240452405524065240752408524095241052411524125241352414524155241652417524185241952420524215242252423524245242552426524275242852429524305243152432524335243452435524365243752438524395244052441524425244352444524455244652447524485244952450524515245252453524545245552456524575245852459524605246152462524635246452465524665246752468524695247052471524725247352474524755247652477524785247952480524815248252483524845248552486524875248852489524905249152492524935249452495524965249752498524995250052501525025250352504525055250652507525085250952510525115251252513525145251552516525175251852519525205252152522525235252452525525265252752528525295253052531525325253352534525355253652537525385253952540525415254252543525445254552546525475254852549525505255152552525535255452555525565255752558525595256052561525625256352564525655256652567525685256952570525715257252573525745257552576525775257852579525805258152582525835258452585525865258752588525895259052591525925259352594525955259652597525985259952600526015260252603526045260552606526075260852609526105261152612526135261452615526165261752618526195262052621526225262352624526255262652627526285262952630526315263252633526345263552636526375263852639526405264152642526435264452645526465264752648526495265052651526525265352654526555265652657526585265952660526615266252663526645266552666526675266852669526705267152672526735267452675526765267752678526795268052681526825268352684526855268652687526885268952690526915269252693526945269552696526975269852699527005270152702527035270452705527065270752708527095271052711527125271352714527155271652717527185271952720527215272252723527245272552726527275272852729527305273152732527335273452735527365273752738527395274052741527425274352744527455274652747527485274952750527515275252753527545275552756527575275852759527605276152762527635276452765527665276752768527695277052771527725277352774527755277652777527785277952780527815278252783527845278552786527875278852789527905279152792527935279452795527965279752798527995280052801528025280352804528055280652807528085280952810528115281252813528145281552816528175281852819528205282152822528235282452825528265282752828528295283052831528325283352834528355283652837528385283952840528415284252843528445284552846528475284852849528505285152852528535285452855528565285752858528595286052861528625286352864528655286652867528685286952870528715287252873528745287552876528775287852879528805288152882528835288452885528865288752888528895289052891528925289352894528955289652897528985289952900529015290252903529045290552906529075290852909529105291152912529135291452915529165291752918529195292052921529225292352924529255292652927529285292952930529315293252933529345293552936529375293852939529405294152942529435294452945529465294752948529495295052951529525295352954529555295652957529585295952960529615296252963529645296552966529675296852969529705297152972529735297452975529765297752978529795298052981529825298352984529855298652987529885298952990529915299252993529945299552996529975299852999530005300153002530035300453005530065300753008530095301053011530125301353014530155301653017530185301953020530215302253023530245302553026530275302853029530305303153032530335303453035530365303753038530395304053041530425304353044530455304653047530485304953050530515305253053530545305553056530575305853059530605306153062530635306453065530665306753068530695307053071530725307353074530755307653077530785307953080530815308253083530845308553086530875308853089530905309153092530935309453095530965309753098530995310053101531025310353104531055310653107531085310953110531115311253113531145311553116531175311853119531205312153122531235312453125531265312753128531295313053131531325313353134531355313653137531385313953140531415314253143531445314553146531475314853149531505315153152531535315453155531565315753158531595316053161531625316353164531655316653167531685316953170531715317253173531745317553176531775317853179531805318153182531835318453185531865318753188531895319053191531925319353194531955319653197531985319953200532015320253203532045320553206532075320853209532105321153212532135321453215532165321753218532195322053221532225322353224532255322653227532285322953230532315323253233532345323553236532375323853239532405324153242532435324453245532465324753248532495325053251532525325353254532555325653257532585325953260532615326253263532645326553266532675326853269532705327153272532735327453275532765327753278532795328053281532825328353284532855328653287532885328953290532915329253293532945329553296532975329853299533005330153302533035330453305533065330753308533095331053311533125331353314533155331653317533185331953320533215332253323533245332553326533275332853329533305333153332533335333453335533365333753338533395334053341533425334353344533455334653347533485334953350533515335253353533545335553356533575335853359533605336153362533635336453365533665336753368533695337053371533725337353374533755337653377533785337953380533815338253383533845338553386533875338853389533905339153392533935339453395533965339753398533995340053401534025340353404534055340653407534085340953410534115341253413534145341553416534175341853419534205342153422534235342453425534265342753428534295343053431534325343353434534355343653437534385343953440534415344253443534445344553446534475344853449534505345153452534535345453455534565345753458534595346053461534625346353464534655346653467534685346953470534715347253473534745347553476534775347853479534805348153482534835348453485534865348753488534895349053491534925349353494534955349653497534985349953500535015350253503535045350553506535075350853509535105351153512535135351453515535165351753518535195352053521535225352353524535255352653527535285352953530535315353253533535345353553536535375353853539535405354153542535435354453545535465354753548535495355053551535525355353554535555355653557535585355953560535615356253563535645356553566535675356853569535705357153572535735357453575535765357753578535795358053581535825358353584535855358653587535885358953590535915359253593535945359553596535975359853599536005360153602536035360453605536065360753608536095361053611536125361353614536155361653617536185361953620536215362253623536245362553626536275362853629536305363153632536335363453635536365363753638536395364053641536425364353644536455364653647536485364953650536515365253653536545365553656536575365853659536605366153662536635366453665536665366753668536695367053671536725367353674536755367653677536785367953680536815368253683536845368553686536875368853689536905369153692536935369453695536965369753698536995370053701537025370353704537055370653707537085370953710537115371253713537145371553716537175371853719537205372153722537235372453725537265372753728537295373053731537325373353734537355373653737537385373953740537415374253743537445374553746537475374853749537505375153752537535375453755537565375753758537595376053761537625376353764537655376653767537685376953770537715377253773537745377553776537775377853779537805378153782537835378453785537865378753788537895379053791537925379353794537955379653797537985379953800538015380253803538045380553806538075380853809538105381153812538135381453815538165381753818538195382053821538225382353824538255382653827538285382953830538315383253833538345383553836538375383853839538405384153842538435384453845538465384753848538495385053851538525385353854538555385653857538585385953860538615386253863538645386553866538675386853869538705387153872538735387453875538765387753878538795388053881538825388353884538855388653887538885388953890538915389253893538945389553896538975389853899539005390153902539035390453905539065390753908539095391053911539125391353914539155391653917539185391953920539215392253923539245392553926539275392853929539305393153932539335393453935539365393753938539395394053941539425394353944539455394653947539485394953950539515395253953539545395553956539575395853959539605396153962539635396453965539665396753968539695397053971539725397353974539755397653977539785397953980539815398253983539845398553986539875398853989539905399153992539935399453995539965399753998539995400054001540025400354004540055400654007540085400954010540115401254013540145401554016540175401854019540205402154022540235402454025540265402754028540295403054031540325403354034540355403654037540385403954040540415404254043540445404554046540475404854049540505405154052540535405454055540565405754058540595406054061540625406354064540655406654067540685406954070540715407254073540745407554076540775407854079540805408154082540835408454085540865408754088540895409054091540925409354094540955409654097540985409954100541015410254103541045410554106541075410854109541105411154112541135411454115541165411754118541195412054121541225412354124541255412654127541285412954130541315413254133541345413554136541375413854139541405414154142541435414454145541465414754148541495415054151541525415354154541555415654157541585415954160541615416254163541645416554166541675416854169541705417154172541735417454175541765417754178541795418054181541825418354184541855418654187541885418954190541915419254193541945419554196541975419854199542005420154202542035420454205542065420754208542095421054211542125421354214542155421654217542185421954220542215422254223542245422554226542275422854229542305423154232542335423454235542365423754238542395424054241542425424354244542455424654247542485424954250542515425254253542545425554256542575425854259542605426154262542635426454265542665426754268542695427054271542725427354274542755427654277542785427954280542815428254283542845428554286542875428854289542905429154292542935429454295542965429754298542995430054301543025430354304543055430654307543085430954310543115431254313543145431554316543175431854319543205432154322543235432454325543265432754328543295433054331543325433354334543355433654337543385433954340543415434254343543445434554346543475434854349543505435154352543535435454355543565435754358543595436054361543625436354364543655436654367543685436954370543715437254373543745437554376543775437854379543805438154382543835438454385543865438754388543895439054391543925439354394543955439654397543985439954400544015440254403544045440554406544075440854409544105441154412544135441454415544165441754418544195442054421544225442354424544255442654427544285442954430544315443254433544345443554436544375443854439544405444154442544435444454445544465444754448544495445054451544525445354454544555445654457544585445954460544615446254463544645446554466544675446854469544705447154472544735447454475544765447754478544795448054481544825448354484544855448654487544885448954490544915449254493544945449554496544975449854499545005450154502545035450454505545065450754508545095451054511545125451354514545155451654517545185451954520545215452254523545245452554526545275452854529545305453154532545335453454535545365453754538545395454054541545425454354544545455454654547545485454954550545515455254553545545455554556545575455854559545605456154562545635456454565545665456754568545695457054571545725457354574545755457654577545785457954580545815458254583545845458554586545875458854589545905459154592545935459454595545965459754598545995460054601546025460354604546055460654607546085460954610546115461254613546145461554616546175461854619546205462154622546235462454625546265462754628546295463054631546325463354634546355463654637546385463954640546415464254643546445464554646546475464854649546505465154652546535465454655546565465754658546595466054661546625466354664546655466654667546685466954670546715467254673546745467554676546775467854679546805468154682546835468454685546865468754688546895469054691546925469354694546955469654697546985469954700547015470254703547045470554706547075470854709547105471154712547135471454715547165471754718547195472054721547225472354724547255472654727547285472954730547315473254733547345473554736547375473854739547405474154742547435474454745547465474754748547495475054751547525475354754547555475654757547585475954760547615476254763547645476554766547675476854769547705477154772547735477454775547765477754778547795478054781547825478354784547855478654787547885478954790547915479254793547945479554796547975479854799548005480154802548035480454805548065480754808548095481054811548125481354814548155481654817548185481954820548215482254823548245482554826548275482854829548305483154832548335483454835548365483754838548395484054841548425484354844548455484654847548485484954850548515485254853548545485554856548575485854859548605486154862548635486454865548665486754868548695487054871548725487354874548755487654877548785487954880548815488254883548845488554886548875488854889548905489154892548935489454895548965489754898548995490054901549025490354904549055490654907549085490954910549115491254913549145491554916549175491854919549205492154922549235492454925549265492754928549295493054931549325493354934549355493654937549385493954940549415494254943549445494554946549475494854949549505495154952549535495454955549565495754958549595496054961549625496354964549655496654967549685496954970549715497254973549745497554976549775497854979549805498154982549835498454985549865498754988549895499054991549925499354994549955499654997549985499955000550015500255003550045500555006550075500855009550105501155012550135501455015550165501755018550195502055021550225502355024550255502655027550285502955030550315503255033550345503555036550375503855039550405504155042550435504455045550465504755048550495505055051550525505355054550555505655057550585505955060550615506255063550645506555066550675506855069550705507155072550735507455075550765507755078550795508055081550825508355084550855508655087550885508955090550915509255093550945509555096550975509855099551005510155102551035510455105551065510755108551095511055111551125511355114551155511655117551185511955120551215512255123551245512555126551275512855129551305513155132551335513455135551365513755138551395514055141551425514355144551455514655147551485514955150551515515255153551545515555156551575515855159551605516155162551635516455165551665516755168551695517055171551725517355174551755517655177551785517955180551815518255183551845518555186551875518855189551905519155192551935519455195551965519755198551995520055201552025520355204552055520655207552085520955210552115521255213552145521555216552175521855219552205522155222552235522455225552265522755228552295523055231552325523355234552355523655237552385523955240552415524255243552445524555246552475524855249552505525155252552535525455255552565525755258552595526055261552625526355264552655526655267552685526955270552715527255273552745527555276552775527855279552805528155282552835528455285552865528755288552895529055291552925529355294552955529655297552985529955300553015530255303553045530555306553075530855309553105531155312553135531455315553165531755318553195532055321553225532355324553255532655327553285532955330553315533255333553345533555336553375533855339553405534155342553435534455345553465534755348553495535055351553525535355354553555535655357553585535955360553615536255363553645536555366553675536855369553705537155372553735537455375553765537755378553795538055381553825538355384553855538655387553885538955390553915539255393553945539555396553975539855399554005540155402554035540455405554065540755408554095541055411554125541355414554155541655417554185541955420554215542255423554245542555426554275542855429554305543155432554335543455435554365543755438554395544055441554425544355444554455544655447554485544955450554515545255453554545545555456554575545855459554605546155462554635546455465554665546755468554695547055471554725547355474554755547655477554785547955480554815548255483554845548555486554875548855489554905549155492554935549455495554965549755498554995550055501555025550355504555055550655507555085550955510555115551255513555145551555516555175551855519555205552155522555235552455525555265552755528555295553055531555325553355534555355553655537555385553955540555415554255543555445554555546555475554855549555505555155552555535555455555555565555755558555595556055561555625556355564555655556655567555685556955570555715557255573555745557555576555775557855579555805558155582555835558455585555865558755588555895559055591555925559355594555955559655597555985559955600556015560255603556045560555606556075560855609556105561155612556135561455615556165561755618556195562055621556225562355624556255562655627556285562955630556315563255633556345563555636556375563855639556405564155642556435564455645556465564755648556495565055651556525565355654556555565655657556585565955660556615566255663556645566555666556675566855669556705567155672556735567455675556765567755678556795568055681556825568355684556855568655687556885568955690556915569255693556945569555696556975569855699557005570155702557035570455705557065570755708557095571055711557125571355714557155571655717557185571955720557215572255723557245572555726557275572855729557305573155732557335573455735557365573755738557395574055741557425574355744557455574655747557485574955750557515575255753557545575555756557575575855759557605576155762557635576455765557665576755768557695577055771557725577355774557755577655777557785577955780557815578255783557845578555786557875578855789557905579155792557935579455795557965579755798557995580055801558025580355804558055580655807558085580955810558115581255813558145581555816558175581855819558205582155822558235582455825558265582755828558295583055831558325583355834558355583655837558385583955840558415584255843558445584555846558475584855849558505585155852558535585455855558565585755858558595586055861558625586355864558655586655867558685586955870558715587255873558745587555876558775587855879558805588155882558835588455885558865588755888558895589055891558925589355894558955589655897558985589955900559015590255903559045590555906559075590855909559105591155912559135591455915559165591755918559195592055921559225592355924559255592655927559285592955930559315593255933559345593555936559375593855939559405594155942559435594455945559465594755948559495595055951559525595355954559555595655957559585595955960559615596255963559645596555966559675596855969559705597155972559735597455975559765597755978559795598055981559825598355984559855598655987559885598955990559915599255993559945599555996559975599855999560005600156002560035600456005560065600756008560095601056011560125601356014560155601656017560185601956020560215602256023560245602556026560275602856029560305603156032560335603456035560365603756038560395604056041560425604356044560455604656047560485604956050560515605256053560545605556056560575605856059560605606156062560635606456065560665606756068560695607056071560725607356074560755607656077560785607956080560815608256083560845608556086560875608856089560905609156092560935609456095560965609756098560995610056101561025610356104561055610656107561085610956110561115611256113561145611556116561175611856119561205612156122561235612456125561265612756128561295613056131561325613356134561355613656137561385613956140561415614256143561445614556146561475614856149561505615156152561535615456155561565615756158561595616056161561625616356164561655616656167561685616956170561715617256173561745617556176561775617856179561805618156182561835618456185561865618756188561895619056191561925619356194561955619656197561985619956200562015620256203562045620556206562075620856209562105621156212562135621456215562165621756218562195622056221562225622356224562255622656227562285622956230562315623256233562345623556236562375623856239562405624156242562435624456245562465624756248562495625056251562525625356254562555625656257562585625956260562615626256263562645626556266562675626856269562705627156272562735627456275562765627756278562795628056281562825628356284562855628656287562885628956290562915629256293562945629556296562975629856299563005630156302563035630456305563065630756308563095631056311563125631356314563155631656317563185631956320563215632256323563245632556326563275632856329563305633156332563335633456335563365633756338563395634056341563425634356344563455634656347563485634956350563515635256353563545635556356563575635856359563605636156362563635636456365563665636756368563695637056371563725637356374563755637656377563785637956380563815638256383563845638556386563875638856389563905639156392563935639456395563965639756398563995640056401564025640356404564055640656407564085640956410564115641256413564145641556416564175641856419564205642156422564235642456425564265642756428564295643056431564325643356434564355643656437564385643956440564415644256443564445644556446564475644856449564505645156452564535645456455564565645756458564595646056461564625646356464564655646656467564685646956470564715647256473564745647556476564775647856479564805648156482564835648456485564865648756488564895649056491564925649356494564955649656497564985649956500565015650256503565045650556506565075650856509565105651156512565135651456515565165651756518565195652056521565225652356524565255652656527565285652956530565315653256533565345653556536565375653856539565405654156542565435654456545565465654756548565495655056551565525655356554565555655656557565585655956560565615656256563565645656556566565675656856569565705657156572565735657456575565765657756578565795658056581565825658356584565855658656587565885658956590565915659256593565945659556596565975659856599566005660156602566035660456605566065660756608566095661056611566125661356614566155661656617566185661956620566215662256623566245662556626566275662856629566305663156632566335663456635566365663756638566395664056641566425664356644566455664656647566485664956650566515665256653566545665556656566575665856659566605666156662566635666456665566665666756668566695667056671566725667356674566755667656677566785667956680566815668256683566845668556686566875668856689566905669156692566935669456695566965669756698566995670056701567025670356704567055670656707567085670956710567115671256713567145671556716567175671856719567205672156722567235672456725567265672756728567295673056731567325673356734567355673656737567385673956740567415674256743567445674556746567475674856749567505675156752567535675456755567565675756758567595676056761567625676356764567655676656767567685676956770567715677256773567745677556776567775677856779567805678156782567835678456785567865678756788567895679056791567925679356794567955679656797567985679956800568015680256803568045680556806568075680856809568105681156812568135681456815568165681756818568195682056821568225682356824568255682656827568285682956830568315683256833568345683556836568375683856839568405684156842568435684456845568465684756848568495685056851568525685356854568555685656857568585685956860568615686256863568645686556866568675686856869568705687156872568735687456875568765687756878568795688056881568825688356884568855688656887568885688956890568915689256893568945689556896568975689856899569005690156902569035690456905569065690756908569095691056911569125691356914569155691656917569185691956920569215692256923569245692556926569275692856929569305693156932569335693456935569365693756938569395694056941569425694356944569455694656947569485694956950569515695256953569545695556956569575695856959569605696156962569635696456965569665696756968569695697056971569725697356974569755697656977569785697956980569815698256983569845698556986569875698856989569905699156992569935699456995569965699756998569995700057001570025700357004570055700657007570085700957010570115701257013570145701557016570175701857019570205702157022570235702457025570265702757028570295703057031570325703357034570355703657037570385703957040570415704257043570445704557046570475704857049570505705157052570535705457055570565705757058570595706057061570625706357064570655706657067570685706957070570715707257073570745707557076570775707857079570805708157082570835708457085570865708757088570895709057091570925709357094570955709657097570985709957100571015710257103571045710557106571075710857109571105711157112571135711457115571165711757118571195712057121571225712357124571255712657127571285712957130571315713257133571345713557136571375713857139571405714157142571435714457145571465714757148571495715057151571525715357154571555715657157571585715957160571615716257163571645716557166571675716857169571705717157172571735717457175571765717757178571795718057181571825718357184571855718657187571885718957190571915719257193571945719557196571975719857199572005720157202572035720457205572065720757208572095721057211572125721357214572155721657217572185721957220572215722257223572245722557226572275722857229572305723157232572335723457235572365723757238572395724057241572425724357244572455724657247572485724957250572515725257253572545725557256572575725857259572605726157262572635726457265572665726757268572695727057271572725727357274572755727657277572785727957280572815728257283572845728557286572875728857289572905729157292572935729457295572965729757298572995730057301573025730357304573055730657307573085730957310573115731257313573145731557316573175731857319573205732157322573235732457325573265732757328573295733057331573325733357334573355733657337573385733957340573415734257343573445734557346573475734857349573505735157352573535735457355573565735757358573595736057361573625736357364573655736657367573685736957370573715737257373573745737557376573775737857379573805738157382573835738457385573865738757388573895739057391573925739357394573955739657397573985739957400574015740257403574045740557406574075740857409574105741157412574135741457415574165741757418574195742057421574225742357424574255742657427574285742957430574315743257433574345743557436574375743857439574405744157442574435744457445574465744757448574495745057451574525745357454574555745657457574585745957460574615746257463574645746557466574675746857469574705747157472574735747457475574765747757478574795748057481574825748357484574855748657487574885748957490574915749257493574945749557496574975749857499575005750157502575035750457505575065750757508575095751057511575125751357514575155751657517575185751957520575215752257523575245752557526575275752857529575305753157532575335753457535575365753757538575395754057541575425754357544575455754657547575485754957550575515755257553575545755557556575575755857559575605756157562575635756457565575665756757568575695757057571575725757357574575755757657577575785757957580575815758257583575845758557586575875758857589575905759157592575935759457595575965759757598575995760057601576025760357604576055760657607576085760957610576115761257613576145761557616576175761857619576205762157622576235762457625576265762757628576295763057631576325763357634576355763657637576385763957640576415764257643576445764557646576475764857649576505765157652576535765457655576565765757658576595766057661576625766357664576655766657667576685766957670576715767257673576745767557676576775767857679576805768157682576835768457685576865768757688576895769057691576925769357694576955769657697576985769957700577015770257703577045770557706577075770857709577105771157712577135771457715577165771757718577195772057721577225772357724577255772657727577285772957730577315773257733577345773557736577375773857739577405774157742577435774457745577465774757748577495775057751577525775357754577555775657757577585775957760577615776257763577645776557766577675776857769577705777157772577735777457775577765777757778577795778057781577825778357784577855778657787577885778957790577915779257793577945779557796577975779857799578005780157802578035780457805578065780757808578095781057811578125781357814578155781657817578185781957820578215782257823578245782557826578275782857829578305783157832578335783457835578365783757838578395784057841578425784357844578455784657847578485784957850578515785257853578545785557856578575785857859578605786157862578635786457865578665786757868578695787057871578725787357874578755787657877578785787957880578815788257883578845788557886578875788857889578905789157892578935789457895578965789757898578995790057901579025790357904579055790657907579085790957910579115791257913579145791557916579175791857919579205792157922579235792457925579265792757928579295793057931579325793357934579355793657937579385793957940579415794257943579445794557946579475794857949579505795157952579535795457955579565795757958579595796057961579625796357964579655796657967579685796957970579715797257973579745797557976579775797857979579805798157982579835798457985579865798757988579895799057991579925799357994579955799657997579985799958000580015800258003580045800558006580075800858009580105801158012580135801458015580165801758018580195802058021580225802358024580255802658027580285802958030580315803258033580345803558036580375803858039580405804158042580435804458045580465804758048580495805058051580525805358054580555805658057580585805958060580615806258063580645806558066580675806858069580705807158072580735807458075580765807758078580795808058081580825808358084580855808658087580885808958090580915809258093580945809558096580975809858099581005810158102581035810458105581065810758108581095811058111581125811358114581155811658117581185811958120581215812258123581245812558126581275812858129581305813158132581335813458135581365813758138581395814058141581425814358144581455814658147581485814958150581515815258153581545815558156581575815858159581605816158162581635816458165581665816758168581695817058171581725817358174581755817658177581785817958180581815818258183581845818558186581875818858189581905819158192581935819458195581965819758198581995820058201582025820358204582055820658207582085820958210582115821258213582145821558216582175821858219582205822158222582235822458225582265822758228582295823058231582325823358234582355823658237582385823958240582415824258243582445824558246582475824858249582505825158252582535825458255582565825758258582595826058261582625826358264582655826658267582685826958270582715827258273582745827558276582775827858279582805828158282582835828458285582865828758288582895829058291582925829358294582955829658297582985829958300583015830258303583045830558306583075830858309583105831158312583135831458315583165831758318583195832058321583225832358324583255832658327583285832958330583315833258333583345833558336583375833858339583405834158342583435834458345583465834758348583495835058351583525835358354583555835658357583585835958360583615836258363583645836558366583675836858369583705837158372583735837458375583765837758378583795838058381583825838358384583855838658387583885838958390583915839258393583945839558396583975839858399584005840158402584035840458405584065840758408584095841058411584125841358414584155841658417584185841958420584215842258423584245842558426584275842858429584305843158432584335843458435584365843758438584395844058441584425844358444584455844658447584485844958450584515845258453584545845558456584575845858459584605846158462584635846458465584665846758468584695847058471584725847358474584755847658477584785847958480584815848258483584845848558486584875848858489584905849158492584935849458495584965849758498584995850058501585025850358504585055850658507585085850958510585115851258513585145851558516585175851858519585205852158522585235852458525585265852758528585295853058531585325853358534585355853658537585385853958540585415854258543585445854558546585475854858549585505855158552585535855458555585565855758558585595856058561585625856358564585655856658567585685856958570585715857258573585745857558576585775857858579585805858158582585835858458585585865858758588585895859058591585925859358594585955859658597585985859958600586015860258603586045860558606586075860858609586105861158612586135861458615586165861758618586195862058621586225862358624586255862658627586285862958630586315863258633586345863558636586375863858639586405864158642586435864458645586465864758648586495865058651586525865358654586555865658657586585865958660586615866258663586645866558666586675866858669586705867158672586735867458675586765867758678586795868058681586825868358684586855868658687586885868958690586915869258693586945869558696586975869858699587005870158702587035870458705587065870758708587095871058711587125871358714587155871658717587185871958720587215872258723587245872558726587275872858729587305873158732587335873458735587365873758738587395874058741587425874358744587455874658747587485874958750587515875258753587545875558756587575875858759587605876158762587635876458765587665876758768587695877058771587725877358774587755877658777587785877958780587815878258783587845878558786587875878858789587905879158792587935879458795587965879758798587995880058801588025880358804588055880658807588085880958810588115881258813588145881558816588175881858819588205882158822588235882458825588265882758828588295883058831588325883358834588355883658837588385883958840588415884258843588445884558846588475884858849588505885158852588535885458855588565885758858588595886058861588625886358864588655886658867588685886958870588715887258873588745887558876588775887858879588805888158882588835888458885588865888758888588895889058891588925889358894588955889658897588985889958900589015890258903589045890558906589075890858909589105891158912589135891458915589165891758918589195892058921589225892358924589255892658927589285892958930589315893258933589345893558936589375893858939589405894158942589435894458945589465894758948589495895058951589525895358954589555895658957589585895958960589615896258963589645896558966589675896858969589705897158972589735897458975589765897758978589795898058981589825898358984589855898658987589885898958990589915899258993589945899558996589975899858999590005900159002590035900459005590065900759008590095901059011590125901359014590155901659017590185901959020590215902259023590245902559026590275902859029590305903159032590335903459035590365903759038590395904059041590425904359044590455904659047590485904959050590515905259053590545905559056590575905859059590605906159062590635906459065590665906759068590695907059071590725907359074590755907659077590785907959080590815908259083590845908559086590875908859089590905909159092590935909459095590965909759098590995910059101591025910359104591055910659107591085910959110591115911259113591145911559116591175911859119591205912159122591235912459125591265912759128591295913059131591325913359134591355913659137591385913959140591415914259143591445914559146591475914859149591505915159152591535915459155591565915759158591595916059161591625916359164591655916659167591685916959170591715917259173591745917559176591775917859179591805918159182591835918459185591865918759188591895919059191591925919359194591955919659197591985919959200592015920259203592045920559206592075920859209592105921159212592135921459215592165921759218592195922059221592225922359224592255922659227592285922959230592315923259233592345923559236592375923859239592405924159242592435924459245592465924759248592495925059251592525925359254592555925659257592585925959260592615926259263592645926559266592675926859269592705927159272592735927459275592765927759278592795928059281592825928359284592855928659287592885928959290592915929259293592945929559296592975929859299593005930159302593035930459305593065930759308593095931059311593125931359314593155931659317593185931959320593215932259323593245932559326593275932859329593305933159332593335933459335593365933759338593395934059341593425934359344593455934659347593485934959350593515935259353593545935559356593575935859359593605936159362593635936459365593665936759368593695937059371593725937359374593755937659377593785937959380593815938259383593845938559386593875938859389593905939159392593935939459395593965939759398593995940059401594025940359404594055940659407594085940959410594115941259413594145941559416594175941859419594205942159422594235942459425594265942759428594295943059431594325943359434594355943659437594385943959440594415944259443594445944559446594475944859449594505945159452594535945459455594565945759458594595946059461594625946359464594655946659467594685946959470594715947259473594745947559476594775947859479594805948159482594835948459485594865948759488594895949059491594925949359494594955949659497594985949959500595015950259503595045950559506595075950859509595105951159512595135951459515595165951759518595195952059521595225952359524595255952659527595285952959530595315953259533595345953559536595375953859539595405954159542595435954459545595465954759548595495955059551595525955359554595555955659557595585955959560595615956259563595645956559566595675956859569595705957159572595735957459575595765957759578595795958059581595825958359584595855958659587595885958959590595915959259593595945959559596595975959859599596005960159602596035960459605596065960759608596095961059611596125961359614596155961659617596185961959620596215962259623596245962559626596275962859629596305963159632596335963459635596365963759638596395964059641596425964359644596455964659647596485964959650596515965259653596545965559656596575965859659596605966159662596635966459665596665966759668596695967059671596725967359674596755967659677596785967959680596815968259683596845968559686596875968859689596905969159692596935969459695596965969759698596995970059701597025970359704597055970659707597085970959710597115971259713597145971559716597175971859719597205972159722597235972459725597265972759728597295973059731597325973359734597355973659737597385973959740597415974259743597445974559746597475974859749597505975159752597535975459755597565975759758597595976059761597625976359764597655976659767597685976959770597715977259773597745977559776597775977859779597805978159782597835978459785597865978759788597895979059791597925979359794597955979659797597985979959800598015980259803598045980559806598075980859809598105981159812598135981459815598165981759818598195982059821598225982359824598255982659827598285982959830598315983259833598345983559836598375983859839598405984159842598435984459845598465984759848598495985059851598525985359854598555985659857598585985959860598615986259863598645986559866598675986859869598705987159872598735987459875598765987759878598795988059881598825988359884598855988659887598885988959890598915989259893598945989559896598975989859899599005990159902599035990459905599065990759908599095991059911599125991359914599155991659917599185991959920599215992259923599245992559926599275992859929599305993159932599335993459935599365993759938599395994059941599425994359944599455994659947599485994959950599515995259953599545995559956599575995859959599605996159962599635996459965599665996759968599695997059971599725997359974599755997659977599785997959980599815998259983599845998559986599875998859989599905999159992599935999459995599965999759998599996000060001600026000360004600056000660007600086000960010600116001260013600146001560016600176001860019600206002160022600236002460025600266002760028600296003060031600326003360034600356003660037600386003960040600416004260043600446004560046600476004860049600506005160052600536005460055600566005760058600596006060061600626006360064600656006660067600686006960070600716007260073600746007560076600776007860079600806008160082600836008460085600866008760088600896009060091600926009360094600956009660097600986009960100601016010260103601046010560106601076010860109601106011160112601136011460115601166011760118601196012060121601226012360124601256012660127601286012960130601316013260133601346013560136601376013860139601406014160142601436014460145601466014760148601496015060151601526015360154601556015660157601586015960160601616016260163601646016560166601676016860169601706017160172601736017460175601766017760178601796018060181601826018360184601856018660187601886018960190601916019260193601946019560196601976019860199602006020160202602036020460205602066020760208602096021060211602126021360214602156021660217602186021960220602216022260223602246022560226602276022860229602306023160232602336023460235602366023760238602396024060241602426024360244602456024660247602486024960250602516025260253602546025560256602576025860259602606026160262602636026460265602666026760268602696027060271602726027360274602756027660277602786027960280602816028260283602846028560286602876028860289602906029160292602936029460295602966029760298602996030060301603026030360304603056030660307603086030960310603116031260313603146031560316603176031860319603206032160322603236032460325603266032760328603296033060331603326033360334603356033660337603386033960340603416034260343603446034560346603476034860349603506035160352603536035460355603566035760358603596036060361603626036360364603656036660367603686036960370603716037260373603746037560376603776037860379603806038160382603836038460385603866038760388603896039060391603926039360394603956039660397603986039960400604016040260403604046040560406604076040860409604106041160412604136041460415604166041760418604196042060421604226042360424604256042660427604286042960430604316043260433604346043560436604376043860439604406044160442604436044460445604466044760448604496045060451604526045360454604556045660457604586045960460604616046260463604646046560466604676046860469604706047160472604736047460475604766047760478604796048060481604826048360484604856048660487604886048960490604916049260493604946049560496604976049860499605006050160502605036050460505605066050760508605096051060511605126051360514605156051660517605186051960520605216052260523605246052560526605276052860529605306053160532605336053460535605366053760538605396054060541605426054360544605456054660547605486054960550605516055260553605546055560556605576055860559605606056160562605636056460565605666056760568605696057060571605726057360574605756057660577605786057960580605816058260583605846058560586605876058860589605906059160592605936059460595605966059760598605996060060601606026060360604606056060660607606086060960610606116061260613606146061560616606176061860619606206062160622606236062460625606266062760628606296063060631606326063360634606356063660637606386063960640606416064260643606446064560646606476064860649606506065160652606536065460655606566065760658606596066060661606626066360664606656066660667606686066960670606716067260673606746067560676606776067860679606806068160682606836068460685606866068760688606896069060691606926069360694606956069660697606986069960700607016070260703607046070560706607076070860709607106071160712607136071460715607166071760718607196072060721607226072360724607256072660727607286072960730607316073260733607346073560736607376073860739607406074160742607436074460745607466074760748607496075060751607526075360754607556075660757607586075960760607616076260763607646076560766607676076860769607706077160772607736077460775607766077760778607796078060781607826078360784607856078660787607886078960790607916079260793607946079560796607976079860799608006080160802608036080460805608066080760808608096081060811608126081360814608156081660817608186081960820608216082260823608246082560826608276082860829608306083160832608336083460835608366083760838608396084060841608426084360844608456084660847608486084960850608516085260853608546085560856608576085860859608606086160862608636086460865608666086760868608696087060871608726087360874608756087660877608786087960880608816088260883608846088560886608876088860889608906089160892608936089460895608966089760898608996090060901609026090360904609056090660907609086090960910609116091260913609146091560916609176091860919609206092160922609236092460925609266092760928609296093060931609326093360934609356093660937609386093960940609416094260943609446094560946609476094860949609506095160952609536095460955609566095760958609596096060961609626096360964609656096660967609686096960970609716097260973609746097560976609776097860979609806098160982609836098460985609866098760988609896099060991609926099360994609956099660997609986099961000610016100261003610046100561006610076100861009610106101161012610136101461015610166101761018610196102061021610226102361024610256102661027610286102961030610316103261033610346103561036610376103861039610406104161042610436104461045610466104761048610496105061051610526105361054610556105661057610586105961060610616106261063610646106561066610676106861069610706107161072610736107461075610766107761078610796108061081610826108361084610856108661087610886108961090610916109261093610946109561096610976109861099611006110161102611036110461105611066110761108611096111061111611126111361114611156111661117611186111961120611216112261123611246112561126611276112861129611306113161132611336113461135611366113761138611396114061141611426114361144611456114661147611486114961150611516115261153611546115561156611576115861159611606116161162611636116461165611666116761168611696117061171611726117361174611756117661177611786117961180611816118261183611846118561186611876118861189611906119161192611936119461195611966119761198611996120061201612026120361204612056120661207612086120961210612116121261213612146121561216612176121861219612206122161222612236122461225612266122761228612296123061231612326123361234612356123661237612386123961240612416124261243612446124561246612476124861249612506125161252612536125461255612566125761258612596126061261612626126361264612656126661267612686126961270612716127261273612746127561276612776127861279612806128161282612836128461285612866128761288612896129061291612926129361294612956129661297612986129961300613016130261303613046130561306613076130861309613106131161312613136131461315613166131761318613196132061321613226132361324613256132661327613286132961330613316133261333613346133561336613376133861339613406134161342613436134461345613466134761348613496135061351613526135361354613556135661357613586135961360613616136261363613646136561366613676136861369613706137161372613736137461375613766137761378613796138061381613826138361384613856138661387613886138961390613916139261393613946139561396613976139861399614006140161402614036140461405614066140761408614096141061411614126141361414614156141661417614186141961420614216142261423614246142561426614276142861429614306143161432614336143461435614366143761438614396144061441614426144361444614456144661447614486144961450614516145261453614546145561456614576145861459614606146161462614636146461465614666146761468614696147061471614726147361474614756147661477614786147961480614816148261483614846148561486614876148861489614906149161492614936149461495614966149761498614996150061501615026150361504615056150661507615086150961510615116151261513615146151561516615176151861519615206152161522615236152461525615266152761528615296153061531615326153361534615356153661537615386153961540615416154261543615446154561546615476154861549615506155161552615536155461555615566155761558615596156061561615626156361564615656156661567615686156961570615716157261573615746157561576615776157861579615806158161582615836158461585615866158761588615896159061591615926159361594615956159661597615986159961600616016160261603616046160561606616076160861609616106161161612616136161461615616166161761618616196162061621616226162361624616256162661627616286162961630616316163261633616346163561636616376163861639616406164161642616436164461645616466164761648616496165061651616526165361654616556165661657616586165961660616616166261663616646166561666616676166861669616706167161672616736167461675616766167761678616796168061681616826168361684616856168661687616886168961690616916169261693616946169561696616976169861699617006170161702617036170461705617066170761708617096171061711617126171361714617156171661717617186171961720617216172261723617246172561726617276172861729617306173161732617336173461735617366173761738617396174061741617426174361744617456174661747617486174961750617516175261753617546175561756617576175861759617606176161762617636176461765617666176761768617696177061771617726177361774617756177661777617786177961780617816178261783617846178561786617876178861789617906179161792617936179461795617966179761798617996180061801618026180361804618056180661807618086180961810618116181261813618146181561816618176181861819618206182161822618236182461825618266182761828618296183061831618326183361834618356183661837618386183961840618416184261843618446184561846618476184861849618506185161852618536185461855618566185761858618596186061861618626186361864618656186661867618686186961870618716187261873618746187561876618776187861879618806188161882618836188461885618866188761888618896189061891618926189361894618956189661897618986189961900619016190261903619046190561906619076190861909619106191161912619136191461915619166191761918619196192061921619226192361924619256192661927619286192961930619316193261933619346193561936619376193861939619406194161942619436194461945619466194761948619496195061951619526195361954619556195661957619586195961960619616196261963619646196561966619676196861969619706197161972619736197461975619766197761978619796198061981619826198361984619856198661987619886198961990619916199261993619946199561996619976199861999620006200162002620036200462005620066200762008620096201062011620126201362014620156201662017620186201962020620216202262023620246202562026620276202862029620306203162032620336203462035620366203762038620396204062041620426204362044620456204662047620486204962050620516205262053620546205562056620576205862059620606206162062620636206462065620666206762068620696207062071620726207362074620756207662077620786207962080620816208262083620846208562086620876208862089620906209162092620936209462095620966209762098620996210062101621026210362104621056210662107621086210962110621116211262113621146211562116621176211862119621206212162122621236212462125621266212762128621296213062131621326213362134621356213662137621386213962140621416214262143621446214562146621476214862149621506215162152621536215462155621566215762158621596216062161621626216362164621656216662167621686216962170621716217262173621746217562176621776217862179621806218162182621836218462185621866218762188621896219062191621926219362194621956219662197621986219962200622016220262203622046220562206622076220862209622106221162212622136221462215622166221762218622196222062221622226222362224622256222662227622286222962230622316223262233622346223562236622376223862239622406224162242622436224462245622466224762248622496225062251622526225362254622556225662257622586225962260622616226262263622646226562266622676226862269622706227162272622736227462275622766227762278622796228062281622826228362284622856228662287622886228962290622916229262293622946229562296622976229862299623006230162302623036230462305623066230762308623096231062311623126231362314623156231662317623186231962320623216232262323623246232562326623276232862329623306233162332623336233462335623366233762338623396234062341623426234362344623456234662347623486234962350623516235262353623546235562356623576235862359623606236162362623636236462365623666236762368623696237062371623726237362374623756237662377623786237962380623816238262383623846238562386623876238862389623906239162392623936239462395623966239762398623996240062401624026240362404624056240662407624086240962410624116241262413624146241562416624176241862419624206242162422624236242462425624266242762428624296243062431624326243362434624356243662437624386243962440624416244262443624446244562446624476244862449624506245162452624536245462455624566245762458624596246062461624626246362464624656246662467624686246962470624716247262473624746247562476624776247862479624806248162482624836248462485624866248762488624896249062491624926249362494624956249662497624986249962500625016250262503625046250562506625076250862509625106251162512625136251462515625166251762518625196252062521625226252362524625256252662527625286252962530625316253262533625346253562536625376253862539625406254162542625436254462545625466254762548625496255062551625526255362554625556255662557625586255962560625616256262563625646256562566625676256862569625706257162572625736257462575625766257762578625796258062581625826258362584625856258662587625886258962590625916259262593625946259562596625976259862599626006260162602626036260462605626066260762608626096261062611626126261362614626156261662617626186261962620626216262262623626246262562626626276262862629626306263162632626336263462635626366263762638626396264062641626426264362644626456264662647626486264962650626516265262653626546265562656626576265862659626606266162662626636266462665626666266762668626696267062671626726267362674626756267662677626786267962680626816268262683626846268562686626876268862689626906269162692626936269462695626966269762698626996270062701627026270362704627056270662707627086270962710627116271262713627146271562716627176271862719627206272162722627236272462725627266272762728627296273062731627326273362734627356273662737627386273962740627416274262743627446274562746627476274862749627506275162752627536275462755627566275762758627596276062761627626276362764627656276662767627686276962770627716277262773627746277562776627776277862779627806278162782627836278462785627866278762788627896279062791627926279362794627956279662797627986279962800628016280262803628046280562806628076280862809628106281162812628136281462815628166281762818628196282062821628226282362824628256282662827628286282962830628316283262833628346283562836628376283862839628406284162842628436284462845628466284762848628496285062851628526285362854628556285662857628586285962860628616286262863628646286562866628676286862869628706287162872628736287462875628766287762878628796288062881628826288362884628856288662887628886288962890628916289262893628946289562896628976289862899629006290162902629036290462905629066290762908629096291062911629126291362914629156291662917629186291962920629216292262923629246292562926629276292862929629306293162932629336293462935629366293762938629396294062941629426294362944629456294662947629486294962950629516295262953629546295562956629576295862959629606296162962629636296462965629666296762968629696297062971629726297362974629756297662977629786297962980629816298262983629846298562986629876298862989629906299162992629936299462995629966299762998629996300063001630026300363004630056300663007630086300963010630116301263013630146301563016630176301863019630206302163022630236302463025630266302763028630296303063031630326303363034630356303663037630386303963040630416304263043630446304563046630476304863049630506305163052630536305463055630566305763058630596306063061630626306363064630656306663067630686306963070630716307263073630746307563076630776307863079630806308163082630836308463085630866308763088630896309063091630926309363094630956309663097630986309963100631016310263103631046310563106631076310863109631106311163112631136311463115631166311763118631196312063121631226312363124631256312663127631286312963130631316313263133631346313563136631376313863139631406314163142631436314463145631466314763148631496315063151631526315363154631556315663157631586315963160631616316263163631646316563166631676316863169631706317163172631736317463175631766317763178631796318063181631826318363184631856318663187631886318963190631916319263193631946319563196631976319863199632006320163202632036320463205632066320763208632096321063211632126321363214632156321663217632186321963220632216322263223632246322563226632276322863229632306323163232632336323463235632366323763238632396324063241632426324363244632456324663247632486324963250632516325263253632546325563256632576325863259632606326163262632636326463265632666326763268632696327063271632726327363274632756327663277632786327963280632816328263283632846328563286632876328863289632906329163292632936329463295632966329763298632996330063301633026330363304633056330663307633086330963310633116331263313633146331563316633176331863319633206332163322633236332463325633266332763328633296333063331633326333363334633356333663337633386333963340633416334263343633446334563346633476334863349633506335163352633536335463355633566335763358633596336063361633626336363364633656336663367633686336963370633716337263373633746337563376633776337863379633806338163382633836338463385633866338763388633896339063391633926339363394633956339663397633986339963400634016340263403634046340563406634076340863409634106341163412634136341463415634166341763418634196342063421634226342363424634256342663427634286342963430634316343263433634346343563436634376343863439634406344163442634436344463445634466344763448634496345063451634526345363454634556345663457634586345963460634616346263463634646346563466634676346863469634706347163472634736347463475634766347763478634796348063481634826348363484634856348663487634886348963490634916349263493634946349563496634976349863499635006350163502635036350463505635066350763508635096351063511635126351363514635156351663517635186351963520635216352263523635246352563526635276352863529635306353163532635336353463535635366353763538635396354063541635426354363544635456354663547635486354963550635516355263553635546355563556635576355863559635606356163562635636356463565635666356763568635696357063571635726357363574635756357663577635786357963580635816358263583635846358563586635876358863589635906359163592635936359463595635966359763598635996360063601636026360363604636056360663607636086360963610636116361263613636146361563616636176361863619636206362163622636236362463625636266362763628636296363063631636326363363634636356363663637636386363963640636416364263643636446364563646636476364863649636506365163652636536365463655636566365763658636596366063661636626366363664636656366663667636686366963670636716367263673636746367563676636776367863679636806368163682636836368463685636866368763688636896369063691636926369363694636956369663697636986369963700637016370263703637046370563706637076370863709637106371163712637136371463715637166371763718637196372063721637226372363724637256372663727637286372963730637316373263733637346373563736637376373863739637406374163742637436374463745637466374763748637496375063751637526375363754637556375663757637586375963760637616376263763637646376563766637676376863769637706377163772637736377463775637766377763778637796378063781637826378363784637856378663787637886378963790637916379263793637946379563796637976379863799638006380163802638036380463805638066380763808638096381063811638126381363814638156381663817638186381963820638216382263823638246382563826638276382863829638306383163832638336383463835638366383763838638396384063841638426384363844638456384663847638486384963850638516385263853638546385563856638576385863859638606386163862638636386463865638666386763868638696387063871638726387363874638756387663877638786387963880638816388263883638846388563886638876388863889638906389163892638936389463895638966389763898638996390063901639026390363904639056390663907639086390963910639116391263913639146391563916639176391863919639206392163922639236392463925639266392763928639296393063931639326393363934639356393663937639386393963940639416394263943639446394563946639476394863949639506395163952639536395463955639566395763958639596396063961639626396363964639656396663967639686396963970639716397263973639746397563976639776397863979639806398163982639836398463985639866398763988639896399063991639926399363994639956399663997639986399964000640016400264003640046400564006640076400864009640106401164012640136401464015640166401764018640196402064021640226402364024640256402664027640286402964030640316403264033640346403564036640376403864039640406404164042640436404464045640466404764048640496405064051640526405364054640556405664057640586405964060640616406264063640646406564066640676406864069640706407164072640736407464075640766407764078640796408064081640826408364084640856408664087640886408964090640916409264093640946409564096640976409864099641006410164102641036410464105641066410764108641096411064111641126411364114641156411664117641186411964120641216412264123641246412564126641276412864129641306413164132641336413464135641366413764138641396414064141641426414364144641456414664147641486414964150641516415264153641546415564156641576415864159641606416164162641636416464165641666416764168641696417064171641726417364174641756417664177641786417964180641816418264183641846418564186641876418864189641906419164192641936419464195641966419764198641996420064201642026420364204642056420664207642086420964210642116421264213642146421564216642176421864219642206422164222642236422464225642266422764228642296423064231642326423364234642356423664237642386423964240642416424264243642446424564246642476424864249642506425164252642536425464255642566425764258642596426064261642626426364264642656426664267642686426964270642716427264273642746427564276642776427864279642806428164282642836428464285642866428764288642896429064291642926429364294642956429664297642986429964300643016430264303643046430564306643076430864309643106431164312643136431464315643166431764318643196432064321643226432364324643256432664327643286432964330643316433264333643346433564336643376433864339643406434164342643436434464345643466434764348643496435064351643526435364354643556435664357643586435964360643616436264363643646436564366643676436864369643706437164372643736437464375643766437764378643796438064381643826438364384643856438664387643886438964390643916439264393643946439564396643976439864399644006440164402644036440464405644066440764408644096441064411644126441364414644156441664417644186441964420644216442264423644246442564426644276442864429644306443164432644336443464435644366443764438644396444064441644426444364444644456444664447644486444964450644516445264453644546445564456644576445864459644606446164462644636446464465644666446764468644696447064471644726447364474644756447664477644786447964480644816448264483644846448564486644876448864489644906449164492644936449464495644966449764498644996450064501645026450364504645056450664507645086450964510645116451264513645146451564516645176451864519645206452164522645236452464525645266452764528645296453064531645326453364534645356453664537645386453964540645416454264543645446454564546645476454864549645506455164552645536455464555645566455764558645596456064561645626456364564645656456664567645686456964570645716457264573645746457564576645776457864579645806458164582645836458464585645866458764588645896459064591645926459364594645956459664597645986459964600646016460264603646046460564606646076460864609646106461164612646136461464615646166461764618646196462064621646226462364624646256462664627646286462964630646316463264633646346463564636646376463864639646406464164642646436464464645646466464764648646496465064651646526465364654646556465664657646586465964660646616466264663646646466564666646676466864669646706467164672646736467464675646766467764678646796468064681646826468364684646856468664687646886468964690646916469264693646946469564696646976469864699647006470164702647036470464705647066470764708647096471064711647126471364714647156471664717647186471964720647216472264723647246472564726647276472864729647306473164732647336473464735647366473764738647396474064741647426474364744647456474664747647486474964750647516475264753647546475564756647576475864759647606476164762647636476464765647666476764768647696477064771647726477364774647756477664777647786477964780647816478264783647846478564786647876478864789647906479164792647936479464795647966479764798647996480064801648026480364804648056480664807648086480964810648116481264813648146481564816648176481864819648206482164822648236482464825648266482764828648296483064831648326483364834648356483664837648386483964840648416484264843648446484564846648476484864849648506485164852648536485464855648566485764858648596486064861648626486364864648656486664867648686486964870648716487264873648746487564876648776487864879648806488164882648836488464885648866488764888648896489064891648926489364894648956489664897648986489964900649016490264903649046490564906649076490864909649106491164912649136491464915649166491764918649196492064921649226492364924649256492664927649286492964930649316493264933649346493564936649376493864939649406494164942649436494464945649466494764948649496495064951649526495364954649556495664957649586495964960649616496264963649646496564966649676496864969649706497164972649736497464975649766497764978649796498064981649826498364984649856498664987649886498964990649916499264993649946499564996649976499864999650006500165002650036500465005650066500765008650096501065011650126501365014650156501665017650186501965020650216502265023650246502565026650276502865029650306503165032650336503465035650366503765038650396504065041650426504365044650456504665047650486504965050650516505265053650546505565056650576505865059650606506165062650636506465065650666506765068650696507065071650726507365074650756507665077650786507965080650816508265083650846508565086650876508865089650906509165092650936509465095650966509765098650996510065101651026510365104651056510665107651086510965110651116511265113651146511565116651176511865119651206512165122651236512465125651266512765128651296513065131651326513365134651356513665137651386513965140651416514265143651446514565146651476514865149651506515165152651536515465155651566515765158651596516065161651626516365164651656516665167651686516965170651716517265173651746517565176651776517865179651806518165182651836518465185651866518765188651896519065191651926519365194651956519665197651986519965200652016520265203652046520565206652076520865209652106521165212652136521465215652166521765218652196522065221652226522365224652256522665227652286522965230652316523265233652346523565236652376523865239652406524165242652436524465245652466524765248652496525065251652526525365254652556525665257652586525965260652616526265263652646526565266652676526865269652706527165272652736527465275652766527765278652796528065281652826528365284652856528665287652886528965290652916529265293652946529565296652976529865299653006530165302653036530465305653066530765308653096531065311653126531365314653156531665317653186531965320653216532265323653246532565326653276532865329653306533165332653336533465335653366533765338653396534065341653426534365344653456534665347653486534965350653516535265353653546535565356653576535865359653606536165362653636536465365653666536765368653696537065371653726537365374653756537665377653786537965380653816538265383653846538565386653876538865389653906539165392653936539465395653966539765398653996540065401654026540365404654056540665407654086540965410654116541265413654146541565416654176541865419654206542165422654236542465425654266542765428654296543065431654326543365434654356543665437654386543965440654416544265443654446544565446654476544865449654506545165452654536545465455654566545765458654596546065461654626546365464654656546665467654686546965470654716547265473654746547565476654776547865479654806548165482654836548465485654866548765488654896549065491654926549365494654956549665497654986549965500655016550265503655046550565506655076550865509655106551165512655136551465515655166551765518655196552065521655226552365524655256552665527655286552965530655316553265533655346553565536655376553865539655406554165542655436554465545655466554765548655496555065551655526555365554655556555665557655586555965560655616556265563655646556565566655676556865569655706557165572655736557465575655766557765578655796558065581655826558365584655856558665587655886558965590655916559265593655946559565596655976559865599656006560165602656036560465605656066560765608656096561065611656126561365614656156561665617656186561965620656216562265623656246562565626656276562865629656306563165632656336563465635656366563765638656396564065641656426564365644656456564665647656486564965650656516565265653656546565565656656576565865659656606566165662656636566465665656666566765668656696567065671656726567365674656756567665677656786567965680656816568265683656846568565686656876568865689656906569165692656936569465695656966569765698656996570065701657026570365704657056570665707657086570965710657116571265713657146571565716657176571865719657206572165722657236572465725657266572765728657296573065731657326573365734657356573665737657386573965740657416574265743657446574565746657476574865749657506575165752657536575465755657566575765758657596576065761657626576365764657656576665767657686576965770657716577265773657746577565776657776577865779657806578165782657836578465785657866578765788657896579065791657926579365794657956579665797657986579965800658016580265803658046580565806658076580865809658106581165812658136581465815658166581765818658196582065821658226582365824658256582665827658286582965830658316583265833658346583565836658376583865839658406584165842658436584465845658466584765848658496585065851658526585365854658556585665857658586585965860658616586265863658646586565866658676586865869658706587165872658736587465875658766587765878658796588065881658826588365884658856588665887658886588965890658916589265893658946589565896658976589865899659006590165902659036590465905659066590765908659096591065911659126591365914659156591665917659186591965920659216592265923659246592565926659276592865929659306593165932659336593465935659366593765938659396594065941659426594365944659456594665947659486594965950659516595265953659546595565956659576595865959659606596165962659636596465965659666596765968659696597065971659726597365974659756597665977659786597965980659816598265983659846598565986659876598865989659906599165992659936599465995659966599765998659996600066001660026600366004660056600666007660086600966010660116601266013660146601566016660176601866019660206602166022660236602466025660266602766028660296603066031660326603366034660356603666037660386603966040660416604266043660446604566046660476604866049660506605166052660536605466055660566605766058660596606066061660626606366064660656606666067660686606966070660716607266073660746607566076660776607866079660806608166082660836608466085660866608766088660896609066091660926609366094660956609666097660986609966100661016610266103661046610566106661076610866109661106611166112661136611466115661166611766118661196612066121661226612366124661256612666127661286612966130661316613266133661346613566136661376613866139661406614166142661436614466145661466614766148661496615066151661526615366154661556615666157661586615966160661616616266163661646616566166661676616866169661706617166172661736617466175661766617766178661796618066181661826618366184661856618666187661886618966190661916619266193661946619566196661976619866199662006620166202662036620466205662066620766208662096621066211662126621366214662156621666217662186621966220662216622266223662246622566226662276622866229662306623166232662336623466235662366623766238662396624066241662426624366244662456624666247662486624966250662516625266253662546625566256662576625866259662606626166262662636626466265662666626766268662696627066271662726627366274662756627666277662786627966280662816628266283662846628566286662876628866289662906629166292662936629466295662966629766298662996630066301663026630366304663056630666307663086630966310663116631266313663146631566316663176631866319663206632166322663236632466325663266632766328663296633066331663326633366334663356633666337663386633966340663416634266343663446634566346663476634866349663506635166352663536635466355663566635766358663596636066361663626636366364663656636666367663686636966370663716637266373663746637566376663776637866379663806638166382663836638466385663866638766388663896639066391663926639366394663956639666397663986639966400664016640266403664046640566406664076640866409664106641166412664136641466415664166641766418664196642066421664226642366424664256642666427664286642966430664316643266433664346643566436664376643866439664406644166442664436644466445664466644766448664496645066451664526645366454664556645666457664586645966460664616646266463664646646566466664676646866469664706647166472664736647466475664766647766478664796648066481664826648366484664856648666487664886648966490664916649266493664946649566496664976649866499665006650166502665036650466505665066650766508665096651066511665126651366514665156651666517665186651966520665216652266523665246652566526665276652866529665306653166532665336653466535665366653766538665396654066541665426654366544665456654666547665486654966550665516655266553665546655566556665576655866559665606656166562665636656466565665666656766568665696657066571665726657366574665756657666577665786657966580665816658266583665846658566586665876658866589665906659166592665936659466595665966659766598665996660066601666026660366604666056660666607666086660966610666116661266613666146661566616666176661866619666206662166622666236662466625666266662766628666296663066631666326663366634666356663666637666386663966640666416664266643666446664566646666476664866649666506665166652666536665466655666566665766658666596666066661666626666366664666656666666667666686666966670666716667266673666746667566676666776667866679666806668166682666836668466685666866668766688666896669066691666926669366694666956669666697666986669966700667016670266703667046670566706667076670866709667106671166712667136671466715667166671766718667196672066721667226672366724667256672666727667286672966730667316673266733667346673566736667376673866739667406674166742667436674466745667466674766748667496675066751667526675366754667556675666757667586675966760667616676266763667646676566766667676676866769667706677166772667736677466775667766677766778667796678066781667826678366784667856678666787667886678966790667916679266793667946679566796667976679866799668006680166802668036680466805668066680766808668096681066811668126681366814668156681666817668186681966820668216682266823668246682566826668276682866829668306683166832668336683466835668366683766838668396684066841668426684366844668456684666847668486684966850668516685266853668546685566856668576685866859668606686166862668636686466865668666686766868668696687066871668726687366874668756687666877668786687966880668816688266883668846688566886668876688866889668906689166892668936689466895668966689766898668996690066901669026690366904669056690666907669086690966910669116691266913669146691566916669176691866919669206692166922669236692466925669266692766928669296693066931669326693366934669356693666937669386693966940669416694266943669446694566946669476694866949669506695166952669536695466955669566695766958669596696066961669626696366964669656696666967669686696966970669716697266973669746697566976669776697866979669806698166982669836698466985669866698766988669896699066991669926699366994669956699666997669986699967000670016700267003670046700567006670076700867009670106701167012670136701467015670166701767018670196702067021670226702367024670256702667027670286702967030670316703267033670346703567036670376703867039670406704167042670436704467045670466704767048670496705067051670526705367054670556705667057670586705967060670616706267063670646706567066670676706867069670706707167072670736707467075670766707767078670796708067081670826708367084670856708667087670886708967090670916709267093670946709567096670976709867099671006710167102671036710467105671066710767108671096711067111671126711367114671156711667117671186711967120671216712267123671246712567126671276712867129671306713167132671336713467135671366713767138671396714067141671426714367144671456714667147671486714967150671516715267153671546715567156671576715867159671606716167162671636716467165671666716767168671696717067171671726717367174671756717667177671786717967180671816718267183671846718567186671876718867189671906719167192671936719467195671966719767198671996720067201672026720367204672056720667207672086720967210672116721267213672146721567216672176721867219672206722167222672236722467225672266722767228672296723067231672326723367234672356723667237672386723967240672416724267243672446724567246672476724867249672506725167252672536725467255672566725767258672596726067261672626726367264672656726667267672686726967270672716727267273672746727567276672776727867279672806728167282672836728467285672866728767288672896729067291672926729367294672956729667297672986729967300673016730267303673046730567306673076730867309673106731167312673136731467315673166731767318673196732067321673226732367324673256732667327673286732967330673316733267333673346733567336673376733867339673406734167342673436734467345673466734767348673496735067351673526735367354673556735667357673586735967360673616736267363673646736567366673676736867369673706737167372673736737467375673766737767378673796738067381673826738367384673856738667387673886738967390673916739267393673946739567396673976739867399674006740167402674036740467405674066740767408674096741067411674126741367414674156741667417674186741967420674216742267423674246742567426674276742867429674306743167432674336743467435674366743767438674396744067441674426744367444674456744667447674486744967450674516745267453674546745567456674576745867459674606746167462674636746467465674666746767468674696747067471674726747367474674756747667477674786747967480674816748267483674846748567486674876748867489674906749167492674936749467495674966749767498674996750067501675026750367504675056750667507675086750967510675116751267513675146751567516675176751867519675206752167522675236752467525675266752767528675296753067531675326753367534675356753667537675386753967540675416754267543675446754567546675476754867549675506755167552675536755467555675566755767558675596756067561675626756367564675656756667567675686756967570675716757267573675746757567576675776757867579675806758167582675836758467585675866758767588675896759067591675926759367594675956759667597675986759967600676016760267603676046760567606676076760867609676106761167612676136761467615676166761767618676196762067621676226762367624676256762667627676286762967630676316763267633676346763567636676376763867639676406764167642676436764467645676466764767648676496765067651676526765367654676556765667657676586765967660676616766267663676646766567666676676766867669676706767167672676736767467675676766767767678676796768067681676826768367684676856768667687676886768967690676916769267693676946769567696676976769867699677006770167702677036770467705677066770767708677096771067711677126771367714677156771667717677186771967720677216772267723677246772567726677276772867729677306773167732677336773467735677366773767738677396774067741677426774367744677456774667747677486774967750677516775267753677546775567756677576775867759677606776167762677636776467765677666776767768677696777067771677726777367774677756777667777677786777967780677816778267783677846778567786677876778867789677906779167792677936779467795677966779767798677996780067801678026780367804678056780667807678086780967810678116781267813678146781567816678176781867819678206782167822678236782467825678266782767828678296783067831678326783367834678356783667837678386783967840678416784267843678446784567846678476784867849678506785167852678536785467855678566785767858678596786067861678626786367864678656786667867678686786967870678716787267873678746787567876678776787867879678806788167882678836788467885678866788767888678896789067891678926789367894678956789667897678986789967900679016790267903679046790567906679076790867909679106791167912679136791467915679166791767918679196792067921679226792367924679256792667927679286792967930679316793267933679346793567936679376793867939679406794167942679436794467945679466794767948679496795067951679526795367954679556795667957679586795967960679616796267963679646796567966679676796867969679706797167972679736797467975679766797767978679796798067981679826798367984679856798667987679886798967990679916799267993679946799567996679976799867999680006800168002680036800468005680066800768008680096801068011680126801368014680156801668017680186801968020680216802268023680246802568026680276802868029680306803168032680336803468035680366803768038680396804068041680426804368044680456804668047680486804968050680516805268053680546805568056680576805868059680606806168062680636806468065680666806768068680696807068071680726807368074680756807668077680786807968080680816808268083680846808568086680876808868089680906809168092680936809468095680966809768098680996810068101681026810368104681056810668107681086810968110681116811268113681146811568116681176811868119681206812168122681236812468125681266812768128681296813068131681326813368134681356813668137681386813968140681416814268143681446814568146681476814868149681506815168152681536815468155681566815768158681596816068161681626816368164681656816668167681686816968170681716817268173681746817568176681776817868179681806818168182681836818468185681866818768188681896819068191681926819368194681956819668197681986819968200682016820268203682046820568206682076820868209682106821168212682136821468215682166821768218682196822068221682226822368224682256822668227682286822968230682316823268233682346823568236682376823868239682406824168242682436824468245682466824768248682496825068251682526825368254682556825668257682586825968260682616826268263682646826568266682676826868269682706827168272682736827468275682766827768278682796828068281682826828368284682856828668287682886828968290682916829268293682946829568296682976829868299683006830168302683036830468305683066830768308683096831068311683126831368314683156831668317683186831968320683216832268323683246832568326683276832868329683306833168332683336833468335683366833768338683396834068341683426834368344683456834668347683486834968350683516835268353683546835568356683576835868359683606836168362683636836468365683666836768368683696837068371683726837368374683756837668377683786837968380683816838268383683846838568386683876838868389683906839168392683936839468395683966839768398683996840068401684026840368404684056840668407684086840968410684116841268413684146841568416684176841868419684206842168422684236842468425684266842768428684296843068431684326843368434684356843668437684386843968440684416844268443684446844568446684476844868449684506845168452684536845468455684566845768458684596846068461684626846368464684656846668467684686846968470684716847268473684746847568476684776847868479684806848168482684836848468485684866848768488684896849068491684926849368494684956849668497684986849968500685016850268503685046850568506685076850868509685106851168512685136851468515685166851768518685196852068521685226852368524685256852668527685286852968530685316853268533685346853568536685376853868539685406854168542685436854468545685466854768548685496855068551685526855368554685556855668557685586855968560685616856268563685646856568566685676856868569685706857168572685736857468575685766857768578685796858068581685826858368584685856858668587685886858968590685916859268593685946859568596685976859868599686006860168602686036860468605686066860768608686096861068611686126861368614686156861668617686186861968620686216862268623686246862568626686276862868629686306863168632686336863468635686366863768638686396864068641686426864368644686456864668647686486864968650686516865268653686546865568656686576865868659686606866168662686636866468665686666866768668686696867068671686726867368674686756867668677686786867968680686816868268683686846868568686686876868868689686906869168692686936869468695686966869768698686996870068701687026870368704687056870668707687086870968710687116871268713687146871568716687176871868719687206872168722687236872468725687266872768728687296873068731687326873368734687356873668737687386873968740687416874268743687446874568746687476874868749687506875168752687536875468755687566875768758687596876068761687626876368764687656876668767687686876968770687716877268773687746877568776687776877868779687806878168782687836878468785687866878768788687896879068791687926879368794687956879668797687986879968800688016880268803688046880568806688076880868809688106881168812688136881468815688166881768818688196882068821688226882368824688256882668827688286882968830688316883268833688346883568836688376883868839688406884168842688436884468845688466884768848688496885068851688526885368854688556885668857688586885968860688616886268863688646886568866688676886868869688706887168872688736887468875688766887768878688796888068881688826888368884688856888668887688886888968890688916889268893688946889568896688976889868899689006890168902689036890468905689066890768908689096891068911689126891368914689156891668917689186891968920689216892268923689246892568926689276892868929689306893168932689336893468935689366893768938689396894068941689426894368944689456894668947689486894968950689516895268953689546895568956689576895868959689606896168962689636896468965689666896768968689696897068971689726897368974689756897668977689786897968980689816898268983689846898568986689876898868989689906899168992689936899468995689966899768998689996900069001690026900369004690056900669007690086900969010690116901269013690146901569016690176901869019690206902169022690236902469025690266902769028690296903069031690326903369034690356903669037690386903969040690416904269043690446904569046690476904869049690506905169052690536905469055690566905769058690596906069061690626906369064690656906669067690686906969070690716907269073690746907569076690776907869079690806908169082690836908469085690866908769088690896909069091690926909369094690956909669097690986909969100691016910269103691046910569106691076910869109691106911169112691136911469115691166911769118691196912069121691226912369124691256912669127691286912969130691316913269133691346913569136691376913869139691406914169142691436914469145691466914769148691496915069151691526915369154691556915669157691586915969160691616916269163691646916569166691676916869169691706917169172691736917469175691766917769178691796918069181691826918369184691856918669187691886918969190691916919269193691946919569196691976919869199692006920169202692036920469205692066920769208692096921069211692126921369214692156921669217692186921969220692216922269223692246922569226692276922869229692306923169232692336923469235692366923769238692396924069241692426924369244692456924669247692486924969250692516925269253692546925569256692576925869259692606926169262692636926469265692666926769268692696927069271692726927369274692756927669277692786927969280692816928269283692846928569286692876928869289692906929169292692936929469295692966929769298692996930069301693026930369304693056930669307693086930969310693116931269313693146931569316693176931869319693206932169322693236932469325693266932769328693296933069331693326933369334693356933669337693386933969340693416934269343693446934569346693476934869349693506935169352693536935469355693566935769358693596936069361693626936369364693656936669367693686936969370693716937269373693746937569376693776937869379693806938169382693836938469385693866938769388693896939069391693926939369394693956939669397693986939969400694016940269403694046940569406694076940869409694106941169412694136941469415694166941769418694196942069421694226942369424694256942669427694286942969430694316943269433694346943569436694376943869439694406944169442694436944469445694466944769448694496945069451694526945369454694556945669457694586945969460694616946269463694646946569466694676946869469694706947169472694736947469475694766947769478694796948069481694826948369484694856948669487694886948969490694916949269493694946949569496694976949869499695006950169502695036950469505695066950769508695096951069511695126951369514695156951669517695186951969520695216952269523695246952569526695276952869529695306953169532695336953469535695366953769538695396954069541695426954369544695456954669547695486954969550695516955269553695546955569556695576955869559695606956169562695636956469565695666956769568695696957069571695726957369574695756957669577695786957969580695816958269583695846958569586695876958869589695906959169592695936959469595695966959769598695996960069601696026960369604696056960669607696086960969610696116961269613696146961569616696176961869619696206962169622696236962469625696266962769628696296963069631696326963369634696356963669637696386963969640696416964269643696446964569646696476964869649696506965169652696536965469655696566965769658696596966069661696626966369664696656966669667696686966969670696716967269673696746967569676696776967869679696806968169682696836968469685696866968769688696896969069691696926969369694696956969669697696986969969700697016970269703697046970569706697076970869709697106971169712697136971469715697166971769718697196972069721697226972369724697256972669727697286972969730697316973269733697346973569736697376973869739697406974169742697436974469745697466974769748697496975069751697526975369754697556975669757697586975969760697616976269763697646976569766697676976869769697706977169772697736977469775697766977769778697796978069781697826978369784697856978669787697886978969790697916979269793697946979569796697976979869799698006980169802698036980469805698066980769808698096981069811698126981369814698156981669817698186981969820698216982269823698246982569826698276982869829698306983169832698336983469835698366983769838698396984069841698426984369844698456984669847698486984969850698516985269853698546985569856698576985869859698606986169862698636986469865698666986769868698696987069871698726987369874698756987669877698786987969880698816988269883698846988569886698876988869889698906989169892698936989469895698966989769898698996990069901699026990369904699056990669907699086990969910699116991269913699146991569916699176991869919699206992169922699236992469925699266992769928699296993069931699326993369934699356993669937699386993969940699416994269943699446994569946699476994869949699506995169952699536995469955699566995769958699596996069961699626996369964699656996669967699686996969970699716997269973699746997569976699776997869979699806998169982699836998469985699866998769988699896999069991699926999369994699956999669997699986999970000700017000270003700047000570006700077000870009700107001170012700137001470015700167001770018700197002070021700227002370024700257002670027700287002970030700317003270033700347003570036700377003870039700407004170042700437004470045700467004770048700497005070051700527005370054700557005670057700587005970060700617006270063700647006570066700677006870069700707007170072700737007470075700767007770078700797008070081700827008370084700857008670087700887008970090700917009270093700947009570096700977009870099701007010170102701037010470105701067010770108701097011070111701127011370114701157011670117701187011970120701217012270123701247012570126701277012870129701307013170132701337013470135701367013770138701397014070141701427014370144701457014670147701487014970150701517015270153701547015570156701577015870159701607016170162701637016470165701667016770168701697017070171701727017370174701757017670177701787017970180701817018270183701847018570186701877018870189701907019170192701937019470195701967019770198701997020070201702027020370204702057020670207702087020970210702117021270213702147021570216702177021870219702207022170222702237022470225702267022770228702297023070231702327023370234702357023670237702387023970240702417024270243702447024570246702477024870249702507025170252702537025470255702567025770258702597026070261702627026370264702657026670267702687026970270702717027270273702747027570276702777027870279702807028170282702837028470285702867028770288702897029070291702927029370294702957029670297702987029970300703017030270303703047030570306703077030870309703107031170312703137031470315703167031770318703197032070321703227032370324703257032670327703287032970330703317033270333703347033570336703377033870339703407034170342703437034470345703467034770348703497035070351703527035370354703557035670357703587035970360703617036270363703647036570366703677036870369703707037170372703737037470375703767037770378703797038070381703827038370384703857038670387703887038970390703917039270393703947039570396703977039870399704007040170402704037040470405704067040770408704097041070411704127041370414704157041670417704187041970420704217042270423704247042570426704277042870429704307043170432704337043470435704367043770438704397044070441704427044370444704457044670447704487044970450704517045270453704547045570456704577045870459704607046170462704637046470465704667046770468704697047070471704727047370474704757047670477704787047970480704817048270483704847048570486704877048870489704907049170492704937049470495704967049770498704997050070501705027050370504705057050670507705087050970510705117051270513705147051570516705177051870519705207052170522705237052470525705267052770528705297053070531705327053370534705357053670537705387053970540705417054270543705447054570546705477054870549705507055170552705537055470555705567055770558705597056070561705627056370564705657056670567705687056970570705717057270573705747057570576705777057870579705807058170582705837058470585705867058770588705897059070591705927059370594705957059670597705987059970600706017060270603706047060570606706077060870609706107061170612706137061470615706167061770618706197062070621706227062370624706257062670627706287062970630706317063270633706347063570636706377063870639706407064170642706437064470645706467064770648706497065070651706527065370654706557065670657706587065970660706617066270663706647066570666706677066870669706707067170672706737067470675706767067770678706797068070681706827068370684706857068670687706887068970690706917069270693706947069570696706977069870699707007070170702707037070470705707067070770708707097071070711707127071370714707157071670717707187071970720707217072270723707247072570726707277072870729707307073170732707337073470735707367073770738707397074070741707427074370744707457074670747707487074970750707517075270753707547075570756707577075870759707607076170762707637076470765707667076770768707697077070771707727077370774707757077670777707787077970780707817078270783707847078570786707877078870789707907079170792707937079470795707967079770798707997080070801708027080370804708057080670807708087080970810708117081270813708147081570816708177081870819708207082170822708237082470825708267082770828708297083070831708327083370834708357083670837708387083970840708417084270843708447084570846708477084870849708507085170852708537085470855708567085770858708597086070861708627086370864708657086670867708687086970870708717087270873708747087570876708777087870879708807088170882708837088470885708867088770888708897089070891708927089370894708957089670897708987089970900709017090270903709047090570906709077090870909709107091170912709137091470915709167091770918709197092070921709227092370924709257092670927709287092970930709317093270933709347093570936709377093870939709407094170942709437094470945709467094770948709497095070951709527095370954709557095670957709587095970960709617096270963709647096570966709677096870969709707097170972709737097470975709767097770978709797098070981709827098370984709857098670987709887098970990709917099270993709947099570996709977099870999710007100171002710037100471005710067100771008710097101071011710127101371014710157101671017710187101971020710217102271023710247102571026710277102871029710307103171032710337103471035710367103771038710397104071041710427104371044710457104671047710487104971050710517105271053710547105571056710577105871059710607106171062710637106471065710667106771068710697107071071710727107371074710757107671077710787107971080710817108271083710847108571086710877108871089710907109171092710937109471095710967109771098710997110071101711027110371104711057110671107711087110971110711117111271113711147111571116711177111871119711207112171122711237112471125711267112771128711297113071131711327113371134711357113671137711387113971140711417114271143711447114571146711477114871149711507115171152711537115471155711567115771158711597116071161711627116371164711657116671167711687116971170711717117271173711747117571176711777117871179711807118171182711837118471185711867118771188711897119071191711927119371194711957119671197711987119971200712017120271203712047120571206712077120871209712107121171212712137121471215712167121771218712197122071221712227122371224712257122671227712287122971230712317123271233712347123571236712377123871239712407124171242712437124471245712467124771248712497125071251712527125371254712557125671257712587125971260712617126271263712647126571266712677126871269712707127171272712737127471275712767127771278712797128071281712827128371284712857128671287712887128971290712917129271293712947129571296712977129871299713007130171302713037130471305713067130771308713097131071311713127131371314713157131671317713187131971320713217132271323713247132571326713277132871329713307133171332713337133471335713367133771338713397134071341713427134371344713457134671347713487134971350713517135271353713547135571356713577135871359713607136171362713637136471365713667136771368713697137071371713727137371374713757137671377713787137971380713817138271383713847138571386713877138871389713907139171392713937139471395713967139771398713997140071401714027140371404714057140671407714087140971410714117141271413714147141571416714177141871419714207142171422714237142471425714267142771428714297143071431714327143371434714357143671437714387143971440714417144271443714447144571446714477144871449714507145171452714537145471455714567145771458714597146071461714627146371464714657146671467714687146971470714717147271473714747147571476714777147871479714807148171482714837148471485714867148771488714897149071491714927149371494714957149671497714987149971500715017150271503715047150571506715077150871509715107151171512715137151471515715167151771518715197152071521715227152371524715257152671527715287152971530715317153271533715347153571536715377153871539715407154171542715437154471545715467154771548715497155071551715527155371554715557155671557715587155971560715617156271563715647156571566715677156871569715707157171572715737157471575715767157771578715797158071581715827158371584715857158671587715887158971590715917159271593715947159571596715977159871599716007160171602716037160471605716067160771608716097161071611716127161371614716157161671617716187161971620716217162271623716247162571626716277162871629716307163171632716337163471635716367163771638716397164071641716427164371644716457164671647716487164971650716517165271653716547165571656716577165871659716607166171662716637166471665716667166771668716697167071671716727167371674716757167671677716787167971680716817168271683716847168571686716877168871689716907169171692716937169471695716967169771698716997170071701717027170371704717057170671707717087170971710717117171271713717147171571716717177171871719717207172171722717237172471725717267172771728717297173071731717327173371734717357173671737717387173971740717417174271743717447174571746717477174871749717507175171752717537175471755717567175771758717597176071761717627176371764717657176671767717687176971770717717177271773717747177571776717777177871779717807178171782717837178471785717867178771788717897179071791717927179371794717957179671797717987179971800718017180271803718047180571806718077180871809718107181171812718137181471815718167181771818718197182071821718227182371824718257182671827718287182971830718317183271833718347183571836718377183871839718407184171842718437184471845718467184771848718497185071851718527185371854718557185671857718587185971860718617186271863718647186571866718677186871869718707187171872718737187471875718767187771878718797188071881718827188371884718857188671887718887188971890718917189271893718947189571896718977189871899719007190171902719037190471905719067190771908719097191071911719127191371914719157191671917719187191971920719217192271923719247192571926719277192871929719307193171932719337193471935719367193771938719397194071941719427194371944719457194671947719487194971950719517195271953719547195571956719577195871959719607196171962719637196471965719667196771968719697197071971719727197371974719757197671977719787197971980719817198271983719847198571986719877198871989719907199171992719937199471995719967199771998719997200072001720027200372004720057200672007720087200972010720117201272013720147201572016720177201872019720207202172022720237202472025720267202772028720297203072031720327203372034720357203672037720387203972040720417204272043720447204572046720477204872049720507205172052720537205472055720567205772058720597206072061720627206372064720657206672067720687206972070720717207272073720747207572076720777207872079720807208172082720837208472085720867208772088720897209072091720927209372094720957209672097720987209972100721017210272103721047210572106721077210872109721107211172112721137211472115721167211772118721197212072121721227212372124721257212672127721287212972130721317213272133721347213572136721377213872139721407214172142721437214472145721467214772148721497215072151721527215372154721557215672157721587215972160721617216272163721647216572166721677216872169721707217172172721737217472175721767217772178721797218072181721827218372184721857218672187721887218972190721917219272193721947219572196721977219872199722007220172202722037220472205722067220772208722097221072211722127221372214722157221672217722187221972220722217222272223722247222572226722277222872229722307223172232722337223472235722367223772238722397224072241722427224372244722457224672247722487224972250722517225272253722547225572256722577225872259722607226172262722637226472265722667226772268722697227072271722727227372274722757227672277722787227972280722817228272283722847228572286722877228872289722907229172292722937229472295722967229772298722997230072301723027230372304723057230672307723087230972310723117231272313723147231572316723177231872319723207232172322723237232472325723267232772328723297233072331723327233372334723357233672337723387233972340723417234272343723447234572346723477234872349723507235172352723537235472355723567235772358723597236072361723627236372364723657236672367723687236972370723717237272373723747237572376723777237872379723807238172382723837238472385723867238772388723897239072391723927239372394723957239672397723987239972400724017240272403724047240572406724077240872409724107241172412724137241472415724167241772418724197242072421724227242372424724257242672427724287242972430724317243272433724347243572436724377243872439724407244172442724437244472445724467244772448724497245072451724527245372454724557245672457724587245972460724617246272463724647246572466724677246872469724707247172472724737247472475724767247772478724797248072481724827248372484724857248672487724887248972490724917249272493724947249572496724977249872499725007250172502725037250472505725067250772508725097251072511725127251372514725157251672517725187251972520725217252272523725247252572526725277252872529725307253172532725337253472535725367253772538725397254072541725427254372544725457254672547725487254972550725517255272553725547255572556725577255872559725607256172562725637256472565725667256772568725697257072571725727257372574725757257672577725787257972580725817258272583725847258572586725877258872589725907259172592725937259472595725967259772598725997260072601726027260372604726057260672607726087260972610726117261272613726147261572616726177261872619726207262172622726237262472625726267262772628726297263072631726327263372634726357263672637726387263972640726417264272643726447264572646726477264872649726507265172652726537265472655726567265772658726597266072661726627266372664726657266672667726687266972670726717267272673726747267572676726777267872679726807268172682726837268472685726867268772688726897269072691726927269372694726957269672697726987269972700727017270272703727047270572706727077270872709727107271172712727137271472715727167271772718727197272072721727227272372724727257272672727727287272972730727317273272733727347273572736727377273872739727407274172742727437274472745727467274772748727497275072751727527275372754727557275672757727587275972760727617276272763727647276572766727677276872769727707277172772727737277472775727767277772778727797278072781727827278372784727857278672787727887278972790727917279272793727947279572796727977279872799728007280172802728037280472805728067280772808728097281072811728127281372814728157281672817728187281972820728217282272823728247282572826728277282872829728307283172832728337283472835728367283772838728397284072841728427284372844728457284672847728487284972850728517285272853728547285572856728577285872859728607286172862728637286472865728667286772868728697287072871728727287372874728757287672877728787287972880728817288272883728847288572886728877288872889728907289172892728937289472895728967289772898728997290072901729027290372904729057290672907729087290972910729117291272913729147291572916729177291872919729207292172922729237292472925729267292772928729297293072931729327293372934729357293672937729387293972940729417294272943729447294572946729477294872949729507295172952729537295472955729567295772958729597296072961729627296372964729657296672967729687296972970729717297272973729747297572976729777297872979729807298172982729837298472985729867298772988729897299072991729927299372994729957299672997729987299973000730017300273003730047300573006730077300873009730107301173012730137301473015730167301773018730197302073021730227302373024730257302673027730287302973030730317303273033730347303573036730377303873039730407304173042730437304473045730467304773048730497305073051730527305373054730557305673057730587305973060730617306273063730647306573066730677306873069730707307173072730737307473075730767307773078730797308073081730827308373084730857308673087730887308973090730917309273093730947309573096730977309873099731007310173102731037310473105731067310773108731097311073111731127311373114731157311673117731187311973120731217312273123731247312573126731277312873129731307313173132731337313473135731367313773138731397314073141731427314373144731457314673147731487314973150731517315273153731547315573156731577315873159731607316173162731637316473165731667316773168731697317073171731727317373174731757317673177731787317973180731817318273183731847318573186731877318873189731907319173192731937319473195731967319773198731997320073201732027320373204732057320673207732087320973210732117321273213732147321573216732177321873219732207322173222732237322473225732267322773228732297323073231732327323373234732357323673237732387323973240732417324273243732447324573246732477324873249732507325173252732537325473255732567325773258732597326073261732627326373264732657326673267732687326973270732717327273273732747327573276732777327873279732807328173282732837328473285732867328773288732897329073291732927329373294732957329673297732987329973300733017330273303733047330573306733077330873309733107331173312733137331473315733167331773318733197332073321733227332373324733257332673327733287332973330733317333273333733347333573336733377333873339733407334173342733437334473345733467334773348733497335073351733527335373354733557335673357733587335973360733617336273363733647336573366733677336873369733707337173372733737337473375733767337773378733797338073381733827338373384733857338673387733887338973390733917339273393733947339573396733977339873399734007340173402734037340473405734067340773408734097341073411734127341373414734157341673417734187341973420734217342273423734247342573426734277342873429734307343173432734337343473435734367343773438734397344073441734427344373444734457344673447734487344973450734517345273453734547345573456734577345873459734607346173462734637346473465734667346773468734697347073471734727347373474734757347673477734787347973480734817348273483734847348573486734877348873489734907349173492734937349473495734967349773498734997350073501735027350373504735057350673507735087350973510735117351273513735147351573516735177351873519735207352173522735237352473525735267352773528735297353073531735327353373534735357353673537735387353973540735417354273543735447354573546735477354873549735507355173552735537355473555735567355773558735597356073561735627356373564735657356673567735687356973570735717357273573735747357573576735777357873579735807358173582735837358473585735867358773588735897359073591735927359373594735957359673597735987359973600736017360273603736047360573606736077360873609736107361173612736137361473615736167361773618736197362073621736227362373624736257362673627736287362973630736317363273633736347363573636736377363873639736407364173642736437364473645736467364773648736497365073651736527365373654736557365673657736587365973660736617366273663736647366573666736677366873669736707367173672736737367473675736767367773678736797368073681736827368373684736857368673687736887368973690736917369273693736947369573696736977369873699737007370173702737037370473705737067370773708737097371073711737127371373714737157371673717737187371973720737217372273723737247372573726737277372873729737307373173732737337373473735737367373773738737397374073741737427374373744737457374673747737487374973750737517375273753737547375573756737577375873759737607376173762737637376473765737667376773768737697377073771737727377373774737757377673777737787377973780737817378273783737847378573786737877378873789737907379173792737937379473795737967379773798737997380073801738027380373804738057380673807738087380973810738117381273813738147381573816738177381873819738207382173822738237382473825738267382773828738297383073831738327383373834738357383673837738387383973840738417384273843738447384573846738477384873849738507385173852738537385473855738567385773858738597386073861738627386373864738657386673867738687386973870738717387273873738747387573876738777387873879738807388173882738837388473885738867388773888738897389073891738927389373894738957389673897738987389973900739017390273903739047390573906739077390873909739107391173912739137391473915739167391773918739197392073921739227392373924739257392673927739287392973930739317393273933739347393573936739377393873939739407394173942739437394473945739467394773948739497395073951739527395373954739557395673957739587395973960739617396273963739647396573966739677396873969739707397173972739737397473975739767397773978739797398073981739827398373984739857398673987739887398973990739917399273993739947399573996739977399873999740007400174002740037400474005740067400774008740097401074011740127401374014740157401674017740187401974020740217402274023740247402574026740277402874029740307403174032740337403474035740367403774038740397404074041740427404374044740457404674047740487404974050740517405274053740547405574056740577405874059740607406174062740637406474065740667406774068740697407074071740727407374074740757407674077740787407974080740817408274083740847408574086740877408874089740907409174092740937409474095740967409774098740997410074101741027410374104741057410674107741087410974110741117411274113741147411574116741177411874119741207412174122741237412474125741267412774128741297413074131741327413374134741357413674137741387413974140741417414274143741447414574146741477414874149741507415174152741537415474155741567415774158741597416074161741627416374164741657416674167741687416974170741717417274173741747417574176741777417874179741807418174182741837418474185741867418774188741897419074191741927419374194741957419674197741987419974200742017420274203742047420574206742077420874209742107421174212742137421474215742167421774218742197422074221742227422374224742257422674227742287422974230742317423274233742347423574236742377423874239742407424174242742437424474245742467424774248742497425074251742527425374254742557425674257742587425974260742617426274263742647426574266742677426874269742707427174272742737427474275742767427774278742797428074281742827428374284742857428674287742887428974290742917429274293742947429574296742977429874299743007430174302743037430474305743067430774308743097431074311743127431374314743157431674317743187431974320743217432274323743247432574326743277432874329743307433174332743337433474335743367433774338743397434074341743427434374344743457434674347743487434974350743517435274353743547435574356743577435874359743607436174362743637436474365743667436774368743697437074371743727437374374743757437674377743787437974380743817438274383743847438574386743877438874389743907439174392743937439474395743967439774398743997440074401744027440374404744057440674407744087440974410744117441274413744147441574416744177441874419744207442174422744237442474425744267442774428744297443074431744327443374434744357443674437744387443974440744417444274443744447444574446744477444874449744507445174452744537445474455744567445774458744597446074461744627446374464744657446674467744687446974470744717447274473744747447574476744777447874479744807448174482744837448474485744867448774488744897449074491744927449374494744957449674497744987449974500745017450274503745047450574506745077450874509745107451174512745137451474515745167451774518745197452074521745227452374524745257452674527745287452974530745317453274533745347453574536745377453874539745407454174542745437454474545745467454774548745497455074551745527455374554745557455674557745587455974560745617456274563745647456574566745677456874569745707457174572745737457474575745767457774578745797458074581745827458374584745857458674587745887458974590745917459274593745947459574596745977459874599746007460174602746037460474605746067460774608746097461074611746127461374614746157461674617746187461974620746217462274623746247462574626746277462874629746307463174632746337463474635746367463774638746397464074641746427464374644746457464674647746487464974650746517465274653746547465574656746577465874659746607466174662746637466474665746667466774668746697467074671746727467374674746757467674677746787467974680746817468274683746847468574686746877468874689746907469174692746937469474695746967469774698746997470074701747027470374704747057470674707747087470974710747117471274713747147471574716747177471874719747207472174722747237472474725747267472774728747297473074731747327473374734747357473674737747387473974740747417474274743747447474574746747477474874749747507475174752747537475474755747567475774758747597476074761747627476374764747657476674767747687476974770747717477274773747747477574776747777477874779747807478174782747837478474785747867478774788747897479074791747927479374794747957479674797747987479974800748017480274803748047480574806748077480874809748107481174812748137481474815748167481774818748197482074821748227482374824748257482674827748287482974830748317483274833748347483574836748377483874839748407484174842748437484474845748467484774848748497485074851748527485374854748557485674857748587485974860748617486274863748647486574866748677486874869748707487174872748737487474875748767487774878748797488074881748827488374884748857488674887748887488974890748917489274893748947489574896748977489874899749007490174902749037490474905749067490774908749097491074911749127491374914749157491674917749187491974920749217492274923749247492574926749277492874929749307493174932749337493474935749367493774938749397494074941749427494374944749457494674947749487494974950749517495274953749547495574956749577495874959749607496174962749637496474965749667496774968749697497074971749727497374974749757497674977749787497974980749817498274983749847498574986749877498874989749907499174992749937499474995749967499774998749997500075001750027500375004750057500675007750087500975010750117501275013750147501575016750177501875019750207502175022750237502475025750267502775028750297503075031750327503375034750357503675037750387503975040750417504275043750447504575046750477504875049750507505175052750537505475055750567505775058750597506075061750627506375064750657506675067750687506975070750717507275073750747507575076750777507875079750807508175082750837508475085750867508775088750897509075091750927509375094750957509675097750987509975100751017510275103751047510575106751077510875109751107511175112751137511475115751167511775118751197512075121751227512375124751257512675127751287512975130751317513275133751347513575136751377513875139751407514175142751437514475145751467514775148751497515075151751527515375154751557515675157751587515975160751617516275163751647516575166751677516875169751707517175172751737517475175751767517775178751797518075181751827518375184751857518675187751887518975190751917519275193751947519575196751977519875199752007520175202752037520475205752067520775208752097521075211752127521375214752157521675217752187521975220752217522275223752247522575226752277522875229752307523175232752337523475235752367523775238752397524075241752427524375244752457524675247752487524975250752517525275253752547525575256752577525875259752607526175262752637526475265752667526775268752697527075271752727527375274752757527675277752787527975280752817528275283752847528575286752877528875289752907529175292752937529475295752967529775298752997530075301753027530375304753057530675307753087530975310753117531275313753147531575316753177531875319753207532175322753237532475325753267532775328753297533075331753327533375334753357533675337753387533975340753417534275343753447534575346753477534875349753507535175352753537535475355753567535775358753597536075361753627536375364753657536675367753687536975370753717537275373753747537575376753777537875379753807538175382753837538475385753867538775388753897539075391753927539375394753957539675397753987539975400754017540275403754047540575406754077540875409754107541175412754137541475415754167541775418754197542075421754227542375424754257542675427754287542975430754317543275433754347543575436754377543875439754407544175442754437544475445754467544775448754497545075451754527545375454754557545675457754587545975460754617546275463754647546575466754677546875469754707547175472754737547475475754767547775478754797548075481754827548375484754857548675487754887548975490754917549275493754947549575496754977549875499755007550175502755037550475505755067550775508755097551075511755127551375514755157551675517755187551975520755217552275523755247552575526755277552875529755307553175532755337553475535755367553775538755397554075541755427554375544755457554675547755487554975550755517555275553755547555575556755577555875559755607556175562755637556475565755667556775568755697557075571755727557375574755757557675577755787557975580755817558275583755847558575586755877558875589755907559175592755937559475595755967559775598755997560075601756027560375604756057560675607756087560975610756117561275613756147561575616756177561875619756207562175622756237562475625756267562775628756297563075631756327563375634756357563675637756387563975640756417564275643756447564575646756477564875649756507565175652756537565475655756567565775658756597566075661756627566375664756657566675667756687566975670756717567275673756747567575676756777567875679756807568175682756837568475685756867568775688756897569075691756927569375694756957569675697756987569975700757017570275703757047570575706757077570875709757107571175712757137571475715757167571775718757197572075721757227572375724757257572675727757287572975730757317573275733757347573575736757377573875739757407574175742757437574475745757467574775748757497575075751757527575375754757557575675757757587575975760757617576275763757647576575766757677576875769757707577175772757737577475775757767577775778757797578075781757827578375784757857578675787757887578975790757917579275793757947579575796757977579875799758007580175802758037580475805758067580775808758097581075811758127581375814758157581675817758187581975820758217582275823758247582575826758277582875829758307583175832758337583475835758367583775838758397584075841758427584375844758457584675847758487584975850758517585275853758547585575856758577585875859758607586175862758637586475865758667586775868758697587075871758727587375874758757587675877758787587975880758817588275883758847588575886758877588875889758907589175892758937589475895758967589775898758997590075901759027590375904759057590675907759087590975910759117591275913759147591575916759177591875919759207592175922759237592475925759267592775928759297593075931759327593375934759357593675937759387593975940759417594275943759447594575946759477594875949759507595175952759537595475955759567595775958759597596075961759627596375964759657596675967759687596975970759717597275973759747597575976759777597875979759807598175982759837598475985759867598775988759897599075991759927599375994759957599675997759987599976000760017600276003760047600576006760077600876009760107601176012760137601476015760167601776018760197602076021760227602376024760257602676027760287602976030760317603276033760347603576036760377603876039760407604176042760437604476045760467604776048760497605076051760527605376054760557605676057760587605976060760617606276063760647606576066760677606876069760707607176072760737607476075760767607776078760797608076081760827608376084760857608676087760887608976090760917609276093760947609576096760977609876099761007610176102761037610476105761067610776108761097611076111761127611376114761157611676117761187611976120761217612276123761247612576126761277612876129761307613176132761337613476135761367613776138761397614076141761427614376144761457614676147761487614976150761517615276153761547615576156761577615876159761607616176162761637616476165761667616776168761697617076171761727617376174761757617676177761787617976180761817618276183761847618576186761877618876189761907619176192761937619476195761967619776198761997620076201762027620376204762057620676207762087620976210762117621276213762147621576216762177621876219762207622176222762237622476225762267622776228762297623076231762327623376234762357623676237762387623976240762417624276243762447624576246762477624876249762507625176252762537625476255762567625776258762597626076261762627626376264762657626676267762687626976270762717627276273762747627576276762777627876279762807628176282762837628476285762867628776288762897629076291762927629376294762957629676297762987629976300763017630276303763047630576306763077630876309763107631176312763137631476315763167631776318763197632076321763227632376324763257632676327763287632976330763317633276333763347633576336763377633876339763407634176342763437634476345763467634776348763497635076351763527635376354763557635676357763587635976360763617636276363763647636576366763677636876369763707637176372763737637476375763767637776378763797638076381763827638376384763857638676387763887638976390763917639276393763947639576396763977639876399764007640176402764037640476405764067640776408764097641076411764127641376414764157641676417764187641976420764217642276423764247642576426764277642876429764307643176432764337643476435764367643776438764397644076441764427644376444764457644676447764487644976450764517645276453764547645576456764577645876459764607646176462764637646476465764667646776468764697647076471764727647376474764757647676477764787647976480764817648276483764847648576486764877648876489764907649176492764937649476495764967649776498764997650076501765027650376504765057650676507765087650976510765117651276513765147651576516765177651876519765207652176522765237652476525765267652776528765297653076531765327653376534765357653676537765387653976540765417654276543765447654576546765477654876549765507655176552765537655476555765567655776558765597656076561765627656376564765657656676567765687656976570765717657276573765747657576576765777657876579765807658176582765837658476585765867658776588765897659076591765927659376594765957659676597765987659976600766017660276603766047660576606766077660876609766107661176612766137661476615766167661776618766197662076621766227662376624766257662676627766287662976630766317663276633766347663576636766377663876639766407664176642766437664476645766467664776648766497665076651766527665376654766557665676657766587665976660766617666276663766647666576666766677666876669766707667176672766737667476675766767667776678766797668076681766827668376684766857668676687766887668976690766917669276693766947669576696766977669876699767007670176702767037670476705767067670776708767097671076711767127671376714767157671676717767187671976720767217672276723767247672576726767277672876729767307673176732767337673476735767367673776738767397674076741767427674376744767457674676747767487674976750767517675276753767547675576756767577675876759767607676176762767637676476765767667676776768767697677076771767727677376774767757677676777767787677976780767817678276783767847678576786767877678876789767907679176792767937679476795767967679776798767997680076801768027680376804768057680676807768087680976810768117681276813768147681576816768177681876819768207682176822768237682476825768267682776828768297683076831768327683376834768357683676837768387683976840768417684276843768447684576846768477684876849768507685176852768537685476855768567685776858768597686076861768627686376864768657686676867768687686976870768717687276873768747687576876768777687876879768807688176882768837688476885768867688776888768897689076891768927689376894768957689676897768987689976900769017690276903769047690576906769077690876909769107691176912769137691476915769167691776918769197692076921769227692376924769257692676927769287692976930769317693276933769347693576936769377693876939769407694176942769437694476945769467694776948769497695076951769527695376954769557695676957769587695976960769617696276963769647696576966769677696876969769707697176972769737697476975769767697776978769797698076981769827698376984769857698676987769887698976990769917699276993769947699576996769977699876999770007700177002770037700477005770067700777008770097701077011770127701377014770157701677017770187701977020770217702277023770247702577026770277702877029770307703177032770337703477035770367703777038770397704077041770427704377044770457704677047770487704977050770517705277053770547705577056770577705877059770607706177062770637706477065770667706777068770697707077071770727707377074770757707677077770787707977080770817708277083770847708577086770877708877089770907709177092770937709477095770967709777098770997710077101771027710377104771057710677107771087710977110771117711277113771147711577116771177711877119771207712177122771237712477125771267712777128771297713077131771327713377134771357713677137771387713977140771417714277143771447714577146771477714877149771507715177152771537715477155771567715777158771597716077161771627716377164771657716677167771687716977170771717717277173771747717577176771777717877179771807718177182771837718477185771867718777188771897719077191771927719377194771957719677197771987719977200772017720277203772047720577206772077720877209772107721177212772137721477215772167721777218772197722077221772227722377224772257722677227772287722977230772317723277233772347723577236772377723877239772407724177242772437724477245772467724777248772497725077251772527725377254772557725677257772587725977260772617726277263772647726577266772677726877269772707727177272772737727477275772767727777278772797728077281772827728377284772857728677287772887728977290772917729277293772947729577296772977729877299773007730177302773037730477305773067730777308773097731077311773127731377314773157731677317773187731977320773217732277323773247732577326773277732877329773307733177332773337733477335773367733777338773397734077341773427734377344773457734677347773487734977350773517735277353773547735577356773577735877359773607736177362773637736477365773667736777368773697737077371773727737377374773757737677377773787737977380773817738277383773847738577386773877738877389773907739177392773937739477395773967739777398773997740077401774027740377404774057740677407774087740977410774117741277413774147741577416774177741877419774207742177422774237742477425774267742777428774297743077431774327743377434774357743677437774387743977440774417744277443774447744577446774477744877449774507745177452774537745477455774567745777458774597746077461774627746377464774657746677467774687746977470774717747277473774747747577476774777747877479774807748177482774837748477485774867748777488774897749077491774927749377494774957749677497774987749977500775017750277503775047750577506775077750877509775107751177512775137751477515775167751777518775197752077521775227752377524775257752677527775287752977530775317753277533775347753577536775377753877539775407754177542775437754477545775467754777548775497755077551775527755377554775557755677557775587755977560775617756277563775647756577566775677756877569775707757177572775737757477575775767757777578775797758077581775827758377584775857758677587775887758977590775917759277593775947759577596775977759877599776007760177602776037760477605776067760777608776097761077611776127761377614776157761677617776187761977620776217762277623776247762577626776277762877629776307763177632776337763477635776367763777638776397764077641776427764377644776457764677647776487764977650776517765277653776547765577656776577765877659776607766177662776637766477665776667766777668776697767077671776727767377674776757767677677776787767977680776817768277683776847768577686776877768877689776907769177692776937769477695776967769777698776997770077701777027770377704777057770677707777087770977710777117771277713777147771577716777177771877719777207772177722777237772477725777267772777728777297773077731777327773377734777357773677737777387773977740777417774277743777447774577746777477774877749777507775177752777537775477755777567775777758777597776077761777627776377764777657776677767777687776977770777717777277773777747777577776777777777877779777807778177782777837778477785777867778777788777897779077791777927779377794777957779677797777987779977800778017780277803778047780577806778077780877809778107781177812778137781477815778167781777818778197782077821778227782377824778257782677827778287782977830778317783277833778347783577836778377783877839778407784177842778437784477845778467784777848778497785077851778527785377854778557785677857778587785977860778617786277863778647786577866778677786877869778707787177872778737787477875778767787777878778797788077881778827788377884778857788677887778887788977890778917789277893778947789577896778977789877899779007790177902779037790477905779067790777908779097791077911779127791377914779157791677917779187791977920779217792277923779247792577926779277792877929779307793177932779337793477935779367793777938779397794077941779427794377944779457794677947779487794977950779517795277953779547795577956779577795877959779607796177962779637796477965779667796777968779697797077971779727797377974779757797677977779787797977980779817798277983779847798577986779877798877989779907799177992779937799477995779967799777998779997800078001780027800378004780057800678007780087800978010780117801278013780147801578016780177801878019780207802178022780237802478025780267802778028780297803078031780327803378034780357803678037780387803978040780417804278043780447804578046780477804878049780507805178052780537805478055780567805778058780597806078061780627806378064780657806678067780687806978070780717807278073780747807578076780777807878079780807808178082780837808478085780867808778088780897809078091780927809378094780957809678097780987809978100781017810278103781047810578106781077810878109781107811178112781137811478115781167811778118781197812078121781227812378124781257812678127781287812978130781317813278133781347813578136781377813878139781407814178142781437814478145781467814778148781497815078151781527815378154781557815678157781587815978160781617816278163781647816578166781677816878169781707817178172781737817478175781767817778178781797818078181781827818378184781857818678187781887818978190781917819278193781947819578196781977819878199782007820178202782037820478205782067820778208782097821078211782127821378214782157821678217782187821978220782217822278223782247822578226782277822878229782307823178232782337823478235782367823778238782397824078241782427824378244782457824678247782487824978250782517825278253782547825578256782577825878259782607826178262782637826478265782667826778268782697827078271782727827378274782757827678277782787827978280782817828278283782847828578286782877828878289782907829178292782937829478295782967829778298782997830078301783027830378304783057830678307783087830978310783117831278313783147831578316783177831878319783207832178322783237832478325783267832778328783297833078331783327833378334783357833678337783387833978340783417834278343783447834578346783477834878349783507835178352783537835478355783567835778358783597836078361783627836378364783657836678367783687836978370783717837278373783747837578376783777837878379783807838178382783837838478385783867838778388783897839078391783927839378394783957839678397783987839978400784017840278403784047840578406784077840878409784107841178412784137841478415784167841778418784197842078421784227842378424784257842678427784287842978430784317843278433784347843578436784377843878439784407844178442784437844478445784467844778448784497845078451784527845378454784557845678457784587845978460784617846278463784647846578466784677846878469784707847178472784737847478475784767847778478784797848078481784827848378484784857848678487784887848978490784917849278493784947849578496784977849878499785007850178502785037850478505785067850778508785097851078511785127851378514785157851678517785187851978520785217852278523785247852578526785277852878529785307853178532785337853478535785367853778538785397854078541785427854378544785457854678547785487854978550785517855278553785547855578556785577855878559785607856178562785637856478565785667856778568785697857078571785727857378574785757857678577785787857978580785817858278583785847858578586785877858878589785907859178592785937859478595785967859778598785997860078601786027860378604786057860678607786087860978610786117861278613786147861578616786177861878619786207862178622786237862478625786267862778628786297863078631786327863378634786357863678637786387863978640786417864278643786447864578646786477864878649786507865178652786537865478655786567865778658786597866078661786627866378664786657866678667786687866978670786717867278673786747867578676786777867878679786807868178682786837868478685786867868778688786897869078691786927869378694786957869678697786987869978700787017870278703787047870578706787077870878709787107871178712787137871478715787167871778718787197872078721787227872378724787257872678727787287872978730787317873278733787347873578736787377873878739787407874178742787437874478745787467874778748787497875078751787527875378754787557875678757787587875978760787617876278763787647876578766787677876878769787707877178772787737877478775787767877778778787797878078781787827878378784787857878678787787887878978790787917879278793787947879578796787977879878799788007880178802788037880478805788067880778808788097881078811788127881378814788157881678817788187881978820788217882278823788247882578826788277882878829788307883178832788337883478835788367883778838788397884078841788427884378844788457884678847788487884978850788517885278853788547885578856788577885878859788607886178862788637886478865788667886778868788697887078871788727887378874788757887678877788787887978880788817888278883788847888578886788877888878889788907889178892788937889478895788967889778898788997890078901789027890378904789057890678907789087890978910789117891278913789147891578916789177891878919789207892178922789237892478925789267892778928789297893078931789327893378934789357893678937789387893978940789417894278943789447894578946789477894878949789507895178952789537895478955789567895778958789597896078961789627896378964789657896678967789687896978970789717897278973789747897578976789777897878979789807898178982789837898478985789867898778988789897899078991789927899378994789957899678997789987899979000790017900279003790047900579006790077900879009790107901179012790137901479015790167901779018790197902079021790227902379024790257902679027790287902979030790317903279033790347903579036790377903879039790407904179042790437904479045790467904779048790497905079051790527905379054790557905679057790587905979060790617906279063790647906579066790677906879069790707907179072790737907479075790767907779078790797908079081790827908379084790857908679087790887908979090790917909279093790947909579096790977909879099791007910179102791037910479105791067910779108791097911079111791127911379114791157911679117791187911979120791217912279123791247912579126791277912879129791307913179132791337913479135791367913779138791397914079141791427914379144791457914679147791487914979150791517915279153791547915579156791577915879159791607916179162791637916479165791667916779168791697917079171791727917379174791757917679177791787917979180791817918279183791847918579186791877918879189791907919179192791937919479195791967919779198791997920079201792027920379204792057920679207792087920979210792117921279213792147921579216792177921879219792207922179222792237922479225792267922779228792297923079231792327923379234792357923679237792387923979240792417924279243792447924579246792477924879249792507925179252792537925479255792567925779258792597926079261792627926379264792657926679267792687926979270792717927279273792747927579276792777927879279792807928179282792837928479285792867928779288792897929079291792927929379294792957929679297792987929979300793017930279303793047930579306793077930879309793107931179312793137931479315793167931779318793197932079321793227932379324793257932679327793287932979330793317933279333793347933579336793377933879339793407934179342793437934479345793467934779348793497935079351793527935379354793557935679357793587935979360793617936279363793647936579366793677936879369793707937179372793737937479375793767937779378793797938079381793827938379384793857938679387793887938979390793917939279393793947939579396793977939879399794007940179402794037940479405794067940779408794097941079411794127941379414794157941679417794187941979420794217942279423794247942579426794277942879429794307943179432794337943479435794367943779438794397944079441794427944379444794457944679447794487944979450794517945279453794547945579456794577945879459794607946179462794637946479465794667946779468794697947079471794727947379474794757947679477794787947979480794817948279483794847948579486794877948879489794907949179492794937949479495794967949779498794997950079501795027950379504795057950679507795087950979510795117951279513795147951579516795177951879519795207952179522795237952479525795267952779528795297953079531795327953379534795357953679537795387953979540795417954279543795447954579546795477954879549795507955179552795537955479555795567955779558795597956079561795627956379564795657956679567795687956979570795717957279573795747957579576795777957879579795807958179582795837958479585795867958779588795897959079591795927959379594795957959679597795987959979600796017960279603796047960579606796077960879609796107961179612796137961479615796167961779618796197962079621796227962379624796257962679627796287962979630796317963279633796347963579636796377963879639796407964179642796437964479645796467964779648796497965079651796527965379654796557965679657796587965979660796617966279663796647966579666796677966879669796707967179672796737967479675796767967779678796797968079681796827968379684796857968679687796887968979690796917969279693796947969579696796977969879699797007970179702797037970479705797067970779708797097971079711797127971379714797157971679717797187971979720797217972279723797247972579726797277972879729797307973179732797337973479735797367973779738797397974079741797427974379744797457974679747797487974979750797517975279753797547975579756797577975879759797607976179762797637976479765797667976779768797697977079771797727977379774797757977679777797787977979780797817978279783797847978579786797877978879789797907979179792797937979479795797967979779798797997980079801798027980379804798057980679807798087980979810798117981279813798147981579816798177981879819798207982179822798237982479825798267982779828798297983079831798327983379834798357983679837798387983979840798417984279843798447984579846798477984879849798507985179852798537985479855798567985779858798597986079861798627986379864798657986679867798687986979870798717987279873798747987579876798777987879879798807988179882798837988479885798867988779888798897989079891798927989379894798957989679897798987989979900799017990279903799047990579906799077990879909799107991179912799137991479915799167991779918799197992079921799227992379924799257992679927799287992979930799317993279933799347993579936799377993879939799407994179942799437994479945799467994779948799497995079951799527995379954799557995679957799587995979960799617996279963799647996579966799677996879969799707997179972799737997479975799767997779978799797998079981799827998379984799857998679987799887998979990799917999279993799947999579996799977999879999800008000180002800038000480005800068000780008800098001080011800128001380014800158001680017800188001980020800218002280023800248002580026800278002880029800308003180032800338003480035800368003780038800398004080041800428004380044800458004680047800488004980050800518005280053800548005580056800578005880059800608006180062800638006480065800668006780068800698007080071800728007380074800758007680077800788007980080800818008280083800848008580086800878008880089800908009180092800938009480095800968009780098800998010080101801028010380104801058010680107801088010980110801118011280113801148011580116801178011880119801208012180122801238012480125801268012780128801298013080131801328013380134801358013680137801388013980140801418014280143801448014580146801478014880149801508015180152801538015480155801568015780158801598016080161801628016380164801658016680167801688016980170801718017280173801748017580176801778017880179801808018180182801838018480185801868018780188801898019080191801928019380194801958019680197801988019980200802018020280203802048020580206802078020880209802108021180212802138021480215802168021780218802198022080221802228022380224802258022680227802288022980230802318023280233802348023580236802378023880239802408024180242802438024480245802468024780248802498025080251802528025380254802558025680257802588025980260802618026280263802648026580266802678026880269802708027180272802738027480275802768027780278802798028080281802828028380284802858028680287802888028980290802918029280293802948029580296802978029880299803008030180302803038030480305803068030780308803098031080311803128031380314803158031680317803188031980320803218032280323803248032580326803278032880329803308033180332803338033480335803368033780338803398034080341803428034380344803458034680347803488034980350803518035280353803548035580356803578035880359803608036180362803638036480365803668036780368803698037080371803728037380374803758037680377803788037980380803818038280383803848038580386803878038880389803908039180392803938039480395803968039780398803998040080401804028040380404804058040680407804088040980410804118041280413804148041580416804178041880419804208042180422804238042480425804268042780428804298043080431804328043380434804358043680437804388043980440804418044280443804448044580446804478044880449804508045180452804538045480455804568045780458804598046080461804628046380464804658046680467804688046980470804718047280473804748047580476804778047880479804808048180482804838048480485804868048780488804898049080491804928049380494804958049680497804988049980500805018050280503805048050580506805078050880509805108051180512805138051480515805168051780518805198052080521805228052380524805258052680527805288052980530805318053280533805348053580536805378053880539805408054180542805438054480545805468054780548805498055080551805528055380554805558055680557805588055980560805618056280563805648056580566805678056880569805708057180572805738057480575805768057780578805798058080581805828058380584805858058680587805888058980590805918059280593805948059580596805978059880599806008060180602806038060480605806068060780608806098061080611806128061380614806158061680617806188061980620806218062280623806248062580626806278062880629806308063180632806338063480635806368063780638806398064080641806428064380644806458064680647806488064980650806518065280653806548065580656806578065880659806608066180662806638066480665806668066780668806698067080671806728067380674806758067680677806788067980680806818068280683806848068580686806878068880689806908069180692806938069480695806968069780698806998070080701807028070380704807058070680707807088070980710807118071280713807148071580716807178071880719807208072180722807238072480725807268072780728807298073080731807328073380734807358073680737807388073980740807418074280743807448074580746807478074880749807508075180752807538075480755807568075780758807598076080761807628076380764807658076680767807688076980770807718077280773807748077580776807778077880779807808078180782807838078480785807868078780788807898079080791807928079380794807958079680797807988079980800808018080280803808048080580806808078080880809808108081180812808138081480815808168081780818808198082080821808228082380824808258082680827808288082980830808318083280833808348083580836808378083880839808408084180842808438084480845808468084780848808498085080851808528085380854808558085680857808588085980860808618086280863808648086580866808678086880869808708087180872808738087480875808768087780878808798088080881808828088380884808858088680887808888088980890808918089280893808948089580896808978089880899809008090180902809038090480905809068090780908809098091080911809128091380914809158091680917809188091980920809218092280923809248092580926809278092880929809308093180932809338093480935809368093780938809398094080941809428094380944809458094680947809488094980950809518095280953809548095580956809578095880959809608096180962809638096480965809668096780968809698097080971809728097380974809758097680977809788097980980809818098280983809848098580986809878098880989809908099180992809938099480995809968099780998809998100081001810028100381004810058100681007810088100981010810118101281013810148101581016810178101881019810208102181022810238102481025810268102781028810298103081031810328103381034810358103681037810388103981040810418104281043810448104581046810478104881049810508105181052810538105481055810568105781058810598106081061810628106381064810658106681067810688106981070810718107281073810748107581076810778107881079810808108181082810838108481085810868108781088810898109081091810928109381094810958109681097810988109981100811018110281103811048110581106811078110881109811108111181112811138111481115811168111781118811198112081121811228112381124811258112681127811288112981130811318113281133811348113581136811378113881139811408114181142811438114481145811468114781148811498115081151811528115381154811558115681157811588115981160811618116281163811648116581166811678116881169811708117181172811738117481175811768117781178811798118081181811828118381184811858118681187811888118981190811918119281193811948119581196811978119881199812008120181202812038120481205812068120781208812098121081211812128121381214812158121681217812188121981220812218122281223812248122581226812278122881229812308123181232812338123481235812368123781238812398124081241812428124381244812458124681247812488124981250812518125281253812548125581256812578125881259812608126181262812638126481265812668126781268812698127081271812728127381274812758127681277812788127981280812818128281283812848128581286812878128881289812908129181292812938129481295812968129781298812998130081301813028130381304813058130681307813088130981310813118131281313813148131581316813178131881319813208132181322813238132481325813268132781328813298133081331813328133381334813358133681337813388133981340813418134281343813448134581346813478134881349813508135181352813538135481355813568135781358813598136081361813628136381364813658136681367813688136981370813718137281373813748137581376813778137881379813808138181382813838138481385813868138781388813898139081391813928139381394813958139681397813988139981400814018140281403814048140581406814078140881409814108141181412814138141481415814168141781418814198142081421814228142381424814258142681427814288142981430814318143281433814348143581436814378143881439814408144181442814438144481445814468144781448814498145081451814528145381454814558145681457814588145981460814618146281463814648146581466814678146881469814708147181472814738147481475814768147781478814798148081481814828148381484814858148681487814888148981490814918149281493814948149581496814978149881499815008150181502815038150481505815068150781508815098151081511815128151381514815158151681517815188151981520815218152281523815248152581526815278152881529815308153181532815338153481535815368153781538815398154081541815428154381544815458154681547815488154981550815518155281553815548155581556815578155881559815608156181562815638156481565815668156781568815698157081571815728157381574815758157681577815788157981580815818158281583815848158581586815878158881589815908159181592815938159481595815968159781598815998160081601816028160381604816058160681607816088160981610816118161281613816148161581616816178161881619816208162181622816238162481625816268162781628816298163081631816328163381634816358163681637816388163981640816418164281643816448164581646816478164881649816508165181652816538165481655816568165781658816598166081661816628166381664816658166681667816688166981670816718167281673816748167581676816778167881679816808168181682816838168481685816868168781688816898169081691816928169381694816958169681697816988169981700817018170281703817048170581706817078170881709817108171181712817138171481715817168171781718817198172081721817228172381724817258172681727817288172981730817318173281733817348173581736817378173881739817408174181742817438174481745817468174781748817498175081751817528175381754817558175681757817588175981760817618176281763817648176581766817678176881769817708177181772817738177481775817768177781778817798178081781817828178381784817858178681787817888178981790817918179281793817948179581796817978179881799818008180181802818038180481805818068180781808818098181081811818128181381814818158181681817818188181981820818218182281823818248182581826818278182881829818308183181832818338183481835818368183781838818398184081841818428184381844818458184681847818488184981850818518185281853818548185581856818578185881859818608186181862818638186481865818668186781868818698187081871818728187381874818758187681877818788187981880818818188281883818848188581886818878188881889818908189181892818938189481895818968189781898818998190081901819028190381904819058190681907819088190981910819118191281913819148191581916819178191881919819208192181922819238192481925819268192781928819298193081931819328193381934819358193681937819388193981940819418194281943819448194581946819478194881949819508195181952819538195481955819568195781958819598196081961819628196381964819658196681967819688196981970819718197281973819748197581976819778197881979819808198181982819838198481985819868198781988819898199081991819928199381994819958199681997819988199982000820018200282003820048200582006820078200882009820108201182012820138201482015820168201782018820198202082021820228202382024820258202682027820288202982030820318203282033820348203582036820378203882039820408204182042820438204482045820468204782048820498205082051820528205382054820558205682057820588205982060820618206282063820648206582066820678206882069820708207182072820738207482075820768207782078820798208082081820828208382084820858208682087820888208982090820918209282093820948209582096820978209882099821008210182102821038210482105821068210782108821098211082111821128211382114821158211682117821188211982120821218212282123821248212582126821278212882129821308213182132821338213482135821368213782138821398214082141821428214382144821458214682147821488214982150821518215282153821548215582156821578215882159821608216182162821638216482165821668216782168821698217082171821728217382174821758217682177821788217982180821818218282183821848218582186821878218882189821908219182192821938219482195821968219782198821998220082201822028220382204822058220682207822088220982210822118221282213822148221582216822178221882219822208222182222822238222482225822268222782228822298223082231822328223382234822358223682237822388223982240822418224282243822448224582246822478224882249822508225182252822538225482255822568225782258822598226082261822628226382264822658226682267822688226982270822718227282273822748227582276822778227882279822808228182282822838228482285822868228782288822898229082291822928229382294822958229682297822988229982300823018230282303823048230582306823078230882309823108231182312823138231482315823168231782318823198232082321823228232382324823258232682327823288232982330823318233282333823348233582336823378233882339823408234182342823438234482345823468234782348823498235082351823528235382354823558235682357823588235982360823618236282363823648236582366823678236882369823708237182372823738237482375823768237782378823798238082381823828238382384823858238682387823888238982390823918239282393823948239582396823978239882399824008240182402824038240482405824068240782408824098241082411824128241382414824158241682417824188241982420824218242282423824248242582426824278242882429824308243182432824338243482435824368243782438824398244082441824428244382444824458244682447824488244982450824518245282453824548245582456824578245882459824608246182462824638246482465824668246782468824698247082471824728247382474824758247682477824788247982480824818248282483824848248582486824878248882489824908249182492824938249482495824968249782498824998250082501825028250382504825058250682507825088250982510825118251282513825148251582516825178251882519825208252182522825238252482525825268252782528825298253082531825328253382534825358253682537825388253982540825418254282543825448254582546825478254882549825508255182552825538255482555825568255782558825598256082561825628256382564825658256682567825688256982570825718257282573825748257582576825778257882579825808258182582825838258482585825868258782588825898259082591825928259382594825958259682597825988259982600826018260282603826048260582606826078260882609826108261182612826138261482615826168261782618826198262082621826228262382624826258262682627826288262982630826318263282633826348263582636826378263882639826408264182642826438264482645826468264782648826498265082651826528265382654826558265682657826588265982660826618266282663826648266582666826678266882669826708267182672826738267482675826768267782678826798268082681826828268382684826858268682687826888268982690826918269282693826948269582696826978269882699827008270182702827038270482705827068270782708827098271082711827128271382714827158271682717827188271982720827218272282723827248272582726827278272882729827308273182732827338273482735827368273782738827398274082741827428274382744827458274682747827488274982750827518275282753827548275582756827578275882759827608276182762827638276482765827668276782768827698277082771827728277382774827758277682777827788277982780827818278282783827848278582786827878278882789827908279182792827938279482795827968279782798827998280082801828028280382804828058280682807828088280982810828118281282813828148281582816828178281882819828208282182822828238282482825828268282782828828298283082831828328283382834828358283682837828388283982840828418284282843828448284582846828478284882849828508285182852828538285482855828568285782858828598286082861828628286382864828658286682867828688286982870828718287282873828748287582876828778287882879828808288182882828838288482885828868288782888828898289082891828928289382894828958289682897828988289982900829018290282903829048290582906829078290882909829108291182912829138291482915829168291782918829198292082921829228292382924829258292682927829288292982930829318293282933829348293582936829378293882939829408294182942829438294482945829468294782948829498295082951829528295382954829558295682957829588295982960829618296282963829648296582966829678296882969829708297182972829738297482975829768297782978829798298082981829828298382984829858298682987829888298982990829918299282993829948299582996829978299882999830008300183002830038300483005830068300783008830098301083011830128301383014830158301683017830188301983020830218302283023830248302583026830278302883029830308303183032830338303483035830368303783038830398304083041830428304383044830458304683047830488304983050830518305283053830548305583056830578305883059830608306183062830638306483065830668306783068830698307083071830728307383074830758307683077830788307983080830818308283083830848308583086830878308883089830908309183092830938309483095830968309783098830998310083101831028310383104831058310683107831088310983110831118311283113831148311583116831178311883119831208312183122831238312483125831268312783128831298313083131831328313383134831358313683137831388313983140831418314283143831448314583146831478314883149831508315183152831538315483155831568315783158831598316083161831628316383164831658316683167831688316983170831718317283173831748317583176831778317883179831808318183182831838318483185831868318783188831898319083191831928319383194831958319683197831988319983200832018320283203832048320583206832078320883209832108321183212832138321483215832168321783218832198322083221832228322383224832258322683227832288322983230832318323283233832348323583236832378323883239832408324183242832438324483245832468324783248832498325083251832528325383254832558325683257832588325983260832618326283263832648326583266832678326883269832708327183272832738327483275832768327783278832798328083281832828328383284832858328683287832888328983290832918329283293832948329583296832978329883299833008330183302833038330483305833068330783308833098331083311833128331383314833158331683317833188331983320833218332283323833248332583326833278332883329833308333183332833338333483335833368333783338833398334083341833428334383344833458334683347833488334983350833518335283353833548335583356833578335883359833608336183362833638336483365833668336783368833698337083371833728337383374833758337683377833788337983380833818338283383833848338583386833878338883389833908339183392833938339483395833968339783398833998340083401834028340383404834058340683407834088340983410834118341283413834148341583416834178341883419834208342183422834238342483425834268342783428834298343083431834328343383434834358343683437834388343983440834418344283443834448344583446834478344883449834508345183452834538345483455834568345783458834598346083461834628346383464834658346683467834688346983470834718347283473834748347583476834778347883479834808348183482834838348483485834868348783488834898349083491834928349383494834958349683497834988349983500835018350283503835048350583506835078350883509835108351183512835138351483515835168351783518835198352083521835228352383524835258352683527835288352983530835318353283533835348353583536835378353883539835408354183542835438354483545835468354783548835498355083551835528355383554835558355683557835588355983560835618356283563835648356583566835678356883569835708357183572835738357483575835768357783578835798358083581835828358383584835858358683587835888358983590835918359283593835948359583596835978359883599836008360183602836038360483605836068360783608836098361083611836128361383614836158361683617836188361983620836218362283623836248362583626836278362883629836308363183632836338363483635836368363783638836398364083641836428364383644836458364683647836488364983650836518365283653836548365583656836578365883659836608366183662836638366483665836668366783668836698367083671836728367383674836758367683677836788367983680836818368283683836848368583686836878368883689836908369183692836938369483695836968369783698836998370083701837028370383704837058370683707837088370983710837118371283713837148371583716837178371883719837208372183722837238372483725837268372783728837298373083731837328373383734837358373683737837388373983740837418374283743837448374583746837478374883749837508375183752837538375483755837568375783758837598376083761837628376383764837658376683767837688376983770837718377283773837748377583776837778377883779837808378183782837838378483785837868378783788837898379083791837928379383794837958379683797837988379983800838018380283803838048380583806838078380883809838108381183812838138381483815838168381783818838198382083821838228382383824838258382683827838288382983830838318383283833838348383583836838378383883839838408384183842838438384483845838468384783848838498385083851838528385383854838558385683857838588385983860838618386283863838648386583866838678386883869838708387183872838738387483875838768387783878838798388083881838828388383884838858388683887838888388983890838918389283893838948389583896838978389883899839008390183902839038390483905839068390783908839098391083911839128391383914839158391683917839188391983920839218392283923839248392583926839278392883929839308393183932839338393483935839368393783938839398394083941839428394383944839458394683947839488394983950839518395283953839548395583956839578395883959839608396183962839638396483965839668396783968839698397083971839728397383974839758397683977839788397983980839818398283983839848398583986839878398883989839908399183992839938399483995839968399783998839998400084001840028400384004840058400684007840088400984010840118401284013840148401584016840178401884019840208402184022840238402484025840268402784028840298403084031840328403384034840358403684037840388403984040840418404284043840448404584046840478404884049840508405184052840538405484055840568405784058840598406084061840628406384064840658406684067840688406984070840718407284073840748407584076840778407884079840808408184082840838408484085840868408784088840898409084091840928409384094840958409684097840988409984100841018410284103841048410584106841078410884109841108411184112841138411484115841168411784118841198412084121841228412384124841258412684127841288412984130841318413284133841348413584136841378413884139841408414184142841438414484145841468414784148841498415084151841528415384154841558415684157841588415984160841618416284163841648416584166841678416884169841708417184172841738417484175841768417784178841798418084181841828418384184841858418684187841888418984190841918419284193841948419584196841978419884199842008420184202842038420484205842068420784208842098421084211842128421384214842158421684217842188421984220842218422284223842248422584226842278422884229842308423184232842338423484235842368423784238842398424084241842428424384244842458424684247842488424984250842518425284253842548425584256842578425884259842608426184262842638426484265842668426784268842698427084271842728427384274842758427684277842788427984280842818428284283842848428584286842878428884289842908429184292842938429484295842968429784298842998430084301843028430384304843058430684307843088430984310843118431284313843148431584316843178431884319843208432184322843238432484325843268432784328843298433084331843328433384334843358433684337843388433984340843418434284343843448434584346843478434884349843508435184352843538435484355843568435784358843598436084361843628436384364843658436684367843688436984370843718437284373843748437584376843778437884379843808438184382843838438484385843868438784388843898439084391843928439384394843958439684397843988439984400844018440284403844048440584406844078440884409844108441184412844138441484415844168441784418844198442084421844228442384424844258442684427844288442984430844318443284433844348443584436844378443884439844408444184442844438444484445844468444784448844498445084451844528445384454844558445684457844588445984460844618446284463844648446584466844678446884469844708447184472844738447484475844768447784478844798448084481844828448384484844858448684487844888448984490844918449284493844948449584496844978449884499845008450184502845038450484505845068450784508845098451084511845128451384514845158451684517845188451984520845218452284523845248452584526845278452884529845308453184532845338453484535845368453784538845398454084541845428454384544845458454684547845488454984550845518455284553845548455584556845578455884559845608456184562845638456484565845668456784568845698457084571845728457384574845758457684577845788457984580845818458284583845848458584586845878458884589845908459184592845938459484595845968459784598845998460084601846028460384604846058460684607846088460984610846118461284613846148461584616846178461884619846208462184622846238462484625846268462784628846298463084631846328463384634846358463684637846388463984640846418464284643846448464584646846478464884649846508465184652846538465484655846568465784658846598466084661846628466384664846658466684667846688466984670846718467284673846748467584676846778467884679846808468184682846838468484685846868468784688846898469084691846928469384694846958469684697846988469984700847018470284703847048470584706847078470884709847108471184712847138471484715847168471784718847198472084721847228472384724847258472684727847288472984730847318473284733847348473584736847378473884739847408474184742847438474484745847468474784748847498475084751847528475384754847558475684757847588475984760847618476284763847648476584766847678476884769847708477184772847738477484775847768477784778847798478084781847828478384784847858478684787847888478984790847918479284793847948479584796847978479884799848008480184802848038480484805848068480784808848098481084811848128481384814848158481684817848188481984820848218482284823848248482584826848278482884829848308483184832848338483484835848368483784838848398484084841848428484384844848458484684847848488484984850848518485284853848548485584856848578485884859848608486184862848638486484865848668486784868848698487084871848728487384874848758487684877848788487984880848818488284883848848488584886848878488884889848908489184892848938489484895848968489784898848998490084901849028490384904849058490684907849088490984910849118491284913849148491584916849178491884919849208492184922849238492484925849268492784928849298493084931849328493384934849358493684937849388493984940849418494284943849448494584946849478494884949849508495184952849538495484955849568495784958849598496084961849628496384964849658496684967849688496984970849718497284973849748497584976849778497884979849808498184982849838498484985849868498784988849898499084991849928499384994849958499684997849988499985000850018500285003850048500585006850078500885009850108501185012850138501485015850168501785018850198502085021850228502385024850258502685027850288502985030850318503285033850348503585036850378503885039850408504185042850438504485045850468504785048850498505085051850528505385054850558505685057850588505985060850618506285063850648506585066850678506885069850708507185072850738507485075850768507785078850798508085081850828508385084850858508685087850888508985090850918509285093850948509585096850978509885099851008510185102851038510485105851068510785108851098511085111851128511385114851158511685117851188511985120851218512285123851248512585126851278512885129851308513185132851338513485135851368513785138851398514085141851428514385144851458514685147851488514985150851518515285153851548515585156851578515885159851608516185162851638516485165851668516785168851698517085171851728517385174851758517685177851788517985180851818518285183851848518585186851878518885189851908519185192851938519485195851968519785198851998520085201852028520385204852058520685207852088520985210852118521285213852148521585216852178521885219852208522185222852238522485225852268522785228852298523085231852328523385234852358523685237852388523985240852418524285243852448524585246852478524885249852508525185252852538525485255852568525785258852598526085261852628526385264852658526685267852688526985270852718527285273852748527585276852778527885279852808528185282852838528485285852868528785288852898529085291852928529385294852958529685297852988529985300853018530285303853048530585306853078530885309853108531185312853138531485315853168531785318853198532085321853228532385324853258532685327853288532985330853318533285333853348533585336853378533885339853408534185342853438534485345853468534785348853498535085351853528535385354853558535685357853588535985360853618536285363853648536585366853678536885369853708537185372853738537485375853768537785378853798538085381853828538385384853858538685387853888538985390853918539285393853948539585396853978539885399854008540185402854038540485405854068540785408854098541085411854128541385414854158541685417854188541985420854218542285423854248542585426854278542885429854308543185432854338543485435854368543785438854398544085441854428544385444854458544685447854488544985450854518545285453854548545585456854578545885459854608546185462854638546485465854668546785468854698547085471854728547385474854758547685477854788547985480854818548285483854848548585486854878548885489854908549185492854938549485495854968549785498854998550085501855028550385504855058550685507855088550985510855118551285513855148551585516855178551885519855208552185522855238552485525855268552785528855298553085531855328553385534855358553685537855388553985540855418554285543855448554585546855478554885549855508555185552855538555485555855568555785558855598556085561855628556385564855658556685567855688556985570855718557285573855748557585576855778557885579855808558185582855838558485585855868558785588855898559085591855928559385594855958559685597855988559985600856018560285603856048560585606856078560885609856108561185612856138561485615856168561785618856198562085621856228562385624856258562685627856288562985630856318563285633856348563585636856378563885639856408564185642856438564485645856468564785648856498565085651856528565385654856558565685657856588565985660856618566285663856648566585666856678566885669856708567185672856738567485675856768567785678856798568085681856828568385684856858568685687856888568985690856918569285693856948569585696856978569885699857008570185702857038570485705857068570785708857098571085711857128571385714857158571685717857188571985720857218572285723857248572585726857278572885729857308573185732857338573485735857368573785738857398574085741857428574385744857458574685747857488574985750857518575285753857548575585756857578575885759857608576185762857638576485765857668576785768857698577085771857728577385774857758577685777857788577985780857818578285783857848578585786857878578885789857908579185792857938579485795857968579785798857998580085801 |
- #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__)
- #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(_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)
- #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
- ////
- #ifdef _WIN32
- /*
- * Dirent interface for Microsoft Visual Studio
- *
- * Copyright (C) 1998-2019 Toni Ronkko
- * This file is part of dirent. Dirent may be freely distributed
- * under the MIT license. For all details and documentation, see
- * https://github.com/tronkko/dirent
- */
- #ifndef DIRENT_H
- #define DIRENT_H
- /* Hide warnings about unreferenced local functions */
- #if defined(__clang__)
- # pragma clang diagnostic ignored "-Wunused-function"
- #elif defined(_MSC_VER)
- # pragma warning(disable:4505)
- #elif defined(__GNUC__)
- # pragma GCC diagnostic ignored "-Wunused-function"
- #endif
- /*
- * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
- * Windows Sockets 2.0.
- */
- #ifndef WIN32_LEAN_AND_MEAN
- # define WIN32_LEAN_AND_MEAN
- #endif
- #include <windows.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <wchar.h>
- #include <string.h>
- #include <stdlib.h>
- #include <malloc.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- /* Indicates that d_type field is available in dirent structure */
- #define _DIRENT_HAVE_D_TYPE
- /* Indicates that d_namlen field is available in dirent structure */
- #define _DIRENT_HAVE_D_NAMLEN
- /* Entries missing from MSVC 6.0 */
- #if !defined(FILE_ATTRIBUTE_DEVICE)
- # define FILE_ATTRIBUTE_DEVICE 0x40
- #endif
- /* File type and permission flags for stat(), general mask */
- #if !defined(S_IFMT)
- # define S_IFMT _S_IFMT
- #endif
- /* Directory bit */
- #if !defined(S_IFDIR)
- # define S_IFDIR _S_IFDIR
- #endif
- /* Character device bit */
- #if !defined(S_IFCHR)
- # define S_IFCHR _S_IFCHR
- #endif
- /* Pipe bit */
- #if !defined(S_IFFIFO)
- # define S_IFFIFO _S_IFFIFO
- #endif
- /* Regular file bit */
- #if !defined(S_IFREG)
- # define S_IFREG _S_IFREG
- #endif
- /* Read permission */
- #if !defined(S_IREAD)
- # define S_IREAD _S_IREAD
- #endif
- /* Write permission */
- #if !defined(S_IWRITE)
- # define S_IWRITE _S_IWRITE
- #endif
- /* Execute permission */
- #if !defined(S_IEXEC)
- # define S_IEXEC _S_IEXEC
- #endif
- /* Pipe */
- #if !defined(S_IFIFO)
- # define S_IFIFO _S_IFIFO
- #endif
- /* Block device */
- #if !defined(S_IFBLK)
- # define S_IFBLK 0
- #endif
- /* Link */
- #if !defined(S_IFLNK)
- # define S_IFLNK 0
- #endif
- /* Socket */
- #if !defined(S_IFSOCK)
- # define S_IFSOCK 0
- #endif
- /* Read user permission */
- #if !defined(S_IRUSR)
- # define S_IRUSR S_IREAD
- #endif
- /* Write user permission */
- #if !defined(S_IWUSR)
- # define S_IWUSR S_IWRITE
- #endif
- /* Execute user permission */
- #if !defined(S_IXUSR)
- # define S_IXUSR 0
- #endif
- /* Read group permission */
- #if !defined(S_IRGRP)
- # define S_IRGRP 0
- #endif
- /* Write group permission */
- #if !defined(S_IWGRP)
- # define S_IWGRP 0
- #endif
- /* Execute group permission */
- #if !defined(S_IXGRP)
- # define S_IXGRP 0
- #endif
- /* Read others permission */
- #if !defined(S_IROTH)
- # define S_IROTH 0
- #endif
- /* Write others permission */
- #if !defined(S_IWOTH)
- # define S_IWOTH 0
- #endif
- /* Execute others permission */
- #if !defined(S_IXOTH)
- # define S_IXOTH 0
- #endif
- /* Maximum length of file name */
- #if !defined(PATH_MAX)
- # define PATH_MAX MAX_PATH
- #endif
- #if !defined(FILENAME_MAX)
- # define FILENAME_MAX MAX_PATH
- #endif
- #if !defined(NAME_MAX)
- # define NAME_MAX FILENAME_MAX
- #endif
- /* File type flags for d_type */
- #define DT_UNKNOWN 0
- #define DT_REG S_IFREG
- #define DT_DIR S_IFDIR
- #define DT_FIFO S_IFIFO
- #define DT_SOCK S_IFSOCK
- #define DT_CHR S_IFCHR
- #define DT_BLK S_IFBLK
- #define DT_LNK S_IFLNK
- /* Macros for converting between st_mode and d_type */
- #define IFTODT(mode) ((mode) & S_IFMT)
- #define DTTOIF(type) (type)
- /*
- * File type macros. Note that block devices, sockets and links cannot be
- * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
- * only defined for compatibility. These macros should always return false
- * on Windows.
- */
- #if !defined(S_ISFIFO)
- # define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
- #endif
- #if !defined(S_ISDIR)
- # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
- #endif
- #if !defined(S_ISREG)
- # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
- #endif
- #if !defined(S_ISLNK)
- # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
- #endif
- #if !defined(S_ISSOCK)
- # define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
- #endif
- #if !defined(S_ISCHR)
- # define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
- #endif
- #if !defined(S_ISBLK)
- # define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
- #endif
- /* Return the exact length of the file name without zero terminator */
- #define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
- /* Return the maximum size of a file name */
- #define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
- #ifdef __cplusplus
- extern "C" {
- #endif
- /* Wide-character version */
- struct _wdirent {
- /* Always zero */
- long d_ino;
- /* File position within stream */
- long d_off;
- /* Structure size */
- unsigned short d_reclen;
- /* Length of name without \0 */
- size_t d_namlen;
- /* File type */
- int d_type;
- /* File name */
- wchar_t d_name[PATH_MAX+1];
- };
- typedef struct _wdirent _wdirent;
- struct _WDIR {
- /* Current directory entry */
- struct _wdirent ent;
- /* Private file data */
- WIN32_FIND_DATAW data;
- /* True if data is valid */
- int cached;
- /* Win32 search handle */
- HANDLE handle;
- /* Initial directory name */
- wchar_t *patt;
- };
- typedef struct _WDIR _WDIR;
- /* Multi-byte character version */
- struct dirent {
- /* Always zero */
- long d_ino;
- /* File position within stream */
- long d_off;
- /* Structure size */
- unsigned short d_reclen;
- /* Length of name without \0 */
- size_t d_namlen;
- /* File type */
- int d_type;
- /* File name */
- char d_name[PATH_MAX+1];
- };
- typedef struct dirent dirent;
- struct DIR {
- struct dirent ent;
- struct _WDIR *wdirp;
- };
- typedef struct DIR DIR;
- /* Dirent functions */
- static DIR *opendir (const char *dirname);
- static _WDIR *_wopendir (const wchar_t *dirname);
- static struct dirent *readdir (DIR *dirp);
- static struct _wdirent *_wreaddir (_WDIR *dirp);
- static int readdir_r(
- DIR *dirp, struct dirent *entry, struct dirent **result);
- static int _wreaddir_r(
- _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
- static int closedir (DIR *dirp);
- static int _wclosedir (_WDIR *dirp);
- static void rewinddir (DIR* dirp);
- static void _wrewinddir (_WDIR* dirp);
- static int scandir (const char *dirname, struct dirent ***namelist,
- int (*filter)(const struct dirent*),
- int (*compare)(const struct dirent**, const struct dirent**));
- static int alphasort (const struct dirent **a, const struct dirent **b);
- static int versionsort (const struct dirent **a, const struct dirent **b);
- /* For compatibility with Symbian */
- #define wdirent _wdirent
- #define WDIR _WDIR
- #define wopendir _wopendir
- #define wreaddir _wreaddir
- #define wclosedir _wclosedir
- #define wrewinddir _wrewinddir
- /* Internal utility functions */
- static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
- static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
- static int dirent_mbstowcs_s(
- size_t *pReturnValue,
- wchar_t *wcstr,
- size_t sizeInWords,
- const char *mbstr,
- size_t count);
- static int dirent_wcstombs_s(
- size_t *pReturnValue,
- char *mbstr,
- size_t sizeInBytes,
- const wchar_t *wcstr,
- size_t count);
- static void dirent_set_errno (int error);
- /*
- * Open directory stream DIRNAME for read and return a pointer to the
- * internal working area that is used to retrieve individual directory
- * entries.
- */
- static _WDIR*
- _wopendir(
- const wchar_t *dirname)
- {
- _WDIR *dirp;
- #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
- /* Desktop */
- DWORD n;
- #else
- /* WinRT */
- size_t n;
- #endif
- wchar_t *p;
- /* Must have directory name */
- if (dirname == NULL || dirname[0] == '\0') {
- dirent_set_errno (ENOENT);
- return NULL;
- }
- /* Allocate new _WDIR structure */
- dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
- if (!dirp) {
- return NULL;
- }
- /* Reset _WDIR structure */
- dirp->handle = INVALID_HANDLE_VALUE;
- dirp->patt = NULL;
- dirp->cached = 0;
- /*
- * Compute the length of full path plus zero terminator
- *
- * Note that on WinRT there's no way to convert relative paths
- * into absolute paths, so just assume it is an absolute path.
- */
- #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
- /* Desktop */
- n = GetFullPathNameW (dirname, 0, NULL, NULL);
- #else
- /* WinRT */
- n = wcslen (dirname);
- #endif
- /* Allocate room for absolute directory name and search pattern */
- dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
- if (dirp->patt == NULL) {
- goto exit_closedir;
- }
- /*
- * Convert relative directory name to an absolute one. This
- * allows rewinddir() to function correctly even when current
- * working directory is changed between opendir() and rewinddir().
- *
- * Note that on WinRT there's no way to convert relative paths
- * into absolute paths, so just assume it is an absolute path.
- */
- #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
- /* Desktop */
- n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
- if (n <= 0) {
- goto exit_closedir;
- }
- #else
- /* WinRT */
- wcsncpy_s (dirp->patt, n+1, dirname, n);
- #endif
- /* Append search pattern \* to the directory name */
- p = dirp->patt + n;
- switch (p[-1]) {
- case '\\':
- case '/':
- case ':':
- /* Directory ends in path separator, e.g. c:\temp\ */
- /*NOP*/;
- break;
- default:
- /* Directory name doesn't end in path separator */
- *p++ = '\\';
- }
- *p++ = '*';
- *p = '\0';
- /* Open directory stream and retrieve the first entry */
- if (!dirent_first (dirp)) {
- goto exit_closedir;
- }
- /* Success */
- return dirp;
- /* Failure */
- exit_closedir:
- _wclosedir (dirp);
- return NULL;
- }
- /*
- * Read next directory entry.
- *
- * Returns pointer to static directory entry which may be overwritten by
- * subsequent calls to _wreaddir().
- */
- static struct _wdirent*
- _wreaddir(
- _WDIR *dirp)
- {
- struct _wdirent *entry;
- /*
- * Read directory entry to buffer. We can safely ignore the return value
- * as entry will be set to NULL in case of error.
- */
- (void) _wreaddir_r (dirp, &dirp->ent, &entry);
- /* Return pointer to statically allocated directory entry */
- return entry;
- }
- /*
- * Read next directory entry.
- *
- * Returns zero on success. If end of directory stream is reached, then sets
- * result to NULL and returns zero.
- */
- static int
- _wreaddir_r(
- _WDIR *dirp,
- struct _wdirent *entry,
- struct _wdirent **result)
- {
- WIN32_FIND_DATAW *datap;
- /* Read next directory entry */
- datap = dirent_next (dirp);
- if (datap) {
- size_t n;
- DWORD attr;
- /*
- * Copy file name as wide-character string. If the file name is too
- * long to fit in to the destination buffer, then truncate file name
- * to PATH_MAX characters and zero-terminate the buffer.
- */
- n = 0;
- while (n < PATH_MAX && datap->cFileName[n] != 0) {
- entry->d_name[n] = datap->cFileName[n];
- n++;
- }
- entry->d_name[n] = 0;
- /* Length of file name excluding zero terminator */
- entry->d_namlen = n;
- /* File type */
- attr = datap->dwFileAttributes;
- if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
- entry->d_type = DT_CHR;
- } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
- entry->d_type = DT_DIR;
- } else {
- entry->d_type = DT_REG;
- }
- /* Reset dummy fields */
- entry->d_ino = 0;
- entry->d_off = 0;
- entry->d_reclen = sizeof (struct _wdirent);
- /* Set result address */
- *result = entry;
- } else {
- /* Return NULL to indicate end of directory */
- *result = NULL;
- }
- return /*OK*/0;
- }
- /*
- * Close directory stream opened by opendir() function. This invalidates the
- * DIR structure as well as any directory entry read previously by
- * _wreaddir().
- */
- static int
- _wclosedir(
- _WDIR *dirp)
- {
- int ok;
- if (dirp) {
- /* Release search handle */
- if (dirp->handle != INVALID_HANDLE_VALUE) {
- FindClose (dirp->handle);
- }
- /* Release search pattern */
- free (dirp->patt);
- /* Release directory structure */
- free (dirp);
- ok = /*success*/0;
- } else {
- /* Invalid directory stream */
- dirent_set_errno (EBADF);
- ok = /*failure*/-1;
- }
- return ok;
- }
- /*
- * Rewind directory stream such that _wreaddir() returns the very first
- * file name again.
- */
- static void
- _wrewinddir(
- _WDIR* dirp)
- {
- if (dirp) {
- /* Release existing search handle */
- if (dirp->handle != INVALID_HANDLE_VALUE) {
- FindClose (dirp->handle);
- }
- /* Open new search handle */
- dirent_first (dirp);
- }
- }
- /* Get first directory entry (internal) */
- static WIN32_FIND_DATAW*
- dirent_first(
- _WDIR *dirp)
- {
- WIN32_FIND_DATAW *datap;
- DWORD error;
- /* Open directory and retrieve the first entry */
- dirp->handle = FindFirstFileExW(
- dirp->patt, FindExInfoStandard, &dirp->data,
- FindExSearchNameMatch, NULL, 0);
- if (dirp->handle != INVALID_HANDLE_VALUE) {
- /* a directory entry is now waiting in memory */
- datap = &dirp->data;
- dirp->cached = 1;
- } else {
- /* Failed to open directory: no directory entry in memory */
- dirp->cached = 0;
- datap = NULL;
- /* Set error code */
- error = GetLastError ();
- switch (error) {
- case ERROR_ACCESS_DENIED:
- /* No read access to directory */
- dirent_set_errno (EACCES);
- break;
- case ERROR_DIRECTORY:
- /* Directory name is invalid */
- dirent_set_errno (ENOTDIR);
- break;
- case ERROR_PATH_NOT_FOUND:
- default:
- /* Cannot find the file */
- dirent_set_errno (ENOENT);
- }
- }
- return datap;
- }
- /*
- * Get next directory entry (internal).
- *
- * Returns
- */
- static WIN32_FIND_DATAW*
- dirent_next(
- _WDIR *dirp)
- {
- WIN32_FIND_DATAW *p;
- /* Get next directory entry */
- if (dirp->cached != 0) {
- /* A valid directory entry already in memory */
- p = &dirp->data;
- dirp->cached = 0;
- } else if (dirp->handle != INVALID_HANDLE_VALUE) {
- /* Get the next directory entry from stream */
- if (FindNextFileW (dirp->handle, &dirp->data) != 0) {
- /* Got a file */
- p = &dirp->data;
- } else {
- /* The very last entry has been processed or an error occurred */
- FindClose (dirp->handle);
- dirp->handle = INVALID_HANDLE_VALUE;
- p = NULL;
- }
- } else {
- /* End of directory stream reached */
- p = NULL;
- }
- return p;
- }
- /*
- * Open directory stream using plain old C-string.
- */
- static DIR*
- opendir(
- const char *dirname)
- {
- struct DIR *dirp;
- /* Must have directory name */
- if (dirname == NULL || dirname[0] == '\0') {
- dirent_set_errno (ENOENT);
- return NULL;
- }
- /* Allocate memory for DIR structure */
- dirp = (DIR*) malloc (sizeof (struct DIR));
- if (!dirp) {
- return NULL;
- }
- {
- int error;
- wchar_t wname[PATH_MAX + 1];
- size_t n;
- /* Convert directory name to wide-character string */
- error = dirent_mbstowcs_s(
- &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1);
- if (error) {
- /*
- * Cannot convert file name to wide-character string. This
- * occurs if the string contains invalid multi-byte sequences or
- * the output buffer is too small to contain the resulting
- * string.
- */
- goto exit_free;
- }
- /* Open directory stream using wide-character name */
- dirp->wdirp = _wopendir (wname);
- if (!dirp->wdirp) {
- goto exit_free;
- }
- }
- /* Success */
- return dirp;
- /* Failure */
- exit_free:
- free (dirp);
- return NULL;
- }
- /*
- * Read next directory entry.
- */
- static struct dirent*
- readdir(
- DIR *dirp)
- {
- struct dirent *entry;
- /*
- * Read directory entry to buffer. We can safely ignore the return value
- * as entry will be set to NULL in case of error.
- */
- (void) readdir_r (dirp, &dirp->ent, &entry);
- /* Return pointer to statically allocated directory entry */
- return entry;
- }
- /*
- * Read next directory entry into called-allocated buffer.
- *
- * Returns zero on success. If the end of directory stream is reached, then
- * sets result to NULL and returns zero.
- */
- static int
- readdir_r(
- DIR *dirp,
- struct dirent *entry,
- struct dirent **result)
- {
- WIN32_FIND_DATAW *datap;
- /* Read next directory entry */
- datap = dirent_next (dirp->wdirp);
- if (datap) {
- size_t n;
- int error;
- /* Attempt to convert file name to multi-byte string */
- error = dirent_wcstombs_s(
- &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1);
- /*
- * If the file name cannot be represented by a multi-byte string,
- * then attempt to use old 8+3 file name. This allows traditional
- * Unix-code to access some file names despite of unicode
- * characters, although file names may seem unfamiliar to the user.
- *
- * Be ware that the code below cannot come up with a short file
- * name unless the file system provides one. At least
- * VirtualBox shared folders fail to do this.
- */
- if (error && datap->cAlternateFileName[0] != '\0') {
- error = dirent_wcstombs_s(
- &n, entry->d_name, PATH_MAX + 1,
- datap->cAlternateFileName, PATH_MAX + 1);
- }
- if (!error) {
- DWORD attr;
- /* Length of file name excluding zero terminator */
- entry->d_namlen = n - 1;
- /* File attributes */
- attr = datap->dwFileAttributes;
- if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
- entry->d_type = DT_CHR;
- } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
- entry->d_type = DT_DIR;
- } else {
- entry->d_type = DT_REG;
- }
- /* Reset dummy fields */
- entry->d_ino = 0;
- entry->d_off = 0;
- entry->d_reclen = sizeof (struct dirent);
- } else {
- /*
- * Cannot convert file name to multi-byte string so construct
- * an erroneous directory entry and return that. Note that
- * we cannot return NULL as that would stop the processing
- * of directory entries completely.
- */
- entry->d_name[0] = '?';
- entry->d_name[1] = '\0';
- entry->d_namlen = 1;
- entry->d_type = DT_UNKNOWN;
- entry->d_ino = 0;
- entry->d_off = -1;
- entry->d_reclen = 0;
- }
- /* Return pointer to directory entry */
- *result = entry;
- } else {
- /* No more directory entries */
- *result = NULL;
- }
- return /*OK*/0;
- }
- /*
- * Close directory stream.
- */
- static int
- closedir(
- DIR *dirp)
- {
- int ok;
- if (dirp) {
- /* Close wide-character directory stream */
- ok = _wclosedir (dirp->wdirp);
- dirp->wdirp = NULL;
- /* Release multi-byte character version */
- free (dirp);
- } else {
- /* Invalid directory stream */
- dirent_set_errno (EBADF);
- ok = /*failure*/-1;
- }
- return ok;
- }
- /*
- * Rewind directory stream to beginning.
- */
- static void
- rewinddir(
- DIR* dirp)
- {
- /* Rewind wide-character string directory stream */
- _wrewinddir (dirp->wdirp);
- }
- /*
- * Scan directory for entries.
- */
- static int
- scandir(
- const char *dirname,
- struct dirent ***namelist,
- int (*filter)(const struct dirent*),
- int (*compare)(const struct dirent**, const struct dirent**))
- {
- struct dirent **files = NULL;
- size_t size = 0;
- size_t allocated = 0;
- const size_t init_size = 1;
- DIR *dir = NULL;
- struct dirent *entry;
- struct dirent *tmp = NULL;
- size_t i;
- int result = 0;
- /* Open directory stream */
- dir = opendir (dirname);
- if (dir) {
- /* Read directory entries to memory */
- while (1) {
- /* Enlarge pointer table to make room for another pointer */
- if (size >= allocated) {
- void *p;
- size_t num_entries;
- /* Compute number of entries in the enlarged pointer table */
- if (size < init_size) {
- /* Allocate initial pointer table */
- num_entries = init_size;
- } else {
- /* Double the size */
- num_entries = size * 2;
- }
- /* Allocate first pointer table or enlarge existing table */
- p = realloc (files, sizeof (void*) * num_entries);
- if (p != NULL) {
- /* Got the memory */
- files = (dirent**) p;
- allocated = num_entries;
- } else {
- /* Out of memory */
- result = -1;
- break;
- }
- }
- /* Allocate room for temporary directory entry */
- if (tmp == NULL) {
- tmp = (struct dirent*) malloc (sizeof (struct dirent));
- if (tmp == NULL) {
- /* Cannot allocate temporary directory entry */
- result = -1;
- break;
- }
- }
- /* Read directory entry to temporary area */
- if (readdir_r (dir, tmp, &entry) == /*OK*/0) {
- /* Did we get an entry? */
- if (entry != NULL) {
- int pass;
- /* Determine whether to include the entry in result */
- if (filter) {
- /* Let the filter function decide */
- pass = filter (tmp);
- } else {
- /* No filter function, include everything */
- pass = 1;
- }
- if (pass) {
- /* Store the temporary entry to pointer table */
- files[size++] = tmp;
- tmp = NULL;
- /* Keep up with the number of files */
- result++;
- }
- } else {
- /*
- * End of directory stream reached => sort entries and
- * exit.
- */
- qsort (files, size, sizeof (void*),
- (int (*) (const void*, const void*)) compare);
- break;
- }
- } else {
- /* Error reading directory entry */
- result = /*Error*/ -1;
- break;
- }
- }
- } else {
- /* Cannot open directory */
- result = /*Error*/ -1;
- }
- /* Release temporary directory entry */
- free (tmp);
- /* Release allocated memory on error */
- if (result < 0) {
- for (i = 0; i < size; i++) {
- free (files[i]);
- }
- free (files);
- files = NULL;
- }
- /* Close directory stream */
- if (dir) {
- closedir (dir);
- }
- /* Pass pointer table to caller */
- if (namelist) {
- *namelist = files;
- }
- return result;
- }
- /* Alphabetical sorting */
- static int
- alphasort(
- const struct dirent **a, const struct dirent **b)
- {
- return strcoll ((*a)->d_name, (*b)->d_name);
- }
- /* Sort versions */
- static int
- versionsort(
- const struct dirent **a, const struct dirent **b)
- {
- /* FIXME: implement strverscmp and use that */
- return alphasort (a, b);
- }
- /* Convert multi-byte string to wide character string */
- static int
- dirent_mbstowcs_s(
- size_t *pReturnValue,
- wchar_t *wcstr,
- size_t sizeInWords,
- const char *mbstr,
- size_t count)
- {
- int error;
- #if defined(_MSC_VER) && _MSC_VER >= 1400
- /* Microsoft Visual Studio 2005 or later */
- error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
- #else
- /* Older Visual Studio or non-Microsoft compiler */
- size_t n;
- /* Convert to wide-character string (or count characters) */
- n = mbstowcs (wcstr, mbstr, sizeInWords);
- if (!wcstr || n < count) {
- /* Zero-terminate output buffer */
- if (wcstr && sizeInWords) {
- if (n >= sizeInWords) {
- n = sizeInWords - 1;
- }
- wcstr[n] = 0;
- }
- /* Length of resulting multi-byte string WITH zero terminator */
- if (pReturnValue) {
- *pReturnValue = n + 1;
- }
- /* Success */
- error = 0;
- } else {
- /* Could not convert string */
- error = 1;
- }
- #endif
- return error;
- }
- /* Convert wide-character string to multi-byte string */
- static int
- dirent_wcstombs_s(
- size_t *pReturnValue,
- char *mbstr,
- size_t sizeInBytes, /* max size of mbstr */
- const wchar_t *wcstr,
- size_t count)
- {
- int error;
- #if defined(_MSC_VER) && _MSC_VER >= 1400
- /* Microsoft Visual Studio 2005 or later */
- error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
- #else
- /* Older Visual Studio or non-Microsoft compiler */
- size_t n;
- /* Convert to multi-byte string (or count the number of bytes needed) */
- n = wcstombs (mbstr, wcstr, sizeInBytes);
- if (!mbstr || n < count) {
- /* Zero-terminate output buffer */
- if (mbstr && sizeInBytes) {
- if (n >= sizeInBytes) {
- n = sizeInBytes - 1;
- }
- mbstr[n] = '\0';
- }
- /* Length of resulting multi-bytes string WITH zero-terminator */
- if (pReturnValue) {
- *pReturnValue = n + 1;
- }
- /* Success */
- error = 0;
- } else {
- /* Cannot convert string */
- error = 1;
- }
- #endif
- return error;
- }
- /* Set errno variable */
- static void
- dirent_set_errno(
- int error)
- {
- #if defined(_MSC_VER) && _MSC_VER >= 1400
- /* Microsoft Visual Studio 2005 and later */
- _set_errno (error);
- #else
- /* Non-Microsoft compiler or older Microsoft compiler */
- errno = error;
- #endif
- }
- #ifdef __cplusplus
- }
- #endif
- #endif /*DIRENT_H*/
- #endif // _WIN32
- ////
- 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;
- }
- extern char const digits36[36];
- size_t u32toa(char buf[minimum_length(11)], uint32_t n);
- size_t i32toa(char buf[minimum_length(12)], int32_t n);
- size_t u64toa(char buf[minimum_length(21)], uint64_t n);
- size_t i64toa(char buf[minimum_length(22)], int64_t n);
- size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned int base);
- size_t i32toa_radix(char buf[minimum_length(34)], int32_t n, unsigned base);
- size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned int base);
- size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base);
- void rqsort(void *base, size_t nmemb, size_t size,
- int (*cmp)(const void *, const void *, void *),
- void *arg);
- 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__)
- return malloc_usable_size((void *)ptr);
- #else
- return 0;
- #endif
- }
- /* Cross-platform threading APIs. */
- #if !defined(EMSCRIPTEN) && !defined(__wasi__)
- #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;
- #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;
- #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);
- #endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */
- #ifdef __cplusplus
- } /* extern "C" { */
- #endif
- #endif /* CUTILS_H */
- /*
- * 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 */
- /*
- * Tiny arbitrary precision floating point library
- *
- * Copyright (c) 2017-2021 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 LIBBF_H
- #define LIBBF_H
- #include <stddef.h>
- #include <stdint.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- #if INTPTR_MAX >= INT64_MAX && !defined(_WIN32) && !defined(__TINYC__)
- #define LIMB_LOG2_BITS 6
- #else
- #define LIMB_LOG2_BITS 5
- #endif
- #define LIMB_BITS (1 << LIMB_LOG2_BITS)
- #if LIMB_BITS == 64
- #ifndef INT128_MAX
- __extension__ typedef __int128 int128_t;
- __extension__ typedef unsigned __int128 uint128_t;
- #endif
- typedef int64_t slimb_t;
- typedef uint64_t limb_t;
- typedef uint128_t dlimb_t;
- #define BF_RAW_EXP_MIN INT64_MIN
- #define BF_RAW_EXP_MAX INT64_MAX
- #define LIMB_DIGITS 19
- #define BF_DEC_BASE UINT64_C(10000000000000000000)
- #else
- typedef int32_t slimb_t;
- typedef uint32_t limb_t;
- typedef uint64_t dlimb_t;
- #define BF_RAW_EXP_MIN INT32_MIN
- #define BF_RAW_EXP_MAX INT32_MAX
- #define LIMB_DIGITS 9
- #define BF_DEC_BASE 1000000000U
- #endif
- /* in bits */
- /* minimum number of bits for the exponent */
- #define BF_EXP_BITS_MIN 3
- /* maximum number of bits for the exponent */
- #define BF_EXP_BITS_MAX (LIMB_BITS - 3)
- /* extended range for exponent, used internally */
- #define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1)
- /* minimum possible precision */
- #define BF_PREC_MIN 2
- /* minimum possible precision */
- #define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2)
- /* some operations support infinite precision */
- #define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */
- #if LIMB_BITS == 64
- #define BF_CHKSUM_MOD (UINT64_C(975620677) * UINT64_C(9795002197))
- #else
- #define BF_CHKSUM_MOD 975620677U
- #endif
- #define BF_EXP_ZERO BF_RAW_EXP_MIN
- #define BF_EXP_INF (BF_RAW_EXP_MAX - 1)
- #define BF_EXP_NAN BF_RAW_EXP_MAX
- /* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,
- +/-infinity is represented with expn = BF_EXP_INF and len = 0,
- NaN is represented with expn = BF_EXP_NAN and len = 0 (sign is ignored)
- */
- typedef struct {
- struct bf_context_t *ctx;
- int sign;
- slimb_t expn;
- limb_t len;
- limb_t *tab;
- } bf_t;
- typedef struct {
- /* must be kept identical to bf_t */
- struct bf_context_t *ctx;
- int sign;
- slimb_t expn;
- limb_t len;
- limb_t *tab;
- } bfdec_t;
- typedef enum {
- BF_RNDN, /* round to nearest, ties to even */
- BF_RNDZ, /* round to zero */
- BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */
- BF_RNDU, /* round to +inf */
- BF_RNDNA, /* round to nearest, ties away from zero */
- BF_RNDA, /* round away from zero */
- BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,
- inexact flag is always set) */
- } bf_rnd_t;
- /* allow subnormal numbers. Only available if the number of exponent
- bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */
- #define BF_FLAG_SUBNORMAL (1 << 3)
- /* 'prec' is the precision after the radix point instead of the whole
- mantissa. Can only be used with bf_round() and
- bfdec_[add|sub|mul|div|sqrt|round](). */
- #define BF_FLAG_RADPNT_PREC (1 << 4)
- #define BF_RND_MASK 0x7
- #define BF_EXP_BITS_SHIFT 5
- #define BF_EXP_BITS_MASK 0x3f
- /* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */
- #define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)
- /* contains the rounding mode and number of exponents bits */
- typedef uint32_t bf_flags_t;
- typedef void *bf_realloc_func_t(void *opaque, void *ptr, size_t size);
- typedef struct {
- bf_t val;
- limb_t prec;
- } BFConstCache;
- typedef struct bf_context_t {
- void *realloc_opaque;
- bf_realloc_func_t *realloc_func;
- BFConstCache log2_cache;
- BFConstCache pi_cache;
- struct BFNTTState *ntt_state;
- } bf_context_t;
- static inline int bf_get_exp_bits(bf_flags_t flags)
- {
- int e;
- e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK;
- if (e == BF_EXP_BITS_MASK)
- return BF_EXP_BITS_MAX + 1;
- else
- return BF_EXP_BITS_MAX - e;
- }
- static inline bf_flags_t bf_set_exp_bits(int n)
- {
- return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT;
- }
- /* returned status */
- #define BF_ST_INVALID_OP (1 << 0)
- #define BF_ST_DIVIDE_ZERO (1 << 1)
- #define BF_ST_OVERFLOW (1 << 2)
- #define BF_ST_UNDERFLOW (1 << 3)
- #define BF_ST_INEXACT (1 << 4)
- /* indicate that a memory allocation error occured. NaN is returned */
- #define BF_ST_MEM_ERROR (1 << 5)
- #define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */
- static inline slimb_t bf_max(slimb_t a, slimb_t b)
- {
- if (a > b)
- return a;
- else
- return b;
- }
- static inline slimb_t bf_min(slimb_t a, slimb_t b)
- {
- if (a < b)
- return a;
- else
- return b;
- }
- void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func,
- void *realloc_opaque);
- void bf_context_end(bf_context_t *s);
- /* free memory allocated for the bf cache data */
- void bf_clear_cache(bf_context_t *s);
- static inline void *bf_realloc(bf_context_t *s, void *ptr, size_t size)
- {
- return s->realloc_func(s->realloc_opaque, ptr, size);
- }
- /* 'size' must be != 0 */
- static inline void *bf_malloc(bf_context_t *s, size_t size)
- {
- return bf_realloc(s, NULL, size);
- }
- static inline void bf_free(bf_context_t *s, void *ptr)
- {
- /* must test ptr otherwise equivalent to malloc(0) */
- if (ptr)
- bf_realloc(s, ptr, 0);
- }
- void bf_init(bf_context_t *s, bf_t *r);
- static inline void bf_delete(bf_t *r)
- {
- bf_context_t *s = r->ctx;
- /* we accept to delete a zeroed bf_t structure */
- if (s && r->tab) {
- bf_realloc(s, r->tab, 0);
- }
- }
- static inline void bf_neg(bf_t *r)
- {
- r->sign ^= 1;
- }
- static inline int bf_is_finite(const bf_t *a)
- {
- return (a->expn < BF_EXP_INF);
- }
- static inline int bf_is_nan(const bf_t *a)
- {
- return (a->expn == BF_EXP_NAN);
- }
- static inline int bf_is_zero(const bf_t *a)
- {
- return (a->expn == BF_EXP_ZERO);
- }
- static inline void bf_memcpy(bf_t *r, const bf_t *a)
- {
- *r = *a;
- }
- int bf_set_ui(bf_t *r, uint64_t a);
- int bf_set_si(bf_t *r, int64_t a);
- void bf_set_nan(bf_t *r);
- void bf_set_zero(bf_t *r, int is_neg);
- void bf_set_inf(bf_t *r, int is_neg);
- int bf_set(bf_t *r, const bf_t *a);
- void bf_move(bf_t *r, bf_t *a);
- int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode);
- int bf_set_float64(bf_t *a, double d);
- int bf_cmpu(const bf_t *a, const bf_t *b);
- int bf_cmp_full(const bf_t *a, const bf_t *b);
- int bf_cmp(const bf_t *a, const bf_t *b);
- static inline int bf_cmp_eq(const bf_t *a, const bf_t *b)
- {
- return bf_cmp(a, b) == 0;
- }
- static inline int bf_cmp_le(const bf_t *a, const bf_t *b)
- {
- return bf_cmp(a, b) <= 0;
- }
- static inline int bf_cmp_lt(const bf_t *a, const bf_t *b)
- {
- return bf_cmp(a, b) < 0;
- }
- int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
- int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
- int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags);
- int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
- int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags);
- int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,
- bf_flags_t flags);
- int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags);
- int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
- #define BF_DIVREM_EUCLIDIAN BF_RNDF
- int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,
- limb_t prec, bf_flags_t flags, int rnd_mode);
- int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags, int rnd_mode);
- int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags, int rnd_mode);
- /* round to integer with infinite precision */
- int bf_rint(bf_t *r, int rnd_mode);
- int bf_round(bf_t *r, limb_t prec, bf_flags_t flags);
- int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a);
- int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
- slimb_t bf_get_exp_min(const bf_t *a);
- int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b);
- int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b);
- int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b);
- /* additional flags for bf_atof */
- /* do not accept hex radix prefix (0x or 0X) if radix = 0 or radix = 16 */
- #define BF_ATOF_NO_HEX (1 << 16)
- /* accept binary (0b or 0B) or octal (0o or 0O) radix prefix if radix = 0 */
- #define BF_ATOF_BIN_OCT (1 << 17)
- /* Do not parse NaN or Inf */
- #define BF_ATOF_NO_NAN_INF (1 << 18)
- /* return the exponent separately */
- #define BF_ATOF_EXPONENT (1 << 19)
- int bf_atof(bf_t *a, const char *str, const char **pnext, int radix,
- limb_t prec, bf_flags_t flags);
- /* this version accepts prec = BF_PREC_INF and returns the radix
- exponent */
- int bf_atof2(bf_t *r, slimb_t *pexponent,
- const char *str, const char **pnext, int radix,
- limb_t prec, bf_flags_t flags);
- int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
- slimb_t expn, limb_t prec, bf_flags_t flags);
- /* Conversion of floating point number to string. Return a null
- terminated string or NULL if memory error. *plen contains its
- length if plen != NULL. The exponent letter is "e" for base 10,
- "p" for bases 2, 8, 16 with a binary exponent and "@" for the other
- bases. */
- #define BF_FTOA_FORMAT_MASK (3 << 16)
- /* fixed format: prec significant digits rounded with (flags &
- BF_RND_MASK). Exponential notation is used if too many zeros are
- needed.*/
- #define BF_FTOA_FORMAT_FIXED (0 << 16)
- /* fractional format: prec digits after the decimal point rounded with
- (flags & BF_RND_MASK) */
- #define BF_FTOA_FORMAT_FRAC (1 << 16)
- /* free format:
- For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum
- number of digits to represent 'a'. The precision and the rounding
- mode are ignored.
- For the non binary radices with bf_ftoa(): use as many digits as
- necessary so that bf_atof() return the same number when using
- precision 'prec', rounding to nearest and the subnormal
- configuration of 'flags'. The result is meaningful only if 'a' is
- already rounded to 'prec' bits. If the subnormal flag is set, the
- exponent in 'flags' must also be set to the desired exponent range.
- */
- #define BF_FTOA_FORMAT_FREE (2 << 16)
- /* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits
- (takes more computation time). Identical to BF_FTOA_FORMAT_FREE for
- binary radices with bf_ftoa() and for bfdec_ftoa(). */
- #define BF_FTOA_FORMAT_FREE_MIN (3 << 16)
- /* force exponential notation for fixed or free format */
- #define BF_FTOA_FORCE_EXP (1 << 20)
- /* add 0x prefix for base 16, 0o prefix for base 8 or 0b prefix for
- base 2 if non zero value */
- #define BF_FTOA_ADD_PREFIX (1 << 21)
- /* return "Infinity" instead of "Inf" and add a "+" for positive
- exponents */
- #define BF_FTOA_JS_QUIRKS (1 << 22)
- char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,
- bf_flags_t flags);
- /* modulo 2^n instead of saturation. NaN and infinity return 0 */
- #define BF_GET_INT_MOD (1 << 0)
- int bf_get_int32(int *pres, const bf_t *a, int flags);
- int bf_get_int64(int64_t *pres, const bf_t *a, int flags);
- int bf_get_uint64(uint64_t *pres, const bf_t *a);
- /* the following functions are exported for testing only. */
- void mp_print_str(const char *str, const limb_t *tab, limb_t n);
- void bf_print_str(const char *str, const bf_t *a);
- int bf_resize(bf_t *r, limb_t len);
- int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len);
- int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags);
- int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k);
- slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,
- int is_ceil1);
- int mp_mul(bf_context_t *s, limb_t *result,
- const limb_t *op1, limb_t op1_size,
- const limb_t *op2, limb_t op2_size);
- limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2,
- limb_t n, limb_t carry);
- limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n);
- int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n);
- int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n);
- limb_t bf_isqrt(limb_t a);
- /* transcendental functions */
- int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags);
- int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);
- int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
- int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
- #define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */
- int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);
- int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
- int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
- int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
- int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
- int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,
- limb_t prec, bf_flags_t flags);
- int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
- int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
- /* decimal floating point */
- static inline void bfdec_init(bf_context_t *s, bfdec_t *r)
- {
- bf_init(s, (bf_t *)r);
- }
- static inline void bfdec_delete(bfdec_t *r)
- {
- bf_delete((bf_t *)r);
- }
- static inline void bfdec_neg(bfdec_t *r)
- {
- r->sign ^= 1;
- }
- static inline int bfdec_is_finite(const bfdec_t *a)
- {
- return (a->expn < BF_EXP_INF);
- }
- static inline int bfdec_is_nan(const bfdec_t *a)
- {
- return (a->expn == BF_EXP_NAN);
- }
- static inline int bfdec_is_zero(const bfdec_t *a)
- {
- return (a->expn == BF_EXP_ZERO);
- }
- static inline void bfdec_memcpy(bfdec_t *r, const bfdec_t *a)
- {
- bf_memcpy((bf_t *)r, (const bf_t *)a);
- }
- int bfdec_set_ui(bfdec_t *r, uint64_t a);
- int bfdec_set_si(bfdec_t *r, int64_t a);
- static inline void bfdec_set_nan(bfdec_t *r)
- {
- bf_set_nan((bf_t *)r);
- }
- static inline void bfdec_set_zero(bfdec_t *r, int is_neg)
- {
- bf_set_zero((bf_t *)r, is_neg);
- }
- static inline void bfdec_set_inf(bfdec_t *r, int is_neg)
- {
- bf_set_inf((bf_t *)r, is_neg);
- }
- static inline int bfdec_set(bfdec_t *r, const bfdec_t *a)
- {
- return bf_set((bf_t *)r, (bf_t *)a);
- }
- static inline void bfdec_move(bfdec_t *r, bfdec_t *a)
- {
- bf_move((bf_t *)r, (bf_t *)a);
- }
- static inline int bfdec_cmpu(const bfdec_t *a, const bfdec_t *b)
- {
- return bf_cmpu((const bf_t *)a, (const bf_t *)b);
- }
- static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b)
- {
- return bf_cmp_full((const bf_t *)a, (const bf_t *)b);
- }
- static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b)
- {
- return bf_cmp((const bf_t *)a, (const bf_t *)b);
- }
- static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)
- {
- return bfdec_cmp(a, b) == 0;
- }
- static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)
- {
- return bfdec_cmp(a, b) <= 0;
- }
- static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)
- {
- return bfdec_cmp(a, b) < 0;
- }
- int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
- bf_flags_t flags);
- int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
- bf_flags_t flags);
- int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
- bf_flags_t flags);
- int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
- bf_flags_t flags);
- int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
- bf_flags_t flags);
- int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
- bf_flags_t flags);
- int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
- limb_t prec, bf_flags_t flags, int rnd_mode);
- int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
- bf_flags_t flags, int rnd_mode);
- int bfdec_rint(bfdec_t *r, int rnd_mode);
- int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);
- int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags);
- int bfdec_get_int32(int *pres, const bfdec_t *a);
- int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b);
- char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags);
- int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,
- limb_t prec, bf_flags_t flags);
- /* the following functions are exported for testing only. */
- extern const limb_t mp_pow_dec[LIMB_DIGITS + 1];
- void bfdec_print_str(const char *str, const bfdec_t *a);
- static inline int bfdec_resize(bfdec_t *r, limb_t len)
- {
- return bf_resize((bf_t *)r, len);
- }
- int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags);
- #ifdef __cplusplus
- } /* extern "C" { */
- #endif
- #endif /* LIBBF_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)
- 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);
- 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_FLOAT64 = 7,
- /* 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_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 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_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;
- }
- #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;
- } 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_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 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);
- /* 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_AtomToCString(JSContext *ctx, JSAtom 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(JSContext *ctx, JSValueConst v)
- {
- (void)&ctx;
- return JS_VALUE_GET_TAG(v) == JS_TAG_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(JSContext *ctx, JSValueConst val);
- JS_EXTERN bool JS_IsUncatchableError(JSContext* ctx, 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_ThrowPlainError(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(2, 3) JS_ThrowReferenceError(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_ThrowInternalError(JSContext *ctx, 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));
- }
- 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, int 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 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, JSValue 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.
- */
- 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);
- /* 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,
- JSValue proto_val);
- JS_EXTERN JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
- 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 void JS_SetPropertyFunctionList(JSContext *ctx, JSValue 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 9
- #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-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.
- */
- #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_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_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)
- #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;
- 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;
- 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;
- bf_context_t bf_ctx;
- 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 */
- /* 0 : the JSVarRef is on the stack. header.link is an element
- of JSStackFrame.var_ref_list.
- 1 : the JSVarRef is detached. header.link has the normal meanning
- */
- uint8_t is_detached : 1;
- uint8_t is_arg : 1;
- uint16_t var_idx; /* index of the corresponding function variable on
- the stack */
- };
- };
- 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;
- /* the same structure is used for big integers.
- Big integers are never infinite or NaNs */
- typedef struct JSBigInt {
- JSRefCountHeader header; /* must come first, 32-bit */
- bf_t num;
- } JSBigInt;
- typedef enum {
- JS_AUTOINIT_ID_PROTOTYPE,
- JS_AUTOINIT_ID_MODULE_NS,
- JS_AUTOINIT_ID_PROP,
- } JSAutoInitIDEnum;
- /* 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_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;
- bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */
- /* 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;
- 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;
- #define JS_ATOM_HASH_MASK ((1 << 30) - 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 : 30;
- 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
- };
- static inline uint8_t *str8(JSString *p)
- {
- return (void *)(p + 1);
- }
- static inline uint16_t *str16(JSString *p)
- {
- return (void *)(p + 1);
- }
- 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 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(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(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(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(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(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(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)
- /* 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)
- /* 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)
- /* 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);
- JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowInternalError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...);
- 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_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_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);
- 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 JSValue JS_NewBigInt(JSContext *ctx);
- static inline bf_t *JS_GetBigInt(JSValueConst val)
- {
- JSBigInt *p = JS_VALUE_GET_PTR(val);
- return &p->num;
- }
- static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val);
- static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
- static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
- static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
- static bf_t *JS_ToBigInt1(JSContext *ctx, bf_t *buf, JSValueConst val);
- static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
- JSValue JS_ThrowOutOfMemory(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_get_length(JSContext *ctx, 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_generator_function_call(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 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_c_function_data_call(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);
- }
- #define JS_NewInt64(ctx, val) js_int64(val)
- 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);
- }
- /* called by libbf */
- static void *js_bf_realloc(void *opaque, void *ptr, size_t size)
- {
- JSRuntime *rt = opaque;
- return js_realloc_rt(rt, ptr, 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, js_map_mark }, /* JS_CLASS_WEAKMAP */
- { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKSET */
- { JS_ATOM_Iterator, NULL, NULL }, /* JS_CLASS_ITERATOR */
- { 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;
- bf_context_init(&rt->bf_ctx, js_bf_realloc, rt);
- 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_c_function_data_call;
- rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function;
- rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_generator_function_call;
- 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->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;
- }
- /* same as JS_FreeValueRT() but faster */
- static inline void js_free_string(JSRuntime *rt, JSString *str)
- {
- if (--str->header.ref_count <= 0) {
- if (str->atom_type) {
- JS_FreeAtomStruct(rt, str);
- } else {
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- list_del(&str->link);
- #endif
- 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);
- bf_context_end(&rt->bf_ctx);
- #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);
- ctx->bf_ctx = &rt->bf_ctx;
- 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->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_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->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->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;
- #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;
- #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)) {
- assert(!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_AtomToCString(JSContext *ctx, JSAtom atom)
- {
- JSValue str;
- const char *cstr;
- str = JS_AtomToString(ctx, atom);
- if (JS_IsException(str))
- return NULL;
- cstr = JS_ToCString(ctx, str);
- JS_FreeValue(ctx, str);
- return cstr;
- }
- /* 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];
- u32toa(buf, n);
- return js_atom_concat_str(ctx, name, buf);
- }
- 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;
- }
- // 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)
- {
- int len = end - start;
- if (start == 0 && end == p->len) {
- return js_dup(JS_MKPTR(JS_TAG_STRING, p));
- }
- if (len <= 0) {
- return JS_AtomToString(ctx, JS_ATOM_empty_string);
- }
- 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_AtomToString(s->ctx, JS_ATOM_empty_string);
- }
- 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_AtomToString(ctx, JS_ATOM_empty_string);
- }
- /* 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);
- }
- 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) {
- 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 = 4; /* 16 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, int 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;
- obj = JS_NewArray(ctx);
- if (JS_IsException(obj))
- return JS_EXCEPTION;
- if (count > 0) {
- p = JS_VALUE_GET_OBJ(obj);
- if (expand_fast_array(ctx, p, count)) {
- JS_FreeValue(ctx, obj);
- return JS_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;
- }
- 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,
- JSValue 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);
- if (!name)
- name = "";
- name_atom = JS_NewAtom(ctx, name);
- 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_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
- JSValueConst this_val,
- int argc, JSValueConst *argv, int flags)
- {
- JSCFunctionDataRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA);
- JSValueConst *arg_buf;
- int i;
- /* XXX: could add the function on the stack for debug */
- if (unlikely(argc < s->length)) {
- arg_buf = alloca(sizeof(arg_buf[0]) * s->length);
- for(i = 0; i < argc; i++)
- arg_buf[i] = argv[i];
- for(i = argc; i < s->length; i++)
- arg_buf[i] = JS_UNDEFINED;
- } else {
- arg_buf = argv;
- }
- return s->func(ctx, this_val, argc, arg_buf, s->magic, vc(s->data));
- }
- JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
- int length, int magic, int data_len,
- JSValueConst *data)
- {
- JSCFunctionDataRecord *s;
- 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);
- js_function_set_properties(ctx, func_obj,
- JS_ATOM_empty_string, length);
- return func_obj;
- }
- 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;
- }
- /* indicate that the object may be part of a function prototype cycle */
- static void set_cycle_flag(JSContext *ctx, JSValueConst obj)
- {
- }
- 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:
- {
- JSString *p = JS_VALUE_GET_STRING(v);
- if (p->atom_type) {
- JS_FreeAtomStruct(rt, p);
- } else {
- #ifdef ENABLE_DUMPS // JS_DUMP_LEAKS
- list_del(&p->link);
- #endif
- js_free_rt(rt, p);
- }
- }
- 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 *bf = JS_VALUE_GET_PTR(v);
- bf_delete(&bf->num);
- js_free_rt(rt, bf);
- }
- 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_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 (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]) {
- 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), js_std_class_def[class_id - 1].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)
- 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_MakeError(JSContext *ctx, JSErrorEnum error_num,
- const char *message, bool add_backtrace)
- {
- 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;
- }
- /* 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)
- {
- char buf[256];
- JSValue obj;
- vsnprintf(buf, sizeof(buf), fmt, ap);
- obj = JS_MakeError(ctx, error_num, buf, add_backtrace);
- 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);
- }
- JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowPlainError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...)
- {
- JSValue val;
- va_list ap;
- va_start(ap, fmt);
- val = JS_ThrowError(ctx, JS_PLAIN_ERROR, fmt, ap);
- va_end(ap);
- return val;
- }
- JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowSyntaxError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...)
- {
- JSValue val;
- va_list ap;
- va_start(ap, fmt);
- val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap);
- va_end(ap);
- return val;
- }
- JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowTypeError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...)
- {
- JSValue val;
- va_list ap;
- va_start(ap, fmt);
- val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
- va_end(ap);
- return val;
- }
- 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_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowReferenceError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...)
- {
- JSValue val;
- va_list ap;
- va_start(ap, fmt);
- val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap);
- va_end(ap);
- return val;
- }
- JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowRangeError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...)
- {
- JSValue val;
- va_list ap;
- va_start(ap, fmt);
- val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap);
- va_end(ap);
- return val;
- }
- JSValue JS_PRINTF_FORMAT_ATTR(2, 3) JS_ThrowInternalError(JSContext *ctx, JS_PRINTF_FORMAT const char *fmt, ...)
- {
- JSValue val;
- va_list ap;
- va_start(ap, fmt);
- val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap);
- va_end(ap);
- return val;
- }
- 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_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 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)) {
- /* XXX: should set a specific flag to avoid catching */
- JS_ThrowInternalError(ctx, "interrupted");
- js_set_uncatchable_error(ctx, ctx->rt->current_exception, true);
- 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, JSValue 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_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);
- }
- /* return the value associated to the autoinit property or an exception */
- typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
- static JSAutoInitFunc *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 */
- };
- /* 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, proto_depth;
- proto_depth = 0;
- 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;
- }
- }
- }
- }
- }
- }
- proto_depth++;
- 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 */
- JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
- {
- 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_ToPropertyKey(ctx, val);
- 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;
- }
- 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 {
- switch(tag) {
- case JS_TAG_NULL:
- JS_FreeValue(ctx, prop);
- return JS_ThrowTypeError(ctx, "cannot read property of null");
- case JS_TAG_UNDEFINED:
- JS_FreeValue(ctx, prop);
- return JS_ThrowTypeError(ctx, "cannot read property of undefined");
- }
- }
- 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);
- 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;
- }
- }
- }
- 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);
- 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 >= typed_array_get_length(ctx, p)) {
- 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);
- 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. 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)
- {
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return false;
- return JS_VALUE_GET_OBJ(val)->class_id == JS_CLASS_REGEXP;
- }
- bool JS_IsMap(JSValueConst val)
- {
- if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
- return false;
- return JS_VALUE_GET_OBJ(val)->class_id == JS_CLASS_MAP;
- }
- bool JS_IsError(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->class_id == JS_CLASS_ERROR);
- }
- /* used to avoid catching interrupt exceptions */
- bool JS_IsUncatchableError(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->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_BIG_INT:
- {
- JSBigInt *p = JS_VALUE_GET_PTR(val);
- bool ret;
- ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
- 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 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;
- }
- /* XXX: remove */
- static double js_strtod(const char *str, int radix, bool is_float)
- {
- double d;
- int c;
- if (!is_float || radix != 10) {
- const char *p = str;
- uint64_t n_max, n;
- int int_exp, is_neg;
- is_neg = 0;
- if (*p == '-') {
- is_neg = 1;
- p++;
- }
- /* skip leading zeros */
- while (*p == '0')
- p++;
- n = 0;
- if (radix == 10)
- n_max = ((uint64_t)-1 - 9) / 10; /* most common case */
- else
- n_max = ((uint64_t)-1 - (radix - 1)) / radix;
- /* XXX: could be more precise */
- int_exp = 0;
- while ((c = to_digit(*p)) < radix) {
- if (n <= n_max) {
- n = n * radix + c;
- } else {
- if (radix == 10)
- goto strtod_case;
- int_exp++;
- }
- p++;
- }
- d = n;
- if (int_exp != 0) {
- d *= pow(radix, int_exp);
- }
- if (is_neg)
- d = -d;
- } else {
- strtod_case:
- d = strtod(str, NULL);
- }
- return d;
- }
- static JSValue js_string_to_bigint(JSContext *ctx, const char *buf, int radix)
- {
- bf_t *a;
- int ret;
- JSValue val;
- val = JS_NewBigInt(ctx);
- if (JS_IsException(val))
- return val;
- a = JS_GetBigInt(val);
- ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ);
- if (ret & BF_ST_MEM_ERROR) {
- JS_FreeValue(ctx, val);
- return JS_ThrowOutOfMemory(ctx);
- }
- return JS_CompactBigInt1(ctx, val);
- }
- /* `js_atof(ctx, p, len, pp, radix, flags)`
- Convert the string pointed to by `p` to a number value.
- Return an exception in case of memory error.
- Return `JS_NAN` if invalid syntax.
- - `p` points to a null terminated UTF-8 encoded char array,
- - `len` the length of the array,
- - `pp` if not null receives a pointer to the next character,
- - `radix` must be in range 2 to 36, else return `JS_NAN`.
- - `flags` is a combination of the flags below.
- There is a null byte at `p[len]`, but there might be embedded null
- bytes between `p[0]` and `p[len]` which must produce `JS_NAN` if
- the `ATOD_NO_TRAILING_CHARS` flag is present.
- */
- #define ATOD_TRIM_SPACES (1 << 0) /* trim white space */
- #define ATOD_ACCEPT_EMPTY (1 << 1) /* accept an empty string, value is 0 */
- #define ATOD_ACCEPT_FLOAT (1 << 2) /* parse decimal floating point syntax */
- #define ATOD_ACCEPT_INFINITY (1 << 3) /* parse Infinity as a float point number */
- #define ATOD_ACCEPT_BIN_OCT (1 << 4) /* accept 0o and 0b prefixes */
- #define ATOD_ACCEPT_HEX_PREFIX (1 << 5) /* accept 0x prefix for radix 16 */
- #define ATOD_ACCEPT_UNDERSCORES (1 << 6) /* accept _ between digits as a digit separator */
- #define ATOD_ACCEPT_SUFFIX (1 << 7) /* allow 'n' suffix to produce BigInt */
- #define ATOD_WANT_BIG_INT (1 << 8) /* return type must be BigInt */
- #define ATOD_DECIMAL_AFTER_SIGN (1 << 9) /* only accept decimal number after sign */
- #define ATOD_NO_TRAILING_CHARS (1 << 10) /* do not accept trailing characters */
- static JSValue js_atof(JSContext *ctx, const char *p, size_t len,
- const char **pp, int radix, int flags)
- {
- const char *p_start;
- const char *end = p + len;
- int sep;
- bool is_float;
- char buf1[64], *buf = buf1;
- size_t i, j;
- JSValue val = JS_NAN;
- double d;
- char sign;
- if (radix < 2 || radix > 36)
- goto done;
- /* optional separator between digits */
- sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
- sign = 0;
- if (flags & ATOD_TRIM_SPACES)
- p += skip_spaces(p);
- if (p == end && (flags & ATOD_ACCEPT_EMPTY)) {
- if (pp) *pp = p;
- if (flags & ATOD_WANT_BIG_INT)
- return JS_NewBigInt64(ctx, 0);
- else
- return js_int32(0);
- }
- if (*p == '+' || *p == '-') {
- sign = *p;
- p++;
- if (flags & ATOD_DECIMAL_AFTER_SIGN)
- flags &= ~(ATOD_ACCEPT_HEX_PREFIX | ATOD_ACCEPT_BIN_OCT);
- }
- if (p[0] == '0') {
- if ((p[1] == 'x' || p[1] == 'X') &&
- ((flags & ATOD_ACCEPT_HEX_PREFIX) || radix == 16)) {
- p += 2;
- radix = 16;
- } else if (flags & ATOD_ACCEPT_BIN_OCT) {
- if (p[1] == 'o' || p[1] == 'O') {
- p += 2;
- radix = 8;
- } else if (p[1] == 'b' || p[1] == 'B') {
- p += 2;
- radix = 2;
- }
- }
- } else {
- if (*p == 'I' && (flags & ATOD_ACCEPT_INFINITY) && js__strstart(p, "Infinity", &p)) {
- d = INF;
- if (sign == '-')
- d = -d;
- val = js_float64(d);
- goto done;
- }
- }
- is_float = false;
- p_start = p;
- while (to_digit(*p) < radix) {
- p++;
- if (*p == sep && to_digit(p[1]) < radix)
- p++;
- }
- if ((flags & ATOD_ACCEPT_FLOAT) && radix == 10) {
- if (*p == '.' && (p > p_start || to_digit(p[1]) < radix)) {
- is_float = true;
- p++;
- while (to_digit(*p) < radix) {
- p++;
- if (*p == sep && to_digit(p[1]) < radix)
- p++;
- }
- }
- if (p > p_start && (*p == 'e' || *p == 'E')) {
- i = 1;
- if (p[1] == '+' || p[1] == '-') {
- i++;
- }
- if (is_digit(p[i])) {
- is_float = true;
- p += i + 1;
- while (is_digit(*p) || (*p == sep && is_digit(p[1])))
- p++;
- }
- }
- }
- if (p == p_start)
- goto done;
- len = p - p_start;
- if (unlikely((len + 2) > sizeof(buf1))) {
- buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */
- if (!buf) {
- if (pp) *pp = p;
- return JS_ThrowOutOfMemory(ctx);
- }
- }
- /* remove the separators and the radix prefix */
- j = 0;
- if (sign == '-')
- 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++;
- flags |= ATOD_WANT_BIG_INT;
- }
- }
- if (flags & ATOD_WANT_BIG_INT) {
- if (!is_float)
- val = js_string_to_bigint(ctx, buf, radix);
- } else {
- d = js_strtod(buf, radix, is_float);
- val = js_number(d); /* return int or float64 */
- }
- done:
- if (flags & ATOD_NO_TRAILING_CHARS) {
- if (flags & ATOD_TRIM_SPACES)
- p += skip_spaces(p);
- if (p != end) {
- JS_FreeValue(ctx, val);
- val = JS_NAN;
- }
- }
- if (buf != buf1)
- js_free_rt(ctx->rt, buf);
- if (pp) *pp = p;
- return val;
- }
- 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:
- 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;
- size_t len;
- int flags;
- str = JS_ToCStringLen(ctx, &len, val);
- JS_FreeValue(ctx, val);
- if (!str)
- return JS_EXCEPTION;
- flags = ATOD_TRIM_SPACES | ATOD_ACCEPT_EMPTY |
- ATOD_ACCEPT_FLOAT | ATOD_ACCEPT_INFINITY |
- ATOD_ACCEPT_HEX_PREFIX | ATOD_ACCEPT_BIN_OCT |
- ATOD_DECIMAL_AFTER_SIGN | ATOD_NO_TRAILING_CHARS;
- ret = js_atof(ctx, str, len, NULL, 10, flags);
- 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)) {
- *pres = NAN;
- return -1;
- }
- 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;
- case JS_TAG_BIG_INT:
- {
- JSBigInt *p = JS_VALUE_GET_PTR(val);
- /* XXX: there can be a double rounding issue with some
- primitives (such as JS_ToUint8ClampFree()), but it is
- not critical to fix it. */
- bf_get_float64(&p->num, &d, BF_RNDN);
- JS_FreeValue(ctx, val);
- }
- break;
- default:
- abort();
- }
- *pres = d;
- return 0;
- }
- 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(ctx, 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;
- case JS_TAG_BIG_INT:
- {
- JSBigInt *p = JS_VALUE_GET_PTR(val);
- bf_t a;
- bool res;
- bf_get_int32((int32_t *)&len, &p->num, BF_GET_INT_MOD);
- bf_init(ctx->bf_ctx, &a);
- bf_set_ui(&a, len);
- res = bf_cmp_eq(&a, &p->num);
- bf_delete(&a);
- JS_FreeValue(ctx, val);
- if (!res)
- goto fail;
- }
- 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_BIG_INT:
- {
- JSBigInt *p = JS_VALUE_GET_PTR(val);
- /* Note: integer zeros are not necessarily positive */
- return p->num.sign && !bf_is_zero(&p->num);
- }
- default:
- return false;
- }
- }
- static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
- {
- JSValue ret;
- bf_t a_s, *a;
- char *str;
- int saved_sign;
- size_t len;
- a = JS_ToBigInt(ctx, &a_s, val);
- if (!a)
- return JS_EXCEPTION;
- saved_sign = a->sign;
- if (a->expn == BF_EXP_ZERO)
- a->sign = 0;
- str = bf_ftoa(&len, a, radix, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC |
- BF_FTOA_JS_QUIRKS);
- a->sign = saved_sign;
- JS_FreeBigInt(ctx, a, &a_s);
- if (!str)
- return JS_ThrowOutOfMemory(ctx);
- ret = js_new_string8_len(ctx, str, len);
- bf_free(ctx->bf_ctx, str);
- return ret;
- }
- static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)
- {
- return js_bigint_to_string1(ctx, val, 10);
- }
- /*---- floating point number to string conversions ----*/
- /* JavaScript rounding is specified as round to nearest tie away
- from zero (RNDNA), but in `printf` the "ties" case is not
- specified (in most cases it is RNDN, round to nearest, tie to even),
- so we must round manually. We generate 2 extra places and make
- an extra call to snprintf if these are exactly '50'.
- We set the current rounding mode to FE_DOWNWARD to check if the
- last 2 places become '49'. If not, we must round up, which is
- performed in place using the string digits.
- Note that we cannot rely on snprintf for rounding up:
- the code below fails on macOS for `0.5.toFixed(0)`: gives `0` expected `1`
- fesetround(FE_UPWARD);
- snprintf(dest, size, "%.*f", n_digits, d);
- fesetround(FE_TONEAREST);
- */
- /* `js_fcvt` minimum buffer length:
- - up to 21 digits in integral part
- - 1 potential decimal point
- - up to 102 decimals
- - 1 null terminator
- */
- #define JS_FCVT_BUF_SIZE (21+1+102+1)
- /* `js_ecvt` minimum buffer length:
- - 1 leading digit
- - 1 potential decimal point
- - up to 102 decimals
- - 5 exponent characters (from 'e-324' to 'e+308')
- - 1 null terminator
- */
- #define JS_ECVT_BUF_SIZE (1+1+102+5+1)
- /* `js_dtoa` minimum buffer length:
- - 8 byte prefix
- - either JS_FCVT_BUF_SIZE or JS_ECVT_BUF_SIZE
- - JS_FCVT_BUF_SIZE is larger than JS_ECVT_BUF_SIZE
- */
- #define JS_DTOA_BUF_SIZE (8+JS_FCVT_BUF_SIZE)
- /* `js_ecvt1`: compute the digits and decimal point spot for a double
- - `d` is finite, positive or zero
- - `n_digits` number of significant digits in range 1..103
- - `buf` receives the printf result
- - `buf` has a fixed format: n_digits with a decimal point at offset 1
- and exponent 'e{+/-}xx[x]' at offset n_digits+1
- Return n_digits
- Store the position of the decimal point into `*decpt`
- */
- static int js_ecvt1(double d, int n_digits,
- char dest[minimum_length(JS_ECVT_BUF_SIZE)],
- size_t size, int *decpt)
- {
- /* d is positive, ensure decimal point is always present */
- snprintf(dest, size, "%#.*e", n_digits - 1, d);
- /* dest contents:
- 0: first digit
- 1: '.' decimal point (locale specific)
- 2..n_digits: (n_digits-1) additional digits
- n_digits+1: 'e' exponent mark
- n_digits+2..: exponent sign, value and null terminator
- */
- /* extract the exponent (actually the position of the decimal point) */
- *decpt = 1 + atoi(dest + n_digits + 2);
- return n_digits;
- }
- /* `js_ecvt`: compute the digits and decimal point spot for a double
- with proper javascript rounding. We cannot use `ecvt` for multiple
- resasons: portability, because of the number of digits is typically
- limited to 17, finally because the default rounding is inadequate.
- `d` is finite and positive or zero.
- `n_digits` number of significant digits in range 1..101
- or 0 for automatic (only as many digits as necessary)
- Return the number of digits produced in `dest`.
- Store the position of the decimal point into `*decpt`
- */
- static int js_ecvt(double d, int n_digits,
- char dest[minimum_length(JS_ECVT_BUF_SIZE)],
- size_t size, int *decpt)
- {
- if (n_digits == 0) {
- /* find the minimum number of digits (XXX: inefficient but simple) */
- // TODO(chqrlie) use direct method from quickjs-printf
- unsigned int n_digits_min = 1;
- unsigned int n_digits_max = 17;
- for (;;) {
- n_digits = (n_digits_min + n_digits_max) / 2;
- js_ecvt1(d, n_digits, dest, size, decpt);
- if (n_digits_min == n_digits_max)
- return n_digits;
- /* dest contents:
- 0: first digit
- 1: '.' decimal point (locale specific)
- 2..n_digits: (n_digits-1) additional digits
- n_digits+1: 'e' exponent mark
- n_digits+2..: exponent sign, value and null terminator
- */
- if (strtod(dest, NULL) == d) {
- unsigned int n0 = n_digits;
- /* enough digits */
- /* strip the trailing zeros */
- while (dest[n_digits] == '0')
- n_digits--;
- if (n_digits == n_digits_min)
- return n_digits;
- /* done if trailing zeros and not denormal or huge */
- if (n_digits < n0 && d > 3e-308 && d < 8e307)
- return n_digits;
- n_digits_max = n_digits;
- } else {
- /* need at least one more digit */
- n_digits_min = n_digits + 1;
- }
- }
- } else {
- #if defined(FE_DOWNWARD) && defined(FE_TONEAREST)
- int i;
- /* generate 2 extra digits: 99% chances to avoid 2 calls */
- js_ecvt1(d, n_digits + 2, dest, size, decpt);
- if (dest[n_digits + 1] < '5')
- return n_digits; /* truncate the 2 extra digits */
- if (dest[n_digits + 1] == '5' && dest[n_digits + 2] == '0') {
- /* close to half-way: try rounding toward 0 */
- fesetround(FE_DOWNWARD);
- js_ecvt1(d, n_digits + 2, dest, size, decpt);
- fesetround(FE_TONEAREST);
- if (dest[n_digits + 1] < '5')
- return n_digits; /* truncate the 2 extra digits */
- }
- /* round up in the string */
- for(i = n_digits;; i--) {
- /* ignore the locale specific decimal point */
- if (is_digit(dest[i])) {
- if (dest[i]++ < '9')
- break;
- dest[i] = '0';
- if (i == 0) {
- dest[0] = '1';
- (*decpt)++;
- break;
- }
- }
- }
- return n_digits; /* truncate the 2 extra digits */
- #else
- /* No disambiguation available, eg: __wasi__ targets */
- return js_ecvt1(d, n_digits, dest, size, decpt);
- #endif
- }
- }
- /* `js_fcvt`: convert a floating point value to %f format using RNDNA
- `d` is finite and positive or zero.
- `n_digits` number of decimal places in range 0..100
- Return the number of characters produced in `dest`.
- */
- static size_t js_fcvt(double d, int n_digits,
- char dest[minimum_length(JS_FCVT_BUF_SIZE)], size_t size)
- {
- #if defined(FE_DOWNWARD) && defined(FE_TONEAREST)
- int i, n1;
- /* generate 2 extra digits: 99% chances to avoid 2 calls */
- n1 = snprintf(dest, size, "%.*f", n_digits + 2, d) - 2;
- if (dest[n1] >= '5') {
- if (dest[n1] == '5' && dest[n1 + 1] == '0') {
- /* close to half-way: try rounding toward 0 */
- fesetround(FE_DOWNWARD);
- n1 = snprintf(dest, size, "%.*f", n_digits + 2, d) - 2;
- fesetround(FE_TONEAREST);
- }
- if (dest[n1] >= '5') { /* number should be rounded up */
- /* d is either exactly half way or greater: round the string manually */
- for (i = n1 - 1;; i--) {
- /* ignore the locale specific decimal point */
- if (is_digit(dest[i])) {
- if (dest[i]++ < '9')
- break;
- dest[i] = '0';
- if (i == 0) {
- dest[0] = '1';
- dest[n1] = '0';
- dest[n1 - n_digits - 1] = '0';
- dest[n1 - n_digits] = '.';
- n1++;
- break;
- }
- }
- }
- }
- }
- /* truncate the extra 2 digits and the decimal point if !n_digits */
- n1 -= !n_digits;
- //dest[n1] = '\0'; // optional
- return n1;
- #else
- /* No disambiguation available, eg: __wasi__ targets */
- return snprintf(dest, size, "%.*f", n_digits, d);
- #endif
- }
- static JSValue js_dtoa_infinite(JSContext *ctx, double d)
- {
- // TODO(chqrlie) use atoms for NaN and Infinite?
- if (isnan(d))
- return js_new_string8(ctx, "NaN");
- if (d < 0)
- return js_new_string8(ctx, "-Infinity");
- else
- return js_new_string8(ctx, "Infinity");
- }
- #define JS_DTOA_TOSTRING 0 /* use as many digits as necessary */
- #define JS_DTOA_EXPONENTIAL 1 /* use exponential notation either fixed or variable digits */
- #define JS_DTOA_FIXED 2 /* force fixed number of fractional digits */
- #define JS_DTOA_PRECISION 3 /* use n_digits significant digits (1 <= n_digits <= 101) */
- /* `js_dtoa`: convert a floating point number to a string
- - `mode`: one of the 4 supported formats
- - `n_digits`: digit number according to mode
- - TOSTRING: 0 only. As many digits as necessary
- - EXPONENTIAL: 0 as many decimals as necessary
- - 1..101 number of significant digits
- - FIXED: 0..100 number of decimal places
- - PRECISION: 1..101 number of significant digits
- */
- // XXX: should use libbf or quickjs-printf.
- static JSValue js_dtoa(JSContext *ctx, double d, int n_digits, int mode)
- {
- char buf[JS_DTOA_BUF_SIZE];
- size_t len;
- char *start;
- int sign, decpt, exp, i, k, n, n_max;
- if (!isfinite(d))
- return js_dtoa_infinite(ctx, d);
- sign = (d < 0);
- start = buf + 8;
- d = fabs(d); /* also converts -0 to 0 */
- if (mode != JS_DTOA_EXPONENTIAL && n_digits == 0) {
- /* fast path for exact integers in variable format:
- clip to MAX_SAFE_INTEGER because to ensure insignificant
- digits are generated as 0.
- used for JS_DTOA_TOSTRING and JS_DTOA_FIXED without decimals.
- */
- if (d <= (double)MAX_SAFE_INTEGER) {
- uint64_t u64 = (uint64_t)d;
- if (d == u64) {
- len = u64toa(start, u64);
- goto done;
- }
- }
- }
- if (mode == JS_DTOA_FIXED) {
- len = js_fcvt(d, n_digits, start, sizeof(buf) - 8);
- // TODO(chqrlie) patch the locale specific decimal point
- goto done;
- }
- n_max = (n_digits > 0) ? n_digits : 21;
- /* the number has k digits (1 <= k <= n_max) */
- k = js_ecvt(d, n_digits, start, sizeof(buf) - 8, &decpt);
- /* buffer contents:
- 0: first digit
- 1: '.' decimal point
- 2..k: (k-1) additional digits
- */
- n = decpt; /* d=10^(n-k)*(buf1) i.e. d= < x.yyyy 10^(n-1) */
- if (mode != JS_DTOA_EXPONENTIAL) {
- /* mode is JS_DTOA_PRECISION or JS_DTOA_TOSTRING */
- if (n >= 1 && n <= n_max) {
- /* between 1 and n_max digits before the decimal point */
- if (k <= n) {
- /* all digits before the point, append zeros */
- start[1] = start[0];
- start++;
- for(i = k; i < n; i++)
- start[i] = '0';
- len = n;
- } else {
- /* k > n: move digits before the point */
- for(i = 1; i < n; i++)
- start[i] = start[i + 1];
- start[i] = '.';
- len = 1 + k;
- }
- goto done;
- }
- if (n >= -5 && n <= 0) {
- /* insert -n leading 0 decimals and a '0.' prefix */
- n = -n;
- start[1] = start[0];
- start -= n + 1;
- start[0] = '0';
- start[1] = '.';
- for(i = 0; i < n; i++)
- start[2 + i] = '0';
- len = 2 + k + n;
- goto done;
- }
- }
- /* exponential notation */
- exp = n - 1;
- /* count the digits and the decimal point if at least one decimal */
- len = k + (k > 1);
- start[1] = '.'; /* patch the locale specific decimal point */
- start[len] = 'e';
- start[len + 1] = '+';
- if (exp < 0) {
- start[len + 1] = '-';
- exp = -exp;
- }
- len += 2 + 1 + (exp > 9) + (exp > 99);
- for (i = len - 1; exp > 9;) {
- int quo = exp / 10;
- start[i--] = (char)('0' + exp % 10);
- exp = quo;
- }
- start[i] = (char)('0' + exp);
- done:
- start[-1] = '-'; /* prepend the sign if negative */
- return js_new_string8_len(ctx, start - sign, len + sign);
- }
- /* `js_dtoa_radix`: convert a floating point number using a specific base
- - `d` must be finite
- - `radix` must be in range 2..36
- */
- static JSValue js_dtoa_radix(JSContext *ctx, double d, int radix)
- {
- char buf[2200], *ptr, *ptr2, *ptr3;
- int sign, digit;
- double frac, d0;
- int64_t n0;
- if (!isfinite(d))
- return js_dtoa_infinite(ctx, d);
- sign = (d < 0);
- d = fabs(d);
- d0 = trunc(d);
- n0 = 0;
- frac = d - d0;
- ptr2 = buf + 1100; /* ptr2 points to the end of the string */
- ptr = ptr2; /* ptr points to the beginning of the string */
- if (d0 <= MAX_SAFE_INTEGER) {
- int64_t n = n0 = (int64_t)d0;
- while (n >= radix) {
- digit = n % radix;
- n = n / radix;
- *--ptr = digits36[digit];
- }
- *--ptr = digits36[(size_t)n];
- } else {
- /* no decimals */
- while (d0 >= radix) {
- digit = fmod(d0, radix);
- d0 = trunc(d0 / radix);
- if (d0 >= MAX_SAFE_INTEGER)
- digit = 0;
- *--ptr = digits36[digit];
- }
- *--ptr = digits36[(size_t)d0];
- goto done;
- }
- if (frac != 0) {
- double log2_radix = log2(radix);
- double prec = 1023 + 51; // handle subnormals
- *ptr2++ = '.';
- while (frac != 0 && n0 <= MAX_SAFE_INTEGER/2 && prec > 0) {
- frac *= radix;
- digit = trunc(frac);
- frac -= digit;
- *ptr2++ = digits36[digit];
- n0 = n0 * radix + digit;
- prec -= log2_radix;
- }
- if (frac * radix >= radix / 2) {
- /* round up the string representation manually */
- char nine = digits36[radix - 1];
- while (ptr2[-1] == nine) {
- /* strip trailing '9' or equivalent digits */
- ptr2--;
- }
- if (ptr2[-1] == '.') {
- /* strip the 'decimal' point */
- ptr2--;
- /* increment the integral part */
- for (ptr3 = ptr2;;) {
- if (ptr3[-1] != nine) {
- ptr3[-1] = (ptr3[-1] == '9') ? 'a' : ptr3[-1] + 1;
- break;
- }
- *--ptr3 = '0';
- if (ptr3 <= ptr) {
- /* prepend a '1' if number was all nines */
- *--ptr = '1';
- break;
- }
- }
- } else {
- /* increment the last fractional digit */
- ptr2[-1] = (ptr2[-1] == '9') ? 'a' : ptr2[-1] + 1;
- }
- } else {
- /* strip trailing fractional zeros */
- while (ptr2[-1] == '0')
- ptr2--;
- /* strip the 'decimal' point if last */
- ptr2 -= (ptr2[-1] == '.');
- }
- }
- done:
- ptr[-1] = '-';
- ptr -= sign;
- return js_new_string8_len(ctx, ptr, ptr2 - ptr);
- }
- JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val,
- bool is_ToPropertyKey)
- {
- 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:
- {
- JSValue val1, ret;
- val1 = JS_ToPrimitive(ctx, val, HINT_STRING);
- if (JS_IsException(val1))
- return val1;
- ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey);
- JS_FreeValue(ctx, val1);
- return ret;
- }
- break;
- case JS_TAG_FUNCTION_BYTECODE:
- return js_new_string8(ctx, "[function bytecode]");
- case JS_TAG_SYMBOL:
- if (is_ToPropertyKey) {
- return js_dup(val);
- } else {
- return JS_ThrowTypeError(ctx, "cannot convert symbol to string");
- }
- case JS_TAG_FLOAT64:
- return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 0, JS_DTOA_TOSTRING);
- 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, false);
- }
- 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);
- }
- JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val)
- {
- return JS_ToStringInternal(ctx, val, true);
- }
- 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_BIG_INT:
- {
- JSBigInt *p = JS_VALUE_GET_PTR(val);
- char *str;
- str = bf_ftoa(NULL, &p->num, 10, 0,
- BF_RNDZ | BF_FTOA_FORMAT_FRAC);
- printf("%sn", str);
- bf_realloc(&rt->bf_ctx, str, 0);
- }
- 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)
- {
- JSValue val;
- bf_t *a;
- val = JS_NewBigInt(ctx);
- if (JS_IsException(val))
- return val;
- a = JS_GetBigInt(val);
- if (bf_set_si(a, v)) {
- JS_FreeValue(ctx, val);
- return JS_ThrowOutOfMemory(ctx);
- }
- return val;
- }
- JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
- {
- JSValue val;
- bf_t *a;
- val = JS_NewBigInt(ctx);
- if (JS_IsException(val))
- return val;
- a = JS_GetBigInt(val);
- if (bf_set_ui(a, v)) {
- JS_FreeValue(ctx, val);
- return JS_ThrowOutOfMemory(ctx);
- }
- return val;
- }
- /* if the returned bigint is allocated it is equal to
- 'buf'. Otherwise it is a pointer to the bigint in 'val'. Return
- NULL in case of error. */
- // TODO(bnoordhuis) Merge with JS_ToBigInt()
- static bf_t *JS_ToBigInt1(JSContext *ctx, bf_t *buf, JSValueConst val)
- {
- uint32_t tag;
- bf_t *r;
- JSBigInt *p;
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- r = buf;
- bf_init(ctx->bf_ctx, r);
- if (bf_set_si(r, JS_VALUE_GET_INT(val)))
- goto fail;
- break;
- case JS_TAG_FLOAT64:
- r = buf;
- bf_init(ctx->bf_ctx, r);
- if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) {
- fail:
- bf_delete(r);
- return NULL;
- }
- break;
- case JS_TAG_BIG_INT:
- p = JS_VALUE_GET_PTR(val);
- r = &p->num;
- break;
- case JS_TAG_UNDEFINED:
- default:
- r = buf;
- bf_init(ctx->bf_ctx, r);
- bf_set_nan(r);
- break;
- }
- return r;
- }
- /* return NaN if bad bigint literal */
- static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
- {
- const char *str;
- size_t len;
- int flags;
- str = JS_ToCStringLen(ctx, &len, val);
- JS_FreeValue(ctx, val);
- if (!str)
- return JS_EXCEPTION;
- flags = ATOD_WANT_BIG_INT |
- ATOD_TRIM_SPACES | ATOD_ACCEPT_EMPTY |
- ATOD_ACCEPT_HEX_PREFIX | ATOD_ACCEPT_BIN_OCT |
- ATOD_DECIMAL_AFTER_SIGN | ATOD_NO_TRAILING_CHARS;
- val = js_atof(ctx, str, len, NULL, 10, flags);
- 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;
- }
- /* if the returned bigint is allocated it is equal to
- 'buf'. Otherwise it is a pointer to the bigint in 'val'. */
- static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
- {
- uint32_t tag;
- bf_t *r;
- JSBigInt *p;
- redo:
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- case JS_TAG_NULL:
- case JS_TAG_UNDEFINED:
- case JS_TAG_FLOAT64:
- goto fail;
- case JS_TAG_BOOL:
- r = buf;
- bf_init(ctx->bf_ctx, r);
- bf_set_si(r, JS_VALUE_GET_INT(val));
- break;
- case JS_TAG_BIG_INT:
- p = JS_VALUE_GET_PTR(val);
- r = &p->num;
- break;
- case JS_TAG_STRING:
- val = JS_StringToBigIntErr(ctx, val);
- if (JS_IsException(val))
- return NULL;
- goto redo;
- case JS_TAG_OBJECT:
- val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
- if (JS_IsException(val))
- return NULL;
- goto redo;
- default:
- fail:
- JS_FreeValue(ctx, val);
- JS_ThrowTypeError(ctx, "cannot convert to BigInt");
- return NULL;
- }
- return r;
- }
- static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val)
- {
- return JS_ToBigIntFree(ctx, buf, js_dup(val));
- }
- static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val)
- {
- if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
- return val;
- } else {
- bf_t a_s, *a, *r;
- int ret;
- JSValue res;
- res = JS_NewBigInt(ctx);
- if (JS_IsException(res))
- return JS_EXCEPTION;
- a = JS_ToBigIntFree(ctx, &a_s, val);
- if (!a) {
- JS_FreeValue(ctx, res);
- return JS_EXCEPTION;
- }
- r = JS_GetBigInt(res);
- ret = bf_set(r, a);
- JS_FreeBigInt(ctx, a, &a_s);
- if (ret) {
- JS_FreeValue(ctx, res);
- return JS_ThrowOutOfMemory(ctx);
- }
- return JS_CompactBigInt(ctx, res);
- }
- }
- /* free the bf_t allocated by JS_ToBigInt */
- static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf)
- {
- if (a == buf) {
- bf_delete(a);
- } else {
- JSBigInt *p = (JSBigInt *)((uint8_t *)a - offsetof(JSBigInt, num));
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_INT, p));
- }
- }
- /* XXX: merge with JS_ToInt64Free with a specific flag */
- static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
- {
- bf_t a_s, *a;
- a = JS_ToBigIntFree(ctx, &a_s, val);
- if (!a) {
- *pres = 0;
- return -1;
- }
- bf_get_int64(pres, a, BF_GET_INT_MOD);
- JS_FreeBigInt(ctx, a, &a_s);
- 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 JSValue JS_NewBigInt(JSContext *ctx)
- {
- JSBigInt *p;
- p = js_malloc(ctx, sizeof(*p));
- if (!p)
- return JS_EXCEPTION;
- p->header.ref_count = 1;
- bf_init(ctx->bf_ctx, &p->num);
- return JS_MKPTR(JS_TAG_BIG_INT, p);
- }
- static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val)
- {
- if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT)
- return val; /* fail safe */
- bf_t *a = JS_GetBigInt(val);
- if (a->expn == BF_EXP_ZERO && a->sign) {
- assert(((JSBigInt*)JS_VALUE_GET_PTR(val))->header.ref_count == 1);
- a->sign = 0;
- }
- return val;
- }
- /* Nnormalize the zero representation. Could also be used to convert the bigint
- to a short bigint value. The reference count of the value must be
- 1. Cannot fail */
- static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
- {
- return JS_CompactBigInt1(ctx, val);
- }
- static JSValue throw_bf_exception(JSContext *ctx, int status)
- {
- const char *str;
- if (status & BF_ST_MEM_ERROR)
- return JS_ThrowOutOfMemory(ctx);
- if (status & BF_ST_DIVIDE_ZERO) {
- str = "division by zero";
- } else if (status & BF_ST_INVALID_OP) {
- str = "invalid operation";
- } else {
- str = "integer overflow";
- }
- return JS_ThrowRangeError(ctx, "%s", str);
- }
- static int js_unary_arith_bigint(JSContext *ctx,
- JSValue *pres, OPCodeEnum op, JSValue op1)
- {
- bf_t a_s, *r, *a;
- int ret, v;
- JSValue res;
- if (op == OP_plus) {
- JS_ThrowTypeError(ctx, "BigInt argument with unary +");
- JS_FreeValue(ctx, op1);
- return -1;
- }
- res = JS_NewBigInt(ctx);
- if (JS_IsException(res)) {
- JS_FreeValue(ctx, op1);
- return -1;
- }
- r = JS_GetBigInt(res);
- a = JS_ToBigIntFree(ctx, &a_s, op1); // infallible, always a bigint
- ret = 0;
- switch(op) {
- case OP_inc:
- case OP_dec:
- v = 2 * (op - OP_dec) - 1;
- ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
- break;
- case OP_plus:
- ret = bf_set(r, a);
- break;
- case OP_neg:
- ret = bf_set(r, a);
- bf_neg(r);
- break;
- case OP_not:
- ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ);
- bf_neg(r);
- break;
- default:
- abort();
- }
- JS_FreeBigInt(ctx, a, &a_s);
- if (unlikely(ret)) {
- JS_FreeValue(ctx, res);
- throw_bf_exception(ctx, ret);
- return -1;
- }
- res = JS_CompactBigInt(ctx, res);
- *pres = res;
- return 0;
- }
- static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
- JSValue *sp,
- OPCodeEnum op)
- {
- JSValue op1;
- int v;
- uint32_t tag;
- 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_BIG_INT:
- if (js_unary_arith_bigint(ctx, sp - 1, op, op1))
- goto exception;
- break;
- default:
- handle_float64:
- {
- double 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 = JS_ToNumericFree(ctx, sp[-1]);
- if (JS_IsException(op1))
- goto exception;
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
- if (js_unary_arith_bigint(ctx, sp - 1, OP_not, op1))
- goto exception;
- } 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 int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
- JSValue *pres, JSValue op1, JSValue op2)
- {
- bf_t a_s, b_s, *r, *a, *b;
- int ret;
- JSValue res;
- a = JS_ToBigIntFree(ctx, &a_s, op1);
- if (!a) {
- JS_FreeValue(ctx, op2);
- return -1;
- }
- b = JS_ToBigIntFree(ctx, &b_s, op2);
- if (!b) {
- JS_FreeBigInt(ctx, a, &a_s);
- return -1;
- }
- res = JS_NewBigInt(ctx);
- if (JS_IsException(res)) {
- JS_FreeBigInt(ctx, a, &a_s);
- JS_FreeBigInt(ctx, b, &b_s);
- return -1;
- }
- r = JS_GetBigInt(res);
- ret = 0;
- switch(op) {
- case OP_add:
- ret = bf_add(r, a, b, BF_PREC_INF, BF_RNDZ);
- break;
- case OP_sub:
- ret = bf_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
- break;
- case OP_mul:
- ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
- break;
- case OP_div:
- {
- bf_t rem_s, *rem = &rem_s;
- bf_init(ctx->bf_ctx, rem);
- ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ);
- bf_delete(rem);
- }
- break;
- case OP_mod:
- ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
- BF_RNDZ) & BF_ST_INVALID_OP;
- break;
- case OP_pow:
- if (b->sign) {
- ret = BF_ST_INVALID_OP;
- } else {
- ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS);
- }
- break;
- /* logical operations */
- case OP_shl:
- case OP_sar:
- {
- slimb_t v2;
- #if LIMB_BITS == 32
- bf_get_int32(&v2, b, 0);
- if (v2 == INT32_MIN)
- v2 = INT32_MIN + 1;
- #else
- bf_get_int64(&v2, b, 0);
- if (v2 == INT64_MIN)
- v2 = INT64_MIN + 1;
- #endif
- if (op == OP_sar)
- v2 = -v2;
- ret = bf_set(r, a);
- ret |= bf_mul_2exp(r, v2, BF_PREC_INF, BF_RNDZ);
- if (v2 < 0) {
- ret |= bf_rint(r, BF_RNDD) & (BF_ST_OVERFLOW | BF_ST_MEM_ERROR);
- }
- }
- break;
- case OP_and:
- ret = bf_logic_and(r, a, b);
- break;
- case OP_or:
- ret = bf_logic_or(r, a, b);
- break;
- case OP_xor:
- ret = bf_logic_xor(r, a, b);
- break;
- default:
- abort();
- }
- JS_FreeBigInt(ctx, a, &a_s);
- JS_FreeBigInt(ctx, b, &b_s);
- if (unlikely(ret)) {
- JS_FreeValue(ctx, res);
- throw_bf_exception(ctx, ret);
- return -1;
- }
- *pres = JS_CompactBigInt(ctx, res);
- return 0;
- }
- 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;
- }
- 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_float64((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_BIG_INT || tag2 == JS_TAG_BIG_INT) {
- if (js_binary_arith_bigint(ctx, op, sp - 2, op1, op2))
- goto exception;
- } 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;
- }
- 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 || tag2 == JS_TAG_BIG_INT) {
- if (js_binary_arith_bigint(ctx, OP_add, sp - 2, op1, op2))
- goto exception;
- } 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);
- 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 || tag2 == JS_TAG_BIG_INT) {
- if (tag1 != tag2) {
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- JS_ThrowTypeError(ctx, "both operands must be BigInt");
- goto exception;
- } else if (js_binary_arith_bigint(ctx, op, sp - 2, op1, op2)) {
- goto exception;
- }
- } 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;
- }
- static int js_compare_bigint(JSContext *ctx, OPCodeEnum op,
- JSValue op1, JSValue op2)
- {
- bf_t a_s, b_s, *a, *b;
- int res;
- a = JS_ToBigInt1(ctx, &a_s, op1);
- if (!a) {
- JS_FreeValue(ctx, op2);
- return -1;
- }
- b = JS_ToBigInt1(ctx, &b_s, op2);
- if (!b) {
- if (a == &a_s)
- bf_delete(a);
- JS_FreeValue(ctx, op1);
- return -1;
- }
- switch(op) {
- case OP_lt:
- res = bf_cmp_lt(a, b); /* if NaN return false */
- break;
- case OP_lte:
- res = bf_cmp_le(a, b); /* if NaN return false */
- break;
- case OP_gt:
- res = bf_cmp_lt(b, a); /* if NaN return false */
- break;
- case OP_gte:
- res = bf_cmp_le(b, a); /* if NaN return false */
- break;
- case OP_eq:
- res = bf_cmp_eq(a, b); /* if NaN return false */
- break;
- default:
- abort();
- }
- if (a == &a_s)
- bf_delete(a);
- if (b == &b_s)
- bf_delete(b);
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- 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 && tag2 == JS_TAG_STRING) ||
- (tag2 == JS_TAG_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)
- goto invalid_bigint_string;
- }
- if (tag2 == JS_TAG_STRING) {
- op2 = JS_StringToBigInt(ctx, op2);
- if (JS_VALUE_GET_TAG(op2) != JS_TAG_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 || tag2 == JS_TAG_BIG_INT) {
- res = js_compare_bigint(ctx, op, op1, op2);
- if (res < 0)
- goto exception;
- } 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_BIG_INT ||
- tag == JS_TAG_FLOAT64);
- }
- 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 || tag2 == JS_TAG_BIG_INT)) {
- if (tag1 == JS_TAG_STRING) {
- op1 = JS_StringToBigInt(ctx, op1);
- if (JS_VALUE_GET_TAG(op1) != JS_TAG_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) {
- 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(op2) == JS_TAG_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_BIG_INT:
- {
- bf_t a_s, *a, b_s, *b;
- if (tag1 != tag2) {
- res = false;
- break;
- }
- a = JS_ToBigInt1(ctx, &a_s, op1);
- b = JS_ToBigInt1(ctx, &b_s, op2);
- res = bf_cmp_eq(a, b);
- if (a == &a_s)
- bf_delete(a);
- if (b == &b_s)
- bf_delete(b);
- }
- 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_NewBool(ctx, 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_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)
- {
- return JS_ThrowTypeError(ctx, "invalid property access");
- }
- /* XXX: not 100% compatible, but mozilla seems to use a similar
- implementation to ensure that caller in non strict mode does not
- throw (ES5 compatibility) */
- static JSValue js_function_proto_caller(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_throw_type_error(ctx, this_val, 0, NULL);
- }
- 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 (done != 2) {
- *pdone = done;
- return obj;
- } 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;
- list_for_each(el, &sf->var_ref_list) {
- var_ref = list_entry(el, JSVarRef, header.link);
- if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) {
- 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;
- var_ref->is_arg = is_arg;
- var_ref->var_idx = var_idx;
- list_add_tail(&var_ref->header.link, &sf->var_ref_list);
- if (is_arg)
- var_ref->pvalue = &sf->arg_buf[var_idx];
- else
- var_ref->pvalue = &sf->var_buf[var_idx];
- 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;
- set_cycle_flag(ctx, obj);
- set_cycle_flag(ctx, this_val);
- 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;
- set_cycle_flag(ctx, ctor);
- set_cycle_flag(ctx, proto);
- 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;
- int var_idx;
- list_for_each_safe(el, el1, &sf->var_ref_list) {
- var_ref = list_entry(el, JSVarRef, header.link);
- var_idx = var_ref->var_idx;
- if (var_ref->is_arg)
- var_ref->value = js_dup(sf->arg_buf[var_idx]);
- else
- var_ref->value = js_dup(sf->var_buf[var_idx]);
- 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)
- {
- 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);
- if (var_idx == var_ref->var_idx && !var_ref->is_arg) {
- var_ref->value = js_dup(sf->var_buf[var_idx]);
- 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,
- } 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)
- /* 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_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_AtomToString(ctx, JS_ATOM_empty_string);
- 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;
- 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);
- if (unlikely(JS_IsException(ret_val)))
- goto exception;
- sp -= call_argc;
- *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_DeleteProperty(ctx, ctx->global_obj, atom, 0);
- 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(ctx, 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_ThrowTypeError(ctx, "not a constructor");
- 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_generator_function_call(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, 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, 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)
- /* 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 __exception int next_token(JSParseState *s);
- 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;
- }
- 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;
- /* 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;
- }
- s->token.val = TOK_TEMPLATE;
- s->token.u.str.sep = c;
- s->token.u.str.str = string_buffer_end(b);
- 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;
- /* 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;
- }
- token->val = TOK_STRING;
- token->u.str.sep = c;
- token->u.str.str = string_buffer_end(b);
- *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;
- 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;
- }
- s->token.val = TOK_REGEXP;
- s->token.u.regexp.body = string_buffer_end(b);
- s->token.u.regexp.flags = string_buffer_end(b2);
- s->buf_ptr = p;
- return 0;
- fail:
- string_buffer_free(b);
- string_buffer_free(b2);
- return -1;
- }
- 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;
- }
- /* 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;
- int flags, radix;
- 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') {
- flags = ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_FLOAT;
- radix = 10;
- goto parse_number;
- }
- goto def_token;
- case '0':
- if (is_digit(p[1])) { /* handle legacy octal */
- if (s->cur_func->is_strict_mode) {
- js_parse_error(s, "Octal literals are not allowed in strict mode");
- goto fail;
- }
- /* Legacy octal: no separators, no suffix, no floats,
- base 8 unless non octal digits are detected */
- flags = 0;
- radix = 8;
- while (is_digit(*p)) {
- if (*p >= '8' && *p <= '9')
- radix = 10;
- p++;
- }
- p = s->token.ptr;
- goto parse_number;
- }
- if (p[1] == '_') {
- js_parse_error(s, "Numeric separator can not be used after leading 0");
- goto fail;
- }
- flags = ATOD_ACCEPT_HEX_PREFIX | ATOD_ACCEPT_BIN_OCT |
- ATOD_ACCEPT_FLOAT | ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_SUFFIX;
- radix = 10;
- goto parse_number;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8':
- case '9':
- /* number */
- {
- JSValue ret;
- const char *p1;
- flags = ATOD_ACCEPT_FLOAT | ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_SUFFIX;
- radix = 10;
- parse_number:
- p1 = (const char *)p;
- ret = js_atof(s->ctx, p1, s->buf_end - p, &p1, radix, flags);
- p = (const uint8_t *)p1;
- if (JS_IsException(ret))
- goto fail;
- /* reject `10instanceof Number` */
- if (JS_VALUE_IS_NAN(ret) ||
- lre_js_is_ident_next(utf8_decode(p, &p_next))) {
- 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;
- }
- 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;
- }
- /* 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)
- 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)
- {
- emit_u32(s, JS_DupAtom(s->ctx, name));
- }
- 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 (label < 0) {
- 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)
- {
- return new_label_fd(s->cur_func, -1);
- }
- /* 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);
- 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);
- 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);
- 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 (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;
- }
- /* '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);
- }
- 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;
- }
- 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;
- }
- 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;
- }
- /* 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);
- 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);
- }
- 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 __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;
- while (s->token.val != '}') {
- 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);
- 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)) {
- js_parse_error(s, "identifier expected");
- goto fail;
- }
- export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- 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;
- }
- }
- 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)) {
- js_parse_error(s, "identifier expected");
- return -1;
- }
- export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- 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)) {
- js_parse_error(s, "identifier expected");
- return -1;
- }
- import_name = JS_DupAtom(ctx, s->token.u.ident.atom);
- 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;
- }
- 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:
- atom = get_u32(bc_buf + pos + 1);
- JS_FreeAtomRT(rt, atom);
- break;
- default:
- break;
- }
- pos += len;
- }
- }
- 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);
- }
- #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
- 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));
- *plabel_done = new_label_fd(s, *plabel_done);
- 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, -1);
- /* 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_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;
- 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. */
- if (fd->has_eval_call)
- add_eval_variables(ctx, fd);
- /* 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;
- }
- static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
- {
- int i;
- 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);
- }
- }
- 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;
- }
- 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);
- }
- /* '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;
- }
- /* 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 19
- 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",
- };
- #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)
- {
- uint32_t tag, tag1;
- int64_t e;
- JSBigInt *bf = JS_VALUE_GET_PTR(obj);
- bf_t *a = &bf->num;
- size_t len, i, n1, j;
- limb_t v;
- tag = JS_VALUE_GET_TAG(obj);
- switch(tag) {
- case JS_TAG_BIG_INT:
- tag1 = BC_TAG_BIG_INT;
- break;
- default:
- abort();
- }
- bc_put_u8(s, tag1);
- /* sign + exponent */
- if (a->expn == BF_EXP_ZERO)
- e = 0;
- else if (a->expn == BF_EXP_INF)
- e = 1;
- else if (a->expn == BF_EXP_NAN)
- e = 2;
- else if (a->expn >= 0)
- e = a->expn + 3;
- else
- e = a->expn;
- e = (e * 2) | a->sign;
- if (e < INT32_MIN || e > INT32_MAX) {
- JS_ThrowRangeError(s->ctx, "maximum BigInt size exceeded");
- return -1;
- }
- bc_put_sleb128(s, e);
- /* mantissa */
- if (a->len != 0) {
- i = 0;
- while (i < a->len && a->tab[i] == 0)
- i++;
- assert(i < a->len);
- v = a->tab[i];
- n1 = sizeof(limb_t);
- while ((v & 0xff) == 0) {
- n1--;
- v >>= 8;
- }
- i++;
- len = (a->len - i) * sizeof(limb_t) + n1;
- if (len > INT32_MAX) {
- JS_ThrowRangeError(s->ctx, "maximum BigInt size exceeded");
- return -1;
- }
- bc_put_leb128(s, len);
- /* always saved in byte based little endian representation */
- for(j = 0; j < n1; j++) {
- bc_put_u8(s, v >> (j * 8));
- }
- for(; i < a->len; i++) {
- limb_t v = a->tab[i];
- #if LIMB_BITS == 32
- bc_put_u32(s, v);
- #else
- bc_put_u64(s, v);
- #endif
- }
- }
- 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_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;
- 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;
- uint8_t v8;
- int32_t e;
- uint32_t len;
- limb_t l, i, n;
- limb_t v;
- bf_t *a;
- obj = JS_NewBigInt(s->ctx);
- if (JS_IsException(obj))
- goto fail;
- /* sign + exponent */
- if (bc_get_sleb128(s, &e))
- goto fail;
- a = JS_GetBigInt(obj);
- a->sign = e & 1;
- e >>= 1;
- if (e == 0)
- a->expn = BF_EXP_ZERO;
- else if (e == 1)
- a->expn = BF_EXP_INF;
- else if (e == 2)
- a->expn = BF_EXP_NAN;
- else if (e >= 3)
- a->expn = e - 3;
- else
- a->expn = e;
- /* mantissa */
- if (a->expn != BF_EXP_ZERO &&
- a->expn != BF_EXP_INF &&
- a->expn != BF_EXP_NAN) {
- if (bc_get_leb128(s, &len))
- goto fail;
- bc_read_trace(s, "len=%" PRId64 "\n", (int64_t)len);
- if (len == 0) {
- JS_ThrowRangeError(s->ctx, "maximum BigInt size exceeded");
- goto fail;
- }
- l = (len + sizeof(limb_t) - 1) / sizeof(limb_t);
- if (bf_resize(a, l)) {
- JS_ThrowOutOfMemory(s->ctx);
- goto fail;
- }
- n = len & (sizeof(limb_t) - 1);
- if (n != 0) {
- v = 0;
- for(i = 0; i < n; i++) {
- if (bc_get_u8(s, &v8))
- goto fail;
- v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8);
- }
- a->tab[0] = v;
- i = 1;
- } else {
- i = 0;
- }
- for(; i < l; i++) {
- #if LIMB_BITS == 32
- if (bc_get_u32(s, &v))
- goto fail;
- #else
- if (bc_get_u64(s, &v))
- goto fail;
- #endif
- a->tab[i] = v;
- }
- }
- return obj;
- 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_str[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, JSValue 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;
- }
- void JS_SetPropertyFunctionList(JSContext *ctx, JSValue obj,
- const JSCFunctionListEntry *tab, int len)
- {
- int i;
- for (i = 0; i < len; i++) {
- const JSCFunctionListEntry *e = &tab[i];
- JSAtom atom = find_atom(ctx, e->name);
- JS_InstantiateFunctionListItem(ctx, obj, atom, e);
- JS_FreeAtom(ctx, atom);
- }
- }
- 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);
- set_cycle_flag(ctx, func_obj);
- set_cycle_flag(ctx, proto);
- }
- 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_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) {
- JS_FreeValue(ctx, item);
- 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_FreeValue(ctx, species);
- return JS_ThrowTypeError(ctx, "not a constructor");
- }
- 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_AtomToString(ctx, JS_ATOM_empty_string);
- }
- 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_AtomToString(ctx, JS_ATOM_empty_string);
- 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_AtomToString(ctx, JS_ATOM_empty_string);
- 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(ctx, 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))
- 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;
- int ok;
- ok = JS_IsUndefined(argv[0]) || JS_IsFunction(ctx, argv[0]);
- if (!ok)
- return JS_ThrowTypeErrorNotAFunction(ctx);
- 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(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);
- }
- 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))
- return JS_EXCEPTION;
- // Check for Infinity.
- if (JS_ToFloat64(ctx, &dlimit, v)) {
- JS_FreeValue(ctx, v);
- return JS_EXCEPTION;
- }
- if (isnan(dlimit)) {
- JS_FreeValue(ctx, v);
- goto fail;
- }
- if (!isfinite(dlimit)) {
- JS_FreeValue(ctx, v);
- if (dlimit < 0)
- goto fail;
- else
- count = MAX_SAFE_INTEGER;
- } else {
- v = JS_ToIntegerFree(ctx, v);
- if (JS_IsException(v))
- return JS_EXCEPTION;
- if (JS_ToInt64Free(ctx, &count, v))
- return JS_EXCEPTION;
- }
- if (count < 0) {
- fail:
- return JS_ThrowRangeError(ctx, "must be positive");
- }
- }
- 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))
- return JS_EXCEPTION;
- }
- break;
- default:
- abort();
- break;
- }
- method = JS_GetProperty(ctx, this_val, JS_ATOM_next);
- if (JS_IsException(method))
- return JS_EXCEPTION;
- obj = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_HELPER);
- if (JS_IsException(obj)) {
- JS_FreeValue(ctx, method);
- return JS_EXCEPTION;
- }
- it = js_malloc(ctx, sizeof(*it));
- if (!it) {
- JS_FreeValue(ctx, obj);
- JS_FreeValue(ctx, method);
- return JS_EXCEPTION;
- }
- 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;
- }
- 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;
- if (check_function(ctx, argv[0]))
- return JS_EXCEPTION;
- 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;
- if (check_function(ctx, argv[0]))
- return JS_EXCEPTION;
- acc = JS_UNDEFINED;
- 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("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_BIG_INT:
- {
- JSBigInt *p = JS_VALUE_GET_PTR(val);
- double d;
- bf_get_float64(&p->num, &d, BF_RNDN);
- 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)
- {
- char buf[72];
- JSValue val;
- int base;
- double d;
- val = js_thisNumberValue(ctx, this_val);
- if (JS_IsException(val))
- return val;
- if (magic || JS_IsUndefined(argv[0])) {
- if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
- size_t len = i32toa(buf, JS_VALUE_GET_INT(val));
- return js_new_string8_len(ctx, buf, len);
- }
- base = 10;
- } else {
- base = js_get_radix(ctx, argv[0]);
- if (base < 0) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- }
- if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
- size_t len = i32toa_radix(buf, JS_VALUE_GET_INT(val), base);
- return js_new_string8_len(ctx, buf, len);
- }
- if (JS_ToFloat64Free(ctx, &d, val))
- return JS_EXCEPTION;
- if (base != 10)
- return js_dtoa_radix(ctx, d, base);
- return js_dtoa(ctx, d, 0, JS_DTOA_TOSTRING);
- }
- static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val;
- int f;
- 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, "toFixed() digits argument must be between 0 and 100");
- }
- if (fabs(d) >= 1e21) {
- // use ToString(d)
- return js_dtoa(ctx, d, 0, JS_DTOA_TOSTRING);
- } else {
- return js_dtoa(ctx, d, f, JS_DTOA_FIXED);
- }
- }
- static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue val;
- double d;
- int f;
- 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_dtoa_infinite(ctx, d);
- if (!JS_IsUndefined(argv[0])) {
- if (f < 0 || f > 100) {
- return JS_ThrowRangeError(ctx, "toExponential() argument must be between 0 and 100");
- }
- f += 1; /* number of significant digits between 1 and 101 */
- }
- return js_dtoa(ctx, d, f, JS_DTOA_EXPONENTIAL);
- }
- 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]))
- return js_dtoa(ctx, d, 0, JS_DTOA_TOSTRING);
- if (JS_ToInt32Sat(ctx, &p, argv[0]))
- return JS_EXCEPTION;
- if (!isfinite(d))
- return js_dtoa_infinite(ctx, d);
- if (p < 1 || p > 100) {
- return JS_ThrowRangeError(ctx, "toPrecision() argument must be between 1 and 100");
- }
- return js_dtoa(ctx, d, p, JS_DTOA_PRECISION);
- }
- 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;
- int radix, flags;
- JSValue ret;
- size_t len;
- str = JS_ToCStringLen(ctx, &len, argv[0]);
- if (!str)
- return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &radix, argv[1])) {
- JS_FreeCString(ctx, str);
- return JS_EXCEPTION;
- }
- flags = ATOD_TRIM_SPACES;
- if (radix == 0) {
- flags |= ATOD_ACCEPT_HEX_PREFIX; // Only 0x and 0X are supported
- radix = 10;
- }
- ret = js_atof(ctx, str, len, 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;
- JSValue ret;
- int flags;
- size_t len;
- str = JS_ToCStringLen(ctx, &len, argv[0]);
- if (!str)
- return JS_EXCEPTION;
- flags = ATOD_TRIM_SPACES | ATOD_ACCEPT_FLOAT | ATOD_ACCEPT_INFINITY;
- ret = js_atof(ctx, str, len, NULL, 10, flags);
- 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_AtomToString(ctx, JS_ATOM_empty_string);
- } 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_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_AtomToString(ctx, JS_ATOM_empty_string);
- } 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_IsUndefined(regexp) && !JS_IsNull(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_IsUndefined(searchValue) && !JS_IsNull(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_IsUndefined(separator) && !JS_IsNull(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 fail2;
- }
- 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);
- }
- static JSValue js_math_sumPrecise(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue iter, next, item, ret;
- bf_t a, b;
- int done;
- double d;
- int r;
- iter = JS_GetIterator(ctx, argv[0], /*async*/false);
- if (JS_IsException(iter))
- return JS_EXCEPTION;
- bf_init(ctx->bf_ctx, &a);
- bf_init(ctx->bf_ctx, &b);
- ret = JS_EXCEPTION;
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- goto fail;
- bf_set_zero(&a, /*is_neg*/true);
- for (;;) {
- item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
- if (JS_IsException(item))
- goto fail;
- if (done)
- break; // item == JS_UNDEFINED
- switch (JS_VALUE_GET_TAG(item)) {
- default:
- JS_FreeValue(ctx, item);
- JS_ThrowTypeError(ctx, "not a number");
- goto fail;
- case JS_TAG_INT:
- d = JS_VALUE_GET_INT(item);
- break;
- case JS_TAG_FLOAT64:
- d = JS_VALUE_GET_FLOAT64(item);
- break;
- }
- if (bf_set_float64(&b, d))
- goto oom;
- // Infinity + -Infinity results in BF_ST_INVALID_OP, sets |a| to nan
- if ((r = bf_add(&a, &a, &b, BF_PREC_INF, BF_RNDN)))
- if (r != BF_ST_INVALID_OP)
- goto oom;
- }
- bf_get_float64(&a, &d, BF_RNDN); // return value deliberately ignored
- ret = js_float64(d);
- fail:
- JS_IteratorClose(ctx, iter, JS_IsException(ret));
- JS_FreeValue(ctx, iter);
- JS_FreeValue(ctx, next);
- bf_delete(&a);
- bf_delete(&b);
- return ret;
- oom:
- JS_ThrowOutOfMemory(ctx);
- goto fail;
- }
- /* 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_AtomToString(ctx, JS_ATOM_empty_string);
- } 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_AtomToString(ctx, JS_ATOM_empty_string);
- 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_AtomToString(ctx, JS_ATOM_empty_string);
- 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);
- }
- 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 {
- 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 {
- 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(ctx, 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_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_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_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_AtomToString(ctx, JS_ATOM_empty_string);
- 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_ThrowTypeError(ctx, "not a constructor");
- } 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_ThrowTypeError(ctx, "not a constructor");
- 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_ThrowTypeError(ctx, "not a constructor");
- 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 */
- 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;
- #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) {
- JS_FreeValue(ctx, item);
- 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;
- bf_t *a;
- 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_BIG_INT:
- a = JS_GetBigInt(key);
- h = hash_string8((void *)a->tab, a->len * sizeof(*a->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;
- size_t slack;
- 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_realloc2(ctx, s->hash_table,
- sizeof(new_hash_table[0]) * new_hash_size, &slack);
- if (!new_hash_table)
- return;
- new_hash_size += slack / sizeof(*new_hash_table);
- 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_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) {
- list_for_each(el, &s->records) {
- mr = list_entry(el, JSMapRecord, link);
- if (!s->is_weak)
- 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_size(JSContext *ctx, JSValueConst setlike,
- int64_t *pout)
- {
- JSMapState *s;
- JSValue v;
- double d;
- s = JS_GetOpaque(setlike, JS_CLASS_SET);
- if (s) {
- *pout = 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 (isnan(d)) {
- JS_ThrowTypeError(ctx, ".size is not a number");
- return -1;
- }
- *pout = d;
- }
- return 0;
- }
- static int js_setlike_get_has(JSContext *ctx, JSValueConst setlike,
- JSValue *pout)
- {
- JSValue v;
- v = JS_GetProperty(ctx, setlike, JS_ATOM_has);
- if (JS_IsException(v))
- return -1;
- if (JS_IsUndefined(v)) {
- JS_ThrowTypeError(ctx, ".has is undefined");
- return -1;
- }
- if (!JS_IsFunction(ctx, v)) {
- JS_ThrowTypeError(ctx, ".has is not a function");
- JS_FreeValue(ctx, v);
- return -1;
- }
- *pout = v;
- return 0;
- }
- static int js_setlike_get_keys(JSContext *ctx, JSValueConst setlike,
- JSValue *pout)
- {
- JSValue v;
- v = JS_GetProperty(ctx, setlike, JS_ATOM_keys);
- if (JS_IsException(v))
- return -1;
- if (JS_IsUndefined(v)) {
- JS_ThrowTypeError(ctx, ".keys is undefined");
- return -1;
- }
- if (!JS_IsFunction(ctx, v)) {
- JS_ThrowTypeError(ctx, ".keys is not a function");
- JS_FreeValue(ctx, v);
- return -1;
- }
- *pout = v;
- return 0;
- }
- static JSValue js_set_isDisjointFrom(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue item, iter, keys, has, next, rv, rval;
- int done;
- bool found;
- JSMapState *s;
- int64_t size;
- int ok;
- has = JS_UNDEFINED;
- iter = JS_UNDEFINED;
- keys = JS_UNDEFINED;
- next = JS_UNDEFINED;
- rval = JS_EXCEPTION;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- goto exception;
- // order matters!
- if (js_setlike_get_size(ctx, argv[0], &size) < 0)
- goto exception;
- if (js_setlike_get_has(ctx, argv[0], &has) < 0)
- goto exception;
- if (js_setlike_get_keys(ctx, argv[0], &keys) < 0)
- goto exception;
- if (s->record_count > size) {
- iter = JS_Call(ctx, keys, argv[0], 0, NULL);
- if (JS_IsException(iter))
- goto exception;
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- goto exception;
- found = false;
- do {
- 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);
- } while (!found);
- } 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, argv[0], 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 item, iter, keys, has, next, rv, rval;
- bool found;
- JSMapState *s;
- int64_t size;
- int done, ok;
- has = JS_UNDEFINED;
- iter = JS_UNDEFINED;
- keys = JS_UNDEFINED;
- next = JS_UNDEFINED;
- rval = JS_EXCEPTION;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- goto exception;
- // order matters!
- if (js_setlike_get_size(ctx, argv[0], &size) < 0)
- goto exception;
- if (js_setlike_get_has(ctx, argv[0], &has) < 0)
- goto exception;
- if (js_setlike_get_keys(ctx, argv[0], &keys) < 0)
- goto 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, argv[0], 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 item, iter, keys, has, next, rval;
- int done;
- bool found;
- JSMapState *s;
- int64_t size;
- has = JS_UNDEFINED;
- iter = JS_UNDEFINED;
- keys = JS_UNDEFINED;
- next = JS_UNDEFINED;
- rval = JS_EXCEPTION;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- goto exception;
- // order matters!
- if (js_setlike_get_size(ctx, argv[0], &size) < 0)
- goto exception;
- if (js_setlike_get_has(ctx, argv[0], &has) < 0)
- goto exception;
- if (js_setlike_get_keys(ctx, argv[0], &keys) < 0)
- goto exception;
- found = false;
- if (s->record_count < size)
- goto fini;
- iter = JS_Call(ctx, keys, argv[0], 0, NULL);
- if (JS_IsException(iter))
- goto exception;
- next = JS_GetProperty(ctx, iter, JS_ATOM_next);
- if (JS_IsException(next))
- goto exception;
- found = true;
- do {
- 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);
- } 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_intersection(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue newset, item, iter, keys, has, next, rv;
- JSMapState *s, *t;
- JSMapRecord *mr;
- int64_t size;
- int done, ok;
- has = JS_UNDEFINED;
- iter = JS_UNDEFINED;
- keys = JS_UNDEFINED;
- next = JS_UNDEFINED;
- newset = JS_UNDEFINED;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- goto exception;
- // order matters!
- if (js_setlike_get_size(ctx, argv[0], &size) < 0)
- goto exception;
- if (js_setlike_get_has(ctx, argv[0], &has) < 0)
- goto exception;
- if (js_setlike_get_keys(ctx, argv[0], &keys) < 0)
- goto exception;
- if (s->record_count > size) {
- iter = JS_Call(ctx, keys, argv[0], 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, argv[0], 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 newset, item, iter, keys, has, next, rv;
- JSMapState *s, *t;
- JSMapRecord *mr;
- int64_t size;
- int done;
- int ok;
- has = JS_UNDEFINED;
- iter = JS_UNDEFINED;
- keys = JS_UNDEFINED;
- next = JS_UNDEFINED;
- newset = JS_UNDEFINED;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- goto exception;
- // order matters!
- if (js_setlike_get_size(ctx, argv[0], &size) < 0)
- goto exception;
- if (js_setlike_get_has(ctx, argv[0], &has) < 0)
- goto exception;
- if (js_setlike_get_keys(ctx, argv[0], &keys) < 0)
- goto exception;
- if (s->record_count > size) {
- iter = JS_Call(ctx, keys, argv[0], 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, argv[0], 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 newset, item, iter, next, rv;
- struct list_head *el;
- JSMapState *s, *t;
- JSMapRecord *mr;
- int64_t size;
- int done;
- bool present;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- return JS_EXCEPTION;
- // order matters! they're JS-observable side effects
- if (js_setlike_get_size(ctx, argv[0], &size) < 0)
- return JS_EXCEPTION;
- if (js_setlike_get_has(ctx, argv[0], &rv) < 0)
- return JS_EXCEPTION;
- JS_FreeValue(ctx, rv);
- newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);
- if (JS_IsException(newset))
- return JS_EXCEPTION;
- t = JS_GetOpaque(newset, JS_CLASS_SET);
- iter = JS_UNDEFINED;
- next = JS_UNDEFINED;
- // 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_GetProperty(ctx, argv[0], JS_ATOM_keys);
- if (JS_IsException(iter))
- goto exception;
- iter = JS_CallFree(ctx, iter, argv[0], 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, next);
- JS_FreeValue(ctx, iter);
- return newset;
- }
- static JSValue js_set_union(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- JSValue newset, item, iter, next, rv;
- struct list_head *el;
- JSMapState *s, *t;
- JSMapRecord *mr;
- int64_t size;
- int done;
- s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
- if (!s)
- return JS_EXCEPTION;
- // order matters! they're JS-observable side effects
- if (js_setlike_get_size(ctx, argv[0], &size) < 0)
- return JS_EXCEPTION;
- if (js_setlike_get_has(ctx, argv[0], &rv) < 0)
- return JS_EXCEPTION;
- JS_FreeValue(ctx, rv);
- newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);
- if (JS_IsException(newset))
- return JS_EXCEPTION;
- t = JS_GetOpaque(newset, JS_CLASS_SET);
- iter = JS_UNDEFINED;
- next = JS_UNDEFINED;
- 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_GetProperty(ctx, argv[0], JS_ATOM_keys);
- if (JS_IsException(iter))
- goto exception;
- iter = JS_CallFree(ctx, iter, argv[0], 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, 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("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("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, 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_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_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 void reject_promise(JSContext *ctx, JSValueConst promise,
- JSValueConst value)
- {
- fulfill_or_reject_promise(ctx, promise, value, true);
- }
- static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
- int argc, JSValueConst *argv)
- {
- JSValueConst promise, thenable, then;
- JSValue args[2], res;
- 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;
- res = JS_Call(ctx, then, thenable, 2, vc(args));
- 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);
- reject_promise(ctx, s->promise, error);
- 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;
- 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;
- 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 executor;
- 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)) {
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- JS_FreeValue(ctx, result_promise);
- return JS_EXCEPTION;
- }
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_promise, result_promise, JS_PROP_C_W_E);
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_resolve, resolving_funcs[0], JS_PROP_C_W_E);
- JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1], JS_PROP_C_W_E);
- return obj;
- }
- 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];
- JSPromiseData *s;
- 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;
- result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
- 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 {
- err = JS_MakeError(ctx, JS_TYPE_ERROR, "throw is not a method",
- true);
- 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_AtomToString(ctx, JS_ATOM_empty_string);
- }
- 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') {
- 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, 9))
- 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, 9)) {
- if (c == '-') {
- if (val == 0)
- return false;
- val = -val;
- }
- fields[0] = val;
- has_year = true;
- }
- }
- } else
- if (string_get_digits(sp, &p, &val, 1, 9)) {
- 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_NewFloat64(ctx, 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)
- {
- ctx->eval_internal = __JS_EvalInternal;
- }
- /* 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_BIG_INT:
- break;
- case JS_TAG_FLOAT64:
- {
- bf_t *a, a_s;
- a = JS_ToBigInt1(ctx, &a_s, val);
- if (!bf_is_finite(a)) {
- JS_FreeValue(ctx, val);
- val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to BigInt");
- } else {
- JSValue val1 = JS_NewBigInt(ctx);
- bf_t *r;
- int ret;
- if (JS_IsException(val1)) {
- JS_FreeValue(ctx, val);
- return JS_EXCEPTION;
- }
- r = JS_GetBigInt(val1);
- ret = bf_set(r, a);
- ret |= bf_rint(r, BF_RNDZ);
- JS_FreeValue(ctx, val);
- if (ret & BF_ST_MEM_ERROR) {
- JS_FreeValue(ctx, val1);
- val = JS_ThrowOutOfMemory(ctx);
- } else if (ret & BF_ST_INEXACT) {
- JS_FreeValue(ctx, val1);
- val = JS_ThrowRangeError(ctx, "cannot convert to BigInt: not an integer");
- } else {
- val = JS_CompactBigInt(ctx, val1);
- }
- }
- if (a == &a_s)
- bf_delete(a);
- }
- 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_ThrowTypeError(ctx, "not a constructor");
- return JS_ToBigIntCtorFree(ctx, js_dup(argv[0]));
- }
- static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
- {
- if (JS_IsBigInt(ctx, 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(ctx, 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;
- bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s;
- JSValue res;
- if (JS_ToIndex(ctx, &bits, argv[0]))
- return JS_EXCEPTION;
- res = JS_NewBigInt(ctx);
- if (JS_IsException(res))
- return JS_EXCEPTION;
- a = JS_ToBigInt(ctx, &a_s, argv[1]);
- if (!a) {
- JS_FreeValue(ctx, res);
- return JS_EXCEPTION;
- }
- /* XXX: optimize */
- r = JS_GetBigInt(res);
- bf_init(ctx->bf_ctx, mask);
- bf_set_ui(mask, 1);
- bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
- bf_add_si(mask, mask, -1, BF_PREC_INF, BF_RNDZ);
- bf_logic_and(r, a, mask);
- if (asIntN && bits != 0) {
- bf_set_ui(mask, 1);
- bf_mul_2exp(mask, bits - 1, BF_PREC_INF, BF_RNDZ);
- if (bf_cmpu(r, mask) >= 0) {
- bf_set_ui(mask, 1);
- bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
- bf_sub(r, r, mask, BF_PREC_INF, BF_RNDZ);
- }
- }
- bf_delete(mask);
- JS_FreeBigInt(ctx, a, &a_s);
- return JS_CompactBigInt(ctx, 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_AtomToString(ctx, JS_ATOM_empty_string),
- 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 */
- obj1 = JS_NewCFunction(ctx, js_function_proto_caller, NULL, 0);
- JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_caller, JS_UNDEFINED,
- obj1, 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,
- obj1, ctx->throw_type_error,
- JS_PROP_HAS_GET | JS_PROP_HAS_SET |
- JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
- JS_FreeValue(ctx, obj1);
- 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]);
- ctx->iterator_ctor = js_dup(obj);
- JS_SetPropertyFunctionList(ctx, obj,
- js_iterator_funcs,
- countof(js_iterator_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));
- /* 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_AtomToString(ctx, JS_ATOM_empty_string));
- 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;
- }
- // 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;
- 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)
- {
- uint32_t size_log2, size_elem;
- struct list_head *el;
- JSArrayBuffer *abuf;
- JSTypedArray *ta;
- JSObject *p;
- 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;
- }
- data = abuf->data;
- // update lengths of all typed arrays backed by this array buffer
- list_for_each(el, &abuf->array_list) {
- ta = list_entry(el, JSTypedArray, link);
- p = ta->obj;
- if (p->class_id == JS_CLASS_DATAVIEW)
- 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];
- }
- }
- }
- 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) {
- 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_get_length(JSContext *ctx, 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;
- bool oob;
- 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;
- oob = false;
- if (special == special_lastIndexOf) {
- k = len - 1;
- if (argc > 1) {
- if (JS_ToFloat64(ctx, &d, argv[1]))
- goto exception;
- if (isnan(d)) {
- k = 0;
- } else {
- if (d >= 0) {
- if (d < k) {
- k = d;
- }
- } else {
- d += len;
- if (d < 0)
- goto done;
- k = d;
- }
- }
- }
- 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;
- oob = true;
- }
- }
- 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 && JS_IsUndefined(argv[0]) && len > 0)
- res = oob ? -1 : 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) {
- JSBigInt *p1 = JS_VALUE_GET_PTR(argv[0]);
- if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
- if (bf_get_int64(&v64, &p1->num, 0) != 0)
- goto done;
- } else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
- if (bf_get_uint64((uint64_t *)&v64, &p1->num) != 0)
- goto done;
- } else {
- goto done;
- }
- 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_get_length(ctx, p1) >= count &&
- typed_array_get_length(ctx, 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) {
- JS_FreeValue(ctx, val);
- 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_ToBigIntValueFree(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);
- /* 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 (!JS_IsFunction(ctx, cb))
- return JS_ThrowTypeError(ctx, "argument must be a function");
- 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);
- 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_NewBool(ctx, 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_NewInt32(ctx, *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));
- }
- bool JS_DetectModule(const char *input, size_t input_len)
- {
- 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;
- }
- 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;
- 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
- #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)
- {
- 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;
- }
- /*--- integer to string conversions --*/
- /* All conversion functions:
- - require a destination array `buf` of sufficient length
- - write the string representation at the beginning of `buf`
- - null terminate the string
- - return the string length
- */
- /* 2 <= base <= 36 */
- char const digits36[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'
- };
- #define USE_SPECIAL_RADIX_10 1 // special case base 10 radix conversions
- #define USE_SINGLE_CASE_FAST 1 // special case single digit numbers
- /* using u32toa_shift variant */
- #define gen_digit(buf, c) if (is_be()) \
- buf = (buf >> 8) | ((uint64_t)(c) << ((sizeof(buf) - 1) * 8)); \
- else \
- buf = (buf << 8) | (c)
- static size_t u7toa_shift(char dest[minimum_length(8)], uint32_t n)
- {
- size_t len = 1;
- uint64_t buf = 0;
- while (n >= 10) {
- uint32_t quo = n % 10;
- n /= 10;
- gen_digit(buf, '0' + quo);
- len++;
- }
- gen_digit(buf, '0' + n);
- memcpy(dest, &buf, sizeof buf);
- return len;
- }
- static size_t u07toa_shift(char dest[minimum_length(8)], uint32_t n, size_t len)
- {
- size_t i;
- dest += len;
- dest[7] = '\0';
- for (i = 7; i-- > 1;) {
- uint32_t quo = n % 10;
- n /= 10;
- dest[i] = (char)('0' + quo);
- }
- dest[i] = (char)('0' + n);
- return len + 7;
- }
- size_t u32toa(char buf[minimum_length(11)], uint32_t n)
- {
- #ifdef USE_SINGLE_CASE_FAST /* 10% */
- if (n < 10) {
- buf[0] = (char)('0' + n);
- buf[1] = '\0';
- return 1;
- }
- #endif
- #define TEN_POW_7 10000000
- if (n >= TEN_POW_7) {
- uint32_t quo = n / TEN_POW_7;
- n %= TEN_POW_7;
- size_t len = u7toa_shift(buf, quo);
- return u07toa_shift(buf, n, len);
- }
- return u7toa_shift(buf, n);
- }
- size_t u64toa(char buf[minimum_length(21)], uint64_t n)
- {
- if (likely(n < 0x100000000))
- return u32toa(buf, n);
- size_t len;
- if (n >= TEN_POW_7) {
- uint64_t n1 = n / TEN_POW_7;
- n %= TEN_POW_7;
- if (n1 >= TEN_POW_7) {
- uint32_t quo = n1 / TEN_POW_7;
- n1 %= TEN_POW_7;
- len = u7toa_shift(buf, quo);
- len = u07toa_shift(buf, n1, len);
- } else {
- len = u7toa_shift(buf, n1);
- }
- return u07toa_shift(buf, n, len);
- }
- return u7toa_shift(buf, n);
- }
- size_t i32toa(char buf[minimum_length(12)], int32_t n)
- {
- if (likely(n >= 0))
- return u32toa(buf, n);
- buf[0] = '-';
- return 1 + u32toa(buf + 1, -(uint32_t)n);
- }
- size_t i64toa(char buf[minimum_length(22)], int64_t n)
- {
- if (likely(n >= 0))
- return u64toa(buf, n);
- buf[0] = '-';
- return 1 + u64toa(buf + 1, -(uint64_t)n);
- }
- /* using u32toa_radix_length variant */
- static uint8_t const radix_shift[64] = {
- 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
- 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- };
- size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned base)
- {
- int shift;
- #ifdef USE_SPECIAL_RADIX_10
- if (likely(base == 10))
- return u32toa(buf, n);
- #endif
- if (n < base) {
- buf[0] = digits36[n];
- buf[1] = '\0';
- return 1;
- }
- shift = radix_shift[base & 63];
- if (shift) {
- uint32_t mask = (1 << shift) - 1;
- size_t len = (32 - clz32(n) + shift - 1) / shift;
- size_t last = n & mask;
- char *end = buf + len;
- n >>= shift;
- *end-- = '\0';
- *end-- = digits36[last];
- while (n >= base) {
- size_t quo = n & mask;
- n >>= shift;
- *end-- = digits36[quo];
- }
- *end = digits36[n];
- return len;
- } else {
- size_t len = 2;
- size_t last = n % base;
- n /= base;
- uint32_t nbase = base;
- while (n >= nbase) {
- nbase *= base;
- len++;
- }
- char *end = buf + len;
- *end-- = '\0';
- *end-- = digits36[last];
- while (n >= base) {
- size_t quo = n % base;
- n /= base;
- *end-- = digits36[quo];
- }
- *end = digits36[n];
- return len;
- }
- }
- size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned base)
- {
- int shift;
- #ifdef USE_SPECIAL_RADIX_10
- if (likely(base == 10))
- return u64toa(buf, n);
- #endif
- shift = radix_shift[base & 63];
- if (shift) {
- if (n < base) {
- buf[0] = digits36[n];
- buf[1] = '\0';
- return 1;
- }
- uint64_t mask = (1 << shift) - 1;
- size_t len = (64 - clz64(n) + shift - 1) / shift;
- size_t last = n & mask;
- char *end = buf + len;
- n >>= shift;
- *end-- = '\0';
- *end-- = digits36[last];
- while (n >= base) {
- size_t quo = n & mask;
- n >>= shift;
- *end-- = digits36[quo];
- }
- *end = digits36[n];
- return len;
- } else {
- if (likely(n < 0x100000000))
- return u32toa_radix(buf, n, base);
- size_t last = n % base;
- n /= base;
- uint64_t nbase = base;
- size_t len = 2;
- while (n >= nbase) {
- nbase *= base;
- len++;
- }
- char *end = buf + len;
- *end-- = '\0';
- *end-- = digits36[last];
- while (n >= base) {
- size_t quo = n % base;
- n /= base;
- *end-- = digits36[quo];
- }
- *end = digits36[n];
- return len;
- }
- }
- size_t i32toa_radix(char buf[minimum_length(34)], int32_t n, unsigned int base)
- {
- if (likely(n >= 0))
- return u32toa_radix(buf, n, base);
- buf[0] = '-';
- return 1 + u32toa_radix(buf + 1, -(uint32_t)n, base);
- }
- size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base)
- {
- if (likely(n >= 0))
- return u64toa_radix(buf, n, base);
- buf[0] = '-';
- return 1 + u64toa_radix(buf + 1, -(uint64_t)n, base);
- }
- #undef gen_digit
- #undef TEN_POW_7
- #undef USE_SPECIAL_RADIX_10
- #undef USE_SINGLE_CASE_FAST
- /*---- 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;
- }
- /*--- Cross-platform threading APIs. ----*/
- #if !defined(EMSCRIPTEN) && !defined(__wasi__)
- #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;
- }
- #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;
- }
- #endif
- #endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */
- #ifdef __GNUC__
- #pragma GCC visibility pop
- #endif
- /*
- * Tiny arbitrary precision floating point library
- *
- * Copyright (c) 2017-2021 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 <inttypes.h>
- #include <math.h>
- #include <string.h>
- #include <assert.h>
- #ifdef __AVX2__
- #include <immintrin.h>
- #endif
- /* enable it to check the multiplication result */
- //#define USE_MUL_CHECK
- /* enable it to use FFT/NTT multiplication */
- #define USE_FFT_MUL
- /* enable decimal floating point support */
- #define USE_BF_DEC
- //#define inline __attribute__((always_inline))
- #ifdef __AVX2__
- #define FFT_MUL_THRESHOLD 100 /* in limbs of the smallest factor */
- #else
- #define FFT_MUL_THRESHOLD 100 /* in limbs of the smallest factor */
- #endif
- /* XXX: adjust */
- #define DIVNORM_LARGE_THRESHOLD 50
- #define UDIV1NORM_THRESHOLD 3
- #if LIMB_BITS == 64
- #define FMT_LIMB1 "%" PRIx64
- #define FMT_LIMB "%016" PRIx64
- #define PRId_LIMB PRId64
- #define PRIu_LIMB PRIu64
- #else
- #define FMT_LIMB1 "%x"
- #define FMT_LIMB "%08x"
- #define PRId_LIMB "d"
- #define PRIu_LIMB "u"
- #endif
- typedef intptr_t mp_size_t;
- typedef int bf_op2_func_t(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags);
- #ifdef USE_FFT_MUL
- #define FFT_MUL_R_OVERLAP_A (1 << 0)
- #define FFT_MUL_R_OVERLAP_B (1 << 1)
- #define FFT_MUL_R_NORESIZE (1 << 2)
- static no_inline int fft_mul(bf_context_t *s,
- bf_t *res, limb_t *a_tab, limb_t a_len,
- limb_t *b_tab, limb_t b_len, int mul_flags);
- static void fft_clear_cache(bf_context_t *s);
- #endif
- #ifdef USE_BF_DEC
- static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos);
- #endif
- /* could leading zeros */
- static inline int clz(limb_t a)
- {
- if (a == 0) {
- return LIMB_BITS;
- } else {
- #if LIMB_BITS == 64
- return clz64(a);
- #else
- return clz32(a);
- #endif
- }
- }
- static inline int ctz(limb_t a)
- {
- if (a == 0) {
- return LIMB_BITS;
- } else {
- #if LIMB_BITS == 64
- return ctz64(a);
- #else
- return ctz32(a);
- #endif
- }
- }
- static inline int ceil_log2(limb_t a)
- {
- if (a <= 1)
- return 0;
- else
- return LIMB_BITS - clz(a - 1);
- }
- /* b must be >= 1 */
- static inline slimb_t ceil_div(slimb_t a, slimb_t b)
- {
- if (a >= 0)
- return (a + b - 1) / b;
- else
- return a / b;
- }
- /* b must be >= 1 */
- static inline slimb_t floor_div(slimb_t a, slimb_t b)
- {
- if (a >= 0) {
- return a / b;
- } else {
- return (a - b + 1) / b;
- }
- }
- /* return r = a modulo b (0 <= r <= b - 1. b must be >= 1 */
- static inline limb_t smod(slimb_t a, slimb_t b)
- {
- a = a % (slimb_t)b;
- if (a < 0)
- a += b;
- return a;
- }
- /* signed addition with saturation */
- static inline slimb_t sat_add(slimb_t a, slimb_t b)
- {
- slimb_t r;
- r = a + b;
- /* overflow ? */
- if (((a ^ r) & (b ^ r)) < 0)
- r = (a >> (LIMB_BITS - 1)) ^ (((limb_t)1 << (LIMB_BITS - 1)) - 1);
- return r;
- }
- static inline __maybe_unused limb_t shrd(limb_t low, limb_t high, long shift)
- {
- if (shift != 0)
- low = (low >> shift) | (high << (LIMB_BITS - shift));
- return low;
- }
- static inline __maybe_unused limb_t shld(limb_t a1, limb_t a0, long shift)
- {
- if (shift != 0)
- return (a1 << shift) | (a0 >> (LIMB_BITS - shift));
- else
- return a1;
- }
- #define malloc(s) malloc_is_forbidden(s)
- #define free(p) free_is_forbidden(p)
- #define realloc(p, s) realloc_is_forbidden(p, s)
- void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func,
- void *realloc_opaque)
- {
- memset(s, 0, sizeof(*s));
- s->realloc_func = realloc_func;
- s->realloc_opaque = realloc_opaque;
- }
- void bf_context_end(bf_context_t *s)
- {
- bf_clear_cache(s);
- }
- void bf_init(bf_context_t *s, bf_t *r)
- {
- r->ctx = s;
- r->sign = 0;
- r->expn = BF_EXP_ZERO;
- r->len = 0;
- r->tab = NULL;
- }
- /* return 0 if OK, -1 if alloc error */
- int bf_resize(bf_t *r, limb_t len)
- {
- limb_t *tab;
- if (len != r->len) {
- tab = bf_realloc(r->ctx, r->tab, len * sizeof(limb_t));
- if (!tab && len != 0)
- return -1;
- r->tab = tab;
- r->len = len;
- }
- return 0;
- }
- /* return 0 or BF_ST_MEM_ERROR */
- int bf_set_ui(bf_t *r, uint64_t a)
- {
- r->sign = 0;
- if (a == 0) {
- r->expn = BF_EXP_ZERO;
- bf_resize(r, 0); /* cannot fail */
- }
- #if LIMB_BITS == 32
- else if (a <= 0xffffffff)
- #else
- else
- #endif
- {
- int shift;
- if (bf_resize(r, 1))
- goto fail;
- shift = clz(a);
- r->tab[0] = a << shift;
- r->expn = LIMB_BITS - shift;
- }
- #if LIMB_BITS == 32
- else {
- uint32_t a1, a0;
- int shift;
- if (bf_resize(r, 2))
- goto fail;
- a0 = a;
- a1 = a >> 32;
- shift = clz(a1);
- r->tab[0] = a0 << shift;
- r->tab[1] = shld(a1, a0, shift);
- r->expn = 2 * LIMB_BITS - shift;
- }
- #endif
- return 0;
- fail:
- bf_set_nan(r);
- return BF_ST_MEM_ERROR;
- }
- /* return 0 or BF_ST_MEM_ERROR */
- int bf_set_si(bf_t *r, int64_t a)
- {
- int ret;
- if (a < 0) {
- ret = bf_set_ui(r, -a);
- r->sign = 1;
- } else {
- ret = bf_set_ui(r, a);
- }
- return ret;
- }
- void bf_set_nan(bf_t *r)
- {
- bf_resize(r, 0); /* cannot fail */
- r->expn = BF_EXP_NAN;
- r->sign = 0;
- }
- void bf_set_zero(bf_t *r, int is_neg)
- {
- bf_resize(r, 0); /* cannot fail */
- r->expn = BF_EXP_ZERO;
- r->sign = is_neg;
- }
- void bf_set_inf(bf_t *r, int is_neg)
- {
- bf_resize(r, 0); /* cannot fail */
- r->expn = BF_EXP_INF;
- r->sign = is_neg;
- }
- /* return 0 or BF_ST_MEM_ERROR */
- int bf_set(bf_t *r, const bf_t *a)
- {
- if (r == a)
- return 0;
- if (bf_resize(r, a->len)) {
- bf_set_nan(r);
- return BF_ST_MEM_ERROR;
- }
- r->sign = a->sign;
- r->expn = a->expn;
- if (a->len > 0)
- memcpy(r->tab, a->tab, a->len * sizeof(limb_t));
- return 0;
- }
- /* equivalent to bf_set(r, a); bf_delete(a) */
- void bf_move(bf_t *r, bf_t *a)
- {
- bf_context_t *s = r->ctx;
- if (r == a)
- return;
- bf_free(s, r->tab);
- *r = *a;
- }
- static limb_t get_limbz(const bf_t *a, limb_t idx)
- {
- if (idx >= a->len)
- return 0;
- else
- return a->tab[idx];
- }
- /* get LIMB_BITS at bit position 'pos' in tab */
- static inline limb_t get_bits(const limb_t *tab, limb_t len, slimb_t pos)
- {
- limb_t i, a0, a1;
- int p;
- i = pos >> LIMB_LOG2_BITS;
- p = pos & (LIMB_BITS - 1);
- if (i < len)
- a0 = tab[i];
- else
- a0 = 0;
- if (p == 0) {
- return a0;
- } else {
- i++;
- if (i < len)
- a1 = tab[i];
- else
- a1 = 0;
- return (a0 >> p) | (a1 << (LIMB_BITS - p));
- }
- }
- static inline limb_t get_bit(const limb_t *tab, limb_t len, slimb_t pos)
- {
- slimb_t i;
- i = pos >> LIMB_LOG2_BITS;
- if (i < 0 || i >= len)
- return 0;
- return (tab[i] >> (pos & (LIMB_BITS - 1))) & 1;
- }
- static inline limb_t limb_mask(int start, int last)
- {
- limb_t v;
- int n;
- n = last - start + 1;
- if (n == LIMB_BITS)
- v = -1;
- else
- v = (((limb_t)1 << n) - 1) << start;
- return v;
- }
- static limb_t mp_scan_nz(const limb_t *tab, mp_size_t n)
- {
- mp_size_t i;
- for(i = 0; i < n; i++) {
- if (tab[i] != 0)
- return 1;
- }
- return 0;
- }
- /* return != 0 if one bit between 0 and bit_pos inclusive is not zero. */
- static inline limb_t scan_bit_nz(const bf_t *r, slimb_t bit_pos)
- {
- slimb_t pos;
- limb_t v;
- pos = bit_pos >> LIMB_LOG2_BITS;
- if (pos < 0)
- return 0;
- v = r->tab[pos] & limb_mask(0, bit_pos & (LIMB_BITS - 1));
- if (v != 0)
- return 1;
- pos--;
- while (pos >= 0) {
- if (r->tab[pos] != 0)
- return 1;
- pos--;
- }
- return 0;
- }
- /* return the addend for rounding. Note that prec can be <= 0 (for
- BF_FLAG_RADPNT_PREC) */
- static int bf_get_rnd_add(int *pret, const bf_t *r, limb_t l,
- slimb_t prec, int rnd_mode)
- {
- int add_one, inexact;
- limb_t bit1, bit0;
- if (rnd_mode == BF_RNDF) {
- bit0 = 1; /* faithful rounding does not honor the INEXACT flag */
- } else {
- /* starting limb for bit 'prec + 1' */
- bit0 = scan_bit_nz(r, l * LIMB_BITS - 1 - bf_max(0, prec + 1));
- }
- /* get the bit at 'prec' */
- bit1 = get_bit(r->tab, l, l * LIMB_BITS - 1 - prec);
- inexact = (bit1 | bit0) != 0;
- add_one = 0;
- switch(rnd_mode) {
- case BF_RNDZ:
- break;
- case BF_RNDN:
- if (bit1) {
- if (bit0) {
- add_one = 1;
- } else {
- /* round to even */
- add_one =
- get_bit(r->tab, l, l * LIMB_BITS - 1 - (prec - 1));
- }
- }
- break;
- case BF_RNDD:
- case BF_RNDU:
- if (r->sign == (rnd_mode == BF_RNDD))
- add_one = inexact;
- break;
- case BF_RNDA:
- add_one = inexact;
- break;
- case BF_RNDNA:
- case BF_RNDF:
- add_one = bit1;
- break;
- default:
- abort();
- }
- if (inexact)
- *pret |= BF_ST_INEXACT;
- return add_one;
- }
- static int bf_set_overflow(bf_t *r, int sign, limb_t prec, bf_flags_t flags)
- {
- slimb_t i, l, e_max;
- int rnd_mode;
- rnd_mode = flags & BF_RND_MASK;
- if (prec == BF_PREC_INF ||
- rnd_mode == BF_RNDN ||
- rnd_mode == BF_RNDNA ||
- rnd_mode == BF_RNDA ||
- (rnd_mode == BF_RNDD && sign == 1) ||
- (rnd_mode == BF_RNDU && sign == 0)) {
- bf_set_inf(r, sign);
- } else {
- /* set to maximum finite number */
- l = (prec + LIMB_BITS - 1) / LIMB_BITS;
- if (bf_resize(r, l)) {
- bf_set_nan(r);
- return BF_ST_MEM_ERROR;
- }
- r->tab[0] = limb_mask((-prec) & (LIMB_BITS - 1),
- LIMB_BITS - 1);
- for(i = 1; i < l; i++)
- r->tab[i] = (limb_t)-1;
- e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
- r->expn = e_max;
- r->sign = sign;
- }
- return BF_ST_OVERFLOW | BF_ST_INEXACT;
- }
- /* round to prec1 bits assuming 'r' is non zero and finite. 'r' is
- assumed to have length 'l' (1 <= l <= r->len). Note: 'prec1' can be
- infinite (BF_PREC_INF). 'ret' is 0 or BF_ST_INEXACT if the result
- is known to be inexact. Can fail with BF_ST_MEM_ERROR in case of
- overflow not returning infinity. */
- static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l,
- int ret)
- {
- limb_t v, a;
- int shift, add_one, rnd_mode;
- slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;
- /* e_min and e_max are computed to match the IEEE 754 conventions */
- e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
- e_min = -e_range + 3;
- e_max = e_range;
- if (flags & BF_FLAG_RADPNT_PREC) {
- /* 'prec' is the precision after the radix point */
- if (prec1 != BF_PREC_INF)
- prec = r->expn + prec1;
- else
- prec = prec1;
- } else if (unlikely(r->expn < e_min) && (flags & BF_FLAG_SUBNORMAL)) {
- /* restrict the precision in case of potentially subnormal
- result */
- assert(prec1 != BF_PREC_INF);
- prec = prec1 - (e_min - r->expn);
- } else {
- prec = prec1;
- }
- /* round to prec bits */
- rnd_mode = flags & BF_RND_MASK;
- add_one = bf_get_rnd_add(&ret, r, l, prec, rnd_mode);
- if (prec <= 0) {
- if (add_one) {
- bf_resize(r, 1); /* cannot fail */
- r->tab[0] = (limb_t)1 << (LIMB_BITS - 1);
- r->expn += 1 - prec;
- ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;
- return ret;
- } else {
- goto underflow;
- }
- } else if (add_one) {
- limb_t carry;
- /* add one starting at digit 'prec - 1' */
- bit_pos = l * LIMB_BITS - 1 - (prec - 1);
- pos = bit_pos >> LIMB_LOG2_BITS;
- carry = (limb_t)1 << (bit_pos & (LIMB_BITS - 1));
- for(i = pos; i < l; i++) {
- v = r->tab[i] + carry;
- carry = (v < carry);
- r->tab[i] = v;
- if (carry == 0)
- break;
- }
- if (carry) {
- /* shift right by one digit */
- v = 1;
- for(i = l - 1; i >= pos; i--) {
- a = r->tab[i];
- r->tab[i] = (a >> 1) | (v << (LIMB_BITS - 1));
- v = a;
- }
- r->expn++;
- }
- }
- /* check underflow */
- if (unlikely(r->expn < e_min)) {
- if (flags & BF_FLAG_SUBNORMAL) {
- /* if inexact, also set the underflow flag */
- if (ret & BF_ST_INEXACT)
- ret |= BF_ST_UNDERFLOW;
- } else {
- underflow:
- ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;
- bf_set_zero(r, r->sign);
- return ret;
- }
- }
- /* check overflow */
- if (unlikely(r->expn > e_max))
- return bf_set_overflow(r, r->sign, prec1, flags);
- /* keep the bits starting at 'prec - 1' */
- bit_pos = l * LIMB_BITS - 1 - (prec - 1);
- i = bit_pos >> LIMB_LOG2_BITS;
- if (i >= 0) {
- shift = bit_pos & (LIMB_BITS - 1);
- if (shift != 0)
- r->tab[i] &= limb_mask(shift, LIMB_BITS - 1);
- } else {
- i = 0;
- }
- /* remove trailing zeros */
- while (r->tab[i] == 0)
- i++;
- if (i > 0) {
- l -= i;
- memmove(r->tab, r->tab + i, l * sizeof(limb_t));
- }
- bf_resize(r, l); /* cannot fail */
- return ret;
- }
- /* 'r' must be a finite number. */
- int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags)
- {
- limb_t l, v, a;
- int shift, ret;
- slimb_t i;
- // bf_print_str("bf_renorm", r);
- l = r->len;
- while (l > 0 && r->tab[l - 1] == 0)
- l--;
- if (l == 0) {
- /* zero */
- r->expn = BF_EXP_ZERO;
- bf_resize(r, 0); /* cannot fail */
- ret = 0;
- } else {
- r->expn -= (r->len - l) * LIMB_BITS;
- /* shift to have the MSB set to '1' */
- v = r->tab[l - 1];
- shift = clz(v);
- if (shift != 0) {
- v = 0;
- for(i = 0; i < l; i++) {
- a = r->tab[i];
- r->tab[i] = (a << shift) | (v >> (LIMB_BITS - shift));
- v = a;
- }
- r->expn -= shift;
- }
- ret = __bf_round(r, prec1, flags, l, 0);
- }
- // bf_print_str("r_final", r);
- return ret;
- }
- /* return true if rounding can be done at precision 'prec' assuming
- the exact result r is such that |r-a| <= 2^(EXP(a)-k). */
- /* XXX: check the case where the exponent would be incremented by the
- rounding */
- int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k)
- {
- bool is_rndn;
- slimb_t bit_pos, n;
- limb_t bit;
- if (a->expn == BF_EXP_INF || a->expn == BF_EXP_NAN)
- return false;
- if (rnd_mode == BF_RNDF) {
- return (k >= (prec + 1));
- }
- if (a->expn == BF_EXP_ZERO)
- return false;
- is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
- if (k < (prec + 2))
- return false;
- bit_pos = a->len * LIMB_BITS - 1 - prec;
- n = k - prec;
- /* bit pattern for RNDN or RNDNA: 0111.. or 1000...
- for other rounding modes: 000... or 111...
- */
- bit = get_bit(a->tab, a->len, bit_pos);
- bit_pos--;
- n--;
- bit ^= is_rndn;
- /* XXX: slow, but a few iterations on average */
- while (n != 0) {
- if (get_bit(a->tab, a->len, bit_pos) != bit)
- return true;
- bit_pos--;
- n--;
- }
- return false;
- }
- /* Cannot fail with BF_ST_MEM_ERROR. */
- int bf_round(bf_t *r, limb_t prec, bf_flags_t flags)
- {
- if (r->len == 0)
- return 0;
- return __bf_round(r, prec, flags, r->len, 0);
- }
- /* for debugging */
- static __maybe_unused void dump_limbs(const char *str, const limb_t *tab, limb_t n)
- {
- limb_t i;
- printf("%s: len=%" PRId_LIMB "\n", str, n);
- for(i = 0; i < n; i++) {
- printf("%" PRId_LIMB ": " FMT_LIMB "\n",
- i, tab[i]);
- }
- }
- void mp_print_str(const char *str, const limb_t *tab, limb_t n)
- {
- slimb_t i;
- printf("%s= 0x", str);
- for(i = n - 1; i >= 0; i--) {
- if (i != (n - 1))
- printf("_");
- printf(FMT_LIMB, tab[i]);
- }
- printf("\n");
- }
- static __maybe_unused void mp_print_str_h(const char *str,
- const limb_t *tab, limb_t n,
- limb_t high)
- {
- slimb_t i;
- printf("%s= 0x", str);
- printf(FMT_LIMB, high);
- for(i = n - 1; i >= 0; i--) {
- printf("_");
- printf(FMT_LIMB, tab[i]);
- }
- printf("\n");
- }
- /* for debugging */
- void bf_print_str(const char *str, const bf_t *a)
- {
- slimb_t i;
- printf("%s=", str);
- if (a->expn == BF_EXP_NAN) {
- printf("NaN");
- } else {
- if (a->sign)
- putchar('-');
- if (a->expn == BF_EXP_ZERO) {
- putchar('0');
- } else if (a->expn == BF_EXP_INF) {
- printf("Inf");
- } else {
- printf("0x0.");
- for(i = a->len - 1; i >= 0; i--)
- printf(FMT_LIMB, a->tab[i]);
- printf("p%" PRId_LIMB, a->expn);
- }
- }
- printf("\n");
- }
- /* compare the absolute value of 'a' and 'b'. Return < 0 if a < b, 0
- if a = b and > 0 otherwise. */
- int bf_cmpu(const bf_t *a, const bf_t *b)
- {
- slimb_t i;
- limb_t len, v1, v2;
- if (a->expn != b->expn) {
- if (a->expn < b->expn)
- return -1;
- else
- return 1;
- }
- len = bf_max(a->len, b->len);
- for(i = len - 1; i >= 0; i--) {
- v1 = get_limbz(a, a->len - len + i);
- v2 = get_limbz(b, b->len - len + i);
- if (v1 != v2) {
- if (v1 < v2)
- return -1;
- else
- return 1;
- }
- }
- return 0;
- }
- /* Full order: -0 < 0, NaN == NaN and NaN is larger than all other numbers */
- int bf_cmp_full(const bf_t *a, const bf_t *b)
- {
- int res;
- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
- if (a->expn == b->expn)
- res = 0;
- else if (a->expn == BF_EXP_NAN)
- res = 1;
- else
- res = -1;
- } else if (a->sign != b->sign) {
- res = 1 - 2 * a->sign;
- } else {
- res = bf_cmpu(a, b);
- if (a->sign)
- res = -res;
- }
- return res;
- }
- /* Standard floating point comparison: return 2 if one of the operands
- is NaN (unordered) or -1, 0, 1 depending on the ordering assuming
- -0 == +0 */
- int bf_cmp(const bf_t *a, const bf_t *b)
- {
- int res;
- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
- res = 2;
- } else if (a->sign != b->sign) {
- if (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO)
- res = 0;
- else
- res = 1 - 2 * a->sign;
- } else {
- res = bf_cmpu(a, b);
- if (a->sign)
- res = -res;
- }
- return res;
- }
- /* Compute the number of bits 'n' matching the pattern:
- a= X1000..0
- b= X0111..1
- When computing a-b, the result will have at least n leading zero
- bits.
- Precondition: a > b and a.expn - b.expn = 0 or 1
- */
- static limb_t count_cancelled_bits(const bf_t *a, const bf_t *b)
- {
- slimb_t bit_offset, b_offset, n;
- int p, p1;
- limb_t v1, v2, mask;
- bit_offset = a->len * LIMB_BITS - 1;
- b_offset = (b->len - a->len) * LIMB_BITS - (LIMB_BITS - 1) +
- a->expn - b->expn;
- n = 0;
- /* first search the equals bits */
- for(;;) {
- v1 = get_limbz(a, bit_offset >> LIMB_LOG2_BITS);
- v2 = get_bits(b->tab, b->len, bit_offset + b_offset);
- // printf("v1=" FMT_LIMB " v2=" FMT_LIMB "\n", v1, v2);
- if (v1 != v2)
- break;
- n += LIMB_BITS;
- bit_offset -= LIMB_BITS;
- }
- /* find the position of the first different bit */
- p = clz(v1 ^ v2) + 1;
- n += p;
- /* then search for '0' in a and '1' in b */
- p = LIMB_BITS - p;
- if (p > 0) {
- /* search in the trailing p bits of v1 and v2 */
- mask = limb_mask(0, p - 1);
- p1 = bf_min(clz(v1 & mask), clz((~v2) & mask)) - (LIMB_BITS - p);
- n += p1;
- if (p1 != p)
- goto done;
- }
- bit_offset -= LIMB_BITS;
- for(;;) {
- v1 = get_limbz(a, bit_offset >> LIMB_LOG2_BITS);
- v2 = get_bits(b->tab, b->len, bit_offset + b_offset);
- // printf("v1=" FMT_LIMB " v2=" FMT_LIMB "\n", v1, v2);
- if (v1 != 0 || v2 != -1) {
- /* different: count the matching bits */
- p1 = bf_min(clz(v1), clz(~v2));
- n += p1;
- break;
- }
- n += LIMB_BITS;
- bit_offset -= LIMB_BITS;
- }
- done:
- return n;
- }
- static int bf_add_internal(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags, int b_neg)
- {
- const bf_t *tmp;
- int is_sub, ret, cmp_res, a_sign, b_sign;
- a_sign = a->sign;
- b_sign = b->sign ^ b_neg;
- is_sub = a_sign ^ b_sign;
- cmp_res = bf_cmpu(a, b);
- if (cmp_res < 0) {
- tmp = a;
- a = b;
- b = tmp;
- a_sign = b_sign; /* b_sign is never used later */
- }
- /* abs(a) >= abs(b) */
- if (cmp_res == 0 && is_sub && a->expn < BF_EXP_INF) {
- /* zero result */
- bf_set_zero(r, (flags & BF_RND_MASK) == BF_RNDD);
- ret = 0;
- } else if (a->len == 0 || b->len == 0) {
- ret = 0;
- if (a->expn >= BF_EXP_INF) {
- if (a->expn == BF_EXP_NAN) {
- /* at least one operand is NaN */
- bf_set_nan(r);
- } else if (b->expn == BF_EXP_INF && is_sub) {
- /* infinities with different signs */
- bf_set_nan(r);
- ret = BF_ST_INVALID_OP;
- } else {
- bf_set_inf(r, a_sign);
- }
- } else {
- /* at least one zero and not subtract */
- bf_set(r, a);
- r->sign = a_sign;
- goto renorm;
- }
- } else {
- slimb_t d, a_offset, b_bit_offset, i, cancelled_bits;
- limb_t carry, v1, v2, u, r_len, carry1, precl, tot_len, z, sub_mask;
- r->sign = a_sign;
- r->expn = a->expn;
- d = a->expn - b->expn;
- /* must add more precision for the leading cancelled bits in
- subtraction */
- if (is_sub) {
- if (d <= 1)
- cancelled_bits = count_cancelled_bits(a, b);
- else
- cancelled_bits = 1;
- } else {
- cancelled_bits = 0;
- }
- /* add two extra bits for rounding */
- precl = (cancelled_bits + prec + 2 + LIMB_BITS - 1) / LIMB_BITS;
- tot_len = bf_max(a->len, b->len + (d + LIMB_BITS - 1) / LIMB_BITS);
- r_len = bf_min(precl, tot_len);
- if (bf_resize(r, r_len))
- goto fail;
- a_offset = a->len - r_len;
- b_bit_offset = (b->len - r_len) * LIMB_BITS + d;
- /* compute the bits before for the rounding */
- carry = is_sub;
- z = 0;
- sub_mask = -is_sub;
- i = r_len - tot_len;
- while (i < 0) {
- slimb_t ap, bp;
- bool inflag;
- ap = a_offset + i;
- bp = b_bit_offset + i * LIMB_BITS;
- inflag = false;
- if (ap >= 0 && ap < a->len) {
- v1 = a->tab[ap];
- inflag = true;
- } else {
- v1 = 0;
- }
- if (bp + LIMB_BITS > 0 && bp < (slimb_t)(b->len * LIMB_BITS)) {
- v2 = get_bits(b->tab, b->len, bp);
- inflag = true;
- } else {
- v2 = 0;
- }
- if (!inflag) {
- /* outside 'a' and 'b': go directly to the next value
- inside a or b so that the running time does not
- depend on the exponent difference */
- i = 0;
- if (ap < 0)
- i = bf_min(i, -a_offset);
- /* b_bit_offset + i * LIMB_BITS + LIMB_BITS >= 1
- equivalent to
- i >= ceil(-b_bit_offset + 1 - LIMB_BITS) / LIMB_BITS)
- */
- if (bp + LIMB_BITS <= 0)
- i = bf_min(i, (-b_bit_offset) >> LIMB_LOG2_BITS);
- } else {
- i++;
- }
- v2 ^= sub_mask;
- u = v1 + v2;
- carry1 = u < v1;
- u += carry;
- carry = (u < carry) | carry1;
- z |= u;
- }
- /* and the result */
- for(i = 0; i < r_len; i++) {
- v1 = get_limbz(a, a_offset + i);
- v2 = get_bits(b->tab, b->len, b_bit_offset + i * LIMB_BITS);
- v2 ^= sub_mask;
- u = v1 + v2;
- carry1 = u < v1;
- u += carry;
- carry = (u < carry) | carry1;
- r->tab[i] = u;
- }
- /* set the extra bits for the rounding */
- r->tab[0] |= (z != 0);
- /* carry is only possible in add case */
- if (!is_sub && carry) {
- if (bf_resize(r, r_len + 1))
- goto fail;
- r->tab[r_len] = 1;
- r->expn += LIMB_BITS;
- }
- renorm:
- ret = bf_normalize_and_round(r, prec, flags);
- }
- return ret;
- fail:
- bf_set_nan(r);
- return BF_ST_MEM_ERROR;
- }
- static int __bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags)
- {
- return bf_add_internal(r, a, b, prec, flags, 0);
- }
- static int __bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags)
- {
- return bf_add_internal(r, a, b, prec, flags, 1);
- }
- limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2,
- limb_t n, limb_t carry)
- {
- slimb_t i;
- limb_t k, a, v, k1;
- k = carry;
- for(i=0;i<n;i++) {
- v = op1[i];
- a = v + op2[i];
- k1 = a < v;
- a = a + k;
- k = (a < k) | k1;
- res[i] = a;
- }
- return k;
- }
- 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;
- }
- limb_t mp_sub(limb_t *res, const limb_t *op1, const limb_t *op2,
- mp_size_t n, limb_t carry)
- {
- int i;
- 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 */
- static limb_t mp_neg(limb_t *res, const limb_t *op2, mp_size_t n, limb_t carry)
- {
- int i;
- limb_t k, a, v, k1;
- k = carry;
- for(i=0;i<n;i++) {
- v = 0;
- a = v - op2[i];
- k1 = a > v;
- v = a - k;
- k = (v > a) | k1;
- res[i] = v;
- }
- return k;
- }
- limb_t mp_sub_ui(limb_t *tab, limb_t b, mp_size_t n)
- {
- mp_size_t i;
- limb_t k, a, v;
- k=b;
- for(i=0;i<n;i++) {
- v = tab[i];
- a = v - k;
- k = a > v;
- tab[i] = a;
- if (k == 0)
- break;
- }
- return k;
- }
- /* 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);
- }
- /* 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;
- }
- /* tabr[] += taba[] * b, return the high word. */
- static limb_t mp_add_mul1(limb_t *tabr, const limb_t *taba, limb_t n,
- limb_t b)
- {
- limb_t i, l;
- dlimb_t t;
- l = 0;
- for(i = 0; i < n; i++) {
- t = (dlimb_t)taba[i] * (dlimb_t)b + l + tabr[i];
- tabr[i] = t;
- l = t >> LIMB_BITS;
- }
- return l;
- }
- /* size of the result : op1_size + op2_size. */
- static void mp_mul_basecase(limb_t *result,
- const limb_t *op1, limb_t op1_size,
- const limb_t *op2, limb_t op2_size)
- {
- limb_t i, r;
- result[op1_size] = mp_mul1(result, op1, op1_size, op2[0], 0);
- for(i=1;i<op2_size;i++) {
- r = mp_add_mul1(result + i, op1, op1_size, op2[i]);
- result[i + op1_size] = r;
- }
- }
- /* return 0 if OK, -1 if memory error */
- /* XXX: change API so that result can be allocated */
- int mp_mul(bf_context_t *s, limb_t *result,
- const limb_t *op1, limb_t op1_size,
- const limb_t *op2, limb_t op2_size)
- {
- #ifdef USE_FFT_MUL
- if (unlikely(bf_min(op1_size, op2_size) >= FFT_MUL_THRESHOLD)) {
- bf_t r_s, *r = &r_s;
- r->tab = result;
- /* XXX: optimize memory usage in API */
- if (fft_mul(s, r, (limb_t *)op1, op1_size,
- (limb_t *)op2, op2_size, FFT_MUL_R_NORESIZE))
- return -1;
- } else
- #endif
- {
- mp_mul_basecase(result, op1, op1_size, op2, op2_size);
- }
- return 0;
- }
- /* tabr[] -= taba[] * b. Return the value to substract to the high
- word. */
- static limb_t mp_sub_mul1(limb_t *tabr, const limb_t *taba, limb_t n,
- limb_t b)
- {
- limb_t i, l;
- dlimb_t t;
- l = 0;
- for(i = 0; i < n; i++) {
- t = tabr[i] - (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;
- }
- /* b must be >= 1 << (LIMB_BITS - 1) */
- static limb_t mp_div1norm(limb_t *tabr, const limb_t *taba, limb_t n,
- limb_t b, limb_t r)
- {
- slimb_t i;
- if (n >= UDIV1NORM_THRESHOLD) {
- limb_t b_inv;
- b_inv = udiv1norm_init(b);
- for(i = n - 1; i >= 0; i--) {
- tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv);
- }
- } else {
- 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;
- }
- static int mp_divnorm_large(bf_context_t *s,
- limb_t *tabq, limb_t *taba, limb_t na,
- const limb_t *tabb, limb_t nb);
- /* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb
- - 1] must be >= 1 << (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 int mp_divnorm(bf_context_t *s, limb_t *tabq, limb_t *taba, limb_t na,
- const limb_t *tabb, limb_t nb)
- {
- limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r;
- slimb_t i, j;
- b1 = tabb[nb - 1];
- if (nb == 1) {
- taba[0] = mp_div1norm(tabq, taba, na, b1, 0);
- return 0;
- }
- n = na - nb;
- if (bf_min(n, nb) >= DIVNORM_LARGE_THRESHOLD) {
- return mp_divnorm_large(s, tabq, taba, na, tabb, nb);
- }
- if (n >= UDIV1NORM_THRESHOLD)
- b1_inv = 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) {
- 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 = udiv1norm(&dummy_r, taba[i + nb], taba[i + nb - 1], b1, b1_inv);
- } else {
- dlimb_t al;
- al = ((dlimb_t)taba[i + nb] << LIMB_BITS) | taba[i + nb - 1];
- q = al / b1;
- r = al % b1;
- }
- r = 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 = 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;
- }
- return 0;
- }
- /* compute r=B^(2*n)/a such as a*r < B^(2*n) < a*r + 2 with n >= 1. 'a'
- has n limbs with a[n-1] >= B/2 and 'r' has n+1 limbs with r[n] = 1.
- See Modern Computer Arithmetic by Richard P. Brent and Paul
- Zimmermann, algorithm 3.5 */
- int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n)
- {
- mp_size_t l, h, k, i;
- limb_t *tabxh, *tabt, c, *tabu;
- if (n <= 2) {
- /* return ceil(B^(2*n)/a) - 1 */
- /* XXX: could avoid allocation */
- tabu = bf_malloc(s, sizeof(limb_t) * (2 * n + 1));
- tabt = bf_malloc(s, sizeof(limb_t) * (n + 2));
- if (!tabt || !tabu)
- goto fail;
- for(i = 0; i < 2 * n; i++)
- tabu[i] = 0;
- tabu[2 * n] = 1;
- if (mp_divnorm(s, tabt, tabu, 2 * n + 1, taba, n))
- goto fail;
- for(i = 0; i < n + 1; i++)
- tabr[i] = tabt[i];
- if (mp_scan_nz(tabu, n) == 0) {
- /* only happens for a=B^n/2 */
- mp_sub_ui(tabr, 1, n + 1);
- }
- } else {
- l = (n - 1) / 2;
- h = n - l;
- /* n=2p -> l=p-1, h = p + 1, k = p + 3
- n=2p+1-> l=p, h = p + 1; k = p + 2
- */
- tabt = bf_malloc(s, sizeof(limb_t) * (n + h + 1));
- tabu = bf_malloc(s, sizeof(limb_t) * (n + 2 * h - l + 2));
- if (!tabt || !tabu)
- goto fail;
- tabxh = tabr + l;
- if (mp_recip(s, tabxh, taba + l, h))
- goto fail;
- if (mp_mul(s, tabt, taba, n, tabxh, h + 1)) /* n + h + 1 limbs */
- goto fail;
- while (tabt[n + h] != 0) {
- mp_sub_ui(tabxh, 1, h + 1);
- c = mp_sub(tabt, tabt, taba, n, 0);
- mp_sub_ui(tabt + n, c, h + 1);
- }
- /* T = B^(n+h) - T */
- mp_neg(tabt, tabt, n + h + 1, 0);
- tabt[n + h]++;
- if (mp_mul(s, tabu, tabt + l, n + h + 1 - l, tabxh, h + 1))
- goto fail;
- /* n + 2*h - l + 2 limbs */
- k = 2 * h - l;
- for(i = 0; i < l; i++)
- tabr[i] = tabu[i + k];
- mp_add(tabr + l, tabr + l, tabu + 2 * h, h, 0);
- }
- bf_free(s, tabt);
- bf_free(s, tabu);
- return 0;
- fail:
- bf_free(s, tabt);
- bf_free(s, tabu);
- return -1;
- }
- /* return -1, 0 or 1 */
- static int mp_cmp(const limb_t *taba, const limb_t *tabb, mp_size_t n)
- {
- mp_size_t i;
- for(i = n - 1; i >= 0; i--) {
- if (taba[i] != tabb[i]) {
- if (taba[i] < tabb[i])
- return -1;
- else
- return 1;
- }
- }
- return 0;
- }
- //#define DEBUG_DIVNORM_LARGE
- //#define DEBUG_DIVNORM_LARGE2
- /* subquadratic divnorm */
- static int mp_divnorm_large(bf_context_t *s,
- limb_t *tabq, limb_t *taba, limb_t na,
- const limb_t *tabb, limb_t nb)
- {
- limb_t *tabb_inv, nq, *tabt, i, n;
- nq = na - nb;
- #ifdef DEBUG_DIVNORM_LARGE
- printf("na=%d nb=%d nq=%d\n", (int)na, (int)nb, (int)nq);
- mp_print_str("a", taba, na);
- mp_print_str("b", tabb, nb);
- #endif
- assert(nq >= 1);
- n = nq;
- if (nq < nb)
- n++;
- tabb_inv = bf_malloc(s, sizeof(limb_t) * (n + 1));
- tabt = bf_malloc(s, sizeof(limb_t) * 2 * (n + 1));
- if (!tabb_inv || !tabt)
- goto fail;
- if (n >= nb) {
- for(i = 0; i < n - nb; i++)
- tabt[i] = 0;
- for(i = 0; i < nb; i++)
- tabt[i + n - nb] = tabb[i];
- } else {
- /* truncate B: need to increment it so that the approximate
- inverse is smaller that the exact inverse */
- for(i = 0; i < n; i++)
- tabt[i] = tabb[i + nb - n];
- if (mp_add_ui(tabt, 1, n)) {
- /* tabt = B^n : tabb_inv = B^n */
- memset(tabb_inv, 0, n * sizeof(limb_t));
- tabb_inv[n] = 1;
- goto recip_done;
- }
- }
- if (mp_recip(s, tabb_inv, tabt, n))
- goto fail;
- recip_done:
- /* Q=A*B^-1 */
- if (mp_mul(s, tabt, tabb_inv, n + 1, taba + na - (n + 1), n + 1))
- goto fail;
- for(i = 0; i < nq + 1; i++)
- tabq[i] = tabt[i + 2 * (n + 1) - (nq + 1)];
- #ifdef DEBUG_DIVNORM_LARGE
- mp_print_str("q", tabq, nq + 1);
- #endif
- bf_free(s, tabt);
- bf_free(s, tabb_inv);
- tabb_inv = NULL;
- /* R=A-B*Q */
- tabt = bf_malloc(s, sizeof(limb_t) * (na + 1));
- if (!tabt)
- goto fail;
- if (mp_mul(s, tabt, tabq, nq + 1, tabb, nb))
- goto fail;
- /* we add one more limb for the result */
- mp_sub(taba, taba, tabt, nb + 1, 0);
- bf_free(s, tabt);
- /* the approximated quotient is smaller than than the exact one,
- hence we may have to increment it */
- #ifdef DEBUG_DIVNORM_LARGE2
- int cnt = 0;
- static int cnt_max;
- #endif
- for(;;) {
- if (taba[nb] == 0 && mp_cmp(taba, tabb, nb) < 0)
- break;
- taba[nb] -= mp_sub(taba, taba, tabb, nb, 0);
- mp_add_ui(tabq, 1, nq + 1);
- #ifdef DEBUG_DIVNORM_LARGE2
- cnt++;
- #endif
- }
- #ifdef DEBUG_DIVNORM_LARGE2
- if (cnt > cnt_max) {
- cnt_max = cnt;
- printf("\ncnt=%d nq=%d nb=%d\n", cnt_max, (int)nq, (int)nb);
- }
- #endif
- return 0;
- fail:
- bf_free(s, tabb_inv);
- bf_free(s, tabt);
- return -1;
- }
- int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags)
- {
- int ret, r_sign;
- if (a->len < b->len) {
- const bf_t *tmp = a;
- a = b;
- b = tmp;
- }
- r_sign = a->sign ^ b->sign;
- /* here b->len <= a->len */
- if (b->len == 0) {
- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- ret = 0;
- } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_INF) {
- if ((a->expn == BF_EXP_INF && b->expn == BF_EXP_ZERO) ||
- (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_INF)) {
- bf_set_nan(r);
- ret = BF_ST_INVALID_OP;
- } else {
- bf_set_inf(r, r_sign);
- ret = 0;
- }
- } else {
- bf_set_zero(r, r_sign);
- ret = 0;
- }
- } else {
- bf_t tmp, *r1 = NULL;
- limb_t a_len, b_len, precl;
- limb_t *a_tab, *b_tab;
- a_len = a->len;
- b_len = b->len;
- if ((flags & BF_RND_MASK) == BF_RNDF) {
- /* faithful rounding does not require using the full inputs */
- precl = (prec + 2 + LIMB_BITS - 1) / LIMB_BITS;
- a_len = bf_min(a_len, precl);
- b_len = bf_min(b_len, precl);
- }
- a_tab = a->tab + a->len - a_len;
- b_tab = b->tab + b->len - b_len;
- #ifdef USE_FFT_MUL
- if (b_len >= FFT_MUL_THRESHOLD) {
- int mul_flags = 0;
- if (r == a)
- mul_flags |= FFT_MUL_R_OVERLAP_A;
- if (r == b)
- mul_flags |= FFT_MUL_R_OVERLAP_B;
- if (fft_mul(r->ctx, r, a_tab, a_len, b_tab, b_len, mul_flags))
- goto fail;
- } else
- #endif
- {
- if (r == a || r == b) {
- bf_init(r->ctx, &tmp);
- r1 = r;
- r = &tmp;
- }
- if (bf_resize(r, a_len + b_len)) {
- fail:
- bf_set_nan(r);
- ret = BF_ST_MEM_ERROR;
- goto done;
- }
- mp_mul_basecase(r->tab, a_tab, a_len, b_tab, b_len);
- }
- r->sign = r_sign;
- r->expn = a->expn + b->expn;
- ret = bf_normalize_and_round(r, prec, flags);
- done:
- if (r == &tmp)
- bf_move(r1, &tmp);
- }
- return ret;
- }
- /* multiply 'r' by 2^e */
- int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags)
- {
- slimb_t e_max;
- if (r->len == 0)
- return 0;
- e_max = ((limb_t)1 << BF_EXT_EXP_BITS_MAX) - 1;
- e = bf_max(e, -e_max);
- e = bf_min(e, e_max);
- r->expn += e;
- return __bf_round(r, prec, flags, r->len, 0);
- }
- /* Return e such as a=m*2^e with m odd integer. return 0 if a is zero,
- Infinite or Nan. */
- slimb_t bf_get_exp_min(const bf_t *a)
- {
- slimb_t i;
- limb_t v;
- int k;
- for(i = 0; i < a->len; i++) {
- v = a->tab[i];
- if (v != 0) {
- k = ctz(v);
- return a->expn - (a->len - i) * LIMB_BITS + k;
- }
- }
- return 0;
- }
- /* a and b must be finite numbers with a >= 0 and b > 0. 'q' is the
- integer defined as floor(a/b) and r = a - q * b. */
- static void bf_tdivremu(bf_t *q, bf_t *r,
- const bf_t *a, const bf_t *b)
- {
- if (bf_cmpu(a, b) < 0) {
- bf_set_ui(q, 0);
- bf_set(r, a);
- } else {
- bf_div(q, a, b, bf_max(a->expn - b->expn + 1, 2), BF_RNDZ);
- bf_rint(q, BF_RNDZ);
- bf_mul(r, q, b, BF_PREC_INF, BF_RNDZ);
- bf_sub(r, a, r, BF_PREC_INF, BF_RNDZ);
- }
- }
- static int __bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags)
- {
- bf_context_t *s = r->ctx;
- int ret, r_sign;
- limb_t n, nb, precl;
- r_sign = a->sign ^ b->sign;
- if (a->expn >= BF_EXP_INF || b->expn >= BF_EXP_INF) {
- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- return 0;
- } else if (a->expn == BF_EXP_INF && b->expn == BF_EXP_INF) {
- bf_set_nan(r);
- return BF_ST_INVALID_OP;
- } else if (a->expn == BF_EXP_INF) {
- bf_set_inf(r, r_sign);
- return 0;
- } else {
- bf_set_zero(r, r_sign);
- return 0;
- }
- } else if (a->expn == BF_EXP_ZERO) {
- if (b->expn == BF_EXP_ZERO) {
- bf_set_nan(r);
- return BF_ST_INVALID_OP;
- } else {
- bf_set_zero(r, r_sign);
- return 0;
- }
- } else if (b->expn == BF_EXP_ZERO) {
- bf_set_inf(r, r_sign);
- return BF_ST_DIVIDE_ZERO;
- }
- /* number of limbs of the quotient (2 extra bits for rounding) */
- precl = (prec + 2 + LIMB_BITS - 1) / LIMB_BITS;
- nb = b->len;
- n = bf_max(a->len, precl);
- {
- limb_t *taba, na;
- slimb_t d;
- na = n + nb;
- #if LIMB_LOG2_BITS == 6
- if (na >= (SIZE_MAX / sizeof(limb_t)) - 1) {
- return BF_ST_MEM_ERROR; /* Return memory error status */
- }
- #endif
- taba = bf_malloc(s, (na + 1) * sizeof(limb_t));
- if (!taba)
- goto fail;
- d = na - a->len;
- memset(taba, 0, d * sizeof(limb_t));
- memcpy(taba + d, a->tab, a->len * sizeof(limb_t));
- if (bf_resize(r, n + 1))
- goto fail1;
- if (mp_divnorm(s, r->tab, taba, na, b->tab, nb)) {
- fail1:
- bf_free(s, taba);
- goto fail;
- }
- /* see if non zero remainder */
- if (mp_scan_nz(taba, nb))
- r->tab[0] |= 1;
- bf_free(r->ctx, taba);
- r->expn = a->expn - b->expn + LIMB_BITS;
- r->sign = r_sign;
- ret = bf_normalize_and_round(r, prec, flags);
- }
- return ret;
- fail:
- bf_set_nan(r);
- return BF_ST_MEM_ERROR;
- }
- /* division and remainder.
- rnd_mode is the rounding mode for the quotient. The additional
- rounding mode BF_RND_EUCLIDIAN is supported.
- 'q' is an integer. 'r' is rounded with prec and flags (prec can be
- BF_PREC_INF).
- */
- int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,
- limb_t prec, bf_flags_t flags, int rnd_mode)
- {
- bf_t a1_s, *a1 = &a1_s;
- bf_t b1_s, *b1 = &b1_s;
- int q_sign, ret;
- bool is_ceil, is_rndn;
- assert(q != a && q != b);
- assert(r != a && r != b);
- assert(q != r);
- if (a->len == 0 || b->len == 0) {
- bf_set_zero(q, 0);
- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- return 0;
- } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_ZERO) {
- bf_set_nan(r);
- return BF_ST_INVALID_OP;
- } else {
- bf_set(r, a);
- return bf_round(r, prec, flags);
- }
- }
- q_sign = a->sign ^ b->sign;
- is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
- switch(rnd_mode) {
- default:
- case BF_RNDZ:
- case BF_RNDN:
- case BF_RNDNA:
- is_ceil = false;
- break;
- case BF_RNDD:
- is_ceil = q_sign;
- break;
- case BF_RNDU:
- is_ceil = q_sign ^ 1;
- break;
- case BF_RNDA:
- is_ceil = true;
- break;
- case BF_DIVREM_EUCLIDIAN:
- is_ceil = a->sign;
- break;
- }
- a1->expn = a->expn;
- a1->tab = a->tab;
- a1->len = a->len;
- a1->sign = 0;
- b1->expn = b->expn;
- b1->tab = b->tab;
- b1->len = b->len;
- b1->sign = 0;
- /* XXX: could improve to avoid having a large 'q' */
- bf_tdivremu(q, r, a1, b1);
- if (bf_is_nan(q) || bf_is_nan(r))
- goto fail;
- if (r->len != 0) {
- if (is_rndn) {
- int res;
- b1->expn--;
- res = bf_cmpu(r, b1);
- b1->expn++;
- if (res > 0 ||
- (res == 0 &&
- (rnd_mode == BF_RNDNA ||
- get_bit(q->tab, q->len, q->len * LIMB_BITS - q->expn)))) {
- goto do_sub_r;
- }
- } else if (is_ceil) {
- do_sub_r:
- ret = bf_add_si(q, q, 1, BF_PREC_INF, BF_RNDZ);
- ret |= bf_sub(r, r, b1, BF_PREC_INF, BF_RNDZ);
- if (ret & BF_ST_MEM_ERROR)
- goto fail;
- }
- }
- r->sign ^= a->sign;
- q->sign = q_sign;
- return bf_round(r, prec, flags);
- fail:
- bf_set_nan(q);
- bf_set_nan(r);
- return BF_ST_MEM_ERROR;
- }
- int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags, int rnd_mode)
- {
- bf_t q_s, *q = &q_s;
- int ret;
- bf_init(r->ctx, q);
- ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode);
- bf_delete(q);
- return ret;
- }
- static inline int bf_get_limb(slimb_t *pres, const bf_t *a, int flags)
- {
- #if LIMB_BITS == 32
- return bf_get_int32(pres, a, flags);
- #else
- return bf_get_int64(pres, a, flags);
- #endif
- }
- int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags, int rnd_mode)
- {
- bf_t q_s, *q = &q_s;
- int ret;
- bf_init(r->ctx, q);
- ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode);
- bf_get_limb(pq, q, BF_GET_INT_MOD);
- bf_delete(q);
- return ret;
- }
- static __maybe_unused inline limb_t mul_mod(limb_t a, limb_t b, limb_t m)
- {
- dlimb_t t;
- t = (dlimb_t)a * (dlimb_t)b;
- return t % m;
- }
- #if defined(USE_MUL_CHECK)
- static limb_t mp_mod1(const limb_t *tab, limb_t n, limb_t m, limb_t r)
- {
- slimb_t i;
- dlimb_t t;
- for(i = n - 1; i >= 0; i--) {
- t = ((dlimb_t)r << LIMB_BITS) | tab[i];
- r = t % m;
- }
- return r;
- }
- #endif
- static const uint16_t sqrt_table[192] = {
- 128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156,157,158,159,160,160,161,162,163,163,164,165,166,167,167,168,169,170,170,171,172,173,173,174,175,176,176,177,178,178,179,180,181,181,182,183,183,184,185,185,186,187,187,188,189,189,190,191,192,192,193,193,194,195,195,196,197,197,198,199,199,200,201,201,202,203,203,204,204,205,206,206,207,208,208,209,209,210,211,211,212,212,213,214,214,215,215,216,217,217,218,218,219,219,220,221,221,222,222,223,224,224,225,225,226,226,227,227,228,229,229,230,230,231,231,232,232,233,234,234,235,235,236,236,237,237,238,238,239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255,
- };
- /* a >= 2^(LIMB_BITS - 2). Return (s, r) with s=floor(sqrt(a)) and
- r=a-s^2. 0 <= r <= 2 * s */
- static limb_t mp_sqrtrem1(limb_t *pr, limb_t a)
- {
- limb_t s1, r1, s, r, q, u, num;
- /* use a table for the 16 -> 8 bit sqrt */
- s1 = sqrt_table[(a >> (LIMB_BITS - 8)) - 64];
- r1 = (a >> (LIMB_BITS - 16)) - s1 * s1;
- if (r1 > 2 * s1) {
- r1 -= 2 * s1 + 1;
- s1++;
- }
- /* one iteration to get a 32 -> 16 bit sqrt */
- num = (r1 << 8) | ((a >> (LIMB_BITS - 32 + 8)) & 0xff);
- q = num / (2 * s1); /* q <= 2^8 */
- u = num % (2 * s1);
- s = (s1 << 8) + q;
- r = (u << 8) | ((a >> (LIMB_BITS - 32)) & 0xff);
- r -= q * q;
- if ((slimb_t)r < 0) {
- s--;
- r += 2 * s + 1;
- }
- #if LIMB_BITS == 64
- s1 = s;
- r1 = r;
- /* one more iteration for 64 -> 32 bit sqrt */
- num = (r1 << 16) | ((a >> (LIMB_BITS - 64 + 16)) & 0xffff);
- q = num / (2 * s1); /* q <= 2^16 */
- u = num % (2 * s1);
- s = (s1 << 16) + q;
- r = (u << 16) | ((a >> (LIMB_BITS - 64)) & 0xffff);
- r -= q * q;
- if ((slimb_t)r < 0) {
- s--;
- r += 2 * s + 1;
- }
- #endif
- *pr = r;
- return s;
- }
- /* return floor(sqrt(a)) */
- limb_t bf_isqrt(limb_t a)
- {
- limb_t s, r;
- int k;
- if (a == 0)
- return 0;
- k = clz(a) & ~1;
- s = mp_sqrtrem1(&r, a << k);
- s >>= (k >> 1);
- return s;
- }
- static limb_t mp_sqrtrem2(limb_t *tabs, limb_t *taba)
- {
- limb_t s1, r1, s, q, u, a0, a1;
- dlimb_t r, num;
- int l;
- a0 = taba[0];
- a1 = taba[1];
- s1 = mp_sqrtrem1(&r1, a1);
- l = LIMB_BITS / 2;
- num = ((dlimb_t)r1 << l) | (a0 >> l);
- q = num / (2 * s1);
- u = num % (2 * s1);
- s = (s1 << l) + q;
- r = ((dlimb_t)u << l) | (a0 & (((limb_t)1 << l) - 1));
- if (unlikely((q >> l) != 0))
- r -= (dlimb_t)1 << LIMB_BITS; /* special case when q=2^l */
- else
- r -= q * q;
- if ((slimb_t)(r >> LIMB_BITS) < 0) {
- s--;
- r += 2 * (dlimb_t)s + 1;
- }
- tabs[0] = s;
- taba[0] = r;
- return r >> LIMB_BITS;
- }
- //#define DEBUG_SQRTREM
- /* tmp_buf must contain (n / 2 + 1 limbs). *prh contains the highest
- limb of the remainder. */
- static int mp_sqrtrem_rec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n,
- limb_t *tmp_buf, limb_t *prh)
- {
- limb_t l, h, rh, ql, qh, c, i;
- if (n == 1) {
- *prh = mp_sqrtrem2(tabs, taba);
- return 0;
- }
- #ifdef DEBUG_SQRTREM
- mp_print_str("a", taba, 2 * n);
- #endif
- l = n / 2;
- h = n - l;
- if (mp_sqrtrem_rec(s, tabs + l, taba + 2 * l, h, tmp_buf, &qh))
- return -1;
- #ifdef DEBUG_SQRTREM
- mp_print_str("s1", tabs + l, h);
- mp_print_str_h("r1", taba + 2 * l, h, qh);
- mp_print_str_h("r2", taba + l, n, qh);
- #endif
- /* the remainder is in taba + 2 * l. Its high bit is in qh */
- if (qh) {
- mp_sub(taba + 2 * l, taba + 2 * l, tabs + l, h, 0);
- }
- /* instead of dividing by 2*s, divide by s (which is normalized)
- and update q and r */
- if (mp_divnorm(s, tmp_buf, taba + l, n, tabs + l, h))
- return -1;
- qh += tmp_buf[l];
- for(i = 0; i < l; i++)
- tabs[i] = tmp_buf[i];
- ql = mp_shr(tabs, tabs, l, 1, qh & 1);
- qh = qh >> 1; /* 0 or 1 */
- if (ql)
- rh = mp_add(taba + l, taba + l, tabs + l, h, 0);
- else
- rh = 0;
- #ifdef DEBUG_SQRTREM
- mp_print_str_h("q", tabs, l, qh);
- mp_print_str_h("u", taba + l, h, rh);
- #endif
- mp_add_ui(tabs + l, qh, h);
- #ifdef DEBUG_SQRTREM
- mp_print_str_h("s2", tabs, n, sh);
- #endif
- /* q = qh, tabs[l - 1 ... 0], r = taba[n - 1 ... l] */
- /* subtract q^2. if qh = 1 then q = B^l, so we can take shortcuts */
- if (qh) {
- c = qh;
- } else {
- if (mp_mul(s, taba + n, tabs, l, tabs, l))
- return -1;
- c = mp_sub(taba, taba, taba + n, 2 * l, 0);
- }
- rh -= mp_sub_ui(taba + 2 * l, c, n - 2 * l);
- if ((slimb_t)rh < 0) {
- mp_sub_ui(tabs, 1, n);
- rh += mp_add_mul1(taba, tabs, n, 2);
- rh += mp_add_ui(taba, 1, n);
- }
- *prh = rh;
- return 0;
- }
- /* 'taba' has 2*n limbs with n >= 1 and taba[2*n-1] >= 2 ^ (LIMB_BITS
- - 2). Return (s, r) with s=floor(sqrt(a)) and r=a-s^2. 0 <= r <= 2
- * s. tabs has n limbs. r is returned in the lower n limbs of
- taba. Its r[n] is the returned value of the function. */
- /* Algorithm from the article "Karatsuba Square Root" by Paul Zimmermann and
- inspirated from its GMP implementation */
- int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n)
- {
- limb_t tmp_buf1[8];
- limb_t *tmp_buf;
- mp_size_t n2;
- int ret;
- n2 = n / 2 + 1;
- if (n2 <= countof(tmp_buf1)) {
- tmp_buf = tmp_buf1;
- } else {
- tmp_buf = bf_malloc(s, sizeof(limb_t) * n2);
- if (!tmp_buf)
- return -1;
- }
- ret = mp_sqrtrem_rec(s, tabs, taba, n, tmp_buf, taba + n);
- if (tmp_buf != tmp_buf1)
- bf_free(s, tmp_buf);
- return ret;
- }
- /* Integer square root with remainder. 'a' must be an integer. r =
- floor(sqrt(a)) and rem = a - r^2. BF_ST_INEXACT is set if the result
- is inexact. 'rem' can be NULL if the remainder is not needed. */
- int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a)
- {
- int ret;
- if (a->len == 0) {
- if (a->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- } else if (a->expn == BF_EXP_INF && a->sign) {
- goto invalid_op;
- } else {
- bf_set(r, a);
- }
- if (rem1)
- bf_set_ui(rem1, 0);
- ret = 0;
- } else if (a->sign) {
- invalid_op:
- bf_set_nan(r);
- if (rem1)
- bf_set_ui(rem1, 0);
- ret = BF_ST_INVALID_OP;
- } else {
- bf_t rem_s, *rem;
- bf_sqrt(r, a, (a->expn + 1) / 2, BF_RNDZ);
- bf_rint(r, BF_RNDZ);
- /* see if the result is exact by computing the remainder */
- if (rem1) {
- rem = rem1;
- } else {
- rem = &rem_s;
- bf_init(r->ctx, rem);
- }
- /* XXX: could avoid recomputing the remainder */
- bf_mul(rem, r, r, BF_PREC_INF, BF_RNDZ);
- bf_neg(rem);
- bf_add(rem, rem, a, BF_PREC_INF, BF_RNDZ);
- if (bf_is_nan(rem)) {
- ret = BF_ST_MEM_ERROR;
- goto done;
- }
- if (rem->len != 0) {
- ret = BF_ST_INEXACT;
- } else {
- ret = 0;
- }
- done:
- if (!rem1)
- bf_delete(rem);
- }
- return ret;
- }
- int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
- {
- bf_context_t *s = a->ctx;
- int ret;
- assert(r != a);
- if (a->len == 0) {
- if (a->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- } else if (a->expn == BF_EXP_INF && a->sign) {
- goto invalid_op;
- } else {
- bf_set(r, a);
- }
- ret = 0;
- } else if (a->sign) {
- invalid_op:
- bf_set_nan(r);
- ret = BF_ST_INVALID_OP;
- } else {
- limb_t *a1;
- slimb_t n, n1;
- limb_t res;
- /* convert the mantissa to an integer with at least 2 *
- prec + 4 bits */
- n = (2 * (prec + 2) + 2 * LIMB_BITS - 1) / (2 * LIMB_BITS);
- if (bf_resize(r, n))
- goto fail;
- a1 = bf_malloc(s, sizeof(limb_t) * 2 * n);
- if (!a1)
- goto fail;
- n1 = bf_min(2 * n, a->len);
- memset(a1, 0, (2 * n - n1) * sizeof(limb_t));
- memcpy(a1 + 2 * n - n1, a->tab + a->len - n1, n1 * sizeof(limb_t));
- if (a->expn & 1) {
- res = mp_shr(a1, a1, 2 * n, 1, 0);
- } else {
- res = 0;
- }
- if (mp_sqrtrem(s, r->tab, a1, n)) {
- bf_free(s, a1);
- goto fail;
- }
- if (!res) {
- res = mp_scan_nz(a1, n + 1);
- }
- bf_free(s, a1);
- if (!res) {
- res = mp_scan_nz(a->tab, a->len - n1);
- }
- if (res != 0)
- r->tab[0] |= 1;
- r->sign = 0;
- r->expn = (a->expn + 1) >> 1;
- ret = bf_round(r, prec, flags);
- }
- return ret;
- fail:
- bf_set_nan(r);
- return BF_ST_MEM_ERROR;
- }
- static no_inline int bf_op2(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags, bf_op2_func_t *func)
- {
- bf_t tmp;
- int ret;
- if (r == a || r == b) {
- bf_init(r->ctx, &tmp);
- ret = func(&tmp, a, b, prec, flags);
- bf_move(r, &tmp);
- } else {
- ret = func(r, a, b, prec, flags);
- }
- return ret;
- }
- int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags)
- {
- return bf_op2(r, a, b, prec, flags, __bf_add);
- }
- int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags)
- {
- return bf_op2(r, a, b, prec, flags, __bf_sub);
- }
- int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
- bf_flags_t flags)
- {
- return bf_op2(r, a, b, prec, flags, __bf_div);
- }
- int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec,
- bf_flags_t flags)
- {
- bf_t b;
- int ret;
- bf_init(r->ctx, &b);
- ret = bf_set_ui(&b, b1);
- ret |= bf_mul(r, a, &b, prec, flags);
- bf_delete(&b);
- return ret;
- }
- int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,
- bf_flags_t flags)
- {
- bf_t b;
- int ret;
- bf_init(r->ctx, &b);
- ret = bf_set_si(&b, b1);
- ret |= bf_mul(r, a, &b, prec, flags);
- bf_delete(&b);
- return ret;
- }
- int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,
- bf_flags_t flags)
- {
- bf_t b;
- int ret;
- bf_init(r->ctx, &b);
- ret = bf_set_si(&b, b1);
- ret |= bf_add(r, a, &b, prec, flags);
- bf_delete(&b);
- return ret;
- }
- static int bf_pow_ui(bf_t *r, const bf_t *a, limb_t b, limb_t prec,
- bf_flags_t flags)
- {
- int ret, n_bits, i;
- assert(r != a);
- if (b == 0)
- return bf_set_ui(r, 1);
- ret = bf_set(r, a);
- n_bits = LIMB_BITS - clz(b);
- for(i = n_bits - 2; i >= 0; i--) {
- ret |= bf_mul(r, r, r, prec, flags);
- if ((b >> i) & 1)
- ret |= bf_mul(r, r, a, prec, flags);
- }
- return ret;
- }
- static int bf_pow_ui_ui(bf_t *r, limb_t a1, limb_t b,
- limb_t prec, bf_flags_t flags)
- {
- bf_t a;
- int ret;
- if (a1 == 10 && b <= LIMB_DIGITS) {
- /* use precomputed powers. We do not round at this point
- because we expect the caller to do it */
- ret = bf_set_ui(r, mp_pow_dec[b]);
- } else {
- bf_init(r->ctx, &a);
- ret = bf_set_ui(&a, a1);
- ret |= bf_pow_ui(r, &a, b, prec, flags);
- bf_delete(&a);
- }
- return ret;
- }
- /* convert to integer (infinite precision) */
- int bf_rint(bf_t *r, int rnd_mode)
- {
- return bf_round(r, 0, rnd_mode | BF_FLAG_RADPNT_PREC);
- }
- /* logical operations */
- #define BF_LOGIC_OR 0
- #define BF_LOGIC_XOR 1
- #define BF_LOGIC_AND 2
- static inline limb_t bf_logic_op1(limb_t a, limb_t b, int op)
- {
- switch(op) {
- case BF_LOGIC_OR:
- return a | b;
- case BF_LOGIC_XOR:
- return a ^ b;
- default:
- case BF_LOGIC_AND:
- return a & b;
- }
- }
- static int bf_logic_op(bf_t *r, const bf_t *a1, const bf_t *b1, int op)
- {
- bf_t b1_s, a1_s, *a, *b;
- limb_t a_sign, b_sign, r_sign;
- slimb_t l, i, a_bit_offset, b_bit_offset;
- limb_t v1, v2, v1_mask, v2_mask, r_mask;
- int ret;
- assert(r != a1 && r != b1);
- if (a1->expn <= 0)
- a_sign = 0; /* minus zero is considered as positive */
- else
- a_sign = a1->sign;
- if (b1->expn <= 0)
- b_sign = 0; /* minus zero is considered as positive */
- else
- b_sign = b1->sign;
- if (a_sign) {
- a = &a1_s;
- bf_init(r->ctx, a);
- if (bf_add_si(a, a1, 1, BF_PREC_INF, BF_RNDZ)) {
- b = NULL;
- goto fail;
- }
- } else {
- a = (bf_t *)a1;
- }
- if (b_sign) {
- b = &b1_s;
- bf_init(r->ctx, b);
- if (bf_add_si(b, b1, 1, BF_PREC_INF, BF_RNDZ))
- goto fail;
- } else {
- b = (bf_t *)b1;
- }
- r_sign = bf_logic_op1(a_sign, b_sign, op);
- if (op == BF_LOGIC_AND && r_sign == 0) {
- /* no need to compute extra zeros for and */
- if (a_sign == 0 && b_sign == 0)
- l = bf_min(a->expn, b->expn);
- else if (a_sign == 0)
- l = a->expn;
- else
- l = b->expn;
- } else {
- l = bf_max(a->expn, b->expn);
- }
- /* Note: a or b can be zero */
- l = (bf_max(l, 1) + LIMB_BITS - 1) / LIMB_BITS;
- if (bf_resize(r, l))
- goto fail;
- a_bit_offset = a->len * LIMB_BITS - a->expn;
- b_bit_offset = b->len * LIMB_BITS - b->expn;
- v1_mask = -a_sign;
- v2_mask = -b_sign;
- r_mask = -r_sign;
- for(i = 0; i < l; i++) {
- v1 = get_bits(a->tab, a->len, a_bit_offset + i * LIMB_BITS) ^ v1_mask;
- v2 = get_bits(b->tab, b->len, b_bit_offset + i * LIMB_BITS) ^ v2_mask;
- r->tab[i] = bf_logic_op1(v1, v2, op) ^ r_mask;
- }
- r->expn = l * LIMB_BITS;
- r->sign = r_sign;
- bf_normalize_and_round(r, BF_PREC_INF, BF_RNDZ); /* cannot fail */
- if (r_sign) {
- if (bf_add_si(r, r, -1, BF_PREC_INF, BF_RNDZ))
- goto fail;
- }
- ret = 0;
- done:
- if (a == &a1_s)
- bf_delete(a);
- if (b == &b1_s)
- bf_delete(b);
- return ret;
- fail:
- bf_set_nan(r);
- ret = BF_ST_MEM_ERROR;
- goto done;
- }
- /* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */
- int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b)
- {
- return bf_logic_op(r, a, b, BF_LOGIC_OR);
- }
- /* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */
- int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b)
- {
- return bf_logic_op(r, a, b, BF_LOGIC_XOR);
- }
- /* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */
- int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b)
- {
- return bf_logic_op(r, a, b, BF_LOGIC_AND);
- }
- /* conversion between fixed size types */
- typedef union {
- double d;
- uint64_t u;
- } Float64Union;
- int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode)
- {
- Float64Union u;
- int e, ret;
- uint64_t m;
- ret = 0;
- if (a->expn == BF_EXP_NAN) {
- u.u = 0x7ff8000000000000; /* quiet nan */
- } else {
- bf_t b_s, *b = &b_s;
- bf_init(a->ctx, b);
- bf_set(b, a);
- if (bf_is_finite(b)) {
- ret = bf_round(b, 53, rnd_mode | BF_FLAG_SUBNORMAL | bf_set_exp_bits(11));
- }
- if (b->expn == BF_EXP_INF) {
- e = (1 << 11) - 1;
- m = 0;
- } else if (b->expn == BF_EXP_ZERO) {
- e = 0;
- m = 0;
- } else {
- e = b->expn + 1023 - 1;
- #if LIMB_BITS == 32
- if (b->len == 2) {
- m = ((uint64_t)b->tab[1] << 32) | b->tab[0];
- } else {
- m = ((uint64_t)b->tab[0] << 32);
- }
- #else
- m = b->tab[0];
- #endif
- if (e <= 0) {
- /* subnormal */
- m = m >> (12 - e);
- e = 0;
- } else {
- m = (m << 1) >> 12;
- }
- }
- u.u = m | ((uint64_t)e << 52) | ((uint64_t)b->sign << 63);
- bf_delete(b);
- }
- *pres = u.d;
- return ret;
- }
- int bf_set_float64(bf_t *a, double d)
- {
- Float64Union u;
- uint64_t m;
- int shift, e, sgn;
- u.d = d;
- sgn = u.u >> 63;
- e = (u.u >> 52) & ((1 << 11) - 1);
- m = u.u & (((uint64_t)1 << 52) - 1);
- if (e == ((1 << 11) - 1)) {
- if (m != 0) {
- bf_set_nan(a);
- } else {
- bf_set_inf(a, sgn);
- }
- } else if (e == 0) {
- if (m == 0) {
- bf_set_zero(a, sgn);
- } else {
- /* subnormal number */
- m <<= 12;
- shift = clz64(m);
- m <<= shift;
- e = -shift;
- goto norm;
- }
- } else {
- m = (m << 11) | ((uint64_t)1 << 63);
- norm:
- a->expn = e - 1023 + 1;
- #if LIMB_BITS == 32
- if (bf_resize(a, 2))
- goto fail;
- a->tab[0] = m;
- a->tab[1] = m >> 32;
- #else
- if (bf_resize(a, 1))
- goto fail;
- a->tab[0] = m;
- #endif
- a->sign = sgn;
- }
- return 0;
- fail:
- bf_set_nan(a);
- return BF_ST_MEM_ERROR;
- }
- /* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there
- is an overflow and 0 otherwise. */
- int bf_get_int32(int *pres, const bf_t *a, int flags)
- {
- uint32_t v;
- int ret;
- if (a->expn >= BF_EXP_INF) {
- ret = BF_ST_INVALID_OP;
- if (flags & BF_GET_INT_MOD) {
- v = 0;
- } else if (a->expn == BF_EXP_INF) {
- v = (uint32_t)INT32_MAX + a->sign;
- } else {
- v = INT32_MAX;
- }
- } else if (a->expn <= 0) {
- v = 0;
- ret = 0;
- } else if (a->expn <= 31) {
- v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);
- if (a->sign)
- v = -v;
- ret = 0;
- } else if (!(flags & BF_GET_INT_MOD)) {
- ret = BF_ST_INVALID_OP;
- if (a->sign) {
- v = (uint32_t)INT32_MAX + 1;
- if (a->expn == 32 &&
- (a->tab[a->len - 1] >> (LIMB_BITS - 32)) == v) {
- ret = 0;
- }
- } else {
- v = INT32_MAX;
- }
- } else {
- v = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn);
- if (a->sign)
- v = -v;
- ret = 0;
- }
- *pres = v;
- return ret;
- }
- /* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there
- is an overflow and 0 otherwise. */
- int bf_get_int64(int64_t *pres, const bf_t *a, int flags)
- {
- uint64_t v;
- int ret;
- if (a->expn >= BF_EXP_INF) {
- ret = BF_ST_INVALID_OP;
- if (flags & BF_GET_INT_MOD) {
- v = 0;
- } else if (a->expn == BF_EXP_INF) {
- v = (uint64_t)INT64_MAX + a->sign;
- } else {
- v = INT64_MAX;
- }
- } else if (a->expn <= 0) {
- v = 0;
- ret = 0;
- } else if (a->expn <= 63) {
- #if LIMB_BITS == 32
- if (a->expn <= 32)
- v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);
- else
- v = (((uint64_t)a->tab[a->len - 1] << 32) |
- get_limbz(a, a->len - 2)) >> (64 - a->expn);
- #else
- v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);
- #endif
- if (a->sign)
- v = -v;
- ret = 0;
- } else if (!(flags & BF_GET_INT_MOD)) {
- ret = BF_ST_INVALID_OP;
- if (a->sign) {
- uint64_t v1;
- v = (uint64_t)INT64_MAX + 1;
- if (a->expn == 64) {
- v1 = a->tab[a->len - 1];
- #if LIMB_BITS == 32
- v1 = (v1 << 32) | get_limbz(a, a->len - 2);
- #endif
- if (v1 == v)
- ret = 0;
- }
- } else {
- v = INT64_MAX;
- }
- } else {
- slimb_t bit_pos = a->len * LIMB_BITS - a->expn;
- v = get_bits(a->tab, a->len, bit_pos);
- #if LIMB_BITS == 32
- v |= (uint64_t)get_bits(a->tab, a->len, bit_pos + 32) << 32;
- #endif
- if (a->sign)
- v = -v;
- ret = 0;
- }
- *pres = v;
- return ret;
- }
- /* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there
- is an overflow and 0 otherwise. */
- int bf_get_uint64(uint64_t *pres, const bf_t *a)
- {
- uint64_t v;
- int ret;
- if (a->expn == BF_EXP_NAN) {
- goto overflow;
- } else if (a->expn <= 0) {
- v = 0;
- ret = 0;
- } else if (a->sign) {
- v = 0;
- ret = BF_ST_INVALID_OP;
- } else if (a->expn <= 64) {
- #if LIMB_BITS == 32
- if (a->expn <= 32)
- v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);
- else
- v = (((uint64_t)a->tab[a->len - 1] << 32) |
- get_limbz(a, a->len - 2)) >> (64 - a->expn);
- #else
- v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);
- #endif
- ret = 0;
- } else {
- overflow:
- v = UINT64_MAX;
- ret = BF_ST_INVALID_OP;
- }
- *pres = v;
- return ret;
- }
- /* base conversion from radix */
- static const uint8_t digits_per_limb_table[BF_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 limb_t get_limb_radix(int radix)
- {
- int i, k;
- limb_t radixl;
- k = digits_per_limb_table[radix - 2];
- radixl = radix;
- for(i = 1; i < k; i++)
- radixl *= radix;
- return radixl;
- }
- /* return != 0 if error */
- static int bf_integer_from_radix_rec(bf_t *r, const limb_t *tab,
- limb_t n, int level, limb_t n0,
- limb_t radix, bf_t *pow_tab)
- {
- int ret;
- if (n == 1) {
- ret = bf_set_ui(r, tab[0]);
- } else {
- bf_t T_s, *T = &T_s, *B;
- limb_t n1, n2;
- n2 = (((n0 * 2) >> (level + 1)) + 1) / 2;
- n1 = n - n2;
- // printf("level=%d n0=%ld n1=%ld n2=%ld\n", level, n0, n1, n2);
- B = &pow_tab[level];
- if (B->len == 0) {
- ret = bf_pow_ui_ui(B, radix, n2, BF_PREC_INF, BF_RNDZ);
- if (ret)
- return ret;
- }
- ret = bf_integer_from_radix_rec(r, tab + n2, n1, level + 1, n0,
- radix, pow_tab);
- if (ret)
- return ret;
- ret = bf_mul(r, r, B, BF_PREC_INF, BF_RNDZ);
- if (ret)
- return ret;
- bf_init(r->ctx, T);
- ret = bf_integer_from_radix_rec(T, tab, n2, level + 1, n0,
- radix, pow_tab);
- if (!ret)
- ret = bf_add(r, r, T, BF_PREC_INF, BF_RNDZ);
- bf_delete(T);
- }
- return ret;
- // bf_print_str(" r=", r);
- }
- /* return 0 if OK != 0 if memory error */
- static int bf_integer_from_radix(bf_t *r, const limb_t *tab,
- limb_t n, limb_t radix)
- {
- bf_context_t *s = r->ctx;
- int pow_tab_len, i, ret;
- limb_t radixl;
- bf_t *pow_tab;
- radixl = get_limb_radix(radix);
- pow_tab_len = ceil_log2(n) + 2; /* XXX: check */
- pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len);
- if (!pow_tab)
- return -1;
- for(i = 0; i < pow_tab_len; i++)
- bf_init(r->ctx, &pow_tab[i]);
- ret = bf_integer_from_radix_rec(r, tab, n, 0, n, radixl, pow_tab);
- for(i = 0; i < pow_tab_len; i++) {
- bf_delete(&pow_tab[i]);
- }
- bf_free(s, pow_tab);
- return ret;
- }
- /* compute and round T * radix^expn. */
- int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
- slimb_t expn, limb_t prec, bf_flags_t flags)
- {
- int ret, expn_sign, overflow;
- slimb_t e, extra_bits, prec1, ziv_extra_bits;
- bf_t B_s, *B = &B_s;
- if (T->len == 0) {
- return bf_set(r, T);
- } else if (expn == 0) {
- ret = bf_set(r, T);
- ret |= bf_round(r, prec, flags);
- return ret;
- }
- e = expn;
- expn_sign = 0;
- if (e < 0) {
- e = -e;
- expn_sign = 1;
- }
- bf_init(r->ctx, B);
- if (prec == BF_PREC_INF) {
- /* infinite precision: only used if the result is known to be exact */
- ret = bf_pow_ui_ui(B, radix, e, BF_PREC_INF, BF_RNDN);
- if (expn_sign) {
- ret |= bf_div(r, T, B, T->len * LIMB_BITS, BF_RNDN);
- } else {
- ret |= bf_mul(r, T, B, BF_PREC_INF, BF_RNDN);
- }
- } else {
- ziv_extra_bits = 16;
- for(;;) {
- prec1 = prec + ziv_extra_bits;
- /* XXX: correct overflow/underflow handling */
- /* XXX: rigorous error analysis needed */
- extra_bits = ceil_log2(e) * 2 + 1;
- ret = bf_pow_ui_ui(B, radix, e, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);
- overflow = !bf_is_finite(B);
- /* XXX: if bf_pow_ui_ui returns an exact result, can stop
- after the next operation */
- if (expn_sign)
- ret |= bf_div(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);
- else
- ret |= bf_mul(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);
- if (ret & BF_ST_MEM_ERROR)
- break;
- if ((ret & BF_ST_INEXACT) &&
- !bf_can_round(r, prec, flags & BF_RND_MASK, prec1) &&
- !overflow) {
- /* and more precision and retry */
- ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);
- } else {
- /* XXX: need to use __bf_round() to pass the inexact
- flag for the subnormal case */
- ret = bf_round(r, prec, flags) | (ret & BF_ST_INEXACT);
- break;
- }
- }
- }
- bf_delete(B);
- return ret;
- }
- static inline int bf_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;
- }
- /* add a limb at 'pos' and decrement pos. new space is created if
- needed. Return 0 if OK, -1 if memory error */
- static int bf_add_limb(bf_t *a, slimb_t *ppos, limb_t v)
- {
- slimb_t pos;
- pos = *ppos;
- if (unlikely(pos < 0)) {
- limb_t new_size, d, *new_tab;
- new_size = bf_max(a->len + 1, a->len * 3 / 2);
- new_tab = bf_realloc(a->ctx, a->tab, sizeof(limb_t) * new_size);
- if (!new_tab)
- return -1;
- a->tab = new_tab;
- d = new_size - a->len;
- memmove(a->tab + d, a->tab, a->len * sizeof(limb_t));
- a->len = new_size;
- pos += d;
- }
- a->tab[pos--] = v;
- *ppos = pos;
- return 0;
- }
- static int bf_tolower(int c)
- {
- if (c >= 'A' && c <= 'Z')
- c = c - 'A' + 'a';
- return c;
- }
- static int strcasestart(const char *str, const char *val, const char **ptr)
- {
- const char *p, *q;
- p = str;
- q = val;
- while (*q != '\0') {
- if (bf_tolower(*p) != *q)
- return 0;
- p++;
- q++;
- }
- if (ptr)
- *ptr = p;
- return 1;
- }
- static int bf_atof_internal(bf_t *r, slimb_t *pexponent,
- const char *str, const char **pnext, int radix,
- limb_t prec, bf_flags_t flags, bool is_dec)
- {
- const char *p, *p_start;
- int is_neg, radix_bits, exp_is_neg, ret, digits_per_limb, shift;
- limb_t cur_limb;
- slimb_t pos, expn, int_len, digit_count;
- bool has_decpt, is_bin_exp;
- bf_t a_s, *a;
- *pexponent = 0;
- p = str;
- if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 &&
- strcasestart(p, "nan", &p)) {
- bf_set_nan(r);
- ret = 0;
- goto done;
- }
- 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) &&
- !(flags & BF_ATOF_NO_HEX)) {
- radix = 16;
- p += 2;
- } else if ((p[1] == 'o' || p[1] == 'O') &&
- radix == 0 && (flags & BF_ATOF_BIN_OCT)) {
- p += 2;
- radix = 8;
- } else if ((p[1] == 'b' || p[1] == 'B') &&
- radix == 0 && (flags & BF_ATOF_BIN_OCT)) {
- p += 2;
- radix = 2;
- } else {
- goto no_prefix;
- }
- /* there must be a digit after the prefix */
- if (bf_to_digit((uint8_t)*p) >= radix) {
- bf_set_nan(r);
- ret = 0;
- goto done;
- }
- no_prefix: ;
- } else {
- if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 &&
- strcasestart(p, "inf", &p)) {
- bf_set_inf(r, is_neg);
- ret = 0;
- goto done;
- }
- }
- if (radix == 0)
- radix = 10;
- if (is_dec) {
- assert(radix == 10);
- radix_bits = 0;
- a = r;
- } else if ((radix & (radix - 1)) != 0) {
- radix_bits = 0; /* base is not a power of two */
- a = &a_s;
- bf_init(r->ctx, a);
- } else {
- radix_bits = ceil_log2(radix);
- a = r;
- }
- /* skip leading zeros */
- /* XXX: could also skip zeros after the decimal point */
- while (*p == '0')
- p++;
- if (radix_bits) {
- shift = digits_per_limb = LIMB_BITS;
- } else {
- radix_bits = 0;
- shift = digits_per_limb = digits_per_limb_table[radix - 2];
- }
- cur_limb = 0;
- bf_resize(a, 1);
- pos = 0;
- has_decpt = false;
- int_len = digit_count = 0;
- for(;;) {
- limb_t c;
- if (*p == '.' && (p > p_start || bf_to_digit(p[1]) < radix)) {
- if (has_decpt)
- break;
- has_decpt = true;
- int_len = digit_count;
- p++;
- }
- c = bf_to_digit(*p);
- if (c >= radix)
- break;
- digit_count++;
- p++;
- if (radix_bits) {
- shift -= radix_bits;
- if (shift <= 0) {
- cur_limb |= c >> (-shift);
- if (bf_add_limb(a, &pos, cur_limb))
- goto mem_error;
- if (shift < 0)
- cur_limb = c << (LIMB_BITS + shift);
- else
- cur_limb = 0;
- shift += LIMB_BITS;
- } else {
- cur_limb |= c << shift;
- }
- } else {
- cur_limb = cur_limb * radix + c;
- shift--;
- if (shift == 0) {
- if (bf_add_limb(a, &pos, cur_limb))
- goto mem_error;
- shift = digits_per_limb;
- cur_limb = 0;
- }
- }
- }
- if (!has_decpt)
- int_len = digit_count;
- /* add the last limb and pad with zeros */
- if (shift != digits_per_limb) {
- if (radix_bits == 0) {
- while (shift != 0) {
- cur_limb *= radix;
- shift--;
- }
- }
- if (bf_add_limb(a, &pos, cur_limb)) {
- mem_error:
- ret = BF_ST_MEM_ERROR;
- if (!radix_bits)
- bf_delete(a);
- bf_set_nan(r);
- goto done;
- }
- }
- /* reset the next limbs to zero (we prefer to reallocate in the
- renormalization) */
- memset(a->tab, 0, (pos + 1) * sizeof(limb_t));
- if (p == p_start) {
- ret = 0;
- if (!radix_bits)
- bf_delete(a);
- bf_set_nan(r);
- goto done;
- }
- /* parse the exponent, if any */
- expn = 0;
- is_bin_exp = false;
- if (((radix == 10 && (*p == 'e' || *p == 'E')) ||
- (radix != 10 && (*p == '@' ||
- (radix_bits && (*p == 'p' || *p == 'P'))))) &&
- p > p_start) {
- is_bin_exp = (*p == 'p' || *p == 'P');
- p++;
- exp_is_neg = 0;
- if (*p == '+') {
- p++;
- } else if (*p == '-') {
- exp_is_neg = 1;
- p++;
- }
- for(;;) {
- int c;
- c = bf_to_digit(*p);
- if (c >= 10)
- break;
- if (unlikely(expn > ((BF_RAW_EXP_MAX - 2 - 9) / 10))) {
- /* exponent overflow */
- if (exp_is_neg) {
- bf_set_zero(r, is_neg);
- ret = BF_ST_UNDERFLOW | BF_ST_INEXACT;
- } else {
- bf_set_inf(r, is_neg);
- ret = BF_ST_OVERFLOW | BF_ST_INEXACT;
- }
- goto done;
- }
- p++;
- expn = expn * 10 + c;
- }
- if (exp_is_neg)
- expn = -expn;
- }
- if (is_dec) {
- a->expn = expn + int_len;
- a->sign = is_neg;
- ret = bfdec_normalize_and_round((bfdec_t *)a, prec, flags);
- } else if (radix_bits) {
- /* XXX: may overflow */
- if (!is_bin_exp)
- expn *= radix_bits;
- a->expn = expn + (int_len * radix_bits);
- a->sign = is_neg;
- ret = bf_normalize_and_round(a, prec, flags);
- } else {
- limb_t l;
- pos++;
- l = a->len - pos; /* number of limbs */
- if (l == 0) {
- bf_set_zero(r, is_neg);
- ret = 0;
- } else {
- bf_t T_s, *T = &T_s;
- expn -= l * digits_per_limb - int_len;
- bf_init(r->ctx, T);
- if (bf_integer_from_radix(T, a->tab + pos, l, radix)) {
- bf_set_nan(r);
- ret = BF_ST_MEM_ERROR;
- } else {
- T->sign = is_neg;
- if (flags & BF_ATOF_EXPONENT) {
- /* return the exponent */
- *pexponent = expn;
- ret = bf_set(r, T);
- } else {
- ret = bf_mul_pow_radix(r, T, radix, expn, prec, flags);
- }
- }
- bf_delete(T);
- }
- bf_delete(a);
- }
- done:
- if (pnext)
- *pnext = p;
- return ret;
- }
- /*
- Return (status, n, exp). 'status' is the floating point status. 'n'
- is the parsed number.
- If (flags & BF_ATOF_EXPONENT) and if the radix is not a power of
- two, the parsed number is equal to r *
- (*pexponent)^radix. Otherwise *pexponent = 0.
- */
- int bf_atof2(bf_t *r, slimb_t *pexponent,
- const char *str, const char **pnext, int radix,
- limb_t prec, bf_flags_t flags)
- {
- return bf_atof_internal(r, pexponent, str, pnext, radix, prec, flags,
- false);
- }
- int bf_atof(bf_t *r, const char *str, const char **pnext, int radix,
- limb_t prec, bf_flags_t flags)
- {
- slimb_t dummy_exp;
- return bf_atof_internal(r, &dummy_exp, str, pnext, radix, prec, flags, false);
- }
- /* base conversion to radix */
- #if LIMB_BITS == 64
- #define RADIXL_10 UINT64_C(10000000000000000000)
- #else
- #define RADIXL_10 UINT64_C(1000000000)
- #endif
- static const uint32_t inv_log2_radix[BF_RADIX_MAX - 1][LIMB_BITS / 32 + 1] = {
- #if LIMB_BITS == 32
- { 0x80000000, 0x00000000,},
- { 0x50c24e60, 0xd4d4f4a7,},
- { 0x40000000, 0x00000000,},
- { 0x372068d2, 0x0a1ee5ca,},
- { 0x3184648d, 0xb8153e7a,},
- { 0x2d983275, 0x9d5369c4,},
- { 0x2aaaaaaa, 0xaaaaaaab,},
- { 0x28612730, 0x6a6a7a54,},
- { 0x268826a1, 0x3ef3fde6,},
- { 0x25001383, 0xbac8a744,},
- { 0x23b46706, 0x82c0c709,},
- { 0x229729f1, 0xb2c83ded,},
- { 0x219e7ffd, 0xa5ad572b,},
- { 0x20c33b88, 0xda7c29ab,},
- { 0x20000000, 0x00000000,},
- { 0x1f50b57e, 0xac5884b3,},
- { 0x1eb22cc6, 0x8aa6e26f,},
- { 0x1e21e118, 0x0c5daab2,},
- { 0x1d9dcd21, 0x439834e4,},
- { 0x1d244c78, 0x367a0d65,},
- { 0x1cb40589, 0xac173e0c,},
- { 0x1c4bd95b, 0xa8d72b0d,},
- { 0x1bead768, 0x98f8ce4c,},
- { 0x1b903469, 0x050f72e5,},
- { 0x1b3b433f, 0x2eb06f15,},
- { 0x1aeb6f75, 0x9c46fc38,},
- { 0x1aa038eb, 0x0e3bfd17,},
- { 0x1a593062, 0xb38d8c56,},
- { 0x1a15f4c3, 0x2b95a2e6,},
- { 0x19d630dc, 0xcc7ddef9,},
- { 0x19999999, 0x9999999a,},
- { 0x195fec80, 0x8a609431,},
- { 0x1928ee7b, 0x0b4f22f9,},
- { 0x18f46acf, 0x8c06e318,},
- { 0x18c23246, 0xdc0a9f3d,},
- #else
- { 0x80000000, 0x00000000, 0x00000000,},
- { 0x50c24e60, 0xd4d4f4a7, 0x021f57bc,},
- { 0x40000000, 0x00000000, 0x00000000,},
- { 0x372068d2, 0x0a1ee5ca, 0x19ea911b,},
- { 0x3184648d, 0xb8153e7a, 0x7fc2d2e1,},
- { 0x2d983275, 0x9d5369c4, 0x4dec1661,},
- { 0x2aaaaaaa, 0xaaaaaaaa, 0xaaaaaaab,},
- { 0x28612730, 0x6a6a7a53, 0x810fabde,},
- { 0x268826a1, 0x3ef3fde6, 0x23e2566b,},
- { 0x25001383, 0xbac8a744, 0x385a3349,},
- { 0x23b46706, 0x82c0c709, 0x3f891718,},
- { 0x229729f1, 0xb2c83ded, 0x15fba800,},
- { 0x219e7ffd, 0xa5ad572a, 0xe169744b,},
- { 0x20c33b88, 0xda7c29aa, 0x9bddee52,},
- { 0x20000000, 0x00000000, 0x00000000,},
- { 0x1f50b57e, 0xac5884b3, 0x70e28eee,},
- { 0x1eb22cc6, 0x8aa6e26f, 0x06d1a2a2,},
- { 0x1e21e118, 0x0c5daab1, 0x81b4f4bf,},
- { 0x1d9dcd21, 0x439834e3, 0x81667575,},
- { 0x1d244c78, 0x367a0d64, 0xc8204d6d,},
- { 0x1cb40589, 0xac173e0c, 0x3b7b16ba,},
- { 0x1c4bd95b, 0xa8d72b0d, 0x5879f25a,},
- { 0x1bead768, 0x98f8ce4c, 0x66cc2858,},
- { 0x1b903469, 0x050f72e5, 0x0cf5488e,},
- { 0x1b3b433f, 0x2eb06f14, 0x8c89719c,},
- { 0x1aeb6f75, 0x9c46fc37, 0xab5fc7e9,},
- { 0x1aa038eb, 0x0e3bfd17, 0x1bd62080,},
- { 0x1a593062, 0xb38d8c56, 0x7998ab45,},
- { 0x1a15f4c3, 0x2b95a2e6, 0x46aed6a0,},
- { 0x19d630dc, 0xcc7ddef9, 0x5aadd61b,},
- { 0x19999999, 0x99999999, 0x9999999a,},
- { 0x195fec80, 0x8a609430, 0xe1106014,},
- { 0x1928ee7b, 0x0b4f22f9, 0x5f69791d,},
- { 0x18f46acf, 0x8c06e318, 0x4d2aeb2c,},
- { 0x18c23246, 0xdc0a9f3d, 0x3fe16970,},
- #endif
- };
- static const limb_t log2_radix[BF_RADIX_MAX - 1] = {
- #if LIMB_BITS == 32
- 0x20000000,
- 0x32b80347,
- 0x40000000,
- 0x4a4d3c26,
- 0x52b80347,
- 0x59d5d9fd,
- 0x60000000,
- 0x6570068e,
- 0x6a4d3c26,
- 0x6eb3a9f0,
- 0x72b80347,
- 0x766a008e,
- 0x79d5d9fd,
- 0x7d053f6d,
- 0x80000000,
- 0x82cc7edf,
- 0x8570068e,
- 0x87ef05ae,
- 0x8a4d3c26,
- 0x8c8ddd45,
- 0x8eb3a9f0,
- 0x90c10501,
- 0x92b80347,
- 0x949a784c,
- 0x966a008e,
- 0x982809d6,
- 0x99d5d9fd,
- 0x9b74948f,
- 0x9d053f6d,
- 0x9e88c6b3,
- 0xa0000000,
- 0xa16bad37,
- 0xa2cc7edf,
- 0xa4231623,
- 0xa570068e,
- #else
- 0x2000000000000000,
- 0x32b803473f7ad0f4,
- 0x4000000000000000,
- 0x4a4d3c25e68dc57f,
- 0x52b803473f7ad0f4,
- 0x59d5d9fd5010b366,
- 0x6000000000000000,
- 0x6570068e7ef5a1e8,
- 0x6a4d3c25e68dc57f,
- 0x6eb3a9f01975077f,
- 0x72b803473f7ad0f4,
- 0x766a008e4788cbcd,
- 0x79d5d9fd5010b366,
- 0x7d053f6d26089673,
- 0x8000000000000000,
- 0x82cc7edf592262d0,
- 0x8570068e7ef5a1e8,
- 0x87ef05ae409a0289,
- 0x8a4d3c25e68dc57f,
- 0x8c8ddd448f8b845a,
- 0x8eb3a9f01975077f,
- 0x90c10500d63aa659,
- 0x92b803473f7ad0f4,
- 0x949a784bcd1b8afe,
- 0x966a008e4788cbcd,
- 0x982809d5be7072dc,
- 0x99d5d9fd5010b366,
- 0x9b74948f5532da4b,
- 0x9d053f6d26089673,
- 0x9e88c6b3626a72aa,
- 0xa000000000000000,
- 0xa16bad3758efd873,
- 0xa2cc7edf592262d0,
- 0xa4231623369e78e6,
- 0xa570068e7ef5a1e8,
- #endif
- };
- /* compute floor(a*b) or ceil(a*b) with b = log2(radix) or
- b=1/log2(radix). For is_inv = 0, strict accuracy is not guaranteed
- when radix is not a power of two. */
- slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,
- int is_ceil1)
- {
- int is_neg;
- limb_t a;
- bool is_ceil;
- is_ceil = is_ceil1;
- a = a1;
- if (a1 < 0) {
- a = -a;
- is_neg = 1;
- } else {
- is_neg = 0;
- }
- is_ceil ^= is_neg;
- if ((radix & (radix - 1)) == 0) {
- int radix_bits;
- /* radix is a power of two */
- radix_bits = ceil_log2(radix);
- if (is_inv) {
- if (is_ceil)
- a += radix_bits - 1;
- a = a / radix_bits;
- } else {
- a = a * radix_bits;
- }
- } else {
- const uint32_t *tab;
- limb_t b0, b1;
- dlimb_t t;
- if (is_inv) {
- tab = inv_log2_radix[radix - 2];
- #if LIMB_BITS == 32
- b1 = tab[0];
- b0 = tab[1];
- #else
- b1 = ((limb_t)tab[0] << 32) | tab[1];
- b0 = (limb_t)tab[2] << 32;
- #endif
- t = (dlimb_t)b0 * (dlimb_t)a;
- t = (dlimb_t)b1 * (dlimb_t)a + (t >> LIMB_BITS);
- a = t >> (LIMB_BITS - 1);
- } else {
- b0 = log2_radix[radix - 2];
- t = (dlimb_t)b0 * (dlimb_t)a;
- a = t >> (LIMB_BITS - 3);
- }
- /* a = floor(result) and 'result' cannot be an integer */
- a += is_ceil;
- }
- if (is_neg)
- a = -a;
- return a;
- }
- /* 'n' is the number of output limbs */
- static int bf_integer_to_radix_rec(bf_t *pow_tab,
- limb_t *out, const bf_t *a, limb_t n,
- int level, limb_t n0, limb_t radixl,
- unsigned int radixl_bits)
- {
- limb_t n1, n2, q_prec;
- int ret;
- assert(n >= 1);
- if (n == 1) {
- out[0] = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn);
- } else if (n == 2) {
- dlimb_t t;
- slimb_t pos;
- pos = a->len * LIMB_BITS - a->expn;
- t = ((dlimb_t)get_bits(a->tab, a->len, pos + LIMB_BITS) << LIMB_BITS) |
- get_bits(a->tab, a->len, pos);
- if (likely(radixl == RADIXL_10)) {
- /* use division by a constant when possible */
- out[0] = t % RADIXL_10;
- out[1] = t / RADIXL_10;
- } else {
- out[0] = t % radixl;
- out[1] = t / radixl;
- }
- } else {
- bf_t Q, R, *B, *B_inv;
- int q_add;
- bf_init(a->ctx, &Q);
- bf_init(a->ctx, &R);
- n2 = (((n0 * 2) >> (level + 1)) + 1) / 2;
- n1 = n - n2;
- B = &pow_tab[2 * level];
- B_inv = &pow_tab[2 * level + 1];
- ret = 0;
- if (B->len == 0) {
- /* compute BASE^n2 */
- ret |= bf_pow_ui_ui(B, radixl, n2, BF_PREC_INF, BF_RNDZ);
- /* we use enough bits for the maximum possible 'n1' value,
- i.e. n2 + 1 */
- ret |= bf_set_ui(&R, 1);
- ret |= bf_div(B_inv, &R, B, (n2 + 1) * radixl_bits + 2, BF_RNDN);
- }
- // printf("%d: n1=% " PRId64 " n2=%" PRId64 "\n", level, n1, n2);
- q_prec = n1 * radixl_bits;
- ret |= bf_mul(&Q, a, B_inv, q_prec, BF_RNDN);
- ret |= bf_rint(&Q, BF_RNDZ);
- ret |= bf_mul(&R, &Q, B, BF_PREC_INF, BF_RNDZ);
- ret |= bf_sub(&R, a, &R, BF_PREC_INF, BF_RNDZ);
- if (ret & BF_ST_MEM_ERROR)
- goto fail;
- /* adjust if necessary */
- q_add = 0;
- while (R.sign && R.len != 0) {
- if (bf_add(&R, &R, B, BF_PREC_INF, BF_RNDZ))
- goto fail;
- q_add--;
- }
- while (bf_cmpu(&R, B) >= 0) {
- if (bf_sub(&R, &R, B, BF_PREC_INF, BF_RNDZ))
- goto fail;
- q_add++;
- }
- if (q_add != 0) {
- if (bf_add_si(&Q, &Q, q_add, BF_PREC_INF, BF_RNDZ))
- goto fail;
- }
- if (bf_integer_to_radix_rec(pow_tab, out + n2, &Q, n1, level + 1, n0,
- radixl, radixl_bits))
- goto fail;
- if (bf_integer_to_radix_rec(pow_tab, out, &R, n2, level + 1, n0,
- radixl, radixl_bits)) {
- fail:
- bf_delete(&Q);
- bf_delete(&R);
- return -1;
- }
- bf_delete(&Q);
- bf_delete(&R);
- }
- return 0;
- }
- /* return 0 if OK != 0 if memory error */
- static int bf_integer_to_radix(bf_t *r, const bf_t *a, limb_t radixl)
- {
- bf_context_t *s = r->ctx;
- limb_t r_len;
- bf_t *pow_tab;
- int i, pow_tab_len, ret;
- r_len = r->len;
- pow_tab_len = (ceil_log2(r_len) + 2) * 2; /* XXX: check */
- pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len);
- if (!pow_tab)
- return -1;
- for(i = 0; i < pow_tab_len; i++)
- bf_init(r->ctx, &pow_tab[i]);
- ret = bf_integer_to_radix_rec(pow_tab, r->tab, a, r_len, 0, r_len, radixl,
- ceil_log2(radixl));
- for(i = 0; i < pow_tab_len; i++) {
- bf_delete(&pow_tab[i]);
- }
- bf_free(s, pow_tab);
- return ret;
- }
- /* a must be >= 0. 'P' is the wanted number of digits in radix
- 'radix'. 'r' is the mantissa represented as an integer. *pE
- contains the exponent. Return != 0 if memory error. */
- static int bf_convert_to_radix(bf_t *r, slimb_t *pE,
- const bf_t *a, int radix,
- limb_t P, bf_rnd_t rnd_mode,
- bool is_fixed_exponent)
- {
- slimb_t E, e, prec, extra_bits, ziv_extra_bits, prec0;
- bf_t B_s, *B = &B_s;
- int e_sign, ret, res;
- if (a->len == 0) {
- /* zero case */
- *pE = 0;
- return bf_set(r, a);
- }
- if (is_fixed_exponent) {
- E = *pE;
- } else {
- /* compute the new exponent */
- E = 1 + bf_mul_log2_radix(a->expn - 1, radix, true, false);
- }
- // bf_print_str("a", a);
- // printf("E=%ld P=%ld radix=%d\n", E, P, radix);
- for(;;) {
- e = P - E;
- e_sign = 0;
- if (e < 0) {
- e = -e;
- e_sign = 1;
- }
- /* Note: precision for log2(radix) is not critical here */
- prec0 = bf_mul_log2_radix(P, radix, false, true);
- ziv_extra_bits = 16;
- for(;;) {
- prec = prec0 + ziv_extra_bits;
- /* XXX: rigorous error analysis needed */
- extra_bits = ceil_log2(e) * 2 + 1;
- ret = bf_pow_ui_ui(r, radix, e, prec + extra_bits,
- BF_RNDN | BF_FLAG_EXT_EXP);
- if (!e_sign)
- ret |= bf_mul(r, r, a, prec + extra_bits,
- BF_RNDN | BF_FLAG_EXT_EXP);
- else
- ret |= bf_div(r, a, r, prec + extra_bits,
- BF_RNDN | BF_FLAG_EXT_EXP);
- if (ret & BF_ST_MEM_ERROR)
- return BF_ST_MEM_ERROR;
- /* if the result is not exact, check that it can be safely
- rounded to an integer */
- if ((ret & BF_ST_INEXACT) &&
- !bf_can_round(r, r->expn, rnd_mode, prec)) {
- /* and more precision and retry */
- ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);
- continue;
- } else {
- ret = bf_rint(r, rnd_mode);
- if (ret & BF_ST_MEM_ERROR)
- return BF_ST_MEM_ERROR;
- break;
- }
- }
- if (is_fixed_exponent)
- break;
- /* check that the result is < B^P */
- /* XXX: do a fast approximate test first ? */
- bf_init(r->ctx, B);
- ret = bf_pow_ui_ui(B, radix, P, BF_PREC_INF, BF_RNDZ);
- if (ret) {
- bf_delete(B);
- return ret;
- }
- res = bf_cmpu(r, B);
- bf_delete(B);
- if (res < 0)
- break;
- /* try a larger exponent */
- E++;
- }
- *pE = E;
- return 0;
- }
- 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 */
- for(i = len - 1; i >= 0; i--) {
- digit = (limb_t)n % 10;
- n = (limb_t)n / 10;
- buf[i] = digit + '0';
- }
- } 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;
- }
- }
- }
- /* for power of 2 radixes */
- static void limb_to_a2(char *buf, limb_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;
- }
- }
- /* 'a' must be an integer if the is_dec = false or if the radix is not
- a power of two. A dot is added before the 'dot_pos' digit. dot_pos
- = n_digits does not display the dot. 0 <= dot_pos <=
- n_digits. n_digits >= 1. */
- static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits,
- limb_t dot_pos, bool is_dec)
- {
- limb_t i, v, l;
- slimb_t pos, pos_incr;
- int digits_per_limb, buf_pos, radix_bits, first_buf_pos;
- char buf[65];
- bf_t a_s, *a;
- if (is_dec) {
- digits_per_limb = LIMB_DIGITS;
- a = (bf_t *)a1;
- radix_bits = 0;
- pos = a->len;
- pos_incr = 1;
- first_buf_pos = 0;
- } else if ((radix & (radix - 1)) == 0) {
- a = (bf_t *)a1;
- radix_bits = ceil_log2(radix);
- digits_per_limb = LIMB_BITS / radix_bits;
- pos_incr = digits_per_limb * radix_bits;
- /* digits are aligned relative to the radix point */
- pos = a->len * LIMB_BITS + smod(-a->expn, radix_bits);
- first_buf_pos = 0;
- } else {
- limb_t n, radixl;
- digits_per_limb = digits_per_limb_table[radix - 2];
- radixl = get_limb_radix(radix);
- a = &a_s;
- bf_init(a1->ctx, a);
- n = (n_digits + digits_per_limb - 1) / digits_per_limb;
- if (bf_resize(a, n)) {
- dbuf_set_error(s);
- goto done;
- }
- if (bf_integer_to_radix(a, a1, radixl)) {
- dbuf_set_error(s);
- goto done;
- }
- radix_bits = 0;
- pos = n;
- pos_incr = 1;
- first_buf_pos = pos * digits_per_limb - n_digits;
- }
- buf_pos = digits_per_limb;
- i = 0;
- while (i < n_digits) {
- if (buf_pos == digits_per_limb) {
- pos -= pos_incr;
- if (radix_bits == 0) {
- v = get_limbz(a, pos);
- limb_to_a(buf, v, radix, digits_per_limb);
- } else {
- v = get_bits(a->tab, a->len, pos);
- limb_to_a2(buf, v, radix_bits, digits_per_limb);
- }
- buf_pos = first_buf_pos;
- first_buf_pos = 0;
- }
- if (i < dot_pos) {
- l = dot_pos;
- } else {
- if (i == dot_pos)
- dbuf_putc(s, '.');
- l = n_digits;
- }
- l = bf_min(digits_per_limb - buf_pos, l - i);
- dbuf_put(s, (uint8_t *)(buf + buf_pos), l);
- buf_pos += l;
- i += l;
- }
- done:
- if (a != a1)
- bf_delete(a);
- }
- static void *bf_dbuf_realloc(void *opaque, void *ptr, size_t size)
- {
- bf_context_t *s = opaque;
- return bf_realloc(s, ptr, size);
- }
- /* return the length in bytes. A trailing '\0' is added */
- static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix,
- limb_t prec, bf_flags_t flags, bool is_dec)
- {
- bf_context_t *ctx = a2->ctx;
- DynBuf s_s, *s = &s_s;
- int radix_bits;
- // bf_print_str("ftoa", a2);
- // printf("radix=%d\n", radix);
- dbuf_init2(s, ctx, bf_dbuf_realloc);
- if (a2->expn == BF_EXP_NAN) {
- dbuf_putstr(s, "NaN");
- } else {
- if (a2->sign)
- dbuf_putc(s, '-');
- if (a2->expn == BF_EXP_INF) {
- if (flags & BF_FTOA_JS_QUIRKS)
- dbuf_putstr(s, "Infinity");
- else
- dbuf_putstr(s, "Inf");
- } else {
- int fmt, ret;
- slimb_t n_digits, n, i, n_max, n1;
- bf_t a1_s, *a1 = &a1_s;
- if ((radix & (radix - 1)) != 0)
- radix_bits = 0;
- else
- radix_bits = ceil_log2(radix);
- fmt = flags & BF_FTOA_FORMAT_MASK;
- bf_init(ctx, a1);
- if (fmt == BF_FTOA_FORMAT_FRAC) {
- if (is_dec || radix_bits != 0) {
- if (bf_set(a1, a2))
- goto fail1;
- #ifdef USE_BF_DEC
- if (is_dec) {
- if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR)
- goto fail1;
- n = a1->expn;
- } else
- #endif
- {
- if (bf_round(a1, prec * radix_bits, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR)
- goto fail1;
- n = ceil_div(a1->expn, radix_bits);
- }
- if (flags & BF_FTOA_ADD_PREFIX) {
- if (radix == 16)
- dbuf_putstr(s, "0x");
- else if (radix == 8)
- dbuf_putstr(s, "0o");
- else if (radix == 2)
- dbuf_putstr(s, "0b");
- }
- if (a1->expn == BF_EXP_ZERO) {
- dbuf_putstr(s, "0");
- if (prec > 0) {
- dbuf_putstr(s, ".");
- for(i = 0; i < prec; i++) {
- dbuf_putc(s, '0');
- }
- }
- } else {
- n_digits = prec + n;
- if (n <= 0) {
- /* 0.x */
- dbuf_putstr(s, "0.");
- for(i = 0; i < -n; i++) {
- dbuf_putc(s, '0');
- }
- if (n_digits > 0) {
- output_digits(s, a1, radix, n_digits, n_digits, is_dec);
- }
- } else {
- output_digits(s, a1, radix, n_digits, n, is_dec);
- }
- }
- } else {
- size_t pos, start;
- bf_t a_s, *a = &a_s;
- /* make a positive number */
- a->tab = a2->tab;
- a->len = a2->len;
- a->expn = a2->expn;
- a->sign = 0;
- /* one more digit for the rounding */
- n = 1 + bf_mul_log2_radix(bf_max(a->expn, 0), radix, true, true);
- n_digits = n + prec;
- n1 = n;
- if (bf_convert_to_radix(a1, &n1, a, radix, n_digits,
- flags & BF_RND_MASK, true))
- goto fail1;
- start = s->size;
- output_digits(s, a1, radix, n_digits, n, is_dec);
- /* remove leading zeros because we allocated one more digit */
- pos = start;
- while ((pos + 1) < s->size && s->buf[pos] == '0' &&
- s->buf[pos + 1] != '.')
- pos++;
- if (pos > start) {
- memmove(s->buf + start, s->buf + pos, s->size - pos);
- s->size -= (pos - start);
- }
- }
- } else {
- #ifdef USE_BF_DEC
- if (is_dec) {
- if (bf_set(a1, a2))
- goto fail1;
- if (fmt == BF_FTOA_FORMAT_FIXED) {
- n_digits = prec;
- n_max = n_digits;
- if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR)
- goto fail1;
- } else {
- /* prec is ignored */
- prec = n_digits = a1->len * LIMB_DIGITS;
- /* remove the trailing zero digits */
- while (n_digits > 1 &&
- get_digit(a1->tab, a1->len, prec - n_digits) == 0) {
- n_digits--;
- }
- n_max = n_digits + 4;
- }
- n = a1->expn;
- } else
- #endif
- if (radix_bits != 0) {
- if (bf_set(a1, a2))
- goto fail1;
- if (fmt == BF_FTOA_FORMAT_FIXED) {
- slimb_t prec_bits;
- n_digits = prec;
- n_max = n_digits;
- /* align to the radix point */
- prec_bits = prec * radix_bits -
- smod(-a1->expn, radix_bits);
- if (bf_round(a1, prec_bits,
- (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR)
- goto fail1;
- } else {
- limb_t digit_mask;
- slimb_t pos;
- /* position of the digit before the most
- significant digit in bits */
- pos = a1->len * LIMB_BITS +
- smod(-a1->expn, radix_bits);
- n_digits = ceil_div(pos, radix_bits);
- /* remove the trailing zero digits */
- digit_mask = ((limb_t)1 << radix_bits) - 1;
- while (n_digits > 1 &&
- (get_bits(a1->tab, a1->len, pos - n_digits * radix_bits) & digit_mask) == 0) {
- n_digits--;
- }
- n_max = n_digits + 4;
- }
- n = ceil_div(a1->expn, radix_bits);
- } else {
- bf_t a_s, *a = &a_s;
- /* make a positive number */
- a->tab = a2->tab;
- a->len = a2->len;
- a->expn = a2->expn;
- a->sign = 0;
- if (fmt == BF_FTOA_FORMAT_FIXED) {
- n_digits = prec;
- n_max = n_digits;
- } else {
- slimb_t n_digits_max, n_digits_min;
- assert(prec != BF_PREC_INF);
- n_digits = 1 + bf_mul_log2_radix(prec, radix, true, true);
- /* max number of digits for non exponential
- notation. The rational is to have the same rule
- as JS i.e. n_max = 21 for 64 bit float in base 10. */
- n_max = n_digits + 4;
- if (fmt == BF_FTOA_FORMAT_FREE_MIN) {
- bf_t b_s, *b = &b_s;
- /* find the minimum number of digits by
- dichotomy. */
- /* XXX: inefficient */
- n_digits_max = n_digits;
- n_digits_min = 1;
- bf_init(ctx, b);
- while (n_digits_min < n_digits_max) {
- n_digits = (n_digits_min + n_digits_max) / 2;
- if (bf_convert_to_radix(a1, &n, a, radix, n_digits,
- flags & BF_RND_MASK, false)) {
- bf_delete(b);
- goto fail1;
- }
- /* convert back to a number and compare */
- ret = bf_mul_pow_radix(b, a1, radix, n - n_digits,
- prec,
- (flags & ~BF_RND_MASK) |
- BF_RNDN);
- if (ret & BF_ST_MEM_ERROR) {
- bf_delete(b);
- goto fail1;
- }
- if (bf_cmpu(b, a) == 0) {
- n_digits_max = n_digits;
- } else {
- n_digits_min = n_digits + 1;
- }
- }
- bf_delete(b);
- n_digits = n_digits_max;
- }
- }
- if (bf_convert_to_radix(a1, &n, a, radix, n_digits,
- flags & BF_RND_MASK, false)) {
- fail1:
- bf_delete(a1);
- goto fail;
- }
- }
- if (a1->expn == BF_EXP_ZERO &&
- fmt != BF_FTOA_FORMAT_FIXED &&
- !(flags & BF_FTOA_FORCE_EXP)) {
- /* just output zero */
- dbuf_putstr(s, "0");
- } else {
- if (flags & BF_FTOA_ADD_PREFIX) {
- if (radix == 16)
- dbuf_putstr(s, "0x");
- else if (radix == 8)
- dbuf_putstr(s, "0o");
- else if (radix == 2)
- dbuf_putstr(s, "0b");
- }
- if (a1->expn == BF_EXP_ZERO)
- n = 1;
- if ((flags & BF_FTOA_FORCE_EXP) ||
- n <= -6 || n > n_max) {
- /* exponential notation */
- output_digits(s, a1, radix, n_digits, 1, is_dec);
- if (radix_bits != 0 && radix <= 16) {
- slimb_t exp_n = (n - 1) * radix_bits;
- if (flags & BF_FTOA_JS_QUIRKS)
- dbuf_printf(s, "p%+" PRId_LIMB, exp_n);
- else
- dbuf_printf(s, "p%" PRId_LIMB, exp_n);
- } else {
- const char c = radix <= 10 ? 'e' : '@';
- if (flags & BF_FTOA_JS_QUIRKS)
- dbuf_printf(s, "%c%+" PRId_LIMB, c, n - 1);
- else
- dbuf_printf(s, "%c%" PRId_LIMB, c, n - 1);
- }
- } else if (n <= 0) {
- /* 0.x */
- dbuf_putstr(s, "0.");
- for(i = 0; i < -n; i++) {
- dbuf_putc(s, '0');
- }
- output_digits(s, a1, radix, n_digits, n_digits, is_dec);
- } else {
- if (n_digits <= n) {
- /* no dot */
- output_digits(s, a1, radix, n_digits, n_digits, is_dec);
- for(i = 0; i < (n - n_digits); i++)
- dbuf_putc(s, '0');
- } else {
- output_digits(s, a1, radix, n_digits, n, is_dec);
- }
- }
- }
- }
- bf_delete(a1);
- }
- }
- dbuf_putc(s, '\0');
- if (dbuf_error(s))
- goto fail;
- if (plen)
- *plen = s->size - 1;
- return (char *)s->buf;
- fail:
- bf_free(ctx, s->buf);
- if (plen)
- *plen = 0;
- return NULL;
- }
- char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,
- bf_flags_t flags)
- {
- return bf_ftoa_internal(plen, a, radix, prec, flags, false);
- }
- /***************************************************************/
- /* transcendental functions */
- /* Note: the algorithm is from MPFR */
- static void bf_const_log2_rec(bf_t *T, bf_t *P, bf_t *Q, limb_t n1,
- limb_t n2, bool need_P)
- {
- bf_context_t *s = T->ctx;
- if ((n2 - n1) == 1) {
- if (n1 == 0) {
- bf_set_ui(P, 3);
- } else {
- bf_set_ui(P, n1);
- P->sign = 1;
- }
- bf_set_ui(Q, 2 * n1 + 1);
- Q->expn += 2;
- bf_set(T, P);
- } else {
- limb_t m;
- bf_t T1_s, *T1 = &T1_s;
- bf_t P1_s, *P1 = &P1_s;
- bf_t Q1_s, *Q1 = &Q1_s;
- m = n1 + ((n2 - n1) >> 1);
- bf_const_log2_rec(T, P, Q, n1, m, true);
- bf_init(s, T1);
- bf_init(s, P1);
- bf_init(s, Q1);
- bf_const_log2_rec(T1, P1, Q1, m, n2, need_P);
- bf_mul(T, T, Q1, BF_PREC_INF, BF_RNDZ);
- bf_mul(T1, T1, P, BF_PREC_INF, BF_RNDZ);
- bf_add(T, T, T1, BF_PREC_INF, BF_RNDZ);
- if (need_P)
- bf_mul(P, P, P1, BF_PREC_INF, BF_RNDZ);
- bf_mul(Q, Q, Q1, BF_PREC_INF, BF_RNDZ);
- bf_delete(T1);
- bf_delete(P1);
- bf_delete(Q1);
- }
- }
- /* compute log(2) with faithful rounding at precision 'prec' */
- static void bf_const_log2_internal(bf_t *T, limb_t prec)
- {
- limb_t w, N;
- bf_t P_s, *P = &P_s;
- bf_t Q_s, *Q = &Q_s;
- w = prec + 15;
- N = w / 3 + 1;
- bf_init(T->ctx, P);
- bf_init(T->ctx, Q);
- bf_const_log2_rec(T, P, Q, 0, N, false);
- bf_div(T, T, Q, prec, BF_RNDN);
- bf_delete(P);
- bf_delete(Q);
- }
- /* PI constant */
- #define CHUD_A 13591409
- #define CHUD_B 545140134
- #define CHUD_C 640320
- #define CHUD_BITS_PER_TERM 47
- static void chud_bs(bf_t *P, bf_t *Q, bf_t *G, int64_t a, int64_t b, int need_g,
- limb_t prec)
- {
- bf_context_t *s = P->ctx;
- int64_t c;
- if (a == (b - 1)) {
- bf_t T0, T1;
- bf_init(s, &T0);
- bf_init(s, &T1);
- bf_set_ui(G, 2 * b - 1);
- bf_mul_ui(G, G, 6 * b - 1, prec, BF_RNDN);
- bf_mul_ui(G, G, 6 * b - 5, prec, BF_RNDN);
- bf_set_ui(&T0, CHUD_B);
- bf_mul_ui(&T0, &T0, b, prec, BF_RNDN);
- bf_set_ui(&T1, CHUD_A);
- bf_add(&T0, &T0, &T1, prec, BF_RNDN);
- bf_mul(P, G, &T0, prec, BF_RNDN);
- P->sign = b & 1;
- bf_set_ui(Q, b);
- bf_mul_ui(Q, Q, b, prec, BF_RNDN);
- bf_mul_ui(Q, Q, b, prec, BF_RNDN);
- bf_mul_ui(Q, Q, (uint64_t)CHUD_C * CHUD_C * CHUD_C / 24, prec, BF_RNDN);
- bf_delete(&T0);
- bf_delete(&T1);
- } else {
- bf_t P2, Q2, G2;
- bf_init(s, &P2);
- bf_init(s, &Q2);
- bf_init(s, &G2);
- c = (a + b) / 2;
- chud_bs(P, Q, G, a, c, 1, prec);
- chud_bs(&P2, &Q2, &G2, c, b, need_g, prec);
- /* Q = Q1 * Q2 */
- /* G = G1 * G2 */
- /* P = P1 * Q2 + P2 * G1 */
- bf_mul(&P2, &P2, G, prec, BF_RNDN);
- if (!need_g)
- bf_set_ui(G, 0);
- bf_mul(P, P, &Q2, prec, BF_RNDN);
- bf_add(P, P, &P2, prec, BF_RNDN);
- bf_delete(&P2);
- bf_mul(Q, Q, &Q2, prec, BF_RNDN);
- bf_delete(&Q2);
- if (need_g)
- bf_mul(G, G, &G2, prec, BF_RNDN);
- bf_delete(&G2);
- }
- }
- /* compute Pi with faithful rounding at precision 'prec' using the
- Chudnovsky formula */
- static void bf_const_pi_internal(bf_t *Q, limb_t prec)
- {
- bf_context_t *s = Q->ctx;
- int64_t n, prec1;
- bf_t P, G;
- /* number of serie terms */
- n = prec / CHUD_BITS_PER_TERM + 1;
- /* XXX: precision analysis */
- prec1 = prec + 32;
- bf_init(s, &P);
- bf_init(s, &G);
- chud_bs(&P, Q, &G, 0, n, 0, BF_PREC_INF);
- bf_mul_ui(&G, Q, CHUD_A, prec1, BF_RNDN);
- bf_add(&P, &G, &P, prec1, BF_RNDN);
- bf_div(Q, Q, &P, prec1, BF_RNDF);
- bf_set_ui(&P, CHUD_C);
- bf_sqrt(&G, &P, prec1, BF_RNDF);
- bf_mul_ui(&G, &G, (uint64_t)CHUD_C / 12, prec1, BF_RNDF);
- bf_mul(Q, Q, &G, prec, BF_RNDN);
- bf_delete(&P);
- bf_delete(&G);
- }
- static int bf_const_get(bf_t *T, limb_t prec, bf_flags_t flags,
- BFConstCache *c,
- void (*func)(bf_t *res, limb_t prec), int sign)
- {
- limb_t ziv_extra_bits, prec1;
- ziv_extra_bits = 32;
- for(;;) {
- prec1 = prec + ziv_extra_bits;
- if (c->prec < prec1) {
- if (c->val.len == 0)
- bf_init(T->ctx, &c->val);
- func(&c->val, prec1);
- c->prec = prec1;
- } else {
- prec1 = c->prec;
- }
- bf_set(T, &c->val);
- T->sign = sign;
- if (!bf_can_round(T, prec, flags & BF_RND_MASK, prec1)) {
- /* and more precision and retry */
- ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);
- } else {
- break;
- }
- }
- return bf_round(T, prec, flags);
- }
- static void bf_const_free(BFConstCache *c)
- {
- bf_delete(&c->val);
- memset(c, 0, sizeof(*c));
- }
- int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags)
- {
- bf_context_t *s = T->ctx;
- return bf_const_get(T, prec, flags, &s->log2_cache, bf_const_log2_internal, 0);
- }
- /* return rounded pi * (1 - 2 * sign) */
- static int bf_const_pi_signed(bf_t *T, int sign, limb_t prec, bf_flags_t flags)
- {
- bf_context_t *s = T->ctx;
- return bf_const_get(T, prec, flags, &s->pi_cache, bf_const_pi_internal,
- sign);
- }
- int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags)
- {
- return bf_const_pi_signed(T, 0, prec, flags);
- }
- void bf_clear_cache(bf_context_t *s)
- {
- #ifdef USE_FFT_MUL
- fft_clear_cache(s);
- #endif
- bf_const_free(&s->log2_cache);
- bf_const_free(&s->pi_cache);
- }
- /* ZivFunc should compute the result 'r' with faithful rounding at
- precision 'prec'. For efficiency purposes, the final bf_round()
- does not need to be done in the function. */
- typedef int ZivFunc(bf_t *r, const bf_t *a, limb_t prec, void *opaque);
- static int bf_ziv_rounding(bf_t *r, const bf_t *a,
- limb_t prec, bf_flags_t flags,
- ZivFunc *f, void *opaque)
- {
- int rnd_mode, ret;
- slimb_t prec1, ziv_extra_bits;
- rnd_mode = flags & BF_RND_MASK;
- if (rnd_mode == BF_RNDF) {
- /* no need to iterate */
- f(r, a, prec, opaque);
- ret = 0;
- } else {
- ziv_extra_bits = 32;
- for(;;) {
- prec1 = prec + ziv_extra_bits;
- ret = f(r, a, prec1, opaque);
- if (ret & (BF_ST_OVERFLOW | BF_ST_UNDERFLOW | BF_ST_MEM_ERROR)) {
- /* overflow or underflow should never happen because
- it indicates the rounding cannot be done correctly,
- but we do not catch all the cases */
- return ret;
- }
- /* if the result is exact, we can stop */
- if (!(ret & BF_ST_INEXACT)) {
- ret = 0;
- break;
- }
- if (bf_can_round(r, prec, rnd_mode, prec1)) {
- ret = BF_ST_INEXACT;
- break;
- }
- ziv_extra_bits = ziv_extra_bits * 2;
- // printf("ziv_extra_bits=%" PRId64 "\n", (int64_t)ziv_extra_bits);
- }
- }
- if (r->len == 0)
- return ret;
- else
- return __bf_round(r, prec, flags, r->len, ret);
- }
- /* add (1 - 2*e_sign) * 2^e */
- static int bf_add_epsilon(bf_t *r, const bf_t *a, slimb_t e, int e_sign,
- limb_t prec, int flags)
- {
- bf_t T_s, *T = &T_s;
- int ret;
- /* small argument case: result = 1 + epsilon * sign(x) */
- bf_init(a->ctx, T);
- bf_set_ui(T, 1);
- T->sign = e_sign;
- T->expn += e;
- ret = bf_add(r, r, T, prec, flags);
- bf_delete(T);
- return ret;
- }
- /* Compute the exponential using faithful rounding at precision 'prec'.
- Note: the algorithm is from MPFR */
- static int bf_exp_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
- {
- bf_context_t *s = r->ctx;
- bf_t T_s, *T = &T_s;
- slimb_t n, K, l, i, prec1;
- assert(r != a);
- /* argument reduction:
- T = a - n*log(2) with 0 <= T < log(2) and n integer.
- */
- bf_init(s, T);
- if (a->expn <= -1) {
- /* 0 <= abs(a) <= 0.5 */
- if (a->sign)
- n = -1;
- else
- n = 0;
- } else {
- bf_const_log2(T, LIMB_BITS, BF_RNDZ);
- bf_div(T, a, T, LIMB_BITS, BF_RNDD);
- bf_get_limb(&n, T, 0);
- }
- K = bf_isqrt((prec + 1) / 2);
- l = (prec - 1) / K + 1;
- /* XXX: precision analysis ? */
- prec1 = prec + (K + 2 * l + 18) + K + 8;
- if (a->expn > 0)
- prec1 += a->expn;
- // printf("n=%ld K=%ld prec1=%ld\n", n, K, prec1);
- bf_const_log2(T, prec1, BF_RNDF);
- bf_mul_si(T, T, n, prec1, BF_RNDN);
- bf_sub(T, a, T, prec1, BF_RNDN);
- /* reduce the range of T */
- bf_mul_2exp(T, -K, BF_PREC_INF, BF_RNDZ);
- /* Taylor expansion around zero :
- 1 + x + x^2/2 + ... + x^n/n!
- = (1 + x * (1 + x/2 * (1 + ... (x/n))))
- */
- {
- bf_t U_s, *U = &U_s;
- bf_init(s, U);
- bf_set_ui(r, 1);
- for(i = l ; i >= 1; i--) {
- bf_set_ui(U, i);
- bf_div(U, T, U, prec1, BF_RNDN);
- bf_mul(r, r, U, prec1, BF_RNDN);
- bf_add_si(r, r, 1, prec1, BF_RNDN);
- }
- bf_delete(U);
- }
- bf_delete(T);
- /* undo the range reduction */
- for(i = 0; i < K; i++) {
- bf_mul(r, r, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP);
- }
- /* undo the argument reduction */
- bf_mul_2exp(r, n, BF_PREC_INF, BF_RNDZ | BF_FLAG_EXT_EXP);
- return BF_ST_INEXACT;
- }
- /* crude overflow and underflow tests for exp(a). a_low <= a <= a_high */
- static int check_exp_underflow_overflow(bf_context_t *s, bf_t *r,
- const bf_t *a_low, const bf_t *a_high,
- limb_t prec, bf_flags_t flags)
- {
- bf_t T_s, *T = &T_s;
- bf_t log2_s, *log2 = &log2_s;
- slimb_t e_min, e_max;
- if (a_high->expn <= 0)
- return 0;
- e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
- e_min = -e_max + 3;
- if (flags & BF_FLAG_SUBNORMAL)
- e_min -= (prec - 1);
- bf_init(s, T);
- bf_init(s, log2);
- bf_const_log2(log2, LIMB_BITS, BF_RNDU);
- bf_mul_ui(T, log2, e_max, LIMB_BITS, BF_RNDU);
- /* a_low > e_max * log(2) implies exp(a) > e_max */
- if (bf_cmp_lt(T, a_low) > 0) {
- /* overflow */
- bf_delete(T);
- bf_delete(log2);
- return bf_set_overflow(r, 0, prec, flags);
- }
- /* a_high < (e_min - 2) * log(2) implies exp(a) < (e_min - 2) */
- bf_const_log2(log2, LIMB_BITS, BF_RNDD);
- bf_mul_si(T, log2, e_min - 2, LIMB_BITS, BF_RNDD);
- if (bf_cmp_lt(a_high, T)) {
- int rnd_mode = flags & BF_RND_MASK;
- /* underflow */
- bf_delete(T);
- bf_delete(log2);
- if (rnd_mode == BF_RNDU) {
- /* set the smallest value */
- bf_set_ui(r, 1);
- r->expn = e_min;
- } else {
- bf_set_zero(r, 0);
- }
- return BF_ST_UNDERFLOW | BF_ST_INEXACT;
- }
- bf_delete(log2);
- bf_delete(T);
- return 0;
- }
- int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
- {
- bf_context_t *s = r->ctx;
- int ret;
- assert(r != a);
- if (a->len == 0) {
- if (a->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- } else if (a->expn == BF_EXP_INF) {
- if (a->sign)
- bf_set_zero(r, 0);
- else
- bf_set_inf(r, 0);
- } else {
- bf_set_ui(r, 1);
- }
- return 0;
- }
- ret = check_exp_underflow_overflow(s, r, a, a, prec, flags);
- if (ret)
- return ret;
- if (a->expn < 0 && (-a->expn) >= (prec + 2)) {
- /* small argument case: result = 1 + epsilon * sign(x) */
- bf_set_ui(r, 1);
- return bf_add_epsilon(r, r, -(prec + 2), a->sign, prec, flags);
- }
- return bf_ziv_rounding(r, a, prec, flags, bf_exp_internal, NULL);
- }
- static int bf_log_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
- {
- bf_context_t *s = r->ctx;
- bf_t T_s, *T = &T_s;
- bf_t U_s, *U = &U_s;
- bf_t V_s, *V = &V_s;
- slimb_t n, prec1, l, i, K;
- assert(r != a);
- bf_init(s, T);
- /* argument reduction 1 */
- /* T=a*2^n with 2/3 <= T <= 4/3 */
- {
- bf_t U_s, *U = &U_s;
- bf_set(T, a);
- n = T->expn;
- T->expn = 0;
- /* U= ~ 2/3 */
- bf_init(s, U);
- bf_set_ui(U, 0xaaaaaaaa);
- U->expn = 0;
- if (bf_cmp_lt(T, U)) {
- T->expn++;
- n--;
- }
- bf_delete(U);
- }
- // printf("n=%ld\n", n);
- // bf_print_str("T", T);
- /* XXX: precision analysis */
- /* number of iterations for argument reduction 2 */
- K = bf_isqrt((prec + 1) / 2);
- /* order of Taylor expansion */
- l = prec / (2 * K) + 1;
- /* precision of the intermediate computations */
- prec1 = prec + K + 2 * l + 32;
- bf_init(s, U);
- bf_init(s, V);
- /* Note: cancellation occurs here, so we use more precision (XXX:
- reduce the precision by computing the exact cancellation) */
- bf_add_si(T, T, -1, BF_PREC_INF, BF_RNDN);
- /* argument reduction 2 */
- for(i = 0; i < K; i++) {
- /* T = T / (1 + sqrt(1 + T)) */
- bf_add_si(U, T, 1, prec1, BF_RNDN);
- bf_sqrt(V, U, prec1, BF_RNDF);
- bf_add_si(U, V, 1, prec1, BF_RNDN);
- bf_div(T, T, U, prec1, BF_RNDN);
- }
- {
- bf_t Y_s, *Y = &Y_s;
- bf_t Y2_s, *Y2 = &Y2_s;
- bf_init(s, Y);
- bf_init(s, Y2);
- /* compute ln(1+x) = ln((1+y)/(1-y)) with y=x/(2+x)
- = y + y^3/3 + ... + y^(2*l + 1) / (2*l+1)
- with Y=Y^2
- = y*(1+Y/3+Y^2/5+...) = y*(1+Y*(1/3+Y*(1/5 + ...)))
- */
- bf_add_si(Y, T, 2, prec1, BF_RNDN);
- bf_div(Y, T, Y, prec1, BF_RNDN);
- bf_mul(Y2, Y, Y, prec1, BF_RNDN);
- bf_set_ui(r, 0);
- for(i = l; i >= 1; i--) {
- bf_set_ui(U, 1);
- bf_set_ui(V, 2 * i + 1);
- bf_div(U, U, V, prec1, BF_RNDN);
- bf_add(r, r, U, prec1, BF_RNDN);
- bf_mul(r, r, Y2, prec1, BF_RNDN);
- }
- bf_add_si(r, r, 1, prec1, BF_RNDN);
- bf_mul(r, r, Y, prec1, BF_RNDN);
- bf_delete(Y);
- bf_delete(Y2);
- }
- bf_delete(V);
- bf_delete(U);
- /* multiplication by 2 for the Taylor expansion and undo the
- argument reduction 2*/
- bf_mul_2exp(r, K + 1, BF_PREC_INF, BF_RNDZ);
- /* undo the argument reduction 1 */
- bf_const_log2(T, prec1, BF_RNDF);
- bf_mul_si(T, T, n, prec1, BF_RNDN);
- bf_add(r, r, T, prec1, BF_RNDN);
- bf_delete(T);
- return BF_ST_INEXACT;
- }
- int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
- {
- bf_context_t *s = r->ctx;
- bf_t T_s, *T = &T_s;
- assert(r != a);
- if (a->len == 0) {
- if (a->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- return 0;
- } else if (a->expn == BF_EXP_INF) {
- if (a->sign) {
- bf_set_nan(r);
- return BF_ST_INVALID_OP;
- } else {
- bf_set_inf(r, 0);
- return 0;
- }
- } else {
- bf_set_inf(r, 1);
- return 0;
- }
- }
- if (a->sign) {
- bf_set_nan(r);
- return BF_ST_INVALID_OP;
- }
- bf_init(s, T);
- bf_set_ui(T, 1);
- if (bf_cmp_eq(a, T)) {
- bf_set_zero(r, 0);
- bf_delete(T);
- return 0;
- }
- bf_delete(T);
- return bf_ziv_rounding(r, a, prec, flags, bf_log_internal, NULL);
- }
- /* x and y finite and x > 0 */
- static int bf_pow_generic(bf_t *r, const bf_t *x, limb_t prec, void *opaque)
- {
- bf_context_t *s = r->ctx;
- const bf_t *y = opaque;
- bf_t T_s, *T = &T_s;
- limb_t prec1;
- bf_init(s, T);
- /* XXX: proof for the added precision */
- prec1 = prec + 32;
- bf_log(T, x, prec1, BF_RNDF | BF_FLAG_EXT_EXP);
- bf_mul(T, T, y, prec1, BF_RNDF | BF_FLAG_EXT_EXP);
- if (bf_is_nan(T))
- bf_set_nan(r);
- else
- bf_exp_internal(r, T, prec1, NULL); /* no overflow/underlow test needed */
- bf_delete(T);
- return BF_ST_INEXACT;
- }
- /* x and y finite, x > 0, y integer and y fits on one limb */
- static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque)
- {
- bf_context_t *s = r->ctx;
- const bf_t *y = opaque;
- bf_t T_s, *T = &T_s;
- limb_t prec1;
- int ret;
- slimb_t y1;
- bf_get_limb(&y1, y, 0);
- if (y1 < 0)
- y1 = -y1;
- /* XXX: proof for the added precision */
- prec1 = prec + ceil_log2(y1) * 2 + 8;
- ret = bf_pow_ui(r, x, y1 < 0 ? -y1 : y1, prec1, BF_RNDN | BF_FLAG_EXT_EXP);
- if (y->sign) {
- bf_init(s, T);
- bf_set_ui(T, 1);
- ret |= bf_div(r, T, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP);
- bf_delete(T);
- }
- return ret;
- }
- /* x must be a finite non zero float. Return true if there is a
- floating point number r such as x=r^(2^n) and return this floating
- point number 'r'. Otherwise return false and r is undefined. */
- static bool check_exact_power2n(bf_t *r, const bf_t *x, slimb_t n)
- {
- bf_context_t *s = r->ctx;
- bf_t T_s, *T = &T_s;
- slimb_t e, i, er;
- limb_t v;
- /* x = m*2^e with m odd integer */
- e = bf_get_exp_min(x);
- /* fast check on the exponent */
- if (n > (LIMB_BITS - 1)) {
- if (e != 0)
- return false;
- er = 0;
- } else {
- if ((e & (((limb_t)1 << n) - 1)) != 0)
- return false;
- er = e >> n;
- }
- /* every perfect odd square = 1 modulo 8 */
- v = get_bits(x->tab, x->len, x->len * LIMB_BITS - x->expn + e);
- if ((v & 7) != 1)
- return false;
- bf_init(s, T);
- bf_set(T, x);
- T->expn -= e;
- for(i = 0; i < n; i++) {
- if (i != 0)
- bf_set(T, r);
- if (bf_sqrtrem(r, NULL, T) != 0)
- return false;
- }
- r->expn += er;
- return true;
- }
- /* prec = BF_PREC_INF is accepted for x and y integers and y >= 0 */
- int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags)
- {
- bf_context_t *s = r->ctx;
- bf_t T_s, *T = &T_s;
- bf_t ytmp_s;
- bool y_is_int, y_is_odd;
- int r_sign, ret, rnd_mode;
- slimb_t y_emin;
- if (x->len == 0 || y->len == 0) {
- if (y->expn == BF_EXP_ZERO) {
- /* pow(x, 0) = 1 */
- bf_set_ui(r, 1);
- } else if (x->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- } else {
- int cmp_x_abs_1;
- bf_set_ui(r, 1);
- cmp_x_abs_1 = bf_cmpu(x, r);
- if (cmp_x_abs_1 == 0 && (flags & BF_POW_JS_QUIRKS) &&
- (y->expn >= BF_EXP_INF)) {
- bf_set_nan(r);
- } else if (cmp_x_abs_1 == 0 &&
- (!x->sign || y->expn != BF_EXP_NAN)) {
- /* pow(1, y) = 1 even if y = NaN */
- /* pow(-1, +/-inf) = 1 */
- } else if (y->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- } else if (y->expn == BF_EXP_INF) {
- if (y->sign == (cmp_x_abs_1 > 0)) {
- bf_set_zero(r, 0);
- } else {
- bf_set_inf(r, 0);
- }
- } else {
- y_emin = bf_get_exp_min(y);
- y_is_odd = (y_emin == 0);
- if (y->sign == (x->expn == BF_EXP_ZERO)) {
- bf_set_inf(r, y_is_odd & x->sign);
- if (y->sign) {
- /* pow(0, y) with y < 0 */
- return BF_ST_DIVIDE_ZERO;
- }
- } else {
- bf_set_zero(r, y_is_odd & x->sign);
- }
- }
- }
- return 0;
- }
- bf_init(s, T);
- bf_set(T, x);
- y_emin = bf_get_exp_min(y);
- y_is_int = (y_emin >= 0);
- rnd_mode = flags & BF_RND_MASK;
- if (x->sign) {
- if (!y_is_int) {
- bf_set_nan(r);
- bf_delete(T);
- return BF_ST_INVALID_OP;
- }
- y_is_odd = (y_emin == 0);
- r_sign = y_is_odd;
- /* change the directed rounding mode if the sign of the result
- is changed */
- if (r_sign && (rnd_mode == BF_RNDD || rnd_mode == BF_RNDU))
- flags ^= 1;
- bf_neg(T);
- } else {
- r_sign = 0;
- }
- bf_set_ui(r, 1);
- if (bf_cmp_eq(T, r)) {
- /* abs(x) = 1: nothing more to do */
- ret = 0;
- } else {
- /* check the overflow/underflow cases */
- {
- bf_t al_s, *al = &al_s;
- bf_t ah_s, *ah = &ah_s;
- limb_t precl = LIMB_BITS;
- bf_init(s, al);
- bf_init(s, ah);
- /* compute bounds of log(abs(x)) * y with a low precision */
- /* XXX: compute bf_log() once */
- /* XXX: add a fast test before this slow test */
- bf_log(al, T, precl, BF_RNDD);
- bf_log(ah, T, precl, BF_RNDU);
- bf_mul(al, al, y, precl, BF_RNDD ^ y->sign);
- bf_mul(ah, ah, y, precl, BF_RNDU ^ y->sign);
- ret = check_exp_underflow_overflow(s, r, al, ah, prec, flags);
- bf_delete(al);
- bf_delete(ah);
- if (ret)
- goto done;
- }
- if (y_is_int) {
- slimb_t T_bits, e;
- int_pow:
- T_bits = T->expn - bf_get_exp_min(T);
- if (T_bits == 1) {
- /* pow(2^b, y) = 2^(b*y) */
- bf_mul_si(T, y, T->expn - 1, LIMB_BITS, BF_RNDZ);
- bf_get_limb(&e, T, 0);
- bf_set_ui(r, 1);
- ret = bf_mul_2exp(r, e, prec, flags);
- } else if (prec == BF_PREC_INF) {
- slimb_t y1;
- /* specific case for infinite precision (integer case) */
- bf_get_limb(&y1, y, 0);
- assert(!y->sign);
- /* x must be an integer, so abs(x) >= 2 */
- if (y1 >= ((slimb_t)1 << BF_EXP_BITS_MAX)) {
- bf_delete(T);
- return bf_set_overflow(r, 0, BF_PREC_INF, flags);
- }
- ret = bf_pow_ui(r, T, y1, BF_PREC_INF, BF_RNDZ);
- } else {
- if (y->expn <= 31) {
- /* small enough power: use exponentiation in all cases */
- } else if (y->sign) {
- /* cannot be exact */
- goto general_case;
- } else {
- if (rnd_mode == BF_RNDF)
- goto general_case; /* no need to track exact results */
- /* see if the result has a chance to be exact:
- if x=a*2^b (a odd), x^y=a^y*2^(b*y)
- x^y needs a precision of at least floor_log2(a)*y bits
- */
- bf_mul_si(r, y, T_bits - 1, LIMB_BITS, BF_RNDZ);
- bf_get_limb(&e, r, 0);
- if (prec < e)
- goto general_case;
- }
- ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_int, (void *)y);
- }
- } else {
- if (rnd_mode != BF_RNDF) {
- bf_t *y1;
- if (y_emin < 0 && check_exact_power2n(r, T, -y_emin)) {
- /* the problem is reduced to a power to an integer */
- bf_set(T, r);
- y1 = &ytmp_s;
- y1->tab = y->tab;
- y1->len = y->len;
- y1->sign = y->sign;
- y1->expn = y->expn - y_emin;
- y = y1;
- goto int_pow;
- }
- }
- general_case:
- ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_generic, (void *)y);
- }
- }
- done:
- bf_delete(T);
- r->sign = r_sign;
- return ret;
- }
- /* compute sqrt(-2*x-x^2) to get |sin(x)| from cos(x) - 1. */
- static void bf_sqrt_sin(bf_t *r, const bf_t *x, limb_t prec1)
- {
- bf_context_t *s = r->ctx;
- bf_t T_s, *T = &T_s;
- bf_init(s, T);
- bf_set(T, x);
- bf_mul(r, T, T, prec1, BF_RNDN);
- bf_mul_2exp(T, 1, BF_PREC_INF, BF_RNDZ);
- bf_add(T, T, r, prec1, BF_RNDN);
- bf_neg(T);
- bf_sqrt(r, T, prec1, BF_RNDF);
- bf_delete(T);
- }
- static int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec)
- {
- bf_context_t *s1 = a->ctx;
- bf_t T_s, *T = &T_s;
- bf_t U_s, *U = &U_s;
- bf_t r_s, *r = &r_s;
- slimb_t K, prec1, i, l, mod, prec2;
- int is_neg;
- assert(c != a && s != a);
- bf_init(s1, T);
- bf_init(s1, U);
- bf_init(s1, r);
- /* XXX: precision analysis */
- K = bf_isqrt(prec / 2);
- l = prec / (2 * K) + 1;
- prec1 = prec + 2 * K + l + 8;
- /* after the modulo reduction, -pi/4 <= T <= pi/4 */
- if (a->expn <= -1) {
- /* abs(a) <= 0.25: no modulo reduction needed */
- bf_set(T, a);
- mod = 0;
- } else {
- slimb_t cancel;
- cancel = 0;
- for(;;) {
- prec2 = prec1 + a->expn + cancel;
- bf_const_pi(U, prec2, BF_RNDF);
- bf_mul_2exp(U, -1, BF_PREC_INF, BF_RNDZ);
- bf_remquo(&mod, T, a, U, prec2, BF_RNDN, BF_RNDN);
- // printf("T.expn=%ld prec2=%ld\n", T->expn, prec2);
- if (mod == 0 || (T->expn != BF_EXP_ZERO &&
- (T->expn + prec2) >= (prec1 - 1)))
- break;
- /* increase the number of bits until the precision is good enough */
- cancel = bf_max(-T->expn, (cancel + 1) * 3 / 2);
- }
- mod &= 3;
- }
- is_neg = T->sign;
- /* compute cosm1(x) = cos(x) - 1 */
- bf_mul(T, T, T, prec1, BF_RNDN);
- bf_mul_2exp(T, -2 * K, BF_PREC_INF, BF_RNDZ);
- /* Taylor expansion:
- -x^2/2 + x^4/4! - x^6/6! + ...
- */
- bf_set_ui(r, 1);
- for(i = l ; i >= 1; i--) {
- bf_set_ui(U, 2 * i - 1);
- bf_mul_ui(U, U, 2 * i, BF_PREC_INF, BF_RNDZ);
- bf_div(U, T, U, prec1, BF_RNDN);
- bf_mul(r, r, U, prec1, BF_RNDN);
- bf_neg(r);
- if (i != 1)
- bf_add_si(r, r, 1, prec1, BF_RNDN);
- }
- bf_delete(U);
- /* undo argument reduction:
- cosm1(2*x)= 2*(2*cosm1(x)+cosm1(x)^2)
- */
- for(i = 0; i < K; i++) {
- bf_mul(T, r, r, prec1, BF_RNDN);
- bf_mul_2exp(r, 1, BF_PREC_INF, BF_RNDZ);
- bf_add(r, r, T, prec1, BF_RNDN);
- bf_mul_2exp(r, 1, BF_PREC_INF, BF_RNDZ);
- }
- bf_delete(T);
- if (c) {
- if ((mod & 1) == 0) {
- bf_add_si(c, r, 1, prec1, BF_RNDN);
- } else {
- bf_sqrt_sin(c, r, prec1);
- c->sign = is_neg ^ 1;
- }
- c->sign ^= mod >> 1;
- }
- if (s) {
- if ((mod & 1) == 0) {
- bf_sqrt_sin(s, r, prec1);
- s->sign = is_neg;
- } else {
- bf_add_si(s, r, 1, prec1, BF_RNDN);
- }
- s->sign ^= mod >> 1;
- }
- bf_delete(r);
- return BF_ST_INEXACT;
- }
- static int bf_cos_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
- {
- return bf_sincos(NULL, r, a, prec);
- }
- int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
- {
- if (a->len == 0) {
- if (a->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- return 0;
- } else if (a->expn == BF_EXP_INF) {
- bf_set_nan(r);
- return BF_ST_INVALID_OP;
- } else {
- bf_set_ui(r, 1);
- return 0;
- }
- }
- /* small argument case: result = 1+r(x) with r(x) = -x^2/2 +
- O(X^4). We assume r(x) < 2^(2*EXP(x) - 1). */
- if (a->expn < 0) {
- slimb_t e;
- e = 2 * a->expn - 1;
- if (e < -(prec + 2)) {
- bf_set_ui(r, 1);
- return bf_add_epsilon(r, r, e, 1, prec, flags);
- }
- }
- return bf_ziv_rounding(r, a, prec, flags, bf_cos_internal, NULL);
- }
- static int bf_sin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
- {
- return bf_sincos(r, NULL, a, prec);
- }
- int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
- {
- if (a->len == 0) {
- if (a->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- return 0;
- } else if (a->expn == BF_EXP_INF) {
- bf_set_nan(r);
- return BF_ST_INVALID_OP;
- } else {
- bf_set_zero(r, a->sign);
- return 0;
- }
- }
- /* small argument case: result = x+r(x) with r(x) = -x^3/6 +
- O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */
- if (a->expn < 0) {
- slimb_t e;
- e = sat_add(2 * a->expn, a->expn - 2);
- if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
- bf_set(r, a);
- return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags);
- }
- }
- return bf_ziv_rounding(r, a, prec, flags, bf_sin_internal, NULL);
- }
- static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
- {
- bf_context_t *s = r->ctx;
- bf_t T_s, *T = &T_s;
- limb_t prec1;
- /* XXX: precision analysis */
- prec1 = prec + 8;
- bf_init(s, T);
- bf_sincos(r, T, a, prec1);
- bf_div(r, r, T, prec1, BF_RNDF);
- bf_delete(T);
- return BF_ST_INEXACT;
- }
- int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
- {
- assert(r != a);
- if (a->len == 0) {
- if (a->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- return 0;
- } else if (a->expn == BF_EXP_INF) {
- bf_set_nan(r);
- return BF_ST_INVALID_OP;
- } else {
- bf_set_zero(r, a->sign);
- return 0;
- }
- }
- /* small argument case: result = x+r(x) with r(x) = x^3/3 +
- O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */
- if (a->expn < 0) {
- slimb_t e;
- e = sat_add(2 * a->expn, a->expn - 1);
- if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
- bf_set(r, a);
- return bf_add_epsilon(r, r, e, a->sign, prec, flags);
- }
- }
- return bf_ziv_rounding(r, a, prec, flags, bf_tan_internal, NULL);
- }
- /* if add_pi2 is true, add pi/2 to the result (used for acos(x) to
- avoid cancellation) */
- static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec,
- void *opaque)
- {
- bf_context_t *s = r->ctx;
- bool add_pi2 = (bool)(intptr_t)opaque;
- bf_t T_s, *T = &T_s;
- bf_t U_s, *U = &U_s;
- bf_t V_s, *V = &V_s;
- bf_t X2_s, *X2 = &X2_s;
- int cmp_1;
- slimb_t prec1, i, K, l;
- /* XXX: precision analysis */
- K = bf_isqrt((prec + 1) / 2);
- l = prec / (2 * K) + 1;
- prec1 = prec + K + 2 * l + 32;
- // printf("prec=%d K=%d l=%d prec1=%d\n", (int)prec, (int)K, (int)l, (int)prec1);
- bf_init(s, T);
- cmp_1 = (a->expn >= 1); /* a >= 1 */
- if (cmp_1) {
- bf_set_ui(T, 1);
- bf_div(T, T, a, prec1, BF_RNDN);
- } else {
- bf_set(T, a);
- }
- /* abs(T) <= 1 */
- /* argument reduction */
- bf_init(s, U);
- bf_init(s, V);
- bf_init(s, X2);
- for(i = 0; i < K; i++) {
- /* T = T / (1 + sqrt(1 + T^2)) */
- bf_mul(U, T, T, prec1, BF_RNDN);
- bf_add_si(U, U, 1, prec1, BF_RNDN);
- bf_sqrt(V, U, prec1, BF_RNDN);
- bf_add_si(V, V, 1, prec1, BF_RNDN);
- bf_div(T, T, V, prec1, BF_RNDN);
- }
- /* Taylor series:
- x - x^3/3 + ... + (-1)^ l * y^(2*l + 1) / (2*l+1)
- */
- bf_mul(X2, T, T, prec1, BF_RNDN);
- bf_set_ui(r, 0);
- for(i = l; i >= 1; i--) {
- bf_set_si(U, 1);
- bf_set_ui(V, 2 * i + 1);
- bf_div(U, U, V, prec1, BF_RNDN);
- bf_neg(r);
- bf_add(r, r, U, prec1, BF_RNDN);
- bf_mul(r, r, X2, prec1, BF_RNDN);
- }
- bf_neg(r);
- bf_add_si(r, r, 1, prec1, BF_RNDN);
- bf_mul(r, r, T, prec1, BF_RNDN);
- /* undo the argument reduction */
- bf_mul_2exp(r, K, BF_PREC_INF, BF_RNDZ);
- bf_delete(U);
- bf_delete(V);
- bf_delete(X2);
- i = add_pi2;
- if (cmp_1 > 0) {
- /* undo the inversion : r = sign(a)*PI/2 - r */
- bf_neg(r);
- i += 1 - 2 * a->sign;
- }
- /* add i*(pi/2) with -1 <= i <= 2 */
- if (i != 0) {
- bf_const_pi(T, prec1, BF_RNDF);
- if (i != 2)
- bf_mul_2exp(T, -1, BF_PREC_INF, BF_RNDZ);
- T->sign = (i < 0);
- bf_add(r, T, r, prec1, BF_RNDN);
- }
- bf_delete(T);
- return BF_ST_INEXACT;
- }
- int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
- {
- bf_context_t *s = r->ctx;
- bf_t T_s, *T = &T_s;
- int res;
- if (a->len == 0) {
- if (a->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- return 0;
- } else if (a->expn == BF_EXP_INF) {
- /* -PI/2 or PI/2 */
- bf_const_pi_signed(r, a->sign, prec, flags);
- bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);
- return BF_ST_INEXACT;
- } else {
- bf_set_zero(r, a->sign);
- return 0;
- }
- }
- bf_init(s, T);
- bf_set_ui(T, 1);
- res = bf_cmpu(a, T);
- bf_delete(T);
- if (res == 0) {
- /* short cut: abs(a) == 1 -> +/-pi/4 */
- bf_const_pi_signed(r, a->sign, prec, flags);
- bf_mul_2exp(r, -2, BF_PREC_INF, BF_RNDZ);
- return BF_ST_INEXACT;
- }
- /* small argument case: result = x+r(x) with r(x) = -x^3/3 +
- O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */
- if (a->expn < 0) {
- slimb_t e;
- e = sat_add(2 * a->expn, a->expn - 1);
- if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
- bf_set(r, a);
- return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags);
- }
- }
- return bf_ziv_rounding(r, a, prec, flags, bf_atan_internal, (void *)false);
- }
- static int bf_atan2_internal(bf_t *r, const bf_t *y, limb_t prec, void *opaque)
- {
- bf_context_t *s = r->ctx;
- const bf_t *x = opaque;
- bf_t T_s, *T = &T_s;
- limb_t prec1;
- int ret;
- if (y->expn == BF_EXP_NAN || x->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- return 0;
- }
- /* compute atan(y/x) assumming inf/inf = 1 and 0/0 = 0 */
- bf_init(s, T);
- prec1 = prec + 32;
- if (y->expn == BF_EXP_INF && x->expn == BF_EXP_INF) {
- bf_set_ui(T, 1);
- T->sign = y->sign ^ x->sign;
- } else if (y->expn == BF_EXP_ZERO && x->expn == BF_EXP_ZERO) {
- bf_set_zero(T, y->sign ^ x->sign);
- } else {
- bf_div(T, y, x, prec1, BF_RNDF);
- }
- ret = bf_atan(r, T, prec1, BF_RNDF);
- if (x->sign) {
- /* if x < 0 (it includes -0), return sign(y)*pi + atan(y/x) */
- bf_const_pi(T, prec1, BF_RNDF);
- T->sign = y->sign;
- bf_add(r, r, T, prec1, BF_RNDN);
- ret |= BF_ST_INEXACT;
- }
- bf_delete(T);
- return ret;
- }
- int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,
- limb_t prec, bf_flags_t flags)
- {
- return bf_ziv_rounding(r, y, prec, flags, bf_atan2_internal, (void *)x);
- }
- static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
- {
- bf_context_t *s = r->ctx;
- bool is_acos = (bool)(intptr_t)opaque;
- bf_t T_s, *T = &T_s;
- limb_t prec1, prec2;
- /* asin(x) = atan(x/sqrt(1-x^2))
- acos(x) = pi/2 - asin(x) */
- prec1 = prec + 8;
- /* increase the precision in x^2 to compensate the cancellation in
- (1-x^2) if x is close to 1 */
- /* XXX: use less precision when possible */
- if (a->expn >= 0)
- prec2 = BF_PREC_INF;
- else
- prec2 = prec1;
- bf_init(s, T);
- bf_mul(T, a, a, prec2, BF_RNDN);
- bf_neg(T);
- bf_add_si(T, T, 1, prec2, BF_RNDN);
- bf_sqrt(r, T, prec1, BF_RNDN);
- bf_div(T, a, r, prec1, BF_RNDN);
- if (is_acos)
- bf_neg(T);
- bf_atan_internal(r, T, prec1, (void *)(intptr_t)is_acos);
- bf_delete(T);
- return BF_ST_INEXACT;
- }
- int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
- {
- bf_context_t *s = r->ctx;
- bf_t T_s, *T = &T_s;
- int res;
- if (a->len == 0) {
- if (a->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- return 0;
- } else if (a->expn == BF_EXP_INF) {
- bf_set_nan(r);
- return BF_ST_INVALID_OP;
- } else {
- bf_set_zero(r, a->sign);
- return 0;
- }
- }
- bf_init(s, T);
- bf_set_ui(T, 1);
- res = bf_cmpu(a, T);
- bf_delete(T);
- if (res > 0) {
- bf_set_nan(r);
- return BF_ST_INVALID_OP;
- }
- /* small argument case: result = x+r(x) with r(x) = x^3/6 +
- O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */
- if (a->expn < 0) {
- slimb_t e;
- e = sat_add(2 * a->expn, a->expn - 2);
- if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
- bf_set(r, a);
- return bf_add_epsilon(r, r, e, a->sign, prec, flags);
- }
- }
- return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)false);
- }
- int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
- {
- bf_context_t *s = r->ctx;
- bf_t T_s, *T = &T_s;
- int res;
- if (a->len == 0) {
- if (a->expn == BF_EXP_NAN) {
- bf_set_nan(r);
- return 0;
- } else if (a->expn == BF_EXP_INF) {
- bf_set_nan(r);
- return BF_ST_INVALID_OP;
- } else {
- bf_const_pi(r, prec, flags);
- bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);
- return BF_ST_INEXACT;
- }
- }
- bf_init(s, T);
- bf_set_ui(T, 1);
- res = bf_cmpu(a, T);
- bf_delete(T);
- if (res > 0) {
- bf_set_nan(r);
- return BF_ST_INVALID_OP;
- } else if (res == 0 && a->sign == 0) {
- bf_set_zero(r, 0);
- return 0;
- }
- return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)true);
- }
- /***************************************************************/
- /* decimal floating point numbers */
- #ifdef USE_BF_DEC
- #define adddq(r1, r0, a1, a0) \
- do { \
- limb_t __t = r0; \
- r0 += (a0); \
- r1 += (a1) + (r0 < __t); \
- } while (0)
- #define subdq(r1, r0, a1, a0) \
- do { \
- limb_t __t = r0; \
- r0 -= (a0); \
- r1 -= (a1) + (r0 > __t); \
- } while (0)
- #if LIMB_BITS == 64
- /* Note: we assume __int128 is available */
- /* uint128_t defined in libbf.h */
- #define muldq(r1, r0, a, b) \
- do { \
- uint128_t __t; \
- __t = (uint128_t)(a) * (uint128_t)(b); \
- r0 = __t; \
- r1 = __t >> 64; \
- } while (0)
- #define divdq(q, r, a1, a0, b) \
- do { \
- uint128_t __t; \
- limb_t __b = (b); \
- __t = ((uint128_t)(a1) << 64) | (a0); \
- q = __t / __b; \
- r = __t % __b; \
- } while (0)
- #else
- #define muldq(r1, r0, a, b) \
- do { \
- uint64_t __t; \
- __t = (uint64_t)(a) * (uint64_t)(b); \
- r0 = __t; \
- r1 = __t >> 32; \
- } while (0)
- #define divdq(q, r, a1, a0, b) \
- do { \
- uint64_t __t; \
- limb_t __b = (b); \
- __t = ((uint64_t)(a1) << 32) | (a0); \
- q = __t / __b; \
- r = __t % __b; \
- } while (0)
- #endif /* LIMB_BITS != 64 */
- #if LIMB_DIGITS == 19
- /* WARNING: hardcoded for b = 1e19. It is assumed that:
- 0 <= a1 < 2^63 */
- #define divdq_base(q, r, a1, a0)\
- do {\
- uint64_t __a0, __a1, __t0, __t1, __b = BF_DEC_BASE; \
- __a0 = a0;\
- __a1 = a1;\
- __t0 = __a1;\
- __t0 = shld(__t0, __a0, 1);\
- muldq(q, __t1, __t0, UINT64_C(17014118346046923173)); \
- muldq(__t1, __t0, q, __b);\
- subdq(__a1, __a0, __t1, __t0);\
- subdq(__a1, __a0, 1, __b * 2); \
- __t0 = (slimb_t)__a1 >> 1; \
- q += 2 + __t0;\
- adddq(__a1, __a0, 0, __b & __t0);\
- q += __a1; \
- __a0 += __b & __a1; \
- r = __a0;\
- } while(0)
- #elif LIMB_DIGITS == 9
- /* WARNING: hardcoded for b = 1e9. It is assumed that:
- 0 <= a1 < 2^29 */
- #define divdq_base(q, r, a1, a0)\
- do {\
- uint32_t __t0, __t1, __b = BF_DEC_BASE; \
- __t0 = a1;\
- __t1 = a0;\
- __t0 = (__t0 << 3) | (__t1 >> (32 - 3)); \
- muldq(q, __t1, __t0, 2305843009U);\
- r = a0 - q * __b;\
- __t1 = (r >= __b);\
- q += __t1;\
- if (__t1)\
- r -= __b;\
- } while(0)
- #endif
- /* fast integer division by a fixed constant */
- typedef struct FastDivData {
- limb_t m1; /* multiplier */
- int8_t shift1;
- int8_t shift2;
- } FastDivData;
- /* From "Division by Invariant Integers using Multiplication" by
- Torborn Granlund and Peter L. Montgomery */
- /* d must be != 0 */
- static inline __maybe_unused void fast_udiv_init(FastDivData *s, limb_t d)
- {
- int l;
- limb_t q, r, m1;
- if (d == 1)
- l = 0;
- else
- l = 64 - clz64(d - 1);
- divdq(q, r, ((limb_t)1 << l) - d, 0, d);
- (void)r;
- m1 = q + 1;
- // printf("d=%lu l=%d m1=0x%016lx\n", d, l, m1);
- s->m1 = m1;
- s->shift1 = l;
- if (s->shift1 > 1)
- s->shift1 = 1;
- s->shift2 = l - 1;
- if (s->shift2 < 0)
- s->shift2 = 0;
- }
- static inline limb_t fast_udiv(limb_t a, const FastDivData *s)
- {
- limb_t t0, t1;
- muldq(t1, t0, s->m1, a);
- t0 = (a - t1) >> s->shift1;
- return (t1 + t0) >> s->shift2;
- }
- /* contains 10^i */
- const limb_t mp_pow_dec[LIMB_DIGITS + 1] = {
- 1U,
- 10U,
- 100U,
- 1000U,
- 10000U,
- 100000U,
- 1000000U,
- 10000000U,
- 100000000U,
- 1000000000U,
- #if LIMB_BITS == 64
- 10000000000U,
- 100000000000U,
- 1000000000000U,
- 10000000000000U,
- 100000000000000U,
- 1000000000000000U,
- 10000000000000000U,
- 100000000000000000U,
- 1000000000000000000U,
- 10000000000000000000U,
- #endif
- };
- /* precomputed from fast_udiv_init(10^i) */
- static const FastDivData mp_pow_div[LIMB_DIGITS + 1] = {
- #if LIMB_BITS == 32
- { 0x00000001, 0, 0 },
- { 0x9999999a, 1, 3 },
- { 0x47ae147b, 1, 6 },
- { 0x0624dd30, 1, 9 },
- { 0xa36e2eb2, 1, 13 },
- { 0x4f8b588f, 1, 16 },
- { 0x0c6f7a0c, 1, 19 },
- { 0xad7f29ac, 1, 23 },
- { 0x5798ee24, 1, 26 },
- { 0x12e0be83, 1, 29 },
- #else
- { 0x0000000000000001, 0, 0 },
- { 0x999999999999999a, 1, 3 },
- { 0x47ae147ae147ae15, 1, 6 },
- { 0x0624dd2f1a9fbe77, 1, 9 },
- { 0xa36e2eb1c432ca58, 1, 13 },
- { 0x4f8b588e368f0847, 1, 16 },
- { 0x0c6f7a0b5ed8d36c, 1, 19 },
- { 0xad7f29abcaf48579, 1, 23 },
- { 0x5798ee2308c39dfa, 1, 26 },
- { 0x12e0be826d694b2f, 1, 29 },
- { 0xb7cdfd9d7bdbab7e, 1, 33 },
- { 0x5fd7fe17964955fe, 1, 36 },
- { 0x19799812dea11198, 1, 39 },
- { 0xc25c268497681c27, 1, 43 },
- { 0x6849b86a12b9b01f, 1, 46 },
- { 0x203af9ee756159b3, 1, 49 },
- { 0xcd2b297d889bc2b7, 1, 53 },
- { 0x70ef54646d496893, 1, 56 },
- { 0x2725dd1d243aba0f, 1, 59 },
- { 0xd83c94fb6d2ac34d, 1, 63 },
- #endif
- };
- /* divide by 10^shift with 0 <= shift <= LIMB_DIGITS */
- static inline limb_t fast_shr_dec(limb_t a, int shift)
- {
- return fast_udiv(a, &mp_pow_div[shift]);
- }
- /* division and remainder by 10^shift */
- #define fast_shr_rem_dec(q, r, a, shift) q = fast_shr_dec(a, shift), r = a - q * mp_pow_dec[shift]
- limb_t mp_add_dec(limb_t *res, const limb_t *op1, const limb_t *op2,
- mp_size_t n, limb_t carry)
- {
- limb_t base = BF_DEC_BASE;
- mp_size_t i;
- limb_t k, a, v;
- k=carry;
- for(i=0;i<n;i++) {
- /* XXX: reuse the trick in add_mod */
- v = op1[i];
- a = v + op2[i] + k - base;
- k = a <= v;
- if (!k)
- a += base;
- res[i]=a;
- }
- return k;
- }
- limb_t mp_add_ui_dec(limb_t *tab, limb_t b, mp_size_t n)
- {
- limb_t base = BF_DEC_BASE;
- mp_size_t i;
- limb_t k, a, v;
- k=b;
- for(i=0;i<n;i++) {
- v = tab[i];
- a = v + k - base;
- k = a <= v;
- if (!k)
- a += base;
- tab[i] = a;
- if (k == 0)
- break;
- }
- return k;
- }
- limb_t mp_sub_dec(limb_t *res, const limb_t *op1, const limb_t *op2,
- mp_size_t n, limb_t carry)
- {
- limb_t base = BF_DEC_BASE;
- mp_size_t i;
- limb_t k, v, a;
- k=carry;
- for(i=0;i<n;i++) {
- v = op1[i];
- a = v - op2[i] - k;
- k = a > v;
- if (k)
- a += base;
- res[i] = a;
- }
- return k;
- }
- limb_t mp_sub_ui_dec(limb_t *tab, limb_t b, mp_size_t n)
- {
- limb_t base = BF_DEC_BASE;
- mp_size_t i;
- limb_t k, v, a;
- k=b;
- for(i=0;i<n;i++) {
- v = tab[i];
- a = v - k;
- k = a > v;
- if (k)
- a += base;
- tab[i]=a;
- if (k == 0)
- break;
- }
- return k;
- }
- /* taba[] = taba[] * b + l. 0 <= b, l <= base - 1. Return the high carry */
- limb_t mp_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n,
- limb_t b, limb_t l)
- {
- mp_size_t i;
- limb_t t0, t1, r;
- for(i = 0; i < n; i++) {
- muldq(t1, t0, taba[i], b);
- adddq(t1, t0, 0, l);
- divdq_base(l, r, t1, t0);
- tabr[i] = r;
- }
- return l;
- }
- /* tabr[] += taba[] * b. 0 <= b <= base - 1. Return the value to add
- to the high word */
- limb_t mp_add_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n,
- limb_t b)
- {
- mp_size_t i;
- limb_t l, t0, t1, r;
- l = 0;
- for(i = 0; i < n; i++) {
- muldq(t1, t0, taba[i], b);
- adddq(t1, t0, 0, l);
- adddq(t1, t0, 0, tabr[i]);
- divdq_base(l, r, t1, t0);
- tabr[i] = r;
- }
- return l;
- }
- /* tabr[] -= taba[] * b. 0 <= b <= base - 1. Return the value to
- substract to the high word. */
- limb_t mp_sub_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n,
- limb_t b)
- {
- limb_t base = BF_DEC_BASE;
- mp_size_t i;
- limb_t l, t0, t1, r, a, v, c;
- /* XXX: optimize */
- l = 0;
- for(i = 0; i < n; i++) {
- muldq(t1, t0, taba[i], b);
- adddq(t1, t0, 0, l);
- divdq_base(l, r, t1, t0);
- v = tabr[i];
- a = v - r;
- c = a > v;
- if (c)
- a += base;
- /* never bigger than base because r = 0 when l = base - 1 */
- l += c;
- tabr[i] = a;
- }
- return l;
- }
- /* size of the result : op1_size + op2_size. */
- void mp_mul_basecase_dec(limb_t *result,
- const limb_t *op1, mp_size_t op1_size,
- const limb_t *op2, mp_size_t op2_size)
- {
- mp_size_t i;
- limb_t r;
- result[op1_size] = mp_mul1_dec(result, op1, op1_size, op2[0], 0);
- for(i=1;i<op2_size;i++) {
- r = mp_add_mul1_dec(result + i, op1, op1_size, op2[i]);
- result[i + op1_size] = r;
- }
- }
- /* taba[] = (taba[] + r*base^na) / b. 0 <= b < base. 0 <= r <
- b. Return the remainder. */
- limb_t mp_div1_dec(limb_t *tabr, const limb_t *taba, mp_size_t na,
- limb_t b, limb_t r)
- {
- limb_t base = BF_DEC_BASE;
- mp_size_t i;
- limb_t t0, t1, q;
- int shift;
- #if (BF_DEC_BASE % 2) == 0
- if (b == 2) {
- limb_t base_div2;
- /* Note: only works if base is even */
- base_div2 = base >> 1;
- if (r)
- r = base_div2;
- for(i = na - 1; i >= 0; i--) {
- t0 = taba[i];
- tabr[i] = (t0 >> 1) + r;
- r = 0;
- if (t0 & 1)
- r = base_div2;
- }
- if (r)
- r = 1;
- } else
- #endif
- if (na >= UDIV1NORM_THRESHOLD) {
- shift = clz(b);
- if (shift == 0) {
- /* normalized case: b >= 2^(LIMB_BITS-1) */
- limb_t b_inv;
- b_inv = udiv1norm_init(b);
- for(i = na - 1; i >= 0; i--) {
- muldq(t1, t0, r, base);
- adddq(t1, t0, 0, taba[i]);
- q = udiv1norm(&r, t1, t0, b, b_inv);
- tabr[i] = q;
- }
- } else {
- limb_t b_inv;
- b <<= shift;
- b_inv = udiv1norm_init(b);
- for(i = na - 1; i >= 0; i--) {
- muldq(t1, t0, r, base);
- adddq(t1, t0, 0, taba[i]);
- t1 = (t1 << shift) | (t0 >> (LIMB_BITS - shift));
- t0 <<= shift;
- q = udiv1norm(&r, t1, t0, b, b_inv);
- r >>= shift;
- tabr[i] = q;
- }
- }
- } else {
- for(i = na - 1; i >= 0; i--) {
- muldq(t1, t0, r, base);
- adddq(t1, t0, 0, taba[i]);
- divdq(q, r, t1, t0, b);
- tabr[i] = q;
- }
- }
- return r;
- }
- static __maybe_unused void mp_print_str_dec(const char *str,
- const limb_t *tab, slimb_t n)
- {
- slimb_t i;
- printf("%s=", str);
- for(i = n - 1; i >= 0; i--) {
- if (i != n - 1)
- printf("_");
- printf("%0*" PRIu_LIMB, LIMB_DIGITS, tab[i]);
- }
- printf("\n");
- }
- static __maybe_unused void mp_print_str_h_dec(const char *str,
- const limb_t *tab, slimb_t n,
- limb_t high)
- {
- slimb_t i;
- printf("%s=", str);
- printf("%0*" PRIu_LIMB, LIMB_DIGITS, high);
- for(i = n - 1; i >= 0; i--) {
- printf("_");
- printf("%0*" PRIu_LIMB, LIMB_DIGITS, tab[i]);
- }
- printf("\n");
- }
- //#define DEBUG_DIV_SLOW
- #define DIV_STATIC_ALLOC_LEN 16
- /* return q = a / b and r = a % b.
- taba[na] must be allocated if tabb1[nb - 1] < B / 2. tabb1[nb - 1]
- must be != zero. na must be >= nb. 's' can be NULL if tabb1[nb - 1]
- >= B / 2.
- The remainder is is returned in taba and contains nb libms. tabq
- contains na - nb + 1 limbs. No overlap is permitted.
- Running time of the standard method: (na - nb + 1) * nb
- Return 0 if OK, -1 if memory alloc error
- */
- /* XXX: optimize */
- static int mp_div_dec(bf_context_t *s, limb_t *tabq,
- limb_t *taba, mp_size_t na,
- const limb_t *tabb1, mp_size_t nb)
- {
- limb_t base = BF_DEC_BASE;
- limb_t r, mult, t0, t1, a, c, q, v, *tabb;
- mp_size_t i, j;
- limb_t static_tabb[DIV_STATIC_ALLOC_LEN];
- #ifdef DEBUG_DIV_SLOW
- mp_print_str_dec("a", taba, na);
- mp_print_str_dec("b", tabb1, nb);
- #endif
- /* normalize tabb */
- r = tabb1[nb - 1];
- assert(r != 0);
- i = na - nb;
- if (r >= BF_DEC_BASE / 2) {
- mult = 1;
- tabb = (limb_t *)tabb1;
- q = 1;
- for(j = nb - 1; j >= 0; j--) {
- if (taba[i + j] != tabb[j]) {
- if (taba[i + j] < tabb[j])
- q = 0;
- break;
- }
- }
- tabq[i] = q;
- if (q) {
- mp_sub_dec(taba + i, taba + i, tabb, nb, 0);
- }
- i--;
- } else {
- mult = base / (r + 1);
- if (likely(nb <= DIV_STATIC_ALLOC_LEN)) {
- tabb = static_tabb;
- } else {
- tabb = bf_malloc(s, sizeof(limb_t) * nb);
- if (!tabb)
- return -1;
- }
- mp_mul1_dec(tabb, tabb1, nb, mult, 0);
- taba[na] = mp_mul1_dec(taba, taba, na, mult, 0);
- }
- #ifdef DEBUG_DIV_SLOW
- printf("mult=" FMT_LIMB "\n", mult);
- mp_print_str_dec("a_norm", taba, na + 1);
- mp_print_str_dec("b_norm", tabb, nb);
- #endif
- for(; i >= 0; i--) {
- if (unlikely(taba[i + nb] >= tabb[nb - 1])) {
- /* XXX: check if it is really possible */
- q = base - 1;
- } else {
- muldq(t1, t0, taba[i + nb], base);
- adddq(t1, t0, 0, taba[i + nb - 1]);
- divdq(q, r, t1, t0, tabb[nb - 1]);
- }
- // printf("i=%d q1=%ld\n", i, q);
- r = mp_sub_mul1_dec(taba + i, tabb, nb, q);
- // mp_dump("r1", taba + i, nb, bd);
- // printf("r2=%ld\n", r);
- v = taba[i + nb];
- a = v - r;
- c = a > v;
- if (c)
- a += base;
- taba[i + nb] = a;
- if (c != 0) {
- /* negative result */
- for(;;) {
- q--;
- c = mp_add_dec(taba + i, taba + i, tabb, nb, 0);
- /* propagate carry and test if positive result */
- if (c != 0) {
- if (++taba[i + nb] == base) {
- break;
- }
- }
- }
- }
- tabq[i] = q;
- }
- #ifdef DEBUG_DIV_SLOW
- mp_print_str_dec("q", tabq, na - nb + 1);
- mp_print_str_dec("r", taba, nb);
- #endif
- /* remove the normalization */
- if (mult != 1) {
- mp_div1_dec(taba, taba, nb, mult, 0);
- if (unlikely(tabb != static_tabb))
- bf_free(s, tabb);
- }
- return 0;
- }
- /* divide by 10^shift */
- static limb_t mp_shr_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n,
- limb_t shift, limb_t high)
- {
- mp_size_t i;
- limb_t l, a, q, r;
- assert(shift >= 1 && shift < LIMB_DIGITS);
- l = high;
- for(i = n - 1; i >= 0; i--) {
- a = tab[i];
- fast_shr_rem_dec(q, r, a, shift);
- tab_r[i] = q + l * mp_pow_dec[LIMB_DIGITS - shift];
- l = r;
- }
- return l;
- }
- /* multiply by 10^shift */
- static limb_t mp_shl_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n,
- limb_t shift, limb_t low)
- {
- mp_size_t i;
- limb_t l, a, q, r;
- assert(shift >= 1 && shift < LIMB_DIGITS);
- l = low;
- for(i = 0; i < n; i++) {
- a = tab[i];
- fast_shr_rem_dec(q, r, a, LIMB_DIGITS - shift);
- tab_r[i] = r * mp_pow_dec[shift] + l;
- l = q;
- }
- return l;
- }
- static limb_t mp_sqrtrem2_dec(limb_t *tabs, limb_t *taba)
- {
- int k;
- dlimb_t a, b, r;
- limb_t taba1[2], s, r0, r1;
- /* convert to binary and normalize */
- a = (dlimb_t)taba[1] * BF_DEC_BASE + taba[0];
- k = clz(a >> LIMB_BITS) & ~1;
- b = a << k;
- taba1[0] = b;
- taba1[1] = b >> LIMB_BITS;
- mp_sqrtrem2(&s, taba1);
- s >>= (k >> 1);
- /* convert the remainder back to decimal */
- r = a - (dlimb_t)s * (dlimb_t)s;
- divdq_base(r1, r0, r >> LIMB_BITS, r);
- taba[0] = r0;
- tabs[0] = s;
- return r1;
- }
- //#define DEBUG_SQRTREM_DEC
- /* tmp_buf must contain (n / 2 + 1 limbs) */
- static limb_t mp_sqrtrem_rec_dec(limb_t *tabs, limb_t *taba, limb_t n,
- limb_t *tmp_buf)
- {
- limb_t l, h, rh, ql, qh, c, i;
- if (n == 1)
- return mp_sqrtrem2_dec(tabs, taba);
- #ifdef DEBUG_SQRTREM_DEC
- mp_print_str_dec("a", taba, 2 * n);
- #endif
- l = n / 2;
- h = n - l;
- qh = mp_sqrtrem_rec_dec(tabs + l, taba + 2 * l, h, tmp_buf);
- #ifdef DEBUG_SQRTREM_DEC
- mp_print_str_dec("s1", tabs + l, h);
- mp_print_str_h_dec("r1", taba + 2 * l, h, qh);
- mp_print_str_h_dec("r2", taba + l, n, qh);
- #endif
- /* the remainder is in taba + 2 * l. Its high bit is in qh */
- if (qh) {
- mp_sub_dec(taba + 2 * l, taba + 2 * l, tabs + l, h, 0);
- }
- /* instead of dividing by 2*s, divide by s (which is normalized)
- and update q and r */
- mp_div_dec(NULL, tmp_buf, taba + l, n, tabs + l, h);
- qh += tmp_buf[l];
- for(i = 0; i < l; i++)
- tabs[i] = tmp_buf[i];
- ql = mp_div1_dec(tabs, tabs, l, 2, qh & 1);
- qh = qh >> 1; /* 0 or 1 */
- if (ql)
- rh = mp_add_dec(taba + l, taba + l, tabs + l, h, 0);
- else
- rh = 0;
- #ifdef DEBUG_SQRTREM_DEC
- mp_print_str_h_dec("q", tabs, l, qh);
- mp_print_str_h_dec("u", taba + l, h, rh);
- #endif
- mp_add_ui_dec(tabs + l, qh, h);
- #ifdef DEBUG_SQRTREM_DEC
- mp_print_str_dec("s2", tabs, n);
- #endif
- /* q = qh, tabs[l - 1 ... 0], r = taba[n - 1 ... l] */
- /* subtract q^2. if qh = 1 then q = B^l, so we can take shortcuts */
- if (qh) {
- c = qh;
- } else {
- mp_mul_basecase_dec(taba + n, tabs, l, tabs, l);
- c = mp_sub_dec(taba, taba, taba + n, 2 * l, 0);
- }
- rh -= mp_sub_ui_dec(taba + 2 * l, c, n - 2 * l);
- if ((slimb_t)rh < 0) {
- mp_sub_ui_dec(tabs, 1, n);
- rh += mp_add_mul1_dec(taba, tabs, n, 2);
- rh += mp_add_ui_dec(taba, 1, n);
- }
- return rh;
- }
- /* 'taba' has 2*n limbs with n >= 1 and taba[2*n-1] >= B/4. Return (s,
- r) with s=floor(sqrt(a)) and r=a-s^2. 0 <= r <= 2 * s. tabs has n
- limbs. r is returned in the lower n limbs of taba. Its r[n] is the
- returned value of the function. */
- int mp_sqrtrem_dec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n)
- {
- limb_t tmp_buf1[8];
- limb_t *tmp_buf;
- mp_size_t n2;
- n2 = n / 2 + 1;
- if (n2 <= countof(tmp_buf1)) {
- tmp_buf = tmp_buf1;
- } else {
- tmp_buf = bf_malloc(s, sizeof(limb_t) * n2);
- if (!tmp_buf)
- return -1;
- }
- taba[n] = mp_sqrtrem_rec_dec(tabs, taba, n, tmp_buf);
- if (tmp_buf != tmp_buf1)
- bf_free(s, tmp_buf);
- return 0;
- }
- /* return the number of leading zero digits, from 0 to LIMB_DIGITS */
- static int clz_dec(limb_t a)
- {
- if (a == 0)
- return LIMB_DIGITS;
- switch(LIMB_BITS - 1 - clz(a)) {
- case 0: /* 1-1 */
- return LIMB_DIGITS - 1;
- case 1: /* 2-3 */
- return LIMB_DIGITS - 1;
- case 2: /* 4-7 */
- return LIMB_DIGITS - 1;
- case 3: /* 8-15 */
- if (a < 10)
- return LIMB_DIGITS - 1;
- else
- return LIMB_DIGITS - 2;
- case 4: /* 16-31 */
- return LIMB_DIGITS - 2;
- case 5: /* 32-63 */
- return LIMB_DIGITS - 2;
- case 6: /* 64-127 */
- if (a < 100)
- return LIMB_DIGITS - 2;
- else
- return LIMB_DIGITS - 3;
- case 7: /* 128-255 */
- return LIMB_DIGITS - 3;
- case 8: /* 256-511 */
- return LIMB_DIGITS - 3;
- case 9: /* 512-1023 */
- if (a < 1000)
- return LIMB_DIGITS - 3;
- else
- return LIMB_DIGITS - 4;
- case 10: /* 1024-2047 */
- return LIMB_DIGITS - 4;
- case 11: /* 2048-4095 */
- return LIMB_DIGITS - 4;
- case 12: /* 4096-8191 */
- return LIMB_DIGITS - 4;
- case 13: /* 8192-16383 */
- if (a < 10000)
- return LIMB_DIGITS - 4;
- else
- return LIMB_DIGITS - 5;
- case 14: /* 16384-32767 */
- return LIMB_DIGITS - 5;
- case 15: /* 32768-65535 */
- return LIMB_DIGITS - 5;
- case 16: /* 65536-131071 */
- if (a < 100000)
- return LIMB_DIGITS - 5;
- else
- return LIMB_DIGITS - 6;
- case 17: /* 131072-262143 */
- return LIMB_DIGITS - 6;
- case 18: /* 262144-524287 */
- return LIMB_DIGITS - 6;
- case 19: /* 524288-1048575 */
- if (a < 1000000)
- return LIMB_DIGITS - 6;
- else
- return LIMB_DIGITS - 7;
- case 20: /* 1048576-2097151 */
- return LIMB_DIGITS - 7;
- case 21: /* 2097152-4194303 */
- return LIMB_DIGITS - 7;
- case 22: /* 4194304-8388607 */
- return LIMB_DIGITS - 7;
- case 23: /* 8388608-16777215 */
- if (a < 10000000)
- return LIMB_DIGITS - 7;
- else
- return LIMB_DIGITS - 8;
- case 24: /* 16777216-33554431 */
- return LIMB_DIGITS - 8;
- case 25: /* 33554432-67108863 */
- return LIMB_DIGITS - 8;
- case 26: /* 67108864-134217727 */
- if (a < 100000000)
- return LIMB_DIGITS - 8;
- else
- return LIMB_DIGITS - 9;
- #if LIMB_BITS == 64
- case 27: /* 134217728-268435455 */
- return LIMB_DIGITS - 9;
- case 28: /* 268435456-536870911 */
- return LIMB_DIGITS - 9;
- case 29: /* 536870912-1073741823 */
- if (a < 1000000000)
- return LIMB_DIGITS - 9;
- else
- return LIMB_DIGITS - 10;
- case 30: /* 1073741824-2147483647 */
- return LIMB_DIGITS - 10;
- case 31: /* 2147483648-4294967295 */
- return LIMB_DIGITS - 10;
- case 32: /* 4294967296-8589934591 */
- return LIMB_DIGITS - 10;
- case 33: /* 8589934592-17179869183 */
- if (a < 10000000000)
- return LIMB_DIGITS - 10;
- else
- return LIMB_DIGITS - 11;
- case 34: /* 17179869184-34359738367 */
- return LIMB_DIGITS - 11;
- case 35: /* 34359738368-68719476735 */
- return LIMB_DIGITS - 11;
- case 36: /* 68719476736-137438953471 */
- if (a < 100000000000)
- return LIMB_DIGITS - 11;
- else
- return LIMB_DIGITS - 12;
- case 37: /* 137438953472-274877906943 */
- return LIMB_DIGITS - 12;
- case 38: /* 274877906944-549755813887 */
- return LIMB_DIGITS - 12;
- case 39: /* 549755813888-1099511627775 */
- if (a < 1000000000000)
- return LIMB_DIGITS - 12;
- else
- return LIMB_DIGITS - 13;
- case 40: /* 1099511627776-2199023255551 */
- return LIMB_DIGITS - 13;
- case 41: /* 2199023255552-4398046511103 */
- return LIMB_DIGITS - 13;
- case 42: /* 4398046511104-8796093022207 */
- return LIMB_DIGITS - 13;
- case 43: /* 8796093022208-17592186044415 */
- if (a < 10000000000000)
- return LIMB_DIGITS - 13;
- else
- return LIMB_DIGITS - 14;
- case 44: /* 17592186044416-35184372088831 */
- return LIMB_DIGITS - 14;
- case 45: /* 35184372088832-70368744177663 */
- return LIMB_DIGITS - 14;
- case 46: /* 70368744177664-140737488355327 */
- if (a < 100000000000000)
- return LIMB_DIGITS - 14;
- else
- return LIMB_DIGITS - 15;
- case 47: /* 140737488355328-281474976710655 */
- return LIMB_DIGITS - 15;
- case 48: /* 281474976710656-562949953421311 */
- return LIMB_DIGITS - 15;
- case 49: /* 562949953421312-1125899906842623 */
- if (a < 1000000000000000)
- return LIMB_DIGITS - 15;
- else
- return LIMB_DIGITS - 16;
- case 50: /* 1125899906842624-2251799813685247 */
- return LIMB_DIGITS - 16;
- case 51: /* 2251799813685248-4503599627370495 */
- return LIMB_DIGITS - 16;
- case 52: /* 4503599627370496-9007199254740991 */
- return LIMB_DIGITS - 16;
- case 53: /* 9007199254740992-18014398509481983 */
- if (a < 10000000000000000)
- return LIMB_DIGITS - 16;
- else
- return LIMB_DIGITS - 17;
- case 54: /* 18014398509481984-36028797018963967 */
- return LIMB_DIGITS - 17;
- case 55: /* 36028797018963968-72057594037927935 */
- return LIMB_DIGITS - 17;
- case 56: /* 72057594037927936-144115188075855871 */
- if (a < 100000000000000000)
- return LIMB_DIGITS - 17;
- else
- return LIMB_DIGITS - 18;
- case 57: /* 144115188075855872-288230376151711743 */
- return LIMB_DIGITS - 18;
- case 58: /* 288230376151711744-576460752303423487 */
- return LIMB_DIGITS - 18;
- case 59: /* 576460752303423488-1152921504606846975 */
- if (a < 1000000000000000000)
- return LIMB_DIGITS - 18;
- else
- return LIMB_DIGITS - 19;
- #endif
- default:
- return 0;
- }
- }
- /* for debugging */
- void bfdec_print_str(const char *str, const bfdec_t *a)
- {
- slimb_t i;
- printf("%s=", str);
- if (a->expn == BF_EXP_NAN) {
- printf("NaN");
- } else {
- if (a->sign)
- putchar('-');
- if (a->expn == BF_EXP_ZERO) {
- putchar('0');
- } else if (a->expn == BF_EXP_INF) {
- printf("Inf");
- } else {
- printf("0.");
- for(i = a->len - 1; i >= 0; i--)
- printf("%0*" PRIu_LIMB, LIMB_DIGITS, a->tab[i]);
- printf("e%" PRId_LIMB, a->expn);
- }
- }
- printf("\n");
- }
- /* return != 0 if one digit between 0 and bit_pos inclusive is not zero. */
- static inline limb_t scan_digit_nz(const bfdec_t *r, slimb_t bit_pos)
- {
- slimb_t pos;
- limb_t v, q;
- int shift;
- if (bit_pos < 0)
- return 0;
- pos = (limb_t)bit_pos / LIMB_DIGITS;
- shift = (limb_t)bit_pos % LIMB_DIGITS;
- fast_shr_rem_dec(q, v, r->tab[pos], shift + 1);
- (void)q;
- if (v != 0)
- return 1;
- pos--;
- while (pos >= 0) {
- if (r->tab[pos] != 0)
- return 1;
- pos--;
- }
- return 0;
- }
- static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos)
- {
- slimb_t i;
- int shift;
- i = floor_div(pos, LIMB_DIGITS);
- if (i < 0 || i >= len)
- return 0;
- shift = pos - i * LIMB_DIGITS;
- return fast_shr_dec(tab[i], shift) % 10;
- }
- /* return the addend for rounding. Note that prec can be <= 0 for bf_rint() */
- static int bfdec_get_rnd_add(int *pret, const bfdec_t *r, limb_t l,
- slimb_t prec, int rnd_mode)
- {
- int add_one, inexact;
- limb_t digit1, digit0;
- // bfdec_print_str("get_rnd_add", r);
- if (rnd_mode == BF_RNDF) {
- digit0 = 1; /* faithful rounding does not honor the INEXACT flag */
- } else {
- /* starting limb for bit 'prec + 1' */
- digit0 = scan_digit_nz(r, l * LIMB_DIGITS - 1 - bf_max(0, prec + 1));
- }
- /* get the digit at 'prec' */
- digit1 = get_digit(r->tab, l, l * LIMB_DIGITS - 1 - prec);
- inexact = (digit1 | digit0) != 0;
- add_one = 0;
- switch(rnd_mode) {
- case BF_RNDZ:
- break;
- case BF_RNDN:
- if (digit1 == 5) {
- if (digit0) {
- add_one = 1;
- } else {
- /* round to even */
- add_one =
- get_digit(r->tab, l, l * LIMB_DIGITS - 1 - (prec - 1)) & 1;
- }
- } else if (digit1 > 5) {
- add_one = 1;
- }
- break;
- case BF_RNDD:
- case BF_RNDU:
- if (r->sign == (rnd_mode == BF_RNDD))
- add_one = inexact;
- break;
- case BF_RNDNA:
- case BF_RNDF:
- add_one = (digit1 >= 5);
- break;
- case BF_RNDA:
- add_one = inexact;
- break;
- default:
- abort();
- }
- if (inexact)
- *pret |= BF_ST_INEXACT;
- return add_one;
- }
- /* round to prec1 bits assuming 'r' is non zero and finite. 'r' is
- assumed to have length 'l' (1 <= l <= r->len). prec1 can be
- BF_PREC_INF. BF_FLAG_SUBNORMAL is not supported. Cannot fail with
- BF_ST_MEM_ERROR.
- */
- static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l)
- {
- int shift, add_one, rnd_mode, ret;
- slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;
- /* XXX: align to IEEE 754 2008 for decimal numbers ? */
- e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
- e_min = -e_range + 3;
- e_max = e_range;
- if (flags & BF_FLAG_RADPNT_PREC) {
- /* 'prec' is the precision after the decimal point */
- if (prec1 != BF_PREC_INF)
- prec = r->expn + prec1;
- else
- prec = prec1;
- } else if (unlikely(r->expn < e_min) && (flags & BF_FLAG_SUBNORMAL)) {
- /* restrict the precision in case of potentially subnormal
- result */
- assert(prec1 != BF_PREC_INF);
- prec = prec1 - (e_min - r->expn);
- } else {
- prec = prec1;
- }
- /* round to prec bits */
- rnd_mode = flags & BF_RND_MASK;
- ret = 0;
- add_one = bfdec_get_rnd_add(&ret, r, l, prec, rnd_mode);
- if (prec <= 0) {
- if (add_one) {
- bfdec_resize(r, 1); /* cannot fail because r is non zero */
- r->tab[0] = BF_DEC_BASE / 10;
- r->expn += 1 - prec;
- ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;
- return ret;
- } else {
- goto underflow;
- }
- } else if (add_one) {
- limb_t carry;
- /* add one starting at digit 'prec - 1' */
- bit_pos = l * LIMB_DIGITS - 1 - (prec - 1);
- pos = bit_pos / LIMB_DIGITS;
- carry = mp_pow_dec[bit_pos % LIMB_DIGITS];
- carry = mp_add_ui_dec(r->tab + pos, carry, l - pos);
- if (carry) {
- /* shift right by one digit */
- mp_shr_dec(r->tab + pos, r->tab + pos, l - pos, 1, 1);
- r->expn++;
- }
- }
- /* check underflow */
- if (unlikely(r->expn < e_min)) {
- if (flags & BF_FLAG_SUBNORMAL) {
- /* if inexact, also set the underflow flag */
- if (ret & BF_ST_INEXACT)
- ret |= BF_ST_UNDERFLOW;
- } else {
- underflow:
- bfdec_set_zero(r, r->sign);
- ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;
- return ret;
- }
- }
- /* check overflow */
- if (unlikely(r->expn > e_max)) {
- bfdec_set_inf(r, r->sign);
- ret |= BF_ST_OVERFLOW | BF_ST_INEXACT;
- return ret;
- }
- /* keep the bits starting at 'prec - 1' */
- bit_pos = l * LIMB_DIGITS - 1 - (prec - 1);
- i = floor_div(bit_pos, LIMB_DIGITS);
- if (i >= 0) {
- shift = smod(bit_pos, LIMB_DIGITS);
- if (shift != 0) {
- r->tab[i] = fast_shr_dec(r->tab[i], shift) *
- mp_pow_dec[shift];
- }
- } else {
- i = 0;
- }
- /* remove trailing zeros */
- while (r->tab[i] == 0)
- i++;
- if (i > 0) {
- l -= i;
- memmove(r->tab, r->tab + i, l * sizeof(limb_t));
- }
- bfdec_resize(r, l); /* cannot fail */
- return ret;
- }
- /* Cannot fail with BF_ST_MEM_ERROR. */
- int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags)
- {
- if (r->len == 0)
- return 0;
- return __bfdec_round(r, prec, flags, r->len);
- }
- /* 'r' must be a finite number. Cannot fail with BF_ST_MEM_ERROR. */
- int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags)
- {
- limb_t l, v;
- int shift, ret;
- // bfdec_print_str("bf_renorm", r);
- l = r->len;
- while (l > 0 && r->tab[l - 1] == 0)
- l--;
- if (l == 0) {
- /* zero */
- r->expn = BF_EXP_ZERO;
- bfdec_resize(r, 0); /* cannot fail */
- ret = 0;
- } else {
- r->expn -= (r->len - l) * LIMB_DIGITS;
- /* shift to have the MSB set to '1' */
- v = r->tab[l - 1];
- shift = clz_dec(v);
- if (shift != 0) {
- mp_shl_dec(r->tab, r->tab, l, shift, 0);
- r->expn -= shift;
- }
- ret = __bfdec_round(r, prec1, flags, l);
- }
- // bf_print_str("r_final", r);
- return ret;
- }
- int bfdec_set_ui(bfdec_t *r, uint64_t v)
- {
- #if LIMB_BITS == 32
- if (v >= BF_DEC_BASE * BF_DEC_BASE) {
- if (bfdec_resize(r, 3))
- goto fail;
- r->tab[0] = v % BF_DEC_BASE;
- v /= BF_DEC_BASE;
- r->tab[1] = v % BF_DEC_BASE;
- r->tab[2] = v / BF_DEC_BASE;
- r->expn = 3 * LIMB_DIGITS;
- } else
- #endif
- if (v >= BF_DEC_BASE) {
- if (bfdec_resize(r, 2))
- goto fail;
- r->tab[0] = v % BF_DEC_BASE;
- r->tab[1] = v / BF_DEC_BASE;
- r->expn = 2 * LIMB_DIGITS;
- } else {
- if (bfdec_resize(r, 1))
- goto fail;
- r->tab[0] = v;
- r->expn = LIMB_DIGITS;
- }
- r->sign = 0;
- return bfdec_normalize_and_round(r, BF_PREC_INF, 0);
- fail:
- bfdec_set_nan(r);
- return BF_ST_MEM_ERROR;
- }
- int bfdec_set_si(bfdec_t *r, int64_t v)
- {
- int ret;
- if (v < 0) {
- ret = bfdec_set_ui(r, -v);
- r->sign = 1;
- } else {
- ret = bfdec_set_ui(r, v);
- }
- return ret;
- }
- static int bfdec_add_internal(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, bf_flags_t flags, int b_neg)
- {
- bf_context_t *s = r->ctx;
- int is_sub, cmp_res, a_sign, b_sign, ret;
- a_sign = a->sign;
- b_sign = b->sign ^ b_neg;
- is_sub = a_sign ^ b_sign;
- cmp_res = bfdec_cmpu(a, b);
- if (cmp_res < 0) {
- const bfdec_t *tmp;
- tmp = a;
- a = b;
- b = tmp;
- a_sign = b_sign; /* b_sign is never used later */
- }
- /* abs(a) >= abs(b) */
- if (cmp_res == 0 && is_sub && a->expn < BF_EXP_INF) {
- /* zero result */
- bfdec_set_zero(r, (flags & BF_RND_MASK) == BF_RNDD);
- ret = 0;
- } else if (a->len == 0 || b->len == 0) {
- ret = 0;
- if (a->expn >= BF_EXP_INF) {
- if (a->expn == BF_EXP_NAN) {
- /* at least one operand is NaN */
- bfdec_set_nan(r);
- ret = 0;
- } else if (b->expn == BF_EXP_INF && is_sub) {
- /* infinities with different signs */
- bfdec_set_nan(r);
- ret = BF_ST_INVALID_OP;
- } else {
- bfdec_set_inf(r, a_sign);
- }
- } else {
- /* at least one zero and not subtract */
- if (bfdec_set(r, a))
- return BF_ST_MEM_ERROR;
- r->sign = a_sign;
- goto renorm;
- }
- } else {
- slimb_t d, a_offset, b_offset, i, r_len;
- limb_t carry;
- limb_t *b1_tab;
- int b_shift;
- mp_size_t b1_len;
- d = a->expn - b->expn;
- /* XXX: not efficient in time and memory if the precision is
- not infinite */
- r_len = bf_max(a->len, b->len + (d + LIMB_DIGITS - 1) / LIMB_DIGITS);
- if (bfdec_resize(r, r_len))
- goto fail;
- r->sign = a_sign;
- r->expn = a->expn;
- a_offset = r_len - a->len;
- for(i = 0; i < a_offset; i++)
- r->tab[i] = 0;
- for(i = 0; i < a->len; i++)
- r->tab[a_offset + i] = a->tab[i];
- b_shift = d % LIMB_DIGITS;
- if (b_shift == 0) {
- b1_len = b->len;
- b1_tab = (limb_t *)b->tab;
- } else {
- b1_len = b->len + 1;
- b1_tab = bf_malloc(s, sizeof(limb_t) * b1_len);
- if (!b1_tab)
- goto fail;
- b1_tab[0] = mp_shr_dec(b1_tab + 1, b->tab, b->len, b_shift, 0) *
- mp_pow_dec[LIMB_DIGITS - b_shift];
- }
- b_offset = r_len - (b->len + (d + LIMB_DIGITS - 1) / LIMB_DIGITS);
- if (is_sub) {
- carry = mp_sub_dec(r->tab + b_offset, r->tab + b_offset,
- b1_tab, b1_len, 0);
- if (carry != 0) {
- carry = mp_sub_ui_dec(r->tab + b_offset + b1_len, carry,
- r_len - (b_offset + b1_len));
- assert(carry == 0);
- }
- } else {
- carry = mp_add_dec(r->tab + b_offset, r->tab + b_offset,
- b1_tab, b1_len, 0);
- if (carry != 0) {
- carry = mp_add_ui_dec(r->tab + b_offset + b1_len, carry,
- r_len - (b_offset + b1_len));
- }
- if (carry != 0) {
- if (bfdec_resize(r, r_len + 1)) {
- if (b_shift != 0)
- bf_free(s, b1_tab);
- goto fail;
- }
- r->tab[r_len] = 1;
- r->expn += LIMB_DIGITS;
- }
- }
- if (b_shift != 0)
- bf_free(s, b1_tab);
- renorm:
- ret = bfdec_normalize_and_round(r, prec, flags);
- }
- return ret;
- fail:
- bfdec_set_nan(r);
- return BF_ST_MEM_ERROR;
- }
- static int __bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
- bf_flags_t flags)
- {
- return bfdec_add_internal(r, a, b, prec, flags, 0);
- }
- static int __bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
- bf_flags_t flags)
- {
- return bfdec_add_internal(r, a, b, prec, flags, 1);
- }
- int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
- bf_flags_t flags)
- {
- return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags,
- (bf_op2_func_t *)__bfdec_add);
- }
- int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
- bf_flags_t flags)
- {
- return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags,
- (bf_op2_func_t *)__bfdec_sub);
- }
- int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
- bf_flags_t flags)
- {
- int ret, r_sign;
- if (a->len < b->len) {
- const bfdec_t *tmp = a;
- a = b;
- b = tmp;
- }
- r_sign = a->sign ^ b->sign;
- /* here b->len <= a->len */
- if (b->len == 0) {
- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
- bfdec_set_nan(r);
- ret = 0;
- } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_INF) {
- if ((a->expn == BF_EXP_INF && b->expn == BF_EXP_ZERO) ||
- (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_INF)) {
- bfdec_set_nan(r);
- ret = BF_ST_INVALID_OP;
- } else {
- bfdec_set_inf(r, r_sign);
- ret = 0;
- }
- } else {
- bfdec_set_zero(r, r_sign);
- ret = 0;
- }
- } else {
- bfdec_t tmp, *r1 = NULL;
- limb_t a_len, b_len;
- limb_t *a_tab, *b_tab;
- a_len = a->len;
- b_len = b->len;
- a_tab = a->tab;
- b_tab = b->tab;
- if (r == a || r == b) {
- bfdec_init(r->ctx, &tmp);
- r1 = r;
- r = &tmp;
- }
- if (bfdec_resize(r, a_len + b_len)) {
- bfdec_set_nan(r);
- ret = BF_ST_MEM_ERROR;
- goto done;
- }
- mp_mul_basecase_dec(r->tab, a_tab, a_len, b_tab, b_len);
- r->sign = r_sign;
- r->expn = a->expn + b->expn;
- ret = bfdec_normalize_and_round(r, prec, flags);
- done:
- if (r == &tmp)
- bfdec_move(r1, &tmp);
- }
- return ret;
- }
- int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
- bf_flags_t flags)
- {
- bfdec_t b;
- int ret;
- bfdec_init(r->ctx, &b);
- ret = bfdec_set_si(&b, b1);
- ret |= bfdec_mul(r, a, &b, prec, flags);
- bfdec_delete(&b);
- return ret;
- }
- int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
- bf_flags_t flags)
- {
- bfdec_t b;
- int ret;
- bfdec_init(r->ctx, &b);
- ret = bfdec_set_si(&b, b1);
- ret |= bfdec_add(r, a, &b, prec, flags);
- bfdec_delete(&b);
- return ret;
- }
- static int __bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
- limb_t prec, bf_flags_t flags)
- {
- int ret, r_sign;
- limb_t n, nb, precl;
- r_sign = a->sign ^ b->sign;
- if (a->expn >= BF_EXP_INF || b->expn >= BF_EXP_INF) {
- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
- bfdec_set_nan(r);
- return 0;
- } else if (a->expn == BF_EXP_INF && b->expn == BF_EXP_INF) {
- bfdec_set_nan(r);
- return BF_ST_INVALID_OP;
- } else if (a->expn == BF_EXP_INF) {
- bfdec_set_inf(r, r_sign);
- return 0;
- } else {
- bfdec_set_zero(r, r_sign);
- return 0;
- }
- } else if (a->expn == BF_EXP_ZERO) {
- if (b->expn == BF_EXP_ZERO) {
- bfdec_set_nan(r);
- return BF_ST_INVALID_OP;
- } else {
- bfdec_set_zero(r, r_sign);
- return 0;
- }
- } else if (b->expn == BF_EXP_ZERO) {
- bfdec_set_inf(r, r_sign);
- return BF_ST_DIVIDE_ZERO;
- }
- nb = b->len;
- if (prec == BF_PREC_INF) {
- /* infinite precision: return BF_ST_INVALID_OP if not an exact
- result */
- /* XXX: check */
- precl = nb + 1;
- } else if (flags & BF_FLAG_RADPNT_PREC) {
- /* number of digits after the decimal point */
- /* XXX: check (2 extra digits for rounding + 2 digits) */
- precl = (bf_max(a->expn - b->expn, 0) + 2 +
- prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;
- } else {
- /* number of limbs of the quotient (2 extra digits for rounding) */
- precl = (prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;
- }
- n = bf_max(a->len, precl);
- {
- limb_t *taba, na, i;
- slimb_t d;
- na = n + nb;
- taba = bf_malloc(r->ctx, (na + 1) * sizeof(limb_t));
- if (!taba)
- goto fail;
- d = na - a->len;
- memset(taba, 0, d * sizeof(limb_t));
- memcpy(taba + d, a->tab, a->len * sizeof(limb_t));
- if (bfdec_resize(r, n + 1))
- goto fail1;
- if (mp_div_dec(r->ctx, r->tab, taba, na, b->tab, nb)) {
- fail1:
- bf_free(r->ctx, taba);
- goto fail;
- }
- /* see if non zero remainder */
- for(i = 0; i < nb; i++) {
- if (taba[i] != 0)
- break;
- }
- bf_free(r->ctx, taba);
- if (i != nb) {
- if (prec == BF_PREC_INF) {
- bfdec_set_nan(r);
- return BF_ST_INVALID_OP;
- } else {
- r->tab[0] |= 1;
- }
- }
- r->expn = a->expn - b->expn + LIMB_DIGITS;
- r->sign = r_sign;
- ret = bfdec_normalize_and_round(r, prec, flags);
- }
- return ret;
- fail:
- bfdec_set_nan(r);
- return BF_ST_MEM_ERROR;
- }
- int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
- bf_flags_t flags)
- {
- return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags,
- (bf_op2_func_t *)__bfdec_div);
- }
- /* a and b must be finite numbers with a >= 0 and b > 0. 'q' is the
- integer defined as floor(a/b) and r = a - q * b. */
- static void bfdec_tdivremu(bf_context_t *s, bfdec_t *q, bfdec_t *r,
- const bfdec_t *a, const bfdec_t *b)
- {
- if (bfdec_cmpu(a, b) < 0) {
- bfdec_set_ui(q, 0);
- bfdec_set(r, a);
- } else {
- bfdec_div(q, a, b, 0, BF_RNDZ | BF_FLAG_RADPNT_PREC);
- bfdec_mul(r, q, b, BF_PREC_INF, BF_RNDZ);
- bfdec_sub(r, a, r, BF_PREC_INF, BF_RNDZ);
- }
- }
- /* division and remainder.
- rnd_mode is the rounding mode for the quotient. The additional
- rounding mode BF_RND_EUCLIDIAN is supported.
- 'q' is an integer. 'r' is rounded with prec and flags (prec can be
- BF_PREC_INF).
- */
- int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
- limb_t prec, bf_flags_t flags, int rnd_mode)
- {
- bf_context_t *s = q->ctx;
- bfdec_t a1_s, *a1 = &a1_s;
- bfdec_t b1_s, *b1 = &b1_s;
- bfdec_t r1_s, *r1 = &r1_s;
- int q_sign, res;
- bool is_ceil, is_rndn;
- assert(q != a && q != b);
- assert(r != a && r != b);
- assert(q != r);
- if (a->len == 0 || b->len == 0) {
- bfdec_set_zero(q, 0);
- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
- bfdec_set_nan(r);
- return 0;
- } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_ZERO) {
- bfdec_set_nan(r);
- return BF_ST_INVALID_OP;
- } else {
- bfdec_set(r, a);
- return bfdec_round(r, prec, flags);
- }
- }
- q_sign = a->sign ^ b->sign;
- is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
- switch(rnd_mode) {
- default:
- case BF_RNDZ:
- case BF_RNDN:
- case BF_RNDNA:
- is_ceil = false;
- break;
- case BF_RNDD:
- is_ceil = q_sign;
- break;
- case BF_RNDU:
- is_ceil = q_sign ^ 1;
- break;
- case BF_RNDA:
- is_ceil = true;
- break;
- case BF_DIVREM_EUCLIDIAN:
- is_ceil = a->sign;
- break;
- }
- a1->expn = a->expn;
- a1->tab = a->tab;
- a1->len = a->len;
- a1->sign = 0;
- b1->expn = b->expn;
- b1->tab = b->tab;
- b1->len = b->len;
- b1->sign = 0;
- // bfdec_print_str("a1", a1);
- // bfdec_print_str("b1", b1);
- /* XXX: could improve to avoid having a large 'q' */
- bfdec_tdivremu(s, q, r, a1, b1);
- if (bfdec_is_nan(q) || bfdec_is_nan(r))
- goto fail;
- // bfdec_print_str("q", q);
- // bfdec_print_str("r", r);
- if (r->len != 0) {
- if (is_rndn) {
- bfdec_init(s, r1);
- if (bfdec_set(r1, r))
- goto fail;
- if (bfdec_mul_si(r1, r1, 2, BF_PREC_INF, BF_RNDZ)) {
- bfdec_delete(r1);
- goto fail;
- }
- res = bfdec_cmpu(r1, b);
- bfdec_delete(r1);
- if (res > 0 ||
- (res == 0 &&
- (rnd_mode == BF_RNDNA ||
- (get_digit(q->tab, q->len, q->len * LIMB_DIGITS - q->expn) & 1) != 0))) {
- goto do_sub_r;
- }
- } else if (is_ceil) {
- do_sub_r:
- res = bfdec_add_si(q, q, 1, BF_PREC_INF, BF_RNDZ);
- res |= bfdec_sub(r, r, b1, BF_PREC_INF, BF_RNDZ);
- if (res & BF_ST_MEM_ERROR)
- goto fail;
- }
- }
- r->sign ^= a->sign;
- q->sign = q_sign;
- return bfdec_round(r, prec, flags);
- fail:
- bfdec_set_nan(q);
- bfdec_set_nan(r);
- return BF_ST_MEM_ERROR;
- }
- int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
- bf_flags_t flags, int rnd_mode)
- {
- bfdec_t q_s, *q = &q_s;
- int ret;
- bfdec_init(r->ctx, q);
- ret = bfdec_divrem(q, r, a, b, prec, flags, rnd_mode);
- bfdec_delete(q);
- return ret;
- }
- /* convert to integer (infinite precision) */
- int bfdec_rint(bfdec_t *r, int rnd_mode)
- {
- return bfdec_round(r, 0, rnd_mode | BF_FLAG_RADPNT_PREC);
- }
- int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags)
- {
- bf_context_t *s = a->ctx;
- int ret, k;
- limb_t *a1, v;
- slimb_t n, n1, prec1;
- limb_t res;
- assert(r != a);
- if (a->len == 0) {
- if (a->expn == BF_EXP_NAN) {
- bfdec_set_nan(r);
- } else if (a->expn == BF_EXP_INF && a->sign) {
- goto invalid_op;
- } else {
- bfdec_set(r, a);
- }
- ret = 0;
- } else if (a->sign || prec == BF_PREC_INF) {
- invalid_op:
- bfdec_set_nan(r);
- ret = BF_ST_INVALID_OP;
- } else {
- if (flags & BF_FLAG_RADPNT_PREC) {
- prec1 = bf_max(floor_div(a->expn + 1, 2) + prec, 1);
- } else {
- prec1 = prec;
- }
- /* convert the mantissa to an integer with at least 2 *
- prec + 4 digits */
- n = (2 * (prec1 + 2) + 2 * LIMB_DIGITS - 1) / (2 * LIMB_DIGITS);
- if (bfdec_resize(r, n))
- goto fail;
- a1 = bf_malloc(s, sizeof(limb_t) * 2 * n);
- if (!a1)
- goto fail;
- n1 = bf_min(2 * n, a->len);
- memset(a1, 0, (2 * n - n1) * sizeof(limb_t));
- memcpy(a1 + 2 * n - n1, a->tab + a->len - n1, n1 * sizeof(limb_t));
- if (a->expn & 1) {
- res = mp_shr_dec(a1, a1, 2 * n, 1, 0);
- } else {
- res = 0;
- }
- /* normalize so that a1 >= B^(2*n)/4. Not need for n = 1
- because mp_sqrtrem2_dec already does it */
- k = 0;
- if (n > 1) {
- v = a1[2 * n - 1];
- while (v < BF_DEC_BASE / 4) {
- k++;
- v *= 4;
- }
- if (k != 0)
- mp_mul1_dec(a1, a1, 2 * n, 1 << (2 * k), 0);
- }
- if (mp_sqrtrem_dec(s, r->tab, a1, n)) {
- bf_free(s, a1);
- goto fail;
- }
- if (k != 0)
- mp_div1_dec(r->tab, r->tab, n, 1 << k, 0);
- if (!res) {
- res = mp_scan_nz(a1, n + 1);
- }
- bf_free(s, a1);
- if (!res) {
- res = mp_scan_nz(a->tab, a->len - n1);
- }
- if (res != 0)
- r->tab[0] |= 1;
- r->sign = 0;
- r->expn = (a->expn + 1) >> 1;
- ret = bfdec_round(r, prec, flags);
- }
- return ret;
- fail:
- bfdec_set_nan(r);
- return BF_ST_MEM_ERROR;
- }
- /* The rounding mode is always BF_RNDZ. Return BF_ST_OVERFLOW if there
- is an overflow and 0 otherwise. No memory error is possible. */
- int bfdec_get_int32(int *pres, const bfdec_t *a)
- {
- uint32_t v;
- int ret;
- if (a->expn >= BF_EXP_INF) {
- ret = 0;
- if (a->expn == BF_EXP_INF) {
- v = (uint32_t)INT32_MAX + a->sign;
- /* XXX: return overflow ? */
- } else {
- v = INT32_MAX;
- }
- } else if (a->expn <= 0) {
- v = 0;
- ret = 0;
- } else if (a->expn <= 9) {
- v = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn);
- if (a->sign)
- v = -v;
- ret = 0;
- } else if (a->expn == 10) {
- uint64_t v1;
- uint32_t v_max;
- #if LIMB_BITS == 64
- v1 = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn);
- #else
- v1 = (uint64_t)a->tab[a->len - 1] * 10 +
- get_digit(a->tab, a->len, (a->len - 1) * LIMB_DIGITS - 1);
- #endif
- v_max = (uint32_t)INT32_MAX + a->sign;
- if (v1 > v_max) {
- v = v_max;
- ret = BF_ST_OVERFLOW;
- } else {
- v = v1;
- if (a->sign)
- v = -v;
- ret = 0;
- }
- } else {
- v = (uint32_t)INT32_MAX + a->sign;
- ret = BF_ST_OVERFLOW;
- }
- *pres = v;
- return ret;
- }
- /* power to an integer with infinite precision */
- int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b)
- {
- int ret, n_bits, i;
- assert(r != a);
- if (b == 0)
- return bfdec_set_ui(r, 1);
- ret = bfdec_set(r, a);
- n_bits = LIMB_BITS - clz(b);
- for(i = n_bits - 2; i >= 0; i--) {
- ret |= bfdec_mul(r, r, r, BF_PREC_INF, BF_RNDZ);
- if ((b >> i) & 1)
- ret |= bfdec_mul(r, r, a, BF_PREC_INF, BF_RNDZ);
- }
- return ret;
- }
- char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags)
- {
- return bf_ftoa_internal(plen, (const bf_t *)a, 10, prec, flags, true);
- }
- int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,
- limb_t prec, bf_flags_t flags)
- {
- slimb_t dummy_exp;
- return bf_atof_internal((bf_t *)r, &dummy_exp, str, pnext, 10, prec,
- flags, true);
- }
- #endif /* USE_BF_DEC */
- #ifdef USE_FFT_MUL
- /***************************************************************/
- /* Integer multiplication with FFT */
- /* or LIMB_BITS at bit position 'pos' in tab */
- static inline void put_bits(limb_t *tab, limb_t len, slimb_t pos, limb_t val)
- {
- limb_t i;
- int p;
- i = pos >> LIMB_LOG2_BITS;
- p = pos & (LIMB_BITS - 1);
- if (i < len)
- tab[i] |= val << p;
- if (p != 0) {
- i++;
- if (i < len) {
- tab[i] |= val >> (LIMB_BITS - p);
- }
- }
- }
- #if defined(__AVX2__)
- typedef double NTTLimb;
- /* we must have: modulo >= 1 << NTT_MOD_LOG2_MIN */
- #define NTT_MOD_LOG2_MIN 50
- #define NTT_MOD_LOG2_MAX 51
- #define NB_MODS 5
- #define NTT_PROOT_2EXP 39
- static const int ntt_int_bits[NB_MODS] = { 254, 203, 152, 101, 50, };
- static const limb_t ntt_mods[NB_MODS] = { 0x00073a8000000001, 0x0007858000000001, 0x0007a38000000001, 0x0007a68000000001, 0x0007fd8000000001,
- };
- static const limb_t ntt_proot[2][NB_MODS] = {
- { 0x00056198d44332c8, 0x0002eb5d640aad39, 0x00047e31eaa35fd0, 0x0005271ac118a150, 0x00075e0ce8442bd5, },
- { 0x000461169761bcc5, 0x0002dac3cb2da688, 0x0004abc97751e3bf, 0x000656778fc8c485, 0x0000dc6469c269fa, },
- };
- static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = {
- 0x00020e4da740da8e, 0x0004c3dc09c09c1d, 0x000063bd097b4271, 0x000799d8f18f18fd,
- 0x0005384222222264, 0x000572b07c1f07fe, 0x00035cd08888889a,
- 0x00066015555557e3, 0x000725960b60b623,
- 0x0002fc1fa1d6ce12,
- };
- #else
- typedef limb_t NTTLimb;
- #if LIMB_BITS == 64
- #define NTT_MOD_LOG2_MIN 61
- #define NTT_MOD_LOG2_MAX 62
- #define NB_MODS 5
- #define NTT_PROOT_2EXP 51
- static const int ntt_int_bits[NB_MODS] = { 307, 246, 185, 123, 61, };
- static const limb_t ntt_mods[NB_MODS] = { 0x28d8000000000001, 0x2a88000000000001, 0x2ed8000000000001, 0x3508000000000001, 0x3aa8000000000001,
- };
- static const limb_t ntt_proot[2][NB_MODS] = {
- { 0x1b8ea61034a2bea7, 0x21a9762de58206fb, 0x02ca782f0756a8ea, 0x278384537a3e50a1, 0x106e13fee74ce0ab, },
- { 0x233513af133e13b8, 0x1d13140d1c6f75f1, 0x12cde57f97e3eeda, 0x0d6149e23cbe654f, 0x36cd204f522a1379, },
- };
- static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = {
- 0x08a9ed097b425eea, 0x18a44aaaaaaaaab3, 0x2493f57f57f57f5d, 0x126b8d0649a7f8d4,
- 0x09d80ed7303b5ccc, 0x25b8bcf3cf3cf3d5, 0x2ce6ce63398ce638,
- 0x0e31fad40a57eb59, 0x02a3529fd4a7f52f,
- 0x3a5493e93e93e94a,
- };
- #elif LIMB_BITS == 32
- /* we must have: modulo >= 1 << NTT_MOD_LOG2_MIN */
- #define NTT_MOD_LOG2_MIN 29
- #define NTT_MOD_LOG2_MAX 30
- #define NB_MODS 5
- #define NTT_PROOT_2EXP 20
- static const int ntt_int_bits[NB_MODS] = { 148, 119, 89, 59, 29, };
- static const limb_t ntt_mods[NB_MODS] = { 0x0000000032b00001, 0x0000000033700001, 0x0000000036d00001, 0x0000000037300001, 0x000000003e500001,
- };
- static const limb_t ntt_proot[2][NB_MODS] = {
- { 0x0000000032525f31, 0x0000000005eb3b37, 0x00000000246eda9f, 0x0000000035f25901, 0x00000000022f5768, },
- { 0x00000000051eba1a, 0x00000000107be10e, 0x000000001cd574e0, 0x00000000053806e6, 0x000000002cd6bf98, },
- };
- static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = {
- 0x000000000449559a, 0x000000001eba6ca9, 0x000000002ec18e46, 0x000000000860160b,
- 0x000000000d321307, 0x000000000bf51120, 0x000000000f662938,
- 0x000000000932ab3e, 0x000000002f40eef8,
- 0x000000002e760905,
- };
- #endif /* LIMB_BITS */
- #endif /* !AVX2 */
- #if defined(__AVX2__)
- #define NTT_TRIG_K_MAX 18
- #else
- #define NTT_TRIG_K_MAX 19
- #endif
- typedef struct BFNTTState {
- bf_context_t *ctx;
- /* used for mul_mod_fast() */
- limb_t ntt_mods_div[NB_MODS];
- limb_t ntt_proot_pow[NB_MODS][2][NTT_PROOT_2EXP + 1];
- limb_t ntt_proot_pow_inv[NB_MODS][2][NTT_PROOT_2EXP + 1];
- NTTLimb *ntt_trig[NB_MODS][2][NTT_TRIG_K_MAX + 1];
- /* 1/2^n mod m */
- limb_t ntt_len_inv[NB_MODS][NTT_PROOT_2EXP + 1][2];
- #if defined(__AVX2__)
- __m256d ntt_mods_cr_vec[NB_MODS * (NB_MODS - 1) / 2];
- __m256d ntt_mods_vec[NB_MODS];
- __m256d ntt_mods_inv_vec[NB_MODS];
- #else
- limb_t ntt_mods_cr_inv[NB_MODS * (NB_MODS - 1) / 2];
- #endif
- } BFNTTState;
- static NTTLimb *get_trig(BFNTTState *s, int k, int inverse, int m_idx);
- /* add modulo with up to (LIMB_BITS-1) bit modulo */
- static inline limb_t add_mod(limb_t a, limb_t b, limb_t m)
- {
- limb_t r;
- r = a + b;
- if (r >= m)
- r -= m;
- return r;
- }
- /* sub modulo with up to LIMB_BITS bit modulo */
- static inline limb_t sub_mod(limb_t a, limb_t b, limb_t m)
- {
- limb_t r;
- r = a - b;
- if (r > a)
- r += m;
- return r;
- }
- /* return (r0+r1*B) mod m
- precondition: 0 <= r0+r1*B < 2^(64+NTT_MOD_LOG2_MIN)
- */
- static inline limb_t mod_fast(dlimb_t r,
- limb_t m, limb_t m_inv)
- {
- limb_t a1, q, t0, r1, r0;
- a1 = r >> NTT_MOD_LOG2_MIN;
- q = ((dlimb_t)a1 * m_inv) >> LIMB_BITS;
- r = r - (dlimb_t)q * m - m * 2;
- r1 = r >> LIMB_BITS;
- t0 = (slimb_t)r1 >> 1;
- r += m & t0;
- r0 = r;
- r1 = r >> LIMB_BITS;
- r0 += m & r1;
- return r0;
- }
- /* faster version using precomputed modulo inverse.
- precondition: 0 <= a * b < 2^(64+NTT_MOD_LOG2_MIN) */
- static inline limb_t mul_mod_fast(limb_t a, limb_t b,
- limb_t m, limb_t m_inv)
- {
- dlimb_t r;
- r = (dlimb_t)a * (dlimb_t)b;
- return mod_fast(r, m, m_inv);
- }
- static inline limb_t init_mul_mod_fast(limb_t m)
- {
- dlimb_t t;
- assert(m < (limb_t)1 << NTT_MOD_LOG2_MAX);
- assert(m >= (limb_t)1 << NTT_MOD_LOG2_MIN);
- t = (dlimb_t)1 << (LIMB_BITS + NTT_MOD_LOG2_MIN);
- return t / m;
- }
- /* Faster version used when the multiplier is constant. 0 <= a < 2^64,
- 0 <= b < m. */
- static inline limb_t mul_mod_fast2(limb_t a, limb_t b,
- limb_t m, limb_t b_inv)
- {
- limb_t r, q;
- q = ((dlimb_t)a * (dlimb_t)b_inv) >> LIMB_BITS;
- r = a * b - q * m;
- if (r >= m)
- r -= m;
- return r;
- }
- /* Faster version used when the multiplier is constant. 0 <= a < 2^64,
- 0 <= b < m. Let r = a * b mod m. The return value is 'r' or 'r +
- m'. */
- static inline limb_t mul_mod_fast3(limb_t a, limb_t b,
- limb_t m, limb_t b_inv)
- {
- limb_t r, q;
- q = ((dlimb_t)a * (dlimb_t)b_inv) >> LIMB_BITS;
- r = a * b - q * m;
- return r;
- }
- static inline limb_t init_mul_mod_fast2(limb_t b, limb_t m)
- {
- return ((dlimb_t)b << LIMB_BITS) / m;
- }
- #ifdef __AVX2__
- static inline limb_t ntt_limb_to_int(NTTLimb a, limb_t m)
- {
- slimb_t v;
- v = a;
- if (v < 0)
- v += m;
- if (v >= m)
- v -= m;
- return v;
- }
- static inline NTTLimb int_to_ntt_limb(limb_t a, limb_t m)
- {
- return (slimb_t)a;
- }
- static inline NTTLimb int_to_ntt_limb2(limb_t a, limb_t m)
- {
- if (a >= (m / 2))
- a -= m;
- return (slimb_t)a;
- }
- /* return r + m if r < 0 otherwise r. */
- static inline __m256d ntt_mod1(__m256d r, __m256d m)
- {
- return _mm256_blendv_pd(r, r + m, r);
- }
- /* input: abs(r) < 2 * m. Output: abs(r) < m */
- static inline __m256d ntt_mod(__m256d r, __m256d mf, __m256d m2f)
- {
- return _mm256_blendv_pd(r, r + m2f, r) - mf;
- }
- /* input: abs(a*b) < 2 * m^2, output: abs(r) < m */
- static inline __m256d ntt_mul_mod(__m256d a, __m256d b, __m256d mf,
- __m256d m_inv)
- {
- __m256d r, q, ab1, ab0, qm0, qm1;
- ab1 = a * b;
- q = _mm256_round_pd(ab1 * m_inv, 0); /* round to nearest */
- qm1 = q * mf;
- qm0 = _mm256_fmsub_pd(q, mf, qm1); /* low part */
- ab0 = _mm256_fmsub_pd(a, b, ab1); /* low part */
- r = (ab1 - qm1) + (ab0 - qm0);
- return r;
- }
- static void *bf_aligned_malloc(bf_context_t *s, size_t size, size_t align)
- {
- void *ptr;
- void **ptr1;
- ptr = bf_malloc(s, size + sizeof(void *) + align - 1);
- if (!ptr)
- return NULL;
- ptr1 = (void **)(((uintptr_t)ptr + sizeof(void *) + align - 1) &
- ~(align - 1));
- ptr1[-1] = ptr;
- return ptr1;
- }
- static void bf_aligned_free(bf_context_t *s, void *ptr)
- {
- if (!ptr)
- return;
- bf_free(s, ((void **)ptr)[-1]);
- }
- static void *ntt_malloc(BFNTTState *s, size_t size)
- {
- return bf_aligned_malloc(s->ctx, size, 64);
- }
- static void ntt_free(BFNTTState *s, void *ptr)
- {
- bf_aligned_free(s->ctx, ptr);
- }
- static no_inline int ntt_fft(BFNTTState *s,
- NTTLimb *out_buf, NTTLimb *in_buf,
- NTTLimb *tmp_buf, int fft_len_log2,
- int inverse, int m_idx)
- {
- limb_t nb_blocks, fft_per_block, p, k, n, stride_in, i, j;
- NTTLimb *tab_in, *tab_out, *tmp, *trig;
- __m256d m_inv, mf, m2f, c, a0, a1, b0, b1;
- limb_t m;
- int l;
- m = ntt_mods[m_idx];
- m_inv = _mm256_set1_pd(1.0 / (double)m);
- mf = _mm256_set1_pd(m);
- m2f = _mm256_set1_pd(m * 2);
- n = (limb_t)1 << fft_len_log2;
- assert(n >= 8);
- stride_in = n / 2;
- tab_in = in_buf;
- tab_out = tmp_buf;
- trig = get_trig(s, fft_len_log2, inverse, m_idx);
- if (!trig)
- return -1;
- p = 0;
- for(k = 0; k < stride_in; k += 4) {
- a0 = _mm256_load_pd(&tab_in[k]);
- a1 = _mm256_load_pd(&tab_in[k + stride_in]);
- c = _mm256_load_pd(trig);
- trig += 4;
- b0 = ntt_mod(a0 + a1, mf, m2f);
- b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv);
- a0 = _mm256_permute2f128_pd(b0, b1, 0x20);
- a1 = _mm256_permute2f128_pd(b0, b1, 0x31);
- a0 = _mm256_permute4x64_pd(a0, 0xd8);
- a1 = _mm256_permute4x64_pd(a1, 0xd8);
- _mm256_store_pd(&tab_out[p], a0);
- _mm256_store_pd(&tab_out[p + 4], a1);
- p += 2 * 4;
- }
- tmp = tab_in;
- tab_in = tab_out;
- tab_out = tmp;
- trig = get_trig(s, fft_len_log2 - 1, inverse, m_idx);
- if (!trig)
- return -1;
- p = 0;
- for(k = 0; k < stride_in; k += 4) {
- a0 = _mm256_load_pd(&tab_in[k]);
- a1 = _mm256_load_pd(&tab_in[k + stride_in]);
- c = _mm256_setr_pd(trig[0], trig[0], trig[1], trig[1]);
- trig += 2;
- b0 = ntt_mod(a0 + a1, mf, m2f);
- b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv);
- a0 = _mm256_permute2f128_pd(b0, b1, 0x20);
- a1 = _mm256_permute2f128_pd(b0, b1, 0x31);
- _mm256_store_pd(&tab_out[p], a0);
- _mm256_store_pd(&tab_out[p + 4], a1);
- p += 2 * 4;
- }
- tmp = tab_in;
- tab_in = tab_out;
- tab_out = tmp;
- nb_blocks = n / 4;
- fft_per_block = 4;
- l = fft_len_log2 - 2;
- while (nb_blocks != 2) {
- nb_blocks >>= 1;
- p = 0;
- k = 0;
- trig = get_trig(s, l, inverse, m_idx);
- if (!trig)
- return -1;
- for(i = 0; i < nb_blocks; i++) {
- c = _mm256_set1_pd(trig[0]);
- trig++;
- for(j = 0; j < fft_per_block; j += 4) {
- a0 = _mm256_load_pd(&tab_in[k + j]);
- a1 = _mm256_load_pd(&tab_in[k + j + stride_in]);
- b0 = ntt_mod(a0 + a1, mf, m2f);
- b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv);
- _mm256_store_pd(&tab_out[p + j], b0);
- _mm256_store_pd(&tab_out[p + j + fft_per_block], b1);
- }
- k += fft_per_block;
- p += 2 * fft_per_block;
- }
- fft_per_block <<= 1;
- l--;
- tmp = tab_in;
- tab_in = tab_out;
- tab_out = tmp;
- }
- tab_out = out_buf;
- for(k = 0; k < stride_in; k += 4) {
- a0 = _mm256_load_pd(&tab_in[k]);
- a1 = _mm256_load_pd(&tab_in[k + stride_in]);
- b0 = ntt_mod(a0 + a1, mf, m2f);
- b1 = ntt_mod(a0 - a1, mf, m2f);
- _mm256_store_pd(&tab_out[k], b0);
- _mm256_store_pd(&tab_out[k + stride_in], b1);
- }
- return 0;
- }
- static void ntt_vec_mul(BFNTTState *s,
- NTTLimb *tab1, NTTLimb *tab2, limb_t fft_len_log2,
- int k_tot, int m_idx)
- {
- limb_t i, c_inv, n, m;
- __m256d m_inv, mf, a, b, c;
- m = ntt_mods[m_idx];
- c_inv = s->ntt_len_inv[m_idx][k_tot][0];
- m_inv = _mm256_set1_pd(1.0 / (double)m);
- mf = _mm256_set1_pd(m);
- c = _mm256_set1_pd(int_to_ntt_limb(c_inv, m));
- n = (limb_t)1 << fft_len_log2;
- for(i = 0; i < n; i += 4) {
- a = _mm256_load_pd(&tab1[i]);
- b = _mm256_load_pd(&tab2[i]);
- a = ntt_mul_mod(a, b, mf, m_inv);
- a = ntt_mul_mod(a, c, mf, m_inv);
- _mm256_store_pd(&tab1[i], a);
- }
- }
- static no_inline void mul_trig(NTTLimb *buf,
- limb_t n, limb_t c1, limb_t m, limb_t m_inv1)
- {
- limb_t i, c2, c3, c4;
- __m256d c, c_mul, a0, mf, m_inv;
- assert(n >= 2);
- mf = _mm256_set1_pd(m);
- m_inv = _mm256_set1_pd(1.0 / (double)m);
- c2 = mul_mod_fast(c1, c1, m, m_inv1);
- c3 = mul_mod_fast(c2, c1, m, m_inv1);
- c4 = mul_mod_fast(c2, c2, m, m_inv1);
- c = _mm256_setr_pd(1, int_to_ntt_limb(c1, m),
- int_to_ntt_limb(c2, m), int_to_ntt_limb(c3, m));
- c_mul = _mm256_set1_pd(int_to_ntt_limb(c4, m));
- for(i = 0; i < n; i += 4) {
- a0 = _mm256_load_pd(&buf[i]);
- a0 = ntt_mul_mod(a0, c, mf, m_inv);
- _mm256_store_pd(&buf[i], a0);
- c = ntt_mul_mod(c, c_mul, mf, m_inv);
- }
- }
- #else
- static void *ntt_malloc(BFNTTState *s, size_t size)
- {
- return bf_malloc(s->ctx, size);
- }
- static void ntt_free(BFNTTState *s, void *ptr)
- {
- bf_free(s->ctx, ptr);
- }
- static inline limb_t ntt_limb_to_int(NTTLimb a, limb_t m)
- {
- if (a >= m)
- a -= m;
- return a;
- }
- static inline NTTLimb int_to_ntt_limb(slimb_t a, limb_t m)
- {
- return a;
- }
- static no_inline int ntt_fft(BFNTTState *s, NTTLimb *out_buf, NTTLimb *in_buf,
- NTTLimb *tmp_buf, int fft_len_log2,
- int inverse, int m_idx)
- {
- limb_t nb_blocks, fft_per_block, p, k, n, stride_in, i, j, m, m2;
- NTTLimb *tab_in, *tab_out, *tmp, a0, a1, b0, b1, c, *trig, c_inv;
- int l;
- m = ntt_mods[m_idx];
- m2 = 2 * m;
- n = (limb_t)1 << fft_len_log2;
- nb_blocks = n;
- fft_per_block = 1;
- stride_in = n / 2;
- tab_in = in_buf;
- tab_out = tmp_buf;
- l = fft_len_log2;
- while (nb_blocks != 2) {
- nb_blocks >>= 1;
- p = 0;
- k = 0;
- trig = get_trig(s, l, inverse, m_idx);
- if (!trig)
- return -1;
- for(i = 0; i < nb_blocks; i++) {
- c = trig[0];
- c_inv = trig[1];
- trig += 2;
- for(j = 0; j < fft_per_block; j++) {
- a0 = tab_in[k + j];
- a1 = tab_in[k + j + stride_in];
- b0 = add_mod(a0, a1, m2);
- b1 = a0 - a1 + m2;
- b1 = mul_mod_fast3(b1, c, m, c_inv);
- tab_out[p + j] = b0;
- tab_out[p + j + fft_per_block] = b1;
- }
- k += fft_per_block;
- p += 2 * fft_per_block;
- }
- fft_per_block <<= 1;
- l--;
- tmp = tab_in;
- tab_in = tab_out;
- tab_out = tmp;
- }
- /* no twiddle in last step */
- tab_out = out_buf;
- for(k = 0; k < stride_in; k++) {
- a0 = tab_in[k];
- a1 = tab_in[k + stride_in];
- b0 = add_mod(a0, a1, m2);
- b1 = sub_mod(a0, a1, m2);
- tab_out[k] = b0;
- tab_out[k + stride_in] = b1;
- }
- return 0;
- }
- static void ntt_vec_mul(BFNTTState *s,
- NTTLimb *tab1, NTTLimb *tab2, int fft_len_log2,
- int k_tot, int m_idx)
- {
- limb_t i, norm, norm_inv, a, n, m, m_inv;
- m = ntt_mods[m_idx];
- m_inv = s->ntt_mods_div[m_idx];
- norm = s->ntt_len_inv[m_idx][k_tot][0];
- norm_inv = s->ntt_len_inv[m_idx][k_tot][1];
- n = (limb_t)1 << fft_len_log2;
- for(i = 0; i < n; i++) {
- a = tab1[i];
- /* need to reduce the range so that the product is <
- 2^(LIMB_BITS+NTT_MOD_LOG2_MIN) */
- if (a >= m)
- a -= m;
- a = mul_mod_fast(a, tab2[i], m, m_inv);
- a = mul_mod_fast3(a, norm, m, norm_inv);
- tab1[i] = a;
- }
- }
- static no_inline void mul_trig(NTTLimb *buf,
- limb_t n, limb_t c_mul, limb_t m, limb_t m_inv)
- {
- limb_t i, c0, c_mul_inv;
- c0 = 1;
- c_mul_inv = init_mul_mod_fast2(c_mul, m);
- for(i = 0; i < n; i++) {
- buf[i] = mul_mod_fast(buf[i], c0, m, m_inv);
- c0 = mul_mod_fast2(c0, c_mul, m, c_mul_inv);
- }
- }
- #endif /* !AVX2 */
- static no_inline NTTLimb *get_trig(BFNTTState *s,
- int k, int inverse, int m_idx)
- {
- NTTLimb *tab;
- limb_t i, n2, c, c_mul, m, c_mul_inv;
- if (k > NTT_TRIG_K_MAX)
- return NULL;
- tab = s->ntt_trig[m_idx][inverse][k];
- if (tab)
- return tab;
- n2 = (limb_t)1 << (k - 1);
- m = ntt_mods[m_idx];
- #ifdef __AVX2__
- tab = ntt_malloc(s, sizeof(NTTLimb) * n2);
- #else
- tab = ntt_malloc(s, sizeof(NTTLimb) * n2 * 2);
- #endif
- if (!tab)
- return NULL;
- c = 1;
- c_mul = s->ntt_proot_pow[m_idx][inverse][k];
- c_mul_inv = s->ntt_proot_pow_inv[m_idx][inverse][k];
- for(i = 0; i < n2; i++) {
- #ifdef __AVX2__
- tab[i] = int_to_ntt_limb2(c, m);
- #else
- tab[2 * i] = int_to_ntt_limb(c, m);
- tab[2 * i + 1] = init_mul_mod_fast2(c, m);
- #endif
- c = mul_mod_fast2(c, c_mul, m, c_mul_inv);
- }
- s->ntt_trig[m_idx][inverse][k] = tab;
- return tab;
- }
- void fft_clear_cache(bf_context_t *s1)
- {
- int m_idx, inverse, k;
- BFNTTState *s = s1->ntt_state;
- if (s) {
- for(m_idx = 0; m_idx < NB_MODS; m_idx++) {
- for(inverse = 0; inverse < 2; inverse++) {
- for(k = 0; k < NTT_TRIG_K_MAX + 1; k++) {
- if (s->ntt_trig[m_idx][inverse][k]) {
- ntt_free(s, s->ntt_trig[m_idx][inverse][k]);
- s->ntt_trig[m_idx][inverse][k] = NULL;
- }
- }
- }
- }
- #if defined(__AVX2__)
- bf_aligned_free(s1, s);
- #else
- bf_free(s1, s);
- #endif
- s1->ntt_state = NULL;
- }
- }
- #define STRIP_LEN 16
- /* dst = buf1, src = buf2 */
- static int ntt_fft_partial(BFNTTState *s, NTTLimb *buf1,
- int k1, int k2, limb_t n1, limb_t n2, int inverse,
- limb_t m_idx)
- {
- limb_t i, j, c_mul, c0, m, m_inv, strip_len, l;
- NTTLimb *buf2, *buf3;
- buf2 = NULL;
- buf3 = ntt_malloc(s, sizeof(NTTLimb) * n1);
- if (!buf3)
- goto fail;
- if (k2 == 0) {
- if (ntt_fft(s, buf1, buf1, buf3, k1, inverse, m_idx))
- goto fail;
- } else {
- strip_len = STRIP_LEN;
- buf2 = ntt_malloc(s, sizeof(NTTLimb) * n1 * strip_len);
- if (!buf2)
- goto fail;
- m = ntt_mods[m_idx];
- m_inv = s->ntt_mods_div[m_idx];
- c0 = s->ntt_proot_pow[m_idx][inverse][k1 + k2];
- c_mul = 1;
- assert((n2 % strip_len) == 0);
- for(j = 0; j < n2; j += strip_len) {
- for(i = 0; i < n1; i++) {
- for(l = 0; l < strip_len; l++) {
- buf2[i + l * n1] = buf1[i * n2 + (j + l)];
- }
- }
- for(l = 0; l < strip_len; l++) {
- if (inverse)
- mul_trig(buf2 + l * n1, n1, c_mul, m, m_inv);
- if (ntt_fft(s, buf2 + l * n1, buf2 + l * n1, buf3, k1, inverse, m_idx))
- goto fail;
- if (!inverse)
- mul_trig(buf2 + l * n1, n1, c_mul, m, m_inv);
- c_mul = mul_mod_fast(c_mul, c0, m, m_inv);
- }
- for(i = 0; i < n1; i++) {
- for(l = 0; l < strip_len; l++) {
- buf1[i * n2 + (j + l)] = buf2[i + l *n1];
- }
- }
- }
- ntt_free(s, buf2);
- }
- ntt_free(s, buf3);
- return 0;
- fail:
- ntt_free(s, buf2);
- ntt_free(s, buf3);
- return -1;
- }
- /* dst = buf1, src = buf2, tmp = buf3 */
- static int ntt_conv(BFNTTState *s, NTTLimb *buf1, NTTLimb *buf2,
- int k, int k_tot, limb_t m_idx)
- {
- limb_t n1, n2, i;
- int k1, k2;
- if (k <= NTT_TRIG_K_MAX) {
- k1 = k;
- } else {
- /* recursive split of the FFT */
- k1 = bf_min(k / 2, NTT_TRIG_K_MAX);
- }
- k2 = k - k1;
- n1 = (limb_t)1 << k1;
- n2 = (limb_t)1 << k2;
- if (ntt_fft_partial(s, buf1, k1, k2, n1, n2, 0, m_idx))
- return -1;
- if (ntt_fft_partial(s, buf2, k1, k2, n1, n2, 0, m_idx))
- return -1;
- if (k2 == 0) {
- ntt_vec_mul(s, buf1, buf2, k, k_tot, m_idx);
- } else {
- for(i = 0; i < n1; i++) {
- ntt_conv(s, buf1 + i * n2, buf2 + i * n2, k2, k_tot, m_idx);
- }
- }
- if (ntt_fft_partial(s, buf1, k1, k2, n1, n2, 1, m_idx))
- return -1;
- return 0;
- }
- static no_inline void limb_to_ntt(BFNTTState *s,
- NTTLimb *tabr, limb_t fft_len,
- const limb_t *taba, limb_t a_len, int dpl,
- int first_m_idx, int nb_mods)
- {
- slimb_t i, n;
- dlimb_t a, b;
- int j, shift;
- limb_t base_mask1, a0, a1, a2, r, m, m_inv;
- memset(tabr, 0, sizeof(NTTLimb) * fft_len * nb_mods);
- shift = dpl & (LIMB_BITS - 1);
- if (shift == 0)
- base_mask1 = -1;
- else
- base_mask1 = ((limb_t)1 << shift) - 1;
- n = bf_min(fft_len, (a_len * LIMB_BITS + dpl - 1) / dpl);
- for(i = 0; i < n; i++) {
- a0 = get_bits(taba, a_len, i * dpl);
- if (dpl <= LIMB_BITS) {
- a0 &= base_mask1;
- a = a0;
- } else {
- a1 = get_bits(taba, a_len, i * dpl + LIMB_BITS);
- if (dpl <= (LIMB_BITS + NTT_MOD_LOG2_MIN)) {
- a = a0 | ((dlimb_t)(a1 & base_mask1) << LIMB_BITS);
- } else {
- if (dpl > 2 * LIMB_BITS) {
- a2 = get_bits(taba, a_len, i * dpl + LIMB_BITS * 2) &
- base_mask1;
- } else {
- a1 &= base_mask1;
- a2 = 0;
- }
- // printf("a=0x%016lx%016lx%016lx\n", a2, a1, a0);
- a = (a0 >> (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) |
- ((dlimb_t)a1 << (NTT_MOD_LOG2_MAX - NTT_MOD_LOG2_MIN)) |
- ((dlimb_t)a2 << (LIMB_BITS + NTT_MOD_LOG2_MAX - NTT_MOD_LOG2_MIN));
- a0 &= ((limb_t)1 << (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) - 1;
- }
- }
- for(j = 0; j < nb_mods; j++) {
- m = ntt_mods[first_m_idx + j];
- m_inv = s->ntt_mods_div[first_m_idx + j];
- r = mod_fast(a, m, m_inv);
- if (dpl > (LIMB_BITS + NTT_MOD_LOG2_MIN)) {
- b = ((dlimb_t)r << (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) | a0;
- r = mod_fast(b, m, m_inv);
- }
- tabr[i + j * fft_len] = int_to_ntt_limb(r, m);
- }
- }
- }
- #if defined(__AVX2__)
- #define VEC_LEN 4
- typedef union {
- __m256d v;
- double d[4];
- } VecUnion;
- static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len,
- const NTTLimb *buf, int fft_len_log2, int dpl,
- int nb_mods)
- {
- const limb_t *mods = ntt_mods + NB_MODS - nb_mods;
- const __m256d *mods_cr_vec, *mf, *m_inv;
- VecUnion y[NB_MODS];
- limb_t u[NB_MODS], carry[NB_MODS], fft_len, base_mask1, r;
- slimb_t i, len, pos;
- int j, k, l, shift, n_limb1, p;
- dlimb_t t;
- j = NB_MODS * (NB_MODS - 1) / 2 - nb_mods * (nb_mods - 1) / 2;
- mods_cr_vec = s->ntt_mods_cr_vec + j;
- mf = s->ntt_mods_vec + NB_MODS - nb_mods;
- m_inv = s->ntt_mods_inv_vec + NB_MODS - nb_mods;
- shift = dpl & (LIMB_BITS - 1);
- if (shift == 0)
- base_mask1 = -1;
- else
- base_mask1 = ((limb_t)1 << shift) - 1;
- n_limb1 = ((unsigned)dpl - 1) / LIMB_BITS;
- for(j = 0; j < NB_MODS; j++)
- carry[j] = 0;
- for(j = 0; j < NB_MODS; j++)
- u[j] = 0; /* avoid warnings */
- memset(tabr, 0, sizeof(limb_t) * r_len);
- fft_len = (limb_t)1 << fft_len_log2;
- len = bf_min(fft_len, (r_len * LIMB_BITS + dpl - 1) / dpl);
- len = (len + VEC_LEN - 1) & ~(VEC_LEN - 1);
- i = 0;
- while (i < len) {
- for(j = 0; j < nb_mods; j++)
- y[j].v = *(__m256d *)&buf[i + fft_len * j];
- /* Chinese remainder to get mixed radix representation */
- l = 0;
- for(j = 0; j < nb_mods - 1; j++) {
- y[j].v = ntt_mod1(y[j].v, mf[j]);
- for(k = j + 1; k < nb_mods; k++) {
- y[k].v = ntt_mul_mod(y[k].v - y[j].v,
- mods_cr_vec[l], mf[k], m_inv[k]);
- l++;
- }
- }
- y[j].v = ntt_mod1(y[j].v, mf[j]);
- for(p = 0; p < VEC_LEN; p++) {
- /* back to normal representation */
- u[0] = (int64_t)y[nb_mods - 1].d[p];
- l = 1;
- for(j = nb_mods - 2; j >= 1; j--) {
- r = (int64_t)y[j].d[p];
- for(k = 0; k < l; k++) {
- t = (dlimb_t)u[k] * mods[j] + r;
- r = t >> LIMB_BITS;
- u[k] = t;
- }
- u[l] = r;
- l++;
- }
- /* XXX: for nb_mods = 5, l should be 4 */
- /* last step adds the carry */
- r = (int64_t)y[0].d[p];
- for(k = 0; k < l; k++) {
- t = (dlimb_t)u[k] * mods[j] + r + carry[k];
- r = t >> LIMB_BITS;
- u[k] = t;
- }
- u[l] = r + carry[l];
- /* write the digits */
- pos = i * dpl;
- for(j = 0; j < n_limb1; j++) {
- put_bits(tabr, r_len, pos, u[j]);
- pos += LIMB_BITS;
- }
- put_bits(tabr, r_len, pos, u[n_limb1] & base_mask1);
- /* shift by dpl digits and set the carry */
- if (shift == 0) {
- for(j = n_limb1 + 1; j < nb_mods; j++)
- carry[j - (n_limb1 + 1)] = u[j];
- } else {
- for(j = n_limb1; j < nb_mods - 1; j++) {
- carry[j - n_limb1] = (u[j] >> shift) |
- (u[j + 1] << (LIMB_BITS - shift));
- }
- carry[nb_mods - 1 - n_limb1] = u[nb_mods - 1] >> shift;
- }
- i++;
- }
- }
- }
- #else
- static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len,
- const NTTLimb *buf, int fft_len_log2, int dpl,
- int nb_mods)
- {
- const limb_t *mods = ntt_mods + NB_MODS - nb_mods;
- const limb_t *mods_cr, *mods_cr_inv;
- limb_t y[NB_MODS], u[NB_MODS], carry[NB_MODS], fft_len, base_mask1, r;
- slimb_t i, len, pos;
- int j, k, l, shift, n_limb1;
- dlimb_t t;
- j = NB_MODS * (NB_MODS - 1) / 2 - nb_mods * (nb_mods - 1) / 2;
- mods_cr = ntt_mods_cr + j;
- mods_cr_inv = s->ntt_mods_cr_inv + j;
- shift = dpl & (LIMB_BITS - 1);
- if (shift == 0)
- base_mask1 = -1;
- else
- base_mask1 = ((limb_t)1 << shift) - 1;
- n_limb1 = ((unsigned)dpl - 1) / LIMB_BITS;
- for(j = 0; j < NB_MODS; j++)
- carry[j] = 0;
- for(j = 0; j < NB_MODS; j++)
- u[j] = 0; /* avoid warnings */
- memset(tabr, 0, sizeof(limb_t) * r_len);
- fft_len = (limb_t)1 << fft_len_log2;
- len = bf_min(fft_len, (r_len * LIMB_BITS + dpl - 1) / dpl);
- for(i = 0; i < len; i++) {
- for(j = 0; j < nb_mods; j++) {
- y[j] = ntt_limb_to_int(buf[i + fft_len * j], mods[j]);
- }
- /* Chinese remainder to get mixed radix representation */
- l = 0;
- for(j = 0; j < nb_mods - 1; j++) {
- for(k = j + 1; k < nb_mods; k++) {
- limb_t m;
- m = mods[k];
- /* Note: there is no overflow in the sub_mod() because
- the modulos are sorted by increasing order */
- y[k] = mul_mod_fast2(y[k] - y[j] + m,
- mods_cr[l], m, mods_cr_inv[l]);
- l++;
- }
- }
- /* back to normal representation */
- u[0] = y[nb_mods - 1];
- l = 1;
- for(j = nb_mods - 2; j >= 1; j--) {
- r = y[j];
- for(k = 0; k < l; k++) {
- t = (dlimb_t)u[k] * mods[j] + r;
- r = t >> LIMB_BITS;
- u[k] = t;
- }
- u[l] = r;
- l++;
- }
- /* last step adds the carry */
- r = y[0];
- for(k = 0; k < l; k++) {
- t = (dlimb_t)u[k] * mods[j] + r + carry[k];
- r = t >> LIMB_BITS;
- u[k] = t;
- }
- u[l] = r + carry[l];
- /* write the digits */
- pos = i * dpl;
- for(j = 0; j < n_limb1; j++) {
- put_bits(tabr, r_len, pos, u[j]);
- pos += LIMB_BITS;
- }
- put_bits(tabr, r_len, pos, u[n_limb1] & base_mask1);
- /* shift by dpl digits and set the carry */
- if (shift == 0) {
- for(j = n_limb1 + 1; j < nb_mods; j++)
- carry[j - (n_limb1 + 1)] = u[j];
- } else {
- for(j = n_limb1; j < nb_mods - 1; j++) {
- carry[j - n_limb1] = (u[j] >> shift) |
- (u[j + 1] << (LIMB_BITS - shift));
- }
- carry[nb_mods - 1 - n_limb1] = u[nb_mods - 1] >> shift;
- }
- }
- }
- #endif
- static int ntt_static_init(bf_context_t *s1)
- {
- BFNTTState *s;
- int inverse, i, j, k, l;
- limb_t c, c_inv, c_inv2, m, m_inv;
- if (s1->ntt_state)
- return 0;
- #if defined(__AVX2__)
- s = bf_aligned_malloc(s1, sizeof(*s), 64);
- #else
- s = bf_malloc(s1, sizeof(*s));
- #endif
- if (!s)
- return -1;
- memset(s, 0, sizeof(*s));
- s1->ntt_state = s;
- s->ctx = s1;
- for(j = 0; j < NB_MODS; j++) {
- m = ntt_mods[j];
- m_inv = init_mul_mod_fast(m);
- s->ntt_mods_div[j] = m_inv;
- #if defined(__AVX2__)
- s->ntt_mods_vec[j] = _mm256_set1_pd(m);
- s->ntt_mods_inv_vec[j] = _mm256_set1_pd(1.0 / (double)m);
- #endif
- c_inv2 = (m + 1) / 2; /* 1/2 */
- c_inv = 1;
- for(i = 0; i <= NTT_PROOT_2EXP; i++) {
- s->ntt_len_inv[j][i][0] = c_inv;
- s->ntt_len_inv[j][i][1] = init_mul_mod_fast2(c_inv, m);
- c_inv = mul_mod_fast(c_inv, c_inv2, m, m_inv);
- }
- for(inverse = 0; inverse < 2; inverse++) {
- c = ntt_proot[inverse][j];
- for(i = 0; i < NTT_PROOT_2EXP; i++) {
- s->ntt_proot_pow[j][inverse][NTT_PROOT_2EXP - i] = c;
- s->ntt_proot_pow_inv[j][inverse][NTT_PROOT_2EXP - i] =
- init_mul_mod_fast2(c, m);
- c = mul_mod_fast(c, c, m, m_inv);
- }
- }
- }
- l = 0;
- for(j = 0; j < NB_MODS - 1; j++) {
- for(k = j + 1; k < NB_MODS; k++) {
- #if defined(__AVX2__)
- s->ntt_mods_cr_vec[l] = _mm256_set1_pd(int_to_ntt_limb2(ntt_mods_cr[l],
- ntt_mods[k]));
- #else
- s->ntt_mods_cr_inv[l] = init_mul_mod_fast2(ntt_mods_cr[l],
- ntt_mods[k]);
- #endif
- l++;
- }
- }
- return 0;
- }
- int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len)
- {
- int dpl, fft_len_log2, n_bits, nb_mods, dpl_found, fft_len_log2_found;
- int int_bits, nb_mods_found;
- limb_t cost, min_cost;
- min_cost = -1;
- dpl_found = 0;
- nb_mods_found = 4;
- fft_len_log2_found = 0;
- for(nb_mods = 3; nb_mods <= NB_MODS; nb_mods++) {
- int_bits = ntt_int_bits[NB_MODS - nb_mods];
- dpl = bf_min((int_bits - 4) / 2,
- 2 * LIMB_BITS + 2 * NTT_MOD_LOG2_MIN - NTT_MOD_LOG2_MAX);
- for(;;) {
- fft_len_log2 = ceil_log2((len * LIMB_BITS + dpl - 1) / dpl);
- if (fft_len_log2 > NTT_PROOT_2EXP)
- goto next;
- n_bits = fft_len_log2 + 2 * dpl;
- if (n_bits <= int_bits) {
- cost = ((limb_t)(fft_len_log2 + 1) << fft_len_log2) * nb_mods;
- // printf("n=%d dpl=%d: cost=%" PRId64 "\n", nb_mods, dpl, (int64_t)cost);
- if (cost < min_cost) {
- min_cost = cost;
- dpl_found = dpl;
- nb_mods_found = nb_mods;
- fft_len_log2_found = fft_len_log2;
- }
- break;
- }
- dpl--;
- if (dpl == 0)
- break;
- }
- next: ;
- }
- if (!dpl_found)
- abort();
- /* limit dpl if possible to reduce fixed cost of limb/NTT conversion */
- if (dpl_found > (LIMB_BITS + NTT_MOD_LOG2_MIN) &&
- ((limb_t)(LIMB_BITS + NTT_MOD_LOG2_MIN) << fft_len_log2_found) >=
- len * LIMB_BITS) {
- dpl_found = LIMB_BITS + NTT_MOD_LOG2_MIN;
- }
- *pnb_mods = nb_mods_found;
- *pdpl = dpl_found;
- return fft_len_log2_found;
- }
- /* return 0 if OK, -1 if memory error */
- static no_inline int fft_mul(bf_context_t *s1,
- bf_t *res, limb_t *a_tab, limb_t a_len,
- limb_t *b_tab, limb_t b_len, int mul_flags)
- {
- BFNTTState *s;
- int dpl, fft_len_log2, j, nb_mods, reduced_mem;
- slimb_t len, fft_len;
- NTTLimb *buf1, *buf2, *ptr;
- #if defined(USE_MUL_CHECK)
- limb_t ha, hb, hr, h_ref;
- #endif
- if (ntt_static_init(s1))
- return -1;
- s = s1->ntt_state;
- /* find the optimal number of digits per limb (dpl) */
- len = a_len + b_len;
- fft_len_log2 = bf_get_fft_size(&dpl, &nb_mods, len);
- fft_len = (uint64_t)1 << fft_len_log2;
- // printf("len=%" PRId64 " fft_len_log2=%d dpl=%d\n", len, fft_len_log2, dpl);
- #if defined(USE_MUL_CHECK)
- ha = mp_mod1(a_tab, a_len, BF_CHKSUM_MOD, 0);
- hb = mp_mod1(b_tab, b_len, BF_CHKSUM_MOD, 0);
- #endif
- if ((mul_flags & (FFT_MUL_R_OVERLAP_A | FFT_MUL_R_OVERLAP_B)) == 0) {
- if (!(mul_flags & FFT_MUL_R_NORESIZE))
- bf_resize(res, 0);
- } else if (mul_flags & FFT_MUL_R_OVERLAP_B) {
- limb_t *tmp_tab, tmp_len;
- /* it is better to free 'b' first */
- tmp_tab = a_tab;
- a_tab = b_tab;
- b_tab = tmp_tab;
- tmp_len = a_len;
- a_len = b_len;
- b_len = tmp_len;
- }
- buf1 = ntt_malloc(s, sizeof(NTTLimb) * fft_len * nb_mods);
- if (!buf1)
- return -1;
- limb_to_ntt(s, buf1, fft_len, a_tab, a_len, dpl,
- NB_MODS - nb_mods, nb_mods);
- if ((mul_flags & (FFT_MUL_R_OVERLAP_A | FFT_MUL_R_OVERLAP_B)) ==
- FFT_MUL_R_OVERLAP_A) {
- if (!(mul_flags & FFT_MUL_R_NORESIZE))
- bf_resize(res, 0);
- }
- reduced_mem = (fft_len_log2 >= 14);
- if (!reduced_mem) {
- buf2 = ntt_malloc(s, sizeof(NTTLimb) * fft_len * nb_mods);
- if (!buf2)
- goto fail;
- limb_to_ntt(s, buf2, fft_len, b_tab, b_len, dpl,
- NB_MODS - nb_mods, nb_mods);
- if (!(mul_flags & FFT_MUL_R_NORESIZE))
- bf_resize(res, 0); /* in case res == b */
- } else {
- buf2 = ntt_malloc(s, sizeof(NTTLimb) * fft_len);
- if (!buf2)
- goto fail;
- }
- for(j = 0; j < nb_mods; j++) {
- if (reduced_mem) {
- limb_to_ntt(s, buf2, fft_len, b_tab, b_len, dpl,
- NB_MODS - nb_mods + j, 1);
- ptr = buf2;
- } else {
- ptr = buf2 + fft_len * j;
- }
- if (ntt_conv(s, buf1 + fft_len * j, ptr,
- fft_len_log2, fft_len_log2, j + NB_MODS - nb_mods))
- goto fail;
- }
- if (!(mul_flags & FFT_MUL_R_NORESIZE))
- bf_resize(res, 0); /* in case res == b and reduced mem */
- ntt_free(s, buf2);
- buf2 = NULL;
- if (!(mul_flags & FFT_MUL_R_NORESIZE)) {
- if (bf_resize(res, len))
- goto fail;
- }
- ntt_to_limb(s, res->tab, len, buf1, fft_len_log2, dpl, nb_mods);
- ntt_free(s, buf1);
- #if defined(USE_MUL_CHECK)
- hr = mp_mod1(res->tab, len, BF_CHKSUM_MOD, 0);
- h_ref = mul_mod(ha, hb, BF_CHKSUM_MOD);
- if (hr != h_ref) {
- printf("ntt_mul_error: len=%" PRId_LIMB " fft_len_log2=%d dpl=%d nb_mods=%d\n",
- len, fft_len_log2, dpl, nb_mods);
- // printf("ha=0x" FMT_LIMB" hb=0x" FMT_LIMB " hr=0x" FMT_LIMB " expected=0x" FMT_LIMB "\n", ha, hb, hr, h_ref);
- exit(1);
- }
- #endif
- return 0;
- fail:
- ntt_free(s, buf1);
- ntt_free(s, buf2);
- return -1;
- }
- #else /* USE_FFT_MUL */
- int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len)
- {
- return 0;
- }
- #endif /* !USE_FFT_MUL */
- #undef malloc
- #undef free
- #undef realloc
- /*
- * 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
- /* 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;
- 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;
- }
- /* return 1 if match, 0 if not match or -1 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 (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 -1;
- 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 -1;
- break;
- case REOP_goto:
- val = get_u32(pc);
- pc += 4 + (int)val;
- 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;
- }
- 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(;;) {
- res = lre_exec_backtrack(s, capture, stack, stack_len,
- pc1, cptr, true);
- if (res == -1)
- 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 -1;
- }
- }
- break;
- default:
- abort();
- }
- }
- }
- /* Return 1 if match, 0 if not match or -1 if error. 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->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
- JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
- JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
- JSModuleDef *js_init_module_bjson(JSContext *ctx, const char *module_name);
- void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
- int js_std_loop(JSContext *ctx);
- JSValue js_std_await(JSContext *ctx, JSValue obj);
- void js_std_init_handlers(JSRuntime *rt);
- void js_std_free_handlers(JSRuntime *rt);
- void js_std_dump_error(JSContext *ctx);
- uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
- int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
- bool use_realpath, bool is_main);
- JSModuleDef *js_module_loader(JSContext *ctx,
- const char *module_name, void *opaque);
- void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
- int flags);
- void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
- JSValueConst reason,
- bool is_handled, void *opaque);
- void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));
- #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>
- #if !defined(_MSC_VER)
- #include <unistd.h>
- #endif
- #include <errno.h>
- #include <fcntl.h>
- #if !defined(_MSC_VER)
- #include <sys/time.h>
- #endif
- #include <time.h>
- #include <signal.h>
- #include <limits.h>
- #include <sys/stat.h>
- #if defined(_MSC_VER)
- #else
- #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>
- #if !defined(__wasi__)
- #include <dlfcn.h>
- #include <termios.h>
- #include <sys/resource.h>
- #include <sys/wait.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 !defined(_WIN32) && !defined(__wasi__)
- /* enable the os.Worker API. IT relies on POSIX threads */
- #define USE_WORKER
- #endif
- #ifdef USE_WORKER
- #include <pthread.h>
- #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;
- 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 {
- int ref_count;
- #ifdef USE_WORKER
- pthread_mutex_t mutex;
- #endif
- struct list_head msg_queue; /* list of JSWorkerMessage.link */
- int read_fd;
- int write_fd;
- } JSWorkerMessagePipe;
- typedef struct {
- struct list_head link;
- JSWorkerMessagePipe *recv_pipe;
- JSValue on_message_func;
- } JSWorkerMessageHandler;
- 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 */
- 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 */
- JSWorkerMessagePipe *recv_pipe, *send_pipe;
- 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[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 (mode[strspn(mode, "rw")] != '\0') {
- 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__)
- 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__)
- 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(ctx, 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 && S_ISDIR(st.st_mode)) {
- 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_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;
- }
- #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, console_fd;
- JSOSRWHandler *rh;
- struct list_head *el;
- /* 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))
- return -1; /* no more events */
- console_fd = -1;
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
- console_fd = rh->fd;
- break;
- }
- }
- if (console_fd >= 0) {
- DWORD ti, ret;
- HANDLE handle;
- if (min_delay == -1)
- ti = INFINITE;
- else
- ti = min_delay;
- handle = (HANDLE)_get_osfhandle(console_fd);
- ret = WaitForSingleObject(handle, ti);
- if (ret == WAIT_OBJECT_0) {
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- if (rh->fd == console_fd && !JS_IsNull(rh->rw_func[0])) {
- return call_handler(ctx, rh->rw_func[0]);
- /* must stop because the list may have been modified */
- }
- }
- }
- } else {
- Sleep(min_delay);
- }
- return 0;
- }
- #else
- #ifdef USE_WORKER
- 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;
- pthread_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);
- if (list_empty(&ps->msg_queue)) {
- uint8_t buf[16];
- int ret;
- for(;;) {
- ret = read(ps->read_fd, buf, sizeof(buf));
- if (ret >= 0)
- break;
- if (errno != EAGAIN && errno != EINTR)
- break;
- }
- }
- pthread_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 {
- pthread_mutex_unlock(&ps->mutex);
- ret = 0;
- }
- return ret;
- }
- #else
- static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
- JSWorkerMessageHandler *port)
- {
- return 0;
- }
- #endif
- static int js_os_poll(JSContext *ctx)
- {
- JSRuntime *rt = JS_GetRuntime(ctx);
- JSThreadState *ts = js_get_thread_state(rt);
- int ret, fd_max, min_delay;
- fd_set rfds, wfds;
- JSOSRWHandler *rh;
- struct list_head *el;
- struct timeval tv, *tvp;
- /* 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 */
- tvp = NULL;
- if (min_delay >= 0) {
- tv.tv_sec = min_delay / 1000;
- tv.tv_usec = (min_delay % 1000) * 1000;
- tvp = &tv;
- }
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- fd_max = -1;
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- fd_max = max_int(fd_max, rh->fd);
- if (!JS_IsNull(rh->rw_func[0]))
- FD_SET(rh->fd, &rfds);
- if (!JS_IsNull(rh->rw_func[1]))
- FD_SET(rh->fd, &wfds);
- }
- 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;
- fd_max = max_int(fd_max, ps->read_fd);
- FD_SET(ps->read_fd, &rfds);
- }
- }
- ret = select(fd_max + 1, &rfds, &wfds, NULL, tvp);
- if (ret > 0) {
- list_for_each(el, &ts->os_rw_handlers) {
- rh = list_entry(el, JSOSRWHandler, link);
- if (!JS_IsNull(rh->rw_func[0]) &&
- FD_ISSET(rh->fd, &rfds)) {
- return call_handler(ctx, rh->rw_func[0]);
- /* must stop because the list may have been modified */
- }
- if (!JS_IsNull(rh->rw_func[1]) &&
- FD_ISSET(rh->fd, &wfds)) {
- return call_handler(ctx, rh->rw_func[1]);
- /* 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 (FD_ISSET(ps->read_fd, &rfds)) {
- if (handle_posted_message(rt, ctx, port))
- goto done;
- }
- }
- }
- }
- done:
- return 0;
- }
- #endif /* !_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[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)
- {
- 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);
- }
- #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, 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[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[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[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) > 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)
- {
- 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;
- 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;
- }
- }
- #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 (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;
- int pipe_fds[2];
- if (pipe(pipe_fds) < 0)
- return NULL;
- ps = malloc(sizeof(*ps));
- if (!ps) {
- close(pipe_fds[0]);
- close(pipe_fds[1]);
- return NULL;
- }
- ps->ref_count = 1;
- init_list_head(&ps->msg_queue);
- pthread_mutex_init(&ps->mutex, NULL);
- ps->read_fd = pipe_fds[0];
- ps->write_fd = pipe_fds[1];
- 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);
- }
- pthread_mutex_destroy(&ps->mutex);
- close(ps->read_fd);
- close(ps->write_fd);
- 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);
- return NULL;
- }
- 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;
- pthread_t tid;
- pthread_attr_t attr;
- 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;
- pthread_attr_init(&attr);
- /* no join at the end */
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- // musl libc gives threads 80 kb stacks, much smaller than
- // JS_DEFAULT_STACK_SIZE (1 MB)
- pthread_attr_setstacksize(&attr, 2 << 20); // 2 MB, glibc default
- ret = pthread_create(&tid, &attr, worker_func, args);
- pthread_attr_destroy(&attr);
- 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;
- pthread_mutex_lock(&ps->mutex);
- /* indicate that data is present */
- if (list_empty(&ps->msg_queue)) {
- uint8_t ch = '\0';
- int ret;
- for(;;) {
- ret = write(ps->write_fd, &ch, 1);
- if (ret == 1)
- break;
- if (ret < 0 && (errno != EAGAIN || errno != EINTR))
- break;
- }
- }
- list_add_tail(&msg->link, &ps->msg_queue);
- pthread_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"
- #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("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);
- 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
- }
- 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);
- }
- #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(ctx, 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);
- }
- void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
- JSValueConst reason,
- bool is_handled, void *opaque)
- {
- if (!is_handled) {
- fprintf(stderr, "Possibly unhandled promise rejection: ");
- js_std_dump_error1(ctx, 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;
- }
- }
- 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 (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;
- }
- } 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
|