Codegen.py 722 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552
  1. # This Source Code Form is subject to the terms of the Mozilla Public
  2. # License, v. 2.0. If a copy of the MPL was not distributed with this file,
  3. # You can obtain one at http://mozilla.org/MPL/2.0/.
  4. # Common codegen classes.
  5. import os
  6. import re
  7. import string
  8. import math
  9. import textwrap
  10. import functools
  11. from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLInterfaceMember, IDLUndefinedValue, IDLEmptySequenceValue, IDLDictionary
  12. from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, getAllTypes, Descriptor, MemberIsUnforgeable, iteratorNativeType
  13. AUTOGENERATED_WARNING_COMMENT = \
  14. "/* THIS FILE IS AUTOGENERATED BY Codegen.py - DO NOT EDIT */\n\n"
  15. AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT = \
  16. "/* THIS FILE IS AUTOGENERATED FROM %s BY Codegen.py - DO NOT EDIT */\n\n"
  17. ADDPROPERTY_HOOK_NAME = '_addProperty'
  18. FINALIZE_HOOK_NAME = '_finalize'
  19. OBJECT_MOVED_HOOK_NAME = '_objectMoved'
  20. CONSTRUCT_HOOK_NAME = '_constructor'
  21. LEGACYCALLER_HOOK_NAME = '_legacycaller'
  22. HASINSTANCE_HOOK_NAME = '_hasInstance'
  23. RESOLVE_HOOK_NAME = '_resolve'
  24. MAY_RESOLVE_HOOK_NAME = '_mayResolve'
  25. ENUMERATE_HOOK_NAME = '_enumerate'
  26. ENUM_ENTRY_VARIABLE_NAME = 'strings'
  27. INSTANCE_RESERVED_SLOTS = 1
  28. def memberReservedSlot(member, descriptor):
  29. return ("(DOM_INSTANCE_RESERVED_SLOTS + %d)" %
  30. member.slotIndices[descriptor.interface.identifier.name])
  31. def memberXrayExpandoReservedSlot(member, descriptor):
  32. return ("(xpc::JSSLOT_EXPANDO_COUNT + %d)" %
  33. member.slotIndices[descriptor.interface.identifier.name])
  34. def mayUseXrayExpandoSlots(descriptor, attr):
  35. assert not attr.getExtendedAttribute("NewObject")
  36. # For attributes whose type is a Gecko interface we always use
  37. # slots on the reflector for caching. Also, for interfaces that
  38. # don't want Xrays we obviously never use the Xray expando slot.
  39. return descriptor.wantsXrays and not attr.type.isGeckoInterface()
  40. def toStringBool(arg):
  41. return str(not not arg).lower()
  42. def toBindingNamespace(arg):
  43. return arg + "Binding"
  44. def isTypeCopyConstructible(type):
  45. # Nullable and sequence stuff doesn't affect copy-constructibility
  46. type = type.unroll()
  47. return (type.isPrimitive() or type.isString() or type.isEnum() or
  48. (type.isUnion() and
  49. CGUnionStruct.isUnionCopyConstructible(type)) or
  50. (type.isDictionary() and
  51. CGDictionary.isDictionaryCopyConstructible(type.inner)) or
  52. # Interface types are only copy-constructible if they're Gecko
  53. # interfaces. SpiderMonkey interfaces are not copy-constructible
  54. # because of rooting issues.
  55. (type.isInterface() and type.isGeckoInterface()))
  56. def idlTypeNeedsCycleCollection(type):
  57. type = type.unroll() # Takes care of sequences and nullables
  58. if ((type.isPrimitive() and type.tag() in builtinNames) or
  59. type.isEnum() or
  60. type.isString() or
  61. type.isAny() or
  62. type.isObject() or
  63. type.isSpiderMonkeyInterface()):
  64. return False
  65. elif type.isCallback() or type.isGeckoInterface():
  66. return True
  67. elif type.isUnion():
  68. return any(idlTypeNeedsCycleCollection(t) for t in type.flatMemberTypes)
  69. elif type.isRecord():
  70. if idlTypeNeedsCycleCollection(type.inner):
  71. raise TypeError("Cycle collection for type %s is not supported" % type)
  72. return False
  73. elif type.isDictionary():
  74. if any(idlTypeNeedsCycleCollection(m.type) for m in type.inner.members):
  75. raise TypeError("Cycle collection for type %s is not supported" % type)
  76. return False
  77. else:
  78. raise TypeError("Don't know whether to cycle-collect type %s" % type)
  79. def wantsAddProperty(desc):
  80. return (desc.concrete and desc.wrapperCache and not desc.isGlobal())
  81. # We'll want to insert the indent at the beginnings of lines, but we
  82. # don't want to indent empty lines. So only indent lines that have a
  83. # non-newline character on them.
  84. lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
  85. def indent(s, indentLevel=2):
  86. """
  87. Indent C++ code.
  88. Weird secret feature: this doesn't indent lines that start with # (such as
  89. #include lines or #ifdef/#endif).
  90. """
  91. if s == "":
  92. return s
  93. return re.sub(lineStartDetector, indentLevel * " ", s)
  94. # dedent() and fill() are often called on the same string multiple
  95. # times. We want to memoize their return values so we don't keep
  96. # recomputing them all the time.
  97. def memoize(fn):
  98. """
  99. Decorator to memoize a function of one argument. The cache just
  100. grows without bound.
  101. """
  102. cache = {}
  103. @functools.wraps(fn)
  104. def wrapper(arg):
  105. retval = cache.get(arg)
  106. if retval is None:
  107. retval = cache[arg] = fn(arg)
  108. return retval
  109. return wrapper
  110. @memoize
  111. def dedent(s):
  112. """
  113. Remove all leading whitespace from s, and remove a blank line
  114. at the beginning.
  115. """
  116. if s.startswith('\n'):
  117. s = s[1:]
  118. return textwrap.dedent(s)
  119. # This works by transforming the fill()-template to an equivalent
  120. # string.Template.
  121. fill_multiline_substitution_re = re.compile(r"( *)\$\*{(\w+)}(\n)?")
  122. find_substitutions = re.compile(r"\${")
  123. @memoize
  124. def compile_fill_template(template):
  125. """
  126. Helper function for fill(). Given the template string passed to fill(),
  127. do the reusable part of template processing and return a pair (t,
  128. argModList) that can be used every time fill() is called with that
  129. template argument.
  130. argsModList is list of tuples that represent modifications to be
  131. made to args. Each modification has, in order: i) the arg name,
  132. ii) the modified name, iii) the indent depth.
  133. """
  134. t = dedent(template)
  135. assert t.endswith("\n") or "\n" not in t
  136. argModList = []
  137. def replace(match):
  138. """
  139. Replaces a line like ' $*{xyz}\n' with '${xyz_n}',
  140. where n is the indent depth, and add a corresponding entry to
  141. argModList.
  142. Note that this needs to close over argModList, so it has to be
  143. defined inside compile_fill_template().
  144. """
  145. indentation, name, nl = match.groups()
  146. depth = len(indentation)
  147. # Check that $*{xyz} appears by itself on a line.
  148. prev = match.string[:match.start()]
  149. if (prev and not prev.endswith("\n")) or nl is None:
  150. raise ValueError("Invalid fill() template: $*{%s} must appear by itself on a line" % name)
  151. # Now replace this whole line of template with the indented equivalent.
  152. modified_name = name + "_" + str(depth)
  153. argModList.append((name, modified_name, depth))
  154. return "${" + modified_name + "}"
  155. t = re.sub(fill_multiline_substitution_re, replace, t)
  156. if not re.search(find_substitutions, t):
  157. raise TypeError("Using fill() when dedent() would do.")
  158. return (string.Template(t), argModList)
  159. def fill(template, **args):
  160. """
  161. Convenience function for filling in a multiline template.
  162. `fill(template, name1=v1, name2=v2)` is a lot like
  163. `string.Template(template).substitute({"name1": v1, "name2": v2})`.
  164. However, it's shorter, and has a few nice features:
  165. * If `template` is indented, fill() automatically dedents it!
  166. This makes code using fill() with Python's multiline strings
  167. much nicer to look at.
  168. * If `template` starts with a blank line, fill() strips it off.
  169. (Again, convenient with multiline strings.)
  170. * fill() recognizes a special kind of substitution
  171. of the form `$*{name}`.
  172. Use this to paste in, and automatically indent, multiple lines.
  173. (Mnemonic: The `*` is for "multiple lines").
  174. A `$*` substitution must appear by itself on a line, with optional
  175. preceding indentation (spaces only). The whole line is replaced by the
  176. corresponding keyword argument, indented appropriately. If the
  177. argument is an empty string, no output is generated, not even a blank
  178. line.
  179. """
  180. t, argModList = compile_fill_template(template)
  181. # Now apply argModList to args
  182. for (name, modified_name, depth) in argModList:
  183. if not (args[name] == "" or args[name].endswith("\n")):
  184. raise ValueError("Argument %s with value %r is missing a newline" % (name, args[name]))
  185. args[modified_name] = indent(args[name], depth)
  186. return t.substitute(args)
  187. class CGThing():
  188. """
  189. Abstract base class for things that spit out code.
  190. """
  191. def __init__(self):
  192. pass # Nothing for now
  193. def declare(self):
  194. """Produce code for a header file."""
  195. assert False # Override me!
  196. def define(self):
  197. """Produce code for a cpp file."""
  198. assert False # Override me!
  199. def deps(self):
  200. """Produce the deps for a pp file"""
  201. assert False # Override me!
  202. class CGStringTable(CGThing):
  203. """
  204. Generate a string table for the given strings with a function accessor:
  205. const char *accessorName(unsigned int index) {
  206. static const char table[] = "...";
  207. static const uint16_t indices = { ... };
  208. return &table[indices[index]];
  209. }
  210. This is more efficient than the more natural:
  211. const char *table[] = {
  212. ...
  213. };
  214. The uint16_t indices are smaller than the pointer equivalents, and the
  215. string table requires no runtime relocations.
  216. """
  217. def __init__(self, accessorName, strings):
  218. CGThing.__init__(self)
  219. self.accessorName = accessorName
  220. self.strings = strings
  221. def declare(self):
  222. return "extern const char *%s(unsigned int aIndex);\n" % self.accessorName
  223. def define(self):
  224. table = ' "\\0" '.join('"%s"' % s for s in self.strings)
  225. indices = []
  226. currentIndex = 0
  227. for s in self.strings:
  228. indices.append(currentIndex)
  229. currentIndex += len(s) + 1 # for the null terminator
  230. return fill(
  231. """
  232. const char *${name}(unsigned int aIndex)
  233. {
  234. static const char table[] = ${table};
  235. static const uint16_t indices[] = { ${indices} };
  236. static_assert(${currentIndex} <= UINT16_MAX, "string table overflow!");
  237. return &table[indices[aIndex]];
  238. }
  239. """,
  240. name=self.accessorName,
  241. table=table,
  242. indices=", ".join("%d" % index for index in indices),
  243. currentIndex=currentIndex)
  244. class CGNativePropertyHooks(CGThing):
  245. """
  246. Generate a NativePropertyHooks for a given descriptor
  247. """
  248. def __init__(self, descriptor, properties):
  249. CGThing.__init__(self)
  250. self.descriptor = descriptor
  251. self.properties = properties
  252. def declare(self):
  253. if not self.descriptor.wantsXrays:
  254. return ""
  255. return dedent("""
  256. // We declare this as an array so that retrieving a pointer to this
  257. // binding's property hooks only requires compile/link-time resolvable
  258. // address arithmetic. Declaring it as a pointer instead would require
  259. // doing a run-time load to fetch a pointer to this binding's property
  260. // hooks. And then structures which embedded a pointer to this structure
  261. // would require a run-time load for proper initialization, which would
  262. // then induce static constructors. Lots of static constructors.
  263. extern const NativePropertyHooks sNativePropertyHooks[];
  264. """)
  265. def define(self):
  266. if not self.descriptor.wantsXrays:
  267. return ""
  268. deleteNamedProperty = "nullptr"
  269. if self.descriptor.concrete and self.descriptor.proxy:
  270. resolveOwnProperty = "ResolveOwnProperty"
  271. enumerateOwnProperties = "EnumerateOwnProperties"
  272. if self.descriptor.needsXrayNamedDeleterHook():
  273. deleteNamedProperty = "DeleteNamedProperty"
  274. elif self.descriptor.needsXrayResolveHooks():
  275. resolveOwnProperty = "ResolveOwnPropertyViaResolve"
  276. enumerateOwnProperties = "EnumerateOwnPropertiesViaGetOwnPropertyNames"
  277. else:
  278. resolveOwnProperty = "nullptr"
  279. enumerateOwnProperties = "nullptr"
  280. if self.properties.hasNonChromeOnly():
  281. regular = "sNativeProperties.Upcast()"
  282. else:
  283. regular = "nullptr"
  284. if self.properties.hasChromeOnly():
  285. chrome = "sChromeOnlyNativeProperties.Upcast()"
  286. else:
  287. chrome = "nullptr"
  288. constructorID = "constructors::id::"
  289. if self.descriptor.interface.hasInterfaceObject():
  290. constructorID += self.descriptor.name
  291. else:
  292. constructorID += "_ID_Count"
  293. prototypeID = "prototypes::id::"
  294. if self.descriptor.interface.hasInterfacePrototypeObject():
  295. prototypeID += self.descriptor.name
  296. else:
  297. prototypeID += "_ID_Count"
  298. parentProtoName = self.descriptor.parentPrototypeName
  299. parentHooks = (toBindingNamespace(parentProtoName) + "::sNativePropertyHooks"
  300. if parentProtoName else 'nullptr')
  301. if self.descriptor.wantsXrayExpandoClass:
  302. expandoClass = "&sXrayExpandoObjectClass"
  303. else:
  304. expandoClass = "&DefaultXrayExpandoObjectClass"
  305. return fill(
  306. """
  307. const NativePropertyHooks sNativePropertyHooks[] = { {
  308. ${resolveOwnProperty},
  309. ${enumerateOwnProperties},
  310. ${deleteNamedProperty},
  311. { ${regular}, ${chrome} },
  312. ${prototypeID},
  313. ${constructorID},
  314. ${parentHooks},
  315. ${expandoClass}
  316. } };
  317. """,
  318. resolveOwnProperty=resolveOwnProperty,
  319. enumerateOwnProperties=enumerateOwnProperties,
  320. deleteNamedProperty=deleteNamedProperty,
  321. regular=regular,
  322. chrome=chrome,
  323. prototypeID=prototypeID,
  324. constructorID=constructorID,
  325. parentHooks=parentHooks,
  326. expandoClass=expandoClass)
  327. def NativePropertyHooks(descriptor):
  328. return "&sEmptyNativePropertyHooks" if not descriptor.wantsXrays else "sNativePropertyHooks"
  329. def DOMClass(descriptor):
  330. protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeNameChain]
  331. # Pad out the list to the right length with _ID_Count so we
  332. # guarantee that all the lists are the same length. _ID_Count
  333. # is never the ID of any prototype, so it's safe to use as
  334. # padding.
  335. protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
  336. return fill(
  337. """
  338. { ${protoChain} },
  339. IsBaseOf<nsISupports, ${nativeType} >::value,
  340. ${hooks},
  341. FindAssociatedGlobalForNative<${nativeType}>::Get,
  342. GetProtoObjectHandle,
  343. GetCCParticipant<${nativeType}>::Get()
  344. """,
  345. protoChain=', '.join(protoList),
  346. nativeType=descriptor.nativeType,
  347. hooks=NativePropertyHooks(descriptor))
  348. class CGDOMJSClass(CGThing):
  349. """
  350. Generate a DOMJSClass for a given descriptor
  351. """
  352. def __init__(self, descriptor):
  353. CGThing.__init__(self)
  354. self.descriptor = descriptor
  355. def declare(self):
  356. return ""
  357. def define(self):
  358. callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
  359. objectMovedHook = OBJECT_MOVED_HOOK_NAME if self.descriptor.wrapperCache else 'nullptr'
  360. slotCount = INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots
  361. classFlags = "JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | "
  362. if self.descriptor.isGlobal():
  363. classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS)"
  364. traceHook = "JS_GlobalObjectTraceHook"
  365. reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
  366. else:
  367. classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
  368. traceHook = 'nullptr'
  369. reservedSlots = slotCount
  370. if self.descriptor.interface.isProbablyShortLivingObject():
  371. classFlags += " | JSCLASS_SKIP_NURSERY_FINALIZE"
  372. if self.descriptor.interface.getExtendedAttribute("NeedResolve"):
  373. resolveHook = RESOLVE_HOOK_NAME
  374. mayResolveHook = MAY_RESOLVE_HOOK_NAME
  375. enumerateHook = ENUMERATE_HOOK_NAME
  376. elif self.descriptor.isGlobal():
  377. resolveHook = "mozilla::dom::ResolveGlobal"
  378. mayResolveHook = "mozilla::dom::MayResolveGlobal"
  379. enumerateHook = "mozilla::dom::EnumerateGlobal"
  380. else:
  381. resolveHook = "nullptr"
  382. mayResolveHook = "nullptr"
  383. enumerateHook = "nullptr"
  384. return fill(
  385. """
  386. static const js::ClassOps sClassOps = {
  387. ${addProperty}, /* addProperty */
  388. nullptr, /* delProperty */
  389. nullptr, /* getProperty */
  390. nullptr, /* setProperty */
  391. ${enumerate}, /* enumerate */
  392. ${resolve}, /* resolve */
  393. ${mayResolve}, /* mayResolve */
  394. ${finalize}, /* finalize */
  395. ${call}, /* call */
  396. nullptr, /* hasInstance */
  397. nullptr, /* construct */
  398. ${trace}, /* trace */
  399. };
  400. static const js::ClassExtension sClassExtension = {
  401. nullptr, /* weakmapKeyDelegateOp */
  402. ${objectMoved} /* objectMovedOp */
  403. };
  404. static const DOMJSClass sClass = {
  405. { "${name}",
  406. ${flags},
  407. &sClassOps,
  408. JS_NULL_CLASS_SPEC,
  409. &sClassExtension,
  410. JS_NULL_OBJECT_OPS
  411. },
  412. $*{descriptor}
  413. };
  414. static_assert(${instanceReservedSlots} == DOM_INSTANCE_RESERVED_SLOTS,
  415. "Must have the right minimal number of reserved slots.");
  416. static_assert(${reservedSlots} >= ${slotCount},
  417. "Must have enough reserved slots.");
  418. """,
  419. name=self.descriptor.interface.identifier.name,
  420. flags=classFlags,
  421. addProperty=ADDPROPERTY_HOOK_NAME if wantsAddProperty(self.descriptor) else 'nullptr',
  422. enumerate=enumerateHook,
  423. resolve=resolveHook,
  424. mayResolve=mayResolveHook,
  425. finalize=FINALIZE_HOOK_NAME,
  426. call=callHook,
  427. trace=traceHook,
  428. objectMoved=objectMovedHook,
  429. descriptor=DOMClass(self.descriptor),
  430. instanceReservedSlots=INSTANCE_RESERVED_SLOTS,
  431. reservedSlots=reservedSlots,
  432. slotCount=slotCount)
  433. class CGDOMProxyJSClass(CGThing):
  434. """
  435. Generate a DOMJSClass for a given proxy descriptor
  436. """
  437. def __init__(self, descriptor):
  438. CGThing.__init__(self)
  439. self.descriptor = descriptor
  440. def declare(self):
  441. return ""
  442. def define(self):
  443. flags = ["JSCLASS_IS_DOMJSCLASS"]
  444. # We don't use an IDL annotation for JSCLASS_EMULATES_UNDEFINED because
  445. # we don't want people ever adding that to any interface other than
  446. # HTMLAllCollection. So just hardcode it here.
  447. if self.descriptor.interface.identifier.name == "HTMLAllCollection":
  448. flags.append("JSCLASS_EMULATES_UNDEFINED")
  449. objectMovedHook = OBJECT_MOVED_HOOK_NAME if self.descriptor.wrapperCache else 'nullptr'
  450. return fill(
  451. """
  452. static const js::ClassExtension sClassExtension = PROXY_MAKE_EXT(
  453. ${objectMoved}
  454. );
  455. static const DOMJSClass sClass = {
  456. PROXY_CLASS_WITH_EXT("${name}",
  457. ${flags},
  458. &sClassExtension),
  459. $*{descriptor}
  460. };
  461. """,
  462. name=self.descriptor.interface.identifier.name,
  463. flags=" | ".join(flags),
  464. objectMoved=objectMovedHook,
  465. descriptor=DOMClass(self.descriptor))
  466. class CGXrayExpandoJSClass(CGThing):
  467. """
  468. Generate a JSClass for an Xray expando object. This is only
  469. needed if we have members in slots (for [Cached] or [StoreInSlot]
  470. stuff).
  471. """
  472. def __init__(self, descriptor):
  473. assert descriptor.interface.totalMembersInSlots != 0
  474. assert descriptor.wantsXrays
  475. assert descriptor.wantsXrayExpandoClass
  476. CGThing.__init__(self)
  477. self.descriptor = descriptor;
  478. def declare(self):
  479. return ""
  480. def define(self):
  481. return fill(
  482. """
  483. // This may allocate too many slots, because we only really need
  484. // slots for our non-interface-typed members that we cache. But
  485. // allocating slots only for those would make the slot index
  486. // computations much more complicated, so let's do this the simple
  487. // way for now.
  488. DEFINE_XRAY_EXPANDO_CLASS(static, sXrayExpandoObjectClass, ${memberSlots});
  489. """,
  490. memberSlots=self.descriptor.interface.totalMembersInSlots)
  491. def PrototypeIDAndDepth(descriptor):
  492. prototypeID = "prototypes::id::"
  493. if descriptor.interface.hasInterfacePrototypeObject():
  494. prototypeID += descriptor.interface.identifier.name
  495. depth = "PrototypeTraits<%s>::Depth" % prototypeID
  496. else:
  497. prototypeID += "_ID_Count"
  498. depth = "0"
  499. return (prototypeID, depth)
  500. def InterfacePrototypeObjectProtoGetter(descriptor):
  501. """
  502. Returns a tuple with two elements:
  503. 1) The name of the function to call to get the prototype to use for the
  504. interface prototype object as a JSObject*.
  505. 2) The name of the function to call to get the prototype to use for the
  506. interface prototype object as a JS::Handle<JSObject*> or None if no
  507. such function exists.
  508. """
  509. parentProtoName = descriptor.parentPrototypeName
  510. if descriptor.hasNamedPropertiesObject:
  511. protoGetter = "GetNamedPropertiesObject"
  512. protoHandleGetter = None
  513. elif parentProtoName is None:
  514. if descriptor.interface.getExtendedAttribute("ArrayClass"):
  515. protoGetter = "JS::GetRealmArrayPrototype"
  516. elif descriptor.interface.getExtendedAttribute("ExceptionClass"):
  517. protoGetter = "JS::GetRealmErrorPrototype"
  518. elif descriptor.interface.isIteratorInterface():
  519. protoGetter = "JS::GetRealmIteratorPrototype"
  520. else:
  521. protoGetter = "JS::GetRealmObjectPrototype"
  522. protoHandleGetter = None
  523. else:
  524. prefix = toBindingNamespace(parentProtoName)
  525. protoGetter = prefix + "::GetProtoObject"
  526. protoHandleGetter = prefix + "::GetProtoObjectHandle"
  527. return (protoGetter, protoHandleGetter)
  528. class CGPrototypeJSClass(CGThing):
  529. def __init__(self, descriptor, properties):
  530. CGThing.__init__(self)
  531. self.descriptor = descriptor
  532. self.properties = properties
  533. def declare(self):
  534. # We're purely for internal consumption
  535. return ""
  536. def define(self):
  537. prototypeID, depth = PrototypeIDAndDepth(self.descriptor)
  538. slotCount = "DOM_INTERFACE_PROTO_SLOTS_BASE"
  539. # Globals handle unforgeables directly in Wrap() instead of
  540. # via a holder.
  541. if (self.descriptor.hasUnforgeableMembers and
  542. not self.descriptor.isGlobal()):
  543. slotCount += " + 1 /* slot for the JSObject holding the unforgeable properties */"
  544. (protoGetter, _) = InterfacePrototypeObjectProtoGetter(self.descriptor)
  545. type = "eGlobalInterfacePrototype" if self.descriptor.isGlobal() else "eInterfacePrototype"
  546. return fill(
  547. """
  548. static const DOMIfaceAndProtoJSClass sPrototypeClass = {
  549. {
  550. "${name}Prototype",
  551. JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
  552. JS_NULL_CLASS_OPS,
  553. JS_NULL_CLASS_SPEC,
  554. JS_NULL_CLASS_EXT,
  555. JS_NULL_OBJECT_OPS
  556. },
  557. ${type},
  558. false,
  559. ${prototypeID},
  560. ${depth},
  561. ${hooks},
  562. "[object ${name}Prototype]",
  563. ${protoGetter}
  564. };
  565. """,
  566. name=self.descriptor.interface.identifier.name,
  567. slotCount=slotCount,
  568. type=type,
  569. hooks=NativePropertyHooks(self.descriptor),
  570. prototypeID=prototypeID,
  571. depth=depth,
  572. protoGetter=protoGetter)
  573. def NeedsGeneratedHasInstance(descriptor):
  574. assert descriptor.interface.hasInterfaceObject()
  575. return descriptor.hasXPConnectImpls or descriptor.interface.isConsequential()
  576. def InterfaceObjectProtoGetter(descriptor, forXrays=False):
  577. """
  578. Returns a tuple with two elements:
  579. 1) The name of the function to call to get the prototype to use for the
  580. interface object as a JSObject*.
  581. 2) The name of the function to call to get the prototype to use for the
  582. interface prototype as a JS::Handle<JSObject*> or None if no such
  583. function exists.
  584. """
  585. parentInterface = descriptor.interface.parent
  586. if parentInterface:
  587. assert not descriptor.interface.isNamespace()
  588. parentIfaceName = parentInterface.identifier.name
  589. parentDesc = descriptor.getDescriptor(parentIfaceName)
  590. prefix = toBindingNamespace(parentDesc.name)
  591. protoGetter = prefix + "::GetConstructorObject"
  592. protoHandleGetter = prefix + "::GetConstructorObjectHandle"
  593. elif descriptor.interface.isNamespace():
  594. if (forXrays or
  595. not descriptor.interface.getExtendedAttribute("ProtoObjectHack")):
  596. protoGetter = "JS::GetRealmObjectPrototype"
  597. else:
  598. protoGetter = "binding_detail::GetHackedNamespaceProtoObject"
  599. protoHandleGetter = None
  600. else:
  601. protoGetter = "JS::GetRealmFunctionPrototype"
  602. protoHandleGetter = None
  603. return (protoGetter, protoHandleGetter)
  604. class CGInterfaceObjectJSClass(CGThing):
  605. def __init__(self, descriptor, properties):
  606. CGThing.__init__(self)
  607. self.descriptor = descriptor
  608. self.properties = properties
  609. def declare(self):
  610. # We're purely for internal consumption
  611. return ""
  612. def define(self):
  613. if self.descriptor.interface.ctor():
  614. assert not self.descriptor.interface.isNamespace()
  615. ctorname = CONSTRUCT_HOOK_NAME
  616. elif self.descriptor.interface.isNamespace():
  617. ctorname = "nullptr"
  618. else:
  619. ctorname = "ThrowingConstructor"
  620. needsHasInstance = (
  621. not NeedsGeneratedHasInstance(self.descriptor) and
  622. self.descriptor.interface.hasInterfacePrototypeObject())
  623. prototypeID, depth = PrototypeIDAndDepth(self.descriptor)
  624. slotCount = "DOM_INTERFACE_SLOTS_BASE"
  625. if len(self.descriptor.interface.namedConstructors) > 0:
  626. slotCount += (" + %i /* slots for the named constructors */" %
  627. len(self.descriptor.interface.namedConstructors))
  628. (protoGetter, _) = InterfaceObjectProtoGetter(self.descriptor,
  629. forXrays=True)
  630. if ctorname == "ThrowingConstructor":
  631. ret = ""
  632. classOpsPtr = "&sBoringInterfaceObjectClassClassOps"
  633. elif ctorname == "nullptr":
  634. ret = ""
  635. classOpsPtr = "JS_NULL_CLASS_OPS"
  636. else:
  637. ret = fill(
  638. """
  639. static const js::ClassOps sInterfaceObjectClassOps = {
  640. nullptr, /* addProperty */
  641. nullptr, /* delProperty */
  642. nullptr, /* getProperty */
  643. nullptr, /* setProperty */
  644. nullptr, /* enumerate */
  645. nullptr, /* resolve */
  646. nullptr, /* mayResolve */
  647. nullptr, /* finalize */
  648. ${ctorname}, /* call */
  649. nullptr, /* hasInstance */
  650. ${ctorname}, /* construct */
  651. nullptr, /* trace */
  652. };
  653. """,
  654. ctorname=ctorname)
  655. classOpsPtr = "&sInterfaceObjectClassOps"
  656. if self.descriptor.interface.isNamespace():
  657. classString = self.descriptor.interface.getExtendedAttribute("ClassString")
  658. if classString is None:
  659. classString = "Object"
  660. else:
  661. classString = classString[0]
  662. toStringResult = "[object %s]" % classString
  663. objectOps = "JS_NULL_OBJECT_OPS"
  664. else:
  665. classString = "Function"
  666. toStringResult = ("function %s() {\\n [native code]\\n}" %
  667. self.descriptor.interface.identifier.name)
  668. # We need non-default ObjectOps so we can actually make
  669. # use of our toStringResult.
  670. objectOps = "&sInterfaceObjectClassObjectOps"
  671. ret = ret + fill(
  672. """
  673. static const DOMIfaceAndProtoJSClass sInterfaceObjectClass = {
  674. {
  675. "${classString}",
  676. JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
  677. ${classOpsPtr},
  678. JS_NULL_CLASS_SPEC,
  679. JS_NULL_CLASS_EXT,
  680. ${objectOps}
  681. },
  682. eInterface,
  683. ${needsHasInstance},
  684. ${prototypeID},
  685. ${depth},
  686. ${hooks},
  687. "${toStringResult}",
  688. ${protoGetter}
  689. };
  690. """,
  691. classString=classString,
  692. slotCount=slotCount,
  693. classOpsPtr=classOpsPtr,
  694. hooks=NativePropertyHooks(self.descriptor),
  695. objectOps=objectOps,
  696. needsHasInstance=toStringBool(needsHasInstance),
  697. prototypeID=prototypeID,
  698. depth=depth,
  699. toStringResult=toStringResult,
  700. protoGetter=protoGetter)
  701. return ret
  702. class CGList(CGThing):
  703. """
  704. Generate code for a list of GCThings. Just concatenates them together, with
  705. an optional joiner string. "\n" is a common joiner.
  706. """
  707. def __init__(self, children, joiner=""):
  708. CGThing.__init__(self)
  709. # Make a copy of the kids into a list, because if someone passes in a
  710. # generator we won't be able to both declare and define ourselves, or
  711. # define ourselves more than once!
  712. self.children = list(children)
  713. self.joiner = joiner
  714. def append(self, child):
  715. self.children.append(child)
  716. def prepend(self, child):
  717. self.children.insert(0, child)
  718. def extend(self, kids):
  719. self.children.extend(kids)
  720. def join(self, iterable):
  721. return self.joiner.join(s for s in iterable if len(s) > 0)
  722. def declare(self):
  723. return self.join(child.declare() for child in self.children if child is not None)
  724. def define(self):
  725. return self.join(child.define() for child in self.children if child is not None)
  726. def deps(self):
  727. deps = set()
  728. for child in self.children:
  729. if child is None:
  730. continue
  731. deps = deps.union(child.deps())
  732. return deps
  733. def __len__(self):
  734. return len(self.children)
  735. class CGGeneric(CGThing):
  736. """
  737. A class that spits out a fixed string into the codegen. Can spit out a
  738. separate string for the declaration too.
  739. """
  740. def __init__(self, define="", declare=""):
  741. self.declareText = declare
  742. self.defineText = define
  743. def declare(self):
  744. return self.declareText
  745. def define(self):
  746. return self.defineText
  747. def deps(self):
  748. return set()
  749. class CGIndenter(CGThing):
  750. """
  751. A class that takes another CGThing and generates code that indents that
  752. CGThing by some number of spaces. The default indent is two spaces.
  753. """
  754. def __init__(self, child, indentLevel=2, declareOnly=False):
  755. assert isinstance(child, CGThing)
  756. CGThing.__init__(self)
  757. self.child = child
  758. self.indentLevel = indentLevel
  759. self.declareOnly = declareOnly
  760. def declare(self):
  761. return indent(self.child.declare(), self.indentLevel)
  762. def define(self):
  763. defn = self.child.define()
  764. if self.declareOnly:
  765. return defn
  766. else:
  767. return indent(defn, self.indentLevel)
  768. class CGWrapper(CGThing):
  769. """
  770. Generic CGThing that wraps other CGThings with pre and post text.
  771. """
  772. def __init__(self, child, pre="", post="", declarePre=None,
  773. declarePost=None, definePre=None, definePost=None,
  774. declareOnly=False, defineOnly=False, reindent=False):
  775. CGThing.__init__(self)
  776. self.child = child
  777. self.declarePre = declarePre or pre
  778. self.declarePost = declarePost or post
  779. self.definePre = definePre or pre
  780. self.definePost = definePost or post
  781. self.declareOnly = declareOnly
  782. self.defineOnly = defineOnly
  783. self.reindent = reindent
  784. def declare(self):
  785. if self.defineOnly:
  786. return ''
  787. decl = self.child.declare()
  788. if self.reindent:
  789. decl = self.reindentString(decl, self.declarePre)
  790. return self.declarePre + decl + self.declarePost
  791. def define(self):
  792. if self.declareOnly:
  793. return ''
  794. defn = self.child.define()
  795. if self.reindent:
  796. defn = self.reindentString(defn, self.definePre)
  797. return self.definePre + defn + self.definePost
  798. @staticmethod
  799. def reindentString(stringToIndent, widthString):
  800. # We don't use lineStartDetector because we don't want to
  801. # insert whitespace at the beginning of our _first_ line.
  802. # Use the length of the last line of width string, in case
  803. # it is a multiline string.
  804. lastLineWidth = len(widthString.splitlines()[-1])
  805. return stripTrailingWhitespace(
  806. stringToIndent.replace("\n", "\n" + (" " * lastLineWidth)))
  807. def deps(self):
  808. return self.child.deps()
  809. class CGIfWrapper(CGList):
  810. def __init__(self, child, condition):
  811. CGList.__init__(self, [
  812. CGWrapper(CGGeneric(condition), pre="if (", post=") {\n", reindent=True),
  813. CGIndenter(child),
  814. CGGeneric("}\n")
  815. ])
  816. class CGIfElseWrapper(CGList):
  817. def __init__(self, condition, ifTrue, ifFalse):
  818. CGList.__init__(self, [
  819. CGWrapper(CGGeneric(condition), pre="if (", post=") {\n", reindent=True),
  820. CGIndenter(ifTrue),
  821. CGGeneric("} else {\n"),
  822. CGIndenter(ifFalse),
  823. CGGeneric("}\n")
  824. ])
  825. class CGElseChain(CGThing):
  826. """
  827. Concatenate if statements in an if-else-if-else chain.
  828. """
  829. def __init__(self, children):
  830. self.children = [c for c in children if c is not None]
  831. def declare(self):
  832. assert False
  833. def define(self):
  834. if not self.children:
  835. return ""
  836. s = self.children[0].define()
  837. assert s.endswith("\n")
  838. for child in self.children[1:]:
  839. code = child.define()
  840. assert code.startswith("if") or code.startswith("{")
  841. assert code.endswith("\n")
  842. s = s.rstrip() + " else " + code
  843. return s
  844. class CGTemplatedType(CGWrapper):
  845. def __init__(self, templateName, child, isConst=False, isReference=False):
  846. if isinstance(child, list):
  847. child = CGList(child, ", ")
  848. const = "const " if isConst else ""
  849. pre = "%s%s<" % (const, templateName)
  850. ref = "&" if isReference else ""
  851. post = ">%s" % ref
  852. CGWrapper.__init__(self, child, pre=pre, post=post)
  853. class CGNamespace(CGWrapper):
  854. def __init__(self, namespace, child, declareOnly=False):
  855. pre = "namespace %s {\n" % namespace
  856. post = "} // namespace %s\n" % namespace
  857. CGWrapper.__init__(self, child, pre=pre, post=post,
  858. declareOnly=declareOnly)
  859. @staticmethod
  860. def build(namespaces, child, declareOnly=False):
  861. """
  862. Static helper method to build multiple wrapped namespaces.
  863. """
  864. if not namespaces:
  865. return CGWrapper(child, declareOnly=declareOnly)
  866. inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly)
  867. return CGNamespace(namespaces[0], inner, declareOnly=declareOnly)
  868. class CGIncludeGuard(CGWrapper):
  869. """
  870. Generates include guards for a header.
  871. """
  872. def __init__(self, prefix, child):
  873. """|prefix| is the filename without the extension."""
  874. define = 'mozilla_dom_%s_h' % prefix
  875. CGWrapper.__init__(self, child,
  876. declarePre='#ifndef %s\n#define %s\n\n' % (define, define),
  877. declarePost='\n#endif // %s\n' % define)
  878. class CGHeaders(CGWrapper):
  879. """
  880. Generates the appropriate include statements.
  881. """
  882. def __init__(self, descriptors, dictionaries, callbacks,
  883. callbackDescriptors,
  884. declareIncludes, defineIncludes, prefix, child,
  885. config=None, jsImplementedDescriptors=[]):
  886. """
  887. Builds a set of includes to cover |descriptors|.
  888. Also includes the files in |declareIncludes| in the header
  889. file and the files in |defineIncludes| in the .cpp.
  890. |prefix| contains the basename of the file that we generate include
  891. statements for.
  892. """
  893. # Determine the filenames for which we need headers.
  894. interfaceDeps = [d.interface for d in descriptors]
  895. ancestors = []
  896. for iface in interfaceDeps:
  897. if iface.parent:
  898. # We're going to need our parent's prototype, to use as the
  899. # prototype of our prototype object.
  900. ancestors.append(iface.parent)
  901. # And if we have an interface object, we'll need the nearest
  902. # ancestor with an interface object too, so we can use its
  903. # interface object as the proto of our interface object.
  904. if iface.hasInterfaceObject():
  905. parent = iface.parent
  906. while parent and not parent.hasInterfaceObject():
  907. parent = parent.parent
  908. if parent:
  909. ancestors.append(parent)
  910. interfaceDeps.extend(ancestors)
  911. # Include parent interface headers needed for jsonifier code.
  912. jsonInterfaceParents = []
  913. for desc in descriptors:
  914. if not desc.operations['Jsonifier']:
  915. continue
  916. parent = desc.interface.parent
  917. while parent:
  918. parentDesc = desc.getDescriptor(parent.identifier.name)
  919. if parentDesc.operations['Jsonifier']:
  920. jsonInterfaceParents.append(parentDesc.interface)
  921. parent = parent.parent
  922. interfaceDeps.extend(jsonInterfaceParents)
  923. bindingIncludes = set(self.getDeclarationFilename(d) for d in interfaceDeps)
  924. # Grab all the implementation declaration files we need.
  925. implementationIncludes = set(d.headerFile for d in descriptors if d.needsHeaderInclude())
  926. # Grab the includes for checking hasInstance
  927. interfacesImplementingSelf = set()
  928. for d in descriptors:
  929. interfacesImplementingSelf |= d.interface.interfacesImplementingSelf
  930. implementationIncludes |= set(self.getDeclarationFilename(i) for i in
  931. interfacesImplementingSelf)
  932. # Grab the includes for the things that involve XPCOM interfaces
  933. hasInstanceIncludes = set("nsIDOM" + d.interface.identifier.name + ".h" for d
  934. in descriptors if
  935. d.interface.hasInterfaceObject() and
  936. NeedsGeneratedHasInstance(d) and
  937. d.interface.hasInterfacePrototypeObject())
  938. if len(hasInstanceIncludes) > 0:
  939. hasInstanceIncludes.add("nsContentUtils.h")
  940. # Now find all the things we'll need as arguments because we
  941. # need to wrap or unwrap them.
  942. bindingHeaders = set()
  943. # KeyframeAnimationOptions.webidl is doing something VERY screwy and
  944. # Unified Building really sucks so directly include this
  945. if prefix == "KeyframeAnimationOptionsBinding":
  946. bindingHeaders.add("mozilla/dom/PrimitiveConversions.h")
  947. declareIncludes = set(declareIncludes)
  948. def addHeadersForType((t, dictionary)):
  949. """
  950. Add the relevant headers for this type. We use dictionary, if
  951. passed, to decide what to do with interface types.
  952. """
  953. # Dictionaries have members that need to be actually
  954. # declared, not just forward-declared.
  955. if dictionary:
  956. headerSet = declareIncludes
  957. else:
  958. headerSet = bindingHeaders
  959. if t.nullable():
  960. # Need to make sure that Nullable as a dictionary
  961. # member works.
  962. headerSet.add("mozilla/dom/Nullable.h")
  963. unrolled = t.unroll()
  964. if unrolled.isUnion():
  965. headerSet.add(self.getUnionDeclarationFilename(config, unrolled))
  966. bindingHeaders.add("mozilla/dom/UnionConversions.h")
  967. elif unrolled.isDate():
  968. if dictionary or jsImplementedDescriptors:
  969. declareIncludes.add("mozilla/dom/Date.h")
  970. else:
  971. bindingHeaders.add("mozilla/dom/Date.h")
  972. elif unrolled.isPromise():
  973. # See comment in the isInterface() case for why we add
  974. # Promise.h to headerSet, not bindingHeaders.
  975. headerSet.add("mozilla/dom/Promise.h")
  976. # We need ToJSValue to do the Promise to JS conversion.
  977. bindingHeaders.add("mozilla/dom/ToJSValue.h")
  978. elif unrolled.isInterface():
  979. if unrolled.isSpiderMonkeyInterface():
  980. bindingHeaders.add("jsfriendapi.h")
  981. if jsImplementedDescriptors:
  982. # Since we can't forward-declare typed array types
  983. # (because they're typedefs), we have to go ahead and
  984. # just include their header if we need to have functions
  985. # taking references to them declared in that header.
  986. headerSet = declareIncludes
  987. headerSet.add("mozilla/dom/TypedArray.h")
  988. else:
  989. try:
  990. typeDesc = config.getDescriptor(unrolled.inner.identifier.name)
  991. except NoSuchDescriptorError:
  992. return
  993. # Dictionaries with interface members rely on the
  994. # actual class definition of that interface member
  995. # being visible in the binding header, because they
  996. # store them in RefPtr and have inline
  997. # constructors/destructors.
  998. #
  999. # XXXbz maybe dictionaries with interface members
  1000. # should just have out-of-line constructors and
  1001. # destructors?
  1002. headerSet.add(typeDesc.headerFile)
  1003. elif unrolled.isDictionary():
  1004. headerSet.add(self.getDeclarationFilename(unrolled.inner))
  1005. elif unrolled.isCallback():
  1006. headerSet.add(self.getDeclarationFilename(unrolled.callback))
  1007. elif unrolled.isFloat() and not unrolled.isUnrestricted():
  1008. # Restricted floats are tested for finiteness
  1009. bindingHeaders.add("mozilla/FloatingPoint.h")
  1010. bindingHeaders.add("mozilla/dom/PrimitiveConversions.h")
  1011. elif unrolled.isEnum():
  1012. filename = self.getDeclarationFilename(unrolled.inner)
  1013. declareIncludes.add(filename)
  1014. elif unrolled.isPrimitive():
  1015. bindingHeaders.add("mozilla/dom/PrimitiveConversions.h")
  1016. elif unrolled.isRecord():
  1017. if dictionary or jsImplementedDescriptors:
  1018. declareIncludes.add("mozilla/dom/Record.h")
  1019. else:
  1020. bindingHeaders.add("mozilla/dom/Record.h")
  1021. # Also add headers for the type the record is
  1022. # parametrized over, if needed.
  1023. addHeadersForType((t.inner, dictionary))
  1024. map(addHeadersForType,
  1025. getAllTypes(descriptors + callbackDescriptors, dictionaries,
  1026. callbacks))
  1027. # Now make sure we're not trying to include the header from inside itself
  1028. declareIncludes.discard(prefix + ".h")
  1029. def addHeaderForFunc(func, desc):
  1030. if func is None:
  1031. return
  1032. # Include the right class header, which we can only do
  1033. # if this is a class member function.
  1034. if desc is not None and not desc.headerIsDefault:
  1035. # An explicit header file was provided, assume that we know
  1036. # what we're doing.
  1037. return
  1038. if "::" in func:
  1039. # Strip out the function name and convert "::" to "/"
  1040. bindingHeaders.add("/".join(func.split("::")[:-1]) + ".h")
  1041. # Now for non-callback descriptors make sure we include any
  1042. # headers needed by Func declarations and other things like that.
  1043. for desc in descriptors:
  1044. # If this is an iterator interface generated for a seperate
  1045. # iterable interface, skip generating type includes, as we have
  1046. # what we need in IterableIterator.h
  1047. if desc.interface.isExternal() or desc.interface.isIteratorInterface():
  1048. continue
  1049. for m in desc.interface.members:
  1050. addHeaderForFunc(PropertyDefiner.getStringAttr(m, "Func"), desc)
  1051. staticTypeOverride = PropertyDefiner.getStringAttr(m, "StaticClassOverride")
  1052. if staticTypeOverride:
  1053. bindingHeaders.add("/".join(staticTypeOverride.split("::")) + ".h")
  1054. # getExtendedAttribute() returns a list, extract the entry.
  1055. funcList = desc.interface.getExtendedAttribute("Func")
  1056. if funcList is not None:
  1057. addHeaderForFunc(funcList[0], desc)
  1058. if desc.interface.maplikeOrSetlikeOrIterable:
  1059. # We need ToJSValue.h for maplike/setlike type conversions
  1060. bindingHeaders.add("mozilla/dom/ToJSValue.h")
  1061. # Add headers for the key and value types of the
  1062. # maplike/setlike/iterable, since they'll be needed for
  1063. # convenience functions
  1064. if desc.interface.maplikeOrSetlikeOrIterable.hasKeyType():
  1065. addHeadersForType((desc.interface.maplikeOrSetlikeOrIterable.keyType,
  1066. None))
  1067. if desc.interface.maplikeOrSetlikeOrIterable.hasValueType():
  1068. addHeadersForType((desc.interface.maplikeOrSetlikeOrIterable.valueType,
  1069. None))
  1070. for d in dictionaries:
  1071. if d.parent:
  1072. declareIncludes.add(self.getDeclarationFilename(d.parent))
  1073. bindingHeaders.add(self.getDeclarationFilename(d))
  1074. for m in d.members:
  1075. addHeaderForFunc(PropertyDefiner.getStringAttr(m, "Func"),
  1076. None)
  1077. # No need to worry about Func on members of ancestors, because that
  1078. # will happen automatically in whatever files those ancestors live
  1079. # in.
  1080. for c in callbacks:
  1081. bindingHeaders.add(self.getDeclarationFilename(c))
  1082. for c in callbackDescriptors:
  1083. bindingHeaders.add(self.getDeclarationFilename(c.interface))
  1084. if len(callbacks) != 0:
  1085. # We need CallbackFunction to serve as our parent class
  1086. declareIncludes.add("mozilla/dom/CallbackFunction.h")
  1087. # And we need ToJSValue.h so we can wrap "this" objects
  1088. declareIncludes.add("mozilla/dom/ToJSValue.h")
  1089. if len(callbackDescriptors) != 0 or len(jsImplementedDescriptors) != 0:
  1090. # We need CallbackInterface to serve as our parent class
  1091. declareIncludes.add("mozilla/dom/CallbackInterface.h")
  1092. # And we need ToJSValue.h so we can wrap "this" objects
  1093. declareIncludes.add("mozilla/dom/ToJSValue.h")
  1094. # Also need to include the headers for ancestors of
  1095. # JS-implemented interfaces.
  1096. for jsImplemented in jsImplementedDescriptors:
  1097. jsParent = jsImplemented.interface.parent
  1098. if jsParent:
  1099. parentDesc = jsImplemented.getDescriptor(jsParent.identifier.name)
  1100. declareIncludes.add(parentDesc.jsImplParentHeader)
  1101. # Let the machinery do its thing.
  1102. def _includeString(includes):
  1103. return ''.join(['#include "%s"\n' % i for i in includes]) + '\n'
  1104. CGWrapper.__init__(self, child,
  1105. declarePre=_includeString(sorted(declareIncludes)),
  1106. definePre=_includeString(sorted(set(defineIncludes) |
  1107. bindingIncludes |
  1108. bindingHeaders |
  1109. hasInstanceIncludes |
  1110. implementationIncludes)))
  1111. @staticmethod
  1112. def getDeclarationFilename(decl):
  1113. # Use our local version of the header, not the exported one, so that
  1114. # test bindings, which don't export, will work correctly.
  1115. basename = os.path.basename(decl.filename())
  1116. return basename.replace('.webidl', 'Binding.h')
  1117. @staticmethod
  1118. def getUnionDeclarationFilename(config, unionType):
  1119. assert unionType.isUnion()
  1120. assert unionType.unroll() == unionType
  1121. # If a union is "defined" in multiple files, it goes in UnionTypes.h.
  1122. if len(config.filenamesPerUnion[unionType.name]) > 1:
  1123. return "mozilla/dom/UnionTypes.h"
  1124. # If a union is defined by a built-in typedef, it also goes in
  1125. # UnionTypes.h.
  1126. assert len(config.filenamesPerUnion[unionType.name]) == 1
  1127. if "<unknown>" in config.filenamesPerUnion[unionType.name]:
  1128. return "mozilla/dom/UnionTypes.h"
  1129. return CGHeaders.getDeclarationFilename(unionType)
  1130. def SortedDictValues(d):
  1131. """
  1132. Returns a list of values from the dict sorted by key.
  1133. """
  1134. return [v for k, v in sorted(d.items())]
  1135. def UnionsForFile(config, webIDLFile):
  1136. """
  1137. Returns a list of union types for all union types that are only used in
  1138. webIDLFile. If webIDLFile is None this will return the list of tuples for
  1139. union types that are used in more than one WebIDL file.
  1140. """
  1141. return config.unionsPerFilename.get(webIDLFile, [])
  1142. def UnionTypes(unionTypes, config):
  1143. """
  1144. The unionTypes argument should be a list of union types. This is typically
  1145. the list generated by UnionsForFile.
  1146. Returns a tuple containing a set of header filenames to include in
  1147. the header for the types in unionTypes, a set of header filenames to
  1148. include in the implementation file for the types in unionTypes, a set
  1149. of tuples containing a type declaration and a boolean if the type is a
  1150. struct for member types of the union, a list of traverse methods,
  1151. unlink methods and a list of union types. These last three lists only
  1152. contain unique union types.
  1153. """
  1154. headers = set()
  1155. implheaders = set()
  1156. declarations = set()
  1157. unionStructs = dict()
  1158. traverseMethods = dict()
  1159. unlinkMethods = dict()
  1160. for t in unionTypes:
  1161. name = str(t)
  1162. if name not in unionStructs:
  1163. unionStructs[name] = t
  1164. def addHeadersForType(f):
  1165. if f.nullable():
  1166. headers.add("mozilla/dom/Nullable.h")
  1167. isSequence = f.isSequence()
  1168. f = f.unroll()
  1169. if f.isPromise():
  1170. headers.add("mozilla/dom/Promise.h")
  1171. # We need ToJSValue to do the Promise to JS conversion.
  1172. headers.add("mozilla/dom/ToJSValue.h")
  1173. elif f.isInterface():
  1174. if f.isSpiderMonkeyInterface():
  1175. headers.add("jsfriendapi.h")
  1176. headers.add("mozilla/dom/TypedArray.h")
  1177. else:
  1178. try:
  1179. typeDesc = config.getDescriptor(f.inner.identifier.name)
  1180. except NoSuchDescriptorError:
  1181. return
  1182. if typeDesc.interface.isCallback() or isSequence:
  1183. # Callback interfaces always use strong refs, so
  1184. # we need to include the right header to be able
  1185. # to Release() in our inlined code.
  1186. #
  1187. # Similarly, sequences always contain strong
  1188. # refs, so we'll need the header to handler
  1189. # those.
  1190. headers.add(typeDesc.headerFile)
  1191. else:
  1192. declarations.add((typeDesc.nativeType, False))
  1193. implheaders.add(typeDesc.headerFile)
  1194. elif f.isDictionary():
  1195. # For a dictionary, we need to see its declaration in
  1196. # UnionTypes.h so we have its sizeof and know how big to
  1197. # make our union.
  1198. headers.add(CGHeaders.getDeclarationFilename(f.inner))
  1199. # And if it needs rooting, we need RootedDictionary too
  1200. if typeNeedsRooting(f):
  1201. headers.add("mozilla/dom/RootedDictionary.h")
  1202. elif f.isEnum():
  1203. # Need to see the actual definition of the enum,
  1204. # unfortunately.
  1205. headers.add(CGHeaders.getDeclarationFilename(f.inner))
  1206. elif f.isCallback():
  1207. # Callbacks always use strong refs, so we need to include
  1208. # the right header to be able to Release() in our inlined
  1209. # code.
  1210. headers.add(CGHeaders.getDeclarationFilename(f.callback))
  1211. elif f.isRecord():
  1212. headers.add("mozilla/dom/Record.h")
  1213. # And add headers for the type we're parametrized over
  1214. addHeadersForType(f.inner)
  1215. implheaders.add(CGHeaders.getUnionDeclarationFilename(config, t))
  1216. for f in t.flatMemberTypes:
  1217. assert not f.nullable()
  1218. addHeadersForType(f)
  1219. if idlTypeNeedsCycleCollection(t):
  1220. declarations.add(("mozilla::dom::%s" % CGUnionStruct.unionTypeName(t, True), False))
  1221. traverseMethods[name] = CGCycleCollectionTraverseForOwningUnionMethod(t)
  1222. unlinkMethods[name] = CGCycleCollectionUnlinkForOwningUnionMethod(t)
  1223. # The order of items in CGList is important.
  1224. # Since the union structs friend the unlinkMethods, the forward-declaration
  1225. # for these methods should come before the class declaration. Otherwise
  1226. # some compilers treat the friend declaration as a forward-declaration in
  1227. # the class scope.
  1228. return (headers, implheaders, declarations,
  1229. SortedDictValues(traverseMethods), SortedDictValues(unlinkMethods),
  1230. SortedDictValues(unionStructs))
  1231. def UnionConversions(unionTypes, config):
  1232. """
  1233. The unionTypes argument should be a list of tuples, each containing two
  1234. elements: a union type and a descriptor. This is typically the list
  1235. generated by UnionsForFile.
  1236. Returns a tuple containing a list of headers and a CGThing to declare all
  1237. union argument conversion helper structs.
  1238. """
  1239. headers = set()
  1240. unionConversions = dict()
  1241. for t in unionTypes:
  1242. name = str(t)
  1243. if name not in unionConversions:
  1244. unionConversions[name] = CGUnionConversionStruct(t, config)
  1245. def addHeadersForType(f):
  1246. f = f.unroll()
  1247. if f.isPromise():
  1248. headers.add("mozilla/dom/Promise.h")
  1249. # We need ToJSValue to do the Promise to JS conversion.
  1250. headers.add("mozilla/dom/ToJSValue.h")
  1251. elif f.isInterface():
  1252. if f.isSpiderMonkeyInterface():
  1253. headers.add("jsfriendapi.h")
  1254. headers.add("mozilla/dom/TypedArray.h")
  1255. elif f.inner.isExternal():
  1256. try:
  1257. typeDesc = config.getDescriptor(f.inner.identifier.name)
  1258. except NoSuchDescriptorError:
  1259. return
  1260. headers.add(typeDesc.headerFile)
  1261. else:
  1262. headers.add(CGHeaders.getDeclarationFilename(f.inner))
  1263. elif f.isDictionary():
  1264. headers.add(CGHeaders.getDeclarationFilename(f.inner))
  1265. elif f.isPrimitive():
  1266. headers.add("mozilla/dom/PrimitiveConversions.h")
  1267. elif f.isRecord():
  1268. headers.add("mozilla/dom/Record.h")
  1269. # And the internal type of the record
  1270. addHeadersForType(f.inner)
  1271. # We plan to include UnionTypes.h no matter what, so it's
  1272. # OK if we throw it into the set here.
  1273. headers.add(CGHeaders.getUnionDeclarationFilename(config, t))
  1274. for f in t.flatMemberTypes:
  1275. addHeadersForType(f)
  1276. return (headers,
  1277. CGWrapper(CGList(SortedDictValues(unionConversions), "\n"),
  1278. post="\n\n"))
  1279. class Argument():
  1280. """
  1281. A class for outputting the type and name of an argument
  1282. """
  1283. def __init__(self, argType, name, default=None):
  1284. self.argType = argType
  1285. self.name = name
  1286. self.default = default
  1287. def declare(self):
  1288. string = self.argType + ' ' + self.name
  1289. if self.default is not None:
  1290. string += " = " + self.default
  1291. return string
  1292. def define(self):
  1293. return self.argType + ' ' + self.name
  1294. class CGAbstractMethod(CGThing):
  1295. """
  1296. An abstract class for generating code for a method. Subclasses
  1297. should override definition_body to create the actual code.
  1298. descriptor is the descriptor for the interface the method is associated with
  1299. name is the name of the method as a string
  1300. returnType is the IDLType of the return value
  1301. args is a list of Argument objects
  1302. inline should be True to generate an inline method, whose body is
  1303. part of the declaration.
  1304. alwaysInline should be True to generate an inline method annotated with
  1305. MOZ_ALWAYS_INLINE.
  1306. static should be True to generate a static method, which only has
  1307. a definition.
  1308. If templateArgs is not None it should be a list of strings containing
  1309. template arguments, and the function will be templatized using those
  1310. arguments.
  1311. """
  1312. def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, templateArgs=None):
  1313. CGThing.__init__(self)
  1314. self.descriptor = descriptor
  1315. self.name = name
  1316. self.returnType = returnType
  1317. self.args = args
  1318. self.inline = inline
  1319. self.alwaysInline = alwaysInline
  1320. self.static = static
  1321. self.templateArgs = templateArgs
  1322. def _argstring(self, declare):
  1323. return ', '.join([a.declare() if declare else a.define() for a in self.args])
  1324. def _template(self):
  1325. if self.templateArgs is None:
  1326. return ''
  1327. return 'template <%s>\n' % ', '.join(self.templateArgs)
  1328. def _decorators(self):
  1329. decorators = []
  1330. if self.alwaysInline:
  1331. decorators.append('MOZ_ALWAYS_INLINE')
  1332. elif self.inline:
  1333. decorators.append('inline')
  1334. if self.static:
  1335. decorators.append('static')
  1336. decorators.append(self.returnType)
  1337. maybeNewline = " " if self.inline else "\n"
  1338. return ' '.join(decorators) + maybeNewline
  1339. def declare(self):
  1340. if self.inline:
  1341. return self._define(True)
  1342. return "%s%s%s(%s);\n" % (self._template(), self._decorators(), self.name, self._argstring(True))
  1343. def indent_body(self, body):
  1344. """
  1345. Indent the code returned by self.definition_body(). Most classes
  1346. simply indent everything two spaces. This is here for
  1347. CGRegisterProtos, which needs custom indentation.
  1348. """
  1349. return indent(body)
  1350. def _define(self, fromDeclare=False):
  1351. return (self.definition_prologue(fromDeclare) +
  1352. self.indent_body(self.definition_body()) +
  1353. self.definition_epilogue())
  1354. def define(self):
  1355. return "" if self.inline else self._define()
  1356. def definition_prologue(self, fromDeclare):
  1357. return "%s%s%s(%s)\n{\n" % (self._template(), self._decorators(),
  1358. self.name, self._argstring(fromDeclare))
  1359. def definition_epilogue(self):
  1360. return "}\n"
  1361. def definition_body(self):
  1362. assert False # Override me!
  1363. class CGAbstractStaticMethod(CGAbstractMethod):
  1364. """
  1365. Abstract base class for codegen of implementation-only (no
  1366. declaration) static methods.
  1367. """
  1368. def __init__(self, descriptor, name, returnType, args):
  1369. CGAbstractMethod.__init__(self, descriptor, name, returnType, args,
  1370. inline=False, static=True)
  1371. def declare(self):
  1372. # We only have implementation
  1373. return ""
  1374. class CGAbstractClassHook(CGAbstractStaticMethod):
  1375. """
  1376. Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
  1377. 'this' unwrapping as it assumes that the unwrapped type is always known.
  1378. """
  1379. def __init__(self, descriptor, name, returnType, args):
  1380. CGAbstractStaticMethod.__init__(self, descriptor, name, returnType,
  1381. args)
  1382. def definition_body_prologue(self):
  1383. return ("%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(obj);\n" %
  1384. (self.descriptor.nativeType, self.descriptor.nativeType))
  1385. def definition_body(self):
  1386. return self.definition_body_prologue() + self.generate_code()
  1387. def generate_code(self):
  1388. assert False # Override me!
  1389. class CGGetJSClassMethod(CGAbstractMethod):
  1390. def __init__(self, descriptor):
  1391. CGAbstractMethod.__init__(self, descriptor, 'GetJSClass', 'const JSClass*',
  1392. [])
  1393. def definition_body(self):
  1394. return "return sClass.ToJSClass();\n"
  1395. class CGAddPropertyHook(CGAbstractClassHook):
  1396. """
  1397. A hook for addProperty, used to preserve our wrapper from GC.
  1398. """
  1399. def __init__(self, descriptor):
  1400. args = [Argument('JSContext*', 'cx'),
  1401. Argument('JS::Handle<JSObject*>', 'obj'),
  1402. Argument('JS::Handle<jsid>', 'id'),
  1403. Argument('JS::Handle<JS::Value>', 'val')]
  1404. CGAbstractClassHook.__init__(self, descriptor, ADDPROPERTY_HOOK_NAME,
  1405. 'bool', args)
  1406. def generate_code(self):
  1407. assert self.descriptor.wrapperCache
  1408. return dedent("""
  1409. // We don't want to preserve if we don't have a wrapper, and we
  1410. // obviously can't preserve if we're not initialized.
  1411. if (self && self->GetWrapperPreserveColor()) {
  1412. PreserveWrapper(self);
  1413. }
  1414. return true;
  1415. """)
  1416. def finalizeHook(descriptor, hookName, freeOp):
  1417. finalize = ""
  1418. if descriptor.wrapperCache:
  1419. finalize += "ClearWrapper(self, self);\n"
  1420. if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  1421. finalize += "self->mExpandoAndGeneration.expando = JS::UndefinedValue();\n"
  1422. if descriptor.isGlobal():
  1423. finalize += "mozilla::dom::FinalizeGlobal(CastToJSFreeOp(%s), obj);\n" % freeOp
  1424. finalize += ("AddForDeferredFinalization<%s>(self);\n" %
  1425. descriptor.nativeType)
  1426. return CGIfWrapper(CGGeneric(finalize), "self")
  1427. class CGClassFinalizeHook(CGAbstractClassHook):
  1428. """
  1429. A hook for finalize, used to release our native object.
  1430. """
  1431. def __init__(self, descriptor):
  1432. args = [Argument('js::FreeOp*', 'fop'), Argument('JSObject*', 'obj')]
  1433. CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
  1434. 'void', args)
  1435. def generate_code(self):
  1436. return finalizeHook(self.descriptor, self.name, self.args[0].name).define()
  1437. class CGClassObjectMovedHook(CGAbstractClassHook):
  1438. """
  1439. A hook for objectMovedOp, used to update the wrapper cache when an object it
  1440. is holding moves.
  1441. """
  1442. def __init__(self, descriptor):
  1443. args = [Argument('JSObject*', 'obj'), Argument('const JSObject*', 'old')]
  1444. CGAbstractClassHook.__init__(self, descriptor, OBJECT_MOVED_HOOK_NAME,
  1445. 'void', args)
  1446. def generate_code(self):
  1447. assert self.descriptor.wrapperCache
  1448. return CGIfWrapper(CGGeneric("UpdateWrapper(self, self, obj, old);\n"),
  1449. "self").define()
  1450. def JSNativeArguments():
  1451. return [Argument('JSContext*', 'cx'),
  1452. Argument('unsigned', 'argc'),
  1453. Argument('JS::Value*', 'vp')]
  1454. class CGClassConstructor(CGAbstractStaticMethod):
  1455. """
  1456. JS-visible constructor for our objects
  1457. """
  1458. def __init__(self, descriptor, ctor, name=CONSTRUCT_HOOK_NAME):
  1459. CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool',
  1460. JSNativeArguments())
  1461. self._ctor = ctor
  1462. def define(self):
  1463. if not self._ctor:
  1464. return ""
  1465. return CGAbstractStaticMethod.define(self)
  1466. def definition_body(self):
  1467. return self.generate_code()
  1468. def generate_code(self):
  1469. # [ChromeOnly] interfaces may only be constructed by chrome.
  1470. chromeOnlyCheck = ""
  1471. if isChromeOnly(self._ctor):
  1472. chromeOnlyCheck = dedent("""
  1473. if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
  1474. return ThrowingConstructor(cx, argc, vp);
  1475. }
  1476. """)
  1477. # Additionally, we want to throw if a caller does a bareword invocation
  1478. # of a constructor without |new|. We don't enforce this for chrome in
  1479. # realease builds to avoid the addon compat fallout of making that
  1480. # change. See bug 916644.
  1481. #
  1482. # Figure out the name of our constructor for error reporting purposes.
  1483. # For unnamed webidl constructors, identifier.name is "constructor" but
  1484. # the name JS sees is the interface name; for named constructors
  1485. # identifier.name is the actual name.
  1486. name = self._ctor.identifier.name
  1487. if name != "constructor":
  1488. ctorName = name
  1489. else:
  1490. ctorName = self.descriptor.interface.identifier.name
  1491. # [HTMLConstructor] for custom element
  1492. # This needs to live in bindings code because it directly examines
  1493. # newtarget and the callee function to do HTMLConstructor specific things.
  1494. if self._ctor.isHTMLConstructor():
  1495. htmlConstructorSanityCheck = dedent("""
  1496. // The newTarget might be a cross-compartment wrapper. Get the underlying object
  1497. // so we can do the spec's object-identity checks.
  1498. JS::Rooted<JSObject*> newTarget(cx, js::CheckedUnwrap(&args.newTarget().toObject()));
  1499. if (!newTarget) {
  1500. return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
  1501. }
  1502. // Step 2 of https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor.
  1503. // Enter the compartment of our underlying newTarget object, so we end
  1504. // up comparing to the constructor object for our interface from that global.
  1505. {
  1506. JSAutoCompartment ac(cx, newTarget);
  1507. JS::Handle<JSObject*> constructor(GetConstructorObjectHandle(cx));
  1508. if (!constructor) {
  1509. return false;
  1510. }
  1511. if (newTarget == constructor) {
  1512. return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
  1513. }
  1514. }
  1515. """)
  1516. # If we are unable to get desired prototype from newTarget, then we
  1517. # fall back to the interface prototype object from newTarget's realm.
  1518. htmlConstructorFallback = dedent("""
  1519. if (!desiredProto) {
  1520. // Step 7 of https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor.
  1521. // This fallback behavior is designed to match analogous behavior for the
  1522. // JavaScript built-ins. So we enter the compartment of our underlying
  1523. // newTarget object and fall back to the prototype object from that global.
  1524. // XXX The spec says to use GetFunctionRealm(), which is not actually
  1525. // the same thing as what we have here (e.g. in the case of scripted callable proxies
  1526. // whose target is not same-compartment with the proxy, or bound functions, etc).
  1527. // https://bugzilla.mozilla.org/show_bug.cgi?id=1317658
  1528. {
  1529. JSAutoCompartment ac(cx, newTarget);
  1530. desiredProto = GetProtoObjectHandle(cx);
  1531. if (!desiredProto) {
  1532. return false;
  1533. }
  1534. }
  1535. // desiredProto is in the compartment of the underlying newTarget object.
  1536. // Wrap it into the context compartment.
  1537. if (!JS_WrapObject(cx, &desiredProto)) {
  1538. return false;
  1539. }
  1540. }
  1541. """)
  1542. else:
  1543. htmlConstructorSanityCheck = ""
  1544. htmlConstructorFallback = ""
  1545. # If we're a constructor, "obj" may not be a function, so calling
  1546. # XrayAwareCalleeGlobal() on it is not safe. Of course in the
  1547. # constructor case either "obj" is an Xray or we're already in the
  1548. # content compartment, not the Xray compartment, so just
  1549. # constructing the GlobalObject from "obj" is fine.
  1550. preamble = fill(
  1551. """
  1552. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  1553. JS::Rooted<JSObject*> obj(cx, &args.callee());
  1554. $*{chromeOnlyCheck}
  1555. if (!args.isConstructing()) {
  1556. // XXXbz wish I could get the name from the callee instead of
  1557. // Adding more relocations
  1558. return ThrowConstructorWithoutNew(cx, "${ctorName}");
  1559. }
  1560. GlobalObject global(cx, obj);
  1561. if (global.Failed()) {
  1562. return false;
  1563. }
  1564. $*{htmlConstructorSanityCheck}
  1565. JS::Rooted<JSObject*> desiredProto(cx);
  1566. if (!GetDesiredProto(cx, args, &desiredProto)) {
  1567. return false;
  1568. }
  1569. $*{htmlConstructorFallback}
  1570. """,
  1571. chromeOnlyCheck=chromeOnlyCheck,
  1572. ctorName=ctorName,
  1573. htmlConstructorSanityCheck=htmlConstructorSanityCheck,
  1574. htmlConstructorFallback=htmlConstructorFallback)
  1575. if self._ctor.isHTMLConstructor():
  1576. signatures = self._ctor.signatures()
  1577. assert len(signatures) == 1
  1578. # Given that HTMLConstructor takes no args, we can just codegen a
  1579. # call to CreateHTMLElement() in BindingUtils which reuses the
  1580. # factory thing in HTMLContentSink. Then we don't have to implement
  1581. # Constructor on all the HTML elements.
  1582. callGenerator = CGPerSignatureCall(signatures[0][0], signatures[0][1],
  1583. "CreateHTMLElement", True,
  1584. self.descriptor, self._ctor,
  1585. isConstructor=True)
  1586. else:
  1587. name = self._ctor.identifier.name
  1588. nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
  1589. callGenerator = CGMethodCall(nativeName, True, self.descriptor,
  1590. self._ctor, isConstructor=True,
  1591. constructorName=ctorName)
  1592. return preamble + "\n" + callGenerator.define()
  1593. # Encapsulate the constructor in a helper method to share genConstructorBody with CGJSImplMethod.
  1594. class CGConstructNavigatorObject(CGAbstractMethod):
  1595. """
  1596. Construct a new JS-implemented WebIDL DOM object, for use on navigator.
  1597. """
  1598. def __init__(self, descriptor):
  1599. args = [Argument('JSContext*', 'cx'),
  1600. Argument('JS::Handle<JSObject*>', 'obj'),
  1601. Argument('ErrorResult&', 'aRv')]
  1602. rtype = 'already_AddRefed<%s>' % descriptor.name
  1603. CGAbstractMethod.__init__(self, descriptor, "ConstructNavigatorObject",
  1604. rtype, args)
  1605. def definition_body(self):
  1606. if not self.descriptor.interface.isJSImplemented():
  1607. raise TypeError("Only JS-implemented classes are currently supported "
  1608. "on navigator. See bug 856820.")
  1609. return dedent(
  1610. """
  1611. GlobalObject global(cx, obj);
  1612. if (global.Failed()) {
  1613. aRv.Throw(NS_ERROR_FAILURE);
  1614. return nullptr;
  1615. }
  1616. """) + genConstructorBody(self.descriptor)
  1617. def NamedConstructorName(m):
  1618. return '_' + m.identifier.name
  1619. class CGNamedConstructors(CGThing):
  1620. def __init__(self, descriptor):
  1621. self.descriptor = descriptor
  1622. CGThing.__init__(self)
  1623. def declare(self):
  1624. return ""
  1625. def define(self):
  1626. if len(self.descriptor.interface.namedConstructors) == 0:
  1627. return ""
  1628. constructorID = "constructors::id::"
  1629. if self.descriptor.interface.hasInterfaceObject():
  1630. constructorID += self.descriptor.name
  1631. else:
  1632. constructorID += "_ID_Count"
  1633. namedConstructors = ""
  1634. for n in self.descriptor.interface.namedConstructors:
  1635. namedConstructors += (
  1636. "{ \"%s\", { %s, &sNamedConstructorNativePropertyHooks }, %i },\n" %
  1637. (n.identifier.name, NamedConstructorName(n), methodLength(n)))
  1638. return fill(
  1639. """
  1640. const NativePropertyHooks sNamedConstructorNativePropertyHooks = {
  1641. nullptr,
  1642. nullptr,
  1643. nullptr,
  1644. { nullptr, nullptr },
  1645. prototypes::id::${name},
  1646. ${constructorID},
  1647. nullptr
  1648. };
  1649. static const NamedConstructor namedConstructors[] = {
  1650. $*{namedConstructors}
  1651. { nullptr, { nullptr, nullptr }, 0 }
  1652. };
  1653. """,
  1654. name=self.descriptor.name,
  1655. constructorID=constructorID,
  1656. namedConstructors=namedConstructors)
  1657. class CGHasInstanceHook(CGAbstractStaticMethod):
  1658. def __init__(self, descriptor):
  1659. args = [Argument('JSContext*', 'cx'),
  1660. Argument('unsigned', 'argc'),
  1661. Argument('JS::Value*', 'vp')]
  1662. assert descriptor.interface.hasInterfaceObject()
  1663. assert NeedsGeneratedHasInstance(descriptor)
  1664. CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME,
  1665. 'bool', args)
  1666. def define(self):
  1667. return CGAbstractStaticMethod.define(self)
  1668. def definition_body(self):
  1669. return self.generate_code()
  1670. def generate_code(self):
  1671. header = dedent("""
  1672. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  1673. if (!args.get(0).isObject()) {
  1674. args.rval().setBoolean(false);
  1675. return true;
  1676. }
  1677. JS::Rooted<JSObject*> instance(cx, &args[0].toObject());
  1678. """)
  1679. if self.descriptor.interface.hasInterfacePrototypeObject():
  1680. return (
  1681. header +
  1682. fill(
  1683. """
  1684. static_assert(IsBaseOf<nsISupports, ${nativeType}>::value,
  1685. "HasInstance only works for nsISupports-based classes.");
  1686. bool ok = InterfaceHasInstance(cx, argc, vp);
  1687. if (!ok || args.rval().toBoolean()) {
  1688. return ok;
  1689. }
  1690. // FIXME Limit this to chrome by checking xpc::AccessCheck::isChrome(obj).
  1691. nsCOMPtr<nsISupports> native =
  1692. xpc::UnwrapReflectorToISupports(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
  1693. nsCOMPtr<nsIDOM${name}> qiResult = do_QueryInterface(native);
  1694. args.rval().setBoolean(!!qiResult);
  1695. return true;
  1696. """,
  1697. nativeType=self.descriptor.nativeType,
  1698. name=self.descriptor.interface.identifier.name))
  1699. hasInstanceCode = dedent("""
  1700. const DOMJSClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
  1701. if (!domClass) {
  1702. // Not a DOM object, so certainly not an instance of this interface
  1703. args.rval().setBoolean(false);
  1704. return true;
  1705. }
  1706. """)
  1707. if self.descriptor.interface.identifier.name == "ChromeWindow":
  1708. setRval = "args.rval().setBoolean(UnwrapDOMObject<nsGlobalWindow>(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false))->IsChromeWindow())"
  1709. else:
  1710. setRval = "args.rval().setBoolean(true)"
  1711. # Sort interaces implementing self by name so we get stable output.
  1712. for iface in sorted(self.descriptor.interface.interfacesImplementingSelf,
  1713. key=lambda iface: iface.identifier.name):
  1714. hasInstanceCode += fill(
  1715. """
  1716. if (domClass->mInterfaceChain[PrototypeTraits<prototypes::id::${name}>::Depth] == prototypes::id::${name}) {
  1717. ${setRval};
  1718. return true;
  1719. }
  1720. """,
  1721. name=iface.identifier.name,
  1722. setRval=setRval)
  1723. hasInstanceCode += ("args.rval().setBoolean(false);\n"
  1724. "return true;\n")
  1725. return header + hasInstanceCode
  1726. def isChromeOnly(m):
  1727. return m.getExtendedAttribute("ChromeOnly")
  1728. class MemberCondition:
  1729. """
  1730. An object representing the condition for a member to actually be
  1731. exposed. Any of the arguments can be None. If not
  1732. None, they should have the following types:
  1733. pref: The name of the preference.
  1734. func: The name of the function.
  1735. secureContext: A bool indicating whether a secure context is required.
  1736. nonExposedGlobals: A set of names of globals. Can be empty, in which case
  1737. it's treated the same way as None.
  1738. """
  1739. def __init__(self, pref=None, func=None, secureContext=False,
  1740. nonExposedGlobals=None):
  1741. assert pref is None or isinstance(pref, str)
  1742. assert func is None or isinstance(func, str)
  1743. assert isinstance(secureContext, bool)
  1744. assert nonExposedGlobals is None or isinstance(nonExposedGlobals, set)
  1745. self.pref = pref
  1746. self.secureContext = secureContext
  1747. def toFuncPtr(val):
  1748. if val is None:
  1749. return "nullptr"
  1750. return "&" + val
  1751. self.func = toFuncPtr(func)
  1752. if nonExposedGlobals:
  1753. # Nonempty set
  1754. self.nonExposedGlobals = " | ".join(
  1755. map(lambda g: "GlobalNames::%s" % g,
  1756. sorted(nonExposedGlobals)))
  1757. else:
  1758. self.nonExposedGlobals = "0"
  1759. def __eq__(self, other):
  1760. return (self.pref == other.pref and self.func == other.func and
  1761. self.secureContext == other.secureContext and
  1762. self.nonExposedGlobals == other.nonExposedGlobals)
  1763. def __ne__(self, other):
  1764. return not self.__eq__(other)
  1765. def hasDisablers(self):
  1766. return (self.pref is not None or
  1767. self.secureContext or
  1768. self.func != "nullptr" or
  1769. self.nonExposedGlobals != "0")
  1770. class PropertyDefiner:
  1771. """
  1772. A common superclass for defining things on prototype objects.
  1773. Subclasses should implement generateArray to generate the actual arrays of
  1774. things we're defining. They should also set self.chrome to the list of
  1775. things only exposed to chrome and self.regular to the list of things exposed
  1776. to both chrome and web pages.
  1777. """
  1778. def __init__(self, descriptor, name):
  1779. self.descriptor = descriptor
  1780. self.name = name
  1781. # self.prefCacheData will store an array of (prefname, bool*)
  1782. # pairs for our bool var caches. generateArray will fill it
  1783. # in as needed.
  1784. self.prefCacheData = []
  1785. def hasChromeOnly(self):
  1786. return len(self.chrome) > 0
  1787. def hasNonChromeOnly(self):
  1788. return len(self.regular) > 0
  1789. def variableName(self, chrome):
  1790. if chrome:
  1791. if self.hasChromeOnly():
  1792. return "sChrome" + self.name
  1793. else:
  1794. if self.hasNonChromeOnly():
  1795. return "s" + self.name
  1796. return "nullptr"
  1797. def usedForXrays(self):
  1798. return self.descriptor.wantsXrays
  1799. def __str__(self):
  1800. # We only need to generate id arrays for things that will end
  1801. # up used via ResolveProperty or EnumerateProperties.
  1802. str = self.generateArray(self.regular, self.variableName(False),
  1803. self.usedForXrays())
  1804. if self.hasChromeOnly():
  1805. str += self.generateArray(self.chrome, self.variableName(True),
  1806. self.usedForXrays())
  1807. return str
  1808. @staticmethod
  1809. def getStringAttr(member, name):
  1810. attr = member.getExtendedAttribute(name)
  1811. if attr is None:
  1812. return None
  1813. # It's a list of strings
  1814. assert len(attr) == 1
  1815. assert attr[0] is not None
  1816. return attr[0]
  1817. @staticmethod
  1818. def getControllingCondition(interfaceMember, descriptor):
  1819. interface = descriptor.interface
  1820. nonExposureSet = interface.exposureSet - interfaceMember.exposureSet
  1821. return MemberCondition(
  1822. PropertyDefiner.getStringAttr(interfaceMember,
  1823. "Pref"),
  1824. PropertyDefiner.getStringAttr(interfaceMember,
  1825. "Func"),
  1826. interfaceMember.getExtendedAttribute("SecureContext") is not None,
  1827. nonExposureSet)
  1828. def generatePrefableArray(self, array, name, specFormatter, specTerminator,
  1829. specType, getCondition, getDataTuple, doIdArrays):
  1830. """
  1831. This method generates our various arrays.
  1832. array is an array of interface members as passed to generateArray
  1833. name is the name as passed to generateArray
  1834. specFormatter is a function that takes a single argument, a tuple,
  1835. and returns a string, a spec array entry
  1836. specTerminator is a terminator for the spec array (inserted every time
  1837. our controlling pref changes and at the end of the array)
  1838. specType is the actual typename of our spec
  1839. getCondition is a callback function that takes an array entry and
  1840. returns the corresponding MemberCondition.
  1841. getDataTuple is a callback function that takes an array entry and
  1842. returns a tuple suitable to be passed to specFormatter.
  1843. """
  1844. # We want to generate a single list of specs, but with specTerminator
  1845. # inserted at every point where the pref name controlling the member
  1846. # changes. That will make sure the order of the properties as exposed
  1847. # on the interface and interface prototype objects does not change when
  1848. # pref control is added to members while still allowing us to define all
  1849. # the members in the smallest number of JSAPI calls.
  1850. assert len(array) != 0
  1851. # So we won't put a specTerminator at the very front of the list:
  1852. lastCondition = getCondition(array[0], self.descriptor)
  1853. specs = []
  1854. disablers = []
  1855. prefableSpecs = []
  1856. disablersTemplate = dedent(
  1857. """
  1858. static PrefableDisablers %s_disablers%d = {
  1859. true, %s, %s, %s
  1860. };
  1861. """)
  1862. prefableWithDisablersTemplate = ' { &%s_disablers%d, &%s_specs[%d] }'
  1863. prefableWithoutDisablersTemplate = ' { nullptr, &%s_specs[%d] }'
  1864. prefCacheTemplate = '&%s[%d].disablers->enabled'
  1865. def switchToCondition(props, condition):
  1866. # Remember the info about where our pref-controlled
  1867. # booleans live.
  1868. if condition.pref is not None:
  1869. props.prefCacheData.append(
  1870. (condition.pref,
  1871. prefCacheTemplate % (name, len(prefableSpecs))))
  1872. # Set up pointers to the new sets of specs inside prefableSpecs
  1873. if condition.hasDisablers():
  1874. prefableSpecs.append(prefableWithDisablersTemplate %
  1875. (name, len(specs), name, len(specs)))
  1876. disablers.append(disablersTemplate %
  1877. (name, len(specs),
  1878. toStringBool(condition.secureContext),
  1879. condition.nonExposedGlobals,
  1880. condition.func))
  1881. else:
  1882. prefableSpecs.append(prefableWithoutDisablersTemplate %
  1883. (name, len(specs)))
  1884. switchToCondition(self, lastCondition)
  1885. for member in array:
  1886. curCondition = getCondition(member, self.descriptor)
  1887. if lastCondition != curCondition:
  1888. # Terminate previous list
  1889. specs.append(specTerminator)
  1890. # And switch to our new condition
  1891. switchToCondition(self, curCondition)
  1892. lastCondition = curCondition
  1893. # And the actual spec
  1894. specs.append(specFormatter(getDataTuple(member)))
  1895. specs.append(specTerminator)
  1896. prefableSpecs.append(" { nullptr, nullptr }")
  1897. specType = "const " + specType
  1898. arrays = fill(
  1899. """
  1900. static ${specType} ${name}_specs[] = {
  1901. ${specs}
  1902. };
  1903. ${disablers}
  1904. // Can't be const because the pref-enabled boolean needs to be writable
  1905. static Prefable<${specType}> ${name}[] = {
  1906. ${prefableSpecs}
  1907. };
  1908. """,
  1909. specType=specType,
  1910. name=name,
  1911. disablers='\n'.join(disablers),
  1912. specs=',\n'.join(specs),
  1913. prefableSpecs=',\n'.join(prefableSpecs))
  1914. if doIdArrays:
  1915. arrays += "static jsid %s_ids[%i];\n\n" % (name, len(specs))
  1916. return arrays
  1917. # The length of a method is the minimum of the lengths of the
  1918. # argument lists of all its overloads.
  1919. def overloadLength(arguments):
  1920. i = len(arguments)
  1921. while i > 0 and arguments[i - 1].optional:
  1922. i -= 1
  1923. return i
  1924. def methodLength(method):
  1925. signatures = method.signatures()
  1926. return min(overloadLength(arguments) for retType, arguments in signatures)
  1927. def clearableCachedAttrs(descriptor):
  1928. return (m for m in descriptor.interface.members if
  1929. m.isAttr() and
  1930. # Constants should never need clearing!
  1931. m.dependsOn != "Nothing" and
  1932. m.slotIndices is not None)
  1933. def MakeClearCachedValueNativeName(member):
  1934. return "ClearCached%sValue" % MakeNativeName(member.identifier.name)
  1935. def MakeJSImplClearCachedValueNativeName(member):
  1936. return "_" + MakeClearCachedValueNativeName(member)
  1937. def IDLToCIdentifier(name):
  1938. return name.replace("-", "_")
  1939. class MethodDefiner(PropertyDefiner):
  1940. """
  1941. A class for defining methods on a prototype object.
  1942. """
  1943. def __init__(self, descriptor, name, static, unforgeable=False):
  1944. assert not (static and unforgeable)
  1945. PropertyDefiner.__init__(self, descriptor, name)
  1946. # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
  1947. # We should be able to check for special operations without an
  1948. # identifier. For now we check if the name starts with __
  1949. # Ignore non-static methods for interfaces without a proto object
  1950. if descriptor.interface.hasInterfacePrototypeObject() or static:
  1951. methods = [m for m in descriptor.interface.members if
  1952. m.isMethod() and m.isStatic() == static and
  1953. MemberIsUnforgeable(m, descriptor) == unforgeable and
  1954. not m.isIdentifierLess()]
  1955. else:
  1956. methods = []
  1957. self.chrome = []
  1958. self.regular = []
  1959. for m in methods:
  1960. if m.identifier.name == 'queryInterface':
  1961. if m.isStatic():
  1962. raise TypeError("Legacy queryInterface member shouldn't be static")
  1963. signatures = m.signatures()
  1964. def argTypeIsIID(arg):
  1965. return arg.type.inner.isExternal() and arg.type.inner.identifier.name == 'IID'
  1966. if len(signatures) > 1 or len(signatures[0][1]) > 1 or not argTypeIsIID(signatures[0][1][0]):
  1967. raise TypeError("There should be only one queryInterface method with 1 argument of type IID")
  1968. # Make sure to not stick QueryInterface on abstract interfaces.
  1969. if (not self.descriptor.interface.hasInterfacePrototypeObject() or
  1970. not self.descriptor.concrete):
  1971. raise TypeError("QueryInterface is only supported on "
  1972. "interfaces that are concrete: " +
  1973. self.descriptor.name)
  1974. condition = "WantsQueryInterface<%s>::Enabled" % descriptor.nativeType
  1975. self.regular.append({
  1976. "name": 'QueryInterface',
  1977. "methodInfo": False,
  1978. "length": 1,
  1979. "flags": "0",
  1980. "condition": MemberCondition(func=condition)
  1981. })
  1982. continue
  1983. # Iterable methods should be enumerable, maplike/setlike methods
  1984. # should not.
  1985. isMaplikeOrSetlikeMethod = (m.isMaplikeOrSetlikeOrIterableMethod() and
  1986. (m.maplikeOrSetlikeOrIterable.isMaplike() or
  1987. m.maplikeOrSetlikeOrIterable.isSetlike()))
  1988. method = {
  1989. "name": m.identifier.name,
  1990. "methodInfo": not m.isStatic(),
  1991. "length": methodLength(m),
  1992. # Methods generated for a maplike/setlike declaration are not
  1993. # enumerable.
  1994. "flags": "JSPROP_ENUMERATE" if not isMaplikeOrSetlikeMethod else "0",
  1995. "condition": PropertyDefiner.getControllingCondition(m, descriptor),
  1996. "allowCrossOriginThis": m.getExtendedAttribute("CrossOriginCallable"),
  1997. "returnsPromise": m.returnsPromise(),
  1998. "hasIteratorAlias": "@@iterator" in m.aliases
  1999. }
  2000. if m.isStatic():
  2001. method["nativeName"] = CppKeywords.checkMethodName(IDLToCIdentifier(m.identifier.name))
  2002. if isChromeOnly(m):
  2003. self.chrome.append(method)
  2004. else:
  2005. self.regular.append(method)
  2006. # TODO: Once iterable is implemented, use tiebreak rules instead of
  2007. # failing. Also, may be more tiebreak rules to implement once spec bug
  2008. # is resolved.
  2009. # https://www.w3.org/Bugs/Public/show_bug.cgi?id=28592
  2010. def hasIterator(methods, regular):
  2011. return (any("@@iterator" in m.aliases for m in methods) or
  2012. any("@@iterator" == r["name"] for r in regular))
  2013. # Check whether we need to output an @@iterator due to having an indexed
  2014. # getter. We only do this while outputting non-static and
  2015. # non-unforgeable methods, since the @@iterator function will be
  2016. # neither.
  2017. if (not static and
  2018. not unforgeable and
  2019. descriptor.supportsIndexedProperties()):
  2020. if hasIterator(methods, self.regular):
  2021. raise TypeError("Cannot have indexed getter/attr on "
  2022. "interface %s with other members "
  2023. "that generate @@iterator, such as "
  2024. "maplike/setlike or aliased functions." %
  2025. self.descriptor.interface.identifier.name)
  2026. self.regular.append({
  2027. "name": "@@iterator",
  2028. "methodInfo": False,
  2029. "selfHostedName": "ArrayValues",
  2030. "length": 0,
  2031. "flags": "JSPROP_ENUMERATE",
  2032. "condition": MemberCondition()
  2033. })
  2034. if (static and
  2035. not unforgeable and
  2036. descriptor.interface.hasInterfaceObject() and
  2037. NeedsGeneratedHasInstance(descriptor)):
  2038. self.regular.append({
  2039. "name": "@@hasInstance",
  2040. "methodInfo": False,
  2041. "nativeName": HASINSTANCE_HOOK_NAME,
  2042. "length": 1,
  2043. # Flags match those of Function[Symbol.hasInstance]
  2044. "flags": "JSPROP_READONLY | JSPROP_PERMANENT",
  2045. "condition": MemberCondition()
  2046. })
  2047. # Generate the keys/values/entries aliases for value iterables.
  2048. maplikeOrSetlikeOrIterable = descriptor.interface.maplikeOrSetlikeOrIterable
  2049. if (not static and
  2050. not unforgeable and
  2051. maplikeOrSetlikeOrIterable and
  2052. maplikeOrSetlikeOrIterable.isIterable() and
  2053. maplikeOrSetlikeOrIterable.isValueIterator()):
  2054. # Add our keys/values/entries/forEach
  2055. self.regular.append({
  2056. "name": "keys",
  2057. "methodInfo": False,
  2058. "selfHostedName": "ArrayKeys",
  2059. "length": 0,
  2060. "flags": "JSPROP_ENUMERATE",
  2061. "condition": PropertyDefiner.getControllingCondition(m,
  2062. descriptor)
  2063. })
  2064. self.regular.append({
  2065. "name": "values",
  2066. "methodInfo": False,
  2067. "selfHostedName": "ArrayValues",
  2068. "length": 0,
  2069. "flags": "JSPROP_ENUMERATE",
  2070. "condition": PropertyDefiner.getControllingCondition(m,
  2071. descriptor)
  2072. })
  2073. self.regular.append({
  2074. "name": "entries",
  2075. "methodInfo": False,
  2076. "selfHostedName": "ArrayEntries",
  2077. "length": 0,
  2078. "flags": "JSPROP_ENUMERATE",
  2079. "condition": PropertyDefiner.getControllingCondition(m,
  2080. descriptor)
  2081. })
  2082. self.regular.append({
  2083. "name": "forEach",
  2084. "methodInfo": False,
  2085. "selfHostedName": "ArrayForEach",
  2086. "length": 1,
  2087. "flags": "JSPROP_ENUMERATE",
  2088. "condition": PropertyDefiner.getControllingCondition(m,
  2089. descriptor)
  2090. })
  2091. if not static:
  2092. stringifier = descriptor.operations['Stringifier']
  2093. if (stringifier and
  2094. unforgeable == MemberIsUnforgeable(stringifier, descriptor)):
  2095. toStringDesc = {
  2096. "name": "toString",
  2097. "nativeName": stringifier.identifier.name,
  2098. "length": 0,
  2099. "flags": "JSPROP_ENUMERATE",
  2100. "condition": PropertyDefiner.getControllingCondition(stringifier, descriptor)
  2101. }
  2102. if isChromeOnly(stringifier):
  2103. self.chrome.append(toStringDesc)
  2104. else:
  2105. self.regular.append(toStringDesc)
  2106. jsonifier = descriptor.operations['Jsonifier']
  2107. if (jsonifier and
  2108. unforgeable == MemberIsUnforgeable(jsonifier, descriptor)):
  2109. toJSONDesc = {
  2110. "name": "toJSON",
  2111. "nativeName": jsonifier.identifier.name,
  2112. "length": 0,
  2113. "flags": "JSPROP_ENUMERATE",
  2114. "condition": PropertyDefiner.getControllingCondition(jsonifier, descriptor)
  2115. }
  2116. if isChromeOnly(jsonifier):
  2117. self.chrome.append(toJSONDesc)
  2118. else:
  2119. self.regular.append(toJSONDesc)
  2120. if (unforgeable and
  2121. descriptor.interface.getExtendedAttribute("Unforgeable")):
  2122. # Synthesize our valueOf method
  2123. self.regular.append({
  2124. "name": 'valueOf',
  2125. "selfHostedName": "Object_valueOf",
  2126. "methodInfo": False,
  2127. "length": 0,
  2128. "flags": "0", # readonly/permanent added automatically.
  2129. "condition": MemberCondition()
  2130. })
  2131. if descriptor.interface.isJSImplemented():
  2132. if static:
  2133. if descriptor.interface.hasInterfaceObject():
  2134. self.chrome.append({
  2135. "name": '_create',
  2136. "nativeName": ("%s::_Create" % descriptor.name),
  2137. "methodInfo": False,
  2138. "length": 2,
  2139. "flags": "0",
  2140. "condition": MemberCondition()
  2141. })
  2142. else:
  2143. for m in clearableCachedAttrs(descriptor):
  2144. attrName = MakeNativeName(m.identifier.name)
  2145. self.chrome.append({
  2146. "name": "_clearCached%sValue" % attrName,
  2147. "nativeName": MakeJSImplClearCachedValueNativeName(m),
  2148. "methodInfo": False,
  2149. "length": "0",
  2150. "flags": "0",
  2151. "condition": MemberCondition()
  2152. })
  2153. self.unforgeable = unforgeable
  2154. if static:
  2155. if not descriptor.interface.hasInterfaceObject():
  2156. # static methods go on the interface object
  2157. assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
  2158. else:
  2159. if not descriptor.interface.hasInterfacePrototypeObject():
  2160. # non-static methods go on the interface prototype object
  2161. assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
  2162. def generateArray(self, array, name, doIdArrays):
  2163. if len(array) == 0:
  2164. return ""
  2165. def condition(m, d):
  2166. return m["condition"]
  2167. def flags(m):
  2168. unforgeable = " | JSPROP_PERMANENT | JSPROP_READONLY" if self.unforgeable else ""
  2169. return m["flags"] + unforgeable
  2170. def specData(m):
  2171. if "selfHostedName" in m:
  2172. selfHostedName = '"%s"' % m["selfHostedName"]
  2173. assert not m.get("methodInfo", True)
  2174. accessor = "nullptr"
  2175. jitinfo = "nullptr"
  2176. else:
  2177. selfHostedName = "nullptr"
  2178. # When defining symbols, function name may not match symbol name
  2179. methodName = m.get("methodName", m["name"])
  2180. accessor = m.get("nativeName", IDLToCIdentifier(methodName))
  2181. if m.get("methodInfo", True):
  2182. # Cast this in case the methodInfo is a
  2183. # JSTypedMethodJitInfo.
  2184. jitinfo = ("reinterpret_cast<const JSJitInfo*>(&%s_methodinfo)" % accessor)
  2185. if m.get("allowCrossOriginThis", False):
  2186. if m.get("returnsPromise", False):
  2187. raise TypeError("%s returns a Promise but should "
  2188. "be allowed cross-origin?" %
  2189. accessor)
  2190. accessor = "genericCrossOriginMethod"
  2191. elif self.descriptor.needsSpecialGenericOps():
  2192. if m.get("returnsPromise", False):
  2193. accessor = "genericPromiseReturningMethod"
  2194. else:
  2195. accessor = "genericMethod"
  2196. elif m.get("returnsPromise", False):
  2197. accessor = "GenericPromiseReturningBindingMethod"
  2198. else:
  2199. accessor = "GenericBindingMethod"
  2200. else:
  2201. if m.get("returnsPromise", False):
  2202. jitinfo = "&%s_methodinfo" % accessor
  2203. accessor = "StaticMethodPromiseWrapper"
  2204. else:
  2205. jitinfo = "nullptr"
  2206. return (m["name"], accessor, jitinfo, m["length"], flags(m), selfHostedName)
  2207. def formatSpec(fields):
  2208. if fields[0].startswith("@@"):
  2209. fields = (fields[0][2:],) + fields[1:]
  2210. return ' JS_SYM_FNSPEC(%s, %s, %s, %s, %s, %s)' % fields
  2211. return ' JS_FNSPEC("%s", %s, %s, %s, %s, %s)' % fields
  2212. return self.generatePrefableArray(
  2213. array, name,
  2214. formatSpec,
  2215. ' JS_FS_END',
  2216. 'JSFunctionSpec',
  2217. condition, specData, doIdArrays)
  2218. def IsCrossOriginWritable(attr, descriptor):
  2219. """
  2220. Return whether the IDLAttribute in question is cross-origin writable on the
  2221. interface represented by descriptor. This is needed to handle the fact that
  2222. some, but not all, interfaces implementing URLUtils want a cross-origin
  2223. writable .href.
  2224. """
  2225. crossOriginWritable = attr.getExtendedAttribute("CrossOriginWritable")
  2226. if not crossOriginWritable:
  2227. return False
  2228. if crossOriginWritable is True:
  2229. return True
  2230. assert (isinstance(crossOriginWritable, list) and
  2231. len(crossOriginWritable) == 1)
  2232. return crossOriginWritable[0] == descriptor.interface.identifier.name
  2233. def isNonExposedNavigatorObjectGetter(attr, descriptor):
  2234. return (attr.navigatorObjectGetter and
  2235. not descriptor.getDescriptor(attr.type.inner.identifier.name).register)
  2236. class AttrDefiner(PropertyDefiner):
  2237. def __init__(self, descriptor, name, static, unforgeable=False):
  2238. assert not (static and unforgeable)
  2239. PropertyDefiner.__init__(self, descriptor, name)
  2240. self.name = name
  2241. # Ignore non-static attributes for interfaces without a proto object
  2242. if descriptor.interface.hasInterfacePrototypeObject() or static:
  2243. attributes = [m for m in descriptor.interface.members if
  2244. m.isAttr() and m.isStatic() == static and
  2245. MemberIsUnforgeable(m, descriptor) == unforgeable and
  2246. not isNonExposedNavigatorObjectGetter(m, descriptor)]
  2247. else:
  2248. attributes = []
  2249. self.chrome = [m for m in attributes if isChromeOnly(m)]
  2250. self.regular = [m for m in attributes if not isChromeOnly(m)]
  2251. self.static = static
  2252. self.unforgeable = unforgeable
  2253. if static:
  2254. if not descriptor.interface.hasInterfaceObject():
  2255. # static attributes go on the interface object
  2256. assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
  2257. else:
  2258. if not descriptor.interface.hasInterfacePrototypeObject():
  2259. # non-static attributes go on the interface prototype object
  2260. assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
  2261. def generateArray(self, array, name, doIdArrays):
  2262. if len(array) == 0:
  2263. return ""
  2264. def flags(attr):
  2265. unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else ""
  2266. # Attributes generated as part of a maplike/setlike declaration are
  2267. # not enumerable.
  2268. enumerable = " | JSPROP_ENUMERATE" if not attr.isMaplikeOrSetlikeAttr() else ""
  2269. return ("JSPROP_SHARED" + enumerable + unforgeable)
  2270. def getter(attr):
  2271. if self.static:
  2272. accessor = 'get_' + IDLToCIdentifier(attr.identifier.name)
  2273. jitinfo = "nullptr"
  2274. else:
  2275. if attr.hasLenientThis():
  2276. accessor = "genericLenientGetter"
  2277. elif attr.getExtendedAttribute("CrossOriginReadable"):
  2278. accessor = "genericCrossOriginGetter"
  2279. elif self.descriptor.needsSpecialGenericOps():
  2280. accessor = "genericGetter"
  2281. else:
  2282. accessor = "GenericBindingGetter"
  2283. jitinfo = ("&%s_getterinfo" %
  2284. IDLToCIdentifier(attr.identifier.name))
  2285. return "{ { %s, %s } }" % \
  2286. (accessor, jitinfo)
  2287. def setter(attr):
  2288. if (attr.readonly and
  2289. attr.getExtendedAttribute("PutForwards") is None and
  2290. attr.getExtendedAttribute("Replaceable") is None and
  2291. attr.getExtendedAttribute("LenientSetter") is None):
  2292. return "JSNATIVE_WRAPPER(nullptr)"
  2293. if self.static:
  2294. accessor = 'set_' + IDLToCIdentifier(attr.identifier.name)
  2295. jitinfo = "nullptr"
  2296. else:
  2297. if attr.hasLenientThis():
  2298. accessor = "genericLenientSetter"
  2299. elif IsCrossOriginWritable(attr, self.descriptor):
  2300. accessor = "genericCrossOriginSetter"
  2301. elif self.descriptor.needsSpecialGenericOps():
  2302. accessor = "genericSetter"
  2303. else:
  2304. accessor = "GenericBindingSetter"
  2305. jitinfo = "&%s_setterinfo" % IDLToCIdentifier(attr.identifier.name)
  2306. return "{ { %s, %s } }" % \
  2307. (accessor, jitinfo)
  2308. def specData(attr):
  2309. return (attr.identifier.name, flags(attr), getter(attr),
  2310. setter(attr))
  2311. return self.generatePrefableArray(
  2312. array, name,
  2313. lambda fields: ' { "%s", %s, { { %s, %s } } }' % fields,
  2314. ' JS_PS_END',
  2315. 'JSPropertySpec',
  2316. PropertyDefiner.getControllingCondition, specData, doIdArrays)
  2317. class ConstDefiner(PropertyDefiner):
  2318. """
  2319. A class for definining constants on the interface object
  2320. """
  2321. def __init__(self, descriptor, name):
  2322. PropertyDefiner.__init__(self, descriptor, name)
  2323. self.name = name
  2324. constants = [m for m in descriptor.interface.members if m.isConst()]
  2325. self.chrome = [m for m in constants if isChromeOnly(m)]
  2326. self.regular = [m for m in constants if not isChromeOnly(m)]
  2327. def generateArray(self, array, name, doIdArrays):
  2328. if len(array) == 0:
  2329. return ""
  2330. def specData(const):
  2331. return (const.identifier.name,
  2332. convertConstIDLValueToJSVal(const.value))
  2333. return self.generatePrefableArray(
  2334. array, name,
  2335. lambda fields: ' { "%s", %s }' % fields,
  2336. ' { 0, JS::UndefinedValue() }',
  2337. 'ConstantSpec',
  2338. PropertyDefiner.getControllingCondition, specData, doIdArrays)
  2339. class PropertyArrays():
  2340. def __init__(self, descriptor):
  2341. self.staticMethods = MethodDefiner(descriptor, "StaticMethods",
  2342. static=True)
  2343. self.staticAttrs = AttrDefiner(descriptor, "StaticAttributes",
  2344. static=True)
  2345. self.methods = MethodDefiner(descriptor, "Methods", static=False)
  2346. self.attrs = AttrDefiner(descriptor, "Attributes", static=False)
  2347. self.unforgeableMethods = MethodDefiner(descriptor, "UnforgeableMethods",
  2348. static=False, unforgeable=True)
  2349. self.unforgeableAttrs = AttrDefiner(descriptor, "UnforgeableAttributes",
  2350. static=False, unforgeable=True)
  2351. self.consts = ConstDefiner(descriptor, "Constants")
  2352. @staticmethod
  2353. def arrayNames():
  2354. return ["staticMethods", "staticAttrs", "methods", "attrs",
  2355. "unforgeableMethods", "unforgeableAttrs", "consts"]
  2356. def hasChromeOnly(self):
  2357. return any(getattr(self, a).hasChromeOnly() for a in self.arrayNames())
  2358. def hasNonChromeOnly(self):
  2359. return any(getattr(self, a).hasNonChromeOnly() for a in self.arrayNames())
  2360. def __str__(self):
  2361. define = ""
  2362. for array in self.arrayNames():
  2363. define += str(getattr(self, array))
  2364. return define
  2365. class CGNativeProperties(CGList):
  2366. def __init__(self, descriptor, properties):
  2367. def generateNativeProperties(name, chrome):
  2368. def check(p):
  2369. return p.hasChromeOnly() if chrome else p.hasNonChromeOnly()
  2370. nativePropsInts = []
  2371. nativePropsTrios = []
  2372. iteratorAliasIndex = -1
  2373. for index, item in enumerate(properties.methods.regular):
  2374. if item.get("hasIteratorAlias"):
  2375. iteratorAliasIndex = index
  2376. break
  2377. nativePropsInts.append(CGGeneric(str(iteratorAliasIndex)))
  2378. offset = 0
  2379. for array in properties.arrayNames():
  2380. propertyArray = getattr(properties, array)
  2381. if check(propertyArray):
  2382. varName = propertyArray.variableName(chrome)
  2383. bitfields = "true, %d /* %s */" % (offset, varName)
  2384. offset += 1
  2385. nativePropsInts.append(CGGeneric(bitfields))
  2386. if propertyArray.usedForXrays():
  2387. ids = "%(name)s_ids"
  2388. else:
  2389. ids = "nullptr"
  2390. trio = "{ %(name)s, " + ids + ", %(name)s_specs }"
  2391. trio = trio % {'name': varName}
  2392. nativePropsTrios.append(CGGeneric(trio))
  2393. else:
  2394. bitfields = "false, 0"
  2395. nativePropsInts.append(CGGeneric(bitfields))
  2396. nativePropsTrios = \
  2397. [CGWrapper(CGIndenter(CGList(nativePropsTrios, ",\n")),
  2398. pre='{\n', post='\n}')]
  2399. nativeProps = nativePropsInts + nativePropsTrios
  2400. pre = ("static const NativePropertiesN<%d> %s = {\n" %
  2401. (offset, name))
  2402. return CGWrapper(CGIndenter(CGList(nativeProps, ",\n")),
  2403. pre=pre, post="\n};\n")
  2404. nativeProperties = []
  2405. if properties.hasNonChromeOnly():
  2406. nativeProperties.append(
  2407. generateNativeProperties("sNativeProperties", False))
  2408. if properties.hasChromeOnly():
  2409. nativeProperties.append(
  2410. generateNativeProperties("sChromeOnlyNativeProperties", True))
  2411. CGList.__init__(self, nativeProperties, "\n")
  2412. def declare(self):
  2413. return ""
  2414. def define(self):
  2415. return CGList.define(self)
  2416. class CGJsonifyAttributesMethod(CGAbstractMethod):
  2417. """
  2418. Generate the JsonifyAttributes method for an interface descriptor
  2419. """
  2420. def __init__(self, descriptor):
  2421. args = [Argument('JSContext*', 'aCx'),
  2422. Argument('JS::Handle<JSObject*>', 'obj'),
  2423. Argument('%s*' % descriptor.nativeType, 'self'),
  2424. Argument('JS::Rooted<JSObject*>&', 'aResult')]
  2425. CGAbstractMethod.__init__(self, descriptor, 'JsonifyAttributes', 'bool', args)
  2426. def definition_body(self):
  2427. ret = ''
  2428. interface = self.descriptor.interface
  2429. for m in interface.members:
  2430. if m.isAttr() and not m.isStatic() and m.type.isSerializable():
  2431. ret += fill(
  2432. """
  2433. { // scope for "temp"
  2434. JS::Rooted<JS::Value> temp(aCx);
  2435. if (!get_${name}(aCx, obj, self, JSJitGetterCallArgs(&temp))) {
  2436. return false;
  2437. }
  2438. if (!JS_DefineProperty(aCx, aResult, "${name}", temp, JSPROP_ENUMERATE)) {
  2439. return false;
  2440. }
  2441. }
  2442. """,
  2443. name=IDLToCIdentifier(m.identifier.name))
  2444. ret += 'return true;\n'
  2445. return ret
  2446. class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
  2447. """
  2448. Generate the CreateInterfaceObjects method for an interface descriptor.
  2449. properties should be a PropertyArrays instance.
  2450. """
  2451. def __init__(self, descriptor, properties, haveUnscopables):
  2452. args = [Argument('JSContext*', 'aCx'),
  2453. Argument('JS::Handle<JSObject*>', 'aGlobal'),
  2454. Argument('ProtoAndIfaceCache&', 'aProtoAndIfaceCache'),
  2455. Argument('bool', 'aDefineOnGlobal')]
  2456. CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
  2457. self.properties = properties
  2458. self.haveUnscopables = haveUnscopables
  2459. def definition_body(self):
  2460. (protoGetter, protoHandleGetter) = InterfacePrototypeObjectProtoGetter(self.descriptor)
  2461. if protoHandleGetter is None:
  2462. parentProtoType = "Rooted"
  2463. getParentProto = "aCx, " + protoGetter
  2464. else:
  2465. parentProtoType = "Handle"
  2466. getParentProto = protoHandleGetter
  2467. getParentProto = getParentProto + "(aCx)"
  2468. (protoGetter, protoHandleGetter) = InterfaceObjectProtoGetter(self.descriptor)
  2469. if protoHandleGetter is None:
  2470. getConstructorProto = "aCx, " + protoGetter
  2471. constructorProtoType = "Rooted"
  2472. else:
  2473. getConstructorProto = protoHandleGetter
  2474. constructorProtoType = "Handle"
  2475. getConstructorProto += "(aCx)"
  2476. needInterfaceObject = self.descriptor.interface.hasInterfaceObject()
  2477. needInterfacePrototypeObject = self.descriptor.interface.hasInterfacePrototypeObject()
  2478. # if we don't need to create anything, why are we generating this?
  2479. assert needInterfaceObject or needInterfacePrototypeObject
  2480. getParentProto = fill(
  2481. """
  2482. JS::${type}<JSObject*> parentProto(${getParentProto});
  2483. if (!parentProto) {
  2484. return;
  2485. }
  2486. """,
  2487. type=parentProtoType,
  2488. getParentProto=getParentProto)
  2489. getConstructorProto = fill(
  2490. """
  2491. JS::${type}<JSObject*> constructorProto(${getConstructorProto});
  2492. if (!constructorProto) {
  2493. return;
  2494. }
  2495. """,
  2496. type=constructorProtoType,
  2497. getConstructorProto=getConstructorProto)
  2498. idsToInit = []
  2499. # There is no need to init any IDs in bindings that don't want Xrays.
  2500. if self.descriptor.wantsXrays:
  2501. for var in self.properties.arrayNames():
  2502. props = getattr(self.properties, var)
  2503. # We only have non-chrome ids to init if we have no chrome ids.
  2504. if props.hasChromeOnly():
  2505. idsToInit.append(props.variableName(True))
  2506. if props.hasNonChromeOnly():
  2507. idsToInit.append(props.variableName(False))
  2508. if len(idsToInit) > 0:
  2509. initIdCalls = ["!InitIds(aCx, %s, %s_ids)" % (varname, varname)
  2510. for varname in idsToInit]
  2511. idsInitedFlag = CGGeneric("static bool sIdsInited = false;\n")
  2512. setFlag = CGGeneric("sIdsInited = true;\n")
  2513. initIdConditionals = [CGIfWrapper(CGGeneric("return;\n"), call)
  2514. for call in initIdCalls]
  2515. initIds = CGList([idsInitedFlag,
  2516. CGIfWrapper(CGList(initIdConditionals + [setFlag]),
  2517. "!sIdsInited && NS_IsMainThread()")])
  2518. else:
  2519. initIds = None
  2520. prefCacheData = []
  2521. for var in self.properties.arrayNames():
  2522. props = getattr(self.properties, var)
  2523. prefCacheData.extend(props.prefCacheData)
  2524. if len(prefCacheData) != 0:
  2525. prefCacheData = [
  2526. CGGeneric('Preferences::AddBoolVarCache(%s, "%s");\n' % (ptr, pref))
  2527. for pref, ptr in prefCacheData]
  2528. prefCache = CGWrapper(CGIndenter(CGList(prefCacheData)),
  2529. pre=("static bool sPrefCachesInited = false;\n"
  2530. "if (!sPrefCachesInited && NS_IsMainThread()) {\n"
  2531. " sPrefCachesInited = true;\n"),
  2532. post="}\n")
  2533. else:
  2534. prefCache = None
  2535. if self.descriptor.interface.ctor():
  2536. constructArgs = methodLength(self.descriptor.interface.ctor())
  2537. else:
  2538. constructArgs = 0
  2539. if len(self.descriptor.interface.namedConstructors) > 0:
  2540. namedConstructors = "namedConstructors"
  2541. else:
  2542. namedConstructors = "nullptr"
  2543. if needInterfacePrototypeObject:
  2544. protoClass = "&sPrototypeClass.mBase"
  2545. protoCache = "&aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::%s)" % self.descriptor.name
  2546. parentProto = "parentProto"
  2547. getParentProto = CGGeneric(getParentProto)
  2548. else:
  2549. protoClass = "nullptr"
  2550. protoCache = "nullptr"
  2551. parentProto = "nullptr"
  2552. getParentProto = None
  2553. if needInterfaceObject:
  2554. interfaceClass = "&sInterfaceObjectClass.mBase"
  2555. interfaceCache = "&aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::%s)" % self.descriptor.name
  2556. getConstructorProto = CGGeneric(getConstructorProto)
  2557. constructorProto = "constructorProto"
  2558. else:
  2559. # We don't have slots to store the named constructors.
  2560. assert len(self.descriptor.interface.namedConstructors) == 0
  2561. interfaceClass = "nullptr"
  2562. interfaceCache = "nullptr"
  2563. getConstructorProto = None
  2564. constructorProto = "nullptr"
  2565. isGlobal = self.descriptor.isGlobal() is not None
  2566. if self.properties.hasNonChromeOnly():
  2567. properties = "sNativeProperties.Upcast()"
  2568. else:
  2569. properties = "nullptr"
  2570. if self.properties.hasChromeOnly():
  2571. chromeProperties = "nsContentUtils::ThreadsafeIsCallerChrome() ? sChromeOnlyNativeProperties.Upcast() : nullptr"
  2572. else:
  2573. chromeProperties = "nullptr"
  2574. call = fill(
  2575. """
  2576. JS::Heap<JSObject*>* protoCache = ${protoCache};
  2577. JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
  2578. dom::CreateInterfaceObjects(aCx, aGlobal, ${parentProto},
  2579. ${protoClass}, protoCache,
  2580. ${constructorProto}, ${interfaceClass}, ${constructArgs}, ${namedConstructors},
  2581. interfaceCache,
  2582. ${properties},
  2583. ${chromeProperties},
  2584. ${name}, aDefineOnGlobal,
  2585. ${unscopableNames},
  2586. ${isGlobal});
  2587. """,
  2588. protoClass=protoClass,
  2589. parentProto=parentProto,
  2590. protoCache=protoCache,
  2591. constructorProto=constructorProto,
  2592. interfaceClass=interfaceClass,
  2593. constructArgs=constructArgs,
  2594. namedConstructors=namedConstructors,
  2595. interfaceCache=interfaceCache,
  2596. properties=properties,
  2597. chromeProperties=chromeProperties,
  2598. name='"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "nullptr",
  2599. unscopableNames="unscopableNames" if self.haveUnscopables else "nullptr",
  2600. isGlobal=toStringBool(isGlobal))
  2601. # If we fail after here, we must clear interface and prototype caches
  2602. # using this code: intermediate failure must not expose the interface in
  2603. # partially-constructed state. Note that every case after here needs an
  2604. # interface prototype object.
  2605. failureCode = dedent(
  2606. """
  2607. *protoCache = nullptr;
  2608. if (interfaceCache) {
  2609. *interfaceCache = nullptr;
  2610. }
  2611. return;
  2612. """)
  2613. aliasedMembers = [m for m in self.descriptor.interface.members if m.isMethod() and m.aliases]
  2614. if aliasedMembers:
  2615. assert needInterfacePrototypeObject
  2616. def defineAlias(alias):
  2617. if alias == "@@iterator":
  2618. symbolJSID = "SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::iterator))"
  2619. getSymbolJSID = CGGeneric(fill("JS::Rooted<jsid> iteratorId(aCx, ${symbolJSID});",
  2620. symbolJSID=symbolJSID))
  2621. defineFn = "JS_DefinePropertyById"
  2622. prop = "iteratorId"
  2623. elif alias.startswith("@@"):
  2624. raise TypeError("Can't handle any well-known Symbol other than @@iterator")
  2625. else:
  2626. getSymbolJSID = None
  2627. defineFn = "JS_DefineProperty"
  2628. prop = '"%s"' % alias
  2629. return CGList([
  2630. getSymbolJSID,
  2631. # XXX If we ever create non-enumerable properties that can
  2632. # be aliased, we should consider making the aliases
  2633. # match the enumerability of the property being aliased.
  2634. CGGeneric(fill(
  2635. """
  2636. if (!${defineFn}(aCx, proto, ${prop}, aliasedVal, JSPROP_ENUMERATE)) {
  2637. $*{failureCode}
  2638. }
  2639. """,
  2640. defineFn=defineFn,
  2641. prop=prop,
  2642. failureCode=failureCode))
  2643. ], "\n")
  2644. def defineAliasesFor(m):
  2645. return CGList([
  2646. CGGeneric(fill(
  2647. """
  2648. if (!JS_GetProperty(aCx, proto, \"${prop}\", &aliasedVal)) {
  2649. $*{failureCode}
  2650. }
  2651. """,
  2652. failureCode=failureCode,
  2653. prop=m.identifier.name))
  2654. ] + [defineAlias(alias) for alias in sorted(m.aliases)])
  2655. defineAliases = CGList([
  2656. CGGeneric(fill("""
  2657. // Set up aliases on the interface prototype object we just created.
  2658. JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx);
  2659. if (!proto) {
  2660. $*{failureCode}
  2661. }
  2662. """,
  2663. failureCode=failureCode)),
  2664. CGGeneric("JS::Rooted<JS::Value> aliasedVal(aCx);\n\n")
  2665. ] + [defineAliasesFor(m) for m in sorted(aliasedMembers)])
  2666. else:
  2667. defineAliases = None
  2668. # Globals handle unforgeables directly in Wrap() instead of
  2669. # via a holder.
  2670. if self.descriptor.hasUnforgeableMembers and not self.descriptor.isGlobal():
  2671. assert needInterfacePrototypeObject
  2672. # We want to use the same JSClass and prototype as the object we'll
  2673. # end up defining the unforgeable properties on in the end, so that
  2674. # we can use JS_InitializePropertiesFromCompatibleNativeObject to do
  2675. # a fast copy. In the case of proxies that's null, because the
  2676. # expando object is a vanilla object, but in the case of other DOM
  2677. # objects it's whatever our class is.
  2678. if self.descriptor.proxy:
  2679. holderClass = "nullptr"
  2680. holderProto = "nullptr"
  2681. else:
  2682. holderClass = "sClass.ToJSClass()"
  2683. holderProto = "*protoCache"
  2684. createUnforgeableHolder = CGGeneric(fill(
  2685. """
  2686. JS::Rooted<JSObject*> unforgeableHolder(aCx);
  2687. {
  2688. JS::Rooted<JSObject*> holderProto(aCx, ${holderProto});
  2689. unforgeableHolder = JS_NewObjectWithoutMetadata(aCx, ${holderClass}, holderProto);
  2690. if (!unforgeableHolder) {
  2691. $*{failureCode}
  2692. }
  2693. }
  2694. """,
  2695. holderProto=holderProto,
  2696. holderClass=holderClass,
  2697. failureCode=failureCode))
  2698. defineUnforgeables = InitUnforgeablePropertiesOnHolder(self.descriptor,
  2699. self.properties,
  2700. failureCode)
  2701. createUnforgeableHolder = CGList(
  2702. [createUnforgeableHolder, defineUnforgeables])
  2703. installUnforgeableHolder = CGGeneric(dedent(
  2704. """
  2705. if (*protoCache) {
  2706. js::SetReservedSlot(*protoCache, DOM_INTERFACE_PROTO_SLOTS_BASE,
  2707. JS::ObjectValue(*unforgeableHolder));
  2708. }
  2709. """))
  2710. unforgeableHolderSetup = CGList(
  2711. [createUnforgeableHolder, installUnforgeableHolder], "\n")
  2712. else:
  2713. unforgeableHolderSetup = None
  2714. if (self.descriptor.interface.isOnGlobalProtoChain() and
  2715. needInterfacePrototypeObject):
  2716. makeProtoPrototypeImmutable = CGGeneric(fill(
  2717. """
  2718. if (*${protoCache}) {
  2719. bool succeeded;
  2720. JS::Handle<JSObject*> prot = GetProtoObjectHandle(aCx);
  2721. if (!JS_SetImmutablePrototype(aCx, prot, &succeeded)) {
  2722. $*{failureCode}
  2723. }
  2724. MOZ_ASSERT(succeeded,
  2725. "making a fresh prototype object's [[Prototype]] "
  2726. "immutable can internally fail, but it should "
  2727. "never be unsuccessful");
  2728. }
  2729. """,
  2730. protoCache=protoCache,
  2731. failureCode=failureCode))
  2732. else:
  2733. makeProtoPrototypeImmutable = None
  2734. return CGList(
  2735. [getParentProto, getConstructorProto, initIds,
  2736. prefCache, CGGeneric(call), defineAliases, unforgeableHolderSetup,
  2737. makeProtoPrototypeImmutable],
  2738. "\n").define()
  2739. class CGGetPerInterfaceObject(CGAbstractMethod):
  2740. """
  2741. A method for getting a per-interface object (a prototype object or interface
  2742. constructor object).
  2743. """
  2744. def __init__(self, descriptor, name, idPrefix="", extraArgs=[]):
  2745. args = [Argument('JSContext*', 'aCx')] + extraArgs
  2746. CGAbstractMethod.__init__(self, descriptor, name,
  2747. 'JS::Handle<JSObject*>', args)
  2748. self.id = idPrefix + "id::" + self.descriptor.name
  2749. def definition_body(self):
  2750. return fill(
  2751. """
  2752. /* Make sure our global is sane. Hopefully we can remove this sometime */
  2753. JSObject* global = JS::CurrentGlobalOrNull(aCx);
  2754. if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
  2755. return nullptr;
  2756. }
  2757. /* Check to see whether the interface objects are already installed */
  2758. ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
  2759. if (!protoAndIfaceCache.EntrySlotIfExists(${id})) {
  2760. JS::Rooted<JSObject*> rootedGlobal(aCx, global);
  2761. CreateInterfaceObjects(aCx, rootedGlobal, protoAndIfaceCache, aDefineOnGlobal);
  2762. }
  2763. /*
  2764. * The object might _still_ be null, but that's OK.
  2765. *
  2766. * Calling fromMarkedLocation() is safe because protoAndIfaceCache is
  2767. * traced by TraceProtoAndIfaceCache() and its contents are never
  2768. * changed after they have been set.
  2769. *
  2770. * Calling address() avoids the read read barrier that does gray
  2771. * unmarking, but it's not possible for the object to be gray here.
  2772. */
  2773. const JS::Heap<JSObject*>& entrySlot = protoAndIfaceCache.EntrySlotMustExist(${id});
  2774. MOZ_ASSERT_IF(entrySlot, !JS::ObjectIsMarkedGray(entrySlot));
  2775. return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
  2776. """,
  2777. id=self.id)
  2778. class CGGetProtoObjectHandleMethod(CGGetPerInterfaceObject):
  2779. """
  2780. A method for getting the interface prototype object.
  2781. """
  2782. def __init__(self, descriptor):
  2783. CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObjectHandle",
  2784. "prototypes::")
  2785. def definition_body(self):
  2786. return dedent("""
  2787. /* Get the interface prototype object for this class. This will create the
  2788. object as needed. */
  2789. bool aDefineOnGlobal = true;
  2790. """) + CGGetPerInterfaceObject.definition_body(self)
  2791. class CGGetProtoObjectMethod(CGAbstractMethod):
  2792. """
  2793. A method for getting the interface prototype object.
  2794. """
  2795. def __init__(self, descriptor):
  2796. CGAbstractMethod.__init__(
  2797. self, descriptor, "GetProtoObject", "JSObject*",
  2798. [Argument('JSContext*', 'aCx')])
  2799. def definition_body(self):
  2800. return "return GetProtoObjectHandle(aCx);\n"
  2801. class CGGetConstructorObjectHandleMethod(CGGetPerInterfaceObject):
  2802. """
  2803. A method for getting the interface constructor object.
  2804. """
  2805. def __init__(self, descriptor):
  2806. CGGetPerInterfaceObject.__init__(
  2807. self, descriptor, "GetConstructorObjectHandle",
  2808. "constructors::",
  2809. extraArgs=[Argument("bool", "aDefineOnGlobal", "true")])
  2810. def definition_body(self):
  2811. return dedent("""
  2812. /* Get the interface object for this class. This will create the object as
  2813. needed. */
  2814. """) + CGGetPerInterfaceObject.definition_body(self)
  2815. class CGGetConstructorObjectMethod(CGAbstractMethod):
  2816. """
  2817. A method for getting the interface constructor object.
  2818. """
  2819. def __init__(self, descriptor):
  2820. CGAbstractMethod.__init__(
  2821. self, descriptor, "GetConstructorObject", "JSObject*",
  2822. [Argument('JSContext*', 'aCx')])
  2823. def definition_body(self):
  2824. return "return GetConstructorObjectHandle(aCx);\n"
  2825. class CGGetNamedPropertiesObjectMethod(CGAbstractStaticMethod):
  2826. def __init__(self, descriptor):
  2827. args = [Argument('JSContext*', 'aCx')]
  2828. CGAbstractStaticMethod.__init__(self, descriptor,
  2829. 'GetNamedPropertiesObject',
  2830. 'JSObject*', args)
  2831. def definition_body(self):
  2832. parentProtoName = self.descriptor.parentPrototypeName
  2833. if parentProtoName is None:
  2834. getParentProto = ""
  2835. parentProto = "nullptr"
  2836. else:
  2837. getParentProto = fill(
  2838. """
  2839. JS::Rooted<JSObject*> parentProto(aCx, ${parent}::GetProtoObjectHandle(aCx));
  2840. if (!parentProto) {
  2841. return nullptr;
  2842. }
  2843. """,
  2844. parent=toBindingNamespace(parentProtoName))
  2845. parentProto = "parentProto"
  2846. return fill(
  2847. """
  2848. /* Make sure our global is sane. Hopefully we can remove this sometime */
  2849. JSObject* global = JS::CurrentGlobalOrNull(aCx);
  2850. if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
  2851. return nullptr;
  2852. }
  2853. /* Check to see whether the named properties object has already been created */
  2854. ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
  2855. JS::Heap<JSObject*>& namedPropertiesObject = protoAndIfaceCache.EntrySlotOrCreate(namedpropertiesobjects::id::${ifaceName});
  2856. if (!namedPropertiesObject) {
  2857. $*{getParentProto}
  2858. namedPropertiesObject = ${nativeType}::CreateNamedPropertiesObject(aCx, ${parentProto});
  2859. DebugOnly<const DOMIfaceAndProtoJSClass*> clasp =
  2860. DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(namedPropertiesObject));
  2861. MOZ_ASSERT(clasp->mType == eNamedPropertiesObject,
  2862. "Expected ${nativeType}::CreateNamedPropertiesObject to return a named properties object");
  2863. MOZ_ASSERT(clasp->mNativeHooks,
  2864. "The named properties object for ${nativeType} should have NativePropertyHooks.");
  2865. MOZ_ASSERT(clasp->mNativeHooks->mResolveOwnProperty,
  2866. "Don't know how to resolve the properties of the named properties object for ${nativeType}.");
  2867. MOZ_ASSERT(clasp->mNativeHooks->mEnumerateOwnProperties,
  2868. "Don't know how to enumerate the properties of the named properties object for ${nativeType}.");
  2869. }
  2870. return namedPropertiesObject.get();
  2871. """,
  2872. getParentProto=getParentProto,
  2873. ifaceName=self.descriptor.name,
  2874. parentProto=parentProto,
  2875. nativeType=self.descriptor.nativeType)
  2876. class CGDefineDOMInterfaceMethod(CGAbstractMethod):
  2877. """
  2878. A method for resolve hooks to try to lazily define the interface object for
  2879. a given interface.
  2880. """
  2881. def __init__(self, descriptor):
  2882. args = [Argument('JSContext*', 'aCx'),
  2883. Argument('JS::Handle<JSObject*>', 'aGlobal'),
  2884. Argument('JS::Handle<jsid>', 'id'),
  2885. Argument('bool', 'aDefineOnGlobal')]
  2886. CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'JSObject*', args)
  2887. def definition_body(self):
  2888. if len(self.descriptor.interface.namedConstructors) > 0:
  2889. getConstructor = dedent("""
  2890. JSObject* interfaceObject = GetConstructorObjectHandle(aCx, aDefineOnGlobal);
  2891. if (!interfaceObject) {
  2892. return nullptr;
  2893. }
  2894. for (unsigned slot = DOM_INTERFACE_SLOTS_BASE; slot < JSCLASS_RESERVED_SLOTS(&sInterfaceObjectClass.mBase); ++slot) {
  2895. JSObject* constructor = &js::GetReservedSlot(interfaceObject, slot).toObject();
  2896. if (JS_GetFunctionId(JS_GetObjectFunction(constructor)) == JSID_TO_STRING(id)) {
  2897. return constructor;
  2898. }
  2899. }
  2900. return interfaceObject;
  2901. """)
  2902. else:
  2903. getConstructor = "return GetConstructorObjectHandle(aCx, aDefineOnGlobal);\n"
  2904. return getConstructor
  2905. def getConditionList(idlobj, cxName, objName):
  2906. """
  2907. Get the list of conditions for idlobj (to be used in "is this enabled"
  2908. checks). This will be returned as a CGList with " &&\n" as the separator,
  2909. for readability.
  2910. objName is the name of the object that we're working with, because some of
  2911. our test functions want that.
  2912. """
  2913. conditions = []
  2914. pref = idlobj.getExtendedAttribute("Pref")
  2915. if pref:
  2916. assert isinstance(pref, list) and len(pref) == 1
  2917. conditions.append('Preferences::GetBool("%s")' % pref[0])
  2918. if idlobj.getExtendedAttribute("ChromeOnly"):
  2919. conditions.append("nsContentUtils::ThreadsafeIsCallerChrome()")
  2920. func = idlobj.getExtendedAttribute("Func")
  2921. if func:
  2922. assert isinstance(func, list) and len(func) == 1
  2923. conditions.append("%s(%s, %s)" % (func[0], cxName, objName))
  2924. if idlobj.getExtendedAttribute("SecureContext"):
  2925. conditions.append("mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(%s, %s)" % (cxName, objName))
  2926. return CGList((CGGeneric(cond) for cond in conditions), " &&\n")
  2927. class CGConstructorEnabled(CGAbstractMethod):
  2928. """
  2929. A method for testing whether we should be exposing this interface
  2930. object or navigator property. This can perform various tests
  2931. depending on what conditions are specified on the interface.
  2932. """
  2933. def __init__(self, descriptor):
  2934. CGAbstractMethod.__init__(self, descriptor,
  2935. 'ConstructorEnabled', 'bool',
  2936. [Argument("JSContext*", "aCx"),
  2937. Argument("JS::Handle<JSObject*>", "aObj")])
  2938. def definition_body(self):
  2939. body = CGList([], "\n")
  2940. iface = self.descriptor.interface
  2941. if not iface.isExposedOnMainThread():
  2942. exposedInWindowCheck = dedent(
  2943. """
  2944. MOZ_ASSERT(!NS_IsMainThread(), "Why did we even get called?");
  2945. """)
  2946. body.append(CGGeneric(exposedInWindowCheck))
  2947. if iface.isExposedInSomeButNotAllWorkers():
  2948. workerGlobals = sorted(iface.getWorkerExposureSet())
  2949. workerCondition = CGList((CGGeneric('strcmp(name, "%s")' % workerGlobal)
  2950. for workerGlobal in workerGlobals), " && ")
  2951. exposedInWorkerCheck = fill(
  2952. """
  2953. const char* name = js::GetObjectClass(aObj)->name;
  2954. if (${workerCondition}) {
  2955. return false;
  2956. }
  2957. """, workerCondition=workerCondition.define())
  2958. exposedInWorkerCheck = CGGeneric(exposedInWorkerCheck)
  2959. if iface.isExposedOnMainThread():
  2960. exposedInWorkerCheck = CGIfWrapper(exposedInWorkerCheck,
  2961. "!NS_IsMainThread()")
  2962. body.append(exposedInWorkerCheck)
  2963. conditions = getConditionList(iface, "aCx", "aObj")
  2964. # We should really have some conditions
  2965. assert len(body) or len(conditions)
  2966. conditionsWrapper = ""
  2967. if len(conditions):
  2968. conditionsWrapper = CGWrapper(conditions,
  2969. pre="return ",
  2970. post=";\n",
  2971. reindent=True)
  2972. else:
  2973. conditionsWrapper = CGGeneric("return true;\n")
  2974. body.append(conditionsWrapper)
  2975. return body.define()
  2976. def CreateBindingJSObject(descriptor, properties):
  2977. objDecl = "BindingJSObjectCreator<%s> creator(aCx);\n" % descriptor.nativeType
  2978. # We don't always need to root obj, but there are a variety
  2979. # of cases where we do, so for simplicity, just always root it.
  2980. if descriptor.proxy:
  2981. create = dedent(
  2982. """
  2983. creator.CreateProxyObject(aCx, &sClass.mBase, DOMProxyHandler::getInstance(),
  2984. proto, aObject, aReflector);
  2985. if (!aReflector) {
  2986. return false;
  2987. }
  2988. """)
  2989. if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  2990. create += dedent("""
  2991. js::SetProxyExtra(aReflector, JSPROXYSLOT_EXPANDO,
  2992. JS::PrivateValue(&aObject->mExpandoAndGeneration));
  2993. """)
  2994. else:
  2995. create = dedent(
  2996. """
  2997. creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
  2998. if (!aReflector) {
  2999. return false;
  3000. }
  3001. """)
  3002. return objDecl + create
  3003. def InitUnforgeablePropertiesOnHolder(descriptor, properties, failureCode,
  3004. holderName="unforgeableHolder"):
  3005. """
  3006. Define the unforgeable properties on the unforgeable holder for
  3007. the interface represented by descriptor.
  3008. properties is a PropertyArrays instance.
  3009. """
  3010. assert (properties.unforgeableAttrs.hasNonChromeOnly() or
  3011. properties.unforgeableAttrs.hasChromeOnly() or
  3012. properties.unforgeableMethods.hasNonChromeOnly() or
  3013. properties.unforgeableMethods.hasChromeOnly())
  3014. unforgeables = []
  3015. defineUnforgeableAttrs = fill(
  3016. """
  3017. if (!DefineUnforgeableAttributes(aCx, ${holderName}, %s)) {
  3018. $*{failureCode}
  3019. }
  3020. """,
  3021. failureCode=failureCode,
  3022. holderName=holderName)
  3023. defineUnforgeableMethods = fill(
  3024. """
  3025. if (!DefineUnforgeableMethods(aCx, ${holderName}, %s)) {
  3026. $*{failureCode}
  3027. }
  3028. """,
  3029. failureCode=failureCode,
  3030. holderName=holderName)
  3031. unforgeableMembers = [
  3032. (defineUnforgeableAttrs, properties.unforgeableAttrs),
  3033. (defineUnforgeableMethods, properties.unforgeableMethods)
  3034. ]
  3035. for (template, array) in unforgeableMembers:
  3036. if array.hasNonChromeOnly():
  3037. unforgeables.append(CGGeneric(template % array.variableName(False)))
  3038. if array.hasChromeOnly():
  3039. unforgeables.append(
  3040. CGIfWrapper(CGGeneric(template % array.variableName(True)),
  3041. "nsContentUtils::ThreadsafeIsCallerChrome()"))
  3042. if descriptor.interface.getExtendedAttribute("Unforgeable"):
  3043. # We do our undefined toPrimitive here, not as a regular property
  3044. # because we don't have a concept of value props anywhere in IDL.
  3045. unforgeables.append(CGGeneric(fill(
  3046. """
  3047. JS::RootedId toPrimitive(aCx,
  3048. SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::toPrimitive)));
  3049. if (!JS_DefinePropertyById(aCx, ${holderName}, toPrimitive,
  3050. JS::UndefinedHandleValue,
  3051. JSPROP_READONLY | JSPROP_PERMANENT)) {
  3052. $*{failureCode}
  3053. }
  3054. """,
  3055. failureCode=failureCode,
  3056. holderName=holderName)))
  3057. return CGWrapper(CGList(unforgeables), pre="\n")
  3058. def CopyUnforgeablePropertiesToInstance(descriptor, failureCode):
  3059. """
  3060. Copy the unforgeable properties from the unforgeable holder for
  3061. this interface to the instance object we have.
  3062. """
  3063. assert not descriptor.isGlobal();
  3064. if not descriptor.hasUnforgeableMembers:
  3065. return ""
  3066. copyCode = [
  3067. CGGeneric(dedent(
  3068. """
  3069. // Important: do unforgeable property setup after we have handed
  3070. // over ownership of the C++ object to obj as needed, so that if
  3071. // we fail and it ends up GCed it won't have problems in the
  3072. // finalizer trying to drop its ownership of the C++ object.
  3073. """))
  3074. ]
  3075. # For proxies, we want to define on the expando object, not directly on the
  3076. # reflector, so we can make sure we don't get confused by named getters.
  3077. if descriptor.proxy:
  3078. copyCode.append(CGGeneric(fill(
  3079. """
  3080. JS::Rooted<JSObject*> expando(aCx,
  3081. DOMProxyHandler::EnsureExpandoObject(aCx, aReflector));
  3082. if (!expando) {
  3083. $*{failureCode}
  3084. }
  3085. """,
  3086. failureCode=failureCode)))
  3087. obj = "expando"
  3088. else:
  3089. obj = "aReflector"
  3090. copyCode.append(CGGeneric(fill(
  3091. """
  3092. JS::Rooted<JSObject*> unforgeableHolder(aCx,
  3093. &js::GetReservedSlot(canonicalProto, DOM_INTERFACE_PROTO_SLOTS_BASE).toObject());
  3094. if (!JS_InitializePropertiesFromCompatibleNativeObject(aCx, ${obj}, unforgeableHolder)) {
  3095. $*{failureCode}
  3096. }
  3097. """,
  3098. obj=obj,
  3099. failureCode=failureCode)))
  3100. return CGWrapper(CGList(copyCode), pre="\n").define()
  3101. def AssertInheritanceChain(descriptor):
  3102. asserts = ""
  3103. iface = descriptor.interface
  3104. while iface:
  3105. desc = descriptor.getDescriptor(iface.identifier.name)
  3106. asserts += (
  3107. "MOZ_ASSERT(static_cast<%s*>(aObject) == \n"
  3108. " reinterpret_cast<%s*>(aObject),\n"
  3109. " \"Multiple inheritance for %s is broken.\");\n" %
  3110. (desc.nativeType, desc.nativeType, desc.nativeType))
  3111. iface = iface.parent
  3112. asserts += "MOZ_ASSERT(ToSupportsIsCorrect(aObject));\n"
  3113. return asserts
  3114. def InitMemberSlots(descriptor, failureCode):
  3115. """
  3116. Initialize member slots on our JS object if we're supposed to have some.
  3117. Note that this is called after the SetWrapper() call in the
  3118. wrapperCache case, since that can affect how our getters behave
  3119. and we plan to invoke them here. So if we fail, we need to
  3120. ClearWrapper.
  3121. """
  3122. if not descriptor.interface.hasMembersInSlots():
  3123. return ""
  3124. return fill(
  3125. """
  3126. if (!UpdateMemberSlots(aCx, aReflector, aObject)) {
  3127. $*{failureCode}
  3128. }
  3129. """,
  3130. failureCode=failureCode)
  3131. def SetImmutablePrototype(descriptor, failureCode):
  3132. if not descriptor.hasNonOrdinaryGetPrototypeOf():
  3133. return ""
  3134. return fill(
  3135. """
  3136. bool succeeded;
  3137. if (!JS_SetImmutablePrototype(aCx, aReflector, &succeeded)) {
  3138. ${failureCode}
  3139. }
  3140. MOZ_ASSERT(succeeded,
  3141. "Making a fresh reflector instance have an immutable "
  3142. "prototype can internally fail, but it should never be "
  3143. "unsuccessful");
  3144. """,
  3145. failureCode=failureCode)
  3146. def DeclareProto():
  3147. """
  3148. Declare the canonicalProto and proto we have for our wrapping operation.
  3149. """
  3150. return dedent(
  3151. """
  3152. JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
  3153. if (!canonicalProto) {
  3154. return false;
  3155. }
  3156. JS::Rooted<JSObject*> proto(aCx);
  3157. if (aGivenProto) {
  3158. proto = aGivenProto;
  3159. // Unfortunately, while aGivenProto was in the compartment of aCx
  3160. // coming in, we changed compartments to that of "parent" so may need
  3161. // to wrap the proto here.
  3162. if (js::GetContextCompartment(aCx) != js::GetObjectCompartment(proto)) {
  3163. if (!JS_WrapObject(aCx, &proto)) {
  3164. return false;
  3165. }
  3166. }
  3167. } else {
  3168. proto = canonicalProto;
  3169. }
  3170. """)
  3171. class CGWrapWithCacheMethod(CGAbstractMethod):
  3172. """
  3173. Create a wrapper JSObject for a given native that implements nsWrapperCache.
  3174. properties should be a PropertyArrays instance.
  3175. """
  3176. def __init__(self, descriptor, properties):
  3177. assert descriptor.interface.hasInterfacePrototypeObject()
  3178. args = [Argument('JSContext*', 'aCx'),
  3179. Argument(descriptor.nativeType + '*', 'aObject'),
  3180. Argument('nsWrapperCache*', 'aCache'),
  3181. Argument('JS::Handle<JSObject*>', 'aGivenProto'),
  3182. Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
  3183. CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
  3184. self.properties = properties
  3185. def definition_body(self):
  3186. if self.descriptor.proxy:
  3187. preserveWrapper = dedent(
  3188. """
  3189. // For DOM proxies, the only reliable way to preserve the wrapper
  3190. // is to force creation of the expando object.
  3191. JS::Rooted<JSObject*> unused(aCx,
  3192. DOMProxyHandler::EnsureExpandoObject(aCx, aReflector));
  3193. """)
  3194. else:
  3195. preserveWrapper = "PreserveWrapper(aObject);\n"
  3196. failureCode = dedent(
  3197. """
  3198. aCache->ReleaseWrapper(aObject);
  3199. aCache->ClearWrapper();
  3200. return false;
  3201. """)
  3202. return fill(
  3203. """
  3204. $*{assertInheritance}
  3205. MOZ_ASSERT(!aCache->GetWrapper(),
  3206. "You should probably not be using Wrap() directly; use "
  3207. "GetOrCreateDOMReflector instead");
  3208. MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
  3209. "nsISupports must be on our primary inheritance chain");
  3210. JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
  3211. if (!global) {
  3212. return false;
  3213. }
  3214. MOZ_ASSERT(JS_IsGlobalObject(global));
  3215. MOZ_ASSERT(!JS::ObjectIsMarkedGray(global));
  3216. // That might have ended up wrapping us already, due to the wonders
  3217. // of XBL. Check for that, and bail out as needed.
  3218. aReflector.set(aCache->GetWrapper());
  3219. if (aReflector) {
  3220. #ifdef DEBUG
  3221. binding_detail::AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
  3222. #endif // DEBUG
  3223. return true;
  3224. }
  3225. JSAutoCompartment ac(aCx, global);
  3226. $*{declareProto}
  3227. $*{createObject}
  3228. aCache->SetWrapper(aReflector);
  3229. $*{unforgeable}
  3230. $*{slots}
  3231. $*{setImmutablePrototype}
  3232. creator.InitializationSucceeded();
  3233. MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
  3234. aCache->GetWrapperPreserveColor() == aReflector);
  3235. // If proto != canonicalProto, we have to preserve our wrapper;
  3236. // otherwise we won't be able to properly recreate it later, since
  3237. // we won't know what proto to use. Note that we don't check
  3238. // aGivenProto here, since it's entirely possible (and even
  3239. // somewhat common) to have a non-null aGivenProto which is the
  3240. // same as canonicalProto.
  3241. if (proto != canonicalProto) {
  3242. $*{preserveWrapper}
  3243. }
  3244. return true;
  3245. """,
  3246. assertInheritance=AssertInheritanceChain(self.descriptor),
  3247. declareProto=DeclareProto(),
  3248. createObject=CreateBindingJSObject(self.descriptor, self.properties),
  3249. unforgeable=CopyUnforgeablePropertiesToInstance(self.descriptor,
  3250. failureCode),
  3251. slots=InitMemberSlots(self.descriptor, failureCode),
  3252. setImmutablePrototype=SetImmutablePrototype(self.descriptor,
  3253. failureCode),
  3254. preserveWrapper=preserveWrapper)
  3255. class CGWrapMethod(CGAbstractMethod):
  3256. def __init__(self, descriptor):
  3257. # XXX can we wrap if we don't have an interface prototype object?
  3258. assert descriptor.interface.hasInterfacePrototypeObject()
  3259. args = [Argument('JSContext*', 'aCx'),
  3260. Argument('T*', 'aObject'),
  3261. Argument('JS::Handle<JSObject*>', 'aGivenProto')]
  3262. CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args,
  3263. inline=True, templateArgs=["class T"])
  3264. def definition_body(self):
  3265. return dedent("""
  3266. JS::Rooted<JSObject*> reflector(aCx);
  3267. return Wrap(aCx, aObject, aObject, aGivenProto, &reflector) ? reflector.get() : nullptr;
  3268. """)
  3269. class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
  3270. """
  3271. Create a wrapper JSObject for a given native that does not implement
  3272. nsWrapperCache.
  3273. properties should be a PropertyArrays instance.
  3274. """
  3275. def __init__(self, descriptor, properties):
  3276. # XXX can we wrap if we don't have an interface prototype object?
  3277. assert descriptor.interface.hasInterfacePrototypeObject()
  3278. args = [Argument('JSContext*', 'aCx'),
  3279. Argument(descriptor.nativeType + '*', 'aObject'),
  3280. Argument('JS::Handle<JSObject*>', 'aGivenProto'),
  3281. Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
  3282. CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
  3283. self.properties = properties
  3284. def definition_body(self):
  3285. failureCode = "return false;\n"
  3286. return fill(
  3287. """
  3288. $*{assertions}
  3289. JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
  3290. $*{declareProto}
  3291. $*{createObject}
  3292. $*{unforgeable}
  3293. $*{slots}
  3294. $*{setImmutablePrototype}
  3295. creator.InitializationSucceeded();
  3296. return true;
  3297. """,
  3298. assertions=AssertInheritanceChain(self.descriptor),
  3299. declareProto=DeclareProto(),
  3300. createObject=CreateBindingJSObject(self.descriptor, self.properties),
  3301. unforgeable=CopyUnforgeablePropertiesToInstance(self.descriptor,
  3302. failureCode),
  3303. slots=InitMemberSlots(self.descriptor, failureCode),
  3304. setImmutablePrototype=SetImmutablePrototype(self.descriptor,
  3305. failureCode))
  3306. class CGWrapGlobalMethod(CGAbstractMethod):
  3307. """
  3308. Create a wrapper JSObject for a global. The global must implement
  3309. nsWrapperCache.
  3310. properties should be a PropertyArrays instance.
  3311. """
  3312. def __init__(self, descriptor, properties):
  3313. assert descriptor.interface.hasInterfacePrototypeObject()
  3314. args = [Argument('JSContext*', 'aCx'),
  3315. Argument(descriptor.nativeType + '*', 'aObject'),
  3316. Argument('nsWrapperCache*', 'aCache'),
  3317. Argument('JS::CompartmentOptions&', 'aOptions'),
  3318. Argument('JSPrincipals*', 'aPrincipal'),
  3319. Argument('bool', 'aInitStandardClasses'),
  3320. Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
  3321. CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
  3322. self.descriptor = descriptor
  3323. self.properties = properties
  3324. def definition_body(self):
  3325. if self.properties.hasNonChromeOnly():
  3326. properties = "sNativeProperties.Upcast()"
  3327. else:
  3328. properties = "nullptr"
  3329. if self.properties.hasChromeOnly():
  3330. chromeProperties = "nsContentUtils::ThreadsafeIsCallerChrome() ? sChromeOnlyNativeProperties.Upcast() : nullptr"
  3331. else:
  3332. chromeProperties = "nullptr"
  3333. failureCode = dedent(
  3334. """
  3335. aCache->ReleaseWrapper(aObject);
  3336. aCache->ClearWrapper();
  3337. return false;
  3338. """);
  3339. if self.descriptor.hasUnforgeableMembers:
  3340. unforgeable = InitUnforgeablePropertiesOnHolder(
  3341. self.descriptor, self.properties, failureCode,
  3342. "aReflector").define();
  3343. else:
  3344. unforgeable = ""
  3345. return fill(
  3346. """
  3347. $*{assertions}
  3348. MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
  3349. "nsISupports must be on our primary inheritance chain");
  3350. if (!CreateGlobal<${nativeType}, GetProtoObjectHandle>(aCx,
  3351. aObject,
  3352. aCache,
  3353. sClass.ToJSClass(),
  3354. aOptions,
  3355. aPrincipal,
  3356. aInitStandardClasses,
  3357. aReflector)) {
  3358. $*{failureCode}
  3359. }
  3360. // aReflector is a new global, so has a new compartment. Enter it
  3361. // before doing anything with it.
  3362. JSAutoCompartment ac(aCx, aReflector);
  3363. if (!DefineProperties(aCx, aReflector, ${properties}, ${chromeProperties})) {
  3364. $*{failureCode}
  3365. }
  3366. $*{unforgeable}
  3367. $*{slots}
  3368. return true;
  3369. """,
  3370. assertions=AssertInheritanceChain(self.descriptor),
  3371. nativeType=self.descriptor.nativeType,
  3372. properties=properties,
  3373. chromeProperties=chromeProperties,
  3374. failureCode=failureCode,
  3375. unforgeable=unforgeable,
  3376. slots=InitMemberSlots(self.descriptor, failureCode))
  3377. class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod):
  3378. def __init__(self, descriptor):
  3379. args = [Argument('JSContext*', 'aCx'),
  3380. Argument('JS::Handle<JSObject*>', 'aWrapper'),
  3381. Argument(descriptor.nativeType + '*', 'aObject')]
  3382. CGAbstractStaticMethod.__init__(self, descriptor, 'UpdateMemberSlots', 'bool', args)
  3383. def definition_body(self):
  3384. body = ("JS::Rooted<JS::Value> temp(aCx);\n"
  3385. "JSJitGetterCallArgs args(&temp);\n")
  3386. for m in self.descriptor.interface.members:
  3387. if m.isAttr() and m.getExtendedAttribute("StoreInSlot"):
  3388. # Skip doing this for the "window" and "self" attributes on the
  3389. # Window interface, because those can't be gotten safely until
  3390. # we have hooked it up correctly to the outer window. The
  3391. # window code handles doing the get itself.
  3392. if (self.descriptor.interface.identifier.name == "Window" and
  3393. (m.identifier.name == "window" or m.identifier.name == "self")):
  3394. continue
  3395. body += fill(
  3396. """
  3397. if (!get_${member}(aCx, aWrapper, aObject, args)) {
  3398. return false;
  3399. }
  3400. // Getter handled setting our reserved slots
  3401. """,
  3402. member=m.identifier.name)
  3403. body += "\nreturn true;\n"
  3404. return body
  3405. class CGClearCachedValueMethod(CGAbstractMethod):
  3406. def __init__(self, descriptor, member):
  3407. self.member = member
  3408. # If we're StoreInSlot, we'll need to call the getter
  3409. if member.getExtendedAttribute("StoreInSlot"):
  3410. args = [Argument('JSContext*', 'aCx')]
  3411. returnType = 'bool'
  3412. else:
  3413. args = []
  3414. returnType = 'void'
  3415. args.append(Argument(descriptor.nativeType + '*', 'aObject'))
  3416. name = MakeClearCachedValueNativeName(member)
  3417. CGAbstractMethod.__init__(self, descriptor, name, returnType, args)
  3418. def definition_body(self):
  3419. slotIndex = memberReservedSlot(self.member, self.descriptor)
  3420. if self.member.getExtendedAttribute("StoreInSlot"):
  3421. # We have to root things and save the old value in case
  3422. # regetting fails, so we can restore it.
  3423. declObj = "JS::Rooted<JSObject*> obj(aCx);\n"
  3424. noopRetval = " true"
  3425. saveMember = (
  3426. "JS::Rooted<JS::Value> oldValue(aCx, js::GetReservedSlot(obj, %s));\n" %
  3427. slotIndex)
  3428. regetMember = fill(
  3429. """
  3430. JS::Rooted<JS::Value> temp(aCx);
  3431. JSJitGetterCallArgs args(&temp);
  3432. JSAutoCompartment ac(aCx, obj);
  3433. if (!get_${name}(aCx, obj, aObject, args)) {
  3434. js::SetReservedSlot(obj, ${slotIndex}, oldValue);
  3435. return false;
  3436. }
  3437. return true;
  3438. """,
  3439. name=self.member.identifier.name,
  3440. slotIndex=slotIndex)
  3441. else:
  3442. declObj = "JSObject* obj;\n"
  3443. noopRetval = ""
  3444. saveMember = ""
  3445. regetMember = ""
  3446. if self.descriptor.wantsXrays:
  3447. clearXrayExpandoSlots = fill(
  3448. """
  3449. xpc::ClearXrayExpandoSlots(obj, ${xraySlotIndex});
  3450. """,
  3451. xraySlotIndex=memberXrayExpandoReservedSlot(self.member,
  3452. self.descriptor))
  3453. else :
  3454. clearXrayExpandoSlots = ""
  3455. return fill(
  3456. """
  3457. $*{declObj}
  3458. obj = aObject->GetWrapper();
  3459. if (!obj) {
  3460. return${noopRetval};
  3461. }
  3462. $*{saveMember}
  3463. js::SetReservedSlot(obj, ${slotIndex}, JS::UndefinedValue());
  3464. $*{clearXrayExpandoSlots}
  3465. $*{regetMember}
  3466. """,
  3467. declObj=declObj,
  3468. noopRetval=noopRetval,
  3469. saveMember=saveMember,
  3470. slotIndex=slotIndex,
  3471. clearXrayExpandoSlots=clearXrayExpandoSlots,
  3472. regetMember=regetMember)
  3473. class CGIsPermittedMethod(CGAbstractMethod):
  3474. """
  3475. crossOriginGetters/Setters/Methods are sets of names of the relevant members.
  3476. """
  3477. def __init__(self, descriptor, crossOriginGetters, crossOriginSetters,
  3478. crossOriginMethods):
  3479. self.crossOriginGetters = crossOriginGetters
  3480. self.crossOriginSetters = crossOriginSetters
  3481. self.crossOriginMethods = crossOriginMethods
  3482. args = [Argument("JSFlatString*", "prop"),
  3483. Argument("char16_t", "propFirstChar"),
  3484. Argument("bool", "set")]
  3485. CGAbstractMethod.__init__(self, descriptor, "IsPermitted", "bool", args,
  3486. inline=True)
  3487. def definition_body(self):
  3488. allNames = self.crossOriginGetters | self.crossOriginSetters | self.crossOriginMethods
  3489. readwrite = self.crossOriginGetters & self.crossOriginSetters
  3490. readonly = (self.crossOriginGetters - self.crossOriginSetters) | self.crossOriginMethods
  3491. writeonly = self.crossOriginSetters - self.crossOriginGetters
  3492. cases = {}
  3493. for name in sorted(allNames):
  3494. cond = 'JS_FlatStringEqualsAscii(prop, "%s")' % name
  3495. if name in readonly:
  3496. cond = "!set && %s" % cond
  3497. elif name in writeonly:
  3498. cond = "set && %s" % cond
  3499. else:
  3500. assert name in readwrite
  3501. firstLetter = name[0]
  3502. case = cases.get(firstLetter, CGList([]))
  3503. case.append(CGGeneric("if (%s) {\n"
  3504. " return true;\n"
  3505. "}\n" % cond))
  3506. cases[firstLetter] = case
  3507. caseList = []
  3508. for firstLetter in sorted(cases.keys()):
  3509. caseList.append(CGCase("'%s'" % firstLetter, cases[firstLetter]))
  3510. switch = CGSwitch("propFirstChar", caseList)
  3511. return switch.define() + "\nreturn false;\n"
  3512. class CGCycleCollectionTraverseForOwningUnionMethod(CGAbstractMethod):
  3513. """
  3514. ImplCycleCollectionUnlink for owning union type.
  3515. """
  3516. def __init__(self, type):
  3517. self.type = type
  3518. args = [Argument("nsCycleCollectionTraversalCallback&", "aCallback"),
  3519. Argument("%s&" % CGUnionStruct.unionTypeName(type, True), "aUnion"),
  3520. Argument("const char*", "aName"),
  3521. Argument("uint32_t", "aFlags", "0")]
  3522. CGAbstractMethod.__init__(self, None, "ImplCycleCollectionTraverse", "void", args)
  3523. def deps(self):
  3524. return self.type.getDeps()
  3525. def definition_body(self):
  3526. memberNames = [getUnionMemberName(t)
  3527. for t in self.type.flatMemberTypes
  3528. if idlTypeNeedsCycleCollection(t)]
  3529. assert memberNames
  3530. conditionTemplate = 'aUnion.Is%s()'
  3531. functionCallTemplate = 'ImplCycleCollectionTraverse(aCallback, aUnion.GetAs%s(), "m%s", aFlags);\n'
  3532. ifStaments = (CGIfWrapper(CGGeneric(functionCallTemplate % (m, m)),
  3533. conditionTemplate % m)
  3534. for m in memberNames)
  3535. return CGElseChain(ifStaments).define()
  3536. class CGCycleCollectionUnlinkForOwningUnionMethod(CGAbstractMethod):
  3537. """
  3538. ImplCycleCollectionUnlink for owning union type.
  3539. """
  3540. def __init__(self, type):
  3541. self.type = type
  3542. args = [Argument("%s&" % CGUnionStruct.unionTypeName(type, True), "aUnion")]
  3543. CGAbstractMethod.__init__(self, None, "ImplCycleCollectionUnlink", "void", args)
  3544. def deps(self):
  3545. return self.type.getDeps()
  3546. def definition_body(self):
  3547. return "aUnion.Uninit();\n"
  3548. builtinNames = {
  3549. IDLType.Tags.bool: 'bool',
  3550. IDLType.Tags.int8: 'int8_t',
  3551. IDLType.Tags.int16: 'int16_t',
  3552. IDLType.Tags.int32: 'int32_t',
  3553. IDLType.Tags.int64: 'int64_t',
  3554. IDLType.Tags.uint8: 'uint8_t',
  3555. IDLType.Tags.uint16: 'uint16_t',
  3556. IDLType.Tags.uint32: 'uint32_t',
  3557. IDLType.Tags.uint64: 'uint64_t',
  3558. IDLType.Tags.unrestricted_float: 'float',
  3559. IDLType.Tags.float: 'float',
  3560. IDLType.Tags.unrestricted_double: 'double',
  3561. IDLType.Tags.double: 'double'
  3562. }
  3563. numericSuffixes = {
  3564. IDLType.Tags.int8: '',
  3565. IDLType.Tags.uint8: '',
  3566. IDLType.Tags.int16: '',
  3567. IDLType.Tags.uint16: '',
  3568. IDLType.Tags.int32: '',
  3569. IDLType.Tags.uint32: 'U',
  3570. IDLType.Tags.int64: 'LL',
  3571. IDLType.Tags.uint64: 'ULL',
  3572. IDLType.Tags.unrestricted_float: 'F',
  3573. IDLType.Tags.float: 'F',
  3574. IDLType.Tags.unrestricted_double: '',
  3575. IDLType.Tags.double: ''
  3576. }
  3577. def numericValue(t, v):
  3578. if (t == IDLType.Tags.unrestricted_double or
  3579. t == IDLType.Tags.unrestricted_float):
  3580. typeName = builtinNames[t]
  3581. if v == float("inf"):
  3582. return "mozilla::PositiveInfinity<%s>()" % typeName
  3583. if v == float("-inf"):
  3584. return "mozilla::NegativeInfinity<%s>()" % typeName
  3585. if math.isnan(v):
  3586. return "mozilla::UnspecifiedNaN<%s>()" % typeName
  3587. return "%s%s" % (v, numericSuffixes[t])
  3588. class CastableObjectUnwrapper():
  3589. """
  3590. A class for unwrapping an object stored in a JS Value (or
  3591. MutableHandle<Value> or Handle<Value>) named by the "source" and
  3592. "mutableSource" arguments based on the passed-in descriptor and storing it
  3593. in a variable called by the name in the "target" argument. The "source"
  3594. argument should be able to produce a Value or Handle<Value>; the
  3595. "mutableSource" argument should be able to produce a MutableHandle<Value>
  3596. codeOnFailure is the code to run if unwrapping fails.
  3597. If isCallbackReturnValue is "JSImpl" and our descriptor is also
  3598. JS-implemented, fall back to just creating the right object if what we
  3599. have isn't one already.
  3600. If allowCrossOriginObj is True, then we'll first do an
  3601. UncheckedUnwrap and then operate on the result.
  3602. """
  3603. def __init__(self, descriptor, source, mutableSource, target, codeOnFailure,
  3604. exceptionCode=None, isCallbackReturnValue=False,
  3605. allowCrossOriginObj=False):
  3606. self.substitution = {
  3607. "type": descriptor.nativeType,
  3608. "protoID": "prototypes::id::" + descriptor.name,
  3609. "target": target,
  3610. "codeOnFailure": codeOnFailure,
  3611. }
  3612. # Supporting both the "cross origin object" case and the "has
  3613. # XPConnect impls" case at the same time is a pain, so let's
  3614. # not do that. That allows us to assume that our source is
  3615. # always a Handle or MutableHandle.
  3616. if allowCrossOriginObj and descriptor.hasXPConnectImpls:
  3617. raise TypeError("Interface %s both allows a cross-origin 'this' "
  3618. "and has XPConnect impls. We don't support that" %
  3619. descriptor.name)
  3620. if allowCrossOriginObj:
  3621. self.substitution["uncheckedObjDecl"] = fill(
  3622. """
  3623. JS::Rooted<JSObject*> maybeUncheckedObj(cx, &${source}.toObject());
  3624. """,
  3625. source=source)
  3626. self.substitution["uncheckedObjGet"] = fill(
  3627. """
  3628. if (xpc::WrapperFactory::IsXrayWrapper(maybeUncheckedObj)) {
  3629. maybeUncheckedObj = js::UncheckedUnwrap(maybeUncheckedObj);
  3630. } else {
  3631. maybeUncheckedObj = js::CheckedUnwrap(maybeUncheckedObj);
  3632. if (!maybeUncheckedObj) {
  3633. $*{codeOnFailure}
  3634. }
  3635. }
  3636. """,
  3637. codeOnFailure=(codeOnFailure % { 'securityError': 'true'}))
  3638. self.substitution["source"] = "maybeUncheckedObj"
  3639. self.substitution["mutableSource"] = "&maybeUncheckedObj"
  3640. # No need to set up xpconnectUnwrap, since it won't be
  3641. # used in the allowCrossOriginObj case.
  3642. else:
  3643. self.substitution["uncheckedObjDecl"] = ""
  3644. self.substitution["uncheckedObjGet"] = ""
  3645. self.substitution["source"] = source
  3646. self.substitution["mutableSource"] = mutableSource
  3647. xpconnectUnwrap = (
  3648. "nsresult rv = UnwrapXPConnect<${type}>(cx, ${mutableSource}, getter_AddRefs(objPtr));\n")
  3649. if descriptor.hasXPConnectImpls:
  3650. self.substitution["codeOnFailure"] = string.Template(
  3651. "RefPtr<${type}> objPtr;\n" +
  3652. xpconnectUnwrap +
  3653. "if (NS_FAILED(rv)) {\n"
  3654. "${indentedCodeOnFailure}"
  3655. "}\n"
  3656. "// We should have an object\n"
  3657. "MOZ_ASSERT(objPtr);\n"
  3658. "${target} = objPtr;\n"
  3659. ).substitute(self.substitution,
  3660. indentedCodeOnFailure=indent(codeOnFailure))
  3661. elif (isCallbackReturnValue == "JSImpl" and
  3662. descriptor.interface.isJSImplemented()):
  3663. exceptionCode = exceptionCode or codeOnFailure
  3664. self.substitution["codeOnFailure"] = fill(
  3665. """
  3666. // Be careful to not wrap random DOM objects here, even if
  3667. // they're wrapped in opaque security wrappers for some reason.
  3668. // XXXbz Wish we could check for a JS-implemented object
  3669. // that already has a content reflection...
  3670. if (!IsDOMObject(js::UncheckedUnwrap(&${source}.toObject()))) {
  3671. nsCOMPtr<nsIGlobalObject> contentGlobal;
  3672. if (!GetContentGlobalForJSImplementedObject(cx, Callback(), getter_AddRefs(contentGlobal))) {
  3673. $*{exceptionCode}
  3674. }
  3675. JS::Rooted<JSObject*> jsImplSourceObj(cx, &${source}.toObject());
  3676. ${target} = new ${type}(jsImplSourceObj, contentGlobal);
  3677. } else {
  3678. $*{codeOnFailure}
  3679. }
  3680. """,
  3681. exceptionCode=exceptionCode,
  3682. **self.substitution)
  3683. else:
  3684. self.substitution["codeOnFailure"] = codeOnFailure
  3685. def __str__(self):
  3686. substitution = self.substitution.copy()
  3687. substitution["codeOnFailure"] %= {
  3688. 'securityError': 'rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO'
  3689. }
  3690. return fill(
  3691. """
  3692. $*{uncheckedObjDecl}
  3693. {
  3694. $*{uncheckedObjGet}
  3695. nsresult rv = UnwrapObject<${protoID}, ${type}>(${mutableSource}, ${target});
  3696. if (NS_FAILED(rv)) {
  3697. $*{codeOnFailure}
  3698. }
  3699. }
  3700. """,
  3701. **substitution)
  3702. class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
  3703. """
  3704. As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
  3705. """
  3706. def __init__(self, descriptor, source, mutableSource, target, exceptionCode,
  3707. isCallbackReturnValue, sourceDescription):
  3708. CastableObjectUnwrapper.__init__(
  3709. self, descriptor, source, mutableSource, target,
  3710. 'ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n'
  3711. '%s' % (sourceDescription, descriptor.interface.identifier.name,
  3712. exceptionCode),
  3713. exceptionCode,
  3714. isCallbackReturnValue)
  3715. class CGCallbackTempRoot(CGGeneric):
  3716. def __init__(self, name):
  3717. define = dedent("""
  3718. { // Scope for tempRoot
  3719. JS::Rooted<JSObject*> tempRoot(cx, &${val}.toObject());
  3720. ${declName} = new %s(cx, tempRoot, mozilla::dom::GetIncumbentGlobal());
  3721. }
  3722. """) % name
  3723. CGGeneric.__init__(self, define=define)
  3724. def getCallbackConversionInfo(type, idlObject, isMember, isCallbackReturnValue,
  3725. isOptional):
  3726. """
  3727. Returns a tuple containing the declType, declArgs, and basic
  3728. conversion for the given callback type, with the given callback
  3729. idl object in the given context (isMember/isCallbackReturnValue/isOptional).
  3730. """
  3731. name = idlObject.identifier.name
  3732. # We can't use fast callbacks if isOptional because then we get an
  3733. # Optional<RootedCallback> thing, which is not transparent to consumers.
  3734. useFastCallback = (not isMember and not isCallbackReturnValue and
  3735. not isOptional)
  3736. if useFastCallback:
  3737. name = "binding_detail::Fast%s" % name
  3738. if type.nullable() or isCallbackReturnValue:
  3739. declType = CGGeneric("RefPtr<%s>" % name)
  3740. else:
  3741. declType = CGGeneric("OwningNonNull<%s>" % name)
  3742. if useFastCallback:
  3743. declType = CGTemplatedType("RootedCallback", declType)
  3744. declArgs = "cx"
  3745. else:
  3746. declArgs = None
  3747. conversion = indent(CGCallbackTempRoot(name).define())
  3748. return (declType, declArgs, conversion)
  3749. class JSToNativeConversionInfo():
  3750. """
  3751. An object representing information about a JS-to-native conversion.
  3752. """
  3753. def __init__(self, template, declType=None, holderType=None,
  3754. dealWithOptional=False, declArgs=None,
  3755. holderArgs=None):
  3756. """
  3757. template: A string representing the conversion code. This will have
  3758. template substitution performed on it as follows:
  3759. ${val} is a handle to the JS::Value in question
  3760. ${maybeMutableVal} May be a mutable handle to the JS::Value in
  3761. question. This is only OK to use if ${val} is
  3762. known to not be undefined.
  3763. ${holderName} replaced by the holder's name, if any
  3764. ${declName} replaced by the declaration's name
  3765. ${haveValue} replaced by an expression that evaluates to a boolean
  3766. for whether we have a JS::Value. Only used when
  3767. defaultValue is not None or when True is passed for
  3768. checkForValue to instantiateJSToNativeConversion.
  3769. This expression may not be already-parenthesized, so if
  3770. you use it with && or || make sure to put parens
  3771. around it.
  3772. ${passedToJSImpl} replaced by an expression that evaluates to a boolean
  3773. for whether this value is being passed to a JS-
  3774. implemented interface.
  3775. declType: A CGThing representing the native C++ type we're converting
  3776. to. This is allowed to be None if the conversion code is
  3777. supposed to be used as-is.
  3778. holderType: A CGThing representing the type of a "holder" which will
  3779. hold a possible reference to the C++ thing whose type we
  3780. returned in declType, or None if no such holder is needed.
  3781. dealWithOptional: A boolean indicating whether the caller has to do
  3782. optional-argument handling. This should only be set
  3783. to true if the JS-to-native conversion is being done
  3784. for an optional argument or dictionary member with no
  3785. default value and if the returned template expects
  3786. both declType and holderType to be wrapped in
  3787. Optional<>, with ${declName} and ${holderName}
  3788. adjusted to point to the Value() of the Optional, and
  3789. Construct() calls to be made on the Optional<>s as
  3790. needed.
  3791. declArgs: If not None, the arguments to pass to the ${declName}
  3792. constructor. These will have template substitution performed
  3793. on them so you can use things like ${val}. This is a
  3794. single string, not a list of strings.
  3795. holderArgs: If not None, the arguments to pass to the ${holderName}
  3796. constructor. These will have template substitution
  3797. performed on them so you can use things like ${val}.
  3798. This is a single string, not a list of strings.
  3799. ${declName} must be in scope before the code from 'template' is entered.
  3800. If holderType is not None then ${holderName} must be in scope before
  3801. the code from 'template' is entered.
  3802. """
  3803. assert isinstance(template, str)
  3804. assert declType is None or isinstance(declType, CGThing)
  3805. assert holderType is None or isinstance(holderType, CGThing)
  3806. self.template = template
  3807. self.declType = declType
  3808. self.holderType = holderType
  3809. self.dealWithOptional = dealWithOptional
  3810. self.declArgs = declArgs
  3811. self.holderArgs = holderArgs
  3812. def getHandleDefault(defaultValue):
  3813. tag = defaultValue.type.tag()
  3814. if tag in numericSuffixes:
  3815. # Some numeric literals require a suffix to compile without warnings
  3816. return numericValue(tag, defaultValue.value)
  3817. assert tag == IDLType.Tags.bool
  3818. return toStringBool(defaultValue.value)
  3819. def handleDefaultStringValue(defaultValue, method):
  3820. """
  3821. Returns a string which ends up calling 'method' with a (char_t*, length)
  3822. pair that sets this string default value. This string is suitable for
  3823. passing as the second argument of handleDefault; in particular it does not
  3824. end with a ';'
  3825. """
  3826. assert (defaultValue.type.isDOMString() or
  3827. defaultValue.type.isUSVString() or
  3828. defaultValue.type.isByteString())
  3829. return ("static const %(char_t)s data[] = { %(data)s };\n"
  3830. "%(method)s(data, ArrayLength(data) - 1)") % {
  3831. 'char_t': "char" if defaultValue.type.isByteString() else "char16_t",
  3832. 'method': method,
  3833. 'data': ", ".join(["'" + char + "'" for char in
  3834. defaultValue.value] + ["0"])
  3835. }
  3836. def recordKeyType(recordType):
  3837. assert recordType.keyType.isString()
  3838. if recordType.keyType.isByteString():
  3839. return "nsCString"
  3840. return "nsString"
  3841. def recordKeyDeclType(recordType):
  3842. return CGGeneric(recordKeyType(recordType))
  3843. # If this function is modified, modify CGNativeMember.getArg and
  3844. # CGNativeMember.getRetvalInfo accordingly. The latter cares about the decltype
  3845. # and holdertype we end up using, because it needs to be able to return the code
  3846. # that will convert those to the actual return value of the callback function.
  3847. def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
  3848. isDefinitelyObject=False,
  3849. isMember=False,
  3850. isOptional=False,
  3851. invalidEnumValueFatal=True,
  3852. defaultValue=None,
  3853. treatNullAs="Default",
  3854. isEnforceRange=False,
  3855. isClamp=False,
  3856. isNullOrUndefined=False,
  3857. exceptionCode=None,
  3858. lenientFloatCode=None,
  3859. allowTreatNonCallableAsNull=False,
  3860. isCallbackReturnValue=False,
  3861. sourceDescription="value",
  3862. nestingLevel=""):
  3863. """
  3864. Get a template for converting a JS value to a native object based on the
  3865. given type and descriptor. If failureCode is given, then we're actually
  3866. testing whether we can convert the argument to the desired type. That
  3867. means that failures to convert due to the JS value being the wrong type of
  3868. value need to use failureCode instead of throwing exceptions. Failures to
  3869. convert that are due to JS exceptions (from toString or valueOf methods) or
  3870. out of memory conditions need to throw exceptions no matter what
  3871. failureCode is. However what actually happens when throwing an exception
  3872. can be controlled by exceptionCode. The only requirement on that is that
  3873. exceptionCode must end up doing a return, and every return from this
  3874. function must happen via exceptionCode if exceptionCode is not None.
  3875. If isDefinitelyObject is True, that means we know the value
  3876. isObject() and we have no need to recheck that.
  3877. if isMember is not False, we're being converted from a property of some JS
  3878. object, not from an actual method argument, so we can't rely on our jsval
  3879. being rooted or outliving us in any way. Callers can pass "Dictionary",
  3880. "Variadic", "Sequence", or "OwningUnion" to indicate that the conversion is
  3881. for something that is a dictionary member, a variadic argument, a sequence,
  3882. or an owning union respectively.
  3883. If isOptional is true, then we are doing conversion of an optional
  3884. argument with no default value.
  3885. invalidEnumValueFatal controls whether an invalid enum value conversion
  3886. attempt will throw (if true) or simply return without doing anything (if
  3887. false).
  3888. If defaultValue is not None, it's the IDL default value for this conversion
  3889. If isEnforceRange is true, we're converting an integer and throwing if the
  3890. value is out of range.
  3891. If isClamp is true, we're converting an integer and clamping if the
  3892. value is out of range.
  3893. If lenientFloatCode is not None, it should be used in cases when
  3894. we're a non-finite float that's not unrestricted.
  3895. If allowTreatNonCallableAsNull is true, then [TreatNonCallableAsNull] and
  3896. [TreatNonObjectAsNull] extended attributes on nullable callback functions
  3897. will be honored.
  3898. If isCallbackReturnValue is "JSImpl" or "Callback", then the declType may be
  3899. adjusted to make it easier to return from a callback. Since that type is
  3900. never directly observable by any consumers of the callback code, this is OK.
  3901. Furthermore, if isCallbackReturnValue is "JSImpl", that affects the behavior
  3902. of the FailureFatalCastableObjectUnwrapper conversion; this is used for
  3903. implementing auto-wrapping of JS-implemented return values from a
  3904. JS-implemented interface.
  3905. sourceDescription is a description of what this JS value represents, to be
  3906. used in error reporting. Callers should assume that it might get placed in
  3907. the middle of a sentence. If it ends up at the beginning of a sentence, its
  3908. first character will be automatically uppercased.
  3909. The return value from this function is a JSToNativeConversionInfo.
  3910. """
  3911. # If we have a defaultValue then we're not actually optional for
  3912. # purposes of what we need to be declared as.
  3913. assert defaultValue is None or not isOptional
  3914. # Also, we should not have a defaultValue if we know we're an object
  3915. assert not isDefinitelyObject or defaultValue is None
  3916. # And we can't both be an object and be null or undefined
  3917. assert not isDefinitelyObject or not isNullOrUndefined
  3918. # If exceptionCode is not set, we'll just rethrow the exception we got.
  3919. # Note that we can't just set failureCode to exceptionCode, because setting
  3920. # failureCode will prevent pending exceptions from being set in cases when
  3921. # they really should be!
  3922. if exceptionCode is None:
  3923. exceptionCode = "return false;\n"
  3924. # Unfortunately, .capitalize() on a string will lowercase things inside the
  3925. # string, which we do not want.
  3926. def firstCap(string):
  3927. return string[0].upper() + string[1:]
  3928. # Helper functions for dealing with failures due to the JS value being the
  3929. # wrong type of value
  3930. def onFailureNotAnObject(failureCode):
  3931. return CGGeneric(
  3932. failureCode or
  3933. ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
  3934. '%s' % (firstCap(sourceDescription), exceptionCode)))
  3935. def onFailureBadType(failureCode, typeName):
  3936. return CGGeneric(
  3937. failureCode or
  3938. ('ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n'
  3939. '%s' % (firstCap(sourceDescription), typeName, exceptionCode)))
  3940. def onFailureNotCallable(failureCode):
  3941. return CGGeneric(
  3942. failureCode or
  3943. ('ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "%s");\n'
  3944. '%s' % (firstCap(sourceDescription), exceptionCode)))
  3945. # A helper function for handling default values. Takes a template
  3946. # body and the C++ code to set the default value and wraps the
  3947. # given template body in handling for the default value.
  3948. def handleDefault(template, setDefault):
  3949. if defaultValue is None:
  3950. return template
  3951. return (
  3952. "if (${haveValue}) {\n" +
  3953. indent(template) +
  3954. "} else {\n" +
  3955. indent(setDefault) +
  3956. "}\n")
  3957. # A helper function for wrapping up the template body for
  3958. # possibly-nullable objecty stuff
  3959. def wrapObjectTemplate(templateBody, type, codeToSetNull, failureCode=None):
  3960. if isNullOrUndefined and type.nullable():
  3961. # Just ignore templateBody and set ourselves to null.
  3962. # Note that we don't have to worry about default values
  3963. # here either, since we already examined this value.
  3964. return codeToSetNull
  3965. if not isDefinitelyObject:
  3966. # Handle the non-object cases by wrapping up the whole
  3967. # thing in an if cascade.
  3968. if type.nullable():
  3969. elifLine = "} else if (${val}.isNullOrUndefined()) {\n"
  3970. elifBody = codeToSetNull
  3971. else:
  3972. elifLine = ""
  3973. elifBody = ""
  3974. # Note that $${val} below expands to ${val}. This string is
  3975. # used as a template later, and val will be filled in then.
  3976. templateBody = fill(
  3977. """
  3978. if ($${val}.isObject()) {
  3979. $*{templateBody}
  3980. $*{elifLine}
  3981. $*{elifBody}
  3982. } else {
  3983. $*{failureBody}
  3984. }
  3985. """,
  3986. templateBody=templateBody,
  3987. elifLine=elifLine,
  3988. elifBody=elifBody,
  3989. failureBody=onFailureNotAnObject(failureCode).define())
  3990. if isinstance(defaultValue, IDLNullValue):
  3991. assert type.nullable() # Parser should enforce this
  3992. templateBody = handleDefault(templateBody, codeToSetNull)
  3993. elif isinstance(defaultValue, IDLEmptySequenceValue):
  3994. # Our caller will handle it
  3995. pass
  3996. else:
  3997. assert defaultValue is None
  3998. return templateBody
  3999. # A helper function for converting things that look like a JSObject*.
  4000. def handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription):
  4001. if not isMember:
  4002. if isOptional:
  4003. # We have a specialization of Optional that will use a
  4004. # Rooted for the storage here.
  4005. declType = CGGeneric("JS::Handle<JSObject*>")
  4006. else:
  4007. declType = CGGeneric("JS::Rooted<JSObject*>")
  4008. declArgs = "cx"
  4009. else:
  4010. assert (isMember in
  4011. ("Sequence", "Variadic", "Dictionary", "OwningUnion", "Record"))
  4012. # We'll get traced by the sequence or dictionary or union tracer
  4013. declType = CGGeneric("JSObject*")
  4014. declArgs = None
  4015. templateBody = "${declName} = &${val}.toObject();\n"
  4016. # For JS-implemented APIs, we refuse to allow passing objects that the
  4017. # API consumer does not subsume. The extra parens around
  4018. # ($${passedToJSImpl}) suppress unreachable code warnings when
  4019. # $${passedToJSImpl} is the literal `false`.
  4020. if not isinstance(descriptorProvider, Descriptor) or descriptorProvider.interface.isJSImplemented():
  4021. templateBody = fill(
  4022. """
  4023. if (($${passedToJSImpl}) && !CallerSubsumes($${val})) {
  4024. ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
  4025. $*{exceptionCode}
  4026. }
  4027. """,
  4028. sourceDescription=sourceDescription,
  4029. exceptionCode=exceptionCode) + templateBody
  4030. setToNullCode = "${declName} = nullptr;\n"
  4031. template = wrapObjectTemplate(templateBody, type, setToNullCode,
  4032. failureCode)
  4033. return JSToNativeConversionInfo(template, declType=declType,
  4034. dealWithOptional=isOptional,
  4035. declArgs=declArgs)
  4036. def incrementNestingLevel():
  4037. if nestingLevel is "":
  4038. return 1
  4039. return nestingLevel + 1
  4040. assert not (isEnforceRange and isClamp) # These are mutually exclusive
  4041. if type.isSequence():
  4042. assert not isEnforceRange and not isClamp
  4043. if failureCode is None:
  4044. notSequence = ('ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "%s");\n'
  4045. "%s" % (firstCap(sourceDescription), exceptionCode))
  4046. else:
  4047. notSequence = failureCode
  4048. nullable = type.nullable()
  4049. # Be very careful not to change "type": we need it later
  4050. if nullable:
  4051. elementType = type.inner.inner
  4052. else:
  4053. elementType = type.inner
  4054. # We want to use auto arrays if we can, but we have to be careful with
  4055. # reallocation behavior for arrays. In particular, if we use auto
  4056. # arrays for sequences and have a sequence of elements which are
  4057. # themselves sequences or have sequences as members, we have a problem.
  4058. # In that case, resizing the outermost AutoTArray to the right size
  4059. # will memmove its elements, but AutoTArrays are not memmovable and
  4060. # hence will end up with pointers to bogus memory, which is bad. To
  4061. # deal with this, we typically map WebIDL sequences to our Sequence
  4062. # type, which is in fact memmovable. The one exception is when we're
  4063. # passing in a sequence directly as an argument without any sort of
  4064. # optional or nullable complexity going on. In that situation, we can
  4065. # use an AutoSequence instead. We have to keep using Sequence in the
  4066. # nullable and optional cases because we don't want to leak the
  4067. # AutoSequence type to consumers, which would be unavoidable with
  4068. # Nullable<AutoSequence> or Optional<AutoSequence>.
  4069. if isMember or isOptional or nullable or isCallbackReturnValue:
  4070. sequenceClass = "Sequence"
  4071. else:
  4072. sequenceClass = "binding_detail::AutoSequence"
  4073. # XXXbz we can't include the index in the sourceDescription, because
  4074. # we don't really have a way to pass one in dynamically at runtime...
  4075. elementInfo = getJSToNativeConversionInfo(
  4076. elementType, descriptorProvider, isMember="Sequence",
  4077. exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
  4078. isCallbackReturnValue=isCallbackReturnValue,
  4079. sourceDescription="element of %s" % sourceDescription,
  4080. nestingLevel=incrementNestingLevel())
  4081. if elementInfo.dealWithOptional:
  4082. raise TypeError("Shouldn't have optional things in sequences")
  4083. if elementInfo.holderType is not None:
  4084. raise TypeError("Shouldn't need holders for sequences")
  4085. typeName = CGTemplatedType(sequenceClass, elementInfo.declType)
  4086. sequenceType = typeName.define()
  4087. if nullable:
  4088. typeName = CGTemplatedType("Nullable", typeName)
  4089. arrayRef = "${declName}.SetValue()"
  4090. else:
  4091. arrayRef = "${declName}"
  4092. elementConversion = string.Template(elementInfo.template).substitute({
  4093. "val": "temp" + str(nestingLevel),
  4094. "maybeMutableVal": "&temp" + str(nestingLevel),
  4095. "declName": "slot" + str(nestingLevel),
  4096. # We only need holderName here to handle isExternal()
  4097. # interfaces, which use an internal holder for the
  4098. # conversion even when forceOwningType ends up true.
  4099. "holderName": "tempHolder" + str(nestingLevel),
  4100. "passedToJSImpl": "${passedToJSImpl}"
  4101. })
  4102. # NOTE: Keep this in sync with variadic conversions as needed
  4103. templateBody = fill(
  4104. """
  4105. JS::ForOfIterator iter${nestingLevel}(cx);
  4106. if (!iter${nestingLevel}.init($${val}, JS::ForOfIterator::AllowNonIterable)) {
  4107. $*{exceptionCode}
  4108. }
  4109. if (!iter${nestingLevel}.valueIsIterable()) {
  4110. $*{notSequence}
  4111. }
  4112. ${sequenceType} &arr${nestingLevel} = ${arrayRef};
  4113. JS::Rooted<JS::Value> temp${nestingLevel}(cx);
  4114. while (true) {
  4115. bool done${nestingLevel};
  4116. if (!iter${nestingLevel}.next(&temp${nestingLevel}, &done${nestingLevel})) {
  4117. $*{exceptionCode}
  4118. }
  4119. if (done${nestingLevel}) {
  4120. break;
  4121. }
  4122. ${elementType}* slotPtr${nestingLevel} = arr${nestingLevel}.AppendElement(mozilla::fallible);
  4123. if (!slotPtr${nestingLevel}) {
  4124. JS_ReportOutOfMemory(cx);
  4125. $*{exceptionCode}
  4126. }
  4127. ${elementType}& slot${nestingLevel} = *slotPtr${nestingLevel};
  4128. $*{elementConversion}
  4129. }
  4130. """,
  4131. exceptionCode=exceptionCode,
  4132. notSequence=notSequence,
  4133. sequenceType=sequenceType,
  4134. arrayRef=arrayRef,
  4135. elementType=elementInfo.declType.define(),
  4136. elementConversion=elementConversion,
  4137. nestingLevel=str(nestingLevel))
  4138. templateBody = wrapObjectTemplate(templateBody, type,
  4139. "${declName}.SetNull();\n", notSequence)
  4140. if isinstance(defaultValue, IDLEmptySequenceValue):
  4141. if type.nullable():
  4142. codeToSetEmpty = "${declName}.SetValue();\n"
  4143. else:
  4144. codeToSetEmpty = "/* Array is already empty; nothing to do */\n"
  4145. templateBody = handleDefault(templateBody, codeToSetEmpty)
  4146. # Sequence arguments that might contain traceable things need
  4147. # to get traced
  4148. if not isMember and typeNeedsRooting(elementType):
  4149. holderType = CGTemplatedType("SequenceRooter", elementInfo.declType)
  4150. # If our sequence is nullable, this will set the Nullable to be
  4151. # not-null, but that's ok because we make an explicit SetNull() call
  4152. # on it as needed if our JS value is actually null.
  4153. holderArgs = "cx, &%s" % arrayRef
  4154. else:
  4155. holderType = None
  4156. holderArgs = None
  4157. return JSToNativeConversionInfo(templateBody, declType=typeName,
  4158. holderType=holderType,
  4159. dealWithOptional=isOptional,
  4160. holderArgs=holderArgs)
  4161. if type.isRecord():
  4162. assert not isEnforceRange and not isClamp
  4163. if failureCode is None:
  4164. notRecord = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
  4165. "%s" % (firstCap(sourceDescription), exceptionCode))
  4166. else:
  4167. notRecord = failureCode
  4168. nullable = type.nullable()
  4169. # Be very careful not to change "type": we need it later
  4170. if nullable:
  4171. recordType = type.inner
  4172. else:
  4173. recordType = type
  4174. valueType = recordType.inner
  4175. valueInfo = getJSToNativeConversionInfo(
  4176. valueType, descriptorProvider, isMember="Record",
  4177. exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
  4178. isCallbackReturnValue=isCallbackReturnValue,
  4179. sourceDescription="value in %s" % sourceDescription,
  4180. nestingLevel=incrementNestingLevel())
  4181. if valueInfo.dealWithOptional:
  4182. raise TypeError("Shouldn't have optional things in record")
  4183. if valueInfo.holderType is not None:
  4184. raise TypeError("Shouldn't need holders for record")
  4185. declType = CGTemplatedType("Record", [recordKeyDeclType(recordType),
  4186. valueInfo.declType])
  4187. typeName = declType.define()
  4188. if nullable:
  4189. declType = CGTemplatedType("Nullable", declType)
  4190. recordRef = "${declName}.SetValue()"
  4191. else:
  4192. recordRef = "${declName}"
  4193. valueConversion = string.Template(valueInfo.template).substitute({
  4194. "val": "temp",
  4195. "maybeMutableVal": "&temp",
  4196. "declName": "slot",
  4197. # We only need holderName here to handle isExternal()
  4198. # interfaces, which use an internal holder for the
  4199. # conversion even when forceOwningType ends up true.
  4200. "holderName": "tempHolder",
  4201. "passedToJSImpl": "${passedToJSImpl}"
  4202. })
  4203. keyType = recordKeyType(recordType)
  4204. if recordType.keyType.isByteString():
  4205. keyConversionFunction = "ConvertJSValueToByteString"
  4206. hashKeyType = "nsCStringHashKey"
  4207. else:
  4208. hashKeyType = "nsStringHashKey"
  4209. if recordType.keyType.isDOMString():
  4210. keyConversionFunction = "ConvertJSValueToString"
  4211. else:
  4212. assert recordType.keyType.isUSVString()
  4213. keyConversionFunction = "ConvertJSValueToUSVString"
  4214. templateBody = fill(
  4215. """
  4216. auto& recordEntries = ${recordRef}.Entries();
  4217. JS::Rooted<JSObject*> recordObj(cx, &$${val}.toObject());
  4218. JS::AutoIdVector ids(cx);
  4219. if (!js::GetPropertyKeys(cx, recordObj,
  4220. JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) {
  4221. $*{exceptionCode}
  4222. }
  4223. if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) {
  4224. JS_ReportOutOfMemory(cx);
  4225. $*{exceptionCode}
  4226. }
  4227. JS::Rooted<JS::Value> propNameValue(cx);
  4228. JS::Rooted<JS::Value> temp(cx);
  4229. JS::Rooted<jsid> curId(cx);
  4230. JS::Rooted<JS::Value> idVal(cx);
  4231. // Use a hashset to keep track of ids seen, to avoid
  4232. // introducing nasty O(N^2) behavior scanning for them all the
  4233. // time. Ideally we'd use a data structure with O(1) lookup
  4234. // _and_ ordering for the MozMap, but we don't have one lying
  4235. // around.
  4236. nsTHashtable<${hashKeyType}> idsSeen;
  4237. for (size_t i = 0; i < ids.length(); ++i) {
  4238. curId = ids[i];
  4239. JS::Rooted<JS::PropertyDescriptor> desc(cx);
  4240. if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId,
  4241. &desc)) {
  4242. $*{exceptionCode}
  4243. }
  4244. if (!desc.object() /* == undefined in spec terms */ ||
  4245. !desc.enumerable()) {
  4246. continue;
  4247. }
  4248. idVal = js::IdToValue(curId);
  4249. ${keyType} propName;
  4250. // This will just throw if idVal is a Symbol, like the spec says
  4251. // to do.
  4252. if (!${keyConversionFunction}(cx, idVal, propName)) {
  4253. $*{exceptionCode}
  4254. }
  4255. if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) {
  4256. $*{exceptionCode}
  4257. }
  4258. ${typeName}::EntryType* entry;
  4259. if (idsSeen.Contains(propName)) {
  4260. // Find the existing entry.
  4261. auto idx = recordEntries.IndexOf(propName);
  4262. MOZ_ASSERT(idx != recordEntries.NoIndex,
  4263. "Why is it not found?");
  4264. // Now blow it away to make it look like it was just added
  4265. // to the array, because it's not obvious that it's
  4266. // safe to write to its already-initialized mValue via our
  4267. // normal codegen conversions. For example, the value
  4268. // could be a union and this would change its type, but
  4269. // codegen assumes we won't do that.
  4270. entry = recordEntries.ReconstructElementAt(idx);
  4271. } else {
  4272. // Safe to do an infallible append here, because we did a
  4273. // SetCapacity above to the right capacity.
  4274. entry = recordEntries.AppendElement();
  4275. idsSeen.PutEntry(propName);
  4276. }
  4277. entry->mKey = propName;
  4278. ${valueType}& slot = entry->mValue;
  4279. $*{valueConversion}
  4280. }
  4281. """,
  4282. exceptionCode=exceptionCode,
  4283. recordRef=recordRef,
  4284. hashKeyType=hashKeyType,
  4285. keyType=keyType,
  4286. keyConversionFunction=keyConversionFunction,
  4287. typeName=typeName,
  4288. valueType=valueInfo.declType.define(),
  4289. valueConversion=valueConversion)
  4290. templateBody = wrapObjectTemplate(templateBody, type,
  4291. "${declName}.SetNull();\n",
  4292. notRecord)
  4293. declArgs = None
  4294. holderType = None
  4295. holderArgs = None
  4296. # record arguments that might contain traceable things need
  4297. # to get traced
  4298. if not isMember and isCallbackReturnValue:
  4299. # Go ahead and just convert directly into our actual return value
  4300. declType = CGWrapper(declType, post="&")
  4301. declArgs = "aRetVal"
  4302. elif not isMember and typeNeedsRooting(valueType):
  4303. holderType = CGTemplatedType("RecordRooter",
  4304. [recordKeyDeclType(recordType),
  4305. valueInfo.declType])
  4306. # If our record is nullable, this will set the Nullable to be
  4307. # not-null, but that's ok because we make an explicit SetNull() call
  4308. # on it as needed if our JS value is actually null.
  4309. holderArgs = "cx, &%s" % recordRef
  4310. return JSToNativeConversionInfo(templateBody, declType=declType,
  4311. declArgs=declArgs,
  4312. holderType=holderType,
  4313. dealWithOptional=isOptional,
  4314. holderArgs=holderArgs)
  4315. if type.isUnion():
  4316. nullable = type.nullable()
  4317. if nullable:
  4318. type = type.inner
  4319. isOwningUnion = isMember or isCallbackReturnValue
  4320. unionArgumentObj = "${declName}" if isOwningUnion else "${holderName}"
  4321. if nullable:
  4322. # If we're owning, we're a Nullable, which hasn't been told it has
  4323. # a value. Otherwise we're an already-constructed Maybe.
  4324. unionArgumentObj += ".SetValue()" if isOwningUnion else ".ref()"
  4325. memberTypes = type.flatMemberTypes
  4326. names = []
  4327. interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
  4328. if len(interfaceMemberTypes) > 0:
  4329. interfaceObject = []
  4330. for memberType in interfaceMemberTypes:
  4331. name = getUnionMemberName(memberType)
  4332. interfaceObject.append(
  4333. CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext" %
  4334. (unionArgumentObj, name)))
  4335. names.append(name)
  4336. interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"),
  4337. pre="done = ", post=";\n\n", reindent=True)
  4338. else:
  4339. interfaceObject = None
  4340. sequenceObjectMemberTypes = filter(lambda t: t.isSequence(), memberTypes)
  4341. if len(sequenceObjectMemberTypes) > 0:
  4342. assert len(sequenceObjectMemberTypes) == 1
  4343. name = getUnionMemberName(sequenceObjectMemberTypes[0])
  4344. sequenceObject = CGGeneric(
  4345. "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
  4346. (unionArgumentObj, name))
  4347. names.append(name)
  4348. else:
  4349. sequenceObject = None
  4350. dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
  4351. if len(dateObjectMemberTypes) > 0:
  4352. assert len(dateObjectMemberTypes) == 1
  4353. memberType = dateObjectMemberTypes[0]
  4354. name = getUnionMemberName(memberType)
  4355. dateObject = CGGeneric("%s.SetTo%s(cx, ${val});\n"
  4356. "done = true;\n" % (unionArgumentObj, name))
  4357. dateObject = CGIfWrapper(dateObject, "JS_ObjectIsDate(cx, argObj)")
  4358. names.append(name)
  4359. else:
  4360. dateObject = None
  4361. callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
  4362. if len(callbackMemberTypes) > 0:
  4363. assert len(callbackMemberTypes) == 1
  4364. memberType = callbackMemberTypes[0]
  4365. name = getUnionMemberName(memberType)
  4366. callbackObject = CGGeneric(
  4367. "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
  4368. (unionArgumentObj, name))
  4369. names.append(name)
  4370. else:
  4371. callbackObject = None
  4372. dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
  4373. if len(dictionaryMemberTypes) > 0:
  4374. assert len(dictionaryMemberTypes) == 1
  4375. name = getUnionMemberName(dictionaryMemberTypes[0])
  4376. setDictionary = CGGeneric(
  4377. "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
  4378. (unionArgumentObj, name))
  4379. names.append(name)
  4380. else:
  4381. setDictionary = None
  4382. recordMemberTypes = filter(lambda t: t.isRecord(), memberTypes)
  4383. if len(recordMemberTypes) > 0:
  4384. assert len(recordMemberTypes) == 1
  4385. name = getUnionMemberName(recordMemberTypes[0])
  4386. recordObject = CGGeneric(
  4387. "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
  4388. (unionArgumentObj, name))
  4389. names.append(name)
  4390. else:
  4391. recordObject = None
  4392. objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
  4393. if len(objectMemberTypes) > 0:
  4394. assert len(objectMemberTypes) == 1
  4395. # Very important to NOT construct a temporary Rooted here, since the
  4396. # SetToObject call can call a Rooted constructor and we need to keep
  4397. # stack discipline for Rooted.
  4398. object = CGGeneric("if (!%s.SetToObject(cx, &${val}.toObject(), ${passedToJSImpl})) {\n"
  4399. "%s"
  4400. "}\n"
  4401. "done = true;\n" % (unionArgumentObj, indent(exceptionCode)))
  4402. names.append(objectMemberTypes[0].name)
  4403. else:
  4404. object = None
  4405. hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or recordObject
  4406. if hasObjectTypes:
  4407. # "object" is not distinguishable from other types
  4408. assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or recordObject)
  4409. if sequenceObject or dateObject or callbackObject:
  4410. # An object can be both an sequence object and a callback or
  4411. # dictionary, but we shouldn't have both in the union's members
  4412. # because they are not distinguishable.
  4413. assert not (sequenceObject and callbackObject)
  4414. templateBody = CGElseChain([sequenceObject, dateObject, callbackObject])
  4415. else:
  4416. templateBody = None
  4417. if interfaceObject:
  4418. assert not object
  4419. if templateBody:
  4420. templateBody = CGIfWrapper(templateBody, "!done")
  4421. templateBody = CGList([interfaceObject, templateBody])
  4422. else:
  4423. templateBody = CGList([templateBody, object])
  4424. if dateObject:
  4425. templateBody.prepend(CGGeneric("JS::Rooted<JSObject*> argObj(cx, &${val}.toObject());\n"))
  4426. if recordObject:
  4427. templateBody = CGList([templateBody,
  4428. CGIfWrapper(recordObject, "!done")])
  4429. templateBody = CGIfWrapper(templateBody, "${val}.isObject()")
  4430. else:
  4431. templateBody = CGGeneric()
  4432. if setDictionary:
  4433. assert not object
  4434. templateBody = CGList([templateBody,
  4435. CGIfWrapper(setDictionary, "!done")])
  4436. stringTypes = [t for t in memberTypes if t.isString() or t.isEnum()]
  4437. numericTypes = [t for t in memberTypes if t.isNumeric()]
  4438. booleanTypes = [t for t in memberTypes if t.isBoolean()]
  4439. if stringTypes or numericTypes or booleanTypes:
  4440. assert len(stringTypes) <= 1
  4441. assert len(numericTypes) <= 1
  4442. assert len(booleanTypes) <= 1
  4443. # We will wrap all this stuff in a do { } while (0); so we
  4444. # can use "break" for flow control.
  4445. def getStringOrPrimitiveConversion(memberType):
  4446. name = getUnionMemberName(memberType)
  4447. return CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n"
  4448. "break;\n" % (unionArgumentObj, name))
  4449. other = CGList([])
  4450. stringConversion = map(getStringOrPrimitiveConversion, stringTypes)
  4451. numericConversion = map(getStringOrPrimitiveConversion, numericTypes)
  4452. booleanConversion = map(getStringOrPrimitiveConversion, booleanTypes)
  4453. if stringConversion:
  4454. if booleanConversion:
  4455. other.append(CGIfWrapper(booleanConversion[0],
  4456. "${val}.isBoolean()"))
  4457. if numericConversion:
  4458. other.append(CGIfWrapper(numericConversion[0],
  4459. "${val}.isNumber()"))
  4460. other.append(stringConversion[0])
  4461. elif numericConversion:
  4462. if booleanConversion:
  4463. other.append(CGIfWrapper(booleanConversion[0],
  4464. "${val}.isBoolean()"))
  4465. other.append(numericConversion[0])
  4466. else:
  4467. assert booleanConversion
  4468. other.append(booleanConversion[0])
  4469. other = CGWrapper(CGIndenter(other), pre="do {\n", post="} while (0);\n")
  4470. if hasObjectTypes or setDictionary:
  4471. other = CGWrapper(CGIndenter(other), "{\n", post="}\n")
  4472. if object:
  4473. templateBody = CGElseChain([templateBody, other])
  4474. else:
  4475. other = CGWrapper(other, pre="if (!done) ")
  4476. templateBody = CGList([templateBody, other])
  4477. else:
  4478. assert templateBody.define() == ""
  4479. templateBody = other
  4480. else:
  4481. other = None
  4482. templateBody = CGWrapper(templateBody, pre="bool done = false, failed = false, tryNext;\n")
  4483. throw = CGGeneric(fill(
  4484. """
  4485. if (failed) {
  4486. $*{exceptionCode}
  4487. }
  4488. if (!done) {
  4489. ThrowErrorMessage(cx, MSG_NOT_IN_UNION, "${desc}", "${names}");
  4490. $*{exceptionCode}
  4491. }
  4492. """,
  4493. exceptionCode=exceptionCode,
  4494. desc=firstCap(sourceDescription),
  4495. names=", ".join(names)))
  4496. templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw])), pre="{\n", post="}\n")
  4497. typeName = CGUnionStruct.unionTypeDecl(type, isOwningUnion)
  4498. argumentTypeName = typeName + "Argument"
  4499. if nullable:
  4500. typeName = "Nullable<" + typeName + " >"
  4501. def handleNull(templateBody, setToNullVar, extraConditionForNull=""):
  4502. nullTest = "%s${val}.isNullOrUndefined()" % extraConditionForNull
  4503. return CGIfElseWrapper(nullTest,
  4504. CGGeneric("%s.SetNull();\n" % setToNullVar),
  4505. templateBody)
  4506. if type.hasNullableType:
  4507. assert not nullable
  4508. # Make sure to handle a null default value here
  4509. if defaultValue and isinstance(defaultValue, IDLNullValue):
  4510. assert defaultValue.type == type
  4511. extraConditionForNull = "!(${haveValue}) || "
  4512. else:
  4513. extraConditionForNull = ""
  4514. templateBody = handleNull(templateBody, unionArgumentObj,
  4515. extraConditionForNull=extraConditionForNull)
  4516. declType = CGGeneric(typeName)
  4517. if isOwningUnion:
  4518. holderType = None
  4519. else:
  4520. holderType = CGGeneric(argumentTypeName)
  4521. if nullable:
  4522. holderType = CGTemplatedType("Maybe", holderType)
  4523. # If we're isOptional and not nullable the normal optional handling will
  4524. # handle lazy construction of our holder. If we're nullable and not
  4525. # owning we do it all by hand because we do not want our holder
  4526. # constructed if we're null. But if we're owning we don't have a
  4527. # holder anyway, so we can do the normal Optional codepath.
  4528. declLoc = "${declName}"
  4529. constructDecl = None
  4530. if nullable:
  4531. if isOptional and not isOwningUnion:
  4532. holderArgs = "${declName}.Value().SetValue()"
  4533. declType = CGTemplatedType("Optional", declType)
  4534. constructDecl = CGGeneric("${declName}.Construct();\n")
  4535. declLoc = "${declName}.Value()"
  4536. else:
  4537. holderArgs = "${declName}.SetValue()"
  4538. if holderType is not None:
  4539. constructHolder = CGGeneric("${holderName}.emplace(%s);\n" % holderArgs)
  4540. else:
  4541. constructHolder = None
  4542. # Don't need to pass those args when the holder is being constructed
  4543. holderArgs = None
  4544. else:
  4545. holderArgs = "${declName}"
  4546. constructHolder = None
  4547. if not isMember and isCallbackReturnValue:
  4548. declType = CGWrapper(declType, post="&")
  4549. declArgs = "aRetVal"
  4550. else:
  4551. declArgs = None
  4552. if defaultValue and not isinstance(defaultValue, IDLNullValue):
  4553. tag = defaultValue.type.tag()
  4554. if tag in numericSuffixes or tag is IDLType.Tags.bool:
  4555. defaultStr = getHandleDefault(defaultValue)
  4556. # Make sure we actually construct the thing inside the nullable.
  4557. value = declLoc + (".SetValue()" if nullable else "")
  4558. name = getUnionMemberName(defaultValue.type)
  4559. default = CGGeneric("%s.RawSetAs%s() = %s;\n" %
  4560. (value, name, defaultStr))
  4561. elif isinstance(defaultValue, IDLEmptySequenceValue):
  4562. name = getUnionMemberName(defaultValue.type)
  4563. # Make sure we actually construct the thing inside the nullable.
  4564. value = declLoc + (".SetValue()" if nullable else "")
  4565. # It's enough to set us to the right type; that will
  4566. # create an empty array, which is all we need here.
  4567. default = CGGeneric("%s.RawSetAs%s();\n" %
  4568. (value, name))
  4569. elif defaultValue.type.isEnum():
  4570. name = getUnionMemberName(defaultValue.type)
  4571. # Make sure we actually construct the thing inside the nullable.
  4572. value = declLoc + (".SetValue()" if nullable else "")
  4573. default = CGGeneric(
  4574. "%s.RawSetAs%s() = %s::%s;\n" %
  4575. (value, name,
  4576. defaultValue.type.inner.identifier.name,
  4577. getEnumValueName(defaultValue.value)))
  4578. else:
  4579. default = CGGeneric(
  4580. handleDefaultStringValue(
  4581. defaultValue, "%s.SetStringData" % unionArgumentObj) +
  4582. ";\n")
  4583. templateBody = CGIfElseWrapper("!(${haveValue})", default, templateBody)
  4584. templateBody = CGList([constructHolder, templateBody])
  4585. if nullable:
  4586. if defaultValue:
  4587. if isinstance(defaultValue, IDLNullValue):
  4588. extraConditionForNull = "!(${haveValue}) || "
  4589. else:
  4590. extraConditionForNull = "(${haveValue}) && "
  4591. else:
  4592. extraConditionForNull = ""
  4593. templateBody = handleNull(templateBody, declLoc,
  4594. extraConditionForNull=extraConditionForNull)
  4595. elif (not type.hasNullableType and defaultValue and
  4596. isinstance(defaultValue, IDLNullValue)):
  4597. assert type.hasDictionaryType()
  4598. assert defaultValue.type.isDictionary()
  4599. if not isOwningUnion and typeNeedsRooting(defaultValue.type):
  4600. ctorArgs = "cx"
  4601. else:
  4602. ctorArgs = ""
  4603. initDictionaryWithNull = CGIfWrapper(
  4604. CGGeneric("return false;\n"),
  4605. ('!%s.RawSetAs%s(%s).Init(cx, JS::NullHandleValue, "Member of %s")'
  4606. % (declLoc, getUnionMemberName(defaultValue.type),
  4607. ctorArgs, type)))
  4608. templateBody = CGIfElseWrapper("!(${haveValue})",
  4609. initDictionaryWithNull,
  4610. templateBody)
  4611. templateBody = CGList([constructDecl, templateBody])
  4612. return JSToNativeConversionInfo(templateBody.define(),
  4613. declType=declType,
  4614. declArgs=declArgs,
  4615. holderType=holderType,
  4616. holderArgs=holderArgs,
  4617. dealWithOptional=isOptional and (not nullable or isOwningUnion))
  4618. if type.isPromise():
  4619. assert not type.nullable()
  4620. assert defaultValue is None
  4621. # We always have to hold a strong ref to Promise here, because
  4622. # Promise::resolve returns an addrefed thing.
  4623. argIsPointer = isCallbackReturnValue
  4624. if argIsPointer:
  4625. declType = CGGeneric("RefPtr<Promise>")
  4626. else:
  4627. declType = CGGeneric("OwningNonNull<Promise>")
  4628. # Per spec, what we're supposed to do is take the original
  4629. # Promise.resolve and call it with the original Promise as this
  4630. # value to make a Promise out of whatever value we actually have
  4631. # here. The question is which global we should use. There are
  4632. # several cases to consider:
  4633. #
  4634. # 1) Normal call to API with a Promise argument. This is a case the
  4635. # spec covers, and we should be using the current Realm's
  4636. # Promise. That means the current compartment.
  4637. # 2) Call to API with a Promise argument over Xrays. In practice,
  4638. # this sort of thing seems to be used for giving an API
  4639. # implementation a way to wait for conclusion of an asyc
  4640. # operation, _not_ to expose the Promise to content code. So we
  4641. # probably want to allow callers to use such an API in a
  4642. # "natural" way, by passing chrome-side promises; indeed, that
  4643. # may be all that the caller has to represent their async
  4644. # operation. That means we really need to do the
  4645. # Promise.resolve() in the caller (chrome) compartment: if we do
  4646. # it in the content compartment, we will try to call .then() on
  4647. # the chrome promise while in the content compartment, which will
  4648. # throw and we'll just get a rejected Promise. Note that this is
  4649. # also the reason why a caller who has a chrome Promise
  4650. # representing an async operation can't itself convert it to a
  4651. # content-side Promise (at least not without some serious
  4652. # gyrations).
  4653. # 3) Promise return value from a callback or callback interface.
  4654. # Per spec, this should use the Realm of the callback object. In
  4655. # our case, that's the compartment of the underlying callback,
  4656. # not the current compartment (which may be the compartment of
  4657. # some cross-compartment wrapper around said callback).
  4658. # 4) Return value from a JS-implemented interface. In this case we
  4659. # have a problem. Our current compartment is the compartment of
  4660. # the JS implementation. But if the JS implementation returned
  4661. # a page-side Promise (which is a totally sane thing to do, and
  4662. # in fact the right thing to do given that this return value is
  4663. # going right to content script) then we don't want to
  4664. # Promise.resolve with our current compartment Promise, because
  4665. # that will wrap it up in a chrome-side Promise, which is
  4666. # decidedly _not_ what's desired here. So in that case we
  4667. # should really unwrap the return value and use the global of
  4668. # the result. CheckedUnwrap should be good enough for that; if
  4669. # it fails, then we're failing unwrap while in a
  4670. # system-privileged compartment, so presumably we have a dead
  4671. # object wrapper. Just error out. Do NOT fall back to using
  4672. # the current compartment instead: that will return a
  4673. # system-privileged rejected (because getting .then inside
  4674. # resolve() failed) Promise to the caller, which they won't be
  4675. # able to touch. That's not helpful. If we error out, on the
  4676. # other hand, they will get a content-side rejected promise.
  4677. # Same thing if the value returned is not even an object.
  4678. if isCallbackReturnValue == "JSImpl":
  4679. # Case 4 above. Note that globalObj defaults to the current
  4680. # compartment global. Note that we don't use $*{exceptionCode}
  4681. # here because that will try to aRv.Throw(NS_ERROR_UNEXPECTED)
  4682. # which we don't really want here.
  4683. assert exceptionCode == "aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n"
  4684. getPromiseGlobal = fill(
  4685. """
  4686. if (!$${val}.isObject()) {
  4687. aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
  4688. return nullptr;
  4689. }
  4690. JSObject* unwrappedVal = js::CheckedUnwrap(&$${val}.toObject());
  4691. if (!unwrappedVal) {
  4692. // A slight lie, but not much of one, for a dead object wrapper.
  4693. aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
  4694. return nullptr;
  4695. }
  4696. globalObj = js::GetGlobalForObjectCrossCompartment(unwrappedVal);
  4697. """,
  4698. sourceDescription=sourceDescription)
  4699. elif isCallbackReturnValue == "Callback":
  4700. getPromiseGlobal = dedent(
  4701. """
  4702. // We basically want our entry global here. Play it safe
  4703. // and use GetEntryGlobal() to get it, with whatever
  4704. // principal-clamping it ends up doing.
  4705. globalObj = GetEntryGlobal()->GetGlobalJSObject();
  4706. """)
  4707. else:
  4708. getPromiseGlobal = ""
  4709. templateBody = fill(
  4710. """
  4711. { // Scope for our GlobalObject, FastErrorResult, JSAutoCompartment,
  4712. // etc.
  4713. JS::Rooted<JSObject*> globalObj(cx, JS::CurrentGlobalOrNull(cx));
  4714. $*{getPromiseGlobal}
  4715. JSAutoCompartment ac(cx, globalObj);
  4716. GlobalObject promiseGlobal(cx, globalObj);
  4717. if (promiseGlobal.Failed()) {
  4718. $*{exceptionCode}
  4719. }
  4720. JS::Rooted<JS::Value> valueToResolve(cx, $${val});
  4721. if (!JS_WrapValue(cx, &valueToResolve)) {
  4722. $*{exceptionCode}
  4723. }
  4724. binding_detail::FastErrorResult promiseRv;
  4725. nsCOMPtr<nsIGlobalObject> global =
  4726. do_QueryInterface(promiseGlobal.GetAsSupports());
  4727. if (!global) {
  4728. promiseRv.Throw(NS_ERROR_UNEXPECTED);
  4729. promiseRv.MaybeSetPendingException(cx);
  4730. $*{exceptionCode}
  4731. }
  4732. $${declName} = Promise::Resolve(global, cx, valueToResolve,
  4733. promiseRv);
  4734. if (promiseRv.MaybeSetPendingException(cx)) {
  4735. $*{exceptionCode}
  4736. }
  4737. }
  4738. """,
  4739. getPromiseGlobal=getPromiseGlobal,
  4740. exceptionCode=exceptionCode)
  4741. return JSToNativeConversionInfo(templateBody,
  4742. declType=declType,
  4743. dealWithOptional=isOptional)
  4744. if type.isGeckoInterface():
  4745. assert not isEnforceRange and not isClamp
  4746. descriptor = descriptorProvider.getDescriptor(
  4747. type.unroll().inner.identifier.name)
  4748. assert descriptor.nativeType != 'JSObject'
  4749. if descriptor.interface.isCallback():
  4750. (declType, declArgs,
  4751. conversion) = getCallbackConversionInfo(type, descriptor.interface,
  4752. isMember,
  4753. isCallbackReturnValue,
  4754. isOptional)
  4755. template = wrapObjectTemplate(conversion, type,
  4756. "${declName} = nullptr;\n",
  4757. failureCode)
  4758. return JSToNativeConversionInfo(template, declType=declType,
  4759. declArgs=declArgs,
  4760. dealWithOptional=isOptional)
  4761. # This is an interface that we implement as a concrete class
  4762. # or an XPCOM interface.
  4763. # Allow null pointers for nullable types and old-binding classes, and
  4764. # use an RefPtr or raw pointer for callback return values to make
  4765. # them easier to return.
  4766. argIsPointer = (type.nullable() or type.unroll().inner.isExternal() or
  4767. isCallbackReturnValue)
  4768. # Sequence and dictionary members, as well as owning unions (which can
  4769. # appear here as return values in JS-implemented interfaces) have to
  4770. # hold a strong ref to the thing being passed down. Those all set
  4771. # isMember.
  4772. #
  4773. # Also, callback return values always end up addrefing anyway, so there
  4774. # is no point trying to avoid it here and it makes other things simpler
  4775. # since we can assume the return value is a strong ref.
  4776. assert not descriptor.interface.isCallback()
  4777. forceOwningType = isMember or isCallbackReturnValue
  4778. typeName = descriptor.nativeType
  4779. typePtr = typeName + "*"
  4780. # Compute a few things:
  4781. # - declType is the type we want to return as the first element of our
  4782. # tuple.
  4783. # - holderType is the type we want to return as the third element
  4784. # of our tuple.
  4785. # Set up some sensible defaults for these things insofar as we can.
  4786. holderType = None
  4787. if argIsPointer:
  4788. if forceOwningType:
  4789. declType = "RefPtr<" + typeName + ">"
  4790. else:
  4791. declType = typePtr
  4792. else:
  4793. if forceOwningType:
  4794. declType = "OwningNonNull<" + typeName + ">"
  4795. else:
  4796. declType = "NonNull<" + typeName + ">"
  4797. templateBody = ""
  4798. if forceOwningType:
  4799. templateBody += 'static_assert(IsRefcounted<%s>::value, "We can only store refcounted classes.");' % typeName
  4800. if (not descriptor.interface.isConsequential() and
  4801. not descriptor.interface.isExternal()):
  4802. if failureCode is not None:
  4803. templateBody += str(CastableObjectUnwrapper(
  4804. descriptor,
  4805. "${val}",
  4806. "${maybeMutableVal}",
  4807. "${declName}",
  4808. failureCode))
  4809. else:
  4810. templateBody += str(FailureFatalCastableObjectUnwrapper(
  4811. descriptor,
  4812. "${val}",
  4813. "${maybeMutableVal}",
  4814. "${declName}",
  4815. exceptionCode,
  4816. isCallbackReturnValue,
  4817. firstCap(sourceDescription)))
  4818. else:
  4819. # Either external, or new-binding non-castable. We always have a
  4820. # holder for these, because we don't actually know whether we have
  4821. # to addref when unwrapping or not. So we just pass an
  4822. # getter_AddRefs(RefPtr) to XPConnect and if we'll need a release
  4823. # it'll put a non-null pointer in there.
  4824. if forceOwningType:
  4825. # Don't return a holderType in this case; our declName
  4826. # will just own stuff.
  4827. templateBody += "RefPtr<" + typeName + "> ${holderName};\n"
  4828. else:
  4829. holderType = "RefPtr<" + typeName + ">"
  4830. templateBody += (
  4831. "JS::Rooted<JSObject*> source(cx, &${val}.toObject());\n" +
  4832. "if (NS_FAILED(UnwrapArg<" + typeName + ">(source, getter_AddRefs(${holderName})))) {\n")
  4833. templateBody += CGIndenter(onFailureBadType(failureCode,
  4834. descriptor.interface.identifier.name)).define()
  4835. templateBody += ("}\n"
  4836. "MOZ_ASSERT(${holderName});\n")
  4837. # And store our value in ${declName}
  4838. templateBody += "${declName} = ${holderName};\n"
  4839. # Just pass failureCode, not onFailureBadType, here, so we'll report
  4840. # the thing as not an object as opposed to not implementing whatever
  4841. # our interface is.
  4842. templateBody = wrapObjectTemplate(templateBody, type,
  4843. "${declName} = nullptr;\n",
  4844. failureCode)
  4845. declType = CGGeneric(declType)
  4846. if holderType is not None:
  4847. holderType = CGGeneric(holderType)
  4848. return JSToNativeConversionInfo(templateBody,
  4849. declType=declType,
  4850. holderType=holderType,
  4851. dealWithOptional=isOptional)
  4852. if type.isSpiderMonkeyInterface():
  4853. assert not isEnforceRange and not isClamp
  4854. name = type.unroll().name # unroll() because it may be nullable
  4855. arrayType = CGGeneric(name)
  4856. declType = arrayType
  4857. if type.nullable():
  4858. declType = CGTemplatedType("Nullable", declType)
  4859. objRef = "${declName}.SetValue()"
  4860. else:
  4861. objRef = "${declName}"
  4862. # Again, this is a bit strange since we are actually building a
  4863. # template string here. ${objRef} and $*{badType} below are filled in
  4864. # right now; $${val} expands to ${val}, to be filled in later.
  4865. template = fill(
  4866. """
  4867. if (!${objRef}.Init(&$${val}.toObject())) {
  4868. $*{badType}
  4869. }
  4870. """,
  4871. objRef=objRef,
  4872. badType=onFailureBadType(failureCode, type.name).define())
  4873. template = wrapObjectTemplate(template, type, "${declName}.SetNull();\n",
  4874. failureCode)
  4875. if not isMember:
  4876. # This is a bit annoying. In a union we don't want to have a
  4877. # holder, since unions don't support that. But if we're optional we
  4878. # want to have a holder, so that the callee doesn't see
  4879. # Optional<RootedTypedArray<ArrayType> >. So do a holder if we're
  4880. # optional and use a RootedTypedArray otherwise.
  4881. if isOptional:
  4882. holderType = CGTemplatedType("TypedArrayRooter", arrayType)
  4883. # If our typed array is nullable, this will set the Nullable to
  4884. # be not-null, but that's ok because we make an explicit
  4885. # SetNull() call on it as needed if our JS value is actually
  4886. # null. XXXbz Because "Maybe" takes const refs for constructor
  4887. # arguments, we can't pass a reference here; have to pass a
  4888. # pointer.
  4889. holderArgs = "cx, &%s" % objRef
  4890. declArgs = None
  4891. else:
  4892. holderType = None
  4893. holderArgs = None
  4894. declType = CGTemplatedType("RootedTypedArray", declType)
  4895. declArgs = "cx"
  4896. else:
  4897. holderType = None
  4898. holderArgs = None
  4899. declArgs = None
  4900. return JSToNativeConversionInfo(template,
  4901. declType=declType,
  4902. holderType=holderType,
  4903. dealWithOptional=isOptional,
  4904. declArgs=declArgs,
  4905. holderArgs=holderArgs)
  4906. if type.isDOMString() or type.isUSVString():
  4907. assert not isEnforceRange and not isClamp
  4908. treatAs = {
  4909. "Default": "eStringify",
  4910. "EmptyString": "eEmpty",
  4911. "Null": "eNull",
  4912. }
  4913. if type.nullable():
  4914. # For nullable strings null becomes a null string.
  4915. treatNullAs = "Null"
  4916. # For nullable strings undefined also becomes a null string.
  4917. undefinedBehavior = "eNull"
  4918. else:
  4919. undefinedBehavior = "eStringify"
  4920. nullBehavior = treatAs[treatNullAs]
  4921. def getConversionCode(varName):
  4922. normalizeCode = ""
  4923. if type.isUSVString():
  4924. normalizeCode = "NormalizeUSVString(%s);\n" % varName
  4925. conversionCode = fill("""
  4926. if (!ConvertJSValueToString(cx, $${val}, ${nullBehavior}, ${undefinedBehavior}, ${varName})) {
  4927. $*{exceptionCode}
  4928. }
  4929. $*{normalizeCode}
  4930. """
  4931. ,
  4932. nullBehavior=nullBehavior,
  4933. undefinedBehavior=undefinedBehavior,
  4934. varName=varName,
  4935. exceptionCode=exceptionCode,
  4936. normalizeCode=normalizeCode)
  4937. if defaultValue is None:
  4938. return conversionCode
  4939. if isinstance(defaultValue, IDLNullValue):
  4940. assert(type.nullable())
  4941. defaultCode = "%s.SetIsVoid(true)" % varName
  4942. else:
  4943. defaultCode = handleDefaultStringValue(defaultValue,
  4944. "%s.Rebind" % varName)
  4945. return handleDefault(conversionCode, defaultCode + ";\n")
  4946. if isMember:
  4947. # Convert directly into the nsString member we have.
  4948. declType = CGGeneric("nsString")
  4949. return JSToNativeConversionInfo(
  4950. getConversionCode("${declName}"),
  4951. declType=declType,
  4952. dealWithOptional=isOptional)
  4953. if isOptional:
  4954. declType = "Optional<nsAString>"
  4955. holderType = CGGeneric("binding_detail::FakeString")
  4956. conversionCode = ("%s"
  4957. "${declName} = &${holderName};\n" %
  4958. getConversionCode("${holderName}"))
  4959. else:
  4960. declType = "binding_detail::FakeString"
  4961. holderType = None
  4962. conversionCode = getConversionCode("${declName}")
  4963. # No need to deal with optional here; we handled it already
  4964. return JSToNativeConversionInfo(
  4965. conversionCode,
  4966. declType=CGGeneric(declType),
  4967. holderType=holderType)
  4968. if type.isByteString():
  4969. assert not isEnforceRange and not isClamp
  4970. nullable = toStringBool(type.nullable())
  4971. conversionCode = fill("""
  4972. if (!ConvertJSValueToByteString(cx, $${val}, ${nullable}, $${declName})) {
  4973. $*{exceptionCode}
  4974. }
  4975. """,
  4976. nullable=nullable,
  4977. exceptionCode=exceptionCode)
  4978. if defaultValue is not None:
  4979. if isinstance(defaultValue, IDLNullValue):
  4980. assert(type.nullable())
  4981. defaultCode = "${declName}.SetIsVoid(true)"
  4982. else:
  4983. defaultCode = handleDefaultStringValue(defaultValue,
  4984. "${declName}.Rebind")
  4985. conversionCode = handleDefault(conversionCode, defaultCode + ";\n")
  4986. return JSToNativeConversionInfo(
  4987. conversionCode,
  4988. declType=CGGeneric("nsCString"),
  4989. dealWithOptional=isOptional)
  4990. if type.isEnum():
  4991. assert not isEnforceRange and not isClamp
  4992. enumName = type.unroll().inner.identifier.name
  4993. declType = CGGeneric(enumName)
  4994. if type.nullable():
  4995. declType = CGTemplatedType("Nullable", declType)
  4996. declType = declType.define()
  4997. enumLoc = "${declName}.SetValue()"
  4998. else:
  4999. enumLoc = "${declName}"
  5000. declType = declType.define()
  5001. if invalidEnumValueFatal:
  5002. handleInvalidEnumValueCode = "MOZ_ASSERT(index >= 0);\n"
  5003. else:
  5004. # invalidEnumValueFatal is false only for attributes. So we won't
  5005. # have a non-default exceptionCode here unless attribute "arg
  5006. # conversion" code starts passing in an exceptionCode. At which
  5007. # point we'll need to figure out what that even means.
  5008. assert exceptionCode == "return false;\n"
  5009. handleInvalidEnumValueCode = dedent("""
  5010. if (index < 0) {
  5011. return true;
  5012. }
  5013. """)
  5014. template = fill(
  5015. """
  5016. {
  5017. int index;
  5018. if (!FindEnumStringIndex<${invalidEnumValueFatal}>(cx, $${val}, ${values}, "${enumtype}", "${sourceDescription}", &index)) {
  5019. $*{exceptionCode}
  5020. }
  5021. $*{handleInvalidEnumValueCode}
  5022. ${enumLoc} = static_cast<${enumtype}>(index);
  5023. }
  5024. """,
  5025. enumtype=enumName,
  5026. values=enumName + "Values::" + ENUM_ENTRY_VARIABLE_NAME,
  5027. invalidEnumValueFatal=toStringBool(invalidEnumValueFatal),
  5028. handleInvalidEnumValueCode=handleInvalidEnumValueCode,
  5029. exceptionCode=exceptionCode,
  5030. enumLoc=enumLoc,
  5031. sourceDescription=firstCap(sourceDescription))
  5032. setNull = "${declName}.SetNull();\n"
  5033. if type.nullable():
  5034. template = CGIfElseWrapper("${val}.isNullOrUndefined()",
  5035. CGGeneric(setNull),
  5036. CGGeneric(template)).define()
  5037. if defaultValue is not None:
  5038. if isinstance(defaultValue, IDLNullValue):
  5039. assert type.nullable()
  5040. template = handleDefault(template, setNull)
  5041. else:
  5042. assert(defaultValue.type.tag() == IDLType.Tags.domstring)
  5043. template = handleDefault(template,
  5044. ("%s = %s::%s;\n" %
  5045. (enumLoc, enumName,
  5046. getEnumValueName(defaultValue.value))))
  5047. return JSToNativeConversionInfo(template, declType=CGGeneric(declType),
  5048. dealWithOptional=isOptional)
  5049. if type.isCallback():
  5050. assert not isEnforceRange and not isClamp
  5051. assert not type.treatNonCallableAsNull() or type.nullable()
  5052. assert not type.treatNonObjectAsNull() or type.nullable()
  5053. assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
  5054. callback = type.unroll().callback
  5055. name = callback.identifier.name
  5056. (declType, declArgs,
  5057. conversion) = getCallbackConversionInfo(type, callback, isMember,
  5058. isCallbackReturnValue,
  5059. isOptional)
  5060. if allowTreatNonCallableAsNull and type.treatNonCallableAsNull():
  5061. haveCallable = "JS::IsCallable(&${val}.toObject())"
  5062. if not isDefinitelyObject:
  5063. haveCallable = "${val}.isObject() && " + haveCallable
  5064. if defaultValue is not None:
  5065. assert(isinstance(defaultValue, IDLNullValue))
  5066. haveCallable = "(${haveValue}) && " + haveCallable
  5067. template = (
  5068. ("if (%s) {\n" % haveCallable) +
  5069. conversion +
  5070. "} else {\n"
  5071. " ${declName} = nullptr;\n"
  5072. "}\n")
  5073. elif allowTreatNonCallableAsNull and type.treatNonObjectAsNull():
  5074. if not isDefinitelyObject:
  5075. haveObject = "${val}.isObject()"
  5076. if defaultValue is not None:
  5077. assert(isinstance(defaultValue, IDLNullValue))
  5078. haveObject = "(${haveValue}) && " + haveObject
  5079. template = CGIfElseWrapper(haveObject,
  5080. CGGeneric(conversion),
  5081. CGGeneric("${declName} = nullptr;\n")).define()
  5082. else:
  5083. template = conversion
  5084. else:
  5085. template = wrapObjectTemplate(
  5086. "if (JS::IsCallable(&${val}.toObject())) {\n" +
  5087. conversion +
  5088. "} else {\n" +
  5089. indent(onFailureNotCallable(failureCode).define()) +
  5090. "}\n",
  5091. type,
  5092. "${declName} = nullptr;\n",
  5093. failureCode)
  5094. return JSToNativeConversionInfo(template, declType=declType,
  5095. declArgs=declArgs,
  5096. dealWithOptional=isOptional)
  5097. if type.isAny():
  5098. assert not isEnforceRange and not isClamp
  5099. declArgs = None
  5100. if isMember in ("Variadic", "Sequence", "Dictionary", "Record"):
  5101. # Rooting is handled by the sequence and dictionary tracers.
  5102. declType = "JS::Value"
  5103. else:
  5104. assert not isMember
  5105. declType = "JS::Rooted<JS::Value>"
  5106. declArgs = "cx"
  5107. assert not isOptional
  5108. templateBody = "${declName} = ${val};\n"
  5109. # For JS-implemented APIs, we refuse to allow passing objects that the
  5110. # API consumer does not subsume. The extra parens around
  5111. # ($${passedToJSImpl}) suppress unreachable code warnings when
  5112. # $${passedToJSImpl} is the literal `false`.
  5113. if not isinstance(descriptorProvider, Descriptor) or descriptorProvider.interface.isJSImplemented():
  5114. templateBody = fill(
  5115. """
  5116. if (($${passedToJSImpl}) && !CallerSubsumes($${val})) {
  5117. ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
  5118. $*{exceptionCode}
  5119. }
  5120. """,
  5121. sourceDescription=sourceDescription,
  5122. exceptionCode=exceptionCode) + templateBody
  5123. # We may not have a default value if we're being converted for
  5124. # a setter, say.
  5125. if defaultValue:
  5126. if isinstance(defaultValue, IDLNullValue):
  5127. defaultHandling = "${declName} = JS::NullValue();\n"
  5128. else:
  5129. assert isinstance(defaultValue, IDLUndefinedValue)
  5130. defaultHandling = "${declName} = JS::UndefinedValue();\n"
  5131. templateBody = handleDefault(templateBody, defaultHandling)
  5132. return JSToNativeConversionInfo(templateBody,
  5133. declType=CGGeneric(declType),
  5134. declArgs=declArgs)
  5135. if type.isObject():
  5136. assert not isEnforceRange and not isClamp
  5137. return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
  5138. if type.isDictionary():
  5139. # There are no nullable dictionary arguments or dictionary members
  5140. assert(not type.nullable() or isCallbackReturnValue or
  5141. (isMember and isMember != "Dictionary"))
  5142. # All optional dictionaries always have default values, so we
  5143. # should be able to assume not isOptional here.
  5144. assert not isOptional
  5145. # In the callback return value case we never have to worry
  5146. # about a default value; we always have a value.
  5147. assert not isCallbackReturnValue or defaultValue is None
  5148. typeName = CGDictionary.makeDictionaryName(type.unroll().inner)
  5149. if not isMember and not isCallbackReturnValue:
  5150. # Since we're not a member and not nullable or optional, no one will
  5151. # see our real type, so we can do the fast version of the dictionary
  5152. # that doesn't pre-initialize members.
  5153. typeName = "binding_detail::Fast" + typeName
  5154. declType = CGGeneric(typeName)
  5155. # We do manual default value handling here, because we
  5156. # actually do want a jsval, and we only handle null anyway
  5157. # NOTE: if isNullOrUndefined or isDefinitelyObject are true,
  5158. # we know we have a value, so we don't have to worry about the
  5159. # default value.
  5160. if (not isNullOrUndefined and not isDefinitelyObject and
  5161. defaultValue is not None):
  5162. assert(isinstance(defaultValue, IDLNullValue))
  5163. val = "(${haveValue}) ? ${val} : JS::NullHandleValue"
  5164. else:
  5165. val = "${val}"
  5166. dictLoc = "${declName}"
  5167. if type.nullable():
  5168. dictLoc += ".SetValue()"
  5169. conversionCode = fill("""
  5170. if (!${dictLoc}.Init(cx, ${val}, "${desc}", $${passedToJSImpl})) {
  5171. $*{exceptionCode}
  5172. }
  5173. """,
  5174. dictLoc=dictLoc,
  5175. val=val,
  5176. desc=firstCap(sourceDescription),
  5177. exceptionCode=exceptionCode)
  5178. if failureCode is not None:
  5179. if isDefinitelyObject:
  5180. dictionaryTest = "IsObjectValueConvertibleToDictionary"
  5181. else:
  5182. dictionaryTest = "IsConvertibleToDictionary"
  5183. template = fill("""
  5184. { // scope for isConvertible
  5185. bool isConvertible;
  5186. if (!${testConvertible}(cx, ${val}, &isConvertible)) {
  5187. $*{exceptionCode}
  5188. }
  5189. if (!isConvertible) {
  5190. $*{failureCode}
  5191. }
  5192. $*{conversionCode}
  5193. }
  5194. """,
  5195. testConvertible=dictionaryTest,
  5196. val=val,
  5197. exceptionCode=exceptionCode,
  5198. failureCode=failureCode,
  5199. conversionCode=conversionCode)
  5200. else:
  5201. template = conversionCode
  5202. if type.nullable():
  5203. declType = CGTemplatedType("Nullable", declType)
  5204. template = CGIfElseWrapper("${val}.isNullOrUndefined()",
  5205. CGGeneric("${declName}.SetNull();\n"),
  5206. CGGeneric(template)).define()
  5207. # Dictionary arguments that might contain traceable things need to get
  5208. # traced
  5209. if not isMember and isCallbackReturnValue:
  5210. # Go ahead and just convert directly into our actual return value
  5211. declType = CGWrapper(declType, post="&")
  5212. declArgs = "aRetVal"
  5213. elif not isMember and typeNeedsRooting(type):
  5214. declType = CGTemplatedType("RootedDictionary", declType)
  5215. declArgs = "cx"
  5216. else:
  5217. declArgs = None
  5218. return JSToNativeConversionInfo(template, declType=declType,
  5219. declArgs=declArgs)
  5220. if type.isVoid():
  5221. assert not isOptional
  5222. # This one only happens for return values, and its easy: Just
  5223. # ignore the jsval.
  5224. return JSToNativeConversionInfo("")
  5225. if type.isDate():
  5226. assert not isEnforceRange and not isClamp
  5227. declType = CGGeneric("Date")
  5228. if type.nullable():
  5229. declType = CGTemplatedType("Nullable", declType)
  5230. dateVal = "${declName}.SetValue()"
  5231. else:
  5232. dateVal = "${declName}"
  5233. if failureCode is None:
  5234. notDate = ('ThrowErrorMessage(cx, MSG_NOT_DATE, "%s");\n'
  5235. "%s" % (firstCap(sourceDescription), exceptionCode))
  5236. else:
  5237. notDate = failureCode
  5238. conversion = fill(
  5239. """
  5240. JS::Rooted<JSObject*> possibleDateObject(cx, &$${val}.toObject());
  5241. { // scope for isDate
  5242. bool isDate;
  5243. if (!JS_ObjectIsDate(cx, possibleDateObject, &isDate)) {
  5244. $*{exceptionCode}
  5245. }
  5246. if (!isDate) {
  5247. $*{notDate}
  5248. }
  5249. if (!${dateVal}.SetTimeStamp(cx, possibleDateObject)) {
  5250. $*{exceptionCode}
  5251. }
  5252. }
  5253. """,
  5254. exceptionCode=exceptionCode,
  5255. dateVal=dateVal,
  5256. notDate=notDate)
  5257. conversion = wrapObjectTemplate(conversion, type,
  5258. "${declName}.SetNull();\n", notDate)
  5259. return JSToNativeConversionInfo(conversion,
  5260. declType=declType,
  5261. dealWithOptional=isOptional)
  5262. if not type.isPrimitive():
  5263. raise TypeError("Need conversion for argument type '%s'" % str(type))
  5264. typeName = builtinNames[type.tag()]
  5265. conversionBehavior = "eDefault"
  5266. if isEnforceRange:
  5267. assert type.isInteger()
  5268. conversionBehavior = "eEnforceRange"
  5269. elif isClamp:
  5270. assert type.isInteger()
  5271. conversionBehavior = "eClamp"
  5272. if type.nullable():
  5273. declType = CGGeneric("Nullable<" + typeName + ">")
  5274. writeLoc = "${declName}.SetValue()"
  5275. readLoc = "${declName}.Value()"
  5276. nullCondition = "${val}.isNullOrUndefined()"
  5277. if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
  5278. nullCondition = "!(${haveValue}) || " + nullCondition
  5279. template = fill("""
  5280. if (${nullCondition}) {
  5281. $${declName}.SetNull();
  5282. } else if (!ValueToPrimitive<${typeName}, ${conversionBehavior}>(cx, $${val}, &${writeLoc})) {
  5283. $*{exceptionCode}
  5284. }
  5285. """,
  5286. nullCondition=nullCondition,
  5287. typeName=typeName,
  5288. conversionBehavior=conversionBehavior,
  5289. writeLoc=writeLoc,
  5290. exceptionCode=exceptionCode)
  5291. else:
  5292. assert(defaultValue is None or
  5293. not isinstance(defaultValue, IDLNullValue))
  5294. writeLoc = "${declName}"
  5295. readLoc = writeLoc
  5296. template = fill("""
  5297. if (!ValueToPrimitive<${typeName}, ${conversionBehavior}>(cx, $${val}, &${writeLoc})) {
  5298. $*{exceptionCode}
  5299. }
  5300. """,
  5301. typeName=typeName,
  5302. conversionBehavior=conversionBehavior,
  5303. writeLoc=writeLoc,
  5304. exceptionCode=exceptionCode)
  5305. declType = CGGeneric(typeName)
  5306. if type.isFloat() and not type.isUnrestricted():
  5307. if lenientFloatCode is not None:
  5308. nonFiniteCode = lenientFloatCode
  5309. else:
  5310. nonFiniteCode = ('ThrowErrorMessage(cx, MSG_NOT_FINITE, "%s");\n'
  5311. "%s" % (firstCap(sourceDescription), exceptionCode))
  5312. # We're appending to an if-block brace, so strip trailing whitespace
  5313. # and add an extra space before the else.
  5314. template = template.rstrip()
  5315. template += fill("""
  5316. else if (!mozilla::IsFinite(${readLoc})) {
  5317. $*{nonFiniteCode}
  5318. }
  5319. """,
  5320. readLoc=readLoc,
  5321. nonFiniteCode=nonFiniteCode)
  5322. if (defaultValue is not None and
  5323. # We already handled IDLNullValue, so just deal with the other ones
  5324. not isinstance(defaultValue, IDLNullValue)):
  5325. tag = defaultValue.type.tag()
  5326. defaultStr = getHandleDefault(defaultValue)
  5327. template = CGIfElseWrapper(
  5328. "${haveValue}",
  5329. CGGeneric(template),
  5330. CGGeneric("%s = %s;\n" % (writeLoc, defaultStr))).define()
  5331. return JSToNativeConversionInfo(template, declType=declType,
  5332. dealWithOptional=isOptional)
  5333. def instantiateJSToNativeConversion(info, replacements, checkForValue=False):
  5334. """
  5335. Take a JSToNativeConversionInfo as returned by getJSToNativeConversionInfo
  5336. and a set of replacements as required by the strings in such an object, and
  5337. generate code to convert into stack C++ types.
  5338. If checkForValue is True, then the conversion will get wrapped in
  5339. a check for ${haveValue}.
  5340. """
  5341. templateBody, declType, holderType, dealWithOptional = (
  5342. info.template, info.declType, info.holderType, info.dealWithOptional)
  5343. if dealWithOptional and not checkForValue:
  5344. raise TypeError("Have to deal with optional things, but don't know how")
  5345. if checkForValue and declType is None:
  5346. raise TypeError("Need to predeclare optional things, so they will be "
  5347. "outside the check for big enough arg count!")
  5348. # We can't precompute our holder constructor arguments, since
  5349. # those might depend on ${declName}, which we change below. Just
  5350. # compute arguments at the point when we need them as we go.
  5351. def getArgsCGThing(args):
  5352. return CGGeneric(string.Template(args).substitute(replacements))
  5353. result = CGList([])
  5354. # Make a copy of "replacements" since we may be about to start modifying it
  5355. replacements = dict(replacements)
  5356. originalDeclName = replacements["declName"]
  5357. if declType is not None:
  5358. if dealWithOptional:
  5359. replacements["declName"] = "%s.Value()" % originalDeclName
  5360. declType = CGTemplatedType("Optional", declType)
  5361. declCtorArgs = None
  5362. elif info.declArgs is not None:
  5363. declCtorArgs = CGWrapper(getArgsCGThing(info.declArgs),
  5364. pre="(", post=")")
  5365. else:
  5366. declCtorArgs = None
  5367. result.append(
  5368. CGList([declType, CGGeneric(" "),
  5369. CGGeneric(originalDeclName),
  5370. declCtorArgs, CGGeneric(";\n")]))
  5371. originalHolderName = replacements["holderName"]
  5372. if holderType is not None:
  5373. if dealWithOptional:
  5374. replacements["holderName"] = "%s.ref()" % originalHolderName
  5375. holderType = CGTemplatedType("Maybe", holderType)
  5376. holderCtorArgs = None
  5377. elif info.holderArgs is not None:
  5378. holderCtorArgs = CGWrapper(getArgsCGThing(info.holderArgs),
  5379. pre="(", post=")")
  5380. else:
  5381. holderCtorArgs = None
  5382. result.append(
  5383. CGList([holderType, CGGeneric(" "),
  5384. CGGeneric(originalHolderName),
  5385. holderCtorArgs, CGGeneric(";\n")]))
  5386. if "maybeMutableVal" not in replacements:
  5387. replacements["maybeMutableVal"] = replacements["val"]
  5388. conversion = CGGeneric(
  5389. string.Template(templateBody).substitute(replacements))
  5390. if checkForValue:
  5391. if dealWithOptional:
  5392. declConstruct = CGIndenter(
  5393. CGGeneric("%s.Construct(%s);\n" %
  5394. (originalDeclName,
  5395. getArgsCGThing(info.declArgs).define() if
  5396. info.declArgs else "")))
  5397. if holderType is not None:
  5398. holderConstruct = CGIndenter(
  5399. CGGeneric("%s.emplace(%s);\n" %
  5400. (originalHolderName,
  5401. getArgsCGThing(info.holderArgs).define() if
  5402. info.holderArgs else "")))
  5403. else:
  5404. holderConstruct = None
  5405. else:
  5406. declConstruct = None
  5407. holderConstruct = None
  5408. conversion = CGList([
  5409. CGGeneric(
  5410. string.Template("if (${haveValue}) {\n").substitute(replacements)),
  5411. declConstruct,
  5412. holderConstruct,
  5413. CGIndenter(conversion),
  5414. CGGeneric("}\n")
  5415. ])
  5416. result.append(conversion)
  5417. return result
  5418. def convertConstIDLValueToJSVal(value):
  5419. if isinstance(value, IDLNullValue):
  5420. return "JS::NullValue()"
  5421. if isinstance(value, IDLUndefinedValue):
  5422. return "JS::UndefinedValue()"
  5423. tag = value.type.tag()
  5424. if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
  5425. IDLType.Tags.uint16, IDLType.Tags.int32]:
  5426. return "JS::Int32Value(%s)" % (value.value)
  5427. if tag == IDLType.Tags.uint32:
  5428. return "JS::NumberValue(%sU)" % (value.value)
  5429. if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
  5430. return "JS::CanonicalizedDoubleValue(%s)" % numericValue(tag, value.value)
  5431. if tag == IDLType.Tags.bool:
  5432. return "JS::BooleanValue(true)" if value.value else "JS::BooleanValue(false)"
  5433. if tag in [IDLType.Tags.float, IDLType.Tags.double]:
  5434. return "JS::CanonicalizedDoubleValue(%s)" % (value.value)
  5435. raise TypeError("Const value of unhandled type: %s" % value.type)
  5436. class CGArgumentConverter(CGThing):
  5437. """
  5438. A class that takes an IDL argument object and its index in the
  5439. argument list and generates code to unwrap the argument to the
  5440. right native type.
  5441. argDescription is a description of the argument for error-reporting
  5442. purposes. Callers should assume that it might get placed in the middle of a
  5443. sentence. If it ends up at the beginning of a sentence, its first character
  5444. will be automatically uppercased.
  5445. """
  5446. def __init__(self, argument, index, descriptorProvider,
  5447. argDescription, member,
  5448. invalidEnumValueFatal=True, lenientFloatCode=None):
  5449. CGThing.__init__(self)
  5450. self.argument = argument
  5451. self.argDescription = argDescription
  5452. assert(not argument.defaultValue or argument.optional)
  5453. replacer = {
  5454. "index": index,
  5455. "argc": "args.length()"
  5456. }
  5457. self.replacementVariables = {
  5458. "declName": "arg%d" % index,
  5459. "holderName": ("arg%d" % index) + "_holder",
  5460. "obj": "obj",
  5461. "passedToJSImpl": toStringBool(isJSImplementedDescriptor(descriptorProvider))
  5462. }
  5463. # If we have a method generated by the maplike/setlike portion of an
  5464. # interface, arguments can possibly be undefined, but will need to be
  5465. # converted to the key/value type of the backing object. In this case,
  5466. # use .get() instead of direct access to the argument. This won't
  5467. # matter for iterable since generated functions for those interface
  5468. # don't take arguments.
  5469. if member.isMethod() and member.isMaplikeOrSetlikeOrIterableMethod():
  5470. self.replacementVariables["val"] = string.Template(
  5471. "args.get(${index})").substitute(replacer)
  5472. self.replacementVariables["maybeMutableVal"] = string.Template(
  5473. "args[${index}]").substitute(replacer)
  5474. else:
  5475. self.replacementVariables["val"] = string.Template(
  5476. "args[${index}]").substitute(replacer)
  5477. haveValueCheck = string.Template(
  5478. "args.hasDefined(${index})").substitute(replacer)
  5479. self.replacementVariables["haveValue"] = haveValueCheck
  5480. self.descriptorProvider = descriptorProvider
  5481. if self.argument.canHaveMissingValue():
  5482. self.argcAndIndex = replacer
  5483. else:
  5484. self.argcAndIndex = None
  5485. self.invalidEnumValueFatal = invalidEnumValueFatal
  5486. self.lenientFloatCode = lenientFloatCode
  5487. def define(self):
  5488. typeConversion = getJSToNativeConversionInfo(
  5489. self.argument.type,
  5490. self.descriptorProvider,
  5491. isOptional=(self.argcAndIndex is not None and
  5492. not self.argument.variadic),
  5493. invalidEnumValueFatal=self.invalidEnumValueFatal,
  5494. defaultValue=self.argument.defaultValue,
  5495. treatNullAs=self.argument.treatNullAs,
  5496. isEnforceRange=self.argument.enforceRange,
  5497. isClamp=self.argument.clamp,
  5498. lenientFloatCode=self.lenientFloatCode,
  5499. isMember="Variadic" if self.argument.variadic else False,
  5500. allowTreatNonCallableAsNull=self.argument.allowTreatNonCallableAsNull(),
  5501. sourceDescription=self.argDescription)
  5502. if not self.argument.variadic:
  5503. return instantiateJSToNativeConversion(
  5504. typeConversion,
  5505. self.replacementVariables,
  5506. self.argcAndIndex is not None).define()
  5507. # Variadic arguments get turned into a sequence.
  5508. if typeConversion.dealWithOptional:
  5509. raise TypeError("Shouldn't have optional things in variadics")
  5510. if typeConversion.holderType is not None:
  5511. raise TypeError("Shouldn't need holders for variadics")
  5512. replacer = dict(self.argcAndIndex, **self.replacementVariables)
  5513. replacer["seqType"] = CGTemplatedType("binding_detail::AutoSequence",
  5514. typeConversion.declType).define()
  5515. if typeNeedsRooting(self.argument.type):
  5516. rooterDecl = ("SequenceRooter<%s> ${holderName}(cx, &${declName});\n" %
  5517. typeConversion.declType.define())
  5518. else:
  5519. rooterDecl = ""
  5520. replacer["elemType"] = typeConversion.declType.define()
  5521. # NOTE: Keep this in sync with sequence conversions as needed
  5522. variadicConversion = string.Template(
  5523. "${seqType} ${declName};\n" +
  5524. rooterDecl +
  5525. dedent("""
  5526. if (${argc} > ${index}) {
  5527. if (!${declName}.SetCapacity(${argc} - ${index}, mozilla::fallible)) {
  5528. JS_ReportOutOfMemory(cx);
  5529. return false;
  5530. }
  5531. for (uint32_t variadicArg = ${index}; variadicArg < ${argc}; ++variadicArg) {
  5532. ${elemType}& slot = *${declName}.AppendElement(mozilla::fallible);
  5533. """)
  5534. ).substitute(replacer)
  5535. val = string.Template("args[variadicArg]").substitute(replacer)
  5536. variadicConversion += indent(
  5537. string.Template(typeConversion.template).substitute({
  5538. "val": val,
  5539. "maybeMutableVal": val,
  5540. "declName": "slot",
  5541. # We only need holderName here to handle isExternal()
  5542. # interfaces, which use an internal holder for the
  5543. # conversion even when forceOwningType ends up true.
  5544. "holderName": "tempHolder",
  5545. # Use the same ${obj} as for the variadic arg itself
  5546. "obj": replacer["obj"],
  5547. "passedToJSImpl": toStringBool(isJSImplementedDescriptor(self.descriptorProvider))
  5548. }), 4)
  5549. variadicConversion += (" }\n"
  5550. "}\n")
  5551. return variadicConversion
  5552. def getMaybeWrapValueFuncForType(type):
  5553. # Callbacks might actually be DOM objects; nothing prevents a page from
  5554. # doing that.
  5555. if type.isCallback() or type.isCallbackInterface() or type.isObject():
  5556. if type.nullable():
  5557. return "MaybeWrapObjectOrNullValue"
  5558. return "MaybeWrapObjectValue"
  5559. # Spidermonkey interfaces are never DOM objects. Neither are sequences or
  5560. # dictionaries, since those are always plain JS objects.
  5561. if type.isSpiderMonkeyInterface() or type.isDictionary() or type.isSequence():
  5562. if type.nullable():
  5563. return "MaybeWrapNonDOMObjectOrNullValue"
  5564. return "MaybeWrapNonDOMObjectValue"
  5565. if type.isAny():
  5566. return "MaybeWrapValue"
  5567. # For other types, just go ahead an fall back on MaybeWrapValue for now:
  5568. # it's always safe to do, and shouldn't be particularly slow for any of
  5569. # them
  5570. return "MaybeWrapValue"
  5571. sequenceWrapLevel = 0
  5572. recordWrapLevel = 0
  5573. def getWrapTemplateForType(type, descriptorProvider, result, successCode,
  5574. returnsNewObject, exceptionCode, typedArraysAreStructs,
  5575. isConstructorRetval=False):
  5576. """
  5577. Reflect a C++ value stored in "result", of IDL type "type" into JS. The
  5578. "successCode" is the code to run once we have successfully done the
  5579. conversion and must guarantee that execution of the conversion template
  5580. stops once the successCode has executed (e.g. by doing a 'return', or by
  5581. doing a 'break' if the entire conversion template is inside a block that
  5582. the 'break' will exit).
  5583. If typedArraysAreStructs is true, then if the type is a typed array,
  5584. "result" is one of the dom::TypedArray subclasses, not a JSObject*.
  5585. The resulting string should be used with string.Template. It
  5586. needs the following keys when substituting:
  5587. jsvalHandle: something that can be passed to methods taking a
  5588. JS::MutableHandle<JS::Value>. This can be a
  5589. JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*.
  5590. jsvalRef: something that can have .address() called on it to get a
  5591. JS::Value* and .set() called on it to set it to a JS::Value.
  5592. This can be a JS::MutableHandle<JS::Value> or a
  5593. JS::Rooted<JS::Value>.
  5594. obj: a JS::Handle<JSObject*>.
  5595. Returns (templateString, infallibility of conversion template)
  5596. """
  5597. if successCode is None:
  5598. successCode = "return true;\n"
  5599. def setUndefined():
  5600. return _setValue("", setter="setUndefined")
  5601. def setNull():
  5602. return _setValue("", setter="setNull")
  5603. def setInt32(value):
  5604. return _setValue(value, setter="setInt32")
  5605. def setString(value):
  5606. return _setValue(value, setter="setString")
  5607. def setObject(value, wrapAsType=None):
  5608. return _setValue(value, wrapAsType=wrapAsType, setter="setObject")
  5609. def setObjectOrNull(value, wrapAsType=None):
  5610. return _setValue(value, wrapAsType=wrapAsType, setter="setObjectOrNull")
  5611. def setUint32(value):
  5612. return _setValue(value, setter="setNumber")
  5613. def setDouble(value):
  5614. return _setValue("JS_NumberValue(%s)" % value)
  5615. def setBoolean(value):
  5616. return _setValue(value, setter="setBoolean")
  5617. def _setValue(value, wrapAsType=None, setter="set"):
  5618. """
  5619. Returns the code to set the jsval to value.
  5620. If wrapAsType is not None, then will wrap the resulting value using the
  5621. function that getMaybeWrapValueFuncForType(wrapAsType) returns.
  5622. Otherwise, no wrapping will be done.
  5623. """
  5624. if wrapAsType is None:
  5625. tail = successCode
  5626. else:
  5627. tail = fill(
  5628. """
  5629. if (!${maybeWrap}(cx, $${jsvalHandle})) {
  5630. $*{exceptionCode}
  5631. }
  5632. $*{successCode}
  5633. """,
  5634. maybeWrap=getMaybeWrapValueFuncForType(wrapAsType),
  5635. exceptionCode=exceptionCode,
  5636. successCode=successCode)
  5637. return ("${jsvalRef}.%s(%s);\n" % (setter, value)) + tail
  5638. def wrapAndSetPtr(wrapCall, failureCode=None):
  5639. """
  5640. Returns the code to set the jsval by calling "wrapCall". "failureCode"
  5641. is the code to run if calling "wrapCall" fails
  5642. """
  5643. if failureCode is None:
  5644. failureCode = exceptionCode
  5645. return fill(
  5646. """
  5647. if (!${wrapCall}) {
  5648. $*{failureCode}
  5649. }
  5650. $*{successCode}
  5651. """,
  5652. wrapCall=wrapCall,
  5653. failureCode=failureCode,
  5654. successCode=successCode)
  5655. if type is None or type.isVoid():
  5656. return (setUndefined(), True)
  5657. if (type.isSequence() or type.isRecord()) and type.nullable():
  5658. # These are both wrapped in Nullable<>
  5659. recTemplate, recInfall = getWrapTemplateForType(type.inner, descriptorProvider,
  5660. "%s.Value()" % result, successCode,
  5661. returnsNewObject, exceptionCode,
  5662. typedArraysAreStructs)
  5663. code = fill(
  5664. """
  5665. if (${result}.IsNull()) {
  5666. $*{setNull}
  5667. }
  5668. $*{recTemplate}
  5669. """,
  5670. result=result,
  5671. setNull=setNull(),
  5672. recTemplate=recTemplate)
  5673. return code, recInfall
  5674. if type.isSequence():
  5675. # Now do non-nullable sequences. Our success code is just to break to
  5676. # where we set the element in the array. Note that we bump the
  5677. # sequenceWrapLevel around this call so that nested sequence conversions
  5678. # will use different iteration variables.
  5679. global sequenceWrapLevel
  5680. index = "sequenceIdx%d" % sequenceWrapLevel
  5681. sequenceWrapLevel += 1
  5682. innerTemplate = wrapForType(
  5683. type.inner, descriptorProvider,
  5684. {
  5685. 'result': "%s[%s]" % (result, index),
  5686. 'successCode': "break;\n",
  5687. 'jsvalRef': "tmp",
  5688. 'jsvalHandle': "&tmp",
  5689. 'returnsNewObject': returnsNewObject,
  5690. 'exceptionCode': exceptionCode,
  5691. 'obj': "returnArray",
  5692. 'typedArraysAreStructs': typedArraysAreStructs
  5693. })
  5694. sequenceWrapLevel -= 1
  5695. code = fill(
  5696. """
  5697. uint32_t length = ${result}.Length();
  5698. JS::Rooted<JSObject*> returnArray(cx, JS_NewArrayObject(cx, length));
  5699. if (!returnArray) {
  5700. $*{exceptionCode}
  5701. }
  5702. // Scope for 'tmp'
  5703. {
  5704. JS::Rooted<JS::Value> tmp(cx);
  5705. for (uint32_t ${index} = 0; ${index} < length; ++${index}) {
  5706. // Control block to let us common up the JS_DefineElement calls when there
  5707. // are different ways to succeed at wrapping the object.
  5708. do {
  5709. $*{innerTemplate}
  5710. } while (0);
  5711. if (!JS_DefineElement(cx, returnArray, ${index}, tmp,
  5712. JSPROP_ENUMERATE)) {
  5713. $*{exceptionCode}
  5714. }
  5715. }
  5716. }
  5717. $*{set}
  5718. """,
  5719. result=result,
  5720. exceptionCode=exceptionCode,
  5721. index=index,
  5722. innerTemplate=innerTemplate,
  5723. set=setObject("*returnArray"))
  5724. return (code, False)
  5725. if type.isRecord():
  5726. # Now do non-nullable record. Our success code is just to break to
  5727. # where we define the property on the object. Note that we bump the
  5728. # recordWrapLevel around this call so that nested record conversions
  5729. # will use different temp value names.
  5730. global recordWrapLevel
  5731. valueName = "recordValue%d" % recordWrapLevel
  5732. recordWrapLevel += 1
  5733. innerTemplate = wrapForType(
  5734. type.inner, descriptorProvider,
  5735. {
  5736. 'result': valueName,
  5737. 'successCode': "break;\n",
  5738. 'jsvalRef': "tmp",
  5739. 'jsvalHandle': "&tmp",
  5740. 'returnsNewObject': returnsNewObject,
  5741. 'exceptionCode': exceptionCode,
  5742. 'obj': "returnObj",
  5743. 'typedArraysAreStructs': typedArraysAreStructs
  5744. })
  5745. recordWrapLevel -= 1
  5746. if type.keyType.isByteString():
  5747. # There is no length-taking JS_DefineProperty. So to keep
  5748. # things sane with embedded nulls, we want to byte-inflate
  5749. # to an nsAString. The only byte-inflation function we
  5750. # have around is AppendASCIItoUTF16, which luckily doesn't
  5751. # assert anything about the input being ASCII.
  5752. expandedKeyDecl = "NS_ConvertASCIItoUTF16 expandedKey(entry.mKey);\n"
  5753. keyName = "expandedKey"
  5754. else:
  5755. expandedKeyDecl = ""
  5756. keyName = "entry.mKey"
  5757. code = fill(
  5758. """
  5759. JS::Rooted<JSObject*> returnObj(cx, JS_NewPlainObject(cx));
  5760. if (!returnObj) {
  5761. $*{exceptionCode}
  5762. }
  5763. // Scope for 'tmp'
  5764. {
  5765. JS::Rooted<JS::Value> tmp(cx);
  5766. for (auto& entry : ${result}.Entries()) {
  5767. auto& ${valueName} = entry.mValue;
  5768. // Control block to let us common up the JS_DefineUCProperty calls when there
  5769. // are different ways to succeed at wrapping the value.
  5770. do {
  5771. $*{innerTemplate}
  5772. } while (0);
  5773. $*{expandedKeyDecl}
  5774. if (!JS_DefineUCProperty(cx, returnObj,
  5775. ${keyName}.BeginReading(),
  5776. ${keyName}.Length(), tmp,
  5777. JSPROP_ENUMERATE)) {
  5778. $*{exceptionCode}
  5779. }
  5780. }
  5781. }
  5782. $*{set}
  5783. """,
  5784. result=result,
  5785. exceptionCode=exceptionCode,
  5786. valueName=valueName,
  5787. innerTemplate=innerTemplate,
  5788. expandedKeyDecl=expandedKeyDecl,
  5789. keyName=keyName,
  5790. set=setObject("*returnObj"))
  5791. return (code, False)
  5792. if type.isPromise():
  5793. assert not type.nullable()
  5794. # The use of ToJSValue here is a bit annoying because the Promise
  5795. # version is not inlined, but we can't put an inline version in either
  5796. # ToJSValue.h or BindingUtils.h, because Promise.h includes ToJSValue.h
  5797. # and that includes BindingUtils.h, so we'd get an include loop if
  5798. # either of those headers included Promise.h. Trying to write the
  5799. # conversion by hand here is annoying because we'd have to handle
  5800. # the various RefPtr, rawptr, NonNull, etc. cases, which ToJSValue will
  5801. # already handle for us, so we just use the function call.
  5802. return (wrapAndSetPtr("ToJSValue(cx, %s, ${jsvalHandle})" % result),
  5803. False)
  5804. if type.isGeckoInterface() and not type.isCallbackInterface():
  5805. descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name)
  5806. if type.nullable():
  5807. wrappingCode = ("if (!%s) {\n" % (result) +
  5808. indent(setNull()) +
  5809. "}\n")
  5810. else:
  5811. wrappingCode = ""
  5812. if not descriptor.interface.isExternal():
  5813. if descriptor.wrapperCache:
  5814. wrapMethod = "GetOrCreateDOMReflector"
  5815. wrapArgs = "cx, %s, ${jsvalHandle}" % result
  5816. else:
  5817. wrapMethod = "WrapNewBindingNonWrapperCachedObject"
  5818. wrapArgs = "cx, ${obj}, %s, ${jsvalHandle}" % result
  5819. if isConstructorRetval:
  5820. wrapArgs += ", desiredProto"
  5821. wrap = "%s(%s)" % (wrapMethod, wrapArgs)
  5822. if not descriptor.hasXPConnectImpls:
  5823. # Can only fail to wrap as a new-binding object
  5824. # if they already threw an exception.
  5825. # XXX Assertion disabled for now, see bug 991271.
  5826. failed = ("MOZ_ASSERT(true || JS_IsExceptionPending(cx));\n" +
  5827. exceptionCode)
  5828. else:
  5829. if descriptor.notflattened:
  5830. raise TypeError("%s has XPConnect impls but not flattened; "
  5831. "fallback won't work correctly" %
  5832. descriptor.interface.identifier.name)
  5833. # Try old-style wrapping for bindings which might be XPConnect impls.
  5834. failed = wrapAndSetPtr("HandleNewBindingWrappingFailure(cx, ${obj}, %s, ${jsvalHandle})" % result)
  5835. else:
  5836. if descriptor.notflattened:
  5837. getIID = "&NS_GET_IID(%s), " % descriptor.nativeType
  5838. else:
  5839. getIID = ""
  5840. wrap = "WrapObject(cx, %s, %s${jsvalHandle})" % (result, getIID)
  5841. failed = None
  5842. wrappingCode += wrapAndSetPtr(wrap, failed)
  5843. return (wrappingCode, False)
  5844. if type.isDOMString() or type.isUSVString():
  5845. if type.nullable():
  5846. return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalHandle})" % result), False)
  5847. else:
  5848. return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
  5849. if type.isByteString():
  5850. if type.nullable():
  5851. return (wrapAndSetPtr("ByteStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
  5852. else:
  5853. return (wrapAndSetPtr("NonVoidByteStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
  5854. if type.isEnum():
  5855. if type.nullable():
  5856. resultLoc = "%s.Value()" % result
  5857. else:
  5858. resultLoc = result
  5859. conversion = fill(
  5860. """
  5861. if (!ToJSValue(cx, ${result}, $${jsvalHandle})) {
  5862. $*{exceptionCode}
  5863. }
  5864. $*{successCode}
  5865. """,
  5866. result=resultLoc,
  5867. exceptionCode=exceptionCode,
  5868. successCode=successCode)
  5869. if type.nullable():
  5870. conversion = CGIfElseWrapper(
  5871. "%s.IsNull()" % result,
  5872. CGGeneric(setNull()),
  5873. CGGeneric(conversion)).define()
  5874. return conversion, False
  5875. if type.isCallback() or type.isCallbackInterface():
  5876. wrapCode = setObject(
  5877. "*GetCallbackFromCallbackObject(%(result)s)",
  5878. wrapAsType=type)
  5879. if type.nullable():
  5880. wrapCode = (
  5881. "if (%(result)s) {\n" +
  5882. indent(wrapCode) +
  5883. "} else {\n" +
  5884. indent(setNull()) +
  5885. "}\n")
  5886. wrapCode = wrapCode % {"result": result}
  5887. return wrapCode, False
  5888. if type.isAny():
  5889. # See comments in GetOrCreateDOMReflector explaining why we need
  5890. # to wrap here.
  5891. # NB: _setValue(..., type-that-is-any) calls JS_WrapValue(), so is fallible
  5892. head = "JS::ExposeValueToActiveJS(%s);\n" % result
  5893. return (head + _setValue(result, wrapAsType=type), False)
  5894. if (type.isObject() or (type.isSpiderMonkeyInterface() and
  5895. not typedArraysAreStructs)):
  5896. # See comments in GetOrCreateDOMReflector explaining why we need
  5897. # to wrap here.
  5898. if type.nullable():
  5899. toValue = "%s"
  5900. setter = setObjectOrNull
  5901. head = """if (%s) {
  5902. JS::ExposeObjectToActiveJS(%s);
  5903. }
  5904. """ % (result, result)
  5905. else:
  5906. toValue = "*%s"
  5907. setter = setObject
  5908. head = "JS::ExposeObjectToActiveJS(%s);\n" % result
  5909. # NB: setObject{,OrNull}(..., some-object-type) calls JS_WrapValue(), so is fallible
  5910. return (head + setter(toValue % result, wrapAsType=type), False)
  5911. if not (type.isUnion() or type.isPrimitive() or type.isDictionary() or
  5912. type.isDate() or
  5913. (type.isSpiderMonkeyInterface() and typedArraysAreStructs)):
  5914. raise TypeError("Need to learn to wrap %s" % type)
  5915. if type.nullable():
  5916. recTemplate, recInfal = getWrapTemplateForType(type.inner, descriptorProvider,
  5917. "%s.Value()" % result, successCode,
  5918. returnsNewObject, exceptionCode,
  5919. typedArraysAreStructs)
  5920. return ("if (%s.IsNull()) {\n" % result +
  5921. indent(setNull()) +
  5922. "}\n" +
  5923. recTemplate, recInfal)
  5924. if type.isSpiderMonkeyInterface():
  5925. assert typedArraysAreStructs
  5926. # See comments in GetOrCreateDOMReflector explaining why we need
  5927. # to wrap here.
  5928. # NB: setObject(..., some-object-type) calls JS_WrapValue(), so is fallible
  5929. return (setObject("*%s.Obj()" % result,
  5930. wrapAsType=type), False)
  5931. if type.isUnion():
  5932. return (wrapAndSetPtr("%s.ToJSVal(cx, ${obj}, ${jsvalHandle})" % result),
  5933. False)
  5934. if type.isDictionary():
  5935. return (wrapAndSetPtr("%s.ToObjectInternal(cx, ${jsvalHandle})" % result),
  5936. False)
  5937. if type.isDate():
  5938. return (wrapAndSetPtr("%s.ToDateObject(cx, ${jsvalHandle})" % result),
  5939. False)
  5940. tag = type.tag()
  5941. if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
  5942. IDLType.Tags.uint16, IDLType.Tags.int32]:
  5943. return (setInt32("int32_t(%s)" % result), True)
  5944. elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
  5945. IDLType.Tags.unrestricted_float, IDLType.Tags.float,
  5946. IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
  5947. # XXXbz will cast to double do the "even significand" thing that webidl
  5948. # calls for for 64-bit ints? Do we care?
  5949. return (setDouble("double(%s)" % result), True)
  5950. elif tag == IDLType.Tags.uint32:
  5951. return (setUint32(result), True)
  5952. elif tag == IDLType.Tags.bool:
  5953. return (setBoolean(result), True)
  5954. else:
  5955. raise TypeError("Need to learn to wrap primitive: %s" % type)
  5956. def wrapForType(type, descriptorProvider, templateValues):
  5957. """
  5958. Reflect a C++ value of IDL type "type" into JS. TemplateValues is a dict
  5959. that should contain:
  5960. * 'jsvalRef': something that can have .address() called on it to get a
  5961. JS::Value* and .set() called on it to set it to a JS::Value.
  5962. This can be a JS::MutableHandle<JS::Value> or a
  5963. JS::Rooted<JS::Value>.
  5964. * 'jsvalHandle': something that can be passed to methods taking a
  5965. JS::MutableHandle<JS::Value>. This can be a
  5966. JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*.
  5967. * 'obj' (optional): the name of the variable that contains the JSObject to
  5968. use as a scope when wrapping, if not supplied 'obj'
  5969. will be used as the name
  5970. * 'result' (optional): the name of the variable in which the C++ value is
  5971. stored, if not supplied 'result' will be used as
  5972. the name
  5973. * 'successCode' (optional): the code to run once we have successfully
  5974. done the conversion, if not supplied 'return
  5975. true;' will be used as the code. The
  5976. successCode must ensure that once it runs no
  5977. more of the conversion template will be
  5978. executed (e.g. by doing a 'return' or 'break'
  5979. as appropriate).
  5980. * 'returnsNewObject' (optional): If true, we're wrapping for the return
  5981. value of a [NewObject] method. Assumed
  5982. false if not set.
  5983. * 'exceptionCode' (optional): Code to run when a JS exception is thrown.
  5984. The default is "return false;". The code
  5985. passed here must return.
  5986. * 'isConstructorRetval' (optional): If true, we're wrapping a constructor
  5987. return value.
  5988. """
  5989. wrap = getWrapTemplateForType(
  5990. type, descriptorProvider,
  5991. templateValues.get('result', 'result'),
  5992. templateValues.get('successCode', None),
  5993. templateValues.get('returnsNewObject', False),
  5994. templateValues.get('exceptionCode', "return false;\n"),
  5995. templateValues.get('typedArraysAreStructs', False),
  5996. isConstructorRetval=templateValues.get('isConstructorRetval', False))[0]
  5997. defaultValues = {'obj': 'obj'}
  5998. return string.Template(wrap).substitute(defaultValues, **templateValues)
  5999. def infallibleForMember(member, type, descriptorProvider):
  6000. """
  6001. Determine the fallibility of changing a C++ value of IDL type "type" into
  6002. JS for the given attribute. Apart from returnsNewObject, all the defaults
  6003. are used, since the fallbility does not change based on the boolean values,
  6004. and the template will be discarded.
  6005. CURRENT ASSUMPTIONS:
  6006. We assume that successCode for wrapping up return values cannot contain
  6007. failure conditions.
  6008. """
  6009. return getWrapTemplateForType(type, descriptorProvider, 'result', None,
  6010. memberReturnsNewObject(member), "return false;\n",
  6011. False)[1]
  6012. def leafTypeNeedsCx(type, retVal):
  6013. return (type.isAny() or type.isObject() or
  6014. (retVal and type.isSpiderMonkeyInterface()))
  6015. def leafTypeNeedsScopeObject(type, retVal):
  6016. return retVal and type.isSpiderMonkeyInterface()
  6017. def leafTypeNeedsRooting(type):
  6018. return leafTypeNeedsCx(type, False) or type.isSpiderMonkeyInterface()
  6019. def typeNeedsRooting(type):
  6020. return typeMatchesLambda(type,
  6021. lambda t: leafTypeNeedsRooting(t))
  6022. def typeNeedsCx(type, retVal=False):
  6023. return typeMatchesLambda(type,
  6024. lambda t: leafTypeNeedsCx(t, retVal))
  6025. def typeNeedsScopeObject(type, retVal=False):
  6026. return typeMatchesLambda(type,
  6027. lambda t: leafTypeNeedsScopeObject(t, retVal))
  6028. def typeMatchesLambda(type, func):
  6029. if type is None:
  6030. return False
  6031. if type.nullable():
  6032. return typeMatchesLambda(type.inner, func)
  6033. if type.isSequence() or type.isRecord():
  6034. return typeMatchesLambda(type.inner, func)
  6035. if type.isUnion():
  6036. return any(typeMatchesLambda(t, func) for t in
  6037. type.unroll().flatMemberTypes)
  6038. if type.isDictionary():
  6039. return dictionaryMatchesLambda(type.inner, func)
  6040. return func(type)
  6041. def dictionaryMatchesLambda(dictionary, func):
  6042. return (any(typeMatchesLambda(m.type, func) for m in dictionary.members) or
  6043. (dictionary.parent and dictionaryMatchesLambda(dictionary.parent, func)))
  6044. # Whenever this is modified, please update CGNativeMember.getRetvalInfo as
  6045. # needed to keep the types compatible.
  6046. def getRetvalDeclarationForType(returnType, descriptorProvider,
  6047. isMember=False):
  6048. """
  6049. Returns a tuple containing five things:
  6050. 1) A CGThing for the type of the return value, or None if there is no need
  6051. for a return value.
  6052. 2) A value indicating the kind of ourparam to pass the value as. Valid
  6053. options are None to not pass as an out param at all, "ref" (to pass a
  6054. reference as an out param), and "ptr" (to pass a pointer as an out
  6055. param).
  6056. 3) A CGThing for a tracer for the return value, or None if no tracing is
  6057. needed.
  6058. 4) An argument string to pass to the retval declaration
  6059. constructor or None if there are no arguments.
  6060. 5) The name of a function that needs to be called with the return value
  6061. before using it, or None if no function needs to be called.
  6062. """
  6063. if returnType is None or returnType.isVoid():
  6064. # Nothing to declare
  6065. return None, None, None, None, None
  6066. if returnType.isPrimitive() and returnType.tag() in builtinNames:
  6067. result = CGGeneric(builtinNames[returnType.tag()])
  6068. if returnType.nullable():
  6069. result = CGTemplatedType("Nullable", result)
  6070. return result, None, None, None, None
  6071. if returnType.isDOMString() or returnType.isUSVString():
  6072. if isMember:
  6073. return CGGeneric("nsString"), "ref", None, None, None
  6074. return CGGeneric("DOMString"), "ref", None, None, None
  6075. if returnType.isByteString():
  6076. return CGGeneric("nsCString"), "ref", None, None, None
  6077. if returnType.isEnum():
  6078. result = CGGeneric(returnType.unroll().inner.identifier.name)
  6079. if returnType.nullable():
  6080. result = CGTemplatedType("Nullable", result)
  6081. return result, None, None, None, None
  6082. if returnType.isGeckoInterface() or returnType.isPromise():
  6083. if returnType.isGeckoInterface():
  6084. typeName = descriptorProvider.getDescriptor(
  6085. returnType.unroll().inner.identifier.name).nativeType
  6086. else:
  6087. typeName = "Promise"
  6088. if isMember:
  6089. conversion = None
  6090. result = CGGeneric("StrongPtrForMember<%s>::Type" % typeName)
  6091. else:
  6092. conversion = CGGeneric("StrongOrRawPtr<%s>" % typeName)
  6093. result = CGGeneric("auto")
  6094. return result, None, None, None, conversion
  6095. if returnType.isCallback():
  6096. name = returnType.unroll().callback.identifier.name
  6097. return CGGeneric("RefPtr<%s>" % name), None, None, None, None
  6098. if returnType.isAny():
  6099. if isMember:
  6100. return CGGeneric("JS::Value"), None, None, None, None
  6101. return CGGeneric("JS::Rooted<JS::Value>"), "ptr", None, "cx", None
  6102. if returnType.isObject() or returnType.isSpiderMonkeyInterface():
  6103. if isMember:
  6104. return CGGeneric("JSObject*"), None, None, None, None
  6105. return CGGeneric("JS::Rooted<JSObject*>"), "ptr", None, "cx", None
  6106. if returnType.isSequence():
  6107. nullable = returnType.nullable()
  6108. if nullable:
  6109. returnType = returnType.inner
  6110. result, _, _, _, _ = getRetvalDeclarationForType(returnType.inner,
  6111. descriptorProvider,
  6112. isMember="Sequence")
  6113. # While we have our inner type, set up our rooter, if needed
  6114. if not isMember and typeNeedsRooting(returnType):
  6115. rooter = CGGeneric("SequenceRooter<%s > resultRooter(cx, &result);\n" %
  6116. result.define())
  6117. else:
  6118. rooter = None
  6119. result = CGTemplatedType("nsTArray", result)
  6120. if nullable:
  6121. result = CGTemplatedType("Nullable", result)
  6122. return result, "ref", rooter, None, None
  6123. if returnType.isRecord():
  6124. nullable = returnType.nullable()
  6125. if nullable:
  6126. returnType = returnType.inner
  6127. result, _, _, _, _ = getRetvalDeclarationForType(returnType.inner,
  6128. descriptorProvider,
  6129. isMember="Record")
  6130. # While we have our inner type, set up our rooter, if needed
  6131. if not isMember and typeNeedsRooting(returnType):
  6132. rooter = CGGeneric("RecordRooter<%s> resultRooter(cx, &result);\n" %
  6133. ("nsString, " + result.define()))
  6134. else:
  6135. rooter = None
  6136. result = CGTemplatedType("Record", [recordKeyDeclType(returnType),
  6137. result])
  6138. if nullable:
  6139. result = CGTemplatedType("Nullable", result)
  6140. return result, "ref", rooter, None, None
  6141. if returnType.isDictionary():
  6142. nullable = returnType.nullable()
  6143. dictName = CGDictionary.makeDictionaryName(returnType.unroll().inner)
  6144. result = CGGeneric(dictName)
  6145. if not isMember and typeNeedsRooting(returnType):
  6146. if nullable:
  6147. result = CGTemplatedType("NullableRootedDictionary", result)
  6148. else:
  6149. result = CGTemplatedType("RootedDictionary", result)
  6150. resultArgs = "cx"
  6151. else:
  6152. if nullable:
  6153. result = CGTemplatedType("Nullable", result)
  6154. resultArgs = None
  6155. return result, "ref", None, resultArgs, None
  6156. if returnType.isUnion():
  6157. result = CGGeneric(CGUnionStruct.unionTypeName(returnType.unroll(), True))
  6158. if not isMember and typeNeedsRooting(returnType):
  6159. if returnType.nullable():
  6160. result = CGTemplatedType("NullableRootedUnion", result)
  6161. else:
  6162. result = CGTemplatedType("RootedUnion", result)
  6163. resultArgs = "cx"
  6164. else:
  6165. if returnType.nullable():
  6166. result = CGTemplatedType("Nullable", result)
  6167. resultArgs = None
  6168. return result, "ref", None, resultArgs, None
  6169. if returnType.isDate():
  6170. result = CGGeneric("Date")
  6171. if returnType.nullable():
  6172. result = CGTemplatedType("Nullable", result)
  6173. return result, None, None, None, None
  6174. raise TypeError("Don't know how to declare return value for %s" %
  6175. returnType)
  6176. def needCx(returnType, arguments, extendedAttributes, considerTypes,
  6177. static=False):
  6178. return (not static and considerTypes and
  6179. (typeNeedsCx(returnType, True) or
  6180. any(typeNeedsCx(a.type) for a in arguments)) or
  6181. 'implicitJSContext' in extendedAttributes)
  6182. def needScopeObject(returnType, arguments, extendedAttributes,
  6183. isWrapperCached, considerTypes, isMember):
  6184. """
  6185. isMember should be true if we're dealing with an attribute
  6186. annotated as [StoreInSlot].
  6187. """
  6188. return (considerTypes and not isWrapperCached and
  6189. ((not isMember and typeNeedsScopeObject(returnType, True)) or
  6190. any(typeNeedsScopeObject(a.type) for a in arguments)))
  6191. class CGCallGenerator(CGThing):
  6192. """
  6193. A class to generate an actual call to a C++ object. Assumes that the C++
  6194. object is stored in a variable whose name is given by the |object| argument.
  6195. needsSubjectPrincipal is a boolean indicating whether the call should
  6196. receive the subject nsIPrincipal as argument.
  6197. needsCallerType is a boolean indicating whether the call should receive
  6198. a PrincipalType for the caller.
  6199. isFallible is a boolean indicating whether the call should be fallible.
  6200. resultVar: If the returnType is not void, then the result of the call is
  6201. stored in a C++ variable named by resultVar. The caller is responsible for
  6202. declaring the result variable. If the caller doesn't care about the result
  6203. value, resultVar can be omitted.
  6204. """
  6205. def __init__(self, isFallible, needsSubjectPrincipal, needsCallerType,
  6206. arguments, argsPre, returnType, extendedAttributes, descriptor,
  6207. nativeMethodName, static, object="self", argsPost=[],
  6208. resultVar=None):
  6209. CGThing.__init__(self)
  6210. result, resultOutParam, resultRooter, resultArgs, resultConversion = \
  6211. getRetvalDeclarationForType(returnType, descriptor)
  6212. args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
  6213. for a, name in arguments:
  6214. arg = CGGeneric(name)
  6215. # Now constify the things that need it
  6216. def needsConst(a):
  6217. if a.type.isDictionary():
  6218. return True
  6219. if a.type.isSequence():
  6220. return True
  6221. if a.type.isRecord():
  6222. return True
  6223. # isObject() types are always a JS::Rooted, whether
  6224. # nullable or not, and it turns out a const JS::Rooted
  6225. # is not very helpful at all (in particular, it won't
  6226. # even convert to a JS::Handle).
  6227. # XXX bz Well, why not???
  6228. if a.type.nullable() and not a.type.isObject():
  6229. return True
  6230. if a.type.isString():
  6231. return True
  6232. if a.canHaveMissingValue():
  6233. # This will need an Optional or it's a variadic;
  6234. # in both cases it should be const.
  6235. return True
  6236. if a.type.isUnion():
  6237. return True
  6238. if a.type.isSpiderMonkeyInterface():
  6239. return True
  6240. return False
  6241. if needsConst(a):
  6242. arg = CGWrapper(arg, pre="Constify(", post=")")
  6243. # And convert NonNull<T> to T&
  6244. if (((a.type.isGeckoInterface() or a.type.isCallback() or
  6245. a.type.isPromise()) and
  6246. not a.type.nullable()) or
  6247. a.type.isDOMString()):
  6248. arg = CGWrapper(arg, pre="NonNullHelper(", post=")")
  6249. args.append(arg)
  6250. needResultDecl = False
  6251. # Return values that go in outparams go here
  6252. if resultOutParam is not None:
  6253. if resultVar is None:
  6254. needResultDecl = True
  6255. resultVar = "result"
  6256. if resultOutParam == "ref":
  6257. args.append(CGGeneric(resultVar))
  6258. else:
  6259. assert resultOutParam == "ptr"
  6260. args.append(CGGeneric("&" + resultVar))
  6261. if needsSubjectPrincipal:
  6262. args.append(CGGeneric("subjectPrincipal"))
  6263. if needsCallerType:
  6264. args.append(CGGeneric("callerType"))
  6265. if isFallible:
  6266. args.append(CGGeneric("rv"))
  6267. args.extend(CGGeneric(arg) for arg in argsPost)
  6268. # Build up our actual call
  6269. self.cgRoot = CGList([])
  6270. call = CGGeneric(nativeMethodName)
  6271. if not static:
  6272. call = CGWrapper(call, pre="%s->" % object)
  6273. call = CGList([call, CGWrapper(args, pre="(", post=")")])
  6274. if resultConversion is not None:
  6275. call = CGList([resultConversion, CGWrapper(call, pre="(", post=")")])
  6276. if resultVar is None and result is not None:
  6277. needResultDecl = True
  6278. resultVar = "result"
  6279. if needResultDecl:
  6280. if resultRooter is not None:
  6281. self.cgRoot.prepend(resultRooter)
  6282. if resultArgs is not None:
  6283. resultArgsStr = "(%s)" % resultArgs
  6284. else:
  6285. resultArgsStr = ""
  6286. result = CGWrapper(result, post=(" %s%s" % (resultVar, resultArgsStr)))
  6287. if resultOutParam is None and resultArgs is None:
  6288. call = CGList([result, CGWrapper(call, pre="(", post=")")])
  6289. else:
  6290. self.cgRoot.prepend(CGWrapper(result, post=";\n"))
  6291. if resultOutParam is None:
  6292. call = CGWrapper(call, pre=resultVar + " = ")
  6293. elif result is not None:
  6294. assert resultOutParam is None
  6295. call = CGWrapper(call, pre=resultVar + " = ")
  6296. call = CGWrapper(call, post=";\n")
  6297. self.cgRoot.append(call)
  6298. if needsSubjectPrincipal:
  6299. getPrincipal = dedent(
  6300. """
  6301. JSCompartment* compartment = js::GetContextCompartment(cx);
  6302. MOZ_ASSERT(compartment);
  6303. JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment);
  6304. """)
  6305. if descriptor.interface.isExposedInAnyWorker():
  6306. self.cgRoot.prepend(CGGeneric(fill(
  6307. """
  6308. Maybe<nsIPrincipal*> subjectPrincipal;
  6309. if (NS_IsMainThread()) {
  6310. $*{getPrincipal}
  6311. subjectPrincipal.emplace(nsJSPrincipals::get(principals));
  6312. }
  6313. """,
  6314. getPrincipal=getPrincipal)))
  6315. else:
  6316. self.cgRoot.prepend(CGGeneric(fill(
  6317. """
  6318. $*{getPrincipal}
  6319. // Initializing a nonnull is pretty darn annoying...
  6320. NonNull<nsIPrincipal> subjectPrincipal;
  6321. subjectPrincipal = static_cast<nsIPrincipal*>(nsJSPrincipals::get(principals));
  6322. """,
  6323. getPrincipal=getPrincipal)))
  6324. if needsCallerType:
  6325. # Note that we do not want to use
  6326. # IsCallerChrome/ThreadsafeIsCallerChrome directly because those
  6327. # will pull in the check for UniversalXPConnect, which we ideally
  6328. # don't want to have in the new thing we're doing here. If not
  6329. # NS_IsMainThread(), though, we'll go ahead and call
  6330. # ThreasafeIsCallerChrome(), since that won't mess with
  6331. # UnivesalXPConnect and we don't want to worry about the right
  6332. # worker includes here.
  6333. callerCheck = CGGeneric("callerType = nsContentUtils::IsSystemPrincipal(nsContentUtils::SubjectPrincipal()) ? CallerType::System : CallerType::NonSystem;\n")
  6334. if descriptor.interface.isExposedInAnyWorker():
  6335. callerCheck = CGIfElseWrapper(
  6336. "NS_IsMainThread()",
  6337. callerCheck,
  6338. CGGeneric("callerType = nsContentUtils::ThreadsafeIsCallerChrome() ? CallerType::System : CallerType::NonSystem;\n"));
  6339. self.cgRoot.prepend(callerCheck)
  6340. self.cgRoot.prepend(CGGeneric("CallerType callerType;\n"))
  6341. if isFallible:
  6342. self.cgRoot.prepend(CGGeneric("binding_detail::FastErrorResult rv;\n"))
  6343. self.cgRoot.append(CGGeneric(dedent(
  6344. """
  6345. if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
  6346. return false;
  6347. }
  6348. """)))
  6349. self.cgRoot.append(CGGeneric("MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"))
  6350. def define(self):
  6351. return self.cgRoot.define()
  6352. def getUnionMemberName(type):
  6353. # Promises can't be in unions, because they're not distinguishable
  6354. # from anything else.
  6355. assert not type.isPromise()
  6356. if type.isGeckoInterface():
  6357. return type.inner.identifier.name
  6358. if type.isEnum():
  6359. return type.inner.identifier.name
  6360. return type.name
  6361. class MethodNotNewObjectError(Exception):
  6362. def __init__(self, typename):
  6363. self.typename = typename
  6364. # A counter for making sure that when we're wrapping up things in
  6365. # nested sequences we don't use the same variable name to iterate over
  6366. # different sequences.
  6367. sequenceWrapLevel = 0
  6368. recordWrapLevel = 0
  6369. def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
  6370. """
  6371. Take the thing named by "value" and if it contains "any",
  6372. "object", or spidermonkey-interface types inside return a CGThing
  6373. that will wrap them into the current compartment.
  6374. """
  6375. if type.isAny():
  6376. assert not type.nullable()
  6377. if isMember:
  6378. value = "JS::MutableHandle<JS::Value>::fromMarkedLocation(&%s)" % value
  6379. else:
  6380. value = "&" + value
  6381. return CGGeneric("if (!JS_WrapValue(cx, %s)) {\n"
  6382. " return false;\n"
  6383. "}\n" % value)
  6384. if type.isObject():
  6385. if isMember:
  6386. value = "JS::MutableHandle<JSObject*>::fromMarkedLocation(&%s)" % value
  6387. else:
  6388. value = "&" + value
  6389. return CGGeneric("if (!JS_WrapObject(cx, %s)) {\n"
  6390. " return false;\n"
  6391. "}\n" % value)
  6392. if type.isSpiderMonkeyInterface():
  6393. origValue = value
  6394. if type.nullable():
  6395. value = "%s.Value()" % value
  6396. wrapCode = CGGeneric("if (!%s.WrapIntoNewCompartment(cx)) {\n"
  6397. " return false;\n"
  6398. "}\n" % value)
  6399. if type.nullable():
  6400. wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue)
  6401. return wrapCode
  6402. if type.isSequence():
  6403. origValue = value
  6404. origType = type
  6405. if type.nullable():
  6406. type = type.inner
  6407. value = "%s.Value()" % value
  6408. global sequenceWrapLevel
  6409. index = "indexName%d" % sequenceWrapLevel
  6410. sequenceWrapLevel += 1
  6411. wrapElement = wrapTypeIntoCurrentCompartment(type.inner,
  6412. "%s[%s]" % (value, index))
  6413. sequenceWrapLevel -= 1
  6414. if not wrapElement:
  6415. return None
  6416. wrapCode = CGWrapper(CGIndenter(wrapElement),
  6417. pre=("for (uint32_t %s = 0; %s < %s.Length(); ++%s) {\n" %
  6418. (index, index, value, index)),
  6419. post="}\n")
  6420. if origType.nullable():
  6421. wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue)
  6422. return wrapCode
  6423. if type.isRecord():
  6424. origType = type
  6425. if type.nullable():
  6426. type = type.inner
  6427. recordRef = "%s.Value()" % value
  6428. else:
  6429. recordRef = value
  6430. global recordWrapLevel
  6431. entryRef = "mapEntry%d" % recordWrapLevel
  6432. recordWrapLevel += 1
  6433. wrapElement = wrapTypeIntoCurrentCompartment(type.inner,
  6434. "%s.mValue" % entryRef)
  6435. recordWrapLevel -= 1
  6436. if not wrapElement:
  6437. return None
  6438. wrapCode = CGWrapper(CGIndenter(wrapElement),
  6439. pre=("for (auto& %s : %s.Entries()) {\n" %
  6440. (entryRef, recordRef)),
  6441. post="}\n")
  6442. if origType.nullable():
  6443. wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % value)
  6444. return wrapCode
  6445. if type.isDictionary():
  6446. assert not type.nullable()
  6447. myDict = type.inner
  6448. memberWraps = []
  6449. while myDict:
  6450. for member in myDict.members:
  6451. memberWrap = wrapArgIntoCurrentCompartment(
  6452. member,
  6453. "%s.%s" % (value, CGDictionary.makeMemberName(member.identifier.name)))
  6454. if memberWrap:
  6455. memberWraps.append(memberWrap)
  6456. myDict = myDict.parent
  6457. return CGList(memberWraps) if len(memberWraps) != 0 else None
  6458. if type.isUnion():
  6459. memberWraps = []
  6460. if type.nullable():
  6461. type = type.inner
  6462. value = "%s.Value()" % value
  6463. for member in type.flatMemberTypes:
  6464. memberName = getUnionMemberName(member)
  6465. memberWrap = wrapTypeIntoCurrentCompartment(
  6466. member, "%s.GetAs%s()" % (value, memberName))
  6467. if memberWrap:
  6468. memberWrap = CGIfWrapper(
  6469. memberWrap, "%s.Is%s()" % (value, memberName))
  6470. memberWraps.append(memberWrap)
  6471. return CGList(memberWraps, "else ") if len(memberWraps) != 0 else None
  6472. if (type.isString() or type.isPrimitive() or type.isEnum() or
  6473. type.isGeckoInterface() or type.isCallback() or type.isDate() or
  6474. type.isPromise()):
  6475. # All of these don't need wrapping.
  6476. return None
  6477. raise TypeError("Unknown type; we don't know how to wrap it in constructor "
  6478. "arguments: %s" % type)
  6479. def wrapArgIntoCurrentCompartment(arg, value, isMember=True):
  6480. """
  6481. As wrapTypeIntoCurrentCompartment but handles things being optional
  6482. """
  6483. origValue = value
  6484. isOptional = arg.canHaveMissingValue()
  6485. if isOptional:
  6486. value = value + ".Value()"
  6487. wrap = wrapTypeIntoCurrentCompartment(arg.type, value, isMember)
  6488. if wrap and isOptional:
  6489. wrap = CGIfWrapper(wrap, "%s.WasPassed()" % origValue)
  6490. return wrap
  6491. def needsContainsHack(m):
  6492. return m.getExtendedAttribute("ReturnValueNeedsContainsHack")
  6493. def needsCallerType(m):
  6494. return m.getExtendedAttribute("NeedsCallerType")
  6495. class CGPerSignatureCall(CGThing):
  6496. """
  6497. This class handles the guts of generating code for a particular
  6498. call signature. A call signature consists of four things:
  6499. 1) A return type, which can be None to indicate that there is no
  6500. actual return value (e.g. this is an attribute setter) or an
  6501. IDLType if there's an IDL type involved (including |void|).
  6502. 2) An argument list, which is allowed to be empty.
  6503. 3) A name of a native method to call.
  6504. 4) Whether or not this method is static. Note that this only controls how
  6505. the method is called (|self->nativeMethodName(...)| vs
  6506. |nativeMethodName(...)|).
  6507. We also need to know whether this is a method or a getter/setter
  6508. to do error reporting correctly.
  6509. The idlNode parameter can be either a method or an attr. We can query
  6510. |idlNode.identifier| in both cases, so we can be agnostic between the two.
  6511. """
  6512. # XXXbz For now each entry in the argument list is either an
  6513. # IDLArgument or a FakeArgument, but longer-term we may want to
  6514. # have ways of flagging things like JSContext* or optional_argc in
  6515. # there.
  6516. def __init__(self, returnType, arguments, nativeMethodName, static,
  6517. descriptor, idlNode, argConversionStartsAt=0, getter=False,
  6518. setter=False, isConstructor=False, useCounterName=None,
  6519. resultVar=None, objectName="obj"):
  6520. assert idlNode.isMethod() == (not getter and not setter)
  6521. assert idlNode.isAttr() == (getter or setter)
  6522. # Constructors are always static
  6523. assert not isConstructor or static
  6524. CGThing.__init__(self)
  6525. self.returnType = returnType
  6526. self.descriptor = descriptor
  6527. self.idlNode = idlNode
  6528. self.extendedAttributes = descriptor.getExtendedAttributes(idlNode,
  6529. getter=getter,
  6530. setter=setter)
  6531. self.arguments = arguments
  6532. self.argCount = len(arguments)
  6533. self.isConstructor = isConstructor
  6534. cgThings = []
  6535. # Here, we check if the current getter, setter, method, interface or
  6536. # inherited interfaces have the UnsafeInPrerendering extended attribute
  6537. # and if so, we add a check to make sure it is safe.
  6538. if (idlNode.getExtendedAttribute("UnsafeInPrerendering") or
  6539. descriptor.interface.getExtendedAttribute("UnsafeInPrerendering") or
  6540. any(i.getExtendedAttribute("UnsafeInPrerendering")
  6541. for i in descriptor.interface.getInheritedInterfaces())):
  6542. cgThings.append(CGGeneric(dedent(
  6543. """
  6544. if (!mozilla::dom::EnforceNotInPrerendering(cx, obj)) {
  6545. // Return false from the JSNative in order to trigger
  6546. // an uncatchable exception.
  6547. MOZ_ASSERT(!JS_IsExceptionPending(cx));
  6548. return false;
  6549. }
  6550. """)))
  6551. deprecated = (idlNode.getExtendedAttribute("Deprecated") or
  6552. (idlNode.isStatic() and descriptor.interface.getExtendedAttribute("Deprecated")))
  6553. if deprecated:
  6554. cgThings.append(CGGeneric(dedent(
  6555. """
  6556. DeprecationWarning(cx, obj, nsIDocument::e%s);
  6557. """ % deprecated[0])))
  6558. lenientFloatCode = None
  6559. if (idlNode.getExtendedAttribute('LenientFloat') is not None and
  6560. (setter or idlNode.isMethod())):
  6561. cgThings.append(CGGeneric(dedent(
  6562. """
  6563. bool foundNonFiniteFloat = false;
  6564. """)))
  6565. lenientFloatCode = "foundNonFiniteFloat = true;\n"
  6566. argsPre = []
  6567. if idlNode.isStatic():
  6568. # If we're a constructor, the GlobalObject struct will be created in
  6569. # CGClassConstructor.
  6570. if not isConstructor:
  6571. cgThings.append(CGGeneric(dedent(
  6572. """
  6573. GlobalObject global(cx, xpc::XrayAwareCalleeGlobal(obj));
  6574. if (global.Failed()) {
  6575. return false;
  6576. }
  6577. """)))
  6578. argsPre.append("global")
  6579. if isConstructor and idlNode.isHTMLConstructor():
  6580. argsPre.extend(["args", "desiredProto"])
  6581. # For JS-implemented interfaces we do not want to base the
  6582. # needsCx decision on the types involved, just on our extended
  6583. # attributes. Also, JSContext is not needed for the static case
  6584. # since GlobalObject already contains the context.
  6585. needsCx = needCx(returnType, arguments, self.extendedAttributes,
  6586. not descriptor.interface.isJSImplemented(), static)
  6587. if needsCx:
  6588. argsPre.append("cx")
  6589. needsUnwrap = False
  6590. argsPost = []
  6591. if isConstructor:
  6592. needsUnwrap = True
  6593. needsUnwrappedVar = False
  6594. unwrappedVar = "obj"
  6595. elif descriptor.interface.isJSImplemented():
  6596. if not idlNode.isStatic():
  6597. needsUnwrap = True
  6598. needsUnwrappedVar = True
  6599. argsPost.append("js::GetObjectCompartment(unwrappedObj ? *unwrappedObj : obj)")
  6600. elif needScopeObject(returnType, arguments, self.extendedAttributes,
  6601. descriptor.wrapperCache, True,
  6602. idlNode.getExtendedAttribute("StoreInSlot")):
  6603. needsUnwrap = True
  6604. needsUnwrappedVar = True
  6605. argsPre.append("unwrappedObj ? *unwrappedObj : obj")
  6606. if needsUnwrap and needsUnwrappedVar:
  6607. # We cannot assign into obj because it's a Handle, not a
  6608. # MutableHandle, so we need a separate Rooted.
  6609. cgThings.append(CGGeneric("Maybe<JS::Rooted<JSObject*> > unwrappedObj;\n"))
  6610. unwrappedVar = "unwrappedObj.ref()"
  6611. if idlNode.isMethod() and idlNode.isLegacycaller():
  6612. # If we can have legacycaller with identifier, we can't
  6613. # just use the idlNode to determine whether we're
  6614. # generating code for the legacycaller or not.
  6615. assert idlNode.isIdentifierLess()
  6616. # Pass in our thisVal
  6617. argsPre.append("args.thisv()")
  6618. ourName = "%s.%s" % (descriptor.interface.identifier.name,
  6619. idlNode.identifier.name)
  6620. if idlNode.isMethod():
  6621. argDescription = "argument %(index)d of " + ourName
  6622. elif setter:
  6623. argDescription = "value being assigned to %s" % ourName
  6624. else:
  6625. assert self.argCount == 0
  6626. if needsUnwrap:
  6627. # It's very important that we construct our unwrappedObj, if we need
  6628. # to do it, before we might start setting up Rooted things for our
  6629. # arguments, so that we don't violate the stack discipline Rooted
  6630. # depends on.
  6631. cgThings.append(CGGeneric(
  6632. "bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);\n"))
  6633. if needsUnwrappedVar:
  6634. cgThings.append(CGIfWrapper(
  6635. CGGeneric("unwrappedObj.emplace(cx, obj);\n"),
  6636. "objIsXray"))
  6637. for i in range(argConversionStartsAt, self.argCount):
  6638. cgThings.append(
  6639. CGArgumentConverter(arguments[i], i, self.descriptor,
  6640. argDescription % {"index": i + 1},
  6641. idlNode, invalidEnumValueFatal=not setter,
  6642. lenientFloatCode=lenientFloatCode))
  6643. # Now that argument processing is done, enforce the LenientFloat stuff
  6644. if lenientFloatCode:
  6645. if setter:
  6646. foundNonFiniteFloatBehavior = "return true;\n"
  6647. else:
  6648. assert idlNode.isMethod()
  6649. foundNonFiniteFloatBehavior = dedent(
  6650. """
  6651. args.rval().setUndefined();
  6652. return true;
  6653. """)
  6654. cgThings.append(CGGeneric(fill(
  6655. """
  6656. if (foundNonFiniteFloat) {
  6657. $*{returnSteps}
  6658. }
  6659. """,
  6660. returnSteps=foundNonFiniteFloatBehavior)))
  6661. if needsUnwrap:
  6662. # Something depends on having the unwrapped object, so unwrap it now.
  6663. xraySteps = []
  6664. # XXXkhuey we should be able to MOZ_ASSERT that ${obj} is
  6665. # not null.
  6666. xraySteps.append(
  6667. CGGeneric(fill(
  6668. """
  6669. ${obj} = js::CheckedUnwrap(${obj});
  6670. if (!${obj}) {
  6671. return false;
  6672. }
  6673. """,
  6674. obj=unwrappedVar)))
  6675. if isConstructor:
  6676. # If we're called via an xray, we need to enter the underlying
  6677. # object's compartment and then wrap up all of our arguments into
  6678. # that compartment as needed. This is all happening after we've
  6679. # already done the conversions from JS values to WebIDL (C++)
  6680. # values, so we only need to worry about cases where there are 'any'
  6681. # or 'object' types, or other things that we represent as actual
  6682. # JSAPI types, present. Effectively, we're emulating a
  6683. # CrossCompartmentWrapper, but working with the C++ types, not the
  6684. # original list of JS::Values.
  6685. cgThings.append(CGGeneric("Maybe<JSAutoCompartment> ac;\n"))
  6686. xraySteps.append(CGGeneric("ac.emplace(cx, obj);\n"))
  6687. xraySteps.append(CGGeneric(dedent(
  6688. """
  6689. if (!JS_WrapObject(cx, &desiredProto)) {
  6690. return false;
  6691. }
  6692. """)))
  6693. xraySteps.extend(
  6694. wrapArgIntoCurrentCompartment(arg, argname, isMember=False)
  6695. for arg, argname in self.getArguments())
  6696. cgThings.append(
  6697. CGIfWrapper(CGList(xraySteps),
  6698. "objIsXray"))
  6699. if (idlNode.getExtendedAttribute('CEReactions') is not None and
  6700. not getter):
  6701. cgThings.append(CGGeneric(dedent(
  6702. """
  6703. Maybe<AutoCEReaction> ceReaction;
  6704. DocGroup* docGroup = self->GetDocGroup();
  6705. if (docGroup) {
  6706. ceReaction.emplace(docGroup->CustomElementReactionsStack(), cx);
  6707. }
  6708. """)))
  6709. # If this is a method that was generated by a maplike/setlike
  6710. # interface, use the maplike/setlike generator to fill in the body.
  6711. # Otherwise, use CGCallGenerator to call the native method.
  6712. if idlNode.isMethod() and idlNode.isMaplikeOrSetlikeOrIterableMethod():
  6713. if (idlNode.maplikeOrSetlikeOrIterable.isMaplike() or
  6714. idlNode.maplikeOrSetlikeOrIterable.isSetlike()):
  6715. cgThings.append(CGMaplikeOrSetlikeMethodGenerator(descriptor,
  6716. idlNode.maplikeOrSetlikeOrIterable,
  6717. idlNode.identifier.name))
  6718. else:
  6719. cgThings.append(CGIterableMethodGenerator(descriptor,
  6720. idlNode.maplikeOrSetlikeOrIterable,
  6721. idlNode.identifier.name))
  6722. else:
  6723. cgThings.append(CGCallGenerator(
  6724. self.isFallible(),
  6725. idlNode.getExtendedAttribute('NeedsSubjectPrincipal'),
  6726. needsCallerType(idlNode),
  6727. self.getArguments(), argsPre, returnType,
  6728. self.extendedAttributes, descriptor,
  6729. nativeMethodName,
  6730. static, argsPost=argsPost, resultVar=resultVar))
  6731. if useCounterName:
  6732. # Generate a telemetry call for when [UseCounter] is used.
  6733. code = "SetDocumentAndPageUseCounter(cx, obj, eUseCounter_%s);\n" % useCounterName
  6734. cgThings.append(CGGeneric(code))
  6735. self.cgRoot = CGList(cgThings)
  6736. def getArguments(self):
  6737. return [(a, "arg" + str(i)) for i, a in enumerate(self.arguments)]
  6738. def isFallible(self):
  6739. return 'infallible' not in self.extendedAttributes
  6740. def wrap_return_value(self):
  6741. wrapCode = ""
  6742. returnsNewObject = memberReturnsNewObject(self.idlNode)
  6743. if (returnsNewObject and
  6744. (self.returnType.isGeckoInterface() or
  6745. self.returnType.isPromise())):
  6746. wrapCode += dedent(
  6747. """
  6748. static_assert(!IsPointer<decltype(result)>::value,
  6749. "NewObject implies that we need to keep the object alive with a strong reference.");
  6750. """)
  6751. setSlot = self.idlNode.isAttr() and self.idlNode.slotIndices is not None
  6752. if setSlot:
  6753. # For attributes in slots, we want to do some
  6754. # post-processing once we've wrapped them.
  6755. successCode = "break;\n"
  6756. else:
  6757. successCode = None
  6758. resultTemplateValues = {
  6759. 'jsvalRef': 'args.rval()',
  6760. 'jsvalHandle': 'args.rval()',
  6761. 'returnsNewObject': returnsNewObject,
  6762. 'isConstructorRetval': self.isConstructor,
  6763. 'successCode': successCode,
  6764. # 'obj' in this dictionary is the thing whose compartment we are
  6765. # trying to do the to-JS conversion in. We're going to put that
  6766. # thing in a variable named "conversionScope" if setSlot is true.
  6767. # Otherwise, just use "obj" for lack of anything better.
  6768. 'obj': "conversionScope" if setSlot else "obj"
  6769. }
  6770. try:
  6771. wrapCode += wrapForType(self.returnType, self.descriptor, resultTemplateValues)
  6772. except MethodNotNewObjectError, err:
  6773. assert not returnsNewObject
  6774. raise TypeError("%s being returned from non-NewObject method or property %s.%s" %
  6775. (err.typename,
  6776. self.descriptor.interface.identifier.name,
  6777. self.idlNode.identifier.name))
  6778. if setSlot:
  6779. # When using a slot on the Xray expando, we need to make sure that
  6780. # our initial conversion to a JS::Value is done in the caller
  6781. # compartment. When using a slot on our reflector, we want to do
  6782. # the conversion in the compartment of that reflector (that is,
  6783. # slotStorage). In both cases we want to make sure that we finally
  6784. # set up args.rval() to be in the caller compartment. We also need
  6785. # to make sure that the conversion steps happen inside a do/while
  6786. # that they can break out of on success.
  6787. #
  6788. # Of course we always have to wrap the value into the slotStorage
  6789. # compartment before we store it in slotStorage.
  6790. # postConversionSteps are the steps that run while we're still in
  6791. # the compartment we do our conversion in but after we've finished
  6792. # the initial conversion into args.rval().
  6793. postConversionSteps = ""
  6794. if needsContainsHack(self.idlNode):
  6795. # Define a .contains on the object that has the same value as
  6796. # .includes; needed for backwards compat in extensions as we
  6797. # migrate some DOMStringLists to FrozenArray.
  6798. postConversionSteps += dedent(
  6799. """
  6800. if (args.rval().isObject() && nsContentUtils::ThreadsafeIsCallerChrome()) {
  6801. JS::Rooted<JSObject*> rvalObj(cx, &args.rval().toObject());
  6802. JS::Rooted<JS::Value> includesVal(cx);
  6803. if (!JS_GetProperty(cx, rvalObj, "includes", &includesVal) ||
  6804. !JS_DefineProperty(cx, rvalObj, "contains", includesVal, JSPROP_ENUMERATE)) {
  6805. return false;
  6806. }
  6807. }
  6808. """)
  6809. if self.idlNode.getExtendedAttribute("Frozen"):
  6810. assert self.idlNode.type.isSequence() or self.idlNode.type.isDictionary()
  6811. freezeValue = CGGeneric(
  6812. "JS::Rooted<JSObject*> rvalObj(cx, &args.rval().toObject());\n"
  6813. "if (!JS_FreezeObject(cx, rvalObj)) {\n"
  6814. " return false;\n"
  6815. "}\n")
  6816. if self.idlNode.type.nullable():
  6817. freezeValue = CGIfWrapper(freezeValue,
  6818. "args.rval().isObject()")
  6819. postConversionSteps += freezeValue.define()
  6820. # slotStorageSteps are steps that run once we have entered the
  6821. # slotStorage compartment.
  6822. slotStorageSteps= fill(
  6823. """
  6824. // Make a copy so that we don't do unnecessary wrapping on args.rval().
  6825. JS::Rooted<JS::Value> storedVal(cx, args.rval());
  6826. if (!${maybeWrap}(cx, &storedVal)) {
  6827. return false;
  6828. }
  6829. js::SetReservedSlot(slotStorage, slotIndex, storedVal);
  6830. """,
  6831. maybeWrap=getMaybeWrapValueFuncForType(self.idlNode.type))
  6832. checkForXray = mayUseXrayExpandoSlots(self.descriptor, self.idlNode)
  6833. # For the case of Cached attributes, go ahead and preserve our
  6834. # wrapper if needed. We need to do this because otherwise the
  6835. # wrapper could get garbage-collected and the cached value would
  6836. # suddenly disappear, but the whole premise of cached values is that
  6837. # they never change without explicit action on someone's part. We
  6838. # don't do this for StoreInSlot, since those get dealt with during
  6839. # wrapper setup, and failure would involve us trying to clear an
  6840. # already-preserved wrapper.
  6841. if (self.idlNode.getExtendedAttribute("Cached") and
  6842. self.descriptor.wrapperCache):
  6843. preserveWrapper = dedent(
  6844. """
  6845. PreserveWrapper(self);
  6846. """)
  6847. if checkForXray:
  6848. preserveWrapper = fill(
  6849. """
  6850. if (!isXray) {
  6851. // In the Xray case we don't need to do this, because getting the
  6852. // expando object already preserved our wrapper.
  6853. $*{preserveWrapper}
  6854. }
  6855. """,
  6856. preserveWrapper=preserveWrapper)
  6857. slotStorageSteps += preserveWrapper
  6858. if checkForXray:
  6859. conversionScope = "isXray ? obj : slotStorage"
  6860. else:
  6861. conversionScope = "slotStorage"
  6862. wrapCode = fill(
  6863. """
  6864. {
  6865. JS::Rooted<JSObject*> conversionScope(cx, ${conversionScope});
  6866. JSAutoCompartment ac(cx, conversionScope);
  6867. do { // block we break out of when done wrapping
  6868. $*{wrapCode}
  6869. } while (0);
  6870. $*{postConversionSteps}
  6871. }
  6872. { // And now store things in the compartment of our slotStorage.
  6873. JSAutoCompartment ac(cx, slotStorage);
  6874. $*{slotStorageSteps}
  6875. }
  6876. // And now make sure args.rval() is in the caller compartment
  6877. return ${maybeWrap}(cx, args.rval());
  6878. """,
  6879. conversionScope=conversionScope,
  6880. wrapCode=wrapCode,
  6881. postConversionSteps=postConversionSteps,
  6882. slotStorageSteps=slotStorageSteps,
  6883. maybeWrap=getMaybeWrapValueFuncForType(self.idlNode.type))
  6884. return wrapCode
  6885. def define(self):
  6886. return (self.cgRoot.define() + self.wrap_return_value())
  6887. class CGSwitch(CGList):
  6888. """
  6889. A class to generate code for a switch statement.
  6890. Takes three constructor arguments: an expression, a list of cases,
  6891. and an optional default.
  6892. Each case is a CGCase. The default is a CGThing for the body of
  6893. the default case, if any.
  6894. """
  6895. def __init__(self, expression, cases, default=None):
  6896. CGList.__init__(self, [CGIndenter(c) for c in cases])
  6897. self.prepend(CGGeneric("switch (" + expression + ") {\n"))
  6898. if default is not None:
  6899. self.append(
  6900. CGIndenter(
  6901. CGWrapper(
  6902. CGIndenter(default),
  6903. pre="default: {\n",
  6904. post=" break;\n}\n")))
  6905. self.append(CGGeneric("}\n"))
  6906. class CGCase(CGList):
  6907. """
  6908. A class to generate code for a case statement.
  6909. Takes three constructor arguments: an expression, a CGThing for
  6910. the body (allowed to be None if there is no body), and an optional
  6911. argument (defaulting to False) for whether to fall through.
  6912. """
  6913. def __init__(self, expression, body, fallThrough=False):
  6914. CGList.__init__(self, [])
  6915. self.append(CGGeneric("case " + expression + ": {\n"))
  6916. bodyList = CGList([body])
  6917. if fallThrough:
  6918. bodyList.append(CGGeneric("MOZ_FALLTHROUGH;\n"))
  6919. else:
  6920. bodyList.append(CGGeneric("break;\n"))
  6921. self.append(CGIndenter(bodyList))
  6922. self.append(CGGeneric("}\n"))
  6923. class CGMethodCall(CGThing):
  6924. """
  6925. A class to generate selection of a method signature from a set of
  6926. signatures and generation of a call to that signature.
  6927. """
  6928. def __init__(self, nativeMethodName, static, descriptor, method,
  6929. isConstructor=False, constructorName=None):
  6930. CGThing.__init__(self)
  6931. if isConstructor:
  6932. assert constructorName is not None
  6933. methodName = constructorName
  6934. else:
  6935. methodName = "%s.%s" % (descriptor.interface.identifier.name, method.identifier.name)
  6936. argDesc = "argument %d of " + methodName
  6937. if method.getExtendedAttribute("UseCounter"):
  6938. useCounterName = methodName.replace(".", "_")
  6939. else:
  6940. useCounterName = None
  6941. if method.isStatic():
  6942. nativeType = descriptor.nativeType
  6943. staticTypeOverride = PropertyDefiner.getStringAttr(method, "StaticClassOverride")
  6944. if (staticTypeOverride):
  6945. nativeType = staticTypeOverride
  6946. nativeMethodName = "%s::%s" % (nativeType, nativeMethodName)
  6947. def requiredArgCount(signature):
  6948. arguments = signature[1]
  6949. if len(arguments) == 0:
  6950. return 0
  6951. requiredArgs = len(arguments)
  6952. while requiredArgs and arguments[requiredArgs-1].optional:
  6953. requiredArgs -= 1
  6954. return requiredArgs
  6955. def getPerSignatureCall(signature, argConversionStartsAt=0):
  6956. return CGPerSignatureCall(signature[0], signature[1],
  6957. nativeMethodName, static, descriptor,
  6958. method,
  6959. argConversionStartsAt=argConversionStartsAt,
  6960. isConstructor=isConstructor,
  6961. useCounterName=useCounterName)
  6962. signatures = method.signatures()
  6963. if len(signatures) == 1:
  6964. # Special case: we can just do a per-signature method call
  6965. # here for our one signature and not worry about switching
  6966. # on anything.
  6967. signature = signatures[0]
  6968. self.cgRoot = CGList([getPerSignatureCall(signature)])
  6969. requiredArgs = requiredArgCount(signature)
  6970. # Skip required arguments check for maplike/setlike interfaces, as
  6971. # they can have arguments which are not passed, and are treated as
  6972. # if undefined had been explicitly passed.
  6973. if requiredArgs > 0 and not method.isMaplikeOrSetlikeOrIterableMethod():
  6974. code = fill(
  6975. """
  6976. if (MOZ_UNLIKELY(args.length() < ${requiredArgs})) {
  6977. return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${methodName}");
  6978. }
  6979. """,
  6980. requiredArgs=requiredArgs,
  6981. methodName=methodName)
  6982. self.cgRoot.prepend(CGGeneric(code))
  6983. return
  6984. # Need to find the right overload
  6985. maxArgCount = method.maxArgCount
  6986. allowedArgCounts = method.allowedArgCounts
  6987. argCountCases = []
  6988. for argCountIdx, argCount in enumerate(allowedArgCounts):
  6989. possibleSignatures = method.signaturesForArgCount(argCount)
  6990. # Try to optimize away cases when the next argCount in the list
  6991. # will have the same code as us; if it does, we can fall through to
  6992. # that case.
  6993. if argCountIdx+1 < len(allowedArgCounts):
  6994. nextPossibleSignatures = method.signaturesForArgCount(allowedArgCounts[argCountIdx+1])
  6995. else:
  6996. nextPossibleSignatures = None
  6997. if possibleSignatures == nextPossibleSignatures:
  6998. # Same set of signatures means we better have the same
  6999. # distinguishing index. So we can in fact just fall through to
  7000. # the next case here.
  7001. assert (len(possibleSignatures) == 1 or
  7002. (method.distinguishingIndexForArgCount(argCount) ==
  7003. method.distinguishingIndexForArgCount(allowedArgCounts[argCountIdx+1])))
  7004. argCountCases.append(CGCase(str(argCount), None, True))
  7005. continue
  7006. if len(possibleSignatures) == 1:
  7007. # easy case!
  7008. signature = possibleSignatures[0]
  7009. argCountCases.append(
  7010. CGCase(str(argCount), getPerSignatureCall(signature)))
  7011. continue
  7012. distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
  7013. def distinguishingArgument(signature):
  7014. args = signature[1]
  7015. if distinguishingIndex < len(args):
  7016. return args[distinguishingIndex]
  7017. assert args[-1].variadic
  7018. return args[-1]
  7019. def distinguishingType(signature):
  7020. return distinguishingArgument(signature).type
  7021. for sig in possibleSignatures:
  7022. # We should not have "any" args at distinguishingIndex,
  7023. # since we have multiple possible signatures remaining,
  7024. # but "any" is never distinguishable from anything else.
  7025. assert not distinguishingType(sig).isAny()
  7026. # We can't handle unions at the distinguishing index.
  7027. if distinguishingType(sig).isUnion():
  7028. raise TypeError("No support for unions as distinguishing "
  7029. "arguments yet: %s" %
  7030. distinguishingArgument(sig).location)
  7031. # We don't support variadics as the distinguishingArgument yet.
  7032. # If you want to add support, consider this case:
  7033. #
  7034. # void(long... foo);
  7035. # void(long bar, Int32Array baz);
  7036. #
  7037. # in which we have to convert argument 0 to long before picking
  7038. # an overload... but all the variadic stuff needs to go into a
  7039. # single array in case we pick that overload, so we have to have
  7040. # machinery for converting argument 0 to long and then either
  7041. # placing it in the variadic bit or not. Or something. We may
  7042. # be able to loosen this restriction if the variadic arg is in
  7043. # fact at distinguishingIndex, perhaps. Would need to
  7044. # double-check.
  7045. if distinguishingArgument(sig).variadic:
  7046. raise TypeError("No support for variadics as distinguishing "
  7047. "arguments yet: %s" %
  7048. distinguishingArgument(sig).location)
  7049. # Convert all our arguments up to the distinguishing index.
  7050. # Doesn't matter which of the possible signatures we use, since
  7051. # they all have the same types up to that point; just use
  7052. # possibleSignatures[0]
  7053. caseBody = [CGArgumentConverter(possibleSignatures[0][1][i],
  7054. i, descriptor,
  7055. argDesc % (i + 1), method)
  7056. for i in range(0, distinguishingIndex)]
  7057. # Select the right overload from our set.
  7058. distinguishingArg = "args[%d]" % distinguishingIndex
  7059. def tryCall(signature, indent, isDefinitelyObject=False,
  7060. isNullOrUndefined=False):
  7061. assert not isDefinitelyObject or not isNullOrUndefined
  7062. assert isDefinitelyObject or isNullOrUndefined
  7063. if isDefinitelyObject:
  7064. failureCode = "break;\n"
  7065. else:
  7066. failureCode = None
  7067. type = distinguishingType(signature)
  7068. # The argument at index distinguishingIndex can't possibly be
  7069. # unset here, because we've already checked that argc is large
  7070. # enough that we can examine this argument. But note that we
  7071. # still want to claim that optional arguments are optional, in
  7072. # case undefined was passed in.
  7073. argIsOptional = distinguishingArgument(signature).canHaveMissingValue()
  7074. testCode = instantiateJSToNativeConversion(
  7075. getJSToNativeConversionInfo(type, descriptor,
  7076. failureCode=failureCode,
  7077. isDefinitelyObject=isDefinitelyObject,
  7078. isNullOrUndefined=isNullOrUndefined,
  7079. isOptional=argIsOptional,
  7080. sourceDescription=(argDesc % (distinguishingIndex + 1))),
  7081. {
  7082. "declName": "arg%d" % distinguishingIndex,
  7083. "holderName": ("arg%d" % distinguishingIndex) + "_holder",
  7084. "val": distinguishingArg,
  7085. "obj": "obj",
  7086. "haveValue": "args.hasDefined(%d)" % distinguishingIndex,
  7087. "passedToJSImpl": toStringBool(isJSImplementedDescriptor(descriptor))
  7088. },
  7089. checkForValue=argIsOptional)
  7090. caseBody.append(CGIndenter(testCode, indent))
  7091. # If we got this far, we know we unwrapped to the right
  7092. # C++ type, so just do the call. Start conversion with
  7093. # distinguishingIndex + 1, since we already converted
  7094. # distinguishingIndex.
  7095. caseBody.append(CGIndenter(
  7096. getPerSignatureCall(signature, distinguishingIndex + 1),
  7097. indent))
  7098. def hasConditionalConversion(type):
  7099. """
  7100. Return whether the argument conversion for this type will be
  7101. conditional on the type of incoming JS value. For example, for
  7102. interface types the conversion is conditional on the incoming
  7103. value being isObject().
  7104. For the types for which this returns false, we do not have to
  7105. output extra isUndefined() or isNullOrUndefined() cases, because
  7106. null/undefined values will just fall through into our
  7107. unconditional conversion.
  7108. """
  7109. if type.isString() or type.isEnum():
  7110. return False
  7111. if type.isBoolean():
  7112. distinguishingTypes = (distinguishingType(s) for s in
  7113. possibleSignatures)
  7114. return any(t.isString() or t.isEnum() or t.isNumeric()
  7115. for t in distinguishingTypes)
  7116. if type.isNumeric():
  7117. distinguishingTypes = (distinguishingType(s) for s in
  7118. possibleSignatures)
  7119. return any(t.isString() or t.isEnum()
  7120. for t in distinguishingTypes)
  7121. return True
  7122. def needsNullOrUndefinedCase(type):
  7123. """
  7124. Return true if the type needs a special isNullOrUndefined() case
  7125. """
  7126. return ((type.nullable() and
  7127. hasConditionalConversion(type)) or
  7128. type.isDictionary())
  7129. # First check for undefined and optional distinguishing arguments
  7130. # and output a special branch for that case. Note that we don't
  7131. # use distinguishingArgument here because we actualy want to
  7132. # exclude variadic arguments. Also note that we skip this check if
  7133. # we plan to output a isNullOrUndefined() special case for this
  7134. # argument anyway, since that will subsume our isUndefined() check.
  7135. # This is safe, because there can be at most one nullable
  7136. # distinguishing argument, so if we're it we'll definitely get
  7137. # picked up by the nullable handling. Also, we can skip this check
  7138. # if the argument has an unconditional conversion later on.
  7139. undefSigs = [s for s in possibleSignatures if
  7140. distinguishingIndex < len(s[1]) and
  7141. s[1][distinguishingIndex].optional and
  7142. hasConditionalConversion(s[1][distinguishingIndex].type) and
  7143. not needsNullOrUndefinedCase(s[1][distinguishingIndex].type)]
  7144. # Can't have multiple signatures with an optional argument at the
  7145. # same index.
  7146. assert len(undefSigs) < 2
  7147. if len(undefSigs) > 0:
  7148. caseBody.append(CGGeneric("if (%s.isUndefined()) {\n" %
  7149. distinguishingArg))
  7150. tryCall(undefSigs[0], 2, isNullOrUndefined=True)
  7151. caseBody.append(CGGeneric("}\n"))
  7152. # Next, check for null or undefined. That means looking for
  7153. # nullable arguments at the distinguishing index and outputting a
  7154. # separate branch for them. But if the nullable argument has an
  7155. # unconditional conversion, we don't need to do that. The reason
  7156. # for that is that at most one argument at the distinguishing index
  7157. # is nullable (since two nullable arguments are not
  7158. # distinguishable), and null/undefined values will always fall
  7159. # through to the unconditional conversion we have, if any, since
  7160. # they will fail whatever the conditions on the input value are for
  7161. # our other conversions.
  7162. nullOrUndefSigs = [s for s in possibleSignatures
  7163. if needsNullOrUndefinedCase(distinguishingType(s))]
  7164. # Can't have multiple nullable types here
  7165. assert len(nullOrUndefSigs) < 2
  7166. if len(nullOrUndefSigs) > 0:
  7167. caseBody.append(CGGeneric("if (%s.isNullOrUndefined()) {\n" %
  7168. distinguishingArg))
  7169. tryCall(nullOrUndefSigs[0], 2, isNullOrUndefined=True)
  7170. caseBody.append(CGGeneric("}\n"))
  7171. # Now check for distinguishingArg being various kinds of objects.
  7172. # The spec says to check for the following things in order:
  7173. # 1) A platform object that's not a platform array object, being
  7174. # passed to an interface or "object" arg.
  7175. # 2) A Date object being passed to a Date or "object" arg.
  7176. # 3) A RegExp object being passed to a RegExp or "object" arg.
  7177. # 4) A callable object being passed to a callback or "object" arg.
  7178. # 5) An iterable object being passed to a sequence arg.
  7179. # 6) Any non-Date and non-RegExp object being passed to a
  7180. # array or callback interface or dictionary or
  7181. # "object" arg.
  7182. # First grab all the overloads that have a non-callback interface
  7183. # (which includes typed arrays and arraybuffers) at the
  7184. # distinguishing index. We can also include the ones that have an
  7185. # "object" here, since if those are present no other object-typed
  7186. # argument will be.
  7187. objectSigs = [
  7188. s for s in possibleSignatures
  7189. if (distinguishingType(s).isObject() or
  7190. distinguishingType(s).isNonCallbackInterface())]
  7191. # And all the overloads that take Date
  7192. objectSigs.extend(s for s in possibleSignatures
  7193. if distinguishingType(s).isDate())
  7194. # And all the overloads that take callbacks
  7195. objectSigs.extend(s for s in possibleSignatures
  7196. if distinguishingType(s).isCallback())
  7197. # And all the overloads that take sequences
  7198. objectSigs.extend(s for s in possibleSignatures
  7199. if distinguishingType(s).isSequence())
  7200. # Now append all the overloads that take a dictionary or callback
  7201. # interface or record. There should be only one of these!
  7202. genericObjectSigs = [
  7203. s for s in possibleSignatures
  7204. if (distinguishingType(s).isDictionary() or
  7205. distinguishingType(s).isRecord() or
  7206. distinguishingType(s).isCallbackInterface())]
  7207. assert len(genericObjectSigs) <= 1
  7208. objectSigs.extend(genericObjectSigs)
  7209. # There might be more than one thing in objectSigs; we need to check
  7210. # which ones we unwrap to.
  7211. if len(objectSigs) > 0:
  7212. # Here it's enough to guard on our argument being an object. The
  7213. # code for unwrapping non-callback interfaces, typed arrays,
  7214. # sequences, and Dates will just bail out and move on to
  7215. # the next overload if the object fails to unwrap correctly,
  7216. # while "object" accepts any object anyway. We could even not
  7217. # do the isObject() check up front here, but in cases where we
  7218. # have multiple object overloads it makes sense to do it only
  7219. # once instead of for each overload. That will also allow the
  7220. # unwrapping test to skip having to do codegen for the
  7221. # null-or-undefined case, which we already handled above.
  7222. caseBody.append(CGGeneric("if (%s.isObject()) {\n" %
  7223. distinguishingArg))
  7224. for sig in objectSigs:
  7225. caseBody.append(CGIndenter(CGGeneric("do {\n")))
  7226. # Indent by 4, since we need to indent further
  7227. # than our "do" statement
  7228. tryCall(sig, 4, isDefinitelyObject=True)
  7229. caseBody.append(CGIndenter(CGGeneric("} while (0);\n")))
  7230. caseBody.append(CGGeneric("}\n"))
  7231. # Now we only have to consider booleans, numerics, and strings. If
  7232. # we only have one of them, then we can just output it. But if not,
  7233. # then we need to output some of the cases conditionally: if we have
  7234. # a string overload, then boolean and numeric are conditional, and
  7235. # if not then boolean is conditional if we have a numeric overload.
  7236. def findUniqueSignature(filterLambda):
  7237. sigs = filter(filterLambda, possibleSignatures)
  7238. assert len(sigs) < 2
  7239. if len(sigs) > 0:
  7240. return sigs[0]
  7241. return None
  7242. stringSignature = findUniqueSignature(
  7243. lambda s: (distinguishingType(s).isString() or
  7244. distinguishingType(s).isEnum()))
  7245. numericSignature = findUniqueSignature(
  7246. lambda s: distinguishingType(s).isNumeric())
  7247. booleanSignature = findUniqueSignature(
  7248. lambda s: distinguishingType(s).isBoolean())
  7249. if stringSignature or numericSignature:
  7250. booleanCondition = "%s.isBoolean()"
  7251. else:
  7252. booleanCondition = None
  7253. if stringSignature:
  7254. numericCondition = "%s.isNumber()"
  7255. else:
  7256. numericCondition = None
  7257. def addCase(sig, condition):
  7258. sigCode = getPerSignatureCall(sig, distinguishingIndex)
  7259. if condition:
  7260. sigCode = CGIfWrapper(sigCode,
  7261. condition % distinguishingArg)
  7262. caseBody.append(sigCode)
  7263. if booleanSignature:
  7264. addCase(booleanSignature, booleanCondition)
  7265. if numericSignature:
  7266. addCase(numericSignature, numericCondition)
  7267. if stringSignature:
  7268. addCase(stringSignature, None)
  7269. if (not booleanSignature and not numericSignature and
  7270. not stringSignature):
  7271. # Just throw; we have no idea what we're supposed to
  7272. # do with this.
  7273. caseBody.append(CGGeneric(
  7274. 'return ThrowErrorMessage(cx, MSG_OVERLOAD_RESOLUTION_FAILED, "%d", "%d", "%s");\n' %
  7275. (distinguishingIndex + 1, argCount, methodName)))
  7276. argCountCases.append(CGCase(str(argCount), CGList(caseBody)))
  7277. overloadCGThings = []
  7278. overloadCGThings.append(
  7279. CGGeneric("unsigned argcount = std::min(args.length(), %du);\n" %
  7280. maxArgCount))
  7281. overloadCGThings.append(
  7282. CGSwitch("argcount",
  7283. argCountCases,
  7284. CGGeneric('return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "%s");\n' %
  7285. methodName)))
  7286. overloadCGThings.append(
  7287. CGGeneric('MOZ_CRASH("We have an always-returning default case");\n'
  7288. 'return false;\n'))
  7289. self.cgRoot = CGList(overloadCGThings)
  7290. def define(self):
  7291. return self.cgRoot.define()
  7292. class CGGetterCall(CGPerSignatureCall):
  7293. """
  7294. A class to generate a native object getter call for a particular IDL
  7295. getter.
  7296. """
  7297. def __init__(self, returnType, nativeMethodName, descriptor, attr):
  7298. if attr.getExtendedAttribute("UseCounter"):
  7299. useCounterName = "%s_%s_getter" % (descriptor.interface.identifier.name,
  7300. attr.identifier.name)
  7301. else:
  7302. useCounterName = None
  7303. if attr.isStatic():
  7304. nativeMethodName = "%s::%s" % (descriptor.nativeType, nativeMethodName)
  7305. CGPerSignatureCall.__init__(self, returnType, [], nativeMethodName,
  7306. attr.isStatic(), descriptor, attr,
  7307. getter=True, useCounterName=useCounterName)
  7308. class CGNavigatorGetterCall(CGPerSignatureCall):
  7309. """
  7310. A class to generate a native object getter call for an IDL getter for a
  7311. property generated by NavigatorProperty.
  7312. """
  7313. def __init__(self, returnType, _, descriptor, attr):
  7314. nativeMethodName = "%s::ConstructNavigatorObject" % (toBindingNamespace(returnType.inner.identifier.name))
  7315. CGPerSignatureCall.__init__(self, returnType, [], nativeMethodName,
  7316. True, descriptor, attr, getter=True)
  7317. def getArguments(self):
  7318. # The navigator object should be associated with the global of
  7319. # the navigator it's coming from, which will be the global of
  7320. # the object whose slot it gets cached in. That's stored in
  7321. # "slotStorage".
  7322. return [(FakeArgument(BuiltinTypes[IDLBuiltinType.Types.object],
  7323. self.idlNode),
  7324. "slotStorage")]
  7325. class FakeIdentifier():
  7326. def __init__(self, name):
  7327. self.name = name
  7328. class FakeArgument():
  7329. """
  7330. A class that quacks like an IDLArgument. This is used to make
  7331. setters look like method calls or for special operations.
  7332. """
  7333. def __init__(self, type, interfaceMember, name="arg", allowTreatNonCallableAsNull=False):
  7334. self.type = type
  7335. self.optional = False
  7336. self.variadic = False
  7337. self.defaultValue = None
  7338. self._allowTreatNonCallableAsNull = allowTreatNonCallableAsNull
  7339. # For FakeArguments generated by maplike/setlike convenience functions,
  7340. # we won't have an interfaceMember to pass in.
  7341. if interfaceMember:
  7342. self.treatNullAs = interfaceMember.treatNullAs
  7343. else:
  7344. self.treatNullAs = "Default"
  7345. if isinstance(interfaceMember, IDLAttribute):
  7346. self.enforceRange = interfaceMember.enforceRange
  7347. self.clamp = interfaceMember.clamp
  7348. else:
  7349. self.enforceRange = False
  7350. self.clamp = False
  7351. self.identifier = FakeIdentifier(name)
  7352. def allowTreatNonCallableAsNull(self):
  7353. return self._allowTreatNonCallableAsNull
  7354. def canHaveMissingValue(self):
  7355. return False
  7356. class CGSetterCall(CGPerSignatureCall):
  7357. """
  7358. A class to generate a native object setter call for a particular IDL
  7359. setter.
  7360. """
  7361. def __init__(self, argType, nativeMethodName, descriptor, attr):
  7362. if attr.getExtendedAttribute("UseCounter"):
  7363. useCounterName = "%s_%s_setter" % (descriptor.interface.identifier.name,
  7364. attr.identifier.name)
  7365. else:
  7366. useCounterName = None
  7367. if attr.isStatic():
  7368. nativeMethodName = "%s::%s" % (descriptor.nativeType, nativeMethodName)
  7369. CGPerSignatureCall.__init__(self, None,
  7370. [FakeArgument(argType, attr, allowTreatNonCallableAsNull=True)],
  7371. nativeMethodName, attr.isStatic(),
  7372. descriptor, attr, setter=True, useCounterName=useCounterName)
  7373. def wrap_return_value(self):
  7374. attr = self.idlNode
  7375. if self.descriptor.wrapperCache and attr.slotIndices is not None:
  7376. if attr.getExtendedAttribute("StoreInSlot"):
  7377. args = "cx, self"
  7378. else:
  7379. args = "self"
  7380. clearSlot = ("%s(%s);\n" %
  7381. (MakeClearCachedValueNativeName(self.idlNode), args))
  7382. else:
  7383. clearSlot = ""
  7384. # We have no return value
  7385. return ("\n"
  7386. "%s"
  7387. "return true;\n" % clearSlot)
  7388. class CGAbstractBindingMethod(CGAbstractStaticMethod):
  7389. """
  7390. Common class to generate the JSNatives for all our methods, getters, and
  7391. setters. This will generate the function declaration and unwrap the
  7392. |this| object. Subclasses are expected to override the generate_code
  7393. function to do the rest of the work. This function should return a
  7394. CGThing which is already properly indented.
  7395. getThisObj should be code for getting a JSObject* for the binding
  7396. object. If this is None, we will auto-generate code based on
  7397. descriptor to do the right thing. "" can be passed in if the
  7398. binding object is already stored in 'obj'.
  7399. callArgs should be code for getting a JS::CallArgs into a variable
  7400. called 'args'. This can be "" if there is already such a variable
  7401. around.
  7402. If allowCrossOriginThis is true, then this-unwrapping will first do an
  7403. UncheckedUnwrap and after that operate on the result.
  7404. """
  7405. def __init__(self, descriptor, name, args, unwrapFailureCode=None,
  7406. getThisObj=None,
  7407. callArgs="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);\n",
  7408. allowCrossOriginThis=False):
  7409. CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
  7410. if unwrapFailureCode is None:
  7411. self.unwrapFailureCode = 'return ThrowErrorMessage(cx, MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "Value", "%s");\n' % descriptor.interface.identifier.name
  7412. else:
  7413. self.unwrapFailureCode = unwrapFailureCode
  7414. if getThisObj == "":
  7415. self.getThisObj = None
  7416. else:
  7417. if getThisObj is None:
  7418. if descriptor.interface.isOnGlobalProtoChain():
  7419. ensureCondition = "!args.thisv().isNullOrUndefined() && !args.thisv().isObject()"
  7420. getThisObj = "args.thisv().isObject() ? &args.thisv().toObject() : js::GetGlobalForObjectCrossCompartment(&args.callee())"
  7421. else:
  7422. ensureCondition = "!args.thisv().isObject()"
  7423. getThisObj = "&args.thisv().toObject()"
  7424. unwrapFailureCode = self.unwrapFailureCode % {'securityError': 'false'}
  7425. ensureThisObj = CGIfWrapper(CGGeneric(unwrapFailureCode),
  7426. ensureCondition)
  7427. else:
  7428. ensureThisObj = None
  7429. self.getThisObj = CGList(
  7430. [ensureThisObj,
  7431. CGGeneric("JS::Rooted<JSObject*> obj(cx, %s);\n" %
  7432. getThisObj)])
  7433. self.callArgs = callArgs
  7434. self.allowCrossOriginThis = allowCrossOriginThis
  7435. def definition_body(self):
  7436. body = self.callArgs
  7437. if self.getThisObj is not None:
  7438. body += self.getThisObj.define() + "\n"
  7439. body += "%s* self;\n" % self.descriptor.nativeType
  7440. body += dedent(
  7441. """
  7442. JS::Rooted<JS::Value> rootSelf(cx, JS::ObjectValue(*obj));
  7443. """)
  7444. # Our descriptor might claim that we're not castable, simply because
  7445. # we're someone's consequential interface. But for this-unwrapping, we
  7446. # know that we're the real deal. So fake a descriptor here for
  7447. # consumption by CastableObjectUnwrapper.
  7448. body += str(CastableObjectUnwrapper(
  7449. self.descriptor,
  7450. "rootSelf",
  7451. "&rootSelf",
  7452. "self",
  7453. self.unwrapFailureCode,
  7454. allowCrossOriginObj=self.allowCrossOriginThis))
  7455. return body + self.generate_code().define()
  7456. def generate_code(self):
  7457. assert False # Override me
  7458. class CGAbstractStaticBindingMethod(CGAbstractStaticMethod):
  7459. """
  7460. Common class to generate the JSNatives for all our static methods, getters
  7461. and setters. This will generate the function declaration and unwrap the
  7462. global object. Subclasses are expected to override the generate_code
  7463. function to do the rest of the work. This function should return a
  7464. CGThing which is already properly indented.
  7465. """
  7466. def __init__(self, descriptor, name):
  7467. CGAbstractStaticMethod.__init__(self, descriptor, name, "bool",
  7468. JSNativeArguments())
  7469. def definition_body(self):
  7470. # Make sure that "obj" is in the same compartment as "cx", since we'll
  7471. # later use it to wrap return values.
  7472. unwrap = dedent("""
  7473. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  7474. JS::Rooted<JSObject*> obj(cx, &args.callee());
  7475. """)
  7476. return unwrap + self.generate_code().define()
  7477. def generate_code(self):
  7478. assert False # Override me
  7479. def MakeNativeName(name):
  7480. return name[0].upper() + IDLToCIdentifier(name[1:])
  7481. class CGGenericMethod(CGAbstractBindingMethod):
  7482. """
  7483. A class for generating the C++ code for an IDL method.
  7484. If allowCrossOriginThis is true, then this-unwrapping will first do an
  7485. UncheckedUnwrap and after that operate on the result.
  7486. """
  7487. def __init__(self, descriptor, allowCrossOriginThis=False):
  7488. unwrapFailureCode = (
  7489. 'return ThrowInvalidThis(cx, args, %%(securityError)s, "%s");\n' %
  7490. descriptor.interface.identifier.name)
  7491. name = "genericCrossOriginMethod" if allowCrossOriginThis else "genericMethod"
  7492. CGAbstractBindingMethod.__init__(self, descriptor, name,
  7493. JSNativeArguments(),
  7494. unwrapFailureCode=unwrapFailureCode,
  7495. allowCrossOriginThis=allowCrossOriginThis)
  7496. def generate_code(self):
  7497. return CGGeneric(dedent("""
  7498. const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  7499. MOZ_ASSERT(info->type() == JSJitInfo::Method);
  7500. JSJitMethodOp method = info->method;
  7501. bool ok = method(cx, obj, self, JSJitMethodCallArgs(args));
  7502. #ifdef DEBUG
  7503. if (ok) {
  7504. AssertReturnTypeMatchesJitinfo(info, args.rval());
  7505. }
  7506. #endif
  7507. return ok;
  7508. """))
  7509. class CGGenericPromiseReturningMethod(CGAbstractBindingMethod):
  7510. """
  7511. A class for generating the C++ code for an IDL method that returns a Promise.
  7512. Does not handle cross-origin this.
  7513. """
  7514. def __init__(self, descriptor):
  7515. unwrapFailureCode = dedent("""
  7516. ThrowInvalidThis(cx, args, %%(securityError)s, "%s");\n
  7517. return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
  7518. args.rval());\n""" %
  7519. descriptor.interface.identifier.name)
  7520. name = "genericPromiseReturningMethod"
  7521. customCallArgs = dedent("""
  7522. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  7523. // Make sure to save the callee before someone maybe messes with rval().
  7524. JS::Rooted<JSObject*> callee(cx, &args.callee());
  7525. """)
  7526. CGAbstractBindingMethod.__init__(self, descriptor, name,
  7527. JSNativeArguments(),
  7528. callArgs=customCallArgs,
  7529. unwrapFailureCode=unwrapFailureCode)
  7530. def generate_code(self):
  7531. return CGGeneric(dedent("""
  7532. const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  7533. MOZ_ASSERT(info->type() == JSJitInfo::Method);
  7534. JSJitMethodOp method = info->method;
  7535. bool ok = method(cx, obj, self, JSJitMethodCallArgs(args));
  7536. if (ok) {
  7537. #ifdef DEBUG
  7538. AssertReturnTypeMatchesJitinfo(info, args.rval());
  7539. #endif
  7540. return true;
  7541. }
  7542. MOZ_ASSERT(info->returnType() == JSVAL_TYPE_OBJECT);
  7543. return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
  7544. args.rval());
  7545. """))
  7546. class CGSpecializedMethod(CGAbstractStaticMethod):
  7547. """
  7548. A class for generating the C++ code for a specialized method that the JIT
  7549. can call with lower overhead.
  7550. """
  7551. def __init__(self, descriptor, method):
  7552. self.method = method
  7553. name = CppKeywords.checkMethodName(IDLToCIdentifier(method.identifier.name))
  7554. args = [Argument('JSContext*', 'cx'),
  7555. Argument('JS::Handle<JSObject*>', 'obj'),
  7556. Argument('%s*' % descriptor.nativeType, 'self'),
  7557. Argument('const JSJitMethodCallArgs&', 'args')]
  7558. CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args)
  7559. def definition_body(self):
  7560. nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
  7561. self.method)
  7562. return CGMethodCall(nativeName, self.method.isStatic(), self.descriptor,
  7563. self.method).define()
  7564. @staticmethod
  7565. def makeNativeName(descriptor, method):
  7566. name = method.identifier.name
  7567. return MakeNativeName(descriptor.binaryNameFor(name))
  7568. class CGMethodPromiseWrapper(CGAbstractStaticMethod):
  7569. """
  7570. A class for generating a wrapper around another method that will
  7571. convert exceptions to promises.
  7572. """
  7573. def __init__(self, descriptor, methodToWrap):
  7574. self.method = methodToWrap
  7575. name = self.makeName(methodToWrap.name)
  7576. args = list(methodToWrap.args)
  7577. CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args)
  7578. def definition_body(self):
  7579. return fill(
  7580. """
  7581. // Make sure to save the callee before someone maybe messes
  7582. // with rval().
  7583. JS::Rooted<JSObject*> callee(cx, &args.callee());
  7584. bool ok = ${methodName}(${args});
  7585. if (ok) {
  7586. return true;
  7587. }
  7588. return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
  7589. args.rval());
  7590. """,
  7591. methodName=self.method.name,
  7592. args=", ".join(arg.name for arg in self.args))
  7593. @staticmethod
  7594. def makeName(methodName):
  7595. return methodName + "_promiseWrapper"
  7596. class CGJsonifierMethod(CGSpecializedMethod):
  7597. def __init__(self, descriptor, method):
  7598. assert method.isJsonifier()
  7599. CGSpecializedMethod.__init__(self, descriptor, method)
  7600. def definition_body(self):
  7601. ret = dedent("""
  7602. JS::Rooted<JSObject*> result(cx, JS_NewPlainObject(cx));
  7603. if (!result) {
  7604. return false;
  7605. }
  7606. """)
  7607. jsonDescriptors = [self.descriptor]
  7608. interface = self.descriptor.interface.parent
  7609. while interface:
  7610. descriptor = self.descriptor.getDescriptor(interface.identifier.name)
  7611. if descriptor.operations['Jsonifier']:
  7612. jsonDescriptors.append(descriptor)
  7613. interface = interface.parent
  7614. # Iterate the array in reverse: oldest ancestor first
  7615. for descriptor in jsonDescriptors[::-1]:
  7616. ret += fill(
  7617. """
  7618. if (!${parentclass}::JsonifyAttributes(cx, obj, self, result)) {
  7619. return false;
  7620. }
  7621. """,
  7622. parentclass=toBindingNamespace(descriptor.name)
  7623. )
  7624. ret += ('args.rval().setObject(*result);\n'
  7625. 'return true;\n')
  7626. return ret
  7627. class CGLegacyCallHook(CGAbstractBindingMethod):
  7628. """
  7629. Call hook for our object
  7630. """
  7631. def __init__(self, descriptor):
  7632. self._legacycaller = descriptor.operations["LegacyCaller"]
  7633. # Our "self" is actually the callee in this case, not the thisval.
  7634. CGAbstractBindingMethod.__init__(
  7635. self, descriptor, LEGACYCALLER_HOOK_NAME,
  7636. JSNativeArguments(), getThisObj="&args.callee()")
  7637. def define(self):
  7638. if not self._legacycaller:
  7639. return ""
  7640. return CGAbstractBindingMethod.define(self)
  7641. def generate_code(self):
  7642. name = self._legacycaller.identifier.name
  7643. nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
  7644. return CGMethodCall(nativeName, False, self.descriptor,
  7645. self._legacycaller)
  7646. class CGResolveHook(CGAbstractClassHook):
  7647. """
  7648. Resolve hook for objects that have the NeedResolve extended attribute.
  7649. """
  7650. def __init__(self, descriptor):
  7651. assert descriptor.interface.getExtendedAttribute("NeedResolve")
  7652. args = [Argument('JSContext*', 'cx'),
  7653. Argument('JS::Handle<JSObject*>', 'obj'),
  7654. Argument('JS::Handle<jsid>', 'id'),
  7655. Argument('bool*', 'resolvedp')]
  7656. CGAbstractClassHook.__init__(self, descriptor, RESOLVE_HOOK_NAME,
  7657. "bool", args)
  7658. def generate_code(self):
  7659. return dedent("""
  7660. JS::Rooted<JS::PropertyDescriptor> desc(cx);
  7661. if (!self->DoResolve(cx, obj, id, &desc)) {
  7662. return false;
  7663. }
  7664. if (!desc.object()) {
  7665. return true;
  7666. }
  7667. // If desc.value() is undefined, then the DoResolve call
  7668. // has already defined it on the object. Don't try to also
  7669. // define it.
  7670. if (!desc.value().isUndefined()) {
  7671. desc.attributesRef() |= JSPROP_RESOLVING;
  7672. if (!JS_DefinePropertyById(cx, obj, id, desc)) {
  7673. return false;
  7674. }
  7675. }
  7676. *resolvedp = true;
  7677. return true;
  7678. """)
  7679. def definition_body(self):
  7680. if self.descriptor.isGlobal():
  7681. # Resolve standard classes
  7682. prefix = dedent("""
  7683. if (!ResolveGlobal(cx, obj, id, resolvedp)) {
  7684. return false;
  7685. }
  7686. if (*resolvedp) {
  7687. return true;
  7688. }
  7689. """)
  7690. else:
  7691. prefix = ""
  7692. return prefix + CGAbstractClassHook.definition_body(self)
  7693. class CGMayResolveHook(CGAbstractStaticMethod):
  7694. """
  7695. Resolve hook for objects that have the NeedResolve extended attribute.
  7696. """
  7697. def __init__(self, descriptor):
  7698. assert descriptor.interface.getExtendedAttribute("NeedResolve")
  7699. args = [Argument('const JSAtomState&', 'names'),
  7700. Argument('jsid', 'id'),
  7701. Argument('JSObject*', 'maybeObj')]
  7702. CGAbstractStaticMethod.__init__(self, descriptor, MAY_RESOLVE_HOOK_NAME,
  7703. "bool", args)
  7704. def definition_body(self):
  7705. if self.descriptor.isGlobal():
  7706. # Check whether this would resolve as a standard class.
  7707. prefix = dedent("""
  7708. if (MayResolveGlobal(names, id, maybeObj)) {
  7709. return true;
  7710. }
  7711. """)
  7712. else:
  7713. prefix = ""
  7714. return (prefix +
  7715. "return %s::MayResolve(id);\n" % self.descriptor.nativeType)
  7716. class CGEnumerateHook(CGAbstractBindingMethod):
  7717. """
  7718. Enumerate hook for objects with custom hooks.
  7719. """
  7720. def __init__(self, descriptor):
  7721. assert descriptor.interface.getExtendedAttribute("NeedResolve")
  7722. args = [Argument('JSContext*', 'cx'),
  7723. Argument('JS::Handle<JSObject*>', 'obj')]
  7724. # Our "self" is actually the "obj" argument in this case, not the thisval.
  7725. CGAbstractBindingMethod.__init__(
  7726. self, descriptor, ENUMERATE_HOOK_NAME,
  7727. args, getThisObj="", callArgs="")
  7728. def generate_code(self):
  7729. return CGGeneric(dedent("""
  7730. AutoTArray<nsString, 8> names;
  7731. binding_detail::FastErrorResult rv;
  7732. self->GetOwnPropertyNames(cx, names, rv);
  7733. if (rv.MaybeSetPendingException(cx)) {
  7734. return false;
  7735. }
  7736. bool dummy;
  7737. for (uint32_t i = 0; i < names.Length(); ++i) {
  7738. if (!JS_HasUCProperty(cx, obj, names[i].get(), names[i].Length(), &dummy)) {
  7739. return false;
  7740. }
  7741. }
  7742. return true;
  7743. """))
  7744. def definition_body(self):
  7745. if self.descriptor.isGlobal():
  7746. # Enumerate standard classes
  7747. prefix = dedent("""
  7748. if (!EnumerateGlobal(cx, obj)) {
  7749. return false;
  7750. }
  7751. """)
  7752. else:
  7753. prefix = ""
  7754. return prefix + CGAbstractBindingMethod.definition_body(self)
  7755. class CppKeywords():
  7756. """
  7757. A class for checking if method names declared in webidl
  7758. are not in conflict with C++ keywords.
  7759. """
  7760. keywords = frozenset([
  7761. 'alignas', 'alignof', 'and', 'and_eq', 'asm', 'assert', 'auto', 'bitand', 'bitor', 'bool',
  7762. 'break', 'case', 'catch', 'char', 'char16_t', 'char32_t', 'class', 'compl', 'const',
  7763. 'constexpr', 'const_cast', 'continue', 'decltype', 'default', 'delete', 'do', 'double',
  7764. 'dynamic_cast', 'else', 'enum', 'explicit', 'export', 'extern', 'false', 'final', 'float',
  7765. 'for', 'friend', 'goto', 'if', 'inline', 'int', 'long', 'mutable', 'namespace', 'new',
  7766. 'noexcept', 'not', 'not_eq', 'nullptr', 'operator', 'or', 'or_eq', 'override', 'private',
  7767. 'protected', 'public', 'register', 'reinterpret_cast', 'return', 'short', 'signed',
  7768. 'sizeof', 'static', 'static_assert', 'static_cast', 'struct', 'switch', 'template', 'this',
  7769. 'thread_local', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'union',
  7770. 'unsigned', 'using', 'virtual', 'void', 'volatile', 'wchar_t', 'while', 'xor', 'xor_eq'])
  7771. @staticmethod
  7772. def checkMethodName(name):
  7773. # Double '_' because 'assert' and '_assert' cannot be used in MS2013 compiler.
  7774. # Bug 964892 and bug 963560.
  7775. if name in CppKeywords.keywords:
  7776. name = '_' + name + '_'
  7777. return name
  7778. class CGStaticMethod(CGAbstractStaticBindingMethod):
  7779. """
  7780. A class for generating the C++ code for an IDL static method.
  7781. """
  7782. def __init__(self, descriptor, method):
  7783. self.method = method
  7784. name = CppKeywords.checkMethodName(IDLToCIdentifier(method.identifier.name))
  7785. CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
  7786. def generate_code(self):
  7787. nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
  7788. self.method)
  7789. return CGMethodCall(nativeName, True, self.descriptor, self.method)
  7790. class CGGenericGetter(CGAbstractBindingMethod):
  7791. """
  7792. A class for generating the C++ code for an IDL attribute getter.
  7793. """
  7794. def __init__(self, descriptor, lenientThis=False, allowCrossOriginThis=False):
  7795. if lenientThis:
  7796. name = "genericLenientGetter"
  7797. unwrapFailureCode = dedent("""
  7798. MOZ_ASSERT(!JS_IsExceptionPending(cx));
  7799. if (!ReportLenientThisUnwrappingFailure(cx, &args.callee())) {
  7800. return false;
  7801. }
  7802. args.rval().set(JS::UndefinedValue());
  7803. return true;
  7804. """)
  7805. else:
  7806. if allowCrossOriginThis:
  7807. name = "genericCrossOriginGetter"
  7808. else:
  7809. name = "genericGetter"
  7810. unwrapFailureCode = (
  7811. 'return ThrowInvalidThis(cx, args, %%(securityError)s, "%s");\n' %
  7812. descriptor.interface.identifier.name)
  7813. CGAbstractBindingMethod.__init__(self, descriptor, name, JSNativeArguments(),
  7814. unwrapFailureCode,
  7815. allowCrossOriginThis=allowCrossOriginThis)
  7816. def generate_code(self):
  7817. return CGGeneric(dedent("""
  7818. const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  7819. MOZ_ASSERT(info->type() == JSJitInfo::Getter);
  7820. JSJitGetterOp getter = info->getter;
  7821. bool ok = getter(cx, obj, self, JSJitGetterCallArgs(args));
  7822. #ifdef DEBUG
  7823. if (ok) {
  7824. AssertReturnTypeMatchesJitinfo(info, args.rval());
  7825. }
  7826. #endif
  7827. return ok;
  7828. """))
  7829. class CGSpecializedGetter(CGAbstractStaticMethod):
  7830. """
  7831. A class for generating the code for a specialized attribute getter
  7832. that the JIT can call with lower overhead.
  7833. """
  7834. def __init__(self, descriptor, attr):
  7835. self.attr = attr
  7836. name = 'get_' + IDLToCIdentifier(attr.identifier.name)
  7837. args = [
  7838. Argument('JSContext*', 'cx'),
  7839. Argument('JS::Handle<JSObject*>', 'obj'),
  7840. Argument('%s*' % descriptor.nativeType, 'self'),
  7841. Argument('JSJitGetterCallArgs', 'args')
  7842. ]
  7843. CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
  7844. def definition_body(self):
  7845. if self.attr.isMaplikeOrSetlikeAttr():
  7846. # If the interface is maplike/setlike, there will be one getter
  7847. # method for the size property of the backing object. Due to having
  7848. # to unpack the backing object from the slot, this requires its own
  7849. # generator.
  7850. return getMaplikeOrSetlikeSizeGetterBody(self.descriptor, self.attr)
  7851. nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
  7852. self.attr)
  7853. if self.attr.slotIndices is not None:
  7854. if self.descriptor.hasXPConnectImpls:
  7855. raise TypeError("Interface '%s' has XPConnect impls, so we "
  7856. "can't use our slot for property '%s'!" %
  7857. (self.descriptor.interface.identifier.name,
  7858. self.attr.identifier.name))
  7859. # We're going to store this return value in a slot on some object,
  7860. # to cache it. The question is, which object? For dictionary and
  7861. # sequence return values, we want to use a slot on the Xray expando
  7862. # if we're called via Xrays, and a slot on our reflector otherwise.
  7863. # On the other hand, when dealing with some interfacce types
  7864. # (navigator properties, window.document) we want to avoid calling
  7865. # the getter more than once. In the case of navigator properties
  7866. # that's because the getter actually creates a new object each time.
  7867. # In the case of window.document, it's because the getter can start
  7868. # returning null, which would get hidden in he non-Xray case by the
  7869. # fact that it's [StoreOnSlot], so the cached version is always
  7870. # around.
  7871. #
  7872. # The upshot is that we use the reflector slot for any getter whose
  7873. # type is a gecko interface, whether we're called via Xrays or not.
  7874. # Since [Cached] and [StoreInSlot] cannot be used with "NewObject",
  7875. # we know that in the interface type case the returned object is
  7876. # wrappercached. So creating Xrays to it is reasonable.
  7877. if mayUseXrayExpandoSlots(self.descriptor, self.attr):
  7878. prefix = fill(
  7879. """
  7880. // Have to either root across the getter call or reget after.
  7881. bool isXray;
  7882. JS::Rooted<JSObject*> slotStorage(cx, GetCachedSlotStorageObject(cx, obj, &isXray));
  7883. if (!slotStorage) {
  7884. return false;
  7885. }
  7886. const size_t slotIndex = isXray ? ${xraySlotIndex} : ${slotIndex};
  7887. """,
  7888. xraySlotIndex=memberXrayExpandoReservedSlot(self.attr,
  7889. self.descriptor),
  7890. slotIndex=memberReservedSlot(self.attr, self.descriptor))
  7891. else:
  7892. prefix = fill(
  7893. """
  7894. // Have to either root across the getter call or reget after.
  7895. JS::Rooted<JSObject*> slotStorage(cx, js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false));
  7896. MOZ_ASSERT(IsDOMObject(slotStorage));
  7897. const size_t slotIndex = ${slotIndex};
  7898. """,
  7899. slotIndex=memberReservedSlot(self.attr, self.descriptor))
  7900. prefix += fill(
  7901. """
  7902. MOZ_ASSERT(JSCLASS_RESERVED_SLOTS(js::GetObjectClass(slotStorage)) > slotIndex);
  7903. {
  7904. // Scope for cachedVal
  7905. JS::Value cachedVal = js::GetReservedSlot(slotStorage, slotIndex);
  7906. if (!cachedVal.isUndefined()) {
  7907. args.rval().set(cachedVal);
  7908. // The cached value is in the compartment of slotStorage,
  7909. // so wrap into the caller compartment as needed.
  7910. return ${maybeWrap}(cx, args.rval());
  7911. }
  7912. }
  7913. """,
  7914. maybeWrap=getMaybeWrapValueFuncForType(self.attr.type))
  7915. else:
  7916. prefix = ""
  7917. if self.attr.navigatorObjectGetter:
  7918. cgGetterCall = CGNavigatorGetterCall
  7919. else:
  7920. cgGetterCall = CGGetterCall
  7921. return (prefix +
  7922. cgGetterCall(self.attr.type, nativeName,
  7923. self.descriptor, self.attr).define())
  7924. @staticmethod
  7925. def makeNativeName(descriptor, attr):
  7926. name = attr.identifier.name
  7927. nativeName = MakeNativeName(descriptor.binaryNameFor(name))
  7928. _, resultOutParam, _, _, _ = getRetvalDeclarationForType(attr.type,
  7929. descriptor)
  7930. infallible = ('infallible' in
  7931. descriptor.getExtendedAttributes(attr, getter=True))
  7932. if resultOutParam or attr.type.nullable() or not infallible:
  7933. nativeName = "Get" + nativeName
  7934. return nativeName
  7935. class CGStaticGetter(CGAbstractStaticBindingMethod):
  7936. """
  7937. A class for generating the C++ code for an IDL static attribute getter.
  7938. """
  7939. def __init__(self, descriptor, attr):
  7940. self.attr = attr
  7941. name = 'get_' + IDLToCIdentifier(attr.identifier.name)
  7942. CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
  7943. def generate_code(self):
  7944. nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
  7945. self.attr)
  7946. return CGGetterCall(self.attr.type, nativeName, self.descriptor,
  7947. self.attr)
  7948. class CGGenericSetter(CGAbstractBindingMethod):
  7949. """
  7950. A class for generating the C++ code for an IDL attribute setter.
  7951. """
  7952. def __init__(self, descriptor, lenientThis=False, allowCrossOriginThis=False):
  7953. if lenientThis:
  7954. name = "genericLenientSetter"
  7955. unwrapFailureCode = dedent("""
  7956. MOZ_ASSERT(!JS_IsExceptionPending(cx));
  7957. if (!ReportLenientThisUnwrappingFailure(cx, &args.callee())) {
  7958. return false;
  7959. }
  7960. args.rval().set(JS::UndefinedValue());
  7961. return true;
  7962. """)
  7963. else:
  7964. if allowCrossOriginThis:
  7965. name = "genericCrossOriginSetter"
  7966. else:
  7967. name = "genericSetter"
  7968. unwrapFailureCode = (
  7969. 'return ThrowInvalidThis(cx, args, %%(securityError)s, "%s");\n' %
  7970. descriptor.interface.identifier.name)
  7971. CGAbstractBindingMethod.__init__(self, descriptor, name, JSNativeArguments(),
  7972. unwrapFailureCode,
  7973. allowCrossOriginThis=allowCrossOriginThis)
  7974. def generate_code(self):
  7975. return CGGeneric(fill(
  7976. """
  7977. if (args.length() == 0) {
  7978. return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${name} attribute setter");
  7979. }
  7980. const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  7981. MOZ_ASSERT(info->type() == JSJitInfo::Setter);
  7982. JSJitSetterOp setter = info->setter;
  7983. if (!setter(cx, obj, self, JSJitSetterCallArgs(args))) {
  7984. return false;
  7985. }
  7986. args.rval().setUndefined();
  7987. #ifdef DEBUG
  7988. AssertReturnTypeMatchesJitinfo(info, args.rval());
  7989. #endif
  7990. return true;
  7991. """,
  7992. name=self.descriptor.interface.identifier.name))
  7993. class CGSpecializedSetter(CGAbstractStaticMethod):
  7994. """
  7995. A class for generating the code for a specialized attribute setter
  7996. that the JIT can call with lower overhead.
  7997. """
  7998. def __init__(self, descriptor, attr):
  7999. self.attr = attr
  8000. name = 'set_' + IDLToCIdentifier(attr.identifier.name)
  8001. args = [Argument('JSContext*', 'cx'),
  8002. Argument('JS::Handle<JSObject*>', 'obj'),
  8003. Argument('%s*' % descriptor.nativeType, 'self'),
  8004. Argument('JSJitSetterCallArgs', 'args')]
  8005. CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
  8006. def definition_body(self):
  8007. nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
  8008. self.attr)
  8009. return CGSetterCall(self.attr.type, nativeName, self.descriptor,
  8010. self.attr).define()
  8011. @staticmethod
  8012. def makeNativeName(descriptor, attr):
  8013. name = attr.identifier.name
  8014. return "Set" + MakeNativeName(descriptor.binaryNameFor(name))
  8015. class CGStaticSetter(CGAbstractStaticBindingMethod):
  8016. """
  8017. A class for generating the C++ code for an IDL static attribute setter.
  8018. """
  8019. def __init__(self, descriptor, attr):
  8020. self.attr = attr
  8021. name = 'set_' + IDLToCIdentifier(attr.identifier.name)
  8022. CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
  8023. def generate_code(self):
  8024. nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
  8025. self.attr)
  8026. checkForArg = CGGeneric(fill(
  8027. """
  8028. if (args.length() == 0) {
  8029. return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${name} setter");
  8030. }
  8031. """,
  8032. name=self.attr.identifier.name))
  8033. call = CGSetterCall(self.attr.type, nativeName, self.descriptor,
  8034. self.attr)
  8035. return CGList([checkForArg, call])
  8036. class CGSpecializedForwardingSetter(CGSpecializedSetter):
  8037. """
  8038. A class for generating the code for a specialized attribute setter with
  8039. PutForwards that the JIT can call with lower overhead.
  8040. """
  8041. def __init__(self, descriptor, attr):
  8042. CGSpecializedSetter.__init__(self, descriptor, attr)
  8043. def definition_body(self):
  8044. attrName = self.attr.identifier.name
  8045. forwardToAttrName = self.attr.getExtendedAttribute("PutForwards")[0]
  8046. # JS_GetProperty and JS_SetProperty can only deal with ASCII
  8047. assert all(ord(c) < 128 for c in attrName)
  8048. assert all(ord(c) < 128 for c in forwardToAttrName)
  8049. return fill(
  8050. """
  8051. JS::Rooted<JS::Value> v(cx);
  8052. if (!JS_GetProperty(cx, obj, "${attr}", &v)) {
  8053. return false;
  8054. }
  8055. if (!v.isObject()) {
  8056. return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "${interface}.${attr}");
  8057. }
  8058. JS::Rooted<JSObject*> targetObj(cx, &v.toObject());
  8059. return JS_SetProperty(cx, targetObj, "${forwardToAttrName}", args[0]);
  8060. """,
  8061. attr=attrName,
  8062. interface=self.descriptor.interface.identifier.name,
  8063. forwardToAttrName=forwardToAttrName)
  8064. class CGSpecializedReplaceableSetter(CGSpecializedSetter):
  8065. """
  8066. A class for generating the code for a specialized attribute setter with
  8067. Replaceable that the JIT can call with lower overhead.
  8068. """
  8069. def __init__(self, descriptor, attr):
  8070. CGSpecializedSetter.__init__(self, descriptor, attr)
  8071. def definition_body(self):
  8072. attrName = self.attr.identifier.name
  8073. # JS_DefineProperty can only deal with ASCII
  8074. assert all(ord(c) < 128 for c in attrName)
  8075. return ('return JS_DefineProperty(cx, obj, "%s", args[0], JSPROP_ENUMERATE);\n' %
  8076. attrName)
  8077. class CGSpecializedLenientSetter(CGSpecializedSetter):
  8078. """
  8079. A class for generating the code for a specialized attribute setter with
  8080. LenientSetter that the JIT can call with lower overhead.
  8081. """
  8082. def __init__(self, descriptor, attr):
  8083. CGSpecializedSetter.__init__(self, descriptor, attr)
  8084. def definition_body(self):
  8085. attrName = self.attr.identifier.name
  8086. # JS_DefineProperty can only deal with ASCII
  8087. assert all(ord(c) < 128 for c in attrName)
  8088. return dedent("""
  8089. DeprecationWarning(cx, obj, nsIDocument::eLenientSetter);
  8090. return true;
  8091. """)
  8092. def memberReturnsNewObject(member):
  8093. return member.getExtendedAttribute("NewObject") is not None
  8094. class CGMemberJITInfo(CGThing):
  8095. """
  8096. A class for generating the JITInfo for a property that points to
  8097. our specialized getter and setter.
  8098. """
  8099. def __init__(self, descriptor, member):
  8100. self.member = member
  8101. self.descriptor = descriptor
  8102. def declare(self):
  8103. return ""
  8104. def defineJitInfo(self, infoName, opName, opType, infallible, movable,
  8105. eliminatable, aliasSet, alwaysInSlot, lazilyInSlot,
  8106. slotIndex, returnTypes, args):
  8107. """
  8108. aliasSet is a JSJitInfo::AliasSet value, without the "JSJitInfo::" bit.
  8109. args is None if we don't want to output argTypes for some
  8110. reason (e.g. we have overloads or we're not a method) and
  8111. otherwise an iterable of the arguments for this method.
  8112. """
  8113. assert(not movable or aliasSet != "AliasEverything") # Can't move write-aliasing things
  8114. assert(not alwaysInSlot or movable) # Things always in slots had better be movable
  8115. assert(not eliminatable or aliasSet != "AliasEverything") # Can't eliminate write-aliasing things
  8116. assert(not alwaysInSlot or eliminatable) # Things always in slots had better be eliminatable
  8117. def jitInfoInitializer(isTypedMethod):
  8118. initializer = fill(
  8119. """
  8120. {
  8121. { ${opName} },
  8122. { prototypes::id::${name} },
  8123. { PrototypeTraits<prototypes::id::${name}>::Depth },
  8124. JSJitInfo::${opType},
  8125. JSJitInfo::${aliasSet}, /* aliasSet. Not relevant for setters. */
  8126. ${returnType}, /* returnType. Not relevant for setters. */
  8127. ${isInfallible}, /* isInfallible. False in setters. */
  8128. ${isMovable}, /* isMovable. Not relevant for setters. */
  8129. ${isEliminatable}, /* isEliminatable. Not relevant for setters. */
  8130. ${isAlwaysInSlot}, /* isAlwaysInSlot. Only relevant for getters. */
  8131. ${isLazilyCachedInSlot}, /* isLazilyCachedInSlot. Only relevant for getters. */
  8132. ${isTypedMethod}, /* isTypedMethod. Only relevant for methods. */
  8133. ${slotIndex} /* Reserved slot index, if we're stored in a slot, else 0. */
  8134. }
  8135. """,
  8136. opName=opName,
  8137. name=self.descriptor.name,
  8138. opType=opType,
  8139. aliasSet=aliasSet,
  8140. returnType=reduce(CGMemberJITInfo.getSingleReturnType, returnTypes,
  8141. ""),
  8142. isInfallible=toStringBool(infallible),
  8143. isMovable=toStringBool(movable),
  8144. isEliminatable=toStringBool(eliminatable),
  8145. isAlwaysInSlot=toStringBool(alwaysInSlot),
  8146. isLazilyCachedInSlot=toStringBool(lazilyInSlot),
  8147. isTypedMethod=toStringBool(isTypedMethod),
  8148. slotIndex=slotIndex)
  8149. return initializer.rstrip()
  8150. slotAssert = fill(
  8151. """
  8152. static_assert(${slotIndex} <= JSJitInfo::maxSlotIndex, "We won't fit");
  8153. static_assert(${slotIndex} < ${classReservedSlots}, "There is no slot for us");
  8154. """,
  8155. slotIndex=slotIndex,
  8156. classReservedSlots=INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots)
  8157. if args is not None:
  8158. argTypes = "%s_argTypes" % infoName
  8159. args = [CGMemberJITInfo.getJSArgType(arg.type) for arg in args]
  8160. args.append("JSJitInfo::ArgTypeListEnd")
  8161. argTypesDecl = (
  8162. "static const JSJitInfo::ArgType %s[] = { %s };\n" %
  8163. (argTypes, ", ".join(args)))
  8164. return fill(
  8165. """
  8166. $*{argTypesDecl}
  8167. static const JSTypedMethodJitInfo ${infoName} = {
  8168. ${jitInfo},
  8169. ${argTypes}
  8170. };
  8171. $*{slotAssert}
  8172. """,
  8173. argTypesDecl=argTypesDecl,
  8174. infoName=infoName,
  8175. jitInfo=indent(jitInfoInitializer(True)),
  8176. argTypes=argTypes,
  8177. slotAssert=slotAssert)
  8178. return fill(
  8179. """
  8180. static const JSJitInfo ${infoName} = ${jitInfo};
  8181. $*{slotAssert}
  8182. """,
  8183. infoName=infoName,
  8184. jitInfo=jitInfoInitializer(False),
  8185. slotAssert=slotAssert)
  8186. def define(self):
  8187. if self.member.isAttr():
  8188. getterinfo = ("%s_getterinfo" %
  8189. IDLToCIdentifier(self.member.identifier.name))
  8190. # We need the cast here because JSJitGetterOp has a "void* self"
  8191. # while we have the right type.
  8192. getter = ("(JSJitGetterOp)get_%s" %
  8193. IDLToCIdentifier(self.member.identifier.name))
  8194. getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True)
  8195. movable = self.mayBeMovable() and getterinfal
  8196. eliminatable = self.mayBeEliminatable() and getterinfal
  8197. aliasSet = self.aliasSet()
  8198. getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
  8199. isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot")
  8200. if self.member.slotIndices is not None:
  8201. assert isAlwaysInSlot or self.member.getExtendedAttribute("Cached")
  8202. isLazilyCachedInSlot = not isAlwaysInSlot
  8203. slotIndex = memberReservedSlot(self.member, self.descriptor)
  8204. # We'll statically assert that this is not too big in
  8205. # CGUpdateMemberSlotsMethod, in the case when
  8206. # isAlwaysInSlot is true.
  8207. else:
  8208. isLazilyCachedInSlot = False
  8209. slotIndex = "0"
  8210. result = self.defineJitInfo(getterinfo, getter, "Getter",
  8211. getterinfal, movable, eliminatable,
  8212. aliasSet, isAlwaysInSlot,
  8213. isLazilyCachedInSlot, slotIndex,
  8214. [self.member.type], None)
  8215. if (not self.member.readonly or
  8216. self.member.getExtendedAttribute("PutForwards") is not None or
  8217. self.member.getExtendedAttribute("Replaceable") is not None or
  8218. self.member.getExtendedAttribute("LenientSetter") is not None):
  8219. setterinfo = ("%s_setterinfo" %
  8220. IDLToCIdentifier(self.member.identifier.name))
  8221. # Actually a JSJitSetterOp, but JSJitGetterOp is first in the
  8222. # union.
  8223. setter = ("(JSJitGetterOp)set_%s" %
  8224. IDLToCIdentifier(self.member.identifier.name))
  8225. # Setters are always fallible, since they have to do a typed unwrap.
  8226. result += self.defineJitInfo(setterinfo, setter, "Setter",
  8227. False, False, False, "AliasEverything",
  8228. False, False, "0",
  8229. [BuiltinTypes[IDLBuiltinType.Types.void]],
  8230. None)
  8231. return result
  8232. if self.member.isMethod():
  8233. methodinfo = ("%s_methodinfo" %
  8234. IDLToCIdentifier(self.member.identifier.name))
  8235. name = CppKeywords.checkMethodName(
  8236. IDLToCIdentifier(self.member.identifier.name))
  8237. if self.member.returnsPromise():
  8238. name = CGMethodPromiseWrapper.makeName(name)
  8239. # Actually a JSJitMethodOp, but JSJitGetterOp is first in the union.
  8240. method = ("(JSJitGetterOp)%s" % name)
  8241. # Methods are infallible if they are infallible, have no arguments
  8242. # to unwrap, and have a return type that's infallible to wrap up for
  8243. # return.
  8244. sigs = self.member.signatures()
  8245. if len(sigs) != 1:
  8246. # Don't handle overloading. If there's more than one signature,
  8247. # one of them must take arguments.
  8248. methodInfal = False
  8249. args = None
  8250. movable = False
  8251. eliminatable = False
  8252. else:
  8253. sig = sigs[0]
  8254. # For methods that affect nothing, it's OK to set movable to our
  8255. # notion of infallible on the C++ side, without considering
  8256. # argument conversions, since argument conversions that can
  8257. # reliably throw would be effectful anyway and the jit doesn't
  8258. # move effectful things.
  8259. hasInfallibleImpl = "infallible" in self.descriptor.getExtendedAttributes(self.member)
  8260. movable = self.mayBeMovable() and hasInfallibleImpl
  8261. eliminatable = self.mayBeEliminatable() and hasInfallibleImpl
  8262. # XXXbz can we move the smarts about fallibility due to arg
  8263. # conversions into the JIT, using our new args stuff?
  8264. if (len(sig[1]) != 0 or
  8265. not infallibleForMember(self.member, sig[0], self.descriptor)):
  8266. # We have arguments or our return-value boxing can fail
  8267. methodInfal = False
  8268. else:
  8269. methodInfal = hasInfallibleImpl
  8270. # For now, only bother to output args if we're side-effect-free.
  8271. if self.member.affects == "Nothing":
  8272. args = sig[1]
  8273. else:
  8274. args = None
  8275. aliasSet = self.aliasSet()
  8276. result = self.defineJitInfo(methodinfo, method, "Method",
  8277. methodInfal, movable, eliminatable,
  8278. aliasSet, False, False, "0",
  8279. [s[0] for s in sigs], args)
  8280. return result
  8281. raise TypeError("Illegal member type to CGPropertyJITInfo")
  8282. def mayBeMovable(self):
  8283. """
  8284. Returns whether this attribute or method may be movable, just
  8285. based on Affects/DependsOn annotations.
  8286. """
  8287. affects = self.member.affects
  8288. dependsOn = self.member.dependsOn
  8289. assert affects in IDLInterfaceMember.AffectsValues
  8290. assert dependsOn in IDLInterfaceMember.DependsOnValues
  8291. # Things that are DependsOn=DeviceState are not movable, because we
  8292. # don't want them coalesced with each other or loop-hoisted, since
  8293. # their return value can change even if nothing is going on from our
  8294. # point of view.
  8295. return (affects == "Nothing" and
  8296. (dependsOn != "Everything" and dependsOn != "DeviceState"))
  8297. def mayBeEliminatable(self):
  8298. """
  8299. Returns whether this attribute or method may be eliminatable, just
  8300. based on Affects/DependsOn annotations.
  8301. """
  8302. # dependsOn shouldn't affect this decision at all, except in jitinfo we
  8303. # have no way to express "Depends on everything, affects nothing",
  8304. # because we only have three alias set values: AliasNone ("depends on
  8305. # nothing, affects nothing"), AliasDOMSets ("depends on DOM sets,
  8306. # affects nothing"), AliasEverything ("depends on everything, affects
  8307. # everything"). So the [Affects=Nothing, DependsOn=Everything] case
  8308. # gets encoded as AliasEverything and defineJitInfo asserts that if our
  8309. # alias state is AliasEverything then we're not eliminatable (because it
  8310. # thinks we might have side-effects at that point). Bug 1155796 is
  8311. # tracking possible solutions for this.
  8312. affects = self.member.affects
  8313. dependsOn = self.member.dependsOn
  8314. assert affects in IDLInterfaceMember.AffectsValues
  8315. assert dependsOn in IDLInterfaceMember.DependsOnValues
  8316. return affects == "Nothing" and dependsOn != "Everything"
  8317. def aliasSet(self):
  8318. """
  8319. Returns the alias set to store in the jitinfo. This may not be the
  8320. effective alias set the JIT uses, depending on whether we have enough
  8321. information about our args to allow the JIT to prove that effectful
  8322. argument conversions won't happen.
  8323. """
  8324. dependsOn = self.member.dependsOn
  8325. assert dependsOn in IDLInterfaceMember.DependsOnValues
  8326. if dependsOn == "Nothing" or dependsOn == "DeviceState":
  8327. assert self.member.affects == "Nothing"
  8328. return "AliasNone"
  8329. if dependsOn == "DOMState":
  8330. assert self.member.affects == "Nothing"
  8331. return "AliasDOMSets"
  8332. return "AliasEverything"
  8333. @staticmethod
  8334. def getJSReturnTypeTag(t):
  8335. if t.nullable():
  8336. # Sometimes it might return null, sometimes not
  8337. return "JSVAL_TYPE_UNKNOWN"
  8338. if t.isVoid():
  8339. # No return, every time
  8340. return "JSVAL_TYPE_UNDEFINED"
  8341. if t.isSequence():
  8342. return "JSVAL_TYPE_OBJECT"
  8343. if t.isRecord():
  8344. return "JSVAL_TYPE_OBJECT"
  8345. if t.isPromise():
  8346. return "JSVAL_TYPE_OBJECT"
  8347. if t.isGeckoInterface():
  8348. return "JSVAL_TYPE_OBJECT"
  8349. if t.isString():
  8350. return "JSVAL_TYPE_STRING"
  8351. if t.isEnum():
  8352. return "JSVAL_TYPE_STRING"
  8353. if t.isCallback():
  8354. return "JSVAL_TYPE_OBJECT"
  8355. if t.isAny():
  8356. # The whole point is to return various stuff
  8357. return "JSVAL_TYPE_UNKNOWN"
  8358. if t.isObject():
  8359. return "JSVAL_TYPE_OBJECT"
  8360. if t.isSpiderMonkeyInterface():
  8361. return "JSVAL_TYPE_OBJECT"
  8362. if t.isUnion():
  8363. u = t.unroll()
  8364. if u.hasNullableType:
  8365. # Might be null or not
  8366. return "JSVAL_TYPE_UNKNOWN"
  8367. return reduce(CGMemberJITInfo.getSingleReturnType,
  8368. u.flatMemberTypes, "")
  8369. if t.isDictionary():
  8370. return "JSVAL_TYPE_OBJECT"
  8371. if t.isDate():
  8372. return "JSVAL_TYPE_OBJECT"
  8373. if not t.isPrimitive():
  8374. raise TypeError("No idea what type " + str(t) + " is.")
  8375. tag = t.tag()
  8376. if tag == IDLType.Tags.bool:
  8377. return "JSVAL_TYPE_BOOLEAN"
  8378. if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
  8379. IDLType.Tags.int16, IDLType.Tags.uint16,
  8380. IDLType.Tags.int32]:
  8381. return "JSVAL_TYPE_INT32"
  8382. if tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
  8383. IDLType.Tags.unrestricted_float, IDLType.Tags.float,
  8384. IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
  8385. # These all use JS_NumberValue, which can return int or double.
  8386. # But TI treats "double" as meaning "int or double", so we're
  8387. # good to return JSVAL_TYPE_DOUBLE here.
  8388. return "JSVAL_TYPE_DOUBLE"
  8389. if tag != IDLType.Tags.uint32:
  8390. raise TypeError("No idea what type " + str(t) + " is.")
  8391. # uint32 is sometimes int and sometimes double.
  8392. return "JSVAL_TYPE_DOUBLE"
  8393. @staticmethod
  8394. def getSingleReturnType(existingType, t):
  8395. type = CGMemberJITInfo.getJSReturnTypeTag(t)
  8396. if existingType == "":
  8397. # First element of the list; just return its type
  8398. return type
  8399. if type == existingType:
  8400. return existingType
  8401. if ((type == "JSVAL_TYPE_DOUBLE" and
  8402. existingType == "JSVAL_TYPE_INT32") or
  8403. (existingType == "JSVAL_TYPE_DOUBLE" and
  8404. type == "JSVAL_TYPE_INT32")):
  8405. # Promote INT32 to DOUBLE as needed
  8406. return "JSVAL_TYPE_DOUBLE"
  8407. # Different types
  8408. return "JSVAL_TYPE_UNKNOWN"
  8409. @staticmethod
  8410. def getJSArgType(t):
  8411. assert not t.isVoid()
  8412. if t.nullable():
  8413. # Sometimes it might return null, sometimes not
  8414. return "JSJitInfo::ArgType(JSJitInfo::Null | %s)" % CGMemberJITInfo.getJSArgType(t.inner)
  8415. if t.isSequence():
  8416. return "JSJitInfo::Object"
  8417. if t.isPromise():
  8418. return "JSJitInfo::Object"
  8419. if t.isGeckoInterface():
  8420. return "JSJitInfo::Object"
  8421. if t.isString():
  8422. return "JSJitInfo::String"
  8423. if t.isEnum():
  8424. return "JSJitInfo::String"
  8425. if t.isCallback():
  8426. return "JSJitInfo::Object"
  8427. if t.isAny():
  8428. # The whole point is to return various stuff
  8429. return "JSJitInfo::Any"
  8430. if t.isObject():
  8431. return "JSJitInfo::Object"
  8432. if t.isSpiderMonkeyInterface():
  8433. return "JSJitInfo::Object"
  8434. if t.isUnion():
  8435. u = t.unroll()
  8436. type = "JSJitInfo::Null" if u.hasNullableType else ""
  8437. return ("JSJitInfo::ArgType(%s)" %
  8438. reduce(CGMemberJITInfo.getSingleArgType,
  8439. u.flatMemberTypes, type))
  8440. if t.isDictionary():
  8441. return "JSJitInfo::Object"
  8442. if t.isDate():
  8443. return "JSJitInfo::Object"
  8444. if not t.isPrimitive():
  8445. raise TypeError("No idea what type " + str(t) + " is.")
  8446. tag = t.tag()
  8447. if tag == IDLType.Tags.bool:
  8448. return "JSJitInfo::Boolean"
  8449. if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
  8450. IDLType.Tags.int16, IDLType.Tags.uint16,
  8451. IDLType.Tags.int32]:
  8452. return "JSJitInfo::Integer"
  8453. if tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
  8454. IDLType.Tags.unrestricted_float, IDLType.Tags.float,
  8455. IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
  8456. # These all use JS_NumberValue, which can return int or double.
  8457. # But TI treats "double" as meaning "int or double", so we're
  8458. # good to return JSVAL_TYPE_DOUBLE here.
  8459. return "JSJitInfo::Double"
  8460. if tag != IDLType.Tags.uint32:
  8461. raise TypeError("No idea what type " + str(t) + " is.")
  8462. # uint32 is sometimes int and sometimes double.
  8463. return "JSJitInfo::Double"
  8464. @staticmethod
  8465. def getSingleArgType(existingType, t):
  8466. type = CGMemberJITInfo.getJSArgType(t)
  8467. if existingType == "":
  8468. # First element of the list; just return its type
  8469. return type
  8470. if type == existingType:
  8471. return existingType
  8472. return "%s | %s" % (existingType, type)
  8473. class CGStaticMethodJitinfo(CGGeneric):
  8474. """
  8475. A class for generating the JITInfo for a promise-returning static method.
  8476. """
  8477. def __init__(self, method):
  8478. CGGeneric.__init__(
  8479. self,
  8480. "\n"
  8481. "static const JSJitInfo %s_methodinfo = {\n"
  8482. " { (JSJitGetterOp)%s },\n"
  8483. " { prototypes::id::_ID_Count }, { 0 }, JSJitInfo::StaticMethod,\n"
  8484. " JSJitInfo::AliasEverything, JSVAL_TYPE_MISSING, false, false,\n"
  8485. " false, false, 0\n"
  8486. "};\n" %
  8487. (IDLToCIdentifier(method.identifier.name),
  8488. CppKeywords.checkMethodName(
  8489. IDLToCIdentifier(method.identifier.name))))
  8490. def getEnumValueName(value):
  8491. # Some enum values can be empty strings. Others might have weird
  8492. # characters in them. Deal with the former by returning "_empty",
  8493. # deal with possible name collisions from that by throwing if the
  8494. # enum value is actually "_empty", and throw on any value
  8495. # containing non-ASCII chars for now. Replace all chars other than
  8496. # [0-9A-Za-z_] with '_'.
  8497. if re.match("[^\x20-\x7E]", value):
  8498. raise SyntaxError('Enum value "' + value + '" contains non-ASCII characters')
  8499. if re.match("^[0-9]", value):
  8500. return '_' + value
  8501. value = re.sub(r'[^0-9A-Za-z_]', '_', value)
  8502. if re.match("^_[A-Z]|__", value):
  8503. raise SyntaxError('Enum value "' + value + '" is reserved by the C++ spec')
  8504. if value == "_empty":
  8505. raise SyntaxError('"_empty" is not an IDL enum value we support yet')
  8506. if value == "":
  8507. return "_empty"
  8508. nativeName = MakeNativeName(value)
  8509. if nativeName == "EndGuard_":
  8510. raise SyntaxError('Enum value "' + value + '" cannot be used because it'
  8511. ' collides with our internal EndGuard_ value. Please'
  8512. ' rename our internal EndGuard_ to something else')
  8513. return nativeName
  8514. class CGEnumToJSValue(CGAbstractMethod):
  8515. def __init__(self, enum):
  8516. enumType = enum.identifier.name
  8517. self.stringsArray = enumType + "Values::" + ENUM_ENTRY_VARIABLE_NAME
  8518. CGAbstractMethod.__init__(self, None, "ToJSValue", "bool",
  8519. [Argument("JSContext*", "aCx"),
  8520. Argument(enumType, "aArgument"),
  8521. Argument("JS::MutableHandle<JS::Value>",
  8522. "aValue")])
  8523. def definition_body(self):
  8524. return fill(
  8525. """
  8526. MOZ_ASSERT(uint32_t(aArgument) < ArrayLength(${strings}));
  8527. JSString* resultStr =
  8528. JS_NewStringCopyN(aCx, ${strings}[uint32_t(aArgument)].value,
  8529. ${strings}[uint32_t(aArgument)].length);
  8530. if (!resultStr) {
  8531. return false;
  8532. }
  8533. aValue.setString(resultStr);
  8534. return true;
  8535. """,
  8536. strings=self.stringsArray)
  8537. class CGEnum(CGThing):
  8538. def __init__(self, enum):
  8539. CGThing.__init__(self)
  8540. self.enum = enum
  8541. strings = CGNamespace(
  8542. self.stringsNamespace(),
  8543. CGGeneric(declare=("extern const EnumEntry %s[%d];\n" %
  8544. (ENUM_ENTRY_VARIABLE_NAME, self.nEnumStrings())),
  8545. define=fill(
  8546. """
  8547. extern const EnumEntry ${name}[${count}] = {
  8548. $*{entries}
  8549. { nullptr, 0 }
  8550. };
  8551. """,
  8552. name=ENUM_ENTRY_VARIABLE_NAME,
  8553. count=self.nEnumStrings(),
  8554. entries=''.join('{"%s", %d},\n' % (val, len(val))
  8555. for val in self.enum.values()))))
  8556. toJSValue = CGEnumToJSValue(enum)
  8557. self.cgThings = CGList([strings, toJSValue], "\n")
  8558. def stringsNamespace(self):
  8559. return self.enum.identifier.name + "Values"
  8560. def nEnumStrings(self):
  8561. return len(self.enum.values()) + 1
  8562. def declare(self):
  8563. decl = fill(
  8564. """
  8565. enum class ${name} : uint32_t {
  8566. $*{enums}
  8567. EndGuard_
  8568. };
  8569. """,
  8570. name=self.enum.identifier.name,
  8571. enums=",\n".join(map(getEnumValueName, self.enum.values())) + ",\n")
  8572. strings = CGNamespace(self.stringsNamespace(),
  8573. CGGeneric(declare="extern const EnumEntry %s[%d];\n"
  8574. % (ENUM_ENTRY_VARIABLE_NAME, self.nEnumStrings())))
  8575. return decl + "\n" + self.cgThings.declare()
  8576. def define(self):
  8577. return self.cgThings.define()
  8578. def deps(self):
  8579. return self.enum.getDeps()
  8580. def getUnionAccessorSignatureType(type, descriptorProvider):
  8581. """
  8582. Returns the types that are used in the getter and setter signatures for
  8583. union types
  8584. """
  8585. # Flat member types have already unwrapped nullables.
  8586. assert not type.nullable()
  8587. # Promise types can never appear in unions, because Promise is not
  8588. # distinguishable from anything.
  8589. assert not type.isPromise()
  8590. if type.isSequence() or type.isRecord():
  8591. if type.isSequence():
  8592. wrapperType = "Sequence"
  8593. else:
  8594. wrapperType = "Record"
  8595. # We don't use the returned template here, so it's OK to just pass no
  8596. # sourceDescription.
  8597. elementInfo = getJSToNativeConversionInfo(type.inner,
  8598. descriptorProvider,
  8599. isMember=wrapperType)
  8600. if wrapperType == "Sequence":
  8601. innerType = elementInfo.declType
  8602. else:
  8603. innerType = [recordKeyDeclType(type), elementInfo.declType]
  8604. return CGTemplatedType(wrapperType, innerType,
  8605. isConst=True, isReference=True)
  8606. # Nested unions are unwrapped automatically into our flatMemberTypes.
  8607. assert not type.isUnion()
  8608. if type.isGeckoInterface():
  8609. descriptor = descriptorProvider.getDescriptor(
  8610. type.unroll().inner.identifier.name)
  8611. typeName = CGGeneric(descriptor.nativeType)
  8612. # Allow null pointers for old-binding classes.
  8613. if type.unroll().inner.isExternal():
  8614. typeName = CGWrapper(typeName, post="*")
  8615. else:
  8616. typeName = CGWrapper(typeName, post="&")
  8617. return typeName
  8618. if type.isSpiderMonkeyInterface():
  8619. typeName = CGGeneric(type.name)
  8620. return CGWrapper(typeName, post=" const &")
  8621. if type.isDOMString() or type.isUSVString():
  8622. return CGGeneric("const nsAString&")
  8623. if type.isByteString():
  8624. return CGGeneric("const nsCString&")
  8625. if type.isEnum():
  8626. return CGGeneric(type.inner.identifier.name)
  8627. if type.isCallback():
  8628. return CGGeneric("%s&" % type.unroll().callback.identifier.name)
  8629. if type.isAny():
  8630. return CGGeneric("JS::Value")
  8631. if type.isObject():
  8632. return CGGeneric("JSObject*")
  8633. if type.isDictionary():
  8634. return CGGeneric("const %s&" % type.inner.identifier.name)
  8635. if not type.isPrimitive():
  8636. raise TypeError("Need native type for argument type '%s'" % str(type))
  8637. return CGGeneric(builtinNames[type.tag()])
  8638. def getUnionTypeTemplateVars(unionType, type, descriptorProvider,
  8639. ownsMembers=False):
  8640. name = getUnionMemberName(type)
  8641. holderName = "m" + name + "Holder"
  8642. # By the time tryNextCode is invoked, we're guaranteed the union has been
  8643. # constructed as some type, since we've been trying to convert into the
  8644. # corresponding member.
  8645. prefix = "" if ownsMembers else "mUnion."
  8646. tryNextCode = ("$*{destroyHolder}\n"
  8647. "%sDestroy%s();\n"
  8648. "tryNext = true;\n"
  8649. "return true;\n" % (prefix, name))
  8650. conversionInfo = getJSToNativeConversionInfo(
  8651. type, descriptorProvider, failureCode=tryNextCode,
  8652. isDefinitelyObject=not type.isDictionary(),
  8653. isMember=("OwningUnion" if ownsMembers else None),
  8654. sourceDescription="member of %s" % unionType)
  8655. if conversionInfo.holderType is not None:
  8656. assert not ownsMembers
  8657. destroyHolder = "%s.reset();\n" % holderName
  8658. else:
  8659. destroyHolder = ""
  8660. ctorNeedsCx = conversionInfo.declArgs == "cx"
  8661. ctorArgs = "cx" if ctorNeedsCx else ""
  8662. structType = conversionInfo.declType.define()
  8663. externalType = getUnionAccessorSignatureType(type, descriptorProvider).define()
  8664. if type.isObject():
  8665. if ownsMembers:
  8666. body = dedent("""
  8667. MOZ_ASSERT(mType == eUninitialized);
  8668. mValue.mObject.SetValue(obj);
  8669. mType = eObject;
  8670. """)
  8671. else:
  8672. body = dedent("""
  8673. MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);
  8674. mUnion.mValue.mObject.SetValue(cx, obj);
  8675. mUnion.mType = mUnion.eObject;
  8676. """)
  8677. # It's a bit sketchy to do the security check after setting the value,
  8678. # but it keeps the code cleaner and lets us avoid rooting |obj| over the
  8679. # call to CallerSubsumes().
  8680. body = body + dedent("""
  8681. if (passedToJSImpl && !CallerSubsumes(obj)) {
  8682. ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "%s");
  8683. return false;
  8684. }
  8685. return true;
  8686. """)
  8687. setter = ClassMethod("SetToObject", "bool",
  8688. [Argument("JSContext*", "cx"),
  8689. Argument("JSObject*", "obj"),
  8690. Argument("bool", "passedToJSImpl", default="false")],
  8691. inline=True, bodyInHeader=True,
  8692. body=body)
  8693. else:
  8694. # Important: we need to not have our declName involve
  8695. # maybe-GCing operations.
  8696. if conversionInfo.holderType is not None:
  8697. holderArgs = conversionInfo.holderArgs
  8698. if holderArgs is None:
  8699. holderArgs = ""
  8700. initHolder = "%s.emplace(%s);\n" % (holderName, holderArgs)
  8701. else:
  8702. initHolder = ""
  8703. jsConversion = fill(
  8704. initHolder + conversionInfo.template,
  8705. val="value",
  8706. maybeMutableVal="value",
  8707. declName="memberSlot",
  8708. holderName=(holderName if ownsMembers else "%s.ref()" % holderName),
  8709. destroyHolder=destroyHolder,
  8710. passedToJSImpl="passedToJSImpl")
  8711. jsConversion = fill(
  8712. """
  8713. tryNext = false;
  8714. { // scope for memberSlot
  8715. ${structType}& memberSlot = RawSetAs${name}(${ctorArgs});
  8716. $*{jsConversion}
  8717. }
  8718. return true;
  8719. """,
  8720. structType=structType,
  8721. name=name,
  8722. ctorArgs=ctorArgs,
  8723. jsConversion=jsConversion)
  8724. if ownsMembers:
  8725. handleType = "JS::Handle<JS::Value>"
  8726. else:
  8727. handleType = "JS::MutableHandle<JS::Value>"
  8728. setter = ClassMethod("TrySetTo" + name, "bool",
  8729. [Argument("JSContext*", "cx"),
  8730. Argument(handleType, "value"),
  8731. Argument("bool&", "tryNext"),
  8732. Argument("bool", "passedToJSImpl", default="false")],
  8733. inline=not ownsMembers,
  8734. bodyInHeader=not ownsMembers,
  8735. body=jsConversion)
  8736. return {
  8737. "name": name,
  8738. "structType": structType,
  8739. "externalType": externalType,
  8740. "setter": setter,
  8741. "holderType": conversionInfo.holderType.define() if conversionInfo.holderType else None,
  8742. "ctorArgs": ctorArgs,
  8743. "ctorArgList": [Argument("JSContext*", "cx")] if ctorNeedsCx else []
  8744. }
  8745. class CGUnionStruct(CGThing):
  8746. def __init__(self, type, descriptorProvider, ownsMembers=False):
  8747. CGThing.__init__(self)
  8748. self.type = type.unroll()
  8749. self.descriptorProvider = descriptorProvider
  8750. self.ownsMembers = ownsMembers
  8751. self.struct = self.getStruct()
  8752. def declare(self):
  8753. return self.struct.declare()
  8754. def define(self):
  8755. return self.struct.define()
  8756. def deps(self):
  8757. return self.type.getDeps()
  8758. def getStruct(self):
  8759. members = [ClassMember("mType", "Type", body="eUninitialized"),
  8760. ClassMember("mValue", "Value")]
  8761. ctor = ClassConstructor([], bodyInHeader=True, visibility="public",
  8762. explicit=True)
  8763. methods = []
  8764. enumValues = ["eUninitialized"]
  8765. toJSValCases = [CGCase("eUninitialized", CGGeneric("return false;\n"))]
  8766. destructorCases = [CGCase("eUninitialized", None)]
  8767. assignmentCases = [
  8768. CGCase("eUninitialized",
  8769. CGGeneric('MOZ_ASSERT(mType == eUninitialized,\n'
  8770. ' "We need to destroy ourselves?");\n'))]
  8771. traceCases = []
  8772. unionValues = []
  8773. if self.type.hasNullableType:
  8774. enumValues.append("eNull")
  8775. methods.append(ClassMethod("IsNull", "bool", [], const=True, inline=True,
  8776. body="return mType == eNull;\n",
  8777. bodyInHeader=True))
  8778. methods.append(ClassMethod("SetNull", "void", [], inline=True,
  8779. body=("Uninit();\n"
  8780. "mType = eNull;\n"),
  8781. bodyInHeader=True))
  8782. destructorCases.append(CGCase("eNull", None))
  8783. assignmentCases.append(CGCase("eNull",
  8784. CGGeneric("MOZ_ASSERT(mType == eUninitialized);\n"
  8785. "mType = eNull;\n")))
  8786. toJSValCases.append(CGCase("eNull", CGGeneric("rval.setNull();\n"
  8787. "return true;\n")))
  8788. hasObjectType = any(t.isObject() for t in self.type.flatMemberTypes)
  8789. for t in self.type.flatMemberTypes:
  8790. vars = getUnionTypeTemplateVars(self.type,
  8791. t, self.descriptorProvider,
  8792. ownsMembers=self.ownsMembers)
  8793. if vars["name"] != "Object" or self.ownsMembers:
  8794. body = fill(
  8795. """
  8796. if (mType == e${name}) {
  8797. return mValue.m${name}.Value();
  8798. }
  8799. %s
  8800. mType = e${name};
  8801. return mValue.m${name}.SetValue(${ctorArgs});
  8802. """,
  8803. **vars)
  8804. # bodyInHeader must be false for return values because they own
  8805. # their union members and we don't want include headers in
  8806. # UnionTypes.h just to call Addref/Release
  8807. methods.append(ClassMethod(
  8808. "RawSetAs" + vars["name"],
  8809. vars["structType"] + "&",
  8810. vars["ctorArgList"],
  8811. bodyInHeader=not self.ownsMembers,
  8812. body=body % "MOZ_ASSERT(mType == eUninitialized);"))
  8813. uninit = "Uninit();"
  8814. if hasObjectType and not self.ownsMembers:
  8815. uninit = 'MOZ_ASSERT(mType != eObject, "This will not play well with Rooted");\n' + uninit
  8816. methods.append(ClassMethod(
  8817. "SetAs" + vars["name"],
  8818. vars["structType"] + "&",
  8819. vars["ctorArgList"],
  8820. bodyInHeader=not self.ownsMembers,
  8821. body=body % uninit))
  8822. if self.ownsMembers:
  8823. methods.append(vars["setter"])
  8824. # Provide a SetStringData() method to support string defaults.
  8825. if t.isByteString():
  8826. methods.append(
  8827. ClassMethod("SetStringData", "void",
  8828. [Argument("const nsCString::char_type*", "aData"),
  8829. Argument("nsCString::size_type", "aLength")],
  8830. inline=True, bodyInHeader=True,
  8831. body="RawSetAs%s().Assign(aData, aLength);\n" % t.name))
  8832. elif t.isString():
  8833. methods.append(
  8834. ClassMethod("SetStringData", "void",
  8835. [Argument("const nsString::char_type*", "aData"),
  8836. Argument("nsString::size_type", "aLength")],
  8837. inline=True, bodyInHeader=True,
  8838. body="RawSetAs%s().Assign(aData, aLength);\n" % t.name))
  8839. body = fill(
  8840. """
  8841. MOZ_ASSERT(Is${name}(), "Wrong type!");
  8842. mValue.m${name}.Destroy();
  8843. mType = eUninitialized;
  8844. """,
  8845. **vars)
  8846. methods.append(ClassMethod("Destroy" + vars["name"],
  8847. "void",
  8848. [],
  8849. visibility="private",
  8850. bodyInHeader=not self.ownsMembers,
  8851. body=body))
  8852. body = fill("return mType == e${name};\n", **vars)
  8853. methods.append(ClassMethod("Is" + vars["name"],
  8854. "bool",
  8855. [],
  8856. const=True,
  8857. bodyInHeader=True,
  8858. body=body))
  8859. body = fill(
  8860. """
  8861. MOZ_ASSERT(Is${name}(), "Wrong type!");
  8862. return mValue.m${name}.Value();
  8863. """,
  8864. **vars)
  8865. # The non-const version of GetAs* returns our internal type
  8866. getterReturnType = "%s&" % vars["structType"]
  8867. methods.append(ClassMethod("GetAs" + vars["name"],
  8868. getterReturnType,
  8869. [],
  8870. bodyInHeader=True,
  8871. body=body))
  8872. # The const version of GetAs* returns our internal type
  8873. # for owning unions, but our external type for non-owning
  8874. # ones.
  8875. if self.ownsMembers:
  8876. getterReturnType = "%s const &" % vars["structType"]
  8877. else:
  8878. getterReturnType = vars["externalType"]
  8879. methods.append(ClassMethod("GetAs" + vars["name"],
  8880. getterReturnType,
  8881. [],
  8882. const=True,
  8883. bodyInHeader=True,
  8884. body=body))
  8885. unionValues.append(
  8886. fill("UnionMember<${structType} > m${name}", **vars))
  8887. enumValues.append("e" + vars["name"])
  8888. skipToJSVal = False
  8889. try:
  8890. toJSValCases.append(
  8891. CGCase("e" + vars["name"],
  8892. self.getConversionToJS(vars, t)))
  8893. except MethodNotNewObjectError:
  8894. # If we can't have a ToJSVal() because one of our members can
  8895. # only be returned from [NewObject] methods, then just skip
  8896. # generating ToJSVal.
  8897. skipToJSVal = True
  8898. destructorCases.append(
  8899. CGCase("e" + vars["name"],
  8900. CGGeneric("Destroy%s();\n" % vars["name"])))
  8901. assignmentCases.append(
  8902. CGCase("e" + vars["name"],
  8903. CGGeneric("SetAs%s() = aOther.GetAs%s();\n" %
  8904. (vars["name"], vars["name"]))))
  8905. if self.ownsMembers and typeNeedsRooting(t):
  8906. if t.isObject():
  8907. traceCases.append(
  8908. CGCase("e" + vars["name"],
  8909. CGGeneric('JS::UnsafeTraceRoot(trc, %s, "%s");\n' %
  8910. ("&mValue.m" + vars["name"] + ".Value()",
  8911. "mValue.m" + vars["name"]))))
  8912. elif t.isDictionary():
  8913. traceCases.append(
  8914. CGCase("e" + vars["name"],
  8915. CGGeneric("mValue.m%s.Value().TraceDictionary(trc);\n" %
  8916. vars["name"])))
  8917. elif t.isSequence():
  8918. traceCases.append(
  8919. CGCase("e" + vars["name"],
  8920. CGGeneric("DoTraceSequence(trc, mValue.m%s.Value());\n" %
  8921. vars["name"])))
  8922. elif t.isRecord():
  8923. traceCases.append(
  8924. CGCase("e" + vars["name"],
  8925. CGGeneric("TraceRecord(trc, mValue.m%s.Value());\n" %
  8926. vars["name"])))
  8927. else:
  8928. assert t.isSpiderMonkeyInterface()
  8929. traceCases.append(
  8930. CGCase("e" + vars["name"],
  8931. CGGeneric("mValue.m%s.Value().TraceSelf(trc);\n" %
  8932. vars["name"])))
  8933. dtor = CGSwitch("mType", destructorCases).define()
  8934. methods.append(ClassMethod("Uninit", "void", [],
  8935. visibility="public", body=dtor,
  8936. bodyInHeader=not self.ownsMembers,
  8937. inline=not self.ownsMembers))
  8938. if not skipToJSVal:
  8939. methods.append(
  8940. ClassMethod(
  8941. "ToJSVal",
  8942. "bool",
  8943. [
  8944. Argument("JSContext*", "cx"),
  8945. Argument("JS::Handle<JSObject*>", "scopeObj"),
  8946. Argument("JS::MutableHandle<JS::Value>", "rval")
  8947. ],
  8948. body=CGSwitch("mType", toJSValCases,
  8949. default=CGGeneric("return false;\n")).define() + "\nreturn false;\n",
  8950. const=True))
  8951. constructors = [ctor]
  8952. selfName = CGUnionStruct.unionTypeName(self.type, self.ownsMembers)
  8953. if self.ownsMembers:
  8954. if traceCases:
  8955. traceBody = CGSwitch("mType", traceCases,
  8956. default=CGGeneric("")).define()
  8957. else:
  8958. traceBody = ""
  8959. methods.append(ClassMethod("TraceUnion", "void",
  8960. [Argument("JSTracer*", "trc")],
  8961. body=traceBody))
  8962. if CGUnionStruct.isUnionCopyConstructible(self.type):
  8963. constructors.append(
  8964. ClassConstructor(
  8965. [Argument("const %s&" % selfName, "aOther")],
  8966. bodyInHeader=True,
  8967. visibility="public",
  8968. explicit=True,
  8969. body="*this = aOther;\n"))
  8970. methods.append(ClassMethod(
  8971. "operator=", "void",
  8972. [Argument("const %s&" % selfName, "aOther")],
  8973. body=CGSwitch("aOther.mType", assignmentCases).define()))
  8974. disallowCopyConstruction = False
  8975. else:
  8976. disallowCopyConstruction = True
  8977. else:
  8978. disallowCopyConstruction = True
  8979. if self.ownsMembers:
  8980. friend = " friend void ImplCycleCollectionUnlink(%s& aUnion);\n" % CGUnionStruct.unionTypeName(self.type, True)
  8981. else:
  8982. friend = " friend class %sArgument;\n" % str(self.type)
  8983. bases = [ClassBase("AllOwningUnionBase")] if self.ownsMembers else []
  8984. return CGClass(selfName,
  8985. bases=bases,
  8986. members=members,
  8987. constructors=constructors,
  8988. methods=methods,
  8989. disallowCopyConstruction=disallowCopyConstruction,
  8990. extradeclarations=friend,
  8991. destructor=ClassDestructor(visibility="public",
  8992. body="Uninit();\n",
  8993. bodyInHeader=True),
  8994. enums=[ClassEnum("Type", enumValues, visibility="private")],
  8995. unions=[ClassUnion("Value", unionValues, visibility="private")])
  8996. def getConversionToJS(self, templateVars, type):
  8997. assert not type.nullable() # flatMemberTypes never has nullable types
  8998. val = "mValue.m%(name)s.Value()" % templateVars
  8999. wrapCode = wrapForType(
  9000. type, self.descriptorProvider,
  9001. {
  9002. "jsvalRef": "rval",
  9003. "jsvalHandle": "rval",
  9004. "obj": "scopeObj",
  9005. "result": val,
  9006. "typedArraysAreStructs": True
  9007. })
  9008. return CGGeneric(wrapCode)
  9009. @staticmethod
  9010. def isUnionCopyConstructible(type):
  9011. return all(isTypeCopyConstructible(t) for t in type.flatMemberTypes)
  9012. @staticmethod
  9013. def unionTypeName(type, ownsMembers):
  9014. """
  9015. Returns a string name for this known union type.
  9016. """
  9017. assert type.isUnion() and not type.nullable()
  9018. return ("Owning" if ownsMembers else "") + type.name
  9019. @staticmethod
  9020. def unionTypeDecl(type, ownsMembers):
  9021. """
  9022. Returns a string for declaring this possibly-nullable union type.
  9023. """
  9024. assert type.isUnion()
  9025. nullable = type.nullable()
  9026. if nullable:
  9027. type = type.inner
  9028. decl = CGGeneric(CGUnionStruct.unionTypeName(type, ownsMembers))
  9029. if nullable:
  9030. decl = CGTemplatedType("Nullable", decl)
  9031. return decl.define()
  9032. class CGUnionConversionStruct(CGThing):
  9033. def __init__(self, type, descriptorProvider):
  9034. CGThing.__init__(self)
  9035. self.type = type.unroll()
  9036. self.descriptorProvider = descriptorProvider
  9037. def declare(self):
  9038. structName = str(self.type)
  9039. members = [ClassMember("mUnion", structName + "&",
  9040. body="const_cast<%s&>(aUnion)" % structName)]
  9041. # Argument needs to be a const ref because that's all Maybe<> allows
  9042. ctor = ClassConstructor([Argument("const %s&" % structName, "aUnion")],
  9043. bodyInHeader=True,
  9044. visibility="public",
  9045. explicit=True)
  9046. methods = []
  9047. if self.type.hasNullableType:
  9048. methods.append(ClassMethod("SetNull", "bool", [],
  9049. body=("MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);\n"
  9050. "mUnion.mType = mUnion.eNull;\n"
  9051. "return true;\n"),
  9052. inline=True, bodyInHeader=True))
  9053. for t in self.type.flatMemberTypes:
  9054. vars = getUnionTypeTemplateVars(self.type,
  9055. t, self.descriptorProvider)
  9056. methods.append(vars["setter"])
  9057. if vars["name"] != "Object":
  9058. body = fill(
  9059. """
  9060. MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);
  9061. mUnion.mType = mUnion.e${name};
  9062. return mUnion.mValue.m${name}.SetValue(${ctorArgs});
  9063. """,
  9064. **vars)
  9065. methods.append(ClassMethod("RawSetAs" + vars["name"],
  9066. vars["structType"] + "&",
  9067. vars["ctorArgList"],
  9068. bodyInHeader=True,
  9069. body=body,
  9070. visibility="private"))
  9071. # Provide a SetStringData() method to support string defaults.
  9072. if t.isByteString():
  9073. methods.append(
  9074. ClassMethod("SetStringData", "void",
  9075. [Argument("const nsDependentCString::char_type*", "aData"),
  9076. Argument("nsDependentCString::size_type", "aLength")],
  9077. inline=True, bodyInHeader=True,
  9078. body="RawSetAs%s().Rebind(aData, aLength);\n" % t.name))
  9079. elif t.isString():
  9080. methods.append(
  9081. ClassMethod("SetStringData", "void",
  9082. [Argument("const nsDependentString::char_type*", "aData"),
  9083. Argument("nsDependentString::size_type", "aLength")],
  9084. inline=True, bodyInHeader=True,
  9085. body="RawSetAs%s().Rebind(aData, aLength);\n" % t.name))
  9086. if vars["holderType"] is not None:
  9087. holderType = CGTemplatedType("Maybe",
  9088. CGGeneric(vars["holderType"])).define()
  9089. members.append(ClassMember("m%sHolder" % vars["name"],
  9090. holderType))
  9091. return CGClass(structName + "Argument",
  9092. members=members,
  9093. constructors=[ctor],
  9094. methods=methods,
  9095. disallowCopyConstruction=True).declare()
  9096. def define(self):
  9097. return ""
  9098. def deps(self):
  9099. return set()
  9100. class ClassItem:
  9101. """ Use with CGClass """
  9102. def __init__(self, name, visibility):
  9103. self.name = name
  9104. self.visibility = visibility
  9105. def declare(self, cgClass):
  9106. assert False
  9107. def define(self, cgClass):
  9108. assert False
  9109. class ClassBase(ClassItem):
  9110. def __init__(self, name, visibility='public'):
  9111. ClassItem.__init__(self, name, visibility)
  9112. def declare(self, cgClass):
  9113. return '%s %s' % (self.visibility, self.name)
  9114. def define(self, cgClass):
  9115. # Only in the header
  9116. return ''
  9117. class ClassMethod(ClassItem):
  9118. def __init__(self, name, returnType, args, inline=False, static=False,
  9119. virtual=False, const=False, bodyInHeader=False,
  9120. templateArgs=None, visibility='public', body=None,
  9121. breakAfterReturnDecl="\n",
  9122. breakAfterSelf="\n", override=False):
  9123. """
  9124. override indicates whether to flag the method as override
  9125. """
  9126. assert not override or virtual
  9127. assert not (override and static)
  9128. self.returnType = returnType
  9129. self.args = args
  9130. self.inline = inline or bodyInHeader
  9131. self.static = static
  9132. self.virtual = virtual
  9133. self.const = const
  9134. self.bodyInHeader = bodyInHeader
  9135. self.templateArgs = templateArgs
  9136. self.body = body
  9137. self.breakAfterReturnDecl = breakAfterReturnDecl
  9138. self.breakAfterSelf = breakAfterSelf
  9139. self.override = override
  9140. ClassItem.__init__(self, name, visibility)
  9141. def getDecorators(self, declaring):
  9142. decorators = []
  9143. if self.inline:
  9144. decorators.append('inline')
  9145. if declaring:
  9146. if self.static:
  9147. decorators.append('static')
  9148. if self.virtual:
  9149. decorators.append('virtual')
  9150. if decorators:
  9151. return ' '.join(decorators) + ' '
  9152. return ''
  9153. def getBody(self):
  9154. # Override me or pass a string to constructor
  9155. assert self.body is not None
  9156. return self.body
  9157. def declare(self, cgClass):
  9158. templateClause = ('template <%s>\n' % ', '.join(self.templateArgs)
  9159. if self.bodyInHeader and self.templateArgs else '')
  9160. args = ', '.join([a.declare() for a in self.args])
  9161. if self.bodyInHeader:
  9162. body = indent(self.getBody())
  9163. body = '\n{\n' + body + '}\n'
  9164. else:
  9165. body = ';\n'
  9166. return fill(
  9167. "${templateClause}${decorators}${returnType}${breakAfterReturnDecl}"
  9168. "${name}(${args})${const}${override}${body}"
  9169. "${breakAfterSelf}",
  9170. templateClause=templateClause,
  9171. decorators=self.getDecorators(True),
  9172. returnType=self.returnType,
  9173. breakAfterReturnDecl=self.breakAfterReturnDecl,
  9174. name=self.name,
  9175. args=args,
  9176. const=' const' if self.const else '',
  9177. override=' override' if self.override else '',
  9178. body=body,
  9179. breakAfterSelf=self.breakAfterSelf)
  9180. def define(self, cgClass):
  9181. if self.bodyInHeader:
  9182. return ''
  9183. templateArgs = cgClass.templateArgs
  9184. if templateArgs:
  9185. if cgClass.templateSpecialization:
  9186. templateArgs = \
  9187. templateArgs[len(cgClass.templateSpecialization):]
  9188. if templateArgs:
  9189. templateClause = \
  9190. 'template <%s>\n' % ', '.join([str(a) for a in templateArgs])
  9191. else:
  9192. templateClause = ''
  9193. return fill(
  9194. """
  9195. ${templateClause}${decorators}${returnType}
  9196. ${className}::${name}(${args})${const}
  9197. {
  9198. $*{body}
  9199. }
  9200. """,
  9201. templateClause=templateClause,
  9202. decorators=self.getDecorators(False),
  9203. returnType=self.returnType,
  9204. className=cgClass.getNameString(),
  9205. name=self.name,
  9206. args=', '.join([a.define() for a in self.args]),
  9207. const=' const' if self.const else '',
  9208. body=self.getBody())
  9209. class ClassUsingDeclaration(ClassItem):
  9210. """
  9211. Used for importing a name from a base class into a CGClass
  9212. baseClass is the name of the base class to import the name from
  9213. name is the name to import
  9214. visibility determines the visibility of the name (public,
  9215. protected, private), defaults to public.
  9216. """
  9217. def __init__(self, baseClass, name, visibility='public'):
  9218. self.baseClass = baseClass
  9219. ClassItem.__init__(self, name, visibility)
  9220. def declare(self, cgClass):
  9221. return "using %s::%s;\n\n" % (self.baseClass, self.name)
  9222. def define(self, cgClass):
  9223. return ''
  9224. class ClassConstructor(ClassItem):
  9225. """
  9226. Used for adding a constructor to a CGClass.
  9227. args is a list of Argument objects that are the arguments taken by the
  9228. constructor.
  9229. inline should be True if the constructor should be marked inline.
  9230. bodyInHeader should be True if the body should be placed in the class
  9231. declaration in the header.
  9232. visibility determines the visibility of the constructor (public,
  9233. protected, private), defaults to private.
  9234. explicit should be True if the constructor should be marked explicit.
  9235. baseConstructors is a list of strings containing calls to base constructors,
  9236. defaults to None.
  9237. body contains a string with the code for the constructor, defaults to empty.
  9238. """
  9239. def __init__(self, args, inline=False, bodyInHeader=False,
  9240. visibility="private", explicit=False, constexpr=False, baseConstructors=None,
  9241. body=""):
  9242. assert not (inline and constexpr)
  9243. assert not (bodyInHeader and constexpr)
  9244. self.args = args
  9245. self.inline = inline or bodyInHeader
  9246. self.bodyInHeader = bodyInHeader or constexpr
  9247. self.explicit = explicit
  9248. self.constexpr = constexpr
  9249. self.baseConstructors = baseConstructors or []
  9250. self.body = body
  9251. ClassItem.__init__(self, None, visibility)
  9252. def getDecorators(self, declaring):
  9253. decorators = []
  9254. if self.explicit:
  9255. decorators.append('explicit')
  9256. if self.inline and declaring:
  9257. decorators.append('inline')
  9258. if self.constexpr and declaring:
  9259. decorators.append('constexpr')
  9260. if decorators:
  9261. return ' '.join(decorators) + ' '
  9262. return ''
  9263. def getInitializationList(self, cgClass):
  9264. items = [str(c) for c in self.baseConstructors]
  9265. for m in cgClass.members:
  9266. if not m.static:
  9267. initialize = m.body
  9268. if initialize:
  9269. items.append(m.name + "(" + initialize + ")")
  9270. if len(items) > 0:
  9271. return '\n : ' + ',\n '.join(items)
  9272. return ''
  9273. def getBody(self):
  9274. return self.body
  9275. def declare(self, cgClass):
  9276. args = ', '.join([a.declare() for a in self.args])
  9277. if self.bodyInHeader:
  9278. body = self.getInitializationList(cgClass) + '\n{\n' + indent(self.getBody()) + '}\n'
  9279. else:
  9280. body = ';\n'
  9281. return fill(
  9282. "${decorators}${className}(${args})${body}\n",
  9283. decorators=self.getDecorators(True),
  9284. className=cgClass.getNameString(),
  9285. args=args,
  9286. body=body)
  9287. def define(self, cgClass):
  9288. if self.bodyInHeader:
  9289. return ''
  9290. return fill(
  9291. """
  9292. ${decorators}
  9293. ${className}::${className}(${args})${initializationList}
  9294. {
  9295. $*{body}
  9296. }
  9297. """,
  9298. decorators=self.getDecorators(False),
  9299. className=cgClass.getNameString(),
  9300. args=', '.join([a.define() for a in self.args]),
  9301. initializationList=self.getInitializationList(cgClass),
  9302. body=self.getBody())
  9303. class ClassDestructor(ClassItem):
  9304. """
  9305. Used for adding a destructor to a CGClass.
  9306. inline should be True if the destructor should be marked inline.
  9307. bodyInHeader should be True if the body should be placed in the class
  9308. declaration in the header.
  9309. visibility determines the visibility of the destructor (public,
  9310. protected, private), defaults to private.
  9311. body contains a string with the code for the destructor, defaults to empty.
  9312. virtual determines whether the destructor is virtual, defaults to False.
  9313. """
  9314. def __init__(self, inline=False, bodyInHeader=False,
  9315. visibility="private", body='', virtual=False):
  9316. self.inline = inline or bodyInHeader
  9317. self.bodyInHeader = bodyInHeader
  9318. self.body = body
  9319. self.virtual = virtual
  9320. ClassItem.__init__(self, None, visibility)
  9321. def getDecorators(self, declaring):
  9322. decorators = []
  9323. if self.virtual and declaring:
  9324. decorators.append('virtual')
  9325. if self.inline and declaring:
  9326. decorators.append('inline')
  9327. if decorators:
  9328. return ' '.join(decorators) + ' '
  9329. return ''
  9330. def getBody(self):
  9331. return self.body
  9332. def declare(self, cgClass):
  9333. if self.bodyInHeader:
  9334. body = '\n{\n' + indent(self.getBody()) + '}\n'
  9335. else:
  9336. body = ';\n'
  9337. return fill(
  9338. "${decorators}~${className}()${body}\n",
  9339. decorators=self.getDecorators(True),
  9340. className=cgClass.getNameString(),
  9341. body=body)
  9342. def define(self, cgClass):
  9343. if self.bodyInHeader:
  9344. return ''
  9345. return fill(
  9346. """
  9347. ${decorators}
  9348. ${className}::~${className}()
  9349. {
  9350. $*{body}
  9351. }
  9352. """,
  9353. decorators=self.getDecorators(False),
  9354. className=cgClass.getNameString(),
  9355. body=self.getBody())
  9356. class ClassMember(ClassItem):
  9357. def __init__(self, name, type, visibility="private", static=False,
  9358. body=None, hasIgnoreInitCheckFlag=False):
  9359. self.type = type
  9360. self.static = static
  9361. self.body = body
  9362. self.hasIgnoreInitCheckFlag = hasIgnoreInitCheckFlag;
  9363. ClassItem.__init__(self, name, visibility)
  9364. def declare(self, cgClass):
  9365. return '%s%s%s %s;\n' % ('static ' if self.static else '',
  9366. 'MOZ_INIT_OUTSIDE_CTOR '
  9367. if self.hasIgnoreInitCheckFlag else '',
  9368. self.type, self.name)
  9369. def define(self, cgClass):
  9370. if not self.static:
  9371. return ''
  9372. if self.body:
  9373. body = " = " + self.body
  9374. else:
  9375. body = ""
  9376. return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(),
  9377. self.name, body)
  9378. class ClassTypedef(ClassItem):
  9379. def __init__(self, name, type, visibility="public"):
  9380. self.type = type
  9381. ClassItem.__init__(self, name, visibility)
  9382. def declare(self, cgClass):
  9383. return 'typedef %s %s;\n' % (self.type, self.name)
  9384. def define(self, cgClass):
  9385. # Only goes in the header
  9386. return ''
  9387. class ClassEnum(ClassItem):
  9388. def __init__(self, name, entries, values=None, visibility="public"):
  9389. self.entries = entries
  9390. self.values = values
  9391. ClassItem.__init__(self, name, visibility)
  9392. def declare(self, cgClass):
  9393. entries = []
  9394. for i in range(0, len(self.entries)):
  9395. if not self.values or i >= len(self.values):
  9396. entry = '%s' % self.entries[i]
  9397. else:
  9398. entry = '%s = %s' % (self.entries[i], self.values[i])
  9399. entries.append(entry)
  9400. name = '' if not self.name else ' ' + self.name
  9401. return 'enum%s\n{\n%s\n};\n' % (name, indent(',\n'.join(entries)))
  9402. def define(self, cgClass):
  9403. # Only goes in the header
  9404. return ''
  9405. class ClassUnion(ClassItem):
  9406. def __init__(self, name, entries, visibility="public"):
  9407. self.entries = [entry + ";\n" for entry in entries]
  9408. ClassItem.__init__(self, name, visibility)
  9409. def declare(self, cgClass):
  9410. return "union %s\n{\n%s\n};\n" % (self.name, indent(''.join(self.entries)))
  9411. def define(self, cgClass):
  9412. # Only goes in the header
  9413. return ''
  9414. class CGClass(CGThing):
  9415. def __init__(self, name, bases=[], members=[], constructors=[],
  9416. destructor=None, methods=[],
  9417. typedefs=[], enums=[], unions=[], templateArgs=[],
  9418. templateSpecialization=[], isStruct=False,
  9419. disallowCopyConstruction=False, indent='',
  9420. decorators='',
  9421. extradeclarations='',
  9422. extradefinitions=''):
  9423. CGThing.__init__(self)
  9424. self.name = name
  9425. self.bases = bases
  9426. self.members = members
  9427. self.constructors = constructors
  9428. # We store our single destructor in a list, since all of our
  9429. # code wants lists of members.
  9430. self.destructors = [destructor] if destructor else []
  9431. self.methods = methods
  9432. self.typedefs = typedefs
  9433. self.enums = enums
  9434. self.unions = unions
  9435. self.templateArgs = templateArgs
  9436. self.templateSpecialization = templateSpecialization
  9437. self.isStruct = isStruct
  9438. self.disallowCopyConstruction = disallowCopyConstruction
  9439. self.indent = indent
  9440. self.defaultVisibility = 'public' if isStruct else 'private'
  9441. self.decorators = decorators
  9442. self.extradeclarations = extradeclarations
  9443. self.extradefinitions = extradefinitions
  9444. def getNameString(self):
  9445. className = self.name
  9446. if self.templateSpecialization:
  9447. className += '<%s>' % ', '.join([str(a)
  9448. for a in self.templateSpecialization])
  9449. return className
  9450. def declare(self):
  9451. result = ''
  9452. if self.templateArgs:
  9453. templateArgs = [a.declare() for a in self.templateArgs]
  9454. templateArgs = templateArgs[len(self.templateSpecialization):]
  9455. result += ('template <%s>\n' %
  9456. ','.join([str(a) for a in templateArgs]))
  9457. type = 'struct' if self.isStruct else 'class'
  9458. if self.templateSpecialization:
  9459. specialization = \
  9460. '<%s>' % ', '.join([str(a) for a in self.templateSpecialization])
  9461. else:
  9462. specialization = ''
  9463. myself = '%s %s%s' % (type, self.name, specialization)
  9464. if self.decorators != '':
  9465. myself += " " + self.decorators
  9466. result += myself
  9467. if self.bases:
  9468. inherit = ' : '
  9469. result += inherit
  9470. # Grab our first base
  9471. baseItems = [CGGeneric(b.declare(self)) for b in self.bases]
  9472. bases = baseItems[:1]
  9473. # Indent the rest
  9474. bases.extend(CGIndenter(b, len(myself) + len(inherit))
  9475. for b in baseItems[1:])
  9476. result += ",\n".join(b.define() for b in bases)
  9477. result += '\n{\n'
  9478. result += self.extradeclarations
  9479. def declareMembers(cgClass, memberList, defaultVisibility):
  9480. members = {'private': [], 'protected': [], 'public': []}
  9481. for member in memberList:
  9482. members[member.visibility].append(member)
  9483. if defaultVisibility == 'public':
  9484. order = ['public', 'protected', 'private']
  9485. else:
  9486. order = ['private', 'protected', 'public']
  9487. result = ''
  9488. lastVisibility = defaultVisibility
  9489. for visibility in order:
  9490. list = members[visibility]
  9491. if list:
  9492. if visibility != lastVisibility:
  9493. result += visibility + ':\n'
  9494. for member in list:
  9495. result += indent(member.declare(cgClass))
  9496. lastVisibility = visibility
  9497. return (result, lastVisibility)
  9498. if self.disallowCopyConstruction:
  9499. class DisallowedCopyConstructor(object):
  9500. def __init__(self):
  9501. self.visibility = "private"
  9502. def declare(self, cgClass):
  9503. name = cgClass.getNameString()
  9504. return ("%s(const %s&) = delete;\n"
  9505. "void operator=(const %s&) = delete;\n" % (name, name, name))
  9506. disallowedCopyConstructors = [DisallowedCopyConstructor()]
  9507. else:
  9508. disallowedCopyConstructors = []
  9509. order = [self.enums, self.unions,
  9510. self.typedefs, self.members,
  9511. self.constructors + disallowedCopyConstructors,
  9512. self.destructors, self.methods]
  9513. lastVisibility = self.defaultVisibility
  9514. pieces = []
  9515. for memberList in order:
  9516. code, lastVisibility = declareMembers(self, memberList, lastVisibility)
  9517. if code:
  9518. code = code.rstrip() + "\n" # remove extra blank lines at the end
  9519. pieces.append(code)
  9520. result += '\n'.join(pieces)
  9521. result += '};\n'
  9522. result = indent(result, len(self.indent))
  9523. return result
  9524. def define(self):
  9525. def defineMembers(cgClass, memberList, itemCount, separator=''):
  9526. result = ''
  9527. for member in memberList:
  9528. if itemCount != 0:
  9529. result = result + separator
  9530. definition = member.define(cgClass)
  9531. if definition:
  9532. # Member variables would only produce empty lines here.
  9533. result += definition
  9534. itemCount += 1
  9535. return (result, itemCount)
  9536. order = [(self.members, ''), (self.constructors, '\n'),
  9537. (self.destructors, '\n'), (self.methods, '\n')]
  9538. result = self.extradefinitions
  9539. itemCount = 0
  9540. for memberList, separator in order:
  9541. memberString, itemCount = defineMembers(self, memberList,
  9542. itemCount, separator)
  9543. result = result + memberString
  9544. return result
  9545. class CGResolveOwnProperty(CGAbstractStaticMethod):
  9546. def __init__(self, descriptor):
  9547. args = [Argument('JSContext*', 'cx'),
  9548. Argument('JS::Handle<JSObject*>', 'wrapper'),
  9549. Argument('JS::Handle<JSObject*>', 'obj'),
  9550. Argument('JS::Handle<jsid>', 'id'),
  9551. Argument('JS::MutableHandle<JS::PropertyDescriptor>', 'desc'),
  9552. ]
  9553. CGAbstractStaticMethod.__init__(self, descriptor, "ResolveOwnProperty",
  9554. "bool", args)
  9555. def definition_body(self):
  9556. return "return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, desc);\n"
  9557. class CGResolveOwnPropertyViaResolve(CGAbstractBindingMethod):
  9558. """
  9559. An implementation of Xray ResolveOwnProperty stuff for things that have a
  9560. resolve hook.
  9561. """
  9562. def __init__(self, descriptor):
  9563. args = [Argument('JSContext*', 'cx'),
  9564. Argument('JS::Handle<JSObject*>', 'wrapper'),
  9565. Argument('JS::Handle<JSObject*>', 'obj'),
  9566. Argument('JS::Handle<jsid>', 'id'),
  9567. Argument('JS::MutableHandle<JS::PropertyDescriptor>', 'desc')]
  9568. CGAbstractBindingMethod.__init__(self, descriptor,
  9569. "ResolveOwnPropertyViaResolve",
  9570. args, getThisObj="",
  9571. callArgs="")
  9572. def generate_code(self):
  9573. return CGGeneric(dedent("""
  9574. {
  9575. // Since we're dealing with an Xray, do the resolve on the
  9576. // underlying object first. That gives it a chance to
  9577. // define properties on the actual object as needed, and
  9578. // then use the fact that it created the objects as a flag
  9579. // to avoid re-resolving the properties if someone deletes
  9580. // them.
  9581. JSAutoCompartment ac(cx, obj);
  9582. JS::Rooted<JS::PropertyDescriptor> objDesc(cx);
  9583. if (!self->DoResolve(cx, obj, id, &objDesc)) {
  9584. return false;
  9585. }
  9586. // If desc.value() is undefined, then the DoResolve call
  9587. // has already defined the property on the object. Don't
  9588. // try to also define it.
  9589. if (objDesc.object() &&
  9590. !objDesc.value().isUndefined() &&
  9591. !JS_DefinePropertyById(cx, obj, id, objDesc)) {
  9592. return false;
  9593. }
  9594. }
  9595. return self->DoResolve(cx, wrapper, id, desc);
  9596. """))
  9597. class CGEnumerateOwnProperties(CGAbstractStaticMethod):
  9598. def __init__(self, descriptor):
  9599. args = [Argument('JSContext*', 'cx'),
  9600. Argument('JS::Handle<JSObject*>', 'wrapper'),
  9601. Argument('JS::Handle<JSObject*>', 'obj'),
  9602. Argument('JS::AutoIdVector&', 'props')]
  9603. CGAbstractStaticMethod.__init__(self, descriptor,
  9604. "EnumerateOwnProperties", "bool", args)
  9605. def definition_body(self):
  9606. return "return js::GetProxyHandler(obj)->ownPropertyKeys(cx, wrapper, props);\n"
  9607. class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod):
  9608. """
  9609. An implementation of Xray EnumerateOwnProperties stuff for things
  9610. that have a resolve hook.
  9611. """
  9612. def __init__(self, descriptor):
  9613. args = [Argument('JSContext*', 'cx'),
  9614. Argument('JS::Handle<JSObject*>', 'wrapper'),
  9615. Argument('JS::Handle<JSObject*>', 'obj'),
  9616. Argument('JS::AutoIdVector&', 'props')]
  9617. CGAbstractBindingMethod.__init__(self, descriptor,
  9618. "EnumerateOwnPropertiesViaGetOwnPropertyNames",
  9619. args, getThisObj="",
  9620. callArgs="")
  9621. def generate_code(self):
  9622. return CGGeneric(dedent("""
  9623. AutoTArray<nsString, 8> names;
  9624. binding_detail::FastErrorResult rv;
  9625. self->GetOwnPropertyNames(cx, names, rv);
  9626. if (rv.MaybeSetPendingException(cx)) {
  9627. return false;
  9628. }
  9629. // OK to pass null as "proxy" because it's ignored if
  9630. // shadowPrototypeProperties is true
  9631. return AppendNamedPropertyIds(cx, nullptr, names, true, props);
  9632. """))
  9633. class CGPrototypeTraitsClass(CGClass):
  9634. def __init__(self, descriptor, indent=''):
  9635. templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
  9636. templateSpecialization = ['prototypes::id::' + descriptor.name]
  9637. enums = [ClassEnum('', ['Depth'],
  9638. [descriptor.interface.inheritanceDepth()])]
  9639. CGClass.__init__(self, 'PrototypeTraits', indent=indent,
  9640. templateArgs=templateArgs,
  9641. templateSpecialization=templateSpecialization,
  9642. enums=enums, isStruct=True)
  9643. def deps(self):
  9644. return set()
  9645. class CGClassForwardDeclare(CGThing):
  9646. def __init__(self, name, isStruct=False):
  9647. CGThing.__init__(self)
  9648. self.name = name
  9649. self.isStruct = isStruct
  9650. def declare(self):
  9651. type = 'struct' if self.isStruct else 'class'
  9652. return '%s %s;\n' % (type, self.name)
  9653. def define(self):
  9654. # Header only
  9655. return ''
  9656. def deps(self):
  9657. return set()
  9658. class CGProxySpecialOperation(CGPerSignatureCall):
  9659. """
  9660. Base class for classes for calling an indexed or named special operation
  9661. (don't use this directly, use the derived classes below).
  9662. If checkFound is False, will just assert that the prop is found instead of
  9663. checking that it is before wrapping the value.
  9664. resultVar: See the docstring for CGCallGenerator.
  9665. foundVar: For getters and deleters, the generated code can also set a bool
  9666. variable, declared by the caller, if the given indexed or named property
  9667. already existed. If the caller wants this, it should pass the name of the
  9668. bool variable as the foundVar keyword argument to the constructor. The
  9669. caller is responsible for declaring the variable and initializing it to
  9670. false.
  9671. """
  9672. def __init__(self, descriptor, operation, checkFound=True,
  9673. argumentHandleValue=None, resultVar=None, foundVar=None):
  9674. self.checkFound = checkFound
  9675. self.foundVar = foundVar or "found"
  9676. nativeName = MakeNativeName(descriptor.binaryNameFor(operation))
  9677. operation = descriptor.operations[operation]
  9678. assert len(operation.signatures()) == 1
  9679. signature = operation.signatures()[0]
  9680. returnType, arguments = signature
  9681. # We pass len(arguments) as the final argument so that the
  9682. # CGPerSignatureCall won't do any argument conversion of its own.
  9683. CGPerSignatureCall.__init__(self, returnType, arguments, nativeName,
  9684. False, descriptor, operation,
  9685. len(arguments), resultVar=resultVar,
  9686. objectName="proxy")
  9687. if operation.isSetter() or operation.isCreator():
  9688. # arguments[0] is the index or name of the item that we're setting.
  9689. argument = arguments[1]
  9690. info = getJSToNativeConversionInfo(
  9691. argument.type, descriptor,
  9692. treatNullAs=argument.treatNullAs,
  9693. sourceDescription=("value being assigned to %s setter" %
  9694. descriptor.interface.identifier.name))
  9695. if argumentHandleValue is None:
  9696. argumentHandleValue = "desc.value()"
  9697. rootedValue = fill(
  9698. """
  9699. JS::Rooted<JS::Value> rootedValue(cx, ${argumentHandleValue});
  9700. """,
  9701. argumentHandleValue = argumentHandleValue)
  9702. templateValues = {
  9703. "declName": argument.identifier.name,
  9704. "holderName": argument.identifier.name + "_holder",
  9705. "val": argumentHandleValue,
  9706. "maybeMutableVal": "&rootedValue",
  9707. "obj": "obj",
  9708. "passedToJSImpl": "false"
  9709. }
  9710. self.cgRoot.prepend(instantiateJSToNativeConversion(info, templateValues))
  9711. # rootedValue needs to come before the conversion, so we
  9712. # need to prepend it last.
  9713. self.cgRoot.prepend(CGGeneric(rootedValue))
  9714. elif operation.isGetter() or operation.isDeleter():
  9715. if foundVar is None:
  9716. self.cgRoot.prepend(CGGeneric("bool found = false;\n"))
  9717. def getArguments(self):
  9718. args = [(a, a.identifier.name) for a in self.arguments]
  9719. if self.idlNode.isGetter() or self.idlNode.isDeleter():
  9720. args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean],
  9721. self.idlNode),
  9722. self.foundVar))
  9723. return args
  9724. def wrap_return_value(self):
  9725. if not self.idlNode.isGetter() or self.templateValues is None:
  9726. return ""
  9727. wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues))
  9728. if self.checkFound:
  9729. wrap = CGIfWrapper(wrap, self.foundVar)
  9730. else:
  9731. wrap = CGList([CGGeneric("MOZ_ASSERT(" + self.foundVar + ");\n"), wrap])
  9732. return "\n" + wrap.define()
  9733. class CGProxyIndexedOperation(CGProxySpecialOperation):
  9734. """
  9735. Class to generate a call to an indexed operation.
  9736. If doUnwrap is False, the caller is responsible for making sure a variable
  9737. named 'self' holds the C++ object somewhere where the code we generate
  9738. will see it.
  9739. If checkFound is False, will just assert that the prop is found instead of
  9740. checking that it is before wrapping the value.
  9741. resultVar: See the docstring for CGCallGenerator.
  9742. foundVar: See the docstring for CGProxySpecialOperation.
  9743. """
  9744. def __init__(self, descriptor, name, doUnwrap=True, checkFound=True,
  9745. argumentHandleValue=None, resultVar=None, foundVar=None):
  9746. self.doUnwrap = doUnwrap
  9747. CGProxySpecialOperation.__init__(self, descriptor, name, checkFound,
  9748. argumentHandleValue=argumentHandleValue,
  9749. resultVar=resultVar,
  9750. foundVar=foundVar)
  9751. def define(self):
  9752. # Our first argument is the id we're getting.
  9753. argName = self.arguments[0].identifier.name
  9754. if argName == "index":
  9755. # We already have our index in a variable with that name
  9756. setIndex = ""
  9757. else:
  9758. setIndex = "uint32_t %s = index;\n" % argName
  9759. if self.doUnwrap:
  9760. unwrap = "%s* self = UnwrapProxy(proxy);\n" % self.descriptor.nativeType
  9761. else:
  9762. unwrap = ""
  9763. return (setIndex + unwrap +
  9764. CGProxySpecialOperation.define(self))
  9765. class CGProxyIndexedGetter(CGProxyIndexedOperation):
  9766. """
  9767. Class to generate a call to an indexed getter. If templateValues is not None
  9768. the returned value will be wrapped with wrapForType using templateValues.
  9769. If doUnwrap is False, the caller is responsible for making sure a variable
  9770. named 'self' holds the C++ object somewhere where the code we generate
  9771. will see it.
  9772. If checkFound is False, will just assert that the prop is found instead of
  9773. checking that it is before wrapping the value.
  9774. foundVar: See the docstring for CGProxySpecialOperation.
  9775. """
  9776. def __init__(self, descriptor, templateValues=None, doUnwrap=True,
  9777. checkFound=True, foundVar=None):
  9778. self.templateValues = templateValues
  9779. CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedGetter',
  9780. doUnwrap, checkFound, foundVar=foundVar)
  9781. class CGProxyIndexedPresenceChecker(CGProxyIndexedGetter):
  9782. """
  9783. Class to generate a call that checks whether an indexed property exists.
  9784. For now, we just delegate to CGProxyIndexedGetter
  9785. foundVar: See the docstring for CGProxySpecialOperation.
  9786. """
  9787. def __init__(self, descriptor, foundVar):
  9788. CGProxyIndexedGetter.__init__(self, descriptor, foundVar=foundVar)
  9789. self.cgRoot.append(CGGeneric("(void)result;\n"))
  9790. class CGProxyIndexedSetter(CGProxyIndexedOperation):
  9791. """
  9792. Class to generate a call to an indexed setter.
  9793. """
  9794. def __init__(self, descriptor, argumentHandleValue=None):
  9795. CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedSetter',
  9796. argumentHandleValue=argumentHandleValue)
  9797. class CGProxyNamedOperation(CGProxySpecialOperation):
  9798. """
  9799. Class to generate a call to a named operation.
  9800. 'value' is the jsval to use for the name; None indicates that it should be
  9801. gotten from the property id.
  9802. resultVar: See the docstring for CGCallGenerator.
  9803. foundVar: See the docstring for CGProxySpecialOperation.
  9804. """
  9805. def __init__(self, descriptor, name, value=None, argumentHandleValue=None,
  9806. resultVar=None, foundVar=None):
  9807. CGProxySpecialOperation.__init__(self, descriptor, name,
  9808. argumentHandleValue=argumentHandleValue,
  9809. resultVar=resultVar,
  9810. foundVar=foundVar)
  9811. self.value = value
  9812. def define(self):
  9813. # Our first argument is the id we're getting.
  9814. argName = self.arguments[0].identifier.name
  9815. if argName == "id":
  9816. # deal with the name collision
  9817. decls = "JS::Rooted<jsid> id_(cx, id);\n"
  9818. idName = "id_"
  9819. else:
  9820. decls = ""
  9821. idName = "id"
  9822. decls += "binding_detail::FakeString %s;\n" % argName
  9823. main = fill(
  9824. """
  9825. ${nativeType}* self = UnwrapProxy(proxy);
  9826. $*{op}
  9827. """,
  9828. nativeType=self.descriptor.nativeType,
  9829. op=CGProxySpecialOperation.define(self))
  9830. if self.value is None:
  9831. return fill(
  9832. """
  9833. $*{decls}
  9834. bool isSymbol;
  9835. if (!ConvertIdToString(cx, ${idName}, ${argName}, isSymbol)) {
  9836. return false;
  9837. }
  9838. if (!isSymbol) {
  9839. $*{main}
  9840. }
  9841. """,
  9842. decls=decls,
  9843. idName=idName,
  9844. argName=argName,
  9845. main=main)
  9846. # Sadly, we have to set up nameVal even if we have an atom id,
  9847. # because we don't know for sure, and we can end up needing it
  9848. # so it needs to be higher up the stack. Using a Maybe here
  9849. # seems like probable overkill.
  9850. return fill(
  9851. """
  9852. $*{decls}
  9853. JS::Rooted<JS::Value> nameVal(cx, ${value});
  9854. if (!nameVal.isSymbol()) {
  9855. if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify,
  9856. ${argName})) {
  9857. return false;
  9858. }
  9859. $*{main}
  9860. }
  9861. """,
  9862. decls=decls,
  9863. value=self.value,
  9864. argName=argName,
  9865. main=main)
  9866. class CGProxyNamedGetter(CGProxyNamedOperation):
  9867. """
  9868. Class to generate a call to an named getter. If templateValues is not None
  9869. the returned value will be wrapped with wrapForType using templateValues.
  9870. 'value' is the jsval to use for the name; None indicates that it should be
  9871. gotten from the property id.
  9872. foundVar: See the docstring for CGProxySpecialOperation.
  9873. """
  9874. def __init__(self, descriptor, templateValues=None, value=None,
  9875. foundVar=None):
  9876. self.templateValues = templateValues
  9877. CGProxyNamedOperation.__init__(self, descriptor, 'NamedGetter', value,
  9878. foundVar=foundVar)
  9879. class CGProxyNamedPresenceChecker(CGProxyNamedGetter):
  9880. """
  9881. Class to generate a call that checks whether a named property exists.
  9882. For now, we just delegate to CGProxyNamedGetter
  9883. foundVar: See the docstring for CGProxySpecialOperation.
  9884. """
  9885. def __init__(self, descriptor, foundVar=None):
  9886. CGProxyNamedGetter.__init__(self, descriptor, foundVar=foundVar)
  9887. self.cgRoot.append(CGGeneric("(void)result;\n"))
  9888. class CGProxyNamedSetter(CGProxyNamedOperation):
  9889. """
  9890. Class to generate a call to a named setter.
  9891. """
  9892. def __init__(self, descriptor, argumentHandleValue=None):
  9893. CGProxyNamedOperation.__init__(self, descriptor, 'NamedSetter',
  9894. argumentHandleValue=argumentHandleValue)
  9895. class CGProxyNamedDeleter(CGProxyNamedOperation):
  9896. """
  9897. Class to generate a call to a named deleter.
  9898. resultVar: See the docstring for CGCallGenerator.
  9899. foundVar: See the docstring for CGProxySpecialOperation.
  9900. """
  9901. def __init__(self, descriptor, resultVar=None, foundVar=None):
  9902. CGProxyNamedOperation.__init__(self, descriptor, 'NamedDeleter',
  9903. resultVar=resultVar,
  9904. foundVar=foundVar)
  9905. class CGProxyIsProxy(CGAbstractMethod):
  9906. def __init__(self, descriptor):
  9907. args = [Argument('JSObject*', 'obj')]
  9908. CGAbstractMethod.__init__(self, descriptor, "IsProxy", "bool", args, alwaysInline=True)
  9909. def declare(self):
  9910. return ""
  9911. def definition_body(self):
  9912. return "return js::IsProxy(obj) && js::GetProxyHandler(obj) == DOMProxyHandler::getInstance();\n"
  9913. class CGProxyUnwrap(CGAbstractMethod):
  9914. def __init__(self, descriptor):
  9915. args = [Argument('JSObject*', 'obj')]
  9916. CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", descriptor.nativeType + '*', args, alwaysInline=True)
  9917. def declare(self):
  9918. return ""
  9919. def definition_body(self):
  9920. return fill(
  9921. """
  9922. MOZ_ASSERT(js::IsProxy(obj));
  9923. if (js::GetProxyHandler(obj) != DOMProxyHandler::getInstance()) {
  9924. MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(obj));
  9925. obj = js::UncheckedUnwrap(obj);
  9926. }
  9927. MOZ_ASSERT(IsProxy(obj));
  9928. return static_cast<${type}*>(js::GetProxyPrivate(obj).toPrivate());
  9929. """,
  9930. type=self.descriptor.nativeType)
  9931. class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod):
  9932. def __init__(self, descriptor):
  9933. args = [Argument('JSContext*', 'cx'),
  9934. Argument('JS::Handle<JSObject*>', 'proxy'),
  9935. Argument('JS::Handle<jsid>', 'id'),
  9936. Argument('bool', 'ignoreNamedProps'),
  9937. Argument('JS::MutableHandle<JS::PropertyDescriptor>', 'desc')]
  9938. ClassMethod.__init__(self, "getOwnPropDescriptor", "bool", args,
  9939. virtual=True, override=True, const=True)
  9940. self.descriptor = descriptor
  9941. def getBody(self):
  9942. indexedGetter = self.descriptor.operations['IndexedGetter']
  9943. indexedSetter = self.descriptor.operations['IndexedSetter']
  9944. if self.descriptor.supportsIndexedProperties():
  9945. readonly = toStringBool(indexedSetter is None)
  9946. fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;\n" % readonly
  9947. templateValues = {
  9948. 'jsvalRef': 'desc.value()',
  9949. 'jsvalHandle': 'desc.value()',
  9950. 'obj': 'proxy',
  9951. 'successCode': fillDescriptor
  9952. }
  9953. getIndexed = fill(
  9954. """
  9955. uint32_t index = GetArrayIndexFromId(cx, id);
  9956. if (IsArrayIndex(index)) {
  9957. $*{callGetter}
  9958. }
  9959. """,
  9960. callGetter=CGProxyIndexedGetter(self.descriptor, templateValues).define())
  9961. else:
  9962. getIndexed = ""
  9963. if self.descriptor.supportsNamedProperties():
  9964. operations = self.descriptor.operations
  9965. readonly = toStringBool(operations['NamedSetter'] is None)
  9966. fillDescriptor = (
  9967. "FillPropertyDescriptor(desc, proxy, %s, %s);\n"
  9968. "return true;\n" %
  9969. (readonly,
  9970. toStringBool(self.descriptor.namedPropertiesEnumerable)))
  9971. templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()',
  9972. 'obj': 'proxy', 'successCode': fillDescriptor}
  9973. computeCondition = dedent("""
  9974. bool hasOnProto;
  9975. if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
  9976. return false;
  9977. }
  9978. callNamedGetter = !hasOnProto;
  9979. """)
  9980. if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  9981. computeCondition = fill(
  9982. """
  9983. if (!isXray) {
  9984. callNamedGetter = true;
  9985. } else {
  9986. $*{hasOnProto}
  9987. }
  9988. """,
  9989. hasOnProto=computeCondition)
  9990. outerCondition = "!ignoreNamedProps"
  9991. if self.descriptor.supportsIndexedProperties():
  9992. outerCondition = "!IsArrayIndex(index) && " + outerCondition
  9993. namedGetCode = CGProxyNamedGetter(self.descriptor,
  9994. templateValues).define()
  9995. namedGet = fill("""
  9996. bool callNamedGetter = false;
  9997. if (${outerCondition}) {
  9998. $*{computeCondition}
  9999. }
  10000. if (callNamedGetter) {
  10001. $*{namedGetCode}
  10002. }
  10003. """,
  10004. outerCondition=outerCondition,
  10005. computeCondition=computeCondition,
  10006. namedGetCode=namedGetCode)
  10007. namedGet += "\n"
  10008. else:
  10009. namedGet = ""
  10010. return fill(
  10011. """
  10012. bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);
  10013. $*{getIndexed}
  10014. JS::Rooted<JSObject*> expando(cx);
  10015. if (!isXray && (expando = GetExpandoObject(proxy))) {
  10016. if (!JS_GetOwnPropertyDescriptorById(cx, expando, id, desc)) {
  10017. return false;
  10018. }
  10019. if (desc.object()) {
  10020. // Pretend the property lives on the wrapper.
  10021. desc.object().set(proxy);
  10022. return true;
  10023. }
  10024. }
  10025. $*{namedGet}
  10026. desc.object().set(nullptr);
  10027. return true;
  10028. """,
  10029. getIndexed=getIndexed,
  10030. namedGet=namedGet)
  10031. class CGDOMJSProxyHandler_defineProperty(ClassMethod):
  10032. def __init__(self, descriptor):
  10033. # The usual convention is to name the ObjectOpResult out-parameter
  10034. # `result`, but that name is a bit overloaded around here.
  10035. args = [Argument('JSContext*', 'cx'),
  10036. Argument('JS::Handle<JSObject*>', 'proxy'),
  10037. Argument('JS::Handle<jsid>', 'id'),
  10038. Argument('JS::Handle<JS::PropertyDescriptor>', 'desc'),
  10039. Argument('JS::ObjectOpResult&', 'opresult'),
  10040. Argument('bool*', 'defined')]
  10041. ClassMethod.__init__(self, "defineProperty", "bool", args, virtual=True, override=True, const=True)
  10042. self.descriptor = descriptor
  10043. def getBody(self):
  10044. set = ""
  10045. indexedSetter = self.descriptor.operations['IndexedSetter']
  10046. if indexedSetter:
  10047. if self.descriptor.operations['IndexedCreator'] is not indexedSetter:
  10048. raise TypeError("Can't handle creator that's different from the setter")
  10049. set += fill(
  10050. """
  10051. uint32_t index = GetArrayIndexFromId(cx, id);
  10052. if (IsArrayIndex(index)) {
  10053. *defined = true;
  10054. $*{callSetter}
  10055. return opresult.succeed();
  10056. }
  10057. """,
  10058. callSetter=CGProxyIndexedSetter(self.descriptor).define())
  10059. elif self.descriptor.supportsIndexedProperties():
  10060. # We allow untrusted content to prevent Xrays from setting a
  10061. # property if that property is an indexed property and we have no
  10062. # indexed setter. That's how the object would normally behave if
  10063. # you tried to set the property on it. That means we don't need to
  10064. # do anything special for Xrays here.
  10065. set += dedent(
  10066. """
  10067. if (IsArrayIndex(GetArrayIndexFromId(cx, id))) {
  10068. *defined = true;
  10069. return opresult.failNoIndexedSetter();
  10070. }
  10071. """)
  10072. namedSetter = self.descriptor.operations['NamedSetter']
  10073. if namedSetter:
  10074. if self.descriptor.hasUnforgeableMembers:
  10075. raise TypeError("Can't handle a named setter on an interface "
  10076. "that has unforgeables. Figure out how that "
  10077. "should work!")
  10078. if self.descriptor.operations['NamedCreator'] is not namedSetter:
  10079. raise TypeError("Can't handle creator that's different from the setter")
  10080. # If we support indexed properties, we won't get down here for
  10081. # indices, so we can just do our setter unconditionally here.
  10082. set += fill(
  10083. """
  10084. *defined = true;
  10085. $*{callSetter}
  10086. return opresult.succeed();
  10087. """,
  10088. callSetter=CGProxyNamedSetter(self.descriptor).define())
  10089. else:
  10090. # We allow untrusted content to prevent Xrays from setting a
  10091. # property if that property is already a named property on the
  10092. # object and we have no named setter. That's how the object would
  10093. # normally behave if you tried to set the property on it. That
  10094. # means we don't need to do anything special for Xrays here.
  10095. if self.descriptor.supportsNamedProperties():
  10096. set += fill(
  10097. """
  10098. bool found = false;
  10099. $*{presenceChecker}
  10100. if (found) {
  10101. *defined = true;
  10102. return opresult.failNoNamedSetter();
  10103. }
  10104. """,
  10105. presenceChecker=CGProxyNamedPresenceChecker(self.descriptor, foundVar="found").define())
  10106. set += ("return mozilla::dom::DOMProxyHandler::defineProperty(%s);\n" %
  10107. ", ".join(a.name for a in self.args))
  10108. return set
  10109. def getDeleterBody(descriptor, type, foundVar=None):
  10110. """
  10111. type should be "Named" or "Indexed"
  10112. The possible outcomes:
  10113. - an error happened (the emitted code returns false)
  10114. - own property not found (foundVar=false, deleteSucceeded=true)
  10115. - own property found and deleted (foundVar=true, deleteSucceeded=true)
  10116. - own property found but can't be deleted (foundVar=true, deleteSucceeded=false)
  10117. """
  10118. assert type in ("Named", "Indexed")
  10119. deleter = descriptor.operations[type + 'Deleter']
  10120. if deleter:
  10121. assert type == "Named"
  10122. assert foundVar is not None
  10123. if descriptor.hasUnforgeableMembers:
  10124. raise TypeError("Can't handle a deleter on an interface "
  10125. "that has unforgeables. Figure out how "
  10126. "that should work!")
  10127. # See if the deleter method is fallible.
  10128. t = deleter.signatures()[0][0]
  10129. if t.isPrimitive() and not t.nullable() and t.tag() == IDLType.Tags.bool:
  10130. # The deleter method has a boolean return value. When a
  10131. # property is found, the return value indicates whether it
  10132. # was successfully deleted.
  10133. setDS = fill(
  10134. """
  10135. if (!${foundVar}) {
  10136. deleteSucceeded = true;
  10137. }
  10138. """,
  10139. foundVar=foundVar)
  10140. else:
  10141. # No boolean return value: if a property is found,
  10142. # deleting it always succeeds.
  10143. setDS = "deleteSucceeded = true;\n"
  10144. body = (CGProxyNamedDeleter(descriptor,
  10145. resultVar="deleteSucceeded",
  10146. foundVar=foundVar).define() +
  10147. setDS)
  10148. elif getattr(descriptor, "supports%sProperties" % type)():
  10149. presenceCheckerClass = globals()["CGProxy%sPresenceChecker" % type]
  10150. foundDecl = ""
  10151. if foundVar is None:
  10152. foundVar = "found"
  10153. foundDecl = "bool found = false;\n"
  10154. body = fill(
  10155. """
  10156. $*{foundDecl}
  10157. $*{presenceChecker}
  10158. deleteSucceeded = !${foundVar};
  10159. """,
  10160. foundDecl=foundDecl,
  10161. presenceChecker=presenceCheckerClass(descriptor, foundVar=foundVar).define(),
  10162. foundVar=foundVar)
  10163. else:
  10164. body = None
  10165. return body
  10166. class CGDeleteNamedProperty(CGAbstractStaticMethod):
  10167. def __init__(self, descriptor):
  10168. args = [Argument('JSContext*', 'cx'),
  10169. Argument('JS::Handle<JSObject*>', 'xray'),
  10170. Argument('JS::Handle<JSObject*>', 'proxy'),
  10171. Argument('JS::Handle<jsid>', 'id'),
  10172. Argument('JS::ObjectOpResult&', 'opresult')]
  10173. CGAbstractStaticMethod.__init__(self, descriptor, "DeleteNamedProperty",
  10174. "bool", args)
  10175. def definition_body(self):
  10176. return fill(
  10177. """
  10178. MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(xray));
  10179. MOZ_ASSERT(js::IsProxy(proxy));
  10180. MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
  10181. JSAutoCompartment ac(cx, proxy);
  10182. bool deleteSucceeded;
  10183. bool found = false;
  10184. $*{namedBody}
  10185. if (!found || deleteSucceeded) {
  10186. return opresult.succeed();
  10187. }
  10188. return opresult.failCantDelete();
  10189. """,
  10190. namedBody=getDeleterBody(self.descriptor, "Named", foundVar="found"))
  10191. class CGDOMJSProxyHandler_delete(ClassMethod):
  10192. def __init__(self, descriptor):
  10193. args = [Argument('JSContext*', 'cx'),
  10194. Argument('JS::Handle<JSObject*>', 'proxy'),
  10195. Argument('JS::Handle<jsid>', 'id'),
  10196. Argument('JS::ObjectOpResult&', 'opresult')]
  10197. ClassMethod.__init__(self, "delete_", "bool", args,
  10198. virtual=True, override=True, const=True)
  10199. self.descriptor = descriptor
  10200. def getBody(self):
  10201. delete = dedent("""
  10202. MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
  10203. "Should not have a XrayWrapper here");
  10204. """)
  10205. indexedBody = getDeleterBody(self.descriptor, "Indexed")
  10206. if indexedBody is not None:
  10207. delete += fill(
  10208. """
  10209. uint32_t index = GetArrayIndexFromId(cx, id);
  10210. if (IsArrayIndex(index)) {
  10211. bool deleteSucceeded;
  10212. $*{indexedBody}
  10213. return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete();
  10214. }
  10215. """,
  10216. indexedBody=indexedBody)
  10217. namedBody = getDeleterBody(self.descriptor, "Named", foundVar="found")
  10218. if namedBody is not None:
  10219. delete += dedent(
  10220. """
  10221. // Try named delete only if the named property visibility
  10222. // algorithm says the property is visible.
  10223. bool tryNamedDelete = true;
  10224. { // Scope for expando
  10225. JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
  10226. if (expando) {
  10227. bool hasProp;
  10228. if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
  10229. return false;
  10230. }
  10231. tryNamedDelete = !hasProp;
  10232. }
  10233. }
  10234. """)
  10235. if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  10236. delete += dedent(
  10237. """
  10238. if (tryNamedDelete) {
  10239. bool hasOnProto;
  10240. if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
  10241. return false;
  10242. }
  10243. tryNamedDelete = !hasOnProto;
  10244. }
  10245. """)
  10246. # We always return above for an index id in the case when we support
  10247. # indexed properties, so we can just treat the id as a name
  10248. # unconditionally here.
  10249. delete += fill(
  10250. """
  10251. if (tryNamedDelete) {
  10252. bool found = false;
  10253. bool deleteSucceeded;
  10254. $*{namedBody}
  10255. if (found) {
  10256. return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete();
  10257. }
  10258. }
  10259. """,
  10260. namedBody=namedBody)
  10261. delete += dedent("""
  10262. return dom::DOMProxyHandler::delete_(cx, proxy, id, opresult);
  10263. """)
  10264. return delete
  10265. class CGDOMJSProxyHandler_ownPropNames(ClassMethod):
  10266. def __init__(self, descriptor, ):
  10267. args = [Argument('JSContext*', 'cx'),
  10268. Argument('JS::Handle<JSObject*>', 'proxy'),
  10269. Argument('unsigned', 'flags'),
  10270. Argument('JS::AutoIdVector&', 'props')]
  10271. ClassMethod.__init__(self, "ownPropNames", "bool", args,
  10272. virtual=True, override=True, const=True)
  10273. self.descriptor = descriptor
  10274. def getBody(self):
  10275. # Per spec, we do indices, then named props, then everything else
  10276. if self.descriptor.supportsIndexedProperties():
  10277. addIndices = dedent("""
  10278. uint32_t length = UnwrapProxy(proxy)->Length();
  10279. MOZ_ASSERT(int32_t(length) >= 0);
  10280. for (int32_t i = 0; i < int32_t(length); ++i) {
  10281. if (!props.append(INT_TO_JSID(i))) {
  10282. return false;
  10283. }
  10284. }
  10285. """)
  10286. else:
  10287. addIndices = ""
  10288. if self.descriptor.supportsNamedProperties():
  10289. if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  10290. shadow = "!isXray"
  10291. else:
  10292. shadow = "false"
  10293. addNames = fill(
  10294. """
  10295. nsTArray<nsString> names;
  10296. UnwrapProxy(proxy)->GetSupportedNames(names);
  10297. if (!AppendNamedPropertyIds(cx, proxy, names, ${shadow}, props)) {
  10298. return false;
  10299. }
  10300. """,
  10301. shadow=shadow)
  10302. if not self.descriptor.namedPropertiesEnumerable:
  10303. addNames = CGIfWrapper(CGGeneric(addNames),
  10304. "flags & JSITER_HIDDEN").define()
  10305. addNames = "\n" + addNames
  10306. else:
  10307. addNames = ""
  10308. return fill(
  10309. """
  10310. bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);
  10311. $*{addIndices}
  10312. $*{addNames}
  10313. JS::Rooted<JSObject*> expando(cx);
  10314. if (!isXray && (expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
  10315. !js::GetPropertyKeys(cx, expando, flags, &props)) {
  10316. return false;
  10317. }
  10318. return true;
  10319. """,
  10320. addIndices=addIndices,
  10321. addNames=addNames)
  10322. class CGDOMJSProxyHandler_hasOwn(ClassMethod):
  10323. def __init__(self, descriptor):
  10324. args = [Argument('JSContext*', 'cx'),
  10325. Argument('JS::Handle<JSObject*>', 'proxy'),
  10326. Argument('JS::Handle<jsid>', 'id'),
  10327. Argument('bool*', 'bp')]
  10328. ClassMethod.__init__(self, "hasOwn", "bool", args,
  10329. virtual=True, override=True, const=True)
  10330. self.descriptor = descriptor
  10331. def getBody(self):
  10332. if self.descriptor.supportsIndexedProperties():
  10333. indexed = fill(
  10334. """
  10335. uint32_t index = GetArrayIndexFromId(cx, id);
  10336. if (IsArrayIndex(index)) {
  10337. bool found = false;
  10338. $*{presenceChecker}
  10339. *bp = found;
  10340. return true;
  10341. }
  10342. """,
  10343. presenceChecker=CGProxyIndexedPresenceChecker(self.descriptor, foundVar="found").define())
  10344. else:
  10345. indexed = ""
  10346. if self.descriptor.supportsNamedProperties():
  10347. # If we support indexed properties we always return above for index
  10348. # property names, so no need to check for those here.
  10349. named = fill(
  10350. """
  10351. bool found = false;
  10352. $*{presenceChecker}
  10353. *bp = found;
  10354. """,
  10355. presenceChecker=CGProxyNamedPresenceChecker(self.descriptor, foundVar="found").define())
  10356. if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  10357. named = fill(
  10358. """
  10359. bool hasOnProto;
  10360. if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
  10361. return false;
  10362. }
  10363. if (!hasOnProto) {
  10364. $*{protoLacksProperty}
  10365. return true;
  10366. }
  10367. """,
  10368. protoLacksProperty=named)
  10369. named += "*bp = false;\n"
  10370. else:
  10371. named += "\n"
  10372. else:
  10373. named = "*bp = false;\n"
  10374. return fill(
  10375. """
  10376. MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
  10377. "Should not have a XrayWrapper here");
  10378. $*{indexed}
  10379. JS::Rooted<JSObject*> expando(cx, GetExpandoObject(proxy));
  10380. if (expando) {
  10381. bool b = true;
  10382. bool ok = JS_HasPropertyById(cx, expando, id, &b);
  10383. *bp = !!b;
  10384. if (!ok || *bp) {
  10385. return ok;
  10386. }
  10387. }
  10388. $*{named}
  10389. return true;
  10390. """,
  10391. indexed=indexed,
  10392. named=named)
  10393. class CGDOMJSProxyHandler_get(ClassMethod):
  10394. def __init__(self, descriptor):
  10395. args = [Argument('JSContext*', 'cx'),
  10396. Argument('JS::Handle<JSObject*>', 'proxy'),
  10397. Argument('JS::Handle<JS::Value>', 'receiver'),
  10398. Argument('JS::Handle<jsid>', 'id'),
  10399. Argument('JS::MutableHandle<JS::Value>', 'vp')]
  10400. ClassMethod.__init__(self, "get", "bool", args,
  10401. virtual=True, override=True, const=True)
  10402. self.descriptor = descriptor
  10403. def getBody(self):
  10404. getUnforgeableOrExpando = dedent("""
  10405. { // Scope for expando
  10406. JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
  10407. if (expando) {
  10408. bool hasProp;
  10409. if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
  10410. return false;
  10411. }
  10412. if (hasProp) {
  10413. // Forward the get to the expando object, but our receiver is whatever our
  10414. // receiver is.
  10415. return JS_ForwardGetPropertyTo(cx, expando, id, receiver, vp);
  10416. }
  10417. }
  10418. }
  10419. """)
  10420. templateValues = {'jsvalRef': 'vp', 'jsvalHandle': 'vp', 'obj': 'proxy'}
  10421. if self.descriptor.supportsIndexedProperties():
  10422. getIndexedOrExpando = fill(
  10423. """
  10424. uint32_t index = GetArrayIndexFromId(cx, id);
  10425. if (IsArrayIndex(index)) {
  10426. $*{callGetter}
  10427. // Even if we don't have this index, we don't forward the
  10428. // get on to our expando object.
  10429. } else {
  10430. $*{getUnforgeableOrExpando}
  10431. }
  10432. """,
  10433. callGetter=CGProxyIndexedGetter(self.descriptor, templateValues).define(),
  10434. getUnforgeableOrExpando=getUnforgeableOrExpando)
  10435. else:
  10436. getIndexedOrExpando = getUnforgeableOrExpando
  10437. if self.descriptor.supportsNamedProperties():
  10438. getNamed = CGProxyNamedGetter(self.descriptor, templateValues)
  10439. if self.descriptor.supportsIndexedProperties():
  10440. getNamed = CGIfWrapper(getNamed, "!IsArrayIndex(index)")
  10441. getNamed = getNamed.define() + "\n"
  10442. else:
  10443. getNamed = ""
  10444. getOnPrototype = dedent("""
  10445. bool foundOnPrototype;
  10446. if (!GetPropertyOnPrototype(cx, proxy, receiver, id, &foundOnPrototype, vp)) {
  10447. return false;
  10448. }
  10449. if (foundOnPrototype) {
  10450. return true;
  10451. }
  10452. """)
  10453. if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  10454. getNamed = getNamed + getOnPrototype
  10455. else:
  10456. getNamed = getOnPrototype + getNamed
  10457. return fill(
  10458. """
  10459. MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
  10460. "Should not have a XrayWrapper here");
  10461. $*{indexedOrExpando}
  10462. $*{named}
  10463. vp.setUndefined();
  10464. return true;
  10465. """,
  10466. indexedOrExpando=getIndexedOrExpando,
  10467. named=getNamed)
  10468. class CGDOMJSProxyHandler_setCustom(ClassMethod):
  10469. def __init__(self, descriptor):
  10470. args = [Argument('JSContext*', 'cx'),
  10471. Argument('JS::Handle<JSObject*>', 'proxy'),
  10472. Argument('JS::Handle<jsid>', 'id'),
  10473. Argument('JS::Handle<JS::Value>', 'v'),
  10474. Argument('bool*', 'done')]
  10475. ClassMethod.__init__(self, "setCustom", "bool", args, virtual=True, override=True, const=True)
  10476. self.descriptor = descriptor
  10477. def getBody(self):
  10478. assertion = ("MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),\n"
  10479. ' "Should not have a XrayWrapper here");\n')
  10480. # Correctness first. If we have a NamedSetter and [OverrideBuiltins],
  10481. # always call the NamedSetter and never do anything else.
  10482. namedSetter = self.descriptor.operations['NamedSetter']
  10483. if (namedSetter is not None and
  10484. self.descriptor.interface.getExtendedAttribute('OverrideBuiltins')):
  10485. # Check assumptions.
  10486. if self.descriptor.supportsIndexedProperties():
  10487. raise ValueError("In interface " + self.descriptor.name + ": " +
  10488. "Can't cope with [OverrideBuiltins] and an indexed getter")
  10489. if self.descriptor.operations['NamedCreator'] is not namedSetter:
  10490. raise ValueError("In interface " + self.descriptor.name + ": " +
  10491. "Can't cope with named setter that is not also a named creator")
  10492. if self.descriptor.hasUnforgeableMembers:
  10493. raise ValueError("In interface " + self.descriptor.name + ": " +
  10494. "Can't cope with [OverrideBuiltins] and unforgeable members")
  10495. callSetter = CGProxyNamedSetter(self.descriptor, argumentHandleValue="v")
  10496. return (assertion +
  10497. callSetter.define() +
  10498. "*done = true;\n"
  10499. "return true;\n")
  10500. # As an optimization, if we are going to call an IndexedSetter, go
  10501. # ahead and call it and have done.
  10502. indexedSetter = self.descriptor.operations['IndexedSetter']
  10503. if indexedSetter is not None:
  10504. if self.descriptor.operations['IndexedCreator'] is not indexedSetter:
  10505. raise ValueError("In interface " + self.descriptor.name + ": " +
  10506. "Can't cope with indexed setter that is not " +
  10507. "also an indexed creator")
  10508. setIndexed = fill(
  10509. """
  10510. uint32_t index = GetArrayIndexFromId(cx, id);
  10511. if (IsArrayIndex(index)) {
  10512. $*{callSetter}
  10513. *done = true;
  10514. return true;
  10515. }
  10516. """,
  10517. callSetter=CGProxyIndexedSetter(self.descriptor,
  10518. argumentHandleValue="v").define())
  10519. else:
  10520. setIndexed = ""
  10521. return (assertion +
  10522. setIndexed +
  10523. "*done = false;\n"
  10524. "return true;\n")
  10525. class CGDOMJSProxyHandler_className(ClassMethod):
  10526. def __init__(self, descriptor):
  10527. args = [Argument('JSContext*', 'cx'),
  10528. Argument('JS::Handle<JSObject*>', 'proxy')]
  10529. ClassMethod.__init__(self, "className", "const char*", args,
  10530. virtual=True, override=True, const=True)
  10531. self.descriptor = descriptor
  10532. def getBody(self):
  10533. return 'return "%s";\n' % self.descriptor.name
  10534. class CGDOMJSProxyHandler_finalizeInBackground(ClassMethod):
  10535. def __init__(self, descriptor):
  10536. args = [Argument('const JS::Value&', 'priv')]
  10537. ClassMethod.__init__(self, "finalizeInBackground", "bool", args,
  10538. virtual=True, override=True, const=True)
  10539. self.descriptor = descriptor
  10540. def getBody(self):
  10541. return "return false;\n"
  10542. class CGDOMJSProxyHandler_finalize(ClassMethod):
  10543. def __init__(self, descriptor):
  10544. args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'proxy')]
  10545. ClassMethod.__init__(self, "finalize", "void", args,
  10546. virtual=True, override=True, const=True)
  10547. self.descriptor = descriptor
  10548. def getBody(self):
  10549. return (("%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(proxy);\n" %
  10550. (self.descriptor.nativeType, self.descriptor.nativeType)) +
  10551. finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name).define())
  10552. class CGDOMJSProxyHandler_getElements(ClassMethod):
  10553. def __init__(self, descriptor):
  10554. assert descriptor.supportsIndexedProperties()
  10555. args = [Argument('JSContext*', 'cx'),
  10556. Argument('JS::Handle<JSObject*>', 'proxy'),
  10557. Argument('uint32_t', 'begin'),
  10558. Argument('uint32_t', 'end'),
  10559. Argument('js::ElementAdder*', 'adder')]
  10560. ClassMethod.__init__(self, "getElements", "bool", args, virtual=True, override=True, const=True)
  10561. self.descriptor = descriptor
  10562. def getBody(self):
  10563. # Just like ownPropertyKeys we'll assume that we have no holes, so
  10564. # we have all properties from 0 to length. If that ever changes
  10565. # (unlikely), we'll need to do something a bit more clever with how we
  10566. # forward on to our ancestor.
  10567. templateValues = {
  10568. 'jsvalRef': 'temp',
  10569. 'jsvalHandle': '&temp',
  10570. 'obj': 'proxy',
  10571. 'successCode': ("if (!adder->append(cx, temp)) return false;\n"
  10572. "continue;\n")
  10573. }
  10574. get = CGProxyIndexedGetter(self.descriptor, templateValues, False, False).define()
  10575. return fill(
  10576. """
  10577. JS::Rooted<JS::Value> temp(cx);
  10578. MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
  10579. "Should not have a XrayWrapper here");
  10580. ${nativeType}* self = UnwrapProxy(proxy);
  10581. uint32_t length = self->Length();
  10582. // Compute the end of the indices we'll get ourselves
  10583. uint32_t ourEnd = std::max(begin, std::min(end, length));
  10584. for (uint32_t index = begin; index < ourEnd; ++index) {
  10585. $*{get}
  10586. }
  10587. if (end > ourEnd) {
  10588. JS::Rooted<JSObject*> proto(cx);
  10589. if (!js::GetObjectProto(cx, proxy, &proto)) {
  10590. return false;
  10591. }
  10592. return js::GetElementsWithAdder(cx, proto, proxy, ourEnd, end, adder);
  10593. }
  10594. return true;
  10595. """,
  10596. nativeType=self.descriptor.nativeType,
  10597. get=get)
  10598. class CGDOMJSProxyHandler_getInstance(ClassMethod):
  10599. def __init__(self):
  10600. ClassMethod.__init__(self, "getInstance", "const DOMProxyHandler*", [], static=True)
  10601. def getBody(self):
  10602. return dedent("""
  10603. static const DOMProxyHandler instance;
  10604. return &instance;
  10605. """)
  10606. class CGDOMJSProxyHandler_getPrototypeIfOrdinary(ClassMethod):
  10607. def __init__(self):
  10608. args = [Argument('JSContext*', 'cx'),
  10609. Argument('JS::Handle<JSObject*>', 'proxy'),
  10610. Argument('bool*', 'isOrdinary'),
  10611. Argument('JS::MutableHandle<JSObject*>', 'proto')]
  10612. ClassMethod.__init__(self, "getPrototypeIfOrdinary", "bool", args,
  10613. virtual=True, override=True, const=True)
  10614. def getBody(self):
  10615. return dedent("""
  10616. *isOrdinary = false;
  10617. return true;
  10618. """)
  10619. class CGDOMJSProxyHandler_call(ClassMethod):
  10620. def __init__(self):
  10621. args = [Argument('JSContext*', 'cx'),
  10622. Argument('JS::Handle<JSObject*>', 'proxy'),
  10623. Argument('const JS::CallArgs&', 'args')]
  10624. ClassMethod.__init__(self, "call", "bool", args, virtual=True, override=True, const=True)
  10625. def getBody(self):
  10626. return fill(
  10627. """
  10628. return js::ForwardToNative(cx, ${legacyCaller}, args);
  10629. """,
  10630. legacyCaller=LEGACYCALLER_HOOK_NAME)
  10631. class CGDOMJSProxyHandler_isCallable(ClassMethod):
  10632. def __init__(self):
  10633. ClassMethod.__init__(self, "isCallable", "bool",
  10634. [Argument('JSObject*', 'obj')],
  10635. virtual=True, override=True, const=True)
  10636. def getBody(self):
  10637. return dedent("""
  10638. return true;
  10639. """)
  10640. class CGDOMJSProxyHandler(CGClass):
  10641. def __init__(self, descriptor):
  10642. assert (descriptor.supportsIndexedProperties() or
  10643. descriptor.supportsNamedProperties() or
  10644. descriptor.hasNonOrdinaryGetPrototypeOf())
  10645. methods = [CGDOMJSProxyHandler_getOwnPropDescriptor(descriptor),
  10646. CGDOMJSProxyHandler_defineProperty(descriptor),
  10647. ClassUsingDeclaration("mozilla::dom::DOMProxyHandler",
  10648. "defineProperty"),
  10649. CGDOMJSProxyHandler_ownPropNames(descriptor),
  10650. CGDOMJSProxyHandler_hasOwn(descriptor),
  10651. CGDOMJSProxyHandler_get(descriptor),
  10652. CGDOMJSProxyHandler_className(descriptor),
  10653. CGDOMJSProxyHandler_finalizeInBackground(descriptor),
  10654. CGDOMJSProxyHandler_finalize(descriptor),
  10655. CGDOMJSProxyHandler_getInstance(),
  10656. CGDOMJSProxyHandler_delete(descriptor)]
  10657. constructors = [
  10658. ClassConstructor(
  10659. [],
  10660. constexpr=True,
  10661. visibility="public",
  10662. explicit=True)
  10663. ]
  10664. if descriptor.supportsIndexedProperties():
  10665. methods.append(CGDOMJSProxyHandler_getElements(descriptor))
  10666. if (descriptor.operations['IndexedSetter'] is not None or
  10667. (descriptor.operations['NamedSetter'] is not None and
  10668. descriptor.interface.getExtendedAttribute('OverrideBuiltins'))):
  10669. methods.append(CGDOMJSProxyHandler_setCustom(descriptor))
  10670. if descriptor.hasNonOrdinaryGetPrototypeOf():
  10671. methods.append(CGDOMJSProxyHandler_getPrototypeIfOrdinary())
  10672. if descriptor.operations['LegacyCaller']:
  10673. methods.append(CGDOMJSProxyHandler_call())
  10674. methods.append(CGDOMJSProxyHandler_isCallable())
  10675. if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  10676. parentClass = 'ShadowingDOMProxyHandler'
  10677. else:
  10678. parentClass = 'mozilla::dom::DOMProxyHandler'
  10679. CGClass.__init__(self, 'DOMProxyHandler',
  10680. bases=[ClassBase(parentClass)],
  10681. constructors=constructors,
  10682. methods=methods)
  10683. class CGDOMJSProxyHandlerDeclarer(CGThing):
  10684. """
  10685. A class for declaring a DOMProxyHandler.
  10686. """
  10687. def __init__(self, handlerThing):
  10688. self.handlerThing = handlerThing
  10689. def declare(self):
  10690. # Our class declaration should happen when we're defining
  10691. return ""
  10692. def define(self):
  10693. return self.handlerThing.declare()
  10694. class CGDOMJSProxyHandlerDefiner(CGThing):
  10695. """
  10696. A class for defining a DOMProxyHandler.
  10697. """
  10698. def __init__(self, handlerThing):
  10699. self.handlerThing = handlerThing
  10700. def declare(self):
  10701. return ""
  10702. def define(self):
  10703. return self.handlerThing.define()
  10704. def stripTrailingWhitespace(text):
  10705. tail = '\n' if text.endswith('\n') else ''
  10706. lines = text.splitlines()
  10707. return '\n'.join(line.rstrip() for line in lines) + tail
  10708. class MemberProperties:
  10709. def __init__(self):
  10710. self.isGenericMethod = False
  10711. self.isCrossOriginMethod = False
  10712. self.isPromiseReturningMethod = False
  10713. self.isGenericGetter = False
  10714. self.isLenientGetter = False
  10715. self.isCrossOriginGetter = False
  10716. self.isGenericSetter = False
  10717. self.isLenientSetter = False
  10718. self.isCrossOriginSetter = False
  10719. self.isJsonifier = False
  10720. def memberProperties(m, descriptor):
  10721. props = MemberProperties()
  10722. if m.isMethod():
  10723. if m == descriptor.operations['Jsonifier']:
  10724. props.isGenericMethod = descriptor.needsSpecialGenericOps()
  10725. props.isJsonifier = True
  10726. elif (not m.isIdentifierLess() or m == descriptor.operations['Stringifier']):
  10727. if not m.isStatic() and descriptor.interface.hasInterfacePrototypeObject():
  10728. if descriptor.needsSpecialGenericOps():
  10729. if m.returnsPromise():
  10730. props.isPromiseReturningMethod = True
  10731. else:
  10732. props.isGenericMethod = True
  10733. if m.getExtendedAttribute("CrossOriginCallable"):
  10734. props.isCrossOriginMethod = True
  10735. elif m.isAttr():
  10736. if not m.isStatic() and descriptor.interface.hasInterfacePrototypeObject():
  10737. if m.hasLenientThis():
  10738. props.isLenientGetter = True
  10739. elif m.getExtendedAttribute("CrossOriginReadable"):
  10740. props.isCrossOriginGetter = True
  10741. elif descriptor.needsSpecialGenericOps():
  10742. props.isGenericGetter = True
  10743. if not m.readonly:
  10744. if not m.isStatic() and descriptor.interface.hasInterfacePrototypeObject():
  10745. if m.hasLenientThis():
  10746. props.isLenientSetter = True
  10747. elif IsCrossOriginWritable(m, descriptor):
  10748. props.isCrossOriginSetter = True
  10749. elif descriptor.needsSpecialGenericOps():
  10750. props.isGenericSetter = True
  10751. elif m.getExtendedAttribute("PutForwards"):
  10752. if IsCrossOriginWritable(m, descriptor):
  10753. props.isCrossOriginSetter = True
  10754. elif descriptor.needsSpecialGenericOps():
  10755. props.isGenericSetter = True
  10756. elif (m.getExtendedAttribute("Replaceable") or
  10757. m.getExtendedAttribute("LenientSetter")):
  10758. if descriptor.needsSpecialGenericOps():
  10759. props.isGenericSetter = True
  10760. return props
  10761. class CGDescriptor(CGThing):
  10762. def __init__(self, descriptor):
  10763. CGThing.__init__(self)
  10764. assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
  10765. self._deps = descriptor.interface.getDeps()
  10766. cgThings = []
  10767. cgThings.append(CGGeneric(declare="typedef %s NativeType;\n" %
  10768. descriptor.nativeType))
  10769. parent = descriptor.interface.parent
  10770. if parent:
  10771. cgThings.append(CGGeneric("static_assert(IsRefcounted<NativeType>::value == IsRefcounted<%s::NativeType>::value,\n"
  10772. " \"Can't inherit from an interface with a different ownership model.\");\n" %
  10773. toBindingNamespace(descriptor.parentPrototypeName)))
  10774. # These are set to true if at least one non-static
  10775. # method/getter/setter or jsonifier exist on the interface.
  10776. (hasMethod, hasGetter, hasLenientGetter, hasSetter, hasLenientSetter,
  10777. hasPromiseReturningMethod) = False, False, False, False, False, False
  10778. jsonifierMethod = None
  10779. crossOriginMethods, crossOriginGetters, crossOriginSetters = set(), set(), set()
  10780. unscopableNames = list()
  10781. for n in descriptor.interface.namedConstructors:
  10782. cgThings.append(CGClassConstructor(descriptor, n,
  10783. NamedConstructorName(n)))
  10784. for m in descriptor.interface.members:
  10785. if m.isMethod() and m.identifier.name == 'queryInterface':
  10786. continue
  10787. props = memberProperties(m, descriptor)
  10788. if m.isMethod():
  10789. if m.getExtendedAttribute("Unscopable"):
  10790. assert not m.isStatic()
  10791. unscopableNames.append(m.identifier.name)
  10792. if props.isJsonifier:
  10793. jsonifierMethod = m
  10794. elif not m.isIdentifierLess() or m == descriptor.operations['Stringifier']:
  10795. if m.isStatic():
  10796. assert descriptor.interface.hasInterfaceObject()
  10797. cgThings.append(CGStaticMethod(descriptor, m))
  10798. if m.returnsPromise():
  10799. cgThings.append(CGStaticMethodJitinfo(m))
  10800. elif descriptor.interface.hasInterfacePrototypeObject():
  10801. specializedMethod = CGSpecializedMethod(descriptor, m)
  10802. cgThings.append(specializedMethod)
  10803. if m.returnsPromise():
  10804. cgThings.append(CGMethodPromiseWrapper(descriptor, specializedMethod))
  10805. cgThings.append(CGMemberJITInfo(descriptor, m))
  10806. if props.isCrossOriginMethod:
  10807. crossOriginMethods.add(m.identifier.name)
  10808. # If we've hit the maplike/setlike member itself, go ahead and
  10809. # generate its convenience functions.
  10810. elif m.isMaplikeOrSetlike():
  10811. cgThings.append(CGMaplikeOrSetlikeHelperGenerator(descriptor, m))
  10812. elif m.isAttr():
  10813. if m.stringifier:
  10814. raise TypeError("Stringifier attributes not supported yet. "
  10815. "See bug 824857.\n"
  10816. "%s" % m.location)
  10817. if m.getExtendedAttribute("Unscopable"):
  10818. assert not m.isStatic()
  10819. unscopableNames.append(m.identifier.name)
  10820. if m.isStatic():
  10821. assert descriptor.interface.hasInterfaceObject()
  10822. cgThings.append(CGStaticGetter(descriptor, m))
  10823. elif descriptor.interface.hasInterfacePrototypeObject():
  10824. if isNonExposedNavigatorObjectGetter(m, descriptor):
  10825. continue
  10826. cgThings.append(CGSpecializedGetter(descriptor, m))
  10827. if props.isCrossOriginGetter:
  10828. crossOriginGetters.add(m.identifier.name)
  10829. if not m.readonly:
  10830. if m.isStatic():
  10831. assert descriptor.interface.hasInterfaceObject()
  10832. cgThings.append(CGStaticSetter(descriptor, m))
  10833. elif descriptor.interface.hasInterfacePrototypeObject():
  10834. cgThings.append(CGSpecializedSetter(descriptor, m))
  10835. if props.isCrossOriginSetter:
  10836. crossOriginSetters.add(m.identifier.name)
  10837. elif m.getExtendedAttribute("PutForwards"):
  10838. cgThings.append(CGSpecializedForwardingSetter(descriptor, m))
  10839. if props.isCrossOriginSetter:
  10840. crossOriginSetters.add(m.identifier.name)
  10841. elif m.getExtendedAttribute("Replaceable"):
  10842. cgThings.append(CGSpecializedReplaceableSetter(descriptor, m))
  10843. elif m.getExtendedAttribute("LenientSetter"):
  10844. cgThings.append(CGSpecializedLenientSetter(descriptor, m))
  10845. if (not m.isStatic() and
  10846. descriptor.interface.hasInterfacePrototypeObject()):
  10847. cgThings.append(CGMemberJITInfo(descriptor, m))
  10848. hasMethod = hasMethod or props.isGenericMethod
  10849. hasPromiseReturningMethod = (hasPromiseReturningMethod or
  10850. props.isPromiseReturningMethod)
  10851. hasGetter = hasGetter or props.isGenericGetter
  10852. hasLenientGetter = hasLenientGetter or props.isLenientGetter
  10853. hasSetter = hasSetter or props.isGenericSetter
  10854. hasLenientSetter = hasLenientSetter or props.isLenientSetter
  10855. if jsonifierMethod:
  10856. cgThings.append(CGJsonifyAttributesMethod(descriptor))
  10857. cgThings.append(CGJsonifierMethod(descriptor, jsonifierMethod))
  10858. cgThings.append(CGMemberJITInfo(descriptor, jsonifierMethod))
  10859. if hasMethod:
  10860. cgThings.append(CGGenericMethod(descriptor))
  10861. if hasPromiseReturningMethod:
  10862. cgThings.append(CGGenericPromiseReturningMethod(descriptor))
  10863. if len(crossOriginMethods):
  10864. cgThings.append(CGGenericMethod(descriptor,
  10865. allowCrossOriginThis=True))
  10866. if hasGetter:
  10867. cgThings.append(CGGenericGetter(descriptor))
  10868. if hasLenientGetter:
  10869. cgThings.append(CGGenericGetter(descriptor, lenientThis=True))
  10870. if len(crossOriginGetters):
  10871. cgThings.append(CGGenericGetter(descriptor,
  10872. allowCrossOriginThis=True))
  10873. if hasSetter:
  10874. cgThings.append(CGGenericSetter(descriptor))
  10875. if hasLenientSetter:
  10876. cgThings.append(CGGenericSetter(descriptor, lenientThis=True))
  10877. if len(crossOriginSetters):
  10878. cgThings.append(CGGenericSetter(descriptor,
  10879. allowCrossOriginThis=True))
  10880. if descriptor.interface.isNavigatorProperty():
  10881. cgThings.append(CGConstructNavigatorObject(descriptor))
  10882. if descriptor.concrete and not descriptor.proxy:
  10883. if wantsAddProperty(descriptor):
  10884. cgThings.append(CGAddPropertyHook(descriptor))
  10885. # Always have a finalize hook, regardless of whether the class
  10886. # wants a custom hook.
  10887. cgThings.append(CGClassFinalizeHook(descriptor))
  10888. if descriptor.concrete and descriptor.wrapperCache:
  10889. cgThings.append(CGClassObjectMovedHook(descriptor))
  10890. # Generate the _ClearCachedFooValue methods before the property arrays that use them.
  10891. if descriptor.interface.isJSImplemented():
  10892. for m in clearableCachedAttrs(descriptor):
  10893. cgThings.append(CGJSImplClearCachedValueMethod(descriptor, m))
  10894. # Need to output our generated hasinstance bits before
  10895. # PropertyArrays tries to use them.
  10896. if (descriptor.interface.hasInterfaceObject() and
  10897. NeedsGeneratedHasInstance(descriptor)):
  10898. cgThings.append(CGHasInstanceHook(descriptor))
  10899. properties = PropertyArrays(descriptor)
  10900. cgThings.append(CGGeneric(define=str(properties)))
  10901. cgThings.append(CGNativeProperties(descriptor, properties))
  10902. if descriptor.interface.hasInterfaceObject():
  10903. cgThings.append(CGClassConstructor(descriptor,
  10904. descriptor.interface.ctor()))
  10905. cgThings.append(CGInterfaceObjectJSClass(descriptor, properties))
  10906. cgThings.append(CGNamedConstructors(descriptor))
  10907. cgThings.append(CGLegacyCallHook(descriptor))
  10908. if descriptor.interface.getExtendedAttribute("NeedResolve"):
  10909. cgThings.append(CGResolveHook(descriptor))
  10910. cgThings.append(CGMayResolveHook(descriptor))
  10911. cgThings.append(CGEnumerateHook(descriptor))
  10912. if descriptor.hasNamedPropertiesObject:
  10913. cgThings.append(CGGetNamedPropertiesObjectMethod(descriptor))
  10914. if descriptor.interface.hasInterfacePrototypeObject():
  10915. cgThings.append(CGPrototypeJSClass(descriptor, properties))
  10916. if ((descriptor.interface.hasInterfaceObject() or descriptor.interface.isNavigatorProperty()) and
  10917. not descriptor.interface.isExternal() and
  10918. descriptor.isExposedConditionally()):
  10919. cgThings.append(CGConstructorEnabled(descriptor))
  10920. if descriptor.registersGlobalNamesOnWindow:
  10921. cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
  10922. if (descriptor.interface.hasMembersInSlots() and
  10923. descriptor.interface.hasChildInterfaces()):
  10924. raise TypeError("We don't support members in slots on "
  10925. "non-leaf interfaces like %s" %
  10926. descriptor.interface.identifier.name)
  10927. if descriptor.concrete:
  10928. if descriptor.proxy:
  10929. if descriptor.interface.totalMembersInSlots != 0:
  10930. raise TypeError("We can't have extra reserved slots for "
  10931. "proxy interface %s" %
  10932. descriptor.interface.identifier.name)
  10933. cgThings.append(CGGeneric(fill(
  10934. """
  10935. static_assert(IsBaseOf<nsISupports, ${nativeType} >::value,
  10936. "We don't support non-nsISupports native classes for "
  10937. "proxy-based bindings yet");
  10938. """,
  10939. nativeType=descriptor.nativeType)))
  10940. if not descriptor.wrapperCache:
  10941. raise TypeError("We need a wrappercache to support expandos for proxy-based "
  10942. "bindings (" + descriptor.name + ")")
  10943. handlerThing = CGDOMJSProxyHandler(descriptor)
  10944. cgThings.append(CGDOMJSProxyHandlerDeclarer(handlerThing))
  10945. cgThings.append(CGProxyIsProxy(descriptor))
  10946. cgThings.append(CGProxyUnwrap(descriptor))
  10947. cgThings.append(CGDOMJSProxyHandlerDefiner(handlerThing))
  10948. cgThings.append(CGDOMProxyJSClass(descriptor))
  10949. else:
  10950. cgThings.append(CGDOMJSClass(descriptor))
  10951. cgThings.append(CGGetJSClassMethod(descriptor))
  10952. if descriptor.interface.hasMembersInSlots():
  10953. cgThings.append(CGUpdateMemberSlotsMethod(descriptor))
  10954. if descriptor.isGlobal():
  10955. assert descriptor.wrapperCache
  10956. cgThings.append(CGWrapGlobalMethod(descriptor, properties))
  10957. elif descriptor.wrapperCache:
  10958. cgThings.append(CGWrapWithCacheMethod(descriptor, properties))
  10959. cgThings.append(CGWrapMethod(descriptor))
  10960. else:
  10961. cgThings.append(CGWrapNonWrapperCacheMethod(descriptor,
  10962. properties))
  10963. # Set up our Xray callbacks as needed. This needs to come
  10964. # after we have our DOMProxyHandler defined.
  10965. if descriptor.wantsXrays:
  10966. if descriptor.concrete and descriptor.proxy:
  10967. cgThings.append(CGResolveOwnProperty(descriptor))
  10968. cgThings.append(CGEnumerateOwnProperties(descriptor))
  10969. if descriptor.needsXrayNamedDeleterHook():
  10970. cgThings.append(CGDeleteNamedProperty(descriptor))
  10971. elif descriptor.needsXrayResolveHooks():
  10972. cgThings.append(CGResolveOwnPropertyViaResolve(descriptor))
  10973. cgThings.append(CGEnumerateOwnPropertiesViaGetOwnPropertyNames(descriptor))
  10974. if descriptor.wantsXrayExpandoClass:
  10975. cgThings.append(CGXrayExpandoJSClass(descriptor))
  10976. # Now that we have our ResolveOwnProperty/EnumerateOwnProperties stuff
  10977. # done, set up our NativePropertyHooks.
  10978. cgThings.append(CGNativePropertyHooks(descriptor, properties))
  10979. # If we're not wrappercached, we don't know how to clear our
  10980. # cached values, since we can't get at the JSObject.
  10981. if descriptor.wrapperCache:
  10982. cgThings.extend(CGClearCachedValueMethod(descriptor, m) for
  10983. m in clearableCachedAttrs(descriptor))
  10984. haveUnscopables = (len(unscopableNames) != 0 and
  10985. descriptor.interface.hasInterfacePrototypeObject())
  10986. if haveUnscopables:
  10987. cgThings.append(
  10988. CGList([CGGeneric("static const char* const unscopableNames[] = {"),
  10989. CGIndenter(CGList([CGGeneric('"%s"' % name) for
  10990. name in unscopableNames] +
  10991. [CGGeneric("nullptr")], ",\n")),
  10992. CGGeneric("};\n")], "\n"))
  10993. # CGCreateInterfaceObjectsMethod needs to come after our
  10994. # CGDOMJSClass and unscopables, if any.
  10995. cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties,
  10996. haveUnscopables))
  10997. # CGGetProtoObjectMethod and CGGetConstructorObjectMethod need
  10998. # to come after CGCreateInterfaceObjectsMethod.
  10999. if descriptor.interface.hasInterfacePrototypeObject():
  11000. cgThings.append(CGGetProtoObjectHandleMethod(descriptor))
  11001. if descriptor.interface.hasChildInterfaces():
  11002. cgThings.append(CGGetProtoObjectMethod(descriptor))
  11003. if descriptor.interface.hasInterfaceObject():
  11004. cgThings.append(CGGetConstructorObjectHandleMethod(descriptor))
  11005. cgThings.append(CGGetConstructorObjectMethod(descriptor))
  11006. # See whether we need we need to generate an IsPermitted method
  11007. if crossOriginGetters or crossOriginSetters or crossOriginMethods:
  11008. cgThings.append(CGIsPermittedMethod(descriptor,
  11009. crossOriginGetters,
  11010. crossOriginSetters,
  11011. crossOriginMethods))
  11012. cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n")
  11013. cgThings = CGWrapper(cgThings, pre='\n', post='\n')
  11014. self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
  11015. cgThings),
  11016. post='\n')
  11017. def declare(self):
  11018. return self.cgRoot.declare()
  11019. def define(self):
  11020. return self.cgRoot.define()
  11021. def deps(self):
  11022. return self._deps
  11023. class CGNamespacedEnum(CGThing):
  11024. def __init__(self, namespace, enumName, names, values, comment=""):
  11025. if not values:
  11026. values = []
  11027. # Account for explicit enum values.
  11028. entries = []
  11029. for i in range(0, len(names)):
  11030. if len(values) > i and values[i] is not None:
  11031. entry = "%s = %s" % (names[i], values[i])
  11032. else:
  11033. entry = names[i]
  11034. entries.append(entry)
  11035. # Append a Count.
  11036. entries.append('_' + enumName + '_Count')
  11037. # Indent.
  11038. entries = [' ' + e for e in entries]
  11039. # Build the enum body.
  11040. enumstr = comment + 'enum %s : uint16_t\n{\n%s\n};\n' % (enumName, ',\n'.join(entries))
  11041. curr = CGGeneric(declare=enumstr)
  11042. # Add some whitespace padding.
  11043. curr = CGWrapper(curr, pre='\n', post='\n')
  11044. # Add the namespace.
  11045. curr = CGNamespace(namespace, curr)
  11046. # Add the typedef
  11047. typedef = '\ntypedef %s::%s %s;\n\n' % (namespace, enumName, enumName)
  11048. curr = CGList([curr, CGGeneric(declare=typedef)])
  11049. # Save the result.
  11050. self.node = curr
  11051. def declare(self):
  11052. return self.node.declare()
  11053. def define(self):
  11054. return ""
  11055. def initIdsClassMethod(identifiers, atomCacheName):
  11056. idinit = ['!atomsCache->%s.init(cx, "%s")' %
  11057. (CGDictionary.makeIdName(id),
  11058. id)
  11059. for id in identifiers]
  11060. idinit.reverse()
  11061. body = fill(
  11062. """
  11063. MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache));
  11064. // Initialize these in reverse order so that any failure leaves the first one
  11065. // uninitialized.
  11066. if (${idinit}) {
  11067. return false;
  11068. }
  11069. return true;
  11070. """,
  11071. idinit=" ||\n ".join(idinit))
  11072. return ClassMethod("InitIds", "bool", [
  11073. Argument("JSContext*", "cx"),
  11074. Argument("%s*" % atomCacheName, "atomsCache")
  11075. ], static=True, body=body, visibility="private")
  11076. class CGDictionary(CGThing):
  11077. def __init__(self, dictionary, descriptorProvider):
  11078. self.dictionary = dictionary
  11079. self.descriptorProvider = descriptorProvider
  11080. self.needToInitIds = len(dictionary.members) > 0
  11081. self.memberInfo = [
  11082. (member,
  11083. getJSToNativeConversionInfo(
  11084. member.type,
  11085. descriptorProvider,
  11086. isEnforceRange=member.enforceRange,
  11087. isClamp=member.clamp,
  11088. isMember="Dictionary",
  11089. isOptional=member.canHaveMissingValue(),
  11090. defaultValue=member.defaultValue,
  11091. sourceDescription=self.getMemberSourceDescription(member)))
  11092. for member in dictionary.members]
  11093. # If we have a union member containing something in the same
  11094. # file as us, bail: the C++ includes won't work out.
  11095. for member in dictionary.members:
  11096. type = member.type.unroll()
  11097. if type.isUnion():
  11098. for t in type.flatMemberTypes:
  11099. if (t.isDictionary() and
  11100. CGHeaders.getDeclarationFilename(t.inner) ==
  11101. CGHeaders.getDeclarationFilename(dictionary)):
  11102. raise TypeError(
  11103. "Dictionary contains a union that contains a "
  11104. "dictionary in the same WebIDL file. This won't "
  11105. "compile. Move the inner dictionary to a "
  11106. "different file.\n%s\n%s" %
  11107. (t.location, t.inner.location))
  11108. self.structs = self.getStructs()
  11109. def declare(self):
  11110. return self.structs.declare()
  11111. def define(self):
  11112. return self.structs.define()
  11113. def base(self):
  11114. if self.dictionary.parent:
  11115. return self.makeClassName(self.dictionary.parent)
  11116. return "DictionaryBase"
  11117. def initMethod(self):
  11118. """
  11119. This function outputs the body of the Init() method for the dictionary.
  11120. For the most part, this is some bookkeeping for our atoms so
  11121. we can avoid atomizing strings all the time, then we just spit
  11122. out the getMemberConversion() output for each member,
  11123. separated by newlines.
  11124. """
  11125. body = dedent("""
  11126. // Passing a null JSContext is OK only if we're initing from null,
  11127. // Since in that case we will not have to do any property gets
  11128. MOZ_ASSERT_IF(!cx, val.isNull());
  11129. """)
  11130. if self.needToInitIds:
  11131. body += fill(
  11132. """
  11133. ${dictName}Atoms* atomsCache = nullptr;
  11134. if (cx) {
  11135. atomsCache = GetAtomCache<${dictName}Atoms>(cx);
  11136. if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
  11137. return false;
  11138. }
  11139. }
  11140. """,
  11141. dictName=self.makeClassName(self.dictionary))
  11142. if self.dictionary.parent:
  11143. body += fill(
  11144. """
  11145. // Per spec, we init the parent's members first
  11146. if (!${dictName}::Init(cx, val)) {
  11147. return false;
  11148. }
  11149. """,
  11150. dictName=self.makeClassName(self.dictionary.parent))
  11151. else:
  11152. body += dedent(
  11153. """
  11154. { // scope for isConvertible
  11155. bool isConvertible;
  11156. if (!IsConvertibleToDictionary(cx, val, &isConvertible)) {
  11157. return false;
  11158. }
  11159. if (!isConvertible) {
  11160. return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
  11161. }
  11162. }
  11163. """)
  11164. memberInits = [self.getMemberConversion(m).define()
  11165. for m in self.memberInfo]
  11166. if memberInits:
  11167. body += fill(
  11168. """
  11169. bool isNull = val.isNullOrUndefined();
  11170. // We only need these if !isNull, in which case we have |cx|.
  11171. Maybe<JS::Rooted<JSObject *> > object;
  11172. Maybe<JS::Rooted<JS::Value> > temp;
  11173. if (!isNull) {
  11174. MOZ_ASSERT(cx);
  11175. object.emplace(cx, &val.toObject());
  11176. temp.emplace(cx);
  11177. }
  11178. $*{memberInits}
  11179. """,
  11180. memberInits="\n".join(memberInits))
  11181. body += "return true;\n"
  11182. return ClassMethod("Init", "bool", [
  11183. Argument('JSContext*', 'cx'),
  11184. Argument('JS::Handle<JS::Value>', 'val'),
  11185. Argument('const char*', 'sourceDescription', default='"Value"'),
  11186. Argument('bool', 'passedToJSImpl', default='false')
  11187. ], body=body)
  11188. def initFromJSONMethod(self):
  11189. return ClassMethod(
  11190. "Init", "bool",
  11191. [Argument('const nsAString&', 'aJSON')],
  11192. body=dedent("""
  11193. AutoJSAPI jsapi;
  11194. JSObject* cleanGlobal = SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail);
  11195. if (!cleanGlobal) {
  11196. return false;
  11197. }
  11198. if (!jsapi.Init(cleanGlobal)) {
  11199. return false;
  11200. }
  11201. JSContext* cx = jsapi.cx();
  11202. JS::Rooted<JS::Value> json(cx);
  11203. bool ok = ParseJSON(cx, aJSON, &json);
  11204. NS_ENSURE_TRUE(ok, false);
  11205. return Init(cx, json);
  11206. """))
  11207. def toJSONMethod(self):
  11208. return ClassMethod(
  11209. "ToJSON", "bool",
  11210. [Argument('nsAString&', 'aJSON')],
  11211. body=dedent("""
  11212. AutoJSAPI jsapi;
  11213. jsapi.Init();
  11214. JSContext *cx = jsapi.cx();
  11215. // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
  11216. // because we'll only be creating objects, in ways that have no
  11217. // side-effects, followed by a call to JS::ToJSONMaybeSafely,
  11218. // which likewise guarantees no side-effects for the sorts of
  11219. // things we will pass it.
  11220. JSAutoCompartment ac(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
  11221. JS::Rooted<JS::Value> val(cx);
  11222. if (!ToObjectInternal(cx, &val)) {
  11223. return false;
  11224. }
  11225. JS::Rooted<JSObject*> obj(cx, &val.toObject());
  11226. return StringifyToJSON(cx, obj, aJSON);
  11227. """), const=True)
  11228. def toObjectInternalMethod(self):
  11229. body = ""
  11230. if self.needToInitIds:
  11231. body += fill(
  11232. """
  11233. ${dictName}Atoms* atomsCache = GetAtomCache<${dictName}Atoms>(cx);
  11234. if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
  11235. return false;
  11236. }
  11237. """,
  11238. dictName=self.makeClassName(self.dictionary))
  11239. if self.dictionary.parent:
  11240. body += fill(
  11241. """
  11242. // Per spec, we define the parent's members first
  11243. if (!${dictName}::ToObjectInternal(cx, rval)) {
  11244. return false;
  11245. }
  11246. JS::Rooted<JSObject*> obj(cx, &rval.toObject());
  11247. """,
  11248. dictName=self.makeClassName(self.dictionary.parent))
  11249. else:
  11250. body += dedent(
  11251. """
  11252. JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
  11253. if (!obj) {
  11254. return false;
  11255. }
  11256. rval.set(JS::ObjectValue(*obj));
  11257. """)
  11258. if self.memberInfo:
  11259. body += "\n".join(self.getMemberDefinition(m).define()
  11260. for m in self.memberInfo)
  11261. body += "\nreturn true;\n"
  11262. return ClassMethod("ToObjectInternal", "bool", [
  11263. Argument('JSContext*', 'cx'),
  11264. Argument('JS::MutableHandle<JS::Value>', 'rval'),
  11265. ], const=True, body=body)
  11266. def initIdsMethod(self):
  11267. assert self.needToInitIds
  11268. return initIdsClassMethod([m.identifier.name for m in self.dictionary.members],
  11269. "%sAtoms" % self.makeClassName(self.dictionary))
  11270. def traceDictionaryMethod(self):
  11271. body = ""
  11272. if self.dictionary.parent:
  11273. cls = self.makeClassName(self.dictionary.parent)
  11274. body += "%s::TraceDictionary(trc);\n" % cls
  11275. memberTraces = [self.getMemberTrace(m)
  11276. for m in self.dictionary.members
  11277. if typeNeedsRooting(m.type)]
  11278. if memberTraces:
  11279. body += "\n".join(memberTraces)
  11280. return ClassMethod("TraceDictionary", "void", [
  11281. Argument("JSTracer*", "trc"),
  11282. ], body=body)
  11283. def assignmentOperator(self):
  11284. body = CGList([])
  11285. if self.dictionary.parent:
  11286. body.append(CGGeneric(
  11287. "%s::operator=(aOther);\n" %
  11288. self.makeClassName(self.dictionary.parent)))
  11289. for m, _ in self.memberInfo:
  11290. memberName = self.makeMemberName(m.identifier.name)
  11291. if m.canHaveMissingValue():
  11292. memberAssign = CGGeneric(fill(
  11293. """
  11294. ${name}.Reset();
  11295. if (aOther.${name}.WasPassed()) {
  11296. ${name}.Construct(aOther.${name}.Value());
  11297. }
  11298. """,
  11299. name=memberName))
  11300. else:
  11301. memberAssign = CGGeneric(
  11302. "%s = aOther.%s;\n" % (memberName, memberName))
  11303. body.append(memberAssign)
  11304. return ClassMethod(
  11305. "operator=", "void",
  11306. [Argument("const %s&" % self.makeClassName(self.dictionary),
  11307. "aOther")],
  11308. body=body.define())
  11309. def getStructs(self):
  11310. d = self.dictionary
  11311. selfName = self.makeClassName(d)
  11312. members = [ClassMember(self.makeMemberName(m[0].identifier.name),
  11313. self.getMemberType(m),
  11314. visibility="public",
  11315. body=self.getMemberInitializer(m),
  11316. hasIgnoreInitCheckFlag=True)
  11317. for m in self.memberInfo]
  11318. if d.parent:
  11319. # We always want to init our parent with our non-initializing
  11320. # constructor arg, because either we're about to init ourselves (and
  11321. # hence our parent) or we don't want any init happening.
  11322. baseConstructors = [
  11323. "%s(%s)" % (self.makeClassName(d.parent),
  11324. self.getNonInitializingCtorArg())
  11325. ]
  11326. else:
  11327. baseConstructors = None
  11328. ctors = [
  11329. ClassConstructor(
  11330. [],
  11331. visibility="public",
  11332. baseConstructors=baseConstructors,
  11333. body=(
  11334. "// Safe to pass a null context if we pass a null value\n"
  11335. "Init(nullptr, JS::NullHandleValue);\n")),
  11336. ClassConstructor(
  11337. [Argument("const FastDictionaryInitializer&", "")],
  11338. visibility="public",
  11339. baseConstructors=baseConstructors,
  11340. explicit=True,
  11341. bodyInHeader=True,
  11342. body='// Do nothing here; this is used by our "Fast" subclass\n')
  11343. ]
  11344. methods = []
  11345. if self.needToInitIds:
  11346. methods.append(self.initIdsMethod())
  11347. methods.append(self.initMethod())
  11348. canBeRepresentedAsJSON = self.dictionarySafeToJSONify(self.dictionary)
  11349. if canBeRepresentedAsJSON:
  11350. methods.append(self.initFromJSONMethod())
  11351. try:
  11352. methods.append(self.toObjectInternalMethod())
  11353. if canBeRepresentedAsJSON:
  11354. methods.append(self.toJSONMethod())
  11355. except MethodNotNewObjectError:
  11356. # If we can't have a ToObjectInternal() because one of our members
  11357. # can only be returned from [NewObject] methods, then just skip
  11358. # generating ToObjectInternal() and ToJSON (since the latter depens
  11359. # on the former).
  11360. pass
  11361. methods.append(self.traceDictionaryMethod())
  11362. if CGDictionary.isDictionaryCopyConstructible(d):
  11363. disallowCopyConstruction = False
  11364. # Note: no base constructors because our operator= will
  11365. # deal with that.
  11366. ctors.append(ClassConstructor([Argument("const %s&" % selfName,
  11367. "aOther")],
  11368. bodyInHeader=True,
  11369. visibility="public",
  11370. explicit=True,
  11371. body="*this = aOther;\n"))
  11372. methods.append(self.assignmentOperator())
  11373. else:
  11374. disallowCopyConstruction = True
  11375. struct = CGClass(selfName,
  11376. bases=[ClassBase(self.base())],
  11377. members=members,
  11378. constructors=ctors,
  11379. methods=methods,
  11380. isStruct=True,
  11381. disallowCopyConstruction=disallowCopyConstruction)
  11382. fastDictionaryCtor = ClassConstructor(
  11383. [],
  11384. visibility="public",
  11385. bodyInHeader=True,
  11386. baseConstructors=["%s(%s)" %
  11387. (selfName,
  11388. self.getNonInitializingCtorArg())],
  11389. body="// Doesn't matter what int we pass to the parent constructor\n")
  11390. fastStruct = CGClass("Fast" + selfName,
  11391. bases=[ClassBase(selfName)],
  11392. constructors=[fastDictionaryCtor],
  11393. isStruct=True)
  11394. return CGList([struct,
  11395. CGNamespace('binding_detail', fastStruct)],
  11396. "\n")
  11397. def deps(self):
  11398. return self.dictionary.getDeps()
  11399. @staticmethod
  11400. def makeDictionaryName(dictionary):
  11401. return dictionary.identifier.name
  11402. def makeClassName(self, dictionary):
  11403. return self.makeDictionaryName(dictionary)
  11404. @staticmethod
  11405. def makeMemberName(name):
  11406. return "m" + name[0].upper() + IDLToCIdentifier(name[1:])
  11407. def getMemberType(self, memberInfo):
  11408. _, conversionInfo = memberInfo
  11409. # We can't handle having a holderType here
  11410. assert conversionInfo.holderType is None
  11411. declType = conversionInfo.declType
  11412. if conversionInfo.dealWithOptional:
  11413. declType = CGTemplatedType("Optional", declType)
  11414. return declType.define()
  11415. def getMemberConversion(self, memberInfo):
  11416. """
  11417. A function that outputs the initialization of a single dictionary
  11418. member from the given dictionary value.
  11419. We start with our conversionInfo, which tells us how to
  11420. convert a JS::Value to whatever type this member is. We
  11421. substiture the template from the conversionInfo with values
  11422. that point to our "temp" JS::Value and our member (which is
  11423. the C++ value we want to produce). The output is a string of
  11424. code to do the conversion. We store this string in
  11425. conversionReplacements["convert"].
  11426. Now we have three different ways we might use (or skip) this
  11427. string of code, depending on whether the value is required,
  11428. optional with default value, or optional without default
  11429. value. We set up a template in the 'conversion' variable for
  11430. exactly how to do this, then substitute into it from the
  11431. conversionReplacements dictionary.
  11432. """
  11433. member, conversionInfo = memberInfo
  11434. replacements = {
  11435. "val": "temp.ref()",
  11436. "maybeMutableVal": "temp.ptr()",
  11437. "declName": self.makeMemberName(member.identifier.name),
  11438. # We need a holder name for external interfaces, but
  11439. # it's scoped down to the conversion so we can just use
  11440. # anything we want.
  11441. "holderName": "holder",
  11442. "passedToJSImpl": "passedToJSImpl"
  11443. }
  11444. # We can't handle having a holderType here
  11445. assert conversionInfo.holderType is None
  11446. if conversionInfo.dealWithOptional:
  11447. replacements["declName"] = "(" + replacements["declName"] + ".Value())"
  11448. if member.defaultValue:
  11449. replacements["haveValue"] = "!isNull && !temp->isUndefined()"
  11450. propId = self.makeIdName(member.identifier.name)
  11451. propGet = ("JS_GetPropertyById(cx, *object, atomsCache->%s, temp.ptr())" %
  11452. propId)
  11453. conversionReplacements = {
  11454. "prop": self.makeMemberName(member.identifier.name),
  11455. "convert": string.Template(conversionInfo.template).substitute(replacements),
  11456. "propGet": propGet
  11457. }
  11458. # The conversion code will only run where a default value or a value passed
  11459. # by the author needs to get converted, so we can remember if we have any
  11460. # members present here.
  11461. conversionReplacements["convert"] += "mIsAnyMemberPresent = true;\n"
  11462. setTempValue = CGGeneric(dedent(
  11463. """
  11464. if (!${propGet}) {
  11465. return false;
  11466. }
  11467. """))
  11468. conditions = getConditionList(member, "cx", "*object")
  11469. if len(conditions) != 0:
  11470. setTempValue = CGIfElseWrapper(conditions.define(),
  11471. setTempValue,
  11472. CGGeneric("temp->setUndefined();\n"))
  11473. setTempValue = CGIfWrapper(setTempValue, "!isNull")
  11474. conversion = setTempValue.define()
  11475. if member.defaultValue:
  11476. if (member.type.isUnion() and
  11477. (not member.type.nullable() or
  11478. not isinstance(member.defaultValue, IDLNullValue))):
  11479. # Since this has a default value, it might have been initialized
  11480. # already. Go ahead and uninit it before we try to init it
  11481. # again.
  11482. memberName = self.makeMemberName(member.identifier.name)
  11483. if member.type.nullable():
  11484. conversion += fill(
  11485. """
  11486. if (!${memberName}.IsNull()) {
  11487. ${memberName}.Value().Uninit();
  11488. }
  11489. """,
  11490. memberName=memberName)
  11491. else:
  11492. conversion += "%s.Uninit();\n" % memberName
  11493. conversion += "${convert}"
  11494. elif not conversionInfo.dealWithOptional:
  11495. # We're required, but have no default value. Make sure
  11496. # that we throw if we have no value provided.
  11497. conversion += dedent(
  11498. """
  11499. if (!isNull && !temp->isUndefined()) {
  11500. ${convert}
  11501. } else if (cx) {
  11502. // Don't error out if we have no cx. In that
  11503. // situation the caller is default-constructing us and we'll
  11504. // just assume they know what they're doing.
  11505. return ThrowErrorMessage(cx, MSG_MISSING_REQUIRED_DICTIONARY_MEMBER,
  11506. "%s");
  11507. }
  11508. """ % self.getMemberSourceDescription(member))
  11509. conversionReplacements["convert"] = indent(conversionReplacements["convert"]).rstrip()
  11510. else:
  11511. conversion += (
  11512. "if (!isNull && !temp->isUndefined()) {\n"
  11513. " ${prop}.Construct();\n"
  11514. "${convert}"
  11515. "}\n")
  11516. conversionReplacements["convert"] = indent(conversionReplacements["convert"])
  11517. return CGGeneric(
  11518. string.Template(conversion).substitute(conversionReplacements))
  11519. def getMemberDefinition(self, memberInfo):
  11520. member = memberInfo[0]
  11521. declType = memberInfo[1].declType
  11522. memberLoc = self.makeMemberName(member.identifier.name)
  11523. if not member.canHaveMissingValue():
  11524. memberData = memberLoc
  11525. else:
  11526. # The data is inside the Optional<>
  11527. memberData = "%s.InternalValue()" % memberLoc
  11528. # If you have to change this list (which you shouldn't!), make sure it
  11529. # continues to match the list in test_Object.prototype_props.html
  11530. if (member.identifier.name in
  11531. ["constructor", "toSource", "toString", "toLocaleString", "valueOf",
  11532. "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
  11533. "__defineGetter__", "__defineSetter__", "__lookupGetter__",
  11534. "__lookupSetter__", "__proto__"]):
  11535. raise TypeError("'%s' member of %s dictionary shadows "
  11536. "a property of Object.prototype, and Xrays to "
  11537. "Object can't handle that.\n"
  11538. "%s" %
  11539. (member.identifier.name,
  11540. self.dictionary.identifier.name,
  11541. member.location))
  11542. propDef = (
  11543. 'JS_DefinePropertyById(cx, obj, atomsCache->%s, temp, JSPROP_ENUMERATE)' %
  11544. self.makeIdName(member.identifier.name))
  11545. innerTemplate = wrapForType(
  11546. member.type, self.descriptorProvider,
  11547. {
  11548. 'result': "currentValue",
  11549. 'successCode': ("if (!%s) {\n"
  11550. " return false;\n"
  11551. "}\n"
  11552. "break;\n" % propDef),
  11553. 'jsvalRef': "temp",
  11554. 'jsvalHandle': "&temp",
  11555. 'returnsNewObject': False,
  11556. # 'obj' can just be allowed to be the string "obj", since that
  11557. # will be our dictionary object, which is presumably itself in
  11558. # the right scope.
  11559. 'typedArraysAreStructs': True
  11560. })
  11561. conversion = CGGeneric(innerTemplate)
  11562. conversion = CGWrapper(conversion,
  11563. pre=("JS::Rooted<JS::Value> temp(cx);\n"
  11564. "%s const & currentValue = %s;\n" %
  11565. (declType.define(), memberData)
  11566. ))
  11567. # Now make sure that our successCode can actually break out of the
  11568. # conversion. This incidentally gives us a scope for 'temp' and
  11569. # 'currentValue'.
  11570. conversion = CGWrapper(
  11571. CGIndenter(conversion),
  11572. pre=("do {\n"
  11573. " // block for our 'break' successCode and scope for 'temp' and 'currentValue'\n"),
  11574. post="} while(0);\n")
  11575. if member.canHaveMissingValue():
  11576. # Only do the conversion if we have a value
  11577. conversion = CGIfWrapper(conversion, "%s.WasPassed()" % memberLoc)
  11578. conditions = getConditionList(member, "cx", "obj")
  11579. if len(conditions) != 0:
  11580. conversion = CGIfWrapper(conversion, conditions.define())
  11581. return conversion
  11582. def getMemberTrace(self, member):
  11583. type = member.type
  11584. assert typeNeedsRooting(type)
  11585. memberLoc = self.makeMemberName(member.identifier.name)
  11586. if not member.canHaveMissingValue():
  11587. memberData = memberLoc
  11588. else:
  11589. # The data is inside the Optional<>
  11590. memberData = "%s.Value()" % memberLoc
  11591. memberName = "%s.%s" % (self.makeClassName(self.dictionary),
  11592. memberLoc)
  11593. if type.isObject():
  11594. trace = CGGeneric('JS::UnsafeTraceRoot(trc, %s, "%s");\n' %
  11595. ("&"+memberData, memberName))
  11596. if type.nullable():
  11597. trace = CGIfWrapper(trace, memberData)
  11598. elif type.isAny():
  11599. trace = CGGeneric('JS::UnsafeTraceRoot(trc, %s, "%s");\n' %
  11600. ("&"+memberData, memberName))
  11601. elif (type.isSequence() or type.isDictionary() or
  11602. type.isSpiderMonkeyInterface() or type.isUnion()):
  11603. if type.nullable():
  11604. memberNullable = memberData
  11605. memberData = "%s.Value()" % memberData
  11606. if type.isSequence():
  11607. trace = CGGeneric('DoTraceSequence(trc, %s);\n' % memberData)
  11608. elif type.isDictionary():
  11609. trace = CGGeneric('%s.TraceDictionary(trc);\n' % memberData)
  11610. elif type.isUnion():
  11611. trace = CGGeneric('%s.TraceUnion(trc);\n' % memberData)
  11612. else:
  11613. assert type.isSpiderMonkeyInterface()
  11614. trace = CGGeneric('%s.TraceSelf(trc);\n' % memberData)
  11615. if type.nullable():
  11616. trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable)
  11617. elif type.isRecord():
  11618. # If you implement this, add a record<DOMString, object> to
  11619. # TestInterfaceJSDictionary and test it in test_bug1036214.html
  11620. # to make sure we end up with the correct security properties.
  11621. assert False
  11622. else:
  11623. assert False # unknown type
  11624. if member.canHaveMissingValue():
  11625. trace = CGIfWrapper(trace, "%s.WasPassed()" % memberLoc)
  11626. return trace.define()
  11627. def getMemberInitializer(self, memberInfo):
  11628. """
  11629. Get the right initializer for the member. Most members don't need one,
  11630. but we need to pre-initialize 'any' and 'object' that have a default
  11631. value, so they're safe to trace at all times.
  11632. """
  11633. member, _ = memberInfo
  11634. if member.canHaveMissingValue():
  11635. # Allowed missing value means no need to set it up front, since it's
  11636. # inside an Optional and won't get traced until it's actually set
  11637. # up.
  11638. return None
  11639. type = member.type
  11640. if type.isAny():
  11641. return "JS::UndefinedValue()"
  11642. if type.isObject():
  11643. return "nullptr"
  11644. if type.isDictionary():
  11645. # When we construct ourselves, we don't want to init our member
  11646. # dictionaries. Either we're being constructed-but-not-initialized
  11647. # ourselves (and then we don't want to init them) or we're about to
  11648. # init ourselves and then we'll init them anyway.
  11649. return CGDictionary.getNonInitializingCtorArg()
  11650. return None
  11651. def getMemberSourceDescription(self, member):
  11652. return ("'%s' member of %s" %
  11653. (member.identifier.name, self.dictionary.identifier.name))
  11654. @staticmethod
  11655. def makeIdName(name):
  11656. return IDLToCIdentifier(name) + "_id"
  11657. @staticmethod
  11658. def getNonInitializingCtorArg():
  11659. return "FastDictionaryInitializer()"
  11660. @staticmethod
  11661. def isDictionaryCopyConstructible(dictionary):
  11662. if (dictionary.parent and
  11663. not CGDictionary.isDictionaryCopyConstructible(dictionary.parent)):
  11664. return False
  11665. return all(isTypeCopyConstructible(m.type) for m in dictionary.members)
  11666. @staticmethod
  11667. def typeSafeToJSONify(type):
  11668. """
  11669. Determine whether the given type is safe to convert to JSON. The
  11670. restriction is that this needs to be safe while in a global controlled
  11671. by an adversary, and "safe" means no side-effects when the JS
  11672. representation of this type is converted to JSON. That means that we
  11673. have to be pretty restrictive about what things we can allow. For
  11674. example, "object" is out, because it may have accessor properties on it.
  11675. """
  11676. if type.nullable():
  11677. # Converting null to JSON is always OK.
  11678. return CGDictionary.typeSafeToJSONify(type.inner)
  11679. if type.isSequence():
  11680. # Sequences are arrays we create ourselves, with no holes. They
  11681. # should be safe if their contents are safe, as long as we suppress
  11682. # invocation of .toJSON on objects.
  11683. return CGDictionary.typeSafeToJSONify(type.inner)
  11684. if type.isUnion():
  11685. # OK if everything in it is ok.
  11686. return all(CGDictionary.typeSafeToJSONify(t)
  11687. for t in type.flatMemberTypes)
  11688. if type.isDictionary():
  11689. # OK if the dictionary is OK
  11690. return CGDictionary.dictionarySafeToJSONify(type.inner)
  11691. if type.isString() or type.isEnum():
  11692. # Strings are always OK.
  11693. return True
  11694. if type.isPrimitive():
  11695. # Primitives (numbers and booleans) are ok, as long as
  11696. # they're not unrestricted float/double.
  11697. return not type.isFloat() or not type.isUnrestricted()
  11698. return False
  11699. @staticmethod
  11700. def dictionarySafeToJSONify(dictionary):
  11701. # The dictionary itself is OK, so we're good if all our types are.
  11702. return all(CGDictionary.typeSafeToJSONify(m.type)
  11703. for m in dictionary.members)
  11704. class CGRegisterWorkerBindings(CGAbstractMethod):
  11705. def __init__(self, config):
  11706. CGAbstractMethod.__init__(self, None, 'RegisterWorkerBindings', 'bool',
  11707. [Argument('JSContext*', 'aCx'),
  11708. Argument('JS::Handle<JSObject*>', 'aObj')])
  11709. self.config = config
  11710. def definition_body(self):
  11711. descriptors = self.config.getDescriptors(hasInterfaceObject=True,
  11712. isExposedInAnyWorker=True,
  11713. register=True)
  11714. conditions = []
  11715. for desc in descriptors:
  11716. bindingNS = toBindingNamespace(desc.name)
  11717. condition = "!%s::GetConstructorObject(aCx)" % bindingNS
  11718. if desc.isExposedConditionally():
  11719. condition = (
  11720. "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
  11721. + condition)
  11722. conditions.append(condition)
  11723. lines = [CGIfWrapper(CGGeneric("return false;\n"), condition) for
  11724. condition in conditions]
  11725. lines.append(CGGeneric("return true;\n"))
  11726. return CGList(lines, "\n").define()
  11727. class CGRegisterWorkerDebuggerBindings(CGAbstractMethod):
  11728. def __init__(self, config):
  11729. CGAbstractMethod.__init__(self, None, 'RegisterWorkerDebuggerBindings', 'bool',
  11730. [Argument('JSContext*', 'aCx'),
  11731. Argument('JS::Handle<JSObject*>', 'aObj')])
  11732. self.config = config
  11733. def definition_body(self):
  11734. descriptors = self.config.getDescriptors(hasInterfaceObject=True,
  11735. isExposedInWorkerDebugger=True,
  11736. register=True)
  11737. conditions = []
  11738. for desc in descriptors:
  11739. bindingNS = toBindingNamespace(desc.name)
  11740. condition = "!%s::GetConstructorObject(aCx)" % bindingNS
  11741. if desc.isExposedConditionally():
  11742. condition = (
  11743. "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
  11744. + condition)
  11745. conditions.append(condition)
  11746. lines = [CGIfWrapper(CGGeneric("return false;\n"), condition) for
  11747. condition in conditions]
  11748. lines.append(CGGeneric("return true;\n"))
  11749. return CGList(lines, "\n").define()
  11750. class CGRegisterWorkletBindings(CGAbstractMethod):
  11751. def __init__(self, config):
  11752. CGAbstractMethod.__init__(self, None, 'RegisterWorkletBindings', 'bool',
  11753. [Argument('JSContext*', 'aCx'),
  11754. Argument('JS::Handle<JSObject*>', 'aObj')])
  11755. self.config = config
  11756. def definition_body(self):
  11757. descriptors = self.config.getDescriptors(hasInterfaceObject=True,
  11758. isExposedInAnyWorklet=True,
  11759. register=True)
  11760. conditions = []
  11761. for desc in descriptors:
  11762. bindingNS = toBindingNamespace(desc.name)
  11763. condition = "!%s::GetConstructorObject(aCx)" % bindingNS
  11764. if desc.isExposedConditionally():
  11765. condition = (
  11766. "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
  11767. + condition)
  11768. conditions.append(condition)
  11769. lines = [CGIfWrapper(CGGeneric("return false;\n"), condition) for
  11770. condition in conditions]
  11771. lines.append(CGGeneric("return true;\n"))
  11772. return CGList(lines, "\n").define()
  11773. class CGResolveSystemBinding(CGAbstractMethod):
  11774. def __init__(self, config):
  11775. CGAbstractMethod.__init__(self, None, 'ResolveSystemBinding', 'bool',
  11776. [Argument('JSContext*', 'aCx'),
  11777. Argument('JS::Handle<JSObject*>', 'aObj'),
  11778. Argument('JS::Handle<jsid>', 'aId'),
  11779. Argument('bool*', 'aResolvedp')])
  11780. self.config = config
  11781. def definition_body(self):
  11782. descriptors = self.config.getDescriptors(hasInterfaceObject=True,
  11783. isExposedInSystemGlobals=True,
  11784. register=True)
  11785. def descNameToId(name):
  11786. return "s%s_id" % name
  11787. jsidNames = [descNameToId(desc.name) for desc in descriptors]
  11788. jsidDecls = CGList(CGGeneric("static jsid %s;\n" % name)
  11789. for name in jsidNames)
  11790. jsidInits = CGList(
  11791. (CGIfWrapper(
  11792. CGGeneric("return false;\n"),
  11793. '!AtomizeAndPinJSString(aCx, %s, "%s")' %
  11794. (descNameToId(desc.name), desc.interface.identifier.name))
  11795. for desc in descriptors),
  11796. "\n")
  11797. jsidInits.append(CGGeneric("idsInited = true;\n"))
  11798. jsidInits = CGIfWrapper(jsidInits, "!idsInited")
  11799. jsidInits = CGList([CGGeneric("static bool idsInited = false;\n"),
  11800. jsidInits])
  11801. definitions = CGList([], "\n")
  11802. for desc in descriptors:
  11803. bindingNS = toBindingNamespace(desc.name)
  11804. defineCode = "!%s::GetConstructorObject(aCx)" % bindingNS
  11805. defineCode = CGIfWrapper(CGGeneric("return false;\n"), defineCode)
  11806. defineCode = CGList([defineCode,
  11807. CGGeneric("*aResolvedp = true;\n")])
  11808. condition = "JSID_IS_VOID(aId) || aId == %s" % descNameToId(desc.name)
  11809. if desc.isExposedConditionally():
  11810. condition = "(%s) && %s::ConstructorEnabled(aCx, aObj)" % (condition, bindingNS)
  11811. definitions.append(CGIfWrapper(defineCode, condition))
  11812. return CGList([CGGeneric("MOZ_ASSERT(NS_IsMainThread());\n"),
  11813. jsidDecls,
  11814. jsidInits,
  11815. definitions,
  11816. CGGeneric("return true;\n")],
  11817. "\n").define()
  11818. def getGlobalNames(config):
  11819. names = []
  11820. for desc in config.getDescriptors(registersGlobalNamesOnWindow=True):
  11821. names.append((desc.name, desc))
  11822. names.extend((n.identifier.name, desc) for n in desc.interface.namedConstructors)
  11823. return names
  11824. class CGGlobalNamesString(CGGeneric):
  11825. def __init__(self, config):
  11826. globalNames = getGlobalNames(config)
  11827. currentOffset = 0
  11828. strings = []
  11829. for (name, _) in globalNames:
  11830. strings.append('/* %i */ "%s\\0"' % (currentOffset, name))
  11831. currentOffset += len(name) + 1 # Add trailing null.
  11832. define = fill("""
  11833. const uint32_t WebIDLGlobalNameHash::sCount = ${count};
  11834. const char WebIDLGlobalNameHash::sNames[] =
  11835. $*{strings}
  11836. """,
  11837. count=len(globalNames),
  11838. strings="\n".join(strings) + ";\n")
  11839. CGGeneric.__init__(self, define=define)
  11840. class CGRegisterGlobalNames(CGAbstractMethod):
  11841. def __init__(self, config):
  11842. CGAbstractMethod.__init__(self, None, 'RegisterWebIDLGlobalNames',
  11843. 'void', [])
  11844. self.config = config
  11845. def definition_body(self):
  11846. def getCheck(desc):
  11847. if not desc.isExposedConditionally():
  11848. return "nullptr"
  11849. return "%sBinding::ConstructorEnabled" % desc.name
  11850. define = ""
  11851. currentOffset = 0
  11852. for (name, desc) in getGlobalNames(self.config):
  11853. length = len(name)
  11854. define += "WebIDLGlobalNameHash::Register(%i, %i, %sBinding::DefineDOMInterface, %s);\n" % (currentOffset, length, desc.name, getCheck(desc))
  11855. currentOffset += length + 1 # Add trailing null.
  11856. return define
  11857. def dependencySortObjects(objects, dependencyGetter, nameGetter):
  11858. """
  11859. Sort IDL objects with dependencies on each other such that if A
  11860. depends on B then B will come before A. This is needed for
  11861. declaring C++ classes in the right order, for example. Objects
  11862. that have no dependencies are just sorted by name.
  11863. objects should be something that can produce a set of objects
  11864. (e.g. a set, iterator, list, etc).
  11865. dependencyGetter is something that, given an object, should return
  11866. the set of objects it depends on.
  11867. """
  11868. # XXXbz this will fail if we have two webidl files F1 and F2 such that F1
  11869. # declares an object which depends on an object in F2, and F2 declares an
  11870. # object (possibly a different one!) that depends on an object in F1. The
  11871. # good news is that I expect this to never happen.
  11872. sortedObjects = []
  11873. objects = set(objects)
  11874. while len(objects) != 0:
  11875. # Find the dictionaries that don't depend on anything else
  11876. # anymore and move them over.
  11877. toMove = [o for o in objects if
  11878. len(dependencyGetter(o) & objects) == 0]
  11879. if len(toMove) == 0:
  11880. raise TypeError("Loop in dependency graph\n" +
  11881. "\n".join(o.location for o in objects))
  11882. objects = objects - set(toMove)
  11883. sortedObjects.extend(sorted(toMove, key=nameGetter))
  11884. return sortedObjects
  11885. class ForwardDeclarationBuilder:
  11886. """
  11887. Create a canonical representation of a set of namespaced forward
  11888. declarations.
  11889. """
  11890. def __init__(self):
  11891. """
  11892. The set of declarations is represented as a tree of nested namespaces.
  11893. Each tree node has a set of declarations |decls| and a dict |children|.
  11894. Each declaration is a pair consisting of the class name and a boolean
  11895. that is true iff the class is really a struct. |children| maps the
  11896. names of inner namespaces to the declarations in that namespace.
  11897. """
  11898. self.decls = set()
  11899. self.children = {}
  11900. def _ensureNonTemplateType(self, type):
  11901. if "<" in type:
  11902. # This is a templated type. We don't really know how to
  11903. # forward-declare those, and trying to do it naively is not going to
  11904. # go well (e.g. we may have :: characters inside the type we're
  11905. # templated on!). Just bail out.
  11906. raise TypeError("Attempt to use ForwardDeclarationBuilder on "
  11907. "templated type %s. We don't know how to do that "
  11908. "yet." % type)
  11909. def _listAdd(self, namespaces, name, isStruct=False):
  11910. """
  11911. Add a forward declaration, where |namespaces| is a list of namespaces.
  11912. |name| should not contain any other namespaces.
  11913. """
  11914. if namespaces:
  11915. child = self.children.setdefault(namespaces[0], ForwardDeclarationBuilder())
  11916. child._listAdd(namespaces[1:], name, isStruct)
  11917. else:
  11918. assert '::' not in name
  11919. self.decls.add((name, isStruct))
  11920. def addInMozillaDom(self, name, isStruct=False):
  11921. """
  11922. Add a forward declaration to the mozilla::dom:: namespace. |name| should not
  11923. contain any other namespaces.
  11924. """
  11925. self._ensureNonTemplateType(name);
  11926. self._listAdd(["mozilla", "dom"], name, isStruct)
  11927. def add(self, nativeType, isStruct=False):
  11928. """
  11929. Add a forward declaration, where |nativeType| is a string containing
  11930. the type and its namespaces, in the usual C++ way.
  11931. """
  11932. self._ensureNonTemplateType(nativeType);
  11933. components = nativeType.split('::')
  11934. self._listAdd(components[:-1], components[-1], isStruct)
  11935. def _build(self, atTopLevel):
  11936. """
  11937. Return a codegenerator for the forward declarations.
  11938. """
  11939. decls = []
  11940. if self.decls:
  11941. decls.append(CGList([CGClassForwardDeclare(cname, isStruct)
  11942. for cname, isStruct in sorted(self.decls)]))
  11943. for namespace, child in sorted(self.children.iteritems()):
  11944. decls.append(CGNamespace(namespace, child._build(atTopLevel=False), declareOnly=True))
  11945. cg = CGList(decls, "\n")
  11946. if not atTopLevel and len(decls) + len(self.decls) > 1:
  11947. cg = CGWrapper(cg, pre='\n', post='\n')
  11948. return cg
  11949. def build(self):
  11950. return self._build(atTopLevel=True)
  11951. def forwardDeclareForType(self, t, config):
  11952. t = t.unroll()
  11953. if t.isGeckoInterface():
  11954. name = t.inner.identifier.name
  11955. try:
  11956. desc = config.getDescriptor(name)
  11957. self.add(desc.nativeType)
  11958. except NoSuchDescriptorError:
  11959. pass
  11960. # Note: Spidermonkey interfaces are typedefs, so can't be
  11961. # forward-declared
  11962. elif t.isPromise():
  11963. self.addInMozillaDom("Promise")
  11964. elif t.isCallback():
  11965. self.addInMozillaDom(t.callback.identifier.name)
  11966. elif t.isDictionary():
  11967. self.addInMozillaDom(t.inner.identifier.name, isStruct=True)
  11968. elif t.isCallbackInterface():
  11969. self.addInMozillaDom(t.inner.identifier.name)
  11970. elif t.isUnion():
  11971. # Forward declare both the owning and non-owning version,
  11972. # since we don't know which one we might want
  11973. self.addInMozillaDom(CGUnionStruct.unionTypeName(t, False))
  11974. self.addInMozillaDom(CGUnionStruct.unionTypeName(t, True))
  11975. elif t.isRecord():
  11976. self.forwardDeclareForType(t.inner, config)
  11977. # Don't need to do anything for void, primitive, string, any or object.
  11978. # There may be some other cases we are missing.
  11979. class CGForwardDeclarations(CGWrapper):
  11980. """
  11981. Code generate the forward declarations for a header file.
  11982. additionalDeclarations is a list of tuples containing a classname and a
  11983. boolean. If the boolean is true we will declare a struct, otherwise we'll
  11984. declare a class.
  11985. """
  11986. def __init__(self, config, descriptors, callbacks,
  11987. dictionaries, callbackInterfaces, additionalDeclarations=[]):
  11988. builder = ForwardDeclarationBuilder()
  11989. # Needed for at least Wrap.
  11990. for d in descriptors:
  11991. # If this is a generated iterator interface, we only create these
  11992. # in the generated bindings, and don't need to forward declare.
  11993. if d.interface.isIteratorInterface():
  11994. continue
  11995. builder.add(d.nativeType)
  11996. # If we're an interface and we have a maplike/setlike declaration,
  11997. # we'll have helper functions exposed to the native side of our
  11998. # bindings, which will need to show up in the header. If either of
  11999. # our key/value types are interfaces, they'll be passed as
  12000. # arguments to helper functions, and they'll need to be forward
  12001. # declared in the header.
  12002. if d.interface.maplikeOrSetlikeOrIterable:
  12003. if d.interface.maplikeOrSetlikeOrIterable.hasKeyType():
  12004. builder.forwardDeclareForType(d.interface.maplikeOrSetlikeOrIterable.keyType,
  12005. config)
  12006. if d.interface.maplikeOrSetlikeOrIterable.hasValueType():
  12007. builder.forwardDeclareForType(d.interface.maplikeOrSetlikeOrIterable.valueType,
  12008. config)
  12009. # We just about always need NativePropertyHooks
  12010. builder.addInMozillaDom("NativePropertyHooks", isStruct=True)
  12011. builder.addInMozillaDom("ProtoAndIfaceCache")
  12012. # Add the atoms cache type, even if we don't need it.
  12013. for d in descriptors:
  12014. # Iterators have native types that are template classes, so
  12015. # creating an 'Atoms' cache type doesn't work for them, and is one
  12016. # of the cases where we don't need it anyways.
  12017. if d.interface.isIteratorInterface():
  12018. continue
  12019. builder.add(d.nativeType + "Atoms", isStruct=True)
  12020. for callback in callbacks:
  12021. builder.addInMozillaDom(callback.identifier.name)
  12022. for t in getTypesFromCallback(callback):
  12023. builder.forwardDeclareForType(t, config)
  12024. for d in callbackInterfaces:
  12025. builder.add(d.nativeType)
  12026. builder.add(d.nativeType + "Atoms", isStruct=True)
  12027. for t in getTypesFromDescriptor(d):
  12028. builder.forwardDeclareForType(t, config)
  12029. if d.hasCEReactions():
  12030. builder.addInMozillaDom("DocGroup")
  12031. for d in dictionaries:
  12032. if len(d.members) > 0:
  12033. builder.addInMozillaDom(d.identifier.name + "Atoms", isStruct=True)
  12034. for t in getTypesFromDictionary(d):
  12035. builder.forwardDeclareForType(t, config)
  12036. for className, isStruct in additionalDeclarations:
  12037. builder.add(className, isStruct=isStruct)
  12038. CGWrapper.__init__(self, builder.build())
  12039. class CGBindingRoot(CGThing):
  12040. """
  12041. Root codegen class for binding generation. Instantiate the class, and call
  12042. declare or define to generate header or cpp code (respectively).
  12043. """
  12044. def __init__(self, config, prefix, webIDLFile):
  12045. bindingHeaders = dict.fromkeys((
  12046. 'mozilla/dom/NonRefcountedDOMObject.h',
  12047. ),
  12048. True)
  12049. bindingDeclareHeaders = dict.fromkeys((
  12050. 'mozilla/dom/BindingDeclarations.h',
  12051. 'mozilla/dom/Nullable.h',
  12052. 'mozilla/ErrorResult.h',
  12053. ),
  12054. True)
  12055. descriptors = config.getDescriptors(webIDLFile=webIDLFile,
  12056. hasInterfaceOrInterfacePrototypeObject=True)
  12057. unionTypes = UnionsForFile(config, webIDLFile)
  12058. (unionHeaders, unionImplheaders, unionDeclarations, traverseMethods,
  12059. unlinkMethods, unionStructs) = UnionTypes(unionTypes, config)
  12060. bindingDeclareHeaders.update(dict.fromkeys(unionHeaders, True))
  12061. bindingHeaders.update(dict.fromkeys(unionImplheaders, True))
  12062. bindingDeclareHeaders["mozilla/dom/UnionMember.h"] = len(unionStructs) > 0
  12063. bindingDeclareHeaders["mozilla/dom/FakeString.h"] = len(unionStructs) > 0
  12064. # BindingUtils.h is only needed for SetToObject.
  12065. # If it stops being inlined or stops calling CallerSubsumes
  12066. # both this bit and the bit in UnionTypes can be removed.
  12067. bindingDeclareHeaders["mozilla/dom/BindingUtils.h"] = any(d.isObject() for t in unionTypes
  12068. for d in t.flatMemberTypes)
  12069. bindingDeclareHeaders["mozilla/dom/IterableIterator.h"] = any(d.interface.isIteratorInterface() or
  12070. d.interface.isIterable() for d in descriptors)
  12071. def descriptorHasCrossOriginProperties(desc):
  12072. def hasCrossOriginProperty(m):
  12073. props = memberProperties(m, desc)
  12074. return (props.isCrossOriginMethod or
  12075. props.isCrossOriginGetter or
  12076. props.isCrossOriginSetter)
  12077. return any(hasCrossOriginProperty(m) for m in desc.interface.members)
  12078. bindingDeclareHeaders["jsapi.h"] = any(descriptorHasCrossOriginProperties(d) for d in descriptors)
  12079. bindingDeclareHeaders["jspubtd.h"] = not bindingDeclareHeaders["jsapi.h"]
  12080. bindingDeclareHeaders["js/RootingAPI.h"] = not bindingDeclareHeaders["jsapi.h"]
  12081. def descriptorRequiresPreferences(desc):
  12082. iface = desc.interface
  12083. return any(m.getExtendedAttribute("Pref") for m in iface.members + [iface])
  12084. def descriptorDeprecated(desc):
  12085. iface = desc.interface
  12086. return any(m.getExtendedAttribute("Deprecated") for m in iface.members + [iface])
  12087. bindingHeaders["nsIDocument.h"] = any(
  12088. descriptorDeprecated(d) for d in descriptors)
  12089. bindingHeaders["mozilla/Preferences.h"] = any(
  12090. descriptorRequiresPreferences(d) for d in descriptors)
  12091. bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any(
  12092. d.concrete and d.proxy for d in descriptors)
  12093. hasCEReactions = any(d.hasCEReactions() for d in descriptors)
  12094. bindingHeaders["mozilla/dom/CustomElementRegistry.h"] = hasCEReactions
  12095. bindingHeaders["mozilla/dom/DocGroup.h"] = hasCEReactions
  12096. def descriptorHasChromeOnly(desc):
  12097. ctor = desc.interface.ctor()
  12098. return (any(isChromeOnly(a) or needsContainsHack(a) or
  12099. needsCallerType(a)
  12100. for a in desc.interface.members) or
  12101. desc.interface.getExtendedAttribute("ChromeOnly") is not None or
  12102. # JS-implemented interfaces with an interface object get a
  12103. # chromeonly _create method. And interfaces with an
  12104. # interface object might have a ChromeOnly constructor.
  12105. (desc.interface.hasInterfaceObject() and
  12106. (desc.interface.isJSImplemented() or
  12107. (ctor and isChromeOnly(ctor)))) or
  12108. # JS-implemented interfaces with clearable cached
  12109. # attrs have chromeonly _clearFoo methods.
  12110. (desc.interface.isJSImplemented() and
  12111. any(clearableCachedAttrs(desc))))
  12112. # XXXkhuey ugly hack but this is going away soon.
  12113. bindingHeaders['xpcprivate.h'] = webIDLFile.endswith("EventTarget.webidl")
  12114. hasThreadChecks = any(d.hasThreadChecks() for d in descriptors)
  12115. bindingHeaders["nsThreadUtils.h"] = hasThreadChecks
  12116. dictionaries = config.getDictionaries(webIDLFile)
  12117. def dictionaryHasChromeOnly(dictionary):
  12118. while dictionary:
  12119. if (any(isChromeOnly(m) for m in dictionary.members)):
  12120. return True
  12121. dictionary = dictionary.parent
  12122. return False
  12123. bindingHeaders["nsContentUtils.h"] = (
  12124. any(descriptorHasChromeOnly(d) for d in descriptors) or
  12125. any(dictionaryHasChromeOnly(d) for d in dictionaries))
  12126. hasNonEmptyDictionaries = any(
  12127. len(dict.members) > 0 for dict in dictionaries)
  12128. callbacks = config.getCallbacks(webIDLFile)
  12129. callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile,
  12130. isCallback=True)
  12131. jsImplemented = config.getDescriptors(webIDLFile=webIDLFile,
  12132. isJSImplemented=True)
  12133. bindingDeclareHeaders["nsWeakReference.h"] = jsImplemented
  12134. bindingHeaders["nsIGlobalObject.h"] = jsImplemented
  12135. bindingHeaders["AtomList.h"] = hasNonEmptyDictionaries or jsImplemented or callbackDescriptors
  12136. def descriptorClearsPropsInSlots(descriptor):
  12137. if not descriptor.wrapperCache:
  12138. return False
  12139. return any(m.isAttr() and m.getExtendedAttribute("StoreInSlot")
  12140. for m in descriptor.interface.members)
  12141. bindingHeaders["nsJSUtils.h"] = any(descriptorClearsPropsInSlots(d) for d in descriptors)
  12142. # Do codegen for all the enums
  12143. enums = config.getEnums(webIDLFile)
  12144. cgthings = [CGEnum(e) for e in enums]
  12145. hasCode = (descriptors or callbackDescriptors or dictionaries or
  12146. callbacks)
  12147. bindingHeaders["mozilla/dom/BindingUtils.h"] = hasCode
  12148. bindingHeaders["mozilla/OwningNonNull.h"] = hasCode
  12149. bindingHeaders["mozilla/dom/BindingDeclarations.h"] = (
  12150. not hasCode and enums)
  12151. bindingHeaders["WrapperFactory.h"] = descriptors
  12152. bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors
  12153. bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries # AutoJSAPI
  12154. # Ensure we see our enums in the generated .cpp file, for the ToJSValue
  12155. # method body. Also ensure that we see jsapi.h.
  12156. if enums:
  12157. bindingHeaders[CGHeaders.getDeclarationFilename(enums[0])] = True
  12158. bindingHeaders["jsapi.h"] = True
  12159. # For things that have [UseCounter]
  12160. def descriptorRequiresTelemetry(desc):
  12161. iface = desc.interface
  12162. return any(m.getExtendedAttribute("UseCounter") for m in iface.members)
  12163. bindingHeaders["mozilla/UseCounter.h"] = any(
  12164. descriptorRequiresTelemetry(d) for d in descriptors)
  12165. bindingHeaders["mozilla/dom/SimpleGlobalObject.h"] = any(
  12166. CGDictionary.dictionarySafeToJSONify(d) for d in dictionaries)
  12167. bindingHeaders["XrayWrapper.h"] = any(
  12168. d.wantsXrays and d.wantsXrayExpandoClass for d in descriptors)
  12169. bindingHeaders["mozilla/dom/XrayExpandoClass.h"] = any(
  12170. d.wantsXrays for d in descriptors)
  12171. cgthings.extend(traverseMethods)
  12172. cgthings.extend(unlinkMethods)
  12173. # Do codegen for all the dictionaries. We have to be a bit careful
  12174. # here, because we have to generate these in order from least derived
  12175. # to most derived so that class inheritance works out. We also have to
  12176. # generate members before the dictionary that contains them.
  12177. def getDependenciesFromType(type):
  12178. if type.isDictionary():
  12179. return set([type.unroll().inner])
  12180. if type.isSequence():
  12181. return getDependenciesFromType(type.unroll())
  12182. if type.isUnion():
  12183. return set([type.unroll()])
  12184. return set()
  12185. def getDependencies(unionTypeOrDictionary):
  12186. if isinstance(unionTypeOrDictionary, IDLDictionary):
  12187. deps = set()
  12188. if unionTypeOrDictionary.parent:
  12189. deps.add(unionTypeOrDictionary.parent)
  12190. for member in unionTypeOrDictionary.members:
  12191. deps |= getDependenciesFromType(member.type)
  12192. return deps
  12193. assert unionTypeOrDictionary.isType() and unionTypeOrDictionary.isUnion()
  12194. deps = set()
  12195. for member in unionTypeOrDictionary.flatMemberTypes:
  12196. deps |= getDependenciesFromType(member)
  12197. return deps
  12198. def getName(unionTypeOrDictionary):
  12199. if isinstance(unionTypeOrDictionary, IDLDictionary):
  12200. return unionTypeOrDictionary.identifier.name
  12201. assert unionTypeOrDictionary.isType() and unionTypeOrDictionary.isUnion()
  12202. return unionTypeOrDictionary.name
  12203. for t in dependencySortObjects(dictionaries + unionStructs, getDependencies, getName):
  12204. if t.isDictionary():
  12205. cgthings.append(CGDictionary(t, config))
  12206. else:
  12207. assert t.isUnion()
  12208. cgthings.append(CGUnionStruct(t, config))
  12209. cgthings.append(CGUnionStruct(t, config, True))
  12210. # Do codegen for all the callbacks.
  12211. cgthings.extend(CGCallbackFunction(c, config) for c in callbacks)
  12212. cgthings.extend([CGNamespace('binding_detail', CGFastCallback(c))
  12213. for c in callbacks])
  12214. # Do codegen for all the descriptors
  12215. cgthings.extend([CGDescriptor(x) for x in descriptors])
  12216. # Do codegen for all the callback interfaces.
  12217. cgthings.extend([CGCallbackInterface(x) for x in callbackDescriptors])
  12218. cgthings.extend([CGNamespace('binding_detail',
  12219. CGFastCallback(x.interface))
  12220. for x in callbackDescriptors])
  12221. # Do codegen for JS implemented classes
  12222. def getParentDescriptor(desc):
  12223. if not desc.interface.parent:
  12224. return set()
  12225. return {desc.getDescriptor(desc.interface.parent.identifier.name)}
  12226. for x in dependencySortObjects(jsImplemented, getParentDescriptor,
  12227. lambda d: d.interface.identifier.name):
  12228. cgthings.append(CGCallbackInterface(x, typedArraysAreStructs=True))
  12229. cgthings.append(CGJSImplClass(x))
  12230. # And make sure we have the right number of newlines at the end
  12231. curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
  12232. # Wrap all of that in our namespaces.
  12233. curr = CGNamespace.build(['mozilla', 'dom'],
  12234. CGWrapper(curr, pre="\n"))
  12235. curr = CGList([CGForwardDeclarations(config, descriptors,
  12236. callbacks,
  12237. dictionaries,
  12238. callbackDescriptors + jsImplemented,
  12239. additionalDeclarations=unionDeclarations),
  12240. curr],
  12241. "\n")
  12242. # Add header includes.
  12243. bindingHeaders = [header
  12244. for header, include in bindingHeaders.iteritems()
  12245. if include]
  12246. bindingDeclareHeaders = [header
  12247. for header, include in bindingDeclareHeaders.iteritems()
  12248. if include]
  12249. curr = CGHeaders(descriptors,
  12250. dictionaries,
  12251. callbacks,
  12252. callbackDescriptors,
  12253. bindingDeclareHeaders,
  12254. bindingHeaders,
  12255. prefix,
  12256. curr,
  12257. config,
  12258. jsImplemented)
  12259. # Add include guards.
  12260. curr = CGIncludeGuard(prefix, curr)
  12261. # Add the auto-generated comment.
  12262. curr = CGWrapper(
  12263. curr,
  12264. pre=(AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT %
  12265. os.path.basename(webIDLFile)))
  12266. # Store the final result.
  12267. self.root = curr
  12268. def declare(self):
  12269. return stripTrailingWhitespace(self.root.declare())
  12270. def define(self):
  12271. return stripTrailingWhitespace(self.root.define())
  12272. def deps(self):
  12273. return self.root.deps()
  12274. class CGNativeMember(ClassMethod):
  12275. def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
  12276. breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
  12277. typedArraysAreStructs=True, variadicIsSequence=False,
  12278. resultNotAddRefed=False,
  12279. virtual=False,
  12280. override=False):
  12281. """
  12282. If typedArraysAreStructs is false, typed arrays will be passed as
  12283. JS::Handle<JSObject*>. If it's true they will be passed as one of the
  12284. dom::TypedArray subclasses.
  12285. If passJSBitsAsNeeded is false, we don't automatically pass in a
  12286. JSContext* or a JSObject* based on the return and argument types. We
  12287. can still pass it based on 'implicitJSContext' annotations.
  12288. """
  12289. self.descriptorProvider = descriptorProvider
  12290. self.member = member
  12291. self.extendedAttrs = extendedAttrs
  12292. self.resultAlreadyAddRefed = not resultNotAddRefed
  12293. self.passJSBitsAsNeeded = passJSBitsAsNeeded
  12294. self.typedArraysAreStructs = typedArraysAreStructs
  12295. self.variadicIsSequence = variadicIsSequence
  12296. breakAfterSelf = "\n" if breakAfter else ""
  12297. ClassMethod.__init__(self, name,
  12298. self.getReturnType(signature[0], False),
  12299. self.getArgs(signature[0], signature[1]),
  12300. static=member.isStatic(),
  12301. # Mark our getters, which are attrs that
  12302. # have a non-void return type, as const.
  12303. const=(not member.isStatic() and member.isAttr() and
  12304. not signature[0].isVoid()),
  12305. breakAfterReturnDecl=" ",
  12306. breakAfterSelf=breakAfterSelf,
  12307. visibility=visibility,
  12308. virtual=virtual,
  12309. override=override)
  12310. def getReturnType(self, type, isMember):
  12311. return self.getRetvalInfo(type, isMember)[0]
  12312. def getRetvalInfo(self, type, isMember):
  12313. """
  12314. Returns a tuple:
  12315. The first element is the type declaration for the retval
  12316. The second element is a default value that can be used on error returns.
  12317. For cases whose behavior depends on isMember, the second element will be
  12318. None if isMember is true.
  12319. The third element is a template for actually returning a value stored in
  12320. "${declName}" and "${holderName}". This means actually returning it if
  12321. we're not outparam, else assigning to the "retval" outparam. If
  12322. isMember is true, this can be None, since in that case the caller will
  12323. never examine this value.
  12324. """
  12325. if type.isVoid():
  12326. return "void", "", ""
  12327. if type.isPrimitive() and type.tag() in builtinNames:
  12328. result = CGGeneric(builtinNames[type.tag()])
  12329. defaultReturnArg = "0"
  12330. if type.nullable():
  12331. result = CGTemplatedType("Nullable", result)
  12332. defaultReturnArg = ""
  12333. return (result.define(),
  12334. "%s(%s)" % (result.define(), defaultReturnArg),
  12335. "return ${declName};\n")
  12336. if type.isDOMString() or type.isUSVString():
  12337. if isMember:
  12338. # No need for a third element in the isMember case
  12339. return "nsString", None, None
  12340. # Outparam
  12341. return "void", "", "aRetVal = ${declName};\n"
  12342. if type.isByteString():
  12343. if isMember:
  12344. # No need for a third element in the isMember case
  12345. return "nsCString", None, None
  12346. # Outparam
  12347. return "void", "", "aRetVal = ${declName};\n"
  12348. if type.isEnum():
  12349. enumName = type.unroll().inner.identifier.name
  12350. if type.nullable():
  12351. enumName = CGTemplatedType("Nullable",
  12352. CGGeneric(enumName)).define()
  12353. defaultValue = "%s()" % enumName
  12354. else:
  12355. defaultValue = "%s(0)" % enumName
  12356. return enumName, defaultValue, "return ${declName};\n"
  12357. if type.isGeckoInterface() or type.isPromise():
  12358. if type.isGeckoInterface():
  12359. iface = type.unroll().inner
  12360. result = CGGeneric(self.descriptorProvider.getDescriptor(
  12361. iface.identifier.name).prettyNativeType)
  12362. else:
  12363. result = CGGeneric("Promise")
  12364. if self.resultAlreadyAddRefed:
  12365. if isMember:
  12366. holder = "RefPtr"
  12367. else:
  12368. holder = "already_AddRefed"
  12369. if memberReturnsNewObject(self.member) or isMember:
  12370. warning = ""
  12371. else:
  12372. warning = "// Return a raw pointer here to avoid refcounting, but make sure it's safe (the object should be kept alive by the callee).\n"
  12373. result = CGWrapper(result,
  12374. pre=("%s%s<" % (warning, holder)),
  12375. post=">")
  12376. else:
  12377. result = CGWrapper(result, post="*")
  12378. # Since we always force an owning type for callback return values,
  12379. # our ${declName} is an OwningNonNull or RefPtr. So we can just
  12380. # .forget() to get our already_AddRefed.
  12381. return result.define(), "nullptr", "return ${declName}.forget();\n"
  12382. if type.isCallback():
  12383. return ("already_AddRefed<%s>" % type.unroll().callback.identifier.name,
  12384. "nullptr", "return ${declName}.forget();\n")
  12385. if type.isAny():
  12386. if isMember:
  12387. # No need for a third element in the isMember case
  12388. return "JS::Value", None, None
  12389. # Outparam
  12390. return "void", "", "aRetVal.set(${declName});\n"
  12391. if type.isObject():
  12392. if isMember:
  12393. # No need for a third element in the isMember case
  12394. return "JSObject*", None, None
  12395. return "void", "", "aRetVal.set(${declName});\n"
  12396. if type.isSpiderMonkeyInterface():
  12397. if isMember:
  12398. # No need for a third element in the isMember case
  12399. return "JSObject*", None, None
  12400. if type.nullable():
  12401. returnCode = "${declName}.IsNull() ? nullptr : ${declName}.Value().Obj()"
  12402. else:
  12403. returnCode = "${declName}.Obj()"
  12404. return "void", "", "aRetVal.set(%s);\n" % returnCode
  12405. if type.isSequence():
  12406. # If we want to handle sequence-of-sequences return values, we're
  12407. # going to need to fix example codegen to not produce nsTArray<void>
  12408. # for the relevant argument...
  12409. assert not isMember
  12410. # Outparam.
  12411. if type.nullable():
  12412. returnCode = dedent("""
  12413. if (${declName}.IsNull()) {
  12414. aRetVal.SetNull();
  12415. } else {
  12416. aRetVal.SetValue().SwapElements(${declName}.Value());
  12417. }
  12418. """)
  12419. else:
  12420. returnCode = "aRetVal.SwapElements(${declName});\n"
  12421. return "void", "", returnCode
  12422. if type.isRecord():
  12423. # If we want to handle record-of-record return values, we're
  12424. # going to need to fix example codegen to not produce record<void>
  12425. # for the relevant argument...
  12426. assert not isMember
  12427. # In this case we convert directly into our outparam to start with
  12428. return "void", "", ""
  12429. if type.isDate():
  12430. result = CGGeneric("Date")
  12431. if type.nullable():
  12432. result = CGTemplatedType("Nullable", result)
  12433. return (result.define(), "%s()" % result.define(),
  12434. "return ${declName};\n")
  12435. if type.isDictionary():
  12436. if isMember:
  12437. # Only the first member of the tuple matters here, but return
  12438. # bogus values for the others in case someone decides to use
  12439. # them.
  12440. return CGDictionary.makeDictionaryName(type.inner), None, None
  12441. # In this case we convert directly into our outparam to start with
  12442. return "void", "", ""
  12443. if type.isUnion():
  12444. if isMember:
  12445. # Only the first member of the tuple matters here, but return
  12446. # bogus values for the others in case someone decides to use
  12447. # them.
  12448. return CGUnionStruct.unionTypeDecl(type, True), None, None
  12449. # In this case we convert directly into our outparam to start with
  12450. return "void", "", ""
  12451. raise TypeError("Don't know how to declare return value for %s" %
  12452. type)
  12453. def getArgs(self, returnType, argList):
  12454. args = [self.getArg(arg) for arg in argList]
  12455. # Now the outparams
  12456. if returnType.isDOMString() or returnType.isUSVString():
  12457. args.append(Argument("nsString&", "aRetVal"))
  12458. elif returnType.isByteString():
  12459. args.append(Argument("nsCString&", "aRetVal"))
  12460. elif returnType.isSequence():
  12461. nullable = returnType.nullable()
  12462. if nullable:
  12463. returnType = returnType.inner
  12464. # And now the actual underlying type
  12465. elementDecl = self.getReturnType(returnType.inner, True)
  12466. type = CGTemplatedType("nsTArray", CGGeneric(elementDecl))
  12467. if nullable:
  12468. type = CGTemplatedType("Nullable", type)
  12469. args.append(Argument("%s&" % type.define(), "aRetVal"))
  12470. elif returnType.isRecord():
  12471. nullable = returnType.nullable()
  12472. if nullable:
  12473. returnType = returnType.inner
  12474. # And now the actual underlying type
  12475. elementDecl = self.getReturnType(returnType.inner, True)
  12476. type = CGTemplatedType("Record", [recordKeyDeclType(returnType),
  12477. CGGeneric(elementDecl)])
  12478. if nullable:
  12479. type = CGTemplatedType("Nullable", type)
  12480. args.append(Argument("%s&" % type.define(), "aRetVal"))
  12481. elif returnType.isDictionary():
  12482. nullable = returnType.nullable()
  12483. if nullable:
  12484. returnType = returnType.inner
  12485. dictType = CGGeneric(CGDictionary.makeDictionaryName(returnType.inner))
  12486. if nullable:
  12487. dictType = CGTemplatedType("Nullable", dictType)
  12488. args.append(Argument("%s&" % dictType.define(), "aRetVal"))
  12489. elif returnType.isUnion():
  12490. args.append(Argument("%s&" %
  12491. CGUnionStruct.unionTypeDecl(returnType, True),
  12492. "aRetVal"))
  12493. elif returnType.isAny():
  12494. args.append(Argument("JS::MutableHandle<JS::Value>", "aRetVal"))
  12495. elif returnType.isObject() or returnType.isSpiderMonkeyInterface():
  12496. args.append(Argument("JS::MutableHandle<JSObject*>", "aRetVal"))
  12497. # And the nsIPrincipal
  12498. if self.member.getExtendedAttribute('NeedsSubjectPrincipal'):
  12499. # Cheat and assume self.descriptorProvider is a descriptor
  12500. if self.descriptorProvider.interface.isExposedInAnyWorker():
  12501. args.append(Argument("Maybe<nsIPrincipal*>", "aSubjectPrincipal"))
  12502. else:
  12503. args.append(Argument("nsIPrincipal&", "aPrincipal"))
  12504. # And the caller type, if desired.
  12505. if needsCallerType(self.member):
  12506. args.append(Argument("CallerType", "aCallerType"))
  12507. # And the ErrorResult
  12508. if 'infallible' not in self.extendedAttrs:
  12509. # Use aRv so it won't conflict with local vars named "rv"
  12510. args.append(Argument("ErrorResult&", "aRv"))
  12511. # The legacycaller thisval
  12512. if self.member.isMethod() and self.member.isLegacycaller():
  12513. # If it has an identifier, we can't deal with it yet
  12514. assert self.member.isIdentifierLess()
  12515. args.insert(0, Argument("const JS::Value&", "aThisVal"))
  12516. # And jscontext bits.
  12517. if needCx(returnType, argList, self.extendedAttrs,
  12518. self.passJSBitsAsNeeded, self.member.isStatic()):
  12519. args.insert(0, Argument("JSContext*", "cx"))
  12520. if needScopeObject(returnType, argList, self.extendedAttrs,
  12521. self.descriptorProvider.wrapperCache,
  12522. self.passJSBitsAsNeeded,
  12523. self.member.getExtendedAttribute("StoreInSlot")):
  12524. args.insert(1, Argument("JS::Handle<JSObject*>", "obj"))
  12525. # And if we're static, a global
  12526. if self.member.isStatic():
  12527. args.insert(0, Argument("const GlobalObject&", "global"))
  12528. return args
  12529. def doGetArgType(self, type, optional, isMember):
  12530. """
  12531. The main work of getArgType. Returns a string type decl, whether this
  12532. is a const ref, as well as whether the type should be wrapped in
  12533. Nullable as needed.
  12534. isMember can be false or one of the strings "Sequence", "Variadic",
  12535. "Record"
  12536. """
  12537. if type.isSequence():
  12538. nullable = type.nullable()
  12539. if nullable:
  12540. type = type.inner
  12541. elementType = type.inner
  12542. argType = self.getArgType(elementType, False, "Sequence")[0]
  12543. decl = CGTemplatedType("Sequence", argType)
  12544. return decl.define(), True, True
  12545. if type.isRecord():
  12546. nullable = type.nullable()
  12547. if nullable:
  12548. type = type.inner
  12549. elementType = type.inner
  12550. argType = self.getArgType(elementType, False, "Record")[0]
  12551. decl = CGTemplatedType("Record", [recordKeyDeclType(type), argType])
  12552. return decl.define(), True, True
  12553. if type.isUnion():
  12554. # unionTypeDecl will handle nullable types, so return False for
  12555. # auto-wrapping in Nullable
  12556. return CGUnionStruct.unionTypeDecl(type, isMember), True, False
  12557. if type.isPromise():
  12558. assert not type.nullable()
  12559. if optional or isMember:
  12560. typeDecl = "OwningNonNull<Promise>"
  12561. else:
  12562. typeDecl = "Promise&"
  12563. return (typeDecl, False, False)
  12564. if type.isGeckoInterface() and not type.isCallbackInterface():
  12565. iface = type.unroll().inner
  12566. argIsPointer = type.nullable() or iface.isExternal()
  12567. forceOwningType = (iface.isCallback() or isMember)
  12568. if argIsPointer:
  12569. if (optional or isMember) and forceOwningType:
  12570. typeDecl = "RefPtr<%s>"
  12571. else:
  12572. typeDecl = "%s*"
  12573. else:
  12574. if optional or isMember:
  12575. if forceOwningType:
  12576. typeDecl = "OwningNonNull<%s>"
  12577. else:
  12578. typeDecl = "NonNull<%s>"
  12579. else:
  12580. typeDecl = "%s&"
  12581. return ((typeDecl %
  12582. self.descriptorProvider.getDescriptor(iface.identifier.name).prettyNativeType),
  12583. False, False)
  12584. if type.isSpiderMonkeyInterface():
  12585. if not self.typedArraysAreStructs:
  12586. return "JS::Handle<JSObject*>", False, False
  12587. # Unroll for the name, in case we're nullable.
  12588. return type.unroll().name, True, True
  12589. if type.isDOMString() or type.isUSVString():
  12590. if isMember:
  12591. declType = "nsString"
  12592. else:
  12593. declType = "nsAString"
  12594. return declType, True, False
  12595. if type.isByteString():
  12596. declType = "nsCString"
  12597. return declType, True, False
  12598. if type.isEnum():
  12599. return type.unroll().inner.identifier.name, False, True
  12600. if type.isCallback() or type.isCallbackInterface():
  12601. forceOwningType = optional or isMember
  12602. if type.nullable():
  12603. if forceOwningType:
  12604. declType = "RefPtr<%s>"
  12605. else:
  12606. declType = "%s*"
  12607. else:
  12608. if forceOwningType:
  12609. declType = "OwningNonNull<%s>"
  12610. else:
  12611. declType = "%s&"
  12612. if type.isCallback():
  12613. name = type.unroll().callback.identifier.name
  12614. else:
  12615. name = type.unroll().inner.identifier.name
  12616. return declType % name, False, False
  12617. if type.isAny():
  12618. # Don't do the rooting stuff for variadics for now
  12619. if isMember:
  12620. declType = "JS::Value"
  12621. else:
  12622. declType = "JS::Handle<JS::Value>"
  12623. return declType, False, False
  12624. if type.isObject():
  12625. if isMember:
  12626. declType = "JSObject*"
  12627. else:
  12628. declType = "JS::Handle<JSObject*>"
  12629. return declType, False, False
  12630. if type.isDictionary():
  12631. typeName = CGDictionary.makeDictionaryName(type.inner)
  12632. return typeName, True, True
  12633. if type.isDate():
  12634. return "Date", False, True
  12635. assert type.isPrimitive()
  12636. return builtinNames[type.tag()], False, True
  12637. def getArgType(self, type, optional, isMember):
  12638. """
  12639. Get the type of an argument declaration. Returns the type CGThing, and
  12640. whether this should be a const ref.
  12641. isMember can be False, "Sequence", or "Variadic"
  12642. """
  12643. decl, ref, handleNullable = self.doGetArgType(type, optional, isMember)
  12644. decl = CGGeneric(decl)
  12645. if handleNullable and type.nullable():
  12646. decl = CGTemplatedType("Nullable", decl)
  12647. ref = True
  12648. if isMember == "Variadic":
  12649. arrayType = "Sequence" if self.variadicIsSequence else "nsTArray"
  12650. decl = CGTemplatedType(arrayType, decl)
  12651. ref = True
  12652. elif optional:
  12653. # Note: All variadic args claim to be optional, but we can just use
  12654. # empty arrays to represent them not being present.
  12655. decl = CGTemplatedType("Optional", decl)
  12656. ref = True
  12657. return (decl, ref)
  12658. def getArg(self, arg):
  12659. """
  12660. Get the full argument declaration for an argument
  12661. """
  12662. decl, ref = self.getArgType(arg.type, arg.canHaveMissingValue(),
  12663. "Variadic" if arg.variadic else False)
  12664. if ref:
  12665. decl = CGWrapper(decl, pre="const ", post="&")
  12666. return Argument(decl.define(), arg.identifier.name)
  12667. def arguments(self):
  12668. return self.member.signatures()[0][1]
  12669. class CGExampleMethod(CGNativeMember):
  12670. def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
  12671. CGNativeMember.__init__(self, descriptor, method,
  12672. CGSpecializedMethod.makeNativeName(descriptor,
  12673. method),
  12674. signature,
  12675. descriptor.getExtendedAttributes(method),
  12676. breakAfter=breakAfter,
  12677. variadicIsSequence=True)
  12678. def declare(self, cgClass):
  12679. assert self.member.isMethod()
  12680. # We skip declaring ourselves if this is a maplike/setlike/iterable
  12681. # method, because those get implemented automatically by the binding
  12682. # machinery, so the implementor of the interface doesn't have to worry
  12683. # about it.
  12684. if self.member.isMaplikeOrSetlikeOrIterableMethod():
  12685. return ''
  12686. return CGNativeMember.declare(self, cgClass);
  12687. def define(self, cgClass):
  12688. return ''
  12689. class CGExampleGetter(CGNativeMember):
  12690. def __init__(self, descriptor, attr):
  12691. CGNativeMember.__init__(self, descriptor, attr,
  12692. CGSpecializedGetter.makeNativeName(descriptor,
  12693. attr),
  12694. (attr.type, []),
  12695. descriptor.getExtendedAttributes(attr,
  12696. getter=True))
  12697. def declare(self, cgClass):
  12698. assert self.member.isAttr()
  12699. # We skip declaring ourselves if this is a maplike/setlike attr (in
  12700. # practice, "size"), because those get implemented automatically by the
  12701. # binding machinery, so the implementor of the interface doesn't have to
  12702. # worry about it.
  12703. if self.member.isMaplikeOrSetlikeAttr():
  12704. return ''
  12705. return CGNativeMember.declare(self, cgClass);
  12706. def define(self, cgClass):
  12707. return ''
  12708. class CGExampleSetter(CGNativeMember):
  12709. def __init__(self, descriptor, attr):
  12710. CGNativeMember.__init__(self, descriptor, attr,
  12711. CGSpecializedSetter.makeNativeName(descriptor,
  12712. attr),
  12713. (BuiltinTypes[IDLBuiltinType.Types.void],
  12714. [FakeArgument(attr.type, attr)]),
  12715. descriptor.getExtendedAttributes(attr,
  12716. setter=True))
  12717. def define(self, cgClass):
  12718. return ''
  12719. class CGBindingImplClass(CGClass):
  12720. """
  12721. Common codegen for generating a C++ implementation of a WebIDL interface
  12722. """
  12723. def __init__(self, descriptor, cgMethod, cgGetter, cgSetter, wantGetParent=True, wrapMethodName="WrapObject", skipStaticMethods=False):
  12724. """
  12725. cgMethod, cgGetter and cgSetter are classes used to codegen methods,
  12726. getters and setters.
  12727. """
  12728. self.descriptor = descriptor
  12729. self._deps = descriptor.interface.getDeps()
  12730. iface = descriptor.interface
  12731. self.methodDecls = []
  12732. def appendMethod(m, isConstructor=False):
  12733. sigs = m.signatures()
  12734. for s in sigs[:-1]:
  12735. # Don't put a blank line after overloads, until we
  12736. # get to the last one.
  12737. self.methodDecls.append(cgMethod(descriptor, m, s,
  12738. isConstructor,
  12739. breakAfter=False))
  12740. self.methodDecls.append(cgMethod(descriptor, m, sigs[-1],
  12741. isConstructor))
  12742. if iface.ctor():
  12743. appendMethod(iface.ctor(), isConstructor=True)
  12744. for n in iface.namedConstructors:
  12745. appendMethod(n, isConstructor=True)
  12746. for m in iface.members:
  12747. if m.isMethod():
  12748. if m.isIdentifierLess():
  12749. continue
  12750. if not m.isStatic() or not skipStaticMethods:
  12751. appendMethod(m)
  12752. elif m.isAttr():
  12753. self.methodDecls.append(cgGetter(descriptor, m))
  12754. if not m.readonly:
  12755. self.methodDecls.append(cgSetter(descriptor, m))
  12756. # Now do the special operations
  12757. def appendSpecialOperation(name, op):
  12758. if op is None:
  12759. return
  12760. if name == "IndexedCreator" or name == "NamedCreator":
  12761. # These are identical to the setters
  12762. return
  12763. assert len(op.signatures()) == 1
  12764. returnType, args = op.signatures()[0]
  12765. # Make a copy of the args, since we plan to modify them.
  12766. args = list(args)
  12767. if op.isGetter() or op.isDeleter():
  12768. # This is a total hack. The '&' belongs with the
  12769. # type, not the name! But it works, and is simpler
  12770. # than trying to somehow make this pretty.
  12771. args.append(FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean],
  12772. op, name="&found"))
  12773. if name == "Stringifier":
  12774. if op.isIdentifierLess():
  12775. # XXXbz I wish we were consistent about our renaming here.
  12776. name = "Stringify"
  12777. else:
  12778. # We already added this method
  12779. return
  12780. if name == "LegacyCaller":
  12781. if op.isIdentifierLess():
  12782. # XXXbz I wish we were consistent about our renaming here.
  12783. name = "LegacyCall"
  12784. else:
  12785. # We already added this method
  12786. return
  12787. if name == "Jsonifier":
  12788. # We already added this method
  12789. return
  12790. self.methodDecls.append(
  12791. CGNativeMember(descriptor, op,
  12792. name,
  12793. (returnType, args),
  12794. descriptor.getExtendedAttributes(op)))
  12795. # Sort things by name so we get stable ordering in the output.
  12796. ops = descriptor.operations.items()
  12797. ops.sort(key=lambda x: x[0])
  12798. for name, op in ops:
  12799. appendSpecialOperation(name, op)
  12800. # If we support indexed properties, then we need a Length()
  12801. # method so we know which indices are supported.
  12802. if descriptor.supportsIndexedProperties():
  12803. # But we don't need it if we already have an infallible
  12804. # "length" attribute, which we often do.
  12805. haveLengthAttr = any(
  12806. m for m in iface.members if m.isAttr() and
  12807. CGSpecializedGetter.makeNativeName(descriptor, m) == "Length")
  12808. if not haveLengthAttr:
  12809. self.methodDecls.append(
  12810. CGNativeMember(descriptor, FakeMember(),
  12811. "Length",
  12812. (BuiltinTypes[IDLBuiltinType.Types.unsigned_long],
  12813. []),
  12814. {"infallible": True}))
  12815. # And if we support named properties we need to be able to
  12816. # enumerate the supported names.
  12817. if descriptor.supportsNamedProperties():
  12818. self.methodDecls.append(
  12819. CGNativeMember(
  12820. descriptor, FakeMember(),
  12821. "GetSupportedNames",
  12822. (IDLSequenceType(None,
  12823. BuiltinTypes[IDLBuiltinType.Types.domstring]),
  12824. []),
  12825. {"infallible": True}))
  12826. wrapArgs = [Argument('JSContext*', 'aCx'),
  12827. Argument('JS::Handle<JSObject*>', 'aGivenProto')]
  12828. if not descriptor.wrapperCache:
  12829. wrapReturnType = "bool"
  12830. wrapArgs.append(Argument('JS::MutableHandle<JSObject*>',
  12831. 'aReflector'))
  12832. else:
  12833. wrapReturnType = "JSObject*"
  12834. self.methodDecls.insert(0,
  12835. ClassMethod(wrapMethodName, wrapReturnType,
  12836. wrapArgs, virtual=descriptor.wrapperCache,
  12837. breakAfterReturnDecl=" ",
  12838. override=descriptor.wrapperCache,
  12839. body=self.getWrapObjectBody()))
  12840. if descriptor.hasCEReactions():
  12841. self.methodDecls.insert(0,
  12842. ClassMethod("GetDocGroup", "DocGroup*", [],
  12843. const=True,
  12844. breakAfterReturnDecl=" ",
  12845. body=self.getGetDocGroupBody()))
  12846. if wantGetParent:
  12847. self.methodDecls.insert(0,
  12848. ClassMethod("GetParentObject",
  12849. self.getGetParentObjectReturnType(),
  12850. [], const=True,
  12851. breakAfterReturnDecl=" ",
  12852. body=self.getGetParentObjectBody()))
  12853. # Invoke CGClass.__init__ in any subclasses afterwards to do the actual codegen.
  12854. def getWrapObjectBody(self):
  12855. return None
  12856. def getGetParentObjectReturnType(self):
  12857. return ("// TODO: return something sensible here, and change the return type\n"
  12858. "%s*" % self.descriptor.nativeType.split('::')[-1])
  12859. def getGetParentObjectBody(self):
  12860. return None
  12861. def getGetDocGroupBody(self):
  12862. return None
  12863. def deps(self):
  12864. return self._deps
  12865. class CGExampleClass(CGBindingImplClass):
  12866. """
  12867. Codegen for the actual example class implementation for this descriptor
  12868. """
  12869. def __init__(self, descriptor):
  12870. CGBindingImplClass.__init__(self, descriptor,
  12871. CGExampleMethod, CGExampleGetter, CGExampleSetter,
  12872. wantGetParent=descriptor.wrapperCache)
  12873. self.parentIface = descriptor.interface.parent
  12874. if self.parentIface:
  12875. self.parentDesc = descriptor.getDescriptor(
  12876. self.parentIface.identifier.name)
  12877. bases = [ClassBase(self.nativeLeafName(self.parentDesc))]
  12878. else:
  12879. bases = [ClassBase("nsISupports /* or NonRefcountedDOMObject if this is a non-refcounted object */")]
  12880. if descriptor.wrapperCache:
  12881. bases.append(ClassBase("nsWrapperCache /* Change wrapperCache in the binding configuration if you don't want this */"))
  12882. destructorVisibility = "protected"
  12883. if self.parentIface:
  12884. extradeclarations = (
  12885. "public:\n"
  12886. " NS_DECL_ISUPPORTS_INHERITED\n"
  12887. " NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(%s, %s)\n"
  12888. "\n" % (self.nativeLeafName(descriptor),
  12889. self.nativeLeafName(self.parentDesc)))
  12890. else:
  12891. extradeclarations = (
  12892. "public:\n"
  12893. " NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
  12894. " NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n"
  12895. "\n" % self.nativeLeafName(descriptor))
  12896. if descriptor.interface.hasChildInterfaces():
  12897. decorators = ""
  12898. else:
  12899. decorators = "final"
  12900. CGClass.__init__(self, self.nativeLeafName(descriptor),
  12901. bases=bases,
  12902. constructors=[ClassConstructor([],
  12903. visibility="public")],
  12904. destructor=ClassDestructor(visibility=destructorVisibility),
  12905. methods=self.methodDecls,
  12906. decorators=decorators,
  12907. extradeclarations=extradeclarations)
  12908. def define(self):
  12909. # Just override CGClass and do our own thing
  12910. ctordtor = dedent("""
  12911. ${nativeType}::${nativeType}()
  12912. {
  12913. // Add |MOZ_COUNT_CTOR(${nativeType});| for a non-refcounted object.
  12914. }
  12915. ${nativeType}::~${nativeType}()
  12916. {
  12917. // Add |MOZ_COUNT_DTOR(${nativeType});| for a non-refcounted object.
  12918. }
  12919. """)
  12920. if self.parentIface:
  12921. ccImpl = dedent("""
  12922. // Only needed for refcounted objects.
  12923. # error "If you don't have members that need cycle collection,
  12924. # then remove all the cycle collection bits from this
  12925. # implementation and the corresponding header. If you do, you
  12926. # want NS_IMPL_CYCLE_COLLECTION_INHERITED(${nativeType},
  12927. # ${parentType}, your, members, here)"
  12928. NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
  12929. NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
  12930. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
  12931. NS_INTERFACE_MAP_END_INHERITING(${parentType})
  12932. """)
  12933. else:
  12934. ccImpl = dedent("""
  12935. // Only needed for refcounted objects.
  12936. NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(${nativeType})
  12937. NS_IMPL_CYCLE_COLLECTING_ADDREF(${nativeType})
  12938. NS_IMPL_CYCLE_COLLECTING_RELEASE(${nativeType})
  12939. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
  12940. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  12941. NS_INTERFACE_MAP_ENTRY(nsISupports)
  12942. NS_INTERFACE_MAP_END
  12943. """)
  12944. if self.descriptor.wrapperCache:
  12945. reflectorArg = ""
  12946. reflectorPassArg = ""
  12947. returnType = "JSObject*"
  12948. else:
  12949. reflectorArg = ", JS::MutableHandle<JSObject*> aReflector"
  12950. reflectorPassArg = ", aReflector"
  12951. returnType = "bool"
  12952. classImpl = ccImpl + ctordtor + "\n" + dedent("""
  12953. ${returnType}
  12954. ${nativeType}::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto${reflectorArg})
  12955. {
  12956. return ${ifaceName}Binding::Wrap(aCx, this, aGivenProto${reflectorPassArg});
  12957. }
  12958. """)
  12959. return string.Template(classImpl).substitute(
  12960. ifaceName=self.descriptor.name,
  12961. nativeType=self.nativeLeafName(self.descriptor),
  12962. parentType=self.nativeLeafName(self.parentDesc) if self.parentIface else "",
  12963. returnType=returnType,
  12964. reflectorArg=reflectorArg,
  12965. reflectorPassArg=reflectorPassArg)
  12966. @staticmethod
  12967. def nativeLeafName(descriptor):
  12968. return descriptor.nativeType.split('::')[-1]
  12969. class CGExampleRoot(CGThing):
  12970. """
  12971. Root codegen class for example implementation generation. Instantiate the
  12972. class and call declare or define to generate header or cpp code,
  12973. respectively.
  12974. """
  12975. def __init__(self, config, interfaceName):
  12976. descriptor = config.getDescriptor(interfaceName)
  12977. self.root = CGWrapper(CGExampleClass(descriptor),
  12978. pre="\n", post="\n")
  12979. self.root = CGNamespace.build(["mozilla", "dom"], self.root)
  12980. builder = ForwardDeclarationBuilder()
  12981. if descriptor.hasCEReactions():
  12982. builder.addInMozillaDom("DocGroup")
  12983. for member in descriptor.interface.members:
  12984. if not member.isAttr() and not member.isMethod():
  12985. continue
  12986. if member.isStatic():
  12987. builder.addInMozillaDom("GlobalObject")
  12988. if member.isAttr() and not member.isMaplikeOrSetlikeAttr():
  12989. builder.forwardDeclareForType(member.type, config)
  12990. else:
  12991. assert member.isMethod()
  12992. if not member.isMaplikeOrSetlikeOrIterableMethod():
  12993. for sig in member.signatures():
  12994. builder.forwardDeclareForType(sig[0], config)
  12995. for arg in sig[1]:
  12996. builder.forwardDeclareForType(arg.type, config)
  12997. self.root = CGList([builder.build(),
  12998. self.root], "\n")
  12999. # Throw in our #includes
  13000. self.root = CGHeaders([], [], [], [],
  13001. ["nsWrapperCache.h",
  13002. "nsCycleCollectionParticipant.h",
  13003. "mozilla/Attributes.h",
  13004. "mozilla/ErrorResult.h",
  13005. "mozilla/dom/BindingDeclarations.h",
  13006. "js/TypeDecls.h"],
  13007. ["mozilla/dom/%s.h" % interfaceName,
  13008. ("mozilla/dom/%s" %
  13009. CGHeaders.getDeclarationFilename(descriptor.interface))], "", self.root)
  13010. # And now some include guards
  13011. self.root = CGIncludeGuard(interfaceName, self.root)
  13012. # And our license block comes before everything else
  13013. self.root = CGWrapper(self.root, pre=dedent("""
  13014. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  13015. /* vim:set ts=2 sw=2 sts=2 et cindent: */
  13016. /* This Source Code Form is subject to the terms of the Mozilla Public
  13017. * License, v. 2.0. If a copy of the MPL was not distributed with this
  13018. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  13019. """))
  13020. def declare(self):
  13021. return self.root.declare()
  13022. def define(self):
  13023. return self.root.define()
  13024. def jsImplName(name):
  13025. return name + "JSImpl"
  13026. class CGJSImplMember(CGNativeMember):
  13027. """
  13028. Base class for generating code for the members of the implementation class
  13029. for a JS-implemented WebIDL interface.
  13030. """
  13031. def __init__(self, descriptorProvider, member, name, signature,
  13032. extendedAttrs, breakAfter=True, passJSBitsAsNeeded=True,
  13033. visibility="public", variadicIsSequence=False,
  13034. virtual=False, override=False):
  13035. CGNativeMember.__init__(self, descriptorProvider, member, name,
  13036. signature, extendedAttrs, breakAfter=breakAfter,
  13037. passJSBitsAsNeeded=passJSBitsAsNeeded,
  13038. visibility=visibility,
  13039. variadicIsSequence=variadicIsSequence,
  13040. virtual=virtual,
  13041. override=override)
  13042. self.body = self.getImpl()
  13043. def getArgs(self, returnType, argList):
  13044. args = CGNativeMember.getArgs(self, returnType, argList)
  13045. args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
  13046. return args
  13047. class CGJSImplMethod(CGJSImplMember):
  13048. """
  13049. Class for generating code for the methods for a JS-implemented WebIDL
  13050. interface.
  13051. """
  13052. def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
  13053. virtual = False
  13054. override = False
  13055. if (method.identifier.name == "eventListenerWasAdded" or
  13056. method.identifier.name == "eventListenerWasRemoved"):
  13057. virtual = True
  13058. override = True
  13059. self.signature = signature
  13060. self.descriptor = descriptor
  13061. self.isConstructor = isConstructor
  13062. CGJSImplMember.__init__(self, descriptor, method,
  13063. CGSpecializedMethod.makeNativeName(descriptor,
  13064. method),
  13065. signature,
  13066. descriptor.getExtendedAttributes(method),
  13067. breakAfter=breakAfter,
  13068. variadicIsSequence=True,
  13069. passJSBitsAsNeeded=False,
  13070. virtual=virtual,
  13071. override=override)
  13072. def getArgs(self, returnType, argList):
  13073. if self.isConstructor:
  13074. # Skip the JSCompartment bits for constructors; it's handled
  13075. # manually in getImpl.
  13076. return CGNativeMember.getArgs(self, returnType, argList)
  13077. return CGJSImplMember.getArgs(self, returnType, argList)
  13078. def getImpl(self):
  13079. args = self.getArgs(self.signature[0], self.signature[1])
  13080. if not self.isConstructor:
  13081. return 'return mImpl->%s(%s);\n' % (self.name, ", ".join(arg.name for arg in args))
  13082. assert self.descriptor.interface.isJSImplemented()
  13083. if self.name != 'Constructor':
  13084. raise TypeError("Named constructors are not supported for JS implemented WebIDL. See bug 851287.")
  13085. if len(self.signature[1]) != 0:
  13086. # The first two arguments to the constructor implementation are not
  13087. # arguments to the WebIDL constructor, so don't pass them to __Init()
  13088. assert args[0].argType == 'const GlobalObject&'
  13089. assert args[1].argType == 'JSContext*'
  13090. constructorArgs = [arg.name for arg in args[2:]]
  13091. constructorArgs.append("js::GetObjectCompartment(scopeObj)")
  13092. initCall = fill(
  13093. """
  13094. // Wrap the object before calling __Init so that __DOM_IMPL__ is available.
  13095. JS::Rooted<JSObject*> scopeObj(cx, globalHolder->GetGlobalJSObject());
  13096. MOZ_ASSERT(js::IsObjectInContextCompartment(scopeObj, cx));
  13097. JS::Rooted<JS::Value> wrappedVal(cx);
  13098. if (!GetOrCreateDOMReflector(cx, impl, &wrappedVal)) {
  13099. //XXX Assertion disabled for now, see bug 991271.
  13100. MOZ_ASSERT(true || JS_IsExceptionPending(cx));
  13101. aRv.Throw(NS_ERROR_UNEXPECTED);
  13102. return nullptr;
  13103. }
  13104. // Initialize the object with the constructor arguments.
  13105. impl->mImpl->__Init(${args});
  13106. if (aRv.Failed()) {
  13107. return nullptr;
  13108. }
  13109. """,
  13110. args=", ".join(constructorArgs))
  13111. else:
  13112. initCall = ""
  13113. return genConstructorBody(self.descriptor, initCall)
  13114. def genConstructorBody(descriptor, initCall=""):
  13115. return fill(
  13116. """
  13117. JS::Rooted<JSObject*> jsImplObj(cx);
  13118. nsCOMPtr<nsIGlobalObject> globalHolder =
  13119. ConstructJSImplementation("${contractId}", global, &jsImplObj, aRv);
  13120. if (aRv.Failed()) {
  13121. return nullptr;
  13122. }
  13123. // Build the C++ implementation.
  13124. RefPtr<${implClass}> impl = new ${implClass}(jsImplObj, globalHolder);
  13125. $*{initCall}
  13126. return impl.forget();
  13127. """,
  13128. contractId=descriptor.interface.getJSImplementation(),
  13129. implClass=descriptor.name,
  13130. initCall=initCall)
  13131. # We're always fallible
  13132. def callbackGetterName(attr, descriptor):
  13133. return "Get" + MakeNativeName(
  13134. descriptor.binaryNameFor(attr.identifier.name))
  13135. def callbackSetterName(attr, descriptor):
  13136. return "Set" + MakeNativeName(
  13137. descriptor.binaryNameFor(attr.identifier.name))
  13138. class CGJSImplClearCachedValueMethod(CGAbstractBindingMethod):
  13139. def __init__(self, descriptor, attr):
  13140. if attr.getExtendedAttribute("StoreInSlot"):
  13141. raise TypeError("[StoreInSlot] is not supported for JS-implemented WebIDL. See bug 1056325.")
  13142. CGAbstractBindingMethod.__init__(self, descriptor,
  13143. MakeJSImplClearCachedValueNativeName(attr),
  13144. JSNativeArguments())
  13145. self.attr = attr
  13146. def generate_code(self):
  13147. return CGGeneric(fill(
  13148. """
  13149. ${bindingNamespace}::${fnName}(self);
  13150. args.rval().setUndefined();
  13151. return true;
  13152. """,
  13153. bindingNamespace=toBindingNamespace(self.descriptor.name),
  13154. fnName=MakeClearCachedValueNativeName(self.attr)))
  13155. class CGJSImplGetter(CGJSImplMember):
  13156. """
  13157. Class for generating code for the getters of attributes for a JS-implemented
  13158. WebIDL interface.
  13159. """
  13160. def __init__(self, descriptor, attr):
  13161. CGJSImplMember.__init__(self, descriptor, attr,
  13162. CGSpecializedGetter.makeNativeName(descriptor,
  13163. attr),
  13164. (attr.type, []),
  13165. descriptor.getExtendedAttributes(attr,
  13166. getter=True),
  13167. passJSBitsAsNeeded=False)
  13168. def getImpl(self):
  13169. callbackArgs = [arg.name for arg in self.getArgs(self.member.type, [])]
  13170. return 'return mImpl->%s(%s);\n' % (
  13171. callbackGetterName(self.member, self.descriptorProvider),
  13172. ", ".join(callbackArgs))
  13173. class CGJSImplSetter(CGJSImplMember):
  13174. """
  13175. Class for generating code for the setters of attributes for a JS-implemented
  13176. WebIDL interface.
  13177. """
  13178. def __init__(self, descriptor, attr):
  13179. CGJSImplMember.__init__(self, descriptor, attr,
  13180. CGSpecializedSetter.makeNativeName(descriptor,
  13181. attr),
  13182. (BuiltinTypes[IDLBuiltinType.Types.void],
  13183. [FakeArgument(attr.type, attr)]),
  13184. descriptor.getExtendedAttributes(attr,
  13185. setter=True),
  13186. passJSBitsAsNeeded=False)
  13187. def getImpl(self):
  13188. callbackArgs = [arg.name for arg in self.getArgs(BuiltinTypes[IDLBuiltinType.Types.void],
  13189. [FakeArgument(self.member.type, self.member)])]
  13190. return 'mImpl->%s(%s);\n' % (
  13191. callbackSetterName(self.member, self.descriptorProvider),
  13192. ", ".join(callbackArgs))
  13193. class CGJSImplClass(CGBindingImplClass):
  13194. def __init__(self, descriptor):
  13195. CGBindingImplClass.__init__(self, descriptor, CGJSImplMethod, CGJSImplGetter, CGJSImplSetter, skipStaticMethods=True)
  13196. if descriptor.interface.parent:
  13197. parentClass = descriptor.getDescriptor(
  13198. descriptor.interface.parent.identifier.name).jsImplParent
  13199. baseClasses = [ClassBase(parentClass)]
  13200. isupportsDecl = "NS_DECL_ISUPPORTS_INHERITED\n"
  13201. ccDecl = ("NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(%s, %s)\n" %
  13202. (descriptor.name, parentClass))
  13203. constructorBody = dedent("""
  13204. // Make sure we're an nsWrapperCache already
  13205. MOZ_ASSERT(static_cast<nsWrapperCache*>(this));
  13206. // And that our ancestor has not called SetIsNotDOMBinding()
  13207. MOZ_ASSERT(IsDOMBinding());
  13208. """)
  13209. extradefinitions = fill(
  13210. """
  13211. NS_IMPL_CYCLE_COLLECTION_INHERITED(${ifaceName}, ${parentClass}, mImpl, mParent)
  13212. NS_IMPL_ADDREF_INHERITED(${ifaceName}, ${parentClass})
  13213. NS_IMPL_RELEASE_INHERITED(${ifaceName}, ${parentClass})
  13214. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(${ifaceName})
  13215. NS_INTERFACE_MAP_END_INHERITING(${parentClass})
  13216. """,
  13217. ifaceName=self.descriptor.name,
  13218. parentClass=parentClass)
  13219. else:
  13220. baseClasses = [ClassBase("nsSupportsWeakReference"),
  13221. ClassBase("nsWrapperCache")]
  13222. isupportsDecl = "NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
  13223. ccDecl = ("NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n" %
  13224. descriptor.name)
  13225. extradefinitions = fill(
  13226. """
  13227. NS_IMPL_CYCLE_COLLECTION_CLASS(${ifaceName})
  13228. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(${ifaceName})
  13229. NS_IMPL_CYCLE_COLLECTION_UNLINK(mImpl)
  13230. NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
  13231. NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
  13232. tmp->ClearWeakReferences();
  13233. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  13234. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(${ifaceName})
  13235. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl)
  13236. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
  13237. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  13238. NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(${ifaceName})
  13239. NS_IMPL_CYCLE_COLLECTING_ADDREF(${ifaceName})
  13240. NS_IMPL_CYCLE_COLLECTING_RELEASE(${ifaceName})
  13241. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${ifaceName})
  13242. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  13243. NS_INTERFACE_MAP_ENTRY(nsISupports)
  13244. NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  13245. NS_INTERFACE_MAP_END
  13246. """,
  13247. ifaceName=self.descriptor.name)
  13248. extradeclarations = fill(
  13249. """
  13250. public:
  13251. $*{isupportsDecl}
  13252. $*{ccDecl}
  13253. private:
  13254. RefPtr<${jsImplName}> mImpl;
  13255. nsCOMPtr<nsIGlobalObject> mParent;
  13256. """,
  13257. isupportsDecl=isupportsDecl,
  13258. ccDecl=ccDecl,
  13259. jsImplName=jsImplName(descriptor.name))
  13260. if descriptor.interface.hasChildInterfaces():
  13261. decorators = ""
  13262. # We need a protected virtual destructor our subclasses can use
  13263. destructor = ClassDestructor(virtual=True, visibility="protected")
  13264. else:
  13265. decorators = "final"
  13266. destructor = ClassDestructor(virtual=False, visibility="private")
  13267. baseConstructors = [
  13268. ("mImpl(new %s(nullptr, aJSImplObject, /* aIncumbentGlobal = */ nullptr))" %
  13269. jsImplName(descriptor.name)),
  13270. "mParent(aParent)"]
  13271. parentInterface = descriptor.interface.parent
  13272. while parentInterface:
  13273. if parentInterface.isJSImplemented():
  13274. baseConstructors.insert(
  13275. 0, "%s(aJSImplObject, aParent)" % parentClass)
  13276. break
  13277. parentInterface = parentInterface.parent
  13278. if not parentInterface and descriptor.interface.parent:
  13279. # We only have C++ ancestors, so only pass along the window
  13280. baseConstructors.insert(0,
  13281. "%s(aParent)" % parentClass)
  13282. constructor = ClassConstructor(
  13283. [Argument("JS::Handle<JSObject*>", "aJSImplObject"),
  13284. Argument("nsIGlobalObject*", "aParent")],
  13285. visibility="public",
  13286. baseConstructors=baseConstructors)
  13287. self.methodDecls.append(
  13288. ClassMethod("_Create",
  13289. "bool",
  13290. JSNativeArguments(),
  13291. static=True,
  13292. body=self.getCreateFromExistingBody()))
  13293. CGClass.__init__(self, descriptor.name,
  13294. bases=baseClasses,
  13295. constructors=[constructor],
  13296. destructor=destructor,
  13297. methods=self.methodDecls,
  13298. decorators=decorators,
  13299. extradeclarations=extradeclarations,
  13300. extradefinitions=extradefinitions)
  13301. def getWrapObjectBody(self):
  13302. return fill(
  13303. """
  13304. JS::Rooted<JSObject*> obj(aCx, ${name}Binding::Wrap(aCx, this, aGivenProto));
  13305. if (!obj) {
  13306. return nullptr;
  13307. }
  13308. // Now define it on our chrome object
  13309. JSAutoCompartment ac(aCx, mImpl->Callback());
  13310. if (!JS_WrapObject(aCx, &obj)) {
  13311. return nullptr;
  13312. }
  13313. if (!JS_DefineProperty(aCx, mImpl->Callback(), "__DOM_IMPL__", obj, 0)) {
  13314. return nullptr;
  13315. }
  13316. return obj;
  13317. """,
  13318. name=self.descriptor.name)
  13319. def getGetParentObjectReturnType(self):
  13320. return "nsISupports*"
  13321. def getGetParentObjectBody(self):
  13322. return "return mParent;\n"
  13323. def getGetDocGroupBody(self):
  13324. return dedent(
  13325. """
  13326. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
  13327. if (!window) {
  13328. return nullptr;
  13329. }
  13330. return window->GetDocGroup();
  13331. """)
  13332. def getCreateFromExistingBody(self):
  13333. # XXXbz we could try to get parts of this (e.g. the argument
  13334. # conversions) auto-generated by somehow creating an IDLMethod and
  13335. # adding it to our interface, but we'd still need to special-case the
  13336. # implementation slightly to have it not try to forward to the JS
  13337. # object...
  13338. return fill(
  13339. """
  13340. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  13341. if (args.length() < 2) {
  13342. return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${ifaceName}._create");
  13343. }
  13344. if (!args[0].isObject()) {
  13345. return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 1 of ${ifaceName}._create");
  13346. }
  13347. if (!args[1].isObject()) {
  13348. return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 2 of ${ifaceName}._create");
  13349. }
  13350. // GlobalObject will go through wrappers as needed for us, and
  13351. // is simpler than the right UnwrapArg incantation.
  13352. GlobalObject global(cx, &args[0].toObject());
  13353. if (global.Failed()) {
  13354. return false;
  13355. }
  13356. nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(global.GetAsSupports());
  13357. MOZ_ASSERT(globalHolder);
  13358. JS::Rooted<JSObject*> arg(cx, &args[1].toObject());
  13359. RefPtr<${implName}> impl = new ${implName}(arg, globalHolder);
  13360. MOZ_ASSERT(js::IsObjectInContextCompartment(arg, cx));
  13361. return GetOrCreateDOMReflector(cx, impl, args.rval());
  13362. """,
  13363. ifaceName=self.descriptor.interface.identifier.name,
  13364. implName=self.descriptor.name)
  13365. def isJSImplementedDescriptor(descriptorProvider):
  13366. return (isinstance(descriptorProvider, Descriptor) and
  13367. descriptorProvider.interface.isJSImplemented())
  13368. class CGCallback(CGClass):
  13369. def __init__(self, idlObject, descriptorProvider, baseName, methods,
  13370. getters=[], setters=[]):
  13371. self.baseName = baseName
  13372. self._deps = idlObject.getDeps()
  13373. self.idlObject = idlObject
  13374. self.name = idlObject.identifier.name
  13375. if isJSImplementedDescriptor(descriptorProvider):
  13376. self.name = jsImplName(self.name)
  13377. # For our public methods that needThisHandling we want most of the
  13378. # same args and the same return type as what CallbackMember
  13379. # generates. So we want to take advantage of all its
  13380. # CGNativeMember infrastructure, but that infrastructure can't deal
  13381. # with templates and most especially template arguments. So just
  13382. # cheat and have CallbackMember compute all those things for us.
  13383. realMethods = []
  13384. for method in methods:
  13385. if not isinstance(method, CallbackMember) or not method.needThisHandling:
  13386. realMethods.append(method)
  13387. else:
  13388. realMethods.extend(self.getMethodImpls(method))
  13389. realMethods.append(
  13390. ClassMethod("operator==", "bool",
  13391. [Argument("const %s&" % self.name, "aOther")],
  13392. inline=True, bodyInHeader=True,
  13393. const=True,
  13394. body=("return %s::operator==(aOther);\n" % baseName)))
  13395. CGClass.__init__(self, self.name,
  13396. bases=[ClassBase(baseName)],
  13397. constructors=self.getConstructors(),
  13398. methods=realMethods+getters+setters)
  13399. def getConstructors(self):
  13400. if (not self.idlObject.isInterface() and
  13401. not self.idlObject._treatNonObjectAsNull):
  13402. body = "MOZ_ASSERT(JS::IsCallable(mCallback));\n"
  13403. else:
  13404. # Not much we can assert about it, other than not being null, and
  13405. # CallbackObject does that already.
  13406. body = ""
  13407. return [
  13408. ClassConstructor(
  13409. [Argument("JSContext*", "aCx"),
  13410. Argument("JS::Handle<JSObject*>", "aCallback"),
  13411. Argument("nsIGlobalObject*", "aIncumbentGlobal")],
  13412. bodyInHeader=True,
  13413. visibility="public",
  13414. explicit=True,
  13415. baseConstructors=[
  13416. "%s(aCx, aCallback, aIncumbentGlobal)" % self.baseName,
  13417. ],
  13418. body=body),
  13419. ClassConstructor(
  13420. [Argument("JSContext*", "aCx"),
  13421. Argument("JS::Handle<JSObject*>", "aCallback"),
  13422. Argument("nsIGlobalObject*", "aIncumbentGlobal"),
  13423. Argument("const FastCallbackConstructor&", "")],
  13424. bodyInHeader=True,
  13425. visibility="public",
  13426. explicit=True,
  13427. baseConstructors=[
  13428. "%s(aCx, aCallback, aIncumbentGlobal, FastCallbackConstructor())" % self.baseName,
  13429. ],
  13430. body=body),
  13431. ClassConstructor(
  13432. [Argument("JS::Handle<JSObject*>", "aCallback"),
  13433. Argument("JS::Handle<JSObject*>", "aAsyncStack"),
  13434. Argument("nsIGlobalObject*", "aIncumbentGlobal")],
  13435. bodyInHeader=True,
  13436. visibility="public",
  13437. explicit=True,
  13438. baseConstructors=[
  13439. "%s(aCallback, aAsyncStack, aIncumbentGlobal)" % self.baseName,
  13440. ],
  13441. body=body)]
  13442. def getMethodImpls(self, method):
  13443. assert method.needThisHandling
  13444. args = list(method.args)
  13445. # Strip out the JSContext*/JSObject* args
  13446. # that got added.
  13447. assert args[0].name == "cx" and args[0].argType == "JSContext*"
  13448. assert args[1].name == "aThisVal" and args[1].argType == "JS::Handle<JS::Value>"
  13449. args = args[2:]
  13450. # Now remember which index the ErrorResult argument is at;
  13451. # we'll need this below.
  13452. assert args[-1].name == "aRv" and args[-1].argType == "ErrorResult&"
  13453. rvIndex = len(args) - 1
  13454. assert rvIndex >= 0
  13455. # Record the names of all the arguments, so we can use them when we call
  13456. # the private method.
  13457. argnames = [arg.name for arg in args]
  13458. argnamesWithThis = ["s.GetContext()", "thisValJS"] + argnames
  13459. argnamesWithoutThis = ["s.GetContext()", "JS::UndefinedHandleValue"] + argnames
  13460. # Now that we've recorded the argnames for our call to our private
  13461. # method, insert our optional argument for the execution reason.
  13462. args.append(Argument("const char*", "aExecutionReason",
  13463. "nullptr"))
  13464. # Make copies of the arg list for the two "without rv" overloads. Note
  13465. # that those don't need aExceptionHandling or aCompartment arguments
  13466. # because those would make not sense anyway: the only sane thing to do
  13467. # with exceptions in the "without rv" cases is to report them.
  13468. argsWithoutRv = list(args)
  13469. argsWithoutRv.pop(rvIndex)
  13470. argsWithoutThisAndRv = list(argsWithoutRv)
  13471. # Add the potional argument for deciding whether the CallSetup should
  13472. # re-throw exceptions on aRv.
  13473. args.append(Argument("ExceptionHandling", "aExceptionHandling",
  13474. "eReportExceptions"))
  13475. # And the argument for communicating when exceptions should really be
  13476. # rethrown. In particular, even when aExceptionHandling is
  13477. # eRethrowExceptions they won't get rethrown if aCompartment is provided
  13478. # and its principal doesn't subsume either the callback or the
  13479. # exception.
  13480. args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
  13481. # And now insert our template argument.
  13482. argsWithoutThis = list(args)
  13483. args.insert(0, Argument("const T&", "thisVal"))
  13484. argsWithoutRv.insert(0, Argument("const T&", "thisVal"))
  13485. argnamesWithoutThisAndRv = [arg.name for arg in argsWithoutThisAndRv]
  13486. argnamesWithoutThisAndRv.insert(rvIndex, "rv");
  13487. # If we just leave things like that, and have no actual arguments in the
  13488. # IDL, we will end up trying to call the templated "without rv" overload
  13489. # with "rv" as the thisVal. That's no good. So explicitly append the
  13490. # aExceptionHandling and aCompartment values we need to end up matching
  13491. # the signature of our non-templated "with rv" overload.
  13492. argnamesWithoutThisAndRv.extend(["eReportExceptions", "nullptr"])
  13493. argnamesWithoutRv = [arg.name for arg in argsWithoutRv]
  13494. # Note that we need to insert at rvIndex + 1, since we inserted a
  13495. # thisVal arg at the start.
  13496. argnamesWithoutRv.insert(rvIndex + 1, "rv")
  13497. errorReturn = method.getDefaultRetval()
  13498. setupCall = fill(
  13499. """
  13500. if (!aExecutionReason) {
  13501. aExecutionReason = "${executionReason}";
  13502. }
  13503. CallSetup s(this, aRv, aExecutionReason, aExceptionHandling, aCompartment);
  13504. if (!s.GetContext()) {
  13505. MOZ_ASSERT(aRv.Failed());
  13506. return${errorReturn};
  13507. }
  13508. """,
  13509. errorReturn=errorReturn,
  13510. executionReason=method.getPrettyName())
  13511. bodyWithThis = fill(
  13512. """
  13513. $*{setupCall}
  13514. JS::Rooted<JS::Value> thisValJS(s.GetContext());
  13515. if (!ToJSValue(s.GetContext(), thisVal, &thisValJS)) {
  13516. aRv.Throw(NS_ERROR_FAILURE);
  13517. return${errorReturn};
  13518. }
  13519. return ${methodName}(${callArgs});
  13520. """,
  13521. setupCall=setupCall,
  13522. errorReturn=errorReturn,
  13523. methodName=method.name,
  13524. callArgs=", ".join(argnamesWithThis))
  13525. bodyWithoutThis = fill(
  13526. """
  13527. $*{setupCall}
  13528. return ${methodName}(${callArgs});
  13529. """,
  13530. setupCall=setupCall,
  13531. errorReturn=errorReturn,
  13532. methodName=method.name,
  13533. callArgs=", ".join(argnamesWithoutThis))
  13534. bodyWithThisWithoutRv = fill(
  13535. """
  13536. IgnoredErrorResult rv;
  13537. return ${methodName}(${callArgs});
  13538. """,
  13539. methodName=method.name,
  13540. callArgs=", ".join(argnamesWithoutRv))
  13541. bodyWithoutThisAndRv = fill(
  13542. """
  13543. IgnoredErrorResult rv;
  13544. return ${methodName}(${callArgs});
  13545. """,
  13546. methodName=method.name,
  13547. callArgs=", ".join(argnamesWithoutThisAndRv))
  13548. return [ClassMethod(method.name, method.returnType, args,
  13549. bodyInHeader=True,
  13550. templateArgs=["typename T"],
  13551. body=bodyWithThis),
  13552. ClassMethod(method.name, method.returnType, argsWithoutThis,
  13553. bodyInHeader=True,
  13554. body=bodyWithoutThis),
  13555. ClassMethod(method.name, method.returnType, argsWithoutRv,
  13556. bodyInHeader=True,
  13557. templateArgs=["typename T"],
  13558. body=bodyWithThisWithoutRv),
  13559. ClassMethod(method.name, method.returnType, argsWithoutThisAndRv,
  13560. bodyInHeader=True,
  13561. body=bodyWithoutThisAndRv),
  13562. method]
  13563. def deps(self):
  13564. return self._deps
  13565. class CGCallbackFunction(CGCallback):
  13566. def __init__(self, callback, descriptorProvider):
  13567. self.callback = callback
  13568. CGCallback.__init__(self, callback, descriptorProvider,
  13569. "CallbackFunction",
  13570. methods=[CallCallback(callback, descriptorProvider)])
  13571. def getConstructors(self):
  13572. return CGCallback.getConstructors(self) + [
  13573. ClassConstructor(
  13574. [Argument("CallbackFunction*", "aOther")],
  13575. bodyInHeader=True,
  13576. visibility="public",
  13577. explicit=True,
  13578. baseConstructors=["CallbackFunction(aOther)"])]
  13579. class CGFastCallback(CGClass):
  13580. def __init__(self, idlObject):
  13581. self._deps = idlObject.getDeps()
  13582. baseName = idlObject.identifier.name
  13583. constructor = ClassConstructor(
  13584. [Argument("JSContext*", "aCx"),
  13585. Argument("JS::Handle<JSObject*>", "aCallback"),
  13586. Argument("nsIGlobalObject*", "aIncumbentGlobal")],
  13587. bodyInHeader=True,
  13588. visibility="public",
  13589. explicit=True,
  13590. baseConstructors=[
  13591. "%s(aCx, aCallback, aIncumbentGlobal, FastCallbackConstructor())" %
  13592. baseName,
  13593. ],
  13594. body="")
  13595. traceMethod = ClassMethod("Trace", "void",
  13596. [Argument("JSTracer*", "aTracer")],
  13597. inline=True,
  13598. bodyInHeader=True,
  13599. visibility="public",
  13600. body="%s::Trace(aTracer);\n" % baseName)
  13601. holdMethod = ClassMethod("HoldJSObjectsIfMoreThanOneOwner", "void",
  13602. [],
  13603. inline=True,
  13604. bodyInHeader=True,
  13605. visibility="public",
  13606. body=(
  13607. "%s::HoldJSObjectsIfMoreThanOneOwner();\n" %
  13608. baseName))
  13609. CGClass.__init__(self, "Fast%s" % baseName,
  13610. bases=[ClassBase(baseName)],
  13611. constructors=[constructor],
  13612. methods=[traceMethod, holdMethod])
  13613. def deps(self):
  13614. return self._deps
  13615. class CGCallbackInterface(CGCallback):
  13616. def __init__(self, descriptor, typedArraysAreStructs=False):
  13617. iface = descriptor.interface
  13618. attrs = [m for m in iface.members if m.isAttr() and not m.isStatic()]
  13619. getters = [CallbackGetter(a, descriptor, typedArraysAreStructs)
  13620. for a in attrs]
  13621. setters = [CallbackSetter(a, descriptor, typedArraysAreStructs)
  13622. for a in attrs if not a.readonly]
  13623. methods = [m for m in iface.members
  13624. if m.isMethod() and not m.isStatic() and not m.isIdentifierLess()]
  13625. methods = [CallbackOperation(m, sig, descriptor, typedArraysAreStructs)
  13626. for m in methods for sig in m.signatures()]
  13627. if iface.isJSImplemented() and iface.ctor():
  13628. sigs = descriptor.interface.ctor().signatures()
  13629. if len(sigs) != 1:
  13630. raise TypeError("We only handle one constructor. See bug 869268.")
  13631. methods.append(CGJSImplInitOperation(sigs[0], descriptor))
  13632. if any(m.isAttr() or m.isMethod() for m in iface.members) or (iface.isJSImplemented() and iface.ctor()):
  13633. methods.append(initIdsClassMethod([descriptor.binaryNameFor(m.identifier.name)
  13634. for m in iface.members
  13635. if m.isAttr() or m.isMethod()] +
  13636. (["__init"] if iface.isJSImplemented() and iface.ctor() else []),
  13637. iface.identifier.name + "Atoms"))
  13638. CGCallback.__init__(self, iface, descriptor, "CallbackInterface",
  13639. methods, getters=getters, setters=setters)
  13640. class FakeMember():
  13641. def __init__(self, name=None):
  13642. self.treatNullAs = "Default"
  13643. if name is not None:
  13644. self.identifier = FakeIdentifier(name)
  13645. def isStatic(self):
  13646. return False
  13647. def isAttr(self):
  13648. return False
  13649. def isMethod(self):
  13650. return False
  13651. def getExtendedAttribute(self, name):
  13652. # Claim to be a [NewObject] so we can avoid the "return a raw pointer"
  13653. # comments CGNativeMember codegen would otherwise stick in.
  13654. if name == "NewObject":
  13655. return True
  13656. return None
  13657. class CallbackMember(CGNativeMember):
  13658. # XXXbz It's OK to use CallbackKnownNotGray for wrapScope because
  13659. # CallSetup already handled the unmark-gray bits for us. we don't have
  13660. # anything better to use for 'obj', really...
  13661. def __init__(self, sig, name, descriptorProvider, needThisHandling,
  13662. rethrowContentException=False, typedArraysAreStructs=False,
  13663. wrapScope='CallbackKnownNotGray()'):
  13664. """
  13665. needThisHandling is True if we need to be able to accept a specified
  13666. thisObj, False otherwise.
  13667. """
  13668. assert not rethrowContentException or not needThisHandling
  13669. self.retvalType = sig[0]
  13670. self.originalSig = sig
  13671. args = sig[1]
  13672. self.argCount = len(args)
  13673. if self.argCount > 0:
  13674. # Check for variadic arguments
  13675. lastArg = args[self.argCount-1]
  13676. if lastArg.variadic:
  13677. self.argCountStr = ("(%d - 1) + %s.Length()" %
  13678. (self.argCount, lastArg.identifier.name))
  13679. else:
  13680. self.argCountStr = "%d" % self.argCount
  13681. self.needThisHandling = needThisHandling
  13682. # If needThisHandling, we generate ourselves as private and the caller
  13683. # will handle generating public versions that handle the "this" stuff.
  13684. visibility = "private" if needThisHandling else "public"
  13685. self.rethrowContentException = rethrowContentException
  13686. self.wrapScope = wrapScope
  13687. # We don't care, for callback codegen, whether our original member was
  13688. # a method or attribute or whatnot. Just always pass FakeMember()
  13689. # here.
  13690. CGNativeMember.__init__(self, descriptorProvider, FakeMember(),
  13691. name, (self.retvalType, args),
  13692. extendedAttrs={},
  13693. passJSBitsAsNeeded=False,
  13694. visibility=visibility,
  13695. typedArraysAreStructs=typedArraysAreStructs)
  13696. # We have to do all the generation of our body now, because
  13697. # the caller relies on us throwing if we can't manage it.
  13698. self.exceptionCode = ("aRv.Throw(NS_ERROR_UNEXPECTED);\n"
  13699. "return%s;\n" % self.getDefaultRetval())
  13700. self.body = self.getImpl()
  13701. def getImpl(self):
  13702. setupCall = self.getCallSetup()
  13703. declRval = self.getRvalDecl()
  13704. if self.argCount > 0:
  13705. argvDecl = fill(
  13706. """
  13707. JS::AutoValueVector argv(cx);
  13708. if (!argv.resize(${argCount})) {
  13709. aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
  13710. return${errorReturn};
  13711. }
  13712. """,
  13713. argCount=self.argCountStr,
  13714. errorReturn=self.getDefaultRetval())
  13715. else:
  13716. # Avoid weird 0-sized arrays
  13717. argvDecl = ""
  13718. convertArgs = self.getArgConversions()
  13719. doCall = self.getCall()
  13720. returnResult = self.getResultConversion()
  13721. return setupCall + declRval + argvDecl + convertArgs + doCall + returnResult
  13722. def getResultConversion(self):
  13723. replacements = {
  13724. "val": "rval",
  13725. "holderName": "rvalHolder",
  13726. "declName": "rvalDecl",
  13727. # We actually want to pass in a null scope object here, because
  13728. # wrapping things into our current compartment (that of mCallback)
  13729. # is what we want.
  13730. "obj": "nullptr",
  13731. "passedToJSImpl": "false"
  13732. }
  13733. if isJSImplementedDescriptor(self.descriptorProvider):
  13734. isCallbackReturnValue = "JSImpl"
  13735. else:
  13736. isCallbackReturnValue = "Callback"
  13737. sourceDescription = "return value of %s" % self.getPrettyName()
  13738. convertType = instantiateJSToNativeConversion(
  13739. getJSToNativeConversionInfo(self.retvalType,
  13740. self.descriptorProvider,
  13741. exceptionCode=self.exceptionCode,
  13742. isCallbackReturnValue=isCallbackReturnValue,
  13743. # Allow returning a callback type that
  13744. # allows non-callable objects.
  13745. allowTreatNonCallableAsNull=True,
  13746. sourceDescription=sourceDescription),
  13747. replacements)
  13748. assignRetval = string.Template(
  13749. self.getRetvalInfo(self.retvalType,
  13750. False)[2]).substitute(replacements)
  13751. type = convertType.define()
  13752. return type + assignRetval
  13753. def getArgConversions(self):
  13754. # Just reget the arglist from self.originalSig, because our superclasses
  13755. # just have way to many members they like to clobber, so I can't find a
  13756. # safe member name to store it in.
  13757. argConversions = [self.getArgConversion(i, arg)
  13758. for i, arg in enumerate(self.originalSig[1])]
  13759. if not argConversions:
  13760. return "\n"
  13761. # Do them back to front, so our argc modifications will work
  13762. # correctly, because we examine trailing arguments first.
  13763. argConversions.reverse()
  13764. # Wrap each one in a scope so that any locals it has don't leak out, and
  13765. # also so that we can just "break;" for our successCode.
  13766. argConversions = [CGWrapper(CGIndenter(CGGeneric(c)),
  13767. pre="do {\n",
  13768. post="} while (0);\n")
  13769. for c in argConversions]
  13770. if self.argCount > 0:
  13771. argConversions.insert(0, self.getArgcDecl())
  13772. # And slap them together.
  13773. return CGList(argConversions, "\n").define() + "\n"
  13774. def getArgConversion(self, i, arg):
  13775. argval = arg.identifier.name
  13776. if arg.variadic:
  13777. argval = argval + "[idx]"
  13778. jsvalIndex = "%d + idx" % i
  13779. else:
  13780. jsvalIndex = "%d" % i
  13781. if arg.canHaveMissingValue():
  13782. argval += ".Value()"
  13783. if arg.type.isDOMString():
  13784. # XPConnect string-to-JS conversion wants to mutate the string. So
  13785. # let's give it a string it can mutate
  13786. # XXXbz if we try to do a sequence of strings, this will kinda fail.
  13787. result = "mutableStr"
  13788. prepend = "nsString mutableStr(%s);\n" % argval
  13789. else:
  13790. result = argval
  13791. prepend = ""
  13792. try:
  13793. conversion = prepend + wrapForType(
  13794. arg.type, self.descriptorProvider,
  13795. {
  13796. 'result': result,
  13797. 'successCode': "continue;\n" if arg.variadic else "break;\n",
  13798. 'jsvalRef': "argv[%s]" % jsvalIndex,
  13799. 'jsvalHandle': "argv[%s]" % jsvalIndex,
  13800. 'obj': self.wrapScope,
  13801. 'returnsNewObject': False,
  13802. 'exceptionCode': self.exceptionCode,
  13803. 'typedArraysAreStructs': self.typedArraysAreStructs
  13804. })
  13805. except MethodNotNewObjectError as err:
  13806. raise TypeError("%s being passed as an argument to %s but is not "
  13807. "wrapper cached, so can't be reliably converted to "
  13808. "a JS object." %
  13809. (err.typename, self.getPrettyName()))
  13810. if arg.variadic:
  13811. conversion = fill(
  13812. """
  13813. for (uint32_t idx = 0; idx < ${arg}.Length(); ++idx) {
  13814. $*{conversion}
  13815. }
  13816. break;
  13817. """,
  13818. arg=arg.identifier.name,
  13819. conversion=conversion)
  13820. elif arg.canHaveMissingValue():
  13821. conversion = fill(
  13822. """
  13823. if (${argName}.WasPassed()) {
  13824. $*{conversion}
  13825. } else if (argc == ${iPlus1}) {
  13826. // This is our current trailing argument; reduce argc
  13827. --argc;
  13828. } else {
  13829. argv[${i}].setUndefined();
  13830. }
  13831. """,
  13832. argName=arg.identifier.name,
  13833. conversion=conversion,
  13834. iPlus1=i + 1,
  13835. i=i)
  13836. return conversion
  13837. def getDefaultRetval(self):
  13838. default = self.getRetvalInfo(self.retvalType, False)[1]
  13839. if len(default) != 0:
  13840. default = " " + default
  13841. return default
  13842. def getArgs(self, returnType, argList):
  13843. args = CGNativeMember.getArgs(self, returnType, argList)
  13844. if not self.needThisHandling:
  13845. # Since we don't need this handling, we're the actual method that
  13846. # will be called, so we need an aRethrowExceptions argument.
  13847. if not self.rethrowContentException:
  13848. args.append(Argument("const char*", "aExecutionReason",
  13849. "nullptr"))
  13850. args.append(Argument("ExceptionHandling", "aExceptionHandling",
  13851. "eReportExceptions"))
  13852. args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
  13853. return args
  13854. # We want to allow the caller to pass in a "this" value, as
  13855. # well as a JSContext.
  13856. return [Argument("JSContext*", "cx"),
  13857. Argument("JS::Handle<JS::Value>", "aThisVal")] + args
  13858. def getCallSetup(self):
  13859. if self.needThisHandling:
  13860. # It's been done for us already
  13861. return ""
  13862. callSetup = "CallSetup s(this, aRv"
  13863. if self.rethrowContentException:
  13864. # getArgs doesn't add the aExceptionHandling argument but does add
  13865. # aCompartment for us.
  13866. callSetup += ', "%s", eRethrowContentExceptions, aCompartment, /* aIsJSImplementedWebIDL = */ ' % self.getPrettyName()
  13867. callSetup += toStringBool(isJSImplementedDescriptor(self.descriptorProvider))
  13868. else:
  13869. callSetup += ', "%s", aExceptionHandling, aCompartment' % self.getPrettyName()
  13870. callSetup += ");\n"
  13871. return fill(
  13872. """
  13873. $*{callSetup}
  13874. JSContext* cx = s.GetContext();
  13875. if (!cx) {
  13876. MOZ_ASSERT(aRv.Failed());
  13877. return${errorReturn};
  13878. }
  13879. """,
  13880. callSetup=callSetup,
  13881. errorReturn=self.getDefaultRetval())
  13882. def getArgcDecl(self):
  13883. return CGGeneric("unsigned argc = %s;\n" % self.argCountStr)
  13884. @staticmethod
  13885. def ensureASCIIName(idlObject):
  13886. type = "attribute" if idlObject.isAttr() else "operation"
  13887. if re.match("[^\x20-\x7E]", idlObject.identifier.name):
  13888. raise SyntaxError('Callback %s name "%s" contains non-ASCII '
  13889. "characters. We can't handle that. %s" %
  13890. (type, idlObject.identifier.name,
  13891. idlObject.location))
  13892. if re.match('"', idlObject.identifier.name):
  13893. raise SyntaxError("Callback %s name '%s' contains "
  13894. "double-quote character. We can't handle "
  13895. "that. %s" %
  13896. (type, idlObject.identifier.name,
  13897. idlObject.location))
  13898. class CallbackMethod(CallbackMember):
  13899. def __init__(self, sig, name, descriptorProvider, needThisHandling,
  13900. rethrowContentException=False, typedArraysAreStructs=False):
  13901. CallbackMember.__init__(self, sig, name, descriptorProvider,
  13902. needThisHandling, rethrowContentException,
  13903. typedArraysAreStructs=typedArraysAreStructs)
  13904. def getRvalDecl(self):
  13905. return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
  13906. def getCall(self):
  13907. if self.argCount > 0:
  13908. args = "JS::HandleValueArray::subarray(argv, 0, argc)"
  13909. else:
  13910. args = "JS::HandleValueArray::empty()"
  13911. return fill(
  13912. """
  13913. $*{declCallable}
  13914. $*{declThis}
  13915. if (${callGuard}!JS::Call(cx, ${thisVal}, callable,
  13916. ${args}, &rval)) {
  13917. aRv.NoteJSContextException(cx);
  13918. return${errorReturn};
  13919. }
  13920. """,
  13921. declCallable=self.getCallableDecl(),
  13922. declThis=self.getThisDecl(),
  13923. callGuard=self.getCallGuard(),
  13924. thisVal=self.getThisVal(),
  13925. args=args,
  13926. errorReturn=self.getDefaultRetval())
  13927. class CallCallback(CallbackMethod):
  13928. def __init__(self, callback, descriptorProvider):
  13929. self.callback = callback
  13930. CallbackMethod.__init__(self, callback.signatures()[0], "Call",
  13931. descriptorProvider, needThisHandling=True)
  13932. def getThisDecl(self):
  13933. return ""
  13934. def getThisVal(self):
  13935. return "aThisVal"
  13936. def getCallableDecl(self):
  13937. return "JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));\n"
  13938. def getPrettyName(self):
  13939. return self.callback.identifier.name
  13940. def getCallGuard(self):
  13941. if self.callback._treatNonObjectAsNull:
  13942. return "JS::IsCallable(mCallback) && "
  13943. return ""
  13944. class CallbackOperationBase(CallbackMethod):
  13945. """
  13946. Common class for implementing various callback operations.
  13947. """
  13948. def __init__(self, signature, jsName, nativeName, descriptor,
  13949. singleOperation, rethrowContentException=False,
  13950. typedArraysAreStructs=False):
  13951. self.singleOperation = singleOperation
  13952. self.methodName = descriptor.binaryNameFor(jsName)
  13953. CallbackMethod.__init__(self, signature, nativeName, descriptor,
  13954. singleOperation, rethrowContentException,
  13955. typedArraysAreStructs=typedArraysAreStructs)
  13956. def getThisDecl(self):
  13957. if not self.singleOperation:
  13958. return "JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));\n"
  13959. # This relies on getCallableDecl declaring a boolean
  13960. # isCallable in the case when we're a single-operation
  13961. # interface.
  13962. return dedent("""
  13963. JS::Rooted<JS::Value> thisValue(cx, isCallable ? aThisVal.get()
  13964. : JS::ObjectValue(*mCallback));
  13965. """)
  13966. def getThisVal(self):
  13967. return "thisValue"
  13968. def getCallableDecl(self):
  13969. getCallableFromProp = fill(
  13970. """
  13971. ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
  13972. if ((!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) ||
  13973. !GetCallableProperty(cx, atomsCache->${methodAtomName}, &callable)) {
  13974. aRv.Throw(NS_ERROR_UNEXPECTED);
  13975. return${errorReturn};
  13976. }
  13977. """,
  13978. methodAtomName=CGDictionary.makeIdName(self.methodName),
  13979. atomCacheName=self.descriptorProvider.interface.identifier.name + "Atoms",
  13980. errorReturn=self.getDefaultRetval())
  13981. if not self.singleOperation:
  13982. return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
  13983. return fill(
  13984. """
  13985. bool isCallable = JS::IsCallable(mCallback);
  13986. JS::Rooted<JS::Value> callable(cx);
  13987. if (isCallable) {
  13988. callable = JS::ObjectValue(*mCallback);
  13989. } else {
  13990. $*{getCallableFromProp}
  13991. }
  13992. """,
  13993. getCallableFromProp=getCallableFromProp)
  13994. def getCallGuard(self):
  13995. return ""
  13996. class CallbackOperation(CallbackOperationBase):
  13997. """
  13998. Codegen actual WebIDL operations on callback interfaces.
  13999. """
  14000. def __init__(self, method, signature, descriptor, typedArraysAreStructs):
  14001. self.ensureASCIIName(method)
  14002. self.method = method
  14003. jsName = method.identifier.name
  14004. CallbackOperationBase.__init__(self, signature,
  14005. jsName,
  14006. MakeNativeName(descriptor.binaryNameFor(jsName)),
  14007. descriptor, descriptor.interface.isSingleOperationInterface(),
  14008. rethrowContentException=descriptor.interface.isJSImplemented(),
  14009. typedArraysAreStructs=typedArraysAreStructs)
  14010. def getPrettyName(self):
  14011. return "%s.%s" % (self.descriptorProvider.interface.identifier.name,
  14012. self.method.identifier.name)
  14013. class CallbackAccessor(CallbackMember):
  14014. """
  14015. Shared superclass for CallbackGetter and CallbackSetter.
  14016. """
  14017. def __init__(self, attr, sig, name, descriptor, typedArraysAreStructs):
  14018. self.ensureASCIIName(attr)
  14019. self.attrName = attr.identifier.name
  14020. CallbackMember.__init__(self, sig, name, descriptor,
  14021. needThisHandling=False,
  14022. rethrowContentException=descriptor.interface.isJSImplemented(),
  14023. typedArraysAreStructs=typedArraysAreStructs)
  14024. def getPrettyName(self):
  14025. return "%s.%s" % (self.descriptorProvider.interface.identifier.name,
  14026. self.attrName)
  14027. class CallbackGetter(CallbackAccessor):
  14028. def __init__(self, attr, descriptor, typedArraysAreStructs):
  14029. CallbackAccessor.__init__(self, attr,
  14030. (attr.type, []),
  14031. callbackGetterName(attr, descriptor),
  14032. descriptor,
  14033. typedArraysAreStructs)
  14034. def getRvalDecl(self):
  14035. return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
  14036. def getCall(self):
  14037. return fill(
  14038. """
  14039. JS::Rooted<JSObject *> callback(cx, mCallback);
  14040. ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
  14041. if ((!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) ||
  14042. !JS_GetPropertyById(cx, callback, atomsCache->${attrAtomName}, &rval)) {
  14043. aRv.Throw(NS_ERROR_UNEXPECTED);
  14044. return${errorReturn};
  14045. }
  14046. """,
  14047. atomCacheName=self.descriptorProvider.interface.identifier.name + "Atoms",
  14048. attrAtomName=CGDictionary.makeIdName(self.descriptorProvider.binaryNameFor(self.attrName)),
  14049. errorReturn=self.getDefaultRetval())
  14050. class CallbackSetter(CallbackAccessor):
  14051. def __init__(self, attr, descriptor, typedArraysAreStructs):
  14052. CallbackAccessor.__init__(self, attr,
  14053. (BuiltinTypes[IDLBuiltinType.Types.void],
  14054. [FakeArgument(attr.type, attr)]),
  14055. callbackSetterName(attr, descriptor),
  14056. descriptor, typedArraysAreStructs)
  14057. def getRvalDecl(self):
  14058. # We don't need an rval
  14059. return ""
  14060. def getCall(self):
  14061. return fill(
  14062. """
  14063. MOZ_ASSERT(argv.length() == 1);
  14064. ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
  14065. if ((!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) ||
  14066. !JS_SetPropertyById(cx, CallbackKnownNotGray(), atomsCache->${attrAtomName}, argv[0])) {
  14067. aRv.Throw(NS_ERROR_UNEXPECTED);
  14068. return${errorReturn};
  14069. }
  14070. """,
  14071. atomCacheName=self.descriptorProvider.interface.identifier.name + "Atoms",
  14072. attrAtomName=CGDictionary.makeIdName(self.descriptorProvider.binaryNameFor(self.attrName)),
  14073. errorReturn=self.getDefaultRetval())
  14074. def getArgcDecl(self):
  14075. return None
  14076. class CGJSImplInitOperation(CallbackOperationBase):
  14077. """
  14078. Codegen the __Init() method used to pass along constructor arguments for JS-implemented WebIDL.
  14079. """
  14080. def __init__(self, sig, descriptor):
  14081. assert sig in descriptor.interface.ctor().signatures()
  14082. CallbackOperationBase.__init__(self, (BuiltinTypes[IDLBuiltinType.Types.void], sig[1]),
  14083. "__init", "__Init", descriptor,
  14084. singleOperation=False,
  14085. rethrowContentException=True,
  14086. typedArraysAreStructs=True)
  14087. def getPrettyName(self):
  14088. return "__init"
  14089. def getMaplikeOrSetlikeErrorReturn(helperImpl):
  14090. """
  14091. Generate return values based on whether a maplike or setlike generated
  14092. method is an interface method (which returns bool) or a helper function
  14093. (which uses ErrorResult).
  14094. """
  14095. if helperImpl:
  14096. return dedent(
  14097. """
  14098. aRv.Throw(NS_ERROR_UNEXPECTED);
  14099. return%s;
  14100. """ % helperImpl.getDefaultRetval())
  14101. return "return false;\n"
  14102. def getMaplikeOrSetlikeBackingObject(descriptor, maplikeOrSetlike, helperImpl=None):
  14103. """
  14104. Generate code to get/create a JS backing object for a maplike/setlike
  14105. declaration from the declaration slot.
  14106. """
  14107. func_prefix = maplikeOrSetlike.maplikeOrSetlikeOrIterableType.title()
  14108. ret = fill(
  14109. """
  14110. JS::Rooted<JSObject*> backingObj(cx);
  14111. bool created = false;
  14112. if (!Get${func_prefix}BackingObject(cx, obj, ${slot}, &backingObj, &created)) {
  14113. $*{errorReturn}
  14114. }
  14115. if (created) {
  14116. PreserveWrapper<${selfType}>(self);
  14117. }
  14118. """,
  14119. slot=memberReservedSlot(maplikeOrSetlike, descriptor),
  14120. func_prefix=func_prefix,
  14121. errorReturn=getMaplikeOrSetlikeErrorReturn(helperImpl),
  14122. selfType=descriptor.nativeType)
  14123. return ret
  14124. def getMaplikeOrSetlikeSizeGetterBody(descriptor, attr):
  14125. """
  14126. Creates the body for the size getter method of maplike/setlike interfaces.
  14127. """
  14128. # We should only have one declaration attribute currently
  14129. assert attr.identifier.name == "size"
  14130. assert attr.isMaplikeOrSetlikeAttr()
  14131. return fill(
  14132. """
  14133. $*{getBackingObj}
  14134. uint32_t result = JS::${funcPrefix}Size(cx, backingObj);
  14135. MOZ_ASSERT(!JS_IsExceptionPending(cx));
  14136. args.rval().setNumber(result);
  14137. return true;
  14138. """,
  14139. getBackingObj=getMaplikeOrSetlikeBackingObject(descriptor,
  14140. attr.maplikeOrSetlike),
  14141. funcPrefix=attr.maplikeOrSetlike.prefix)
  14142. class CGMaplikeOrSetlikeMethodGenerator(CGThing):
  14143. """
  14144. Creates methods for maplike/setlike interfaces. It is expected that all
  14145. methods will be have a maplike/setlike object attached. Unwrapping/wrapping
  14146. will be taken care of by the usual method generation machinery in
  14147. CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
  14148. using CGCallGenerator.
  14149. """
  14150. def __init__(self, descriptor, maplikeOrSetlike, methodName,
  14151. helperImpl=None):
  14152. CGThing.__init__(self)
  14153. # True if this will be the body of a C++ helper function.
  14154. self.helperImpl = helperImpl
  14155. self.descriptor = descriptor
  14156. self.maplikeOrSetlike = maplikeOrSetlike
  14157. self.cgRoot = CGList([])
  14158. impl_method_name = methodName
  14159. if impl_method_name[0] == "_":
  14160. # double underscore means this is a js-implemented chrome only rw
  14161. # function. Truncate the double underscore so calling the right
  14162. # underlying JSAPI function still works.
  14163. impl_method_name = impl_method_name[2:]
  14164. self.cgRoot.append(CGGeneric(
  14165. getMaplikeOrSetlikeBackingObject(self.descriptor,
  14166. self.maplikeOrSetlike,
  14167. self.helperImpl)))
  14168. self.returnStmt = getMaplikeOrSetlikeErrorReturn(self.helperImpl)
  14169. # Generates required code for the method. Method descriptions included
  14170. # in definitions below. Throw if we don't have a method to fill in what
  14171. # we're looking for.
  14172. try:
  14173. methodGenerator = getattr(self, impl_method_name)
  14174. except AttributeError:
  14175. raise TypeError("Missing %s method definition '%s'" %
  14176. (self.maplikeOrSetlike.maplikeOrSetlikeType,
  14177. methodName))
  14178. # Method generator returns tuple, containing:
  14179. #
  14180. # - a list of CGThings representing setup code for preparing to call
  14181. # the JS API function
  14182. # - a list of arguments needed for the JS API function we're calling
  14183. # - list of code CGThings needed for return value conversion.
  14184. (setupCode, arguments, setResult) = methodGenerator()
  14185. # Create the actual method call, and then wrap it with the code to
  14186. # return the value if needed.
  14187. funcName = (self.maplikeOrSetlike.prefix +
  14188. MakeNativeName(impl_method_name))
  14189. # Append the list of setup code CGThings
  14190. self.cgRoot.append(CGList(setupCode))
  14191. # Create the JS API call
  14192. self.cgRoot.append(CGWrapper(
  14193. CGGeneric(fill(
  14194. """
  14195. if (!JS::${funcName}(${args})) {
  14196. $*{errorReturn}
  14197. }
  14198. """,
  14199. funcName=funcName,
  14200. args=", ".join(["cx", "backingObj"] + arguments),
  14201. errorReturn=self.returnStmt))))
  14202. # Append result conversion
  14203. self.cgRoot.append(CGList(setResult))
  14204. def mergeTuples(self, a, b):
  14205. """
  14206. Expecting to take 2 tuples were all elements are lists, append the lists in
  14207. the second tuple to the lists in the first.
  14208. """
  14209. return tuple([x + y for x, y in zip(a, b)])
  14210. def appendArgConversion(self, name):
  14211. """
  14212. Generate code to convert arguments to JS::Values, so they can be
  14213. passed into JSAPI functions.
  14214. """
  14215. return CGGeneric(fill(
  14216. """
  14217. JS::Rooted<JS::Value> ${name}Val(cx);
  14218. if (!ToJSValue(cx, ${name}, &${name}Val)) {
  14219. $*{errorReturn}
  14220. }
  14221. """,
  14222. name=name,
  14223. errorReturn=self.returnStmt))
  14224. def appendKeyArgConversion(self):
  14225. """
  14226. Generates the key argument for methods. Helper functions will use
  14227. an AutoValueVector, while interface methods have seperate JS::Values.
  14228. """
  14229. if self.helperImpl:
  14230. return ([], ["argv[0]"], [])
  14231. return ([self.appendArgConversion("arg0")], ["arg0Val"], [])
  14232. def appendKeyAndValueArgConversion(self):
  14233. """
  14234. Generates arguments for methods that require a key and value. Helper
  14235. functions will use an AutoValueVector, while interface methods have
  14236. seperate JS::Values.
  14237. """
  14238. r = self.appendKeyArgConversion()
  14239. if self.helperImpl:
  14240. return self.mergeTuples(r, ([], ["argv[1]"], []))
  14241. return self.mergeTuples(r, ([self.appendArgConversion("arg1")],
  14242. ["arg1Val"],
  14243. []))
  14244. def appendIteratorResult(self):
  14245. """
  14246. Generate code to output JSObject* return values, needed for functions that
  14247. return iterators. Iterators cannot currently be wrapped via Xrays. If
  14248. something that would return an iterator is called via Xray, fail early.
  14249. """
  14250. # TODO: Bug 1173651 - Remove check once bug 1023984 is fixed.
  14251. code = CGGeneric(dedent(
  14252. """
  14253. // TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change
  14254. // after bug 1023984 is fixed.
  14255. if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
  14256. JS_ReportErrorASCII(cx, "Xray wrapping of iterators not supported.");
  14257. return false;
  14258. }
  14259. JS::Rooted<JSObject*> result(cx);
  14260. JS::Rooted<JS::Value> v(cx);
  14261. """))
  14262. arguments = "&v"
  14263. setResult = CGGeneric(dedent(
  14264. """
  14265. result = &v.toObject();
  14266. """))
  14267. return ([code], [arguments], [setResult])
  14268. def appendSelfResult(self):
  14269. """
  14270. Generate code to return the interface object itself.
  14271. """
  14272. code = CGGeneric(dedent(
  14273. """
  14274. JS::Rooted<JSObject*> result(cx);
  14275. """))
  14276. setResult = CGGeneric(dedent(
  14277. """
  14278. result = obj;
  14279. """))
  14280. return ([code], [], [setResult])
  14281. def appendBoolResult(self):
  14282. if self.helperImpl:
  14283. return ([CGGeneric()], ["&aRetVal"], [])
  14284. return ([CGGeneric("bool result;\n")], ["&result"], [])
  14285. def forEach(self):
  14286. """
  14287. void forEach(callback c, any thisval);
  14288. ForEach takes a callback, and a possible value to use as 'this'. The
  14289. callback needs to take value, key, and the interface object
  14290. implementing maplike/setlike. In order to make sure that the third arg
  14291. is our interface object instead of the map/set backing object, we
  14292. create a js function with the callback and original object in its
  14293. storage slots, then use a helper function in BindingUtils to make sure
  14294. the callback is called correctly.
  14295. """
  14296. assert(not self.helperImpl)
  14297. code = [CGGeneric(dedent(
  14298. """
  14299. // Create a wrapper function.
  14300. JSFunction* func = js::NewFunctionWithReserved(cx, ForEachHandler, 3, 0, nullptr);
  14301. if (!func) {
  14302. return false;
  14303. }
  14304. JS::Rooted<JSObject*> funcObj(cx, JS_GetFunctionObject(func));
  14305. JS::Rooted<JS::Value> funcVal(cx, JS::ObjectValue(*funcObj));
  14306. js::SetFunctionNativeReserved(funcObj, FOREACH_CALLBACK_SLOT,
  14307. JS::ObjectValue(*arg0));
  14308. js::SetFunctionNativeReserved(funcObj, FOREACH_MAPLIKEORSETLIKEOBJ_SLOT,
  14309. JS::ObjectValue(*obj));
  14310. """))]
  14311. arguments = ["funcVal", "arg1"]
  14312. return (code, arguments, [])
  14313. def set(self):
  14314. """
  14315. object set(key, value);
  14316. Maplike only function, takes key and sets value to it, returns
  14317. interface object unless being called from a C++ helper.
  14318. """
  14319. assert self.maplikeOrSetlike.isMaplike()
  14320. r = self.appendKeyAndValueArgConversion()
  14321. if self.helperImpl:
  14322. return r
  14323. return self.mergeTuples(r, self.appendSelfResult())
  14324. def add(self):
  14325. """
  14326. object add(value);
  14327. Setlike only function, adds value to set, returns interface object
  14328. unless being called from a C++ helper
  14329. """
  14330. assert self.maplikeOrSetlike.isSetlike()
  14331. r = self.appendKeyArgConversion()
  14332. if self.helperImpl:
  14333. return r
  14334. return self.mergeTuples(r, self.appendSelfResult())
  14335. def get(self):
  14336. """
  14337. type? get(key);
  14338. Retrieves a value from a backing object based on the key. Returns value
  14339. if key is in backing object, undefined otherwise.
  14340. """
  14341. assert self.maplikeOrSetlike.isMaplike()
  14342. r = self.appendKeyArgConversion()
  14343. code = [CGGeneric(dedent(
  14344. """
  14345. JS::Rooted<JS::Value> result(cx);
  14346. """))]
  14347. arguments = ["&result"]
  14348. return self.mergeTuples(r, (code, arguments, []))
  14349. def has(self):
  14350. """
  14351. bool has(key);
  14352. Check if an entry exists in the backing object. Returns true if value
  14353. exists in backing object, false otherwise.
  14354. """
  14355. return self.mergeTuples(self.appendKeyArgConversion(),
  14356. self.appendBoolResult())
  14357. def keys(self):
  14358. """
  14359. object keys();
  14360. Returns new object iterator with all keys from backing object.
  14361. """
  14362. return self.appendIteratorResult()
  14363. def values(self):
  14364. """
  14365. object values();
  14366. Returns new object iterator with all values from backing object.
  14367. """
  14368. return self.appendIteratorResult()
  14369. def entries(self):
  14370. """
  14371. object entries();
  14372. Returns new object iterator with all keys and values from backing
  14373. object. Keys will be null for set.
  14374. """
  14375. return self.appendIteratorResult()
  14376. def clear(self):
  14377. """
  14378. void clear();
  14379. Removes all entries from map/set.
  14380. """
  14381. return ([], [], [])
  14382. def delete(self):
  14383. """
  14384. bool delete(key);
  14385. Deletes an entry from the backing object. Returns true if value existed
  14386. in backing object, false otherwise.
  14387. """
  14388. return self.mergeTuples(self.appendKeyArgConversion(),
  14389. self.appendBoolResult())
  14390. def define(self):
  14391. return self.cgRoot.define()
  14392. class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember):
  14393. """
  14394. Generates code to allow C++ to perform operations on backing objects. Gets
  14395. a context from the binding wrapper, turns arguments into JS::Values (via
  14396. CallbackMember/CGNativeMember argument conversion), then uses
  14397. CGMaplikeOrSetlikeMethodGenerator to generate the body.
  14398. """
  14399. class HelperFunction(CGAbstractMethod):
  14400. """
  14401. Generates context retrieval code and rooted JSObject for interface for
  14402. CGMaplikeOrSetlikeMethodGenerator to use
  14403. """
  14404. def __init__(self, descriptor, name, args, code, needsBoolReturn=False):
  14405. self.code = code
  14406. CGAbstractMethod.__init__(self, descriptor, name,
  14407. "bool" if needsBoolReturn else "void",
  14408. args)
  14409. def definition_body(self):
  14410. return self.code
  14411. def __init__(self, descriptor, maplikeOrSetlike, name, needsKeyArg=False,
  14412. needsValueArg=False, needsBoolReturn=False):
  14413. args = []
  14414. self.maplikeOrSetlike = maplikeOrSetlike
  14415. self.needsBoolReturn = needsBoolReturn
  14416. if needsKeyArg:
  14417. args.append(FakeArgument(maplikeOrSetlike.keyType, None, 'aKey'))
  14418. if needsValueArg:
  14419. assert needsKeyArg
  14420. args.append(FakeArgument(maplikeOrSetlike.valueType, None, 'aValue'))
  14421. # Run CallbackMember init function to generate argument conversion code.
  14422. # wrapScope is set to 'obj' when generating maplike or setlike helper
  14423. # functions, as we don't have access to the CallbackPreserveColor
  14424. # method.
  14425. CallbackMember.__init__(self,
  14426. [BuiltinTypes[IDLBuiltinType.Types.void], args],
  14427. name, descriptor, False,
  14428. wrapScope='obj')
  14429. # Wrap CallbackMember body code into a CGAbstractMethod to make
  14430. # generation easier.
  14431. self.implMethod = CGMaplikeOrSetlikeHelperFunctionGenerator.HelperFunction(
  14432. descriptor, name, self.args, self.body, needsBoolReturn)
  14433. def getCallSetup(self):
  14434. return dedent(
  14435. """
  14436. MOZ_ASSERT(self);
  14437. AutoJSAPI jsapi;
  14438. jsapi.Init();
  14439. JSContext* cx = jsapi.cx();
  14440. // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because
  14441. // all we want is to wrap into _some_ scope and then unwrap to find
  14442. // the reflector, and wrapping has no side-effects.
  14443. JSAutoCompartment tempCompartment(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
  14444. JS::Rooted<JS::Value> v(cx);
  14445. if(!ToJSValue(cx, self, &v)) {
  14446. aRv.Throw(NS_ERROR_UNEXPECTED);
  14447. return%s;
  14448. }
  14449. // This is a reflector, but due to trying to name things
  14450. // similarly across method generators, it's called obj here.
  14451. JS::Rooted<JSObject*> obj(cx);
  14452. obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false);
  14453. JSAutoCompartment reflectorCompartment(cx, obj);
  14454. """ % self.getDefaultRetval())
  14455. def getArgs(self, returnType, argList):
  14456. # We don't need the context or the value. We'll generate those instead.
  14457. args = CGNativeMember.getArgs(self, returnType, argList)
  14458. # Prepend a pointer to the binding object onto the arguments
  14459. return [Argument(self.descriptorProvider.nativeType + "*", "self")] + args
  14460. def getResultConversion(self):
  14461. if self.needsBoolReturn:
  14462. return "return aRetVal;\n"
  14463. return "return;\n"
  14464. def getRvalDecl(self):
  14465. if self.needsBoolReturn:
  14466. return "bool aRetVal;\n"
  14467. return ""
  14468. def getArgcDecl(self):
  14469. # Don't need argc for anything.
  14470. return None
  14471. def getDefaultRetval(self):
  14472. if self.needsBoolReturn:
  14473. return " false"
  14474. return ""
  14475. def getCall(self):
  14476. return CGMaplikeOrSetlikeMethodGenerator(self.descriptorProvider,
  14477. self.maplikeOrSetlike,
  14478. self.name.lower(),
  14479. helperImpl=self).define()
  14480. def getPrettyName(self):
  14481. return self.name
  14482. def declare(self):
  14483. return self.implMethod.declare()
  14484. def define(self):
  14485. return self.implMethod.define()
  14486. class CGMaplikeOrSetlikeHelperGenerator(CGNamespace):
  14487. """
  14488. Declares and defines convenience methods for accessing backing objects on
  14489. setlike/maplike interface. Generates function signatures, un/packs
  14490. backing objects from slot, etc.
  14491. """
  14492. def __init__(self, descriptor, maplikeOrSetlike):
  14493. self.descriptor = descriptor
  14494. # Since iterables are folded in with maplike/setlike, make sure we've
  14495. # got the right type here.
  14496. assert maplikeOrSetlike.isMaplike() or maplikeOrSetlike.isSetlike()
  14497. self.maplikeOrSetlike = maplikeOrSetlike
  14498. self.namespace = "%sHelpers" % (self.maplikeOrSetlike.maplikeOrSetlikeOrIterableType.title())
  14499. self.helpers = [
  14500. CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
  14501. maplikeOrSetlike,
  14502. "Clear"),
  14503. CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
  14504. maplikeOrSetlike,
  14505. "Delete",
  14506. needsKeyArg=True,
  14507. needsBoolReturn=True),
  14508. CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
  14509. maplikeOrSetlike,
  14510. "Has",
  14511. needsKeyArg=True,
  14512. needsBoolReturn=True)]
  14513. if self.maplikeOrSetlike.isMaplike():
  14514. self.helpers.append(
  14515. CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
  14516. maplikeOrSetlike,
  14517. "Set",
  14518. needsKeyArg=True,
  14519. needsValueArg=True))
  14520. else:
  14521. assert(self.maplikeOrSetlike.isSetlike())
  14522. self.helpers.append(
  14523. CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
  14524. maplikeOrSetlike,
  14525. "Add",
  14526. needsKeyArg=True))
  14527. CGNamespace.__init__(self, self.namespace, CGList(self.helpers))
  14528. class CGIterableMethodGenerator(CGGeneric):
  14529. """
  14530. Creates methods for iterable interfaces. Unwrapping/wrapping
  14531. will be taken care of by the usual method generation machinery in
  14532. CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
  14533. using CGCallGenerator.
  14534. """
  14535. def __init__(self, descriptor, iterable, methodName):
  14536. if methodName == "forEach":
  14537. CGGeneric.__init__(self, fill(
  14538. """
  14539. if (!JS::IsCallable(arg0)) {
  14540. ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "Argument 1 of ${ifaceName}.forEach");
  14541. return false;
  14542. }
  14543. JS::AutoValueArray<3> callArgs(cx);
  14544. callArgs[2].setObject(*obj);
  14545. JS::Rooted<JS::Value> ignoredReturnVal(cx);
  14546. for (size_t i = 0; i < self->GetIterableLength(); ++i) {
  14547. if (!ToJSValue(cx, self->GetValueAtIndex(i), callArgs[0])) {
  14548. return false;
  14549. }
  14550. if (!ToJSValue(cx, self->GetKeyAtIndex(i), callArgs[1])) {
  14551. return false;
  14552. }
  14553. if (!JS::Call(cx, arg1, arg0, JS::HandleValueArray(callArgs),
  14554. &ignoredReturnVal)) {
  14555. return false;
  14556. }
  14557. }
  14558. """,
  14559. ifaceName=descriptor.interface.identifier.name))
  14560. return
  14561. CGGeneric.__init__(self, fill(
  14562. """
  14563. typedef ${iterClass} itrType;
  14564. RefPtr<itrType> result(new itrType(self,
  14565. itrType::IterableIteratorType::${itrMethod},
  14566. &${ifaceName}IteratorBinding::Wrap));
  14567. """,
  14568. iterClass=iteratorNativeType(descriptor),
  14569. ifaceName=descriptor.interface.identifier.name,
  14570. itrMethod=methodName.title()))
  14571. class GlobalGenRoots():
  14572. """
  14573. Roots for global codegen.
  14574. To generate code, call the method associated with the target, and then
  14575. call the appropriate define/declare method.
  14576. """
  14577. @staticmethod
  14578. def GeneratedAtomList(config):
  14579. # Atom enum
  14580. dictionaries = config.dictionaries
  14581. structs = []
  14582. def memberToAtomCacheMember(binaryNameFor, m):
  14583. binaryMemberName = binaryNameFor(m.identifier.name)
  14584. return ClassMember(CGDictionary.makeIdName(binaryMemberName),
  14585. "PinnedStringId", visibility="public")
  14586. def buildAtomCacheStructure(idlobj, binaryNameFor, members):
  14587. classMembers = [memberToAtomCacheMember(binaryNameFor, m)
  14588. for m in members]
  14589. structName = idlobj.identifier.name + "Atoms"
  14590. return (structName,
  14591. CGWrapper(CGClass(structName,
  14592. bases=None,
  14593. isStruct=True,
  14594. members=classMembers), post='\n'))
  14595. for dict in dictionaries:
  14596. if len(dict.members) == 0:
  14597. continue
  14598. structs.append(buildAtomCacheStructure(dict, lambda x: x, dict.members))
  14599. for d in (config.getDescriptors(isJSImplemented=True) +
  14600. config.getDescriptors(isCallback=True)):
  14601. members = [m for m in d.interface.members if m.isAttr() or m.isMethod()]
  14602. if d.interface.isJSImplemented() and d.interface.ctor():
  14603. # We'll have an __init() method.
  14604. members.append(FakeMember('__init'))
  14605. if len(members) == 0:
  14606. continue
  14607. structs.append(buildAtomCacheStructure(d.interface,
  14608. lambda x: d.binaryNameFor(x),
  14609. members))
  14610. structs.sort()
  14611. generatedStructs = [struct for structName, struct in structs]
  14612. structNames = [structName for structName, struct in structs]
  14613. mainStruct = CGWrapper(CGClass("PerThreadAtomCache",
  14614. bases=[ClassBase(structName) for structName in structNames],
  14615. isStruct=True),
  14616. post='\n')
  14617. structs = CGList(generatedStructs + [mainStruct])
  14618. # Wrap all of that in our namespaces.
  14619. curr = CGNamespace.build(['mozilla', 'dom'],
  14620. CGWrapper(structs, pre='\n'))
  14621. curr = CGWrapper(curr, post='\n')
  14622. # Add include statement for PinnedStringId.
  14623. declareIncludes = ['mozilla/dom/BindingUtils.h']
  14624. curr = CGHeaders([], [], [], [], declareIncludes, [], 'GeneratedAtomList',
  14625. curr)
  14626. # Add include guards.
  14627. curr = CGIncludeGuard('GeneratedAtomList', curr)
  14628. # Add the auto-generated comment.
  14629. curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
  14630. # Done.
  14631. return curr
  14632. @staticmethod
  14633. def GeneratedEventList(config):
  14634. eventList = CGList([])
  14635. for generatedEvent in config.generatedEvents:
  14636. eventList.append(CGGeneric(declare=("GENERATED_EVENT(%s)\n" % generatedEvent)))
  14637. return eventList
  14638. @staticmethod
  14639. def PrototypeList(config):
  14640. # Prototype ID enum.
  14641. descriptorsWithPrototype = config.getDescriptors(hasInterfacePrototypeObject=True)
  14642. protos = [d.name for d in descriptorsWithPrototype]
  14643. idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + protos,
  14644. [0, '_ID_Start'])
  14645. idEnum = CGList([idEnum])
  14646. def fieldSizeAssert(amount, jitInfoField, message):
  14647. maxFieldValue = "(uint64_t(1) << (sizeof(((JSJitInfo*)nullptr)->%s) * 8))" % jitInfoField
  14648. return CGGeneric(declare="static_assert(%s < %s, \"%s\");\n\n"
  14649. % (amount, maxFieldValue, message))
  14650. idEnum.append(fieldSizeAssert("id::_ID_Count", "protoID",
  14651. "Too many prototypes!"))
  14652. # Wrap all of that in our namespaces.
  14653. idEnum = CGNamespace.build(['mozilla', 'dom', 'prototypes'],
  14654. CGWrapper(idEnum, pre='\n'))
  14655. idEnum = CGWrapper(idEnum, post='\n')
  14656. curr = CGList([CGGeneric(define="#include <stdint.h>\n\n"),
  14657. idEnum])
  14658. # Let things know the maximum length of the prototype chain.
  14659. maxMacroName = "MAX_PROTOTYPE_CHAIN_LENGTH"
  14660. maxMacro = CGGeneric(declare="#define " + maxMacroName + " " + str(config.maxProtoChainLength))
  14661. curr.append(CGWrapper(maxMacro, post='\n\n'))
  14662. curr.append(fieldSizeAssert(maxMacroName, "depth",
  14663. "Some inheritance chain is too long!"))
  14664. # Constructor ID enum.
  14665. constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True)]
  14666. idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + constructors,
  14667. ['prototypes::id::_ID_Count', '_ID_Start'])
  14668. # Wrap all of that in our namespaces.
  14669. idEnum = CGNamespace.build(['mozilla', 'dom', 'constructors'],
  14670. CGWrapper(idEnum, pre='\n'))
  14671. idEnum = CGWrapper(idEnum, post='\n')
  14672. curr.append(idEnum)
  14673. # Named properties object enum.
  14674. namedPropertiesObjects = [d.name for d in config.getDescriptors(hasNamedPropertiesObject=True)]
  14675. idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + namedPropertiesObjects,
  14676. ['constructors::id::_ID_Count', '_ID_Start'])
  14677. # Wrap all of that in our namespaces.
  14678. idEnum = CGNamespace.build(['mozilla', 'dom', 'namedpropertiesobjects'],
  14679. CGWrapper(idEnum, pre='\n'))
  14680. idEnum = CGWrapper(idEnum, post='\n')
  14681. curr.append(idEnum)
  14682. traitsDecls = [CGGeneric(declare=dedent("""
  14683. template <prototypes::ID PrototypeID>
  14684. struct PrototypeTraits;
  14685. """))]
  14686. traitsDecls.extend(CGPrototypeTraitsClass(d) for d in descriptorsWithPrototype)
  14687. ifaceNamesWithProto = [d.interface.identifier.name
  14688. for d in descriptorsWithPrototype]
  14689. traitsDecls.append(CGStringTable("NamesOfInterfacesWithProtos",
  14690. ifaceNamesWithProto))
  14691. traitsDecl = CGNamespace.build(['mozilla', 'dom'],
  14692. CGList(traitsDecls))
  14693. curr.append(traitsDecl)
  14694. # Add include guards.
  14695. curr = CGIncludeGuard('PrototypeList', curr)
  14696. # Add the auto-generated comment.
  14697. curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
  14698. # Done.
  14699. return curr
  14700. @staticmethod
  14701. def RegisterBindings(config):
  14702. curr = CGList([CGGlobalNamesString(config), CGRegisterGlobalNames(config)])
  14703. # Wrap all of that in our namespaces.
  14704. curr = CGNamespace.build(['mozilla', 'dom'],
  14705. CGWrapper(curr, post='\n'))
  14706. curr = CGWrapper(curr, post='\n')
  14707. # Add the includes
  14708. defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
  14709. for desc in config.getDescriptors(hasInterfaceObject=True,
  14710. isExposedInWindow=True,
  14711. register=True)]
  14712. defineIncludes.append('mozilla/dom/WebIDLGlobalNameHash.h')
  14713. defineIncludes.extend([CGHeaders.getDeclarationFilename(desc.interface)
  14714. for desc in config.getDescriptors(isNavigatorProperty=True,
  14715. register=True)])
  14716. curr = CGHeaders([], [], [], [], [], defineIncludes, 'RegisterBindings',
  14717. curr)
  14718. # Add include guards.
  14719. curr = CGIncludeGuard('RegisterBindings', curr)
  14720. # Done.
  14721. return curr
  14722. @staticmethod
  14723. def RegisterWorkerBindings(config):
  14724. curr = CGRegisterWorkerBindings(config)
  14725. # Wrap all of that in our namespaces.
  14726. curr = CGNamespace.build(['mozilla', 'dom'],
  14727. CGWrapper(curr, post='\n'))
  14728. curr = CGWrapper(curr, post='\n')
  14729. # Add the includes
  14730. defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
  14731. for desc in config.getDescriptors(hasInterfaceObject=True,
  14732. register=True,
  14733. isExposedInAnyWorker=True)]
  14734. curr = CGHeaders([], [], [], [], [], defineIncludes,
  14735. 'RegisterWorkerBindings', curr)
  14736. # Add include guards.
  14737. curr = CGIncludeGuard('RegisterWorkerBindings', curr)
  14738. # Done.
  14739. return curr
  14740. @staticmethod
  14741. def RegisterWorkerDebuggerBindings(config):
  14742. curr = CGRegisterWorkerDebuggerBindings(config)
  14743. # Wrap all of that in our namespaces.
  14744. curr = CGNamespace.build(['mozilla', 'dom'],
  14745. CGWrapper(curr, post='\n'))
  14746. curr = CGWrapper(curr, post='\n')
  14747. # Add the includes
  14748. defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
  14749. for desc in config.getDescriptors(hasInterfaceObject=True,
  14750. register=True,
  14751. isExposedInWorkerDebugger=True)]
  14752. curr = CGHeaders([], [], [], [], [], defineIncludes,
  14753. 'RegisterWorkerDebuggerBindings', curr)
  14754. # Add include guards.
  14755. curr = CGIncludeGuard('RegisterWorkerDebuggerBindings', curr)
  14756. # Done.
  14757. return curr
  14758. @staticmethod
  14759. def RegisterWorkletBindings(config):
  14760. curr = CGRegisterWorkletBindings(config)
  14761. # Wrap all of that in our namespaces.
  14762. curr = CGNamespace.build(['mozilla', 'dom'],
  14763. CGWrapper(curr, post='\n'))
  14764. curr = CGWrapper(curr, post='\n')
  14765. # Add the includes
  14766. defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
  14767. for desc in config.getDescriptors(hasInterfaceObject=True,
  14768. register=True,
  14769. isExposedInAnyWorklet=True)]
  14770. curr = CGHeaders([], [], [], [], [], defineIncludes,
  14771. 'RegisterWorkletBindings', curr)
  14772. # Add include guards.
  14773. curr = CGIncludeGuard('RegisterWorkletBindings', curr)
  14774. # Done.
  14775. return curr
  14776. @staticmethod
  14777. def ResolveSystemBinding(config):
  14778. curr = CGResolveSystemBinding(config)
  14779. # Wrap all of that in our namespaces.
  14780. curr = CGNamespace.build(['mozilla', 'dom'],
  14781. CGWrapper(curr, post='\n'))
  14782. curr = CGWrapper(curr, post='\n')
  14783. # Add the includes
  14784. defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
  14785. for desc in config.getDescriptors(hasInterfaceObject=True,
  14786. register=True,
  14787. isExposedInSystemGlobals=True)]
  14788. defineIncludes.append("nsThreadUtils.h") # For NS_IsMainThread
  14789. defineIncludes.append("js/Id.h") # For jsid
  14790. defineIncludes.append("mozilla/dom/BindingUtils.h") # AtomizeAndPinJSString
  14791. curr = CGHeaders([], [], [], [], [], defineIncludes,
  14792. 'ResolveSystemBinding', curr)
  14793. # Add include guards.
  14794. curr = CGIncludeGuard('ResolveSystemBinding', curr)
  14795. # Done.
  14796. return curr
  14797. @staticmethod
  14798. def UnionTypes(config):
  14799. unionTypes = UnionsForFile(config, None)
  14800. (includes, implincludes, declarations,
  14801. traverseMethods, unlinkMethods,
  14802. unionStructs) = UnionTypes(unionTypes, config)
  14803. unions = CGList(traverseMethods +
  14804. unlinkMethods +
  14805. [CGUnionStruct(t, config) for t in unionStructs] +
  14806. [CGUnionStruct(t, config, True) for t in unionStructs],
  14807. "\n")
  14808. includes.add("mozilla/OwningNonNull.h")
  14809. includes.add("mozilla/dom/UnionMember.h")
  14810. includes.add("mozilla/dom/BindingDeclarations.h")
  14811. # BindingUtils.h is only needed for SetToObject.
  14812. # If it stops being inlined or stops calling CallerSubsumes
  14813. # both this bit and the bit in CGBindingRoot can be removed.
  14814. includes.add("mozilla/dom/BindingUtils.h")
  14815. implincludes.add("mozilla/dom/PrimitiveConversions.h")
  14816. # Wrap all of that in our namespaces.
  14817. curr = CGNamespace.build(['mozilla', 'dom'], unions)
  14818. curr = CGWrapper(curr, post='\n')
  14819. builder = ForwardDeclarationBuilder()
  14820. for className, isStruct in declarations:
  14821. builder.add(className, isStruct=isStruct)
  14822. curr = CGList([builder.build(), curr], "\n")
  14823. curr = CGHeaders([], [], [], [], includes, implincludes, 'UnionTypes',
  14824. curr)
  14825. # Add include guards.
  14826. curr = CGIncludeGuard('UnionTypes', curr)
  14827. # Done.
  14828. return curr
  14829. @staticmethod
  14830. def UnionConversions(config):
  14831. unionTypes = []
  14832. for l in config.unionsPerFilename.itervalues():
  14833. unionTypes.extend(l)
  14834. unionTypes.sort(key=lambda u: u.name)
  14835. headers, unions = UnionConversions(unionTypes,
  14836. config)
  14837. # Wrap all of that in our namespaces.
  14838. curr = CGNamespace.build(['mozilla', 'dom'], unions)
  14839. curr = CGWrapper(curr, post='\n')
  14840. headers.update(["nsDebug.h", "mozilla/dom/UnionTypes.h"])
  14841. curr = CGHeaders([], [], [], [], headers, [], 'UnionConversions', curr)
  14842. # Add include guards.
  14843. curr = CGIncludeGuard('UnionConversions', curr)
  14844. # Done.
  14845. return curr
  14846. # Code generator for simple events
  14847. class CGEventGetter(CGNativeMember):
  14848. def __init__(self, descriptor, attr):
  14849. ea = descriptor.getExtendedAttributes(attr, getter=True)
  14850. CGNativeMember.__init__(self, descriptor, attr,
  14851. CGSpecializedGetter.makeNativeName(descriptor,
  14852. attr),
  14853. (attr.type, []),
  14854. ea,
  14855. resultNotAddRefed=not attr.type.isSequence())
  14856. self.body = self.getMethodBody()
  14857. def getArgs(self, returnType, argList):
  14858. if 'infallible' not in self.extendedAttrs:
  14859. raise TypeError("Event code generator does not support [Throws]!")
  14860. if not self.member.isAttr():
  14861. raise TypeError("Event code generator does not support methods")
  14862. if self.member.isStatic():
  14863. raise TypeError("Event code generators does not support static attributes")
  14864. return CGNativeMember.getArgs(self, returnType, argList)
  14865. def getMethodBody(self):
  14866. type = self.member.type
  14867. memberName = CGDictionary.makeMemberName(self.member.identifier.name)
  14868. if ((type.isPrimitive() and type.tag() in builtinNames) or
  14869. type.isEnum() or
  14870. type.isPromise() or
  14871. type.isGeckoInterface()):
  14872. return "return " + memberName + ";\n"
  14873. if type.isDOMString() or type.isByteString() or type.isUSVString():
  14874. return "aRetVal = " + memberName + ";\n"
  14875. if type.isSpiderMonkeyInterface() or type.isObject():
  14876. return fill(
  14877. """
  14878. if (${memberName}) {
  14879. JS::ExposeObjectToActiveJS(${memberName});
  14880. }
  14881. aRetVal.set(${memberName});
  14882. return;
  14883. """,
  14884. memberName=memberName)
  14885. if type.isAny():
  14886. return fill(
  14887. """
  14888. ${selfName}(aRetVal);
  14889. """,
  14890. selfName=self.name)
  14891. if type.isUnion():
  14892. return "aRetVal = " + memberName + ";\n"
  14893. if type.isSequence():
  14894. return "aRetVal = " + memberName + ";\n"
  14895. raise TypeError("Event code generator does not support this type!")
  14896. def declare(self, cgClass):
  14897. if getattr(self.member, "originatingInterface",
  14898. cgClass.descriptor.interface) != cgClass.descriptor.interface:
  14899. return ""
  14900. return CGNativeMember.declare(self, cgClass)
  14901. def define(self, cgClass):
  14902. if getattr(self.member, "originatingInterface",
  14903. cgClass.descriptor.interface) != cgClass.descriptor.interface:
  14904. return ""
  14905. return CGNativeMember.define(self, cgClass)
  14906. class CGEventSetter(CGNativeMember):
  14907. def __init__(self):
  14908. raise TypeError("Event code generator does not support setters!")
  14909. class CGEventMethod(CGNativeMember):
  14910. def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
  14911. self.isInit = False
  14912. CGNativeMember.__init__(self, descriptor, method,
  14913. CGSpecializedMethod.makeNativeName(descriptor,
  14914. method),
  14915. signature,
  14916. descriptor.getExtendedAttributes(method),
  14917. breakAfter=breakAfter,
  14918. variadicIsSequence=True)
  14919. self.originalArgs = list(self.args)
  14920. iface = descriptor.interface
  14921. allowed = isConstructor
  14922. if not allowed and iface.getExtendedAttribute("LegacyEventInit"):
  14923. # Allow it, only if it fits the initFooEvent profile exactly
  14924. # We could check the arg types but it's not worth the effort.
  14925. if (method.identifier.name == "init" + iface.identifier.name and
  14926. signature[1][0].type.isDOMString() and
  14927. signature[1][1].type.isBoolean() and
  14928. signature[1][2].type.isBoolean() and
  14929. # -3 on the left to ignore the type, bubbles, and cancelable parameters
  14930. # -1 on the right to ignore the .trusted property which bleeds through
  14931. # here because it is [Unforgeable].
  14932. len(signature[1]) - 3 == len(filter(lambda x: x.isAttr(), iface.members)) - 1):
  14933. allowed = True
  14934. self.isInit = True
  14935. if not allowed:
  14936. raise TypeError("Event code generator does not support methods!")
  14937. def getArgs(self, returnType, argList):
  14938. args = [self.getArg(arg) for arg in argList]
  14939. return args
  14940. def getArg(self, arg):
  14941. decl, ref = self.getArgType(arg.type,
  14942. arg.canHaveMissingValue(),
  14943. "Variadic" if arg.variadic else False)
  14944. if ref:
  14945. decl = CGWrapper(decl, pre="const ", post="&")
  14946. name = arg.identifier.name
  14947. name = "a" + name[0].upper() + name[1:]
  14948. return Argument(decl.define(), name)
  14949. def declare(self, cgClass):
  14950. if self.isInit:
  14951. constructorForNativeCaller = ""
  14952. else:
  14953. self.args = list(self.originalArgs)
  14954. self.args.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
  14955. constructorForNativeCaller = CGNativeMember.declare(self, cgClass)
  14956. self.args = list(self.originalArgs)
  14957. if needCx(None, self.arguments(), [], considerTypes=True, static=True):
  14958. self.args.insert(0, Argument("JSContext*", "aCx"))
  14959. if not self.isInit:
  14960. self.args.insert(0, Argument("const GlobalObject&", "aGlobal"))
  14961. self.args.append(Argument('ErrorResult&', 'aRv'))
  14962. return constructorForNativeCaller + CGNativeMember.declare(self, cgClass)
  14963. def defineInit(self, cgClass):
  14964. iface = self.descriptorProvider.interface
  14965. members = ""
  14966. while iface.identifier.name != "Event":
  14967. i = 3 # Skip the boilerplate args: type, bubble,s cancelable.
  14968. for m in iface.members:
  14969. if m.isAttr():
  14970. # We need to initialize all the member variables that do
  14971. # not come from Event.
  14972. if getattr(m, "originatingInterface",
  14973. iface).identifier.name == "Event":
  14974. continue
  14975. name = CGDictionary.makeMemberName(m.identifier.name)
  14976. members += "%s = %s;\n" % (name, self.args[i].name)
  14977. i += 1
  14978. iface = iface.parent
  14979. self.body = fill(
  14980. """
  14981. InitEvent(${typeArg}, ${bubblesArg}, ${cancelableArg});
  14982. ${members}
  14983. """,
  14984. typeArg=self.args[0].name,
  14985. bubblesArg=self.args[1].name,
  14986. cancelableArg=self.args[2].name,
  14987. members=members)
  14988. return CGNativeMember.define(self, cgClass)
  14989. def define(self, cgClass):
  14990. self.args = list(self.originalArgs)
  14991. if self.isInit:
  14992. return self.defineInit(cgClass)
  14993. members = ""
  14994. holdJS = ""
  14995. iface = self.descriptorProvider.interface
  14996. while iface.identifier.name != "Event":
  14997. for m in self.descriptorProvider.getDescriptor(iface.identifier.name).interface.members:
  14998. if m.isAttr():
  14999. # We initialize all the other member variables in the
  15000. # Constructor except those ones coming from the Event.
  15001. if getattr(m, "originatingInterface",
  15002. cgClass.descriptor.interface).identifier.name == "Event":
  15003. continue
  15004. name = CGDictionary.makeMemberName(m.identifier.name)
  15005. if m.type.isSequence():
  15006. # For sequences we may not be able to do a simple
  15007. # assignment because the underlying types may not match.
  15008. # For example, the argument can be a
  15009. # Sequence<OwningNonNull<SomeInterface>> while our
  15010. # member is an nsTArray<RefPtr<SomeInterface>>. So
  15011. # use AppendElements, which is actually a template on
  15012. # the incoming type on nsTArray and does the right thing
  15013. # for this case.
  15014. target = name
  15015. source = "%s.%s" % (self.args[1].name, name)
  15016. sequenceCopy = "e->%s.AppendElements(%s);\n"
  15017. if m.type.nullable():
  15018. sequenceCopy = CGIfWrapper(
  15019. CGGeneric(sequenceCopy),
  15020. "!%s.IsNull()" % source).define()
  15021. target += ".SetValue()"
  15022. source += ".Value()"
  15023. members += sequenceCopy % (target, source)
  15024. elif m.type.isSpiderMonkeyInterface():
  15025. srcname = "%s.%s" % (self.args[1].name, name)
  15026. if m.type.nullable():
  15027. members += fill(
  15028. """
  15029. if (${srcname}.IsNull()) {
  15030. e->${varname} = nullptr;
  15031. } else {
  15032. e->${varname} = ${srcname}.Value().Obj();
  15033. }
  15034. """,
  15035. varname=name,
  15036. srcname=srcname)
  15037. else:
  15038. members += fill(
  15039. """
  15040. e->${varname}.set(${srcname}.Obj());
  15041. """,
  15042. varname=name, srcname=srcname)
  15043. else:
  15044. members += "e->%s = %s.%s;\n" % (name, self.args[1].name, name)
  15045. if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface():
  15046. holdJS = "mozilla::HoldJSObjects(e.get());\n"
  15047. iface = iface.parent
  15048. self.body = fill(
  15049. """
  15050. RefPtr<${nativeType}> e = new ${nativeType}(aOwner);
  15051. bool trusted = e->Init(aOwner);
  15052. e->InitEvent(${eventType}, ${eventInit}.mBubbles, ${eventInit}.mCancelable);
  15053. $*{members}
  15054. e->SetTrusted(trusted);
  15055. e->SetComposed(${eventInit}.mComposed);
  15056. $*{holdJS}
  15057. return e.forget();
  15058. """,
  15059. nativeType=self.descriptorProvider.nativeType.split('::')[-1],
  15060. eventType=self.args[0].name,
  15061. eventInit=self.args[1].name,
  15062. members=members,
  15063. holdJS=holdJS)
  15064. self.args.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
  15065. constructorForNativeCaller = CGNativeMember.define(self, cgClass) + "\n"
  15066. self.args = list(self.originalArgs)
  15067. self.body = fill(
  15068. """
  15069. nsCOMPtr<mozilla::dom::EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
  15070. return Constructor(owner, ${arg0}, ${arg1});
  15071. """,
  15072. arg0=self.args[0].name,
  15073. arg1=self.args[1].name)
  15074. if needCx(None, self.arguments(), [], considerTypes=True, static=True):
  15075. self.args.insert(0, Argument("JSContext*", "aCx"))
  15076. self.args.insert(0, Argument("const GlobalObject&", "aGlobal"))
  15077. self.args.append(Argument('ErrorResult&', 'aRv'))
  15078. return constructorForNativeCaller + CGNativeMember.define(self, cgClass)
  15079. class CGEventClass(CGBindingImplClass):
  15080. """
  15081. Codegen for the actual Event class implementation for this descriptor
  15082. """
  15083. def __init__(self, descriptor):
  15084. CGBindingImplClass.__init__(self, descriptor, CGEventMethod, CGEventGetter, CGEventSetter, False, "WrapObjectInternal")
  15085. members = []
  15086. extraMethods = []
  15087. for m in descriptor.interface.members:
  15088. if m.isAttr():
  15089. if m.type.isAny():
  15090. # Add a getter that doesn't need a JSContext. Note that we
  15091. # don't need to do this if our originating interface is not
  15092. # the descriptor's interface, because in that case we
  15093. # wouldn't generate the getter that _does_ need a JSContext
  15094. # either.
  15095. extraMethods.append(
  15096. ClassMethod(
  15097. CGSpecializedGetter.makeNativeName(descriptor, m),
  15098. "void",
  15099. [Argument("JS::MutableHandle<JS::Value>",
  15100. "aRetVal")],
  15101. const=True,
  15102. body=fill(
  15103. """
  15104. JS::ExposeValueToActiveJS(${memberName});
  15105. aRetVal.set(${memberName});
  15106. """,
  15107. memberName=CGDictionary.makeMemberName(m.identifier.name))))
  15108. if getattr(m, "originatingInterface",
  15109. descriptor.interface) != descriptor.interface:
  15110. continue
  15111. nativeType = self.getNativeTypeForIDLType(m.type).define()
  15112. members.append(ClassMember(CGDictionary.makeMemberName(m.identifier.name),
  15113. nativeType,
  15114. visibility="private",
  15115. body="body"))
  15116. parent = self.descriptor.interface.parent
  15117. self.parentType = self.descriptor.getDescriptor(parent.identifier.name).nativeType.split('::')[-1]
  15118. baseDeclarations = fill(
  15119. """
  15120. public:
  15121. NS_DECL_ISUPPORTS_INHERITED
  15122. NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(${nativeType}, ${parentType})
  15123. protected:
  15124. virtual ~${nativeType}();
  15125. explicit ${nativeType}(mozilla::dom::EventTarget* aOwner);
  15126. """,
  15127. nativeType=self.descriptor.nativeType.split('::')[-1],
  15128. parentType=self.parentType)
  15129. className = descriptor.nativeType.split('::')[-1]
  15130. asConcreteTypeMethod = ClassMethod("As%s" % className,
  15131. "%s*" % className,
  15132. [],
  15133. virtual=True,
  15134. body="return this;\n",
  15135. breakAfterReturnDecl=" ",
  15136. override=True)
  15137. extraMethods.append(asConcreteTypeMethod)
  15138. CGClass.__init__(self, className,
  15139. bases=[ClassBase(self.parentType)],
  15140. methods=extraMethods+self.methodDecls,
  15141. members=members,
  15142. extradeclarations=baseDeclarations)
  15143. def getWrapObjectBody(self):
  15144. return "return %sBinding::Wrap(aCx, this, aGivenProto);\n" % self.descriptor.name
  15145. def implTraverse(self):
  15146. retVal = ""
  15147. for m in self.descriptor.interface.members:
  15148. # Unroll the type so we pick up sequences of interfaces too.
  15149. if m.isAttr() and idlTypeNeedsCycleCollection(m.type):
  15150. retVal += (" NS_IMPL_CYCLE_COLLECTION_TRAVERSE(" +
  15151. CGDictionary.makeMemberName(m.identifier.name) +
  15152. ")\n")
  15153. return retVal
  15154. def implUnlink(self):
  15155. retVal = ""
  15156. for m in self.descriptor.interface.members:
  15157. if m.isAttr():
  15158. name = CGDictionary.makeMemberName(m.identifier.name)
  15159. # Unroll the type so we pick up sequences of interfaces too.
  15160. if idlTypeNeedsCycleCollection(m.type):
  15161. retVal += " NS_IMPL_CYCLE_COLLECTION_UNLINK(" + name + ")\n"
  15162. elif m.type.isAny():
  15163. retVal += " tmp->" + name + ".setUndefined();\n"
  15164. elif m.type.isObject() or m.type.isSpiderMonkeyInterface():
  15165. retVal += " tmp->" + name + " = nullptr;\n"
  15166. return retVal
  15167. def implTrace(self):
  15168. retVal = ""
  15169. for m in self.descriptor.interface.members:
  15170. if m.isAttr():
  15171. name = CGDictionary.makeMemberName(m.identifier.name)
  15172. if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface():
  15173. retVal += " NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(" + name + ")\n"
  15174. elif typeNeedsRooting(m.type):
  15175. raise TypeError("Need to implement tracing for event "
  15176. "member of type %s" % m.type)
  15177. return retVal
  15178. def define(self):
  15179. dropJS = ""
  15180. for m in self.descriptor.interface.members:
  15181. if m.isAttr():
  15182. member = CGDictionary.makeMemberName(m.identifier.name)
  15183. if m.type.isAny():
  15184. dropJS += member + " = JS::UndefinedValue();\n"
  15185. elif m.type.isObject() or m.type.isSpiderMonkeyInterface():
  15186. dropJS += member + " = nullptr;\n"
  15187. if dropJS != "":
  15188. dropJS += "mozilla::DropJSObjects(this);\n"
  15189. # Just override CGClass and do our own thing
  15190. nativeType = self.descriptor.nativeType.split('::')[-1]
  15191. ctorParams = ("aOwner, nullptr, nullptr" if self.parentType == "Event"
  15192. else "aOwner")
  15193. classImpl = fill(
  15194. """
  15195. NS_IMPL_CYCLE_COLLECTION_CLASS(${nativeType})
  15196. NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
  15197. NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
  15198. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(${nativeType}, ${parentType})
  15199. $*{traverse}
  15200. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  15201. NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(${nativeType}, ${parentType})
  15202. $*{trace}
  15203. NS_IMPL_CYCLE_COLLECTION_TRACE_END
  15204. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(${nativeType}, ${parentType})
  15205. $*{unlink}
  15206. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  15207. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(${nativeType})
  15208. NS_INTERFACE_MAP_END_INHERITING(${parentType})
  15209. ${nativeType}::${nativeType}(mozilla::dom::EventTarget* aOwner)
  15210. : ${parentType}(${ctorParams})
  15211. {
  15212. }
  15213. ${nativeType}::~${nativeType}()
  15214. {
  15215. $*{dropJS}
  15216. }
  15217. """,
  15218. ifaceName=self.descriptor.name,
  15219. nativeType=nativeType,
  15220. ctorParams=ctorParams,
  15221. parentType=self.parentType,
  15222. traverse=self.implTraverse(),
  15223. unlink=self.implUnlink(),
  15224. trace=self.implTrace(),
  15225. dropJS=dropJS)
  15226. return classImpl + CGBindingImplClass.define(self)
  15227. def getNativeTypeForIDLType(self, type):
  15228. if type.isPrimitive() and type.tag() in builtinNames:
  15229. nativeType = CGGeneric(builtinNames[type.tag()])
  15230. if type.nullable():
  15231. nativeType = CGTemplatedType("Nullable", nativeType)
  15232. elif type.isEnum():
  15233. nativeType = CGGeneric(type.unroll().inner.identifier.name)
  15234. if type.nullable():
  15235. nativeType = CGTemplatedType("Nullable", nativeType)
  15236. elif type.isDOMString() or type.isUSVString():
  15237. nativeType = CGGeneric("nsString")
  15238. elif type.isByteString():
  15239. nativeType = CGGeneric("nsCString")
  15240. elif type.isPromise():
  15241. nativeType = CGGeneric("RefPtr<Promise>")
  15242. elif type.isGeckoInterface():
  15243. iface = type.unroll().inner
  15244. nativeType = self.descriptor.getDescriptor(
  15245. iface.identifier.name).nativeType
  15246. # Now trim off unnecessary namespaces
  15247. nativeType = nativeType.split("::")
  15248. if nativeType[0] == "mozilla":
  15249. nativeType.pop(0)
  15250. if nativeType[0] == "dom":
  15251. nativeType.pop(0)
  15252. nativeType = CGWrapper(CGGeneric("::".join(nativeType)), pre="RefPtr<", post=">")
  15253. elif type.isAny():
  15254. nativeType = CGGeneric("JS::Heap<JS::Value>")
  15255. elif type.isObject() or type.isSpiderMonkeyInterface():
  15256. nativeType = CGGeneric("JS::Heap<JSObject*>")
  15257. elif type.isUnion():
  15258. nativeType = CGGeneric(CGUnionStruct.unionTypeDecl(type, True))
  15259. elif type.isSequence():
  15260. if type.nullable():
  15261. innerType = type.inner.inner
  15262. else:
  15263. innerType = type.inner
  15264. if (not innerType.isPrimitive() and not innerType.isEnum() and
  15265. not innerType.isDOMString() and not innerType.isByteString() and
  15266. not innerType.isPromise() and not innerType.isGeckoInterface()):
  15267. raise TypeError("Don't know how to properly manage GC/CC for "
  15268. "event member of type %s" %
  15269. type)
  15270. nativeType = CGTemplatedType(
  15271. "nsTArray",
  15272. self.getNativeTypeForIDLType(innerType))
  15273. if type.nullable():
  15274. nativeType = CGTemplatedType("Nullable", nativeType)
  15275. else:
  15276. raise TypeError("Don't know how to declare event member of type %s" %
  15277. type)
  15278. return nativeType
  15279. class CGEventRoot(CGThing):
  15280. def __init__(self, config, interfaceName):
  15281. descriptor = config.getDescriptor(interfaceName)
  15282. self.root = CGWrapper(CGEventClass(descriptor),
  15283. pre="\n", post="\n")
  15284. self.root = CGNamespace.build(["mozilla", "dom"], self.root)
  15285. self.root = CGList([CGClassForwardDeclare("JSContext", isStruct=True),
  15286. self.root])
  15287. parent = descriptor.interface.parent.identifier.name
  15288. # Throw in our #includes
  15289. self.root = CGHeaders(
  15290. [descriptor],
  15291. [],
  15292. [],
  15293. [],
  15294. [
  15295. config.getDescriptor(parent).headerFile,
  15296. "mozilla/Attributes.h",
  15297. "mozilla/ErrorResult.h",
  15298. "mozilla/dom/%sBinding.h" % interfaceName,
  15299. 'mozilla/dom/BindingUtils.h',
  15300. ],
  15301. [
  15302. "%s.h" % interfaceName,
  15303. "js/GCAPI.h",
  15304. 'mozilla/dom/Nullable.h',
  15305. ],
  15306. "", self.root, config)
  15307. # And now some include guards
  15308. self.root = CGIncludeGuard(interfaceName, self.root)
  15309. self.root = CGWrapper(
  15310. self.root,
  15311. pre=(AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT %
  15312. os.path.basename(descriptor.interface.filename())))
  15313. self.root = CGWrapper(self.root, pre=dedent("""
  15314. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  15315. /* vim:set ts=2 sw=2 sts=2 et cindent: */
  15316. /* This Source Code Form is subject to the terms of the Mozilla Public
  15317. * License, v. 2.0. If a copy of the MPL was not distributed with this
  15318. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  15319. """))
  15320. def declare(self):
  15321. return self.root.declare()
  15322. def define(self):
  15323. return self.root.define()