123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700 |
- /*
- Expression Evaluator Library (NS-EEL) v2
- Copyright (C) 2004-2013 Cockos Incorporated
- Copyright (C) 1999-2003 Nullsoft, Inc.
-
- nseel-compiler.c
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- #include "ns-eel-int.h"
- #include "denormal.h"
- #include "wdlcstring.h"
- #include <string.h>
- #include <math.h>
- #include <stdio.h>
- #include <ctype.h>
- #if !defined(EEL_TARGET_PORTABLE) && !defined(_WIN32)
- #include <sys/mman.h>
- #include <stdint.h>
- #include <unistd.h>
- #endif
- #include "glue_x86.h"
- #ifdef _WIN64
- #include "glue_x86_64.h"
- #endif // _WIN64
- #define NSEEL_VARS_MALLOC_CHUNKSIZE 8
- //#define LOG_OPT
- //#define EEL_PRINT_FAILS
- //#define EEL_VALIDATE_WORKTABLE_USE
- //#define EEL_VALIDATE_FSTUBS
- #ifdef EEL_PRINT_FAILS
- #ifdef _WIN32
- #define RET_MINUS1_FAIL(x) { OutputDebugString(x); return -1; }
- #else
- #define RET_MINUS1_FAIL(x) { printf("%s\n",x); return -1; }
- #endif
- #else
- #define RET_MINUS1_FAIL(x) return -1;
- #endif
- #ifdef EEL_DUMP_OPS
- FILE *g_eel_dump_fp, *g_eel_dump_fp2;
- #endif
- #ifdef EEL_VALIDATE_WORKTABLE_USE
- #define MIN_COMPUTABLE_SIZE 0
- #define COMPUTABLE_EXTRA_SPACE 64 // safety buffer, if EEL_VALIDATE_WORKTABLE_USE set, used for magic-value-checking
- #else
- #define MIN_COMPUTABLE_SIZE 32 // always use at least this big of a temp storage table (and reset the temp ptr when it goes past this boundary)
- #define COMPUTABLE_EXTRA_SPACE 16 // safety buffer, if EEL_VALIDATE_WORKTABLE_USE set, used for magic-value-checking
- #endif
- /*
- P1 is rightmost parameter
- P2 is second rightmost, if any
- P3 is third rightmost, if any
- registers on x86 are (RAX etc on x86-64)
- P1(ret) EAX
- P2 EDI
- P3 ECX
- WTP RSI
- x86_64: r12 is a pointer to ram_state.blocks
- x86_64: r13 is a pointer to closenessfactor
- registers on PPC are:
- P1(ret) r3
- P2 r14
- P3 r15
- WTP r16 (r17 has the original value)
- r13 is a pointer to ram_state.blocks
- ppc uses f31 and f30 and others for certain constants
- */
- #ifdef EEL_TARGET_PORTABLE
- #define EEL_DOESNT_NEED_EXEC_PERMS
- #include "glue_port.h"
- #elif defined(__ppc__)
- #include "glue_ppc.h"
- #elif defined(__aarch64__)
- #include "glue_aarch64.h"
- #elif defined(__arm__) || (defined (_M_ARM) && _M_ARM == 7)
- #include "glue_arm.h"
- #elif defined(_WIN64) || defined(__LP64__)
- #include "glue_x86_64.h"
- #else
- #include "glue_x86.h"
- #endif
- #ifndef GLUE_INVSQRT_NEEDREPL
- #define GLUE_INVSQRT_NEEDREPL 0
- #endif
- // used by //#eel-no-optimize:xxx, in ctx->optimizeDisableFlags
- #define OPTFLAG_NO_OPTIMIZE 1
- #define OPTFLAG_NO_FPSTACK 2
- #define OPTFLAG_NO_INLINEFUNC 4
- #define OPTFLAG_FULL_DENORMAL_CHECKS 8 // if set, denormals/NaN are always filtered on assign
- #define OPTFLAG_NO_DENORMAL_CHECKS 16 // if set and FULL not set, denormals/NaN are never filtered on assign
- #define DENORMAL_CLEARING_THRESHOLD 1.0e-50 // when adding/subtracting a constant, assume if it's greater than this, it will clear denormal (the actual value is probably 10^-290...)
- #define MAX_SUB_NAMESPACES 32
- typedef struct
- {
- const char *namespacePathToThis;
- const char *subParmInfo[MAX_SUB_NAMESPACES];
- } namespaceInformation;
- static int nseel_evallib_stats[5]; // source bytes, static code bytes, call code bytes, data bytes, segments
- int *NSEEL_getstats()
- {
- return nseel_evallib_stats;
- }
- static int findLineNumber(const char *exp, int byteoffs)
- {
- int lc=0;
- while (byteoffs-->0 && *exp) if (*exp++ =='\n') lc++;
- return lc;
- }
- static int nseel_vms_referencing_globallist_cnt;
- nseel_globalVarItem *nseel_globalreg_list;
- static EEL_F *get_global_var(compileContext *ctx, const char *gv, int addIfNotPresent);
- static void *__newBlock(llBlock **start,int size, int wantMprotect);
- #define OPCODE_IS_TRIVIAL(x) ((x)->opcodeType <= OPCODETYPE_VARPTRPTR)
- enum {
- OPCODETYPE_DIRECTVALUE=0,
- OPCODETYPE_DIRECTVALUE_TEMPSTRING, // like directvalue, but will generate a new tempstring value on generate
- OPCODETYPE_VALUE_FROM_NAMESPACENAME, // this.* or namespace.* are encoded this way
- OPCODETYPE_VARPTR,
- OPCODETYPE_VARPTRPTR,
- OPCODETYPE_FUNC1,
- OPCODETYPE_FUNC2,
- OPCODETYPE_FUNC3,
- OPCODETYPE_FUNCX,
- OPCODETYPE_MOREPARAMS,
- OPCODETYPE_INVALID,
- };
- struct opcodeRec
- {
- int opcodeType;
- int fntype;
- void *fn;
-
- union {
- struct opcodeRec *parms[3];
- struct {
- double directValue;
- EEL_F *valuePtr; // if direct value, valuePtr can be cached
- } dv;
- } parms;
-
- int namespaceidx;
-
- // OPCODETYPE_VALUE_FROM_NAMESPACENAME (relname is either empty or blah)
- // OPCODETYPE_VARPTR if it represents a global variable, will be nonempty
- // OPCODETYPE_FUNC* with fntype=FUNCTYPE_EELFUNC
- const char *relname;
- };
- static void *newTmpBlock(compileContext *ctx, int size)
- {
- const int align = 8;
- const int a1=align-1;
- char *p=(char*)__newBlock(&ctx->tmpblocks_head,size+a1, 0);
- return p+((align-(((INT_PTR)p)&a1))&a1);
- }
- static void *__newBlock_align(compileContext *ctx, int size, int align, int isForCode)
- {
- const int a1=align-1;
- char *p=(char*)__newBlock(
- (
- isForCode < 0 ? (isForCode == -2 ? &ctx->pblocks : &ctx->tmpblocks_head) :
- isForCode > 0 ? &ctx->blocks_head :
- &ctx->blocks_head_data) ,size+a1, isForCode>0);
- return p+((align-(((INT_PTR)p)&a1))&a1);
- }
- static opcodeRec *newOpCode(compileContext *ctx, const char *str, int opType)
- {
- const size_t strszfull = str ? strlen(str) : 0;
- const size_t str_sz = wdl_min(NSEEL_MAX_VARIABLE_NAMELEN, strszfull);
- opcodeRec *rec = (opcodeRec*)__newBlock_align(ctx,
- (int) (sizeof(opcodeRec) + (str_sz>0 ? str_sz+1 : 0)),
- 8, ctx->isSharedFunctions ? 0 : -1);
- if (rec)
- {
- memset(rec,0,sizeof(*rec));
- rec->opcodeType = opType;
- if (str_sz > 0)
- {
- char *p = (char *)(rec+1);
- memcpy(p,str,str_sz);
- p[str_sz]=0;
- rec->relname = p;
- }
- else
- {
- rec->relname = "";
- }
- }
- return rec;
- }
- #define newCodeBlock(x,a) __newBlock_align(ctx,x,a,1)
- #define newDataBlock(x,a) __newBlock_align(ctx,x,a,0)
- #define newCtxDataBlock(x,a) __newBlock_align(ctx,x,a,-2)
- static void freeBlocks(llBlock **start);
- static int __growbuf_resize(eel_growbuf *buf, int newsize)
- {
- if (newsize<0)
- {
- free(buf->ptr);
- buf->ptr=NULL;
- buf->alloc=buf->size=0;
- return 0;
- }
- if (newsize > buf->alloc)
- {
- const int newalloc = newsize + 4096 + newsize/2;
- void *newptr = realloc(buf->ptr,newalloc);
- if (!newptr)
- {
- newptr = malloc(newalloc);
- if (!newptr) return 1;
- if (buf->ptr && buf->size) memcpy(newptr,buf->ptr,buf->size);
- free(buf->ptr);
- buf->ptr=newptr;
- }
- else
- buf->ptr = newptr;
- buf->alloc=newalloc;
- }
- buf->size = newsize;
- return 0;
- }
- #ifndef DECL_ASMFUNC
- #define DECL_ASMFUNC(x) \
- void nseel_asm_##x(void); \
- void nseel_asm_##x##_end(void);
- void _asm_megabuf(void);
- void _asm_megabuf_end(void);
- void _asm_gmegabuf(void);
- void _asm_gmegabuf_end(void);
- #endif
- DECL_ASMFUNC(booltofp)
- DECL_ASMFUNC(fptobool)
- DECL_ASMFUNC(fptobool_rev)
- DECL_ASMFUNC(sin)
- DECL_ASMFUNC(cos)
- DECL_ASMFUNC(tan)
- DECL_ASMFUNC(1pdd)
- DECL_ASMFUNC(2pdd)
- DECL_ASMFUNC(2pdds)
- DECL_ASMFUNC(1pp)
- DECL_ASMFUNC(2pp)
- DECL_ASMFUNC(sqr)
- DECL_ASMFUNC(sqrt)
- DECL_ASMFUNC(log)
- DECL_ASMFUNC(log10)
- DECL_ASMFUNC(abs)
- DECL_ASMFUNC(min)
- DECL_ASMFUNC(max)
- DECL_ASMFUNC(min_fp)
- DECL_ASMFUNC(max_fp)
- DECL_ASMFUNC(sig)
- DECL_ASMFUNC(sign)
- DECL_ASMFUNC(band)
- DECL_ASMFUNC(bor)
- DECL_ASMFUNC(bnot)
- DECL_ASMFUNC(bnotnot)
- DECL_ASMFUNC(if)
- DECL_ASMFUNC(fcall)
- DECL_ASMFUNC(repeat)
- DECL_ASMFUNC(repeatwhile)
- DECL_ASMFUNC(equal)
- DECL_ASMFUNC(equal_exact)
- DECL_ASMFUNC(notequal_exact)
- DECL_ASMFUNC(notequal)
- DECL_ASMFUNC(below)
- DECL_ASMFUNC(above)
- DECL_ASMFUNC(beloweq)
- DECL_ASMFUNC(aboveeq)
- DECL_ASMFUNC(assign)
- DECL_ASMFUNC(assign_fromfp)
- DECL_ASMFUNC(assign_fast)
- DECL_ASMFUNC(assign_fast_fromfp)
- DECL_ASMFUNC(add)
- DECL_ASMFUNC(sub)
- DECL_ASMFUNC(add_op)
- DECL_ASMFUNC(sub_op)
- DECL_ASMFUNC(add_op_fast)
- DECL_ASMFUNC(sub_op_fast)
- DECL_ASMFUNC(mul)
- DECL_ASMFUNC(div)
- DECL_ASMFUNC(mul_op)
- DECL_ASMFUNC(div_op)
- DECL_ASMFUNC(mul_op_fast)
- DECL_ASMFUNC(div_op_fast)
- DECL_ASMFUNC(mod)
- DECL_ASMFUNC(shl)
- DECL_ASMFUNC(shr)
- DECL_ASMFUNC(mod_op)
- DECL_ASMFUNC(or)
- DECL_ASMFUNC(or0)
- DECL_ASMFUNC(xor)
- DECL_ASMFUNC(xor_op)
- DECL_ASMFUNC(and)
- DECL_ASMFUNC(or_op)
- DECL_ASMFUNC(and_op)
- DECL_ASMFUNC(uplus)
- DECL_ASMFUNC(uminus)
- DECL_ASMFUNC(invsqrt)
- DECL_ASMFUNC(dbg_getstackptr)
- #ifdef NSEEL_EEL1_COMPAT_MODE
- DECL_ASMFUNC(exec2)
- #endif
- DECL_ASMFUNC(stack_push)
- DECL_ASMFUNC(stack_pop)
- DECL_ASMFUNC(stack_pop_fast) // just returns value, doesn't mod param
- DECL_ASMFUNC(stack_peek)
- DECL_ASMFUNC(stack_peek_int)
- DECL_ASMFUNC(stack_peek_top)
- DECL_ASMFUNC(stack_exch)
- static void *NSEEL_PProc_GRAM(void *data, int data_size, compileContext *ctx)
- {
- if (data_size>0) data=EEL_GLUE_set_immediate(data, (INT_PTR)ctx->gram_blocks);
- return data;
- }
- static void *NSEEL_PProc_Stack(void *data, int data_size, compileContext *ctx)
- {
- codeHandleType *ch=ctx->tmpCodeHandle;
- if (data_size>0)
- {
- UINT_PTR m1=(UINT_PTR)(NSEEL_STACK_SIZE * sizeof(EEL_F) - 1);
- UINT_PTR stackptr = ((UINT_PTR) (&ch->stack));
- ch->want_stack=1;
- if (!ch->stack) ch->stack = newDataBlock(NSEEL_STACK_SIZE*sizeof(EEL_F),NSEEL_STACK_SIZE*sizeof(EEL_F));
- data=EEL_GLUE_set_immediate(data, stackptr);
- data=EEL_GLUE_set_immediate(data, m1); // and
- data=EEL_GLUE_set_immediate(data, ((UINT_PTR)ch->stack&~m1)); //or
- }
- return data;
- }
- static void *NSEEL_PProc_Stack_PeekInt(void *data, int data_size, compileContext *ctx, INT_PTR offs)
- {
- codeHandleType *ch=ctx->tmpCodeHandle;
- if (data_size>0)
- {
- UINT_PTR m1=(UINT_PTR)(NSEEL_STACK_SIZE * sizeof(EEL_F) - 1);
- UINT_PTR stackptr = ((UINT_PTR) (&ch->stack));
- ch->want_stack=1;
- if (!ch->stack) ch->stack = newDataBlock(NSEEL_STACK_SIZE*sizeof(EEL_F),NSEEL_STACK_SIZE*sizeof(EEL_F));
- data=EEL_GLUE_set_immediate(data, stackptr);
- data=EEL_GLUE_set_immediate(data, offs);
- data=EEL_GLUE_set_immediate(data, m1); // and
- data=EEL_GLUE_set_immediate(data, ((UINT_PTR)ch->stack&~m1)); //or
- }
- return data;
- }
- static void *NSEEL_PProc_Stack_PeekTop(void *data, int data_size, compileContext *ctx)
- {
- codeHandleType *ch=ctx->tmpCodeHandle;
- if (data_size>0)
- {
- UINT_PTR stackptr = ((UINT_PTR) (&ch->stack));
- ch->want_stack=1;
- if (!ch->stack) ch->stack = newDataBlock(NSEEL_STACK_SIZE*sizeof(EEL_F),NSEEL_STACK_SIZE*sizeof(EEL_F));
- data=EEL_GLUE_set_immediate(data, stackptr);
- }
- return data;
- }
- #if defined(_MSC_VER) && _MSC_VER >= 1400
- //static double __floor(double a) { return floor(a); }
- //static double __ceil(double a) { return ceil(a); }
- #define floor __floor
- #define ceil __ceil
- #endif
- #ifdef NSEEL_EEL1_COMPAT_MODE
- static double eel1band(double a, double b)
- {
- return (fabs(a)>NSEEL_CLOSEFACTOR && fabs(b) > NSEEL_CLOSEFACTOR) ? 1.0 : 0.0;
- }
- static double eel1bor(double a, double b)
- {
- return (fabs(a)>NSEEL_CLOSEFACTOR || fabs(b) > NSEEL_CLOSEFACTOR) ? 1.0 : 0.0;
- }
- static double eel1sigmoid(double x, double constraint)
- {
- double t = (1+exp(-x * (constraint)));
- return fabs(t)>NSEEL_CLOSEFACTOR ? 1.0/t : 0;
- }
- #endif
- #define FUNCTIONTYPE_PARAMETERCOUNTMASK 0xff
- #define BIF_NPARAMS_MASK 0x7ffff00
- #define BIF_RETURNSONSTACK 0x0000100
- #define BIF_LASTPARMONSTACK 0x0000200
- #define BIF_RETURNSBOOL 0x0000400
- #define BIF_LASTPARM_ASBOOL 0x0000800
- // 0x00?0000 -- taken by FP stack flags
- #define BIF_TAKES_VARPARM 0x0400000
- #define BIF_TAKES_VARPARM_EX 0x0C00000 // this is like varparm but check count exactly
- #define BIF_WONTMAKEDENORMAL 0x0100000
- #define BIF_CLEARDENORMAL 0x0200000
- #if defined(GLUE_HAS_FXCH) && GLUE_MAX_FPSTACK_SIZE > 0
- #define BIF_SECONDLASTPARMST 0x0001000 // use with BIF_LASTPARMONSTACK only (last two parameters get passed on fp stack)
- #define BIF_LAZYPARMORDERING 0x0002000 // allow optimizer to avoid fxch when using BIF_TWOPARMSONFPSTACK_LAZY etc
- #define BIF_REVERSEFPORDER 0x0004000 // force a fxch (reverse order of last two parameters on fp stack, used by comparison functions)
- #ifndef BIF_FPSTACKUSE
- #define BIF_FPSTACKUSE(x) (((x)>=0&&(x)<8) ? ((7-(x))<<16):0)
- #endif
- #ifndef BIF_GETFPSTACKUSE
- #define BIF_GETFPSTACKUSE(x) (7 - (((x)>>16)&7))
- #endif
- #else
- // do not support fp stack use unless GLUE_HAS_FXCH and GLUE_MAX_FPSTACK_SIZE>0
- #define BIF_SECONDLASTPARMST 0
- #define BIF_LAZYPARMORDERING 0
- #define BIF_REVERSEFPORDER 0
- #define BIF_FPSTACKUSE(x) 0
- #define BIF_GETFPSTACKUSE(x) 0
- #endif
- #define BIF_TWOPARMSONFPSTACK (BIF_SECONDLASTPARMST|BIF_LASTPARMONSTACK)
- #define BIF_TWOPARMSONFPSTACK_LAZY (BIF_LAZYPARMORDERING|BIF_SECONDLASTPARMST|BIF_LASTPARMONSTACK)
- #ifndef GLUE_HAS_NATIVE_TRIGSQRTLOG
- static double sqrt_fabs(double a) { return sqrt(fabs(a)); }
- #endif
- EEL_F NSEEL_CGEN_CALL nseel_int_rand(EEL_F f);
- #define FNPTR_HAS_CONDITIONAL_EXEC(op) \
- (op->fntype == FN_LOGICAL_AND || \
- op->fntype == FN_LOGICAL_OR || \
- op->fntype == FN_IF_ELSE || \
- op->fntype == FN_WHILE || \
- op->fntype == FN_LOOP)
- static functionType fnTable1[] = {
- #ifndef GLUE_HAS_NATIVE_TRIGSQRTLOG
- { "sin", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_WONTMAKEDENORMAL, {&sin} },
- { "cos", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL, {&cos} },
- { "tan", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&tan} },
- { "sqrt", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_WONTMAKEDENORMAL, {&sqrt_fabs}, },
- { "log", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&log} },
- { "log10", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&log10} },
- #else
- { "sin", nseel_asm_sin,nseel_asm_sin_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_WONTMAKEDENORMAL|BIF_FPSTACKUSE(1) },
- { "cos", nseel_asm_cos,nseel_asm_cos_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL|BIF_FPSTACKUSE(1) },
- { "tan", nseel_asm_tan,nseel_asm_tan_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1) },
- { "sqrt", nseel_asm_sqrt,nseel_asm_sqrt_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1)|BIF_WONTMAKEDENORMAL },
- { "log", nseel_asm_log,nseel_asm_log_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(3), },
- { "log10", nseel_asm_log10,nseel_asm_log10_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(3), },
- #endif
- { "asin", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&asin}, },
- { "acos", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&acos}, },
- { "atan", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&atan}, },
- { "atan2", nseel_asm_2pdd,nseel_asm_2pdd_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK, {&atan2}, },
- { "exp", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&exp}, },
- { "abs", nseel_asm_abs,nseel_asm_abs_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(0)|BIF_WONTMAKEDENORMAL },
- { "sqr", nseel_asm_sqr,nseel_asm_sqr_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1) },
- { "min", nseel_asm_min,nseel_asm_min_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_FPSTACKUSE(3)|BIF_WONTMAKEDENORMAL },
- { "max", nseel_asm_max,nseel_asm_max_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_FPSTACKUSE(3)|BIF_WONTMAKEDENORMAL },
- { "sign", nseel_asm_sign,nseel_asm_sign_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL, },
- { "rand", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL, {&nseel_int_rand}, },
- //{ "floor", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL, {&floor} },
- //{ "ceil", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL, {&ceil} },
- { "invsqrt", nseel_asm_invsqrt,nseel_asm_invsqrt_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(3), {GLUE_INVSQRT_NEEDREPL} },
- { "__dbg_getstackptr", nseel_asm_dbg_getstackptr,nseel_asm_dbg_getstackptr_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1), },
- #ifdef NSEEL_EEL1_COMPAT_MODE
- { "sigmoid", nseel_asm_2pdd,nseel_asm_2pdd_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK, {&eel1sigmoid}, },
- // these differ from _and/_or, they always evaluate both...
- { "band", nseel_asm_2pdd,nseel_asm_2pdd_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_CLEARDENORMAL , {&eel1band}, },
- { "bor", nseel_asm_2pdd,nseel_asm_2pdd_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_CLEARDENORMAL , {&eel1bor}, },
- {"exec2",nseel_asm_exec2,nseel_asm_exec2_end,2|NSEEL_NPARAMS_FLAG_CONST|BIF_WONTMAKEDENORMAL},
- {"exec3",nseel_asm_exec2,nseel_asm_exec2_end,3|NSEEL_NPARAMS_FLAG_CONST|BIF_WONTMAKEDENORMAL},
- #endif // end EEL1 compat
- {"freembuf",_asm_generic1parm,_asm_generic1parm_end,1,{&__NSEEL_RAM_MemFree},NSEEL_PProc_RAM},
- {"memcpy",_asm_generic3parm,_asm_generic3parm_end,3,{&__NSEEL_RAM_MemCpy},NSEEL_PProc_RAM},
- {"memset",_asm_generic3parm,_asm_generic3parm_end,3,{&__NSEEL_RAM_MemSet},NSEEL_PProc_RAM},
- {"__memtop",_asm_generic1parm,_asm_generic1parm_end,1,{&__NSEEL_RAM_MemTop},NSEEL_PProc_RAM},
- {"mem_set_values",_asm_generic2parm_retd,_asm_generic2parm_retd_end,2|BIF_TAKES_VARPARM|BIF_RETURNSONSTACK,{&__NSEEL_RAM_Mem_SetValues},NSEEL_PProc_RAM},
- {"mem_get_values",_asm_generic2parm_retd,_asm_generic2parm_retd_end,2|BIF_TAKES_VARPARM|BIF_RETURNSONSTACK,{&__NSEEL_RAM_Mem_GetValues},NSEEL_PProc_RAM},
- {"stack_push",nseel_asm_stack_push,nseel_asm_stack_push_end,1|BIF_FPSTACKUSE(0),{0,},NSEEL_PProc_Stack},
- {"stack_pop",nseel_asm_stack_pop,nseel_asm_stack_pop_end,1|BIF_FPSTACKUSE(1),{0,},NSEEL_PProc_Stack},
- {"stack_peek",nseel_asm_stack_peek,nseel_asm_stack_peek_end,1|NSEEL_NPARAMS_FLAG_CONST|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(0),{0,},NSEEL_PProc_Stack},
- {"stack_exch",nseel_asm_stack_exch,nseel_asm_stack_exch_end,1|BIF_FPSTACKUSE(1), {0,},NSEEL_PProc_Stack_PeekTop},
- };
- static eel_function_table default_user_funcs;
- static int functable_lowerbound(functionType *list, int list_sz, const char *name, int *ismatch)
- {
- int a = 0, c = list_sz;
- while (a != c)
- {
- const int b = (a+c)/2;
- const int cmp = stricmp(name,list[b].name);
- if (cmp > 0) a = b+1;
- else if (cmp < 0) c = b;
- else
- {
- *ismatch = 1;
- return b;
- }
- }
- *ismatch = 0;
- return a;
- }
- static int funcTypeCmp(const void *a, const void *b) { return stricmp(((functionType*)a)->name,((functionType*)b)->name); }
- functionType *nseel_getFunctionByName(compileContext *ctx, const char *name, int *mchk)
- {
- eel_function_table *tab = ctx && ctx->registered_func_tab ? ctx->registered_func_tab : &default_user_funcs;
- static char sorted;
- const int fn1size = (int) (sizeof(fnTable1)/sizeof(fnTable1[0]));
- int idx,match;
- if (!sorted)
- {
- NSEEL_HOSTSTUB_EnterMutex();
- if (!sorted) qsort(fnTable1,fn1size,sizeof(fnTable1[0]),funcTypeCmp);
- sorted=1;
- NSEEL_HOSTSTUB_LeaveMutex();
- }
- idx=functable_lowerbound(fnTable1,fn1size,name,&match);
- if (match) return fnTable1+idx;
- if ((!ctx || !(ctx->current_compile_flags&NSEEL_CODE_COMPILE_FLAG_ONLY_BUILTIN_FUNCTIONS)) && tab->list)
- {
- idx=functable_lowerbound(tab->list,tab->list_size,name,&match);
- if (match)
- {
- if (mchk)
- {
- while (idx>0 && !stricmp(tab->list[idx-1].name,name)) idx--;
- *mchk = tab->list_size - 1 - idx;
- }
- return tab->list + idx;
- }
- }
- return NULL;
- }
- int NSEEL_init() // returns 0 on success
- {
- #ifdef EEL_VALIDATE_FSTUBS
- int a;
- for (a=0;a < sizeof(fnTable1)/sizeof(fnTable1[0]);a++)
- {
- char *code_startaddr = (char*)fnTable1[a].afunc;
- char *endp = (char *)fnTable1[a].func_e;
- // validate
- int sz=0;
- char *f=(char *)GLUE_realAddress(code_startaddr,endp,&sz);
- if (f+sz > endp)
- {
- #ifdef _WIN32
- OutputDebugString("bad eel function stub\n");
- #else
- printf("bad eel function stub\n");
- #endif
- *(char *)NULL = 0;
- }
- }
- #ifdef _WIN32
- OutputDebugString("eel function stub (builtin) validation complete\n");
- #else
- printf("eel function stub (builtin) validation complete\n");
- #endif
- #endif
- NSEEL_quit();
- return 0;
- }
- void NSEEL_quit()
- {
- free(default_user_funcs.list);
- default_user_funcs.list = NULL;
- default_user_funcs.list_size = 0;
- }
- void NSEEL_addfunc_varparm_ex(const char *name, int min_np, int want_exact, NSEEL_PPPROC pproc, EEL_F (NSEEL_CGEN_CALL *fptr)(void *, INT_PTR, EEL_F **), eel_function_table *destination)
- {
- const int sz = (int) ((char *)_asm_generic2parm_retd_end-(char *)_asm_generic2parm_retd);
- NSEEL_addfunctionex2(name,min_np|(want_exact?BIF_TAKES_VARPARM_EX:BIF_TAKES_VARPARM),(char *)_asm_generic2parm_retd,sz,pproc,fptr,NULL,destination);
- }
- void NSEEL_addfunc_ret_type(const char *name, int np, int ret_type, NSEEL_PPPROC pproc, void *fptr, eel_function_table *destination) // ret_type=-1 for bool, 1 for value, 0 for ptr
- {
- char *stub=NULL;
- int stubsz=0;
- #define DOSTUB(np) { \
- stub = (ret_type == 1 ? (char*)_asm_generic##np##parm_retd : (char*)_asm_generic##np##parm); \
- stubsz = (int) ((ret_type == 1 ? (char*)_asm_generic##np##parm_retd_end : (char *)_asm_generic##np##parm_end) - stub); \
- }
- if (np == 1) DOSTUB(1)
- else if (np == 2) DOSTUB(2)
- else if (np == 3) DOSTUB(3)
- #undef DOSTUB
- if (stub) NSEEL_addfunctionex2(name,np|(ret_type == -1 ? BIF_RETURNSBOOL:0), stub, stubsz, pproc,fptr,NULL,destination);
- }
- void NSEEL_addfunctionex2(const char *name, int nparms, char *code_startaddr, int code_len, NSEEL_PPPROC pproc, void *fptr, void *fptr2, eel_function_table *destination)
- {
- const int list_size_chunk = 128;
- functionType *r;
- if (!destination) destination = &default_user_funcs;
- if (!destination->list || !(destination->list_size & (list_size_chunk-1)))
- {
- void *nv = realloc(destination->list, (destination->list_size + list_size_chunk)*sizeof(functionType));
- if (!nv) return;
- destination->list = (functionType *)nv;
- }
- if (destination->list)
- {
- int match,idx;
- idx=functable_lowerbound(destination->list,destination->list_size,name,&match);
- #ifdef EEL_VALIDATE_FSTUBS
- {
- char *endp = code_startaddr+code_len;
- // validate
- int sz=0;
- char *f=(char *)GLUE_realAddress(code_startaddr,endp,&sz);
- if (f+sz > endp)
- {
- #ifdef _WIN32
- OutputDebugString("bad eel function stub\n");
- #else
- printf("bad eel function stub\n");
- #endif
- *(char *)NULL = 0;
- }
- #ifdef _WIN32
- OutputDebugString(name);
- OutputDebugString(" - validated eel function stub\n");
- #else
- printf("eel function stub validation complete for %s\n",name);
- #endif
- }
- #endif
- r = destination->list + idx;
- if (idx < destination->list_size)
- memmove(r + 1, r, (destination->list_size - idx) * sizeof(functionType));
- destination->list_size++;
- memset(r, 0, sizeof(functionType));
- if (!(nparms & BIF_RETURNSBOOL))
- {
- if (code_startaddr == (void *)&_asm_generic1parm_retd ||
- code_startaddr == (void *)&_asm_generic2parm_retd ||
- code_startaddr == (void *)&_asm_generic3parm_retd)
- {
- nparms |= BIF_RETURNSONSTACK;
- }
- }
- r->nParams = nparms;
- r->name = name;
- r->afunc = code_startaddr;
- r->func_e = code_startaddr + code_len;
- r->pProc = pproc;
- r->replptrs[0] = fptr;
- r->replptrs[1] = fptr2;
- }
- }
- //---------------------------------------------------------------------------------------------------------------
- static void freeBlocks(llBlock **start)
- {
- llBlock *s=*start;
- *start=0;
- while (s)
- {
- llBlock *llB = s->next;
- free(s);
- s=llB;
- }
- }
- //---------------------------------------------------------------------------------------------------------------
- static void *__newBlock(llBlock **start, int size, int wantMprotect)
- {
- #if !defined(EEL_DOESNT_NEED_EXEC_PERMS) && defined(_WIN32)
- DWORD ov;
- UINT_PTR offs,eoffs;
- #endif
- llBlock *llb;
- int alloc_size;
- if (*start && (LLB_DSIZE - (*start)->sizeused) >= size)
- {
- void *t=(*start)->block+(*start)->sizeused;
- (*start)->sizeused+=(size+7)&~7;
- return t;
- }
- alloc_size=sizeof(llBlock);
- if ((int)size > LLB_DSIZE) alloc_size += size - LLB_DSIZE;
- llb = (llBlock *)malloc(alloc_size); // grab bigger block if absolutely necessary (heh)
- if (!llb) return NULL;
-
- #ifndef EEL_DOESNT_NEED_EXEC_PERMS
- if (wantMprotect)
- {
- #ifdef _WIN32
- offs=((UINT_PTR)llb)&~4095;
- eoffs=((UINT_PTR)llb + alloc_size + 4095)&~4095;
- VirtualProtect((LPVOID)offs,eoffs-offs,PAGE_EXECUTE_READWRITE,&ov);
- // MessageBox(NULL,"vprotecting, yay\n","a",0);
- #else
- {
- static int pagesize = 0;
- if (!pagesize)
- {
- pagesize=sysconf(_SC_PAGESIZE);
- if (!pagesize) pagesize=4096;
- }
- uintptr_t offs,eoffs;
- offs=((uintptr_t)llb)&~(pagesize-1);
- eoffs=((uintptr_t)llb + alloc_size + pagesize-1)&~(pagesize-1);
- mprotect((void*)offs,eoffs-offs,PROT_WRITE|PROT_READ|PROT_EXEC);
- }
- #endif
- }
- #endif
- llb->sizeused=(size+7)&~7;
- llb->next = *start;
- *start = llb;
- return llb->block;
- }
- //---------------------------------------------------------------------------------------------------------------
- opcodeRec *nseel_createCompiledValue(compileContext *ctx, EEL_F value)
- {
- opcodeRec *r=newOpCode(ctx,NULL,OPCODETYPE_DIRECTVALUE);
- if (r)
- {
- r->parms.dv.directValue = value;
- }
- return r;
- }
- opcodeRec *nseel_createCompiledValuePtr(compileContext *ctx, EEL_F *addrValue, const char *namestr)
- {
- opcodeRec *r=newOpCode(ctx,namestr,OPCODETYPE_VARPTR);
- if (!r) return 0;
- r->parms.dv.valuePtr=addrValue;
- return r;
- }
- static int validate_varname_for_function(compileContext *ctx, const char *name)
- {
- if (!ctx->function_curName || !ctx->function_globalFlag) return 1;
- if (ctx->function_localTable_Size[2] > 0 && ctx->function_localTable_Names[2])
- {
- char * const * const namelist = ctx->function_localTable_Names[2];
- const int namelist_sz = ctx->function_localTable_Size[2];
- int i;
- const size_t name_len = strlen(name);
- for (i=0;i<namelist_sz;i++)
- {
- const char *nmchk=namelist[i];
- const size_t l = strlen(nmchk);
- if (l > 1 && nmchk[l-1] == '*')
- {
- if (name_len >= l && !strnicmp(nmchk,name,l-1) && name[l-1]=='.') return 1;
- }
- else
- {
- if (name_len == l && !stricmp(nmchk,name)) return 1;
- }
- }
- }
- return 0;
- }
- opcodeRec *nseel_resolve_named_symbol(compileContext *ctx, opcodeRec *rec, int parmcnt, int *errOut)
- {
- const int isFunctionMode = parmcnt >= 0;
- int rel_prefix_len=0;
- int rel_prefix_idx=-2;
- int i;
- char match_parmcnt[4]={-1,-1,-1,-1}; // [3] is guess
- unsigned char match_parmcnt_pos=0;
- char *sname = (char *)rec->relname;
- int is_string_prefix = parmcnt < 0 && sname[0] == '#';
- const char *prevent_function_calls = NULL;
- if (errOut) *errOut = 0;
- if (sname) sname += is_string_prefix;
- if (rec->opcodeType != OPCODETYPE_VARPTR || !sname || !sname[0]) return NULL;
- if (!isFunctionMode && !is_string_prefix && !strnicmp(sname,"reg",3) && isdigit(sname[3]) && isdigit(sname[4]) && !sname[5])
- {
- EEL_F *a=get_global_var(ctx,sname,1);
- if (a)
- {
- rec->parms.dv.valuePtr = a;
- sname[0]=0; // for dump_ops compat really, but this shouldn't be needed anyway
- }
- return rec;
- }
- if (ctx->function_curName)
- {
- if (!strnicmp(sname,"this.",5))
- {
- rel_prefix_len=5;
- rel_prefix_idx=-1;
- }
- else if (!stricmp(sname,"this"))
- {
- rel_prefix_len=4;
- rel_prefix_idx=-1;
- }
-
- // scan for parameters/local variables before user functions
- if (rel_prefix_idx < -1 &&
- ctx->function_localTable_Size[0] > 0 &&
- ctx->function_localTable_Names[0] &&
- ctx->function_localTable_ValuePtrs)
- {
- char * const * const namelist = ctx->function_localTable_Names[0];
- const int namelist_sz = ctx->function_localTable_Size[0];
- for (i=0; i < namelist_sz; i++)
- {
- const char *p = namelist[i];
- if (p)
- {
- if (!isFunctionMode && !is_string_prefix && !strnicmp(p,sname,NSEEL_MAX_VARIABLE_NAMELEN))
- {
- rec->opcodeType = OPCODETYPE_VARPTRPTR;
- rec->parms.dv.valuePtr=(EEL_F *)(ctx->function_localTable_ValuePtrs+i);
- rec->parms.dv.directValue=0.0;
- return rec;
- }
- else
- {
- const size_t plen = strlen(p);
- if (plen > 1 && p[plen-1] == '*' && !strnicmp(p,sname,plen-1) && ((sname[plen-1] == '.'&&sname[plen]) || !sname[plen-1]))
- {
- rel_prefix_len=(int) (sname[plen-1] ? plen : plen-1);
- rel_prefix_idx=i;
- break;
- }
- }
- }
- }
- }
- // if instance name set, translate sname or sname.* into "this.sname.*"
- if (rel_prefix_idx < -1 &&
- ctx->function_localTable_Size[1] > 0 &&
- ctx->function_localTable_Names[1])
- {
- char * const * const namelist = ctx->function_localTable_Names[1];
- const int namelist_sz = ctx->function_localTable_Size[1];
- const char *full_sname = rec->relname; // include # in checks
- for (i=0; i < namelist_sz; i++)
- {
- const char *p = namelist[i];
- if (p && *p)
- {
- const size_t tl = strlen(p);
- if (!strnicmp(p,full_sname,tl) && (full_sname[tl] == 0 || full_sname[tl] == '.'))
- {
- rel_prefix_len=0; // treat as though this. prefixes is present
- rel_prefix_idx=-1;
- break;
- }
- }
- }
- }
- if (rel_prefix_idx >= -1)
- {
- ctx->function_usesNamespaces=1;
- }
- } // ctx->function_curName
- if (!isFunctionMode)
- {
- // instance variables
- if (rel_prefix_idx >= -1)
- {
- rec->opcodeType = OPCODETYPE_VALUE_FROM_NAMESPACENAME;
- rec->namespaceidx = rel_prefix_idx;
- if (rel_prefix_len > 0)
- {
- if (is_string_prefix) sname[-1] = '#';
- memmove(sname, sname+rel_prefix_len, strlen(sname + rel_prefix_len) + 1);
- }
- }
- else
- {
- // no namespace index, so it must be a global
- if (!validate_varname_for_function(ctx,rec->relname))
- {
- if (errOut) *errOut = 1;
- if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string));
- snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"global '%s' inaccessible",rec->relname);
- return NULL;
- }
- }
-
- return rec;
- }
- if (ctx->func_check)
- prevent_function_calls = ctx->func_check(sname,ctx->func_check_user);
-
- ////////// function mode
- // first off, while() and loop() are special and can't be overridden
- //
- if (parmcnt == 1 && !stricmp("while",sname) && !prevent_function_calls)
- {
- rec->opcodeType = OPCODETYPE_FUNC1;
- rec->fntype = FN_WHILE;
- return rec;
- }
- if (parmcnt == 2 && !stricmp("loop",sname) && !prevent_function_calls)
- {
- rec->opcodeType = OPCODETYPE_FUNC2;
- rec->fntype = FN_LOOP;
- return rec;
- }
-
- //
- // resolve user function names before builtin functions -- this allows the user to override default functions
- if (!(ctx->current_compile_flags & NSEEL_CODE_COMPILE_FLAG_ONLY_BUILTIN_FUNCTIONS))
- {
- _codeHandleFunctionRec *best=NULL;
- size_t bestlen=0;
- const char * const ourcall = sname+rel_prefix_len;
- const size_t ourcall_len = strlen(ourcall);
- int pass;
- for (pass=0;pass<2;pass++)
- {
- _codeHandleFunctionRec *fr = pass ? ctx->functions_common : ctx->functions_local;
- // sname is [namespace.[ns.]]function, find best match of function that matches the right end
- while (fr)
- {
- int this_np = fr->num_params;
- const char *thisfunc = fr->fname;
- const size_t thisfunc_len = strlen(thisfunc);
- if (this_np < 1) this_np=1;
- if (thisfunc_len == ourcall_len && !stricmp(thisfunc,ourcall))
- {
- if (this_np == parmcnt)
- {
- bestlen = thisfunc_len;
- best = fr;
- break; // found exact match, finished
- }
- else
- {
- if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = fr->num_params;
- }
- }
- if (thisfunc_len > bestlen && thisfunc_len < ourcall_len && ourcall[ourcall_len - thisfunc_len - 1] == '.' && !stricmp(thisfunc,ourcall + ourcall_len - thisfunc_len))
- {
- if (this_np == parmcnt)
- {
- bestlen = thisfunc_len;
- best = fr;
- }
- else
- if (match_parmcnt[3]<0) match_parmcnt[3]=fr->num_params;
- }
- fr=fr->next;
- }
- if (fr) break; // found exact match, finished
- }
-
- if (best)
- {
- switch (parmcnt)
- {
- case 0:
- case 1: rec->opcodeType = OPCODETYPE_FUNC1; break;
- case 2: rec->opcodeType = OPCODETYPE_FUNC2; break;
- case 3: rec->opcodeType = OPCODETYPE_FUNC3; break;
- default: rec->opcodeType = OPCODETYPE_FUNCX; break;
- }
- if (ourcall != rec->relname) memmove((char *)rec->relname, ourcall, strlen(ourcall)+1);
- if (ctx->function_curName && rel_prefix_idx<0)
- {
- // if no namespace specified, and this.commonprefix.func() called, remove common prefixes and set prefixidx to be this
- const char *p=ctx->function_curName;
- if (*p) p++;
- while (*p && *p != '.') p++;
- if (*p && p[1]) // we have a dot!
- {
- while (p[1]) p++; // go to last char of string, which doesn't allow possible trailing dot to be checked
- while (--p > ctx->function_curName) // do not check possible leading dot
- {
- if (*p == '.')
- {
- const size_t cmplen = p+1-ctx->function_curName;
- if (!strnicmp(rec->relname,ctx->function_curName,cmplen) && rec->relname[cmplen])
- {
- const char *src=rec->relname + cmplen;
- memmove((char *)rec->relname, src, strlen(src)+1);
- rel_prefix_idx=-1;
- ctx->function_usesNamespaces=1;
- break;
- }
- }
- }
- }
- }
- if (ctx->function_curName && rel_prefix_idx < -1 &&
- strchr(rec->relname,'.') && !validate_varname_for_function(ctx,rec->relname))
- {
- if (errOut) *errOut = 1;
- if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string));
- snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"namespaced function '%s' inaccessible",rec->relname);
- return NULL;
- }
- rec->namespaceidx = rel_prefix_idx;
- rec->fntype = FUNCTYPE_EELFUNC;
- rec->fn = best;
- return rec;
- }
- }
- if (prevent_function_calls)
- {
- if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string));
- snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"'%.30s': %s",sname, prevent_function_calls);
- if (errOut) *errOut = 0;
- return NULL;
- }
- #ifdef NSEEL_EEL1_COMPAT_MODE
- if (!stricmp(sname,"assign"))
- {
- if (parmcnt == 2)
- {
- rec->opcodeType = OPCODETYPE_FUNC2;
- rec->fntype = FN_ASSIGN;
- return rec;
- }
- if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2;
- }
- else if (!stricmp(sname,"if"))
- {
- if (parmcnt == 3)
- {
- rec->opcodeType = OPCODETYPE_FUNC3;
- rec->fntype = FN_IF_ELSE;
- return rec;
- }
- if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 3;
- }
- else if (!stricmp(sname,"equal"))
- {
- if (parmcnt == 2)
- {
- rec->opcodeType = OPCODETYPE_FUNC2;
- rec->fntype = FN_EQ;
- return rec;
- }
- if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2;
- }
- else if (!stricmp(sname,"below"))
- {
- if (parmcnt == 2)
- {
- rec->opcodeType = OPCODETYPE_FUNC2;
- rec->fntype = FN_LT;
- return rec;
- }
- if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2;
- }
- else if (!stricmp(sname,"above"))
- {
- if (parmcnt == 2)
- {
- rec->opcodeType = OPCODETYPE_FUNC2;
- rec->fntype = FN_GT;
- return rec;
- }
- if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2;
- }
- else if (!stricmp(sname,"bnot"))
- {
- if (parmcnt == 1)
- {
- rec->opcodeType = OPCODETYPE_FUNC1;
- rec->fntype = FN_NOT;
- return rec;
- }
- if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 1;
- }
- else if (!stricmp(sname,"megabuf"))
- {
- if (parmcnt == 1)
- {
- rec->opcodeType = OPCODETYPE_FUNC1;
- rec->fntype = FN_MEMORY;
- return rec;
- }
- if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 1;
- }
- else if (!stricmp(sname,"gmegabuf"))
- {
- if (parmcnt == 1)
- {
- rec->opcodeType = OPCODETYPE_FUNC1;
- rec->fntype = FN_GMEMORY;
- return rec;
- }
- if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 1;
- }
- else
- #endif
- // convert legacy pow() to FN_POW
- if (!stricmp("pow",sname))
- {
- if (parmcnt == 2)
- {
- rec->opcodeType = OPCODETYPE_FUNC2;
- rec->fntype = FN_POW;
- return rec;
- }
- if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2;
- }
- else if (!stricmp("__denormal_likely",sname) || !stricmp("__denormal_unlikely",sname))
- {
- if (parmcnt == 1)
- {
- rec->opcodeType = OPCODETYPE_FUNC1;
- rec->fntype = !stricmp("__denormal_likely",sname) ? FN_DENORMAL_LIKELY : FN_DENORMAL_UNLIKELY;
- return rec;
- }
- }
-
- {
- int chkamt=0;
- functionType *f=nseel_getFunctionByName(ctx,sname,&chkamt);
- if (f) while (chkamt-->=0)
- {
- const int pc_needed=(f->nParams&FUNCTIONTYPE_PARAMETERCOUNTMASK);
- if ((f->nParams&BIF_TAKES_VARPARM_EX)==BIF_TAKES_VARPARM ? (parmcnt >= pc_needed) : (parmcnt == pc_needed))
- {
- rec->fntype = FUNCTYPE_FUNCTIONTYPEREC;
- rec->fn = (void *)f;
- switch (parmcnt)
- {
- case 0:
- case 1: rec->opcodeType = OPCODETYPE_FUNC1; break;
- case 2: rec->opcodeType = OPCODETYPE_FUNC2; break;
- case 3: rec->opcodeType = OPCODETYPE_FUNC3; break;
- default: rec->opcodeType = OPCODETYPE_FUNCX; break;
- }
- return rec;
- }
- if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = (f->nParams&FUNCTIONTYPE_PARAMETERCOUNTMASK);
- f++;
- if (stricmp(f->name,sname)) break;
- }
- }
- if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string));
- if (match_parmcnt[3] >= 0)
- {
- if (match_parmcnt_pos<3) match_parmcnt[match_parmcnt_pos] = match_parmcnt[3];
- match_parmcnt_pos++;
- }
- if (!match_parmcnt_pos)
- snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"'%.30s' undefined",sname);
- else
- {
- int x;
- snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"'%.30s' needs ",sname);
- for (x = 0; x < match_parmcnt_pos; x++)
- snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"%s%d",x==0?"" : x == match_parmcnt_pos-1?" or ":",",match_parmcnt[x]);
- lstrcatn(ctx->last_error_string," parms",sizeof(ctx->last_error_string));
- }
- if (errOut) *errOut = match_parmcnt_pos > 0 ? parmcnt<match_parmcnt[0]?2:(match_parmcnt[0] < 2 ? 4:1) : 0;
- return NULL;
- }
- opcodeRec *nseel_setCompiledFunctionCallParameters(compileContext *ctx, opcodeRec *fn, opcodeRec *code1, opcodeRec *code2, opcodeRec *code3, opcodeRec *postCode, int *errOut)
- {
- opcodeRec *r;
- int np=0,x;
- if (!fn || fn->opcodeType != OPCODETYPE_VARPTR || !fn->relname || !fn->relname[0])
- {
- return NULL;
- }
- fn->parms.parms[0] = code1;
- fn->parms.parms[1] = code2;
- fn->parms.parms[2] = code3;
- for (x=0;x<3;x++)
- {
- opcodeRec *prni=fn->parms.parms[x];
- while (prni && np < NSEEL_MAX_EELFUNC_PARAMETERS)
- {
- const int isMP = prni->opcodeType == OPCODETYPE_MOREPARAMS;
- np++;
- if (!isMP) break;
- prni = prni->parms.parms[1];
- }
- }
- r = nseel_resolve_named_symbol(ctx, fn, np<1 ? 1 : np ,errOut);
- if (postCode && r)
- {
- if (code1 && r->opcodeType == OPCODETYPE_FUNC1 && r->fntype == FN_WHILE)
- {
- // change while(x) (postcode) to be
- // while ((x) ? (postcode;1) : 0);
-
- r->parms.parms[0] =
- nseel_createIfElse(ctx,r->parms.parms[0],
- nseel_createSimpleCompiledFunction(ctx,FN_JOIN_STATEMENTS,2,postCode,nseel_createCompiledValue(ctx,1.0f)),
- NULL); // NULL defaults to 0.0
-
- }
- else
- {
- snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"syntax error following function");
- *errOut = -1;
- return NULL;
- }
- }
- return r;
- }
- struct eelStringSegmentRec *nseel_createStringSegmentRec(compileContext *ctx, const char *str, int len)
- {
- struct eelStringSegmentRec *r = newTmpBlock(ctx,sizeof(struct eelStringSegmentRec));
- if (r)
- {
- r->_next=0;
- r->str_start=str;
- r->str_len = len;
- }
- return r;
- }
- opcodeRec *nseel_eelMakeOpcodeFromStringSegments(compileContext *ctx, struct eelStringSegmentRec *rec)
- {
- if (ctx && ctx->onString)
- {
- return nseel_createCompiledValue(ctx, ctx->onString(ctx->caller_this,rec));
- }
- return NULL;
- }
- opcodeRec *nseel_createMoreParametersOpcode(compileContext *ctx, opcodeRec *code1, opcodeRec *code2)
- {
- opcodeRec *r=code1 && code2 ? newOpCode(ctx,NULL,OPCODETYPE_MOREPARAMS) : NULL;
- if (r)
- {
- r->parms.parms[0] = code1;
- r->parms.parms[1] = code2;
- }
- return r;
- }
- opcodeRec *nseel_createIfElse(compileContext *ctx, opcodeRec *code1, opcodeRec *code2, opcodeRec *code3)
- {
- opcodeRec *r=code1 ? newOpCode(ctx,NULL,OPCODETYPE_FUNC3) : NULL;
- if (r)
- {
- if (!code2) code2 = nseel_createCompiledValue(ctx,0.0);
- if (!code3) code3 = nseel_createCompiledValue(ctx,0.0);
- if (!code2||!code3) return NULL;
- r->fntype = FN_IF_ELSE;
- r->parms.parms[0] = code1;
- r->parms.parms[1] = code2;
- r->parms.parms[2] = code3;
- }
- return r;
- }
- opcodeRec *nseel_createMemoryAccess(compileContext *ctx, opcodeRec *code1, opcodeRec *code2)
- {
- if (code1 && code1->opcodeType == OPCODETYPE_VARPTR && !stricmp(code1->relname,"gmem"))
- {
- return nseel_createSimpleCompiledFunction(ctx, FN_GMEMORY,1,code2?code2:nseel_createCompiledValue(ctx,0.0),0);
- }
- if (code2 && (code2->opcodeType != OPCODETYPE_DIRECTVALUE || code2->parms.dv.directValue != 0.0))
- {
- code1 = nseel_createSimpleCompiledFunction(ctx,FN_ADD,2,code1,code2);
- }
- return nseel_createSimpleCompiledFunction(ctx, FN_MEMORY,1,code1,0);
- }
- opcodeRec *nseel_createSimpleCompiledFunction(compileContext *ctx, int fn, int np, opcodeRec *code1, opcodeRec *code2)
- {
- opcodeRec *r=code1 && (np<2 || code2) ? newOpCode(ctx,NULL,np>=2 ? OPCODETYPE_FUNC2:OPCODETYPE_FUNC1) : NULL;
- if (r)
- {
- r->fntype = fn;
- r->parms.parms[0] = code1;
- r->parms.parms[1] = code2;
- if (fn == FN_JOIN_STATEMENTS)
- {
- r->fn = r; // for joins, fn is temporarily used for _tail pointers
- if (code1 && code1->opcodeType == OPCODETYPE_FUNC2 && code1->fntype == fn)
- {
- opcodeRec *t = (opcodeRec *)code1->fn;
- // keep joins in the form of dosomething->morestuff.
- // in this instance, code1 is previous stuff to do, code2 is new stuff to do
- r->parms.parms[0] = t->parms.parms[1];
- code1->fn = (t->parms.parms[1] = r);
- return code1;
- }
- }
- }
- return r;
- }
- // these are bitmasks; on request you can tell what is supported, and compileOpcodes will return one of them
- #define RETURNVALUE_IGNORE 0 // ignore return value
- #define RETURNVALUE_NORMAL 1 // pointer
- #define RETURNVALUE_FPSTACK 2
- #define RETURNVALUE_BOOL 4 // P1 is nonzero if true
- #define RETURNVALUE_BOOL_REVERSED 8 // P1 is zero if true
- #define RETURNVALUE_CACHEABLE 16 // only to be used when (at least) RETURNVALUE_NORMAL is set
- static int compileOpcodes(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTable, const namespaceInformation *namespacePathToThis,
- int supportedReturnValues, int *rvType, int *fpStackUsage, int *canHaveDenormalOutput);
- static unsigned char *compileCodeBlockWithRet(compileContext *ctx, opcodeRec *rec, int *computTableSize, const namespaceInformation *namespacePathToThis,
- int supportedReturnValues, int *rvType, int *fpStackUse, int *canHaveDenormalOutput);
- _codeHandleFunctionRec *eel_createFunctionNamespacedInstance(compileContext *ctx, _codeHandleFunctionRec *fr, const char *nameptr)
- {
- size_t n;
- _codeHandleFunctionRec *subfr =
- fr->isCommonFunction ?
- ctx->isSharedFunctions ? newDataBlock(sizeof(_codeHandleFunctionRec),8) :
- newCtxDataBlock(sizeof(_codeHandleFunctionRec),8) : // if common function, but derived version is in non-common context, set ownership to VM rather than us
- newTmpBlock(ctx,sizeof(_codeHandleFunctionRec));
- if (!subfr) return 0;
- // fr points to functionname()'s rec, nameptr to blah.functionname()
- *subfr = *fr;
- n = strlen(nameptr);
- if (n > sizeof(subfr->fname)-1) n=sizeof(subfr->fname)-1;
- memcpy(subfr->fname,nameptr,n);
- subfr->fname[n]=0;
- subfr->next = NULL;
- subfr->startptr=0; // make sure this code gets recompiled (with correct member ptrs) for this instance!
- subfr->startptr_size=-1;
- // subfr->derivedCopies already points to the right place
- fr->derivedCopies = subfr;
-
- return subfr;
- }
- static void combineNamespaceFields(char *nm, const namespaceInformation *namespaceInfo, const char *relname, int thisctx) // nm must be NSEEL_MAX_VARIABLE_NAMELEN+1 bytes
- {
- const char *prefix = namespaceInfo ?
- thisctx<0 ? (thisctx == -1 ? namespaceInfo->namespacePathToThis : NULL) : (thisctx < MAX_SUB_NAMESPACES ? namespaceInfo->subParmInfo[thisctx] : NULL)
- : NULL;
- int lfp = 0, lrn=relname ? (int)strlen(relname) : 0;
- if (prefix) while (prefix[lfp] && prefix[lfp] != ':' && lfp < NSEEL_MAX_VARIABLE_NAMELEN) lfp++;
- if (!relname) relname = "";
- while (*relname == '.') // if relname begins with ., then remove a chunk of context from prefix
- {
- relname++;
- while (lfp>0 && prefix[lfp-1] != '.') lfp--;
- if (lfp>0) lfp--;
- }
- if (lfp > NSEEL_MAX_VARIABLE_NAMELEN-3) lfp=NSEEL_MAX_VARIABLE_NAMELEN-3;
- if (lfp>0) memcpy(nm,prefix,lfp);
- if (lrn > NSEEL_MAX_VARIABLE_NAMELEN - lfp - (lfp>0)) lrn=NSEEL_MAX_VARIABLE_NAMELEN - lfp - (lfp>0);
- if (lrn > 0)
- {
- if (lfp>0) nm[lfp++] = '.';
- memcpy(nm+lfp,relname,lrn);
- lfp+=lrn;
- }
- nm[lfp++]=0;
- }
- //---------------------------------------------------------------------------------------------------------------
- static void *nseel_getBuiltinFunctionAddress(compileContext *ctx,
- int fntype, void *fn,
- NSEEL_PPPROC *pProc, void ***replList,
- void **endP, int *abiInfo, int preferredReturnValues, const EEL_F *hasConstParm1, const EEL_F *hasConstParm2)
- {
- const EEL_F *firstConstParm = hasConstParm1 ? hasConstParm1 : hasConstParm2;
- static void *pow_replptrs[4]={&pow,};
- switch (fntype)
- {
- #define RF(x) *endP = nseel_asm_##x##_end; return (void*)nseel_asm_##x
- case FN_MUL_OP:
- *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
- RF(mul_op);
- case FN_DIV_OP:
- *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
- RF(div_op);
- case FN_OR_OP:
- *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
- RF(or_op);
- case FN_XOR_OP:
- *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
- RF(xor_op);
- case FN_AND_OP:
- *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
- RF(and_op);
- case FN_MOD_OP:
- *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
- RF(mod_op);
- case FN_ADD_OP:
- *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
- RF(add_op);
- case FN_SUB_OP:
- *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
- RF(sub_op);
- case FN_POW_OP:
- *abiInfo=BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL;
- *replList = pow_replptrs;
- RF(2pdds);
- case FN_POW:
- *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK;//BIF_FPSTACKUSE(2) might be safe, need to look at pow()'s implementation, but safer bet is to disallow fp stack caching for this expression
- *replList = pow_replptrs;
- RF(2pdd);
- case FN_ADD:
- *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2);
- // for x +- non-denormal-constant, we can set BIF_CLEARDENORMAL
- if (firstConstParm && fabs(*firstConstParm) > DENORMAL_CLEARING_THRESHOLD) *abiInfo |= BIF_CLEARDENORMAL;
- RF(add);
- case FN_SUB:
- *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(2);
- // for x +- non-denormal-constant, we can set BIF_CLEARDENORMAL
- if (firstConstParm && fabs(*firstConstParm) > DENORMAL_CLEARING_THRESHOLD) *abiInfo |= BIF_CLEARDENORMAL;
- RF(sub);
- case FN_MULTIPLY:
- *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2);
- // for x*constant-greater-than-eq-1, we can set BIF_WONTMAKEDENORMAL
- if (firstConstParm && fabs(*firstConstParm) >= 1.0) *abiInfo |= BIF_WONTMAKEDENORMAL;
- RF(mul);
- case FN_DIVIDE:
- *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(2);
- // for x/constant-less-than-eq-1, we can set BIF_WONTMAKEDENORMAL
- if (firstConstParm && fabs(*firstConstParm) <= 1.0) *abiInfo |= BIF_WONTMAKEDENORMAL;
- RF(div);
- case FN_MOD:
- *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(1)|BIF_CLEARDENORMAL;
- RF(mod);
- case FN_ASSIGN:
- *abiInfo = BIF_FPSTACKUSE(1)|BIF_CLEARDENORMAL;
- RF(assign);
- case FN_AND: *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; RF(and);
- case FN_OR: *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; RF(or);
- case FN_XOR:
- *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
- RF(xor);
- case FN_SHR:
- *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
- RF(shr);
- case FN_SHL:
- *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL;
- RF(shl);
- #ifndef EEL_TARGET_PORTABLE
- case FN_NOTNOT: *abiInfo = BIF_LASTPARM_ASBOOL|BIF_RETURNSBOOL|BIF_FPSTACKUSE(1); RF(uplus);
- #else
- case FN_NOTNOT: *abiInfo = BIF_LASTPARM_ASBOOL|BIF_RETURNSBOOL|BIF_FPSTACKUSE(1); RF(bnotnot);
- #endif
- case FN_UMINUS: *abiInfo = BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_WONTMAKEDENORMAL; RF(uminus);
- case FN_NOT: *abiInfo = BIF_LASTPARM_ASBOOL|BIF_RETURNSBOOL|BIF_FPSTACKUSE(1); RF(bnot);
- case FN_EQ:
- *abiInfo = BIF_TWOPARMSONFPSTACK_LAZY|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2);
- RF(equal);
- case FN_EQ_EXACT:
- *abiInfo=BIF_TWOPARMSONFPSTACK_LAZY|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2);
- RF(equal_exact);
- case FN_NE:
- *abiInfo=BIF_TWOPARMSONFPSTACK_LAZY|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2);
- RF(notequal);
- case FN_NE_EXACT:
- *abiInfo=BIF_TWOPARMSONFPSTACK_LAZY|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2);
- RF(notequal_exact);
- case FN_LOGICAL_AND:
- *abiInfo = BIF_RETURNSBOOL;
- RF(band);
- case FN_LOGICAL_OR:
- *abiInfo = BIF_RETURNSBOOL;
- RF(bor);
- #ifdef GLUE_HAS_FXCH
- case FN_GT:
- *abiInfo = BIF_TWOPARMSONFPSTACK|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2);
- RF(above);
- case FN_GTE:
- *abiInfo = BIF_TWOPARMSONFPSTACK|BIF_RETURNSBOOL|BIF_REVERSEFPORDER|BIF_FPSTACKUSE(2);
- RF(beloweq);
- case FN_LT:
- *abiInfo = BIF_TWOPARMSONFPSTACK|BIF_RETURNSBOOL|BIF_REVERSEFPORDER|BIF_FPSTACKUSE(2);
- RF(above);
- case FN_LTE:
- *abiInfo = BIF_TWOPARMSONFPSTACK|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2);
- RF(beloweq);
- #else
- case FN_GT:
- *abiInfo = BIF_RETURNSBOOL|BIF_LASTPARMONSTACK;
- RF(above);
- case FN_GTE:
- *abiInfo = BIF_RETURNSBOOL|BIF_LASTPARMONSTACK;
- RF(aboveeq);
- case FN_LT:
- *abiInfo = BIF_RETURNSBOOL|BIF_LASTPARMONSTACK;
- RF(below);
- case FN_LTE:
- *abiInfo = BIF_RETURNSBOOL|BIF_LASTPARMONSTACK;
- RF(beloweq);
- #endif
- #undef RF
- #define RF(x) *endP = _asm_##x##_end; return (void*)_asm_##x
- case FN_MEMORY:
- {
- static void *replptrs[4]={&__NSEEL_RAMAlloc,};
- *replList = replptrs;
- *abiInfo = BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1)|BIF_CLEARDENORMAL;
- #ifdef GLUE_MEM_NEEDS_PPROC
- *pProc = NSEEL_PProc_RAM;
- #endif
- RF(megabuf);
- }
- break;
- case FN_GMEMORY:
- {
- static void *replptrs[4]={&__NSEEL_RAMAllocGMEM,};
- *replList = replptrs;
- *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1)|BIF_CLEARDENORMAL;
- *pProc=NSEEL_PProc_GRAM;
- RF(gmegabuf);
- }
- break;
- #undef RF
- case FUNCTYPE_FUNCTIONTYPEREC:
- if (fn)
- {
- functionType *p=(functionType *)fn;
- // if prefers fpstack or bool, or ignoring value, then use fp-stack versions
- if ((preferredReturnValues&(RETURNVALUE_BOOL|RETURNVALUE_FPSTACK)) || !preferredReturnValues)
- {
- static functionType min2={ "min", nseel_asm_min_fp,nseel_asm_min_fp_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_WONTMAKEDENORMAL };
- static functionType max2={ "max", nseel_asm_max_fp,nseel_asm_max_fp_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_WONTMAKEDENORMAL };
- if (p->afunc == (void*)nseel_asm_min) p = &min2;
- else if (p->afunc == (void*)nseel_asm_max) p = &max2;
- }
- *replList=p->replptrs;
- *pProc=p->pProc;
- *endP = p->func_e;
- *abiInfo = p->nParams & BIF_NPARAMS_MASK;
- if (firstConstParm)
- {
- const char *name=p->name;
- if (!strcmp(name,"min") && *firstConstParm < -1.0e-10) *abiInfo |= BIF_CLEARDENORMAL;
- else if (!strcmp(name,"max") && *firstConstParm > 1.0e-10) *abiInfo |= BIF_CLEARDENORMAL;
- }
- return p->afunc;
- }
- break;
- }
-
- return 0;
- }
- static void *nseel_getEELFunctionAddress(compileContext *ctx,
- opcodeRec *op,
- int *customFuncParmSize, int *customFuncLocalStorageSize,
- EEL_F ***customFuncLocalStorage, int *computTableTop,
- void **endP, int *isRaw, int wantCodeGenerated,
- const namespaceInformation *namespacePathToThis, int *rvMode, int *fpStackUse, int *canHaveDenormalOutput,
- opcodeRec **ordered_parmptrs, int num_ordered_parmptrs
- ) // if wantCodeGenerated is false, can return bogus pointers in raw mode
- {
- _codeHandleFunctionRec *fn = (_codeHandleFunctionRec*)op->fn;
- namespaceInformation local_namespace={NULL};
- char prefix_buf[NSEEL_MAX_VARIABLE_NAMELEN+1], nm[NSEEL_MAX_FUNCSIG_NAME+1];
- if (!fn) return NULL;
- // op->relname ptr is [whatever.]funcname
- if (fn->parameterAsNamespaceMask || fn->usesNamespaces)
- {
- if (wantCodeGenerated)
- {
- char *p = prefix_buf;
- combineNamespaceFields(nm,namespacePathToThis,op->relname,op->namespaceidx);
- lstrcpyn_safe(prefix_buf,nm,sizeof(prefix_buf));
- local_namespace.namespacePathToThis = prefix_buf;
- // nm is full path of function, prefix_buf will be the path not including function name (unless function name only)
- while (*p) p++;
- while (p >= prefix_buf && *p != '.') p--;
- if (p > prefix_buf) *p=0;
- }
- if (fn->parameterAsNamespaceMask)
- {
- int x;
- for(x=0;x<MAX_SUB_NAMESPACES && x < fn->num_params;x++)
- {
- if (fn->parameterAsNamespaceMask & (((unsigned int)1)<<x))
- {
- if (wantCodeGenerated)
- {
- const char *rn=NULL;
- char tmp[NSEEL_MAX_VARIABLE_NAMELEN+1];
- if (x < num_ordered_parmptrs && ordered_parmptrs[x])
- {
- if (ordered_parmptrs[x]->opcodeType == OPCODETYPE_VARPTR)
- {
- rn=ordered_parmptrs[x]->relname;
- }
- else if (ordered_parmptrs[x]->opcodeType == OPCODETYPE_VALUE_FROM_NAMESPACENAME)
- {
- const char *p=ordered_parmptrs[x]->relname;
- if (*p == '#') p++;
- combineNamespaceFields(tmp,namespacePathToThis,p,ordered_parmptrs[x]->namespaceidx);
- rn = tmp;
- }
- }
-
- if (!rn)
- {
- // todo: figure out how to give correct line number/offset (ugh)
- snprintf(ctx->last_error_string,sizeof(ctx->last_error_string),"parameter %d to %.120s() must be namespace",x+1,fn->fname);
- return NULL;
- }
- lstrcatn(nm,":",sizeof(nm));
- local_namespace.subParmInfo[x] = nm+strlen(nm);
- lstrcatn(nm,rn,sizeof(nm));
- }
- ordered_parmptrs[x] = NULL; // prevent caller from bothering generating parameters
- }
- }
- }
- if (wantCodeGenerated)
- {
- _codeHandleFunctionRec *fr = fn;
- // find namespace-adjusted function (if generating code, otherwise assume size is the same)
- fn = 0; // if this gets re-set, it will be the new function
- while (fr && !fn)
- {
- if (!stricmp(fr->fname,nm)) fn = fr;
- fr=fr->derivedCopies;
- }
- if (!fn) // generate copy of function
- {
- fn = eel_createFunctionNamespacedInstance(ctx,(_codeHandleFunctionRec*)op->fn,nm);
- }
- }
- }
- if (!fn) return NULL;
- if (!fn->startptr && fn->opcodes && fn->startptr_size != 0)
- {
- int sz = fn->startptr_size;
- if (sz < 0)
- {
- fn->tmpspace_req=0;
- fn->rvMode = RETURNVALUE_IGNORE;
- fn->canHaveDenormalOutput=0;
- sz = compileOpcodes(ctx,fn->opcodes,NULL,128*1024*1024,&fn->tmpspace_req,
- wantCodeGenerated ? &local_namespace : NULL,RETURNVALUE_NORMAL|RETURNVALUE_FPSTACK,
- &fn->rvMode,&fn->fpStackUsage,&fn->canHaveDenormalOutput);
- if (sz<0) return NULL;
- fn->startptr_size = sz;
- }
- if (!wantCodeGenerated)
- {
- // don't compile anything for now, just give stats
- if (computTableTop) *computTableTop += fn->tmpspace_req;
- *customFuncParmSize = fn->num_params;
- *customFuncLocalStorage = fn->localstorage;
- *customFuncLocalStorageSize = fn->localstorage_size;
- *rvMode = fn->rvMode;
- *fpStackUse = fn->fpStackUsage;
- if (canHaveDenormalOutput) *canHaveDenormalOutput=fn->canHaveDenormalOutput;
- if (sz <= NSEEL_MAX_FUNCTION_SIZE_FOR_INLINE && !(ctx->optimizeDisableFlags&OPTFLAG_NO_INLINEFUNC))
- {
- *isRaw = 1;
- *endP = ((char *)1) + sz;
- return (char *)1;
- }
- *endP = (void*)nseel_asm_fcall_end;
- return (void*)nseel_asm_fcall;
- }
- if (sz <= NSEEL_MAX_FUNCTION_SIZE_FOR_INLINE && !(ctx->optimizeDisableFlags&OPTFLAG_NO_INLINEFUNC))
- {
- void *p=newTmpBlock(ctx,sz);
- fn->tmpspace_req=0;
- if (p)
- {
- fn->canHaveDenormalOutput=0;
- if (fn->isCommonFunction) ctx->isGeneratingCommonFunction++;
- sz=compileOpcodes(ctx,fn->opcodes,(unsigned char*)p,sz,&fn->tmpspace_req,&local_namespace,RETURNVALUE_NORMAL|RETURNVALUE_FPSTACK,&fn->rvMode,&fn->fpStackUsage,&fn->canHaveDenormalOutput);
- if (fn->isCommonFunction) ctx->isGeneratingCommonFunction--;
- // recompile function with native context pointers
- if (sz>0)
- {
- fn->startptr_size=sz;
- fn->startptr=p;
- }
- }
- }
- else
- {
- unsigned char *codeCall;
- fn->tmpspace_req=0;
- fn->fpStackUsage=0;
- fn->canHaveDenormalOutput=0;
- if (fn->isCommonFunction) ctx->isGeneratingCommonFunction++;
- codeCall=compileCodeBlockWithRet(ctx,fn->opcodes,&fn->tmpspace_req,&local_namespace,RETURNVALUE_NORMAL|RETURNVALUE_FPSTACK,&fn->rvMode,&fn->fpStackUsage,&fn->canHaveDenormalOutput);
- if (fn->isCommonFunction) ctx->isGeneratingCommonFunction--;
- if (codeCall)
- {
- void *f=GLUE_realAddress(nseel_asm_fcall,nseel_asm_fcall_end,&sz);
- fn->startptr = newTmpBlock(ctx,sz);
- if (fn->startptr)
- {
- memcpy(fn->startptr,f,sz);
- EEL_GLUE_set_immediate(fn->startptr,(INT_PTR)codeCall);
- fn->startptr_size = sz;
- }
- }
- }
- }
- if (fn->startptr)
- {
- if (computTableTop) *computTableTop += fn->tmpspace_req;
- *customFuncParmSize = fn->num_params;
- *customFuncLocalStorage = fn->localstorage;
- *customFuncLocalStorageSize = fn->localstorage_size;
- *rvMode = fn->rvMode;
- *fpStackUse = fn->fpStackUsage;
- if (canHaveDenormalOutput) *canHaveDenormalOutput= fn->canHaveDenormalOutput;
- *endP = (char*)fn->startptr + fn->startptr_size;
- *isRaw=1;
- return fn->startptr;
- }
-
- return 0;
- }
- // returns true if does something (other than calculating and throwing away a value)
- static char optimizeOpcodes(compileContext *ctx, opcodeRec *op, int needsResult)
- {
- opcodeRec *lastJoinOp=NULL;
- char retv, retv_parm[3], joined_retv=0;
- while (op && op->opcodeType == OPCODETYPE_FUNC2 && op->fntype == FN_JOIN_STATEMENTS)
- {
- if (!optimizeOpcodes(ctx,op->parms.parms[0], 0) || OPCODE_IS_TRIVIAL(op->parms.parms[0]))
- {
- // direct value, can skip ourselves
- memcpy(op,op->parms.parms[1],sizeof(*op));
- }
- else
- {
- joined_retv |= 1;
- lastJoinOp = op;
- op = op->parms.parms[1];
- }
- }
- goto start_over;
- #define RESTART_DIRECTVALUE(X) { op->parms.dv.directValue = (X); goto start_over_directvalue; }
- start_over_directvalue:
- op->opcodeType = OPCODETYPE_DIRECTVALUE;
- op->parms.dv.valuePtr=NULL;
-
- start_over: // when an opcode changed substantially in optimization, goto here to reprocess it
- retv = retv_parm[0]=retv_parm[1]=retv_parm[2]=0;
- if (!op || // should never really happen
- OPCODE_IS_TRIVIAL(op) || // should happen often (vars)
- op->opcodeType < 0 || op->opcodeType >= OPCODETYPE_INVALID // should never happen (assert would be appropriate heh)
- ) return joined_retv;
-
- if (!needsResult)
- {
- if (op->fntype == FUNCTYPE_EELFUNC)
- {
- needsResult=1; // assume eel functions are non-const for now
- }
- else if (op->fntype == FUNCTYPE_FUNCTIONTYPEREC)
- {
- functionType *pfn = (functionType *)op->fn;
- if (!pfn || !(pfn->nParams&NSEEL_NPARAMS_FLAG_CONST)) needsResult=1;
- }
- else if (op->fntype >= FN_NONCONST_BEGIN && op->fntype < FUNCTYPE_SIMPLEMAX)
- {
- needsResult=1;
- }
- }
- if (op->opcodeType>=OPCODETYPE_FUNC2) retv_parm[1] = optimizeOpcodes(ctx,op->parms.parms[1], needsResult);
- if (op->opcodeType>=OPCODETYPE_FUNC3) retv_parm[2] = optimizeOpcodes(ctx,op->parms.parms[2], needsResult);
- retv_parm[0] = optimizeOpcodes(ctx,op->parms.parms[0], needsResult ||
- (FNPTR_HAS_CONDITIONAL_EXEC(op) && (retv_parm[1] || retv_parm[2] || op->opcodeType <= OPCODETYPE_FUNC1)) );
- if (op->opcodeType != OPCODETYPE_MOREPARAMS)
- {
- if (op->fntype >= 0 && op->fntype < FUNCTYPE_SIMPLEMAX)
- {
- if (op->opcodeType == OPCODETYPE_FUNC1) // within FUNCTYPE_SIMPLE
- {
- if (op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE)
- {
- switch (op->fntype)
- {
- case FN_NOTNOT: RESTART_DIRECTVALUE(fabs(op->parms.parms[0]->parms.dv.directValue)>=NSEEL_CLOSEFACTOR ? 1.0 : 0.0);
- case FN_NOT: RESTART_DIRECTVALUE(fabs(op->parms.parms[0]->parms.dv.directValue)>=NSEEL_CLOSEFACTOR ? 0.0 : 1.0);
- case FN_UMINUS: RESTART_DIRECTVALUE(- op->parms.parms[0]->parms.dv.directValue);
- }
- }
- else if (op->fntype == FN_NOT || op->fntype == FN_NOTNOT)
- {
- if (op->parms.parms[0]->opcodeType == OPCODETYPE_FUNC1)
- {
- switch (op->parms.parms[0]->fntype)
- {
- case FN_UMINUS:
- case FN_NOTNOT: // ignore any NOTNOTs UMINUS or UPLUS, they would have no effect anyway
- op->parms.parms[0] = op->parms.parms[0]->parms.parms[0];
- goto start_over;
- case FN_NOT:
- op->fntype = op->fntype==FN_NOT ? FN_NOTNOT : FN_NOT; // switch between FN_NOT and FN_NOTNOT
- op->parms.parms[0] = op->parms.parms[0]->parms.parms[0];
- goto start_over;
- }
- }
- else if (op->parms.parms[0]->opcodeType == OPCODETYPE_FUNC2)
- {
- int repl_type = -1;
- switch (op->parms.parms[0]->fntype)
- {
- case FN_EQ: repl_type = FN_NE; break;
- case FN_NE: repl_type = FN_EQ; break;
- case FN_EQ_EXACT: repl_type = FN_NE_EXACT; break;
- case FN_NE_EXACT: repl_type = FN_EQ_EXACT; break;
- case FN_LT: repl_type = FN_GTE; break;
- case FN_LTE: repl_type = FN_GT; break;
- case FN_GT: repl_type = FN_LTE; break;
- case FN_GTE: repl_type = FN_LT; break;
- }
- if (repl_type != -1)
- {
- const int oldtype = op->fntype;
- memcpy(op,op->parms.parms[0],sizeof(*op));
- if (oldtype == FN_NOT) op->fntype = repl_type;
- goto start_over;
- }
- }
- }
- }
- else if (op->opcodeType == OPCODETYPE_FUNC2) // within FUNCTYPE_SIMPLE
- {
- const int dv0 = op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE;
- const int dv1 = op->parms.parms[1]->opcodeType == OPCODETYPE_DIRECTVALUE;
- if (dv0 && dv1)
- {
- int reval = -1;
- switch (op->fntype)
- {
- case FN_MOD:
- {
- int a = (int) op->parms.parms[1]->parms.dv.directValue;
- if (a)
- {
- a = (int) op->parms.parms[0]->parms.dv.directValue % a;
- if (a<0) a=-a;
- }
- RESTART_DIRECTVALUE((EEL_F)a);
- }
- break;
- case FN_SHL: RESTART_DIRECTVALUE(((int)op->parms.parms[0]->parms.dv.directValue) << ((int)op->parms.parms[1]->parms.dv.directValue));
- case FN_SHR: RESTART_DIRECTVALUE(((int)op->parms.parms[0]->parms.dv.directValue) >> ((int)op->parms.parms[1]->parms.dv.directValue));
- case FN_POW: RESTART_DIRECTVALUE(pow(op->parms.parms[0]->parms.dv.directValue, op->parms.parms[1]->parms.dv.directValue));
- case FN_DIVIDE: RESTART_DIRECTVALUE(op->parms.parms[0]->parms.dv.directValue / op->parms.parms[1]->parms.dv.directValue);
- case FN_MULTIPLY: RESTART_DIRECTVALUE(op->parms.parms[0]->parms.dv.directValue * op->parms.parms[1]->parms.dv.directValue);
- case FN_ADD: RESTART_DIRECTVALUE(op->parms.parms[0]->parms.dv.directValue + op->parms.parms[1]->parms.dv.directValue);
- case FN_SUB: RESTART_DIRECTVALUE(op->parms.parms[0]->parms.dv.directValue - op->parms.parms[1]->parms.dv.directValue);
- case FN_AND: RESTART_DIRECTVALUE((double) (((WDL_INT64)op->parms.parms[0]->parms.dv.directValue) & ((WDL_INT64)op->parms.parms[1]->parms.dv.directValue)));
- case FN_OR: RESTART_DIRECTVALUE((double) (((WDL_INT64)op->parms.parms[0]->parms.dv.directValue) | ((WDL_INT64)op->parms.parms[1]->parms.dv.directValue)));
- case FN_XOR: RESTART_DIRECTVALUE((double) (((WDL_INT64)op->parms.parms[0]->parms.dv.directValue) ^ ((WDL_INT64)op->parms.parms[1]->parms.dv.directValue)));
- case FN_EQ: reval = fabs(op->parms.parms[0]->parms.dv.directValue - op->parms.parms[1]->parms.dv.directValue) < NSEEL_CLOSEFACTOR; break;
- case FN_NE: reval = fabs(op->parms.parms[0]->parms.dv.directValue - op->parms.parms[1]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR; break;
- case FN_EQ_EXACT: reval = op->parms.parms[0]->parms.dv.directValue == op->parms.parms[1]->parms.dv.directValue; break;
- case FN_NE_EXACT: reval = op->parms.parms[0]->parms.dv.directValue != op->parms.parms[1]->parms.dv.directValue; break;
- case FN_LT: reval = op->parms.parms[0]->parms.dv.directValue < op->parms.parms[1]->parms.dv.directValue; break;
- case FN_LTE: reval = op->parms.parms[0]->parms.dv.directValue <= op->parms.parms[1]->parms.dv.directValue; break;
- case FN_GT: reval = op->parms.parms[0]->parms.dv.directValue > op->parms.parms[1]->parms.dv.directValue; break;
- case FN_GTE: reval = op->parms.parms[0]->parms.dv.directValue >= op->parms.parms[1]->parms.dv.directValue; break;
- case FN_LOGICAL_AND: reval = fabs(op->parms.parms[0]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR && fabs(op->parms.parms[1]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR; break;
- case FN_LOGICAL_OR: reval = fabs(op->parms.parms[0]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR || fabs(op->parms.parms[1]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR; break;
- }
-
- if (reval >= 0) RESTART_DIRECTVALUE((EEL_F) reval);
- }
- else if (dv0 || dv1)
- {
- double dvalue = op->parms.parms[!dv0]->parms.dv.directValue;
- switch (op->fntype)
- {
- case FN_OR:
- case FN_XOR:
- if (!(WDL_INT64)dvalue)
- {
- // replace with or0
- static functionType fr={"or0",nseel_asm_or0, nseel_asm_or0_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_LASTPARMONSTACK|BIF_RETURNSONSTACK|BIF_CLEARDENORMAL, {0}, NULL};
- op->opcodeType = OPCODETYPE_FUNC1;
- op->fntype = FUNCTYPE_FUNCTIONTYPEREC;
- op->fn = &fr;
- if (dv0) op->parms.parms[0] = op->parms.parms[1];
- goto start_over;
- }
- break;
- case FN_SUB:
- if (dv0)
- {
- if (dvalue == 0.0)
- {
- op->opcodeType = OPCODETYPE_FUNC1;
- op->fntype = FN_UMINUS;
- op->parms.parms[0] = op->parms.parms[1];
- goto start_over;
- }
- break;
- }
- // fall through, if dv1 we can remove +0.0
- case FN_ADD:
- if (dvalue == 0.0)
- {
- memcpy(op,op->parms.parms[!!dv0],sizeof(*op));
- goto start_over;
- }
- break;
- case FN_AND:
- if ((WDL_INT64)dvalue) break;
- dvalue = 0.0; // treat x&0 as x*0, which optimizes to 0
-
- // fall through
- case FN_MULTIPLY:
- if (dvalue == 0.0) // remove multiply by 0.0 (using 0.0 direct value as replacement), unless the nonzero side did something
- {
- if (!retv_parm[!!dv0])
- {
- memcpy(op,op->parms.parms[!dv0],sizeof(*op)); // set to 0 if other action wouldn't do anything
- goto start_over;
- }
- else
- {
- // this is 0.0 * oldexpressionthatmustbeprocessed or oldexpressionthatmustbeprocessed*0.0
- op->fntype = FN_JOIN_STATEMENTS;
- if (dv0) // 0.0*oldexpression, reverse the order so that 0 is returned
- {
- // set to (oldexpression;0)
- opcodeRec *tmp = op->parms.parms[1];
- op->parms.parms[1] = op->parms.parms[0];
- op->parms.parms[0] = tmp;
- }
- goto start_over;
- }
- }
- else if (dvalue == 1.0) // remove multiply by 1.0 (using non-1.0 value as replacement)
- {
- memcpy(op,op->parms.parms[!!dv0],sizeof(*op));
- goto start_over;
- }
- break;
- case FN_POW:
- if (dv1)
- {
- // x^0 = 1
- if (fabs(dvalue) < 1e-30)
- {
- RESTART_DIRECTVALUE(1.0);
- }
- // x^1 = x
- if (fabs(dvalue-1.0) < 1e-30)
- {
- memcpy(op,op->parms.parms[0],sizeof(*op));
- goto start_over;
- }
- }
- else if (dv0)
- {
- // pow(constant, x) = exp((x) * ln(constant)), if constant>0
- // opcodeRec *parm0 = op->parms.parms[0];
- if (dvalue > 0.0)
- {
- static functionType expcpy={ "exp", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&exp}, };
- // 1^x = 1
- if (fabs(dvalue-1.0) < 1e-30)
- {
- RESTART_DIRECTVALUE(1.0);
- }
- dvalue=log(dvalue);
- if (fabs(dvalue-1.0) < 1e-9)
- {
- // caller wanted e^x
- op->parms.parms[0]=op->parms.parms[1];
- }
- else
- {
- // it would be nice to replace 10^x with exp(log(10)*x) or 2^x with exp(log(2),x), but
- // doing so breaks rounding. we could maybe only allow 10^x, which is used for dB conversion,
- // but for now we should just force the programmer do it exp(log(10)*x) themselves.
- break;
- /*
- parm0->opcodeType = OPCODETYPE_FUNC2;
- parm0->fntype = FN_MULTIPLY;
- parm0->parms.parms[0] = nseel_createCompiledValue(ctx,dvalue);
- parm0->parms.parms[1] = op->parms.parms[1];
- */
- }
- op->opcodeType = OPCODETYPE_FUNC1;
- op->fntype = FUNCTYPE_FUNCTIONTYPEREC;
- op->fn = &expcpy;
- goto start_over;
- }
- }
- break;
- case FN_MOD:
- if (dv1)
- {
- const int a = (int) dvalue;
- if (!a)
- {
- RESTART_DIRECTVALUE(0.0);
- }
- }
- break;
- case FN_DIVIDE:
- if (dv1)
- {
- if (dvalue == 1.0) // remove divide by 1.0 (using non-1.0 value as replacement)
- {
- memcpy(op,op->parms.parms[!!dv0],sizeof(*op));
- goto start_over;
- }
- else
- {
- // change to a multiply
- if (dvalue == 0.0)
- {
- op->fntype = FN_MULTIPLY;
- goto start_over;
- }
- else
- {
- double d = 1.0/dvalue;
- WDL_DenormalDoubleAccess *p = (WDL_DenormalDoubleAccess*)&d;
- // allow conversion to multiply if reciprocal is exact
- // we could also just look to see if the last few digits of the mantissa were 0, which would probably be good
- // enough, but if the user really wants it they should do * (1/x) instead to force precalculation of reciprocal.
- if (!p->w.lw && !(p->w.hw & 0xfffff))
- {
- op->fntype = FN_MULTIPLY;
- op->parms.parms[1]->parms.dv.directValue = d;
- op->parms.parms[1]->parms.dv.valuePtr=NULL;
- goto start_over;
- }
- }
- }
- }
- else if (dvalue == 0.0)
- {
- if (!retv_parm[!!dv0])
- {
- // if 0/x set to always 0.
- // this is 0.0 / (oldexpression that can be eliminated)
- memcpy(op,op->parms.parms[!dv0],sizeof(*op)); // set to 0 if other action wouldn't do anything
- }
- else
- {
- opcodeRec *tmp;
- // this is 0.0 / oldexpressionthatmustbeprocessed
- op->fntype = FN_JOIN_STATEMENTS;
- tmp = op->parms.parms[1];
- op->parms.parms[1] = op->parms.parms[0];
- op->parms.parms[0] = tmp;
- // set to (oldexpression;0)
- }
- goto start_over;
- }
- break;
- case FN_EQ:
- if (dvalue == 0.0)
- {
- // convert x == 0.0 to !x
- op->opcodeType=OPCODETYPE_FUNC1;
- op->fntype = FN_NOT;
- if (dv0) op->parms.parms[0]=op->parms.parms[1];
- goto start_over;
- }
- break;
- case FN_NE:
- if (dvalue == 0.0)
- {
- // convert x != 0.0 to !!
- op->opcodeType=OPCODETYPE_FUNC1;
- op->fntype = FN_NOTNOT;
- if (dv0) op->parms.parms[0]=op->parms.parms[1];
- goto start_over;
- }
- break;
- case FN_LOGICAL_AND:
- if (dv0)
- {
- // dvalue && expr
- if (fabs(dvalue) < NSEEL_CLOSEFACTOR)
- {
- // 0 && expr, replace with 0
- RESTART_DIRECTVALUE(0.0);
- }
- else
- {
- // 1 && expr, replace with 0 != expr
- op->fntype = FN_NE;
- op->parms.parms[0]->parms.dv.valuePtr=NULL;
- op->parms.parms[0]->parms.dv.directValue = 0.0;
- }
- }
- else
- {
- // expr && dvalue
- if (fabs(dvalue) < NSEEL_CLOSEFACTOR)
- {
- // expr && 0
- if (!retv_parm[0])
- {
- // expr has no consequence, drop it
- RESTART_DIRECTVALUE(0.0);
- }
- else
- {
- // replace with (expr; 0)
- op->fntype = FN_JOIN_STATEMENTS;
- op->parms.parms[1]->parms.dv.valuePtr=NULL;
- op->parms.parms[1]->parms.dv.directValue = 0.0;
- }
- }
- else
- {
- // expr && 1, replace with expr != 0
- op->fntype = FN_NE;
- op->parms.parms[1]->parms.dv.valuePtr=NULL;
- op->parms.parms[1]->parms.dv.directValue = 0.0;
- }
- }
- goto start_over;
- case FN_LOGICAL_OR:
- if (dv0)
- {
- // dvalue || expr
- if (fabs(dvalue) >= NSEEL_CLOSEFACTOR)
- {
- // 1 || expr, replace with 1
- RESTART_DIRECTVALUE(1.0);
- }
- else
- {
- // 0 || expr, replace with 0 != expr
- op->fntype = FN_NE;
- op->parms.parms[0]->parms.dv.valuePtr=NULL;
- op->parms.parms[0]->parms.dv.directValue = 0.0;
- }
- }
- else
- {
- // expr || dvalue
- if (fabs(dvalue) >= NSEEL_CLOSEFACTOR)
- {
- // expr || 1
- if (!retv_parm[0])
- {
- // expr has no consequence, drop it and return 1
- RESTART_DIRECTVALUE(1.0);
- }
- else
- {
- // replace with (expr; 1)
- op->fntype = FN_JOIN_STATEMENTS;
- op->parms.parms[1]->parms.dv.valuePtr=NULL;
- op->parms.parms[1]->parms.dv.directValue = 1.0;
- }
- }
- else
- {
- // expr || 0, replace with expr != 0
- op->fntype = FN_NE;
- op->parms.parms[1]->parms.dv.valuePtr=NULL;
- op->parms.parms[1]->parms.dv.directValue = 0.0;
- }
- }
- goto start_over;
- }
- } // dv0 || dv1
- // general optimization of two parameters
- switch (op->fntype)
- {
- case FN_MULTIPLY:
- {
- opcodeRec *first_parm = op->parms.parms[0],*second_parm = op->parms.parms[1];
- if (second_parm->opcodeType == first_parm->opcodeType)
- {
- switch(first_parm->opcodeType)
- {
- case OPCODETYPE_VALUE_FROM_NAMESPACENAME:
- if (first_parm->namespaceidx != second_parm->namespaceidx) break;
- // fall through
- case OPCODETYPE_VARPTR:
- if (first_parm->relname && second_parm->relname && !stricmp(second_parm->relname,first_parm->relname)) second_parm=NULL;
- break;
- case OPCODETYPE_VARPTRPTR:
- if (first_parm->parms.dv.valuePtr && first_parm->parms.dv.valuePtr==second_parm->parms.dv.valuePtr) second_parm=NULL;
- break;
- }
- if (!second_parm) // switch from x*x to sqr(x)
- {
- static functionType sqrcpy={ "sqr", nseel_asm_sqr,nseel_asm_sqr_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1) };
- op->opcodeType = OPCODETYPE_FUNC1;
- op->fntype = FUNCTYPE_FUNCTIONTYPEREC;
- op->fn = &sqrcpy;
- goto start_over;
- }
- }
- }
- break;
- case FN_POW:
- {
- opcodeRec *first_parm = op->parms.parms[0];
- if (first_parm->opcodeType == op->opcodeType && first_parm->fntype == FN_POW)
- {
- // since first_parm is a pow too, we can multiply the exponents.
- // set our base to be the base of the inner pow
- op->parms.parms[0] = first_parm->parms.parms[0];
- // make the old extra pow be a multiply of the exponents
- first_parm->fntype = FN_MULTIPLY;
- first_parm->parms.parms[0] = op->parms.parms[1];
- // put that as the exponent
- op->parms.parms[1] = first_parm;
- goto start_over;
- }
- }
- break;
- case FN_LOGICAL_AND:
- case FN_LOGICAL_OR:
- if (op->parms.parms[0]->fntype == FN_NOTNOT)
- {
- // remove notnot, unnecessary for input to &&/|| operators
- op->parms.parms[0] = op->parms.parms[0]->parms.parms[0];
- goto start_over;
- }
- if (op->parms.parms[1]->fntype == FN_NOTNOT)
- {
- // remove notnot, unnecessary for input to &&/|| operators
- op->parms.parms[1] = op->parms.parms[1]->parms.parms[0];
- goto start_over;
- }
- break;
- }
- }
- else if (op->opcodeType==OPCODETYPE_FUNC3) // within FUNCTYPE_SIMPLE
- {
- if (op->fntype == FN_IF_ELSE)
- {
- if (op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE)
- {
- int s = fabs(op->parms.parms[0]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR;
- memcpy(op,op->parms.parms[s ? 1 : 2],sizeof(opcodeRec));
- goto start_over;
- }
- if (op->parms.parms[0]->opcodeType == OPCODETYPE_FUNC1)
- {
- if (op->parms.parms[0]->fntype == FN_NOTNOT)
- {
- // remove notnot, unnecessary for input to ? operator
- op->parms.parms[0] = op->parms.parms[0]->parms.parms[0];
- goto start_over;
- }
- }
- }
- }
- if (op->fntype >= FN_NONCONST_BEGIN && op->fntype < FUNCTYPE_SIMPLEMAX) retv|=1;
- // FUNCTYPE_SIMPLE
- }
- else if (op->fntype == FUNCTYPE_FUNCTIONTYPEREC && op->fn)
- {
- /*
- probably worth doing reduction on:
- _divop (constant change to multiply)
- _and
- _or
- abs
- maybe:
- min
- max
- also, optimize should (recursively or maybe iteratively?) search transitive functions (mul/div) for more constant reduction possibilities
- */
- functionType *pfn = (functionType *)op->fn;
- if (!(pfn->nParams&NSEEL_NPARAMS_FLAG_CONST)) retv|=1;
- if (op->opcodeType==OPCODETYPE_FUNC1) // within FUNCTYPE_FUNCTIONTYPEREC
- {
- if (op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE)
- {
- int suc=1;
- EEL_F v = op->parms.parms[0]->parms.dv.directValue;
- #define DOF(x) if (!strcmp(pfn->name,#x)) v = x(v); else
- #define DOF2(x,y) if (!strcmp(pfn->name,#x)) v = x(y); else
- DOF(sin)
- DOF(cos)
- DOF(tan)
- DOF(asin)
- DOF(acos)
- DOF(atan)
- DOF2(sqrt, fabs(v))
- DOF(exp)
- DOF(log)
- DOF(log10)
- /* else */ suc=0;
- #undef DOF
- #undef DOF2
- if (suc)
- {
- RESTART_DIRECTVALUE(v);
- }
- }
- }
- else if (op->opcodeType==OPCODETYPE_FUNC2) // within FUNCTYPE_FUNCTIONTYPEREC
- {
- const int dv0=op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE;
- const int dv1=op->parms.parms[1]->opcodeType == OPCODETYPE_DIRECTVALUE;
- if (dv0 && dv1)
- {
- if (!strcmp(pfn->name,"atan2"))
- {
- RESTART_DIRECTVALUE(atan2(op->parms.parms[0]->parms.dv.directValue, op->parms.parms[1]->parms.dv.directValue));
- }
- }
- }
- // FUNCTYPE_FUNCTIONTYPEREC
- }
- else
- {
- // unknown or eel func, assume non-const
- retv |= 1;
- }
- }
- // if we need results, or our function has effects itself, then finish
- if (retv || needsResult)
- {
- return retv || joined_retv || retv_parm[0] || retv_parm[1] || retv_parm[2];
- }
- // we don't need results here, and our function is const, which means we can remove it
- {
- int cnt=0, idx1=0, idx2=0, x;
- for (x=0;x<3;x++) if (retv_parm[x]) { if (!cnt++) idx1=x; else idx2=x; }
- if (!cnt) // none of the parameters do anything, remove this opcode
- {
- if (lastJoinOp)
- {
- // replace previous join with its first linked opcode, removing this opcode completely
- memcpy(lastJoinOp,lastJoinOp->parms.parms[0],sizeof(*lastJoinOp));
- }
- else if (op->opcodeType != OPCODETYPE_DIRECTVALUE)
- {
- // allow caller to easily detect this as trivial and remove it
- op->opcodeType = OPCODETYPE_DIRECTVALUE;
- op->parms.dv.valuePtr=NULL;
- op->parms.dv.directValue=0.0;
- }
- // return joined_retv below
- }
- else
- {
- // if parameters are non-const, and we're a conditional, preserve our function
- if (FNPTR_HAS_CONDITIONAL_EXEC(op)) return 1;
- // otherwise, condense into either the non-const statement, or a join
- if (cnt==1)
- {
- memcpy(op,op->parms.parms[idx1],sizeof(*op));
- }
- else if (cnt == 2)
- {
- op->opcodeType = OPCODETYPE_FUNC2;
- op->fntype = FN_JOIN_STATEMENTS;
- op->fn = op;
- op->parms.parms[0] = op->parms.parms[idx1];
- op->parms.parms[1] = op->parms.parms[idx2];
- op->parms.parms[2] = NULL;
- }
- else
- {
- // todo need to create a new opcodeRec here, for now just leave as is
- // (non-conditional const 3 parameter functions are rare anyway)
- }
- return 1;
- }
- }
- return joined_retv;
- }
- static int generateValueToReg(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int whichReg, const namespaceInformation *functionPrefix, int allowCache)
- {
- EEL_F *b=NULL;
- if (op->opcodeType==OPCODETYPE_VALUE_FROM_NAMESPACENAME)
- {
- char nm[NSEEL_MAX_VARIABLE_NAMELEN+1];
- const char *p = op->relname;
- combineNamespaceFields(nm,functionPrefix,p+(*p == '#'),op->namespaceidx);
- if (!nm[0]) return -1;
- if (*p == '#')
- {
- if (ctx->isGeneratingCommonFunction)
- b = newCtxDataBlock(sizeof(EEL_F),sizeof(EEL_F));
- else
- b = newDataBlock(sizeof(EEL_F),sizeof(EEL_F));
- if (!b) RET_MINUS1_FAIL("error creating storage for str")
- if (!ctx->onNamedString) return -1; // should never happen, will not generate OPCODETYPE_VALUE_FROM_NAMESPACENAME with # prefix if !onNamedString
- *b = ctx->onNamedString(ctx->caller_this,nm);
- }
- else
- {
- b = nseel_int_register_var(ctx,nm,0,NULL);
- if (!b) RET_MINUS1_FAIL("error registering var")
- }
- }
- else
- {
- if (op->opcodeType != OPCODETYPE_DIRECTVALUE) allowCache=0;
- if (op->opcodeType==OPCODETYPE_DIRECTVALUE_TEMPSTRING && ctx->onNamedString)
- {
- op->parms.dv.directValue = ctx->onNamedString(ctx->caller_this,"");
- op->parms.dv.valuePtr = NULL;
- }
- b=op->parms.dv.valuePtr;
- if (!b && op->opcodeType == OPCODETYPE_VARPTR && op->relname && op->relname[0])
- {
- op->parms.dv.valuePtr = b = nseel_int_register_var(ctx,op->relname,0,NULL);
- }
- if (b && op->opcodeType == OPCODETYPE_VARPTRPTR) b = *(EEL_F **)b;
- if (!b && allowCache)
- {
- int n=50; // only scan last X items
- opcodeRec *r = ctx->directValueCache;
- while (r && n--)
- {
- if (r->parms.dv.directValue == op->parms.dv.directValue && (b=r->parms.dv.valuePtr)) break;
- r=(opcodeRec*)r->fn;
- }
- }
- if (!b)
- {
- ctx->l_stats[3]++;
- if (ctx->isGeneratingCommonFunction)
- b = newCtxDataBlock(sizeof(EEL_F),sizeof(EEL_F));
- else
- b = newDataBlock(sizeof(EEL_F),sizeof(EEL_F));
- if (!b) RET_MINUS1_FAIL("error allocating data block")
- if (op->opcodeType != OPCODETYPE_VARPTRPTR) op->parms.dv.valuePtr = b;
- #if EEL_F_SIZE == 8
- *b = denormal_filter_double2(op->parms.dv.directValue);
- #else
- *b = denormal_filter_float2(op->parms.dv.directValue);
- #endif
- if (allowCache)
- {
- op->fn = ctx->directValueCache;
- ctx->directValueCache = op;
- }
- }
- }
- GLUE_MOV_PX_DIRECTVALUE_GEN(bufOut,(INT_PTR)b,whichReg);
- return GLUE_MOV_PX_DIRECTVALUE_SIZE;
- }
- unsigned char *compileCodeBlockWithRet(compileContext *ctx, opcodeRec *rec, int *computTableSize, const namespaceInformation *namespacePathToThis,
- int supportedReturnValues, int *rvType, int *fpStackUsage, int *canHaveDenormalOutput)
- {
- unsigned char *p, *newblock2;
- // generate code call
- int funcsz=compileOpcodes(ctx,rec,NULL,1024*1024*128,NULL,namespacePathToThis,supportedReturnValues, rvType,fpStackUsage, NULL);
- if (funcsz<0) return NULL;
-
- p = newblock2 = newCodeBlock(funcsz+ sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32);
- if (!newblock2) return NULL;
- #if GLUE_FUNC_ENTER_SIZE > 0
- memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE);
- p += GLUE_FUNC_ENTER_SIZE;
- #endif
- *fpStackUsage=0;
- funcsz=compileOpcodes(ctx,rec,p, funcsz, computTableSize,namespacePathToThis,supportedReturnValues, rvType,fpStackUsage, canHaveDenormalOutput);
- if (funcsz<0) return NULL;
- p+=funcsz;
- #if GLUE_FUNC_LEAVE_SIZE > 0
- memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE);
- p+=GLUE_FUNC_LEAVE_SIZE;
- #endif
- memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET);
- #if defined(__arm__) || defined(__aarch64__)
- __clear_cache(newblock2,p);
- #endif
-
- ctx->l_stats[2]+=funcsz+2;
- return newblock2;
- }
- static int compileNativeFunctionCall(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTableSize, const namespaceInformation *namespacePathToThis,
- int *rvMode, int *fpStackUsage, int preferredReturnValues, int *canHaveDenormalOutput)
- {
- // builtin function generation
- int func_size=0;
- int cfunc_abiinfo=0;
- int local_fpstack_use=0; // how many items we have pushed onto the fp stack
- int parm_size=0;
- int restore_stack_amt=0;
- void *func_e=NULL;
- NSEEL_PPPROC preProc=0;
- void **repl=NULL;
- int n_params= 1 + op->opcodeType - OPCODETYPE_FUNC1;
- const int parm0_dv = op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE;
- const int parm1_dv = n_params > 1 && op->parms.parms[1]->opcodeType == OPCODETYPE_DIRECTVALUE;
- void *func = nseel_getBuiltinFunctionAddress(ctx, op->fntype, op->fn, &preProc,&repl,&func_e,&cfunc_abiinfo,preferredReturnValues,
- parm0_dv ? &op->parms.parms[0]->parms.dv.directValue : NULL,
- parm1_dv ? &op->parms.parms[1]->parms.dv.directValue : NULL
- );
- if (!func) RET_MINUS1_FAIL("error getting funcaddr")
- *fpStackUsage=BIF_GETFPSTACKUSE(cfunc_abiinfo);
- *rvMode = RETURNVALUE_NORMAL;
- if (cfunc_abiinfo & BIF_TAKES_VARPARM)
- {
- #if defined(__arm__) || (defined (_M_ARM) && _M_ARM == 7)
- const int max_params=16384; // arm uses up to two instructions, should be good for at leaast 64k (16384*4)
- #elif defined(__ppc__)
- const int max_params=4096; // 32kb max offset addressing for stack, so 4096*4 = 16384, should be safe
- #elif defined(__aarch64__)
- const int max_params=32768;
- #else
- const int max_params=32768; // sanity check, the stack is free to grow on x86/x86-64
- #endif
- int x;
- // this mode is less efficient in that it creates a list of pointers on the stack to pass to the function
- // but it is more flexible and works for >3 parameters.
- if (op->opcodeType == OPCODETYPE_FUNCX)
- {
- n_params=0;
- for (x=0;x<3;x++)
- {
- opcodeRec *prni=op->parms.parms[x];
- while (prni)
- {
- const int isMP = prni->opcodeType == OPCODETYPE_MOREPARAMS;
- n_params++;
- if (!isMP||n_params>=max_params) break;
- prni = prni->parms.parms[1];
- }
- }
- }
- restore_stack_amt = (sizeof(void *) * n_params + 15)&~15;
- if (restore_stack_amt)
- {
- int offs = restore_stack_amt;
- while (offs > 0)
- {
- int amt = offs;
- if (amt > 4096) amt=4096;
- if (bufOut_len < parm_size+GLUE_MOVE_STACK_SIZE) RET_MINUS1_FAIL("insufficient size for varparm")
- if (bufOut) GLUE_MOVE_STACK(bufOut+parm_size, - amt);
- parm_size += GLUE_MOVE_STACK_SIZE;
- offs -= amt;
- if (offs>0) // make sure this page is in memory
- {
- if (bufOut_len < parm_size+GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(0))
- RET_MINUS1_FAIL("insufficient size for varparm stackchk")
- if (bufOut) GLUE_STORE_P1_TO_STACK_AT_OFFS(bufOut+parm_size,0);
- parm_size += GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(0);
- }
- }
- }
- if (op->opcodeType == OPCODETYPE_FUNCX)
- {
- n_params=0;
- for (x=0;x<3;x++)
- {
- opcodeRec *prni=op->parms.parms[x];
- while (prni)
- {
- const int isMP = prni->opcodeType == OPCODETYPE_MOREPARAMS;
- opcodeRec *r = isMP ? prni->parms.parms[0] : prni;
- if (r)
- {
- int canHaveDenorm=0;
- int rvt=RETURNVALUE_NORMAL;
- int subfpstackuse=0, use_offs;
-
- int lsz = compileOpcodes(ctx,r,bufOut ? bufOut + parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, rvt,&rvt, &subfpstackuse, &canHaveDenorm);
- if (canHaveDenorm && canHaveDenormalOutput) *canHaveDenormalOutput = 1;
- if (lsz<0) RET_MINUS1_FAIL("call coc for varparmX failed")
- if (rvt != RETURNVALUE_NORMAL) RET_MINUS1_FAIL("call coc for varparmX gave bad type back");
- parm_size += lsz;
- use_offs = n_params*(int) sizeof(void *);
- if (bufOut_len < parm_size+GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(use_offs))
- RET_MINUS1_FAIL("call coc for varparmX size");
- if (bufOut) GLUE_STORE_P1_TO_STACK_AT_OFFS(bufOut + parm_size, use_offs);
- parm_size+=GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(use_offs);
- if (subfpstackuse+local_fpstack_use > *fpStackUsage) *fpStackUsage = subfpstackuse+local_fpstack_use;
- }
- else RET_MINUS1_FAIL("zero parameter varparmX")
- n_params++;
- if (!isMP||n_params>=max_params) break;
- prni = prni->parms.parms[1];
- }
- }
- }
- else for (x=0;x<n_params;x++)
- {
- opcodeRec *r = op->parms.parms[x];
- if (r)
- {
- int canHaveDenorm=0;
- int subfpstackuse=0;
- int rvt=RETURNVALUE_NORMAL;
- int use_offs;
-
- int lsz = compileOpcodes(ctx,r,bufOut ? bufOut + parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, rvt,&rvt, &subfpstackuse, &canHaveDenorm);
- if (canHaveDenorm && canHaveDenormalOutput) *canHaveDenormalOutput = 1;
- if (lsz<0) RET_MINUS1_FAIL("call coc for varparm123 failed")
- if (rvt != RETURNVALUE_NORMAL) RET_MINUS1_FAIL("call coc for varparm123 gave bad type back");
- parm_size += lsz;
- use_offs = x*(int)sizeof(void *);
- if (bufOut_len < parm_size+GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(use_offs))
- RET_MINUS1_FAIL("call coc for varparm123 size");
- if (bufOut) GLUE_STORE_P1_TO_STACK_AT_OFFS(bufOut + parm_size, use_offs);
- parm_size+=GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(use_offs);
- if (subfpstackuse+local_fpstack_use > *fpStackUsage) *fpStackUsage = subfpstackuse+local_fpstack_use;
- }
- else RET_MINUS1_FAIL("zero parameter for varparm123");
- }
- if (bufOut_len < parm_size+GLUE_MOV_PX_DIRECTVALUE_SIZE+GLUE_MOVE_PX_STACKPTR_SIZE) RET_MINUS1_FAIL("insufficient size for varparm p1")
- if (bufOut) GLUE_MOV_PX_DIRECTVALUE_GEN(bufOut+parm_size, (INT_PTR)n_params,1);
- parm_size+=GLUE_MOV_PX_DIRECTVALUE_SIZE;
- if (bufOut) GLUE_MOVE_PX_STACKPTR_GEN(bufOut+parm_size, 0);
- parm_size+=GLUE_MOVE_PX_STACKPTR_SIZE;
-
- }
- else // not varparm
- {
- int pn;
- #ifdef GLUE_HAS_FXCH
- int need_fxch=0;
- #endif
- int last_nt_parm=-1, last_nt_parm_type=-1;
-
- if (op->opcodeType == OPCODETYPE_FUNCX)
- {
- // this is not yet supported (calling conventions will need to be sorted, among other things)
- RET_MINUS1_FAIL("funcx for native functions requires BIF_TAKES_VARPARM or BIF_TAKES_VARPARM_EX")
- }
- if (parm0_dv)
- {
- if (func == nseel_asm_stack_pop)
- {
- func = GLUE_realAddress(nseel_asm_stack_pop_fast,nseel_asm_stack_pop_fast_end,&func_size);
- if (!func || bufOut_len < func_size) RET_MINUS1_FAIL(func?"failed on popfast size":"failed on popfast addr")
- if (bufOut)
- {
- memcpy(bufOut,func,func_size);
- NSEEL_PProc_Stack(bufOut,func_size,ctx);
- }
- return func_size;
- }
- else if (func == nseel_asm_stack_peek)
- {
- int f = (int) op->parms.parms[0]->parms.dv.directValue;
- if (!f)
- {
- func = GLUE_realAddress(nseel_asm_stack_peek_top,nseel_asm_stack_peek_top_end,&func_size);
- if (!func || bufOut_len < func_size) RET_MINUS1_FAIL(func?"failed on peek size":"failed on peek addr")
- if (bufOut)
- {
- memcpy(bufOut,func,func_size);
- NSEEL_PProc_Stack_PeekTop(bufOut,func_size,ctx);
- }
- return func_size;
- }
- else
- {
- func = GLUE_realAddress(nseel_asm_stack_peek_int,nseel_asm_stack_peek_int_end,&func_size);
- if (!func || bufOut_len < func_size) RET_MINUS1_FAIL(func?"failed on peekint size":"failed on peekint addr")
- if (bufOut)
- {
- memcpy(bufOut,func,func_size);
- NSEEL_PProc_Stack_PeekInt(bufOut,func_size,ctx,f*sizeof(EEL_F));
- }
- return func_size;
- }
- }
- }
- // end of built-in function specific special casing
- // first pass, calculate any non-trivial parameters
- for (pn=0; pn < n_params; pn++)
- {
- if (!OPCODE_IS_TRIVIAL(op->parms.parms[pn]))
- {
- int canHaveDenorm=0;
- int subfpstackuse=0;
- int lsz=0;
- int rvt=RETURNVALUE_NORMAL;
- int may_need_fppush=-1;
- if (last_nt_parm>=0)
- {
- if (last_nt_parm_type==RETURNVALUE_FPSTACK)
- {
- may_need_fppush= parm_size;
- }
- else
- {
- // push last result
- if (bufOut_len < parm_size + (int)sizeof(GLUE_PUSH_P1)) RET_MINUS1_FAIL("failed on size, pushp1")
- if (bufOut) memcpy(bufOut + parm_size, &GLUE_PUSH_P1, sizeof(GLUE_PUSH_P1));
- parm_size += sizeof(GLUE_PUSH_P1);
- }
- }
- if (func == nseel_asm_bnot) rvt=RETURNVALUE_BOOL_REVERSED|RETURNVALUE_BOOL;
- else if (pn == n_params - 1)
- {
- if (cfunc_abiinfo&BIF_LASTPARMONSTACK) rvt=RETURNVALUE_FPSTACK;
- else if (cfunc_abiinfo&BIF_LASTPARM_ASBOOL) rvt=RETURNVALUE_BOOL;
- else if (func == nseel_asm_assign) rvt=RETURNVALUE_FPSTACK|RETURNVALUE_NORMAL;
- }
- else if (pn == n_params -2 && (cfunc_abiinfo&BIF_SECONDLASTPARMST))
- {
- rvt=RETURNVALUE_FPSTACK;
- }
- lsz = compileOpcodes(ctx,op->parms.parms[pn],bufOut ? bufOut + parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, rvt,&rvt, &subfpstackuse, &canHaveDenorm);
- if (lsz<0) RET_MINUS1_FAIL("call coc failed")
- if (func == nseel_asm_bnot && rvt==RETURNVALUE_BOOL_REVERSED)
- {
- // remove bnot, compileOpcodes() used fptobool_rev
- #ifndef EEL_TARGET_PORTABLE
- func = nseel_asm_uplus;
- func_e = nseel_asm_uplus_end;
- #else
- func = nseel_asm_bnotnot;
- func_e = nseel_asm_bnotnot_end;
- #endif
- rvt = RETURNVALUE_BOOL;
- }
- if (canHaveDenorm && canHaveDenormalOutput) *canHaveDenormalOutput = 1;
- parm_size += lsz;
- if (may_need_fppush>=0)
- {
- if (local_fpstack_use+subfpstackuse >= (GLUE_MAX_FPSTACK_SIZE-1) || (ctx->optimizeDisableFlags&OPTFLAG_NO_FPSTACK))
- {
- if (bufOut_len < parm_size + (int)sizeof(GLUE_POP_FPSTACK_TOSTACK))
- RET_MINUS1_FAIL("failed on size, popfpstacktostack")
- if (bufOut)
- {
- memmove(bufOut + may_need_fppush + sizeof(GLUE_POP_FPSTACK_TOSTACK), bufOut + may_need_fppush, parm_size - may_need_fppush);
- memcpy(bufOut + may_need_fppush, &GLUE_POP_FPSTACK_TOSTACK, sizeof(GLUE_POP_FPSTACK_TOSTACK));
- }
- parm_size += sizeof(GLUE_POP_FPSTACK_TOSTACK);
- }
- else
- {
- local_fpstack_use++;
- }
- }
- if (subfpstackuse+local_fpstack_use > *fpStackUsage) *fpStackUsage = subfpstackuse+local_fpstack_use;
- last_nt_parm = pn;
- last_nt_parm_type = rvt;
- if (pn == n_params - 1 && func == nseel_asm_assign)
- {
- if (!(ctx->optimizeDisableFlags & OPTFLAG_FULL_DENORMAL_CHECKS) &&
- (!canHaveDenorm || (ctx->optimizeDisableFlags & OPTFLAG_NO_DENORMAL_CHECKS)))
- {
- if (rvt == RETURNVALUE_FPSTACK)
- {
- cfunc_abiinfo |= BIF_LASTPARMONSTACK;
- func = nseel_asm_assign_fast_fromfp;
- func_e = nseel_asm_assign_fast_fromfp_end;
- }
- else
- {
- func = nseel_asm_assign_fast;
- func_e = nseel_asm_assign_fast_end;
- }
- }
- else
- {
- if (rvt == RETURNVALUE_FPSTACK)
- {
- cfunc_abiinfo |= BIF_LASTPARMONSTACK;
- func = nseel_asm_assign_fromfp;
- func_e = nseel_asm_assign_fromfp_end;
- }
- }
-
- }
- }
- }
- pn = last_nt_parm;
-
- if (pn >= 0) // if the last thing executed doesn't go to the last parameter, move it there
- {
- if ((cfunc_abiinfo&BIF_SECONDLASTPARMST) && pn == n_params-2)
- {
- // do nothing, things are in the right place
- }
- else if (pn != n_params-1)
- {
- // generate mov p1->pX
- if (bufOut_len < parm_size + GLUE_SET_PX_FROM_P1_SIZE) RET_MINUS1_FAIL("size, pxfromp1")
- if (bufOut) GLUE_SET_PX_FROM_P1(bufOut + parm_size,n_params - 1 - pn);
- parm_size += GLUE_SET_PX_FROM_P1_SIZE;
- }
- }
- // pop any pushed parameters
- while (--pn >= 0)
- {
- if (!OPCODE_IS_TRIVIAL(op->parms.parms[pn]))
- {
- if ((cfunc_abiinfo&BIF_SECONDLASTPARMST) && pn == n_params-2)
- {
- if (!local_fpstack_use)
- {
- if (bufOut_len < parm_size + (int)sizeof(GLUE_POP_STACK_TO_FPSTACK)) RET_MINUS1_FAIL("size, popstacktofpstack 2")
- if (bufOut) memcpy(bufOut+parm_size,GLUE_POP_STACK_TO_FPSTACK,sizeof(GLUE_POP_STACK_TO_FPSTACK));
- parm_size += sizeof(GLUE_POP_STACK_TO_FPSTACK);
- #ifdef GLUE_HAS_FXCH
- need_fxch = 1;
- #endif
- }
- else
- {
- local_fpstack_use--;
- }
- }
- else
- {
- if (bufOut_len < parm_size + GLUE_POP_PX_SIZE) RET_MINUS1_FAIL("size, poppx")
- if (bufOut) GLUE_POP_PX(bufOut + parm_size,n_params - 1 - pn);
- parm_size += GLUE_POP_PX_SIZE;
- }
- }
- }
- // finally, set trivial pointers
- for (pn=0; pn < n_params; pn++)
- {
- if (OPCODE_IS_TRIVIAL(op->parms.parms[pn]))
- {
- if (pn == n_params-2 && (cfunc_abiinfo&(BIF_SECONDLASTPARMST))) // second to last parameter
- {
- int a = compileOpcodes(ctx,op->parms.parms[pn],bufOut ? bufOut+parm_size : NULL,bufOut_len - parm_size,computTableSize,namespacePathToThis,
- RETURNVALUE_FPSTACK,NULL,NULL,canHaveDenormalOutput);
- if (a<0) RET_MINUS1_FAIL("coc call here 2")
- parm_size+=a;
- #ifdef GLUE_HAS_FXCH
- need_fxch = 1;
- #endif
- }
- else if (pn == n_params-1) // last parameter, but we should call compileOpcodes to get it in the right format (compileOpcodes can optimize that process if it needs to)
- {
- int rvt=0, a;
- int wantFpStack = func == nseel_asm_assign;
- #ifdef GLUE_PREFER_NONFP_DV_ASSIGNS // x86-64, and maybe others, prefer to avoid the fp stack for a simple copy
- if (wantFpStack &&
- (op->parms.parms[pn]->opcodeType != OPCODETYPE_DIRECTVALUE ||
- (op->parms.parms[pn]->parms.dv.directValue != 1.0 && op->parms.parms[pn]->parms.dv.directValue != 0.0)))
- {
- wantFpStack=-1; // cacheable but non-FP stack
- }
- #endif
- a = compileOpcodes(ctx,op->parms.parms[pn],bufOut ? bufOut+parm_size : NULL,bufOut_len - parm_size,computTableSize,namespacePathToThis,
- func == nseel_asm_bnot ? (RETURNVALUE_BOOL_REVERSED|RETURNVALUE_BOOL) :
- (cfunc_abiinfo & BIF_LASTPARMONSTACK) ? RETURNVALUE_FPSTACK :
- (cfunc_abiinfo & BIF_LASTPARM_ASBOOL) ? RETURNVALUE_BOOL :
- wantFpStack < 0 ? (RETURNVALUE_CACHEABLE|RETURNVALUE_NORMAL) :
- wantFpStack ? (RETURNVALUE_FPSTACK|RETURNVALUE_NORMAL) :
- RETURNVALUE_NORMAL,
- &rvt, NULL,canHaveDenormalOutput);
-
- if (a<0) RET_MINUS1_FAIL("coc call here 3")
- if (func == nseel_asm_bnot && rvt == RETURNVALUE_BOOL_REVERSED)
- {
- // remove bnot, compileOpcodes() used fptobool_rev
- #ifndef EEL_TARGET_PORTABLE
- func = nseel_asm_uplus;
- func_e = nseel_asm_uplus_end;
- #else
- func = nseel_asm_bnotnot;
- func_e = nseel_asm_bnotnot_end;
- #endif
- rvt = RETURNVALUE_BOOL;
- }
- parm_size+=a;
- #ifdef GLUE_HAS_FXCH
- need_fxch = 0;
- #endif
- if (func == nseel_asm_assign)
- {
- if (rvt == RETURNVALUE_FPSTACK)
- {
- if (!(ctx->optimizeDisableFlags & OPTFLAG_FULL_DENORMAL_CHECKS))
- {
- func = nseel_asm_assign_fast_fromfp;
- func_e = nseel_asm_assign_fast_fromfp_end;
- }
- else
- {
- func = nseel_asm_assign_fromfp;
- func_e = nseel_asm_assign_fromfp_end;
- }
- }
- else if (!(ctx->optimizeDisableFlags & OPTFLAG_FULL_DENORMAL_CHECKS))
- {
- // assigning a value (from a variable or other non-computer), can use a fast assign (no denormal/result checking)
- func = nseel_asm_assign_fast;
- func_e = nseel_asm_assign_fast_end;
- }
- }
- }
- else
- {
- if (bufOut_len < parm_size + GLUE_MOV_PX_DIRECTVALUE_SIZE) RET_MINUS1_FAIL("size, pxdvsz")
- if (bufOut)
- {
- if (generateValueToReg(ctx,op->parms.parms[pn],bufOut + parm_size,n_params - 1 - pn,namespacePathToThis, 0/*nocaching, function gets pointer*/)<0) RET_MINUS1_FAIL("gvtr")
- }
- parm_size += GLUE_MOV_PX_DIRECTVALUE_SIZE;
- }
- }
- }
- #ifdef GLUE_HAS_FXCH
- if ((cfunc_abiinfo&(BIF_SECONDLASTPARMST)) && !(cfunc_abiinfo&(BIF_LAZYPARMORDERING))&&
- ((!!need_fxch)^!!(cfunc_abiinfo&BIF_REVERSEFPORDER))
- )
- {
- // emit fxch
- if (bufOut_len < sizeof(GLUE_FXCH)) RET_MINUS1_FAIL("len,fxch")
- if (bufOut)
- {
- memcpy(bufOut+parm_size,GLUE_FXCH,sizeof(GLUE_FXCH));
- }
- parm_size+=sizeof(GLUE_FXCH);
- }
- #endif
-
- if (!*canHaveDenormalOutput)
- {
- // if add_op or sub_op, and constant non-denormal input, safe to omit denormal checks
- if (func == (void*)nseel_asm_add_op && parm1_dv && fabs(op->parms.parms[1]->parms.dv.directValue) >= DENORMAL_CLEARING_THRESHOLD)
- {
- func = nseel_asm_add_op_fast;
- func_e = nseel_asm_add_op_fast_end;
- }
- else if (func == (void*)nseel_asm_sub_op && parm1_dv && fabs(op->parms.parms[1]->parms.dv.directValue) >= DENORMAL_CLEARING_THRESHOLD)
- {
- func = nseel_asm_sub_op_fast;
- func_e = nseel_asm_sub_op_fast_end;
- }
- // or if mul/div by a fixed value of >= or <= 1.0
- else if (func == (void *)nseel_asm_mul_op && parm1_dv && fabs(op->parms.parms[1]->parms.dv.directValue) >= 1.0)
- {
- func = nseel_asm_mul_op_fast;
- func_e = nseel_asm_mul_op_fast_end;
- }
- else if (func == (void *)nseel_asm_div_op && parm1_dv && fabs(op->parms.parms[1]->parms.dv.directValue) <= 1.0)
- {
- func = nseel_asm_div_op_fast;
- func_e = nseel_asm_div_op_fast_end;
- }
- }
- } // not varparm
- if (cfunc_abiinfo & (BIF_CLEARDENORMAL | BIF_RETURNSBOOL) ) *canHaveDenormalOutput=0;
- else if (!(cfunc_abiinfo & BIF_WONTMAKEDENORMAL)) *canHaveDenormalOutput=1;
- func = GLUE_realAddress(func,func_e,&func_size);
- if (!func) RET_MINUS1_FAIL("failrealladdrfunc")
-
- if (bufOut_len < parm_size + func_size) RET_MINUS1_FAIL("funcsz")
- if (bufOut)
- {
- unsigned char *p=bufOut + parm_size;
- memcpy(p, func, func_size);
- if (preProc) p=preProc(p,func_size,ctx);
- if (repl)
- {
- if (repl[0]) p=EEL_GLUE_set_immediate(p,(INT_PTR)repl[0]);
- if (repl[1]) p=EEL_GLUE_set_immediate(p,(INT_PTR)repl[1]);
- if (repl[2]) p=EEL_GLUE_set_immediate(p,(INT_PTR)repl[2]);
- if (repl[3]) p=EEL_GLUE_set_immediate(p,(INT_PTR)repl[3]);
- }
- }
- if (restore_stack_amt)
- {
- int rem = restore_stack_amt;
- while (rem > 0)
- {
- int amt = rem;
- if (amt > 4096) amt=4096;
- rem -= amt;
- if (bufOut_len < parm_size + func_size + GLUE_MOVE_STACK_SIZE) RET_MINUS1_FAIL("insufficient size for varparm")
- if (bufOut) GLUE_MOVE_STACK(bufOut + parm_size + func_size, amt);
- parm_size += GLUE_MOVE_STACK_SIZE;
- }
- }
- if (cfunc_abiinfo&BIF_RETURNSONSTACK) *rvMode = RETURNVALUE_FPSTACK;
- else if (cfunc_abiinfo&BIF_RETURNSBOOL) *rvMode=RETURNVALUE_BOOL;
- return parm_size + func_size;
- }
- static int compileEelFunctionCall(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTableSize, const namespaceInformation *namespacePathToThis,
- int *rvMode, int *fpStackUse, int *canHaveDenormalOutput)
- {
- int func_size=0, parm_size=0;
- int pn;
- int last_nt_parm=-1,last_nt_parm_mode=0;
- void *func_e=NULL;
- int n_params;
- opcodeRec *parmptrs[NSEEL_MAX_EELFUNC_PARAMETERS];
- int cfp_numparams=-1;
- int cfp_statesize=0;
- EEL_F **cfp_ptrs=NULL;
- int func_raw=0;
- int do_parms;
- int x;
- void *func;
- for (x=0; x < 3; x ++) parmptrs[x] = op->parms.parms[x];
- if (op->opcodeType == OPCODETYPE_FUNCX)
- {
- n_params=0;
- for (x=0;x<3;x++)
- {
- opcodeRec *prni=op->parms.parms[x];
- while (prni && n_params < NSEEL_MAX_EELFUNC_PARAMETERS)
- {
- const int isMP = prni->opcodeType == OPCODETYPE_MOREPARAMS;
- parmptrs[n_params++] = isMP ? prni->parms.parms[0] : prni;
- if (!isMP) break;
- prni = prni->parms.parms[1];
- }
- }
- }
- else
- {
- n_params = 1 + op->opcodeType - OPCODETYPE_FUNC1;
- }
-
- *fpStackUse = 0;
- func = nseel_getEELFunctionAddress(ctx, op,
- &cfp_numparams,&cfp_statesize,&cfp_ptrs,
- computTableSize,
- &func_e, &func_raw,
- !!bufOut,namespacePathToThis,rvMode,fpStackUse,canHaveDenormalOutput, parmptrs, n_params);
- if (func_raw) func_size = (int) ((char*)func_e - (char*)func);
- else if (func) func = GLUE_realAddress(func,func_e,&func_size);
-
- if (!func) RET_MINUS1_FAIL("eelfuncaddr")
- *fpStackUse += 1;
- if (cfp_numparams>0 && n_params != cfp_numparams)
- {
- RET_MINUS1_FAIL("eelfuncnp")
- }
- // user defined function
- do_parms = cfp_numparams>0 && cfp_ptrs && cfp_statesize>0;
- // if function local/parameter state is zero, we need to allocate storage for it
- if (cfp_statesize>0 && cfp_ptrs && !cfp_ptrs[0])
- {
- EEL_F *pstate = newDataBlock(sizeof(EEL_F)*cfp_statesize,8);
- if (!pstate) RET_MINUS1_FAIL("eelfuncdb")
- for (pn=0;pn<cfp_statesize;pn++)
- {
- pstate[pn]=0;
- cfp_ptrs[pn] = pstate + pn;
- }
- }
- // first process parameters that are non-trivial
- for (pn=0; pn < n_params; pn++)
- {
- int needDenorm=0;
- int lsz,sUse=0;
-
- if (!parmptrs[pn] || OPCODE_IS_TRIVIAL(parmptrs[pn])) continue; // skip and process after
- if (last_nt_parm >= 0 && do_parms)
- {
- if (last_nt_parm_mode == RETURNVALUE_FPSTACK)
- {
- if (bufOut_len < parm_size + (int)sizeof(GLUE_POP_FPSTACK_TOSTACK)) RET_MINUS1_FAIL("eelfunc_size popfpstacktostack")
- if (bufOut) memcpy(bufOut + parm_size,GLUE_POP_FPSTACK_TOSTACK,sizeof(GLUE_POP_FPSTACK_TOSTACK));
- parm_size+=sizeof(GLUE_POP_FPSTACK_TOSTACK);
- }
- else
- {
- if (bufOut_len < parm_size + (int)sizeof(GLUE_PUSH_P1PTR_AS_VALUE)) RET_MINUS1_FAIL("eelfunc_size pushp1ptrasval")
-
- // push
- if (bufOut) memcpy(bufOut + parm_size,&GLUE_PUSH_P1PTR_AS_VALUE,sizeof(GLUE_PUSH_P1PTR_AS_VALUE));
- parm_size+=sizeof(GLUE_PUSH_P1PTR_AS_VALUE);
- }
- }
- last_nt_parm_mode=0;
- lsz = compileOpcodes(ctx,parmptrs[pn],bufOut ? bufOut + parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis,
- do_parms ? (RETURNVALUE_FPSTACK|RETURNVALUE_NORMAL) : RETURNVALUE_IGNORE,&last_nt_parm_mode,&sUse, &needDenorm);
- // todo: if needDenorm, denorm convert when copying parameter
- if (lsz<0) RET_MINUS1_FAIL("eelfunc, coc fail")
- if (last_nt_parm_mode == RETURNVALUE_FPSTACK) sUse++;
- if (sUse > *fpStackUse) *fpStackUse=sUse;
- parm_size += lsz;
- last_nt_parm = pn;
- }
- // pop non-trivial results into place
- if (last_nt_parm >=0 && do_parms)
- {
- while (--pn >= 0)
- {
- if (!parmptrs[pn] || OPCODE_IS_TRIVIAL(parmptrs[pn])) continue; // skip and process after
- if (pn == last_nt_parm)
- {
- if (last_nt_parm_mode == RETURNVALUE_FPSTACK)
- {
- // pop to memory directly
- const int cpsize = GLUE_POP_FPSTACK_TO_PTR(NULL,NULL);
- if (bufOut_len < parm_size + cpsize) RET_MINUS1_FAIL("eelfunc size popfpstacktoptr")
- if (bufOut) GLUE_POP_FPSTACK_TO_PTR((unsigned char *)bufOut + parm_size,cfp_ptrs[pn]);
- parm_size += cpsize;
- }
- else
- {
- // copy direct p1ptr to mem
- const int cpsize = GLUE_COPY_VALUE_AT_P1_TO_PTR(NULL,NULL);
- if (bufOut_len < parm_size + cpsize) RET_MINUS1_FAIL("eelfunc size copyvalueatp1toptr")
- if (bufOut) GLUE_COPY_VALUE_AT_P1_TO_PTR((unsigned char *)bufOut + parm_size,cfp_ptrs[pn]);
- parm_size += cpsize;
- }
- }
- else
- {
- const int popsize = GLUE_POP_VALUE_TO_ADDR(NULL,NULL);
- if (bufOut_len < parm_size + popsize) RET_MINUS1_FAIL("eelfunc size pop value to addr")
- if (bufOut) GLUE_POP_VALUE_TO_ADDR((unsigned char *)bufOut + parm_size,cfp_ptrs[pn]);
- parm_size+=popsize;
- }
- }
- }
- // finally, set any trivial parameters
- if (do_parms)
- {
- const int cpsize = GLUE_MOV_PX_DIRECTVALUE_SIZE + GLUE_COPY_VALUE_AT_P1_TO_PTR(NULL,NULL);
- for (pn=0; pn < n_params; pn++)
- {
- if (!parmptrs[pn] || !OPCODE_IS_TRIVIAL(parmptrs[pn])) continue; // set trivial values, we already set nontrivials
- if (bufOut_len < parm_size + cpsize) RET_MINUS1_FAIL("eelfunc size trivial set")
- if (bufOut)
- {
- if (generateValueToReg(ctx,parmptrs[pn],bufOut + parm_size,0,namespacePathToThis, 1)<0) RET_MINUS1_FAIL("eelfunc gvr fail")
- GLUE_COPY_VALUE_AT_P1_TO_PTR(bufOut + parm_size + GLUE_MOV_PX_DIRECTVALUE_SIZE,cfp_ptrs[pn]);
- }
- parm_size += cpsize;
- }
- }
- if (bufOut_len < parm_size + func_size) RET_MINUS1_FAIL("eelfunc size combined")
-
- if (bufOut) memcpy(bufOut + parm_size, func, func_size);
- return parm_size + func_size;
- // end of EEL function generation
- }
- #ifdef DUMP_OPS_DURING_COMPILE
- void dumpOp(compileContext *ctx, opcodeRec *op, int start);
- #endif
- #ifdef EEL_DUMP_OPS
- void dumpOpcodeTree(compileContext *ctx, FILE *fp, opcodeRec *op, int indent_amt)
- {
- const char *fname="";
- fprintf(fp,"%*sOP TYPE %d", indent_amt, "",
- op->opcodeType==OPCODETYPE_DIRECTVALUE_TEMPSTRING ? 10000 : // remap around OPCODETYPE_DIRECTVALUE_TEMPSTRING
- op->opcodeType > OPCODETYPE_DIRECTVALUE_TEMPSTRING ? op->opcodeType - 1 :
- op->opcodeType);
- if ((op->opcodeType == OPCODETYPE_FUNC1 ||
- op->opcodeType == OPCODETYPE_FUNC2 ||
- op->opcodeType == OPCODETYPE_FUNC3 ||
- op->opcodeType == OPCODETYPE_FUNCX))
- {
- if (op->fntype == FUNCTYPE_FUNCTIONTYPEREC)
- {
- functionType *fn_ptr = (functionType *)op->fn;
- fname = fn_ptr->name;
- }
- else if (op->fntype == FUNCTYPE_EELFUNC)
- {
- fname = op->relname;
- }
- if (!fname) fname ="";
- }
- switch (op->opcodeType)
- {
- case OPCODETYPE_DIRECTVALUE:
- fprintf(fp," DV=%f\r\n",op->parms.dv.directValue);
- break;
- case OPCODETYPE_VALUE_FROM_NAMESPACENAME: // this.* or namespace.* are encoded this way
- fprintf(fp," NSN=%s(%d)\r\n",op->relname?op->relname : "(null)",op->namespaceidx);
- break;
- case OPCODETYPE_VARPTR:
- {
- const char *nm = op->relname;
- if (!nm || !*nm)
- {
- int wb;
- for (wb = 0; wb < ctx->varTable_numBlocks; wb ++)
- {
- char **plist=ctx->varTable_Names[wb];
- if (!plist) break;
-
- if (op->parms.dv.valuePtr >= ctx->varTable_Values[wb] && op->parms.dv.valuePtr < ctx->varTable_Values[wb] + NSEEL_VARS_PER_BLOCK)
- {
- nm = plist[op->parms.dv.valuePtr - ctx->varTable_Values[wb]];
- break;
- }
- }
- }
- fprintf(fp," VP=%s\r\n", nm?nm : "(null)");
- }
- break;
- case OPCODETYPE_VARPTRPTR:
- fprintf(fp, " VPP?\r\n");
- break;
- case OPCODETYPE_FUNC1:
- if (op->fntype == FN_NOT)
- fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_not");
- else if (op->fntype == FN_NOTNOT)
- fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_notnot");
- else if (op->fntype == FN_MEMORY)
- fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_mem");
- else if (op->fntype == FN_GMEMORY)
- fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_gmem");
- else if (op->fntype == FN_WHILE)
- fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "while");
- else
- fprintf(fp," FUNC1 %d %s {\r\n",op->fntype, fname);
- if (op->parms.parms[0])
- dumpOpcodeTree(ctx,fp,op->parms.parms[0],indent_amt+2);
- else
- fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,"");
- fprintf(fp,"%*s}\r\n", indent_amt, "");
- break;
- case OPCODETYPE_MOREPARAMS:
- case OPCODETYPE_FUNC2:
- if (op->opcodeType == OPCODETYPE_MOREPARAMS)
- fprintf(fp," MOREPARAMS {\r\n");
- else
- {
- if (op->fntype == FN_POW)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "pow");
- else if (op->fntype == FN_MOD)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_mod");
- else if (op->fntype == FN_XOR)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_xor");
- else if (op->fntype == FN_SHL)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_shl");
- else if (op->fntype == FN_SHR)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_shr");
- else if (op->fntype == FN_LT)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_below");
- else if (op->fntype == FN_GT)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_above");
- else if (op->fntype == FN_LTE)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_beleq");
- else if (op->fntype == FN_GTE)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_aboeq");
- else if (op->fntype == FN_EQ)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_equal");
- else if (op->fntype == FN_NE)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_noteq");
- else if (op->fntype == FN_EQ_EXACT)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_equal_exact");
- else if (op->fntype == FN_NE_EXACT)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_noteq_exact");
- else if (op->fntype == FN_LOGICAL_AND)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_and");
- else if (op->fntype == FN_LOGICAL_OR)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_or");
- else if (op->fntype == FN_ASSIGN)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_set");
- else if (op->fntype == FN_ADD_OP)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_addop");
- else if (op->fntype == FN_SUB_OP)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_subop");
- else if (op->fntype == FN_MUL_OP)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_mulop");
- else if (op->fntype == FN_DIV_OP)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_divop");
- else if (op->fntype == FN_OR_OP)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_orop");
- else if (op->fntype == FN_AND_OP)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_andop");
- else if (op->fntype == FN_XOR_OP)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_xorop");
- else if (op->fntype == FN_MOD_OP)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_modop");
- else if (op->fntype == FN_POW_OP)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_powop");
- else if (op->fntype == FN_LOOP)
- fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "loop");
- else
- fprintf(fp," FUNC2 %d %s {\r\n",op->fntype, fname);
- }
- if (op->parms.parms[0])
- dumpOpcodeTree(ctx,fp,op->parms.parms[0],indent_amt+2);
- else
- fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,"");
- if (op->parms.parms[1])
- dumpOpcodeTree(ctx,fp,op->parms.parms[1],indent_amt+2);
- else
- fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,"");
- fprintf(fp,"%*s}\r\n", indent_amt, "");
- break;
- case OPCODETYPE_FUNCX:
- case OPCODETYPE_FUNC3:
- if (op->opcodeType == OPCODETYPE_FUNCX)
- fprintf(fp," FUNCX %d %s {\r\n",op->fntype, fname);
- else if (op->fntype == FN_IF_ELSE)
- fprintf(fp," FUNC3 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_if");
- else
- fprintf(fp," FUNC3 %d %s {\r\n",op->fntype, fname);
- if (op->parms.parms[0])
- dumpOpcodeTree(ctx,fp,op->parms.parms[0],indent_amt+2);
- else
- fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,"");
- if (op->parms.parms[1])
- dumpOpcodeTree(ctx,fp,op->parms.parms[1],indent_amt+2);
- else
- fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,"");
- if (op->parms.parms[2])
- dumpOpcodeTree(ctx,fp,op->parms.parms[2],indent_amt+2);
- else
- fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,"");
- fprintf(fp,"%*s}\r\n", indent_amt, "");
- break;
- }
- }
- #endif
- #ifdef GLUE_MAX_JMPSIZE
- #define CHECK_SIZE_FORJMP(x,y) if ((x)<0 || (x)>=GLUE_MAX_JMPSIZE) goto y;
- #define RET_MINUS1_FAIL_FALLBACK(err,j) goto j;
- #else
- #define CHECK_SIZE_FORJMP(x,y)
- #define RET_MINUS1_FAIL_FALLBACK(err,j) RET_MINUS1_FAIL(err)
- #endif
- static int compileOpcodesInternal(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTableSize, const namespaceInformation *namespacePathToThis, int *calledRvType, int preferredReturnValues, int *fpStackUse, int *canHaveDenormalOutput)
- {
- int rv_offset=0, denormal_force=-1;
- if (!op) RET_MINUS1_FAIL("coi !op")
- *fpStackUse=0;
- for (;;)
- {
- // special case: statement delimiting means we can process the left side into place, and iteratively do the second parameter without recursing
- // also we don't need to save/restore anything to the stack (which the normal 2 parameter function processing does)
- if (op->opcodeType == OPCODETYPE_FUNC2 && op->fntype == FN_JOIN_STATEMENTS)
- {
- int fUse1;
- int parm_size = compileOpcodes(ctx,op->parms.parms[0],bufOut,bufOut_len, computTableSize, namespacePathToThis, RETURNVALUE_IGNORE, NULL,&fUse1,NULL);
- if (parm_size < 0) RET_MINUS1_FAIL("coc join fail")
- op = op->parms.parms[1];
- if (!op) RET_MINUS1_FAIL("join got to null")
- if (fUse1>*fpStackUse) *fpStackUse=fUse1;
- if (bufOut) bufOut += parm_size;
- bufOut_len -= parm_size;
- rv_offset += parm_size;
- #ifdef DUMP_OPS_DURING_COMPILE
- if (op->opcodeType != OPCODETYPE_FUNC2 || op->fntype != FN_JOIN_STATEMENTS) dumpOp(ctx,op,0);
- #endif
- denormal_force=-1;
- }
- // special case: __denormal_likely(), __denormal_unlikely()
- else if (op->opcodeType == OPCODETYPE_FUNC1 && (op->fntype == FN_DENORMAL_LIKELY || op->fntype == FN_DENORMAL_UNLIKELY))
- {
- denormal_force = op->fntype == FN_DENORMAL_LIKELY;
- op = op->parms.parms[0];
- }
- else
- {
- break;
- }
- }
- if (denormal_force >= 0 && canHaveDenormalOutput)
- {
- *canHaveDenormalOutput = denormal_force;
- canHaveDenormalOutput = &denormal_force; // prevent it from being changed by functions below
- }
- // special case: BAND/BOR
- if (op->opcodeType == OPCODETYPE_FUNC2 && (op->fntype == FN_LOGICAL_AND || op->fntype == FN_LOGICAL_OR))
- {
- int fUse1=0;
- int parm_size;
- #ifdef GLUE_MAX_JMPSIZE
- int parm_size_pre;
- #endif
- int retType=RETURNVALUE_IGNORE;
- if (preferredReturnValues != RETURNVALUE_IGNORE) retType = RETURNVALUE_BOOL;
- *calledRvType = retType;
-
- parm_size = compileOpcodes(ctx,op->parms.parms[0],bufOut,bufOut_len, computTableSize, namespacePathToThis, RETURNVALUE_BOOL, NULL, &fUse1, NULL);
- if (parm_size < 0) RET_MINUS1_FAIL("loop band/bor coc fail")
-
- if (fUse1 > *fpStackUse) *fpStackUse=fUse1;
- #ifdef GLUE_MAX_JMPSIZE
- parm_size_pre=parm_size;
- #endif
- {
- int sz2, fUse2=0;
- unsigned char *destbuf;
- const int testsz=op->fntype == FN_LOGICAL_OR ? sizeof(GLUE_JMP_IF_P1_NZ) : sizeof(GLUE_JMP_IF_P1_Z);
- if (bufOut_len < parm_size+testsz) RET_MINUS1_FAIL_FALLBACK("band/bor size fail",doNonInlinedAndOr_)
- if (bufOut) memcpy(bufOut+parm_size,op->fntype == FN_LOGICAL_OR ? GLUE_JMP_IF_P1_NZ : GLUE_JMP_IF_P1_Z,testsz);
- parm_size += testsz;
- destbuf = bufOut + parm_size;
- sz2= compileOpcodes(ctx,op->parms.parms[1],bufOut?bufOut+parm_size:NULL,bufOut_len-parm_size, computTableSize, namespacePathToThis, retType, NULL,&fUse2, NULL);
- CHECK_SIZE_FORJMP(sz2,doNonInlinedAndOr_)
- if (sz2<0) RET_MINUS1_FAIL("band/bor coc fail")
- parm_size+=sz2;
- if (bufOut) GLUE_JMP_SET_OFFSET(destbuf, (bufOut + parm_size) - destbuf);
- if (fUse2 > *fpStackUse) *fpStackUse=fUse2;
- return rv_offset + parm_size;
- }
- #ifdef GLUE_MAX_JMPSIZE
- if (0)
- {
- void *stub;
- int stubsize;
- unsigned char *newblock2, *p;
-
- // encode as function call
- doNonInlinedAndOr_:
- parm_size = parm_size_pre;
- if (op->fntype == FN_LOGICAL_AND)
- {
- stub = GLUE_realAddress(nseel_asm_band,nseel_asm_band_end,&stubsize);
- }
- else
- {
- stub = GLUE_realAddress(nseel_asm_bor,nseel_asm_bor_end,&stubsize);
- }
-
- if (bufOut_len < parm_size + stubsize) RET_MINUS1_FAIL("band/bor len fail")
-
- if (bufOut)
- {
- int fUse2=0;
- newblock2 = compileCodeBlockWithRet(ctx,op->parms.parms[1],computTableSize,namespacePathToThis, retType, NULL, &fUse2, NULL);
- if (!newblock2) RET_MINUS1_FAIL("band/bor ccbwr fail")
- if (fUse2 > *fpStackUse) *fpStackUse=fUse2;
-
- p = bufOut + parm_size;
- memcpy(p, stub, stubsize);
-
- p=EEL_GLUE_set_immediate(p,(INT_PTR)newblock2);
- }
- return rv_offset + parm_size + stubsize;
- }
- #endif
- }
- if (op->opcodeType == OPCODETYPE_FUNC3 && op->fntype == FN_IF_ELSE) // special case: IF
- {
- int fUse1=0;
- #ifdef GLUE_MAX_JMPSIZE
- int parm_size_pre;
- #endif
- int use_rv = RETURNVALUE_IGNORE;
- int rvMode=0;
- int parm_size = compileOpcodes(ctx,op->parms.parms[0],bufOut,bufOut_len, computTableSize, namespacePathToThis, RETURNVALUE_BOOL|RETURNVALUE_BOOL_REVERSED, &rvMode,&fUse1, NULL);
- if (parm_size < 0) RET_MINUS1_FAIL("if coc fail")
- if (fUse1 > *fpStackUse) *fpStackUse=fUse1;
- if (preferredReturnValues & RETURNVALUE_NORMAL) use_rv=RETURNVALUE_NORMAL;
- else if (preferredReturnValues & RETURNVALUE_FPSTACK) use_rv=RETURNVALUE_FPSTACK;
- else if (preferredReturnValues & RETURNVALUE_BOOL) use_rv=RETURNVALUE_BOOL;
-
- *calledRvType = use_rv;
- #ifdef GLUE_MAX_JMPSIZE
- parm_size_pre = parm_size;
- #endif
- {
- int csz,hasSecondHalf;
- if (rvMode & RETURNVALUE_BOOL_REVERSED)
- {
- if (bufOut_len < parm_size + (int)sizeof(GLUE_JMP_IF_P1_NZ)) RET_MINUS1_FAIL_FALLBACK("if size fail",doNonInlineIf_)
- if (bufOut) memcpy(bufOut+parm_size,GLUE_JMP_IF_P1_NZ,sizeof(GLUE_JMP_IF_P1_NZ));
- parm_size += sizeof(GLUE_JMP_IF_P1_NZ);
- }
- else
- {
- if (bufOut_len < parm_size + (int)sizeof(GLUE_JMP_IF_P1_Z)) RET_MINUS1_FAIL_FALLBACK("if size fail",doNonInlineIf_)
- if (bufOut) memcpy(bufOut+parm_size,GLUE_JMP_IF_P1_Z,sizeof(GLUE_JMP_IF_P1_Z));
- parm_size += sizeof(GLUE_JMP_IF_P1_Z);
- }
- csz=compileOpcodes(ctx,op->parms.parms[1],bufOut ? bufOut+parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, use_rv, NULL,&fUse1, canHaveDenormalOutput);
- if (fUse1 > *fpStackUse) *fpStackUse=fUse1;
- hasSecondHalf = preferredReturnValues || !OPCODE_IS_TRIVIAL(op->parms.parms[2]);
- CHECK_SIZE_FORJMP(csz,doNonInlineIf_)
- if (csz<0) RET_MINUS1_FAIL("if coc fial")
- if (bufOut) GLUE_JMP_SET_OFFSET(bufOut + parm_size, csz + (hasSecondHalf?sizeof(GLUE_JMP_NC):0));
- parm_size+=csz;
- if (hasSecondHalf)
- {
- if (bufOut_len < parm_size + (int)sizeof(GLUE_JMP_NC)) RET_MINUS1_FAIL_FALLBACK("if len fail",doNonInlineIf_)
- if (bufOut) memcpy(bufOut+parm_size,GLUE_JMP_NC,sizeof(GLUE_JMP_NC));
- parm_size+=sizeof(GLUE_JMP_NC);
- csz=compileOpcodes(ctx,op->parms.parms[2],bufOut ? bufOut+parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, use_rv, NULL, &fUse1, canHaveDenormalOutput);
- CHECK_SIZE_FORJMP(csz,doNonInlineIf_)
- if (csz<0) RET_MINUS1_FAIL("if coc 2 fail")
- // update jump address
- if (bufOut) GLUE_JMP_SET_OFFSET(bufOut + parm_size,csz);
- parm_size+=csz;
- if (fUse1 > *fpStackUse) *fpStackUse=fUse1;
- }
- return rv_offset + parm_size;
- }
- #ifdef GLUE_MAX_JMPSIZE
- if (0)
- {
- unsigned char *newblock2,*newblock3,*ptr;
- void *stub;
- int stubsize;
- doNonInlineIf_:
- parm_size = parm_size_pre;
- stub = GLUE_realAddress(nseel_asm_if,nseel_asm_if_end,&stubsize);
-
- if (!stub || bufOut_len < parm_size + stubsize) RET_MINUS1_FAIL(stub ? "if sz fail" : "if addr fail")
-
- if (bufOut)
- {
- int fUse2=0;
- newblock2 = compileCodeBlockWithRet(ctx,op->parms.parms[1],computTableSize,namespacePathToThis, use_rv, NULL,&fUse2, canHaveDenormalOutput);
- if (fUse2 > *fpStackUse) *fpStackUse=fUse2;
- newblock3 = compileCodeBlockWithRet(ctx,op->parms.parms[2],computTableSize,namespacePathToThis, use_rv, NULL,&fUse2, canHaveDenormalOutput);
- if (fUse2 > *fpStackUse) *fpStackUse=fUse2;
- if (!newblock2 || !newblock3) RET_MINUS1_FAIL("if subblock gen fail")
-
- ptr = bufOut + parm_size;
- memcpy(ptr, stub, stubsize);
-
- ptr=EEL_GLUE_set_immediate(ptr,(INT_PTR)newblock2);
- EEL_GLUE_set_immediate(ptr,(INT_PTR)newblock3);
- }
- return rv_offset + parm_size + stubsize;
- }
- #endif
- }
- {
- // special case: while
- if (op->opcodeType == OPCODETYPE_FUNC1 && op->fntype == FN_WHILE)
- {
- *calledRvType = RETURNVALUE_BOOL;
- #ifndef GLUE_INLINE_LOOPS
- // todo: PPC looping support when loop length is small enough
- {
- unsigned char *pwr=bufOut;
- unsigned char *newblock2;
- int stubsz;
- void *stubfunc = GLUE_realAddress(nseel_asm_repeatwhile,nseel_asm_repeatwhile_end,&stubsz);
- if (!stubfunc || bufOut_len < stubsz) RET_MINUS1_FAIL(stubfunc ? "repeatwhile size fail" :"repeatwhile addr fail")
- if (bufOut)
- {
- newblock2=compileCodeBlockWithRet(ctx,op->parms.parms[0],computTableSize,namespacePathToThis, RETURNVALUE_BOOL, NULL, fpStackUse, NULL);
- if (!newblock2) RET_MINUS1_FAIL("repeatwhile ccbwr fail")
-
- memcpy(pwr,stubfunc,stubsz);
- pwr=EEL_GLUE_set_immediate(pwr,(INT_PTR)newblock2);
- }
-
- return rv_offset+stubsz;
- }
- #else
- {
- #ifndef GLUE_WHILE_END_NOJUMP
- unsigned char *jzoutpt;
- #endif
- unsigned char *looppt;
- int parm_size=0,subsz;
- if (bufOut_len < parm_size + (int)(GLUE_WHILE_SETUP_SIZE + sizeof(GLUE_WHILE_BEGIN))) RET_MINUS1_FAIL("while size fail 1")
- if (bufOut) memcpy(bufOut + parm_size,GLUE_WHILE_SETUP,GLUE_WHILE_SETUP_SIZE);
- parm_size+=GLUE_WHILE_SETUP_SIZE;
- looppt = bufOut + parm_size;
- if (bufOut) memcpy(bufOut + parm_size,GLUE_WHILE_BEGIN,sizeof(GLUE_WHILE_BEGIN));
- parm_size+=sizeof(GLUE_WHILE_BEGIN);
- subsz = compileOpcodes(ctx,op->parms.parms[0],bufOut ? (bufOut + parm_size) : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, RETURNVALUE_BOOL, NULL,fpStackUse, NULL);
- if (subsz<0) RET_MINUS1_FAIL("while coc fail")
- if (bufOut_len < parm_size + (int)(sizeof(GLUE_WHILE_END) + sizeof(GLUE_WHILE_CHECK_RV))) RET_MINUS1_FAIL("which size fial 2")
- parm_size+=subsz;
- if (bufOut) memcpy(bufOut + parm_size, GLUE_WHILE_END, sizeof(GLUE_WHILE_END));
- parm_size+=sizeof(GLUE_WHILE_END);
- #ifndef GLUE_WHILE_END_NOJUMP
- jzoutpt = bufOut + parm_size;
- #endif
- if (bufOut) memcpy(bufOut + parm_size, GLUE_WHILE_CHECK_RV, sizeof(GLUE_WHILE_CHECK_RV));
- parm_size+=sizeof(GLUE_WHILE_CHECK_RV);
- if (bufOut)
- {
- GLUE_JMP_SET_OFFSET(bufOut + parm_size,(looppt - (bufOut+parm_size)) );
- #ifndef GLUE_WHILE_END_NOJUMP
- GLUE_JMP_SET_OFFSET(jzoutpt, (bufOut + parm_size) - jzoutpt);
- #endif
- }
- return rv_offset+parm_size;
- }
- #endif
- }
- // special case: loop
- if (op->opcodeType == OPCODETYPE_FUNC2 && op->fntype == FN_LOOP)
- {
- int fUse1;
- int parm_size = compileOpcodes(ctx,op->parms.parms[0],bufOut,bufOut_len, computTableSize, namespacePathToThis, RETURNVALUE_FPSTACK, NULL,&fUse1, NULL);
- if (parm_size < 0) RET_MINUS1_FAIL("loop coc fail")
-
- *calledRvType = RETURNVALUE_BOOL;
- if (fUse1 > *fpStackUse) *fpStackUse=fUse1;
-
- #ifndef GLUE_INLINE_LOOPS
- // todo: PPC looping support when loop length is small enough
- {
- void *stub;
- int stubsize;
- unsigned char *newblock2, *p;
- stub = GLUE_realAddress(nseel_asm_repeat,nseel_asm_repeat_end,&stubsize);
- if (bufOut_len < parm_size + stubsize) RET_MINUS1_FAIL("loop size fail")
- if (bufOut)
- {
- newblock2 = compileCodeBlockWithRet(ctx,op->parms.parms[1],computTableSize,namespacePathToThis, RETURNVALUE_IGNORE, NULL,fpStackUse, NULL);
-
- p = bufOut + parm_size;
- memcpy(p, stub, stubsize);
-
- p=EEL_GLUE_set_immediate(p,(INT_PTR)newblock2);
- }
- return rv_offset + parm_size + stubsize;
- }
- #else
- {
- int subsz;
- int fUse2=0;
- unsigned char *skipptr1,*loopdest;
- if (bufOut_len < parm_size + (int)(sizeof(GLUE_LOOP_LOADCNT) + GLUE_LOOP_CLAMPCNT_SIZE + GLUE_LOOP_BEGIN_SIZE)) RET_MINUS1_FAIL("loop size fail")
- // store, convert to int, compare against 1, if less than, skip to end
- if (bufOut) memcpy(bufOut+parm_size,GLUE_LOOP_LOADCNT,sizeof(GLUE_LOOP_LOADCNT));
- parm_size += sizeof(GLUE_LOOP_LOADCNT);
- skipptr1 = bufOut+parm_size;
- // compare aginst max loop length, jump to loop start if not above it
- if (bufOut) memcpy(bufOut+parm_size,GLUE_LOOP_CLAMPCNT,GLUE_LOOP_CLAMPCNT_SIZE);
- parm_size += GLUE_LOOP_CLAMPCNT_SIZE;
- // loop code:
- loopdest = bufOut + parm_size;
- if (bufOut) memcpy(bufOut+parm_size,GLUE_LOOP_BEGIN,GLUE_LOOP_BEGIN_SIZE);
- parm_size += GLUE_LOOP_BEGIN_SIZE;
- subsz = compileOpcodes(ctx,op->parms.parms[1],bufOut ? (bufOut + parm_size) : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, RETURNVALUE_IGNORE, NULL, &fUse2, NULL);
- if (subsz<0) RET_MINUS1_FAIL("loop coc fail")
- if (fUse2 > *fpStackUse) *fpStackUse=fUse2;
- parm_size += subsz;
- if (bufOut_len < parm_size + (int)sizeof(GLUE_LOOP_END)) RET_MINUS1_FAIL("loop size fail 2")
- if (bufOut) memcpy(bufOut+parm_size,GLUE_LOOP_END,sizeof(GLUE_LOOP_END));
- parm_size += sizeof(GLUE_LOOP_END);
-
- if (bufOut)
- {
- GLUE_JMP_SET_OFFSET(bufOut + parm_size,loopdest - (bufOut+parm_size));
- GLUE_JMP_SET_OFFSET(skipptr1, (bufOut+parm_size) - skipptr1);
- }
- return rv_offset + parm_size;
- }
- #endif
- }
- }
-
- switch (op->opcodeType)
- {
- case OPCODETYPE_DIRECTVALUE:
- if (preferredReturnValues == RETURNVALUE_BOOL)
- {
- int w = fabs(op->parms.dv.directValue) >= NSEEL_CLOSEFACTOR;
- int wsz=(w?sizeof(GLUE_SET_P1_NZ):sizeof(GLUE_SET_P1_Z));
- *calledRvType = RETURNVALUE_BOOL;
- if (bufOut_len < wsz) RET_MINUS1_FAIL("direct bool size fail3")
- if (bufOut) memcpy(bufOut,w?GLUE_SET_P1_NZ:GLUE_SET_P1_Z,wsz);
- return rv_offset+wsz;
- }
- else if (preferredReturnValues & RETURNVALUE_FPSTACK)
- {
- #ifdef GLUE_HAS_FLDZ
- if (op->parms.dv.directValue == 0.0)
- {
- *fpStackUse = 1;
- *calledRvType = RETURNVALUE_FPSTACK;
- if (bufOut_len < sizeof(GLUE_FLDZ)) RET_MINUS1_FAIL("direct fp fail 1")
- if (bufOut) memcpy(bufOut,GLUE_FLDZ,sizeof(GLUE_FLDZ));
- return rv_offset+sizeof(GLUE_FLDZ);
- }
- #endif
- #ifdef GLUE_HAS_FLD1
- if (op->parms.dv.directValue == 1.0)
- {
- *fpStackUse = 1;
- *calledRvType = RETURNVALUE_FPSTACK;
- if (bufOut_len < sizeof(GLUE_FLD1)) RET_MINUS1_FAIL("direct fp fail 1")
- if (bufOut) memcpy(bufOut,GLUE_FLD1,sizeof(GLUE_FLD1));
- return rv_offset+sizeof(GLUE_FLD1);
- }
- #endif
- }
- // fall through
- case OPCODETYPE_DIRECTVALUE_TEMPSTRING:
- case OPCODETYPE_VALUE_FROM_NAMESPACENAME:
- case OPCODETYPE_VARPTR:
- case OPCODETYPE_VARPTRPTR:
- #ifdef GLUE_MOV_PX_DIRECTVALUE_TOSTACK_SIZE
- if (OPCODE_IS_TRIVIAL(op))
- {
- if (preferredReturnValues & RETURNVALUE_FPSTACK)
- {
- *fpStackUse = 1;
- if (bufOut_len < GLUE_MOV_PX_DIRECTVALUE_TOSTACK_SIZE) RET_MINUS1_FAIL("direct fp fail 2")
- if (bufOut)
- {
- if (generateValueToReg(ctx,op,bufOut,-1,namespacePathToThis, 1 /*allow caching*/)<0) RET_MINUS1_FAIL("direct fp fail gvr")
- }
- *calledRvType = RETURNVALUE_FPSTACK;
- return rv_offset+GLUE_MOV_PX_DIRECTVALUE_TOSTACK_SIZE;
- }
- }
- #endif
- if (bufOut_len < GLUE_MOV_PX_DIRECTVALUE_SIZE)
- {
- RET_MINUS1_FAIL("direct value fail 1")
- }
- if (bufOut)
- {
- if (generateValueToReg(ctx,op,bufOut,0,namespacePathToThis,
- (preferredReturnValues&(RETURNVALUE_FPSTACK|RETURNVALUE_CACHEABLE))!=0)<0)
- {
- RET_MINUS1_FAIL("direct value gvr fail3")
- }
- }
- return rv_offset + GLUE_MOV_PX_DIRECTVALUE_SIZE;
- case OPCODETYPE_FUNCX:
- case OPCODETYPE_FUNC1:
- case OPCODETYPE_FUNC2:
- case OPCODETYPE_FUNC3:
-
- if (op->fntype == FUNCTYPE_EELFUNC)
- {
- int a;
-
- a = compileEelFunctionCall(ctx,op,bufOut,bufOut_len,computTableSize,namespacePathToThis, calledRvType,fpStackUse,canHaveDenormalOutput);
- if (a<0) return a;
- rv_offset += a;
- }
- else
- {
- int a;
- a = compileNativeFunctionCall(ctx,op,bufOut,bufOut_len,computTableSize,namespacePathToThis, calledRvType,fpStackUse,preferredReturnValues,canHaveDenormalOutput);
- if (a<0)return a;
- rv_offset += a;
- }
- return rv_offset;
- }
- RET_MINUS1_FAIL("default opcode fail")
- }
- #ifdef DUMP_OPS_DURING_COMPILE
- FILE *g_debugfp;
- int g_debugfp_indent;
- int g_debugfp_histsz=0;
- void dumpOp(compileContext *ctx, opcodeRec *op, int start)
- {
- if (start>=0)
- {
- if (g_debugfp)
- {
- static opcodeRec **hist;
-
- int x;
- int hit=0;
- if (!hist) hist = (opcodeRec**) calloc(1024,1024*sizeof(opcodeRec*));
- for(x=0;x<g_debugfp_histsz;x++)
- {
- if (hist[x] == op) { hit=1; break; }
- }
- if (x ==g_debugfp_histsz && g_debugfp_histsz<1024*1024) hist[g_debugfp_histsz++] = op;
- if (!start)
- {
- g_debugfp_indent-=2;
- fprintf(g_debugfp,"%*s}(join)\n",g_debugfp_indent," ");
- }
- if (g_debugfp_indent>=100) *(char *)1=0;
- fprintf(g_debugfp,"%*s{ %p : %d%s: ",g_debugfp_indent," ",op,op->opcodeType, hit ? " -- DUPLICATE" : "");
- switch (op->opcodeType)
- {
- case OPCODETYPE_DIRECTVALUE:
- fprintf(g_debugfp,"dv %f",op->parms.dv.directValue);
- break;
- case OPCODETYPE_VARPTR:
- if (op->relname && op->relname[0])
- {
- fprintf(g_debugfp,"var %s",op->relname);
- }
- else
- {
- int wb;
- for (wb = 0; wb < ctx->varTable_numBlocks; wb ++)
- {
- char **plist=ctx->varTable_Names[wb];
- if (!plist) break;
-
- if (op->parms.dv.valuePtr >= ctx->varTable_Values[wb] && op->parms.dv.valuePtr < ctx->varTable_Values[wb] + NSEEL_VARS_PER_BLOCK)
- {
- fprintf(g_debugfp,"var %s",plist[op->parms.dv.valuePtr - ctx->varTable_Values[wb]]);
- break;
- }
- }
- }
- break;
- case OPCODETYPE_FUNC1:
- case OPCODETYPE_FUNC2:
- case OPCODETYPE_FUNC3:
- case OPCODETYPE_FUNCX:
- if (op->fntype == FUNCTYPE_FUNCTIONTYPEREC)
- {
- functionType *p=(functionType*)op->fn;
- fprintf(g_debugfp,"func %d: %s",p->nParams&0xff,p->name);
- }
- else
- fprintf(g_debugfp,"sf %d",op->fntype);
- break;
- }
- fprintf(g_debugfp,"\n");
- g_debugfp_indent+=2;
- }
- }
- else
- {
- if (g_debugfp)
- {
- g_debugfp_indent-=2;
- fprintf(g_debugfp,"%*s}%p\n",g_debugfp_indent," ",op);
- }
- }
- }
- #endif
- int compileOpcodes(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTableSize, const namespaceInformation *namespacePathToThis,
- int supportedReturnValues, int *rvType, int *fpStackUse, int *canHaveDenormalOutput)
- {
- int code_returns=RETURNVALUE_NORMAL;
- int fpsu=0;
- int codesz;
- int denorm=0;
- #ifdef DUMP_OPS_DURING_COMPILE
- dumpOp(ctx,op,1);
- #endif
-
- codesz = compileOpcodesInternal(ctx,op,bufOut,bufOut_len,computTableSize,namespacePathToThis,&code_returns, supportedReturnValues,&fpsu,&denorm);
- if (denorm && canHaveDenormalOutput) *canHaveDenormalOutput=1;
- #ifdef DUMP_OPS_DURING_COMPILE
- dumpOp(ctx,op,-1);
- #endif
- #ifdef EEL_DUMP_OPS
- // dump opcode trees for verification, after optimizing
- if (g_eel_dump_fp2)
- {
- fprintf(g_eel_dump_fp2,"-- compileOpcodes generated %d bytes of code!\r\n",codesz);
- }
- #endif
- if (codesz < 0) return codesz;
- /*
- {
- char buf[512];
- sprintf(buf,"opcode %d %d (%s): fpu use: %d\n",op->opcodeType,op->fntype,
- op->opcodeType >= OPCODETYPE_FUNC1 && op->fntype == FUNCTYPE_FUNCTIONTYPEREC ? (
- ((functionType *)op->fn)->name
- ) : "",
- fpsu);
- OutputDebugString(buf);
- }
- */
- if (fpStackUse) *fpStackUse=fpsu;
- if (bufOut) bufOut += codesz;
- bufOut_len -= codesz;
- if (code_returns == RETURNVALUE_BOOL && !(supportedReturnValues & RETURNVALUE_BOOL) && supportedReturnValues)
- {
- int stubsize;
- void *stub = GLUE_realAddress(nseel_asm_booltofp,nseel_asm_booltofp_end,&stubsize);
- if (!stub || bufOut_len < stubsize) RET_MINUS1_FAIL(stub?"booltofp size":"booltfp addr")
- if (bufOut)
- {
- memcpy(bufOut,stub,stubsize);
- bufOut += stubsize;
- }
- codesz+=stubsize;
- bufOut_len -= stubsize;
-
- code_returns = RETURNVALUE_FPSTACK;
- }
- // default processing of code_returns to meet return value requirements
- if (supportedReturnValues & code_returns)
- {
- if (rvType) *rvType = code_returns;
- return codesz;
- }
- if (rvType) *rvType = RETURNVALUE_IGNORE;
- if (code_returns == RETURNVALUE_NORMAL)
- {
- if (supportedReturnValues & (RETURNVALUE_FPSTACK|RETURNVALUE_BOOL))
- {
- if (bufOut_len < GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE) RET_MINUS1_FAIL("pushvalatpxtofpstack,size")
- if (bufOut)
- {
- GLUE_PUSH_VAL_AT_PX_TO_FPSTACK(bufOut,0); // always fld qword [eax] but we might change that later
- bufOut += GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE;
- }
- codesz += GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE;
- bufOut_len -= GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE;
- if (supportedReturnValues & RETURNVALUE_BOOL)
- {
- code_returns = RETURNVALUE_FPSTACK;
- }
- else
- {
- if (rvType) *rvType = RETURNVALUE_FPSTACK;
- }
- }
- }
- if (code_returns == RETURNVALUE_FPSTACK)
- {
- if (supportedReturnValues & (RETURNVALUE_BOOL|RETURNVALUE_BOOL_REVERSED))
- {
- int stubsize;
- void *stub;
-
- if (supportedReturnValues & RETURNVALUE_BOOL_REVERSED)
- {
- if (rvType) *rvType = RETURNVALUE_BOOL_REVERSED;
- stub = GLUE_realAddress(nseel_asm_fptobool_rev,nseel_asm_fptobool_rev_end,&stubsize);
- }
- else
- {
- if (rvType) *rvType = RETURNVALUE_BOOL;
- stub = GLUE_realAddress(nseel_asm_fptobool,nseel_asm_fptobool_end,&stubsize);
- }
- if (!stub || bufOut_len < stubsize) RET_MINUS1_FAIL(stub?"fptobool size":"fptobool addr")
- if (bufOut)
- {
- memcpy(bufOut,stub,stubsize);
- bufOut += stubsize;
- }
- codesz+=stubsize;
- bufOut_len -= stubsize;
- }
- else if (supportedReturnValues & RETURNVALUE_NORMAL)
- {
- if (computTableSize) (*computTableSize) ++;
- if (bufOut_len < GLUE_POP_FPSTACK_TO_WTP_TO_PX_SIZE) RET_MINUS1_FAIL("popfpstacktowtptopxsize")
- // generate fp-pop to temp space
- if (bufOut) GLUE_POP_FPSTACK_TO_WTP_TO_PX(bufOut,0);
- codesz+=GLUE_POP_FPSTACK_TO_WTP_TO_PX_SIZE;
- if (rvType) *rvType = RETURNVALUE_NORMAL;
- }
- else
- {
- // toss return value that will be ignored
- if (bufOut_len < GLUE_POP_FPSTACK_SIZE) RET_MINUS1_FAIL("popfpstack size")
- if (bufOut) memcpy(bufOut,GLUE_POP_FPSTACK,GLUE_POP_FPSTACK_SIZE);
- codesz+=GLUE_POP_FPSTACK_SIZE;
- }
- }
- return codesz;
- }
- #if 0
- static void movestringover(char *str, int amount)
- {
- char tmp[1024+8];
- int l=(int)strlen(str);
- l=wdl_min(1024-amount-1,l);
- memcpy(tmp,str,l+1);
- while (l >= 0 && tmp[l]!='\n') l--;
- l++;
- tmp[l]=0;//ensure we null terminate
- memcpy(str+amount,tmp,l+1);
- }
- #endif
- //------------------------------------------------------------------------------
- NSEEL_CODEHANDLE NSEEL_code_compile(NSEEL_VMCTX _ctx, const char *_expression, int lineoffs)
- {
- return NSEEL_code_compile_ex(_ctx,_expression,lineoffs,0);
- }
- typedef struct topLevelCodeSegmentRec {
- struct topLevelCodeSegmentRec *_next;
- void *code;
- int codesz;
- int tmptable_use;
- } topLevelCodeSegmentRec;
- NSEEL_CODEHANDLE NSEEL_code_compile_ex(NSEEL_VMCTX _ctx, const char *_expression, int lineoffs, int compile_flags)
- {
- compileContext *ctx = (compileContext *)_ctx;
- const char *endptr;
- const char *_expression_end;
- codeHandleType *handle;
- topLevelCodeSegmentRec *startpts_tail=NULL;
- topLevelCodeSegmentRec *startpts=NULL;
- _codeHandleFunctionRec *oldCommonFunctionList;
- int curtabptr_sz=0;
- void *curtabptr=NULL;
- int had_err=0;
- if (!ctx) return 0;
- ctx->directValueCache=0;
- ctx->optimizeDisableFlags=0;
- ctx->gotEndOfInput=0;
- ctx->current_compile_flags = compile_flags;
- if (compile_flags & NSEEL_CODE_COMPILE_FLAG_COMMONFUNCS_RESET)
- {
- ctx->functions_common=NULL; // reset common function list
- }
- else
- {
- // reset common compiled function code, forcing a recompile if shared
- _codeHandleFunctionRec *a = ctx->functions_common;
- while (a)
- {
- _codeHandleFunctionRec *b = a->derivedCopies;
- if (a->localstorage)
- {
- // force local storage actual values to be reallocated if used again
- memset(a->localstorage,0,sizeof(EEL_F *) * a->localstorage_size);
- }
- a->startptr = NULL; // force this copy to be recompiled
- a->startptr_size = -1;
- while (b)
- {
- b->startptr = NULL; // force derived copies to get recompiled
- b->startptr_size = -1;
- // no need to reset b->localstorage, since it points to a->localstorage
- b=b->derivedCopies;
- }
- a=a->next;
- }
- }
-
- ctx->last_error_string[0]=0;
- if (!_expression || !*_expression) return 0;
- _expression_end = _expression + strlen(_expression);
- oldCommonFunctionList = ctx->functions_common;
- ctx->isGeneratingCommonFunction=0;
- ctx->isSharedFunctions = !!(compile_flags & NSEEL_CODE_COMPILE_FLAG_COMMONFUNCS);
- ctx->functions_local = NULL;
- freeBlocks(&ctx->tmpblocks_head); // free blocks
- freeBlocks(&ctx->blocks_head); // free blocks
- freeBlocks(&ctx->blocks_head_data); // free blocks
- memset(ctx->l_stats,0,sizeof(ctx->l_stats));
- handle = (codeHandleType*)newDataBlock(sizeof(codeHandleType),8);
- if (!handle)
- {
- return 0;
- }
-
- memset(handle,0,sizeof(codeHandleType));
- ctx->l_stats[0] += (int)(_expression_end - _expression);
- ctx->tmpCodeHandle = handle;
- endptr=_expression;
- while (*endptr)
- {
- int computTableTop = 0;
- int startptr_size=0;
- void *startptr=NULL;
- opcodeRec *start_opcode=NULL;
- const char *expr=endptr;
-
- int function_numparms=0;
- char is_fname[NSEEL_MAX_VARIABLE_NAMELEN+1];
- is_fname[0]=0;
- memset(ctx->function_localTable_Size,0,sizeof(ctx->function_localTable_Size));
- memset(ctx->function_localTable_Names,0,sizeof(ctx->function_localTable_Names));
- ctx->function_localTable_ValuePtrs=0;
- ctx->function_usesNamespaces=0;
- ctx->function_curName=NULL;
- ctx->function_globalFlag=0;
-
- ctx->errVar=0;
- // single out top level segment
- {
- int had_something = 0, pcnt=0, pcnt2=0;
- int state=0;
- for (;;)
- {
- int l;
- const char *p=nseel_simple_tokenizer(&endptr,_expression_end,&l,&state);
- if (!p)
- {
- if (pcnt || pcnt2) ctx->gotEndOfInput|=4;
- break;
- }
- if (*p == ';')
- {
- if (had_something && !pcnt && !pcnt2) break;
- }
- else if (*p == '/' && l > 1 && (p[1] == '/' || p[1] == '*'))
- {
- if (l > 19 && !strnicmp(p,"//#eel-no-optimize:",19))
- ctx->optimizeDisableFlags = atoi(p+19);
- }
- else
- {
- if (!had_something)
- {
- expr = p;
- had_something = 1;
- }
- if (*p == '(') pcnt++;
- else if (*p == ')') { if (--pcnt<0) pcnt=0; }
- else if (*p == '[') pcnt2++;
- else if (*p == ']') { if (--pcnt2<0) pcnt2=0; }
- }
- }
- if (!*expr || !had_something) break;
- }
- // parse
- {
- int tmplen,funcname_len;
- const char *p = expr;
- const char *tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL);
- const char *funcname = nseel_simple_tokenizer(&p,endptr,&funcname_len,NULL);
- if (tok1 && funcname && tmplen == 8 && !strnicmp(tok1,"function",8) && (isalpha(funcname[0]) || funcname[0] == '_'))
- {
- int had_parms_locals=0;
- if (funcname_len > sizeof(is_fname)-1) funcname_len=sizeof(is_fname)-1;
- memcpy(is_fname, funcname, funcname_len);
- is_fname[funcname_len]=0;
- ctx->function_curName = is_fname; // only assigned for the duration of the loop, cleared later //-V507
- while (NULL != (tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL)))
- {
- int is_parms = 0, localTableContext = 0;
- int maxcnt=0;
- const char *sp_save;
- if (tok1[0] == '(')
- {
- if (had_parms_locals)
- {
- expr = p-1; // begin compilation at this code!
- break;
- }
- is_parms = 1;
- }
- else
- {
- if (tmplen == 5 && !strnicmp(tok1,"local",tmplen)) localTableContext=0;
- else if (tmplen == 6 && !strnicmp(tok1,"static",tmplen)) localTableContext=0;
- else if (tmplen == 8 && !strnicmp(tok1,"instance",tmplen)) localTableContext=1;
- else if ((tmplen == 7 && !strnicmp(tok1,"globals",tmplen)) ||
- (tmplen == 6 && !strnicmp(tok1,"global",tmplen)))
- {
- ctx->function_globalFlag = 1;
- localTableContext=2;
- }
- else break; // unknown token!
- tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL);
- if (!tok1 || tok1[0] != '(') break;
- }
- had_parms_locals = 1;
- sp_save=p;
- while (NULL != (tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL)))
- {
- if (tok1[0] == ')') break;
- if (*tok1 == '#' && localTableContext!=1 && localTableContext!=2)
- {
- ctx->errVar = (int) (tok1 - _expression);
- lstrcpyn_safe(ctx->last_error_string,"#string can only be in instance() or globals()",sizeof(ctx->last_error_string));
- goto had_error;
- }
- if (isalpha(*tok1) || *tok1 == '_' || *tok1 == '#')
- {
- maxcnt++;
- if (p < endptr && *p == '*')
- {
- if (!is_parms && localTableContext!=2)
- {
- ctx->errVar = (int) (p - _expression);
- lstrcpyn_safe(ctx->last_error_string,"namespace* can only be used in parameters or globals()",sizeof(ctx->last_error_string));
- goto had_error;
- }
- p++;
- }
- }
- else if (*tok1 != ',')
- {
- ctx->errVar = (int)(tok1 - _expression);
- lstrcpyn_safe(ctx->last_error_string,"unknown character in function parameters",sizeof(ctx->last_error_string));
- goto had_error;
- }
- }
- if (tok1 && maxcnt > 0)
- {
- char **ot = ctx->function_localTable_Names[localTableContext];
- const int osz = ctx->function_localTable_Size[localTableContext];
-
- maxcnt += osz;
- ctx->function_localTable_Names[localTableContext] = (char **)newTmpBlock(ctx,sizeof(char *) * maxcnt);
- if (ctx->function_localTable_Names[localTableContext])
- {
- int i=osz;
- if (osz && ot) memcpy(ctx->function_localTable_Names[localTableContext],ot,sizeof(char *) * osz);
- p=sp_save;
- while (NULL != (tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL)))
- {
- if (tok1[0] == ')') break;
- if (isalpha(*tok1) || *tok1 == '_' || *tok1 == '#')
- {
- char *newstr;
- int l = tmplen;
- if (*p == '*') // xyz* for namespace
- {
- p++;
- l++;
- }
- if (l > NSEEL_MAX_VARIABLE_NAMELEN) l = NSEEL_MAX_VARIABLE_NAMELEN;
- newstr = newTmpBlock(ctx,l+1);
- if (newstr)
- {
- memcpy(newstr,tok1,l);
- newstr[l]=0;
- ctx->function_localTable_Names[localTableContext][i++] = newstr;
- }
- }
- }
- ctx->function_localTable_Size[localTableContext]=i;
- if (is_parms) function_numparms = i;
- }
- }
- }
- }
- }
- if (ctx->function_localTable_Size[0]>0)
- {
- ctx->function_localTable_ValuePtrs =
- ctx->isSharedFunctions ? newDataBlock(ctx->function_localTable_Size[0] * sizeof(EEL_F *),8) :
- newTmpBlock(ctx,ctx->function_localTable_Size[0] * sizeof(EEL_F *));
- if (!ctx->function_localTable_ValuePtrs)
- {
- ctx->function_localTable_Size[0]=0;
- function_numparms=0;
- }
- else
- {
- memset(ctx->function_localTable_ValuePtrs,0,sizeof(EEL_F *) * ctx->function_localTable_Size[0]); // force values to be allocated
- }
- }
- {
- int nseelparse(compileContext* context);
- void nseelrestart (void *input_file ,void *yyscanner );
- ctx->rdbuf_start = _expression;
- #ifdef NSEEL_SUPER_MINIMAL_LEXER
- ctx->rdbuf = expr;
- ctx->rdbuf_end = endptr;
- if (!nseelparse(ctx) && !ctx->errVar)
- {
- start_opcode = ctx->result;
- }
- #else
- nseelrestart(NULL,ctx->scanner);
- ctx->rdbuf = expr;
- ctx->rdbuf_end = endptr;
- if (!nseelparse(ctx) && !ctx->errVar)
- {
- start_opcode = ctx->result;
- }
- if (ctx->errVar)
- {
- const char *p=expr;
- ctx->errVar += expr-_expression;
- }
- #endif
- ctx->rdbuf = NULL;
- }
-
- if (start_opcode)
- {
- int rvMode=0, fUse=0;
- #ifdef LOG_OPT
- char buf[512];
- int sd=0;
- sprintf(buf,"pre opt sz=%d (tsackDepth=%d)\n",compileOpcodes(ctx,start_opcode,NULL,1024*1024*256,NULL, NULL,RETURNVALUE_IGNORE,NULL,&sd,NULL),sd);
- #ifdef _WIN32
- OutputDebugString(buf);
- #else
- printf("%s\n",buf);
- #endif
- #endif
- #ifdef EEL_DUMP_OPS
- // dump opcode trees for verification, before optimizing
- if (g_eel_dump_fp)
- {
- fprintf(g_eel_dump_fp,"-- opcode chunk --\r\n");
- dumpOpcodeTree(ctx,g_eel_dump_fp,start_opcode,2);
- }
- #endif
- if (!(ctx->optimizeDisableFlags&OPTFLAG_NO_OPTIMIZE)) optimizeOpcodes(ctx,start_opcode,is_fname[0] ? 1 : 0);
- #ifdef LOG_OPT
- sprintf(buf,"post opt sz=%d, stack depth=%d\n",compileOpcodes(ctx,start_opcode,NULL,1024*1024*256,NULL,NULL, RETURNVALUE_IGNORE,NULL,&sd,NULL),sd);
- #ifdef _WIN32
- OutputDebugString(buf);
- #else
- printf("%s\n",buf);
- #endif
- #endif
- #ifdef EEL_DUMP_OPS
- // dump opcode trees for verification, after optimizing
- if (g_eel_dump_fp2)
- {
- fprintf(g_eel_dump_fp2,"-- POST-OPTIMIZED opcode chunk --\r\n");
- dumpOpcodeTree(ctx,g_eel_dump_fp2,start_opcode,2);
- }
- #endif
- if (is_fname[0])
- {
- _codeHandleFunctionRec *fr = ctx->isSharedFunctions ? newDataBlock(sizeof(_codeHandleFunctionRec),8) :
- newTmpBlock(ctx,sizeof(_codeHandleFunctionRec));
- if (fr)
- {
- memset(fr,0,sizeof(_codeHandleFunctionRec));
- fr->startptr_size = -1;
- fr->opcodes = start_opcode;
- if (ctx->function_localTable_Size[0] > 0 && ctx->function_localTable_ValuePtrs)
- {
- if (ctx->function_localTable_Names[0])
- {
- int i;
- for(i=0;i<function_numparms;i++)
- {
- const char *nptr = ctx->function_localTable_Names[0][i];
- if (nptr && *nptr && nptr[strlen(nptr)-1] == '*')
- {
- fr->parameterAsNamespaceMask |= ((unsigned int)1)<<i;
- }
- }
- }
- fr->num_params=function_numparms;
- fr->localstorage = ctx->function_localTable_ValuePtrs;
- fr->localstorage_size = ctx->function_localTable_Size[0];
- }
- fr->usesNamespaces = ctx->function_usesNamespaces;
- fr->isCommonFunction = ctx->isSharedFunctions;
- lstrcpyn_safe(fr->fname,is_fname,sizeof(fr->fname));
- if (ctx->isSharedFunctions)
- {
- fr->next = ctx->functions_common;
- ctx->functions_common = fr;
- }
- else
- {
- fr->next = ctx->functions_local;
- ctx->functions_local = fr;
- }
- }
- continue;
- }
- #ifdef DUMP_OPS_DURING_COMPILE
- g_debugfp_indent=0;
- g_debugfp_histsz=0;
- g_debugfp = fopen("C:/temp/foo.txt","w");
- #endif
- startptr_size = compileOpcodes(ctx,start_opcode,NULL,1024*1024*256,NULL, NULL,
- is_fname[0] ? (RETURNVALUE_NORMAL|RETURNVALUE_FPSTACK) : RETURNVALUE_IGNORE, &rvMode, &fUse, NULL); // if not a function, force return value as address (avoid having to pop it ourselves
- // if a function, allow the code to decide how return values are generated
- #ifdef DUMP_OPS_DURING_COMPILE
- if (g_debugfp) fclose(g_debugfp);
- g_debugfp=0;
- #endif
- if (!startptr_size) continue; // optimized away
- if (startptr_size>0)
- {
- startptr = newTmpBlock(ctx,startptr_size);
- if (startptr)
- {
- startptr_size=compileOpcodes(ctx,start_opcode,(unsigned char*)startptr,startptr_size,&computTableTop, NULL, RETURNVALUE_IGNORE, NULL,NULL, NULL);
- if (startptr_size<=0) startptr = NULL;
-
- }
- }
- }
- if (!startptr)
- {
- had_error:
- #ifdef NSEEL_EEL1_COMPAT_MODE
- continue;
- #else
- //if (!ctx->last_error_string[0])
- {
- int byteoffs = ctx->errVar;
- int linenumber;
- char cur_err[sizeof(ctx->last_error_string)];
- lstrcpyn_safe(cur_err,ctx->last_error_string,sizeof(cur_err));
- if (cur_err[0]) lstrcatn(cur_err,": ",sizeof(cur_err));
- else lstrcpyn_safe(cur_err,"syntax error: ",sizeof(cur_err));
- if (_expression + byteoffs >= _expression_end)
- {
- if (ctx->gotEndOfInput&4) byteoffs = (int)(expr-_expression);
- else byteoffs=(int)(_expression_end-_expression);
- }
- if (byteoffs < 0) byteoffs=0;
- linenumber=findLineNumber(_expression,byteoffs)+1;
- if (ctx->gotEndOfInput&4)
- {
- snprintf(ctx->last_error_string,sizeof(ctx->last_error_string),"%d: %smissing ) or ]",linenumber+lineoffs,cur_err);
- }
- else
- {
- const char *p = _expression + byteoffs;
- int x=0, right_amt_nospace=0, left_amt_nospace=0;
- while (x < 32 && p-x > _expression && p[-x] != '\r' && p[-x] != '\n')
- {
- if (!isspace(p[-x])) left_amt_nospace=x;
- x++;
- }
- x=0;
- while (x < 60 && p[x] && p[x] != '\r' && p[x] != '\n')
- {
- if (!isspace(p[x])) right_amt_nospace=x;
- x++;
- }
- if (right_amt_nospace<1) right_amt_nospace=1;
- // display left_amt >>>> right_amt_nospace
- if (left_amt_nospace > 0)
- snprintf(ctx->last_error_string,sizeof(ctx->last_error_string),"%d: %s'%.*s <!> %.*s'",linenumber+lineoffs,cur_err,
- left_amt_nospace,p-left_amt_nospace,
- right_amt_nospace,p);
- else
- snprintf(ctx->last_error_string,sizeof(ctx->last_error_string),"%d: %s'%.*s'",linenumber+lineoffs,cur_err,right_amt_nospace,p);
- }
- }
- startpts=NULL;
- startpts_tail=NULL;
- had_err=1;
- break;
- #endif
- }
-
- if (!is_fname[0]) // redundant check (if is_fname[0] is set and we succeeded, it should continue)
- // but we'll be on the safe side
- {
- topLevelCodeSegmentRec *p = newTmpBlock(ctx,sizeof(topLevelCodeSegmentRec));
- p->_next=0;
- p->code = startptr;
- p->codesz = startptr_size;
- p->tmptable_use = computTableTop;
-
- if (!startpts_tail) startpts_tail=startpts=p;
- else
- {
- startpts_tail->_next=p;
- startpts_tail=p;
- }
- if (curtabptr_sz < computTableTop)
- {
- curtabptr_sz=computTableTop;
- }
- }
- }
- memset(ctx->function_localTable_Size,0,sizeof(ctx->function_localTable_Size));
- memset(ctx->function_localTable_Names,0,sizeof(ctx->function_localTable_Names));
- ctx->function_localTable_ValuePtrs=0;
- ctx->function_usesNamespaces=0;
- ctx->function_curName=NULL;
- ctx->function_globalFlag=0;
- ctx->tmpCodeHandle = NULL;
-
- if (handle->want_stack)
- {
- if (!handle->stack) startpts=NULL;
- }
- if (startpts)
- {
- curtabptr_sz += 2; // many functions use the worktable for temporary storage of up to 2 EEL_F's
- handle->workTable_size = curtabptr_sz;
- handle->workTable = curtabptr = newDataBlock((curtabptr_sz+MIN_COMPUTABLE_SIZE + COMPUTABLE_EXTRA_SPACE) * sizeof(EEL_F),32);
- #ifdef EEL_VALIDATE_WORKTABLE_USE
- if (curtabptr) memset(curtabptr,0x3a,(curtabptr_sz+MIN_COMPUTABLE_SIZE + COMPUTABLE_EXTRA_SPACE) * sizeof(EEL_F));
- #endif
- if (!curtabptr) startpts=NULL;
- }
- if (startpts || (!had_err && (compile_flags & NSEEL_CODE_COMPILE_FLAG_COMMONFUNCS)))
- {
- unsigned char *writeptr;
- topLevelCodeSegmentRec *p=startpts;
- int size=sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE; // for ret at end :)
- int wtpos=0;
- // now we build one big code segment out of our list of them, inserting a mov esi, computable before each item as necessary
- while (p)
- {
- if (wtpos <= 0)
- {
- wtpos=MIN_COMPUTABLE_SIZE;
- size += GLUE_RESET_WTP(NULL,0);
- }
- size+=p->codesz;
- wtpos -= p->tmptable_use;
- p=p->_next;
- }
- handle->code = newCodeBlock(size,32);
- if (handle->code)
- {
- writeptr=(unsigned char *)handle->code;
- #if GLUE_FUNC_ENTER_SIZE > 0
- memcpy(writeptr,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE);
- writeptr += GLUE_FUNC_ENTER_SIZE;
- #endif
- p=startpts;
- wtpos=0;
- while (p)
- {
- if (wtpos <= 0)
- {
- wtpos=MIN_COMPUTABLE_SIZE;
- writeptr+=GLUE_RESET_WTP(writeptr,curtabptr);
- }
- memcpy(writeptr,(char*)p->code,p->codesz);
- writeptr += p->codesz;
- wtpos -= p->tmptable_use;
-
- p=p->_next;
- }
- #if GLUE_FUNC_LEAVE_SIZE > 0
- memcpy(writeptr,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE);
- writeptr += GLUE_FUNC_LEAVE_SIZE;
- #endif
- memcpy(writeptr,&GLUE_RET,sizeof(GLUE_RET)); writeptr += sizeof(GLUE_RET);
- ctx->l_stats[1]=size;
- handle->code_size = (int) (writeptr - (unsigned char *)handle->code);
- #if defined(__arm__) || defined(__aarch64__)
- __clear_cache(handle->code,writeptr);
- #endif
- }
-
- handle->blocks = ctx->blocks_head;
- handle->blocks_data = ctx->blocks_head_data;
- ctx->blocks_head=0;
- ctx->blocks_head_data=0;
- }
- else
- {
- // failed compiling, or failed calloc()
- handle=NULL; // return NULL (after resetting blocks_head)
- }
- ctx->directValueCache=0;
- ctx->functions_local = NULL;
-
- ctx->isGeneratingCommonFunction=0;
- ctx->isSharedFunctions=0;
- freeBlocks(&ctx->tmpblocks_head); // free blocks
- freeBlocks(&ctx->blocks_head); // free blocks of code (will be nonzero only on error)
- freeBlocks(&ctx->blocks_head_data); // free blocks of data (will be nonzero only on error)
- if (handle)
- {
- handle->compile_flags = compile_flags;
- handle->ramPtr = ctx->ram_state.blocks;
- memcpy(handle->code_stats,ctx->l_stats,sizeof(ctx->l_stats));
- nseel_evallib_stats[0]+=ctx->l_stats[0];
- nseel_evallib_stats[1]+=ctx->l_stats[1];
- nseel_evallib_stats[2]+=ctx->l_stats[2];
- nseel_evallib_stats[3]+=ctx->l_stats[3];
- nseel_evallib_stats[4]++;
- }
- else
- {
- ctx->functions_common = oldCommonFunctionList; // failed compiling, remove any added common functions from the list
- // remove any derived copies of functions due to error, since we may have added some that have been freed
- while (oldCommonFunctionList)
- {
- oldCommonFunctionList->derivedCopies=NULL;
- oldCommonFunctionList=oldCommonFunctionList->next;
- }
- }
- memset(ctx->l_stats,0,sizeof(ctx->l_stats));
- return (NSEEL_CODEHANDLE)handle;
- }
- //------------------------------------------------------------------------------
- void NSEEL_code_execute(NSEEL_CODEHANDLE code)
- {
- #ifndef GLUE_TABPTR_IGNORED
- INT_PTR tabptr;
- #endif
- INT_PTR codeptr;
- codeHandleType *h = (codeHandleType *)code;
- if (!h || !h->code) return;
- codeptr = (INT_PTR) h->code;
- #if 0
- {
- unsigned int *p=(unsigned int *)codeptr;
- while (*p != GLUE_RET[0])
- {
- printf("instr:%04X:%04X\n",*p>>16,*p&0xffff);
- p++;
- }
- }
- #endif
- #ifndef GLUE_TABPTR_IGNORED
- tabptr=(INT_PTR)h->workTable;
- #endif
- //printf("calling code!\n");
- GLUE_CALL_CODE(tabptr,codeptr,(INT_PTR)h->ramPtr);
- }
- int NSEEL_code_geterror_flag(NSEEL_VMCTX ctx)
- {
- compileContext *c=(compileContext *)ctx;
- if (c) return (c->gotEndOfInput ? 1 : 0);
- return 0;
- }
- char *NSEEL_code_getcodeerror(NSEEL_VMCTX ctx)
- {
- compileContext *c=(compileContext *)ctx;
- if (ctx && c->last_error_string[0]) return c->last_error_string;
- return 0;
- }
- //------------------------------------------------------------------------------
- void NSEEL_code_free(NSEEL_CODEHANDLE code)
- {
- codeHandleType *h = (codeHandleType *)code;
- if (h != NULL)
- {
- #ifdef EEL_VALIDATE_WORKTABLE_USE
- if (h->workTable)
- {
- char *p = ((char*)h->workTable) + h->workTable_size*sizeof(EEL_F);
- int x;
- for(x=COMPUTABLE_EXTRA_SPACE*sizeof(EEL_F) - 1;x >= 0; x --)
- if (p[x] != 0x3a)
- {
- char buf[512];
- snprintf(buf,sizeof(buf),"worktable overrun at byte %d (wts=%d), value = %f\n",x,h->workTable_size, *(EEL_F*)(p+(x&~(sizeof(EEL_F)-1))));
- #ifdef _WIN32
- OutputDebugString(buf);
- #else
- printf("%s",buf);
- #endif
- break;
- }
- }
- #endif
- nseel_evallib_stats[0]-=h->code_stats[0];
- nseel_evallib_stats[1]-=h->code_stats[1];
- nseel_evallib_stats[2]-=h->code_stats[2];
- nseel_evallib_stats[3]-=h->code_stats[3];
- nseel_evallib_stats[4]--;
- #if defined(__ppc__) && defined(__APPLE__)
- {
- FILE *fp = fopen("/var/db/receipts/com.apple.pkg.Rosetta.plist","r");
- if (fp)
- {
- fclose(fp);
- // on PPC, but rosetta installed, do not free h->blocks, as rosetta won't detect changes to these pages
- }
- else
- {
- freeBlocks(&h->blocks);
- }
- }
- #else
- freeBlocks(&h->blocks);
- #endif
-
- freeBlocks(&h->blocks_data);
- }
- }
- //------------------------------------------------------------------------------
- NSEEL_VMCTX NSEEL_VM_alloc() // return a handle
- {
- compileContext *ctx=calloc(1,sizeof(compileContext));
- #ifdef NSEEL_SUPER_MINIMAL_LEXER
- if (ctx) ctx->scanner = ctx;
- #else
- if (ctx)
- {
- int nseellex_init(void ** ptr_yy_globals);
- void nseelset_extra(void *user_defined , void *yyscanner);
- if (nseellex_init(&ctx->scanner))
- {
- free(ctx);
- return NULL;
- }
- nseelset_extra(ctx,ctx->scanner);
- }
- #endif
- if (ctx)
- {
- ctx->ram_state.maxblocks = NSEEL_RAM_BLOCKS_DEFAULTMAX;
- ctx->ram_state.closefact = NSEEL_CLOSEFACTOR;
- }
- return ctx;
- }
- int NSEEL_VM_setramsize(NSEEL_VMCTX _ctx, int maxent)
- {
- compileContext *ctx = (compileContext *)_ctx;
- if (!ctx) return 0;
- if (maxent > 0)
- {
- maxent = (maxent + NSEEL_RAM_ITEMSPERBLOCK - 1)/NSEEL_RAM_ITEMSPERBLOCK;
- if (maxent > NSEEL_RAM_BLOCKS) maxent = NSEEL_RAM_BLOCKS;
- ctx->ram_state.maxblocks = maxent;
- }
-
- return ctx->ram_state.maxblocks * NSEEL_RAM_ITEMSPERBLOCK;
- }
- void NSEEL_VM_SetFunctionValidator(NSEEL_VMCTX _ctx, const char * (*validateFunc)(const char *fn_name, void *user), void *user)
- {
- if (_ctx)
- {
- compileContext *ctx = (compileContext *)_ctx;
- ctx->func_check = validateFunc;
- ctx->func_check_user = user;
- }
- }
- void NSEEL_VM_SetFunctionTable(NSEEL_VMCTX _ctx, eel_function_table *tab)
- {
- if (_ctx)
- {
- compileContext *ctx = (compileContext *)_ctx;
- ctx->registered_func_tab = tab;
- }
- }
- void NSEEL_VM_free(NSEEL_VMCTX _ctx) // free when done with a VM and ALL of its code have been freed, as well
- {
- if (_ctx)
- {
- compileContext *ctx=(compileContext *)_ctx;
- EEL_GROWBUF_RESIZE(&ctx->varNameList,-1);
- NSEEL_VM_freeRAM(_ctx);
- freeBlocks(&ctx->pblocks);
- // these should be 0 normally but just in case
- freeBlocks(&ctx->tmpblocks_head); // free blocks
- freeBlocks(&ctx->blocks_head); // free blocks
- freeBlocks(&ctx->blocks_head_data); // free blocks
- #ifndef NSEEL_SUPER_MINIMAL_LEXER
- if (ctx->scanner)
- {
- int nseellex_destroy(void *yyscanner);
- nseellex_destroy(ctx->scanner);
- }
- #endif
- ctx->scanner=0;
- if (ctx->has_used_global_vars)
- {
- nseel_globalVarItem *p = NULL;
- NSEEL_HOSTSTUB_EnterMutex();
- if (--nseel_vms_referencing_globallist_cnt == 0)
- {
- // clear and free globals
- p = nseel_globalreg_list;
- nseel_globalreg_list=0;
- }
- NSEEL_HOSTSTUB_LeaveMutex();
- while (p)
- {
- nseel_globalVarItem *op = p;
- p=p->_next;
- free(op);
- }
- }
- free(ctx);
- }
- }
- int *NSEEL_code_getstats(NSEEL_CODEHANDLE code)
- {
- codeHandleType *h = (codeHandleType *)code;
- if (h)
- {
- return h->code_stats;
- }
- return 0;
- }
- void NSEEL_VM_SetStringFunc(NSEEL_VMCTX ctx,
- EEL_F (*onString)(void *caller_this, struct eelStringSegmentRec *list),
- EEL_F (*onNamedString)(void *caller_this, const char *name))
- {
- if (ctx)
- {
- compileContext *c=(compileContext*)ctx;
- c->onString = onString;
- c->onNamedString = onNamedString;
- }
- }
- void NSEEL_VM_SetCustomFuncThis(NSEEL_VMCTX ctx, void *thisptr)
- {
- if (ctx)
- {
- compileContext *c=(compileContext*)ctx;
- c->caller_this=thisptr;
- }
- }
- void *NSEEL_PProc_RAM(void *data, int data_size, compileContext *ctx)
- {
- if (data_size>0) data=EEL_GLUE_set_immediate(data, (INT_PTR)ctx->ram_state.blocks);
- return data;
- }
- void *NSEEL_PProc_THIS(void *data, int data_size, compileContext *ctx)
- {
- if (data_size>0) data=EEL_GLUE_set_immediate(data, (INT_PTR)ctx->caller_this);
- return data;
- }
- static int vartable_lowerbound(compileContext *ctx, const char *name, int *ismatch)
- {
- int a = 0, c = EEL_GROWBUF_GET_SIZE(&ctx->varNameList);
- varNameRec **list = EEL_GROWBUF_GET(&ctx->varNameList);
- while (a != c)
- {
- const int b = (a+c)/2;
- const int cmp = strnicmp(name,list[b]->str,NSEEL_MAX_VARIABLE_NAMELEN);
- if (cmp > 0) a = b+1;
- else if (cmp < 0) c = b;
- else
- {
- *ismatch = 1;
- return b;
- }
- }
- *ismatch = 0;
- return a;
- }
- static void vartable_cull_list(compileContext *ctx, int refcnt_chk)
- {
- const int ni = EEL_GROWBUF_GET_SIZE(&ctx->varNameList);
- int i = ni, ndel = 0;
- varNameRec **rd = EEL_GROWBUF_GET(&ctx->varNameList), **wr=rd;
- while (i--)
- {
- varNameRec *v = rd[0];
- if ((!refcnt_chk || !v->refcnt) && !v->isreg)
- {
- ndel++;
- }
- else
- {
- if (wr != rd) *wr = *rd;
- wr++;
- }
- rd++;
- }
- if (ndel) EEL_GROWBUF_RESIZE(&ctx->varNameList,ni - ndel);
- }
- void NSEEL_VM_remove_unused_vars(NSEEL_VMCTX _ctx)
- {
- compileContext *ctx = (compileContext *)_ctx;
- if (ctx) vartable_cull_list(ctx,1);
- }
- void NSEEL_VM_remove_all_nonreg_vars(NSEEL_VMCTX _ctx)
- {
- compileContext *ctx = (compileContext *)_ctx;
- if (ctx) vartable_cull_list(ctx,0);
- }
- void NSEEL_VM_clear_var_refcnts(NSEEL_VMCTX _ctx)
- {
- compileContext *ctx = (compileContext *)_ctx;
- if (ctx)
- {
- int i = EEL_GROWBUF_GET_SIZE(&ctx->varNameList);
- varNameRec **rd = EEL_GROWBUF_GET(&ctx->varNameList);
- while (i--)
- {
- rd[0]->refcnt=0;
- rd++;
- }
- }
- }
- #ifdef NSEEL_EEL1_COMPAT_MODE
- static EEL_F __nseel_global_regs[100];
- double *NSEEL_getglobalregs() { return __nseel_global_regs; }
- #endif
- EEL_F *get_global_var(compileContext *ctx, const char *gv, int addIfNotPresent)
- {
- nseel_globalVarItem *p;
- #ifdef NSEEL_EEL1_COMPAT_MODE
- if (!strnicmp(gv,"reg",3) && gv[3]>='0' && gv[3] <= '9' && gv[4] >= '0' && gv[4] <= '9' && !gv[5])
- {
- return __nseel_global_regs + atoi(gv+3);
- }
- #endif
- NSEEL_HOSTSTUB_EnterMutex();
- if (!ctx->has_used_global_vars)
- {
- ctx->has_used_global_vars++;
- nseel_vms_referencing_globallist_cnt++;
- }
- p = nseel_globalreg_list;
- while (p)
- {
- if (!stricmp(p->name,gv)) break;
- p=p->_next;
- }
- if (!p && addIfNotPresent)
- {
- size_t gvl = strlen(gv);
- p = (nseel_globalVarItem*)malloc(sizeof(nseel_globalVarItem) + gvl);
- if (p)
- {
- p->data=0.0;
- strcpy(p->name,gv);
- p->_next = nseel_globalreg_list;
- nseel_globalreg_list=p;
- }
- }
- NSEEL_HOSTSTUB_LeaveMutex();
- return p ? &p->data : NULL;
- }
- EEL_F *nseel_int_register_var(compileContext *ctx, const char *name, int isReg, const char **namePtrOut)
- {
- int slot, match;
- if (isReg == 0 && ctx->getVariable)
- {
- EEL_F *ret = ctx->getVariable(ctx->getVariable_userctx, name);
- if (ret) return ret;
- }
- if (!strnicmp(name,"_global.",8) && name[8])
- {
- EEL_F *a=get_global_var(ctx,name+8,isReg >= 0);
- if (a) return a;
- }
- slot = vartable_lowerbound(ctx,name, &match);
- if (match)
- {
- varNameRec *v = EEL_GROWBUF_GET(&ctx->varNameList)[slot];
- if (isReg >= 0)
- {
- v->refcnt++;
- if (isReg) v->isreg=isReg;
- if (namePtrOut) *namePtrOut = v->str;
- }
- return v->value;
- }
- if (isReg < 0) return NULL;
- if (ctx->varValueStore_left<1)
- {
- const int sz=500;
- ctx->varValueStore_left = sz;
- ctx->varValueStore = (EEL_F *)newCtxDataBlock((int)sizeof(EEL_F)*sz,8);
- }
- if (ctx->varValueStore)
- {
- int listsz = EEL_GROWBUF_GET_SIZE(&ctx->varNameList);
- size_t l = strlen(name);
- varNameRec *vh;
- if (l > NSEEL_MAX_VARIABLE_NAMELEN) l = NSEEL_MAX_VARIABLE_NAMELEN;
- vh = (varNameRec*) newCtxDataBlock( (int) (sizeof(varNameRec) + l),8);
- if (!vh || EEL_GROWBUF_RESIZE(&ctx->varNameList, (listsz+1))) return NULL; // alloc fail
- (vh->value = ctx->varValueStore++)[0]=0.0;
- ctx->varValueStore_left--;
- vh->refcnt=1;
- vh->isreg=isReg;
- memcpy(vh->str,name,l);
- vh->str[l] = 0;
- if (namePtrOut) *namePtrOut = vh->str;
- if (slot < listsz)
- {
- memmove(EEL_GROWBUF_GET(&ctx->varNameList) + slot+1,
- EEL_GROWBUF_GET(&ctx->varNameList) + slot, (listsz - slot) * sizeof(EEL_GROWBUF_GET(&ctx->varNameList)[0]));
- }
- EEL_GROWBUF_GET(&ctx->varNameList)[slot] = vh;
- return vh->value;
- }
- return NULL;
- }
- //------------------------------------------------------------------------------
- void NSEEL_VM_enumallvars(NSEEL_VMCTX ctx, int (*func)(const char *name, EEL_F *val, void *ctx), void *userctx)
- {
- compileContext *tctx = (compileContext *) ctx;
- int ni;
- varNameRec **rd;
- if (!tctx) return;
-
- ni = EEL_GROWBUF_GET_SIZE(&tctx->varNameList);
- rd = EEL_GROWBUF_GET(&tctx->varNameList);
- while (ni--)
- {
- if (!func(rd[0]->str,rd[0]->value,userctx)) break;
- rd++;
- }
- }
- //------------------------------------------------------------------------------
- EEL_F *NSEEL_VM_regvar(NSEEL_VMCTX _ctx, const char *var)
- {
- compileContext *ctx = (compileContext *)_ctx;
- if (!ctx) return 0;
-
- if (!strnicmp(var,"reg",3) && strlen(var) == 5 && isdigit(var[3]) && isdigit(var[4]))
- {
- EEL_F *a=get_global_var(ctx,var,1);
- if (a) return a;
- }
-
- return nseel_int_register_var(ctx,var,1,NULL);
- }
- EEL_F *NSEEL_VM_getvar(NSEEL_VMCTX _ctx, const char *var)
- {
- compileContext *ctx = (compileContext *)_ctx;
- if (!ctx) return 0;
-
- if (!strnicmp(var,"reg",3) && strlen(var) == 5 && isdigit(var[3]) && isdigit(var[4]))
- {
- EEL_F *a=get_global_var(ctx,var,0);
- if (a) return a;
- }
-
- return nseel_int_register_var(ctx,var,-1,NULL);
- }
- int NSEEL_VM_get_var_refcnt(NSEEL_VMCTX _ctx, const char *name)
- {
- compileContext *ctx = (compileContext *)_ctx;
- int slot,match;
- if (!ctx) return -1;
- slot = vartable_lowerbound(ctx,name, &match);
- return match ? EEL_GROWBUF_GET(&ctx->varNameList)[slot]->refcnt : -1;
- }
- opcodeRec *nseel_createFunctionByName(compileContext *ctx, const char *name, int np, opcodeRec *code1, opcodeRec *code2, opcodeRec *code3)
- {
- int chkamt=0;
- functionType *f=nseel_getFunctionByName(ctx,name,&chkamt);
- if (f) while (chkamt-->=0)
- {
- if ((f->nParams&FUNCTIONTYPE_PARAMETERCOUNTMASK) == np)
- {
- opcodeRec *o=newOpCode(ctx,NULL, np==3?OPCODETYPE_FUNC3:np==2?OPCODETYPE_FUNC2:OPCODETYPE_FUNC1);
- if (o)
- {
- o->fntype = FUNCTYPE_FUNCTIONTYPEREC;
- o->fn = f;
- o->parms.parms[0]=code1;
- o->parms.parms[1]=code2;
- o->parms.parms[2]=code3;
- }
- return o;
- }
- f++;
- if (stricmp(f->name,name)) break;
- }
- return NULL;
- }
- //------------------------------------------------------------------------------
- opcodeRec *nseel_translate(compileContext *ctx, const char *tmp, size_t tmplen) // tmplen 0 = null term
- {
- // this depends on the string being nul terminated eventually, tmplen is used more as a hint than anything else
- if ((tmp[0] == '0' || tmp[0] == '$') && toupper(tmp[1])=='X')
- {
- char *p;
- return nseel_createCompiledValue(ctx,(EEL_F)strtoul(tmp+2,&p,16));
- }
- else if (tmp[0] == '$')
- {
- if (tmp[1] == '~')
- {
- char *p=(char*)tmp+2;
- unsigned int v=strtoul(tmp+2,&p,10);
- if (v>53) v=53;
- return nseel_createCompiledValue(ctx,(EEL_F)((((WDL_INT64)1) << v) - 1));
- }
- else if (!tmplen ? !stricmp(tmp,"$E") : (tmplen == 2 && !strnicmp(tmp,"$E",2)))
- return nseel_createCompiledValue(ctx,(EEL_F)2.71828183);
- else if (!tmplen ? !stricmp(tmp, "$PI") : (tmplen == 3 && !strnicmp(tmp, "$PI", 3)))
- return nseel_createCompiledValue(ctx,(EEL_F)3.141592653589793);
- else if (!tmplen ? !stricmp(tmp, "$PHI") : (tmplen == 4 && !strnicmp(tmp, "$PHI", 4)))
- return nseel_createCompiledValue(ctx,(EEL_F)1.61803399);
- else if ((!tmplen || tmplen == 4) && tmp[1] == '\'' && tmp[2] && tmp[3] == '\'')
- return nseel_createCompiledValue(ctx,(EEL_F)tmp[2]);
- else return NULL;
- }
- else if (tmp[0] == '\'')
- {
- char b[64];
- int x,sz;
- unsigned int rv=0;
- if (!tmplen) // nul terminated tmplen, calculate a workable length
- {
- // faster than strlen(tmp) if tmp is large, we'll never need more than ~18 chars anyway
- while (tmplen < 32 && tmp[tmplen]) tmplen++;
- }
-
- sz = tmplen > 0 ? nseel_filter_escaped_string(b,sizeof(b),tmp+1, tmplen - 1, '\'') : 0;
-
- if (sz > 4)
- {
- if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string));
- snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"multi-byte character '%.5s...' too long",b);
- return NULL; // do not allow 'xyzxy', limit to 4 bytes
- }
- for (x=0;x<sz;x++) rv = (rv<<8) + ((unsigned char*)b)[x];
- return nseel_createCompiledValue(ctx,(EEL_F)rv);
- }
- else if (tmp[0] == '#')
- {
- char buf[2048];
- if (!tmplen) while (tmplen < sizeof(buf)-1 && tmp[tmplen]) tmplen++;
- else if (tmplen > sizeof(buf)-1) tmplen = sizeof(buf)-1;
- memcpy(buf,tmp,tmplen);
- buf[tmplen]=0;
- if (ctx->onNamedString)
- {
- if (tmplen>0 && buf[1]&&ctx->function_curName)
- {
- int err=0;
- opcodeRec *r = nseel_resolve_named_symbol(ctx,nseel_createCompiledValuePtr(ctx,NULL,buf),-1, &err);
- if (r)
- {
- if (r->opcodeType!=OPCODETYPE_VALUE_FROM_NAMESPACENAME)
- {
- r->opcodeType = OPCODETYPE_DIRECTVALUE;
- r->parms.dv.directValue = ctx->onNamedString(ctx->caller_this,buf+1);
- r->parms.dv.valuePtr=NULL;
- }
- return r;
- }
- if (err) return NULL;
- }
- // if not namespaced symbol, return directly
- if (!buf[1])
- {
- opcodeRec *r=newOpCode(ctx,NULL,OPCODETYPE_DIRECTVALUE_TEMPSTRING);
- if (r) r->parms.dv.directValue = -10000.0;
- return r;
- }
- return nseel_createCompiledValue(ctx,ctx->onNamedString(ctx->caller_this,buf+1));
- }
- }
- return nseel_createCompiledValue(ctx,(EEL_F)atof(tmp));
- }
- void NSEEL_VM_set_var_resolver(NSEEL_VMCTX _ctx, EEL_F *(*res)(void *userctx, const char *name), void *userctx)
- {
- compileContext *ctx = (compileContext *)_ctx;
- if (ctx)
- {
- ctx->getVariable = res;
- ctx->getVariable_userctx = userctx;
- }
- }
- #if defined(__ppc__) || defined(EEL_TARGET_PORTABLE)
- // blank stubs
- void eel_setfp_round() { }
- void eel_setfp_trunc() { }
- void eel_enterfp(int s[2]) {}
- void eel_leavefp(int s[2]) {}
- #endif
|